'Matches Add/Mul "pattern" to an expression "expr".
repl_dict ... a dictionary of (wild: expression) pairs, that get
returned with the results
This function is the main workhorse for Add/Mul.
For instance:
>>> from sympy import symbols, Wild, sin
>>> a = Wild("a")
>>> b = Wild("b")
>>> c = Wild("c")
>>> x, y, z = symbols("x y z")
>>> (a+sin(b)*c)._matches_commutative(x+sin(y)*z)
{a_: x, b_: y, c_: z}
In the example above, "a+sin(b)*c" is the pattern, and "x+sin(y)*z" is
the expression.
The repl_dict contains parts that were already matched. For example
here:
>>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z, repl_dict={a: x})
{a_: x, b_: y, c_: z}
the only function of the repl_dict is to return it in the
result, e.g. if you omit it:
>>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z)
{b_: y, c_: z}
the "a: x" is not returned in the result, but otherwise it is
equivalent.'

def _matches_commutative(self, expr, repl_dict={}, old=False):

    from .expr import Add, Expr
    from sympy import Mul
    if (isinstance(self, Expr) and (not isinstance(expr, Expr))):
        return None
    if (self == expr):
        return repl_dict
    d = self._matches_simple(expr, repl_dict)
    if (d is not None):
        return d
    from .function import WildFunction
    from .symbol import Wild
    wild_part = []
    exact_part = []
    for p in ordered(self.args):
        if (p.has(Wild, WildFunction) and (not expr.has(p))):
            wild_part.append(p)
        else:
            exact_part.append(p)
    if exact_part:
        exact = self.func(*exact_part)
        free = expr.free_symbols
        if (free and (exact.free_symbols - free)):
            return None
        newpattern = self.func(*wild_part)
        newexpr = self._combine_inverse(expr, exact)
        if ((not old) and (expr.is_Add or expr.is_Mul)):
            if (newexpr.count_ops() > expr.count_ops()):
                return None
        return newpattern.matches(newexpr, repl_dict)
    i = 0
    saw = set()
    while (expr not in saw):
        saw.add(expr)
        expr_list = ((self.identity,) + tuple(ordered(self.make_args(expr))))
        for last_op in reversed(expr_list):
            for w in reversed(wild_part):
                d1 = w.matches(last_op, repl_dict)
                if (d1 is not None):
                    d2 = self.xreplace(d1).matches(expr, d1)
                    if (d2 is not None):
                        return d2
        if (i == 0):
            if self.is_Mul:
                if (expr.is_Pow and expr.exp.is_Integer):
                    if (expr.exp > 0):
                        expr = Mul(evaluate=False, *[expr.base, (expr.base ** (expr.exp - 1))])
                    else:
                        expr = Mul(evaluate=False, *[(1 / expr.base), (expr.base ** (expr.exp + 1))])
                    i += 1
                    continue
            elif self.is_Add:
                (c, e) = expr.as_coeff_Mul()
                if (abs(c) > 1):
                    if (c > 0):
                        expr = Add(evaluate=False, *[e, ((c - 1) * e)])
                    else:
                        expr = Add(evaluate=False, *[(- e), ((c + 1) * e)])
                    i += 1
                    continue
                from sympy.simplify.radsimp import collect
                was = expr
                did = set()
                for w in reversed(wild_part):
                    (c, w) = w.as_coeff_mul(Wild)
                    free = (c.free_symbols - did)
                    if free:
                        did.update(free)
                        expr = collect(expr, free)
                if (expr != was):
                    i += 0
                    continue
            break
    return
