From 0d1f4904a82a8eaf3c7b6c985d33ce71bd6d25a4 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Wed, 9 Jul 2025 21:53:35 +0100 Subject: [PATCH 1/2] Fix arb.repr() and have it round trip --- src/flint/test/test_all.py | 35 +++++++++++++++++++++++++++-------- src/flint/types/arb.pxd | 2 ++ src/flint/types/arb.pyx | 28 +++++++++++++++++++++------- src/flint/types/arf.pyx | 3 ++- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index cdd3f06d..11127646 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -1647,14 +1647,32 @@ def test_nmod_series(): def test_arb(): - A = flint.arb - assert A(3) > A(2.5) - assert A(3) >= A("2.5") - assert A(3) < A((3,1)) - assert A(3) <= A("inf") - assert A(3) == A(3) - assert A(3) != A(2) - assert not (A("1.1") == A("1.1")) + arb = flint.arb + assert arb(3) > arb(2.5) + assert arb(3) >= arb("2.5") + assert arb(3) < arb((3,1)) + assert arb(3) <= arb("inf") + assert arb(3) == arb(3) + assert arb(3) != arb(2) + assert not (arb("1.1") == arb("1.1")) + + assert arb(3).repr() == 'arb((0x3, 0x0))' + assert arb("nan").repr() == "arb('nan')" + assert arb(0, "inf").repr() == "arb(0.0, '+inf')" + assert arb((1,2), (3,4)).repr() == "arb((0x1, 0x2), (0x3, 0x4))" + assert arb(1, arb("inf")).repr() == "arb((0x1, 0x0), '+inf')" + assert arb(1, "inf").repr() == "arb((0x1, 0x0), '+inf')" + assert arb(1, "nan").repr() == "arb((0x1, 0x0), '+inf')" + assert arb("nan", 1).repr() == "arb('nan')" + assert arb("nan", "nan").repr() == "arb('nan')" + + for a in [arb(2), arb((1,2), (3,4)), arb("nan"), arb(0, "inf")]: + assert eval(a.repr()).repr() == a.repr() + + +def test_acb(): + acb = flint.acb + assert acb(1, 2).repr() == "acb(arb((0x1, 0x0)), arb((0x1, 0x1)))" def test_pickling(): @@ -5038,6 +5056,7 @@ def test_all_tests(): test_fq_default_poly, test_arb, + test_acb, test_pickling, diff --git a/src/flint/types/arb.pxd b/src/flint/types/arb.pxd index df422ff3..63728cfd 100644 --- a/src/flint/types/arb.pxd +++ b/src/flint/types/arb.pxd @@ -15,3 +15,5 @@ cdef class arb(flint_scalar): cpdef bint is_nan(self) cpdef bint is_exact(self) cpdef bint is_integer(self) + + cdef tuple _to_arfs(self) diff --git a/src/flint/types/arb.pyx b/src/flint/types/arb.pyx index 5f1426f1..2b9dab79 100644 --- a/src/flint/types/arb.pyx +++ b/src/flint/types/arb.pyx @@ -196,14 +196,21 @@ cdef class arb(flint_scalar): arb_clear(self.val) def __init__(self, mid=None, rad=None): + cdef arf _rad + cdef fmpz man, exp if mid is not None: if arb_set_python(self.val, mid, 1) == 0: raise TypeError("cannot create arb from type %s" % type(mid)) if rad is not None: - rad = arb(rad) - arb_add_error(self.val, (rad).val) - # rad = arf(rad) - # arb_add_error_arf(self.val, (rad).val) + if isinstance(rad, tuple): + # Set the radius exactly from tuple of ints so that + # eval(a.repr()) round trips. + _rad = arf(rad) + man, exp = _rad.man_exp() + mag_set_fmpz_2exp_fmpz(arb_radref(self.val), man.val, exp.val) + else: + rad = arb(rad) + arb_add_error(self.val, (rad).val) cpdef bint is_zero(self): return arb_is_zero(self.val) @@ -385,10 +392,17 @@ cdef class arb(flint_scalar): else: return (0, man, int(exp), man.bit_length()) + # Make this a public function? + cdef tuple _to_arfs(self): + cdef arf mid = arf.__new__(arf) + cdef arf rad = arf.__new__(arf) + arf_set(mid.val, arb_midref(self.val)) + arf_set_mag(rad.val, arb_radref(self.val)) + return (mid, rad) + def repr(self): - mid = self.mid() - rad = self.rad() - if rad.is_zero(): + mid, rad = self._to_arfs() + if rad.is_zero() or mid.is_nan(): return "arb(%s)" % mid._repr_str() else: return "arb(%s, %s)" % (mid._repr_str(), rad._repr_str()) diff --git a/src/flint/types/arf.pyx b/src/flint/types/arf.pyx index 39b2857c..097e8d30 100644 --- a/src/flint/types/arf.pyx +++ b/src/flint/types/arf.pyx @@ -94,7 +94,8 @@ cdef class arf: if arf_is_zero(self.val): return "0.0" elif arf_is_finite(self.val): - return "(%s, %s)" % self.man_exp() + man, exp = self.man_exp() + return "(%s, %s)" % (hex(man), hex(exp)) elif arf_is_pos_inf(self.val): return "'+inf'" elif arf_is_neg_inf(self.val): From 4d03e19ead9e7b917b299965f5d87253a94c0f94 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Wed, 9 Jul 2025 22:52:55 +0100 Subject: [PATCH 2/2] Add release not for arb.repr --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index af01d3a8..d4b728c8 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,8 @@ Contributors Changes +- [gh-300](https://github.com/flintlib/python-flint/pull/300), Fix `arb.repr` + which now returns a Python representation that round trips. (OB) - [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)