def usecase__construct_surfaces(): ''' We construct a surface parametrization and its Neron-Severi lattice. Requires the linear_series package. ''' # Blowup of projective plane in 3 colinear points # and 2 infinitely near points. The image of the # map associated to the linear series is a quartic # del Pezzo surface with 5 families of conics. # Moreover the surface contains 8 straight lines. # ring = PolyRing('x,y,z', True) p1 = (-1, 0) p2 = (0, 0) p3 = (1, 0) p4 = (0, 1) p5 = (2, 0) bp_tree = BasePointTree() bp_tree.add('z', p1, 1) bp_tree.add('z', p2, 1) bp_tree.add('z', p3, 1) bp = bp_tree.add('z', p4, 1) bp.add('t', p5, 1) ls = LinearSeries.get([3], bp_tree) NSTools.p(ls.get_bp_tree()) NSTools.p('implicit equation =\n\t', ls.get_implicit_image()) # construct NS-lattice where p1=e1,...,p5=e5 rank = 6 d_lst = ['e0-e1-e2-e3', 'e4-e5'] # basepoint p5 is infinitely near to p4 Md_lst = [] M = sage_identity_matrix(6) d_lst = [Div.new(d, rank) for d in d_lst] Md_lst = [Div.new(Md, rank) for Md in Md_lst] M = sage_matrix(M) dpl = DPLattice(d_lst, Md_lst, M) NSTools.p('Neron-Severi lattice =', dpl) # search representative for the equivalence class in classification assert dpl in DPLattice.get_cls(rank)
def complete_basis(d_lst): ''' Parameters ---------- d_lst : list<Div> A list of "Div" objects. Returns ------- sage_matrix<sage_QQ> Returns a square matrix over QQ of full rank. The first columns correspond to the elements in d_lst (where d_lst is sorted). The appended columns are orthogonal to the first "len(d_lst)" columns. Examples -------- We explain with 3 examples where the dotted (:) vertical lines denote which columns are appended. | 0 0 : 1 0 0 0 | | 0 0 0 : 1 0 0 | | 0 0 0 1 : -3 0 | | 0 0 : 0 -1 0 0 | | 0 0 0 : 0 -1 0 | | 1 0 0 -1 : 1 0 | | 0 0 : 0 0 -1 0 | | 1 0 0 : 0 0 -1 | |-1 1 0 -1 : 1 0 | | 1 0 : 0 0 0 -1 | |-1 1 0 : 0 0 -1 | | 0 -1 0 -1 : 1 0 | |-1 1 : 0 0 0 -1 | | 0 -1 1 : 0 0 -1 | | 0 0 1 0 : 0 1 | | 0 -1 : 0 0 0 -1 | | 0 0 -1 : 0 0 -1 | | 0 0 -1 0 : 0 1 | ''' # sort d_lst = [d for d in d_lst] d_lst.sort() # extend with orthogonal vectors row_lst = [d.e_lst for d in d_lst] ext_lst = [] for v_lst in sage_matrix(sage_ZZ, row_lst).right_kernel().basis(): ext_lst += [[-v_lst[0]] + list(v_lst[1:]) ] # accounts for signature (1,rank-1) mat = sage_matrix(sage_QQ, row_lst + ext_lst).transpose() # verify output if mat.rank() < d_lst[0].rank(): raise Error('Matrix expected to have full rank: ', d_lst, '\n' + str(mat)) de_lst = [Div(ext) for ext in ext_lst] for de in de_lst: for d in d_lst: if d * de != 0: raise Error('Extended columns are expected to be orthogonal: ', de, d, de_lst, d_lst, list(mat)) return mat
def get_ak(rank): ''' Parameters ---------- rank : int Returns ------- Div A Div object of given rank of the form 3e0 - e1 - ... - er Mathematically this is the anticanonical class of the blowup of the projective plane. ''' return Div([3] + (rank - 1) * [-1])
def __str__(self): self.set_attributes() s = '\n' s += 50 * '=' + '\n' s += 'Degree = ' + str(self.get_degree()) + '\n' s += 'Rank = ' + str(self.get_rank()) + '\n' s += 'Intersection = ' + str(list(self.m1_lst[0].int_mat)) + '\n' s += 'Real structure = ' + str(self.get_marked_Mtype()) + '\n' s += 'Singularities = ' + str(self.type) + '\n' s += 'Cardinalities = ' + '(' + str(len(self.or_lst)) + ', ' + str( len(self.sr_lst)) + ')\n' arrow = ' ---> ' s += 'Real involution:\n' b_lst = [ Div(row) for row in sage_identity_matrix(sage_ZZ, self.get_rank()).rows() ] for b in b_lst: s += '\t' + str(b) + arrow + str(b.mat_mul(self.M)) + '\n' s += 'Indecomposable (-2)-classes:\n' for d in self.d_lst: s += '\t' + str(d) + arrow + str(d.mat_mul(self.M)) + '\n' s += '\t#real = ' + str(len(self.real_d_lst)) + '\n' s += 'Indecomposable (-1)-classes:\n' for m1 in self.m1_lst: s += '\t' + str(m1) + arrow + str(m1.mat_mul(self.M)) + '\n' s += '\t#real = ' + str(len(self.real_m1_lst)) + '\n' s += 'Classes of conical families:\n' for fam in self.fam_lst: s += '\t' + str(fam) + arrow + str(fam.mat_mul(self.M)) + '\n' s += '\t#real = ' + str(len(self.real_fam_lst)) + '\n' s += 50 * '=' + '\n' return s
def usecase__roman_circles(): ''' We compute circles on a Roman surface. ''' # parametrization of the Roman surface # p_lst = '[ z^2+x^2+y^2, -z*x, -x*y, z*y ]' # we consider the stereographic projection from # S^3 = { x in P^4 | -x0^2+x1^2+x2^2+x3^2+x4^2 = 0 } # where the center of projection is (1:0:0:0:1): # (x0:x1:x2:x3:x4) |---> (x0-x4:x1:x2:x3) # inverse stereographic projection into 3-sphere # s_lst = '[ y0^2+y1^2+y2^2+y3^2, 2*y0*y1, 2*y0*y2, 2*y0*y3, -y0^2+y1^2+y2^2+y3^2 ]' # compose p_lst with s_lst # ring = PolyRing('x,y,z,y0,y1,y2,y3') x, y, z, y0, y1, y2, y3 = ring.gens() p_lst = ring.coerce(p_lst) s_lst = ring.coerce(s_lst) dct = {y0: p_lst[0], y1: p_lst[1], y2: p_lst[2], y3: p_lst[3]} sp_lst = [s.subs(dct) for s in s_lst] NSTools.p('sp_lst =') for sp in sp_lst: NSTools.p('\t\t', sage_factor(sp)) NSTools.p('gcd(sp_lst) =', sage_gcd(sp_lst)) # determine base points # ring = PolyRing('x,y,z', True) sp_lst = ring.coerce(sp_lst) ls = LinearSeries(sp_lst, ring) NSTools.p(ls.get_bp_tree()) # We expect that the basepoints come from the intersection # of the Roman surface with the absolute conic: # A = { (y0:y1:y2:y3) in P^3 | y0=y1^2+y2^2+y3^2 = 0 } # # Circles are the image via p_lst of lines that pass through # complex conjugate points. # ring = PolyRing('x,y,z', False) # reinitialize ring with updated numberfield a0, a1, a2, a3 = ring.root_gens() # a0=(1-I*sqrt(3)) with conjugate a0-1 and minimal polynomial t^2-t+1 # we compute candidate classes of circles # h = Div.new('4e0-e1-e2-e3-e4-e5-e6-e7-e8') div_lst = get_divs(h, 2, -2, False) + get_divs(h, 2, -1, False) NSTools.p('Classes of circles up to permutation:') for c in div_lst: NSTools.p('\t\t', c) # We recover the preimages of circles in the Roman surface # under the map p_lst, by constructing for each candidate # class the corresponding linear series. # 2e0-e1-e2-e3-e4-e5-e6-e7-e8 b = [(a0 - 1, -a0), (-a0, a0 - 1)] b += [(-a0 + 1, a0), (a0, -a0 + 1)] b += [(a0 - 1, a0), (-a0, -a0 + 1)] b += [(-a0 + 1, -a0), (a0, a0 - 1)] bp_tree = BasePointTree() for i in range(6): bp_tree.add('z', b[i], 1) NSTools.p('basepoints =', b) NSTools.p(LinearSeries.get([2], bp_tree)) # e0-e1-e2 b = [(a0 - 1, -a0), (-a0, a0 - 1)] bp_tree = BasePointTree() bp = bp_tree.add('z', b[0], 1) bp = bp_tree.add('z', b[1], 1) NSTools.p('basepoints =', b) NSTools.p(LinearSeries.get([1], bp_tree)) # e0-e3-e4 b = [(-a0 + 1, a0), (a0, -a0 + 1)] bp_tree = BasePointTree() bp = bp_tree.add('z', b[0], 1) bp = bp_tree.add('z', b[1], 1) NSTools.p('basepoints =', b) NSTools.p(LinearSeries.get([1], bp_tree)) # e0-e5-e6 b = [(a0 - 1, a0), (-a0, -a0 + 1)] bp_tree = BasePointTree() bp = bp_tree.add('z', b[0], 1) bp = bp_tree.add('z', b[1], 1) NSTools.p('basepoints =', b) NSTools.p(LinearSeries.get([1], bp_tree)) # e0-e7-e8 b = [(-a0 + 1, -a0), (a0, a0 - 1)] bp_tree = BasePointTree() bp = bp_tree.add('z', b[0], 1) bp = bp_tree.add('z', b[1], 1) NSTools.p('basepoints =', b) NSTools.p(LinearSeries.get([1], bp_tree)) return
def get_divs(d, dc, cc, perm=False): ''' Computes divisors in unimodular lattice with prescribed intersection product. Parameters ---------- d : Div object d0*e0 + d1*e1 +...+ dr*er such that * product signature equals (1,d.rank()-1) * d0>0 * d1,...,dr<=0 dc : int A positive integer. cc : int Self intersection. perm : boolean If True, then generators are permuted. Returns ------- list<Div> Returns a sorted list of "Div" objects * c = c0*e0 + c1*e1 +...+ cr*er such that * d.rank() == r+1 * dc == d*c (signature = (1,rank-1)) * cc == c*c (signature = (1,rank-1)) and each Div object satisfies exactly one of the following conditions: * c == ei - ej for 0>i>j>=r, * c == ei for i>0, or * c0 > 0, c1,...,cr <= 0 If "perm" is False, then then only one representative for each c is returned up to permutation of ei for i>0. For example, e0-e1-e2 and e0-e1-e3 are considered equivalent, and only e0-e1-e2 is returned, since e0-e1-e2>e0-e1-e3 (see "get_div_set()" for the ordering). In particular, c1 >= c2 >= ... >= cr. Note ---- If d=[3]+8*[-1], (dc,cc)==(0,-2) and perm=False then the Div classes are '12', '1123', '212' and '308'. See "Div.get_label()" for the notation. These classes correspond to the (-2)-classes in the Neron-Severi lattice associated to a weak del Pezzo surface. If perm==False then only one representative for each q is returned up to permutation of ei for i>0. For example, e0-e1-e2 and e0-e1-e3 are considered equivalent, and only e0-e1-e2 is returned, since e0-e1-e2>e0-e1-e3 (see "Div.__lt__()" for the ordering). ''' # check if input was already computed # key = 'get_divs_' + str((d, dc, cc, perm)) if key in NSTools.get_tool_dct(): return NSTools.get_tool_dct()[key] # construct div set # NSTools.p('Constructing div set classes for ', (d, dc, cc, perm)) out_lst = [] # compute classes of the form ei or ei-ej for i,j>0 # if (dc, cc) == (1, -1) or (dc, cc) == (0, -2): m2_lst = [] # list of divisors of the form ei-ej for i,j>0 m1_lst = [] # list of divisors of the form ei for i>0 if perm: # Example: # >>> list(Combinations( [1,2,3,4], 2 )) # [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] # Notice that r=d.rank()-1 if c = c0*e0 + c1*e1 +...+ cr*er. # for comb in sage_Combinations(range(1, d.rank()), 2): m2_lst += [Div.new(str(comb[0]) + str(comb[1]), d.rank())] m1_lst += [ Div.new('e' + str(i), d.rank()) for i in range(1, d.rank()) ] else: # up to permutation of the generators # we may assume that i==1 and j==2. # m2_lst += [Div.new('12', d.rank())] m1_lst += [Div.new('e1', d.rank())] # add the classes that satisfy return # specification to the output list # for c in m1_lst + m2_lst: if (dc, cc) == (d * c, c * c): out_lst += [c] # # Note: cc = c0^2 - c1^2 -...- cr^2 # c0 = 0 cur_eq_diff = -1 while True: c0 = c0 + 1 dc_tail = d[0] * c0 - dc # = d1*c1 +...+ dr*cr dd_tail = d[0]**2 - d * d # = d1^2 +...+ dr^2 cc_tail = c0**2 - cc # = c1^2 +...+ cr^2 # not possible according to io-specs. # if dc_tail < 0 or dd_tail < 0 or cc_tail < 0: NSTools.p('continue... (c0, dc_tail, dd_tail, cc_tail) =', (c0, dc_tail, dd_tail, cc_tail)) if dd_tail < 0: raise Exception('dd_tail =', dd_tail) continue # Cauchy-Schwarz inequality <x,y>^2 <= <x,x>*<y,y> holds? # prv_eq_diff = cur_eq_diff cur_eq_diff = abs(dc_tail * dc_tail - dd_tail * cc_tail) if prv_eq_diff == -1: prv_eq_diff = cur_eq_diff NSTools.p('prv_eq_diff =', prv_eq_diff, ', cur_eq_diff =', cur_eq_diff, ', dc_tail^2 =', dc_tail * dc_tail, ', dd_tail*cc_tail =', dd_tail * cc_tail, ', (c0, dc_tail, dd_tail, cc_tail) =', (c0, dc_tail, dd_tail, cc_tail)) if prv_eq_diff < cur_eq_diff and dc_tail * dc_tail > dd_tail * cc_tail: NSTools.p('stop by Cauchy-Schwarz inequality...') break # out of while loop # obtain all possible [d1*c1+1,...,dr*cr+1] # r = d.rank() - 1 if perm and len(set(d[1:])) != 1: p_lst_lst = sage_Compositions(dc_tail + r, length=r) else: p_lst_lst = sage_Partitions(dc_tail + r, length=r) # data for ETA computation total = len(p_lst_lst) counter = 0 ival = 5000 # obtain [c1,...,cr] from [d1*c1+1,...,dr*cr+1] # for p_lst in p_lst_lst: # ETA if counter % ival == 0: start = time.time() counter += 1 if counter % ival == 0: passed_time = time.time() - start NSTools.p('ETA in minutes =', passed_time * (total - counter) / (ival * 60), ' (', counter, '/', total, '), c0 =', c0, ', prv_eq_diff =', prv_eq_diff, ', cur_eq_diff =', cur_eq_diff) # dc_tail=d1*c1 +...+ dr*cr = p1 +...+ pr with pi>=0 p_lst = [p - 1 for p in p_lst] # obtain c_tail=[c1,...,cr] from [p1,...,pr] valid_part = True c_tail = [] # =[c1,...,cr] for i in range(0, len(p_lst)): if p_lst[i] == 0 or d[i + 1] == 0: c_tail += [p_lst[i]] else: quo, rem = sage_ZZ(p_lst[i]).quo_rem(d[i + 1]) if rem != 0: valid_part = False break # out of i-for-loop else: c_tail += [quo] if not valid_part: continue # add to out list if valid # c = Div([c0] + c_tail) if c.rank() == d.rank() and (dc, cc) == (d * c, c * c): if perm and len(set(d[1:])) == 1: # since d1==...==dr we do not have to # check each permutation. for pc_tail in sage_Permutations(c_tail): out_lst += [Div([c0] + list(pc_tail))] else: out_lst += [c] # sort list of "Div" objects out_lst.sort() # cache output NSTools.get_tool_dct()[key] = out_lst NSTools.save_tool_dct() return out_lst
def cls_to_tex(): ''' Create tex code for the output of DPLattice.get_cls() Returns ------- string A string representing a table of tables in Tex format. The table represent the classification of Neron-Severi lattice of weak del Pezzo surfaces. ''' # create a list of occuring divisors # div_lst = [] for rank in range(3, 9 + 1): for dpl in DPLattice.get_cls(rank): # construct list for involution (e0,...,er)|-->(i0,...,ir) i_lst = [ Div(row).mat_mul(dpl.M) for row in sage_identity_matrix(rank) ] # add each divisor that occurs to div_lst for elt in i_lst + dpl.d_lst: div_lst += [Div(elt.e_lst + (9 - len(elt.e_lst)) * [0])] div_lst = list(set(div_lst)) div_lst.sort() e0 = Div([1, 0, 0, 0, 0, 0, 0, 0, 0]) div_lst.remove(e0) div_lst = [e0] + div_lst # create dictionary characters for elements in div_lst # abc = 'abcdefghijklmnopqrstuvwxyz' ch_lst = [] ch_lst += [ '\\frac{' + ch1 + '}{' + ch2 + '}\\!' for ch1 in '0123456789' for ch2 in '0123456789' ] ch_lst += [ '\\frac{' + ch1 + '}{' + ch2 + '}\\!' for ch1 in '0123456789' for ch2 in 'abcdef' ] NSTools.p('(len(ch_lst), len(div_lst)) =', (len(ch_lst), len(div_lst))) assert len(ch_lst) >= len(div_lst) # create legend and dictionary # lgd_lst = [] sym_dct = {} for i in range(len(div_lst)): sym_dct.update({str(div_lst[i]): ch_lst[i]}) lgd_lst += [[ '$' + ch_lst[i] + '$ :', ('$' + str(div_lst[i]) + '$').replace('e', 'e_') ]] while len(lgd_lst) % 3 != 0: lgd_lst += [['', '']] nnrows = len(lgd_lst) / 3 # create tex for legend # tex_lgd = '' tex_lgd += '\\begin{table}\n' tex_lgd += '\\setstretch{1.4}\n' tex_lgd += '\\tiny\n' tex_lgd += '\\caption{Classification of Neron-Severi lattices of weak del Pezzo surfaces (see THM{nsl})}\n' tex_lgd += '\\label{tab:nsl}\n' tex_lgd += 'A dictionary for symbols in the columns $\\sigma_A$ and $B$:\n\\\\\n' tex_lgd += '\\begin{tabular}{@{}l@{}l@{~~~~}l@{}l@{~~~~}l@{}l@{}}\n' for idx in range(nnrows): c1, c2, c3, c4, c5, c6 = lgd_lst[idx] + lgd_lst[ idx + nnrows] + lgd_lst[idx + 2 * nnrows] tex_lgd += c1 + ' & ' + c2 + ' & ' + c3 + ' & ' + c4 + ' & ' + c5 + ' & ' + c6 tex_lgd += '\\\\\n' tex_lgd += '\\end{tabular}\n' tex_lgd += '\\end{table}\n\n' # number of rows of the big table # nrows = 57 # dictionary for replacing string symbols # rep_dct = { 'A': 'A_', 'D': 'D_', 'E': 'E_', '{': '\\underline{', '[': '\\udot{', ']': '}' } # create classification table # tab_lst = [] # rank 1 and 2 tab9 = [['i ', '$9$', "$A_0 $", '$A_0$', '$0$', '$1$', '']] tab8 = [['ii ', '$8$', "$A_0 $", '$A_0$', '$0$', '$2$', ''], ['iii', '$8$', "$A_0 $", '$A_0$', '$0$', '$1$', ''], ['iv ', '$8$', "$A_0 $", '$A_0$', '$1$', '$1$', ''], ['v ', '$8$', "$A_0 $", '$A_1$', '$0$', '$1$', '']] tab_lst += [tab9, tab8] # rank 3,4,5,6,7,8 and 9 idx = 0 Mtype_lst = ['A1', '4A1'] # for breaking up table for degree 2 case for rank in range(3, 9 + 1): tab = [] for dpl in DPLattice.get_cls(rank): col1 = '$' + str(idx) + '$' col2 = '$' + str(dpl.get_degree()) + '$' col3 = '$' + str(dpl.get_marked_Mtype()) + '$' for key in rep_dct: col3 = str(col3).replace(key, rep_dct[key]) col4 = '$' + str(dpl.get_real_type()) + '$' for key in rep_dct: col4 = str(col4).replace(key, rep_dct[key]) col5 = '$' + str(dpl.get_numbers()[4]) + '$' col6 = '$' + str(dpl.get_numbers()[5]) + '$' i_lst = [ str(Div(rw).mat_mul(dpl.M)) for rw in sage_identity_matrix(rank) ] col7 = '' for i in i_lst: col7 += sym_dct[i] if col7 in [ '012', '0123', '01234', '012345', '0123456', '01234567', '012345678' ]: col7 = '' col8 = '' for d in dpl.d_lst: col8 += sym_dct[str(d)] # these subroot systems cannot be realized as weak del Pezzo surfaces if col4 in [ '$7\underline{A_1}$', '$8\underline{A_1}$', '$4\underline{A_1}+\underline{D_4}$' ]: col1 = '$\\times$' # break (sometimes) the table for degree 2 according to Mtype if dpl.get_degree() == 2 and dpl.Mtype in Mtype_lst: nheaders = len( tab) / nrows # each header shifts the row number while len( tab ) % nrows != nrows - 1 - nheaders: # add rows until end of table tab += [7 * ['']] Mtype_lst.remove(dpl.Mtype) # add row tab += [[ col1, col2, col3, col4, col5, col6, '$' + col7 + '||\!' + col8 + '$' ]] idx += 1 tab_lst += [tab] # reformat table # # i d A B E G Ac%Bc hl = '@{~}l@{~~~}l@{~~~}l@{~~}l@{~~}l@{~~}l@{~~}l@{}' hrow = ['', 'd', '$D(A)$', '$D(B)$', '$\#E$', '$\#G$', '$\sigma_A||B$'] etab_lst = [] etab = [hrow] tab_idx = 0 for tab in tab_lst: for row in tab: if len(etab) >= nrows: etab_lst += [etab] etab = [hrow] etab += [row] if len(etab) < nrows and tab_idx <= 3: etab += [ 7 * [''], 7 * [''] ] # add two empty rows to separate tables with different rank else: while len(etab) < nrows: etab += [7 * ['']] # add empty rows to fill up table etab_lst += [etab] etab = [hrow] tab_idx += 1 NSTools.p('etab_lst: ', [len(etab) for etab in etab_lst]) # create tex for main classification table # tex_tab = '' tab_idx = 0 for etab in etab_lst: if tab_idx % 2 == 0: tex_tab += '\\begin{table}\n' tex_tab += '\\setstretch{1.6}\n' tex_tab += '\\centering\\tiny\n' tex_tab += '\\begin{tabular}{@{}l@{\\hspace{1cm}}l@{}}\n' elif tab_idx % 2 == 1: tex_tab += '&\n' tex_tab += '\\begin{tabular}{' + hl + '}\n' for row in etab: col1, col2, col3, col4, col5, col6, col78 = row tex_tab += col1 + ' & ' + col2 + ' & ' + col3 + ' & ' + col4 + ' & ' tex_tab += col5 + ' & ' + col6 + ' & ' + col78 tex_tab += ' \\\\\n' if row == hrow: tex_tab += '\\hline\n' tex_tab += '\\end{tabular}\n' if tab_idx % 2 == 1: tex_tab += '\\end{tabular}\n' tex_tab += '\\end{table}\n\n' tab_idx += 1 if tab_idx % 2 == 1: tex_tab += '&\n' tex_tab += '\\end{tabular}\n\n' # creating tex for commands tex_cmd = '' tex_cmd += '\\newcommand{\\udot}[1]{\\tikz[baseline=(todotted.base)]{\\node[inner sep=1pt,outer sep=0pt] (todotted) {$#1$};\\draw[densely dotted] (todotted.south west) -- (todotted.south east);}}' tex_cmd += '\n' tex_cmd += '\\newcommand{\\udash}[1]{\\tikz[baseline=(todotted.base)]{\\node[inner sep=1pt,outer sep=0pt] (todotted) {$#1$};\\draw[densely dashed] (todotted.south west) -- (todotted.south east);}}' tex_cmd += '\n\n' out = tex_cmd + tex_lgd + tex_tab return out
def get_bas_lst(rank=9): ''' See [Algorithm 5, http://arxiv.org/abs/1302.6678] for more info. Parameters ---------- rank : int An integer in [3,...,9]. Returns ------- list<DPLattice> A list of "DPLattice" objects dpl such that dpl.d_lst is the bases of a root subsystem and dpl.Mtype == A0. The list contains exactly one representative for all root subsystems up to equivalence. The list represents a classification of root subsystems of the root system with Dynkin type either: A1, A1+A2, A4, D5, E6, E7 or E8, corresponding to ranks 3, 4, 5, 6, 7, 8 and 9 respectively (eg. A1+A2 if rank equals 4, and E8 if rank equals 9). Note that the root systems live in a subspace of the vector space associated to the Neron-Severi lattice of a weak Del Pezzo surface. ''' # check whether classification of root bases is in cache key = 'get_bas_lst__' + str(rank) if key in NSTools.get_tool_dct(): return NSTools.get_tool_dct()[key] NSTools.p('start') A = [12, 23, 34, 45, 56, 67, 78] B = [1123, 1145, 1456, 1567, 1678, 278] C = [1127, 1347, 1567, 234, 278, 308] D = [1123, 1345, 1156, 1258, 1367, 1247, 1468, 1178] dpl_lst = [] for (lst1, lst2) in [(A, []), (A, B), (A, C), ([], D)]: # restrict to divisors in list, that are of rank at most "max_rank" lst1 = [ Div.new(str(e), rank) for e in lst1 if rank >= Div.get_min_rank(str(e)) ] lst2 = [ Div.new(str(e), rank) for e in lst2 if rank >= Div.get_min_rank(str(e)) ] # the involution is trivial Md_lst = [] M = sage_identity_matrix(sage_QQ, rank) # loop through the lists sub1 = sage_Subsets(range(len(lst1))) sub2 = sage_Subsets(range(len(lst2))) eta = ETA(len(sub1) * len(sub2), 20) for idx2_lst in sub2: for idx1_lst in sub1: eta.update('get_bas_lst rank =', rank) d_lst = [lst1[idx1] for idx1 in idx1_lst] d_lst += [lst2[idx2] for idx2 in idx2_lst] if not is_root_basis(d_lst): continue dpl = DPLattice(d_lst, Md_lst, M) if dpl not in dpl_lst: dpl.set_attributes() dpl_lst += [dpl] # cache output dpl_lst.sort() NSTools.get_tool_dct()[key] = dpl_lst NSTools.save_tool_dct() return dpl_lst
def get_cls(rank=9): ''' Parameters ---------- rank : int An integer in [1,...,9]. Returns ------- list<DPLattice> A list of DPLattice objects corresponding to Neron-Severi lattices of weak Del Pezzo surfaces of degree (10-rank). The list contains exactly one representative for each equivalence class. All the Div objects referenced in the DPLattice objects of the output have the default intersection matrix: diagonal matrix with diagonal: (1,-1,...,-1). If rank<3 then the empty list is returned. ''' if rank < 3: return [] # check cache key = 'get_cls_' + str(rank) if key in NSTools.get_tool_dct(): return NSTools.get_tool_dct()[key] NSTools.p('rank =', rank) # collect all lattices with either d_lst==[] of Md_lst==[] bas_lst = DPLattice.get_bas_lst(rank) inv_lst = DPLattice.get_inv_lst(rank) # we loop through all involutions NSTools.p('start looping through inv_lst: ', len(inv_lst), [inv.get_marked_Mtype() for inv in inv_lst]) dpl_lst = [] for inv in inv_lst: NSTools.p('looping through inv_lst:', (rank, inv.get_marked_Mtype(), inv.Md_lst)) # recover the known classification if inv.Mtype == 'A0': NSTools.p( 'Since Mtype equals A0 we recover the classification from bas_lst.' ) dpl_lst += [bas for bas in bas_lst] continue # partition the roots into two sets s_lst, q_lst = DPLattice.get_part_roots(inv) # import classification for rank-1 bas1_lst = DPLattice.import_cls(DPLattice.get_cls(rank - 1), inv) NSTools.p( 'looping through inv_lst continued after recursive call:', (rank, inv.get_marked_Mtype(), inv.Md_lst)) # correct partition of roots (bas1_lst always contains inv) if len(bas1_lst) > 1: e = Div.new('e' + str(rank - 1), inv.get_rank()) s_lst = [s for s in s_lst if s * e != 0] q_lst = [q for q in q_lst if q * e != 0] NSTools.p('bas1_lst =', len(bas1_lst), [(bas1.Mtype, bas1.type) for bas1 in bas1_lst]) NSTools.p('s_lst =', len(s_lst), s_lst) NSTools.p('q_lst =', len(q_lst), q_lst) # collect all possible root bases in s_lst and q_lst bas2_lst = [] bas3_lst = [] visited_type_lst = [] eta = ETA(len(bas_lst), 1) for bas in bas_lst: # display progress info eta.update('get_cls seeking bases in s_lst and q_lst: ', (rank, inv.get_marked_Mtype(), bas.get_real_type())) # each type in bas_lst is treated only once if bas.type in visited_type_lst: continue visited_type_lst += [bas.type] # collect bases of type bas.type in s_lst if DPLattice.get_num_types(inv, bas, bas_lst) != 0: bas2_lst += DPLattice.seek_bases(inv, bas.d_lst, s_lst) # collect bases of type bas.type in q_lst if 2 * len(bas.d_lst) > rank - 1: continue # the rank of a root subsystem is bounded by rank-1 tmp_lst = DPLattice.seek_bases(inv, bas.d_lst, q_lst) for tmp in tmp_lst: tmp.d_lst += [d.mat_mul(inv.M) for d in tmp.d_lst] if is_root_basis( tmp.d_lst ): # the roots and their involutions might have intersection product 1 tmp.d_lst.sort() bas3_lst += [tmp] # debug info NSTools.p('Setting Dynkin types of', len(bas2_lst + bas3_lst), 'items...please wait...') eta = ETA(len(bas2_lst + bas3_lst), len(bas2_lst + bas3_lst) / 10) for bas in bas2_lst + bas3_lst: bas.type = get_dynkin_type(bas.d_lst) bas.Mtype = get_dynkin_type(bas.Md_lst) eta.update(bas.get_rank(), bas.get_marked_Mtype(), bas.type) bas1_lst.sort() bas2_lst.sort() bas3_lst.sort() t_lst1 = [bas.type for bas in bas1_lst] t_lst2 = [bas.type for bas in bas2_lst] t_lst3 = [bas.type for bas in bas3_lst] lst1 = sorted(list(set([(t, t_lst1.count(t)) for t in t_lst1]))) lst2 = sorted(list(set([(t, t_lst2.count(t)) for t in t_lst2]))) lst3 = sorted(list(set([(t, t_lst3.count(t)) for t in t_lst3]))) NSTools.p('inv =', inv.get_marked_Mtype(), ', rank =', rank) NSTools.p('bas1_lst =', len(bas1_lst), lst1) NSTools.p('bas2_lst =', len(bas2_lst), lst2) NSTools.p('bas3_lst =', len(bas3_lst), lst3) # construct a list of combinations of DPLattice objects in bas1_lst bas2_lst and comb_lst = [] total = len(bas1_lst) * len(bas2_lst) * len(bas3_lst) step = total / 10 if total > 10 else total eta = ETA(total, step) for bas1 in bas1_lst: for bas2 in bas2_lst: for bas3 in bas3_lst: eta.update( 'last loop in get_cls: ( bas1.type, bas2.type, bas3.type )=', (bas1.type, bas2.type, bas3.type)) d_lst = bas1.d_lst + bas2.d_lst + bas3.d_lst # notice that d_lst can be equal to [] if len(d_lst) > rank - 1: continue # the rank of a root subsystem is bounded by rank-1 if is_root_basis(d_lst): dpl = DPLattice(d_lst, inv.Md_lst, inv.M) if dpl not in dpl_lst: dpl.set_attributes() dpl_lst += [dpl] NSTools.p( '\t appended: ', (rank, dpl.get_marked_Mtype(), dpl.get_real_type()), ', ( bas1.type, bas2.type, bas3.type ) =', (bas1.type, bas2.type, bas3.type)) # store in cache # dpl_lst.sort() NSTools.get_tool_dct()[key] = dpl_lst NSTools.save_tool_dct() return dpl_lst