def _parse_quadratic_expression(expression, expanded=False):
    """
    Parse a quadratic expression. It is assumed that the expression is known to be quadratic or linear.

    The 'expanded' parameter tells whether the expression has already been expanded. If it hasn't the parsing
    might fail and will expand the expression and try again.
    """
    linear_coefficients = {}
    quadratic_coefficients = {}
    offset = 0

    if expression.is_Number:  # Constant expression, no coefficients
        return float(expression), linear_coefficients, quadratic_coefficients

    if expression.is_Mul:
        terms = (expression,)
    elif expression.is_Add:
        terms = expression.args
    else:
        raise ValueError("Expression of type {} could not be parsed.".format(type(expression)))

    try:
        for term in terms:
            if term.is_Number:
                offset += float(term)
                continue
            if term.is_Pow:
                term = 1.0 * term
            assert term.is_Mul, "What is this? {}".format(type(term))
            factors = term.args
            coef = factors[0]
            vars = factors[1:]
            assert len(vars) <= 2, "This should not happen. Is this expression quadratic?"
            if len(vars) == 2:
                key = frozenset(vars)
                quadratic_coefficients[key] = quadratic_coefficients.get(key, 0) + coef
            else:
                var = vars[0]
                if var.is_Symbol:
                    linear_coefficients[var] = linear_coefficients.get(var, 0) + coef
                elif var.is_Pow:
                    var, exponent = var.args
                    if exponent != 2:
                        raise ValueError("The expression is not quadratic")
                    key = frozenset((var,))
                    quadratic_coefficients[key] = quadratic_coefficients.get(key, 0) + coef
        if quadratic_coefficients:
            assert all(var.is_Symbol for var in frozenset.union(*quadratic_coefficients))  # Raise an exception to trigger expand
        if linear_coefficients:
            assert all(var.is_Symbol for var in linear_coefficients)
    except Exception as e:
        if expanded:
            raise e
        else:
            # Try to expand the expression and parse it again
            return _parse_quadratic_expression(expression.expand(), expanded=True)

    return offset, linear_coefficients, quadratic_coefficients
def _parse_quadratic_expression ( expression , expanded = False ) : linear_coefficients = { } quadratic_coefficients = { } offset = 0 if expression . is_Number : return float ( expression ) , linear_coefficients , quadratic_coefficients if expression . is_Mul : terms = ( expression , ) elif expression . is_Add : terms = expression . args else : raise ValueError ( "Expression of type {} could not be parsed." . format ( type ( expression ) ) ) try : for term in terms : if term . is_Number : offset += float ( term ) continue if term . is_Pow : term = 1.0 * term assert term . is_Mul , "What is this? {}" . format ( type ( term ) ) factors = term . args coef = factors [ 0 ] vars = factors [ 1 : ] assert len ( vars ) <= 2 , "This should not happen. Is this expression quadratic?" if len ( vars ) == 2 : key = frozenset ( vars ) quadratic_coefficients [ key ] = quadratic_coefficients . get ( key , 0 ) + coef else : var = vars [ 0 ] if var . is_Symbol : linear_coefficients [ var ] = linear_coefficients . get ( var , 0 ) + coef elif var . is_Pow : var , exponent = var . args if exponent != 2 : raise ValueError ( "The expression is not quadratic" ) key = frozenset ( ( var , ) ) quadratic_coefficients [ key ] = quadratic_coefficients . get ( key , 0 ) + coef if quadratic_coefficients : assert all ( var . is_Symbol for var in frozenset . union ( * quadratic_coefficients ) ) if linear_coefficients : assert all ( var . is_Symbol for var in linear_coefficients ) except Exception as e : if expanded : raise e else : return _parse_quadratic_expression ( expression . expand ( ) , expanded = True ) return offset , linear_coefficients , quadratic_coefficients
Parse a quadratic expression. It is assumed that the expression is known to be quadratic or linear.

    The 'expanded' parameter tells whether the expression has already been expanded. If it hasn't the parsing
    might fail and will expand the expression and try again.