Package jmathexpr.arithmetic.equation.rule

Source Code of jmathexpr.arithmetic.equation.rule.RuleMachine

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

package jmathexpr.arithmetic.equation.rule;

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

import jmathexpr.Expression;
import jmathexpr.arithmetic.equation.AbsoluteValueEquation;
import jmathexpr.arithmetic.equation.Equation;
import jmathexpr.arithmetic.equation.EquationSolveException;
import jmathexpr.relation.Equality;
import jmathexpr.set.EmptySet;
import jmathexpr.set.Set;
import jmathexpr.util.context.ExpressionContext;
import jmathexpr.util.context.Statement;
import jmathexpr.util.context.Statement.Command;
import jmathexpr.util.rule.Rule;

/**
* A rule machine can be filled in with rules and the machine executes these rules
* until the terminate rule provides the solution.
*
* @author Elemér Furka
*/
public class RuleMachine {
   
    private final Equation equation;
   
    private final List<Rule> rules = new ArrayList();
   
    private final List<Rule> terminationRules = new ArrayList();
   
    private Rule terminationRule;
   
    private Equality actual;
   
    private Rule rule, lastRule;

    /**
     * Creates a rule machine that can solve the given equation.
     *
     * @param equation the equation to be solved
     */
    public RuleMachine(Equation equation) {
        this.equation = equation;
       
        terminationRules.add(new LinearTerminationRule(equation.variable()));
    }
   
    /**
     * Adds an applicable rule to this machine.
     *
     * @param rule an arbitrary rule
     */
    public void addRule(Rule rule) {
        rules.add(rule);
    }
   
    /**
     * Adds a termination rule to this machine.
     *
     * @param rule an arbitrary rule that returns a set
     */
    public void addTerminationRule(Rule rule) {
        terminationRules.add(rule);
    }
   
    /**
     * Executes the rules to solve this machine's equation.
     *
     * @return a set of equation roots
     * @throws jmathexpr.number.equation.EquationSolveException iff no more matching
     * rule can be found while solving the equation
     */
    public Set execute() throws EquationSolveException {
        Expression result;
       
        actual = equation;
        addToContext(actual);
       
        actual = new Equality(actual.lhs().evaluate(), actual.rhs().evaluate()); // simplify both sides
        System.out.printf("    simplified: %s%n", actual);
        addToContext(actual);
       
        rule = rules.get(0);
       
        while (!terminated()) {
            if (rule == null) {
                throw new EquationSolveException("No more matching rule");
            }
            System.out.printf("    rule: %s%n", rule);
            if (isApplicable()) {
                if (rule instanceof EquationRule) {
                    return fork(((EquationRule) rule).convertedEquations());
                }
               
                result = rule.apply();
               
                if (result instanceof Equality) {
                    actual = (Equality) result;
                } else if (result instanceof Set) {
                    System.out.printf("      root(s): %s%n", result);
                    return (Set) result;
                }
               
                if (actual instanceof Equation && !actual.getClass().equals(equation.getClass())) {
                    return new RuleMachine((Equation) actual).execute();
                } else {
                    System.out.printf("      applied: %s%n", actual);
                    addToContext(actual);

                    actual = new Equality(actual.lhs().evaluate(), actual.rhs().evaluate());
                    System.out.printf("      eval'd:  %s%n", actual);
                    addToContext(actual);

                    rule = nextRule(true);
                }
            } else {
                rule = nextRule(false);
            }
        }
       
        return (Set) terminationRule.apply();
    }
   
    private boolean isApplicable() {
        if (rule instanceof AbsoluteValueEquation.IterativeRule) {
            AbsoluteValueEquation.IterativeRule multirule = (AbsoluteValueEquation.IterativeRule) rule;
            boolean isApplicable = false;
           
            while (multirule.hasNext()) {
                isApplicable = actual.isApplicable(multirule);
               
                if (isApplicable) {
                    multirule.advance();
                }
            }
           
            return isApplicable;
        } else {
            return actual.isApplicable(rule);
        }
    }
   
    private Set fork(List<Equation> equations) throws EquationSolveException {
        List<Set> results = new ArrayList();
       
        for (Equation e : equations) {
            System.out.printf("  solving %s: %s%n", e.getClass().getSimpleName(), e);
            results.add(e.solve());
        }
       
        Set result = new EmptySet();
       
        for (Set s : results) {
            result = result.union(s);
        }
       
        return result;
    }
   
    private Rule nextRule(boolean justApplied) {
        Rule next;
       
        if (justApplied) {
            lastRule = rule;
        }

        int lastRuleIndex = rules.indexOf(rule);

        if (++lastRuleIndex < rules.size()) {
            next = rules.get(lastRuleIndex);
        } else if (lastRule == null) { // no more rule and no rule matched
            return null;
        } else {
            next = rules.get(0);
        }
       
        next.reset();

        if (rule.equals(lastRule) && !justApplied) {
            return null;
        } else {
            return next;
        }
    }
   
    private boolean terminated() {
        for (Rule r : terminationRules) {
            if (r.matches(actual)) {
                terminationRule = r;
               
                return true;
            }
        }
       
        return false;
    }
   
    private void addToContext(Equality equality) {
        ExpressionContext.getInstance().addStatement(
                new Statement(Command.Expression, equality));
    }
}
TOP

Related Classes of jmathexpr.arithmetic.equation.rule.RuleMachine

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.