def fast_substitute(monomial, old_sub, new_sub):
if is_number_type(monomial):<EOL><INDENT>return monomial<EOL><DEDENT>if monomial.is_Add:<EOL><INDENT>return sum([fast_substitute(element, old_sub, new_sub) for element in<EOL>monomial.as_ordered_terms()])<EOL><DEDENT>comm_factors, ncomm_factors = split_commutative_parts(monomial)<EOL>old_comm_factors, old_ncomm_factors = split_commutative_parts(old_sub)<EOL>if not isinstance(new_sub, (int, float, complex)):<EOL><INDENT>new_comm_factors, _ = split_commutative_parts(new_sub)<EOL><DEDENT>else:<EOL><INDENT>new_comm_factors = [new_sub]<EOL><DEDENT>comm_monomial = <NUM_LIT:1><EOL>is_constant_term = False<EOL>if comm_factors != ():<EOL><INDENT>if len(comm_factors) == <NUM_LIT:1> and is_number_type(comm_factors[<NUM_LIT:0>]):<EOL><INDENT>is_constant_term = True<EOL>comm_monomial = comm_factors[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>for comm_factor in comm_factors:<EOL><INDENT>comm_monomial *= comm_factor<EOL><DEDENT>if old_comm_factors != ():<EOL><INDENT>comm_old_sub = <NUM_LIT:1><EOL>for comm_factor in old_comm_factors:<EOL><INDENT>comm_old_sub *= comm_factor<EOL><DEDENT>comm_new_sub = <NUM_LIT:1><EOL>for comm_factor in new_comm_factors:<EOL><INDENT>comm_new_sub *= comm_factor<EOL><DEDENT>if isinstance(comm_old_sub, Pow):<EOL><INDENT>old_base = comm_old_sub.base<EOL>if comm_monomial.has(old_base):<EOL><INDENT>old_degree = comm_old_sub.exp<EOL>new_monomial = <NUM_LIT:1><EOL>match = False<EOL>for factor in comm_monomial.as_ordered_factors():<EOL><INDENT>if factor.has(old_base):<EOL><INDENT>if isinstance(factor, Pow):<EOL><INDENT>degree = factor.exp<EOL>if degree >= old_degree:<EOL><INDENT>match = True<EOL>new_monomial *=old_base**(degree-old_degree) *comm_new_sub<EOL><DEDENT><DEDENT>else:<EOL><INDENT>new_monomial *= factor<EOL><DEDENT><DEDENT>else:<EOL><INDENT>new_monomial *= factor<EOL><DEDENT><DEDENT>if match:<EOL><INDENT>comm_monomial = new_monomial<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>comm_monomial = comm_monomial.subs(comm_old_sub,<EOL>comm_new_sub)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if ncomm_factors == () or old_ncomm_factors == ():<EOL><INDENT>return comm_monomial<EOL><DEDENT>new_var_list = []<EOL>new_monomial = <NUM_LIT:1><EOL>left_remainder = <NUM_LIT:1><EOL>right_remainder = <NUM_LIT:1><EOL>for i in range(len(ncomm_factors) - len(old_ncomm_factors) + <NUM_LIT:1>):<EOL><INDENT>for j, old_ncomm_factor in enumerate(old_ncomm_factors):<EOL><INDENT>ncomm_factor = ncomm_factors[i + j]<EOL>if isinstance(ncomm_factor, Symbol) and(isinstance(old_ncomm_factor, Operator) or<EOL>(isinstance(old_ncomm_factor, Symbol) and<EOL>ncomm_factor != old_ncomm_factor)):<EOL><INDENT>break<EOL><DEDENT>if isinstance(ncomm_factor, Operator) and((isinstance(old_ncomm_factor, Operator) and<EOL>ncomm_factor != old_ncomm_factor) or<EOL>isinstance(old_ncomm_factor, Pow)):<EOL><INDENT>break<EOL><DEDENT>if is_adjoint(ncomm_factor):<EOL><INDENT>if not is_adjoint(old_ncomm_factor) orncomm_factor != old_ncomm_factor:<EOL><INDENT>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not isinstance(ncomm_factor, Pow):<EOL><INDENT>if is_adjoint(old_ncomm_factor):<EOL><INDENT>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if isinstance(old_ncomm_factor, Pow):<EOL><INDENT>old_base = old_ncomm_factor.base<EOL>old_degree = old_ncomm_factor.exp<EOL><DEDENT>else:<EOL><INDENT>old_base = old_ncomm_factor<EOL>old_degree = <NUM_LIT:1><EOL><DEDENT>if old_base != ncomm_factor.base:<EOL><INDENT>break<EOL><DEDENT>if old_degree > ncomm_factor.exp:<EOL><INDENT>break<EOL><DEDENT>if old_degree < ncomm_factor.exp:<EOL><INDENT>if j != len(old_ncomm_factors) - <NUM_LIT:1>:<EOL><INDENT>if j != <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>else:<EOL><INDENT>left_remainder = old_base ** (<EOL>ncomm_factor.exp - old_degree)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>right_remainder = old_base ** (<EOL>ncomm_factor.exp - old_degree)<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>new_monomial = <NUM_LIT:1><EOL>for var in new_var_list:<EOL><INDENT>new_monomial *= var<EOL><DEDENT>new_monomial *= left_remainder * new_sub * right_remainder<EOL>for j in range(i + len(old_ncomm_factors), len(ncomm_factors)):<EOL><INDENT>new_monomial *= ncomm_factors[j]<EOL><DEDENT>new_monomial *= comm_monomial<EOL>break<EOL><DEDENT>new_var_list.append(ncomm_factors[i])<EOL><DEDENT>else:<EOL><INDENT>if not is_constant_term and comm_factors != ():<EOL><INDENT>new_monomial = comm_monomial<EOL>for factor in ncomm_factors:<EOL><INDENT>new_monomial *= factor<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return monomial<EOL><DEDENT><DEDENT>if not isinstance(new_sub, (float, int, complex)) and new_sub.is_Add:<EOL><INDENT>return expand(new_monomial)<EOL><DEDENT>else:<EOL><INDENT>return new_monomial<EOL><DEDENT>
Experimental fast substitution routine that considers only restricted
    cases of noncommutative algebras. In rare cases, it fails to find a
    substitution. Use it with proper testing.

    :param monomial: The monomial with parts need to be substituted.
    :param old_sub: The part to be replaced.
    :param new_sub: The replacement.