def test__diff_mat__a00b(self): mat = ring('matrix([(a,0),(0,1/a)])') a = ring('a') dmat = MARing.diff_mat(mat, a) print(mat) print(dmat) assert dmat == sage_matrix(MARing.FF, [(1, 0), (0, -1 / a**2)])
def get_aut_P8(c_lst): ''' The double Segre surface S is isomorphic to P^1xP^1. The pair (A,B) of 2x2 matrices denotes an automorphism of P^1xP^1. We compute the representation of this automorphism in P^8 by using the parametrization as provided by ".get_pmz_lst". Since we consider the 2x2 matrices up to multiplication by a constant, it follows that the automorphism group is 6-dimensional. Formally, this method computes Sym^2(A)@Sym^2(B) where @ denotes the tensor product (otimes in tex). Parameters ---------- c_lst: list<MARing.FF> A list of length 8 with elements c0,...,c7 in "MARing.FF". We assume that the pair of matrices ( [ c0 c1 ] [ c4 c5 ] ) = (A,B) ( [ c2 c3 ] , [ c6 c7 ] ) represent an automorphism of P^1xP^1. Returns ------- sage_matrix A 9x9 matrix defined over "MARing.FF", which represents a (parametrized) automorphism of P^8 that preserves the double Segre surface S. ''' # obtain parametrization in order to compute Sym^2(?)@Sym^2(?) # pmz_lst = DSegre.get_pmz_lst() # compute automorphisms double Segre surface # c0, c1, c2, c3, c4, c5, c6, c7 = c_lst x0, x1, y0, y1 = ring('x0,x1,y0,y1') s, t, u, w = ring('s,t,u,w') # coordinates of P^1xP^1 dct1 = {} dct1.update({s: c0 * x0 + c1 * x1}) dct1.update({t: c2 * x0 + c3 * x1}) dct1.update({u: c4 * y0 + c5 * y1}) dct1.update({w: c6 * y0 + c7 * y1}) dct2 = {x0: s, x1: t, y0: u, y1: w} spmz_lst = [pmz.subs(dct1).subs(dct2) for pmz in pmz_lst] # compute matrix from reparametrization "spmz_lst" # this is a representation of element in Aut(P^1xP^1) # mat = [] for spmz in spmz_lst: row = [] for pmz in pmz_lst: row += [spmz.coefficient(pmz)] mat += [row] mat = sage_matrix(MARing.FF, mat) MATools.p('c_lst =', c_lst) MATools.p('mat =\n' + str(mat)) return mat
def get_aut_P5(c_lst): ''' Parameters ---------- c_lst : list A list of length 9 with elements c0,...,c8 in "MARing.FF". The matrix [ c0 c1 c2 ] M = [ c3 c4 c5 ] [ c6 c7 c8 ] represents an automorphism of P^2. Returns ------- sage_matrix This method returns a 6x6 matrix defined over "MARing.FF", which represents a (parametrized) automorphism of P^5 that preserves the Veronese surface V. Notes ----- The Veronese surface V is isomorphic to P^2. The automorphism M of P^2 is via the parametrization ".get_pmz_lst" represented as an automorphism of P^5. Algebraically this is the symmetric tensor Sym^2(M). ''' # obtain parametrization in order to compute Sym^2(M) # pmz_lst = Veronese.get_pmz_lst() # compute automorphisms double Segre surface # c0, c1, c2, c3, c4, c5, c6, c7, c8 = c_lst x0, x1, x2 = ring('x0,x1,x2') s, t, u = ring('s,t,u') # coordinates of P^2 dct1 = {} dct1.update({s: c0 * x0 + c1 * x1 + c2 * x2}) dct1.update({t: c3 * x0 + c4 * x1 + c5 * x2}) dct1.update({u: c6 * x0 + c7 * x1 + c8 * x2}) dct2 = {x0: s, x1: t, x2: u} spmz_lst = [pmz.subs(dct1).subs(dct2) for pmz in pmz_lst] # compute matrix from reparametrization "spmz_lst" # this is a representation of element in Aut(P^1xP^1) # mat = [] for spmz in spmz_lst: row = [] for pmz in pmz_lst: row += [spmz.coefficient(pmz)] mat += [row] mat = sage_matrix(MARing.FF, mat) MATools.p('c_lst =', c_lst) MATools.p('mat =\n' + str(mat)) return mat
def test__get_invariant_qf__5678_SO2xSO2(self): k = ring('k') c_lst_lst = [] c_lst_lst += [[k + 1, 0, 0, 1 / (k + 1), 1, 0, 0, 1]] c_lst_lst += [[1, 0, 0, 1, k + 1, 0, 0, 1 / (k + 1)]] iqf_lst = DSegre.get_invariant_qf(c_lst_lst, [5, 6, 7, 8]) print(iqf_lst) assert iqf_lst == ring('[x0^2 - x1*x2, x0^2 - x3*x4]')
def test__get_rand_sigs__(self): pol_lst = [] pol_lst += [ring('x4^2 - x6^2 - x7^2 ')] pol_lst += [ring('x0^2 - x3*x4 ')] sig_lst = MARing.get_rand_sigs(pol_lst, 1) print(sig_lst) assert [1, 2] in sig_lst
def test__replace_conj_pairs(self): q_lst = ring('[ x0-I*x1, x0+I*x1, x0+x2, x3*I, x3+I*x4]') new_lst = MARing.replace_conj_pairs(q_lst) chk_lst = sorted(ring('[ x0, x1, x0+x2, x3, x3+I*x4]')) print(q_lst) print(new_lst) print(chk_lst) assert chk_lst == new_lst
def test__get_invariant_qf__SO2xSO2(self): k = ring('k') c_lst_lst = [] c_lst_lst += [[k + 1, 0, 0, 1 / (k + 1), 1, 0, 0, 1]] c_lst_lst += [[1, 0, 0, 1, k + 1, 0, 0, 1 / (k + 1)]] iqf_lst = DSegre.get_invariant_qf(c_lst_lst) print(iqf_lst) assert iqf_lst == ring( '[x0^2 - x7*x8, x0^2 - x5*x6, x0^2 - x3*x4, x0^2 - x1*x2]')
def test__get_invariant_q_lst(self): k = ring('k') ig_lst = DSegre.get_invariant_q_lst( [k + 1, 0, 0, 1 / (k + 1), 1, 0, 0, 1]) print(ig_lst) assert ig_lst == ring( '[q8 + q12, -q9 - q13, q16, -q17, q18, -q19, q8 + q12, 4*q4, -q16, -q18, -q9 - q13, (-4)*q5, q19, q17, -q16, q19, q9, -q12, -q18, q17, -q8, q13, q16, -q8, (-2)*q4, -q17, q9, 2*q5, q18, -q12, (-2)*q4, -q19, q13, 2*q5]' ) ig_lst = DSegre.get_invariant_q_lst([1, k, 0, 1, 1, 0, 0, 1]) print(ig_lst) assert ig_lst == ring( '[2*q8 + 2*q12, 2*q4, q1 + q2 + q3, (-1/2)*q11 + 1/2*q15, 1/2*q10 + (-1/2)*q14, 2*q4, 1/2*q8 + 1/2*q12, (-1/2)*q18, (-1/2)*q16, q1 + q2 + q3, 1/2*q8 + 1/2*q12, q9 + q13, (-1/2)*q10 + 1/2*q14, 1/2*q11 + (-1/2)*q15, 1/2*q16, 1/2*q18, (-1/2)*q10 + 1/2*q14, -q8 - q12, (-1/2)*q1 - q2, -q4, 1/2*q11 + (-1/2)*q15, -q8 - q12, -q4, (-1/2)*q1 - q3, 1/2*q16, -q4, (-1/2)*q8, (-1/2)*q11 + 1/2*q15, (-1/2)*q18, (-1/2)*q1 - q2, (-1/2)*q8, (-1/2)*q9 + (-1/2)*q13, 1/2*q18, -q4, (-1/2)*q12, 1/2*q10 + (-1/2)*q14, (-1/2)*q16, (-1/2)*q1 - q3, (-1/2)*q9 + (-1/2)*q13, (-1/2)*q12]' )
def test__change_basis_rotate(self): qf_lst = DSegre.get_ideal_lst() nqf_lst = DSegre.change_basis(qf_lst, 'rotate') chk_lst = '[' chk_lst += 'x0^2 - x1^2 - x2^2,' chk_lst += 'x0^2 - x3^2 - x4^2,' chk_lst += 'x0^2 - x5^2 - x6^2,' chk_lst += 'x0^2 - x7^2 - x8^2,' chk_lst += 'x1^2 + 2*I*x1*x2 - x2^2 - x5*x7 - I*x6*x7 - I*x5*x8 + x6*x8,' chk_lst += 'x1^2 - 2*I*x1*x2 - x2^2 - x5*x7 + I*x6*x7 + I*x5*x8 + x6*x8,' chk_lst += 'x3^2 + 2*I*x3*x4 - x4^2 - x5*x7 - I*x6*x7 + I*x5*x8 - x6*x8,' chk_lst += 'x3^2 - 2*I*x3*x4 - x4^2 - x5*x7 + I*x6*x7 - I*x5*x8 - x6*x8,' chk_lst += 'x0*x1 + I*x0*x2 - x3*x5 + I*x4*x5 - I*x3*x6 - x4*x6,' chk_lst += 'x0*x1 - I*x0*x2 - x3*x5 - I*x4*x5 + I*x3*x6 - x4*x6,' chk_lst += 'x0*x3 + I*x0*x4 - x1*x5 + I*x2*x5 - I*x1*x6 - x2*x6,' chk_lst += 'x0*x3 - I*x0*x4 - x1*x5 - I*x2*x5 + I*x1*x6 - x2*x6,' chk_lst += 'x0*x1 + I*x0*x2 - x3*x7 - I*x4*x7 - I*x3*x8 + x4*x8,' chk_lst += 'x0*x1 - I*x0*x2 - x3*x7 + I*x4*x7 + I*x3*x8 + x4*x8,' chk_lst += 'x0*x3 + I*x0*x4 - x1*x7 - I*x2*x7 + I*x1*x8 - x2*x8,' chk_lst += 'x0*x3 - I*x0*x4 - x1*x7 + I*x2*x7 - I*x1*x8 - x2*x8,' chk_lst += '-x1*x3 - I*x2*x3 - I*x1*x4 + x2*x4 + x0*x5 + I*x0*x6,' chk_lst += '-x1*x3 + I*x2*x3 + I*x1*x4 + x2*x4 + x0*x5 - I*x0*x6,' chk_lst += '-x1*x3 - I*x2*x3 + I*x1*x4 - x2*x4 + x0*x7 + I*x0*x8,' chk_lst += '-x1*x3 + I*x2*x3 - I*x1*x4 - x2*x4 + x0*x7 - I*x0*x8' chk_lst += ']' assert nqf_lst == ring(chk_lst)
def test__change_basis_leftright(self): qf_lst = DSegre.get_ideal_lst() nqf_lst = DSegre.change_basis(qf_lst, 'leftright') chk_lst = '[' chk_lst += 'x0^2 - x1^2 - x2^2,' chk_lst += 'x0^2 - x3*x4,' chk_lst += 'x0^2 + I*x5*x6 - x5*x7 - x6*x8 - I*x7*x8,' chk_lst += 'x0^2 - I*x5*x6 - x5*x7 - x6*x8 + I*x7*x8,' chk_lst += 'x1^2 + 2*I*x1*x2 - x2^2 - I*x5*x6 - x5*x7 + x6*x8 - I*x7*x8,' chk_lst += 'x1^2 - 2*I*x1*x2 - x2^2 + I*x5*x6 - x5*x7 + x6*x8 + I*x7*x8,' chk_lst += 'x3^2 - x5^2 - x8^2,' chk_lst += 'x4^2 - x6^2 - x7^2,' chk_lst += 'x0*x1 + I*x0*x2 - x4*x5 - I*x4*x8,' chk_lst += 'x0*x1 - I*x0*x2 + I*x3*x6 - x3*x7,' chk_lst += 'x0*x3 - x1*x5 + I*x2*x5 - I*x1*x8 - x2*x8,' chk_lst += 'x0*x4 + I*x1*x6 - x2*x6 - x1*x7 - I*x2*x7,' chk_lst += 'x0*x1 + I*x0*x2 - I*x3*x6 - x3*x7,' chk_lst += 'x0*x1 - I*x0*x2 - x4*x5 + I*x4*x8,' chk_lst += 'x0*x3 - x1*x5 - I*x2*x5 + I*x1*x8 - x2*x8,' chk_lst += 'x0*x4 - I*x1*x6 - x2*x6 - x1*x7 + I*x2*x7,' chk_lst += '-x1*x3 - I*x2*x3 + x0*x5 + I*x0*x8,' chk_lst += '-x1*x4 + I*x2*x4 - I*x0*x6 + x0*x7,' chk_lst += '-x1*x4 - I*x2*x4 + I*x0*x6 + x0*x7,' chk_lst += '-x1*x3 + I*x2*x3 + x0*x5 - I*x0*x8' chk_lst += ']' for nqf in nqf_lst: print(nqf) assert nqf_lst == ring(chk_lst)
def test__get_aut_P5__abcdefghk(self): chk_mat = '' chk_mat += '[' chk_mat += '( k^2 , 2*g*h , 2*g*k , 2*h*k , g^2 , h^2 ),' chk_mat += '( c*f , b*d + a*e , c*d + a*f , c*e + b*f , a*d , b*e ),' chk_mat += '( c*k , b*g + a*h , c*g + a*k , c*h + b*k , a*g , b*h ),' chk_mat += '( f*k , e*g + d*h , f*g + d*k , f*h + e*k , d*g , e*h ),' chk_mat += '( c^2 , 2*a*b , 2*a*c , 2*b*c , a^2 , b^2 ),' chk_mat += '( f^2 , 2*d*e , 2*d*f , 2*e*f , d^2 , e^2 )' chk_mat += ']' chk_mat = 'matrix(' + chk_mat + ')' a, b, c, d, e, f, g, h, k = ring('a, b, c, d, e, f, g, h, k') out = Veronese.get_aut_P5([a, b, c, d, e, f, g, h, k]) assert out == ring(chk_mat)
def get_invariant_q_lst(c_lst): ''' Parameters ---------- c_lst : list A list of length 9 with elements c0,...,c8 in the subring in QQ(k) of "MARing.FF". The matrix [ c0 c1 c2 ] M = [ c3 c4 c5 ] [ c6 c7 c8 ] represents---for each value of k---an automorphism of P^2. If we set k:=0 then "c_lst" must correspond to the identity matrix: [ 1,0,0, 0,1,0, 0,0,1 ]. If M is not normalized to have determinant 1 then the method should be taken with care (see doc. ".get_c_lst_lst_dct"). Returns ------- list<MARing.R> A list of generators of an ideal J in the subring QQ[q0,...,q6] of "MARing.R". Each point p in the zeroset V(J), when substituted in the matrix ".get_qmat()", defines a quadratic form in the ideal ".get_ideal_lst()" that is preserved by a 1-parameter subgroup H, where H is the representation of M in P^5 (see ".get_aut_P5()"). Thus H corresponds to a 1-parameter subgroup of Aut(P^5), such that each automorphism preserves the Veronese surface in projective 5-space P^5. ''' # get representation of 1-parameter subgroup in Aut(P^5) # H = Veronese.get_aut_P5(c_lst) # consider the tangent vector of the curve H at the identity # k = ring('k') D = MARing.diff_mat(H, k).subs({k: 0}) MATools.p('D =\n' + str(D)) # Note that if we differentiate the condition # A=H.T*A*H on both sides, evaluate k=0, then # we obtain the condition D.T * A + A * D=0. # Here A denotes the matrix of a quadratic form # in the ideal of the double Segre surface S. # A = Veronese.get_qmat() Z = D.T * A + A * D iq_lst = [iq for iq in Z.list() if iq != 0] MATools.p('qi_lst =', iq_lst) return iq_lst
def test__get_ideal_lst__56_y(self): chk_str = '[' chk_str += 'y0^2 - y1*y2, y0^2 - y3*y4, y0^2 - y7*y8,' chk_str += 'y0*y1 - y3*y7, y0*y2 - y4*y8, y0*y3 - y1*y8,' chk_str += 'y0*y4 - y2*y7, -y1*y4 + y0*y7, -y2*y3 + y0*y8' chk_str += ']' out = DSegre.get_ideal_lst([5, 6], 'y') print(out) assert out == ring(chk_str)
def test__get_pmz_lst(self): id_lst = Veronese.get_ideal_lst() p = Veronese.get_pmz_lst() x = ring('x0,x1,x2,x3,x4,x5') dct = {x[i]: p[i] for i in range(5 + 1)} for id in id_lst: ids = id.subs(dct) print(id, '--->', ids) assert ids == 0
def get_pmz_lst(): ''' Returns ------- list<MARing.R> A list of polynomials of degree 2 in the subring QQ[s,t,u] of the ring "MARing.R". These polynomials represent a parametrization of the Veronese surface. ''' s_lst = ['u^2', 's*t', 's*u', 't*u', 's^2', 't^2'] return [ring(s) for s in s_lst]
def test__get_aut_P8__abcdefgh(self): chk_mat = '' chk_mat += '[' chk_mat += '(b*c*f*g + a*d*f*g + b*c*e*h + a*d*e*h, a*c*f*g + a*c*e*h, b*d*f*g + b*d*e*h, b*c*e*g + a*d*e*g, b*c*f*h + a*d*f*h, a*c*e*g, b*d*f*h, a*c*f*h, b*d*e*g),' chk_mat += '(2*a*b*f*g + 2*a*b*e*h, a^2*f*g + a^2*e*h, b^2*f*g + b^2*e*h, 2*a*b*e*g, 2*a*b*f*h, a^2*e*g, b^2*f*h, a^2*f*h, b^2*e*g),' chk_mat += '(2*c*d*f*g + 2*c*d*e*h, c^2*f*g + c^2*e*h, d^2*f*g + d^2*e*h, 2*c*d*e*g, 2*c*d*f*h, c^2*e*g, d^2*f*h, c^2*f*h, d^2*e*g),' chk_mat += '(2*b*c*e*f + 2*a*d*e*f, 2*a*c*e*f, 2*b*d*e*f, b*c*e^2 + a*d*e^2, b*c*f^2 + a*d*f^2, a*c*e^2, b*d*f^2, a*c*f^2, b*d*e^2),' chk_mat += '(2*b*c*g*h + 2*a*d*g*h, 2*a*c*g*h, 2*b*d*g*h, b*c*g^2 + a*d*g^2, b*c*h^2 + a*d*h^2, a*c*g^2, b*d*h^2, a*c*h^2, b*d*g^2),' chk_mat += '(4*a*b*e*f, 2*a^2*e*f, 2*b^2*e*f, 2*a*b*e^2, 2*a*b*f^2, a^2*e^2, b^2*f^2, a^2*f^2, b^2*e^2),' chk_mat += '(4*c*d*g*h, 2*c^2*g*h, 2*d^2*g*h, 2*c*d*g^2, 2*c*d*h^2, c^2*g^2, d^2*h^2, c^2*h^2, d^2*g^2),' chk_mat += '(4*a*b*g*h, 2*a^2*g*h, 2*b^2*g*h, 2*a*b*g^2, 2*a*b*h^2, a^2*g^2, b^2*h^2, a^2*h^2, b^2*g^2),' chk_mat += '(4*c*d*e*f, 2*c^2*e*f, 2*d^2*e*f, 2*c*d*e^2, 2*c*d*f^2, c^2*e^2, d^2*f^2, c^2*f^2, d^2*e^2)' chk_mat += ']' chk_mat = 'matrix(' + chk_mat + ')' a, b, c, d, e, f, g, h = ring('a, b, c, d, e, f, g, h') out = DSegre.get_aut_P8([a, b, c, d, e, f, g, h]) print(list(out)) print(out) assert out == ring(chk_mat)
def test__get_invariant_q_lst__SO2(self): h1, h2, a1, a2, a3, b1, b2, b3 = Veronese.get_c_lst_lst_dct()['SL3(C)'] q_lst = Veronese.get_invariant_q_lst(h1) out = sorted(list(set(q_lst))) print('q_lst =', q_lst) print('out =', out) q0, q1, q2, q3, q4, q5 = MARing.q()[:6] assert out == ring( '[-1/2*q5, 1/2*q5, -1/2*q4, 1/2*q4, -2*q3, q3, -q2, 2*q2]')
def test__change_basis(self): l_lst = l0, l1, l2, l3, l4, l5 = Veronese.change_basis( Veronese.get_ideal_lst()) print('l_lst =', l_lst) # # l_lst = [ # x1^2 - x4^2 - x5^2, # x0*x1 - x2^2 - x3^2, # x2^2 + (2*I)*x2*x3 - x3^2 - x0*x4 + ((-I))*x0*x5, # x2^2 + ((-2*I))*x2*x3 - x3^2 - x0*x4 + (I)*x0*x5, # x1*x2 + (I)*x1*x3 - x2*x4 + (I)*x3*x4 + ((-I))*x2*x5 - x3*x5, # x1*x2 + ((-I))*x1*x3 - x2*x4 + ((-I))*x3*x4 + (I)*x2*x5 - x3*x5 # ] # m0 = l0 m1 = l1 m2 = (l2 + l3) * ring('1/2') m3 = (l2 - l3) * ring('1/2*I') m4 = (l4 + l5) * ring('1/2') m5 = (l4 - l5) * ring('1/2*I') m_lst = [m0, m1, m2, m3, m4, m5] print('m_lst =', m_lst) x0, x1 = ring('x0,x1') dct = {x1: -x0 - x1} n_lst = n0, n1, n2, n3, n4, n5 = [m.subs(dct) for m in m_lst] print('n_lst =', n_lst) print(n0 + 2 * n1) chk = ring('x1^2-x0^2-2*x2^2-2*x3^2-x4^2-x5^2') assert n0 + 2 * n1 == chk
def test__get_aut_P8__moduli(self): a, b, c, d, e, f, g, h = ring('a, b, c, d, e, f, g, h') M = DSegre.get_aut_P8([a, b, c, d, e, f, g, h]) print(M) x = ring('[x0, x1, x2, x3, x4, x5, x6, x7, x8]') y = ring('[y0, y1, y2, y3, y4, y5, y6, y7, y8]') My = M * sage_vector(y) dct = {x[i]: My[i] for i in range(9)} pol = ring('x0^2-x1*x2') print(pol.subs(dct)) # We may use this to check the dimension of the moduli space # of invariant quadratic forms, since coefficients of some of the # terms are necessarily 0. # chk = '' chk += '(b^2*c^2*f^2*g^2 - 2*a*b*c*d*f^2*g^2 + a^2*d^2*f^2*g^2 + 2*b^2*c^2*e*f*g*h - 4*a*b*c*d*e*f*g*h + 2*a^2*d^2*e*f*g*h + b^2*c^2*e^2*h^2 - 2*a*b*c*d*e^2*h^2 + a^2*d^2*e^2*h^2 )*y0^2 + ' chk += '(-b^2*c^2*f^2*g^2 + 2*a*b*c*d*f^2*g^2 - a^2*d^2*f^2*g^2 - 2*b^2*c^2*e*f*g*h + 4*a*b*c*d*e*f*g*h - 2*a^2*d^2*e*f*g*h - b^2*c^2*e^2*h^2 + 2*a*b*c*d*e^2*h^2 - a^2*d^2*e^2*h^2)*y1*y2 + ' chk += '(2*b^2*c^2*e*f*g*h - 4*a*b*c*d*e*f*g*h + 2*a^2*d^2*e*f*g*h )*y3*y4 + ' chk += '(-b^2*c^2*e*f*g*h + 2*a*b*c*d*e*f*g*h - a^2*d^2*e*f*g*h )*y5*y6 + ' chk += '(-b^2*c^2*e*f*g*h + 2*a*b*c*d*e*f*g*h - a^2*d^2*e*f*g*h )*y7*y8 + ' chk += '(b^2*c^2*e^2*g^2 - 2*a*b*c*d*e^2*g^2 + a^2*d^2*e^2*g^2 )*y3^2 + ' chk += '(b^2*c^2*f^2*h^2 - 2*a*b*c*d*f^2*h^2 + a^2*d^2*f^2*h^2 )*y4^2 + ' chk += '(2*b^2*c^2*e*f*g^2 - 4*a*b*c*d*e*f*g^2 + 2*a^2*d^2*e*f*g^2 + 2*b^2*c^2*e^2*g*h - 4*a*b*c*d*e^2*g*h + 2*a^2*d^2*e^2*g*h )*y0*y3 + ' chk += '(2*b^2*c^2*f^2*g*h - 4*a*b*c*d*f^2*g*h + 2*a^2*d^2*f^2*g*h + 2*b^2*c^2*e*f*h^2 - 4*a*b*c*d*e*f*h^2 + 2*a^2*d^2*e*f*h^2 )*y0*y4 + ' chk += '(-b^2*c^2*e*f*g^2 + 2*a*b*c*d*e*f*g^2 - a^2*d^2*e*f*g^2 - b^2*c^2*e^2*g*h + 2*a*b*c*d*e^2*g*h - a^2*d^2*e^2*g*h )*y2*y5 + ' chk += '(-b^2*c^2*f^2*g*h + 2*a*b*c*d*f^2*g*h - a^2*d^2*f^2*g*h - b^2*c^2*e*f*h^2 + 2*a*b*c*d*e*f*h^2 - a^2*d^2*e*f*h^2 )*y1*y6 + ' chk += '(-b^2*c^2*f^2*g*h + 2*a*b*c*d*f^2*g*h - a^2*d^2*f^2*g*h - b^2*c^2*e*f*h^2 + 2*a*b*c*d*e*f*h^2 - a^2*d^2*e*f*h^2 )*y2*y7 + ' chk += '(-b^2*c^2*f^2*h^2 + 2*a*b*c*d*f^2*h^2 - a^2*d^2*f^2*h^2 )*y6*y7 + ' chk += '(-b^2*c^2*e*f*g^2 + 2*a*b*c*d*e*f*g^2 - a^2*d^2*e*f*g^2 - b^2*c^2*e^2*g*h + 2*a*b*c*d*e^2*g*h - a^2*d^2*e^2*g*h )*y1*y8 + ' chk += '(-b^2*c^2*e^2*g^2 + 2*a*b*c*d*e^2*g^2 - a^2*d^2*e^2*g^2 )*y5*y8 ' assert pol.subs(dct) == ring(chk)
def test__get_c_lst_lst_lst(self): k = ring('k') for c_lst_lst in DSegre.get_c_lst_lst_lst(): for c_lst in c_lst_lst: # evaluate at k=0 n_lst = [] for c in c_lst: if c in sage_ZZ: n_lst += [c] else: n_lst += [c.subs({k: 0})] print(n_lst) assert n_lst == [1, 0, 0, 1, 1, 0, 0, 1] for c in c_lst: assert c in MARing.FF
def get_ideal_lst(): ''' Returns ------- list<MARing.R> A list of generators for the ideal of the Veronese surface. The ideal lives in a subring QQ[x0,...,x8] of the ring represented by "MARing.R". The generators for the ideal are all quadratic forms and also form a vector space over CC of all quadratic forms that contain the Veronese surface. Notes ----- We consider a toric parametrization of the Veronese surface: (s,t) |--> (1 : s*t : s : t : s^2 : t^2 ) = (x0 : x1 : x2 : x3 : x4 : x5 ) We can put the exponents of the monomials in a lattice where x0 corresponds to coordinate (0,0), x4 to (2,0) and x5 to (0,2): x5 x7 x8 x3 x1 x6 x0 x2 x4 The monomial parametrization of the Veronese corresponds to the following lattice polygon: * * * * * * ''' s_lst = [] s_lst += ['x1*x1 - x4*x5'] s_lst += ['x0*x1 - x2*x3'] s_lst += ['x2*x2 - x0*x4'] s_lst += ['x3*x3 - x0*x5'] s_lst += ['x1*x2 - x3*x4'] s_lst += ['x1*x3 - x2*x5'] return [ring(s) for s in s_lst]
def test__qmat(self): chk_mat = '' chk_mat += '[' chk_mat += '(q0 + q1 + q2 + q3, 1/2*q8 + 1/2*q12, 1/2*q9 + 1/2*q13, 1/2*q10 + 1/2*q14, 1/2*q11 + 1/2*q15, 1/2*q16, 1/2*q17, 1/2*q18, 1/2*q19),' chk_mat += '(1/2*q8 + 1/2*q12, q4, (-1/2)*q0, (-1/2)*q16, (-1/2)*q18, 0, (-1/2)*q11, 0, (-1/2)*q14),' chk_mat += '(1/2*q9 + 1/2*q13, (-1/2)*q0, q5, (-1/2)*q19, (-1/2)*q17, (-1/2)*q10, 0, (-1/2)*q15, 0),' chk_mat += '(1/2*q10 + 1/2*q14, (-1/2)*q16, (-1/2)*q19, q6, (-1/2)*q1, 0, (-1/2)*q9, (-1/2)*q12, 0),' chk_mat += '(1/2*q11 + 1/2*q15, (-1/2)*q18, (-1/2)*q17, (-1/2)*q1, q7, (-1/2)*q8, 0, 0, (-1/2)*q13),' chk_mat += '(1/2*q16, 0, (-1/2)*q10, 0, (-1/2)*q8, 0, (-1/2)*q2, (-1/2)*q4, (-1/2)*q6),' chk_mat += '(1/2*q17, (-1/2)*q11, 0, (-1/2)*q9, 0, (-1/2)*q2, 0, (-1/2)*q7, (-1/2)*q5),' chk_mat += '(1/2*q18, 0, (-1/2)*q15, (-1/2)*q12, 0, (-1/2)*q4, (-1/2)*q7, 0, (-1/2)*q3),' chk_mat += '(1/2*q19, (-1/2)*q14, 0, 0, (-1/2)*q13, (-1/2)*q6, (-1/2)*q5, (-1/2)*q3, 0)' chk_mat += ']' chk_mat = 'matrix(' + chk_mat + ')' qmat = DSegre.get_qmat() for row in qmat: print(row) assert qmat == ring(chk_mat)
def test__get_aut_P8__action_of_involution(self): ''' OUPUT: - We check how the action of the involution J: P^8---->P^8 acts on elements "c_lst" in Aut(P^1xP^1) by conjugation. See documentation "DSegre.change_basis()" and "DSegre.get_aut_P8()" for our internal implementation of J and "c_lst" respectively. ''' a, b, c, d, e, f, g, h = ring('a, b, c, d, e, f, g, h') # left-right involution # M = DSegre.get_aut_P8([a, b, c, d] + [e, f, g, h]) L = sage_matrix([(1, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 1, 0, 0, 0, 0, 0), (0, 0, 0, 0, 1, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 1), (0, 0, 0, 0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 0, 1, 0, 0, 0)]) assert L == ~L LML = ~L * M * L LML_chk = DSegre.get_aut_P8([d, c, b, a] + [e, f, g, h]) assert LML_chk == LML # rotate # M = DSegre.get_aut_P8([a, b, c, d] + [e, f, g, h]) R = sage_matrix([(1, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 1, 0, 0, 0, 0), (0, 0, 0, 1, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 0, 1, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 1), (0, 0, 0, 0, 0, 0, 0, 1, 0)]) assert R == ~R RMR = ~R * M * R RMR_chk = DSegre.get_aut_P8([d, c, b, a] + [h, g, f, e]) assert RMR_chk == RMR
def test__get_c_lst_lst_dct(self): k = ring('k') for key in Veronese.get_c_lst_lst_dct(): for c_lst in Veronese.get_c_lst_lst_dct()[key]: print('key =', key) print('c_lst =', c_lst) print('det =', sage_matrix(3, 3, c_lst).det()) n_lst = [] for c in c_lst: if c in sage_QQ: n_lst += [c] else: n_lst += [c.subs({k: 0})] print('n_lst =', n_lst) print if key != 'SO3(R)': assert sage_matrix(3, 3, c_lst).det() == 1 assert n_lst == [1, 0, 0, 0, 1, 0, 0, 0, 1]
def test__get_aut_P8__SO2xID(self): chk_mat = '' chk_mat += '[' chk_mat += '(1, 0, 0, 0, 0, 0, 0, 0, 0),' chk_mat += '(0, k^2 + 2*k + 1, 0, 0, 0, 0, 0, 0, 0),' chk_mat += '(0, 0, 1/(k^2 + 2*k + 1), 0, 0, 0, 0, 0, 0),' chk_mat += '(0, 0, 0, 1, 0, 0, 0, 0, 0),' chk_mat += '(0, 0, 0, 0, 1, 0, 0, 0, 0),' chk_mat += '(0, 0, 0, 0, 0, k^2 + 2*k + 1, 0, 0, 0),' chk_mat += '(0, 0, 0, 0, 0, 0, 1/(k^2 + 2*k + 1), 0, 0),' chk_mat += '(0, 0, 0, 0, 0, 0, 0, k^2 + 2*k + 1, 0),' chk_mat += '(0, 0, 0, 0, 0, 0, 0, 0, 1/(k^2 + 2*k + 1))' chk_mat += ']' chk_mat = 'matrix(' + chk_mat + ')' k = ring('k') out = DSegre.get_aut_P8([k + 1, 0, 0, 1 / (k + 1), 1, 0, 0, 1]) print(list(out)) print(out) t = (k + 1)**2 assert out == sage_diagonal_matrix( [1, t, 1 / t, 1, 1, t, 1 / t, t, 1 / t])
def get_pmz_lst(): ''' Returns ------- list<MARing> Returns a list of polynomials of bidegree (2,2) in the subring QQ[s,t;u,w] of the ring "MARing.R". ''' s_lst = [] s_lst += ['s*t*u*w'] s_lst += ['s*s*u*w'] s_lst += ['t*t*u*w'] s_lst += ['s*t*u*u'] s_lst += ['s*t*w*w'] s_lst += ['s*s*u*u'] s_lst += ['t*t*w*w'] s_lst += ['s*s*w*w'] s_lst += ['t*t*u*u'] p_lst = [ring(s) for s in s_lst] return p_lst
def get_gens_sl2(): ''' Returns ------- list<MARing.FF> A list of lists L of length 4 with elements c0,...,c3 in QQ(k) where the function field QQ(k) is a subfield of "MARing.FF". If we substitute k:=0 in the entries of L then we obtain the list [1,0,0,1]. A list L represent a 2x2 matrix [ c0 c1 ] [ c2 c3 ] with the property that c0*c3-c1*c2!=0. The antiholomorphic involution coming from the real structure induces---up to conjugacy---two possible antiholomorphic involutions acting on the 2x2-matrices: R0: [c0,c1,c2,c3] |--> [c0,c1,c2,c3] followed by complex conjugation. R1: [c0,c1,c2,c3] |--> [c3,c2,c1,c0] followed by complex conjugation. A list L represents a real 1-parameter subgroup of PSL(2) wrt R0 or R1. We assume that we are only interested in the tangent vector of this subgroup at the identity. This tangent vector is an element in the Lie algebra sl(2). For example for the rotations wrt. R0 we have that [ cos(k) -sin(k) ] [ sin(k) cos(k) ] but we represent this element by "r": [ 1 -k ] [ k 1 ] because their tangent vectors at the identity coincide. The 1-parameter subgroup of translations with real structure R0 corresponds to "t": [ 1 k ] [ 0 1 ] The corresponding element in the Lie algebra is [ 0 1 ] [ 0 0 ] and is conjugate to [ I I ] [ -I -I ] where I is the imaginary unit. This latter element is real wrt R1. A 1-parameter subgroup which has---up to scalar multiplication---this element as tangent vector is "T": [ k+1 k ] [ -k (k+1)^(-1) ] See the code for an overview of generators L. The tangent vectors of t, q and s generate the Lie algebra sl(2). Examples -------- t, q, s, r, e, T = DSegre.get_gens_sl2() c_lst_lst = [s+e, e+s] iq_lst = DSegre.get_invariant_qf( c_lst_lst, [] ) iq_lst = DSegre.change_basis( iq_lst, "rotate" ) iq_lst = MARing.replace_conj_pairs( iq_lst ) sig_lst = MARing.get_rand_sigs( iq_lst, 10 ) ''' k = ring('k') a = k + 1 b = 1 / (k + 1) t = [1, k, 0, 1] # translation for R0 q = [1, 0, k, 1] s = [a, 0, 0, b] # scalings for R0/rotations for R1 r = [1, -k, k, 1] # rotations for R0/scalings for R1 e = [1, 0, 0, 1] # identity T = [a, k, -k, b] # translations for R1 return t, q, s, r, e, T
def get_invariant_q_lst(c_lst, exc_idx_lst=[]): ''' Parameters ---------- c_lst : list<MARing.FF> A list of length 8 with elements c0,...,c7 in QQ(k), where QQ(k) is a subfield of "MARing.FF". If we substitute k:=0 in the entries of "c_lst" then we should obtain the list: [1,0,0,1,1,0,0,1]. A c_lst represents a pair of two matrices: ( [ c0 c1 ] [ c4 c5 ] ) ( [ c2 c3 ] , [ c6 c7 ] ) with the property that c0*c3-c1*c2!=0 and c4*c7-c5*c6!=0. If the two matrices are not normalized to have determinant 1, then the method should be taken with care (it should be checked that the tangent vectors at the identity generate the correct Lie algebra). exc_idx_lst : list<int> A list of integers in [0,8]. Returns ------- list<MARing.R> A list of generators of an ideal J in the subring QQ[q0,...,q19] of "MARing.R". Each point p in the zeroset V(J), when substituted in the matrix ".get_qmat(exc_idx_lst)", defines a quadratic form in the ideal ".get_ideal_lst(exc_idx_lst)" that is preserved by the 1-parameter subgroup H, where H be the representation of the pair of matrices ( [ c0 c1 ] [ c4 c5 ] ) ( [ c2 c3 ] , [ c6 c7 ] ) into P^8 (see also ".get_aut_P8()"). We assume here that H is an element in Aut(P^1xP^1) and normalized so that each 2x2 matrix has determinant 1. Thus H corresponds to a 1-parameter subgroup of Aut(P^8), such that each automorphism preserves the double Segre surface S in projective 8-space P^8. ''' # get representation of 1-parameter subgroup in Aut(P^8) # H = DSegre.get_aut_P8(c_lst) # consider the tangent vector of the curve H at the identity # k = ring('k') D = MARing.diff_mat(H, k).subs({k: 0}) # Note that if we differentiate the condition # A=H.T*A*H on both sides, evalute k=0, then # we obtain the condition D.T * A + A * D=0. # Here A denotes the matrix of a quadratic form # in the ideal of the double Segre surface S. # A = DSegre.get_qmat(exc_idx_lst) Z = D.T * A + A * D iq_lst = [iq for iq in Z.list() if iq != 0] return iq_lst
def get_ideal_lst(exc_idx_lst=[], varname='x'): ''' We consider a toric parametrization of double Segre surface whose completion to P^1xP^1 is provided by "get_pmz_lst": (s,u) |--> (1:s:s^{-1}:u:u^{-1}:s*u:s^{-1}*u^{-1}:s*u^{-1}:s^{-1}*u) = (1:x1:x2:x3:x4:x5:x6:x7:x8) If we compose this parametrization with for example the projection (1:x1:x2:x3:x4:x5:x6:x7:x8) |-> (1:x1:x2:x3:x4:x7:x8) then we obtain a degree 6 Del Pezzo surface. The ideal of this surface is obtained by setting the input parameter "exc_idx_lst" to "[5,6]". Parameters ---------- exc_idx_lst: list<int> A list of integers in [0,8]. varname: ch A character in [ 'x', 'y', 'z' ]. Returns ------- list A (sub-)list of generators for the ideal of the double Segre surface. The ideal lives in a subring QQ[x0,...,x8] (or QQ[y0,...,y8] or QQ[z0,...,z8]) of the ring represented by "MARing.R". The variable names are determined by "varname". For each index i in "exc_idx_lst" the generators that contain xi (or yi or zi) are omitted. ''' s_lst = [] s_lst += ['x0^2-x1*x2'] s_lst += ['x0^2-x3*x4'] s_lst += ['x0^2-x5*x6'] s_lst += ['x0^2-x7*x8'] s_lst += ['x1^2-x5*x7'] s_lst += ['x2^2-x6*x8'] s_lst += ['x3^2-x5*x8'] s_lst += ['x4^2-x6*x7'] s_lst += ['x0*x1-x4*x5'] s_lst += ['x0*x2-x3*x6'] s_lst += ['x0*x3-x2*x5'] s_lst += ['x0*x4-x1*x6'] s_lst += ['x0*x1-x3*x7'] s_lst += ['x0*x2-x4*x8'] s_lst += ['x0*x3-x1*x8'] s_lst += ['x0*x4-x2*x7'] s_lst += ['x0*x5-x1*x3'] s_lst += ['x0*x6-x2*x4'] s_lst += ['x0*x7-x1*x4'] s_lst += ['x0*x8-x2*x3'] s_lst = [s.replace('x', varname) for s in s_lst] # exclude generators depending on exc_lst exc_lst = [varname + str(i) for i in exc_idx_lst] for exc in exc_lst: s_lst = [s for s in s_lst if str(exc) not in s] e_lst = [ring(s) for s in s_lst] return e_lst
def change_basis(iqf_lst, involution='identity'): ''' This method allows us to change coordinates of the ideal generated by "iqf_lst" so that the antiholomorphic involution defined by "involution" becomes complex conjugation. Parameters ---------- iqf_lst: list<MARing> A list of elements in the subring NF[x0,...,x8] of "MARing.R" where NF denotes the Gaussian rationals QQ(I) with I^2=-1. involution: str Either one of the following strings: 'identity', 'leftright', 'rotate', 'diagonal'. Returns ------- We consider the input "iqf_lst" as a map. We compose this map composed with the map corresponding to <identity>, <leftright>, <rotate> or <diagonal>. We return a list of elements in NF[x0,...,x8] that represents the composition. Notes ----- A double Segre surface in projective 8-space P^8 is represented by a toric parametrization whose completion to P^1xP^1 is provided by "get_pmz_lst": (s,u) |--> (1:s:s^{-1}:u:u^{-1}:s*u:s^{-1}*u^{-1}:s*u^{-1}:s^{-1}*u) = (x0:x1:x2:x3:x4:x5:x6:x7:x8) We can put the exponents of the monomials in a lattice where x0 corresponds to coordinate (0,0), x6 to (-1,-1) x5 to (1,1) and x8 to (-1,1): x8 x3 x5 x2 x0 x1 x6 x4 x7 An antiholomorphic involution, that preserves the toric structure, acts on the above lattice as a unimodular involution: identity_*: ( a, b ) |--> ( a, b) leftright_*: ( a, b ) |--> (-a, b) rotate_*: ( a, b ) |--> (-a,-b) diagonal_*: ( a, b ) |--> ( b, a) These unimodular lattice involutions induce an involution on P^8. We compose the toric parametrization of the double Segre surface with the one of the following maps in order to make the antiholomorphic involution that acts on P^8, equal to complex conjugation. identity: (x0:...:x8) |--> (x0:...:x8) leftright: x3 |--> x3, x0 |--> x0, x4 |--> x4, x1 |--> x1 + I*x2, x2 |--> x1 - I*x2, x5 |--> x5 + I*x8, x8 |--> x5 - I*x8, x7 |--> x7 + I*x6, x6 |--> x7 - I*x6 rotate: x0 |--> x0, x1 |--> x1 + I*x2, x2 |--> x1 - I*x2, x3 |--> x3 + I*x4, x4 |--> x3 - I*x4, x5 |--> x5 + I*x6, x6 |--> x5 - I*x6, x7 |--> x7 + I*x8, x8 |--> x7 - I*x8 diagonal: x5 |--> x5, x0 |--> x0, x6 |--> x6, x3 |--> x3 + I*x1, x1 |--> x3 - I*x1, x8 |--> x8 + I*x7, x7 |--> x8 - I*x7, x2 |--> x2 + I*x4, x4 |--> x2 - I*x4 ''' I = ring('I') x = x0, x1, x2, x3, x4, x5, x6, x7, x8 = MARing.x() z = z0, z1, z2, z3, z4, z5, z6, z7, z8 = MARing.z() dct = {} dct['identity'] = {x[i]: z[i] for i in range(9)} dct['rotate'] = { x0: z0, x1: z1 + I * z2, x2: z1 - I * z2, x3: z3 + I * z4, x4: z3 - I * z4, x5: z5 + I * z6, x6: z5 - I * z6, x7: z7 + I * z8, x8: z7 - I * z8 } dct['leftright'] = { x0: z0, x3: z3, x4: z4, x5: z5 + I * z8, x8: z5 - I * z8, x1: z1 + I * z2, x2: z1 - I * z2, x7: z7 + I * z6, x6: z7 - I * z6 } dct['diagonal'] = { x0: z0, x6: z6, x5: z5, x3: z3 + I * z1, x1: z3 - I * z1, x8: z8 + I * z7, x7: z8 - I * z7, x2: z2 + I * z4, x4: z2 - I * z4 } zx_dct = {z[i]: x[i] for i in range(9)} new_lst = [iqf.subs(dct[involution]).subs(zx_dct) for iqf in iqf_lst] return new_lst