'Replace matching subexpressions of ``self`` with ``value``.
If ``map = True`` then also return the mapping {old: new} where ``old``
was a sub-expression found with query and ``new`` is the replacement
value for it. If the expression itself doesn\'t match the query, then
the returned value will be ``self.xreplace(map)`` otherwise it should
be ``self.subs(ordered(map.items()))``.
Traverses an expression tree and performs replacement of matching
subexpressions from the bottom to the top of the tree. The default
approach is to do the replacement in a simultaneous fashion so
changes made are targeted only once. If this is not desired or causes
problems, ``simultaneous`` can be set to False. In addition, if an
expression containing more than one Wild symbol is being used to match
subexpressions and  the ``exact`` flag is True, then the match will only
succeed if non-zero values are received for each Wild that appears in
the match pattern.
The list of possible combinations of queries and replacement values
is listed below:
Examples
Initial setup
>>> from sympy import log, sin, cos, tan, Wild, Mul, Add
>>> from sympy.abc import x, y
>>> f = log(sin(x)) + tan(sin(x**2))
1.1. type -> type
obj.replace(type, newtype)
When object of type ``type`` is found, replace it with the
result of passing its argument(s) to ``newtype``.
>>> f.replace(sin, cos)
log(cos(x)) + tan(cos(x**2))
>>> sin(x).replace(sin, cos, map=True)
(cos(x), {sin(x): cos(x)})
>>> (x*y).replace(Mul, Add)
x + y
1.2. type -> func
obj.replace(type, func)
When object of type ``type`` is found, apply ``func`` to its
argument(s). ``func`` must be written to handle the number
of arguments of ``type``.
>>> f.replace(sin, lambda arg: sin(2*arg))
log(sin(2*x)) + tan(sin(2*x**2))
>>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args)))
sin(2*x*y)
2.1. pattern -> expr
obj.replace(pattern(wild), expr(wild))
Replace subexpressions matching ``pattern`` with the expression
written in terms of the Wild symbols in ``pattern``.
>>> a = Wild(\'a\')
>>> f.replace(sin(a), tan(a))
log(tan(x)) + tan(tan(x**2))
>>> f.replace(sin(a), tan(a/2))
log(tan(x/2)) + tan(tan(x**2/2))
>>> f.replace(sin(a), a)
log(x) + tan(x**2)
>>> (x*y).replace(a*x, a)
y
When the default value of False is used with patterns that have
more than one Wild symbol, non-intuitive results may be obtained:
>>> b = Wild(\'b\')
>>> (2*x).replace(a*x + b, b - a)
2/x
For this reason, the ``exact`` option can be used to make the
replacement only when the match gives non-zero values for all
Wild symbols:
>>> (2*x + y).replace(a*x + b, b - a, exact=True)
y - 2
>>> (2*x).replace(a*x + b, b - a, exact=True)
2*x
2.2. pattern -> func
obj.replace(pattern(wild), lambda wild: expr(wild))
All behavior is the same as in 2.1 but now a function in terms of
pattern variables is used rather than an expression:
>>> f.replace(sin(a), lambda a: sin(2*a))
log(sin(2*x)) + tan(sin(2*x**2))
3.1. func -> func
obj.replace(filter, func)
Replace subexpression ``e`` with ``func(e)`` if ``filter(e)``
is True.
>>> g = 2*sin(x**3)
>>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2)
4*sin(x**9)
The expression itself is also targeted by the query but is done in
such a fashion that changes are not made twice.
>>> e = x*(x*y + 1)
>>> e.replace(lambda x: x.is_Mul, lambda x: 2*x)
2*x*(2*x*y + 1)
See Also
subs: substitution of subexpressions as defined by the objects
themselves.
xreplace: exact node replacement in expr tree; also capable of
using matching rules'

def replace(self, query, value, map=False, simultaneous=True, exact=False):

    from sympy.core.symbol import Dummy
    from sympy.simplify.simplify import bottom_up
    try:
        query = sympify(query)
    except SympifyError:
        pass
    try:
        value = sympify(value)
    except SympifyError:
        pass
    if isinstance(query, type):
        _query = (lambda expr: isinstance(expr, query))
        if isinstance(value, type):
            _value = (lambda expr, result: value(*expr.args))
        elif callable(value):
            _value = (lambda expr, result: value(*expr.args))
        else:
            raise TypeError('given    a    type,    replace()    expects    another    type    or    a    callable')
    elif isinstance(query, Basic):
        _query = (lambda expr: expr.match(query))
        if isinstance(value, Basic):
            if exact:
                _value = (lambda expr, result: (value.subs(result) if all((val for val in result.values())) else expr))
            else:
                _value = (lambda expr, result: value.subs(result))
        elif callable(value):
            if exact:
                _value = (lambda expr, result: (value(**dict([(str(key)[:(-1)], val) for (key, val) in result.items()])) if all((val for val in result.values())) else expr))
            else:
                _value = (lambda expr, result: value(**dict([(str(key)[:(-1)], val) for (key, val) in result.items()])))
        else:
            raise TypeError('given    an    expression,    replace()    expects    another    expression    or    a    callable')
    elif callable(query):
        _query = query
        if callable(value):
            _value = (lambda expr, result: value(expr))
        else:
            raise TypeError('given    a    callable,    replace()    expects    another    callable')
    else:
        raise TypeError('first    argument    to    replace()    must    be    a    type,    an    expression    or    a    callable')
    mapping = {}
    mask = []
    def rec_replace(expr):
        result = _query(expr)
        if (result or (result == {})):
            new = _value(expr, result)
            if ((new is not None) and (new != expr)):
                mapping[expr] = new
                if simultaneous:
                    com = getattr(new, 'is_commutative', True)
                    if (com is None):
                        com = True
                    d = Dummy(commutative=com)
                    mask.append((d, new))
                    expr = d
                else:
                    expr = new
        return expr
    rv = bottom_up(self, rec_replace, atoms=True)
    if simultaneous:
        mask = list(reversed(mask))
        for (o, n) in mask:
            r = {o: n}
            rv = rv.xreplace(r)
    if (not map):
        return rv
    else:
        if simultaneous:
            for (o, n) in mask:
                r = {o: n}
                mapping = {k.xreplace(r): v.xreplace(r) for (k, v) in mapping.items()}
        return (rv, mapping)
