Repository: sympy/sympy (Python)

Issue:
Regression in 1.2: cse with ignore
A downstream project of mine [has started failing](https://github.com/bjodah/pyodesys/pull/86#issue-205269220) when trying to upgrade sympy from v1.1.1 to v1.2.

Here is a minimal test:
```python
def test_cse_ignore_regression():
    x, y1, y2, p1 = symbols('x y1 y2 p1')
    l = [
        p1*exp(x)*exp(-y2),
        exp(y1)*exp(x)*exp(-y2)
    ]
    substs, reduced = cse(l, ignore=(x,))
    rl = [e.subs(reversed(substs)) for e in reduced]
    assert rl == l
```
I ran git bisect which identified gh-13221 as the source of the regression.

cc @isuruf 

EDIT:
Traceback:
```
Traceback (most recent call last):
  File "/usr/lib/python3.5/pdb.py", line 1661, in main
    pdb._runscript(mainpyfile)
  File "/usr/lib/python3.5/pdb.py", line 1542, in _runscript
    self.run(statement)
  File "/usr/lib/python3.5/bdb.py", line 431, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "/home/bjorn/doc/src/py/sympy/cse_regression_mwe.py", line 1, in <module>
    from sympy import symbols, cse, exp, simplify
  File "/home/bjorn/doc/src/py/sympy/cse_regression_mwe.py", line 9, in test_cse_ignore
    substs, reduced = cse(l, ignore=(x,))
  File "/home/bjorn/vc/sympy/sympy/simplify/cse_main.py", line 722, in cse
    order, ignore)
  File "/home/bjorn/vc/sympy/sympy/simplify/cse_main.py", line 531, in tree_cse
    _find_repeated(e)
  File "/home/bjorn/vc/sympy/sympy/simplify/cse_main.py", line 527, in _find_repeated
    list(map(_find_repeated, args))
  File "/home/bjorn/vc/sympy/sympy/simplify/cse_main.py", line 514, in _find_repeated
    if ign in expr.free_symbols:
AttributeError: 'Unevaluated' object has no attribute 'free_symbols'
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> /home/bjorn/vc/sympy/sympy/simplify/cse_main.py(514)_find_repeated()
-> if ign in expr.free_symbols:
(Pdb) p expr
Uneval<<class 'sympy.core.mul.Mul'>>(exp(x), exp(-y2))
(Pdb) p expr.__class__
<class 'sympy.simplify.cse_main.Unevaluated'>
```



Discussion:

Patch:
diff --git a/sympy/simplify/cse_main.py b/sympy/simplify/cse_main.py
index cdbab4f60849..204f384d104e 100644
--- a/sympy/simplify/cse_main.py
+++ b/sympy/simplify/cse_main.py
@@ -276,6 +276,10 @@ def __str__(self):
     def as_unevaluated_basic(self):
         return self.func(*self.args, evaluate=False)
 
+    @property
+    def free_symbols(self):
+        return set().union(*[a.free_symbols for a in self.args])
+
     __repr__ = __str__
 
 


Test patch:
diff --git a/sympy/simplify/tests/test_cse.py b/sympy/simplify/tests/test_cse.py
index 8fed9b4b35be..249432fa8c51 100644
--- a/sympy/simplify/tests/test_cse.py
+++ b/sympy/simplify/tests/test_cse.py
@@ -494,6 +494,14 @@ def test_cse_ignore():
     assert not any(y in sub.free_symbols for _, sub in subst2), "Sub-expressions containing y must be ignored"
     assert any(sub - sqrt(x + 1) == 0 for _, sub in subst2), "cse failed to identify sqrt(x + 1) as sub-expression"
 
+def test_cse_ignore_issue_15002():
+    l = [
+        w*exp(x)*exp(-z),
+        exp(y)*exp(x)*exp(-z)
+    ]
+    substs, reduced = cse(l, ignore=(x,))
+    rl = [e.subs(reversed(substs)) for e in reduced]
+    assert rl == l
 
 def test_cse__performance():
     import time