Skip to content

Commit 0ef6292

Browse files
Release Managervbraun
Release Manager
authored andcommitted
Trac #23338: Clean up polynomial constructor
This ticket cleans up the `PolynomialRing()` function in many ways. Mainly: 1. Use `normalize_names()` as much as possible to deal with variable names. 2. Fix indentation in docstring. 3. Pass arguments like `sparse` and `implementation` as `**kwds` to the single-variate or multi-variate polynomial constructor. 4. Make the code easier to understand. 5. Allow `PolynomialRing(..., implementation="singular")` which forces Singular. This allows simplifying some code in `src/sage/algebras/free_algebra.py` which currently needs to jump through hoops to get a `MPolynomialRing_libsingular`. 6. Check more error conditions, for example currently we have {{{ sage: PolynomialRing(QQ, name="x", names="y") Univariate Polynomial Ring in y over Rational Field }}} 7. Change some arguments of `PolynomialRing()` to keyword-only arguments. This does break some existing uses of `PolynomialRing()`, although much more likely in library code and not user code (some code in Sage gets this even wrong and was passing `sparse="lex"` instead of `order="lex"`) Apart from items 6 and 7, no existing functionality is changed. URL: https://trac.sagemath.org/23338 Reported by: jdemeyer Ticket author(s): Jeroen Demeyer Reviewer(s): Travis Scrimshaw
2 parents 3a7528f + fc75734 commit 0ef6292

15 files changed

+417
-292
lines changed

src/doc/en/constructions/polynomials.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ This example illustrates multivariate polynomial GCD's:
114114

115115
::
116116

117-
sage: R = PolynomialRing(RationalField(),3, ['x','y','z'], 'lex')
118-
sage: x,y,z = PolynomialRing(RationalField(),3, ['x','y','z'], 'lex').gens()
117+
sage: R.<x,y,z> = PolynomialRing(RationalField(), order='lex')
119118
sage: f = 3*x^2*(x+y)
120119
sage: g = 9*x*(y^2 - x^2)
121120
sage: f.gcd(g)

src/sage/algebras/free_algebra.py

+18-24
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,21 @@
116116
sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace')
117117
Traceback (most recent call last):
118118
...
119-
NotImplementedError: The letterplace implementation is not available for the free algebra you requested
120-
119+
TypeError: The base ring Free Algebra on 2 generators (a, b) over Integer Ring is not a commutative ring
121120
"""
121+
122122
#*****************************************************************************
123-
# Copyright (C) 2005 David Kohel <[email protected]>
124-
# Copyright (C) 2005,2006 William Stein <[email protected]>
125-
# Copyright (C) 2011 Simon King <[email protected]>
123+
# Copyright (C) 2005 David Kohel <[email protected]>
124+
# Copyright (C) 2005,2006 William Stein <[email protected]>
125+
# Copyright (C) 2011 Simon King <[email protected]>
126126
#
127-
# Distributed under the terms of the GNU General Public License (GPL)
127+
# This program is free software: you can redistribute it and/or modify
128+
# it under the terms of the GNU General Public License as published by
129+
# the Free Software Foundation, either version 2 of the License, or
130+
# (at your option) any later version.
128131
# http://www.gnu.org/licenses/
129132
#*****************************************************************************
133+
130134
from __future__ import absolute_import
131135
from six.moves import range
132136
from six import integer_types
@@ -139,13 +143,10 @@
139143

140144
from sage.algebras.free_algebra_element import FreeAlgebraElement
141145

142-
import sage.structure.parent_gens
143-
144146
from sage.structure.factory import UniqueFactory
145147
from sage.misc.cachefunc import cached_method
146148
from sage.all import PolynomialRing
147149
from sage.rings.ring import Algebra
148-
from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
149150
from sage.categories.algebras_with_basis import AlgebrasWithBasis
150151
from sage.combinat.free_module import CombinatorialFreeModule
151152
from sage.combinat.words.word import Word
@@ -266,21 +267,14 @@ def create_key(self,base_ring, arg1=None, arg2=None,
266267
return tuple(degrees),base_ring
267268
PolRing = None
268269
# test if we can use libSingular/letterplace
269-
if implementation is not None and implementation != 'generic':
270-
try:
271-
PolRing = PolynomialRing(base_ring, arg1, arg2,
272-
sparse=sparse, order=order,
273-
names=names, name=name,
274-
implementation=implementation if implementation != 'letterplace' else None)
275-
if not isinstance(PolRing, MPolynomialRing_libsingular):
276-
if PolRing.ngens() == 1:
277-
PolRing = PolynomialRing(base_ring, 1, PolRing.variable_names())
278-
if not isinstance(PolRing, MPolynomialRing_libsingular):
279-
raise TypeError
280-
else:
281-
raise TypeError
282-
except (TypeError, NotImplementedError) as msg:
283-
raise NotImplementedError("The letterplace implementation is not available for the free algebra you requested")
270+
if implementation == "letterplace":
271+
args = [arg for arg in (arg1, arg2) if arg is not None]
272+
kwds = dict(sparse=sparse, order=order, implementation="singular")
273+
if name is not None:
274+
kwds["name"] = name
275+
if names is not None:
276+
kwds["names"] = names
277+
PolRing = PolynomialRing(base_ring, *args, **kwds)
284278
if PolRing is not None:
285279
if degrees is None:
286280
return (PolRing,)

src/sage/algebras/letterplace/free_algebra_letterplace.pyx

+3-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring,blocks):
173173
for i from 1<=i<blocks:
174174
T += T0
175175
names.extend([x+'_'+str(i) for x in names0])
176-
return PolynomialRing(base_ring.base_ring(),len(names),names,order=T)
176+
return PolynomialRing(base_ring.base_ring(), names, order=T,
177+
implementation="singular")
178+
177179

178180
#####################
179181
# The free algebra

src/sage/interfaces/singular.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1640,13 +1640,13 @@ def sage_poly(self, R=None, kcache=None):
16401640
16411641
EXAMPLES::
16421642
1643-
sage: R = PolynomialRing(GF(2^8,'a'),2,'xy')
1644-
sage: f=R('a^20*x^2*y+a^10+x')
1645-
sage: f._singular_().sage_poly(R)==f
1643+
sage: R = PolynomialRing(GF(2^8,'a'), 'x,y')
1644+
sage: f = R('a^20*x^2*y+a^10+x')
1645+
sage: f._singular_().sage_poly(R) == f
16461646
True
1647-
sage: R = PolynomialRing(GF(2^8,'a'),1,'x')
1648-
sage: f=R('a^20*x^3+x^2+a^10')
1649-
sage: f._singular_().sage_poly(R)==f
1647+
sage: R = PolynomialRing(GF(2^8,'a'), 'x', implementation="singular")
1648+
sage: f = R('a^20*x^3+x^2+a^10')
1649+
sage: f._singular_().sage_poly(R) == f
16501650
True
16511651
16521652
::

src/sage/libs/singular/function.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,7 @@ cdef class SingularFunction(SageObject):
13171317
if ring is None:
13181318
if dummy_ring is None:
13191319
from sage.all import QQ, PolynomialRing
1320-
dummy_ring = PolynomialRing(QQ,"dummy",1) # seems a reasonable default
1320+
dummy_ring = PolynomialRing(QQ, "dummy", implementation="singular") # seems a reasonable default
13211321
ring = dummy_ring
13221322
if not (isinstance(ring, MPolynomialRing_libsingular) or isinstance(ring, NCPolynomialRing_plural)):
13231323
raise TypeError("Cannot call Singular function '%s' with ring parameter of type '%s'"%(self._name,type(ring)))

src/sage/libs/singular/ring.pyx

+12-16
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
137137
_ring = NULL
138138

139139
n = int(n)
140-
if n<1:
141-
raise ArithmeticError("The number of variables must be at least 1.")
140+
if n < 1:
141+
raise NotImplementedError(f"polynomials in {n} variables are not supported in Singular")
142142

143143
nvars = n
144144
order = TermOrder(term_order, n)
@@ -226,10 +226,8 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
226226

227227
elif isinstance(base_ring, NumberField) and base_ring.is_absolute():
228228
characteristic = 1
229-
try:
230-
k = PolynomialRing(RationalField(), 1, [base_ring.variable_name()], 'lex')
231-
except TypeError:
232-
raise TypeError("The multivariate polynomial ring in a single variable %s in lex order over Rational Field is supposed to be of type %s" % (base_ring.variable_name(), MPolynomialRing_libsingular))
229+
k = PolynomialRing(RationalField(),
230+
name=base_ring.variable_name(), order="lex", implementation="singular")
233231

234232
minpoly = base_ring.polynomial()(k.gen())
235233

@@ -257,8 +255,6 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
257255
_ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
258256

259257
elif (isinstance(base_ring, FiniteField_generic) and base_ring.is_prime_field()):
260-
#or (is_IntegerModRing(base_ring) and base_ring.characteristic().is_prime()):
261-
262258
if base_ring.characteristic() <= 2147483647:
263259
characteristic = base_ring.characteristic()
264260
else:
@@ -274,11 +270,10 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
274270
characteristic = -base_ring.characteristic() # note the negative characteristic
275271
else:
276272
raise TypeError("characteristic must be <= 2147483647.")
277-
# TODO: This is lazy, it should only call Singular stuff not MPolynomial stuff
278-
try:
279-
k = PolynomialRing(base_ring.prime_subfield(), 1, [base_ring.variable_name()], 'lex')
280-
except TypeError:
281-
raise TypeError("The multivariate polynomial ring in a single variable %s in lex order over %s is supposed to be of type %s" % (base_ring.variable_name(), base_ring,MPolynomialRing_libsingular))
273+
274+
# TODO: This is lazy, it should only call Singular stuff not PolynomialRing()
275+
k = PolynomialRing(base_ring.prime_subfield(),
276+
name=base_ring.variable_name(), order="lex", implementation="singular")
282277
minpoly = base_ring.polynomial()(k.gen())
283278

284279
ch = base_ring.characteristic()
@@ -307,6 +302,9 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
307302
elif is_IntegerModRing(base_ring):
308303

309304
ch = base_ring.characteristic()
305+
if ch < 2:
306+
raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular")
307+
310308
isprime = ch.is_prime()
311309

312310
if not isprime and ch.is_power_of(2):
@@ -356,10 +354,8 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
356354
_cf = nInitChar( n_Zn, <void *>&_info )
357355
_ring = rDefault( _cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
358356

359-
360357
else:
361-
raise NotImplementedError("Base ring is not supported.")
362-
358+
raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular")
363359

364360
if (_ring is NULL):
365361
raise ValueError("Failed to allocate Singular ring.")

src/sage/matrix/matrix_generic_sparse.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse):
160160
sage: loads(dumps(m)) == m
161161
True
162162
163-
sage: R2.<a,b> = PolynomialRing(QQ,'a','b')
163+
sage: R2.<a,b> = PolynomialRing(QQ)
164164
sage: M2 = MatrixSpace(R2,2,3,sparse=True)
165165
sage: M2(m)
166166
[4 1 0]

src/sage/misc/explain_pickle.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
pg_make_integer('c1p')
1919
sage: explain_pickle(dumps(polygen(QQ)))
2020
pg_Polynomial_rational_flint = unpickle_global('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')
21-
pg_PolynomialRing = unpickle_global('sage.rings.polynomial.polynomial_ring_constructor', 'PolynomialRing')
21+
pg_unpickle_PolynomialRing = unpickle_global('sage.rings.polynomial.polynomial_ring_constructor', 'unpickle_PolynomialRing')
2222
pg_RationalField = unpickle_global('sage.rings.rational_field', 'RationalField')
2323
pg = unpickle_instantiate(pg_RationalField, ())
2424
pg_make_rational = unpickle_global('sage.rings.rational', 'make_rational')
25-
pg_Polynomial_rational_flint(pg_PolynomialRing(pg, 'x', None, False), [pg_make_rational('0'), pg_make_rational('1')], False, True)
25+
pg_Polynomial_rational_flint(pg_unpickle_PolynomialRing(pg, ('x',), None, False), [pg_make_rational('0'), pg_make_rational('1')], False, True)
2626
sage: sage_eval(explain_pickle(dumps(polygen(QQ)))) == polygen(QQ)
2727
True
2828
@@ -40,8 +40,9 @@
4040
make_integer('c1p')
4141
sage: explain_pickle(dumps(polygen(QQ)), in_current_sage=True)
4242
from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint
43+
from sage.rings.polynomial.polynomial_ring_constructor import unpickle_PolynomialRing
4344
from sage.rings.rational import make_rational
44-
Polynomial_rational_flint(PolynomialRing(RationalField(), 'x', None, False), [make_rational('0'), make_rational('1')], False, True)
45+
Polynomial_rational_flint(unpickle_PolynomialRing(RationalField(), ('x',), None, False), [make_rational('0'), make_rational('1')], False, True)
4546
4647
The explain_pickle function has several use cases.
4748

src/sage/rings/ideal.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1661,7 +1661,7 @@ def Katsura(R, n=None, homog=False, singular=singular_default):
16611661
16621662
::
16631663
1664-
sage: Q.<x> = PolynomialRing(QQ,1)
1664+
sage: Q.<x> = PolynomialRing(QQ, implementation="singular")
16651665
sage: J = sage.rings.ideal.Katsura(Q,1); J
16661666
Ideal (x - 1) of Multivariate Polynomial Ring in x over Rational Field
16671667
"""

src/sage/rings/polynomial/laurent_polynomial_ring.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def _multi_variate(base_ring, names, n, sparse, order):
383383
break
384384
else:
385385
break
386-
R = _multi_variate_poly(base_ring, names, n, sparse, order, None)
386+
R = _multi_variate_poly(base_ring, names, sparse, order)
387387
P = LaurentPolynomialRing_mpair(R, prepend_string, names)
388388
_save_in_cache(key, P)
389389
return P

src/sage/rings/polynomial/multi_polynomial_libsingular.pyx

+23-3
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ TESTS::
137137
sage: loads(dumps(x)) == x
138138
True
139139
140-
sage: Rt.<t> = PolynomialRing(QQ,1)
140+
sage: Rt.<t> = PolynomialRing(QQ, implementation="singular")
141141
sage: p = 1+t
142142
sage: R.<u,v> = PolynomialRing(QQ, 2)
143143
sage: p(u/v)
@@ -363,6 +363,26 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic):
363363
Polynomial base injection morphism:
364364
From: Integer Ring
365365
To: Multivariate Polynomial Ring in x, y over Integer Ring
366+
367+
Check some invalid input::
368+
369+
sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
370+
sage: MPolynomialRing_libsingular(Zmod(1), 1, ["x"], "lex")
371+
Traceback (most recent call last):
372+
...
373+
NotImplementedError: polynomials over Ring of integers modulo 1 are not supported in Singular
374+
sage: MPolynomialRing_libsingular(SR, 1, ["x"], "lex")
375+
Traceback (most recent call last):
376+
...
377+
NotImplementedError: polynomials over Symbolic Ring are not supported in Singular
378+
sage: MPolynomialRing_libsingular(QQ, 0, [], "lex")
379+
Traceback (most recent call last):
380+
...
381+
NotImplementedError: polynomials in 0 variables are not supported in Singular
382+
sage: MPolynomialRing_libsingular(QQ, -1, [], "lex")
383+
Traceback (most recent call last):
384+
...
385+
ValueError: Multivariate Polynomial Rings must have more than 0 variables.
366386
"""
367387
MPolynomialRing_generic.__init__(self, base_ring, n, names, order)
368388
self._has_singular = True
@@ -1947,7 +1967,7 @@ def unpickle_MPolynomialRing_libsingular(base_ring, names, term_order):
19471967
from sage.rings.polynomial.polynomial_ring_constructor import _multi_variate
19481968
# If libsingular would be replaced by a different implementation in future
19491969
# sage version, the unpickled ring will belong the new implementation.
1950-
return _multi_variate(base_ring, tuple(names), len(names), False, term_order, None)
1970+
return _multi_variate(base_ring, tuple(names), False, term_order, None)
19511971

19521972
cdef class MPolynomial_libsingular(MPolynomial):
19531973
"""
@@ -3018,7 +3038,7 @@ cdef class MPolynomial_libsingular(MPolynomial):
30183038
sage: f[0,1]
30193039
0
30203040
3021-
sage: R.<x> = PolynomialRing(GF(7),1); R
3041+
sage: R.<x> = PolynomialRing(GF(7), implementation="singular"); R
30223042
Multivariate Polynomial Ring in x over Finite Field of size 7
30233043
sage: f = 5*x^2 + 3; f
30243044
-2*x^2 + 3

src/sage/rings/polynomial/plural.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2227,7 +2227,7 @@ cdef class NCPolynomial_plural(RingElement):
22272227
sage: f[0,0,0]
22282228
0
22292229
2230-
sage: R.<x> = PolynomialRing(GF(7),1); R
2230+
sage: R.<x> = PolynomialRing(GF(7), implementation="singular"); R
22312231
Multivariate Polynomial Ring in x over Finite Field of size 7
22322232
sage: f = 5*x^2 + 3; f
22332233
-2*x^2 + 3

src/sage/rings/polynomial/polynomial_ring.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
121121
Check that :trac:`5562` has been fixed::
122122
123-
sage: R.<u> = PolynomialRing(RDF, 1, 'u')
123+
sage: R.<u> = PolynomialRing(RDF, 1)
124124
sage: v1 = vector([u])
125125
sage: v2 = vector([CDF(2)])
126126
sage: v1 * v2
@@ -210,9 +210,7 @@ def is_PolynomialRing(x):
210210
211211
::
212212
213-
sage: is_PolynomialRing(PolynomialRing(ZZ,1,'w'))
214-
False
215-
sage: R = PolynomialRing(ZZ,1,'w'); R
213+
sage: R.<w> = PolynomialRing(ZZ, implementation="singular"); R
216214
Multivariate Polynomial Ring in w over Integer Ring
217215
sage: is_PolynomialRing(R)
218216
False
@@ -294,10 +292,9 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ
294292
self._Karatsuba_threshold = 8
295293

296294
def __reduce__(self):
297-
import sage.rings.polynomial.polynomial_ring_constructor
298-
return (sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing,
299-
(self.base_ring(), self.variable_name(), None, self.is_sparse()))
300-
295+
from sage.rings.polynomial.polynomial_ring_constructor import unpickle_PolynomialRing
296+
args = (self.base_ring(), self.variable_names(), None, self.is_sparse())
297+
return unpickle_PolynomialRing, args
301298

302299
def _element_constructor_(self, x=None, check=True, is_gen=False,
303300
construct=False, **kwds):
@@ -1598,7 +1595,7 @@ def __init__(self, base_ring, name="x", sparse=False, implementation=None,
15981595
element_class = Polynomial_integer_dense_flint
15991596
self._implementation_names = (None, 'FLINT')
16001597
else:
1601-
raise ValueError("Unknown implementation %s for ZZ[x]"%implementation)
1598+
raise ValueError("unknown implementation %r for ZZ[%r]" % (implementation, name[0]))
16021599
PolynomialRing_commutative.__init__(self, base_ring, name=name,
16031600
sparse=sparse, element_class=element_class, category=category)
16041601

0 commit comments

Comments
 (0)