Arbitrary constraints?

128 views
Skip to first unread message

Andrew Spielberg

unread,
Nov 10, 2014, 4:58:01 PM11/10/14
to sy...@googlegroups.com
Hi all,

When creating variables, I know you can provide certain constraints on the domain of that variable.  For instance, one could say that a certain variable, x, is positive, real, rational, etc.  These constraints affect the way the simplify function behaves.

I am wondering, without creating auxiliary variables, can add other constraints?  For example, if I have a variable x that always must be greater than another variable y, can I specify:

x > y

in some way, and have the simplifier intelligently know how to handle it?  I know I could change my representation to be a = (x - y) and do everything in terms of my variable a, and set a positive, but this is less than ideal and will not work in a lot of my cases.

If there is no way to set these assumptions, is there some other recommended way to do intelligent simplification in some way?

-Andy S.

Aaron Meurer

unread,
Nov 10, 2014, 5:06:48 PM11/10/14
to sy...@googlegroups.com
There is a framework to do this with refine, like refine(sqrt((x - y)**2), Q.positive(x - y)), but not much is implemented yet, so the simplifications possible are quite limited (in fact, there's not much more than the one that I just showed that is implemented).

Aaron Meurer

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at http://groups.google.com/group/sympy.
To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/80f87d8d-1504-40f6-b6d4-efb08cdcc824%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andrew Spielberg

unread,
Nov 10, 2014, 6:42:31 PM11/10/14
to sy...@googlegroups.com
Hi Aaron,

Thanks for the speedy reply.  I'm not sure I fully understand what this example does, or how.  Could you perhaps elaborate?  What is Q?  What is the difference between refine and simplify?

I should note that the entirety of my constraints will be linear, so if the current functionality can do that, that's enough.

-Andy S.

Aaron Meurer

unread,
Nov 10, 2014, 7:13:36 PM11/10/14
to sy...@googlegroups.com
Q is just a namespace for the assumptions, like Q.positive or Q.real.

refine() simplifies things based on assumptions. This example returns x - y, because sqrt((x - y)**2) is equal to x - y if x - y is positive (but not in general).

What kinds of simplifications are you expecting to get out of your constraints?

Aaron Meurer


Andrew Spielberg

unread,
Nov 10, 2014, 7:30:25 PM11/10/14
to sy...@googlegroups.com
Hi Aaron,

Thanks for the reply.  One of the main things I'm hoping to do is make absolute values go away.  I frequently in my code am getting things like (x - y) / Abs(x - y).  I know x - y is > 0, so this is just 1.

I should note that when I run your code, I get the following:

In [1]: x, y = symbols('x y')

In [2]: refine(sqrt((x - y)**2))
Out[2]: 
          __________
       ╱        2 
╲╱  (x - y)  

In [3]: Q.positive(x - y)
Out[3]: Q.positive(x - y)

In [4]: refine(sqrt((x - y)**2))
Out[4]: 
          __________
       ╱        2 
╲╱  (x - y)  


James Crist

unread,
Nov 10, 2014, 11:59:36 PM11/10/14
to sy...@googlegroups.com
You need to include the assumptions in the call to refine:


>>> refine(sqrt((x - y)**2), Q.positive(x - y))
x - y

If I remember correctly, the `assuming` context manager also works for this, but I can't be certain.

Mateusz Paprocki

unread,
Nov 11, 2014, 3:16:46 AM11/11/14
to sympy
Hi,

On 11 November 2014 01:13, Aaron Meurer <asme...@gmail.com> wrote:
> Q is just a namespace for the assumptions, like Q.positive or Q.real.
>
> refine() simplifies things based on assumptions.

I think we shouldn't use "refine()" and "simplifies" together as this
only can increase confusion. Simplification implies that there is an
optimisation procedure applied. refine() just transforms an expression
given some facts about it.

Mateusz
> https://groups.google.com/d/msgid/sympy/CAKgW%3D6%2Bn0vvxOd3H%2B-4rRdQOh4Std7uCfjzFudvbs9gQzOM5yQ%40mail.gmail.com.

Andrew Spielberg

unread,
Nov 11, 2014, 6:09:40 PM11/11/14
to sy...@googlegroups.com
Thanks guys.  This seems to be mostly working so far.

Any idea why this wouldn't be, though?

In [1]: assumptions
Out[1]: And(Q.positive(-beamwidth), Q.positive(-length), Q.positive(0.9*beamwidth - length))

In [2]: exp
Out[2]: 0.866025403784439*beamwidth*(0.866025403784438*beamwidth - length)/Abs(0.866025403784438*beamwidth - length)

In [3]: math.refine(exp, assumptions)
Out[3]: 0.866025403784439*beamwidth*(0.866025403784438*beamwidth - length)/Abs(0.866025403784438*beamwidth - length)

(math is my sympy module)

A little confused here as to why the fraction wouldn't simplify out.  (0.866025403784438*beamwidth - length)/Abs(0.866025403784438*beamwidth - length) should be 1.

-Andy S.


Andrew Spielberg

unread,
Nov 12, 2014, 10:44:49 PM11/12/14
to sy...@googlegroups.com
refine_abs isn't doing the trick here either.  Am I using this module incorrectly?

Aaron Meurer

unread,
Nov 14, 2014, 6:02:50 PM11/14/14
to sy...@googlegroups.com
As I said, it's *very* proof of concept. Many advanced things don't work. 

In this case, I think the issue is with the assumptions in general. They can't deduce from the facts And(Q.positive(-beamwidth), Q.positive(-length), Q.positive(0.9*beamwidth - length))
 that 0.866025403784438*beamwidth - length is positive.  I'm not even sure what algorithms need to be implemented to make this work.

Why are your beamwidth and length variables negative? From the variable names, they sound like they should be positive?

Aaron Meurer

Aaron Meurer

unread,
Nov 14, 2014, 6:03:39 PM11/14/14
to sy...@googlegroups.com
Note that if you want to kill all abs in your expression, there's an easier way. expr.replace(Abs, Id)

Aaron Meurer

Andrew Spielberg

unread,
Jan 2, 2015, 2:13:10 PM1/2/15
to sy...@googlegroups.com
Hi guys,

Thanks for your help so far.  I am revisiting this after ignoring this issue for a while.

I'm still trying to come up with a good way to use this.  I've noticed the following:

Say:
a = Symbol('a')
b = Symbol('b')
assumptions = Q.positive(a - b)
expr = 1/Abs(a - b)

If I try:

refine(expr, assumptions)

it returns:

1/(a - b)

as desired.  But, if I try:

expr = Abs(b - a)/Abs(a - b)

it returns:

│-b + a│
────────
 a - b

I can add an assumption that:

assumptions = assumptions &  Q.negative(b - a)  

And then refining returns 1.  But then I can do something like:

expr = Abs(0.5*b - 0.5*a)/Abs(a - b)

And it fails again.  Is the pattern matcher this weak?  Is there any way to get what I want that doesn't require refine, or is there a better way to use refine to get what I want?  My assumptions are simple - they will all be linear equations of variables.

-Andy S.

Aaron Meurer

unread,
Jan 2, 2015, 10:06:34 PM1/2/15
to sy...@googlegroups.com
On Fri, Jan 2, 2015 at 12:13 PM, Andrew Spielberg <aespi...@gmail.com> wrote:
Hi guys,

Thanks for your help so far.  I am revisiting this after ignoring this issue for a while.

I'm still trying to come up with a good way to use this.  I've noticed the following:

Say:
a = Symbol('a')
b = Symbol('b')
assumptions = Q.positive(a - b)
expr = 1/Abs(a - b)

If I try:

refine(expr, assumptions)

it returns:

1/(a - b)

as desired.  But, if I try:

expr = Abs(b - a)/Abs(a - b)

it returns:

│-b + a│
────────
 a - b

I can add an assumption that:

assumptions = assumptions &  Q.negative(b - a)  

And then refining returns 1.  But then I can do something like:

expr = Abs(0.5*b - 0.5*a)/Abs(a - b)

And it fails again.  Is the pattern matcher this weak?  Is there any way to get what I want that doesn't require refine, or is there a better way to use refine to get what I want?  My assumptions are simple - they will all be linear equations of variables.

I don't think refine is even using a pattern matcher. It really isn't very powerful yet, as I noted earlier in this thread.

replace() has a better pattern matching abilities if that's all you're going for.

Aaron Meurer

Andrew Spielberg

unread,
Jan 2, 2015, 11:47:22 PM1/2/15
to sy...@googlegroups.com
This may be a dumb question, but can you please explain what is going on here...?  exp was made using simpify, expr was created from scratch.  Replace operates on them differently.

In [48]: exp
Out[48]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [49]: expr
Out[49]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [50]: exp.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[50]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [51]: expr.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[51]: 0

In [52]: exp == expr
Out[52]: False

-Andy S.

Andrew Spielberg

unread,
Jan 2, 2015, 11:50:01 PM1/2/15
to sy...@googlegroups.com
Sorry for the double post.  It seems replace is very weak as well, not being able to detect multiples :-/

In [60]: expr.replace(math.Abs(guardlength - 0.5*length), guardlength - 0.5*length)
Out[60]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [61]: expr.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[61]: 0

Aaron Meurer

unread,
Jan 3, 2015, 2:29:09 PM1/3/15
to sy...@googlegroups.com
On Fri, Jan 2, 2015 at 9:50 PM, Andrew Spielberg <aespi...@gmail.com> wrote:
Sorry for the double post.  It seems replace is very weak as well, not being able to detect multiples :-/

In [60]: expr.replace(math.Abs(guardlength - 0.5*length), guardlength - 0.5*length)
Out[60]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [61]: expr.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[61]: 0

You can use Wild symbols to match against coefficients. 

But in your case, if all you want to do is kill all the Abs in the expression, use expr.replace(Abs, Id).

Aaron Meurer
 


On Fri, Jan 2, 2015 at 11:47 PM, Andrew Spielberg <aespi...@gmail.com> wrote:
This may be a dumb question, but can you please explain what is going on here...?  exp was made using simpify, expr was created from scratch.  Replace operates on them differently.

In [48]: exp
Out[48]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [49]: expr
Out[49]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [50]: exp.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[50]: width*(-2*guardlength + length + Abs(2*guardlength - length))/Abs(2*guardlength - length)

In [51]: expr.replace(math.Abs(2*guardlength - length), 2*guardlength - length)
Out[51]: 0

In [52]: exp == expr
Out[52]: False

I can't say. According to this, exp and expr (without replace) are different. I can't say why, though, without seeing how you made them, as the string forms are identical. Are you using assumptions on your symbols?

Aaron Meurer
 

Andrew Spielberg

unread,
Jan 3, 2015, 6:50:50 PM1/3/15
to sy...@googlegroups.com
Hi Aaron,

w.r.t. killing the Abs, that's not sufficient, because sometimes I need the Abs( ) to turn into -Id( ).

One of those, exp, was created via simpify.  The other, expr, was created from "the ground up" using Symbols.  No assumptions are being made.

-Andy S.

Andrew Spielberg

unread,
Jan 3, 2015, 6:51:22 PM1/3/15
to sy...@googlegroups.com
Sorry, one more thing - I can't get the wildcards to work.  Can you provide an example?

-Andy S.

Aaron Meurer

unread,
Jan 4, 2015, 2:27:56 PM1/4/15
to sy...@googlegroups.com
Something like expr.replace(Abs(a*guardlength - length), a*guardlength - length), where a = Wild('a'). If you are getting strange results you can try Wild('a', exclude=[guardlength, length]).

Aaron Meurer

Reply all
Reply to author
Forward
0 new messages