def get_S1xS1_pmz(xyvw_pmz_lst): ''' Attributes ---------- xyvw_pmz_lst: list<sage_POLY> A list of bi-homogeneous polynomials in QQ[x,y;v,w] that represent a parametric map P^1xP^1 ---> P^n. Returns ------- list<sage_POLY> Returns a list of polynomials in QQ[c0,s0,s1,c1] / <c0^2+s0^2-1,c1^2+s1^2-1> that represents the composition of the input parametric map with a birational map: S^1xS^1 ---> P^1xP^1 (1:c0:s0)x(1:c1:s1) |--> (1-s0:c0)x(1-s1:c1) ''' R = sage_PolynomialRing(sage_QQ, 'x,y,v,w') x, y, v, w = R.gens() xyvw_pmz_lst = sage__eval(str(xyvw_pmz_lst), R.gens_dict()) c0, s0, c1, s1 = OrbRing.coerce('c0,s0,c1,s1') sub_dct = {x: 1 - s0, y: c0, v: 1 - s1, w: c1} pmz_lst = [ OrbRing.coerce(xyvw_pmz.subs(sub_dct)) for xyvw_pmz in xyvw_pmz_lst ] return pmz_lst
def approx_QQ(mat): ''' Computes a matrix over QQ that approximates the input matrix "mat" over algebraic closure of the rationals QQbar. Attributes ---------- mat: sage_matrix<QQbar> A matrix defined over QQbar. close_exact: bool Returns ------- sage_matrix<QQ> An approximation of the iput matrix over QQ. ''' # compute rational approximation of U # A = [] for row in list(mat): for col in row: tmp = sage__eval(str(col).replace('?', '')) if tmp in sage_QQ: A += [tmp] else: A += [tmp.simplest_rational()] return sage_matrix(sage_QQ, mat.nrows(), mat.ncols(), A)
def coerce_ff( self, elt ): ''' Some symbolic methods in sage are not available in the polynomial ring over a number field, but are available in the polynomial ring over a fraction field. INPUT: - "elt" -- String of an symbolic expression with polynomials in "self.pol_ring". OUTPUT: - Elements in a polynomial ring R with generators "self.gens()". The ground field of R is the fraction field of a polynomial ring whose generators corresponds to the roots in the number field "PolyRing.num_field". For example R=FF[x,y,z] where FF=FractionField( QQ[a0,a1,a2,a3] ). ''' eval_dct = {} # construct fraction field FF FF = sage_QQ if PolyRing.num_field != sage_QQ: ngens = PolyRing.num_field.gens_dict().keys() # (a0,a1,...) FF = sage_FractionField( sage_PolynomialRing( sage_QQ, ngens ) ) eval_dct.update( FF.gens_dict() ) # construct polynomial ring R over FF pgens = self.pol_ring.gens_dict().keys() R = sage_PolynomialRing( FF, pgens ) eval_dct.update( R.gens_dict() ) # coerce "elt" to R return sage__eval( str( elt ), eval_dct )
def coerce( self, elt ): ''' INPUT: - "elt" -- A string of a list of polynomials in "self.pol_ring". OUTPUT: - Coerces the string "elt" to an element of "self.pol_ring". ''' return sage__eval( str( elt ), self.ring_dct )
def get_implicit_image(ls): ''' INPUT: - "ls" -- LinearSeries object. Elements in "ls.pol_lst" should be homogeneous polynomials over QQ. These polynomials represent a map F between projective spaces. We assume that the polynomials are co-prime. OUTPUT - A list of polynomials in QQ[x0,...,xn]. These polynomials represent the ideal of the image of the map F in projective n-space, where n is "len(ls.pol_lst)-1". This method might not terminate within reasonable time. ''' # QQ[x0,...,xn] vx_lst = ['x' + str(i) for i in range(len(ls.pol_lst))] ring = sage_PolynomialRing(sage_QQ, vx_lst + list(ls.ring.gens())) x_lst = ring.gens()[0:len(vx_lst)] v_lst = ring.gens()[len(vx_lst):] # coerce "ls.pol_lst"" p_lst = [sage__eval(str(pol), ring.gens_dict()) for pol in ls.pol_lst] # construct ideal s_lst = [x_lst[i] - p_lst[i] for i in range(len(p_lst))] s_ideal = ring.ideal(s_lst) LSTools.p(len(s_lst), s_lst) # eliminate all variables except for the xi's e_lst = list(s_ideal.elimination_ideal(v_lst).gens()) LSTools.p(len(e_lst), e_lst) # test dct = {x_lst[i]: p_lst[i] for i in range(len(p_lst))} r_lst = [e.subs(dct) for e in e_lst] LSTools.p('test:', sum(r_lst) == 0) return e_lst
def hilbert_poly(X, base=sage_QQ): ''' Computes the Hilbert polynomial of an ideal. Parameters ---------- X : string(sage_POLY) A polynomial in the variables x=(x0,...,xn) or y=(y0,...,yn). base : sage_RING Ground field of polynomials. Returns ------- sage_POLY Hilbert polynomial of ideal. ''' # make sure that the input are strings X = str(X) # if the input are polynomials in x then the output # is a list of poynomials in y (vx, vy) = ('x', 'y') if 'x' in X else ('y', 'x') # detect the number of x-variables occurring n_lst = [] n = 0 while n < 50: if vx + str(n) in X: n_lst += [n] n = n + 1 n = max(n_lst) x_lst = [vx + str(i) for i in range(n + 1)] ring = sage_PolynomialRing(base, x_lst) x_lst = ring.gens() dct = ring_dict(ring) X = sage__eval(X, dct) return sage_ideal(X).hilbert_polynomial()
def get_deg_surf(imp_lst, emb_dim): ''' Attributes ---------- imp_lst: list<sage_POLY> A list of polynomials in QQ[x0,...,xn] defining a surface where n==emb_dim. emb_dim: int A non-negative integer, representing the embedding dimension. Returns ------- Degree of surface defined by "imp_lst". ''' ring = sage_PolynomialRing(sage_QQ, ['x' + str(i) for i in range(emb_dim + 1)]) imp_lst = sage__eval(str(imp_lst), ring.gens_dict()) hpol = ring.ideal(imp_lst).hilbert_polynomial() return hpol.diff().diff()
def coerce_sr( self, elt ): ''' Some symbolic methods in sage are not available in the polynomial ring over a number field, but are available in the "SymbolicRing" of Sage. INPUT: - "elt" -- String of expression with polynomials in "self.pol_ring". OUTPUT: - Elements in the "SymbolicRing" of Sage. This can be seen as a polynomial ring over QQ where generators correspond to the roots in "PolyRing.num_field" and "self.gens()". For example: QQ[a0,a1,a2,x,y,z]. ''' # construct dictionary for "sage_eval" sym_dct = self.ring_dct.copy() for key in sym_dct.keys(): sym_dct[key] = sage_SR( str( sym_dct[key] ) ) # SR = Symbolic Ring # coerce "elt" to symbolic ring return sage__eval( str( elt ), sym_dct )
def usecase__neron_severi_lattice(): ''' Compute NS-lattice of a linear series and the dimension of complete linear with base points. ''' # Blowup of projective plane in 3 colinear points # and 2 infinitly 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) LSTools.p('ls = ', ls) LSTools.p(ls.get_bp_tree(), '\n\n ', ls.get_implicit_image()) # Detects that 3 base points lie on a line. # bp_tree = BasePointTree() bp_tree.add('z', p1, 1) bp_tree.add('z', p2, 1) bp_tree.add('z', p3, 1) ls123 = LinearSeries.get([1], bp_tree) LSTools.p('ls123 =', ls123) assert ls123.pol_lst == ring.coerce('[y]') # example of infinitly near base points # that is colinear with another simple base point. # bp_tree = BasePointTree() bp_tree.add('z', p1, 1) bp = bp_tree.add('z', p4, 1) bp.add('t', (1, 0), 1) ls1 = LinearSeries.get([1], bp_tree) LSTools.p('ls1 =', ls1) assert ls1.pol_lst == ring.coerce('[x-y+z]') # Detects that an infinitly near base points # is not colinear with other point. # for p in [p1, p2, p3]: bp_tree = BasePointTree() bp = bp_tree.add('z', p4, 1) bp.add('t', p5, 1) bp_tree.add('z', p, 1) ls45i = LinearSeries.get([1], bp_tree) assert ls45i.pol_lst == [] # line with predefined tangent # bp_tree = BasePointTree() bp = bp_tree.add('z', p4, 1) bp.add('t', p5, 1) ls45 = LinearSeries.get([1], bp_tree) LSTools.p('ls45 =', ls45) assert ls45.pol_lst == ring.coerce('[x-2*y+2*z]') # class of conics through 5 basepoints # 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) ls1234 = LinearSeries.get([2], bp_tree) LSTools.p('ls1234 =', ls1234) LSTools.p('\t\t', sage_factor(ls1234.pol_lst[0])) assert ring.coerce('(x - 2*y + 2*z, 1)') in ring.aux_gcd(ls1234.pol_lst)[0] assert ring.coerce('(y, 1)') in ring.aux_gcd(ls1234.pol_lst)[0] # class of conics through 4 basepoints # has a fixed component # bp_tree = BasePointTree() bp_tree.add('z', p4, 1) ls4 = LinearSeries.get([1], bp_tree) LSTools.p('ls4 =', ls4) bp_tree = BasePointTree() bp_tree.add('z', p1, 1) bp_tree.add('z', p2, 1) bp_tree.add('z', p3, 1) bp_tree.add('z', p4, 1) ls1234 = LinearSeries.get([2], bp_tree) LSTools.p('ls1234 =', ls1234) # return # Compose map associated to linear series "ls" # with the inverse stereographic projection "Pinv". # R = sage_PolynomialRing(sage_QQ, 'y0,y1,y2,y3,y4,x,y,z') y0, y1, y2, y3, y4, x, y, z = R.gens() delta = y1**2 + y2**2 + y3**2 + y4**2 Pinv = [ y0**2 + delta, 2 * y0 * y1, 2 * y0 * y2, 2 * y0 * y3, 2 * y0 * y4, -y0**2 + delta ] H = sage__eval(str(ls.pol_lst), R.gens_dict()) PinvH = [ elt.subs({ y0: H[0], y1: H[1], y2: H[2], y3: H[3], y4: H[4] }) for elt in Pinv ] LSTools.p('Pinv =', Pinv) LSTools.p('H =', H) LSTools.p('Pinv o H =', PinvH) # In order to compute the NS-lattice of the image # of "PinvH" we do a base point analysis. # ls_PinvH = LinearSeries([str(elt) for elt in PinvH], ring) LSTools.p('ls_PinvH =', ls_PinvH) LSTools.p('\t\t', ls_PinvH.get_implicit_image()) if False: # takes a long time LSTools.p(ls_PinvH.get_bp_tree())
def get_linear_series(deg_lst, bp_tree): ''' INPUT: - "deg_lst" -- A list of either one or two integers representing the degree of polynomials. - "bp_tree" -- BasePointTree where base points might be in overlapping charts. We require that "bp_tree.chart_lst" equals either ['z', 'x', 'y'] or ['xv', 'xw', 'yv', 'yw']. OUTPUT: - Return A LinearSeries "ls" with base points defined by "bp_tree". The polynomials in "ls.pol_lst" are either * homogeneous in (x:y:z) and of degree "deg_tup[0]" or * bi-homogenous in (x:y)(v:w) and of bi-degree ("deg_tup[0]","deg_tup[1]") Note that there might unassigned base points. ''' # # Obtain generators of polynomial ring from "bp_tree.chart_lst" # Note that for initializing PolyRing, it is important that the # base field is not reset to the rationals QQ. The input "bp_tree" # could already be defined over some extension field. # if bp_tree.chart_lst == ['z', 'x', 'y']: ring = PolyRing('x,y,z', False) elif bp_tree.chart_lst == ['xv', 'xw', 'yv', 'yw']: ring = PolyRing('x,y,v,w', False) else: raise ValueError('Expect "bp_tree.chart_lst" in ', (['z', 'x', 'y'], ['xv', 'xw', 'yv', 'yw'])) # # Obtain linear series defined by # monomials of degree "deg_lst[0]" or bidegree ("deg_lst[0]","deg_lst[1]"). # mon_lst = get_mon_lst(deg_lst, ring.gens()) LSTools.p('mon_lst =', mon_lst) ls = class_linear_series.LinearSeries(mon_lst, ring) # # For each chart "c" we obtain a list of linear series. # ls_lst = [] for c in bp_tree.chart_lst: ls_lst += get_ls_lst(ls.copy().chart(c), bp_tree[c]) # # Create matrix whose coefficients are obtained # by evaluating each polynomial in linear series # in "ls_lst" at (0,0). # row_lst = [] for ls in ls_lst: LSTools.p(ls) for g in ls.ring.gens(): ls.subs({g: 0}) row = sage__eval(str(ls.pol_lst), PolyRing.num_field.gens_dict()) row_lst += [row] LSTools.p('matrix =', row_lst) # # Compute kernel. # kern = list(sage_matrix(row_lst).right_kernel().matrix()) LSTools.p('kernel =', kern) LSTools.p(mon_lst) # # Obtain linear series from linear conditions on "mon_lst". # if kern != []: mon_lst = ring.coerce(mon_lst) # update w.r.t. PolyRing.num_field kern = ring.coerce(kern) pol_lst = sage_matrix(kern) * sage_vector(mon_lst) else: pol_lst = [] LSTools.p(pol_lst) return class_linear_series.LinearSeries(pol_lst, ring)
def invert_map(f, X, base=sage_QQ): ''' Computes the inverse of a map defined by polynomials. If the parameters f and X are not strings, then they are automatically converted to strings. Parameters ---------- f : string(list<sage_POLY>) A string of a list of m+1 polynomials in x=(x0,...,xn) or y=(y0,...,yn) with n<=50 that define a projective map: F: X ---> P^m where P^m denotes projective n-space. X : string(list<sage_POLY>) A string of a list of polynomials in the same variables as parameter f that define the ideal of a variety X in projective space. base : sage_RING Ground field of polynomials. Returns ------- list<sage_POLY> Suppose that the input were polynomials in x. The output is of the form [ p0(x)-r0(y) ,..., pn(x)-rn(y) ] were ri(y) are rational functions and pi(x) are polynomials. If f is a birational map, then pi(x)=xi. The polynomials live in the polynomial ring R[x] where R=B(y) and base ring B is defined by the base parameter. ''' # make sure that the input are strings f = str(f) X = str(X) # if the input are polynomials in x then the output # is a list of poynomials in y (vx, vy) = ('x', 'y') if 'x' in f else ('y', 'x') # detect the number of x-variables occurring n_lst = [] n = 0 while n < 50: if vx + str(n) in f or vx + str(n) in X: n_lst += [n] n = n + 1 n = max(n_lst) # construct ring B(y0,...ym)[x0,...,xn] # over fraction field B(y0,...ym) # where m is the number of elements in map f and B equals base # # For example B is rationals sage_QQ so that: # xring = sage_PolynomialRing( sage_QQ, 'x0,x1,x2,x3,x4') # yfield = sage_FractionField( sage_PolynomialRing( sage_QQ, 'y0,y1,y2,y3' ) ) # ring = sage_PolynomialRing( yfield, 'x0,x1,x2,x3,x4') # x_lst = [vx + str(i) for i in range(n + 1)] y_lst = [vy + str(i) for i in range(len(f.split(',')))] yfield = sage_FractionField(sage_PolynomialRing(base, y_lst)) ring = sage_PolynomialRing(yfield, x_lst) y_lst = yfield.gens() x_lst = ring.gens() dct = ring_dict(ring) X = sage__eval(X, dct) f = sage__eval(f, dct) map = [y_lst[i] - f[i] for i in range(len(f))] gb_lst = list(sage_ideal(X + map).groebner_basis()) OrbTools.p(gb_lst) return gb_lst
def euclidean_type_form(X, base=sage_QQ): ''' Outputs the equation of a hypersurface in P^n in a form so that the intersection with the hyperplane at infinity becomes apparent. Parameters ---------- X : string(sage_POLY) A polynomial in the variables x=(x0,...,xn) or y=(y0,...,yn). base : sage_RING Ground field of polynomials. Returns ------- string A string of the equations in the normal form X1 + X2 where X1 = sage_factor( X.subs({x0:0}) ) X2 = sage_factor( X-X1 ) If #variables is equal to 3, then also include the form in x,y and z variables. ''' # make sure that the input are strings X = str(X) # if the input are polynomials in x then the output # is a list of poynomials in y (vx, vy) = ('x', 'y') if 'x' in X else ('y', 'x') # detect the number of x-variables occurring n_lst = [] n = 0 while n < 50: if vx + str(n) in X: n_lst += [n] n = n + 1 n = max(n_lst) x_lst = [vx + str(i) for i in range(n + 1)] ring = sage_PolynomialRing(base, x_lst) x_lst = ring.gens() dct = ring_dict(ring) X = sage__eval(X, dct) XA = sage_factor(X.subs({x_lst[0]: 0})) XB = sage_factor(X - XA) assert X == XA + XB OrbTools.p('X =', XA, '+', XB) out = str(XA) + ' + ' + str(XB) if n == 3: x0, x1, x2, x3 = ring.gens() x, y, z = sage_var('x,y,z') W = X.subs({x1: x, x2: y, x3: z}) WA = W.subs({x0: 0}) WB = W - WA assert W == WA + WB WA = sage_factor(WA.subs({x0: 1})) WB = sage_factor(WB.subs({x0: 1})) OrbTools.p('W =', WA, '+', WB) out += '\n' + str(WA) + ' + ' + str(WB) return out
def compose_maps(g, f, base=sage_QQ): ''' Computes the composition of polynomial maps. Both parameters and return value are all polynomials in either x=(x0,...,xn) or y=(y0,...,yn) with n<=50, but not both. The input parameters are explicitly converted to strings, in case they are not strings. Parameters ---------- f : string(list<sage_POLY>) A string of a list of b+1 polynomials that defines a projective map: f: P^a ---> P^b where P^a denotes projective n-space. If the value is not a string, then it will be converted to a string. g : string(list<sage_POLY>) A string of a list of c+1 polynomials that defines a projective map: g: P^b ---> P^c. If the value is not a string, then it will be converted to a string. base : sage_RING Ground field of polynomials. Returns ------- list<sage_POLY> The composition of the maps f o g: P^a ---> P^c. ''' # make sure that the input are strings g = str(g) f = str(f) # check variables (vf, vg) = ('x', 'y') if 'x' in f else ('y', 'x') if vg not in g: g = g.replace(vf, vg) # detect the number of vf-variables occurring n_lst = [] n = 0 while n < 50: if vf + str(n) in f or vg + str(n) in g: n_lst += [n] n = n + 1 n = max(n_lst) # construct the ring v_lst = [] v_lst += [vf + str(i) for i in range(n + 1)] v_lst += [vg + str(i) for i in range(n + 1)] ring = sage_PolynomialRing(base, v_lst) vg_lst = ring.gens()[n + 1:] dct = ring_dict(ring) g_lst = sage__eval(g, dct) f_lst = sage__eval(f, dct) # compose the maps for i in range(len(f_lst)): g_lst = [g.subs({vg_lst[i]: f_lst[i]}) for g in g_lst] OrbTools.p(g_lst) return g_lst
def preimage_map(f, X, Y, base=sage_QQ): ''' Computes the preimage f^{-1}(Y) of a variety Y under a map f: X ---> P^m, defined by polynomials, where the domain X is a variety and P^m denotes projective space. If the parameters f, X and Y are not strings, then they are automatically converted to strings. Parameters ---------- f : string(list<sage_POLY>) A string of a list of m+1 polynomials in x=(x0,...,xn) or y=(y0,...,yn) with n<=50 that define a projective map: f: X ---> P^m where P^m denotes projective n-space. X : string(list<sage_POLY>) A string of a list of polynomials in the same variables as parameter f that define the ideal of a variety X in projective space. Y : string(list<sage_POLY>) A string of a list of polynomials in y if f consists of polynomials in x (and vice versa). Polynomials define the generators of an ideal of a variety Y in projective space. base : sage_RING Ground field of polynomials. Returns ------- list(list<sage_POLY>) A list of lists of polynomials. Each list of polynomials defines a component in the primary decomposition of the ideal of the preimage f^{-1}(Y). The polynomials are in x or y if parameter f represents polynomials in x respectively y. Note that some of the components in the primary decomposition are not part of the ideal, but correspond to the locus where the map f is not defined. ''' # make sure that the input are strings f = str(f) X = str(X) Y = str(Y) # if the input are polynomials in x then the output # is a list of poynomials in y (vx, vy) = ('x', 'y') if 'x' in f else ('y', 'x') # detect the number of x-variables occurring n_lst = [] n = 0 while n < 50: if vx + str(n) in f or vx + str(n) in X: n_lst += [n] n = n + 1 n = max(n_lst) # construct polynomial ring B[x0,...,xn,y0,...,ym] # where B is given by parameter base. x_lst = [vx + str(i) for i in range(n + 1)] y_lst = [vy + str(i) for i in range(len(f.split(',')))] mord = 'degrevlex' if base == sage_QQ else 'lex' # needed for elimination xyring = sage_PolynomialRing(base, y_lst + x_lst, order=mord) y_lst = xyring.gens()[:len(y_lst)] x_lst = xyring.gens()[len(y_lst):] # coerce into common ring with xi and yi variables dct = ring_dict(xyring) f_lst = sage__eval(f, dct) X_lst = sage__eval(X, dct) Y_lst = sage__eval(Y, dct) mf_lst = [y_lst[i] - f_lst[i] for i in range(len(f_lst))] # compute image by using groebner basis OrbTools.p(X_lst + mf_lst + Y_lst) try: img_id = sage_ideal(X_lst + mf_lst + Y_lst).elimination_ideal(y_lst) img_lst = img_id.primary_decomposition() img_lst = [img.gens() for img in img_lst] OrbTools.p(img_lst) return img_lst except Exception, e: OrbTools.p('Exception occurred:', repr(e)) gb_lst = sage_ideal(X_lst + mf_lst + Y_lst).groebner_basis() OrbTools.p(gb_lst) e_lst = [] for gb in gb_lst: if vy not in str(gb): e_lst += [gb] return e_lst
def image_map(f, X, base=sage_QQ): ''' Computes the image f(X) of a variety X under a map f, defined by polynomials. If the parameters f and X are not strings, then they are automatically converted to strings. Parameters ---------- f : string(list<sage_POLY>) A string of a list of m+1 polynomials in x=(x0,...,xn) or y=(y0,...,yn) with n<=50 that define a projective map: f: X ---> P^m where P^m denotes projective n-space. X : string(list<sage_POLY>) A string of a list of polynomials in the same variables as parameter f that define the ideal of a variety X in projective space. base : sage_RING Ground field of polynomials. Returns ------- list<sage_POLY> A list of polynomials that define the ideal of f(X). The polynomials are in y if the input are polynomials in x, and vice versa. ''' # make sure that the input are strings f = str(f) X = str(X) # if the input are polynomials in x then the output # is a list of poynomials in y (vx, vy) = ('x', 'y') if 'x' in f else ('y', 'x') # detect the number of x-variables occurring n_lst = [] n = 0 while n < 50: if vx + str(n) in f or vx + str(n) in X: n_lst += [n] n = n + 1 n = max(n_lst) # construct polynomial ring B[x0,...,xn,y0,...,ym] # where B is given by parameter base. x_lst = [vx + str(i) for i in range(n + 1)] y_lst = [vy + str(i) for i in range(len(f.split(',')))] mord = 'degrevlex' if base == sage_QQ else 'lexdeg' # needed for elimination xyring = sage_PolynomialRing(base, x_lst + y_lst, mord) x_lst = xyring.gens()[:len(x_lst)] y_lst = xyring.gens()[len(x_lst):] # coerce into common ring with xi and yi variables dct = ring_dict(xyring) f_lst = sage__eval(f, dct) X_lst = sage__eval(X, dct) mf_lst = [y_lst[i] - f_lst[i] for i in range(len(f_lst))] # compute image by using groebner basis OrbTools.p(X_lst + mf_lst) try: # compute image by using groebner basis img_lst = sage_ideal(X_lst + mf_lst).elimination_ideal(x_lst).gens() OrbTools.p(img_lst) return img_lst except Exception, e: OrbTools.p('Exception occurred:', repr(e)) gb_lst = sage_ideal(X_lst + mf_lst).groebner_basis() OrbTools.p(gb_lst) e_lst = [] for gb in gb_lst: if vx not in str(gb): e_lst += [gb] return e_lst
def usecase__linear_normalization__and__adjoint(): ''' In this usecase are some applications of the "linear_series" library. we show by example how to compute a linear normalization X of a surface Y, or equivalently, how to compute the completion of a linear series. Also we contruct an example of a surface Z such that X is its adjoint surface. ''' # # Linear series corresponding to the parametrization # of a cubic surface X in P^4 that is the projection # of the Veronese embedding of P^2 into P^5. # ring = PolyRing('x,y,z', True) bp_tree = BasePointTree() bp = bp_tree.add('z', (0, 0), 1) ls = LinearSeries.get([2], bp_tree) imp_lst = ls.get_implicit_image() LSTools.p('linear series =', ls.get_bp_tree()) LSTools.p('implicit image =', imp_lst) # # compute Hilbert polynomial of X in QQ[x0,...,x6] # R = sage_PolynomialRing(sage_QQ, ['x' + str(i) for i in range(len(ls.pol_lst))]) x_lst = R.gens() imp_lst = sage__eval(str(imp_lst), R.gens_dict()) hpol = R.ideal(imp_lst).hilbert_polynomial() hdeg = hpol.diff().diff() LSTools.p('Hilbert polynomial =', hpol) LSTools.p('implicit degree =', hdeg) # # projection of X in P^4 to Y in P^3, where Y is singular. # ls = LinearSeries(['x^2-x*y', 'x*z', 'y^2', 'y*z'], PolyRing('x,y,z', True)) bp_tree = ls.get_bp_tree() LSTools.p('basepoint tree of projection =', bp_tree) eqn = ls.get_implicit_image() assert len(eqn) == 1 eqn = sage_SR(eqn[0]) x0, x1, x2, x3 = sage_var('x0,x1,x2,x3') LSTools.p('eqn =', eqn) LSTools.p('D(eqn,x0) =', sage_diff(eqn, x0)) LSTools.p('D(eqn,x1) =', sage_diff(eqn, x1)) LSTools.p('D(eqn,x2) =', sage_diff(eqn, x2)) LSTools.p('D(eqn,x3) =', sage_diff(eqn, x3)) # # compute normalization X of Y # ls_norm = LinearSeries.get([2], bp_tree) LSTools.p('normalization = ', ls_norm) LSTools.p(' = ', ls_norm.get_implicit_image()) # # define pre-adjoint surface Z # ring = PolyRing('x,y,z', True) bp_tree = BasePointTree() bp_tree.add('z', (0, 0), 2) bp_tree.add('z', (0, 1), 1) ls = LinearSeries.get([5], bp_tree) LSTools.p(ls.get_bp_tree())
def get_implicit_projection(ls, deg): ''' This function does not work properly, since the output polynomial still contains undeterminate variables. These need to be solved. INPUT: - "ls" -- LinearSeries s.t. "ls.pol_lst" consist of polynomials in x,y,z and of the same degree. Note that the polynomials in "ls.pol_lst" define a birational map from the projective plane to a surface S in projective n-space where n equals "len(ls.pol_lst)-1". - "deg" -- An integer representing the degree of the parametrized surface S. OUTPUT: - A polynomial F(x0:x1:x2:x3) of degree at most "deg" and undetermined coefficients in (r0,r1,...). The ".parent()" of the polynomial is "SymbolicRing". The zero-set V(F) is a projection of the surface S by the map (x0:x1:...:xn) |-> (x0:x1:x2:x3) ''' p0, p1, p2, p3 = ls.pol_lst[0:4] # construct a polynomial ring c_len = len(sage_Compositions(deg + 4, length=4).list()) c_str_lst = ['c' + str(i) for i in range(c_len)] R = sage_PolynomialRing(PolyRing.num_field, ['x0', 'x1', 'x2', 'x3'] + c_str_lst + ['x', 'y', 'z'], order='lex') x0, x1, x2, x3 = R.gens()[0:4] c_lst = R.gens()[4:4 + c_len] x, y, z = R.gens()[4 + c_len:] m_lst = [] for a, b, c, d in sage_Compositions(deg + 4, length=4): m_lst += [x0**(a - 1) * x1**(b - 1) * x2**(c - 1) * x3**(d - 1)] R_dict = R.gens_dict() R_dict.update(PolyRing.num_field.gens_dict()) p0, p1, p2, p3 = sage__eval(str([p0, p1, p2, p3]), R_dict) LSTools.p(R) LSTools.p('m_lst =', m_lst) LSTools.p('(p0, p1, p2, p3) =', (p0, p1, p2, p3)) # construct polynomial in x0, x1, x2 with coefficients in c_lst F = 0 for i in range(len(m_lst)): F += c_lst[i] * m_lst[i] LSTools.p('F =', F) # compute F( p0(x,y,z):...: p3(x,y,z) ) FP = sage_expand(F.subs({ x0: p0, x1: p1, x2: p2, x3: p3 })) # expand to prevent a bug in sage. LSTools.p('FP =', FP) # obtain coefficients w.r.t. x, y and z coef_lst = [] pmzdeg = p0.total_degree() comp_lst = sage_Compositions(deg * pmzdeg + 3, length=3).list() # e.g. [1,1,2]=[0,0,1] LSTools.p('comp_lst =', comp_lst) for comp in comp_lst: coef = FP.coefficient({x: comp[0] - 1, y: comp[1] - 1, z: comp[2] - 1}) coef_lst += [coef] LSTools.p('coef_lst =', coef_lst) # compute groebner basis and reduce F w.r.t. the GB # # alternative code # ---------------- # GB = list( R.ideal( coef_lst ).groebner_basis() ) # LSTools.p( 'GB =', GB ) # red_F = F.reduce( R.ideal( GB ) ) # for g in GB: # red_F = red_F.quo_rem( g )[1] # LSTools.p( 'red_F =', red_F ) # ---------------- # scoef_lst = [sage_SR(coef) for coef in coef_lst] sc_lst = [sage_SR(c) for c in c_lst] sol_lst = sage_solve(scoef_lst, sc_lst, solution_dict=True) LSTools.p(sol_lst) red_F = sage_expand(sage_SR(F).subs(sol_lst[0])) LSTools.p('red_F =', red_F) # check the solutions sp0, sp1, sp2, sp3 = sage_SR(p0), sage_SR(p1), sage_SR(p2), sage_SR(p3) sx0, sx1, sx2, sx3 = sage_SR(x0), sage_SR(x1), sage_SR(x2), sage_SR(x3) chk_F = sage_expand(red_F.subs({sx0: sp0, sx1: sp1, sx2: sp2, sx3: sp3})) LSTools.p('chk_F =', chk_F) if chk_F != 0: warnings.warn('The polynomial red_F(p0:p1:p2:p3) does not vanish.') return red_F
def coerce(expr): return sage__eval(str(expr), OrbRing.R.gens_dict())
def usecase__get_implicit__DP6(): ''' Construct linear series of curves in P^1xP^1, with a given tree of (infinitely near) base points. The defining polynomials of this linear series, correspond to a parametric map of an anticanonical model of a Del Pezzo surface of degree 6 in P^6. Its ideal is generated by quadratic forms. We search for a quadratic form in this ideal of signature (1,6). This quadratic form corresponds to a hyperquadric in P^6, such that the sextic Del Pezzo surface is contained in this hyperquadric. We construct a real projective isomorphism from this hyperquadric to the projectivization of the unit 5-sphere in P^6. ''' # # parametrization of degree 6 del Pezzo surface in projective 6-space. # See ".usecase__get_linear_series__P1P1_DP6()" for the construction of # this linear series. # pmz_lst = [ 'x^2*v^2 - y^2*w^2', 'x^2*v*w + y^2*v*w', 'x^2*w^2 + y^2*w^2', 'x*y*v^2 - y^2*v*w', 'x*y*v*w - y^2*w^2', 'y^2*v*w + x*y*w^2', 'y^2*v^2 + y^2*w^2' ] ls = LinearSeries(pmz_lst, PolyRing('x,y,v,w', True)) # # base points of linear series # bp_tree = ls.get_bp_tree() LSTools.p('parametrization =', ls.pol_lst) LSTools.p('base points =' + str(bp_tree)) # # implicit image in projective 6-space # of map associated to linear series # imp_lst = ls.get_implicit_image() LSTools.p('implicit equations =', imp_lst) # # compute Hilbert polynomial in QQ[x0,...,x6] # ring = sage_PolynomialRing(sage_QQ, ['x' + str(i) for i in range(7)]) x_lst = ring.gens() imp_lst = sage__eval(str(imp_lst), ring.gens_dict()) hpol = ring.ideal(imp_lst).hilbert_polynomial() hdeg = hpol.diff().diff() LSTools.p('Hilbert polynomial =', hpol) LSTools.p('implicit degree =', hdeg) # # equation of unit sphere is not in the ideal # s_pol = sum([-x_lst[0]**2] + [x**2 for x in x_lst[1:]]) LSTools.p('Inside sphere?: ', s_pol in ring.ideal(imp_lst)) # # compute random quadrics containing del Pezzo surface # until a quadric with signature (1,6) is found # or set a precomputed quadric with given "c_lst" # LSTools.p( 'Look for quadric in ideal of signature (1,6)...(may take a while)...') sig = [] while sorted(sig) != [0, 1, 6]: # set coefficient list c_lst = [] c_lst = [-1, -1, 0, 0, 0, -1, 1, 0, -1, -1, -1] # uncomment to speed up execution if c_lst == []: lst = [-1, 0, 1] for imp in imp_lst: idx = int(sage_ZZ.random_element(0, len(lst))) c_lst += [lst[idx]] # obtain quadric in ideal from "c_lst" i_lst = range(len(imp_lst)) M_pol = [ c_lst[i] * imp_lst[i] for i in i_lst if imp_lst[i].total_degree() == 2 ] M_pol = sum(M_pol) # eigendecomposition M = sage_invariant_theory.quadratic_form( M_pol, x_lst).as_QuadraticForm().matrix() M = sage_matrix(sage_QQ, M) vx = sage_vector(x_lst) D, V = M.eigenmatrix_right() # determine signature of quadric num_pos = len([d for d in D.diagonal() if d > 0]) num_neg = len([d for d in D.diagonal() if d < 0]) num_zer = len([d for d in D.diagonal() if d == 0]) sig = [num_pos, num_neg, num_zer] LSTools.p('\t sig =', sig, c_lst) # # output of M.eigenmatrix_right() ensures that # D has signature either (--- --- +) or (- +++ +++) # if num_pos < num_neg: # (--- --- +) ---> (+ --- ---) V.swap_columns(0, 6) D.swap_columns(0, 6) D.swap_rows(0, 6) # # diagonal orthonormalization # note: M == W.T*D*W == W.T*L.T*J*L*W = U.T*J*U # W = sage_matrix([col / col.norm() for col in V.columns()]) J = [] for d in D.diagonal(): if d > 0: J += [1] elif d < 0: J += [-1] J = sage_diagonal_matrix(J) L = sage_diagonal_matrix([d.abs().sqrt() for d in D.diagonal()]) U = L * W # # Do some tests # assert M_pol in ring.ideal(imp_lst) assert vx * M * vx == M_pol assert M * V == V * D # # output values # LSTools.p('quadratic form of signature (1,6) in ideal =', M_pol) LSTools.p('matrix M associated to quadratic form =', list(M)) LSTools.p('M == U.T*J*U =', list(U.T * J * U)) LSTools.p('U =', list(U)) LSTools.p('J =', list(J))