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
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
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
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
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
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
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
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