Package jmathexpr.arithmetic.equation

Source Code of jmathexpr.arithmetic.equation.AbsoluteValueEquation$Isolate$Addition

/*
* 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.Variable;
import jmathexpr.arithmetic.equation.rule.EquationRule;
import jmathexpr.arithmetic.equation.rule.RuleMachine;
import jmathexpr.arithmetic.func.Abs;
import jmathexpr.arithmetic.op.Negation;
import jmathexpr.arithmetic.op.Subtraction;
import jmathexpr.arithmetic.op.Sum;
import jmathexpr.relation.Equality;
import jmathexpr.set.Set;
import jmathexpr.util.pattern.AnyPattern;
import jmathexpr.util.pattern.ExpressionPattern;
import jmathexpr.util.pattern.FunctionPattern;
import jmathexpr.util.pattern.NotPattern;
import jmathexpr.util.pattern.TerminationPattern;
import jmathexpr.util.rule.CompositeRule;
import jmathexpr.util.rule.SubRule;

/**
* Absolute value equation in one unknown.
*
* @author Elemér Furka
*/
public class AbsoluteValueEquation extends Equation {
   
    /**
     * Creates a new absolute value 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 AbsoluteValueEquation(Expression lhs, Expression rhs, Variable x) {
        super(lhs, rhs, x);
    }

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

    @Override
    protected AbsoluteValueEquation create(Expression lhs, Expression rhs) {
        return new AbsoluteValueEquation(lhs, rhs, x);
    }
   
    @Override
    public Set solve() throws EquationSolveException {
        rules = new RuleMachine(this);
       
        rules.addRule(new Isolate());
        rules.addRule(new IterativeRule());

        Set result = rules.execute();
       
        result = check(result);
                       
        return result;
    }
   
    /**
     * Tests if the given equality is an absolute value equation.
     *
     * @param equality the equality to test
     * @param x the unknown in the equation
     * @return true if the equality is an absolute value equation
     */
    public static boolean isA(Equality equality, Variable x) {
        return equality.contains(new Abs(new FunctionPattern(x)));
    }
   
    /**
     * Isolates the absolute value expression if possible.
     */
    private class Isolate extends CompositeRule {

        private final TerminationPattern a = new AnyPattern();
       
        private final ExpressionPattern b = new NotPattern(new Abs(new FunctionPattern(x)));
        private final ExpressionPattern s = new FunctionPattern(
                new Abs(new FunctionPattern(x)));
       
        private Isolate() {
            super(false);
        }
        @Override
        public boolean matches(Expression expr) {
            target = expr;
           
            if ((rule = new Addition()).matches(expr)) return true;
            if ((rule = new Difference()).matches(expr)) return true;
           
            return false;
        }      

        /**
         * abs(f(x)) + a = b -> abs(f(x)) = b - a
         */
        private class Addition extends SubRule {

            @Override
            public boolean matches(Expression expr) {
                ExpressionPattern sum = new Sum(s, a);
               
                return new Equality(sum, b).matches(expr);
            }

            @Override
            public Expression apply() {
                Equality eq = (Equality) target;
                Expression lhs = Sum.subtract(eq.lhs(), a.hit());
                Expression rhs = Sum.subtract(eq.rhs(), a.hit());

                return new Equality(lhs, rhs);
            }
        }

        /**
         * abs(f(x)) - a = b -> abs(f(x)) = b + a
         */
        private class Difference extends SubRule {

            @Override
            public boolean matches(Expression expr) {
                ExpressionPattern diff = new Subtraction(s, a);
               
                return new Equality(diff, b).matches(expr);
            }

            @Override
            public Expression apply() {
                Equality eq = (Equality) target;
                Expression lhs = Sum.add(eq.lhs(), a.hit());
                Expression rhs = Sum.add(eq.rhs(), a.hit());

                return new Equality(lhs, rhs);
            }
        }
    }
   
    /**
     * This rule transforms the current equation into a pair of linear equations.
     * |x| = x if x >= 0 and |x| = -x if x < 0.
     */
    public class IterativeRule extends CompositeRule implements EquationRule {
       
        private final FunctionPattern f = new FunctionPattern(x);
       
        private final RuleVariations variations = new RuleVariations();
       
        private final List<Equation> equations = new ArrayList();
       
        private int run = 0;
       
        private IterativeRule() {
            super(true);
           
            // ruleList initialization (this could be done automatically using reflection...)
            variations.addRule(new NonNegative());
            variations.addRule(new Negative());
        }
       
        public boolean hasNext() {
            boolean hasNext = variations.hasNextVariation();
           
            run++;
           
            if (hasNext) {
                rule = variations.nextRule();
            }
           
            return hasNext;
        }
       
        public void advance() {
            if (run == 1) {
                variations.initialize();
            }
           
            equations.add(Equation.convert((Equality) target, x));
        }
       
        @Override
        public boolean matches(Expression expr) {
            boolean matches;
           
            matches = rule.matches(expr);
           
            if (!variations.isInitialized()) {
                if (matches) {
                    variations.addCase();
                }               
            }
           
            return matches;
        }

        @Override
        public List<Equation> convertedEquations() {
            return equations;
        }

        @Override
        public Expression subapply() {
            Expression applied = rule.apply();
           
            if (variations.hasNextRule()) {
                rule = variations.nextRule();
            }
           
            return applied;
        }

        /**
         * |x| = x if x >= 0
         */
        private class NonNegative extends SubRule {

            @Override
            public boolean matches(Expression expr) {
                return new Abs(f).matches(expr);
            }

            @Override
            public Expression apply() {
                return f.hit();
            }
        }

        /**
         * |x| = -x if x < 0
         */
        private class Negative extends SubRule {

            @Override
            public boolean matches(Expression expr) {
                return new Abs(f).matches(expr);
            }

            @Override
            public Expression apply() {
                return new Negation(f.hit());
            }
        }
       
        private class RuleVariations {
           
            private final List<SubRule> rules = new ArrayList();
           
            /**
             * E.g. (0 0 0), (1 0 0), (2 0 0), (0 1 0), ..., (2 2 2). In this case
             * rules.size() == 3 and the expression has three matching subexpressions.
             */
            private final List<Integer> variations = new ArrayList();
           
            private boolean initialized = false;
           
            private int idx = 0;
           
            private void addRule(SubRule rule) {
                rules.add(rule);
            }
           
            private void addCase() {
                variations.add(0);
            }
           
            private void initialize() {
                initialized = true;
            }
           
            private boolean isInitialized() {
                return initialized;
            }
           
            private boolean hasNextVariation() {
                if (!initialized) {
                    return true;
                } else {
                    return increment();
                }
            }
           
            private boolean increment() {
                int p, r = rules.size() - 1;
               
                idx = 0;
               
                for (int i = 0; i < variations.size(); i++) {
                    p = variations.get(i);
                   
                    if (p < r) {
                        variations.set(i, ++p);
                       
                        if (i > 0) {
                            variations.set(i - 1, 0);
                        }
                       
                        return true;
                    }
                }   
               
                return false;
            }
           
            public boolean hasNextRule() {
                return idx < variations.size();
            }
           
            private SubRule nextRule() {
                if (!initialized) {
                    return rules.get(0);
                } else {
                    return rules.get(variations.get(idx++));
                }
            }
           
            @Override
            public String toString() {
                return variations.toString();
            }
        }
    }
}
TOP

Related Classes of jmathexpr.arithmetic.equation.AbsoluteValueEquation$Isolate$Addition

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.