def dup_prem(f, g, K): """Polynomial pseudo-remainder in `K[x]`. """ df = dup_degree(f) dg = dup_degree(g) r = f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return r N = df - dg + 1 lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) j, N = dr-dg, N-1 R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) r = dup_sub(R, G, K) return dup_mul_ground(r, lc_g**N, K)
def dup_ext_factor(f, K): """Factor univariate polynomials over algebraic number fields. """ n, lc = dup_degree(f), dup_LC(f, K) f = dup_monic(f, K) if n <= 0: return lc, [] if n == 1: return lc, [(f, 1)] f, F = dup_sqf_part(f, K), f s, g, r = dup_sqf_norm(f, K) factors = dup_factor_list_include(r, K.dom) if len(factors) == 1: return lc, [(f, n//dup_degree(f))] H = s*K.unit for i, (factor, _) in enumerate(factors): h = dup_convert(factor, K.dom, K) h, _, g = dup_inner_gcd(h, g, K) h = dup_shift(h, H, K) factors[i] = h factors = dup_trial_division(F, factors, K) return lc, factors
def dup_gff_list(f, K): """ Compute greatest factorial factorization of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2) [(x, 1), (x + 2, 4)] """ if not f: raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial") f = dup_monic(f, K) if not dup_degree(f): return [] else: g = dup_gcd(f, dup_shift(f, K.one, K), K) H = dup_gff_list(g, K) for i, (h, k) in enumerate(H): g = dup_mul(g, dup_shift(h, -K(k), K), K) H[i] = (h, k + 1) f = dup_quo(f, g, K) if not dup_degree(f): return H else: return [(f, 1)] + H
def dup_ff_div(f, g, K): """Polynomial division with remainder over a field. """ df = dup_degree(f) dg = dup_degree(g) q, r = [], f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) if not K.is_Exact: r = dup_normal(r, K) return q, r
def dup_rr_div(f, g, K): """Univariate division with remainder over a ring. """ df = dup_degree(f) dg = dup_degree(g) q, r = [], f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) if lc_r % lc_g: break c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) return q, r
def dup_add(f, g, K): """ Add dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_add(x**2 - 1, x - 2) x**2 + x - 3 """ if not f: return g if not g: return f df = dup_degree(f) dg = dup_degree(g) if df == dg: return dup_strip([ a + b for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = g[:k], g[k:] return h + [ a + b for a, b in zip(f, g) ]
def dup_sub(f, g, K): """ Subtract dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sub(x**2 - 1, x - 2) x**2 - x + 1 """ if not f: return dup_neg(g, K) if not g: return f df = dup_degree(f) dg = dup_degree(g) if df == dg: return dup_strip([ a - b for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = dup_neg(g[:k], K), g[k:] return h + [ a - b for a, b in zip(f, g) ]
def dup_mul(f, g, K): """ Multiply dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mul(x - 2, x + 2) x**2 - 4 """ if f == g: return dup_sqr(f, K) if not (f and g): return [] df = dup_degree(f) dg = dup_degree(g) h = [] for i in xrange(0, df + dg + 1): coeff = K.zero for j in xrange(max(0, i - dg), min(df, i) + 1): coeff += f[j]*g[i - j] h.append(coeff) return dup_strip(h)
def dup_sub(f, g, K): """ Subtract dense polynomials in ``K[x]``. **Examples** >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densearith import dup_sub >>> f = ZZ.map([1, 0, -1]) >>> g = ZZ.map([1, -2]) >>> dup_sub(f, g, ZZ) [1, -1, 1] """ if not f: return dup_neg(g, K) if not g: return f df = dup_degree(f) dg = dup_degree(g) if df == dg: return dup_strip([ a - b for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = dup_neg(g[:k], K), g[k:] return h + [ a - b for a, b in zip(f, g) ]
def dup_sqf_list(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.sqfreetools import dup_sqf_list >>> f = ZZ.map([2, 16, 50, 76, 56, 16]) >>> dup_sqf_list(f, ZZ) (2, [([1, 1], 2), ([1, 2], 3)]) >>> dup_sqf_list(f, ZZ, all=True) (2, [([1], 1), ([1, 1], 2), ([1, 2], 3)]) """ if not K.has_CharacteristicZero: return dup_gf_sqf_list(f, K, all=all) if K.has_Field or not K.is_Exact: coeff = dup_LC(f, K) f = dup_monic(f, K) else: coeff, f = dup_primitive(f, K) if K.is_negative(dup_LC(f, K)): f = dup_neg(f, K) coeff = -coeff if dup_degree(f) <= 0: return coeff, [] result, i = [], 1 h = dup_diff(f, 1, K) g, p, q = dup_inner_gcd(f, h, K) while True: d = dup_diff(p, 1, K) h = dup_sub(q, d, K) if not h: result.append((p, i)) break g, p, q = dup_inner_gcd(p, h, K) if all or dup_degree(g) > 0: result.append((g, i)) i += 1 return coeff, result
def dup_mul(f, g, K): """ Multiply dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mul(x - 2, x + 2) x**2 - 4 """ if f == g: return dup_sqr(f, K) if not (f and g): return [] df = dup_degree(f) dg = dup_degree(g) n = max(df, dg) + 1 if n < 100: h = [] for i in xrange(0, df + dg + 1): coeff = K.zero for j in xrange(max(0, i - dg), min(df, i) + 1): coeff += f[j]*g[i - j] h.append(coeff) return dup_strip(h) else: # Use Karatsuba's algorithm (divide and conquer), see e.g.: # Joris van der Hoeven, Relax But Don't Be Too Lazy, # J. Symbolic Computation, 11 (2002), section 3.1.1. n2 = n//2 fl, gl = dup_slice(f, 0, n2, K), dup_slice(g, 0, n2, K) fh = dup_rshift(dup_slice(f, n2, n, K), n2, K) gh = dup_rshift(dup_slice(g, n2, n, K), n2, K) lo, hi = dup_mul(fl, gl, K), dup_mul(fh, gh, K) mid = dup_mul(dup_add(fl, fh, K), dup_add(gl, gh, K), K) mid = dup_sub(mid, dup_add(lo, hi, K), K) return dup_add(dup_add(lo, dup_lshift(mid, n2, K), K), dup_lshift(hi, 2*n2, K), K)
def dup_sqf_list(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 >>> R.dup_sqf_list(f) (2, [(x + 1, 2), (x + 2, 3)]) >>> R.dup_sqf_list(f, all=True) (2, [(1, 1), (x + 1, 2), (x + 2, 3)]) """ if K.is_FiniteField: return dup_gf_sqf_list(f, K, all=all) if K.has_Field: coeff = dup_LC(f, K) f = dup_monic(f, K) else: coeff, f = dup_primitive(f, K) if K.is_negative(dup_LC(f, K)): f = dup_neg(f, K) coeff = -coeff if dup_degree(f) <= 0: return coeff, [] result, i = [], 1 h = dup_diff(f, 1, K) g, p, q = dup_inner_gcd(f, h, K) while True: d = dup_diff(p, 1, K) h = dup_sub(q, d, K) if not h: result.append((p, i)) break g, p, q = dup_inner_gcd(p, h, K) if all or dup_degree(g) > 0: result.append((g, i)) i += 1 return coeff, result
def dup_prs_resultant(f, g, K): """ Resultant algorithm in `K[x]` using subresultant PRS. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.euclidtools import dup_prs_resultant >>> f = ZZ.map([1, 0, 1]) >>> g = ZZ.map([1, 0, -1]) >>> dup_prs_resultant(f, g, ZZ) (4, [[1, 0, 1], [1, 0, -1], [-2]]) """ if not f or not g: return (K.zero, []) R, B, D = dup_inner_subresultants(f, g, K) if dup_degree(R[-1]) > 0: return (K.zero, R) if R[-2] == [K.one]: return (dup_LC(R[-1], K), R) s, i = 1, 1 p, q = K.one, K.one for b, d in list(zip(B, D))[:-1]: du = dup_degree(R[i - 1]) dv = dup_degree(R[i ]) dw = dup_degree(R[i + 1]) if du % 2 and dv % 2: s = -s lc, i = dup_LC(R[i], K), i + 1 p *= b**dv * lc**(du - dw) q *= lc**(dv*(1 + d)) if s < 0: p = -p i = dup_degree(R[-2]) res = dup_LC(R[-1], K)**i res = K.quo(res*p, q) return res, R
def dup_pdiv(f, g, K): """ Polynomial pseudo-division in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densearith import dup_pdiv >>> f = ZZ.map([1, 0, 1]) >>> g = ZZ.map([2, -4]) >>> dup_pdiv(f, g, ZZ) ([2, 4], [20]) """ df = dup_degree(f) dg = dup_degree(g) q, r = [], f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r N = df - dg + 1 lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) j, N = dr-dg, N-1 Q = dup_mul_ground(q, lc_g, K) q = dup_add_term(Q, lc_r, j, K) R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) r = dup_sub(R, G, K) c = lc_g**N q = dup_mul_ground(q, c, K) r = dup_mul_ground(r, c, K) return q, r
def dup_pdiv(f, g, K): """ Polynomial pseudo-division in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_pdiv(x**2 + 1, 2*x - 4) (2*x + 4, 20) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r N = df - dg + 1 lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) j, N = dr - dg, N - 1 Q = dup_mul_ground(q, lc_g, K) q = dup_add_term(Q, lc_r, j, K) R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) r = dup_sub(R, G, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) c = lc_g**N q = dup_mul_ground(q, c, K) r = dup_mul_ground(r, c, K) return q, r
def dup_ff_div(f, g, K): """ Polynomial division with remainder over a field. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_ff_div(x**2 + 1, 2*x - 4) (1/2*x + 1, 5) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif dr == _dr and not K.is_Exact: # remove leading term created by rounding error r = dup_strip(r[1:]) dr = dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r
def dup_prs_resultant(f, g, K): """ Resultant algorithm in `K[x]` using subresultant PRS. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_prs_resultant(x**2 + 1, x**2 - 1) (4, [x**2 + 1, x**2 - 1, -2]) """ if not f or not g: return (K.zero, []) R, B, D = dup_inner_subresultants(f, g, K) if dup_degree(R[-1]) > 0: return (K.zero, R) if R[-2] == [K.one]: return (dup_LC(R[-1], K), R) s, i = 1, 1 p, q = K.one, K.one for b, d in list(zip(B, D))[:-1]: du = dup_degree(R[i - 1]) dv = dup_degree(R[i ]) dw = dup_degree(R[i + 1]) if du % 2 and dv % 2: s = -s lc, i = dup_LC(R[i], K), i + 1 p *= b**dv * lc**(du - dw) q *= lc**(dv*(1 + d)) if s < 0: p = -p i = dup_degree(R[-2]) res = dup_LC(R[-1], K)**i res = K.quo(res*p, q) return res, R
def dup_ff_div(f, g, K): """ Polynomial division with remainder over a field. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.densearith import dup_ff_div >>> f = QQ.map([1, 0, 1]) >>> g = QQ.map([2, -4]) >>> dup_ff_div(f, g, QQ) ([1/2, 1/1], [5/1]) """ df = dup_degree(f) dg = dup_degree(g) q, r = [], f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) if not K.is_Exact: r = dup_normal(r, K) return q, r
def dup_rr_div(f, g, K): """ Univariate division with remainder over a ring. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densearith import dup_rr_div >>> f = ZZ.map([1, 0, 1]) >>> g = ZZ.map([2, -4]) >>> dup_rr_div(f, g, ZZ) ([], [1, 0, 1]) """ df = dup_degree(f) dg = dup_degree(g) q, r = [], f if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: dr = dup_degree(r) if dr < dg: break lc_r = dup_LC(r, K) if lc_r % lc_g: break c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) return q, r
def dup_transform(f, p, q, K): """ Evaluate functional transformation ``q**n * f(p/q)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_transform(x**2 - 2*x + 1, x**2 + 1, x - 1) x**4 - 2*x**3 + 5*x**2 - 4*x + 4 """ if not f: return [] n = dup_degree(f) h, Q = [f[0]], [[K.one]] for i in xrange(0, n): Q.append(dup_mul(Q[-1], q, K)) for c, q in zip(f[1:], Q[1:]): h = dup_mul(h, p, K) q = dup_mul_ground(q, c, K) h = dup_add(h, q, K) return h
def dup_transform(f, p, q, K): """ Evaluate functional transformation ``q**n * f(p/q)`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densetools import dup_transform >>> f = ZZ.map([1, -2, 1]) >>> p = ZZ.map([1, 0, 1]) >>> q = ZZ.map([1, -1]) >>> dup_transform(f, p, q, ZZ) [1, -2, 5, -4, 4] """ if not f: return [] n = dup_degree(f) h, Q = [f[0]], [[K.one]] for i in xrange(0, n): Q.append(dup_mul(Q[-1], q, K)) for c, q in zip(f[1:], Q[1:]): h = dup_mul(h, p, K) q = dup_mul_ground(q, c, K) h = dup_add(h, q, K) return h
def dup_discriminant(f, K): """ Computes discriminant of a polynomial in `K[x]`. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.euclidtools import dup_discriminant >>> dup_discriminant([ZZ(1), ZZ(2), ZZ(3)], ZZ) -8 """ d = dup_degree(f) if d <= 0: return K.zero else: s = (-1)**((d*(d-1)) // 2) c = dup_LC(f, K) r = dup_resultant(f, dup_diff(f, 1, K), K) return K.quo(r, c*K(s))
def dup_zz_mignotte_bound(f, K): """Mignotte bound for univariate polynomials in `K[x]`. """ a = dup_max_norm(f, K) b = abs(dup_LC(f, K)) n = dup_degree(f) return K.sqrt(K(n+1))*2**n*a*b
def dup_zz_factor_sqf(f, K): """Factor square-free (non-primitive) polyomials in `Z[x]`. """ cont, g = dup_primitive(f, K) n = dup_degree(g) if dup_LC(g, K) < 0: cont, g = -cont, dup_neg(g, K) if n <= 0: return cont, [] elif n == 1: return cont, [(g, 1)] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): return cont, [(g, 1)] factors = None if query('USE_CYCLOTOMIC_FACTOR'): factors = dup_zz_cyclotomic_factor(g, K) if factors is None: factors = dup_zz_zassenhaus(g, K) return cont, _sort_factors(factors, multiple=False)
def dup_revert(f, n, K): """ Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. This function computes first ``2**n`` terms of a polynomial that is a result of inversion of a polynomial modulo ``x**n``. This is useful to efficiently compute series expansion of ``1/f``. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.densetools import dup_revert >>> f = [-QQ(1,720), QQ(0), QQ(1,24), QQ(0), -QQ(1,2), QQ(0), QQ(1)] >>> dup_revert(f, 8, QQ) [61/720, 0/1, 5/24, 0/1, 1/2, 0/1, 1/1] """ g = [K.revert(dup_TC(f, K))] h = [K.one, K.zero, K.zero] N = int(_ceil(_log(n, 2))) for i in xrange(1, N + 1): a = dup_mul_ground(g, K(2), K) b = dup_mul(f, dup_sqr(g, K), K) g = dup_rem(dup_sub(a, b, K), h, K) h = dup_lshift(h, dup_degree(h), K) return g
def dup_revert(f, n, K): """ Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. This function computes first ``2**n`` terms of a polynomial that is a result of inversion of a polynomial modulo ``x**n``. This is useful to efficiently compute series expansion of ``1/f``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = -QQ(1,720)*x**6 + QQ(1,24)*x**4 - QQ(1,2)*x**2 + 1 >>> R.dup_revert(f, 8) 61/720*x**6 + 5/24*x**4 + 1/2*x**2 + 1 """ g = [K.revert(dup_TC(f, K))] h = [K.one, K.zero, K.zero] N = int(_ceil(_log(n, 2))) for i in range(1, N + 1): a = dup_mul_ground(g, K(2), K) b = dup_mul(f, dup_sqr(g, K), K) g = dup_rem(dup_sub(a, b, K), h, K) h = dup_lshift(h, dup_degree(h), K) return g
def dup_sqr(f, K): """Square dense polynomials in `K[x]`. """ df, h = dup_degree(f), [] for i in xrange(0, 2*df+1): c = K.zero jmin = max(0, i-df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 for j in xrange(jmin, jmax+1): c += f[j]*f[i-j] c += c if n & 1: elem = f[jmax+1] c += elem**2 h.append(c) return h
def _dup_right_decompose(f, s, K): """Helper function for :func:`_dup_decompose`.""" n = dup_degree(f) lc = dup_LC(f, K) f = dup_to_raw_dict(f) g = { s: K.one } r = n // s for i in xrange(1, s): coeff = K.zero for j in xrange(0, i): if not n + j - i in f: continue if not s - j in g: continue fc, gc = f[n + j - i], g[s - j] coeff += (i - r*j)*fc*gc g[s - i] = K.quo(coeff, i*r*lc) return dup_from_raw_dict(g, K)
def dup_discriminant(f, K): """ Computes discriminant of a polynomial in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_discriminant(x**2 + 2*x + 3) -8 """ d = dup_degree(f) if d <= 0: return K.zero else: s = (-1)**((d*(d - 1)) // 2) c = dup_LC(f, K) r = dup_resultant(f, dup_diff(f, 1, K), K) return K.quo(r, c*K(s))
def dup_rr_div(f, g, K): """ Univariate division with remainder over a ring. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_rr_div(x**2 + 1, 2*x - 4) (0, x**2 + 1) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) if lc_r % lc_g: break c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r
def dup_inner_subresultants(f, g, K): """ Subresultant PRS algorithm in ``K[x]``. Computes the subresultant polynomial remainder sequence (PRS) of ``f`` and ``g``, and the values for $\\beta_i$ and $\\delta_i$. The last two sequences of values are necessary for computing the resultant in :func:`dup_prs_resultant`. **Examples** >>> from sympy.polys.domains import ZZ >>> from sympy.polys.euclidtools import dup_inner_subresultants >>> f = ZZ.map([1, 0, 1]) >>> g = ZZ.map([1, 0, -1]) >>> dup_inner_subresultants(f, g, ZZ) ([[1, 0, 1], [1, 0, -1], [-2]], [-1, -1], [0, 2]) """ n = dup_degree(f) m = dup_degree(g) if n < m: f, g = g, f n, m = m, n R = [f, g] d = n - m b = (-K.one)**(d + 1) c = -K.one B, D = [b], [d] if not f or not g: return R, B, D h = dup_prem(f, g, K) h = dup_mul_ground(h, b, K) while h: k = dup_degree(h) R.append(h) lc = dup_LC(g, K) if not d: q = c else: q = c**(d - 1) c = K.exquo((-lc)**d, q) b = -lc * c**(m - k) f, g, m, d = g, h, k, m - k B.append(b) D.append(d) h = dup_prem(f, g, K) h = dup_exquo_ground(h, b, K) return R, B, D
def dmp_zz_modular_resultant(f, g, p, u, K): """ Compute resultant of ``f`` and ``g`` modulo a prime ``p``. **Examples** >>> from sympy.polys.domains import ZZ >>> from sympy.polys.euclidtools import dmp_zz_modular_resultant >>> f = ZZ.map([[1], [1, 2]]) >>> g = ZZ.map([[2, 1], [3]]) >>> dmp_zz_modular_resultant(f, g, ZZ(5), 1, ZZ) [-2, 0, 1] """ if not u: return gf_int(dup_prs_resultant(f, g, K)[0] % p, p) v = u - 1 n = dmp_degree(f, u) m = dmp_degree(g, u) N = dmp_degree_in(f, 1, u) M = dmp_degree_in(g, 1, u) B = n * M + m * N D, a = [K.one], -K.one r = dmp_zero(v) while dup_degree(D) <= B: while True: a += K.one if a == p: raise HomomorphismFailed('no luck') F = dmp_eval_in(f, gf_int(a, p), 1, u, K) if dmp_degree(F, v) == n: G = dmp_eval_in(g, gf_int(a, p), 1, u, K) if dmp_degree(G, v) == m: break R = dmp_zz_modular_resultant(F, G, p, v, K) e = dmp_eval(r, a, v, K) if not v: R = dup_strip([R]) e = dup_strip([e]) else: R = [R] e = [e] d = K.invert(dup_eval(D, a, K), p) d = dup_mul_ground(D, d, K) d = dmp_raise(d, v, 0, K) c = dmp_mul(d, dmp_sub(R, e, v, K), v, K) r = dmp_add(r, c, v, K) r = dmp_ground_trunc(r, p, v, K) D = dup_mul(D, [K.one, -a], K) D = dup_trunc(D, p, K) return r
def test_dup_degree(): assert dup_degree([]) == -1 assert dup_degree([1]) == 0 assert dup_degree([1, 0]) == 1 assert dup_degree([1, 0, 0, 0, 1]) == 4
def dup_zz_zassenhaus(f, K): """Factor primitive square-free polynomials in `Z[x]`. """ n = dup_degree(f) if n == 1: return [f] A = dup_max_norm(f, K) b = dup_LC(f, K) B = int(abs(K.sqrt(K(n + 1)) * 2**n * A * b)) C = int((n + 1)**(2 * n) * A**(2 * n - 1)) gamma = int(ceil(2 * log(C, 2))) bound = int(2 * gamma * log(gamma)) for p in xrange(3, bound + 1): if not isprime(p) or b % p == 0: continue p = K.convert(p) F = gf_from_int_poly(f, p) if gf_sqf_p(F, p, K): break l = int(ceil(log(2 * B + 1, p))) modular = [] for ff in gf_factor_sqf(F, p, K)[1]: modular.append(gf_to_int_poly(ff, p)) g = dup_zz_hensel_lift(p, f, modular, l, K) T = set(range(len(g))) factors, s = [], 1 while 2 * s <= len(T): for S in subsets(T, s): G, H = [b], [b] S = set(S) for i in S: G = dup_mul(G, g[i], K) for i in T - S: H = dup_mul(H, g[i], K) G = dup_trunc(G, p**l, K) H = dup_trunc(H, p**l, K) G_norm = dup_l1_norm(G, K) H_norm = dup_l1_norm(H, K) if G_norm * H_norm <= B: T = T - S G = dup_primitive(G, K)[1] f = dup_primitive(H, K)[1] factors.append(G) b = dup_LC(f, K) break else: s += 1 return factors + [f]
def dup_inner_subresultants(f, g, K): """ Subresultant PRS algorithm in `K[x]`. Computes the subresultant polynomial remainder sequence (PRS) of `f` and `g`, and the values for `\beta_i` and `\delta_i`. The last two sequences of values are necessary for computing the resultant in :func:`dup_prs_resultant`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1) ([x**2 + 1, x**2 - 1, -2], [-1, -1], [0, 2]) """ n = dup_degree(f) m = dup_degree(g) if n < m: f, g = g, f n, m = m, n R = [f, g] d = n - m b = (-K.one)**(d + 1) c = -K.one B, D = [b], [d] if not f or not g: return R, B, D h = dup_prem(f, g, K) h = dup_mul_ground(h, b, K) while h: k = dup_degree(h) R.append(h) lc = dup_LC(g, K) if not d: q = c else: q = c**(d - 1) c = K.quo((-lc)**d, q) b = -lc * c**(m - k) f, g, m, d = g, h, k, m - k B.append(b) D.append(d) h = dup_prem(f, g, K) h = dup_quo_ground(h, b, K) return R, B, D
def dup_zz_zassenhaus(f, K): """Factor primitive square-free polynomials in `Z[x]`. """ n = dup_degree(f) if n == 1: return [f] fc = f[-1] A = dup_max_norm(f, K) b = dup_LC(f, K) B = int(abs(K.sqrt(K(n + 1)) * 2**n * A * b)) C = int((n + 1)**(2 * n) * A**(2 * n - 1)) gamma = int(_ceil(2 * _log(C, 2))) bound = int(2 * gamma * _log(gamma)) a = [] # choose a prime number `p` such that `f` be square free in Z_p # if there are many factors in Z_p, choose among a few different `p` # the one with fewer factors for px in range(3, bound + 1): if not isprime(px) or b % px == 0: continue px = K.convert(px) F = gf_from_int_poly(f, px) if not gf_sqf_p(F, px, K): continue fsqfx = gf_factor_sqf(F, px, K)[1] a.append((px, fsqfx)) if len(fsqfx) < 15 or len(a) > 4: break p, fsqf = min(a, key=lambda x: len(x[1])) l = int(_ceil(_log(2 * B + 1, p))) modular = [gf_to_int_poly(ff, p) for ff in fsqf] g = dup_zz_hensel_lift(p, f, modular, l, K) sorted_T = range(len(g)) T = set(sorted_T) factors, s = [], 1 pl = p**l while 2 * s <= len(T): for S in subsets(sorted_T, s): # lift the constant coefficient of the product `G` of the factors # in the subset `S`; if it is does not divide `fc`, `G` does # not divide the input polynomial if b == 1: q = 1 for i in S: q = q * g[i][-1] q = q % pl if not _test_pl(fc, q, pl): continue else: G = [b] for i in S: G = dup_mul(G, g[i], K) G = dup_trunc(G, pl, K) G = dup_primitive(G, K)[1] q = G[-1] if q and fc % q != 0: continue H = [b] S = set(S) T_S = T - S if b == 1: G = [b] for i in S: G = dup_mul(G, g[i], K) G = dup_trunc(G, pl, K) for i in T_S: H = dup_mul(H, g[i], K) H = dup_trunc(H, pl, K) G_norm = dup_l1_norm(G, K) H_norm = dup_l1_norm(H, K) if G_norm * H_norm <= B: T = T_S sorted_T = [i for i in sorted_T if i not in S] G = dup_primitive(G, K)[1] f = dup_primitive(H, K)[1] factors.append(G) b = dup_LC(f, K) break else: s += 1 return factors + [f]
def test_dmp_zz_wang(): p = ZZ(nextprime(dmp_zz_mignotte_bound(w_1, 2, ZZ))) assert p == ZZ(6291469) t_1, k_1, e_1 = dmp_normal([[1], []], 1, ZZ), 1, ZZ(-14) t_2, k_2, e_2 = dmp_normal([[1, 0]], 1, ZZ), 2, ZZ(3) t_3, k_3, e_3 = dmp_normal([[1], [1, 0]], 1, ZZ), 2, ZZ(-11) t_4, k_4, e_4 = dmp_normal([[1], [-1, 0]], 1, ZZ), 1, ZZ(-17) T = [t_1, t_2, t_3, t_4] K = [k_1, k_2, k_3, k_4] E = [e_1, e_2, e_3, e_4] T = zip(T, K) A = [ZZ(-14), ZZ(3)] S = dmp_eval_tail(w_1, A, 2, ZZ) cs, s = dup_primitive(S, ZZ) assert cs == 1 and s == S == \ dup_normal([1036728, 915552, 55748, 105621, -17304, -26841, -644], ZZ) assert dmp_zz_wang_non_divisors(E, cs, 4, ZZ) == [7, 3, 11, 17] assert dup_sqf_p(s, ZZ) and dup_degree(s) == dmp_degree(w_1, 2) _, H = dup_zz_factor_sqf(s, ZZ) h_1 = dup_normal([44, 42, 1], ZZ) h_2 = dup_normal([126, -9, 28], ZZ) h_3 = dup_normal([187, 0, -23], ZZ) assert H == [h_1, h_2, h_3] lc_1 = dmp_normal([[-4], [-4, 0]], 1, ZZ) lc_2 = dmp_normal([[-1, 0, 0], []], 1, ZZ) lc_3 = dmp_normal([[1], [], [-1, 0, 0]], 1, ZZ) LC = [lc_1, lc_2, lc_3] assert dmp_zz_wang_lead_coeffs(w_1, T, cs, E, H, A, 2, ZZ) == (w_1, H, LC) H_1 = [ dmp_normal(t, 0, ZZ) for t in [[44L, 42L, 1L], [126L, -9L, 28L], [187L, 0L, -23L]] ] H_2 = [ dmp_normal(t, 1, ZZ) for t in [[[-4, -12], [-3, 0], [1]], [[-9, 0], [-9], [-2, 0]], [[1, 0, -9], [], [1, -9]]] ] H_3 = [ dmp_normal(t, 1, ZZ) for t in [[[-4, -12], [-3, 0], [1]], [[-9, 0], [-9], [-2, 0]], [[1, 0, -9], [], [1, -9]]] ] c_1 = dmp_normal([-70686, -5863, -17826, 2009, 5031, 74], 0, ZZ) c_2 = dmp_normal( [[9, 12, -45, -108, -324], [18, -216, -810, 0], [2, 9, -252, -288, -945], [-30, -414, 0], [2, -54, -3, 81], [12, 0]], 1, ZZ) c_3 = dmp_normal( [[-36, -108, 0], [-27, -36, -108], [-8, -42, 0], [-6, 0, 9], [2, 0]], 1, ZZ) T_1 = [dmp_normal(t, 0, ZZ) for t in [[-3, 0], [-2], [1]]] T_2 = [dmp_normal(t, 1, ZZ) for t in [[[-1, 0], []], [[-3], []], [[-6]]]] T_3 = [dmp_normal(t, 1, ZZ) for t in [[[]], [[]], [[-1]]]] assert dmp_zz_diophantine(H_1, c_1, [], 5, p, 0, ZZ) == T_1 assert dmp_zz_diophantine(H_2, c_2, [ZZ(-14)], 5, p, 1, ZZ) == T_2 assert dmp_zz_diophantine(H_3, c_3, [ZZ(-14)], 5, p, 1, ZZ) == T_3 factors = dmp_zz_wang_hensel_lifting(w_1, H, LC, A, p, 2, ZZ) assert dmp_expand(factors, 2, ZZ) == w_1
def dup_zz_factor(f, K): """ Factor (non square-free) polynomials in `Z[x]`. Given a univariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: f = content(f) f_1**k_1 ... f_n**k_n The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Zassenhaus algorithm. Trial division is used to recover the multiplicities of factors. The result is returned as a tuple consisting of:: (content(f), [(f_1, k_1), ..., (f_n, k_n)) Consider polynomial `f = 2*x**4 - 2`:: >>> from sympy.polys.factortools import dup_zz_factor >>> from sympy.polys.domains import ZZ >>> dup_zz_factor([2, 0, 0, 0, -2], ZZ) (2, [([1, -1], 1), ([1, 1], 1), ([1, 0, 1], 1)]) In result we got the following factorization:: f = 2 (x - 1) (x + 1) (x**2 + 1) Note that this is a complete factorization over integers, however over Gaussian integers we can factor the last term. By default, polynomials `x**n - 1` and `x**n + 1` are factored using cyclotomic decomposition to speedup computations. To disable this behaviour set cyclotomic=False. **References** 1. [Gathen99]_ """ cont, g = dup_primitive(f, K) n = dup_degree(g) if dup_LC(g, K) < 0: cont, g = -cont, dup_neg(g, K) if n <= 0: return cont, [] elif n == 1: return cont, [(g, 1)] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): return cont, [(g, 1)] g = dup_sqf_part(g, K) H, factors = None, [] if query('USE_CYCLOTOMIC_FACTOR'): H = dup_zz_cyclotomic_factor(g, K) if H is None: H = dup_zz_zassenhaus(g, K) for h in H: k = 0 while True: q, r = dup_div(f, h, K) if not r: f, k = q, k + 1 else: break factors.append((h, k)) return cont, _sort_factors(factors)
def dup_inner_subresultants(f, g, K): """ Subresultant PRS algorithm in `K[x]`. Computes the subresultant polynomial remainder sequence (PRS) and the non-zero scalar subresultants of `f` and `g`. By [1] Thm. 3, these are the constants '-c' (- to optimize computation of sign). The first subdeterminant is set to 1 by convention to match the polynomial and the scalar subdeterminants. If 'deg(f) < deg(g)', the subresultants of '(g,f)' are computed. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1) ([x**2 + 1, x**2 - 1, -2], [1, 1, 4]) References ========== .. [1] W.S. Brown, The Subresultant PRS Algorithm. ACM Transaction of Mathematical Software 4 (1978) 237-249 """ n = dup_degree(f) m = dup_degree(g) if n < m: f, g = g, f n, m = m, n if not f: return [], [] if not g: return [f], [K.one] R = [f, g] d = n - m b = (-K.one)**(d + 1) h = dup_prem(f, g, K) h = dup_mul_ground(h, b, K) lc = dup_LC(g, K) c = lc**d # Conventional first scalar subdeterminant is 1 S = [K.one, c] c = -c while h: k = dup_degree(h) R.append(h) f, g, m, d = g, h, k, m - k b = -lc * c**d h = dup_prem(f, g, K) h = dup_quo_ground(h, b, K) lc = dup_LC(g, K) if d > 1: # abnormal case q = c**(d - 1) c = K.quo((-lc)**d, q) else: c = -lc S.append(-c) return R, S
def dmp_zz_diophantine(F, c, A, d, p, u, K): """Wang/EEZ: Solve multivariate Diophantine equations. """ if not A: S = [[] for _ in F] n = dup_degree(c) for i, coeff in enumerate(c): if not coeff: continue T = dup_zz_diophantine(F, n - i, p, K) for j, (s, t) in enumerate(zip(S, T)): t = dup_mul_ground(t, coeff, K) S[j] = dup_trunc(dup_add(s, t, K), p, K) else: n = len(A) e = dmp_expand(F, u, K) a, A = A[-1], A[:-1] B, G = [], [] for f in F: B.append(dmp_quo(e, f, u, K)) G.append(dmp_eval_in(f, a, n, u, K)) C = dmp_eval_in(c, a, n, u, K) v = u - 1 S = dmp_zz_diophantine(G, C, A, d, p, v, K) S = [dmp_raise(s, 1, v, K) for s in S] for s, b in zip(S, B): c = dmp_sub_mul(c, s, b, u, K) c = dmp_ground_trunc(c, p, u, K) m = dmp_nest([K.one, -a], n, K) M = dmp_one(n, K) for k in xrange(0, d): if dmp_zero_p(c, u): break M = dmp_mul(M, m, u, K) C = dmp_diff_eval_in(c, k + 1, a, n, u, K) if not dmp_zero_p(C, v): C = dmp_quo_ground(C, K.factorial(k + 1), v, K) T = dmp_zz_diophantine(G, C, A, d, p, v, K) for i, t in enumerate(T): T[i] = dmp_mul(dmp_raise(t, 1, v, K), M, u, K) for i, (s, t) in enumerate(zip(S, T)): S[i] = dmp_add(s, t, u, K) for t, b in zip(T, B): c = dmp_sub_mul(c, t, b, u, K) c = dmp_ground_trunc(c, p, u, K) S = [dmp_ground_trunc(s, p, u, K) for s in S] return S
def dup_zz_factor(f, K): """ Factor (non square-free) polynomials in `Z[x]`. Given a univariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: f = content(f) f_1**k_1 ... f_n**k_n The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Zassenhaus algorithm. Trial division is used to recover the multiplicities of factors. The result is returned as a tuple consisting of:: (content(f), [(f_1, k_1), ..., (f_n, k_n)) Examples ======== Consider the polynomial `f = 2*x**4 - 2`:: >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_zz_factor(2*x**4 - 2) (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)]) In result we got the following factorization:: f = 2 (x - 1) (x + 1) (x**2 + 1) Note that this is a complete factorization over integers, however over Gaussian integers we can factor the last term. By default, polynomials `x**n - 1` and `x**n + 1` are factored using cyclotomic decomposition to speedup computations. To disable this behaviour set cyclotomic=False. References ========== .. [1] [Gathen99]_ """ cont, g = dup_primitive(f, K) n = dup_degree(g) if dup_LC(g, K) < 0: cont, g = -cont, dup_neg(g, K) if n <= 0: return cont, [] elif n == 1: return cont, [(g, 1)] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): return cont, [(g, 1)] g = dup_sqf_part(g, K) H = None if query('USE_CYCLOTOMIC_FACTOR'): H = dup_zz_cyclotomic_factor(g, K) if H is None: H = dup_zz_zassenhaus(g, K) factors = dup_trial_division(f, H, K) return cont, factors
def dup_cyclotomic_p(f, K, irreducible=False): """ Efficiently test if ``f`` is a cyclotomic polnomial. **Examples** >>> from sympy.polys.factortools import dup_cyclotomic_p >>> from sympy.polys.domains import ZZ >>> f = [1, 0, 1, 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 1, 0, 1] >>> dup_cyclotomic_p(f, ZZ) False >>> g = [1, 0, 1, 0, 0, 0,-1, 0,-1, 0,-1, 0, 0, 0, 1, 0, 1] >>> dup_cyclotomic_p(g, ZZ) True """ if K.is_QQ: try: K0, K = K, K.get_ring() f = dup_convert(f, K0, K) except CoercionFailed: return False elif not K.is_ZZ: return False lc = dup_LC(f, K) tc = dup_TC(f, K) if lc != 1 or (tc != -1 and tc != 1): return False if not irreducible: coeff, factors = dup_factor_list(f, K) if coeff != K.one or factors != [(f, 1)]: return False n = dup_degree(f) g, h = [], [] for i in xrange(n, -1, -2): g.insert(0, f[i]) for i in xrange(n - 1, -1, -2): h.insert(0, f[i]) g = dup_sqr(dup_strip(g), K) h = dup_sqr(dup_strip(h), K) F = dup_sub(g, dup_lshift(h, 1, K), K) if K.is_negative(dup_LC(F, K)): F = dup_neg(F, K) if F == f: return True g = dup_mirror(f, K) if K.is_negative(dup_LC(g, K)): g = dup_neg(g, K) if F == g and dup_cyclotomic_p(g, K): return True G = dup_sqf_part(F, K) if dup_sqr(G, K) == F and dup_cyclotomic_p(G, K): return True return False
def dup_zz_heu_gcd(f, g, K): """ Heuristic polynomial GCD in `Z[x]`. Given univariate polynomials `f` and `g` in `Z[x]`, returns their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` such that:: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm is purely heuristic which means it may fail to compute the GCD. This will be signaled by raising an exception. In this case you will need to switch to another GCD method. The algorithm computes the polynomial GCD by evaluating polynomials f and g at certain points and computing (fast) integer GCD of those evaluations. The polynomial GCD is recovered from the integer image by interpolation. The final step is to verify if the result is the correct GCD. This gives cofactors as a side effect. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_zz_heu_gcd(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) References ========== .. [1] [Liao95]_ """ result = _dup_rr_trivial_gcd(f, g, K) if result is not None: return result df = dup_degree(f) dg = dup_degree(g) gcd, f, g = dup_extract(f, g, K) if df == 0 or dg == 0: return [gcd], f, g f_norm = dup_max_norm(f, K) g_norm = dup_max_norm(g, K) B = K(2 * min(f_norm, g_norm) + 29) x = max( min(B, 99 * K.sqrt(B)), 2 * min(f_norm // abs(dup_LC(f, K)), g_norm // abs(dup_LC(g, K))) + 2) for i in range(0, HEU_GCD_MAX): ff = dup_eval(f, x, K) gg = dup_eval(g, x, K) if ff and gg: h = K.gcd(ff, gg) cff = ff // h cfg = gg // h h = _dup_zz_gcd_interpolate(h, x, K) h = dup_primitive(h, K)[1] cff_, r = dup_div(f, h, K) if not r: cfg_, r = dup_div(g, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff_, cfg_ cff = _dup_zz_gcd_interpolate(cff, x, K) h, r = dup_div(f, cff, K) if not r: cfg_, r = dup_div(g, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff, cfg_ cfg = _dup_zz_gcd_interpolate(cfg, x, K) h, r = dup_div(g, cfg, K) if not r: cff_, r = dup_div(f, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff_, cfg x = 73794 * x * K.sqrt(K.sqrt(x)) // 27011 raise HeuristicGCDFailed('no luck')
def dmp_zz_modular_resultant(f, g, p, u, K): """ Compute resultant of `f` and `g` modulo a prime `p`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x + y + 2 >>> g = 2*x*y + x + 3 >>> R.dmp_zz_modular_resultant(f, g, 5) -2*y**2 + 1 """ if not u: return gf_int(dup_prs_resultant(f, g, K)[0] % p, p) v = u - 1 n = dmp_degree(f, u) m = dmp_degree(g, u) N = dmp_degree_in(f, 1, u) M = dmp_degree_in(g, 1, u) B = n*M + m*N D, a = [K.one], -K.one r = dmp_zero(v) while dup_degree(D) <= B: while True: a += K.one if a == p: raise HomomorphismFailed('no luck') F = dmp_eval_in(f, gf_int(a, p), 1, u, K) if dmp_degree(F, v) == n: G = dmp_eval_in(g, gf_int(a, p), 1, u, K) if dmp_degree(G, v) == m: break R = dmp_zz_modular_resultant(F, G, p, v, K) e = dmp_eval(r, a, v, K) if not v: R = dup_strip([R]) e = dup_strip([e]) else: R = [R] e = [e] d = K.invert(dup_eval(D, a, K), p) d = dup_mul_ground(D, d, K) d = dmp_raise(d, v, 0, K) c = dmp_mul(d, dmp_sub(R, e, v, K), v, K) r = dmp_add(r, c, v, K) r = dmp_ground_trunc(r, p, v, K) D = dup_mul(D, [K.one, -a], K) D = dup_trunc(D, p, K) return r