'Return tuple with factor expression and dimension expression.'

@staticmethod
def _collect_factor_and_dimension(expr):

    if isinstance(expr, Quantity):
        return (expr.scale_factor, expr.dimension)
    elif isinstance(expr, Mul):
        factor = 1
        dimension = Dimension(1)
        for arg in expr.args:
            (arg_factor, arg_dim) = Quantity._collect_factor_and_dimension(arg)
            factor *= arg_factor
            dimension *= arg_dim
        return (factor, dimension)
    elif isinstance(expr, Pow):
        (factor, dim) = Quantity._collect_factor_and_dimension(expr.base)
        (exp_factor, exp_dim) = Quantity._collect_factor_and_dimension(expr.exp)
        if exp_dim.is_dimensionless:
            exp_dim = 1
        return ((factor ** exp_factor), (dim ** (exp_factor * exp_dim)))
    elif isinstance(expr, Add):
        (factor, dim) = Quantity._collect_factor_and_dimension(expr.args[0])
        for addend in expr.args[1:]:
            (addend_factor, addend_dim) = Quantity._collect_factor_and_dimension(addend)
            if (dim != addend_dim):
                raise TypeError('Dimension    of    "{0}"    is    {1},    but    it    should    be    {2}'.format(addend, addend_dim.name, dim.name))
            factor += addend_factor
        return (factor, dim)
    elif isinstance(expr, Derivative):
        (factor, dim) = Quantity._collect_factor_and_dimension(expr.args[0])
        for independent in expr.args[1:]:
            (ifactor, idim) = Quantity._collect_factor_and_dimension(independent)
            factor /= ifactor
            dim /= idim
        return (factor, dim)
    elif isinstance(expr, Function):
        fds = [Quantity._collect_factor_and_dimension(arg) for arg in expr.args]
        return (expr.func(*(f[0] for f in fds)), expr.func(*(d[1] for d in fds)))
    elif isinstance(expr, Dimension):
        return (1, expr)
    else:
        return (expr, Dimension(1))
