Open dkrenn opened 9 years ago
Branch: u/dkrenn/SR/eval
New commits:
9f8d483 | create method eval |
68b65ca | rename eval to evaluate |
24348f7 | docstring: output clearified |
c3d0670 | rename ring to convert_to |
6449f20 | implement automatic detection when convert_to=None |
cd29dca | examples rewritten |
bc2bb47 | add seealso-block |
9419e1f | fix typo |
9e83cb2 | docstring for helper function _evaluate_ |
c3696a8 | fix links in doc |
Author: Daniel Krenn
+ The reason is that :meth:`subs` convert its arguments to the
+ symbolic ring, so we even have::
+
+ sage: x.subs(x=RIF(3.42)).parent()
+ Symbolic Ring
+
+ The :meth:`evaluate`-method prevents this conversion and
I think you misunderstand. x
is not converted, it is wrapped in an expression:
sage: x.subs(x=RIF(3.42)).pyobject().parent()
Real Interval Field with 53 bits of precision
I have no idea if your idea is worth the effort, but suspect that not if it is only based on the necessity to prevent "conversion".
Description changed:
---
+++
@@ -1,4 +1,4 @@
-`subs` of a symbolic expression converts its values to the symbolic ring before performing the actual substitution. This ticket proposes a new method `evaluate` which comes over this.
+`subs` of a symbolic expression wraps its values to the symbolic ring (if possible) before performing the actual substitution. This ticket proposes a new method `evaluate` which comes over this.
sage: E = (1+x).evaluate(x=RIF(3.42)) @@ -7,4 +7,17 @@ sage: E.parent() Real Interval Field with 53 bits of precision
+While in the example above you can come over this by doing a conversion afterwards, it changes with power series:
+```
+sage: P.<p> = ZZ[[]]
+sage: x.subs(x=p)
+Traceback (most recent call last):
+...
+TypeError: no canonical coercion from Power Series Ring in p over Integer Ring to Symbolic Ring
+
+sage: E = x.evaluate(x=p)
+sage: E, E.parent()
+p, Power Series Ring in p over Integer Ring)
+```
+
Replying to @rwst:
I think you misunderstand.
x
is not converted, it is wrapped in an expression:
Ok, I used the wrong word; however, this example was to point out the differences between the two commands.
sage: x.subs(x=RIF(3.42)).pyobject().parent() Real Interval Field with 53 bits of precision
I have no idea if your idea is worth the effort, but suspect that not if it is only based on the necessity to prevent "conversion".
subs
is not possible with something that does go into the symbolic ring, like power series:
sage: P.<p> = ZZ[[]]
sage: x.subs(x=p)
Traceback (most recent call last):
...
TypeError: no canonical coercion from Power Series Ring in p over Integer Ring to Symbolic Ring
sage: E = x.evaluate(x=p)
sage: E, E.parent()
p, Power Series Ring in p over Integer Ring)
Changed keywords from none to sd66
I thought everything coerces to SR
? Maybe this is just a coercion bug?
Replying to @rwst:
I thought everything coerces to
SR
? Maybe this is just a coercion bug?
IMHO, not everything coerces into SR
and this for a good reason. But this is not (or should not) under discussion here.
The following is not possible at with subs:
sage: sage: P.<p> = ZZ[[]]
sage: var('a,b')
(a, b)
sage: (a+b).subs({a: p, b: p^2})
evaluate
can do.
Hello,
Why not
sage: E = (1+x).subs(x=RIF(3.42))
sage: E.parent()
sage: F = E.pyobject()
sage: F
4.4200000000000000?
sage: F.parent()
Real Interval Field with 53 bits of precision
Vincent
added a doctest and corrected a small bug
Replying to @videlec:
Why not
sage: E = (1+x).subs(x=RIF(3.42)) sage: E.parent() sage: F = E.pyobject() sage: F 4.4200000000000000? sage: F.parent() Real Interval Field with 53 bits of precision
Ok, I see. Maybe RIFs are not a good example since they coerce into SR. Power series are better" example; since there problems.
I'll rewrite the description of the ticket and the examples.
The general idea is that the result of arithmetic only depends on the parents of the input data, not on the values of the input data (because the idea is that these things implement maps, which have domains and codomains). When you evaluate a SR element at a non-symbolic value, you don't know if the result can live in the parent of the original result (e.g., (sin(x)+y).subs(y=1)
).
The appropriate solution is probably to first convert your symbolic expression to a parent where the parent is the desired thing, e.g.
sage: f = SR(1+x)
sage: R.<t>= ZZ[[]]
sage: P=R['x']
sage: P(f)(x=t^2+O(t^3))
This also has other advantages: in principle, when you do this with RIF, you might end up with an evaluation routine that takes into account that the coefficients are not exact and hence it could choose some more stable way of doing the evaluation (I think that's hypothetical--likely no such effort is made right now, but it could).
Description changed:
---
+++
@@ -1,13 +1,14 @@
-`subs` of a symbolic expression wraps its values to the symbolic ring (if possible) before performing the actual substitution. This ticket proposes a new method `evaluate` which comes over this.
+This ticket proposes a new method `evaluate` which can evaluate symbolic expressions at values coming from a ring which not coerces into `SR`. The result again lives in the ring of the values. This forces the calculation to be done completely in the given ring (and not in the symbolic ring, where sometimes one does not know exactly what's going on).
+
+For example:
-sage: E = (1+x).evaluate(x=RIF(3.42)) -sage: E -4.4200000000000000? -sage: E.parent() -Real Interval Field with 53 bits of precision +sage: P.
= ZZ[[]] +sage: E = x.evaluate(x=p) +sage: E, E.parent() +(p, Power Series Ring in p over Integer Ring)
-While in the example above you can come over this by doing a conversion afterwards, it changes with power series:
+which is not possible with `subs`
sage: P.
= ZZ[[]]
Branch pushed to git repo; I updated commit sha1. New commits:
276f0f3 | rewrite documentation (examples) after discussion on trac |
rewritten documentation of function
Replying to @nbruin:
The general idea is that the result of arithmetic only depends on the parents of the input data, not on the values of the input data (because the idea is that these things implement maps, which have domains and codomains). When you evaluate a SR element at a non-symbolic value, you don't know if the result can live in the parent of the original result (e.g.,
(sin(x)+y).subs(y=1)
).
True.
The appropriate solution is probably to first convert your symbolic expression to a parent where the parent is the desired thing, e.g.
sage: f = SR(1+x) sage: R.<t>= ZZ[[]] sage: P=R['x'] sage: P(f)(x=t^2+O(t^3))
What if
f = SR(1+2^x)
or something worse (including e.g. exp, log, sin, ... or other functions)? There are no parents (except SR) for any of these constructs.
Replying to @dkrenn:
What if
f = SR(1+2^x)
or something worse (including e.g. exp, log, sin, ... or other functions)? There are no parents (except SR) for any of these constructs.
And indeed it's tricky to evaluate the result. What is 2^<power series>
? I guess exp(log(2)*x)
, which requires a ring that contains both log(2)
and inverses of all integers., so that doesn't work in Z[[t]]
. I think Sage is right in putting the onus on the user to first find a parent in which the expression fits and where the evaluation behaviour is the desired one.
Anyway, fast_callable
takes a best effort approach towards compiling a program that tries to perform the evaluation, so that might be your best bet.
Replying to @nbruin:
Anyway,
fast_callable
takes a best effort approach towards compiling a program that tries to perform the evaluation, so that might be your best bet.
Ok, I'll make some experiments and run some tests to see if it satisfies my needs.
Thanks
Hello,
Would this ticket solve the following issue (from #9787)?
sage: parent(exp(1.2))
Real Field with 53 bits of precision
sage: f(x) = exp(x)
sage: parent(f(1.2))
Symbolic Ring
Vincent
Replying to @videlec:
Hello,
Would this ticket solve the following issue (from #9787)?
sage: parent(exp(1.2)) Real Field with 53 bits of precision sage: f(x) = exp(x) sage: parent(f(1.2)) Symbolic Ring
Yes.
sage: f(x).evaluate({x: 1.2}).parent()
Real Field with 53 bits of precision
Replying to @dkrenn:
Replying to @videlec:
Hello,
Would this ticket solve the following issue (from #9787)?
sage: parent(exp(1.2)) Real Field with 53 bits of precision sage: f(x) = exp(x) sage: parent(f(1.2)) Symbolic Ring
Yes.
sage: f(x).evaluate({x: 1.2}).parent() Real Field with 53 bits of precision
Sorry. This was not my question. What would be parent(f(1.2))
? Is this modified by this ticket?
Replying to @videlec:
Replying to @dkrenn:
Replying to @videlec:
Would this ticket solve the following issue (from #9787)?
sage: parent(exp(1.2)) Real Field with 53 bits of precision sage: f(x) = exp(x) sage: parent(f(1.2)) Symbolic Ring
[...]
Sorry. This was not my question. What would be
parent(f(1.2))
? Is this modified by this ticket?
No, not modified by this ticket.
Replying to @dkrenn:
Replying to @videlec:
Replying to @dkrenn:
Replying to @videlec:
Would this ticket solve the following issue (from #9787)?
...
Sorry. This was not my question. What would be
parent(f(1.2))
? Is this modified by this ticket?No, not modified by this ticket.
I saw too late your answer on #9878 ;-)
By the way, let me repeat another question from #9878. I found the behavior of evaluate
in your comment:22 very weird. I thought it was a modification of .subs
in order to take care of the parent. But
sage: f(x) = 2*x
sage: f.subs(x=3)
x |--> 6
ie, f
remains a function. It is hopefully not changed into a number.
Replying to @videlec:
By the way, let me repeat another question from #9878. I found the behavior of
evaluate
in your comment:22 very weird. I thought it was a modification of.subs
in order to take care of the parent.
In the following it does the same as subs:
sage: sage: f(x) = 2*x
sage: sage: f(x).subs(x=3)
6
sage: sage: f(x).evaluate(x=3)
6
But
sage: f(x) = 2*x sage: f.subs(x=3) x |--> 6
ie,
f
remains a function. It is hopefully not changed into a number.
Indeed, this changes (I wasn't aware of this up to now):
sage: sage: f.evaluate(x=3)
6
This is because evaluate
uses
sage: f.operator()
<built-in function mul>
sage: f.operands()
[x, 2]
From this, f
is equal to 2*x
. Sage sees these two as equal as well:
sage: bool(f == 2*x)
True
Replying to @dkrenn:
Replying to @videlec:
By the way, let me repeat another question from #9878. I found the behavior of
evaluate
in your comment:22 very weird. I thought it was a modification of.subs
in order to take care of the parent.From this,
f
is equal to2*x
. Sage sees these two as equal as well:sage: bool(f == 2*x) True
Argh. Definitely a bug to me. Another bug is that the variable defining a function should be transparent. And currently
sage: f(x) = 2*x
sage: g(y) = 2*y
sage: bool(f == g)
False
Vincent
Please Cc: me with any ticket you open regarding Expression.nonzero()
or pynac.
Replying to @videlec:
sage: f(x) = 2*x
From this,
f
is equal to2*x
. Sage sees these two as equal as well:sage: bool(f == 2*x) True
Argh. Definitely a bug to me. Another bug is that the variable defining a function should be transparent. And currently
sage: f(x) = 2*x sage: g(y) = 2*y sage: bool(f == g) False
This is now #18259.
As to the original subs
error, nbruin has explained why there is no general solution, a workaround for polynomials would be
sage: P.<p> = ZZ[[]]
sage: x.power_series(ZZ)
x + O(x^2)
sage: P(_)
p + O(p^2)
I believe a more general way to have all possibilities of both SR
and the series rings is to fix conversions between them, and use a series ring over SR
. This depends on #17659, please review.
Replying to @nbruin:
Anyway,
fast_callable
takes a best effort approach towards compiling a program that tries to perform the evaluation, so that might be your best bet.
I had another instance where I needed a version of .subs
like in this ticket, because there is no coercion from a number field to the symbolic ring.
sage: K.<omega> = NumberField(x^4 + 1)
sage: var('u')
sage: z = u/(u + 1)^2
sage: z.subs(u=omega)
Traceback (most recent call last):
...
TypeError: no canonical coercion from Number Field
in omega with defining polynomial x^16 + 1 to
Symbolic Ring
Using fast_callable
works in this case:
sage: fast_callable(z, vars=[u])(omega)
1/2*omega^3 - 1/2*omega + 1
It works, but the solution is hard to find and the notation a bit cumbersome.
I see several solutions:
fast_callable
and some examples from this ticket to the documentation of subs
.fast_callable
.Opinions?
Replying to @rwst:
I believe a more general way to have all possibilities of both
SR
and the series rings is to fix conversions between them, and use a series ring overSR
. This depends on #17659, please review.
Is it realistic to hope that all conversions will exist? Do they always make sense?
I am now neutral or positive on this ticket. Still,
Is it realistic to hope that all conversions will exist? Do they always make sense?
I suspect many will and do. You can easily find out by reviewing #16203 and #17402.
This ticket proposes a new method
evaluate
which can evaluate symbolic expressions at values coming from a ring which not coerces intoSR
. The result again lives in the ring of the values. This forces the calculation to be done completely in the given ring (and not in the symbolic ring, where sometimes one does not know exactly what's going on).For example:
which is not possible with
subs
CC: @cheuberg @mezzarobba
Component: symbolics
Keywords: sd66
Author: Daniel Krenn
Branch/Commit: u/dkrenn/SR/eval @
276f0f3
Issue created by migration from https://trac.sagemath.org/ticket/18092