def implicitize_3d(x_fn, y_fn, z_fn, s, t): """Implicitize a 3D parametric triangle. Args: x_fn (sympy.Expr): Function :math:`x(s)` in the triangle. y_fn (sympy.Expr): Function :math:`y(s)` in the triangle. z_fn (sympy.Expr): Function :math:`z(s)` in the triangle. s (sympy.Symbol): The first symbol used to define ``x_fn``, ``y_fn`` and ``z_fn``. t (sympy.Symbol): The second symbol used to define ``x_fn``, ``y_fn`` and ``z_fn``. Returns: sympy.Expr: The implicitized function :math:`f(x, y, z)` such that the triangle satisfies :math:`f(x(s, t), y(s, t), z(s, t)) = 0`. """ # NOTE: We import SymPy at runtime to avoid the import-time cost for users # that don't want to do symbolic computation. The ``sympy`` import is # a tad expensive. import sympy # pylint: disable=import-outside-toplevel x_sym, y_sym, z_sym = sympy.symbols("x, y, z") f_xy = sympy.resultant(x_fn - x_sym, y_fn - y_sym, s) f_yz = sympy.resultant(y_fn - x_sym, z_fn - z_sym, s) return sympy.resultant(f_xy, f_yz, t).factor()
def implicit_quadratic(): x, y, t = map(Symbol, ['x', 'y', 't']) a2, a1, a0 = map(Symbol, ['a2', 'a1', 'a0']) b2, b1, b0 = map(Symbol, ['b2', 'b1', 'b0']) P1 = Poly(a2 * t**2 + a1 * t + a0 - x, t) P2 = Poly(b2 * t**2 + b1 * t + b0 - y, t) P = Poly(resultant(P1, P2), x, y) print(P) return P
def implicit_linear(): x, y, t = map(Symbol, ['x', 'y', 't']) a1, a0 = map(Symbol, ['a1', 'a0']) b1, b0 = map(Symbol, ['b1', 'b0']) P1 = Poly(a1 * t + a0 - x, t) P2 = Poly(b1 * t + b0 - y, t) P = Poly(resultant(P1, P2), x, y) print(P) return P
def implicit_cubic(): x, y, t = map(Symbol, ['x', 'y', 't']) a3, a2, a1, a0 = map(Symbol, ['a3', 'a2', 'a1', 'a0']) b3, b2, b1, b0 = map(Symbol, ['b3', 'b2', 'b1', 'b0']) P1 = Poly(a3 * t**3 + a2 * t**2 + a1 * t + a0 - x, t) P2 = Poly(b3 * t**3 + b2 * t**2 + b1 * t + b0 - y, t) P = Poly(resultant(P1, P2), x, y) #print(P) return P
def discriminant_points(self): """Returns the ordered discriminant points of the curve. The discriminant points are ordered by increasing argument with the base point. """ if not self._discriminant_points is None: return self._discriminant_points f = self.RS.f x = self.RS.x y = self.RS.y p = sympy.Poly(f, [x,y]) res = sympy.Poly(sympy.resultant(p, p.diff(y), y), x) # Compute the numerical roots. Since Sympy has issues balancing # between precision and speed we compute the roots of each # factor of the resultant. dps = sympy.mpmath.mp.dps rts = [] for factor,degree in res.factor_list_include(): rts.extend(factor.nroots(n=dps+3)) rts = map(lambda z: z.as_real_imag(), rts) disc_pts = map(lambda z: sympy.mpmath.mpc(*z), rts) # Pop any roots that appear to be equal up to the set # multiprecision. Geometrically, this may cause two roots to be # interpreted as one thus reducing the genus of the curve. N = len(disc_pts) i = 0 while i < N: k = 0 while k < N: eq = sympy.mpmath.almosteq(disc_pts[i], disc_pts[k]) if (k != i) and eq: disc_pts.remove(disc_pts[k]) N -= 1 else: k += 1 i += 1 # sort the discriminant points first by argument with the base # point and then by distance from the base point. def cmp(z, a=None): return (sympy.mpmath.arg(z - a), sympy.mpmath.absmax(z - a)) # determine the base point if self._base_point is None: a = min([numpy.complex(bi).real - 1 for bi in disc_pts]) self._base_point = a disc_pts = sorted(disc_pts, key=lambda z: cmp(z, a=self._base_point)) self._discriminant_points = numpy.array(disc_pts, dtype=numpy.complex) return self._discriminant_points
def implicitize_3d(x_fn, y_fn, z_fn, s, t): """Implicitize a 3D parametric triangle. Args: x_fn (sympy.Expr): Function :math:`x(s)` in the triangle. y_fn (sympy.Expr): Function :math:`y(s)` in the triangle. z_fn (sympy.Expr): Function :math:`z(s)` in the triangle. s (sympy.Symbol): The first symbol used to define ``x_fn``, ``y_fn`` and ``z_fn``. t (sympy.Symbol): The second symbol used to define ``x_fn``, ``y_fn`` and ``z_fn``. Returns: sympy.Expr: The implicitized function :math:`f(x, y, z)` such that the triangle satisfies :math:`f(x(s, t), y(s, t), z(s, t)) = 0`. """ x_sym, y_sym, z_sym = sympy.symbols("x, y, z") f_xy = sympy.resultant(x_fn - x_sym, y_fn - y_sym, s) f_yz = sympy.resultant(y_fn - x_sym, z_fn - z_sym, s) return sympy.resultant(f_xy, f_yz, t).factor()
def implicitize_2d(x_fn, y_fn, s): """Implicitize a 2D parametric curve. Args: x_fn (sympy.Expr): Function :math:`x(s)` in the curve. y_fn (sympy.Expr): Function :math:`y(s)` in the curve. s (sympy.Symbol): The symbol used to define ``x_fn`` and ``y_fn``. Returns: sympy.Expr: The implicitized function :math:`f(x, y)` such that the curve satisfies :math:`f(x(s), y(s)) = 0`. """ x_sym, y_sym = sympy.symbols("x, y") return sympy.resultant(x_fn - x_sym, y_fn - y_sym, s).factor()
def implicitize_2d(x_fn, y_fn, s): """Implicitize a 2D parametric curve. Args: x_fn (sympy.Expr): Function :math:`x(s)` in the curve. y_fn (sympy.Expr): Function :math:`y(s)` in the curve. s (sympy.Symbol): The symbol used to define ``x_fn`` and ``y_fn``. Returns: sympy.Expr: The implicitized function :math:`f(x, y)` such that the curve satisfies :math:`f(x(s), y(s)) = 0`. """ # NOTE: We import SymPy at runtime to avoid the import-time cost for users # that don't want to do symbolic computation. The ``sympy`` import is # a tad expensive. import sympy # pylint: disable=import-outside-toplevel x_sym, y_sym = sympy.symbols("x, y") return sympy.resultant(x_fn - x_sym, y_fn - y_sym, s).factor()
def _singular_points_finite(f,x,y): """ Returns the finite singular points of f. """ S = [] # compute the finite singularities: use the resultant p = sympy.Poly(f,[x,y]) n = p.degree(y) res = sympy.Poly(sympy.resultant(p,p.diff(y),y),x) for xk,deg in res.all_roots(multiple=False,radicals=False): if deg > 1: fxk = sympy.Poly(f.subs({x:xk,y:_Z}), _Z) for ykj,_ in fxk.all_roots(multiple=False,radicals=False): fx = f.diff(x) fy = f.diff(y) subs = {x:xk,y:ykj} if (fx.subs(subs) == 0) and (fy.subs(subs) == 0): S.append((xk,ykj,1)) return S
def discriminant_points(self): """ Returns the list of discriminant points of a plane algebraic curve `f = f(x,y)` in order. """ # self.monodromy_graph requires that we compute the discriminant # points, unordered, first. However, once we order the points # we set the result as self._discriminant_points if self._discriminant_points: return self._discriminant_points x, y = self.x, self.y p = sympy.Poly(self.f,[x,y]) res = sympy.Poly(sympy.resultant(p,p.diff(y),y),x) # compute the numerical roots dps = sympy.mpmath.mp.dps rts = [rt for rt,ord in res.all_roots(multiple=False, radicals=False)] rts = map(lambda z: sympy.N(z,n=dps).as_real_imag(), rts) disc_pts = map(lambda z: sympy.mpmath.mpc(*z), rts) return disc_pts
def ratint_logpart(f, g, x, t=None): """Lazard-Rioboo-Trager algorithm. Given a field K and polynomials f and g in K[x], such that f and g are coprime, deg(f) < deg(g) and g is square-free, returns a list of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i in K[t, x] and q_i in K[t], and: ___ ___ d f d \ ` \ ` -- - = -- ) ) a log(s_i(a, x)) dx g dx /__, /__, i=1..n a | q_i(a) = 0 """ f, g = Poly(f, x), Poly(g, x) t = t or Dummy('t') a, b = g, f - g.diff()*Poly(t, x) R = subresultants(a, b) res = Poly(resultant(a, b), t) R_map, H = {}, [] for r in R: R_map[r.degree()] = r def _include_sign(c, sqf): if c < 0: h, k = sqf[0] sqf[0] = h*c, k C, res_sqf = res.sqf_list() _include_sign(C, res_sqf) for q, i in res_sqf: _, q = q.primitive() if g.degree() == i: H.append((g, q)) else: h = R_map[i] h_lc = Poly(h.LC(), t, field=True) c, h_lc_sqf = h_lc.sqf_list(all=True) _include_sign(c, h_lc_sqf) for a, j in h_lc_sqf: h = h.exquo(Poly(a.gcd(q)**j, x)) inv, coeffs = h_lc.invert(q), [S(1)] for coeff in h.coeffs()[1:]: T = (inv*coeff).rem(q) coeffs.append(T.as_basic()) h = Poly(dict(zip(h.monoms(), coeffs)), x) H.append((h, q)) return H
def log_to_real(h, q, x, t): """Convert complex logarithms to real functions. Given real field K and polynomials h in K[t,x] and q in K[t], returns real function f such that: ___ df d \ ` -- = -- ) a log(h(a, x)) dx dx /__, a | q(a) = 0 """ u, v = symbols('u v') H = h.as_basic().subs({t: u + I * v}).expand() Q = q.as_basic().subs({t: u + I * v}).expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) a, b = H_map.get(S(1), S(0)), H_map.get(I, S(0)) c, d = Q_map.get(S(1), S(0)), Q_map.get(I, S(0)) R = Poly(resultant(c, d, v), u) R_u = roots(R, filter='R') if len(R_u) != number_of_real_roots(R): return None result = S(0) for r_u in R_u.iterkeys(): C = Poly(c.subs({u: r_u}), v) R_v = roots(C, filter='R') if len(R_v) != number_of_real_roots(C): return None for r_v in R_v: if not r_v.is_positive: continue D = d.subs({u: r_u, v: r_v}) if D.evalf(chop=True) != 0: continue A = Poly(a.subs({u: r_u, v: r_v}), x) B = Poly(b.subs({u: r_u, v: r_v}), x) AB = (A**2 + B**2).as_basic() result += r_u * log(AB) + r_v * log_to_atan(A, B) R_q = roots(q, filter='R') if len(R_q) != number_of_real_roots(q): return None for r in R_q.iterkeys(): result += r * log(h.as_basic().subs(t, r)) return result
def ratint_logpart(f, g, x, t=None): """Lazard-Rioboo-Trager algorithm. Given a field K and polynomials f and g in K[x], such that f and g are coprime, deg(f) < deg(g) and g is square-free, returns a list of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i in K[t, x] and q_i in K[t], and: ___ ___ d f d \ ` \ ` -- - = -- ) ) a log(s_i(a, x)) dx g dx /__, /__, i=1..n a | q_i(a) = 0 """ f, g = Poly(f, x), Poly(g, x) t = t or Dummy('t') a, b = g, f - g.diff() * Poly(t, x) R = subresultants(a, b) res = Poly(resultant(a, b), t) R_map, H = {}, [] for r in R: R_map[r.degree()] = r def _include_sign(c, sqf): if c < 0: h, k = sqf[0] sqf[0] = h * c, k C, res_sqf = res.sqf_list() _include_sign(C, res_sqf) for q, i in res_sqf: _, q = q.primitive() if g.degree() == i: H.append((g, q)) else: h = R_map[i] h_lc = Poly(h.LC(), t, field=True) c, h_lc_sqf = h_lc.sqf_list(all=True) _include_sign(c, h_lc_sqf) for a, j in h_lc_sqf: h = h.exquo(Poly(a.gcd(q)**j, x)) inv, coeffs = h_lc.invert(q), [S(1)] for coeff in h.coeffs()[1:]: T = (inv * coeff).rem(q) coeffs.append(T.as_basic()) h = Poly(dict(zip(h.monoms(), coeffs)), x) H.append((h, q)) return H
def test_H11(): skip('takes too much time') assert resultant(p1 * q, p2 * q, x) == 0
def test_H11(): assert resultant(p1 * q, p2 * q, x) == 0
def test_H10(): p1 = 3*x**4 + 3*x**3 + x**2 - x - 2 p2 = x**3 - 3*x**2 + x + 5 assert resultant(p1, p2, x) == 0
def integral_basis(f,x,y): """ Compute the integral basis {b1, ..., bg} of the algebraic function field C[x,y] / (f). """ # If the curve is not monic then map y |-> y/lc(x) where lc(x) # is the leading coefficient of f T = sympy.Dummy('T') d = sympy.degree(f,y) lc = sympy.LC(f,y) if x in lc: f = sympy.ratsimp( f.subs(y,y/lc)*lc**(d-1) ) else: f = f/lc lc = 1 # # Compute df # p = sympy.Poly(f,[x,y]) n = p.degree(y) res = sympy.resultant(p,p.diff(y),y) factors = sympy.factor_list(res)[1] df = [k for k,deg in factors if (deg > 1) and (sympy.LC(k) == 1)] # # Compute series truncations at appropriate x points # alpha = [] r = [] for l in range(len(df)): k = df[l] alphak = sympy.roots(k).keys()[0] rk = compute_series_truncations(f,x,y,alphak,T) alpha.append(alphak) r.append(rk) # # Main Loop # a = [sympy.Dummy('a%d'%k) for k in xrange(n)] b = [1] for d in range(1,n): bd = y*b[-1] for l in range(len(df)): k = df[l] alphak = alpha[l] rk = r[l] found_something = True while found_something: # construct system of equations consisting of the coefficients # of negative powers of (x-alphak) in the substitutions # A(r_{k,1}),...,A(r_{k,n}) A = (sum(ak*bk for ak,bk in zip(a,b)) + bd) / (x - alphak) coeffs = [] for rki in rk: # substitute and extract coefficients A_rki = A.subs(y,rki) coeffs.extend(_negative_power_coeffs(A_rki, x, alphak)) # solve the coefficient equations for a0,...,a_{d-1} coeffs = [coeff.as_numer_denom()[0] for coeff in coeffs] sols = sympy.solve_poly_system(coeffs, a[:d]) if sols is None or sols == []: found_something = False else: sol = sols[0] bdm1 = sum( sol[i]*bk for i,bk in zip(range(d),b) ) bd = (bdm1 + bd) / k # bd found. Append to list of basis elements b.append( bd ) # finally, convert back to singularized curve if necessary for i in xrange(1,len(b)): b[i] = b[i].subs(y,y*lc).ratsimp() return b
def test_H10(): p1 = 3 * x**4 + 3 * x**3 + x**2 - x - 2 p2 = x**3 - 3 * x**2 + x + 5 assert resultant(p1, p2, x) == 0
def calc_g33335(): # solid2sorted_C_Ks: ## (3, 3, 3, 3, 5): ((1/2, 1/2 + sqrt(5)/2), (2, 1)), # 0.463856880645439 solid = (3, 3, 3, 3, 5) f = solid2zero_poly_GG(solid) ggs = solve(f) ## print(ggs) ## print(list(map(N, ggs))) gg, = ggs g33335 = nsimplify(sqrt(gg)) _g33335 = sqrt(-(-(-188 + 12*sqrt(5))**3/(27*(-29 + sqrt(5))**3) - (-192 + 64*sqrt(5))/(2*(-29 + sqrt(5))) + sqrt((-(-188 + 12*sqrt(5))**2/(9*(-29 + sqrt(5))**2) + (-368 + 48*sqrt(5))/(3*(-29 + sqrt(5))))**3 + (-2*(-188 + 12*sqrt(5))**3/(27*(-29 + sqrt(5))**3) - (-192 + 64*sqrt(5))/(-29 + sqrt(5)) + (-368 + 48*sqrt(5))*(-188 + 12*sqrt(5)) /(3*(-29 + sqrt(5))**2))**2/4) + (-368 + 48*sqrt(5))*(-188 + 12*sqrt(5)) /(6*(-29 + sqrt(5))**2))**(1/3) + (-(-188 + 12*sqrt(5))**2/(9*(-29 + sqrt(5))**2) + (-368 + 48*sqrt(5))/(3*(-29 + sqrt(5)))) /(-(-188 + 12*sqrt(5))**3/(27*(-29 + sqrt(5))**3) - (-192 + 64*sqrt(5))/(2*(-29 + sqrt(5))) + sqrt((-(-188 + 12*sqrt(5))**2/(9*(-29 + sqrt(5))**2) + (-368 + 48*sqrt(5))/(3*(-29 + sqrt(5))))**3 + (-2*(-188 + 12*sqrt(5))**3/(27*(-29 + sqrt(5))**3) - (-192 + 64*sqrt(5))/(-29 + sqrt(5)) + (-368 + 48*sqrt(5))*(-188 + 12*sqrt(5)) /(3*(-29 + sqrt(5))**2))**2/4) + (-368 + 48*sqrt(5))*(-188 + 12*sqrt(5)) /(6*(-29 + sqrt(5))**2))**(1/3) + (-188 + 12*sqrt(5))/(3*(-29 + sqrt(5)))) assert verify_G(solid, g33335) # new form of g33335 h = expand(f*(sqrt(5) + 29)/2) h = collect(h, GG) assert h == 209*GG**3 + GG**2*(-1348 + 40*sqrt(5)) + GG*(-256*sqrt(5) + 2608) - 1312 + 416*sqrt(5) fr_one = Fraction(1) # Fraction(1) sr_one = GG/GG # Rational(1) A = 1881*sqrt(2)*sqrt(5760573 + 2813807*sqrt(5)) B = (A + 2563547*sqrt(15) + 6192143*sqrt(3)) D = 4**(sr_one/3)*3**(sr_one/6)/B**(sr_one/3) fr_D = 4**(fr_one/3)*3**(fr_one/6)/B**(fr_one/3) # NOTE: 4**Fraction(1,3) -> float #assert not 0 == nsimplify(D-fr_D) _GG = 2*(-6/D - 71208*D + sqrt(5)*(-19752*D - 60) + 2022)/1881 _g33335 = sqrt(_GG) assert verify_G(solid, _g33335) assert 0 == nsimplify(g33335 - _g33335) # factor the below 'f' into h over QQ[sqrt(5)] # see below 'f' u = (209*GG**6 - 2696*GG**5 + 13872*GG**4 - 35776*GG**3 + 47104*GG**2 - 27648*GG + 4096) #assert factor(u,extension={sqrt(5)}) == 209*(GG**3 + GG**2*(-1348/209 - 40*sqrt(5)/209) + GG*(256*sqrt(5)/209 + 2608/209) - 1312/209 - 416*sqrt(5)/209)*(GG**3 + GG**2*(-1348/209 + 40*sqrt(5)/209) + GG*(-256*sqrt(5)/209 + 2608/209) - 1312/209 + 416*sqrt(5)/209) assert resultant(u,h) == 0 # so, they have a same root that is GG assert 0 == expand(gcd(u,h,extension=True)*209 - h) return _g33335 _g = 0.463856880645439 _gg = _g**2 ef = lambda f, gg=_gg: N(f.subs(GG, gg)) tf = lambda f: bool(abs(ef(f)) < 1e-7) assert tf(f) P = sqrt(5) f = expand(2*f) f = collect(f, P) A, B = seperate_term(f, P) assert f == A+B f = expand(A**2 - B**2) assert tf(f) print(f) f /= 4 assert f == (209*GG**6 - 2696*GG**5 + 13872*GG**4 - 35776*GG**3 + 47104*GG**2 - 27648*GG + 4096) assert tf(f) ggs = solve(f) # sympy bug1: # solve(f) ==>> [1.50152930508540, 2.97263618194513, 2.40355087229957, 2.97263618194513] # NOTE: 2.97263618194513 appear twice but miss 0.21516320572211706 # sympy bug2: # root of f == 4*(root of h)?? since solve(f)=[4*RootOf(h)...] # where h = 209*GG**6 - 674*GG**5 + 867*GG**4 - 559*GG**3 + 184*GG**2 - 27*GG + 1 # but solve(h) == [] !!! # while GG:positive=True # but var('x'), solve(h)==[6 roots (4 reals)] and two real roots be the same print('gg', [N((gg)) for gg in ggs]) print('g', [N(sqrt(gg)) for gg in ggs]) ggs = [gg for gg in ggs if (0 < N(gg) < 4)] print([ef(f,gg) for gg in ggs]) ggs = [gg for gg in ggs if verify_G(solid, sqrt(gg))] print(ggs) raise g33335 = sqrt(gg) g33335 = nsimplify(g33335) #assert 0 == nsimplify(g33335 - _g33335) assert verify_G(solid, g33335) return g33335
def log_to_real(h, q, x, t): """Convert complex logarithms to real functions. Given real field K and polynomials h in K[t,x] and q in K[t], returns real function f such that: ___ df d \ ` -- = -- ) a log(h(a, x)) dx dx /__, a | q(a) = 0 """ u, v = symbols('u v') H = h.subs({t:u+I*v}).as_basic().expand() Q = q.subs({t:u+I*v}).as_basic().expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) a, b = H_map.get(S(1), S(0)), H_map.get(I, S(0)) c, d = Q_map.get(S(1), S(0)), Q_map.get(I, S(0)) R = Poly(resultant(c, d, v), u) R_u = roots(R, domain='R') if len(R_u) != number_of_real_roots(R): return None result = S(0) for r_u in R_u.iterkeys(): C = Poly(c.subs({u:r_u}), v) R_v = roots(C, domain='R') if len(R_v) != number_of_real_roots(C): return None for r_v in R_v: if not r_v.is_positive: continue D = d.subs({u:r_u, v:r_v}) if D.evalf(chop=True) != 0: continue A = Poly(a.subs({u:r_u, v:r_v}), x) B = Poly(b.subs({u:r_u, v:r_v}), x) AB = (A**2 + B**2).as_basic() result += r_u*log(AB) + r_v*log_to_atan(A, B) R_q = roots(q, domain='R') if len(R_q) != number_of_real_roots(q): return None for r in R_q.iterkeys(): result += r*log(h.subs(t, r).as_basic()) return result