Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

evaluating symbolic expressions (without conversion to SR, i.e., staying in ring of values) #18092

Open
dkrenn opened this issue Mar 31, 2015 · 36 comments

Comments

@dkrenn
Copy link
Contributor

dkrenn commented Mar 31, 2015

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: P.<p> = ZZ[[]]
sage: E = x.evaluate(x=p)
sage: E, E.parent()
(p, Power Series Ring in p over Integer Ring)

which is not possible with subs

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)

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

@dkrenn dkrenn added this to the sage-6.6 milestone Mar 31, 2015
@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

Branch: u/dkrenn/SR/eval

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

New commits:

9f8d483create method eval
68b65carename eval to evaluate
24348f7docstring: output clearified
c3d0670rename ring to convert_to
6449f20implement automatic detection when convert_to=None
cd29dcaexamples rewritten
bc2bb47add seealso-block
9419e1ffix typo
9e83cb2docstring for helper function _evaluate_
c3696a8fix links in doc

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

Commit: c3696a8

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

Author: Daniel Krenn

@rwst
Copy link

rwst commented Mar 31, 2015

comment:4
+        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".

@dkrenn

This comment has been minimized.

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:5

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)

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

Changed keywords from none to sd66

@rwst
Copy link

rwst commented Mar 31, 2015

comment:7

I thought everything coerces to SR? Maybe this is just a coercion bug?

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:8

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.

@videlec
Copy link
Contributor

videlec commented Mar 31, 2015

comment:10

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

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 31, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

ba59f5dadditional example: inserting power series
7e0be7fcorrect bug when evaluating user-defined functions

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 31, 2015

Changed commit from c3696a8 to 7e0be7f

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:12

added a doctest and corrected a small bug

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:13

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.

@nbruin
Copy link
Contributor

nbruin commented Mar 31, 2015

comment:14

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).

@dkrenn

This comment has been minimized.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 31, 2015

Changed commit from 7e0be7f to 276f0f3

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 31, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

276f0f3rewrite documentation (examples) after discussion on trac

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:17

rewritten documentation of function

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:18

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.

@nbruin
Copy link
Contributor

nbruin commented Mar 31, 2015

comment:19

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.

@dkrenn
Copy link
Contributor Author

dkrenn commented Mar 31, 2015

comment:20

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

@videlec
Copy link
Contributor

videlec commented Apr 20, 2015

comment:21

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

@dkrenn
Copy link
Contributor Author

dkrenn commented Apr 20, 2015

comment:22

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

@videlec
Copy link
Contributor

videlec commented Apr 20, 2015

comment:23

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?

@dkrenn
Copy link
Contributor Author

dkrenn commented Apr 20, 2015

comment:24

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.

@videlec
Copy link
Contributor

videlec commented Apr 20, 2015

comment:25

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.

@dkrenn
Copy link
Contributor Author

dkrenn commented Apr 20, 2015

comment:26

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

@videlec
Copy link
Contributor

videlec commented Apr 20, 2015

comment:27

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 to 2*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

@rwst
Copy link

rwst commented Apr 20, 2015

comment:28

Please Cc: me with any ticket you open regarding Expression.nonzero() or pynac.

@dkrenn
Copy link
Contributor Author

dkrenn commented Apr 20, 2015

comment:29

Replying to @videlec:

sage: f(x) = 2*x

From this, f is equal to 2*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.

@rwst
Copy link

rwst commented Jun 20, 2015

comment:30

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.

@cheuberg
Copy link
Contributor

comment:31

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:

  1. adding a link to fast_callable and some examples from this ticket to the documentation of subs.
  2. indeed create a method as proposed here which acts as a wrapper for fast_callable.

Opinions?

@cheuberg
Copy link
Contributor

comment:32

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 over SR. This depends on #17659, please review.

Is it realistic to hope that all conversions will exist? Do they always make sense?

@rwst
Copy link

rwst commented Feb 11, 2016

comment:33

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants