Sympy comparing expressions after evaluation - sympy

I want a function that will compare, whether evaluated and non-evaluated expressions are different. So this:
import sympy.parsing.sympy_parser as spp
string = "x+x"
exp1 = spp.parse_expr(string, evaluate = False)
exp2 = spp.parse_expr(string)
print exp1
print exp2
print exp1 == exp2
Should output
x + x
2*x
False
And the same code with string = "x**2+1" should output
x**2+1
x**2+1
True # But it outputs False here too.
Yes, I have read the FAQ, but it doesn't explain how to fix/work around this.

The relevant issue is https://github.com/sympy/sympy/issues/5904.
When evaluate=False, the args property is not sorted:
>>> a = sympify('x**2 + 1', evaluate=False)
>>> b = sympify('x**2 + 1')
>>> a == b
False
>>> a.args
(x**2, 1)
>>> b.args
(1, x**2)
I don't believe (but you should check on the mailing list to be sure) that there is a built-in way to resolve this. The best approach depends on what you are trying to accomplish with this comparison.
The discussion at https://groups.google.com/forum/#!msg/sympy/LU5DQGJJhfc/_Le_u8UGtx0J (though outdated!) suggests making a custom comparison function, perhaps using the _sorted_args property:
>>> a._sorted_args
[1, x**2]
>>> b._sorted_args
[1, x**2]

Related

Sympy: Is there a function that gives all the factors of an expression but does not work sums?

I have an expression which is composed only of factors (e.g. (x**2+1)*(x**2)*(x+4). I want to delete the factor x**2 from it using the function .args with an if condition. However, if I have the following equation x**2+1+x+4, the .args thinks I have x**2 in the expression which is not true (I only have one factor). I have the code below.:
if q**2 in expr.args:
expr = expr.func(*[term for term in expr.args if term != q**2])
else:
expr = expr*2
By using Mul.make_args(expr) you will get a singleton if the expression is not a product, otherwise a tuple of the factors:
>>> from sympy.abc import x, y
>>> from sympy import Mul
>>> Mul.make_args(x + y)
(x + y,)
>>> Mul.make_args(x*y)
(x, y)

fastest and elegant way to check whether a given list contains some element by regular expression

Fastest and elegant way to check whether some element expressed by regular expression is in a given list.
For example:
given a list:
newlist = ['this','thiis','thas','sada']
regex = re.compile('th.s')
In this question: Regular Expressions: Search in list
list(filter(regex.match,newlist))
give me a list
['this','thas']
However, I just want to return True or False. Therefore above method is not efficient since it looks through all element of newlist. Is there a way like
'this' in newlist
to efficiently and elegantly check whether some element expressed by regular expression is in a given list.
As Loocid suggested, you can use any. I would do it with a generator expression like so:
newlist = ['this','thiis','thas','sada']
regex = re.compile('th.s')
result = any(regex.match(word) for word in newlist)
print(result) # True
Here is another version with map that is slightly faster:
result = any(map(regex.match, newlist))
This will evaluate the list until it finds the first match.
def search_for_match(list):
result = False
for i in newlist:
if bool(re.match(r"th.s", i)) is True:
result = True
break
return result
Or to make it more general:
def search_for_match(list, pattern):
result = False
for i in list:
if bool(re.match(pattern, i)) is True:
result = True
break
return result
newlist = ['this','thiis','thas','sada']
found = search_for_match(newlist, r"th.s")
print(found) # True
Just for kicks I ran these through the timer. I sooo lost:
t = time.process_time()
newlist = ['this','thiis','thas','sada']
search_for_match(newlist, r"th.s")
elapsed_time1 = time.process_time() - t
print(elapsed_time1) # 0.00015399999999998748
t2 = time.process_time()
newlist = ['this','thiis','thas','sada']
regex = re.compile('th.s')
result = any(regex.match(word) for word in newlist)
elapsed_time2 = time.process_time() - t2
print(elapsed_time2) # 1.1999999999900979e-05
t3 = time.process_time()
newlist = ['this','thiis','thas','sada']
regex = re.compile('th.s')
result = any(map(regex.match, newlist))
elapsed_time3 = time.process_time() - t3
print(elapsed_time3) # 5.999999999950489e-06
I can think of (besides using any)
next((x for x in newlist if regex.match(x)), False)
Does not return True but probably OK for conditional testing if you have no empty strings :)

check if expression contains symbol

I would like to find out programatically if a SymPy expression contains a symbol. E.g., for
import sympy
x = sympy.Symbol('x')
y = sympy.Symbol('y')
a = 4 + x**2 + y
b = 4 + y**2
a contains both x and y, b contains only y.
>>> x in a.free_symbols, y in a.free_symbols
(True, True)
>>> x in b.free_symbols, y in b.free_symbols
(False, True)
You can also use .atoms(Symbol) to check that. atoms(Symbol) differs from .free_symbols in some cases. free_symbols doesn't return dummy symbols, like integration variables.
it's usually what you want, since expressions don't mathematically depend on dummy symbols
example:
>>> Integral(f(x), (x, 0, 1)).atoms(Symbol)
set([x])
>>> Integral(f(x), (x, 0, 1)).free_symbols
set([])

Python - Enforce non-occurence of bool in list

I want to check in python 2.7 if a dictionary satisfies some restrictions I set. An satisfying example is: {1:[2], 2: [2,3], 3:False, 4: True}, however {1:[1, True]} is not ok. I want to forbid that keys map to True or False which are inside a list. Note, that I only want to detect if my restrictions are violated, I don't want to handle the case.
In the beginning I tested if a key maps to a list, and if it does I test if I have for some entry v: v == False or v == True, and if so I raise an ValueError. Then I learned that it does not work, because 1 == True is true.
Should I instead test v is False or v is True? Do you have suggestions on how to enforce the restrictions, or do you think my restrictions are bad practice?
Background: The dictionary maps state/label-tuples to successor states for an NFA, and I map to True and False to immediately accept/reject the word.
You can use isinstance:
In [16]: isinstance(True, bool)
Out[16]: True
In [17]: isinstance(1, bool)
Out[17]: False
You can use is as well:
In [18]: any(x is True or x is False for x in [True, 2])
Out[18]: True
An example one-line function with isinstance:
In [21]: is_good = lambda d: not any(any(isinstance(x, bool) for x in l)
....: for l in d.values() if isinstance(l, list))
In [22]: d = {1:[2], 2: [2,3], 3:False, 4: True}
In [23]: is_good(d)
Out[23]: True
In [24]: d[1][0] = False
In [25]: is_good(d)
Out[25]: False
A more explicit version of the same function:
def is_good(d):
for v in d.values():
if isinstance(v, list):
for x in v:
if isinstance(v, bool):
return False
return True
To respect duck-typing, if I did not want elements with a length to test true, I would test that, using len(), in addition to == True:
def issingle(v):
try:
len(v)
return False
except:
return True
x=[2,3]
y=1
issingle(x) ->> False
issingle(y) ->> True

How to check if all of the following items are in a list?

I found, that there is related question, about how to find if at least one item exists in a list:
How to check if one of the following items is in a list?
But what is the best and pythonic way to find whether all items exists in a list?
Searching through the docs I found this solution:
>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False
Other solution would be this:
>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False
But here you must do more typing.
Is there any other solutions?
Operators like <= in Python are generally not overriden to mean something significantly different than "less than or equal to". It's unusual for the standard library does this--it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset. Note that you don't need to convert the argument to a set; it'll do that for you if needed.
set(['a', 'b']).issubset(['a', 'b', 'c'])
I would probably use set in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation ...
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
What if your lists contain duplicates like this:
v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
Not OP's case, but - for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) - you need to work with dict.items:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That's because dict.items returns tuples of key/value pairs, and much like any object in Python, they're interchangeably comparable
Another solution would be:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False
What makes my solution great is that you can write one-liners by putting the lists inline.
An example of how to do this using a lambda expression would be:
issublist = lambda x, y: 0 in [_ in x for _ in y]
Short syntax
I discovered a very readable syntax while experimenting on the Python interpreter.
>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True
List of items to search for
If you have a long list of objects to search for, held in a sub_list variable:
>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']
If any (at least one) item is contained in the superset (or statement):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False
>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
If all items are contained in superset (and statement), then sub_list is a full subset. Also featuring a bit of De Morgan's Law:
>>> next((False for item in sub_list if item not in my_list), True)
False
>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True