Skip to content

Commit

Permalink
gh-36645: sage.libs.pari, sage.rings.real_mpfr: Modularization fixes
Browse files Browse the repository at this point in the history
    
<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes #1234" use "Introduce new method to
calculate 1+1"
-->
<!-- Describe your changes here in detail -->
Main change: Eliminate the compile-time dependency of
`sage.rings.real_mpfr` on PARI.


<!-- Why is this change required? What problem does it solve? -->
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
- Cherry-picked from #35095
<!-- If your change requires a documentation PR, please link it
appropriately. -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
<!-- Feel free to remove irrelevant items. -->

- [x] The title is concise, informative, and self-explanatory.
- [ ] The description explains in detail what this PR is about.
- [x] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #36645
Reported by: Matthias Köppe
Reviewer(s): Kwankyu Lee
  • Loading branch information
Release Manager committed Dec 9, 2023
2 parents d15e490 + 241ac56 commit 37a2501
Show file tree
Hide file tree
Showing 14 changed files with 439 additions and 317 deletions.
15 changes: 9 additions & 6 deletions src/sage/interfaces/gp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# sage_setup: distribution = sagemath-pari
# sage.doctest: needs sage.libs.pari
r"""
Interface to the GP calculator of PARI/GP
Expand Down Expand Up @@ -142,14 +141,18 @@
##########################################################################
import os

import sage.interfaces.abc

from sage.env import DOT_SAGE
from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement
from sage.misc.verbose import verbose
from sage.interfaces.tab_completion import ExtraTabCompletion
from sage.libs.pari.all import pari
import sage.rings.complex_mpfr
from sage.misc.instancedoc import instancedoc
import sage.interfaces.abc
from sage.misc.lazy_import import lazy_import
from sage.misc.verbose import verbose

lazy_import('sage.rings.cc', 'CC')

from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement


class Gp(ExtraTabCompletion, Expect):
Expand Down Expand Up @@ -987,7 +990,7 @@ def _complex_double_(self, CDF):
"""
# Retrieving values from another computer algebra system is
# slow anyway, right?
cc_val = self._complex_mpfr_field_(sage.rings.complex_mpfr.ComplexField())
cc_val = self._complex_mpfr_field_(CC)
return CDF(cc_val)

def __len__(self):
Expand Down
2 changes: 2 additions & 0 deletions src/sage/libs/pari/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# sage.doctest: needs sage.rings.real_mpfr
"""
Interface between Sage and PARI
Expand Down Expand Up @@ -51,6 +52,7 @@
functions). For instance, if we want to use the PARI library to compute
``sqrt(pi)`` with a precision of 100 bits::
sage: # needs sage.symbolic
sage: R = RealField(100)
sage: s = R(pi); s
3.1415926535897932384626433833
Expand Down
2 changes: 1 addition & 1 deletion src/sage/libs/pari/convert_gmp.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ cdef Gen rational_matrix(mpq_t** B, long nr, long nc) noexcept:
EXAMPLES::
sage: matrix(QQ,2,[1..6]).__pari__() # indirect doctest
sage: matrix(QQ,2,[1..6]).__pari__() # indirect doctest # needs sage.modules
[1, 2, 3; 4, 5, 6]
"""
sig_on()
Expand Down
157 changes: 45 additions & 112 deletions src/sage/libs/pari/convert_sage.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,30 @@ from sage.libs.pari.convert_gmp cimport INT_to_mpz, new_gen_from_mpz_t, new_gen_
from sage.ext.stdsage cimport PY_NEW
from sage.libs.gmp.mpz cimport mpz_fits_slong_p, mpz_sgn, mpz_get_ui, mpz_set, mpz_set_si, mpz_set_ui
from sage.libs.gmp.mpq cimport mpq_denref, mpq_numref
from sage.misc.lazy_import import LazyImport
from sage.rings.integer cimport smallInteger
from sage.rings.real_mpfr import RealField
from sage.rings.complex_mpfr import ComplexField
from sage.rings.number_field.number_field import QuadraticField
from sage.matrix.args cimport (MatrixArgs, MA_ENTRIES_SEQ_SEQ,
MA_ENTRIES_SEQ_FLAT, MA_ENTRIES_CALLABLE,
MA_ENTRIES_UNKNOWN, MA_ENTRIES_SCALAR)
from sage.rings.padics.factory import Qp
from sage.rings.infinity import Infinity

try:
from sage.rings.real_mpfr import RealField
from sage.rings.complex_mpfr import ComplexField
except ImportError:
pass

try:
from sage.rings.number_field.number_field import QuadraticField
except ImportError:
pass
else:
QQi = QuadraticField(-1, 'i')

try:
from sage.rings.padics.factory import Qp
except ImportError:
pass

pari_typ_to_entries_type = LazyImport('sage.libs.pari.convert_sage_matrix', 'pari_typ_to_entries_type')


cpdef gen_to_sage(Gen z, locals=None) noexcept:
"""
Expand Down Expand Up @@ -117,15 +131,15 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
15
sage: z = pari('1.234'); z
1.234000000000000000000000000000000000000000000000000000000000000000000
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.real_mpfr
1.234000000000000000000000000000000000000000000000000000000000000000000000000
sage: a.parent()
sage: a.parent() # needs sage.rings.real_mpfr
Real Field with 256 bits of precision
sage: pari.set_real_precision(15)
70
sage: a = gen_to_sage(pari('1.234')); a
sage: a = gen_to_sage(pari('1.234')); a # needs sage.rings.real_mpfr
1.23400000000000000
sage: a.parent()
sage: a.parent() # needs sage.rings.real_mpfr
Real Field with 64 bits of precision
For complex numbers, the parent depends on the PARI type::
Expand All @@ -134,37 +148,37 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
3 + I
sage: z.type()
't_COMPLEX'
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.number_field
i + 3
sage: a.parent()
sage: a.parent() # needs sage.rings.number_field
Number Field in i with defining polynomial x^2 + 1 with i = 1*I
sage: z = pari('(3+I)/2'); z
3/2 + 1/2*I
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.number_field
1/2*i + 3/2
sage: a.parent()
sage: a.parent() # needs sage.rings.number_field
Number Field in i with defining polynomial x^2 + 1 with i = 1*I
sage: z = pari('1.0 + 2.0*I'); z
1.00000000000000 + 2.00000000000000*I
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.real_mpfr
1.00000000000000000 + 2.00000000000000000*I
sage: a.parent()
sage: a.parent() # needs sage.rings.real_mpfr
Complex Field with 64 bits of precision
sage: z = pari('1 + 1.0*I'); z
1 + 1.00000000000000*I
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.real_mpfr
1.00000000000000000 + 1.00000000000000000*I
sage: a.parent()
sage: a.parent() # needs sage.rings.real_mpfr
Complex Field with 64 bits of precision
sage: z = pari('1.0 + 1*I'); z
1.00000000000000 + I
sage: a = gen_to_sage(z); a
sage: a = gen_to_sage(z); a # needs sage.rings.real_mpfr
1.00000000000000000 + 1.00000000000000000*I
sage: a.parent()
sage: a.parent() # needs sage.rings.real_mpfr
Complex Field with 64 bits of precision
Converting polynomials::
Expand All @@ -179,6 +193,7 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
sage: parent(gen_to_sage(f, {'x': x, 'y': y}))
Multivariate Polynomial Ring in x, y over Rational Field
sage: # needs sage.symbolic
sage: x,y = SR.var('x,y')
sage: gen_to_sage(f, {'x': x, 'y': y})
2/3*x^3 + x + y - 5/7
Expand All @@ -192,6 +207,7 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
Converting vectors::
sage: # needs sage.rings.number_field sage.rings.real_mpfr
sage: z1 = pari('[-3, 2.1, 1+I]'); z1
[-3, 2.10000000000000, 1 + I]
sage: z2 = pari('[1.0*I, [1,2]]~'); z2
Expand Down Expand Up @@ -224,6 +240,8 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
sage: z = pari('[1,2;3,4]')
sage: z.type()
't_MAT'
sage: # needs sage.modules
sage: a = gen_to_sage(z); a
[1 2]
[3 4]
Expand All @@ -232,6 +250,7 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
Conversion of p-adics::
sage: # needs sage.rings.padics
sage: z = pari('569 + O(7^8)'); z
2 + 4*7 + 4*7^2 + 7^3 + O(7^8)
sage: a = gen_to_sage(z); a
Expand Down Expand Up @@ -294,20 +313,14 @@ cpdef gen_to_sage(Gen z, locals=None) noexcept:
C = ComplexField(sage_prec)
return C(R(real), R(imag))
else:
K = QuadraticField(-1, 'i')
return K([gen_to_sage(real), gen_to_sage(imag)])
return QQi([gen_to_sage(real), gen_to_sage(imag)])
elif t == t_VEC or t == t_COL:
return [gen_to_sage(x, locals) for x in z.python_list()]
elif t == t_VECSMALL:
return z.python_list_small()
elif t == t_MAT:
nc = lg(g) - 1
nr = 0 if nc == 0 else lg(gel(g,1)) - 1
ma = MatrixArgs.__new__(MatrixArgs)
ma.nrows = nr
ma.ncols = nc
ma.entries = [gen_to_sage(z[i,j], locals) for i in range(nr) for j in range(nc)]
return ma.matrix()
from .convert_sage_matrix import gen_to_sage_matrix
return gen_to_sage_matrix(z, locals)
elif t == t_PADIC:
p = z.padicprime()
K = Qp(Integer(p), precp(g))
Expand All @@ -330,7 +343,7 @@ cpdef set_integer_from_gen(Integer self, Gen x) noexcept:
r"""
EXAMPLES::
sage: [Integer(pari(x)) for x in [1, 2^60, 2., GF(3)(1), GF(9,'a')(2)]]
sage: [Integer(pari(x)) for x in [1, 2^60, 2., GF(3)(1), GF(9,'a')(2)]] # needs sage.rings.finite_rings
[1, 1152921504606846976, 2, 1, 2]
sage: Integer(pari(2.1)) # indirect doctest
Traceback (most recent call last):
Expand Down Expand Up @@ -390,7 +403,7 @@ cpdef set_rational_from_gen(Rational self, Gen x) noexcept:
r"""
EXAMPLES::
sage: [Rational(pari(x)) for x in [1, 1/2, 2^60, 2., GF(3)(1), GF(9,'a')(2)]]
sage: [Rational(pari(x)) for x in [1, 1/2, 2^60, 2., GF(3)(1), GF(9,'a')(2)]] # needs sage.rings.finite_rings
[1, 1/2, 1152921504606846976, 2, 1, 2]
sage: Rational(pari(2.1)) # indirect doctest
Traceback (most recent call last):
Expand Down Expand Up @@ -576,83 +589,3 @@ cpdef list pari_prime_range(long c_start, long c_stop, bint py_ints=False) noexc
res.append(z)
NEXT_PRIME_VIADIFF(p, pari_prime_ptr)
return res


def pari_typ_to_entries_type(MatrixArgs self):
"""
Determine the ``entries_type`` of a :class:`sage.matrix.args.MatrixArgs`
with PARI entries.
This will modify the entries.
TESTS:
``MA_ENTRIES_SEQ_SEQ``::
sage: from sage.libs.pari.convert_sage import pari_typ_to_entries_type
sage: from sage.matrix.args import MatrixArgs
sage: ma = MatrixArgs(QQ, entries=pari("[1,2;3,4]"))
sage: 0x10_03 == pari_typ_to_entries_type(ma)
True
``MA_ENTRIES_SEQ_FLAT``::
sage: ma = MatrixArgs(QQ, entries=pari("[1,2]"))
sage: 0x10_04 == pari_typ_to_entries_type(ma)
True
sage: ma = MatrixArgs(QQ, entries=pari(vector([1,2])))
sage: 0x10_04 == pari_typ_to_entries_type(ma)
True
sage: ma = MatrixArgs(QQ, entries=pari(matrix(2, range(4))[0]))
sage: 0x10_04 == pari_typ_to_entries_type(ma)
True
``MA_ENTRIES_CALLABLE``::
sage: ma = MatrixArgs(QQ, entries=pari(lambda x: x))
sage: 0x13_06 == pari_typ_to_entries_type(ma)
True
``MA_ENTRIES_SCALAR``::
sage: ma = MatrixArgs(QQ, entries=pari(1/2))
sage: 0x17_02 == pari_typ_to_entries_type(ma)
True
``MA_ENTRIES_UNKNOWN``::
sage: ma = MatrixArgs(QQ, entries=pari('"2"'))
sage: 0 == pari_typ_to_entries_type(ma)
True
A second call gives an error::
sage: ma = MatrixArgs(QQ, entries=pari("[1,2]"))
sage: 0x10_04 == pari_typ_to_entries_type(ma)
True
sage: 0x10_04 == pari_typ_to_entries_type(ma)
Traceback (most recent call last):
...
ValueError: entries are not a PARI generator
"""
if not isinstance(self.entries, Gen):
raise ValueError("entries are not a PARI generator")
cdef long t = typ((<Gen>self.entries).g)
if t == t_MAT:
R = self.base
if R is None:
self.entries = self.entries.Col().sage()
else:
self.entries = [[R(x) for x in v]
for v in self.entries.mattranspose()]
return MA_ENTRIES_SEQ_SEQ
elif t in [t_VEC, t_COL, t_VECSMALL, t_LIST]:
self.entries = self.entries.sage()
return MA_ENTRIES_SEQ_FLAT
elif t == t_CLOSURE:
return MA_ENTRIES_CALLABLE
elif t == t_STR:
return MA_ENTRIES_UNKNOWN
else:
self.entries = self.entries.sage()
return MA_ENTRIES_SCALAR
4 changes: 3 additions & 1 deletion src/sage/libs/pari/convert_sage_complex_double.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# sage.doctest: needs sage.rings.complex_double

from cysignals.signals cimport sig_on, sig_off

from sage.libs.gsl.complex cimport *
Expand Down Expand Up @@ -25,7 +27,7 @@ cpdef ComplexDoubleElement pari_to_cdf(Gen g) noexcept:
Traceback (most recent call last):
...
PariError: overflow in t_REAL->double conversion
sage: CDF(pari(x^2 + 5))
sage: CDF(pari(x^2 + 5)) # needs sage.symbolic
Traceback (most recent call last):
...
PariError: incorrect type in gtofp (t_POL)
Expand Down
Loading

0 comments on commit 37a2501

Please sign in to comment.