def dup_zz_hensel_step(m, f, g, h, s, t, K): """ One step in Hensel lifting in `Z[x]`. Given positive integer `m` and `Z[x]` polynomials `f`, `g`, `h`, `s` and `t` such that:: f == g*h (mod m) s*g + t*h == 1 (mod m) lc(f) is not a zero divisor (mod m) lc(h) == 1 deg(f) == deg(g) + deg(h) deg(s) < deg(h) deg(t) < deg(g) returns polynomials `G`, `H`, `S` and `T`, such that:: f == G*H (mod m**2) S*G + T**H == 1 (mod m**2) References ========== .. [1] [Gathen99]_ """ M = m**2 e = dup_sub_mul(f, g, h, K) e = dup_trunc(e, M, K) q, r = dup_div(dup_mul(s, e, K), h, K) q = dup_trunc(q, M, K) r = dup_trunc(r, M, K) u = dup_add(dup_mul(t, e, K), dup_mul(q, g, K), K) G = dup_trunc(dup_add(g, u, K), M, K) H = dup_trunc(dup_add(h, r, K), M, K) u = dup_add(dup_mul(s, G, K), dup_mul(t, H, K), K) b = dup_trunc(dup_sub(u, [K.one], K), M, K) c, d = dup_div(dup_mul(s, b, K), H, K) c = dup_trunc(c, M, K) d = dup_trunc(d, M, K) u = dup_add(dup_mul(t, b, K), dup_mul(c, G, K), K) S = dup_trunc(dup_sub(s, d, K), M, K) T = dup_trunc(dup_sub(t, u, K), M, K) return G, H, S, T
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 diofant.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 test_dmp_sub(): assert dmp_sub([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == \ dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) assert dmp_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], 0, QQ) == \ dup_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) assert dmp_sub([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_sub([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_sub([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_sub([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_sub([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_sub([[[]]], [[[]]], 2, QQ) == [[[]]] assert dmp_sub([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[QQ(1, 2)]]] assert dmp_sub([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[QQ(-1, 2)]]] assert dmp_sub([[[QQ(2, 7)]]], [[[QQ(1, 7)]]], 2, QQ) == [[[QQ(1, 7)]]] assert dmp_sub([[[QQ(1, 7)]]], [[[QQ(2, 7)]]], 2, QQ) == [[[QQ(-1, 7)]]]
def dup_chebyshevt(n, K): """Low-level implementation of Chebyshev polynomials of the 1st kind. """ seq = [[K.one], [K.one, K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n]
def dup_spherical_bessel_fn_minus(n, K): """ Low-level implementation of fn(-n, x) """ seq = [[K.one, K.zero], [K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(3 - 2 * i), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n]
def dup_sqf_list(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from diofant.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_laguerre(n, alpha, K): """Low-level implementation of Laguerre polynomials. """ seq = [[K.zero], [K.one]] for i in range(1, n + 1): a = dup_mul(seq[-1], [-K.one / i, alpha / i + K(2 * i - 1) / i], K) b = dup_mul_ground(seq[-2], alpha / i + K(i - 1) / i, K) seq.append(dup_sub(a, b, K)) return seq[-1]
def dup_legendre(n, K): """Low-level implementation of Legendre polynomials. """ seq = [[K.one], [K.one, K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2 * i - 1, i), K) b = dup_mul_ground(seq[-2], K(i - 1, i), K) seq.append(dup_sub(a, b, K)) return seq[n]
def dup_gegenbauer(n, a, K): """Low-level implementation of Gegenbauer polynomials. """ seq = [[K.one], [K(2) * a, K.zero]] for i in range(2, n + 1): f1 = K(2) * (i + a - K.one) / i f2 = (i + K(2) * a - K(2)) / i p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) p2 = dup_mul_ground(seq[-2], f2, K) seq.append(dup_sub(p1, p2, K)) return seq[n]
def dup_hermite(n, K): """Low-level implementation of Hermite polynomials. """ seq = [[K.one], [K(2), K.zero]] for i in range(2, n + 1): a = dup_lshift(seq[-1], 1, K) b = dup_mul_ground(seq[-2], K(i - 1), K) c = dup_mul_ground(dup_sub(a, b, K), K(2), K) seq.append(c) return seq[n]
def dup_jacobi(n, a, b, K): """Low-level implementation of Jacobi polynomials. """ seq = [[K.one], [(a + b + K(2)) / K(2), (a - b) / K(2)]] for i in range(2, n + 1): den = K(i) * (a + b + i) * (a + b + K(2) * i - K(2)) f0 = (a + b + K(2) * i - K.one) * (a * a - b * b) / (K(2) * den) f1 = (a + b + K(2) * i - K.one) * (a + b + K(2) * i - K(2)) * ( a + b + K(2) * i) / (K(2) * den) f2 = (a + i - K.one) * (b + i - K.one) * (a + b + K(2) * i) / den p0 = dup_mul_ground(seq[-1], f0, K) p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) p2 = dup_mul_ground(seq[-2], f2, K) seq.append(dup_sub(dup_add(p0, p1, K), p2, K)) return seq[n]
def test_dup_sub(): assert dup_sub([], [], ZZ) == [] assert dup_sub([ZZ(1)], [], ZZ) == [ZZ(1)] assert dup_sub([], [ZZ(1)], ZZ) == [ZZ(-1)] assert dup_sub([ZZ(1)], [ZZ(1)], ZZ) == [] assert dup_sub([ZZ(1)], [ZZ(2)], ZZ) == [ZZ(-1)] assert dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1), ZZ(1)] assert dup_sub([ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(-1), ZZ(-1)] assert dup_sub([ZZ(3), ZZ(2), ZZ(1)], [ZZ(8), ZZ(9), ZZ(10)], ZZ) == [ZZ(-5), ZZ(-7), ZZ(-9)] assert dup_sub([], [], QQ) == [] assert dup_sub([QQ(1, 2)], [], QQ) == [QQ(1, 2)] assert dup_sub([], [QQ(1, 2)], QQ) == [QQ(-1, 2)] assert dup_sub([QQ(1, 3)], [QQ(1, 3)], QQ) == [] assert dup_sub([QQ(1, 3)], [QQ(2, 3)], QQ) == [QQ(-1, 3)] assert dup_sub([QQ(1, 7), QQ(2, 7)], [QQ(1)], QQ) == [QQ(1, 7), QQ(-5, 7)] assert dup_sub([QQ(1)], [QQ(1, 7), QQ(2, 7)], QQ) == [QQ(-1, 7), QQ(5, 7)] assert dup_sub([QQ(3, 7), QQ(2, 7), QQ(1, 7)], [QQ(8, 7), QQ(9, 7), QQ(10, 7)], QQ) == [QQ(-5, 7), QQ(-7, 7), QQ(-9, 7)]
def dup_cyclotomic_p(f, K, irreducible=False): """ Efficiently test if ``f`` is a cyclotomic polnomial. Examples ======== >>> from diofant.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(f) False >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(g) 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 range(n, -1, -2): g.insert(0, f[i]) for i in range(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