Skip to content

Commit 072cc1b

Browse files
committed
RDF[] for libsingular, delegate ideal comparison to singular
1 parent 981d7d7 commit 072cc1b

File tree

6 files changed

+166
-27
lines changed

6 files changed

+166
-27
lines changed

src/sage/libs/singular/ring.pyx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ from sage.libs.singular.decl cimport rChangeCurrRing, rComplete, rDelete, idInit
2626
from sage.libs.singular.decl cimport omAlloc0, omStrDup, omAlloc
2727
from sage.libs.singular.decl cimport ringorder_dp, ringorder_Dp, ringorder_lp, ringorder_ip, ringorder_ds, ringorder_Ds, ringorder_ls, ringorder_M, ringorder_c, ringorder_C, ringorder_wp, ringorder_Wp, ringorder_ws, ringorder_Ws, ringorder_a, rRingOrder_t
2828
from sage.libs.singular.decl cimport prCopyR
29-
from sage.libs.singular.decl cimport n_unknown, n_algExt, n_transExt, n_Z, n_Zn, n_Znm, n_Z2m
29+
from sage.libs.singular.decl cimport n_unknown, n_R, n_algExt, n_transExt, n_long_C, n_Z, n_Zn, n_Znm, n_Z2m
3030
from sage.libs.singular.decl cimport n_coeffType
3131
from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgExtInfo, TransExtInfo
3232

33+
cdef extern from "coeffs/coeffs.h":
34+
ctypedef struct LongComplexInfo:
35+
short float_len
36+
short float_len2
37+
const char* par_name
38+
3339

3440
from sage.rings.integer cimport Integer
3541
from sage.rings.integer_ring cimport IntegerRing_class
@@ -327,6 +333,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
327333
cdef AlgExtInfo extParam
328334
cdef TransExtInfo trextParam
329335
cdef n_coeffType _type = n_unknown
336+
cdef LongComplexInfo info
330337

331338
#cdef cfInitCharProc myfunctionptr;
332339

@@ -510,6 +517,17 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
510517
_cf = nInitChar( n_Z, NULL) # integer coefficient ring
511518
_ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
512519

520+
elif isinstance(base_ring, sage.rings.abc.RealDoubleField):
521+
_cf = nInitChar(n_R, NULL)
522+
_ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
523+
524+
elif isinstance(base_ring, sage.rings.abc.ComplexDoubleField):
525+
info.float_len = 15
526+
info.float_len2 = 0
527+
info.par_name = "I"
528+
_cf = nInitChar(n_long_C, <void *>&info)
529+
_ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
530+
513531
elif isinstance(base_ring, sage.rings.abc.IntegerModRing):
514532

515533
ch = base_ring.characteristic()

src/sage/libs/singular/singular.pyx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,37 @@ from sage.rings.finite_rings.finite_field_base import FiniteField
4040
from sage.rings.polynomial.polynomial_ring import PolynomialRing_field
4141
from sage.rings.fraction_field import FractionField_generic
4242

43+
from sage.rings.real_double cimport RealDoubleElement
44+
from sage.rings.complex_double cimport ComplexDoubleElement
45+
import sage.rings.abc
46+
4347
from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn
4448
from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro
4549
from sage.rings.finite_rings.finite_field_ntl_gf2e import FiniteField_ntl_gf2e
4650
from sage.libs.gmp.all cimport *
4751

52+
cdef extern from "coeffs/mpr_complex.h":
53+
cdef cppclass gmp_float:
54+
gmp_float(double v)
55+
double to_double "operator double"() const
56+
57+
cdef cppclass gmp_complex:
58+
gmp_complex(double re, double im)
59+
gmp_float real() const
60+
gmp_float imag() const
61+
62+
char *floatToStr(const gmp_float & r, const unsigned int oprec)
63+
char *complexToStr(gmp_complex & c, const unsigned int oprec, const n_Procs_s* src)
64+
4865
from sage.cpython.string import FS_ENCODING
4966
from sage.cpython.string cimport str_to_bytes, char_to_str, bytes_to_str
5067

5168
from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular
5269

70+
ctypedef union _nf_real:
71+
double f
72+
number* n
73+
5374
ctypedef struct fraction "fractionObject":
5475
poly *numerator
5576
poly *denominator
@@ -1599,6 +1620,10 @@ cdef object si2sa(number *n, ring *_ring, object base):
15991620
16001621
An element of ``base``
16011622
"""
1623+
cdef gmp_float* f
1624+
cdef gmp_complex* c
1625+
cdef _nf_real u
1626+
cdef char* s
16021627
if isinstance(base, FiniteField_prime_modn) and _ring.cf.type == n_Zp:
16031628
return base(_ring.cf.cfInt(n, _ring.cf))
16041629

@@ -1629,6 +1654,18 @@ cdef object si2sa(number *n, ring *_ring, object base):
16291654
elif isinstance(base, IntegerModRing_generic):
16301655
return si2sa_ZZmod(n, _ring, base)
16311656

1657+
elif isinstance(base, sage.rings.abc.RealDoubleField) and _ring.cf.type == n_R:
1658+
u.n = n
1659+
return base(u.f)
1660+
1661+
elif isinstance(base, sage.rings.abc.RealDoubleField) and _ring.cf.type == n_long_R:
1662+
f = <gmp_float*>n
1663+
return base(f[0].to_double())
1664+
1665+
elif isinstance(base, sage.rings.abc.ComplexDoubleField) and _ring.cf.type == n_long_C:
1666+
c = <gmp_complex*>n
1667+
return base(c[0].real().to_double(), c[0].imag().to_double())
1668+
16321669
else:
16331670
raise ValueError("cannot convert from SINGULAR number")
16341671

@@ -1648,6 +1685,10 @@ cdef number *sa2si(Element elem, ring * _ring) noexcept:
16481685
a (pointer to) a singular number
16491686
"""
16501687
cdef int i = 0
1688+
cdef _nf_real u
1689+
cdef ComplexDoubleElement z
1690+
cdef RealDoubleElement re
1691+
cdef RealDoubleElement im
16511692

16521693
if isinstance(elem._parent, FiniteField_prime_modn) and _ring.cf.type == n_Zp:
16531694
return n_Init(int(elem),_ring.cf)
@@ -1671,6 +1712,16 @@ cdef number *sa2si(Element elem, ring * _ring) noexcept:
16711712
return sa2si_NF(elem, _ring)
16721713
elif isinstance(elem._parent, IntegerModRing_generic):
16731714
return sa2si_ZZmod(elem, _ring)
1715+
elif isinstance(elem._parent, sage.rings.abc.RealDoubleField) and _ring.cf.type == n_R:
1716+
u.f = (<RealDoubleElement>elem)._value
1717+
return u.n
1718+
elif isinstance(elem._parent, sage.rings.abc.RealDoubleField) and _ring.cf.type == n_long_R:
1719+
return <number*><void*>new gmp_float((<RealDoubleElement>elem)._value)
1720+
elif isinstance(elem._parent, sage.rings.abc.ComplexDoubleField) and _ring.cf.type == n_long_C:
1721+
z = <ComplexDoubleElement>elem
1722+
re = <RealDoubleElement>z.real()
1723+
im = <RealDoubleElement>z.imag()
1724+
return <number*><void*>new gmp_complex(re._value, im._value)
16741725
elif isinstance(elem._parent, FractionField_generic) and isinstance(elem._parent.base(), (MPolynomialRing_libsingular, PolynomialRing_field)):
16751726
if isinstance(elem._parent.base().base_ring(), RationalField):
16761727
return sa2si_transext_QQ(elem, _ring)

src/sage/rings/ideal.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -367,24 +367,29 @@ def _richcmp_(self, other, op):
367367
sage: I == J
368368
True
369369
370-
TESTS:
371-
372-
Check that the example from :issue:`37409` raises an error
373-
rather than silently returning an incorrect result::
370+
TESTS::
374371
375372
sage: R.<x> = ZZ[]
376373
sage: I = R.ideal(1-2*x,2)
377-
sage: I.is_trivial() # not implemented -- see #37409
374+
sage: I.is_trivial() # needs sage.libs.singular
375+
True
376+
sage: R.ideal(x, 2) <= R.ideal(1) # needs sage.libs.singular
378377
True
379-
sage: I.is_trivial()
380-
Traceback (most recent call last):
381-
...
382-
NotImplementedError: ideal comparison in Univariate Polynomial Ring in x over Integer Ring is not implemented
383378
"""
384379
if self.is_zero():
385380
return rich_to_bool(op, other.is_zero() - 1)
386381
if other.is_zero():
387382
return rich_to_bool(op, 1) # self.is_zero() is already False
383+
384+
from sage.rings.integer_ring import ZZ
385+
if self.ring().base_ring() is ZZ:
386+
#assert self.ring().implementation() != "singular"
387+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
388+
Rs = PolynomialRing(ZZ, self.ring().variable_names(), implementation="singular")
389+
Is = Rs.ideal(self.gens())
390+
Js = Rs.ideal(other.gens())
391+
return Is.__richcmp__(Js, op)
392+
388393
S = set(self.gens())
389394
T = set(other.gens())
390395
if S == T:

src/sage/rings/polynomial/multi_polynomial_libsingular.pyx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,6 @@ AUTHORS:
170170
# * pNext and pIter don't need currRing
171171
# * p_Normalize apparently needs currRing
172172

173-
from warnings import warn
174-
175173
from libc.limits cimport INT_MAX
176174

177175
from cpython.object cimport Py_NE
@@ -4687,6 +4685,22 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base):
46874685
46884686
A :exc:`ValueError` exception is raised if ``g (== self)`` does not belong to ``I``.
46894687
4688+
.. WARNING::
4689+
4690+
This method is unreliable when the base ring is inexact::
4691+
4692+
sage: R.<x> = PolynomialRing(RDF, implementation="singular")
4693+
sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; R(1).lift((g, m))
4694+
sage: g.inverse_mod(m)
4695+
sage: inverse_mod(g, m)
4696+
sage: R.<x> = PolynomialRing(RDF)
4697+
sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; inverse_mod(g, m)
4698+
sage: g.inverse_mod(m)
4699+
4700+
But this is because of Singular::
4701+
4702+
Singular -q -c 'ring r = real,(x),lp; poly f = 5*x3 + x - 7; poly g = x4 - 12*x + 13; ideal M = f,g; ideal G = std(M); ideal SM = f; matrix T = lift(G,SM); T; quit;'
4703+
46904704
INPUT:
46914705
46924706
- ``I`` -- an ideal in ``self.parent()`` or tuple of generators of that ideal
@@ -4803,9 +4817,10 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base):
48034817
finally:
48044818
s = check_error()
48054819
if s:
4820+
msg = "polynomial is not in the ideal"
48064821
if s != ('2nd module does not lie in the first',):
4807-
warn(f'unexpected error from singular: {s}')
4808-
raise ValueError("polynomial is not in the ideal")
4822+
msg += f'; unexpected error from singular: {s}'
4823+
raise ValueError(msg)
48094824

48104825
l = [new_MP(parent, pTakeOutComp(&res.m[i], 1))
48114826
for i in range(IDELEMS(res)) for _ in range(IDELEMS(_I))]

src/sage/rings/polynomial/polynomial_element.pyx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,16 +1669,10 @@ cdef class Polynomial(CommutativePolynomial):
16691669
"""
16701670
from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular
16711671
P = a.parent()
1672-
if can_convert_to_singular(P):
1672+
if P.is_exact() and can_convert_to_singular(P):
16731673
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
1674-
try:
1675-
R = PolynomialRing(P.base_ring(), P.variable_names(), implementation="singular")
1676-
except NotImplementedError:
1677-
# PolynomialRing over RDF/CDF etc. are still not implemented in libsingular
1678-
# (in particular singular_ring_new) even though they are implemented in _do_singular_init_
1679-
pass
1680-
else:
1681-
return P(R(a).inverse_mod(R.ideal(m)))
1674+
R = PolynomialRing(P.base_ring(), P.variable_names(), implementation="singular")
1675+
return P(R(a).inverse_mod(R.ideal(m)))
16821676
from sage.rings.ideal import Ideal_generic
16831677
if isinstance(m, Ideal_generic):
16841678
v = m.gens_reduced()
@@ -11588,6 +11582,12 @@ cdef class Polynomial(CommutativePolynomial):
1158811582
sage: q.divides(p * q)
1158911583
True
1159011584
sage: R.<x> = Zmod(6)[]
11585+
sage: f = x - 2
11586+
sage: g = 3
11587+
sage: R.ideal(f*g) <= R.ideal(f)
11588+
True
11589+
sage: f.divides(f*g)
11590+
True
1159111591
sage: p = 4*x + 3
1159211592
sage: q = 5*x**2 + x + 2
1159311593
sage: q.divides(p)
@@ -11620,9 +11620,7 @@ cdef class Polynomial(CommutativePolynomial):
1162011620
sage: p = 4*x + 3
1162111621
sage: q = 2*x**2 + x + 2
1162211622
sage: p.divides(q)
11623-
Traceback (most recent call last):
11624-
...
11625-
NotImplementedError: divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms
11623+
False
1162611624
"""
1162711625
if p.is_zero():
1162811626
return True # everything divides 0
@@ -11642,7 +11640,13 @@ cdef class Polynomial(CommutativePolynomial):
1164211640
return False
1164311641

1164411642
if not self.base_ring().is_integral_domain():
11645-
raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms")
11643+
from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular
11644+
P = self.parent()
11645+
if can_convert_to_singular(P):
11646+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
11647+
R = PolynomialRing(P.base_ring(), P.variable_names(), implementation="singular")
11648+
return bool(R(self).divides(R(p)))
11649+
raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain unless Singular can be used")
1164611650

1164711651
try:
1164811652
return (p % self).is_zero() # if quo_rem is defined

src/sage/rings/polynomial/polynomial_ring_constructor.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,52 @@ def PolynomialRing(base_ring, *args, **kwds):
488488
...
489489
NotImplementedError: polynomials over Real Field with 53 bits of precision are not supported in Singular
490490
491+
Polynomial rings over double-precision real and complex fields are supported
492+
by the ``'singular'`` implementation::
493+
494+
sage: R.<x> = PolynomialRing(RDF, implementation='singular') # needs sage.libs.singular
495+
sage: x^2 + 1
496+
x^2 + (1.000e + 00)
497+
498+
sage: S.<x> = PolynomialRing(CDF, implementation='singular') # needs sage.libs.singular
499+
sage: x^2 + 1
500+
x^2 + 1
501+
502+
The ring printing via libSingular matches the output of the Singular
503+
interface::
504+
505+
sage: from sage.libs.singular.function import singular_function # needs sage.libs.singular
506+
sage: R.<x> = PolynomialRing(RDF, implementation="singular") # needs sage.libs.singular
507+
sage: C.<x> = PolynomialRing(CDF, implementation="singular") # needs sage.libs.singular
508+
sage: print(singular_function("print")(R)) # needs sage.libs.singular
509+
polynomial ring, over a field, global ordering
510+
// coefficients: Float() considered as a field
511+
// number of vars : 1
512+
// block 1 : ordering dp
513+
// : names x
514+
// block 2 : ordering C
515+
sage: print(singular_function("print")(C)) # needs sage.libs.singular
516+
polynomial ring, over a field, global ordering
517+
// coefficients: real[I](complex:15 digits, additional 0 digits)/(I^2+1) considered as a field
518+
// number of vars : 1
519+
// block 1 : ordering dp
520+
// : names x
521+
// block 2 : ordering C
522+
sage: print(singular(R)) # needs sage.libs.singular
523+
polynomial ring, over a field, global ordering
524+
// coefficients: Float() considered as a field
525+
// number of vars : 1
526+
// block 1 : ordering dp
527+
// : names x
528+
// block 2 : ordering C
529+
sage: print(singular(C)) # needs sage.libs.singular
530+
polynomial ring, over a field, global ordering
531+
// coefficients: real[I](complex:15 digits, additional 0 digits)/(I^2+1) considered as a field
532+
// number of vars : 1
533+
// block 1 : ordering dp
534+
// : names x
535+
// block 2 : ordering C
536+
491537
The following corner case used to result in a warning message from
492538
``libSingular``, and the generators of the resulting polynomial
493539
ring were not zero::

0 commit comments

Comments
 (0)