package org.matheclipse.core.patternmatching;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IEvaluationEngine;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IPattern;
import org.matheclipse.core.interfaces.ISymbol;

import com.google.common.collect.ArrayListMultimap;

/**
 * The pattern matching rules associated with a symbol.
 */
public class DownRulesData implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6438521796226265180L;

	// private transient Map> fEqualRules;
	private transient Map fEqualDownRules;
	private transient ArrayListMultimap fSimplePatternDownRules;
	private transient List fPatternDownRules;

	public DownRulesData() {
		this.fEqualDownRules = null;
		this.fSimplePatternDownRules = null;
		this.fPatternDownRules = null;
	}

	public void clear() {
		fEqualDownRules = null;
		fSimplePatternDownRules = null;
		fPatternDownRules = null;
	}

	public IExpr evalDownRule(final IExpr expression) {
		return evalDownRule(EvalEngine.get(), expression);
	}

	public IExpr evalDownRule(final IEvaluationEngine ee, final IExpr expression) {
		PatternMatcherEquals res;
		boolean showSteps = false;
		if (Config.SHOW_PATTERN_EVAL_STEPS) {
			showSteps = Config.SHOW_PATTERN_SYMBOL_STEPS.contains(expression.topHead());
			if (showSteps) {
				System.out.println("EVAL_EXPR: " + expression.toString());
			}
		}
		if (fEqualDownRules != null) {
			if (showSteps) {
				System.out.println("  EQUAL RULES");
			}
			res = fEqualDownRules.get(expression);
			if (res != null) {
				if (showSteps) {
					System.out.println("\n  >>>> " + res.getRHS().toString());
				}
				return res.getRHS();
			}
		}

		try {
			IExpr result;
			IPatternMatcher pmEvaluator;
			if ((fSimplePatternDownRules != null) && (expression instanceof IAST)) {
				final Integer hash = Integer.valueOf(((IAST) expression).patternHashCode());
				final List list = fSimplePatternDownRules.get(hash);
				if (list != null) {
					for (int i = 0; i < list.size(); i++) {
						pmEvaluator = (IPatternMatcher) list.get(i).clone();
						if (showSteps) {
							IExpr rhs = pmEvaluator.getRHS();
							if (rhs==null){
								rhs = F.Null;
							}
							System.out.println("  SIMPLE:  " + pmEvaluator.getLHS().toString() + "  :=  "+ rhs.toString());
						}
						result = pmEvaluator.eval(expression);
						if (result != null) {
							if (showSteps) {
								System.out.println("\n  >>>> " + result.toString());
							}
							return result;
						}
					}
				}
			}

			if (fPatternDownRules != null) {
				for (int i = 0; i < fPatternDownRules.size(); i++) {
					pmEvaluator = (IPatternMatcher) fPatternDownRules.get(i).clone();
					if (showSteps) {
						IExpr rhs = pmEvaluator.getRHS();
						if (rhs==null){
							rhs = F.Null;
						}
						System.out.println("  COMPLEX: " + pmEvaluator.getLHS().toString() + "  :=  "+ rhs.toString());
					}
					result = pmEvaluator.eval(expression);
					if (result != null) {
						if (showSteps) {
							System.out.println("\n  >>>> " + result.toString());
						}
						return result;
					}
				}
			}
		} catch (CloneNotSupportedException cnse) {
			cnse.printStackTrace();
		}
		return null;
	}

	public IPatternMatcher putDownRule(ISymbol setSymbol, final boolean equalRule, final IExpr leftHandSide,
			final IExpr rightHandSide, final int priority) {
		if (equalRule) {
			fEqualDownRules = getEqualDownRules();
			// fEqualRules.put(leftHandSide, new Pair(setSymbol,
			// rightHandSide));
			PatternMatcherEquals pmEquals = new PatternMatcherEquals(setSymbol, leftHandSide, rightHandSide);
			fEqualDownRules.put(leftHandSide, pmEquals);
			return pmEquals;
		}

		final PatternMatcherAndEvaluator pmEvaluator = new PatternMatcherAndEvaluator(setSymbol, leftHandSide, rightHandSide);

		if (pmEvaluator.isRuleWithoutPatterns()) {
			fEqualDownRules = getEqualDownRules();
			// fEqualRules.put(leftHandSide, new Pair(setSymbol,
			// rightHandSide));
			PatternMatcherEquals pmEquals = new PatternMatcherEquals(setSymbol, leftHandSide, rightHandSide);
			fEqualDownRules.put(leftHandSide, pmEquals);
			return pmEquals;
		}

		// pmEvaluator.setCondition(condition);
		if (!isComplicatedPatternRule(leftHandSide)) {

			fSimplePatternDownRules = getSimplePatternDownRules();
			return addSimplePatternDownRule(leftHandSide, pmEvaluator);

		} else {

			fPatternDownRules = getPatternDownRules();
			if (F.isSystemInitialized) {
				for (int i = 0; i < fPatternDownRules.size(); i++) {
					if (pmEvaluator.equals(fPatternDownRules.get(i))) {
						fPatternDownRules.set(i, pmEvaluator);

						return pmEvaluator;
					}
				}
			}
			fPatternDownRules.add(pmEvaluator);
			return pmEvaluator;

		}

	}

	/**
	 * Create a pattern hash value for the left-hand-side expression and insert the left-hand-side as a simple pattern rule to the
	 * fSimplePatternRules.
	 * 
	 * @param leftHandSide
	 * @param pmEvaluator
	 * @return
	 */
	private PatternMatcher addSimplePatternDownRule(final IExpr leftHandSide, final PatternMatcher pmEvaluator) {
		final Integer hash = Integer.valueOf(((IAST) leftHandSide).patternHashCode());
		if (F.isSystemInitialized && fSimplePatternDownRules.containsEntry(hash, pmEvaluator)) {
			fSimplePatternDownRules.remove(hash, pmEvaluator);
		}
		fSimplePatternDownRules.put(hash, pmEvaluator);
		return pmEvaluator;
	}

	/** {@inheritDoc} */
	public PatternMatcher putDownRule(final PatternMatcherAndInvoker pmEvaluator) {
		final IExpr leftHandSide = pmEvaluator.getLHS();
		if (!isComplicatedPatternRule(leftHandSide)) {

			fSimplePatternDownRules = getSimplePatternDownRules();
			return addSimplePatternDownRule(leftHandSide, pmEvaluator);

		} else {

			fPatternDownRules = getPatternDownRules();
			for (int i = 0; i < fPatternDownRules.size(); i++) {
				if (pmEvaluator.equals(fPatternDownRules.get(i))) {
					fPatternDownRules.set(i, pmEvaluator);
					return pmEvaluator;
				}
			}
			fPatternDownRules.add(pmEvaluator);
			return pmEvaluator;
		}
	}

	private boolean isComplicatedPatternRule(final IExpr lhsExpr) {
		if (lhsExpr.isAST()) {
			final IAST lhsAST = ((IAST) lhsExpr);
			if (lhsAST.size() > 1) {
				final int attr = lhsAST.topHead().getAttributes();
				if ((ISymbol.ORDERLESS & attr) == ISymbol.ORDERLESS) {
					return true;
				}
				if (lhsAST.get(1).isAST()) {
					IAST arg1 = (IAST) lhsAST.get(1);
					if (arg1.isCondition()) {
						return true;
					}
					// the left hand side is associated with the first argument
					// see if the first argument is complicated
					for (int i = 2; i < arg1.size(); i++) {
						if (arg1.get(i).isPattern() && ((IPattern) arg1.get(i)).isDefault()) {
							return true;
						}
					}
				} else if (lhsAST.get(1).isPattern()) {
					return true;
				} else if (lhsAST.get(1).isPatternSequence()) {
					return true;
				}
				for (int i = 2; i < lhsAST.size(); i++) {
					if (lhsAST.get(i).isPattern() && ((IPattern) lhsAST.get(i)).isDefault()) {
						return true;
					}
				}
			}
		} else if (lhsExpr.isPattern()) {
			return true;
		} else if (lhsExpr.isPatternSequence()) {
			return true;
		}
		return false;
	}

	/**
	 * @return Returns the equalRules.
	 */
	public Map getEqualDownRules() {
		if (fEqualDownRules == null) {
			fEqualDownRules = new HashMap();
		}
		return fEqualDownRules;
	}

	private List getPatternDownRules() {
		if (fPatternDownRules == null) {
			fPatternDownRules = new ArrayList();
		}
		return fPatternDownRules;
	}

	private ArrayListMultimap getSimplePatternDownRules() {
		if (fSimplePatternDownRules == null) {
			fSimplePatternDownRules = ArrayListMultimap.create();
		}
		return fSimplePatternDownRules;
	}

	public List definition() {
		ArrayList definitionList = new ArrayList();
		Iterator iter;
		IExpr key;
		PatternMatcherEquals pme;
		IExpr condition;
		ISymbol setSymbol;
		IAST ast;
		PatternMatcherAndEvaluator pmEvaluator;
		if (fEqualDownRules != null && fEqualDownRules.size() > 0) {
			iter = fEqualDownRules.keySet().iterator();
			while (iter.hasNext()) {
				key = iter.next();
				pme = fEqualDownRules.get(key);
				setSymbol = pme.getSetSymbol();
				ast = F.ast(setSymbol);
				ast.add(key);
				ast.add(pme.getRHS());
				definitionList.add(ast);
			}
		}
		if (fSimplePatternDownRules != null && fSimplePatternDownRules.size() > 0) {
			Iterator listIter = fSimplePatternDownRules.values().iterator();
			IPatternMatcher elem;
			while (listIter.hasNext()) {
				elem = listIter.next();
				if (elem instanceof PatternMatcherAndEvaluator) {
					pmEvaluator = (PatternMatcherAndEvaluator) elem;
					setSymbol = pmEvaluator.getSetSymbol();

					ast = F.ast(setSymbol);
					ast.add(pmEvaluator.getLHS());
					condition = pmEvaluator.getCondition();
					if (condition != null) {
						ast.add(F.Condition(pmEvaluator.getRHS(), condition));
					} else {
						ast.add(pmEvaluator.getRHS());
					}
					definitionList.add(ast);
				}
				// if (elem instanceof PatternMatcherAndInvoker) {
				// don't show internal methods associated with a pattern
				// }
			}
		}
		if (fPatternDownRules != null && fPatternDownRules.size() > 0) {
			for (int i = 0; i < fPatternDownRules.size(); i++) {
				if (fPatternDownRules.get(i) instanceof PatternMatcherAndEvaluator) {
					pmEvaluator = (PatternMatcherAndEvaluator) fPatternDownRules.get(i);
					setSymbol = pmEvaluator.getSetSymbol();
					ast = F.ast(setSymbol);
					ast.add(pmEvaluator.getLHS());
					condition = pmEvaluator.getCondition();
					if (condition != null) {
						ast.add(F.Condition(pmEvaluator.getRHS(), condition));
					} else {
						ast.add(pmEvaluator.getRHS());
					}
					definitionList.add(ast);
				}
			}

		}

		return definitionList;
	}

	public void readSymbol(java.io.ObjectInputStream stream) throws IOException {

		String astString;
		IExpr key;
		IExpr value;
		EvalEngine engine = new EvalEngine(true, true);
		ISymbol setSymbol;
		int len = stream.read();
		if (len > 0) {
			// fEqualRules = new HashMap>();
			// for (int i = 0; i < len; i++) {
			// astString = stream.readUTF();
			// setSymbol = F.$s(astString);
			//
			// astString = stream.readUTF();
			// key = engine.parse(astString);
			// astString = stream.readUTF();
			// value = engine.parse(astString);
			// fEqualRules.put(key, new Pair(setSymbol, value));
			// }
			fEqualDownRules = new HashMap();
			for (int i = 0; i < len; i++) {
				astString = stream.readUTF();
				setSymbol = F.$s(astString);

				astString = stream.readUTF();
				key = engine.parse(astString);
				astString = stream.readUTF();
				value = engine.parse(astString);
				fEqualDownRules.put(key, new PatternMatcherEquals(setSymbol, key, value));
			}
		}

		len = stream.read();
		IExpr lhs;
		IExpr rhs;
		IExpr condition;
		int listLength;
		int condLength;
		PatternMatcherAndEvaluator pmEvaluator;
		if (len > 0) {
			fSimplePatternDownRules = ArrayListMultimap.create();
			for (int i = 0; i < len; i++) {
				astString = stream.readUTF();
				setSymbol = F.$s(astString);

				astString = stream.readUTF();
				lhs = engine.parse(astString);
				astString = stream.readUTF();
				rhs = engine.parse(astString);
				pmEvaluator = new PatternMatcherAndEvaluator(setSymbol, lhs, rhs);

				condLength = stream.read();
				if (condLength == 0) {
					condition = null;
				} else {
					astString = stream.readUTF();
					condition = engine.parse(astString);
					pmEvaluator.setCondition(condition);
				}
				addSimplePatternDownRule(lhs, pmEvaluator);
			}

		}

		len = stream.read();
		if (len > 0) {
			fPatternDownRules = new ArrayList();
			listLength = stream.read();
			for (int j = 0; j < listLength; j++) {
				astString = stream.readUTF();
				setSymbol = F.$s(astString);

				astString = stream.readUTF();
				lhs = engine.parse(astString);
				astString = stream.readUTF();
				rhs = engine.parse(astString);
				pmEvaluator = new PatternMatcherAndEvaluator(setSymbol, lhs, rhs);

				condLength = stream.read();
				if (condLength == 0) {
					condition = null;
				} else {
					astString = stream.readUTF();
					condition = engine.parse(astString);
					pmEvaluator.setCondition(condition);
				}
				addSimplePatternDownRule(lhs, pmEvaluator);
			}
		}
	}

	public void writeSymbol(java.io.ObjectOutputStream stream) throws java.io.IOException {
		Iterator iter;
		IExpr key;
		IExpr condition;
		// Pair pair;
		// ISymbol setSymbol;
		// PatternMatcherAndEvaluator pmEvaluator;
		// if (fEqualRules == null || fEqualRules.size() == 0) {
		// stream.write(0);
		// } else {
		// stream.write(fEqualRules.size());
		// iter = fEqualRules.keySet().iterator();
		// while (iter.hasNext()) {
		// key = iter.next();
		// pair = fEqualRules.get(key);
		// stream.writeUTF(pair.getFirst().toString());
		// stream.writeUTF(key.fullFormString());
		// stream.writeUTF(pair.getSecond().fullFormString());
		// }
		// }
		PatternMatcherEquals pme;
		ISymbol setSymbol;
		PatternMatcherAndEvaluator pmEvaluator;
		if (fEqualDownRules == null || fEqualDownRules.size() == 0) {
			stream.write(0);
		} else {
			stream.write(fEqualDownRules.size());
			iter = fEqualDownRules.keySet().iterator();
			while (iter.hasNext()) {
				key = iter.next();
				pme = fEqualDownRules.get(key);
				stream.writeUTF(pme.getSetSymbol().toString());
				stream.writeUTF(key.fullFormString());
				stream.writeUTF(pme.getRHS().fullFormString());
			}
		}

		if (fSimplePatternDownRules == null || fSimplePatternDownRules.size() == 0) {
			stream.write(0);
		} else {
			stream.write(fSimplePatternDownRules.size());
			Iterator listIter = fSimplePatternDownRules.values().iterator();
			IPatternMatcher elem;
			while (listIter.hasNext()) {
				elem = listIter.next();
				pmEvaluator = (PatternMatcherAndEvaluator) elem;
				setSymbol = pmEvaluator.getSetSymbol();
				stream.writeUTF(setSymbol.toString());
				stream.writeUTF(pmEvaluator.getLHS().fullFormString());
				stream.writeUTF(pmEvaluator.getRHS().fullFormString());
				condition = pmEvaluator.getCondition();
				if (condition == null) {
					stream.write(0);
				} else {
					stream.write(1);
					stream.writeUTF(condition.fullFormString());
				}
			}
		}
		if (fPatternDownRules == null || fPatternDownRules.size() == 0) {
			stream.write(0);
		} else {
			stream.write(fPatternDownRules.size());

			for (int i = 0; i < fPatternDownRules.size(); i++) {
				pmEvaluator = (PatternMatcherAndEvaluator) fPatternDownRules.get(i);
				setSymbol = pmEvaluator.getSetSymbol();
				stream.writeUTF(setSymbol.toString());
				stream.writeUTF(pmEvaluator.getLHS().fullFormString());
				stream.writeUTF(pmEvaluator.getRHS().fullFormString());
				condition = pmEvaluator.getCondition();
				if (condition == null) {
					stream.write(0);
				} else {
					stream.write(1);
					stream.writeUTF(condition.fullFormString());
				}
			}

		}
	}
}
 

Ads help maintain this website.