def long_element_hardcoded(self): """ Returns the long Weyl group element (hardcoded data) Do we really want to keep it? There is a generic implementation which works in all cases. The hardcoded should have a better complexity (for large classical types), but there is a cache, so does this really matter? EXAMPLES:: sage: types = [ ['A',5],['B',3],['C',3],['D',4],['G',2],['F',4],['E',6] ] sage: [WeylGroup(t).long_element().length() for t in types] [15, 9, 9, 12, 6, 24, 36] sage: all( WeylGroup(t).long_element() == WeylGroup(t).long_element_hardcoded() for t in types ) # long time (17s on sage.math, 2011) True """ type = self.cartan_type() if type[0] == 'D' and type[1]%2 == 1: l = [-1 for i in range(self.n-1)] l.append(1) m = diagonal_matrix(QQ,l) elif type[0] == 'A': l = [0 for k in range((self.n)**2)] for k in range(self.n-1, (self.n)**2-1, self.n-1): l[k] = 1 m = matrix(QQ, self.n, l) elif type[0] == 'E': if type[1] == 6: half = ZZ(1)/ZZ(2) l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], [half, -half, -half, -half, 0, 0, 0, 0], [0, 0, 0, 0, half, half, half, -half], [0, 0, 0, 0, half, half, -half, half], [0, 0, 0, 0, half, -half, half, half], [0, 0, 0, 0, -half, half, half, half]] m = matrix(QQ, 8, l) else: raise NotImplementedError, "Not implemented yet for this type" elif type[0] == 'G': third = ZZ(1)/ZZ(3) twothirds = ZZ(2)/ZZ(3) l = [[-third, twothirds, twothirds], [twothirds, -third, twothirds], [twothirds, twothirds, -third]] m = matrix(QQ, 3, l) else: m = diagonal_matrix([-1 for i in range(self.n)]) return self.__call__(m)
def long_element_hardcoded(self): """ Returns the long Weyl group element (hardcoded data) Do we really want to keep it? There is a generic implementation which works in all cases. The hardcoded should have a better complexity (for large classical types), but there is a cache, so does this really matter? EXAMPLES:: sage: types = [ ['A',5],['B',3],['C',3],['D',4],['G',2],['F',4],['E',6] ] sage: [WeylGroup(t).long_element().length() for t in types] [15, 9, 9, 12, 6, 24, 36] sage: all( WeylGroup(t).long_element() == WeylGroup(t).long_element_hardcoded() for t in types ) # long time (17s on sage.math, 2011) True """ type = self.cartan_type() if type[0] == 'D' and type[1]%2 == 1: l = [-1 for i in range(self.n-1)] l.append(1) m = diagonal_matrix(QQ,l) elif type[0] == 'A': l = [0 for k in range((self.n)**2)] for k in range(self.n-1, (self.n)**2-1, self.n-1): l[k] = 1 m = matrix(QQ, self.n, l) elif type[0] == 'E': if type[1] == 6: half = ZZ(1)/ZZ(2) l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], [half, -half, -half, -half, 0, 0, 0, 0], [0, 0, 0, 0, half, half, half, -half], [0, 0, 0, 0, half, half, -half, half], [0, 0, 0, 0, half, -half, half, half], [0, 0, 0, 0, -half, half, half, half]] m = matrix(QQ, 8, l) else: raise NotImplementedError("Not implemented yet for this type") elif type[0] == 'G': third = ZZ(1)/ZZ(3) twothirds = ZZ(2)/ZZ(3) l = [[-third, twothirds, twothirds], [twothirds, -third, twothirds], [twothirds, twothirds, -third]] m = matrix(QQ, 3, l) else: m = diagonal_matrix([-1 for i in range(self.n)]) return self(m)
def _kohnen_phi(self, a, t) : ## We use a modified power of a, namely for each prime factor p of a ## we use p**floor(v_p(a)/2). This is compensated for in the routine ## of \rho a_modif = 1 for (p,e) in a.factor() : a_modif = a_modif * p**(e // 2) res = 0 for dsq in filter(lambda d: d.is_square(), a.divisors()) : d = isqrt(dsq) for g_diag in itertools.ifilter( lambda diag: prod(diag) == d, itertools.product(*[d.divisors() for _ in xrange(t.nrows())]) ) : for subents in itertools.product(*[xrange(r) for (j,r) in enumerate(g_diag) for _ in xrange(j)]) : columns = [subents[(j * (j - 1)) // 2:(j * (j + 1)) // 2] for j in xrange(t.nrows())] g = diagonal_matrix(list(g_diag)) for j in xrange(t.nrows()) : for i in xrange(j) : g[i,j] = columns[j][i] ginv = g.inverse() tg = ginv.transpose() * t * ginv try : tg= matrix(ZZ, tg) except : continue if any(tg[i,i] % 2 == 1 for i in xrange(tg.nrows())) : continue tg.set_immutable() res = res + self._kohnen_rho(tg, a // dsq) return a_modif * res
def to_matrix(self): """ Return a matrix of ``self``. The colors are mapped to roots of unity. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: s1,s2,t = C.gens() sage: x = s1*s2*t*s2; x.one_line_form() [(1, 2), (0, 1), (0, 3)] sage: M = x.to_matrix(); M [ 0 1 0] [zeta4 0 0] [ 0 0 1] The matrix multiplication is in the *opposite* order:: sage: M == s2.to_matrix()*t.to_matrix()*s2.to_matrix()*s1.to_matrix() True """ Cp = CyclotomicField(self.parent()._m) g = Cp.gen() D = diagonal_matrix(Cp, [g ** i for i in self._colors]) return self._perm.to_matrix() * D
def to_matrix(self): """ Return a matrix of ``self``. The colors are mapped to roots of unity. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: s1,s2,t = C.gens() sage: x = s1*s2*t*s2; x.one_line_form() [(1, 2), (0, 1), (0, 3)] sage: M = x.to_matrix(); M [ 0 1 0] [zeta4 0 0] [ 0 0 1] The matrix multiplication is in the *opposite* order:: sage: M == s2.to_matrix()*t.to_matrix()*s2.to_matrix()*s1.to_matrix() True """ Cp = CyclotomicField(self.parent()._m) g = Cp.gen() D = diagonal_matrix(Cp, [g**i for i in self._colors]) return self._perm.to_matrix() * D
def _rank(self, K) : if K is QQ or K in NumberFields() : return len(_jacobi_forms_by_taylor_expansion_coords(self.__index, self.__weight, 0)) ## This is the formula used by Poor and Yuen in Paramodular cusp forms if self.__weight == 2 : delta = len(self.__index.divisors()) // 2 - 1 else : delta = 0 return sum( ModularForms(1, self.__weight + 2 * j).dimension() + j**2 // (4 * self.__index) for j in xrange(self.__index + 1) ) \ + delta ## This is the formula given by Skoruppa in ## Jacobi forms of critical weight and Weil representations ##FIXME: There is some mistake here if self.__weight % 2 != 0 : ## Otherwise the space X(i**(n - 2 k)) is different ## See: Skoruppa, Jacobi forms of critical weight and Weil representations raise NotImplementedError m = self.__index K = CyclotomicField(24 * m, 'zeta') zeta = K.gen(0) quadform = lambda x : 6 * x**2 bilinform = lambda x,y : quadform(x + y) - quadform(x) - quadform(y) T = diagonal_matrix([zeta**quadform(i) for i in xrange(2*m)]) S = sum(zeta**(-quadform(x)) for x in xrange(2 * m)) / (2 * m) \ * matrix([[zeta**(-bilinform(j,i)) for j in xrange(2*m)] for i in xrange(2*m)]) subspace_matrix_1 = matrix( [ [1 if j == i or j == 2*m - i else 0 for j in xrange(m + 1) ] for i in xrange(2*m)] ) subspace_matrix_2 = zero_matrix(ZZ, m + 1, 2*m) subspace_matrix_2.set_block(0,0,identity_matrix(m+1)) T = subspace_matrix_2 * T * subspace_matrix_1 S = subspace_matrix_2 * S * subspace_matrix_1 sqrt3 = (zeta**(4*m) - zeta**(-4*m)) * zeta**(-6*m) rank = (self.__weight - 1/2 - 1) / 2 * (m + 1) \ + 1/8 * ( zeta**(3*m * (2*self.__weight - 1)) * S.trace() + zeta**(3*m * (1 - 2*self.__weight)) * S.trace().conjugate() ) \ + 2/(3*sqrt3) * ( zeta**(4 * m * self.__weight) * (S*T).trace() + zeta**(-4 * m * self.__weight) * (S*T).trace().conjugate() ) \ - sum((j**2 % (m+1))/(m+1) -1/2 for j in range(0,m+1)) if self.__weight > 5 / 2 : return rank else : raise NotImplementedError raise NotImplementedError
def elementary_divisors(self): r""" This returns the elementary divisors of the group, using Pari. .. note:: Here is another algorithm for computing the elementary divisors `d_1, d_2, d_3, \ldots`, of a finite abelian group (where `d_1 | d_2 | d_3 | \ldots` are composed of prime powers dividing the invariants of the group in a way described below). Just factor the invariants `a_i` that define the abelian group. Then the biggest `d_i` is the product of the maximum prime powers dividing some `a_j`. In other words, the largest `d_i` is the product of `p^v`, where `v = max(ord_p(a_j) \mathrm{ for all } j`). Now divide out all those `p^v`'s into the list of invariants `a_i`, and get a new list of "smaller invariants"". Repeat the above procedure on these ""smaller invariants"" to compute `d_{i-1}`, and so on. (Thanks to Robert Miller for communicating this algorithm.) TODO: When somebody wants to speed this code up, please implement he above algorithm. EXAMPLES:: sage: G = AbelianGroup(2,[2,3]) sage: G.elementary_divisors() [6] sage: G = AbelianGroup(1, [6]) sage: G.elementary_divisors() [6] sage: G = AbelianGroup(2,[2,6]) sage: G Multiplicative Abelian Group isomorphic to C2 x C6 sage: G.invariants() [2, 6] sage: G.elementary_divisors() [2, 6] sage: J = AbelianGroup([1,3,5,12]) sage: J.elementary_divisors() [3, 60] sage: G = AbelianGroup(2,[0,6]) sage: G.elementary_divisors() [6, 0] """ from sage.matrix.constructor import diagonal_matrix inv = self.invariants() eldivs = diagonal_matrix(ZZ, inv).elementary_divisors() if len(eldivs) == 1 or not (1 in eldivs): return eldivs else: eldivs.remove(1) return eldivs
def linear_representation(p, polys): """ Assuming that ``p`` is a linear combination of ``polys``, determine coefficients that describe the linear combination. This probably does not work for any inputs except ``p``, a polynomial, and ``polys``, a sequence of polynomials. If ``p`` is not in fact a linear combination of ``polys``, the function raises an exception. The algorithm creates a matrix of coefficients of the monomials of ``polys`` and ``p``, with the coefficients of ``p`` in the last row. It augments this matrix with the appropriate identity matrix, then computes the echelon form of the augmented matrix. The last row should contain zeroes in the first columns, and the last columns contain a linear dependence relation. Solving for the desired linear relation is straightforward. INPUT: - ``p`` - a polynomial - ``polys`` - a list/tuple of polynomials OUTPUT: If ``n == len(polys)``, returns ``[a[0],a[1],...,a[n-1]]`` such that ``p == a[0]*poly[0] + ... + a[n-1]*poly[n-1]``. EXAMPLES:: sage: from sage.rings.polynomial.toy_variety import linear_representation sage: R.<x,y> = PolynomialRing(GF(32003)) sage: B = [x^2 + 1, y^2 + 1, x*y + 1] sage: p = 3*B[0] - 2*B[1] + B[2] sage: linear_representation(p, B) [3, 32001, 1] """ from sage.matrix.constructor import diagonal_matrix R = p.base_ring() M = coefficient_matrix(polys + [p]).augment( diagonal_matrix(R, [1 for each in range(len(polys) + 1)])) M.echelonize() j = M.ncols() - 1 n = M.nrows() - 1 offset = M.ncols() - M.nrows() return [M[n, offset + each] / (-M[n, j]) for each in range(len(polys))]
def elementary_divisors(self): r""" Return the elementary divisors of this group. See :meth:`sage.groups.abelian_gps.abelian_group_gap.elementary_divisors`. EXAMPLES:: sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: G.elementary_divisors() (2, 60) """ ediv = self.gap().AbelianInvariants().sage() from sage.matrix.constructor import diagonal_matrix ed = diagonal_matrix(ZZ, ediv).elementary_divisors() return tuple(d for d in ed if d != 1)
def linear_representation(p, polys): """ Assuming that ``p`` is a linear combination of ``polys``, determines coefficients that describe the linear combination. This probably doesn't work for any inputs except ``p``, a polynomial, and ``polys``, a sequence of polynomials. If ``p`` is not in fact a linear combination of ``polys``, the function raises an exception. The algorithm creates a matrix of coefficients of the monomials of ``polys`` and ``p``, with the coefficients of ``p`` in the last row. It augments this matrix with the appropriate identity matrix, then computes the echelon form of the augmented matrix. The last row should contain zeroes in the first columns, and the last columns contain a linear dependence relation. Solving for the desired linear relation is straightforward. INPUT: - ``p`` - a polynomial - ``polys`` - a list/tuple of polynomials OUTPUT: If ``n == len(polys)``, returns ``[a[0],a[1],...,a[n-1]]`` such that ``p == a[0]*poly[0] + ... + a[n-1]*poly[n-1]``. EXAMPLE:: sage: from sage.rings.polynomial.toy_variety import linear_representation sage: R.<x,y> = PolynomialRing(GF(32003)) sage: B = [x^2 + 1, y^2 + 1, x*y + 1] sage: p = 3*B[0] - 2*B[1] + B[2] sage: linear_representation(p, B) [3, 32001, 1] """ from sage.matrix.constructor import diagonal_matrix R = p.base_ring() M = coefficient_matrix(polys + [p]).augment(diagonal_matrix(R, [1 for each in xrange(len(polys) + 1)])) M.echelonize() j = M.ncols() - 1 n = M.nrows() - 1 offset = M.ncols() - M.nrows() return [M[n, offset + each] / (-M[n, j]) for each in xrange(len(polys))]
def elementary_divisors(self): r""" This returns the elementary divisors of the group, using Pari. .. note:: Here is another algorithm for computing the elementary divisors `d_1, d_2, d_3, \ldots`, of a finite abelian group (where `d_1 | d_2 | d_3 | \ldots` are composed of prime powers dividing the invariants of the group in a way described below). Just factor the invariants `a_i` that define the abelian group. Then the biggest `d_i` is the product of the maximum prime powers dividing some `a_j`. In other words, the largest `d_i` is the product of `p^v`, where `v = max(ord_p(a_j) \mathrm{ for all } j`). Now divide out all those `p^v`'s into the list of invariants `a_i`, and get a new list of "smaller invariants"". Repeat the above procedure on these ""smaller invariants"" to compute `d_{i-1}`, and so on. (Thanks to Robert Miller for communicating this algorithm.) EXAMPLES:: sage: G = AbelianGroup(2,[2,3]) sage: G.elementary_divisors() [6] sage: G = AbelianGroup(1, [6]) sage: G.elementary_divisors() [6] sage: G = AbelianGroup(2,[2,6]) sage: G Multiplicative Abelian Group isomorphic to C2 x C6 sage: G.invariants() [2, 6] sage: G.elementary_divisors() [2, 6] sage: J = AbelianGroup([1,3,5,12]) sage: J.elementary_divisors() [3, 60] sage: G = AbelianGroup(2,[0,6]) sage: G.elementary_divisors() [6, 0] sage: AbelianGroup([3,4,5]).elementary_divisors() [60] """ from sage.matrix.constructor import diagonal_matrix ed = diagonal_matrix(ZZ, self.invariants()).elementary_divisors() return [d for d in ed if d!=1]
def gen(self, i = 0) : if i < self.__n : t = diagonal_matrix(ZZ, i * [0] + [2] + (self.__n - i - 1) * [0]) t.set_immutable() return t elif i >= self.__n and i < (self.__n * (self.__n + 1)) // 2 : i = i - self.__n for r in xrange(self.__n) : if i >= self.__n - r - 1 : i = i - (self.__n - r - 1) continue c = i + r + 1 break t = zero_matrix(ZZ, self.__n) t[r,c] = 1 t[c,r] = 1 t.set_immutable() return t elif not self.__reduced and i >= (self.__n * (self.__n + 1)) // 2 \ and i < self.__n**2 : i = i - (self.__n * (self.__n + 1)) // 2 for r in xrange(self.__n) : if i >= self.__n - r - 1 : i = i - (self.__n - r - 1) continue c = i + r + 1 break t = zero_matrix(ZZ, self.__n) t[r,c] = -1 t[c,r] = -1 t.set_immutable() return t raise ValueError, "Generator not defined"
def _kohnen_phi(self, a, t): ## We use a modified power of a, namely for each prime factor p of a ## we use p**floor(v_p(a)/2). This is compensated for in the routine ## of \rho a_modif = 1 for (p, e) in a.factor(): a_modif = a_modif * p**(e // 2) res = 0 for dsq in [d for d in a.divisors() if d.is_square()]: d = isqrt(dsq) for g_diag in filter( lambda diag: prod(diag) == d, itertools.product( *[d.divisors() for _ in range(t.nrows())])): for subents in itertools.product(*[ range(r) for (j, r) in enumerate(g_diag) for _ in range(j) ]): columns = [ subents[(j * (j - 1)) // 2:(j * (j + 1)) // 2] for j in range(t.nrows()) ] g = diagonal_matrix(list(g_diag)) for j in range(t.nrows()): for i in range(j): g[i, j] = columns[j][i] ginv = g.inverse() tg = ginv.transpose() * t * ginv try: tg = matrix(ZZ, tg) except: continue if any(tg[i, i] % 2 == 1 for i in range(tg.nrows())): continue tg.set_immutable() res = res + self._kohnen_rho(tg, a // dsq) return a_modif * res
def _parity_check_matrix_vandermonde(self): """ Return a parity check matrix for ``self`` using Vandermonde matrix. EXAMPLES:: sage: F = GF(2^3) sage: R.<x> = F[] sage: g = x^2 + x+ 1 sage: L = [a for a in F.list() if g(a) != 0] sage: C = codes.GoppaCode(g, L) sage: C [8, 2] Goppa code over GF(2) sage: C._parity_check_matrix_vandermonde() [1 0 0 0 0 0 0 1] [0 0 1 0 1 1 1 0] [0 1 1 1 0 0 1 0] [---------------] [0 1 1 1 1 1 1 1] [0 1 0 1 1 0 1 0] [0 0 1 1 1 1 0 0] """ L = self._defining_set g = self._generating_pol t = g.degree() from sage.matrix.constructor import matrix, diagonal_matrix, block_matrix V = matrix.vandermonde(L) V = V.transpose() GL = [g(i) for i in L] GLI = [j.inverse_of_unit() for j in GL] D = diagonal_matrix(GLI) VF = matrix([V.row(i) for i in range(t)]) H = VF * D matrices = [matrix([vector(i) for i in H.row(j)]) for j in range(t)] matrices = [m.transpose() for m in matrices] m = block_matrix(t, 1, matrices) return m
def lift(A, N): r""" Lift a matrix A from SL_m(Z/NZ) to SL_m(Z). Follows Shimura, Lemma 1.38, p21. """ assert A.is_square() assert A.determinant() != 0 m = A.nrows() if m == 1: return identity_matrix(1) D, U, V = A.smith_form() if U.determinant() == -1: U = matrix(2, 2, [-1, 0, 0, 1]) * U if V.determinant() == -1: V = V * matrix(2, 2, [-1, 0, 0, 1]) D = U * A * V assert U.determinant() == 1 assert V.determinant() == 1 a = [D[i, i] for i in range(m)] b = prod(a[1:]) W = identity_matrix(m) W[0, 0] = b W[1, 0] = b - 1 W[0, 1] = 1 X = identity_matrix(m) X[0, 1] = -a[1] Ap = D.parent()(D) Ap[0, 0] = 1 Ap[1, 0] = 1 - a[0] Ap[1, 1] *= a[0] assert (W * U * A * V * X).change_ring(Zmod(N)) == Ap.change_ring(Zmod(N)) Cp = diagonal_matrix(a[1:]) Cp[0, 0] *= a[0] C = lift(Cp, N) Cpp = block_diagonal_matrix(identity_matrix(1), C) Cpp[1, 0] = 1 - a[0] return (~U * ~W * Cpp * ~X * ~V).change_ring(ZZ)
def lift(A, N): r""" Lift a matrix A from SL_m(Z/NZ) to SL_m(Z). Follows Shimura, Lemma 1.38, p21. """ assert A.is_square() assert A.determinant() != 0 m = A.nrows() if m == 1: return identity_matrix(1) D, U, V = A.smith_form() if U.determinant() == -1 : U = matrix(2,2,[-1,0,0,1])* U if V.determinant() == -1 : V = V *matrix(2,2,[-1,0,0,1]) D = U*A*V assert U.determinant() == 1 assert V.determinant() == 1 a = [ D[i, i] for i in range(m) ] b = prod(a[1:]) W = identity_matrix(m) W[0, 0] = b W[1, 0] = b-1 W[0, 1] = 1 X = identity_matrix(m) X[0, 1] = -a[1] Ap = D.parent()(D) Ap[0, 0] = 1 Ap[1, 0] = 1-a[0] Ap[1, 1] *= a[0] assert (W*U*A*V*X).change_ring(Zmod(N)) == Ap.change_ring(Zmod(N)) Cp = diagonal_matrix(a[1:]) Cp[0, 0] *= a[0] C = lift(Cp, N) Cpp = block_diagonal_matrix(identity_matrix(1), C) Cpp[1, 0] = 1-a[0] return (~U * ~W * Cpp * ~X * ~V).change_ring(ZZ)
def to_matrix(self): """ Return a matrix of ``self``. EXAMPLES:: sage: S = SignedPermutations(4) sage: s1,s2,s3,s4 = S.gens() sage: x = s4*s1*s2*s3*s4 sage: M = x.to_matrix(); M [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 -1] [-1 0 0 0] The matrix multiplication is in the *opposite* order:: sage: m1,m2,m3,m4 = [g.to_matrix() for g in S.gens()] sage: M == m4 * m3 * m2 * m1 * m4 True """ return self._perm.to_matrix() * diagonal_matrix(self._colors)
def has_rational_point(self, point=False, algorithm='default', read_cache=True): r""" Returns True if and only if the conic ``self`` has a point over its base field `F(t)`, which is a field of rational functions. If ``point`` is True, then returns a second output, which is a rational point if one exists. Points are cached whenever they are found. Cached information is used if and only if ``read_cache`` is True. The default algorithm does not (yet) work for all base fields `F`. In particular, sage is required to have: * an algorithm for finding the square root of elements in finite extensions of `F`; * a factorization and gcd algorithm for `F[t]`; * an algorithm for solving conics over `F`. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: * ``'default'`` -- use a native Sage implementation, based on the algorithm Conic in [HC2006]_. * ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES: We can find points for function fields over (extensions of) `\QQ` and finite fields:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) sage: C.has_rational_point(point=True) (True, (-3 : (t + 1)/t : 1)) sage: R.<t> = FiniteField(23)[] sage: C = Conic([2, t^2+1, t^2+5]) sage: C.has_rational_point() True sage: C.has_rational_point(point=True) (True, (5*t : 8 : 1)) sage: F.<i> = QuadraticField(-1) sage: R.<t> = F[] sage: C = Conic([1,i*t,-t^2+4]) sage: C.has_rational_point(point = True) (True, (-t - 2*i : -2*i : 1)) It works on non-diagonal conics as well:: sage: K.<t> = QQ[] sage: C = Conic([4, -4, 8, 1, -4, t + 4]) sage: C.has_rational_point(point=True) (True, (1/2 : 1 : 0)) If no point exists output still depends on the argument ``point``:: sage: K.<t> = QQ[] sage: C = Conic(K, [t^2, (t-1), -2*(t-1)]) sage: C.has_rational_point() False sage: C.has_rational_point(point=True) (False, None) Due to limitations in Sage of algorithms we depend on, it is not yet possible to find points on conics over multivariate function fields (see the requirements above):: sage: F.<t1> = FractionField(QQ['t1']) sage: K.<t2> = FractionField(F['t2']) sage: a = K(1) sage: b = 2*t2^2+2*t1*t2-t1^2 sage: c = -3*t2^4-4*t1*t2^3+8*t1^2*t2^2+16*t1^3-t2-48*t1^4 sage: C = Conic([a,b,c]) sage: C.has_rational_point() Traceback (most recent call last): ... NotImplementedError: is_square() not implemented for elements of Univariate Quotient Polynomial Ring in tbar over Fraction Field of Univariate Polynomial Ring in t1 over Rational Field with modulus tbar^2 + t1*tbar - 1/2*t1^2 In some cases, the algorithm requires us to be able to solve conics over `F`. In particular, the following does not work:: sage: P.<u> = QQ[] sage: E = P.fraction_field() sage: Q.<Y> = E[] sage: F.<v> = E.extension(Y^2 - u^3 - 1) sage: R.<t> = F[] sage: K = R.fraction_field() sage: C = Conic(K, [u, v, 1]) sage: C.has_rational_point() Traceback (most recent call last): ... NotImplementedError: has_rational_point not implemented for conics over base field Univariate Quotient Polynomial Ring in v over Fraction Field of Univariate Polynomial Ring in u over Rational Field with modulus v^2 - u^3 - 1 ``has_rational_point`` fails for some conics over function fields over finite fields, due to :trac:`20003`:: sage: K.<t> = PolynomialRing(GF(7)) sage: C = Conic([5*t^2+4, t^2+3*t+3, 6*t^2+3*t+2, 5*t^2+5, 4*t+3, 4*t^2+t+5]) sage: C.has_rational_point() Traceback (most recent call last): ... TypeError: self (=Scheme morphism: From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + ((6*t^3 + 3*t^2 + 5*t + 5)/(t + 3))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z^2 To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + (t^2 + 3*t + 3)*x*y + (5*t^2 + 5)*y^2 + (6*t^2 + 3*t + 2)*x*z + (4*t + 3)*y*z + (4*t^2 + t + 5)*z^2 Defn: Defined on coordinates by sending (x : y : z) to (x + ((2*t + 5)/(t + 3))*y + ((3*t^4 + 2*t^3 + 5*t^2 + 5*t + 3)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z : y + ((6*t^3 + 6*t^2 + 3*t + 6)/(t^3 + 4*t^2 + 2*t + 2))*z : z)) domain must equal right (=Scheme morphism: From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^3 + 6*t^2 + 3*t + 3)*x^2 + (t + 4)*y^2 + (6*t^7 + 2*t^5 + t^4 + 2*t^3 + 3*t^2 + 6*t + 6)*z^2 To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5/(t^3 + 4*t^2 + 2*t + 2))*x^2 + (1/(t^3 + 3*t^2 + 5*t + 1))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^9 + 5*t^8 + t^7 + 6*t^6 + 3*t^5 + 4*t^3 + t^2 + 5*t + 3))*z^2 Defn: Defined on coordinates by sending (x : y : z) to ((t^3 + 4*t^2 + 2*t + 2)*x : (t^2 + 5)*y : (t^5 + 4*t^4 + t^2 + 3*t + 3)*z)) codomain TESTS:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: a = (2*t^2 - 3/2*t + 1)/(37/3*t^2 + t - 1/4) sage: b = (1/2*t^2 + 1/3)/(-73*t^2 - 2*t + 11/4) sage: c = (6934/3*t^6 + 8798/3*t^5 - 947/18*t^4 + 3949/9*t^3 + 20983/18*t^2 + 28/3*t - 131/3)/(-2701/3*t^4 - 293/3*t^3 + 301/6*t^2 + 13/4*t - 11/16) sage: C = Conic([a,b,c]) sage: C.has_rational_point(point=True) (True, (4*t + 4 : 2*t + 2 : 1)) A long time test:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: a = (-1/3*t^6 - 14*t^5 - 1/4*t^4 + 7/2*t^2 - 1/2*t - 1)/(24/5*t^6 - t^5 - 1/4*t^4 + t^3 - 3*t^2 + 8/5*t + 5) sage: b = (-3*t^3 + 8*t + 1/2)/(-1/3*t^3 + 3/2*t^2 + 1/12*t + 1/2) sage: c = (1232009/225*t^25 - 1015925057/8100*t^24 + 1035477411553/1458000*t^23 + 7901338091/30375*t^22 - 1421379260447/729000*t^21 + 266121260843/972000*t^20 + 80808723191/486000*t^19 - 516656082523/972000*t^18 + 21521589529/40500*t^17 + 4654758997/21600*t^16 - 20064038625227/9720000*t^15 - 173054270347/324000*t^14 + 536200870559/540000*t^13 - 12710739349/50625*t^12 - 197968226971/135000*t^11 - 134122025657/810000*t^10 + 22685316301/120000*t^9 - 2230847689/21600*t^8 - 70624099679/270000*t^7 - 4298763061/270000*t^6 - 41239/216000*t^5 - 13523/36000*t^4 + 493/36000*t^3 + 83/2400*t^2 + 1/300*t + 1/200)/(-27378/125*t^17 + 504387/500*t^16 - 97911/2000*t^15 + 1023531/4000*t^14 + 1874841/8000*t^13 + 865381/12000*t^12 + 15287/375*t^11 + 6039821/6000*t^10 + 599437/1500*t^9 + 18659/250*t^8 + 1218059/6000*t^7 + 2025127/3000*t^6 + 1222759/6000*t^5 + 38573/200*t^4 + 8323/125*t^3 + 15453/125*t^2 + 17031/500*t + 441/10) sage: C = Conic([a,b,c]) sage: C.has_rational_point(point = True) # long time (4 seconds) (True, ((-2/117*t^8 + 304/1053*t^7 + 40/117*t^6 - 1/27*t^5 - 110/351*t^4 - 2/195*t^3 + 11/351*t^2 + 1/117)/(t^4 + 2/39*t^3 + 4/117*t^2 + 2/39*t + 14/39) : -5/3*t^4 + 19*t^3 : 1)) """ from .constructor import Conic if read_cache: if self._rational_point is not None: return (True, self._rational_point) if point else True if algorithm != 'default': return ProjectiveConic_field.has_rational_point( self, point, algorithm, read_cache) # Default algorithm if self.base_ring().characteristic() == 2: raise NotImplementedError("has_rational_point not implemented \ for function field of characteristic 2.") new_conic, transformation, inverse = self.diagonalization() coeff = new_conic.coefficients() if coeff[0] == 0: return (True, transformation([1, 0, 0])) if point else True elif coeff[3] == 0: return (True, transformation([0, 1, 0])) if point else True elif coeff[5] == 0: return (True, transformation([0, 0, 1])) if point else True # We save the coefficients of the reduced form in coeff # A zero of the reduced conic can be multiplied by multipliers # to get a zero of the old conic (coeff, multipliers) = new_conic._reduce_conic() new_conic = Conic(coeff) transformation = transformation \ * new_conic.hom(diagonal_matrix(multipliers)) if coeff[0].degree() % 2 == coeff[1].degree() % 2 and \ coeff[1].degree() % 2 == coeff[2].degree() % 2: case = 0
def FinitelyGeneratedAbelianPresentation(int_list): r""" Return canonical presentation of finitely generated abelian group. INPUT: - ``int_list`` -- List of integers defining the group to be returned, the defining list is reduced to the invariants of the input list before generating the corresponding group. OUTPUT: Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}` as a finite presentation, where `n_i` forms the invariants of the input list. EXAMPLES:: sage: groups.presentation.FGAbelian([2,2]) Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([2,3]) Finitely presented group < a | a^6 > sage: groups.presentation.FGAbelian([2,4]) Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b > You can create free abelian groups:: sage: groups.presentation.FGAbelian([0]) Finitely presented group < a | > sage: groups.presentation.FGAbelian([0,0]) Finitely presented group < a, b | a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,0,0]) Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > And various infinite abelian groups:: sage: groups.presentation.FGAbelian([0,2]) Finitely presented group < a, b | a^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,2,2]) Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > Outputs are reduced to minimal generators and relations:: sage: groups.presentation.FGAbelian([3,5,2,7,3]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([3,210]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > The trivial group is an acceptable output:: sage: groups.presentation.FGAbelian([]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1]) Finitely presented group < | > Input list must consist of positive integers:: sage: groups.presentation.FGAbelian([2,6,3,9,-4]) Traceback (most recent call last): ... ValueError: input list must contain nonnegative entries sage: groups.presentation.FGAbelian([2,'a',4]) Traceback (most recent call last): ... TypeError: unable to convert 'a' to an integer TESTS:: sage: ag = groups.presentation.FGAbelian([2,2]) sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour()) True sage: G = groups.presentation.FGAbelian([2,4,8]) sage: C2 = CyclicPermutationGroup(2) sage: C4 = CyclicPermutationGroup(4) sage: C8 = CyclicPermutationGroup(8) sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0] sage: gg.is_isomorphic(G.as_permutation_group()) True sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35]) True """ from sage.groups.free_group import _lexi_gen check_ls = [Integer(x) for x in int_list if Integer(x) >= 0] if len(check_ls) != len(int_list): raise ValueError('input list must contain nonnegative entries') col_sp = diagonal_matrix(int_list).column_space() invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants() name_gen = _lexi_gen() F = FreeGroup([next(name_gen) for i in invariants]) ret_rls = [ F([i + 1])**invariants[i] for i in range(len(invariants)) if invariants[i] != 0 ] # Build commutator relations gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1) for j in range(i + 1, F.ngens())] ret_rls = ret_rls + [ x[0]**(-1) * x[1]**(-1) * x[0] * x[1] for x in gen_pairs ] return FinitelyPresentedGroup(F, tuple(ret_rls))
def has_rational_point(self, point = False, algorithm = 'default', read_cache = True): r""" Returns True if and only if the conic ``self`` has a point over its base field `F(t)`, which is a field of rational functions. If ``point`` is True, then returns a second output, which is a rational point if one exists. Points are cached whenever they are found. Cached information is used if and only if ``read_cache`` is True. The default algorithm does not (yet) work for all base fields `F`. In particular, sage is required to have: * an algorithm for finding the square root of elements in finite extensions of `F`; * a factorization and gcd algorithm for `F[t]`; * an algorithm for solving conics over `F`. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: * ``'default'`` -- use a native Sage implementation, based on the algorithm Conic in [HC2006]_. * ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES: We can find points for function fields over (extensions of) `\QQ` and finite fields:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) sage: C.has_rational_point(point=True) (True, (-3 : (t + 1)/t : 1)) sage: R.<t> = FiniteField(23)[] sage: C = Conic([2, t^2+1, t^2+5]) sage: C.has_rational_point() True sage: C.has_rational_point(point=True) (True, (5*t : 8 : 1)) sage: F.<i> = QuadraticField(-1) sage: R.<t> = F[] sage: C = Conic([1,i*t,-t^2+4]) sage: C.has_rational_point(point = True) verbose 0 (3369: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. ... (True, (-t - 2*i : -2*i : 1)) It works on non-diagonal conics as well:: sage: K.<t> = QQ[] sage: C = Conic([4, -4, 8, 1, -4, t + 4]) sage: C.has_rational_point(point=True) (True, (1/2 : 1 : 0)) If no point exists output still depends on the argument ``point``:: sage: K.<t> = QQ[] sage: C = Conic(K, [t^2, (t-1), -2*(t-1)]) sage: C.has_rational_point() False sage: C.has_rational_point(point=True) (False, None) Due to limitations in Sage of algorithms we depend on, it is not yet possible to find points on conics over multivariate function fields (see the requirements above):: sage: F.<t1> = FractionField(QQ['t1']) sage: K.<t2> = FractionField(F['t2']) sage: a = K(1) sage: b = 2*t2^2+2*t1*t2-t1^2 sage: c = -3*t2^4-4*t1*t2^3+8*t1^2*t2^2+16*t1^3-t2-48*t1^4 sage: C = Conic([a,b,c]) sage: C.has_rational_point() ... Traceback (most recent call last): ... NotImplementedError: is_square() not implemented for elements of Univariate Quotient Polynomial Ring in tbar over Fraction Field of Univariate Polynomial Ring in t1 over Rational Field with modulus tbar^2 + t1*tbar - 1/2*t1^2 In some cases, the algorithm requires us to be able to solve conics over `F`. In particular, the following does not work:: sage: P.<u> = QQ[] sage: E = P.fraction_field() sage: Q.<Y> = E[] sage: F.<v> = E.extension(Y^2 - u^3 - 1) sage: R.<t> = F[] sage: K = R.fraction_field() sage: C = Conic(K, [u, v, 1]) sage: C.has_rational_point() ... Traceback (most recent call last): ... NotImplementedError: has_rational_point not implemented for conics over base field Univariate Quotient Polynomial Ring in v over Fraction Field of Univariate Polynomial Ring in u over Rational Field with modulus v^2 - u^3 - 1 ``has_rational_point`` fails for some conics over function fields over finite fields, due to :trac:`20003`:: sage: K.<t> = PolynomialRing(GF(7)) sage: C = Conic([5*t^2+4, t^2+3*t+3, 6*t^2+3*t+2, 5*t^2+5, 4*t+3, 4*t^2+t+5]) sage: C.has_rational_point() ... Traceback (most recent call last): ... TypeError: self (=Scheme morphism: From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + ((6*t^3 + 3*t^2 + 5*t + 5)/(t + 3))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z^2 To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + (t^2 + 3*t + 3)*x*y + (5*t^2 + 5)*y^2 + (6*t^2 + 3*t + 2)*x*z + (4*t + 3)*y*z + (4*t^2 + t + 5)*z^2 Defn: Defined on coordinates by sending (x : y : z) to (x + ((2*t + 5)/(t + 3))*y + ((3*t^4 + 2*t^3 + 5*t^2 + 5*t + 3)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z : y + ((6*t^3 + 6*t^2 + 3*t + 6)/(t^3 + 4*t^2 + 2*t + 2))*z : z)) domain must equal right (=Scheme morphism: From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^3 + 6*t^2 + 3*t + 3)*x^2 + (t + 4)*y^2 + (6*t^7 + 2*t^5 + t^4 + 2*t^3 + 3*t^2 + 6*t + 6)*z^2 To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5/(t^3 + 4*t^2 + 2*t + 2))*x^2 + (1/(t^3 + 3*t^2 + 5*t + 1))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^9 + 5*t^8 + t^7 + 6*t^6 + 3*t^5 + 4*t^3 + t^2 + 5*t + 3))*z^2 Defn: Defined on coordinates by sending (x : y : z) to ((t^3 + 4*t^2 + 2*t + 2)*x : (t^2 + 5)*y : (t^5 + 4*t^4 + t^2 + 3*t + 3)*z)) codomain TESTS:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: a = (2*t^2 - 3/2*t + 1)/(37/3*t^2 + t - 1/4) sage: b = (1/2*t^2 + 1/3)/(-73*t^2 - 2*t + 11/4) sage: c = (6934/3*t^6 + 8798/3*t^5 - 947/18*t^4 + 3949/9*t^3 + 20983/18*t^2 + 28/3*t - 131/3)/(-2701/3*t^4 - 293/3*t^3 + 301/6*t^2 + 13/4*t - 11/16) sage: C = Conic([a,b,c]) sage: C.has_rational_point(point=True) (True, (4*t + 4 : 2*t + 2 : 1)) A long time test:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: a = (-1/3*t^6 - 14*t^5 - 1/4*t^4 + 7/2*t^2 - 1/2*t - 1)/(24/5*t^6 - t^5 - 1/4*t^4 + t^3 - 3*t^2 + 8/5*t + 5) sage: b = (-3*t^3 + 8*t + 1/2)/(-1/3*t^3 + 3/2*t^2 + 1/12*t + 1/2) sage: c = (1232009/225*t^25 - 1015925057/8100*t^24 + 1035477411553/1458000*t^23 + 7901338091/30375*t^22 - 1421379260447/729000*t^21 + 266121260843/972000*t^20 + 80808723191/486000*t^19 - 516656082523/972000*t^18 + 21521589529/40500*t^17 + 4654758997/21600*t^16 - 20064038625227/9720000*t^15 - 173054270347/324000*t^14 + 536200870559/540000*t^13 - 12710739349/50625*t^12 - 197968226971/135000*t^11 - 134122025657/810000*t^10 + 22685316301/120000*t^9 - 2230847689/21600*t^8 - 70624099679/270000*t^7 - 4298763061/270000*t^6 - 41239/216000*t^5 - 13523/36000*t^4 + 493/36000*t^3 + 83/2400*t^2 + 1/300*t + 1/200)/(-27378/125*t^17 + 504387/500*t^16 - 97911/2000*t^15 + 1023531/4000*t^14 + 1874841/8000*t^13 + 865381/12000*t^12 + 15287/375*t^11 + 6039821/6000*t^10 + 599437/1500*t^9 + 18659/250*t^8 + 1218059/6000*t^7 + 2025127/3000*t^6 + 1222759/6000*t^5 + 38573/200*t^4 + 8323/125*t^3 + 15453/125*t^2 + 17031/500*t + 441/10) sage: C = Conic([a,b,c]) sage: C.has_rational_point(point = True) # long time (4 seconds) (True, ((-2/117*t^8 + 304/1053*t^7 + 40/117*t^6 - 1/27*t^5 - 110/351*t^4 - 2/195*t^3 + 11/351*t^2 + 1/117)/(t^4 + 2/39*t^3 + 4/117*t^2 + 2/39*t + 14/39) : -5/3*t^4 + 19*t^3 : 1)) """ from constructor import Conic if read_cache: if self._rational_point is not None: return (True, self._rational_point) if point else True if algorithm != 'default': return ProjectiveConic_field.has_rational_point(self, point, algorithm, read_cache) # Default algorithm if self.base_ring().characteristic() == 2: raise NotImplementedError("has_rational_point not implemented \ for function field of characteristic 2.") new_conic, transformation, inverse = self.diagonalization() coeff = new_conic.coefficients() if coeff[0] == 0: return (True, transformation([1,0,0])) if point else True elif coeff[3] == 0: return (True, transformation([0,1,0])) if point else True elif coeff[5] == 0: return (True, transformation([0,0,1])) if point else True # We save the coefficients of the reduced form in coeff # A zero of the reduced conic can be multiplied by multipliers # to get a zero of the old conic (coeff, multipliers) = new_conic._reduce_conic() new_conic = Conic(coeff) transformation = transformation \ * new_conic.hom(diagonal_matrix(multipliers)) if coeff[0].degree() % 2 == coeff[1].degree() % 2 and \ coeff[1].degree() % 2 == coeff[2].degree() % 2: case = 0 else: case = 1 t, = self.base_ring().base().gens() # t in F[t] supp = [] roots = [[], [], []] remove = None # loop through the coefficients and find a root of f_i (as in # [HC2006]) modulo each element in the coefficients' support for i in (0,1,2): supp.append(list(coeff[i].factor())) for p in supp[i]: if p[1] != 1: raise ValueError("Expected factor of exponent 1.") # Convert to monic factor x = p[0]/list(p[0])[-1] N = p[0].base_ring().extension(x, 'tbar') R = PolynomialRing(N, 'u') u, = R.gens() # If p[0] has degree 1, sage might forget the "defining # polynomial" of N, so we define our own modulo operation if p[0].degree() == 1: mod = t.parent().hom([-x[0]]) else: mod = N if i == 0: x = -mod(coeff[2])/mod(coeff[1]) elif i == 1: x = -mod(coeff[0])/mod(coeff[2]) else: x = -mod(coeff[1])/mod(coeff[0]) if x.is_square(): root = N(x.sqrt()) else: return (False, None) if point else False # if case == 0 and p[0] has degree 1, we switch to case # 1 and remove this factor out of the support. In [HC2006] # this is done later, in FindPoint. if case == 0 and p[0].degree() == 1: case = 1 # remove later so the loop iterator stays in place. remove = (i,p) else: roots[i].append(root) if remove: supp[remove[0]].remove(remove[1]) supp = [[p[0] for p in supp[i]] for i in (0,1,2)] if case == 0: # Find a solution of (5) in [HC2006] leading_conic = Conic(self.base_ring().base_ring(), [coeff[0].leading_coefficient(), coeff[1].leading_coefficient(), coeff[2].leading_coefficient()]) has_point = leading_conic.has_rational_point(True) if has_point[0]: if point: pt = new_conic.find_point(supp, roots, case, has_point[1]) else: pt = True return (True, transformation(pt)) if point else True else: return (False, None) if point else False # case == 1: if point: pt = new_conic.find_point(supp, roots, case) else: pt = True return (True, transformation(pt)) if point else True
def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True): r""" Tries to construct a skew Hadamard matrix A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few more exotic ones are implemented. INPUT: - ``n`` (integer) -- dimension of the matrix - ``existence`` (boolean) -- whether to build the matrix or merely query if a construction is available in Sage. When set to ``True``, the function returns: - ``True`` -- meaning that Sage knows how to build the matrix - ``Unknown`` -- meaning that Sage does not know how to build the matrix, but that the design may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the matrix does not exist. - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and adjust the 1st column accordingly. Set to ``True`` by default. - ``check`` (boolean) -- whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix sage: skew_hadamard_matrix(12).det() 2985984 sage: 12^6 2985984 sage: skew_hadamard_matrix(1) [1] sage: skew_hadamard_matrix(2) [ 1 1] [-1 1] TESTS:: sage: skew_hadamard_matrix(10,existence=True) False sage: skew_hadamard_matrix(12,existence=True) True sage: skew_hadamard_matrix(784,existence=True) True sage: skew_hadamard_matrix(10) Traceback (most recent call last): ... ValueError: A skew Hadamard matrix of order 10 does not exist sage: skew_hadamard_matrix(36) 36 x 36 dense matrix over Integer Ring... sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False) False sage: skew_hadamard_matrix(52) 52 x 52 dense matrix over Integer Ring... sage: skew_hadamard_matrix(92) 92 x 92 dense matrix over Integer Ring... sage: skew_hadamard_matrix(816) # long time 816 x 816 dense matrix over Integer Ring... sage: skew_hadamard_matrix(100) Traceback (most recent call last): ... ValueError: A skew Hadamard matrix of order 100 is not yet implemented. sage: skew_hadamard_matrix(100,existence=True) Unknown REFERENCES: .. [Ha83] \M. Hall, Combinatorial Theory, 2nd edition, Wiley, 1983 """ def true(): _skew_had_cache[n] = True return True M = None if existence and n in _skew_had_cache: return True if not (n % 4 == 0) and (n > 2): if existence: return False raise ValueError("A skew Hadamard matrix of order %s does not exist" % n) if n == 2: if existence: return true() M = matrix([[1, 1], [-1, 1]]) elif n == 1: if existence: return true() M = matrix([1]) elif is_prime_power(n - 1) and ((n - 1) % 4 == 3): if existence: return true() M = hadamard_matrix_paleyI(n, normalize=False) elif n % 8 == 0: if skew_hadamard_matrix(n // 2, existence=True): # (Lemma 14.1.6 in [Ha83]_) if existence: return true() H = skew_hadamard_matrix(n // 2, check=False) M = block_matrix([[H, H], [-H.T, H.T]]) else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n n1 = n // d if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ and skew_hadamard_matrix(n1,existence=True): if existence: return true() H = skew_hadamard_matrix(n1, check=False) - I(n1) U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\ 1 if i==j==1 or (i>1 and j-1==d-i)\ else 0) A = block_matrix( [[matrix([0]), matrix(ZZ, 1, d - 1, [1] * (d - 1))], [ matrix(ZZ, d - 1, 1, [-1] * (d - 1)), _helper_payley_matrix(d - 1, zero_position=0) ]]) + I(d) M = A.tensor_product(I(n1)) + (U * A).tensor_product(H) break if M is None: # try Williamson-Goethals-Seidel construction if GS_skew_hadamard_smallcases(n, existence=True): if existence: return true() M = GS_skew_hadamard_smallcases(n) else: if existence: return Unknown raise ValueError( "A skew Hadamard matrix of order %s is not yet implemented." % n) if skew_normalize: dd = diagonal_matrix(M[0]) M = dd * M * dd if check: assert is_hadamard_matrix(M, normalized=False, skew=True) if skew_normalize: from sage.modules.free_module_element import vector assert M[0] == vector([1] * n) _skew_had_cache[n] = True return M
def rshcd_from_close_prime_powers(n): r""" Return a `(n^2,1)`-RSHCD when `n-1` and `n+1` are odd prime powers and `n=0\pmod{4}`. The construction implemented here appears in Theorem 4.3 from [GS70]_. Note that the authors of [SWW72]_ claim in Corollary 5.12 (page 342) to have proved the same result without the `n=0\pmod{4}` restriction with a *very* similar construction. So far, however, I (Nathann Cohen) have not been able to make it work. INPUT: - ``n`` -- an integer congruent to `0\pmod{4}` .. SEEALSO:: :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal` EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_close_prime_powers sage: rshcd_from_close_prime_powers(4) [-1 -1 1 -1 1 -1 -1 1 -1 1 -1 -1 1 -1 1 -1] [-1 -1 1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 1] [ 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 1 -1] [-1 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 1] [ 1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1] [-1 -1 -1 1 1 -1 1 1 -1 -1 -1 1 -1 1 -1 -1] [-1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 1 1 -1 -1] [ 1 -1 -1 -1 -1 1 -1 -1 -1 1 -1 1 -1 1 1 -1] [-1 -1 -1 -1 -1 -1 1 -1 -1 -1 1 1 1 -1 1 1] [ 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 1 1 -1 1] [-1 1 1 -1 -1 -1 1 -1 1 -1 -1 -1 -1 1 1 -1] [-1 -1 -1 1 -1 1 -1 1 1 -1 -1 -1 -1 -1 1 1] [ 1 -1 -1 -1 1 -1 1 -1 1 1 -1 -1 -1 -1 -1 1] [-1 1 -1 -1 -1 1 1 1 -1 1 1 -1 -1 -1 -1 -1] [ 1 -1 1 -1 -1 -1 -1 1 1 -1 1 1 -1 -1 -1 -1] [-1 1 -1 1 -1 -1 -1 -1 1 1 -1 1 1 -1 -1 -1] REFERENCE: .. [SWW72] A Street, W. Wallis, J. Wallis, Combinatorics: Room squares, sum-free sets, Hadamard matrices. Lecture notes in Mathematics 292 (1972). """ if n % 4: raise ValueError("n(={}) must be congruent to 0 mod 4") a, b = sorted([n - 1, n + 1], key=lambda x: -x % 4) Sa = _helper_payley_matrix(a) Sb = _helper_payley_matrix(b) U = matrix(a, [[int(i + j == a - 1) for i in range(a)] for j in range(a)]) K = (U * Sa).tensor_product(Sb) + U.tensor_product(J(b) - I(b)) - J( a).tensor_product(I(b)) F = lambda x: diagonal_matrix([-(-1)**i for i in range(x)]) G = block_diagonal_matrix([J(1), I(a).tensor_product(F(b))]) e = matrix(a * b, [1] * (a * b)) H = block_matrix(2, [-J(1), e.transpose(), e, K]) HH = G * H * G assert len(set(map(sum, HH))) == 1 assert HH**2 == n**2 * I(n**2) return HH
def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): r""" Tries to construct a skew Hadamard matrix A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few more exotic ones are implemented. INPUT: - ``n`` (integer) -- dimension of the matrix - ``existence`` (boolean) -- whether to build the matrix or merely query if a construction is available in Sage. When set to ``True``, the function returns: - ``True`` -- meaning that Sage knows how to build the matrix - ``Unknown`` -- meaning that Sage does not know how to build the matrix, but that the design may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the matrix does not exist. - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and adjust the 1st column accordingly. Set to ``True`` by default. - ``check`` (boolean) -- whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix sage: skew_hadamard_matrix(12).det() 2985984 sage: 12^6 2985984 sage: skew_hadamard_matrix(1) [1] sage: skew_hadamard_matrix(2) [ 1 1] [-1 1] TESTS:: sage: skew_hadamard_matrix(10,existence=True) False sage: skew_hadamard_matrix(12,existence=True) True sage: skew_hadamard_matrix(784,existence=True) True sage: skew_hadamard_matrix(10) Traceback (most recent call last): ... ValueError: A skew Hadamard matrix of order 10 does not exist sage: skew_hadamard_matrix(36) 36 x 36 dense matrix over Integer Ring... sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False) False sage: skew_hadamard_matrix(52) 52 x 52 dense matrix over Integer Ring... sage: skew_hadamard_matrix(92) 92 x 92 dense matrix over Integer Ring... sage: skew_hadamard_matrix(816) # long time 816 x 816 dense matrix over Integer Ring... sage: skew_hadamard_matrix(100) Traceback (most recent call last): ... ValueError: A skew Hadamard matrix of order 100 is not yet implemented. sage: skew_hadamard_matrix(100,existence=True) Unknown REFERENCES: .. [Ha83] \M. Hall, Combinatorial Theory, 2nd edition, Wiley, 1983 """ def true(): _skew_had_cache[n]=True return True M = None if existence and n in _skew_had_cache: return True if not(n % 4 == 0) and (n > 2): if existence: return False raise ValueError("A skew Hadamard matrix of order %s does not exist" % n) if n == 2: if existence: return true() M = matrix([[1, 1], [-1, 1]]) elif n == 1: if existence: return true() M = matrix([1]) elif is_prime_power(n - 1) and ((n - 1) % 4 == 3): if existence: return true() M = hadamard_matrix_paleyI(n, normalize=False) elif n % 8 == 0: if skew_hadamard_matrix(n//2,existence=True): # (Lemma 14.1.6 in [Ha83]_) if existence: return true() H = skew_hadamard_matrix(n//2,check=False) M = block_matrix([[H,H], [-H.T,H.T]]) else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n n1 = n//d if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ and skew_hadamard_matrix(n1,existence=True): if existence: return true() H = skew_hadamard_matrix(n1, check=False)-I(n1) U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\ 1 if i==j==1 or (i>1 and j-1==d-i)\ else 0) A = block_matrix([[matrix([0]), matrix(ZZ,1,d-1,[1]*(d-1))], [ matrix(ZZ,d-1,1,[-1]*(d-1)), _helper_payley_matrix(d-1,zero_position=0)]])+I(d) M = A.tensor_product(I(n1))+(U*A).tensor_product(H) break if M is None: # try Williamson-Goethals-Seidel construction if GS_skew_hadamard_smallcases(n, existence=True): if existence: return true() M = GS_skew_hadamard_smallcases(n) else: if existence: return Unknown raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) if skew_normalize: dd = diagonal_matrix(M[0]) M = dd*M*dd if check: assert is_hadamard_matrix(M, normalized=False, skew=True) if skew_normalize: from sage.modules.free_module_element import vector assert M[0]==vector([1]*n) _skew_had_cache[n]=True return M
def rshcd_from_close_prime_powers(n): r""" Return a `(n^2,1)`-RSHCD when `n-1` and `n+1` are odd prime powers and `n=0\pmod{4}`. The construction implemented here appears in Theorem 4.3 from [GS70]_. Note that the authors of [SWW72]_ claim in Corollary 5.12 (page 342) to have proved the same result without the `n=0\pmod{4}` restriction with a *very* similar construction. So far, however, I (Nathann Cohen) have not been able to make it work. INPUT: - ``n`` -- an integer congruent to `0\pmod{4}` .. SEEALSO:: :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal` EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_close_prime_powers sage: rshcd_from_close_prime_powers(4) [-1 -1 1 -1 1 -1 -1 1 -1 1 -1 -1 1 -1 1 -1] [-1 -1 1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 1] [ 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 1 -1] [-1 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 1] [ 1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1] [-1 -1 -1 1 1 -1 1 1 -1 -1 -1 1 -1 1 -1 -1] [-1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 1 1 -1 -1] [ 1 -1 -1 -1 -1 1 -1 -1 -1 1 -1 1 -1 1 1 -1] [-1 -1 -1 -1 -1 -1 1 -1 -1 -1 1 1 1 -1 1 1] [ 1 1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 1 1 -1 1] [-1 1 1 -1 -1 -1 1 -1 1 -1 -1 -1 -1 1 1 -1] [-1 -1 -1 1 -1 1 -1 1 1 -1 -1 -1 -1 -1 1 1] [ 1 -1 -1 -1 1 -1 1 -1 1 1 -1 -1 -1 -1 -1 1] [-1 1 -1 -1 -1 1 1 1 -1 1 1 -1 -1 -1 -1 -1] [ 1 -1 1 -1 -1 -1 -1 1 1 -1 1 1 -1 -1 -1 -1] [-1 1 -1 1 -1 -1 -1 -1 1 1 -1 1 1 -1 -1 -1] REFERENCE: .. [SWW72] A Street, W. Wallis, J. Wallis, Combinatorics: Room squares, sum-free sets, Hadamard matrices. Lecture notes in Mathematics 292 (1972). """ if n%4: raise ValueError("n(={}) must be congruent to 0 mod 4") a,b = sorted([n-1,n+1],key=lambda x:-x%4) Sa = _helper_payley_matrix(a) Sb = _helper_payley_matrix(b) U = matrix(a,[[int(i+j == a-1) for i in range(a)] for j in range(a)]) K = (U*Sa).tensor_product(Sb) + U.tensor_product(J(b)-I(b)) - J(a).tensor_product(I(b)) F = lambda x:diagonal_matrix([-(-1)**i for i in range(x)]) G = block_diagonal_matrix([J(1),I(a).tensor_product(F(b))]) e = matrix(a*b,[1]*(a*b)) H = block_matrix(2,[-J(1),e.transpose(),e,K]) HH = G*H*G assert len(set(map(sum,HH))) == 1 assert HH**2 == n**2*I(n**2) return HH
def FinitelyGeneratedAbelianPresentation(int_list): r""" Return canonical presentation of finitely generated abelian group. INPUT: - ``int_list`` -- List of integers defining the group to be returned, the defining list is reduced to the invariants of the input list before generating the corresponding group. OUTPUT: Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}` as a finite presentation, where `n_i` forms the invariants of the input list. EXAMPLES:: sage: groups.presentation.FGAbelian([2,2]) Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([2,3]) Finitely presented group < a | a^6 > sage: groups.presentation.FGAbelian([2,4]) Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b > You can create free abelian groups:: sage: groups.presentation.FGAbelian([0]) Finitely presented group < a | > sage: groups.presentation.FGAbelian([0,0]) Finitely presented group < a, b | a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,0,0]) Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > And various infinite abelian groups:: sage: groups.presentation.FGAbelian([0,2]) Finitely presented group < a, b | a^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,2,2]) Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > Outputs are reduced to minimal generators and relations:: sage: groups.presentation.FGAbelian([3,5,2,7,3]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([3,210]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > The trivial group is an acceptable output:: sage: groups.presentation.FGAbelian([]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1]) Finitely presented group < | > Input list must consist of positive integers:: sage: groups.presentation.FGAbelian([2,6,3,9,-4]) Traceback (most recent call last): ... ValueError: input list must contain nonnegative entries sage: groups.presentation.FGAbelian([2,'a',4]) Traceback (most recent call last): ... TypeError: unable to convert 'a' to an integer TESTS:: sage: ag = groups.presentation.FGAbelian([2,2]) sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour()) True sage: G = groups.presentation.FGAbelian([2,4,8]) sage: C2 = CyclicPermutationGroup(2) sage: C4 = CyclicPermutationGroup(4) sage: C8 = CyclicPermutationGroup(8) sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0] sage: gg.is_isomorphic(G.as_permutation_group()) True sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35]) True """ from sage.groups.free_group import _lexi_gen check_ls = [Integer(x) for x in int_list if Integer(x) >= 0] if len(check_ls) != len(int_list): raise ValueError('input list must contain nonnegative entries') col_sp = diagonal_matrix(int_list).column_space() invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants() name_gen = _lexi_gen() F = FreeGroup([next(name_gen) for i in invariants]) ret_rls = [F([i+1])**invariants[i] for i in range(len(invariants)) if invariants[i]!=0] # Build commutator relations gen_pairs = [[F.gen(i),F.gen(j)] for i in range(F.ngens()-1) for j in range(i+1,F.ngens())] ret_rls = ret_rls + [x[0]**(-1)*x[1]**(-1)*x[0]*x[1] for x in gen_pairs] return FinitelyPresentedGroup(F, tuple(ret_rls))