LaurentPolynomialRing and PolynomialRing behave inconsistently -- Request For Comments

78 views
Skip to first unread message

VulK

unread,
Apr 8, 2016, 7:14:40 PM4/8/16
to sage-devel
Dear All,
for some project I have been working on for some time I found myself interested
in comparing elements of two different LaurentPolynomialRing. Unfortunately,
at the moment this is somewhat broken. The current behaviour is this:


sage: L1 = LaurentPolynomialRing(ZZ, 'x0,x1,x2,y0,y1,y2')
sage: L2 = LaurentPolynomialRing(ZZ, 'y0,y1,y2')
sage: L2.gen(0) in L1
False
sage: L1(L2.gen(0))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: tuple key must have same length as ngens


On the other hand PolynomialRing behave differently:

sage: P1 = PolynomialRing(ZZ, 'x0,x1,x2,y0,y1,y2')
sage: P2 = PolynomialRing(ZZ, 'y0,y1,y2')
sage: P2.gen(0) in P1
True
sage: P1(P2.gen(0))
y0


I made a ticket to address this issue #19538 and in the discussion there many
more inconsistencies popped out. This e-mail is to ask the community which should
be the desired behavior of both PolynomialRing and LaurentPolynomialRing and how
to get them to agree.

I will use this function to prettyprint

sage: def printmap(target, source):
print(str(source) + " --> " + str(map(target,source)))


* PolynomialRing

sage: P1 = PolynomialRing(ZZ, 'x,y')
sage: P2 = PolynomialRing(ZZ, 'x,t')
sage: P3 = PolynomialRing(ZZ, 't,x')
sage: P4 = PolynomialRing(ZZ, 'x,t,y')
##### these behave somewhat predictably
sage: printmap(P4, P1.gens())
(x, y) --> [x, y]
sage: printmap(P4, P3.gens())
(t, x) --> [t, x]
y
sage: P1(P4('t'))
Traceback (most recent call last):
...
TypeError: Could not find a mapping of the passed element to this ring.
#### these instead are not really behaving in the same way
sage: printmap(P1, P3.gens()) # this maps the i-th generator to the i-th generator irregardless of their names (t to x and x to y)
(t, x) --> [x, y]
sage: printmap(P3, P2.gens()) # this instead maps x to x and t to t
(x, t) --> [x, t]

* LaurentPolynomialRing

sage: L1 = LaurentPolynomialRing(ZZ, 'x,y')
sage: L2 = LaurentPolynomialRing(ZZ, 'x,t')
sage: L3 = LaurentPolynomialRing(ZZ, 't,x')
sage: L4 = LaurentPolynomialRing(ZZ, 'x,t,y')
sage: printmap(L4, L1.gens())
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: tuple key must have same length as ngens
sage: printmap(L4, L3.gens())
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: tuple key must have same length as ngens
sage: L1(L4('t'))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: tuple key must have same length as ngens
sage: sage: printmap(L1, L3.gens())
(t, x) --> [x, y]
sage: sage: printmap(L3, L2.gens())
(x, t) --> [t, x]

As you can see for LaurentPolynomialRing the maps currently work only if source
and target have the same number of variables. Moreover, whenever they do, the
behaviour is different from the one of PolynomialRing: in any case the map sends
the i-th generator to the i-th generator (arguably this could e seen as more
consistent).

After the patch I wrote the situation is the following:

* patched LaurentPolynomialRing

sage: R1 = LaurentPolynomialRing(ZZ, 'x,y')
sage: R2 = LaurentPolynomialRing(ZZ, 'x,t')
sage: R3 = LaurentPolynomialRing(ZZ, 't,x')
sage: R4 = LaurentPolynomialRing(ZZ, 'x,t,y')
sage: printmap(R4, R1.gens())
(x, y) --> [x, y]
sage: printmap(R4, R3.gens())
(t, x) --> [t, x]
sage: R1(R4('t'))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
...
ValueError: tuple.index(x): x not in tuple
sage: sage: printmap(R1, R3.gens())
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
ValueError: tuple.index(x): x not in tuple
sage: sage: printmap(R3, R2.gens())
(x, t) --> [x, t]

The patch maps a generator to the generator having the same name, if any (which
explain the failures). The error code should probably be improved. Note that

sage: R1(R3.gen(1))
x

works as expected. This patch, though, while making LaurentPolynomialRing behave
like PolynomialRing in most cases, makes the behaviour inconsistent in the
previous to last case.

A note on speed: I expect the patched code to be slower than the original one. I
did not make any test to gauge how much.


In view of the above examples, which do you think should be the behaviour of both
LaurentpolynomialRing and PolynomialRing? This is quite a central piece of code
in sage and it would be better if the decision about how to proceed is not taken
in some obscure ticket.

Best
S.



Volker Braun

unread,
Apr 9, 2016, 4:15:38 AM4/9/16
to sage-devel, etn4...@gmail.com
Let me try to summarize the expected behavior: If there is a coercion of the base rings, then there should be a coercion to the (laurent) polynomial ring with additional variables. The variables in the different rings are identified using their name (and not index in gens() or any other rule). 

sage: cm = get_coercion_model()
sage: R.<x> = QQ[]
sage: S.<x,t> = QQ[]
sage: cm.explain(R, S, operator.add)
Coercion on left operand via
    Conversion map:
      From: Univariate Polynomial Ring in x over Rational Field
      To:   Multivariate Polynomial Ring in x, t over Rational Field
Arithmetic performed after coercions.
Result lives in Multivariate Polynomial Ring in x, t over Rational Field
Multivariate Polynomial Ring in x, t over Rational Field

No coercion if variable names are not strict subsets:

sage: T.<x,y> = QQ[]
sage: cm.explain(T, S, operator.add)
Unknown result parent.

But explicit conversion can still work, e.g. by falling back to the index in gens():

sage: T(S.gen(0))
x
sage: T(S.gen(1))
y

Vincent Delecroix

unread,
Apr 9, 2016, 9:09:08 AM4/9/16
to sage-...@googlegroups.com
Still, we have this strange (conversion) behavior

sage: R.<x,y> = QQ[]
sage: S.<y,t> = QQ[]
sage: R(S('y'))
x
sage: S(R('x'))
y

Volker Braun

unread,
Apr 9, 2016, 9:32:38 AM4/9/16
to sage-devel
I mentioned that; Is it really strange though? It does not happen implicitly through coercion. You have to explicitly ask to convert one polynomial ring in two variables to another polynomial ring in two variables (with mismatching generator names).

David Roe

unread,
Apr 9, 2016, 11:09:12 AM4/9/16
to sage-devel, etn4...@gmail.com
I think that this summary is right, including the explicit conversion that relies on the index in gens().
David

--
You received this message because you are subscribed to the Google Groups "sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+...@googlegroups.com.
To post to this group, send email to sage-...@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

VulK

unread,
Apr 24, 2016, 2:00:54 PM4/24/16
to sage-devel
Dear All,
sorry for the late reply: my todo list came knocking at my door and required
immediate attention.

I did a small test and it appears that both Polynomial and LaurentPolynomial
behave in the same way with respect to coercion. On the other hand their
behavior under conversion is different.

Do we want the behavior under conversion to also be the same? If so, which
one should it be?
Best
S.





* David Roe <roed...@gmail.com> [2016-04-09 11:08:51]:

> I think that this summary is right, including the explicit conversion
> that relies on the index in gens().
> David
>
> On Sat, Apr 9, 2016 at 4:15 AM, Volker Braun <[1]vbrau...@gmail.com>
> wrote:
>
> Let me try to summarize the expected behavior: If there is a coercion
> of the base rings, then there should be a coercion to the (laurent)
> polynomial ring with additional variables. The variables in the
> different rings are identified using their name (and not index in
> gens() or any other rule).Â
> sage: cm = get_coercion_model()
> sage: R.<x> = QQ[]
> sage: S.<x,t> = QQ[]
> sage: cm.explain(R, S, operator.add)
> Coercion on left operand via
> Â Â Conversion map:
> Â Â Â From: Univariate Polynomial Ring in x over Rational Field
> Â Â Â To: Â Multivariate Polynomial Ring in x, t over Rational
> Field
> Arithmetic performed after coercions.
> Result lives in Multivariate Polynomial Ring in x, t over Rational
> Field
> Multivariate Polynomial Ring in x, t over Rational Field
> No coercion if variable names are not strict subsets:
> sage: T.<x,y> = QQ[]
> sage: cm.explain(T, S, operator.add)
> Unknown result parent.
> But explicit conversion can still work, e.g. by falling back to the
> index in gens():
> sage: T(S.gen(0))
> x
> sage: T(S.gen(1))
> y
>
> --
> You received this message because you are subscribed to the Google
> Groups "sage-devel" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to [2]sage-devel+...@googlegroups.com.
> To post to this group, send email to [3]sage-...@googlegroups.com.
> Visit this group at [4]https://groups.google.com/group/sage-devel.
> For more options, visit [5]https://groups.google.com/d/optout.
>
> References
>
> 1. mailto:vbrau...@gmail.com
> 2. mailto:sage-devel+...@googlegroups.com
> 3. mailto:sage-...@googlegroups.com
> 4. https://groups.google.com/group/sage-devel
> 5. https://groups.google.com/d/optout
Reply all
Reply to author
Forward
0 new messages