package org.matheclipse.core.generic;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.Serializable;

import javax.annotation.Nullable;

import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IEvaluator;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IPattern;
import org.matheclipse.core.interfaces.ISymbol;

import com.google.common.base.Predicate;

public class Predicates {
	private Predicates() {

	}

	private static class InASTPredicate implements Predicate, Serializable {
		private final IAST target;

		private InASTPredicate(IAST target) {
			this.target = checkNotNull(target);
		}

		public boolean apply(IExpr t) {
			for (IExpr expr : target) {
				if (expr.equals(t)) {
					return true;
				}
			}
			return false;
		}

		@Override
		public boolean equals(@Nullable Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj instanceof InASTPredicate) {
				InASTPredicate that = (InASTPredicate) obj;
				return target.equals(that.target);
			}
			return false;
		}

		@Override
		public int hashCode() {
			return target.hashCode();
		}

		@Override
		public String toString() {
			return "In(" + target + ")";
		}

		private static final long serialVersionUID = 0;
	}

	/**
	 * Check if the evaluation of an unary AST object gives True.
	 * 
	 */
	private static class IsUnaryTrue implements Predicate {
		protected final EvalEngine fEngine;

		protected final IAST fAST;

		/**
		 * Define an unary AST with the header head. The apply() method evaluates the cretaed AST with the
		 * given expression and checks if the result equals True.
		 * 
		 * @param head
		 *            the AST's head expresion
		 */
		public IsUnaryTrue(final IExpr head) {
			this(EvalEngine.get(), head);
		}

		/**
		 * Define an unary AST with the header head.
		 * 
		 * @param engine
		 *            the evaluation engine
		 * @param head
		 *            the AST's head expresion
		 */
		public IsUnaryTrue(final EvalEngine engine, final IExpr head) {
			fEngine = EvalEngine.get();
			fAST = F.ast(head, 1, false);
		}

		/**
		 * Check if the evaluation of an unary AST object gives True, by setting the first argument of the AST to
		 * arg.
		 * 
		 */
		public boolean apply(final IExpr arg) {
			final IAST ast = fAST.clone();
			ast.add(arg);
			return fEngine.evalTrue(ast);
		}

	}

	/**
	 * Check if the evaluation of an unary AST object gives True.
	 * 
	 * @param head
	 * @return
	 */
	public static Predicate isTrue(IExpr head) {
		if (head.isSymbol()) {
			IEvaluator eval = ((ISymbol) head).getEvaluator();
			if (eval != null && (eval instanceof Predicate)) {
				return (Predicate) eval;
			}
		}
		return new IsUnaryTrue(head);
	}

	/**
	 * Check if the evaluation of an unary AST object gives True.
	 * 
	 * @param engine
	 * @param head
	 * @return
	 */
	public static Predicate isTrue(final EvalEngine engine, final IExpr head) {
		if (head.isSymbol()) {
			IEvaluator eval = ((ISymbol) head).getEvaluator();
			if (eval != null && (eval instanceof Predicate)) {
				return (Predicate) eval;
			}
		}
		return new IsUnaryTrue(engine, head);
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if the object reference being tested is one of the arguments of the given
	 * ast. It does not defensively copy the collection passed in, so future changes to it will alter the behavior of
	 * the predicate.
	 * 
	 * @param ast
	 *            the AST those arguments may contain the function input
	 */
	public static Predicate in(IAST ast) {
		return new InASTPredicate(ast);
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if the object reference being tested is one of the arguments of the given
	 * ast. It does not defensively copy the collection passed in, so future changes to it will alter the behavior of
	 * the predicate.
	 * 
	 * @param expr
	 *            the expr which may macth the function input
	 */
	public static Predicate in(IExpr expr) {
		return new InASTPredicate(F.List(expr));
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if the input is an instanceof IPattern.
	 * 
	 * @return
	 */
	public static Predicate isPattern() {
		return new Predicate() {
			@Override
			public boolean apply(IExpr input) {
				return (input instanceof IPattern);
			}
		};
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if input.isNumber() gives {@code true}.
	 * 
	 * @return
	 */
	public static Predicate isNumber() {
		return new Predicate() {
			@Override
			public boolean apply(IExpr input) {
				return input.isNumber();
			}
		};
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if input.isNumeric() gives {@code true}.
	 * 
	 * @return
	 */
	public static Predicate isNumeric() {
		return new Predicate() {
			@Override
			public boolean apply(IExpr input) {
				return input.isNumeric();
			}
		};
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if input.isSignedNumber() gives {@code true}.
	 * 
	 * @return
	 */
	public static Predicate isSignedNumber() {
		return new Predicate() {
			@Override
			public boolean apply(IExpr input) {
				return input.isSignedNumber();
			}
		};
	}

	/**
	 * Returns a predicate that evaluates to {@code true} if the input is an AST list, which contains one of the given
	 * header elements at index position 0.
	 * 
	 */
	public static Predicate isAST(final ISymbol[] heads) {
		return new Predicate() {
			@Override
			public boolean apply(IExpr input) {
				for (int i = 0; i < heads.length; i++) {
					if (input.isAST(heads[i])) {
						return true;
					}
				}
				return false;
			}
		};
	}
}

 

Ads help maintain this website.