sqrt(x) * sqrt(y) versus sqrt(xy)

404 views
Skip to first unread message

Vincent Delecroix

unread,
May 17, 2016, 4:27:40 PM5/17/16
to sage-s...@googlegroups.com
Hello,

I would expect the following to return True but it does not

x = SR.var('x')
y = SR.var('y')
assume(x,'real')
assume(x > 0)
assume(y,'real')
assume(y > 0)
bool(sqrt(x) * sqrt(y) == sqrt(x*y))

Is there a way to let Sage knows about sqrt(xy) = sqrt(x) sqrt(y) in the
case x and y real positive?

Vincent

Nils Bruin

unread,
May 17, 2016, 5:26:12 PM5/17/16
to sage-support

On Tuesday, May 17, 2016 at 1:27:40 PM UTC-7, vdelecroix wrote:
Is there a way to let Sage knows about sqrt(xy) = sqrt(x) sqrt(y) in the
case x and y real positive?

Vincent

Perhaps this is cheating:
 
sage: maxima_calculus("domain:real")
real
sage: var("x,y");
sage: bool(sqrt(x)*sqrt(y)==sqrt(x*y))
False
sage: assume(x>0,y>0)
sage: bool(sqrt(x)*sqrt(y)==sqrt(x*y))
True

With domain real and the assumptions in place, it's really just roundtripping to maxima that already does this for you:

sage: sqrt(x*y)._maxima_()._sage_()
sqrt(x)*sqrt(y)

so I guess you could see how in maxima we can activate this simplification rule (which depends on x,y>0!) to be active when domain:complex is set.

Vincent Delecroix

unread,
May 17, 2016, 5:36:45 PM5/17/16
to sage-s...@googlegroups.com
Nice! Thanks Nils. What about introducing the following scheme in all
relevant functions

{{{
if all variables are real:
turn maxima in real domain

do what has to be done

if all variables are real:
turn back maxima in complex domain
}}}

We can even wrap this nicely as follows

{{{
with forwarding_assumptions(expression):
do what has to be done with expression
}}}

Nils Bruin

unread,
May 17, 2016, 6:34:33 PM5/17/16
to sage-support
On Tuesday, May 17, 2016 at 2:36:45 PM UTC-7, vdelecroix wrote:
Nice! Thanks Nils. What about introducing the following scheme in all
relevant functions

{{{
if all variables are real:
    turn maxima in real domain

do what has to be done

if all variables are real:
    turn back maxima in complex domain
}}}

Hm, might be risky:


sage: maxima_calculus("domain:real")
real
sage: assume(x>0)
sage: sqrt(x^2*sqrt(-x))._maxima_()._sage_()
(-1)^(1/4)*x^(5/4)

I'm pretty sure you can force this to make an unexpected branch choice. Just having your variables real doesn't mean you're doing real analysis.

Eric Gourgoulhon

unread,
May 24, 2016, 5:39:36 AM5/24/16
to sage-support
Hi Vincent,

Note that with your assumptions, invoking simplify_real() does the job:

sage: bool((sqrt(x) * sqrt(y) == sqrt(x*y)).simplify_real())
True

This is because

sage: sqrt(x*y).simplify_real()
sqrt(x)*sqrt(y)

Best regards,

Eric.


Vincent Delecroix

unread,
May 24, 2016, 8:21:23 AM5/24/16
to sage-s...@googlegroups.com
Hi Eric,

Thanks for sharing the `simplify_real`!

However, I am not happy with this solution either. The method
simplify_real never checks the domain of functions. This is a complete
nonsense.

sage: (sqrt(-x) * sqrt(-x)).simplify_real()
-x

I would like simplify to do the following

- if there is a product of `sqrt` in the tree
- determine whether the argument inside are `>= 0`
- if this is true then replace `sqrt(x_1) sqrt(x_2) ... sqrt(x_n)` by
`sqrt(x_1 x_2 ... x_n)`

For example, I would the following to be automatic

sage: x = SR.var('x')
sage: y = SR.var('y')
sage: assume(x, 'real')
sage: assumE(y, 'real')
sage: p = sqrt(x^2 + 1) * sqrt(y^2 + 1)
sage: p.simplify() # or maybe expand?
sqrt(x^2*y^2 + x^2 + y^2 + 1)

An equality involving only sum/prod/rational powers can be decided (at
least if the domain of a variable is determined by linear conditions).

Best,
Vincent

Eric Gourgoulhon

unread,
May 24, 2016, 9:13:33 AM5/24/16
to sage-support


Le mardi 24 mai 2016 14:21:23 UTC+2, vdelecroix a écrit :
Hi Eric,

Thanks for sharing the `simplify_real`!

However, I am not happy with this solution either. The method
simplify_real never checks the domain of functions. This is a complete
nonsense.

sage: (sqrt(-x) * sqrt(-x)).simplify_real()
-x


Why is this a complete nonsense? If the user is manipulating sqrt(-x) while working in the real domain, this means that x <= 0. Then it is correct to have  sqrt(-x) * sqrt(-x) = - x
Here are other examples where simplify_real behaves well:


sage: x = SR.var('x')
sage: y = SR.var('y')
sage: sqrt(x*y).simplify_real()
sqrt(x*y)
sage: assume(x<0)
sage: assume(y<0)
sage: sqrt(x*y).simplify_real()
sqrt(-x)*sqrt(-y)
sage: forget()
sage: assume(x>0)
sage: assume(y>0)
sage: sqrt(x*y).simplify_real()
sqrt(x)*sqrt(y)

All the above outputs seem correct to me.
 
I would like simplify to do the following

- if there is a product of `sqrt` in the tree
- determine whether the argument inside are `>= 0`
- if this is true then replace `sqrt(x_1) sqrt(x_2) ... sqrt(x_n)` by
`sqrt(x_1 x_2 ... x_n)`

This is the opposite of simplify_real(), which splits sqrt(x_1 x_2 ... x_n) into sqrt(x_1) sqrt(x_2) ... sqrt(x_n).

For example, I would the following to be automatic

sage: x = SR.var('x')
sage: y = SR.var('y')
sage: assume(x, 'real')
sage: assumE(y, 'real')
sage: p = sqrt(x^2 + 1) * sqrt(y^2 + 1)
sage: p.simplify()   # or maybe expand?

Yes, rather expand.
 
sqrt(x^2*y^2 + x^2 + y^2 + 1)

An equality involving only sum/prod/rational powers can be decided (at
least if the domain of a variable is determined by linear conditions).

Yes.

Best regards,

Eric.

Vincent Delecroix

unread,
May 24, 2016, 9:55:40 AM5/24/16
to sage-s...@googlegroups.com
Well

sage: (sqrt(-x) * sqrt(x) * sqrt(-x) * sqrt(x)).simplify_real()
-x^2

Vincent

Michael Orlitzky

unread,
May 24, 2016, 10:03:55 AM5/24/16
to sage-s...@googlegroups.com
On 05/24/2016 09:55 AM, Vincent Delecroix wrote:
> Well
>
> sage: (sqrt(-x) * sqrt(x) * sqrt(-x) * sqrt(x)).simplify_real()
> -x^2
>

If you're sure that every expression involved is real, that's still the
correct answer, because x == 0. If sqrt(x) or sqrt(-x) might not be
real, you're going to get nonsense calling simplify_real() on them.



Eric Gourgoulhon

unread,
May 24, 2016, 10:13:15 AM5/24/16
to sage-support


Le mardi 24 mai 2016 16:03:55 UTC+2, Michael Orlitzky a écrit :

If you're sure that every expression involved is real, that's still the
correct answer, because x == 0. If sqrt(x) or sqrt(-x) might not be
real, you're going to get nonsense calling simplify_real() on them.


Yes, I think this is the very spirit of this simplify_real() function: it gives standard results for real expressions, with sqrt considered as a bijective map R+ --> R+, whose inverse is R+ --> R+, x |--> x^2.
Another example of good behavior of simplify_real():

sage: assume(x<0)
sage: sqrt(x^2).simplify_real()
-x

Best regards,

Eric.

Vincent Delecroix

unread,
May 24, 2016, 10:20:54 AM5/24/16
to sage-s...@googlegroups.com
The above is coherent. But I would prefer if simplify_real would raise
an error if some argument of sqrt has a chance to be < 0.

Michael Orlitzky

unread,
May 24, 2016, 9:05:43 PM5/24/16
to sage-s...@googlegroups.com
On 05/24/2016 10:20 AM, Vincent Delecroix wrote:
>
> The above is coherent. But I would prefer if simplify_real would raise
> an error if some argument of sqrt has a chance to be < 0.
>

What about sqrt(2*x^16 + 10*x^11 - 9*x^10 + x^7 + x^4 - 17*x^2 - x)?

Vincent Delecroix

unread,
May 24, 2016, 10:14:26 PM5/24/16
to sage-s...@googlegroups.com
What is the problem with this expression? It is very easy to decide the
sign of any polynomial expression in one variable on any given interval.
More subtle would be something like

sqrt(cos(x^3*y + x^2*y - 2*x + y^2) + sin(x^5 - x*y + 1))

But in that case I would be happy with Sage printing some warnings.

Vincent

Michael Orlitzky

unread,
May 25, 2016, 11:09:43 AM5/25/16
to sage-s...@googlegroups.com
On 05/24/2016 10:14 PM, Vincent Delecroix wrote:
>>
>> What about sqrt(2*x^16 + 10*x^11 - 9*x^10 + x^7 + x^4 - 17*x^2 - x)?
>>
>
> What is the problem with this expression? It is very easy to decide the
> sign of any polynomial expression in one variable on any given interval.

But how much computation are you willing to do to determine that an
expression is nonnegative on the real line? I can think of worse things:

sage: x = SR.var('x', domain='real')
sage: assume(x > 0)
sage: f = sqrt(x)

It should be safe to call simplify_real() on f, right?

sage: f(x=I)
sqrt(I)

To use simplify_real(), you need to be sure that all possible
subexpressions of your expression will remain real at all times
regardless of the values that you substitute for any variables. I don't
think anyone but the user can make that claim. Users probably shouldn't
do it either, but there's no other way to get simplifications like
log(8) + log(2) -> log(16).

Reply all
Reply to author
Forward
0 new messages