예제 #1
0
파일: etaproducts.py 프로젝트: shalec/sage
    def __init__(self, parent, rdict):
        r"""
        Create an eta product object. Usually called implicitly via
        EtaGroup_class.__call__ or the EtaProduct factory function.

        EXAMPLES::

            sage: EtaGroupElement(EtaGroup(8), {1:24, 2:-24})
            Eta product of level 8 : (eta_1)^24 (eta_2)^-24
            sage: g = _; g == loads(dumps(g))
            True
        """
        MultiplicativeGroupElement.__init__(self, parent)

        self._N = self.parent().level()
        N = self._N

        if isinstance(rdict, EtaGroupElement):
            rdict = rdict._rdict
            # Note: This is needed because the "x in G" test tries to call G(x)
            # and see if it returns an error. So sometimes this will be getting
            # called with rdict being an eta product, not a dictionary.

        if rdict == 1:
            rdict = {}
        # Check Ligozat criteria
        sumR = sumDR = sumNoverDr = 0
        prod = 1

        for d in rdict.keys():
            if N % d:
                raise ValueError("%s does not divide %s" % (d, N))

        for d in rdict.keys():
            if rdict[d] == 0:
                rdict.pop(d)
                continue
            sumR += rdict[d]
            sumDR += rdict[d] * d
            sumNoverDr += rdict[d] * N / d
            prod *= (N / d)**rdict[d]

        if sumR != 0:
            raise ValueError("sum r_d (=%s) is not 0" % sumR)
        if (sumDR % 24) != 0:
            raise ValueError("sum d r_d (=%s) is not 0 mod 24" % sumDR)
        if (sumNoverDr % 24) != 0:
            raise ValueError("sum (N/d) r_d (=%s) is not 0 mod 24" %
                             sumNoverDr)
        if not is_square(prod):
            raise ValueError("product (N/d)^(r_d) (=%s) is not a square" %
                             prod)

        self._sumDR = sumDR  # this is useful to have around
        self._rdict = rdict
        self._keys = rdict.keys()  # avoid factoring N every time
예제 #2
0
    def __init__(self, parent, rdict):
        r"""
        Create an eta product object. Usually called implicitly via
        EtaGroup_class.__call__ or the EtaProduct factory function.

        EXAMPLE::

            sage: EtaGroupElement(EtaGroup(8), {1:24, 2:-24})
            Eta product of level 8 : (eta_1)^24 (eta_2)^-24
            sage: g = _; g == loads(dumps(g))
            True
        """
        MultiplicativeGroupElement.__init__(self, parent)

        self._N = self.parent().level()
        N = self._N

        if isinstance(rdict, EtaGroupElement):
            rdict = rdict._rdict
            # Note: This is needed because the "x in G" test tries to call G(x)
            # and see if it returns an error. So sometimes this will be getting
            # called with rdict being an eta product, not a dictionary.

        if rdict == 1:
            rdict = {}
        # Check Ligozat criteria
        sumR = sumDR = sumNoverDr = 0
        prod = 1

        for d in rdict.keys():
            if N % d:
                raise ValueError("%s does not divide %s" % (d, N))

        for d in rdict.keys():
            if rdict[d] == 0:
                rdict.pop(d)
                continue
            sumR += rdict[d]
            sumDR += rdict[d]*d
            sumNoverDr += rdict[d]*N/d
            prod *= (N/d)**rdict[d]

        if sumR != 0:
            raise ValueError("sum r_d (=%s) is not 0" % sumR)
        if (sumDR % 24) != 0:
            raise ValueError("sum d r_d (=%s) is not 0 mod 24" % sumDR)
        if (sumNoverDr % 24) != 0:
            raise ValueError("sum (N/d) r_d (=%s) is not 0 mod 24" % sumNoverDr)
        if not is_square(prod):
            raise ValueError("product (N/d)^(r_d) (=%s) is not a square" % prod)

        self._sumDR = sumDR # this is useful to have around
        self._rdict = rdict
        self._keys = rdict.keys() # avoid factoring N every time
예제 #3
0
파일: sha_tate.py 프로젝트: drupel/sage
    def an(self, use_database=False, descent_second_limit=12):
        r"""
        Returns the Birch and Swinnerton-Dyer conjectural order of `Sha`
        as a provably correct integer, unless the analytic rank is > 1,
        in which case this function returns a numerical value.

        INPUT:

            - ``use_database`` -- bool (default: ``False``); if ``True``, try
              to use any databases installed to lookup the analytic order of
              `Sha`, if possible.  The order of `Sha` is computed if it cannot
              be looked up.

            - ``descent_second_limit`` -- int (default: 12); limit to use on
              point searching for the quartic twist in the hard case

        This result is proved correct if the order of vanishing is 0
        and the Manin constant is <= 2.

        If the optional parameter ``use_database`` is ``True`` (default:
        ``False``), this function returns the analytic order of `Sha` as
        listed in Cremona's tables, if this curve appears in Cremona's
        tables.

        NOTE:

        If you come across the following error::

            sage: E = EllipticCurve([0, 0, 1, -34874, -2506691])
            sage: E.sha().an()
            Traceback (most recent call last):
            ...
            RuntimeError: Unable to compute the rank, hence generators, with certainty (lower bound=0, generators found=[]).  This could be because Sha(E/Q)[2] is nontrivial.
            Try increasing descent_second_limit then trying this command again.

        You can increase the ``descent_second_limit`` (in the above example,
        set to the default, 12) option to try again::

            sage: E.sha().an(descent_second_limit=16)  # long time (2s on sage.math, 2011)
            1

        EXAMPLES::

            sage: E = EllipticCurve([0, -1, 1, -10, -20])   # 11A  = X_0(11)
            sage: E.sha().an()
            1
            sage: E = EllipticCurve([0, -1, 1, 0, 0])       # X_1(11)
            sage: E.sha().an()
            1

            sage: EllipticCurve('14a4').sha().an()
            1
            sage: EllipticCurve('14a4').sha().an(use_database=True)   # will be faster if you have large Cremona database installed
            1

        The smallest conductor curve with nontrivial `Sha`::

            sage: E = EllipticCurve([1,1,1,-352,-2689])     # 66b3
            sage: E.sha().an()
            4

        The four optimal quotients with nontrivial `Sha` and conductor <= 1000::

            sage: E = EllipticCurve([0, -1, 1, -929, -10595])       # 571A
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([1, 1, 0, -1154, -15345])       # 681B
            sage: E.sha().an()
            9
            sage: E = EllipticCurve([0, -1, 0, -900, -10098])       # 960D
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([0, 1, 0, -20, -42])            # 960N
            sage: E.sha().an()
            4

        The smallest conductor curve of rank > 1::

            sage: E = EllipticCurve([0, 1, 1, -2, 0])       # 389A (rank 2)
            sage: E.sha().an()
            1.00000000000000

        The following are examples that require computation of the Mordell-
        Weil group and regulator::

            sage: E = EllipticCurve([0, 0, 1, -1, 0])                     # 37A  (rank 1)
            sage: E.sha().an()
            1

            sage: E = EllipticCurve("1610f3")
            sage: E.sha().an()
            4

        In this case the input curve is not minimal, and if this function did
        not transform it to be minimal, it would give nonsense::

            sage: E = EllipticCurve([0,-432*6^2])
            sage: E.sha().an()
            1

        See :trac:`10096`: this used to give the wrong result 6.0000
        before since the minimal model was not used::

            sage: E = EllipticCurve([1215*1216,0]) # non-minimal model
            sage: E.sha().an()  # long time (2s on sage.math, 2011)
            1.00000000000000
            sage: E.minimal_model().sha().an()  # long time (1s on sage.math, 2011)
            1.00000000000000
        """
        if hasattr(self, '__an'):
            return self.__an
        if use_database:
            d = self.Emin.database_curve()
            if hasattr(d, 'db_extra'):
                self.__an = Integer(round(float(d.db_extra[4])))
                return self.__an

        # it's critical to switch to the minimal model.
        E = self.Emin
        eps = E.root_number()
        if eps == 1:
            L1_over_omega = E.lseries().L_ratio()
            if L1_over_omega == 0: # order of vanishing is at least 2
                return self.an_numerical(use_database=use_database)
            T = E.torsion_subgroup().order()
            Sha = (L1_over_omega * T * T) / Q(E.tamagawa_product())
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha)
            if not arith.is_square(Sha):
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha

        else:  # rank > 0  (Not provably correct)
            L1, error_bound = E.lseries().deriv_at1(10*sqrt(E.conductor()) + 10)
            if abs(L1) < error_bound:
                s = self.an_numerical()
                E.__an = s
                self.__an = s
                return s

            regulator = E.regulator(use_database=use_database, descent_second_limit=descent_second_limit)
            T = E.torsion_subgroup().order()
            omega = E.period_lattice().omega()
            Sha = Integer(round ( (L1 * T * T) / (E.tamagawa_product() * regulator * omega) ))
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha)
            if not arith.is_square(Sha):
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha
예제 #4
0
def regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e,existence=False):
    r"""
    Return a Regular Symmetric Hadamard Matrix with Constant Diagonal.

    A Hadamard matrix is said to be *regular* if its rows all sum to the same
    value.

    For `\epsilon\in\{-1,+1\}`, we say that `M` is a `(n,\epsilon)-RSHCD` if
    `M` is a regular symmetric Hadamard matrix with constant diagonal
    `\delta\in\{-1,+1\}` and row sums all equal to `\delta \epsilon
    \sqrt(n)`. For more information, see [HX10]_ or 10.5.1 in
    [BH12]_. For the case `n=324`, see :func:`RSHCD_324` and [CP16]_.

    INPUT:

    - ``n`` (integer) -- side of the matrix

    - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import regular_symmetric_hadamard_matrix_with_constant_diagonal
        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(4,1)
        [ 1  1  1 -1]
        [ 1  1 -1  1]
        [ 1 -1  1  1]
        [-1  1  1  1]
        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(4,-1)
        [ 1 -1 -1 -1]
        [-1  1 -1 -1]
        [-1 -1  1 -1]
        [-1 -1 -1  1]

    Other hardcoded values::

        sage: for n,e in [(36,1),(36,-1),(100,1),(100,-1),(196, 1)]:
        ....:     print regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e)
        36 x 36 dense matrix over Integer Ring
        36 x 36 dense matrix over Integer Ring
        100 x 100 dense matrix over Integer Ring
        100 x 100 dense matrix over Integer Ring
        196 x 196 dense matrix over Integer Ring

        sage: for n,e in [(324,1),(324,-1)]: # not tested - long time, tested in RSHCD_324
        ....:     print regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e) # not tested - long time
        324 x 324 dense matrix over Integer Ring
        324 x 324 dense matrix over Integer Ring

    From two close prime powers::

        sage: print regular_symmetric_hadamard_matrix_with_constant_diagonal(64,-1)
        64 x 64 dense matrix over Integer Ring

    Recursive construction::

        sage: print regular_symmetric_hadamard_matrix_with_constant_diagonal(144,-1)
        144 x 144 dense matrix over Integer Ring

    REFERENCE:

    .. [BH12] \A. Brouwer and W. Haemers,
      Spectra of graphs,
      Springer, 2012,
      http://homepages.cwi.nl/~aeb/math/ipm/ipm.pdf

    .. [HX10] \W. Haemers and Q. Xiang,
      Strongly regular graphs with parameters `(4m^4,2m^4+m^2,m^4+m^2,m^4+m^2)` exist for all `m>1`,
      European Journal of Combinatorics,
      Volume 31, Issue 6, August 2010, Pages 1553-1559,
      http://dx.doi.org/10.1016/j.ejc.2009.07.009.
    """
    if existence and (n,e) in _rshcd_cache:
        return _rshcd_cache[n,e]

    from sage.graphs.strongly_regular_db import strongly_regular_graph

    def true():
        _rshcd_cache[n,e] = True
        return True

    M = None
    if abs(e) != 1:
        raise ValueError
    if n<0:
        if existence:
            return False
        raise ValueError
    elif n == 4:
        if existence:
            return true()
        if e == 1:
            M = J(4)-2*matrix(4,[[int(i+j == 3) for i in range(4)] for j in range(4)])
        else:
            M = -J(4)+2*I(4)
    elif n ==  36:
        if existence:
            return true()
        if e == 1:
            M = strongly_regular_graph(36, 15, 6, 6).adjacency_matrix()
            M = J(36) - 2*M
        else:
            M = strongly_regular_graph(36,14,4,6).adjacency_matrix()
            M =  -J(36) + 2*M + 2*I(36)
    elif n == 100:
        if existence:
            return true()
        if e == -1:
            M = strongly_regular_graph(100,44,18,20).adjacency_matrix()
            M = 2*M - J(100) + 2*I(100)
        else:
            M = strongly_regular_graph(100,45,20,20).adjacency_matrix()
            M = J(100) - 2*M
    elif n == 196 and e == 1:
        if existence:
            return true()
        M = strongly_regular_graph(196,91,42,42).adjacency_matrix()
        M = J(196) - 2*M
    elif n == 324:
        if existence:
            return true()
        M = RSHCD_324(e)
    elif (  e  == 1                 and
          n%16 == 0                 and
          is_square(n)              and
          is_prime_power(sqrt(n)-1) and
          is_prime_power(sqrt(n)+1)):
        if existence:
            return true()
        M = -rshcd_from_close_prime_powers(int(sqrt(n)))

    # Recursive construction: the kronecker product of two RSHCD is a RSHCD
    else:
        from itertools import product
        for n1,e1 in product(divisors(n)[1:-1],[-1,1]):
            e2 = e1*e
            n2 = n//n1
            if (regular_symmetric_hadamard_matrix_with_constant_diagonal(n1,e1,existence=True) and
                regular_symmetric_hadamard_matrix_with_constant_diagonal(n2,e2,existence=True)):
                if existence:
                    return true()
                M1 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n1,e1)
                M2 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n2,e2)
                M  = M1.tensor_product(M2)
                break

    if M is None:
        from sage.misc.unknown import Unknown
        _rshcd_cache[n,e] = Unknown
        if existence:
            return Unknown
        raise ValueError("I do not know how to build a {}-RSHCD".format((n,e)))

    assert M*M.transpose() == n*I(n)
    assert set(map(sum,M)) == {e*sqrt(n)}

    return M
예제 #5
0
파일: sha_tate.py 프로젝트: yjjcc/sage
    def an(self, use_database=False, descent_second_limit=12):
        r"""
        Returns the Birch and Swinnerton-Dyer conjectural order of `Sha`
        as a provably correct integer, unless the analytic rank is > 1,
        in which case this function returns a numerical value.

        INPUT:

        - ``use_database`` -- bool (default: ``False``); if ``True``, try
          to use any databases installed to lookup the analytic order of
          `Sha`, if possible.  The order of `Sha` is computed if it cannot
          be looked up.

        - ``descent_second_limit`` -- int (default: 12); limit to use on
          point searching for the quartic twist in the hard case

        This result is proved correct if the order of vanishing is 0
        and the Manin constant is <= 2.

        If the optional parameter ``use_database`` is ``True`` (default:
        ``False``), this function returns the analytic order of `Sha` as
        listed in Cremona's tables, if this curve appears in Cremona's
        tables.

        NOTE:

        If you come across the following error::

            sage: E = EllipticCurve([0, 0, 1, -34874, -2506691])
            sage: E.sha().an()
            Traceback (most recent call last):
            ...
            RuntimeError: Unable to compute the rank, hence generators, with certainty (lower bound=0, generators found=[]).  This could be because Sha(E/Q)[2] is nontrivial.
            Try increasing descent_second_limit then trying this command again.

        You can increase the ``descent_second_limit`` (in the above example,
        set to the default, 12) option to try again::

            sage: E.sha().an(descent_second_limit=16)  # long time (2s on sage.math, 2011)
            1

        EXAMPLES::

            sage: E = EllipticCurve([0, -1, 1, -10, -20])   # 11A  = X_0(11)
            sage: E.sha().an()
            1
            sage: E = EllipticCurve([0, -1, 1, 0, 0])       # X_1(11)
            sage: E.sha().an()
            1

            sage: EllipticCurve('14a4').sha().an()
            1
            sage: EllipticCurve('14a4').sha().an(use_database=True)   # will be faster if you have large Cremona database installed
            1

        The smallest conductor curve with nontrivial `Sha`::

            sage: E = EllipticCurve([1,1,1,-352,-2689])     # 66b3
            sage: E.sha().an()
            4

        The four optimal quotients with nontrivial `Sha` and conductor <= 1000::

            sage: E = EllipticCurve([0, -1, 1, -929, -10595])       # 571A
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([1, 1, 0, -1154, -15345])       # 681B
            sage: E.sha().an()
            9
            sage: E = EllipticCurve([0, -1, 0, -900, -10098])       # 960D
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([0, 1, 0, -20, -42])            # 960N
            sage: E.sha().an()
            4

        The smallest conductor curve of rank > 1::

            sage: E = EllipticCurve([0, 1, 1, -2, 0])       # 389A (rank 2)
            sage: E.sha().an()
            1.00000000000000

        The following are examples that require computation of the Mordell-
        Weil group and regulator::

            sage: E = EllipticCurve([0, 0, 1, -1, 0])                     # 37A  (rank 1)
            sage: E.sha().an()
            1

            sage: E = EllipticCurve("1610f3")
            sage: E.sha().an()
            4

        In this case the input curve is not minimal, and if this function did
        not transform it to be minimal, it would give nonsense::

            sage: E = EllipticCurve([0,-432*6^2])
            sage: E.sha().an()
            1

        See :trac:`10096`: this used to give the wrong result 6.0000
        before since the minimal model was not used::

            sage: E = EllipticCurve([1215*1216,0]) # non-minimal model
            sage: E.sha().an()  # long time (2s on sage.math, 2011)
            1.00000000000000
            sage: E.minimal_model().sha().an()  # long time (1s on sage.math, 2011)
            1.00000000000000
        """
        if hasattr(self, '__an'):
            return self.__an
        if use_database:
            d = self.Emin.database_curve()
            if hasattr(d, 'db_extra'):
                self.__an = Integer(round(float(d.db_extra[4])))
                return self.__an

        # it's critical to switch to the minimal model.
        E = self.Emin
        eps = E.root_number()
        if eps == 1:
            L1_over_omega = E.lseries().L_ratio()
            if L1_over_omega == 0:  # order of vanishing is at least 2
                return self.an_numerical(use_database=use_database)
            T = E.torsion_subgroup().order()
            Sha = (L1_over_omega * T * T) / Q(E.tamagawa_product())
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError(
                    "There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."
                    % Sha)
            if not arith.is_square(Sha):
                raise RuntimeError(
                    "There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."
                    % Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha

        else:  # rank > 0  (Not provably correct)
            L1, error_bound = E.lseries().deriv_at1(10 * sqrt(E.conductor()) +
                                                    10)
            if abs(L1) < error_bound:
                s = self.an_numerical()
                E.__an = s
                self.__an = s
                return s

            regulator = E.regulator(use_database=use_database,
                                    descent_second_limit=descent_second_limit)
            T = E.torsion_subgroup().order()
            omega = E.period_lattice().omega()
            Sha = ((L1 * T * T) /
                   (E.tamagawa_product() * regulator * omega)).round()
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError(
                    "There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."
                    % Sha)
            if not arith.is_square(Sha):
                raise RuntimeError(
                    "There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."
                    % Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha
예제 #6
0
def regular_symmetric_hadamard_matrix_with_constant_diagonal(
        n, e, existence=False):
    r"""
    Return a Regular Symmetric Hadamard Matrix with Constant Diagonal.

    A Hadamard matrix is said to be *regular* if its rows all sum to the same
    value.

    For `\epsilon\in\{-1,+1\}`, we say that `M` is a `(n,\epsilon)-RSHCD` if
    `M` is a regular symmetric Hadamard matrix with constant diagonal
    `\delta\in\{-1,+1\}` and row sums all equal to `\delta \epsilon
    \sqrt(n)`. For more information, see [HX10]_ or 10.5.1 in
    [BH12]_. For the case `n=324`, see :func:`RSHCD_324` and [CP16]_.

    INPUT:

    - ``n`` (integer) -- side of the matrix

    - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import regular_symmetric_hadamard_matrix_with_constant_diagonal
        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(4,1)
        [ 1  1  1 -1]
        [ 1  1 -1  1]
        [ 1 -1  1  1]
        [-1  1  1  1]
        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(4,-1)
        [ 1 -1 -1 -1]
        [-1  1 -1 -1]
        [-1 -1  1 -1]
        [-1 -1 -1  1]

    Other hardcoded values::

        sage: for n,e in [(36,1),(36,-1),(100,1),(100,-1),(196, 1)]:  # long time
        ....:     print(repr(regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e)))
        36 x 36 dense matrix over Integer Ring
        36 x 36 dense matrix over Integer Ring
        100 x 100 dense matrix over Integer Ring
        100 x 100 dense matrix over Integer Ring
        196 x 196 dense matrix over Integer Ring

        sage: for n,e in [(324,1),(324,-1)]: # not tested - long time, tested in RSHCD_324
        ....:     print(repr(regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e)))
        324 x 324 dense matrix over Integer Ring
        324 x 324 dense matrix over Integer Ring

    From two close prime powers::

        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(64,-1)
        64 x 64 dense matrix over Integer Ring (use the '.str()' method to see the entries)

    From a prime power and a conference matrix::

        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(676,1)  # long time
        676 x 676 dense matrix over Integer Ring (use the '.str()' method to see the entries)

    Recursive construction::

        sage: regular_symmetric_hadamard_matrix_with_constant_diagonal(144,-1)
        144 x 144 dense matrix over Integer Ring (use the '.str()' method to see the entries)

    REFERENCE:

    .. [BH12] \A. Brouwer and W. Haemers,
      Spectra of graphs,
      Springer, 2012,
      http://homepages.cwi.nl/~aeb/math/ipm/ipm.pdf

    .. [HX10] \W. Haemers and Q. Xiang,
      Strongly regular graphs with parameters `(4m^4,2m^4+m^2,m^4+m^2,m^4+m^2)` exist for all `m>1`,
      European Journal of Combinatorics,
      Volume 31, Issue 6, August 2010, Pages 1553-1559,
      :doi:`10.1016/j.ejc.2009.07.009`
    """
    if existence and (n, e) in _rshcd_cache:
        return _rshcd_cache[n, e]

    from sage.graphs.strongly_regular_db import strongly_regular_graph

    def true():
        _rshcd_cache[n, e] = True
        return True

    M = None
    if abs(e) != 1:
        raise ValueError
    sqn = None
    if is_square(n):
        sqn = int(sqrt(n))
    if n < 0:
        if existence:
            return False
        raise ValueError
    elif n == 4:
        if existence:
            return true()
        if e == 1:
            M = J(4) - 2 * matrix(4, [[int(i + j == 3) for i in range(4)]
                                      for j in range(4)])
        else:
            M = -J(4) + 2 * I(4)
    elif n == 36:
        if existence:
            return true()
        if e == 1:
            M = strongly_regular_graph(36, 15, 6, 6).adjacency_matrix()
            M = J(36) - 2 * M
        else:
            M = strongly_regular_graph(36, 14, 4, 6).adjacency_matrix()
            M = -J(36) + 2 * M + 2 * I(36)
    elif n == 100:
        if existence:
            return true()
        if e == -1:
            M = strongly_regular_graph(100, 44, 18, 20).adjacency_matrix()
            M = 2 * M - J(100) + 2 * I(100)
        else:
            M = strongly_regular_graph(100, 45, 20, 20).adjacency_matrix()
            M = J(100) - 2 * M
    elif n == 196 and e == 1:
        if existence:
            return true()
        M = strongly_regular_graph(196, 91, 42, 42).adjacency_matrix()
        M = J(196) - 2 * M
    elif n == 324:
        if existence:
            return true()
        M = RSHCD_324(e)
    elif (e == 1 and n % 16 == 0 and not sqn is None
          and is_prime_power(sqn - 1) and is_prime_power(sqn + 1)):
        if existence:
            return true()
        M = -rshcd_from_close_prime_powers(sqn)

    elif (e == 1 and not sqn is None and sqn % 4 == 2
          and True == strongly_regular_graph(sqn - 1, (sqn - 2) // 2,
                                             (sqn - 6) // 4,
                                             existence=True)
          and is_prime_power(ZZ(sqn + 1))):
        if existence:
            return true()
        M = rshcd_from_prime_power_and_conference_matrix(sqn + 1)

    # Recursive construction: the kronecker product of two RSHCD is a RSHCD
    else:
        from itertools import product
        for n1, e1 in product(divisors(n)[1:-1], [-1, 1]):
            e2 = e1 * e
            n2 = n // n1
            if (regular_symmetric_hadamard_matrix_with_constant_diagonal(
                    n1, e1, existence=True) and
                    regular_symmetric_hadamard_matrix_with_constant_diagonal(
                        n2, e2, existence=True)):
                if existence:
                    return true()
                M1 = regular_symmetric_hadamard_matrix_with_constant_diagonal(
                    n1, e1)
                M2 = regular_symmetric_hadamard_matrix_with_constant_diagonal(
                    n2, e2)
                M = M1.tensor_product(M2)
                break

    if M is None:
        from sage.misc.unknown import Unknown
        _rshcd_cache[n, e] = Unknown
        if existence:
            return Unknown
        raise ValueError("I do not know how to build a {}-RSHCD".format(
            (n, e)))

    assert M * M.transpose() == n * I(n)
    assert set(map(sum, M)) == {ZZ(e * sqn)}

    return M
예제 #7
0
def radical_difference_set(K, k, l=1, existence=False, check=True):
    r"""
    Return a difference set made of a cyclotomic coset in the finite field
    ``K`` and with paramters ``k`` and ``l``.

    Most of these difference sets appear in chapter VI.18.48 of the Handbook of
    combinatorial designs.

    EXAMPLES::

        sage: from sage.combinat.designs.difference_family import radical_difference_set

        sage: D = radical_difference_set(GF(7), 3, 1); D
        [[1, 2, 4]]
        sage: sorted(x-y for x in D[0] for y in D[0] if x != y)
        [1, 2, 3, 4, 5, 6]

        sage: D = radical_difference_set(GF(16,'a'), 6, 2)
        sage: sorted(x-y for x in D[0] for y in D[0] if x != y)
        [1,
         1,
         a,
         a,
         a + 1,
         a + 1,
         a^2,
         a^2,
         ...
         a^3 + a^2 + a + 1,
         a^3 + a^2 + a + 1]

        sage: for k in range(2,50):
        ....:     for l in reversed(divisors(k*(k-1))):
        ....:         v = k*(k-1)//l + 1
        ....:         if is_prime_power(v) and radical_difference_set(GF(v,'a'),k,l,existence=True):
        ....:             _ = radical_difference_set(GF(v,'a'),k,l)
        ....:             print "{:3} {:3} {:3}".format(v,k,l)
          3   2   1
          4   3   2
          7   3   1
          5   4   3
          7   4   2
         13   4   1
         11   5   2
          7   6   5
         11   6   3
         16   6   2
          8   7   6
          9   8   7
         19   9   4
         37   9   2
         73   9   1
         11  10   9
         19  10   5
         23  11   5
         13  12  11
         23  12   6
         27  13   6
         27  14   7
         16  15  14
         31  15   7
        ...
         41  40  39
         79  40  20
         83  41  20
         43  42  41
         83  42  21
         47  46  45
         49  48  47
        197  49  12
    """
    v = K.cardinality()

    if l*(v-1) != k*(k-1):
        if existence:
            return False
        raise EmptySetError("l*(v-1) is not equal to k*(k-1)")

    # trivial case
    if (v-1) == k:
        if existence:
            return True
        add_zero = False

    # q = 3 mod 4
    elif v%4 == 3 and k == (v-1)//2:
        if existence:
            return True
        add_zero = False

    # q = 3 mod 4
    elif v%4 == 3 and k == (v+1)//2:
        if existence:
            return True
        add_zero = True

    # 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
        add_zero = False

    # 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
        add_zero = True

    # exceptional case 1
    elif (v,k,l) == (16,6,2):
        if existence:
            return True
        add_zero = True

    # exceptional case 2
    elif (v,k,l) == (73,9,1):
        if existence:
            return True
        add_zero = False

    # are there more ??
    else:
        x = K.multiplicative_generator()
        D = K.cyclotomic_cosets(x**((v-1)//k), [K.one()])
        if is_difference_family(K, D, v, k, l):
            print "**  You found a new example of radical difference set **\n"\
                  "**  for the parameters (v,k,l)=({},{},{}).            **\n"\
                  "**  Please contact [email protected]        **\n".format(v,k,l)
            if existence:
                return True
            add_zero = False

        else:
            D = K.cyclotomic_cosets(x**((v-1)//(k-1)), [K.one()])
            D[0].insert(0,K.zero())
            if is_difference_family(K, D, v, k, l):
                print "**  You found a new example of radical difference set **\n"\
                      "**  for the parameters (v,k,l)=({},{},{}).            **\n"\
                      "**  Please contact [email protected]        **\n".format(v,k,l)
                if existence:
                    return True
                add_zero = True

            elif existence:
                return False
            else:
                raise EmptySetError("no radical difference set exist "
                        "for the parameters (v,k,l) = ({},{},{}".format(v,k,l))

    x = K.multiplicative_generator()
    if add_zero:
        r = x**((v-1)//(k-1))
        D = K.cyclotomic_cosets(r, [K.one()])
        D[0].insert(0, K.zero())
    else:
        r = x**((v-1)//k)
        D = K.cyclotomic_cosets(r, [K.one()])

    if check and not is_difference_family(K, D, v, k, l):
        raise RuntimeError("Sage tried to build a radical difference set with "
                "parameters ({},{},{}) but it seems that it failed! Please "
                "e-mail [email protected]".format(v,k,l))

    return D
예제 #8
0
def radical_difference_set(K, k, l=1, existence=False, check=True):
    r"""
    Return a difference set made of a cyclotomic coset in the finite field
    ``K`` and with paramters ``k`` and ``l``.

    Most of these difference sets appear in chapter VI.18.48 of the Handbook of
    combinatorial designs.

    EXAMPLES::

        sage: from sage.combinat.designs.difference_family import radical_difference_set

        sage: D = radical_difference_set(GF(7), 3, 1); D
        [[1, 2, 4]]
        sage: sorted(x-y for x in D[0] for y in D[0] if x != y)
        [1, 2, 3, 4, 5, 6]

        sage: D = radical_difference_set(GF(16,'a'), 6, 2)
        sage: sorted(x-y for x in D[0] for y in D[0] if x != y)
        [1,
         1,
         a,
         a,
         a + 1,
         a + 1,
         a^2,
         a^2,
         ...
         a^3 + a^2 + a + 1,
         a^3 + a^2 + a + 1]

        sage: for k in range(2,50):
        ....:     for l in reversed(divisors(k*(k-1))):
        ....:         v = k*(k-1)//l + 1
        ....:         if is_prime_power(v) and radical_difference_set(GF(v,'a'),k,l,existence=True):
        ....:             _ = radical_difference_set(GF(v,'a'),k,l)
        ....:             print "{:3} {:3} {:3}".format(v,k,l)
          3   2   1
          4   3   2
          7   3   1
          5   4   3
          7   4   2
         13   4   1
         11   5   2
          7   6   5
         11   6   3
         16   6   2
          8   7   6
          9   8   7
         19   9   4
         37   9   2
         73   9   1
         11  10   9
         19  10   5
         23  11   5
         13  12  11
         23  12   6
         27  13   6
         27  14   7
         16  15  14
         31  15   7
        ...
         41  40  39
         79  40  20
         83  41  20
         43  42  41
         83  42  21
         47  46  45
         49  48  47
        197  49  12
    """
    v = K.cardinality()

    if l * (v - 1) != k * (k - 1):
        if existence:
            return False
        raise EmptySetError("l*(v-1) is not equal to k*(k-1)")

    # trivial case
    if (v - 1) == k:
        if existence:
            return True
        add_zero = False

    # q = 3 mod 4
    elif v % 4 == 3 and k == (v - 1) // 2:
        if existence:
            return True
        add_zero = False

    # q = 3 mod 4
    elif v % 4 == 3 and k == (v + 1) // 2:
        if existence:
            return True
        add_zero = True

    # 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
        add_zero = False

    # 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
        add_zero = True

    # exceptional case 1
    elif (v, k, l) == (16, 6, 2):
        if existence:
            return True
        add_zero = True

    # exceptional case 2
    elif (v, k, l) == (73, 9, 1):
        if existence:
            return True
        add_zero = False

    # are there more ??
    else:
        x = K.multiplicative_generator()
        D = K.cyclotomic_cosets(x**((v - 1) // k), [K.one()])
        if is_difference_family(K, D, v, k, l):
            print "**  You found a new example of radical difference set **\n"\
                  "**  for the parameters (v,k,l)=({},{},{}).            **\n"\
                  "**  Please contact [email protected]        **\n".format(v,k,l)
            if existence:
                return True
            add_zero = False

        else:
            D = K.cyclotomic_cosets(x**((v - 1) // (k - 1)), [K.one()])
            D[0].insert(0, K.zero())
            if is_difference_family(K, D, v, k, l):
                print "**  You found a new example of radical difference set **\n"\
                      "**  for the parameters (v,k,l)=({},{},{}).            **\n"\
                      "**  Please contact [email protected]        **\n".format(v,k,l)
                if existence:
                    return True
                add_zero = True

            elif existence:
                return False
            else:
                raise EmptySetError(
                    "no radical difference set exist "
                    "for the parameters (v,k,l) = ({},{},{}".format(v, k, l))

    x = K.multiplicative_generator()
    if add_zero:
        r = x**((v - 1) // (k - 1))
        D = K.cyclotomic_cosets(r, [K.one()])
        D[0].insert(0, K.zero())
    else:
        r = x**((v - 1) // k)
        D = K.cyclotomic_cosets(r, [K.one()])

    if check and not is_difference_family(K, D, v, k, l):
        raise RuntimeError(
            "Sage tried to build a radical difference set with "
            "parameters ({},{},{}) but it seems that it failed! Please "
            "e-mail [email protected]".format(v, k, l))

    return D