# Coercions between polynomial rings and term orders

The line

PolynomialRing(QQ, ['x', 'y', 'z'], order=TermOrder('lex', [1, 1, 1]))('x') + PolynomialRing(QQ, 'y')('y')


produces an error in Sage, while the line

PolynomialRing(QQ, ['x', 'y', 'z'])('x') + PolynomialRing(QQ, 'y')('y')


does not and returns x+y.

I do not quite understand how the details work. I have two questions: 1) Is the above line indeed supposed to trigger an exception, or is this a bug? 2) I need to work with a polynomial ring and the subring generated by one of the variables, as above. If I do not specify a term order, then all goes well, but as soon as I specify the term order I want (typically the above one), I run into problems when I combine elements from the bigger ring with elements from the smaller one (unless I explicitly coerce from the smaller ring to the bigger one). How am I supposed to proceed if I do want to use a term order and do not want to have to add explicit coercions?

edit retag close merge delete

Sort by ยป oldest newest most voted

Let us give names to the rings and the variables. The one-liners are mixing stuff. First of all, let us introduce some rings that live longer that in that line, and see what happens with the tacit coercion.

We introduce a ring $R=\Bbb Q[x,y,z]$, and use the lexicographic term order in it as part of the structure. The following works:

sage: R = PolynomialRing(QQ, 3, names='x,y,z', order=TermOrder('lex', [1, 1, 1]))
sage: R
Multivariate Polynomial Ring in x, y, z over Rational Field
sage: R('x')
x
sage: R('y')
y
sage: R('z')
z
sage: R('x').parent()
Multivariate Polynomial Ring in x, y, z over Rational Field
sage: R('x').parent() == R
True


So $R$ (in the code R) is a ring and its variables are accessed via R('x') and so on. I would want to inject them when dealing with the situation, but since two rings live together in the question and the question depends on them this is postponed. (The last injection of y would win and the variable y would live in the corresponding "injected ring".)

Note that the type of R is:

sage: type(R)
<class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'>


Also, R has a term order,

sage: R.term_order()
Lexicographic term order with weights (1, 1, 1)


which is needed e.g. when "typing" the polynomial $x+y$.

Let us do the same for the other ring, $S=\Bbb Q[y]$, with "an other $y$".

sage: S = PolynomialRing(QQ, names='y')
sage: S('y')
y
sage: S('y').parent()
Univariate Polynomial Ring in y over Rational Field
sage: S('y').parent() == S
True


The type of S is...

sage: type(S)
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category'>


And there is no term order.

Now the line

sage: R('x') + S('y')


leads to an error. The error has something to do with the coercion, and finally we have mentioned:

ValueError: impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring

In such cases it is a bad idea to let the machine guess too much.

Here are some solutions:

(1) To start with the $y$ from $S$, and see it as an element of $R$, we can simply type

sage: R(S('y'))
y


And this works. The coercion is done in a controlled manner. Now we can also ask for

sage: ( R('x') + R(S('y')) )^3
x^3 + 3*x^2*y + 3*x*y^2 + y^3


and the computations are done in $R$.

sage: _.parent() == R
True


(2) We can use explicitly a morphism between the two rings, $S\to R$, which maps $y\to y$. In this case, to have a piece of code that is better suited for the mathematician (arguably...), i will use $R=\Bbb Q[x,y,z]$, and $S=\Bbb Q[Y]$, with the morphism $f:S\to R$, $f(Y)=y$.

Then we can introduce the rings, inject variables, and compute $(x+f(Y))^3=(x+y)^3$ in $R$ using the code:

R = PolynomialRing(QQ, 3, names='x,y,z', order=TermOrder('lex', [1, 1, 1]))
S = PolynomialRing(QQ, names='Y')

R.inject_variables()
S.inject_variables()

f = S.Hom(R)(y)    # map the ring generator of $S$ to $y$ from $R$.

print( (x + f(Y))^3 )


And the above delivers:

Defining x, y, z
Defining Y
x^3 + 3*x^2*y + 3*x*y^2 + y^3


(3) This is (2) made shorter, the preparser works for us:

R.<x,y,z> = PolynomialRing(QQ, order=TermOrder('lex', [1, 1, 1]))
S.<Y> = PolynomialRing(QQ)

f = S.Hom(R)(y)    # map the ring generator of $S$ to $y$ from $R$.

print( (x + f(Y))^3 )


And we get the print we wanted.

Arguably, the above $f$ is an "explicit coercion", and as such it was excluded as a valid solution from the OP. But it is a "cheap coercion", mathematically we also have it, and it is always a good idea to mention in code morphisms when passing from one structure to an other one... If this is not wanted, then use R(S('y')), but for my taste, using $f$ makes the code readable.

more

A workaround is to define the second ring as multivariate, that is, PolynomialRing(QQ, 1, 'y') instead of PolynomialRing(QQ, 'y').

more