multi-polynomial substitution consistency

131 views
Skip to first unread message

Vincent Delecroix

unread,
May 9, 2021, 4:50:06 AM5/9/21
to sage-devel
Dear all,

Sage currently supports in a weird way partial substitution
of multivariate polynomials

sage: R.<x,y> = QQ[]
sage: S.<q> = QQ[]
sage: p = x
sage: p.subs(x=q)
q
sage: p.subs(x=q).parent()
Univariate Polynomial Ring in q over Rational Field

What is annoying in the above scenario is that it breaks
badly the rule "same input parent" -> "same output parent".
Here are three distinct output parents for the same substitution
command

sage: p1 = R.zero()
sage: p2 = x
sage: p3 = x + y
sage: p1.subs(x=q).parent()
Rational Field
sage: p2.subs(x=q).parent()
Univariate Polynomial Ring in q over Rational Field
sage: p3.subs(x=q).parent()
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +:
'Univariate Polynomial Ring in q over Rational Field' and
'Multivariate Polynomial Ring in x, y over Rational Field'

I propose to raise a TypeError in all the above scenarii. In case
somebody wants to mutate the parent, she should provide a full
translation, namely

sage: x.subs(x=q, y=S.zero())

In other words

x.subs(x=*): partial substitution, output has parent parent(x)
x.subs(x=*, y=*): full substitution, output has parent the merge of
the base ring and the arguments

What do you think?

Best
Vincent

Nils Bruin

unread,
May 9, 2021, 5:01:45 PM5/9/21
to sage-devel
I'd say that for a "full" evaluation at a list of images V for all variables, a guide would be that f(*V)  should be roughly:

sum(c*prod(m^e for e,m in zip(es,V)) for es,c in f.dict().items())

Only roughly, though, because for, for instance, if f==0, then this code evaluates to an empty sum, so we probably get the integer 0 back, which is not particularly desirable.

So, I'd say for a full evaluation, the result should be whatever the coercion system can find to be the "common over-ring" for f.base_ring() and the elements of V. We'd probably want to have some shortcuts in determining this codomain. It also suggests that if you want to do multiple evaluations, building the corresponding homomorphism might be faster, since it  avoids a lot of discovery.

I'd say that a partial evaluation such as
R.<x,y>=QQ[]
f=x^2+x*y+y^2
f(x=1)
should correspond to a full evaluation, where the unmentioned variables are taken to be evaluated at themselves, so the result should be
f(1,y)
which means it's f(*V) with V=(1,y). The same codomain determination rules as above apply.

In particular, this means that something like
f(x=1.0)
still works and would give the same result as
f(1.0,y)

It looks like the example you give would then not work anymore, because sage does not create a common parent for QQ['x','y'] and QQ['q']. I think this ends up being a little more permissive rule for (partial) evaluations than you are proposing, but it would be a little more consistent with what we''re doing right now.

Andrey Novoseltsev

unread,
May 24, 2021, 5:44:09 PM5/24/21
to sage-devel
On Sunday, 9 May 2021 at 02:50:06 UTC-6 vdelecroix wrote:
What is annoying in the above scenario is that it breaks
badly the rule "same input parent" -> "same output parent".
Here are three distinct output parents for the same substitution
command

I completely agree with Vincent on this point. If you are going to do something further with the output in your code, having potentially different objects is very inconvenient. Since partial substitution (which is supported by "subs" method) almost certainly has to live in the same polynomial ring as the starting polynomial, I strongly favour the result of subs to be in this ring whenever possible. Perhaps if there is a full substitution and another natural ring to live in, as is the case with ring homomorphisms, it can be there, but do not drop to the ring of coefficients just because it is possible for a particular case.

On the other hand, call method does not support partial substitution and acts as an evaluation where it makes a lot of sense to use the coefficient ring by default, but again one can consider natural subcases.

Having these two methods with different intended output would be quite clean, it seems to me. 

Nils Bruin

unread,
May 25, 2021, 3:42:24 AM5/25/21
to sage-devel
On Monday, 24 May 2021 at 14:44:09 UTC-7 ... wrote:
On Sunday, 9 May 2021 at 02:50:06 UTC-6 vdelecroix wrote:
What is annoying in the above scenario is that it breaks
badly the rule "same input parent" -> "same output parent".
Here are three distinct output parents for the same substitution
command

I completely agree with Vincent on this point. If you are going to do something further with the output in your code, having potentially different objects is very inconvenient. Since partial substitution (which is supported by "subs" method) almost certainly has to live in the same polynomial ring as the starting polynomial, I strongly favour the result of subs to be in this ring whenever possible. Perhaps if there is a full substitution and another natural ring to live in, as is the case with ring homomorphisms, it can be there, but do not drop to the ring of coefficients just because it is possible for a particular case.

+1 on letting the codomain only depend on the parents of the argument; not on the values themselves. Note, though, that currently

sage: R.<x,y>=QQ[]
sage: f=x+y
sage: f.subs(x=1.0)
y + 1.00000000000000
sage: f.subs(x=1.0).parent()
Multivariate Polynomial Ring in x, y over Real Field with 53 bits of precision

I don't think you'd want to break that. The parent here gets discovered because the coercion system can figure out that adding/multiplying elements from RR and from QQ['x','y'] can be performed using a base change and produce elements of RR['x','y']
 
On the other hand, call method does not support partial substitution and acts as an evaluation where it makes a lot of sense to use the coefficient ring by default, but again one can consider natural subcases.

It does:

sage: f(x=1.0)
y + 1.00000000000000

I agree it's a bit redundant to have __call__ as well as subs, but that's a historic artefact by now. I'd say making them completely synonymous is the easiest way of dealing with this.

 
Reply all
Reply to author
Forward
0 new messages