def compute_series_truncations(f,x,y,alpha,T): """ Computes the Puiseux series expansions at the `x`-point `x=a` with the necessary number of terms in order to compute the integral basis of the algebraic functions field corresponding to `f`. The Puiseux series is returned in parametric form for computational efficiency. (Sympy doesn't do as well with fractional exponents.) """ # compute the first terms of the Puiseux series expansions p = puiseux(f,x,y,alpha,nterms=1,parametric=False) # compute the expansion bounds N = compute_expansion_bounds(p,x,alpha) Nmax = max(N) # compute Puiseux series and truncate using the expansion bounds. r = puiseux(f,x,y,alpha,degree_bound=Nmax) n = len(r) for i in xrange(n): ri = r[i].subs(x,x+alpha).expand(log=False,power_base=False, power_exp=False,multinomial=False, basic=False,force=True) terms = ri.collect(x,evaluate=False) ri_trunc = sum( coeff*term for term,coeff in terms.iteritems() if term.as_coeff_exponent(x)[1] < N[i] ) r[i] = ri_trunc return r
def _delta_invariant(f,x,y,singular_pt): """ Returns the delta invariant corresponding to the singular point `singular_pt` = [alpha, beta, gamma] on the plane algebraic curve f(x,y) = 0. """ # compute the Puiseux series at the projective point [alpha, # beta, gamma]. If on the line at infinity, make the # appropriate variable transformation. g,u,v,u0,v0 = _transform(f,x,y,singular_pt) # compute Puiseux expansions at u=u0 and filter out # only those with v(t=0) == v0 P = puiseux(g,u,v,u0,nterms=1,parametric=_t) P_v0 = [(X,Y) for X,Y in P if Y.subs(_t,0) == v0] P_v0_x = [] for X,Y in P_v0: solns = sympy.solve(u-X,_t) P_v0_x.append(Y.subs(_t,solns[0]).simplify().collect(u-u0)) P_x = puiseux(g,u,v,u0,nterms=1,parametric=False) # for each place compute its contribution to the delta invariant delta = sympy.Rational(0,1) for i in range(len(P_v0_x)): yhat = P_v0_x[i] j = P_x.index(yhat) IntPj = Int(j,P_x,u,u0) rj = (P[i][0]-u0).expand().leadterm(_t)[1] delta += sympy.Rational(rj * IntPj - rj + 1, 2) return int(delta)
def _multiplicity(f,x,y,singular_pt): """ Returns the multiplicity of the place (alpha : beta : 1) from the Puiseux series P at the place. For each (parametric) Puiseux series Pj = { x = x(t) { y = y(t) at (alpha : beta : 1) the contribution from Pj to the multiplicity is min( deg x(t), deg y(t) ). """ # compute the Puiseux series at the projective point [alpha, # beta, gamma]. If on the line at infinity, make the # appropriate variable transformation. g,u,v,u0,v0 = _transform(f,x,y,singular_pt) # compute Puiseux expansions at u=u0 and filter out # only those with v(t=0) == v0 P = puiseux(g,u,v,u0,nterms=1,parametric=_t) m = 0 for X,Y in P: X = X - u0 # Shift so no constant Y = Y - v0 # term remains. ri = abs( X.leadterm(_t)[1] ) # Get order of lead term si = abs( Y.leadterm(_t)[1] ) m += min(ri,si) return int(m)
def _branching_number(f,x,y,singular_pt): """ Returns the branching number of the place [alpha : beta : 1] from the Puiseux series P at the place. The braching number is simply the number of distinct branches (i.e. non-interacting branches) at the place. In parametric form, this is simply the number of Puiseux series at the place. """ # compute the Puiseux series at the projective point [alpha, # beta, gamma]. If on the line at infinity, make the # appropriate variable transformation. g,u,v,u0,v0 = _transform(f,x,y,singular_pt) # compute Puiseux expansions at u=u0 and filter out # only those with v(t=0) == v0 P = puiseux(g,u,v,u0,nterms=1,parametric=_t) P_v0 = [(X,Y) for X,Y in P if Y.subs(_t,0) == v0] return len(P_v0)