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

Add simplify_real method to symbolic expressions #14630

Closed
orlitzky opened this issue May 23, 2013 · 29 comments
Closed

Add simplify_real method to symbolic expressions #14630

orlitzky opened this issue May 23, 2013 · 29 comments

Comments

@orlitzky
Copy link
Contributor

Symbolic expressions in sage are by default assumed complex. There is a maxima variable, called the "simplification domain," which affects whether or not it simplifies sqrt(x^2) to abs(x). Since our expressions are complex, we set the simplification domain to complex, but provide no easy way to change it.

By adding a simplify_real() method to Expression, we give the user a way to perform the aforementioned simplification by declaring his expression real.

This might provide a quick fix for #14305. See also:

https://groups.google.com/forum/?fromgroups=#!topic/sage-support/jhCJujRtNA4/discussion

Depends on #11912

CC: @egourgoulhon

Component: symbolics

Author: Michael Orlitzky

Branch/Commit: 649e3b3

Reviewer: Karl-Dieter Crisman, Ralf Stephan

Issue created by migration from https://trac.sagemath.org/ticket/14630

@orlitzky
Copy link
Contributor Author

Author: Michael Orlitzky

@orlitzky
Copy link
Contributor Author

comment:1

MathJAX is throwing a "Math Processing Error" -- I'm not sure whether it's busted or I screwed up but the docs definitely need a review.

@kcrisman
Copy link
Member

comment:2

You need to do \left|x\\right|.


I'm not sure about all the stuff in the doc and the code, but I think that some of the doc is doing the code and vice versa? For instance,

# Forget all assumptions

but you don't do that in the code. And the corresponding part in the doc seems to imply that in order to use simplify_real you have to assume variables are real... I may be misunderstanding something here. I think this could be a good way to solve the issue at hand.

My question is how this will interact with the other simplifications. I seem to recall that in some of the more controversial (e.g. radcan-related) simplifications we do, part of the issue is whether the variable is real... that recollection may be outdated. Anyway, I could imagine that simplify_foo simplified differently whether one was real or complex, though I hesitate to add simplify_foo_real for all foo!

@orlitzky
Copy link
Contributor Author

Attachment: sage-trac_14630.patch.gz

Add simplify_real() method to Expression

@orlitzky
Copy link
Contributor Author

comment:3

Replying to @kcrisman:

You need to do \left|x\\right|.

Fixed in the new patch, but my MathJAX still doesn't work, so please give it a look.

I'm not sure about all the stuff in the doc and the code, but I think that some of the doc is doing the code and vice versa? For instance,

# Forget all assumptions

but you don't do that in the code.

Whoops, I forgot to call forget(); the comment was correct. I fixed it and added a doctest to ensure that no new assumptions remain after the call.

And the corresponding part in the doc seems to imply that in order to use simplify_real you have to assume variables are real... I may be misunderstanding something here. I think this could be a good way to solve the issue at hand.

I didn't mean that the user has to assume() anything, only that we have to assume things are real in the traditional sense. You can call simplify_real() on an expression containing complex variables, but the answer might not make sense.

My question is how this will interact with the other simplifications. I seem to recall that in some of the more controversial (e.g. radcan-related) simplifications we do, part of the issue is whether the variable is real... that recollection may be outdated. Anyway, I could imagine that simplify_foo simplified differently whether one was real or complex, though I hesitate to add simplify_foo_real for all foo!

Expressions should be complex everywhere. I believe there are one or two functions which treat them as real, but they're documented to do that, so it's fine. Radcan via simplify_radical() will still produce crazy answers that are invalid for complex numbers, but there isn't much that can be done about that now except revoke the name "simplify" from "simplify_radical."

Not many expressions are actually affected by the domain and 'real' assumptions. We can get most of the benefit of simplify_foo_real() by doing simplify_foo().simplify_real(). Simplifications can be combined/repeated to produce better answers, and we already have a situation where calling e.g. simplify_full() twice might give you a better answer than calling it once. So you're kind of on your own regarding how many simplifications to try and in what order.

@sagetrac-sluther
Copy link
Mannequin

sagetrac-sluther mannequin commented May 29, 2013

comment:4

What about adding a parameter to all the simplify_* functions instead of adding more functions?
Like "def simplify(real_domain=False):..."

@orlitzky
Copy link
Contributor Author

comment:5

Replying to @sagetrac-sluther:

What about adding a parameter to all the simplify_* functions instead of adding more functions?
Like "def simplify(real_domain=False):..."

If instead of simplify_rational, simplify_log, etc. we had simplify(rational=True, log=True,...) that's what I would have done. As it is, if you want to do both rational and log simplifications, you just have to do expr.simplify_rational().simplify_log().

Particularly with simplify_real(), it only does one specific thing that isn't done by other methods so you can be somewhat confident that simplify_foo().simplify_real() will give you both simplifications. In other words I don't think you'd get a nicer expression back by setting the simplification domain to real before simplify_rational() than you would by calling the two in succession.

@sagetrac-sluther
Copy link
Mannequin

sagetrac-sluther mannequin commented May 30, 2013

comment:6

Well I'd say this feels like mixing different concepts. The log, radical, etc. are about the form of the expression that's going to be transformed, whereas the domain is about the values the variables in the expression may take.

You're right that sometimes the application of simplifications in different order yields different results. But I find this rather annoying (not that I know how to fix it). By adding even more functions to the mix we make this situation even worse.

I usually use simplify_full(). So as I understand it I'd always need to call simplify_full() and simplify_real() in some order to benefit from the knowledge about the domain.

And then I'm still left wondering if there are simplifications in simplify_full() hat could benefit from this knowledge too, but didn't get it because there's only simplify_real() and not simplify_full_real().

Is there a list of which simplify_* function could use this domain parameter?

@burcin
Copy link

burcin commented May 30, 2013

comment:7

Instead of adding a new function simplify_real() or a domain parameter to the existing functions, can we use a context manager instead?

Example use would be:

sage: t = sqrt(x^2)
sage: t.simplify()
sqrt(x^2)
sage: with maxima_domain(RR):
....:    u = t.simplify()
....:
sage: u
abs(x)
sage: t.simplify()
sqrt(x^2)

@orlitzky
Copy link
Contributor Author

orlitzky commented Jun 4, 2013

comment:8

Replying to @sagetrac-sluther:

All of the simplify_foo() functions except simplify_radical() could benefit from it. There are only a small number of subexpressions that can be simplified by simplify_real(), and I think only simplify_radical() will "simplify" out those subexpressions making simplify_real() redundant.

The simplify_radical() method will change the expression sqrt(x^2) to either x or -x "consistently but arbitrarily.". This is not really a simplification, since it gives the wrong answer in the default case, so beware using simplify_full(). All of the rest could be combined with simplify_real() in some way.

@orlitzky
Copy link
Contributor Author

orlitzky commented Jun 4, 2013

comment:9

Replying to @burcin:

Instead of adding a new function simplify_real() or a domain parameter to the existing functions, can we use a context manager instead?

Example use would be:

sage: t = sqrt(x^2)
sage: t.simplify()
sqrt(x^2)
sage: with maxima_domain(RR):
....:    u = t.simplify()
....:
sage: u
abs(x)
sage: t.simplify()
sqrt(x^2)

This is way better than what we currently have to do:

sage: maxima_lib.eval('domain: real;')
'real'
sage: (sqrt(x^2)).simplify()
abs(x)
sage: maxima_lib.eval('domain: complex;')
'complex'

but still does two things undesirably:

  1. The user has to know about the maxima_domain() call, and there's no easy way to find out about it. This is in contrast with x.<tab> "what can I do with this expression?"

  2. It ties the simplification to the maxima backend. If we ever want to use sympy or some other backend, we're going to have a mess.

@jdemeyer jdemeyer modified the milestones: sage-5.11, sage-5.12 Aug 13, 2013
@nbruin
Copy link
Contributor

nbruin commented Aug 23, 2013

comment:11

Replying to @burcin:

Instead of adding a new function simplify_real() or a domain parameter to the existing functions, can we use a context manager instead?

You'd need to document that the user of the context manager should make sure to not relinquish control inside the context manager. Thanks to "yield" in python, lexical enclosure doesn't necessarily mean runtime enclosure.

@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.1, sage-6.2 Jan 30, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.2, sage-6.3 May 6, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.3, sage-6.4 Aug 10, 2014
@rwst
Copy link

rwst commented Nov 2, 2014

comment:15

I think the form/domain-simplify design issue has not been resolved and should be discussed/decided first: the/an author may benefit from presenting a solution to sage-devel, and if the crowd has no opinion then it should be implemented. Thus, I'm setting to needs_info.

@orlitzky
Copy link
Contributor Author

orlitzky commented Nov 5, 2014

Commit: 24cc554

@orlitzky
Copy link
Contributor Author

orlitzky commented Nov 5, 2014

New commits:

24cc554Trac #14630: Add Expression.simplify_real() method.

@orlitzky
Copy link
Contributor Author

orlitzky commented Nov 5, 2014

Branch: u/mjo/ticket/14630

@kcrisman
Copy link
Member

comment:18

This seems fine, given that it is extremely unlikely a context manager will appear and that having many options seems undesirable. However, if someone gets a sage-devel discussion on this going I'm not going to stop them.

sage: A = e^(sqrt(x^2))
sage: A
e^(sqrt(x^2))
sage: A.simplify_real()
e^abs(x)

I was pleased this worked, wasn't sure how much it would do. Maybe the following would be a useful test to show what it does and doesn't do.

sage: var('y z')
(y, z)
sage: A = e^(sqrt(x^2)+sqrt(y^2)+sqrt(i*z^2))
sage: A.simplify_real()
e^((-1)^(1/4)*abs(z) + abs(x) + abs(y))

Here's another one that, again, pleasantly works as one would think.

sage: C = (x^2+y^2).imag()
sage: C
2*imag_part(x)*real_part(x) + 2*imag_part(y)*real_part(y)
sage: C.simplify_real()
0

Now if only we had to use this for the following simplification!

sage: B = conjugate(z)
sage: B.simplify_real()
z
sage: B.simplify()  # wa-wa "you lose" noise - #6862
z

@kcrisman
Copy link
Member

comment:19

Also note this probably conflicts slightly with #11912.

@orlitzky
Copy link
Contributor Author

comment:20

Just making a note to myself here to update all of the "see also" references in the other simplify_* methods. We should mention simplify_real(), simplify_rectform(), and any other new similar methods.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Nov 22, 2014

Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:

f34ddfcTrac #11912: Rename and deprecate Expression.simplify_radical().
2d50b88Trac #11912, Trac #3520: Add numerical integral example.
e5ab339Trac #11912 (review): Remove superfluous documentation paragraph.
5d24f4cTrac #11912 (review): Add canonicalize_radical() to the "see also" list for Expression.simplify().
612f8edTrac #14630: Add Expression.simplify_real() method.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Nov 22, 2014

Changed commit from 24cc554 to 612f8ed

@orlitzky
Copy link
Contributor Author

comment:22

I just force-pushed a branch that's rebased on top of #11912 because of a conflict. That one has a positive review, so I guess when it's merged I could rebase this on top of the develop branch? Not sure what's easiest for the release manager.

@orlitzky
Copy link
Contributor Author

Dependencies: #11912

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Nov 22, 2014

Changed commit from 612f8ed to 649e3b3

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Nov 22, 2014

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

649e3b3Trac #14630: Add Expression.simplify_hypergeometric() to the "see also" list for Expression.simplify().

@orlitzky
Copy link
Contributor Author

comment:24

And per my note, I've included another left-out function in the simplify() "see also" list.

@rwst
Copy link

rwst commented Dec 12, 2014

comment:25

I think it is fine now and certainly should be included, test pass in expression.pyx.

@rwst
Copy link

rwst commented Dec 12, 2014

Reviewer: Karl-Dieter Crisman, Ralf Stephan

@vbraun
Copy link
Member

vbraun commented Dec 15, 2014

Changed branch from u/mjo/ticket/14630 to 649e3b3

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

7 participants