Full text
Hadamard ranks of algebraic varieties guided examples and computational proofs Dario Antolini Guido Montúfar Alessandro Oneto Disclaimer. This is the printed version of a Jupyter Notebook in SageMath [1] containing computational examples and proofs related to the work [2]. The original Jupyter Notebook is stored in the Zenodo page [3]. 1 Computing the parameterization of the Veronese variety Vd,n = ν(d)(Pn) [1]: def veronese(d, var_list): ''' INPUT: - d, the degree - var_list, the list of variables of the source projective space OUTPUT: the polynomials defining the d-Veronese embedding of the projective␣ ,→space with variables var_list ''' P=ProjectiveSpace(QQ, len(var_list) - 1, var_list) return list(P.veronese_embedding(d).defining_polynomials()) 1.1 Example: the Veronese embedding ν(2) :P2,→P5 [2]: veronese(2,[var('x0'),var('x1'),var('x2')]) [2]: x2 0, x0x1, x0x2, x2 1, x1x2, x2 2 Its image is the Veronese surface V2,2⊂P5 2 Computing the parameterization of the secant variety σr(Vd,n) [3]: def secant_veronese(d, n, r, vars_list): ''' INPUT: - d, the degree - n, the dimension - r, the rank 1
- vars_list, the list of variables in the source projective space. It␣ ,→is a list of r lists of variables, one for each summand OUTPUT: the polynomials defining the parameterization of the r-secant␣ ,→variety of the d-Veronese embedding in the variables vars_list copy the first line to use as variables x_{ij} for i = 1 , ... , r␣ ,→and j = 0, ... , n ''' #vars_list = [[var('x'+str(i)+str(j)) for j in range(n+1)] for i in␣ ,→range(1,r+1)] N=binomial(n+d, d) P=PolynomialRing(QQ, [v[i] for vin vars_list for iin range(n+1)]) copies_veronese =[[P(f) for fin veronese(d,vars_list[i])] for iin␣ ,→range(r)] return [sum([copies_veronese[i][j] for iin range(r)]) for jin range(N)] 2.1 Example: the parameterization of σ2(V2,2) [4]: secant_veronese(2,2,2, [ [var('x'+str(i)+str(j)) for jin range(2+1)] for iin range(1,2+1) ]) [4]: x2 10 +x2 20, x10x11 +x20x21, x10x12 +x20x22, x2 11 +x2 21, x11x12 +x21x22, x2 12 +x2 22 3 Computing the parameterization of the Hadamard product of secant varieties σ(r1,...,rm)(Vd,n) = σr1(Vd,n)⋆· · · ⋆ σrm(Vd,n) [5]: def hadamard_secant_veronese(d, n, r): ''' INPUT: - d, the degree - n, the dimension - r, the list of ranks OUTPUT: the polynomials defining the parameterization of the Hadamard␣ ,→product of all the r[i]-secant varieties to the d-Veronese embedding the variables are x_{ijk} for i = 1 , ... , m, j = 1 , ... , r[i], k␣ ,→= 0 , ... , n, where m = len(r) ''' N=binomial(n+d, d) m=len(r) vars_list_hadamard =[ [ [var('x'+str(i+1)+str(j+1)+str(k)) for kin range(n+1)] for jin range(r[i])] for iin range(m) ] 2
P=PolynomialRing(QQ, [vars_list_hadamard[i][j][k] for iin range(m) for j␣ ,→in range(r[i]) for kin range(n+1)]) copies_secant_veronese =[[P(f) for fin␣ ,→secant_veronese(d,n,r[i],vars_list_hadamard[i])] for iin range(m)] return [prod([copies_secant_veronese[i][j] for iin range(m)]) for jin␣ ,→range(N)] 3.1 Example: the parameterization of σ2(V2,2)⋆2 [6]: hadamard_secant_veronese(2,2,[2,2]) [6]: [x2 110x2 210 +x2 120x2 210 +x2 110x2 220 +x2 120x2 220, x110x111x210x211 +x120x121x210x211 +x110x111x220x221 +x120x121x220x221, x110x112x210x212 +x120x122x210x212 +x110x112x220x222 +x120x122x220x222, x2 111x2 211 +x2 121x2 211 +x2 111x2 221 +x2 121x2 221, x111x112x211x212 +x121x122x211x212 +x111x112x221x222 +x121x122x221x222, x2 112x2 212 +x2 122x2 212 +x2 112x2 222 +x2 122x2 222] 4 Computing Jacobians of polynomial maps [7]: def jacobian(f): ''' INPUT: f, a list of polynomials OUTPUT: the Jacobian matrix of the polynomial map corresponding to f ''' return Matrix([list(g.gradient()) for gin f]) 4.1 Example: the Veronese surface V3,2is not (2,2)-Hadamard defective, i.e. σ2(V3,2)⋆2has the expected dimension, by Corollary 4.4 of the paper and by the Alexander–Hirschowitz Theorem [8]: M=jacobian(hadamard_secant_veronese(3,2,[2,2])) [9]: N= 2*2*(2+1)# number of variables in the source of the parameterization v=[QQ.random_element(10^6,10^6)for iin range(N)] # a random point in the␣ ,→source of the parameterization M(v).rank() -1==min(binomial(2+3,3)- 1, (2*(2-1)+1)*2+(2*(2-1)+1)- 1)#␣ ,→evaluation of the rank of the Jacobian #␣ ,→at a random point gives the expected dimension [9]: True 3
Remark: once a generic rational vector is chosen, the computation of the rank of the Jacobian at that vector is exact, since it is performed using symbolic Gaussian elimination 5 Proof of Corollary 4.10: if d≥3, in the defective cases (d, n, s)of the Alexander–Hirschowitz Theorem such that s=Pm i=1(ri−1)+1, the Hadamard product σ(r1,...,rm)(Vd,n)fills the ambient space PN−1, where N=n+d d Startegy: for each d≥3, we consider a defective triple (d, n, s). There are finitely many of them. Then, for each (d, n, s): •we consider a non-trivial partition λ= (λ1, . . . , λm), λi≥1, m ≥2of s−1 •we set r= (λ1+ 1, . . . , λm+ 1) •we compute the parameterization of σr(Vd,n)and its Jacobian •we evaluate the Jacobian at a generic rational point and check that its rank is equal to N 5.1 d= 3, n = 4, s = 7 [10]: d= 3 n= 4 s= 7 N=binomial(n+d, d) partitions_s =Partitions(s-1).list()[1:] # non-trivial partitions of s-1 possible_r =[[t+1 for tin r] for rin partitions_s] # possible values of the␣ ,→vector r [11]: for rin possible_r: M=jacobian(hadamard_secant_veronese(d,n,r)) V=sum(r)*(n+1)# number of variables in the source of the parameterization v=[QQ.random_element(10^6,10^6)for iin range(V)] # random point in the␣ ,→source of the parameterization print(r, M(v).rank() == N) [6, 2] True [5, 3] True [5, 2, 2] True [4, 4] True [4, 3, 2] True [4, 2, 2, 2] True [3, 3, 3] True [3, 3, 2, 2] True [3, 2, 2, 2, 2] True [2, 2, 2, 2, 2, 2] True 4
5.2 d= 4, n = 2, s = 5 [12]: d= 4 n= 2 s= 5 N=binomial(n+d, d) partitions_s =Partitions(s-1).list()[1:] # non-trivial partitions of s-1 possible_r =[[t+1 for tin r] for rin partitions_s] # possible values of the␣ ,→vector r [13]: for rin possible_r: M=jacobian(hadamard_secant_veronese(d,n,r)) V=sum(r)*(n+1)# number of variables in the source of the parameterization v=[QQ.random_element(10^6,10^6)for iin range(V)] # random point in the␣ ,→source of the parameterization print(r, M(v).rank() == N) [4, 2] True [3, 3] True [3, 2, 2] True [2, 2, 2, 2] True 5.3 d= 4, n = 3, s = 9 [14]: d= 4 n= 3 s= 9 N=binomial(n+d, d) partitions_s =Partitions(s-1).list()[1:] # non-trivial partitions of s-1 possible_r =[[t+1 for tin r] for rin partitions_s] # possible values of the␣ ,→vector r [15]: for rin possible_r: M=jacobian(hadamard_secant_veronese(d,n,r)) V=sum(r)*(n+1)# number of variables in the source of the parameterization v=[QQ.random_element(10^6,10^6)for iin range(V)] # random point in the␣ ,→source of the parameterization print(r, M(v).rank() == N) [8, 2] True [7, 3] True [7, 2, 2] True [6, 4] True [6, 3, 2] True [6, 2, 2, 2] True [5, 5] True [5, 4, 2] True [5, 3, 3] True 5
[5, 3, 2, 2] True [5, 2, 2, 2, 2] True [4, 4, 3] True [4, 4, 2, 2] True [4, 3, 3, 2] True [4, 3, 2, 2, 2] True [4, 2, 2, 2, 2, 2] True [3, 3, 3, 3] True [3, 3, 3, 2, 2] True [3, 3, 2, 2, 2, 2] True [3, 2, 2, 2, 2, 2, 2] True [2, 2, 2, 2, 2, 2, 2, 2] True 5.4 d= 4, n = 4, s = 14 [45]: d= 4 n= 4 s= 14 N=binomial(n+d,d) partitions_s =Partitions(s-1).list()[1:] # non-trivial partitions of s-1 possible_r =[[t+1 for tin r] for rin partitions_s] # possible value of the␣ ,→vector r [47]: for iin range(100): M1 =hadamard_secant_veronese(d,n,possible_r[i]) V=sum(possible_r[i])*(n+1)# number of variables in the source of the␣ ,→parameterization v=[QQ.random_element(10^6,10^6)for iin range(V)] # random point in the␣ ,→source of the parameterization M2 =[[h(v) for hin g.gradient()] for gin M1] print(i+1, Matrix(M2).rank() == N) The computation reveals that the Corollary holds true in all these cases. For the sake of conciseness, we omit the output, which is visible on the notebook. Time for this computation: 8023 seconds 6 Computing parameterizations of Segre products [16]: def segre(polynomials_lists): ''' INPUT: polynomials_list, a list of lists of polynomials OUTPUT: the parameterization of the Segre embedding of these lists of␣ ,→polynomials ''' k=len(polynomials_lists) if k== 2: 6
return [f*gfor fin polynomials_lists[0]for gin polynomials_lists[1]] else: return [f*gfor fin polynomials_lists[0]for gin␣ ,→segre(polynomials_lists[1:])] 6.1 Example: the Segre embedding P1×P1,→P3 [17]: P.<x0,x1,y0,y1>=PolynomialRing(QQ) segre([ [x0,x1], [y0,y1] ]) [17]: [x0y0, x0y1, x1y0, x1y1] 6.2 Example: the Segre embedding P1×P1×P1,→P7 [18]: P.<x0,x1,y0,y1,z0,z1>=PolynomialRing(QQ) segre([ [x0,x1], [y0,y1], [z0,z1] ]) [18]: [x0y0z0, x0y0z1, x0y1z0, x0y1z1, x1y0z0, x1y0z1, x1y1z0, x1y1z1] 7 Computing parameterizations of Segre-Veronese varieties [19]: def segre_veronese(d, vars_list): ''' INPUT: - d, a list of degrees for the Veronese embeddings - vars_list, a list of variables for the various copies of the␣ ,→Veronese embeddings. It is a list of k lists of variables, where k = len(d) OUTPUT: the parameterization of the Segre-Veronese embedding in degrees d␣ ,→with respect to the variables in vars_list copy the first line to use as variables x_{ij} for i = 1, ... , k,␣ ,→for j = 0, ... , n[i], where n is a list of dimensions ''' #vars_list = [[var('x'+str(i+1)+str(j)) for j in range(n[i]+1)] for i in␣ ,→range(len(n))] P=PolynomialRing(QQ, [v for iin range(len(d)) for vin vars_list[i]]) list_veronese =[[P(f) for fin veronese(d[i],vars_list[i])] for iin␣ ,→range(len(d))] return segre(list_veronese) 7
7.1 Example: the Segre-Veronese embedding ν(2,2) :P1×P1,→P8 [20]: d=[2,2] n=[1,1] vars_list =[ [var('x'+str(i+1)+str(j)) for jin range(n[i]+1)] for iin range(len(n)) ] vars_list [20]: [[x10, x11],[x20, x21]] [21]: segre_veronese(d,vars_list) [21]: x2 10x2 20, x2 10x20x21, x2 10x2 21, x10x11x2 20, x10x11x20x21, x10x11x2 21, x2 11x2 20, x2 11x20x21, x2 11x2 21 8 Computing parameterizations of secant varieties to SegreVeronese varieties [22]: def secant_segre_veronese(d, r, vars_list): ''' INPUT: - d, a list of degrees of the various Veronese embeddings - r, the rank of the secant variety - vars_list, a list of variables for the various copies of the␣ ,→Veronese embeddings. It is a list of k lists of variables, where k = len(d) OUTPUT: the parameterization of the r-secant variety to the Segre-Veronese␣ ,→embedding in degrees d with respect to the variables in vars_list ''' n=[len(e)-1 for ein vars_list[0]] N=prod([binomial(n[i]+d[i],d[i]) for iin range(len(n))]) P=PolynomialRing(QQ, [l[i][j] for lin vars_list for iin range(len(l))␣ ,→for jin range(len(l[i]))]) copies_segre_veronese =[[P(f) for fin segre_veronese(d,vars_list[i])] for␣ ,→iin range(r)] return [sum([copies_segre_veronese[i][j] for iin range(r)]) for jin␣ ,→range(N)] 8.1 Example: parameterization of σ2(ν(2,2)(P1×P1)) ,→P8 [23]: d=[2,2] r= 2 n=[1,1] vars_list =[ [ [var('x'+str(i+1)+str(j)+str(k)) for jin range(n[i]+1)] for iin range(len(n))] for kin range(1,r+1) 8
] vars_list [23]: [[[x101, x111],[x201, x211]] ,[[x102, x112],[x202, x212]]] [24]: secant_segre_veronese(d,r,vars_list) [24]: [x2 101x2 201 +x2 102x2 202, x2 101x201x211 +x2 102x202x212, x2 101x2 211 +x2 102x2 212, x101x111x2 201 +x102x112x2 202, x101x111x201x211 +x102x112x202x212, x101x111x2 211 +x102x112x2 212, x2 111x2 201 +x2 112x2 202, x2 111x201x211 +x2 112x202x212, x2 111x2 211 +x2 112x2 212] 9 Computing parameterizations of Hadamard powers of secant varieties to Segre-Veronese varieties [25]: def hadamard_secant_segre_veronese(d, n, r): ''' INPUT: - d, a list of degrees of the various Veronese embeddings - n, a list of dimensions for the various sources of the Veronese␣ ,→embeddings - r, a list of ranks OUTPUT: the polynomials defining the parameterization of the Hadamard product of all the r[i]-secant varieties to the␣ ,→d[i]-Veronese embedding of P^{n[i]} with respect to the variables x_{ijkl}, for i = 1, ... , m, for j =␣ ,→1, ... , r[i], for k = 1, ... , t, for l = 0, ... , n[k] where t is the number of factors in the Segre embedding, i.e. t =␣ ,→len(n), and m is the number of Hadamard factors, i.e. m = len(r) ''' t=len(n) m=len(r) N=prod([binomial(n[i]+d[i],d[i]) for iin range(t)]) vars_list =[ [ [ [var('x'+str(i+1)+str(j+1)+str(k+1)+str(l)) for lin␣ ,→range(n[k]+1)] for kin range(t)] for jin range(r[i])] for iin range(m) ] P=PolynomialRing(QQ, [e[i][j][k] for ein vars_list for iin range(len(e))␣ ,→for jin range(len(e[i])) for kin range(len(e[i][j]))]) copies_secant_segre_veronese =[[P(f) for fin␣ ,→secant_segre_veronese(d,r[i],vars_list[i])] for iin range(m)] 9