Package jmathexpr.arithmetic.equation

Source Code of jmathexpr.arithmetic.equation.QuadraticEquation$QuadraticFormula

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.equation;

import java.util.ArrayList;
import java.util.List;

import jmathexpr.Expression;
import jmathexpr.Precedence;
import jmathexpr.Variable;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.arithmetic.Numbers;
import jmathexpr.arithmetic.Polynomial;
import static jmathexpr.arithmetic.equation.LinearEquation.isLinear;
import jmathexpr.arithmetic.equation.rule.EquationRule;
import jmathexpr.arithmetic.equation.rule.Fraction;
import jmathexpr.arithmetic.equation.rule.RuleMachine;
import jmathexpr.arithmetic.func.Sqrt;
import jmathexpr.arithmetic.natural.NaturalNumber;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.op.Addition;
import jmathexpr.arithmetic.op.Division;
import jmathexpr.arithmetic.op.Multiplication;
import jmathexpr.arithmetic.op.Negation;
import jmathexpr.arithmetic.op.Subtraction;
import jmathexpr.arithmetic.pattern.PolynomialTermPattern;
import jmathexpr.op.Operation;
import jmathexpr.relation.Equality;
import jmathexpr.set.EmptySet;
import jmathexpr.set.FiniteSet;
import jmathexpr.set.OrderedPair;
import jmathexpr.set.Set;
import jmathexpr.util.context.ExpressionContext;
import jmathexpr.util.pattern.AnyPattern;
import jmathexpr.util.pattern.ExpressionPattern;
import jmathexpr.util.pattern.TerminationPattern;
import jmathexpr.util.rule.SimpleRule;

/**
* Quadratic equation in one unknown.
*
* @author Elemér Furka
*/
public class QuadraticEquation extends Equation {
   
    /**
     * Creates a new quadratic equation specifying the two sides of the equality.
     *
     * @param lhs left hand side of the equality
     * @param rhs right hand side of the equality
     * @param x the unknown in the equation
     */
    public QuadraticEquation(Expression lhs, Expression rhs, Variable x) {
        super(lhs, rhs, x);
    }

    /**
     * Creates a new quadratic equation instance using an existing equality.
     *
     * @param equality the equality to be transformed into an equation
     * @param x the unknown in the equation
     */
    public QuadraticEquation(Equality equality, Variable x) {
        this(equality.lhs(), equality.rhs(), x);
    }

    @Override
    protected QuadraticEquation create(Expression lhs, Expression rhs) {
        return new QuadraticEquation(lhs, rhs, x);
    }
   
    @Override
    public Set solve() throws EquationSolveException {
        rules = new RuleMachine(this);
       
        rules.addRule(new Fraction());
        rules.addRule(new Canonical());
        rules.addRule(new RootFreeA());
        rules.addRule(new PlusMinus());
        rules.addRule(new Factor());
        rules.addRule(new ZeroProduct());
        rules.addRule(new QuadraticFormula());

        Set result = rules.execute();
       
        result = check(result);
       
        return result;
    }
   
    /**
     * Tests whether the given expression could be converted into a quadratic
     * equation in the given indeterminate.
     *
     * @param expr an arbitrary expression
     * @param x the indeterminate
     * @return true iff the given expression is an equation that only contains
     * quadratic, linear or constant terms
     */
    public static boolean isConvertible(Expression expr, Variable x) {
        if (!(expr instanceof Equality)) {
            return false;
        }
       
        Expression lhs = ((Equality) expr).lhs();
        Expression rhs = ((Equality) expr).rhs();
        boolean lhsIsQuadratic = isQuadratic(lhs, x);
        boolean rhsIsQuadratic = isQuadratic(rhs, x);
       
        return (lhsIsQuadratic
                && (rhs.isConstant() || LinearEquation.isLinear(rhs, x) || rhsIsQuadratic))
                || (rhsIsQuadratic
                && (lhs.isConstant() || LinearEquation.isLinear(lhs, x) || lhsIsQuadratic));
    }
   
    private static boolean isQuadratic(Expression expr, Variable x) {
        NaturalNumber two = Naturals.getInstance().create(2);
        ExpressionPattern pattern = new PolynomialTermPattern(x, 2);
       
        if (pattern.matches(expr)) {
            return true;
        } else if (expr instanceof Negation) {
            return isQuadratic(((Negation) expr).getChild(), x);
        } else if (expr instanceof Division) {
            Expression lhs = ((Division) expr).lhs();
            Expression rhs = ((Division) expr).rhs();
           
            return rhs.isConstant() && isQuadratic(lhs, x);
        } else if (expr instanceof Operation
                && expr.getPrecedence() == Precedence.Addition) {
            boolean isQuadratic = false;

            for (Expression t : ((Operation) expr).operands()) {
                if (isQuadratic(t, x)) {
                    isQuadratic = true;
                } else if (!(t.isConstant() || isLinear(t, x))) {
                    return false;
                }
            }

            return isQuadratic;
        } else if (expr instanceof Polynomial) {
            return ((Polynomial) expr).degree().equals(two);
        }

        return false;
    }
   
    private class Canonical extends SimpleRule {

        @Override
        public boolean matches(Expression expr) {
            target = expr;

            return true;
        }

        @Override
        public Expression apply() {
            Polynomial pl = Polynomial.create(((Equality) target).lhs(), x);
            Polynomial pr = Polynomial.create(((Equality) target).rhs(), x);
            Polynomial reduced;

            if (pl.degree().lt(pr.degree())) {
                reduced = pr.subtract(pl);
            } else {
                reduced = pl.subtract(pr);
            }
           
            Expression a = reduced.leadCoefficient();
           
            if (a instanceof ANumber && ((ANumber) a).isNegative()) {
                reduced = reduced.negate();
            }

            return new Equality(reduced, Naturals.zero());
        }
    }
   
    /**
     * sqrt(a) x^2 + bx + c = 0  / * sqrt(a)
     */
    private class RootFreeA extends SimpleRule {
       
        private Polynomial p;
       
        private final AnyPattern arg = new AnyPattern();

        @Override
        public boolean matches(Expression expr) {
            p = (Polynomial) ((Equality) expr).lhs();
           
            Expression a = p.leadCoefficient();

            return new Sqrt(arg).matches(a);
        }

        @Override
        public Expression apply() {
            return new Equality(new Multiplication(p, new Sqrt(arg.hit())), Naturals.zero());
        }
    }
   
    /**
     * ax^2 - c = 0 -> x = +-sqrt(c/a)
     */
    private class PlusMinus extends SimpleRule {
       
        private Polynomial p;

        @Override
        public boolean matches(Expression expr) {
            p = (Polynomial) ((Equality) expr).lhs();
           
            Expression linear = p.getCoefficient(1);

            return linear instanceof ANumber && ((ANumber) linear).isZero();
        }

        @Override
        public Expression apply() {
            Expression a = p.getCoefficient(2);
            Expression c = p.getCoefficient(0);
           
            if (c instanceof ANumber) {
                if (((ANumber) c).isZero()) {
                    Expression x1 = Naturals.zero();
                   
                    ExpressionContext.getInstance().addExpression(new Equality(x, x1));
                   
                    return new FiniteSet(x1);
                } else if (!((ANumber) c).isNegative()) {
                    return new EmptySet();
                }
            }
           
            Expression x1 = new Sqrt(new Division(new Negation(c), a));
            Expression x2 = new Negation(x1);
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 1), x1));
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 2), x2));
           
            x1 = x1.evaluate();
            x2 = x2.evaluate();
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 1), x1));
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 2), x2));
           
            return new FiniteSet(x1, x2);
        }
    }
   
    /**
     * ax^2 + bx = (ax + b)x
     */
    private class Factor extends SimpleRule {
       
        private Polynomial p;

        @Override
        public boolean matches(Expression expr) {
            p = (Polynomial) ((Equality) expr).lhs();
           
            Expression constant = p.getTerm(Naturals.zero());

            return constant instanceof ANumber && ((ANumber) constant).isZero();
        }

        @Override
        public Expression apply() {
            OrderedPair factor = p.euclideanDivision(Polynomial.create(x, x));
           
            return new Equality(new Multiplication(factor.a(), x), Naturals.zero());
        }
    }
   
    /**
     * a * b = 0 -> a = 0 or b = 0
     */
    private class ZeroProduct extends SimpleRule implements EquationRule {
       
        private final TerminationPattern a = new AnyPattern();
        private final TerminationPattern b = new AnyPattern();

        @Override
        public boolean matches(Expression expr) {
            return new Equality(new Multiplication(a, b), Naturals.zero()).matches(expr);
        }

        @Override
        public Expression apply() {
            throw new UnsupportedOperationException("Call convertedEquations() instead!");
        }

        @Override
        public List<Equation> convertedEquations() {
            List<Equation> equations = new ArrayList();
           
            equations.add(new LinearEquation(a.hit(), Naturals.zero(), x));
            equations.add(new LinearEquation(b.hit(), Naturals.zero(), x));
           
            return equations;
        }
    }
   
    /**
     * x1,2 = (-b +- sqrt(b^2 - 4ac))/2a
     */
    private class QuadraticFormula extends SimpleRule {
       
        private Polynomial p;

        @Override
        public boolean matches(Expression expr) {
            p = (Polynomial) ((Equality) expr).lhs();

            return true;
        }

        @Override
        public Expression apply() {
            Expression dd = p.discriminant();
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.constant("D"), dd));
           
            dd = dd.evaluate();
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.constant("D"), dd));
           
            Expression a = p.getCoefficient(2);
            Expression b = p.getCoefficient(1);
            Expression c = p.getCoefficient(0);
            NaturalNumber two = Naturals.getInstance().create(2);
           
            if (dd instanceof ANumber) {
                ANumber d = (ANumber) dd;
               
                if (d.isNegative()) {
                    return new EmptySet();
                } else if (d.isZero()) {
                    return new FiniteSet(new Division(new Negation(b),
                            new Multiplication(two, a)).evaluate());
                }
            }
           
            Expression sd = new Sqrt(dd);
            Expression x1 = new Division(
                    new Addition(new Negation(b), sd),
                    new Multiplication(two, a));
            Expression x2 = new Division(
                    new Subtraction(new Negation(b), sd),
                    new Multiplication(two, a));
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 1), x1));
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 2), x2));
           
            x1 = x1.evaluate();
            x2 = x2.evaluate();
           
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 1), x1));
            ExpressionContext.getInstance().addExpression(new Equality(Numbers.variable("x", 2), x2));
           
            return new FiniteSet(x1, x2);
        }
    }
}
TOP

Related Classes of jmathexpr.arithmetic.equation.QuadraticEquation$QuadraticFormula

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.