Repository: sympy/sympy
File: sympy/solvers/solvers.py (Python)

Code before:
            if fr and fi and fr != fi and not any(
                    i.atoms(re, im, arg, atan2) - had for i in (fr, fi)):
                if bare_f:
                    bare_f = False
                f[i: i + 1] = [fr, fi]

    # real/imag handling -----------------------------
    if any(isinstance(fi, (bool, BooleanAtom)) for fi in f):
        if as_set:
            return [], set()
        return []

    for i, fi in enumerate(f):
        # Abs / Max / Min
        # Rewrites as piecewise functions prior to solving
        while True:
            was = fi
            fi = fi.replace(Abs, lambda arg:
                separatevars(Abs(arg)).rewrite(Piecewise) if arg.has(*symbols)
                else Abs(arg))
            fi = fi.replace(Max, lambda *args:
                separatevars(Max(*args)).rewrite(Piecewise) if any(arg.has(*symbols) for arg in args)
                else Max(*args))
            fi = fi.replace(Min, lambda *args:
                separatevars(Min(*args)).rewrite(Piecewise) if any(arg.has(*symbols) for arg in args)
                else Min(*args))
            if was == fi:
                break

        for e in fi.find(Abs):
            if e.has(*symbols):
                raise NotImplementedError('solving %s when the argument '
                    'is not real or imaginary.' % e)
        for e in fi.find(Max):
            if e.has(*symbols):
                raise NotImplementedError('solving %s when the argument '
                    'is not real or imaginary.' % e)
        for e in fi.find(Min):
            if e.has(*symbols):
                raise NotImplementedError('solving %s when the argument '
                    'is not real or imaginary.' % e)

        # arg
        fi = fi.replace(arg, lambda a: arg(a).rewrite(atan2).rewrite(atan))

        # save changes
        f[i] = fi

    # see if re(s) or im(s) appear
    freim = [fi for fi in f if fi.has(re, im)]
    if freim:

Review comment (suggestion):
Each of these is recursing down rebuilding the whole expression tree. It should be possible to do this in one pass rather than three.

Code after:
            if fr and fi and fr != fi and not any(
                    i.atoms(re, im, arg, atan2) - had for i in (fr, fi)):
                if bare_f:
                    bare_f = False
                f[i: i + 1] = [fr, fi]

    # real/imag handling -----------------------------
    if any(isinstance(fi, (bool, BooleanAtom)) for fi in f):
        if as_set:
            return [], set()
        return []

    repl_funcs = (Abs, Min, Max)
    for i, fi in enumerate(f):
        # Abs / Max / Min
        # Rewrites as piecewise functions prior to solving
        while True:
            was = fi
            fi = fi.replace(lambda ex: type(ex) in repl_funcs,
                       lambda ex: separatevars(ex).rewrite(Piecewise) if any(
                           arg.has(*symbols) for arg in ex.args) else ex)
            if was == fi:
                break

        for e in fi.find(lambda ex: type(ex) in repl_funcs):
            if e.has(*symbols):
                raise NotImplementedError('solving %s when the argument '
                    'is not real or imaginary.' % e)

        # arg
        fi = fi.replace(arg, lambda a: arg(a).rewrite(atan2).rewrite(atan))

        # save changes
        f[i] = fi

    # see if re(s) or im(s) appear
    freim = [fi for fi in f if fi.has(re, im)]
    if freim:
        irf = []
        for s in symbols:
            if s.is_real or s.is_imaginary:
                continue  # neither re(x) nor im(x) will appear
            # if re(s) or im(s) appear, the auxiliary equation must be present
            if any(fi.has(re(s), im(s)) for fi in freim):
                irf.append((s, re(s) + S.ImaginaryUnit*im(s)))
        if irf:
            for s, rhs in irf:
                f = [fi.xreplace({s: rhs}) for fi in f] + [s - rhs]
                symbols.extend([re(s), im(s)])
            if bare_f:
                bare_f = False