which option: top to bottom vs bottom to top or stop after 1 hit? This
starts to get complicated:

simultaneous or not
exact or not
from top or bottom
recursive or not

Is it worth it?

Below, I go through all the different options for replace input and see
what it looks like for subs and xreplace. Only for the case of pattern
matching are things awkward for xreplace, otherwise xreplace and replace
can do the same things.

expr/expr
----

(3+sin(3)).subs(3,2)
(3+sin(3)).subs(S(3),S(2))  # should work -- needs fix
(3+sin(3)).xreplace({S(3):S(2)})


type/type where type is a function
----
sin(x).subs(sin, cos)
sin(x).replace(sin, cos)
sin(x).xreplace(Transform(lambda x: cos(x.args[0]), lambda x:x.func is sin))


type/type where type is an object
-subs
(x+y).replace(Add, Mul)
(x+y).xreplace(Transform(lambda x: Mul(*x.args), lambda x:x.is_Add))


type/func
----
-subs
sin(x).replace(sin, lambda x:x**2)
sin(x).xreplace(Transform(lambda x: x.args[0]**2, lambda x:x.func is sin))

pattern/(expr or func in terms of pattern variables)
----
-subs
sin(x + sin(x)).replace(a+sin(a), a**2)
pat = a+sin(a)
def rep(d): return (a**2).xreplace(d)
sin(x+sin(x)).xreplace(Transform(lambda x: rep(x.match(pat)), lambda
x:x.match(pat)))

func/func
----
-subs
fil = lambda x: x.is_Add
do = lambda x: x/2
(x+y).replace(fil, do)
(x+y).xreplace(Transform(do, fil))


fails gracefully (i.e. is restricted in where it operates)
----
i = Integral(x, (x, 1, 2))
>>> i.subs(x, 1)
Integral(x, (x, 1, 2))
>>> Integral(x,(x,1,2)).replace(x,S(1))
Traceback (most recent call last):
...
ValueError: Invalid limits given: ((1, 1, 2),)
>>> Integral(x,(x,1,2)).xreplace({x:S(1)})
Traceback (most recent call last):
...
ValueError: Invalid limits given: ((1, 1, 2),)