Search code examples
symbolic-mathmath.net

Solving linear equation using Math.NET Symbolics


I tried modified the code given here to solve linear equations for values of x. Such as

(3*x+7)/3+(2*x)/9=6/10

by first splitting it into two expressions right and left and then using the "SolveSimpleRoot" and it worked giving the value of x. But if the linear equation was written in the form of

(3+2*x)/(5*x-2)=7, which you can mulitiply throughout by (5*x-2) and indeed is a linear then the code fails at

// extract coefficients, solve known forms of order up to 1
MathNet.Symbolics.Expression[] coeff = MathNet.Symbolics.Polynomial.Coefficients(variable, simple);

with an error of:

The input sequence was empty.Parameter name: source

It also fails to solve if the expression was like (2x+7)/x=2, which still expands out to be linear.

Any idea why?

The code is basically:

    public void solveForX()
    {
        string eqn = "(3*x+7)/3+(2*x)/9=6/10"

        string[] expString = eqn.Split('=');

        var x = MathNet.Symbolics.Expression.Symbol("x");

        MathNet.Symbolics.Expression aleft = MathNet.Symbolics.Infix.ParseOrThrow(expString[0]);
        MathNet.Symbolics.Expression aright = MathNet.Symbolics.Infix.ParseOrThrow(expString[1]);


        ans = SolveSimpleRoot(x, aleft - aright);
        SelectionInsertText(MathNet.Symbolics.Infix.Print(cx));
    }

    private MathNet.Symbolics.Expression SolveSimpleRoot(MathNet.Symbolics.Expression variable, MathNet.Symbolics.Expression expr)
    {
        // try to bring expression into polynomial form
        MathNet.Symbolics.Expression simple = MathNet.Symbolics.Algebraic.Expand(MathNet.Symbolics.Rational.Simplify(variable, expr));

        // extract coefficients, solve known forms of order up to 1
        MathNet.Symbolics.Expression[] coeff = MathNet.Symbolics.Polynomial.Coefficients(variable, simple);
        switch (coeff.Length)
        {
            case 1: return variable;
            case 2: return MathNet.Symbolics.Rational.Simplify(variable, MathNet.Symbolics.Algebraic.Expand(-coeff[0] / coeff[1]));
            default: return MathNet.Symbolics.Expression.Undefined;
        }
    }

Solution

  • You can extend it to support such rational cases by multiplying both sides with the denominator (hence effectively taking the numerator only, with Rational.Numerator):

    private Expr SolveSimpleRoot(Expr variable, Expr expr)
    {
        // try to bring expression into polynomial form
        Expr simple = Algebraic.Expand(Rational.Numerator(Rational.Simplify(variable, expr)));
    
        // extract coefficients, solve known forms of order up to 1
        Expr[] coeff = Polynomial.Coefficients(variable, simple);
        switch (coeff.Length)
        {
            case 1: return Expr.Zero.Equals(coeff[0]) ? variable : Expr.Undefined;
            case 2: return Rational.Simplify(variable, Algebraic.Expand(-coeff[0] / coeff[1]));
            default: return Expr.Undefined;
        }
    }
    

    This way it can also handle (3+2*x)/(5*x-2)=7. I also fixed case 1 to return undefined if the coefficient is not equal to zero in this case, so the solution of the other example, (2*x+7)/x=2, will be undefined as expected.

    Of course this still remains a very simplistic routine which will not be able to handle any higher order problems.