Issue with positive variable assumption

97 views
Skip to first unread message

Paul Royik

unread,
Feb 25, 2015, 9:11:03 AM2/25/15
to sy...@googlegroups.com
Hello.

I recently needed to make all variables in expression positive.

I do this like following:

f = log(x)
a=Wild('a')
symbols = f.free_symbols
for symbol in symbols:
   f = f.subs(symbol, dummy)
   f = f.subs(symbol, sympy.Symbol(symbol.name, positive=True))


Now, when I do f.replace(log(a), log(Abs(a))) it shows log(x) as expected, since x is positive
Now, make inverse process: convert positive to any

for symbol in symbols:
   f = f.subs(symbol, dummy)
   f = f.subs(symbol, sympy.Symbol(symbol.name))

But f.replace(log(a), log(Abs(a))) shows log(x) and in debugger x is still positive.

Setting f.subs(symbol, sympy.Symbol(symbol.name, positive=None)) doesn't help.
Helps following:
f.subs(symbol, sympy.Symbol(symbol.name, positive=False))
But I don't want negative variable.
How can I just reset assumptions?

Paul Royik

unread,
Feb 25, 2015, 11:04:04 AM2/25/15
to sy...@googlegroups.com
It appeared, that problem is with cache.
Clearing cache solves the problem.

Now, I want to ask, how cache is working in multithreaded environment?
Do all people share same cache?

Joachim Durchholz

unread,
Feb 25, 2015, 11:38:12 AM2/25/15
to sy...@googlegroups.com
Am 25.02.2015 um 17:04 schrieb Paul Royik:
> It appeared, that problem is with cache.
> Clearing cache solves the problem.
>
> Now, I want to ask, how cache is working in multithreaded environment?
> Do all people share same cache?

Actually I wouldn't expect caching to affect the outcome: at worst, the
same cache entry is computed twice, with the second entry overwriting
the first, identical entry.

Can you reproduce the problem in a single-threaded environment, with
caching enabled?

Paul Royik

unread,
Feb 25, 2015, 12:10:06 PM2/25/15
to sy...@googlegroups.com
I mean in multithreaded environment, do people share same cache (and same symbols)
If person1 created x=Symbol('x') and this is cached, and person2 created x=Symbol('x', positive=True), do they have separate x's or they mixed, so person1 can get positive x if it was overwritten in cache by person 2?



Reproduction.

from sympy import *
x = Symbol('x')
f = log(x)
a=Wild('a')
symbols = f.free_symbols
for symbol in symbols:
   f = f.subs(symbol, sympy.Symbol(symbol.name, positive=True))

print f.replace(log(a),log(Abs(a))) # prints log(x) as expected

# clear_cache() solves the problem

symbols = f.free_symbols
for symbol in symbols:
   f = f.subs(symbol, sympy.Symbol(symbol.name))

print f.replace(log(a),log(Abs(a))) # OOPS! prints log(x) instead of log(|x|)

Joachim Durchholz

unread,
Feb 25, 2015, 3:18:06 PM2/25/15
to sy...@googlegroups.com
Am 25.02.2015 um 18:10 schrieb Paul Royik:
> I mean in multithreaded environment, do people share same cache (and same
> symbols)
> If person1 created x=Symbol('x') and this is cached, and person2 created
> x=Symbol('x', positive=True), do they have separate x's or they mixed, so
> person1 can get positive x if it was overwritten in cache by person 2?

If that's different persons (or, more precisely, shell sessions), they
get different copies of the SymPy process anyway, and there's no
confusion possible at all.

> Reproduction.
>
> from sympy import *
> x = Symbol('x')
> f = log(x)
> a=Wild('a')
> symbols = f.free_symbols
> for symbol in symbols:
> f = f.subs(symbol, sympy.Symbol(symbol.name, positive=True))
>

Nit to pick: This wouldn't work for me, I'd have to do "import sympy" first.

> print f.replace(log(a),log(Abs(a))) # prints log(x) as expected
>
> # clear_cache() solves the problem
>
> symbols = f.free_symbols
> for symbol in symbols:
> f = f.subs(symbol, sympy.Symbol(symbol.name))
>
> print f.replace(log(a),log(Abs(a))) # OOPS! prints log(x) instead of
> log(|x|)

Yes, that's happening for me, too, without any multithreading.

It's okay though. You replaced that x in the original f==log(x) with a
new x constructed as

sympy.Symbol('x', positive=True)

so you now have a new f, with an x that's already under an assumption
that it must be positive.
So I think what happens is that SymPy smartly infers that substituting
an Abs(x) around an already-positive x is a nop and can be simplified out.

Now I'd like to see a transcript of what happens with clear_cache().
If my theory is correct, then clear_cache should not affect the outcome.

Aaron Meurer

unread,
Feb 25, 2015, 3:58:53 PM2/25/15
to sy...@googlegroups.com
Are you using 0.7.6 (note that it introduced a new cache)? And if so,
are you using fastcache?

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/300957bd-6491-4a70-98b1-1fe7edde327b%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

Paul Royik

unread,
Feb 25, 2015, 4:33:51 PM2/25/15
to sy...@googlegroups.com
I'm using 0.7.6, but didn't hear about fastcache.
Can you tell me what is it.

Also, can you tell me will be there cache mixing in multithreaded environment like mod_wsgi? 

Paul Royik

unread,
Feb 25, 2015, 4:35:15 PM2/25/15
to sy...@googlegroups.com
But then, when I substitute positive symbol back to normal:
> symbols = f.free_symbols 
> for symbol in symbols: 
> f = f.subs(symbol, sympy.Symbol(symbol.name)) 

It still shows log(x), isntead of log(|x|)

Aaron Meurer

unread,
Feb 25, 2015, 4:49:11 PM2/25/15
to sy...@googlegroups.com
fastcache is a library you can install that will make the new caching
in 0.7.6 faster, since it is written in C. I don't know how it handles
threads.

Aaron Meurer
> https://groups.google.com/d/msgid/sympy/dfd961fc-ef83-4a54-aadf-9c9c37715670%40googlegroups.com.

Joachim Durchholz

unread,
Feb 25, 2015, 5:19:10 PM2/25/15
to sy...@googlegroups.com
Am 25.02.2015 um 22:35 schrieb Paul Royik:
> But then, when I substitute positive symbol back to normal:
>> symbols = f.free_symbols
>> for symbol in symbols:
>> f = f.subs(symbol, sympy.Symbol(symbol.name))
>
> It still shows log(x), isntead of log(|x|)

Maybe that's a bug.
I'm not sure how to make SymPy print the assumptions for a symbol; that
should help verify what's actually going on.

Chris Smith

unread,
Feb 26, 2015, 1:00:22 AM2/26/15
to sy...@googlegroups.com
To see the assumptions of x use `x.assumptions0` which gives a dictionary of assumptions on x.

Chris Smith

unread,
Feb 26, 2015, 1:07:47 AM2/26/15
to sy...@googlegroups.com
print f.replace(log(a),log(Abs(a))) # OOPS! prints log(x) instead of log(|x|)


It prints `log(Abs(x))` for me in the current git version of sympy. BTW, your earlier examples had symbol being replaced with dummy (though that wasn't defined); if you are actually doing that then the 2nd substitution will no longer find symbol and that substitution will have no effect on f.
Reply all
Reply to author
Forward
0 new messages