From d3fdee32ef1325e12162d56db55382a695d367f1 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 21:31:03 +0100 Subject: [PATCH 1/8] Add .prec attribute to series Adds .prec attribute to fmpz_series, fmpq_series, arb_series and acb_series. Also fixes the doctest runner to run all tests and fixes some doctests. Make sure that doctests use the correct precision. --- src/flint/test/test_all.py | 8 + src/flint/test/test_docstrings.py | 31 ++- src/flint/types/acb_series.pxd | 2 +- src/flint/types/acb_series.pyx | 340 ++++++++++++++++-------------- src/flint/types/acb_theta.pyx | 68 +++--- src/flint/types/arb.pyx | 29 ++- src/flint/types/arb_mat.pyx | 23 +- src/flint/types/arb_poly.pyx | 2 + src/flint/types/arb_series.pxd | 2 +- src/flint/types/arb_series.pyx | 302 ++++++++++++++------------ src/flint/types/arf.pyx | 2 + src/flint/types/dirichlet.pyx | 2 + src/flint/types/fmpq_poly.pyx | 3 +- src/flint/types/fmpq_series.pxd | 2 +- src/flint/types/fmpq_series.pyx | 185 ++++++++++------ src/flint/types/fmpz_poly.pyx | 3 + src/flint/types/fmpz_series.pxd | 2 +- src/flint/types/fmpz_series.pyx | 124 +++++++---- 18 files changed, 680 insertions(+), 450 deletions(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index 8ef88ac6..bee2d5d0 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -666,7 +666,11 @@ def test_fmpz_series(): s2 = Z([1,2]) s3 = Z([1,1]) s4 = Z([1,2],11) + s5 = Z([1,2],3) p1 = Zp([1,2]) + assert s1.prec == 10 + assert s4.prec == 11 + assert s5.prec == 3 assert s1._equal_repr(s1) is True assert s1._equal_repr(s2) is True assert s1._equal_repr(s3) is False @@ -1157,10 +1161,14 @@ def test_fmpq_series(): s2 = Q([1,2]) s3 = Q([1,1]) s4 = Q([1,2],1,11) + s5 = Q([1,2],1,3) p1 = Qp([1,2]) sz1 = Z([1,2]) sz2 = Z([1,1]) sz3 = Z([1,1],11) + assert s1.prec == 10 + assert s4.prec == 11 + assert s5.prec == 3 assert s1._equal_repr(s1) is True assert s1._equal_repr(s2) is True assert s1._equal_repr(s3) is False diff --git a/src/flint/test/test_docstrings.py b/src/flint/test/test_docstrings.py index 88785f8b..ef788deb 100644 --- a/src/flint/test/test_docstrings.py +++ b/src/flint/test/test_docstrings.py @@ -5,7 +5,7 @@ import flint -dunder_test_regex = re.compile(r'^(.*?)__test__\.(.*?\.)(.*) \(line (\d+)\)$') +dunder_test_regex = re.compile(r'^(.*?)__test__\.(.*?) \(line (\d+)\)$') test_flint_at_least = { "flint.types._gr.gr_ctx.gens": 30100, @@ -16,23 +16,36 @@ def find_doctests(module): finder = doctest.DocTestFinder() tests = [] + tests_seen = set() for module_info in pkgutil.walk_packages(module.__path__, flint.__name__ + "."): try: module = importlib.import_module(module_info.name) res = [] for test in filter(lambda x: bool(x.examples), finder.find(module)): + m = dunder_test_regex.match(test.name) if m is not None: groups = m.groups() - test.name = groups[0] + groups[2] - test.lineno = int(groups[3]) - - if ( - test_flint_at_least.get("".join(groups[:3]), flint.__FLINT_RELEASE__) - <= flint.__FLINT_RELEASE__ - ): - res.append(test) + test.name = groups[0] + groups[1] + test.lineno = int(groups[2]) + + # Prefer the __test__ version of the test (remove the other) + if test.name in tests_seen: + n = len(res) + res = [r for r in res if r.name != test.name] + if len(res) != n - 1: + raise Exception(f"Duplicate test name: {test.name}") + tests_seen.remove(test.name) + + # Doctests that fail without latest flint + if test.name in test_flint_at_least: + if test_flint_at_least[test.name] > flint.__FLINT_RELEASE__: + continue + + if test.name not in tests_seen: + tests_seen.add(test.name) + res.append(test) tests.append((module_info.name, res)) diff --git a/src/flint/types/acb_series.pxd b/src/flint/types/acb_series.pxd index 6ff883fa..b34e14c5 100644 --- a/src/flint/types/acb_series.pxd +++ b/src/flint/types/acb_series.pxd @@ -4,6 +4,6 @@ from flint.flintlib.functions.acb_poly cimport acb_poly_t cdef class acb_series(flint_series): cdef acb_poly_t val - cdef long prec + cdef long _prec cpdef long length(self) cpdef valuation(self) diff --git a/src/flint/types/acb_series.pyx b/src/flint/types/acb_series.pyx index 7aac621c..f7ddd895 100644 --- a/src/flint/types/acb_series.pyx +++ b/src/flint/types/acb_series.pyx @@ -30,34 +30,48 @@ cdef acb_series_coerce_operands(x, y): return NotImplemented, NotImplemented cdef class acb_series(flint_series): + """ + Arb series. + + >>> from flint import acb_series, ctx + >>> ctx.cap = 3 + >>> x = acb_series([0, 1]) + >>> x + 1.00000000000000*x + O(x^3) + >>> 1 / (1 + x) + 1.00000000000000 + (-1.00000000000000)*x + 1.00000000000000*x^2 + O(x^3) + >>> x.cos() + 1.00000000000000 + (-0.500000000000000)*x^2 + O(x^3) + + """ # cdef acb_poly_t val # cdef long prec def __cinit__(self): acb_poly_init(self.val) - self.prec = 0 + self._prec = 0 def __dealloc__(self): acb_poly_clear(self.val) def __init__(self, val=None, prec=None): if prec is None: - self.prec = getcap() + self._prec = getcap() else: - self.prec = prec - if self.prec < 0: - self.prec = -1 + self._prec = prec + if self._prec < 0: + self._prec = -1 if val is not None: if typecheck(val, acb_series): acb_poly_set(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, arb_series): acb_poly_set_arb_poly(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_series): acb_poly_set_fmpz_poly(self.val, (val).val, getprec()) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_poly): acb_poly_set_fmpz_poly(self.val, (val).val, getprec()) elif typecheck(val, acb_poly): @@ -66,7 +80,27 @@ cdef class acb_series(flint_series): acb_poly_set_list(self.val, val, getprec()) else: acb_poly_set_list(self.val, [val], getprec()) - acb_poly_truncate(self.val, max(0, self.prec)) + acb_poly_truncate(self.val, max(0, self._prec)) + + @property + def prec(self): + """ + The precision of the finitely approximated power series. + + >>> from flint import acb_series, ctx + >>> ctx.cap = 10 + >>> a = acb_series([1,2,3]) + >>> a + 1.00000000000000 + 2.00000000000000*x + 3.00000000000000*x^2 + O(x^10) + >>> a.prec + 10 + >>> b = acb_series([1,2,3], prec=5) + >>> b + 1.00000000000000 + 2.00000000000000*x + 3.00000000000000*x^2 + O(x^5) + >>> b.prec + 5 + """ + return self._prec def __len__(self): return acb_poly_length(self.val) @@ -90,13 +124,13 @@ cdef class acb_series(flint_series): acb_poly_set_coeff_acb(self.val, i, (x).val) def repr(self, **kwargs): - return "acb_series([%s], prec=%s)" % (", ".join(map(str, self)), self.prec) + return "acb_series([%s], prec=%s)" % (", ".join(map(str, self)), self._prec) def str(self, *args, **kwargs): - if self.prec > 0: + if self._prec > 0: s = acb_poly(list(self)).str(ascending=True, *args, **kwargs) - return s + (" + O(x^%s)" % self.prec) - elif self.prec == 0: + return s + (" + O(x^%s)" % self._prec) + elif self._prec == 0: return "O(x^0)" else: return "(invalid power series)" @@ -108,11 +142,11 @@ cdef class acb_series(flint_series): cdef long cap u = acb_series.__new__(acb_series) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if cap > 0: acb_poly_neg((u).val, (s).val) acb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __add__(s, t): @@ -125,12 +159,12 @@ cdef class acb_series(flint_series): u = acb_series.__new__(acb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: acb_poly_add((u).val, (s).val, (t).val, getprec()) acb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __radd__(s, t): @@ -149,12 +183,12 @@ cdef class acb_series(flint_series): u = acb_series.__new__(acb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: acb_poly_sub((u).val, (s).val, (t).val, getprec()) acb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rsub__(s, t): @@ -173,11 +207,11 @@ cdef class acb_series(flint_series): u = acb_series.__new__(acb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: acb_poly_mullow((u).val, (s).val, (t).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def __rmul__(s, t): @@ -206,8 +240,8 @@ cdef class acb_series(flint_series): return s / t cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if (t).length() == 0: raise ZeroDivisionError("power series division") @@ -239,7 +273,7 @@ cdef class acb_series(flint_series): acb_poly_clear(stmp) acb_poly_clear(ttmp) - (u).prec = cap + (u)._prec = cap return u def __rtruediv__(s, t): @@ -260,11 +294,11 @@ cdef class acb_series(flint_series): u = acb_series.__new__(acb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: acb_poly_pow_series((u).val, (s).val, (t).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def __rpow__(s, t): @@ -280,221 +314,221 @@ cdef class acb_series(flint_series): if (t).valuation() < 1: raise ValueError("power series composition with nonzero constant term") cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) acb_poly_compose_series((u).val, (s).val, (t).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u raise TypeError("cannot call acb_series with input of type %s", type(t)) def reversion(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if s.length() < 2 or (not acb_is_zero(&s.val.coeffs[0])) or \ (acb_contains_zero(&s.val.coeffs[1])): raise ValueError("power series reversion requires valuation 1") u = acb_series.__new__(acb_series) acb_poly_revert_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def inv(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if s.length() == 0: raise ZeroDivisionError u = acb_series.__new__(acb_series) acb_poly_inv_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def derivative(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec - 1) + cap = min(cap, (s)._prec - 1) u = acb_series.__new__(acb_series) acb_poly_derivative((u).val, (s).val, getprec()) acb_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def integral(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec + 1) + cap = min(cap, (s)._prec + 1) u = acb_series.__new__(acb_series) acb_poly_integral((u).val, (s).val, getprec()) acb_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def sqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_sqrt_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rsqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_rsqrt_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def exp(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_exp_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def log(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_log_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def atan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_atan_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_sin_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def cos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_cos_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin_cos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) v = acb_series.__new__(acb_series) acb_poly_sin_cos_series((u).val, (v).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def sin_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_sin_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def cos_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_cos_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin_cos_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) v = acb_series.__new__(acb_series) acb_poly_sin_cos_pi_series((u).val, (v).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def cot_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_cot_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def tan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_tan_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def gamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_gamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rgamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_rgamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def lgamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_lgamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rising(s, ulong n): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_rising_ui_series((u).val, (s).val, n, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def zeta(s, a=1, bint deflate=0): cdef long cap a = acb(a) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_zeta_series((u).val, (s).val, (a).val, deflate, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def dirichlet_l(s, chi, bint deflate=0): @@ -505,32 +539,32 @@ cdef class acb_series(flint_series): else: cchar = dirichlet_char(chi[0], chi[1]) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_dirichlet_l_series((u).val, (s).val, cchar.G.val, cchar.val, deflate, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod def polylog(cls, s, z): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) s = acb_series(s) z = acb(z) u = acb_series.__new__(acb_series) acb_poly_polylog_series((u).val, (s).val, (z).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def agm(s, t=None): cdef long cap if t is None: cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_agm1_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u else: return (s / t).agm() * t @@ -538,47 +572,47 @@ cdef class acb_series(flint_series): def elliptic_k(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_poly_elliptic_k_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def elliptic_p(s, tau): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) tau = acb(tau) u = acb_series.__new__(acb_series) acb_poly_elliptic_p_series((u).val, (s).val, (tau).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erf(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_erf_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erfc(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_erfc_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erfi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_erfi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -587,10 +621,10 @@ cdef class acb_series(flint_series): s = acb(s) z = acb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_gamma_upper_series((u).val, (s).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -599,10 +633,10 @@ cdef class acb_series(flint_series): s = acb(s) z = acb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_gamma_lower_series((u).val, (s).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -612,10 +646,10 @@ cdef class acb_series(flint_series): b = acb(b) z = acb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_beta_lower_series((u).val, (a).val, (b).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -639,86 +673,86 @@ cdef class acb_series(flint_series): aa = libc.stdlib.malloc(p * cython.sizeof(acb_poly_struct)) bb = libc.stdlib.malloc(q * cython.sizeof(acb_poly_struct)) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) for i in range(p): - cap = min(cap, ((a[i])).prec) + cap = min(cap, ((a[i]))._prec) aa[i] = ((a[i])).val[0] for i in range(q): - cap = min(cap, ((b[i])).prec) + cap = min(cap, ((b[i]))._prec) bb[i] = ((b[i])).val[0] u = acb_series.__new__(acb_series) acb_hypgeom_pfq_series_direct((u).val, aa, p, bb, q, (z).val, regularized, n, cap, getprec()) libc.stdlib.free(aa) libc.stdlib.free(bb) - (u).prec = cap + (u)._prec = cap return u def airy_ai(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_airy_series((u).val, NULL, NULL, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_ai_prime(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_airy_series(NULL, (u).val, NULL, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_bi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_airy_series(NULL, NULL, (u).val, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_bi_prime(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_airy_series(NULL, NULL, NULL, (u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) v = acb_series.__new__(acb_series) w = acb_series.__new__(acb_series) z = acb_series.__new__(acb_series) acb_hypgeom_airy_series((u).val, (v).val, (w).val, (z).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap - (w).prec = cap - (z).prec = cap + (u)._prec = cap + (v)._prec = cap + (w)._prec = cap + (z)._prec = cap return u, v, w, z def modular_theta(self, tau): cdef long cap tau = acb(tau) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) t1 = acb_series.__new__(acb_series) t2 = acb_series.__new__(acb_series) t3 = acb_series.__new__(acb_series) t4 = acb_series.__new__(acb_series) acb_modular_theta_series((t1).val, (t2).val, (t3).val, (t4).val, (self).val, (tau).val, cap, getprec()) - (t1).prec = cap - (t2).prec = cap - (t3).prec = cap - (t4).prec = cap + (t1)._prec = cap + (t2)._prec = cap + (t3)._prec = cap + (t4)._prec = cap return t1, t2, t3, t4 def coulomb(self, l, eta): @@ -726,7 +760,7 @@ cdef class acb_series(flint_series): l = acb(l) eta = acb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) F = acb_series.__new__(acb_series) G = acb_series.__new__(acb_series) Hpos = acb_series.__new__(acb_series) @@ -734,10 +768,10 @@ cdef class acb_series(flint_series): acb_hypgeom_coulomb_series((F).val, (G).val, (Hpos).val, (Hneg).val, (l).val, (eta).val, (self).val, cap, getprec()) - (F).prec = cap - (G).prec = cap - (Hpos).prec = cap - (Hneg).prec = cap + (F)._prec = cap + (G)._prec = cap + (Hpos)._prec = cap + (Hneg)._prec = cap return F, G, Hpos, Hneg def coulomb_f(self, l, eta): @@ -745,11 +779,11 @@ cdef class acb_series(flint_series): l = acb(l) eta = acb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) F = acb_series.__new__(acb_series) acb_hypgeom_coulomb_series((F).val, NULL, NULL, NULL, (l).val, (eta).val, (self).val, cap, getprec()) - (F).prec = cap + (F)._prec = cap return F def coulomb_g(self, l, eta): @@ -757,102 +791,102 @@ cdef class acb_series(flint_series): l = acb(l) eta = acb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) G = acb_series.__new__(acb_series) acb_hypgeom_coulomb_series(NULL, (G).val, NULL, NULL, (l).val, (eta).val, (self).val, cap, getprec()) - (G).prec = cap + (G)._prec = cap return G def fresnel(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) v = acb_series.__new__(acb_series) acb_hypgeom_fresnel_series((u).val, (v).val, (s).val, normalized, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def fresnel_s(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_fresnel_series((u).val, NULL, (s).val, normalized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def fresnel_c(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_fresnel_series(NULL, (u).val, (s).val, normalized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def ei(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_ei_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def si(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_si_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def ci(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_ci_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def shi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_shi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def chi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_chi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def li(s, bint offset=False): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = acb_series.__new__(acb_series) acb_hypgeom_li_series((u).val, (s).val, offset, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def lambertw(s, branch=0): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) k = any_as_fmpz(branch) u = acb_series.__new__(acb_series) acb_poly_lambertw_series((u).val, (s).val, (k).val, 0, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u diff --git a/src/flint/types/acb_theta.pyx b/src/flint/types/acb_theta.pyx index 09e2e168..269728ad 100644 --- a/src/flint/types/acb_theta.pyx +++ b/src/flint/types/acb_theta.pyx @@ -23,48 +23,48 @@ def acb_theta(acb_mat z, acb_mat tau, ulong square=False): >>> from flint import acb, acb_mat, showgood, ctx >>> z = acb(1+1j); tau = acb(1.25+3j) >>> t0, t1, t2, t3 = acb_mat([[tau]]).theta(acb_mat([[z]])).entries() - >>> sum([abs(x) for x in acb_mat([z.modular_theta(tau)]) - acb_mat([[-t3,t2,t0,t1]])]) - [+/- 3.82e-14] + >>> all([abs(x) < 1e-13 for x in acb_mat([z.modular_theta(tau)]) - acb_mat([[-t3,t2,t0,t1]])]) + True >>> showgood(lambda: acb_mat([[tau]]).theta(acb_mat([[z]])).transpose(), dps=25) [0.9694430387796704100046143 - 0.03055696120816803328582847j] [ 1.030556961196006476576271 + 0.03055696120816803328582847j] [ -1.220790267576967690128359 - 1.827055516791154669091679j] [ -1.820235910124989594900076 + 1.216251950154477951760042j] >>> acb_mat([[1j,0],[0,2*1j]]).theta(acb_mat([[0],[0]])).transpose() - [ [1.09049252082308 +/- 3.59e-15] + [+/- 2.43e-16]j] - [ [1.08237710165638 +/- 4.15e-15] + [+/- 2.43e-16]j] - [[0.916991251621117 +/- 6.30e-16] + [+/- 2.43e-16]j] - [[0.910167024735558 +/- 7.93e-16] + [+/- 2.43e-16]j] - [[0.451696791791346 +/- 5.46e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [[0.379830212998946 +/- 4.47e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [[0.916991251621117 +/- 6.30e-16] + [+/- 2.43e-16]j] - [[0.910167024735558 +/- 7.93e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [[0.379830212998946 +/- 4.47e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] - [ [+/- 2.43e-16] + [+/- 2.43e-16]j] + [ [1.09049252082308 +/- 5.07e-15] + [+/- 1.73e-15]j] + [ [1.08237710165638 +/- 5.64e-15] + [+/- 1.74e-15]j] + [ [0.91699125162112 +/- 4.17e-15] + [+/- 1.33e-15]j] + [ [0.91016702473556 +/- 3.01e-15] + [+/- 1.34e-15]j] + [[0.451696791791346 +/- 4.89e-16] + [+/- 1.86e-16]j] + [ [+/- 5.42e-16] + [+/- 5.42e-16]j] + [[0.379830212998946 +/- 3.47e-16] + [+/- 1.43e-16]j] + [ [+/- 4.62e-16] + [+/- 4.62e-16]j] + [ [0.91699125162112 +/- 6.83e-15] + [+/- 4.00e-15]j] + [ [0.91016702473556 +/- 5.70e-15] + [+/- 4.02e-15]j] + [ [+/- 2.44e-16] + [+/- 2.44e-16]j] + [ [+/- 2.45e-16] + [+/- 2.45e-16]j] + [[0.379830212998946 +/- 6.39e-16] + [+/- 4.35e-16]j] + [ [+/- 5.86e-16] + [+/- 5.86e-16]j] + [ [+/- 2.60e-17] + [+/- 2.60e-17]j] + [ [+/- 1.16e-16] + [+/- 1.16e-16]j] >>> ctx.prec = 10000 >>> print(acb_mat([[1j, 0],[0,1j]]).theta(acb_mat([[0],[0]])).transpose().str(25)) - [ [1.180340599016096226045338 +/- 5.95e-26] + [+/- 1.23e-3010]j] - [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 1.23e-3010]j] - [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 1.23e-3010]j] - [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 1.23e-3010]j] - [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 1.23e-3010]j] - [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] - [ [+/- 1.23e-3010] + [+/- 1.23e-3010]j] + [ [1.180340599016096226045338 +/- 5.95e-26] + [+/- 2.35e-3010]j] + [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 2.79e-3010]j] + [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 1.88e-3010]j] + [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 2.23e-3010]j] + [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 5.80e-3011]j] + [ [+/- 1.35e-3009] + [+/- 1.35e-3009]j] + [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 4.64e-3011]j] + [ [+/- 1.14e-3009] + [+/- 1.14e-3009]j] + [[0.9925441784910574194770081 +/- 3.15e-26] + [+/- 3.16e-3009]j] + [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 3.75e-3009]j] + [ [+/- 4.05e-3011] + [+/- 4.05e-3011]j] + [ [+/- 4.81e-3011] + [+/- 4.81e-3011]j] + [[0.8346268416740731862814297 +/- 3.29e-26] + [+/- 7.80e-3010]j] + [ [+/- 5.19e-3009] + [+/- 5.19e-3009]j] + [ [+/- 1.00e-3011] + [+/- 1.00e-3011]j] + [ [+/- 2.81e-3010] + [+/- 2.81e-3010]j] >>> ctx.default() """ diff --git a/src/flint/types/arb.pyx b/src/flint/types/arb.pyx index 94c281ae..4902f65f 100644 --- a/src/flint/types/arb.pyx +++ b/src/flint/types/arb.pyx @@ -222,6 +222,8 @@ cdef class arb(flint_scalar): returning an *fmpz* pair. Requires that *self* is exact and finite. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb("1.1").mid().man_exp() (4953959590107545, -52) >>> arb("1.1").rad().man_exp() @@ -268,6 +270,8 @@ cdef class arb(flint_scalar): """ Returns the midpoint of *self* as an exact *arb*: + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb("1 +/- 0.3").mid() 1.00000000000000 """ @@ -399,6 +403,8 @@ cdef class arb(flint_scalar): Binary-decimal-binary roundtrips may result in significantly larger intervals, and should therefore be done sparingly. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> print(arb.pi().str()) [3.14159265358979 +/- 3.34e-15] >>> print(arb.pi().str(5)) @@ -561,6 +567,8 @@ cdef class arb(flint_scalar): """ Sign function, returning an *arb*. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb(-3).sgn() -1.00000000000000 >>> arb(0).sgn() @@ -700,6 +708,8 @@ cdef class arb(flint_scalar): r""" Floor function `\lfloor s \rfloor`. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> print(arb.pi().floor()) 3.00000000000000 >>> print((arb.pi() - arb.pi()).floor().str(more=True)) @@ -833,6 +843,8 @@ cdef class arb(flint_scalar): r""" Returns `\log_b(s)`, computed exactly when possible. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb(2048).log_base(2) 11.0000000000000 """ @@ -1358,6 +1370,8 @@ cdef class arb(flint_scalar): The current implementation does not use the gamma function, so *n* should be moderate. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> u, v = arb(3).rising2(5) >>> print(u); print(v) 2520.00000000000 @@ -1506,6 +1520,8 @@ cdef class arb(flint_scalar): """ Factorial `n!`, given an integer. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> print(arb.fac_ui(10)) 3628800.00000000 >>> from flint import showgood @@ -1522,9 +1538,10 @@ cdef class arb(flint_scalar): to an integer; this restriction will be removed in the future by using the gamma function. + >>> from flint import arb, ctx, showgood + >>> ctx.prec = 53 >>> print(arb(10).bin(5)) 252.000000000000 - >>> from flint import showgood >>> showgood(lambda: arb.pi().bin(100), dps=25) 5.478392395095119521549286e-9 """ @@ -1537,6 +1554,8 @@ cdef class arb(flint_scalar): r""" Binomial coefficient `{n \choose k}`. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> print(arb.bin_uiui(10, 5)) 252.000000000000 """ @@ -1550,6 +1569,8 @@ cdef class arb(flint_scalar): Computes the Fibonacci number `F_n` as an *arb*, where *n* is a given integer. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> print(arb.fib(10)) 55.0000000000000 >>> from flint import showgood @@ -2495,6 +2516,8 @@ cdef class arb(flint_scalar): """ Returns a ball containing the union of *s* and *t*. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> x = arb(3).union(5); x.lower(); x.upper() [2.99999999813735 +/- 4.86e-15] [5.00000000186265 +/- 4.86e-15] @@ -2526,6 +2549,8 @@ cdef class arb(flint_scalar): """ Minimum value of *s* and *t*. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb(2).min(3) 2.00000000000000 >>> arb(2).min(arb("3 +/- 1.1")) @@ -2585,6 +2610,8 @@ cdef class arb(flint_scalar): Number of zeros of the Riemann zeta function with positive imaginary part between 0 and *x*. + >>> from flint import arb, ctx + >>> ctx.prec = 53 >>> arb("-5").zeta_nzeros() 0 >>> arb("14").zeta_nzeros() diff --git a/src/flint/types/arb_mat.pyx b/src/flint/types/arb_mat.pyx index 92097a1d..ed8f13ab 100644 --- a/src/flint/types/arb_mat.pyx +++ b/src/flint/types/arb_mat.pyx @@ -46,6 +46,8 @@ cdef class arb_mat(flint_mat): """ Represents a matrix over the real numbers. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> A = arb_mat([[1,2],[3,4]]) ** 2 / 5 >>> A [[1.40000000000000 +/- 3.12e-16], 2.00000000000000] @@ -202,7 +204,8 @@ cdef class arb_mat(flint_mat): """ Returns the determinant of the square matrix *s* as an *arb*. - >>> from flint import showgood + >>> from flint import showgood, ctx + >>> ctx.prec = 53 >>> A = arb_mat(3, 3, range(9)) >>> showgood(lambda: A.det(), dps=25) # exact singular 0 @@ -351,6 +354,8 @@ cdef class arb_mat(flint_mat): unless *nonstop* is set in which case a matrix with NaN entries is returned. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> A = arb_mat(2, 2, [1, 5, 2, 4]) >>> print(A * A.inv()) [[1.00000000000000 +/- 6.11e-16], [+/- 3.34e-16]] @@ -388,6 +393,8 @@ cdef class arb_mat(flint_mat): unless *nonstop* is set in which case a matrix with NaN entries is returned. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> A = arb_mat(2, 2, [1, 2, 3, 4]) >>> X = arb_mat(2, 3, range(6)) >>> B = A * X @@ -438,6 +445,8 @@ cdef class arb_mat(flint_mat): """ Returns the matrix exponential of *s*. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> print(arb_mat(2, 2, [1, 4, -2, 1]).exp()) [ [-2.58607310345045 +/- 5.06e-15], [1.18429895089106 +/- 1.15e-15]] [[-0.592149475445530 +/- 5.73e-16], [-2.58607310345045 +/- 5.06e-15]] @@ -454,6 +463,8 @@ cdef class arb_mat(flint_mat): """ Returns the characteristic polynomial of *s* as an *arb_poly*. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> print(arb_mat(2, 2, [1, 1, 1, 0]).charpoly()) 1.00000000000000*x^2 + (-1.00000000000000)*x + (-1.00000000000000) """ @@ -481,6 +492,8 @@ cdef class arb_mat(flint_mat): """ Returns the trace of the square matrix *s* as an *arb*. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> arb_mat([[3,4],[5,7]]).trace() 10.0000000000000 """ @@ -496,6 +509,8 @@ cdef class arb_mat(flint_mat): """ Returns the *n* by *m* truncated Hilbert matrix. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> arb_mat.hilbert(6,2) [ 1.00000000000000, 0.500000000000000] [ 0.500000000000000, [0.333333333333333 +/- 3.71e-16]] @@ -520,6 +535,8 @@ cdef class arb_mat(flint_mat): *triangular* is -1 or 1, the lower or upper triangular version of the Pascal matrix is returned. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> arb_mat.pascal(3, 4) [1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000] [1.00000000000000, 2.00000000000000, 3.00000000000000, 4.00000000000000] @@ -550,6 +567,8 @@ cdef class arb_mat(flint_mat): first kind, 1 for signed Stirling numbers of the first kind, and 2 for Stirling numbers of the second kind. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> arb_mat.stirling(5, 4) [1.00000000000000, 0, 0, 0] [ 0, 1.00000000000000, 0, 0] @@ -645,6 +664,8 @@ cdef class arb_mat(flint_mat): Returns a copy of *s* where entries that are bounded by *tol* in magnitude have been replaced by exact zeros. + >>> from flint import arb_mat, ctx + >>> ctx.prec = 53 >>> print(arb_mat.stirling(4, 4).inv().str(5, radius=False)) [1.0000, 0, 0, 0] [ 0, 1.0000, 0e-14, 0e-15] diff --git a/src/flint/types/arb_poly.pyx b/src/flint/types/arb_poly.pyx index aae3025a..41e99699 100644 --- a/src/flint/types/arb_poly.pyx +++ b/src/flint/types/arb_poly.pyx @@ -95,6 +95,8 @@ cdef class arb_poly(flint_poly): """ Constructs the monic polynomial whose roots are the given real numbers. + >>> from flint import arb_poly, ctx + >>> ctx.prec = 53 >>> arb_poly.from_roots(range(4)) 1.00000000000000*x^4 + (-6.00000000000000)*x^3 + 11.0000000000000*x^2 + (-6.00000000000000)*x diff --git a/src/flint/types/arb_series.pxd b/src/flint/types/arb_series.pxd index a26e17cb..c7bc04ab 100644 --- a/src/flint/types/arb_series.pxd +++ b/src/flint/types/arb_series.pxd @@ -4,6 +4,6 @@ from flint.flintlib.functions.arb_poly cimport arb_poly_t cdef class arb_series(flint_series): cdef arb_poly_t val - cdef long prec + cdef long _prec cpdef long length(self) cpdef valuation(self) diff --git a/src/flint/types/arb_series.pyx b/src/flint/types/arb_series.pyx index f18e38a5..016070c5 100644 --- a/src/flint/types/arb_series.pyx +++ b/src/flint/types/arb_series.pyx @@ -31,29 +31,29 @@ cdef arb_series_coerce_operands(x, y): cdef class arb_series(flint_series): # cdef arb_poly_t val - # cdef long prec + # cdef long _prec def __cinit__(self): arb_poly_init(self.val) - self.prec = 0 + self._prec = 0 def __dealloc__(self): arb_poly_clear(self.val) def __init__(self, val=None, prec=None): if prec is None: - self.prec = getcap() + self._prec = getcap() else: - self.prec = prec - if self.prec < 0: - self.prec = -1 + self._prec = prec + if self._prec < 0: + self._prec = -1 if val is not None: if typecheck(val, arb_series): arb_poly_set(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_series): arb_poly_set_fmpz_poly(self.val, (val).val, getprec()) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_poly): arb_poly_set_fmpz_poly(self.val, (val).val, getprec()) elif typecheck(val, arb_poly): @@ -62,7 +62,27 @@ cdef class arb_series(flint_series): arb_poly_set_list(self.val, val, getprec()) else: arb_poly_set_list(self.val, [val], getprec()) - arb_poly_truncate(self.val, max(0, self.prec)) + arb_poly_truncate(self.val, max(0, self._prec)) + + @property + def prec(self): + """ + The term precision of the finitely approximated series. + + >>> from flint import arb_series, ctx + >>> ctx.cap = 10 + >>> s = arb_series([1,2]) + >>> s + 1.00000000000000 + 2.00000000000000*x + O(x^10) + >>> s.prec + 10 + >>> s2 = arb_series([1,2], prec=3) + >>> s2 + 1.00000000000000 + 2.00000000000000*x + O(x^3) + >>> s2.prec + 3 + """ + return self._prec def __len__(self): return arb_poly_length(self.val) @@ -86,13 +106,13 @@ cdef class arb_series(flint_series): arb_poly_set_coeff_arb(self.val, i, (x).val) def repr(self, **kwargs): - return "arb_series([%s], prec=%s)" % (", ".join(map(str, self)), self.prec) + return "arb_series([%s], prec=%s)" % (", ".join(map(str, self)), self._prec) def str(self, *args, **kwargs): - if self.prec > 0: + if self._prec > 0: s = arb_poly(list(self)).str(ascending=True, *args, **kwargs) - return s + (" + O(x^%s)" % self.prec) - elif self.prec == 0: + return s + (" + O(x^%s)" % self._prec) + elif self._prec == 0: return "O(x^0)" else: return "(invalid power series)" @@ -104,11 +124,11 @@ cdef class arb_series(flint_series): cdef long cap u = arb_series.__new__(arb_series) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if cap > 0: arb_poly_neg((u).val, (s).val) arb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __add__(s, t): @@ -120,12 +140,12 @@ cdef class arb_series(flint_series): return s + t u = arb_series.__new__(arb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: arb_poly_add((u).val, (s).val, (t).val, getprec()) arb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __radd__(s, t): @@ -143,12 +163,12 @@ cdef class arb_series(flint_series): return s - t u = arb_series.__new__(arb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: arb_poly_sub((u).val, (s).val, (t).val, getprec()) arb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rsub__(s, t): @@ -166,12 +186,12 @@ cdef class arb_series(flint_series): return s * t u = arb_series.__new__(arb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: arb_poly_mul((u).val, (s).val, (t).val, getprec()) arb_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rmul__(s, t): @@ -199,8 +219,8 @@ cdef class arb_series(flint_series): return s / t cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if (t).length() == 0: raise ZeroDivisionError("power series division") @@ -232,7 +252,7 @@ cdef class arb_series(flint_series): arb_poly_clear(stmp) arb_poly_clear(ttmp) - (u).prec = cap + (u)._prec = cap return u def __rtruediv__(s, t): @@ -253,11 +273,11 @@ cdef class arb_series(flint_series): u = arb_series.__new__(arb_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: arb_poly_pow_series((u).val, (s).val, (t).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def __rpow__(s, t, mod): @@ -273,419 +293,419 @@ cdef class arb_series(flint_series): if (t).valuation() < 1: raise ValueError("power series composition with nonzero constant term") cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) arb_poly_compose_series((u).val, (s).val, (t).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u raise TypeError("cannot call arb_series with input of type %s", type(t)) def reversion(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if s.length() < 2 or (not arb_is_zero(&s.val.coeffs[0])) or \ (not arb_is_nonzero(&s.val.coeffs[1])): raise ValueError("power series reversion requires valuation 1") u = arb_series.__new__(arb_series) arb_poly_revert_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def inv(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if s.length() == 0: raise ZeroDivisionError u = arb_series.__new__(arb_series) arb_poly_inv_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def derivative(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec - 1) + cap = min(cap, (s)._prec - 1) u = arb_series.__new__(arb_series) arb_poly_derivative((u).val, (s).val, getprec()) arb_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def integral(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec + 1) + cap = min(cap, (s)._prec + 1) u = arb_series.__new__(arb_series) arb_poly_integral((u).val, (s).val, getprec()) arb_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def sqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_sqrt_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rsqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_rsqrt_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def exp(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_exp_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def log(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_log_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def atan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_atan_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def asin(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_asin_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def acos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_acos_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_sin_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def cos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_cos_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin_cos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) v = arb_series.__new__(arb_series) arb_poly_sin_cos_series((u).val, (v).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def sin_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_sin_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def cos_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_cos_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def sin_cos_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) v = arb_series.__new__(arb_series) arb_poly_sin_cos_pi_series((u).val, (v).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def cot_pi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_cot_pi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def tan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_tan_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def gamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_gamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rgamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_rgamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def lgamma(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_lgamma_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def rising(s, ulong n): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_rising_ui_series((u).val, (s).val, n, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def zeta(s, a=1, bint deflate=0): cdef long cap a = arb(a) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_zeta_series((u).val, (s).val, (a).val, deflate, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def riemann_siegel_theta(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_riemann_siegel_theta_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def riemann_siegel_z(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_riemann_siegel_z_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erf(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_erf_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erfc(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_erfc_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def erfi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_erfi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def fresnel(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) v = arb_series.__new__(arb_series) arb_hypgeom_fresnel_series((u).val, (v).val, (s).val, normalized, cap, getprec()) - (u).prec = cap - (v).prec = cap + (u)._prec = cap + (v)._prec = cap return u, v def fresnel_s(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_fresnel_series((u).val, NULL, (s).val, normalized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def fresnel_c(s, bint normalized=True): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_fresnel_series(NULL, (u).val, (s).val, normalized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def ei(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_ei_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def si(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_si_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def ci(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_ci_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def shi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_shi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def chi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_chi_series((u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def li(s, bint offset=False): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_li_series((u).val, (s).val, offset, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_ai(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_airy_series((u).val, NULL, NULL, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_ai_prime(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_airy_series(NULL, (u).val, NULL, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_bi(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_airy_series(NULL, NULL, (u).val, NULL, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy_bi_prime(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_airy_series(NULL, NULL, NULL, (u).val, (s).val, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def airy(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) v = arb_series.__new__(arb_series) w = arb_series.__new__(arb_series) z = arb_series.__new__(arb_series) arb_hypgeom_airy_series((u).val, (v).val, (w).val, (z).val, (s).val, cap, getprec()) - (u).prec = cap - (v).prec = cap - (w).prec = cap - (z).prec = cap + (u)._prec = cap + (v)._prec = cap + (w)._prec = cap + (z)._prec = cap return u, v, w, z def coulomb(self, l, eta): @@ -693,13 +713,13 @@ cdef class arb_series(flint_series): l = arb(l) eta = arb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) F = arb_series.__new__(arb_series) G = arb_series.__new__(arb_series) arb_hypgeom_coulomb_series((F).val, (G).val, (l).val, (eta).val, (self).val, cap, getprec()) - (F).prec = cap - (G).prec = cap + (F)._prec = cap + (G)._prec = cap return F, G def coulomb_f(self, l, eta): @@ -707,11 +727,11 @@ cdef class arb_series(flint_series): l = arb(l) eta = arb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) F = arb_series.__new__(arb_series) arb_hypgeom_coulomb_series((F).val, NULL, (l).val, (eta).val, (self).val, cap, getprec()) - (F).prec = cap + (F)._prec = cap return F def coulomb_g(self, l, eta): @@ -719,11 +739,11 @@ cdef class arb_series(flint_series): l = arb(l) eta = arb(eta) cap = getcap() - cap = min(cap, (self).prec) + cap = min(cap, (self)._prec) G = arb_series.__new__(arb_series) arb_hypgeom_coulomb_series(NULL, (G).val, (l).val, (eta).val, (self).val, cap, getprec()) - (G).prec = cap + (G)._prec = cap return G @classmethod @@ -732,10 +752,10 @@ cdef class arb_series(flint_series): s = arb(s) z = arb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_gamma_upper_series((u).val, (s).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -744,10 +764,10 @@ cdef class arb_series(flint_series): s = arb(s) z = arb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_gamma_lower_series((u).val, (s).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @classmethod @@ -757,10 +777,10 @@ cdef class arb_series(flint_series): b = arb(b) z = arb_series(z) cap = getcap() - cap = min(cap, (z).prec) + cap = min(cap, (z)._prec) u = arb_series.__new__(arb_series) arb_hypgeom_beta_lower_series((u).val, (a).val, (b).val, (z).val, regularized, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u def lambertw(s, int branch=0): @@ -773,10 +793,10 @@ cdef class arb_series(flint_series): else: raise ValueError("invalid branch") cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = arb_series.__new__(arb_series) arb_poly_lambertw_series((u).val, (s).val, flags, cap, getprec()) - (u).prec = cap + (u)._prec = cap return u @staticmethod @@ -789,6 +809,8 @@ cdef class arb_series(flint_series): This is just a test implementation; more options including support for Newton refinement will be added in a future version. + >>> from flint import arb_series, ctx + >>> ctx.prec = 53 >>> for c in arb_series.find_roots(lambda x: x.sin(), -8, 8): print(c) ... (-6.96875000000000, -5.93750000000000) diff --git a/src/flint/types/arf.pyx b/src/flint/types/arf.pyx index e9eba4fb..39b2857c 100644 --- a/src/flint/types/arf.pyx +++ b/src/flint/types/arf.pyx @@ -26,6 +26,8 @@ cdef class arf: Create a new arf from an integer, a Python float, an existing arf, or a tuple containing (mantissa, exponent):: + >>> from flint import arf, ctx + >>> ctx.prec = 53 >>> arf(-100) -100.000000000000 >>> arf(15.125) diff --git a/src/flint/types/dirichlet.pyx b/src/flint/types/dirichlet.pyx index 550cf038..de58790e 100644 --- a/src/flint/types/dirichlet.pyx +++ b/src/flint/types/dirichlet.pyx @@ -59,6 +59,8 @@ cdef class dirichlet_char(object): Calling the character evaluates the character at the given integer, returning an acb. + >>> from flint import dirichlet_char, ctx + >>> ctx.prec = 53 >>> chi = dirichlet_char(7, 1) >>> for n in range(7): ... print(chi(n)) diff --git a/src/flint/types/fmpq_poly.pyx b/src/flint/types/fmpq_poly.pyx index cd59ec01..389ad6ad 100644 --- a/src/flint/types/fmpq_poly.pyx +++ b/src/flint/types/fmpq_poly.pyx @@ -541,7 +541,8 @@ cdef class fmpq_poly(flint_poly): Computes the complex roots of this polynomial. See :meth:`.fmpz_poly.roots`. - >>> from flint import fmpq + >>> from flint import fmpq, ctx + >>> ctx.prec = 53 >>> fmpq_poly([fmpq(2,3),1]).complex_roots() [([-0.666666666666667 +/- 3.34e-16], 1)] """ diff --git a/src/flint/types/fmpq_series.pxd b/src/flint/types/fmpq_series.pxd index 8bfc5905..e1e02a01 100644 --- a/src/flint/types/fmpq_series.pxd +++ b/src/flint/types/fmpq_series.pxd @@ -3,7 +3,7 @@ from flint.flintlib.functions.fmpq_poly cimport fmpq_poly_t cdef class fmpq_series(flint_series): cdef fmpq_poly_t val - cdef long prec + cdef long _prec cpdef long length(self) cpdef valuation(self) cdef bint zero_constant_term(s) diff --git a/src/flint/types/fmpq_series.pyx b/src/flint/types/fmpq_series.pyx index a2ee0260..1ce75c10 100644 --- a/src/flint/types/fmpq_series.pyx +++ b/src/flint/types/fmpq_series.pyx @@ -31,30 +31,54 @@ cdef fmpq_series_coerce_operands(x, y): cdef class fmpq_series(flint_series): + """ + Approximate truncated power series with rational coefficients. + + >>> from flint import fmpq_series, ctx + >>> ctx.cap = 10 + + >>> fmpq_series([1,2,3]) + 1 + 2*x + 3*x^2 + O(x^10) + >>> fmpq_series([1,2,3], prec=2) + 1 + 2*x + O(x^2) + + >>> x = fmpq_series([0,1]) + >>> x + x + O(x^10) + >>> 1/(x+1) + 1 + (-1)*x + x^2 + (-1)*x^3 + x^4 + (-1)*x^5 + x^6 + (-1)*x^7 + x^8 + (-1)*x^9 + O(x^10) + >>> x.sin() + x + (-1/6)*x^3 + 1/120*x^5 + (-1/5040)*x^7 + 1/362880*x^9 + O(x^10) + + Elements can have greater or less precision than the context's ``cap`` + but operations will be truncated to ``cap`` terms. + + """ + # cdef fmpq_poly_t val - # cdef long prec + # cdef long _prec def __cinit__(self): fmpq_poly_init(self.val) - self.prec = 0 + self._prec = 0 def __dealloc__(self): fmpq_poly_clear(self.val) def __init__(self, val=None, den=None, prec=None): if prec is None: - self.prec = getcap() + self._prec = getcap() else: - self.prec = prec - if self.prec < 0: - self.prec = -1 + self._prec = prec + if self._prec < 0: + self._prec = -1 if val is not None: if typecheck(val, fmpq_series): fmpq_poly_set(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_series): fmpq_poly_set_fmpz_poly(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_poly): fmpq_poly_set_fmpz_poly(self.val, (val).val) elif typecheck(val, fmpq_poly): @@ -63,7 +87,7 @@ cdef class fmpq_series(flint_series): fmpq_poly_set_list(self.val, val) else: fmpq_poly_set_list(self.val, [val]) - fmpq_poly_truncate(self.val, max(0, self.prec)) + fmpq_poly_truncate(self.val, max(0, self._prec)) if den is not None: den = any_as_fmpz(den) if den is NotImplemented: @@ -72,13 +96,33 @@ cdef class fmpq_series(flint_series): raise ZeroDivisionError("cannot create fmpq_series with zero denominator") fmpq_poly_scalar_div_fmpz(self.val, self.val, (den).val) + @property + def prec(self): + """ + The term precision of the finitely approximated series. + + >>> from flint import fmpq_series, ctx + >>> ctx.cap = 10 + >>> s = fmpq_series([1,2]) + >>> s + 1 + 2*x + O(x^10) + >>> s.prec + 10 + >>> s2 = fmpq_series([1,2], prec=3) + >>> s2 + 1 + 2*x + O(x^3) + >>> s2.prec + 3 + """ + return self._prec + def _equal_repr(s, t): cdef bint r if not typecheck(t, fmpq_series): return False r = fmpq_poly_equal((s).val, (t).val) if r: - r = (s).prec == (t).prec + r = (s)._prec == (t)._prec return r def __len__(self): @@ -90,7 +134,7 @@ cdef class fmpq_series(flint_series): def numer(self): cdef fmpz_series x = fmpz_series.__new__(fmpz_series) fmpq_poly_get_numerator(x.val, self.val) - x.prec = self.prec + x._prec = self._prec return x def denom(self): @@ -117,13 +161,13 @@ cdef class fmpq_series(flint_series): fmpq_poly_set_coeff_fmpq(self.val, i, (x).val) def repr(self, **kwargs): - return "fmpq_series([%s], %s, prec=%s)" % (", ".join(map(str, self.numer())), str(self.denom()), self.prec) + return "fmpq_series([%s], %s, prec=%s)" % (", ".join(map(str, self.numer())), str(self.denom()), self._prec) def str(self, **kwargs): - if self.prec > 0: + if self._prec > 0: s = fmpq_poly(list(self)).str(ascending=True) - return s + (" + O(x^%s)" % self.prec) - elif self.prec == 0: + return s + (" + O(x^%s)" % self._prec) + elif self._prec == 0: return "O(x^0)" else: return "(invalid power series)" @@ -135,11 +179,11 @@ cdef class fmpq_series(flint_series): cdef long cap u = fmpq_series.__new__(fmpq_series) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if cap > 0: fmpq_poly_neg((u).val, (s).val) fmpq_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __add__(s, t): @@ -151,12 +195,12 @@ cdef class fmpq_series(flint_series): cdef long cap u = fmpq_series.__new__(fmpq_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpq_poly_add((u).val, (s).val, (t).val) fmpq_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __radd__(s, t): @@ -174,12 +218,12 @@ cdef class fmpq_series(flint_series): cdef long cap u = fmpq_series.__new__(fmpq_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpq_poly_sub((u).val, (s).val, (t).val) fmpq_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rsub__(s, t): @@ -197,11 +241,11 @@ cdef class fmpq_series(flint_series): cdef long cap u = fmpq_series.__new__(fmpq_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpq_poly_mullow((u).val, (s).val, (t).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rmul__(s, t): @@ -224,8 +268,8 @@ cdef class fmpq_series(flint_series): cdef long cap, sval, tval cdef fmpq_poly_t stmp, ttmp cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if fmpq_poly_is_zero((t).val): raise ZeroDivisionError("power series division") @@ -233,7 +277,7 @@ cdef class fmpq_series(flint_series): u = fmpq_series.__new__(fmpq_series) if fmpq_poly_is_zero((s).val): - (u).prec = cap + (u)._prec = cap return u sval = (s).valuation() @@ -257,7 +301,7 @@ cdef class fmpq_series(flint_series): fmpq_poly_clear(stmp) fmpq_poly_clear(ttmp) - (u).prec = cap + (u)._prec = cap return u def __truediv__(s, t): @@ -301,10 +345,10 @@ cdef class fmpq_series(flint_series): if (t).valuation() < 1: raise ValueError("power series composition with nonzero constant term") cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) fmpq_poly_compose_series((u).val, (s).val, (t).val, cap) - (u).prec = cap + (u)._prec = cap return u raise TypeError("cannot call fmpq_series with input of type %s", type(t)) @@ -312,30 +356,33 @@ cdef class fmpq_series(flint_series): """ Returns the power series reversion (compositional inverse) of *s*. + >>> from flint import fmpq_series, ctx + >>> ctx.cap = 10 + >>> x = fmpq_series([0,1]); print((x/2-x**2).reversion()) 2*x + 8*x^2 + 64*x^3 + 640*x^4 + 7168*x^5 + 86016*x^6 + 1081344*x^7 + 14057472*x^8 + 187432960*x^9 + O(x^10) """ cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if (s).valuation() != 1: raise ValueError("power series reversion must have valuation 1") if fmpz_is_zero(&((s).val.coeffs[1])): raise ValueError("leading term is not a unit") u = fmpq_series.__new__(fmpq_series) fmpq_poly_revert_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def inv(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if (s).valuation() != 0: raise ValueError("can only invert series with nonzero constant term") u = fmpq_series.__new__(fmpq_series) fmpq_poly_inv_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u cdef bint zero_constant_term(s): @@ -355,173 +402,173 @@ cdef class fmpq_series(flint_series): def derivative(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec - 1) + cap = min(cap, (s)._prec - 1) u = fmpq_series.__new__(fmpq_series) fmpq_poly_derivative((u).val, (s).val) fmpq_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def integral(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec + 1) + cap = min(cap, (s)._prec + 1) u = fmpq_series.__new__(fmpq_series) fmpq_poly_integral((u).val, (s).val) fmpq_poly_truncate((u).val, max(0, cap)) - (u).prec = cap + (u)._prec = cap return u def sqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.one_constant_term(): raise ValueError("sqrt() of power series: constant term != 1") u = fmpq_series.__new__(fmpq_series) fmpq_poly_sqrt_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def rsqrt(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.one_constant_term(): raise ValueError("rsqrt() of power series: constant term != 1") u = fmpq_series.__new__(fmpq_series) fmpq_poly_invsqrt_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def exp(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("exp() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_exp_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def log(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.one_constant_term(): raise ValueError("log() of power series: constant term must be one") u = fmpq_series.__new__(fmpq_series) fmpq_poly_log_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def atan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("atan() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_atan_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def atanh(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("atanh() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_atanh_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def asin(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("asin() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_asin_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def asinh(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("asinh() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_asinh_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def sin(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("sin() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_sin_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def cos(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("cos() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_cos_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def tan(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("tan() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_tan_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def sinh(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("sinh() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_sinh_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def cosh(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("cosh() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_cosh_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u def tanh(s): cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if not s.zero_constant_term(): raise ValueError("tanh() of power series: constant term must be zero") u = fmpq_series.__new__(fmpq_series) fmpq_poly_tanh_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u diff --git a/src/flint/types/fmpz_poly.pyx b/src/flint/types/fmpz_poly.pyx index 241eaa44..74037cba 100644 --- a/src/flint/types/fmpz_poly.pyx +++ b/src/flint/types/fmpz_poly.pyx @@ -487,6 +487,9 @@ cdef class fmpz_poly(flint_poly): Returns a list of pairs (*c*, *m*) where *c* is the root as an *acb* and *m* is the multiplicity of the root. + >>> from flint import fmpz_poly, ctx + >>> ctx.prec = 53 + >>> fmpz_poly([]).complex_roots() [] >>> fmpz_poly([1]).complex_roots() diff --git a/src/flint/types/fmpz_series.pxd b/src/flint/types/fmpz_series.pxd index 9efd3911..47b8ee7e 100644 --- a/src/flint/types/fmpz_series.pxd +++ b/src/flint/types/fmpz_series.pxd @@ -4,6 +4,6 @@ from flint.flintlib.functions.fmpz_poly cimport fmpz_poly_t cdef class fmpz_series(flint_series): cdef fmpz_poly_t val - cdef long prec + cdef long _prec cpdef long length(self) cpdef valuation(self) diff --git a/src/flint/types/fmpz_series.pyx b/src/flint/types/fmpz_series.pyx index d0292991..d7588a15 100644 --- a/src/flint/types/fmpz_series.pyx +++ b/src/flint/types/fmpz_series.pyx @@ -34,6 +34,8 @@ cdef class fmpz_series(flint_series): """ Power series with integer coefficients. + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 >>> fmpz_series([1,2,3]) 1 + 2*x + 3*x^2 + O(x^10) >>> fmpz_series([1,2,3], prec=2) @@ -47,33 +49,54 @@ cdef class fmpz_series(flint_series): """ # cdef fmpz_poly_t val - # cdef long prec + # cdef long _prec def __cinit__(self): fmpz_poly_init(self.val) - self.prec = 0 + self._prec = 0 def __dealloc__(self): fmpz_poly_clear(self.val) def __init__(self, val=None, prec=None): if prec is None: - self.prec = getcap() + self._prec = getcap() else: - self.prec = prec - if self.prec < 0: - self.prec = -1 + self._prec = prec + if self._prec < 0: + self._prec = -1 if val is not None: if typecheck(val, fmpz_series): fmpz_poly_set(self.val, (val).val) - self.prec = min((val).prec, getcap()) + self._prec = min((val)._prec, getcap()) elif typecheck(val, fmpz_poly): fmpz_poly_set(self.val, (val).val) elif typecheck(val, list): fmpz_poly_set_list(self.val, val) else: fmpz_poly_set_list(self.val, [val]) - fmpz_poly_truncate(self.val, max(0, self.prec)) + fmpz_poly_truncate(self.val, max(0, self._prec)) + + + @property + def prec(self): + """ + The term precision of the finitely approximated series. + + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 + >>> s = fmpz_series([1,2]) + >>> s + 1 + 2*x + O(x^10) + >>> s.prec + 10 + >>> s2 = fmpz_series([1,2], prec=3) + >>> s2 + 1 + 2*x + O(x^3) + >>> s2.prec + 3 + """ + return self._prec def _equal_repr(self, other): cdef bint r @@ -81,7 +104,7 @@ cdef class fmpz_series(flint_series): return False r = fmpz_poly_equal((self).val, (other).val) if r: - r = (self).prec == (other).prec + r = (self)._prec == (other)._prec return r def __len__(self): @@ -105,13 +128,13 @@ cdef class fmpz_series(flint_series): fmpz_poly_set_coeff_fmpz(self.val, i, (x).val) def repr(self, **kwargs): - return "fmpz_series([%s], prec=%s)" % (", ".join(map(str, self)), self.prec) + return "fmpz_series([%s], prec=%s)" % (", ".join(map(str, self)), self._prec) def str(self, **kwargs): - if self.prec > 0: + if self._prec > 0: s = fmpz_poly(list(self)).str(ascending=True) - return s + (" + O(x^%s)" % self.prec) - elif self.prec == 0: + return s + (" + O(x^%s)" % self._prec) + elif self._prec == 0: return "O(x^0)" else: return "(invalid power series)" @@ -123,11 +146,11 @@ cdef class fmpz_series(flint_series): cdef long cap u = fmpz_series.__new__(fmpz_series) cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if cap > 0: fmpz_poly_neg((u).val, (s).val) fmpz_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __add__(s, t): @@ -139,12 +162,12 @@ cdef class fmpz_series(flint_series): cdef long cap u = fmpz_series.__new__(fmpz_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpz_poly_add((u).val, (s).val, (t).val) fmpz_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __radd__(s, t): @@ -162,12 +185,12 @@ cdef class fmpz_series(flint_series): cdef long cap u = fmpz_series.__new__(fmpz_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpz_poly_sub((u).val, (s).val, (t).val) fmpz_poly_truncate((u).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rsub__(s, t): @@ -185,11 +208,11 @@ cdef class fmpz_series(flint_series): cdef long cap u = fmpz_series.__new__(fmpz_series) cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if cap > 0: fmpz_poly_mullow((u).val, (s).val, (t).val, cap) - (u).prec = cap + (u)._prec = cap return u def __rmul__(s, t): @@ -203,12 +226,27 @@ cdef class fmpz_series(flint_series): Returns the valuation of this power series. If there are no known nonzero coefficients, returns -1. - >>> fmpz_series([1,2,3]).valuation() + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 + + >>> s1 = fmpz_series([1,2,3]) + >>> s1 + 1 + 2*x + 3*x^2 + O(x^10) + >>> s1.valuation() 0 - >>> fmpz_series([0,0,0,1,2,3]).valuation() + + >>> s2 = fmpz_series([0,0,0,1,2,3]) + >>> s2 + x^3 + 2*x^4 + 3*x^5 + O(x^10) + >>> s2.valuation() 3 - >>> fmpz_series([]).valuation() + + >>> s3 = fmpz_series([]) + >>> s3 + 0 + O(x^10) + >>> s3.valuation() -1 + """ cdef long i if fmpz_poly_is_zero(self.val): @@ -222,6 +260,9 @@ cdef class fmpz_series(flint_series): """ Power series division. + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 + >>> fmpz_series([1]) / fmpz_series([1,-1,-1]) 1 + x + 2*x^2 + 3*x^3 + 5*x^4 + 8*x^5 + 13*x^6 + 21*x^7 + 34*x^8 + 55*x^9 + O(x^10) >>> fmpz_series([0,1,2]) / fmpz_series([0,1,2]) @@ -241,8 +282,8 @@ cdef class fmpz_series(flint_series): cdef long cap, sval, tval cdef fmpz_poly_t stmp, ttmp cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) if fmpz_poly_is_zero((t).val): raise ZeroDivisionError("power series division") @@ -250,7 +291,7 @@ cdef class fmpz_series(flint_series): u = fmpz_series.__new__(fmpz_series) if fmpz_poly_is_zero((s).val): - (u).prec = cap + (u)._prec = cap return u sval = (s).valuation() @@ -274,7 +315,7 @@ cdef class fmpz_series(flint_series): fmpz_poly_clear(stmp) fmpz_poly_clear(ttmp) - (u).prec = cap + (u)._prec = cap return u def __truediv__(s, t): @@ -295,6 +336,8 @@ cdef class fmpz_series(flint_series): """ Power series exponentiation. + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 >>> fmpz_series([3,4,5], prec=4) ** 5 243 + 1620*x + 6345*x^2 + 16560*x^3 + O(x^4) """ @@ -302,16 +345,18 @@ cdef class fmpz_series(flint_series): if mod is not None: raise NotImplementedError("fmpz_series modular exponentiation") cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) u = fmpz_series.__new__(fmpz_series) fmpz_poly_pow_trunc((u).val, (s).val, exp, cap) - (u).prec = cap + (u)._prec = cap return u def __call__(s, t): """ Power series composition. + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 >>> fmpz_series([1,2,3])(fmpz_series([0,1,2])) 1 + 2*x + 7*x^2 + 12*x^3 + 12*x^4 + O(x^10) >>> fmpz_series([1,2,3])(fmpz_series([1,1,2])) @@ -326,10 +371,10 @@ cdef class fmpz_series(flint_series): if (t).valuation() < 1: raise ValueError("power series composition with nonzero constant term") cap = getcap() - cap = min(cap, (s).prec) - cap = min(cap, (t).prec) + cap = min(cap, (s)._prec) + cap = min(cap, (t)._prec) fmpz_poly_compose_series((u).val, (s).val, (t).val, cap) - (u).prec = cap + (u)._prec = cap return u raise TypeError("cannot call fmpz_series with input of type %s", type(t)) @@ -337,6 +382,9 @@ cdef class fmpz_series(flint_series): """ Power series reversion. + >>> from flint import fmpz_series, ctx + >>> ctx.cap = 10 + >>> fmpz_series([0,1,-2,-3]).reversion() x + 2*x^2 + 11*x^3 + 70*x^4 + 503*x^5 + 3864*x^6 + 31092*x^7 + 258654*x^8 + 2206655*x^9 + O(x^10) >>> fmpz_series([0,1,-2,-3]).reversion()(fmpz_series([0,1,-2,-3])) @@ -349,12 +397,12 @@ cdef class fmpz_series(flint_series): """ cdef long cap cap = getcap() - cap = min(cap, (s).prec) + cap = min(cap, (s)._prec) if (s).valuation() != 1: raise ValueError("power series reversion must have valuation 1") if not fmpz_is_pm1(fmpz_poly_get_coeff_ptr((s).val, 1)): raise ValueError("leading term is not a unit") u = fmpz_series.__new__(fmpz_series) fmpz_poly_revert_series((u).val, (s).val, cap) - (u).prec = cap + (u)._prec = cap return u From ad1550a81c991d8fb224b7a41aad8e9d00d611f4 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 21:37:12 +0100 Subject: [PATCH 2/8] Add release note --- README.md | 4 ++++ src/flint/types/fmpz_series.pyx | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9f591e3..af01d3a8 100644 --- a/README.md +++ b/README.md @@ -164,10 +164,14 @@ Next release (0.8.0)... Contributors +- Oscar Benjamin (OB) - Robert Dougherty-Bliss (RDB) Changes +- [gh-289](https://github.com/flintlib/python-flint/pull/289), + Add `.prec` attribute to series types `fmpz_series`, `fmpq_series`, + `arb_series` and `acb_series`. (OB) - [gh-274](https://github.com/flintlib/python-flint/pull/274), Add resultant methods to `fmpz_poly`, `fmpq_poly` and `nmod_poly`. Now all univariate and polynomial types have the diff --git a/src/flint/types/fmpz_series.pyx b/src/flint/types/fmpz_series.pyx index d7588a15..06ff936d 100644 --- a/src/flint/types/fmpz_series.pyx +++ b/src/flint/types/fmpz_series.pyx @@ -77,7 +77,6 @@ cdef class fmpz_series(flint_series): fmpz_poly_set_list(self.val, [val]) fmpz_poly_truncate(self.val, max(0, self._prec)) - @property def prec(self): """ From 33bf0bb5290d4428c56b773d96101601b3c97ff1 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 22:04:54 +0100 Subject: [PATCH 3/8] Skip acb_theta doctest for FLINT<3.3 --- src/flint/test/test_docstrings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flint/test/test_docstrings.py b/src/flint/test/test_docstrings.py index ef788deb..d5b5a51d 100644 --- a/src/flint/test/test_docstrings.py +++ b/src/flint/test/test_docstrings.py @@ -10,6 +10,7 @@ test_flint_at_least = { "flint.types._gr.gr_ctx.gens": 30100, "flint.types._gr.gr_ctx.neg": 30100, + "flint.types.acb_theta.acb_theta": 30300, } From 497879fb7e357a03e8743a6da62a7f6b583bb55b Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 22:10:31 +0100 Subject: [PATCH 4/8] pin msys2 action to v2.27.0 to fix windows build --- .github/workflows/buildwheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index dfcc003f..8310e586 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -19,7 +19,7 @@ jobs: with: python-version: '3.13' - - uses: msys2/setup-msys2@v2 + - uses: msys2/setup-msys2@v2.27.0 with: msystem: mingw64 # path-type inherit is used so that when cibuildwheel calls msys2 to From d4d018674e9ede5cc017c85f7b1fcfe477ebc990 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 22:15:34 +0100 Subject: [PATCH 5/8] Bump from windows-2019 to windows-2025 --- .github/workflows/buildwheel.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 8310e586..519ad735 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, macos-13, macos-14] steps: - uses: actions/checkout@v4 @@ -29,17 +29,17 @@ jobs: # problematic in some situations. Maybe there is a better way to do # this. path-type: inherit - if: ${{ matrix.os == 'windows-2019' }} + if: ${{ matrix.os == 'windows-2025' }} # Install pkgconfig on Windows from choco rather than from msys and # avoid using the Strawberry one. - run: choco install -y --stoponfirstfailure --checksum 6004DF17818F5A6DBF19CB335CC92702 pkgconfiglite - if: ${{ matrix.os == 'windows-2019' }} + if: ${{ matrix.os == 'windows-2025' }} # We have to set this here rather than in the cibuildwheel config # This is probably something to do with \ vs / in paths... - run: echo "PKG_CONFIG_PATH=${{ github.workspace }}/.local/lib/pkgconfig" >> $env:GITHUB_ENV - if: ${{ matrix.os == 'windows-2019' }} + if: ${{ matrix.os == 'windows-2025' }} - name: Build wheels uses: pypa/cibuildwheel@90a0ddeff0f23eebc21630e65d66d0f4955e9b94 # v3.0.0b1 @@ -83,7 +83,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, macos-13, macos-14] # This list to be kept in sync with python-requires in pyproject.toml. python-version: ['3.11', '3.12', '3.13', '3.13t', 'pypy3.11'] From 514ed8238e57d920fc0c26029a198da3f9b82f6f Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 22:21:47 +0100 Subject: [PATCH 6/8] Unpin msys2 in CI... --- .github/workflows/buildwheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 519ad735..7bf0d340 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -19,7 +19,7 @@ jobs: with: python-version: '3.13' - - uses: msys2/setup-msys2@v2.27.0 + - uses: msys2/setup-msys2@v2 with: msystem: mingw64 # path-type inherit is used so that when cibuildwheel calls msys2 to From cf7db1ddd445d5fbb721c5345faf67aefc36cef3 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 22:31:34 +0100 Subject: [PATCH 7/8] Pin msys2 to v2.27.0 again --- .github/workflows/buildwheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 7bf0d340..519ad735 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -19,7 +19,7 @@ jobs: with: python-version: '3.13' - - uses: msys2/setup-msys2@v2 + - uses: msys2/setup-msys2@v2.27.0 with: msystem: mingw64 # path-type inherit is used so that when cibuildwheel calls msys2 to From 7d6f96f26b9d199afcb431a45e4fabef52c43fef Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 23 Jun 2025 23:04:18 +0100 Subject: [PATCH 8/8] Back to windows-2019 --- .github/workflows/buildwheel.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 519ad735..8310e586 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, macos-13, macos-14] + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] steps: - uses: actions/checkout@v4 @@ -29,17 +29,17 @@ jobs: # problematic in some situations. Maybe there is a better way to do # this. path-type: inherit - if: ${{ matrix.os == 'windows-2025' }} + if: ${{ matrix.os == 'windows-2019' }} # Install pkgconfig on Windows from choco rather than from msys and # avoid using the Strawberry one. - run: choco install -y --stoponfirstfailure --checksum 6004DF17818F5A6DBF19CB335CC92702 pkgconfiglite - if: ${{ matrix.os == 'windows-2025' }} + if: ${{ matrix.os == 'windows-2019' }} # We have to set this here rather than in the cibuildwheel config # This is probably something to do with \ vs / in paths... - run: echo "PKG_CONFIG_PATH=${{ github.workspace }}/.local/lib/pkgconfig" >> $env:GITHUB_ENV - if: ${{ matrix.os == 'windows-2025' }} + if: ${{ matrix.os == 'windows-2019' }} - name: Build wheels uses: pypa/cibuildwheel@90a0ddeff0f23eebc21630e65d66d0f4955e9b94 # v3.0.0b1 @@ -83,7 +83,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, macos-13, macos-14] + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] # This list to be kept in sync with python-requires in pyproject.toml. python-version: ['3.11', '3.12', '3.13', '3.13t', 'pypy3.11']