Split a product into sympy and qnet factors

    This is a helper routine for applying some sympy transformation on an
    arbitrary product-like expression in QNET. The idea is this::

        expr -> sympy_factor, quantum_factor
        sympy_factor -> sympy_function(sympy_factor)
        expr -> sympy_factor * quantum_factor

def _split_sympy_quantum_factor(expr):
    """Split a product into sympy and qnet factors

    This is a helper routine for applying some sympy transformation on an
    arbitrary product-like expression in QNET. The idea is this::

        expr -> sympy_factor, quantum_factor
        sympy_factor -> sympy_function(sympy_factor)
        expr -> sympy_factor * quantum_factor
    """
    from qnet.algebra.core.abstract_quantum_algebra import (
        QuantumExpression, ScalarTimesQuantumExpression)
    from qnet.algebra.core.scalar_algebra import ScalarValue, ScalarTimes, One
    if isinstance(expr, ScalarTimesQuantumExpression):
        sympy_factor, quantum_factor = _split_sympy_quantum_factor(expr.coeff)
        quantum_factor *= expr.term
    elif isinstance(expr, ScalarValue):
        sympy_factor = expr.val
        quantum_factor = expr._one
    elif isinstance(expr, ScalarTimes):
        sympy_factor = sympy.S(1)
        quantum_factor = expr._one
        for op in expr.operands:
            op_sympy, op_quantum = _split_sympy_quantum_factor(op)
            sympy_factor *= op_sympy
            quantum_factor *= op_quantum
    elif isinstance(expr, sympy.Basic):
        sympy_factor = expr
        quantum_factor = One
    else:
        sympy_factor = sympy.S(1)
        quantum_factor = expr
    assert isinstance(sympy_factor, sympy.Basic)
    assert isinstance(quantum_factor, QuantumExpression)
    return sympy_factor, quantum_factor