package org.matheclipse.core.expression;

import java.util.List;
import java.util.Map;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.IterationLimitExceeded;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IComplex;
import org.matheclipse.core.interfaces.IComplexNum;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IFraction;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.INum;
import org.matheclipse.core.interfaces.INumber;
import org.matheclipse.core.interfaces.IRational;
import org.matheclipse.core.interfaces.ISignedNumber;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.patternmatching.IPatternMatcher;
import org.matheclipse.core.patternmatching.PatternMatcher;
import org.matheclipse.core.visit.VisitorReplaceAll;
import org.matheclipse.core.visit.VisitorReplacePart;
import org.matheclipse.core.visit.VisitorReplaceSlots;

import com.google.common.base.Function;
import com.google.common.base.Predicate;

import edu.jas.structure.ElemFactory;

/**
 * Abstract base class for atomic expression objects.
 * 
 */
@SuppressWarnings("serial")
public abstract class ExprImpl implements IExpr {

	public IExpr opposite() {
		return F.eval(F.Times(F.CN1, this));
	}

	/**
	 * Additional negative method, which works like opposite to fulfill groovy's method signature
	 * 
	 * @return
	 */
	@Override
	public final IExpr negative() {
		return opposite();
	}

	@Override
	public IExpr minus(final IExpr that) {
		if (this.isNumber() && that.isNumber()) {
			return F.eval(F.Plus(this, ((INumber) that).opposite()));
		}
		if (that.isNumber()) {
			return F.eval(F.Plus(this, ((INumber) that).opposite()));
		}
		return F.eval(F.Plus(this, F.Times(F.CN1, that)));
	}

	@Override
	public IExpr plus(final IExpr that) {
		return F.eval(F.Plus(this, that));
	}

	@Override
	public IExpr inverse() {
		return F.eval(F.Power(this, F.CN1));
	}

	@Override
	public IExpr times(final IExpr that) {
		return F.eval(F.Times(this, that));
	}

	/**
	 * Additional multiply method which works like times to fulfill groovy's method signature
	 * 
	 * @param that
	 * @return
	 */
	@Override
	public final IExpr multiply(final IExpr that) {
		return times(that);
	}

	@Override
	public final IExpr power(final Integer n) {
		if (this.isNumber()) {
			return F.eval(F.Power(this, F.integer(n)));
		}
		return F.Power(this, F.integer(n));
	}

	@Override
	public final IExpr power(final IExpr that) {
		if (this.isNumber() && that.isNumber()) {
			return F.eval(F.Power(this, that));
		}
		return F.Power(this, that);
	}

	// @Override
	// public IExpr div(final IExpr that) {
	// if (that.isNumber()) {
	// return F.eval(F.Times(this, that.inverse()));
	// }
	// return F.eval(F.Times(this, F.Power(that, F.CN1)));
	// }

	@Override
	public IExpr mod(final IExpr that) {
		return F.Mod(this, that);
	}

	@Override
	public IExpr and(final IExpr that) {
		return F.And(this, that);
	}

	@Override
	public IExpr or(final IExpr that) {
		return F.Or(this, that);
	}

	@Override
	public IExpr getAt(final int index) {
		return F.Part(this, F.integer(index));
	}

	@Override
	@SuppressWarnings("unchecked")
	public Object asType(Class clazz) {
		if (clazz.equals(Boolean.class)) {
			if (this.equals(F.True)) {
				return Boolean.TRUE;
			}
			if (this.equals(F.False)) {
				return Boolean.FALSE;
			}
		} else if (clazz.equals(Integer.class)) {
			if (isSignedNumber()) {
				try {
					return Integer.valueOf(((ISignedNumber) this).toInt());
				} catch (final ArithmeticException e) {
				}
			}
		} else if (clazz.equals(java.math.BigInteger.class)) {
			if (this instanceof IntegerSym) {
				return new java.math.BigInteger(((IntegerSym) this).toByteArray());
			}
		} else if (clazz.equals(String.class)) {
			return toString();
		}
		throw new UnsupportedOperationException("ExprImpl.asType() - cast not supported.");
	}

	@Override
	public abstract ISymbol head();

	@Override
	public ISymbol topHead() {
		return head();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isConstant() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isComplexInfinity() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isDirectedInfinity() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isInfinity() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNegative() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNegativeInfinity() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isList() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isSequence() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isListOfLists() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isTrue() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isFalse() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isSame(IExpr expression) {
		return isSame(expression, Config.DOUBLE_EPSILON);
	}

	@Override
	public boolean isSame(IExpr expression, double epsilon) {
		return equals(expression);
	}

	@Override
	public final int[] isMatrix() {
		// default: no matrix
		return null;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isValue() {
		return false;
	}

	@Override
	public final int isVector() {
		// default: no vector
		return -1;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isAST() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isOrderlessAST() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isFlatAST() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isAST(final IExpr header) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isAST(final IExpr header, final int sz) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isASTSizeGE(final IExpr header, final int length) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isAST(final String symbol) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isAST(final String symbol, final int length) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isAST(IExpr header, int length, IExpr... args) {
		return false;
	}

	@Override
	public final boolean isPlus() {
		return false;
	}

	@Override
	public final boolean isPower() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public final boolean isRuleAST() {
		return false;
	}

	@Override
	public final boolean isTimes() {
		return false;
	}

	@Override
	public final boolean isSin() {
		return false;
	}

	@Override
	public final boolean isCos() {
		return false;
	}

	@Override
	public final boolean isTan() {
		return false;
	}

	@Override
	public final boolean isArcSin() {
		return false;
	}

	@Override
	public final boolean isAnd() {
		return false;
	}

	@Override
	public final boolean isArcCos() {
		return false;
	}

	@Override
	public final boolean isArcTan() {
		return false;
	}

	@Override
	public final boolean isSinh() {
		return false;
	}

	@Override
	public final boolean isCosh() {
		return false;
	}

	@Override
	public final boolean isTanh() {
		return false;
	}

	@Override
	public final boolean isArcSinh() {
		return false;
	}

	@Override
	public final boolean isArcCosh() {
		return false;
	}

	@Override
	public final boolean isArcTanh() {
		return false;
	}

	@Override
	public final boolean isLog() {
		return false;
	}

	@Override
	public boolean isOne() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isOr() {
		return false;
	}

	@Override
	public boolean isMinusOne() {
		return false;
	}

	@Override
	public boolean isZero() {
		return false;
	}

	@Override
	public boolean isSlot() {
		return false;
	}

	@Override
	public boolean isSlotSequence() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isFree(final IExpr pattern, boolean heads) {
		final IPatternMatcher matcher = new PatternMatcher(pattern);
		return !matcher.apply(this);
	}

	/** {@inheritDoc} */
	@Override
	public boolean isFree(Predicate predicate, boolean heads) {
		return !predicate.apply(this);
	}

	/** {@inheritDoc} */
	@Override
	public boolean isMember(final IExpr pattern, boolean heads) {
		final IPatternMatcher matcher = new PatternMatcher(pattern);
		return isMember(matcher, heads);
	}

	/** {@inheritDoc} */
	@Override
	public boolean isMember(Predicate predicate, boolean heads) {
		return predicate.apply(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isFunction() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isPattern() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isPatternExpr() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isPatternSequence() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isPositive() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isCondition() {
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isModule() {
		return false;
	}

	@Override
	public boolean isSymbol() {
		return this instanceof ISymbol;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isComplex() {
		return this instanceof IComplex;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isComplexNumeric() {
		return this instanceof IComplexNum;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isFraction() {
		return this instanceof IFraction;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isInteger() {
		return this instanceof IInteger;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNumEqualInteger(IInteger ii) throws ArithmeticException {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNumIntValue() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isRational() {
		return this instanceof IRational;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isSignedNumber() {
		return this instanceof ISignedNumber;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNot() {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNumeric() {
		return this instanceof INum || this instanceof IComplexNum;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNumericFunction() {
		return isNumber() || isConstant();
	}

	/** {@inheritDoc} */
	@Override
	public boolean isRealFunction() {
		return isSignedNumber() || isConstant();
	}

	/** {@inheritDoc} */
	@Override
	public boolean isNumber() {
		return this instanceof INumber;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isLTOrdered(final IExpr obj) {
		return compareTo(obj) < 0;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isLEOrdered(final IExpr obj) {
		return compareTo(obj) <= 0;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isGTOrdered(final IExpr obj) {
		return compareTo(obj) > 0;
	}

	/** {@inheritDoc} */
	@Override
	public boolean isGEOrdered(final IExpr obj) {
		return compareTo(obj) >= 0;
	}

	@Override
	public boolean isAtom() {
		return true;
	}

	// public INestedList castTo() {
	// return null;
	// }

	@Override
	public IExpr variables2Slots(final Map map, final List variableList) {
		return this;
	}

	// public IExpr save() {
	// return (IExpr) super.export();
	// }
	//
	// public IExpr saveHeap() {
	// return (IExpr) super.moveHeap();
	// }

	@Override
	public String fullFormString() {
		return toString();
	}

	@Override
	public String internalFormString(boolean symbolsAsFactoryMethod, int depth) {
		return toString();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List leaves() {
		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr apply(List leaves) {
		final IAST ast = F.ast(head());
		for (int i = 0; i < leaves.size(); i++) {
			ast.add(leaves.get(i));
		}
		return ast;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr apply(IExpr... leaves) {
		final IAST ast = F.ast(head());
		for (int i = 0; i < leaves.length; i++) {
			ast.add(leaves[i]);
		}
		return ast;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replaceAll(final IAST astRules) {
		return this.accept(new VisitorReplaceAll(astRules));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replaceAll(final Function function) {
		return this.accept(new VisitorReplaceAll(function));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replacePart(final IAST astRules) {
		return this.accept(new VisitorReplacePart(astRules));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replaceRepeated(final IAST astRules) {
		return replaceRepeated(this, new VisitorReplaceAll(astRules));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replaceSlots(final IAST astSlots) {
		return this.accept(new VisitorReplaceSlots(astSlots));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public IExpr replaceRepeated(final Function function) {
		return replaceRepeated(this, new VisitorReplaceAll(function));
	}

	public static IExpr replaceRepeated(final IExpr expr, VisitorReplaceAll visitor) {
		IExpr result = expr;
		IExpr temp = expr.accept(visitor);
		final int iterationLimit = EvalEngine.get().getIterationLimit();
		int iterationCounter = 1;
		while (temp != null) {
			result = temp;
			temp = result.accept(visitor);
			if (iterationLimit >= 0 && iterationLimit <= ++iterationCounter) {
				IterationLimitExceeded.throwIt(iterationCounter, result);
			}
		}
		return result;
	}

	@Override
	public IExpr[] egcd(IExpr b) {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public IExpr evaluate(EvalEngine engine) {
		return null;
	}

	@Override
	public IExpr gcd(IExpr b) {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public IExpr abs() {
		if (this instanceof INumber) {
			return ((INumber) this).eabs();
		}
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public boolean isZERO() {
		return isZero();
	}

	/**
	 * Signum functionality is used in JAS toString() method, don't use it as math signum function.
	 * 
	 * @deprecated
	 */
	@Deprecated
	@Override
	public int signum() {
		if (isZERO()) {
			return 0;
		}
		if (isSignedNumber()) {
			return ((ISignedNumber) this).sign();
		}
		return 1;
	}

	@Override
	public IExpr subtract(IExpr that) {
		return this.plus(that.negate());
	}

	@Override
	public IExpr sum(IExpr that) {
		return this.plus(that);
	}

	@Override
	public ElemFactory factory() {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public String toScript() {
		return toString();
	}

	@Override
	public String toScriptFactory() {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public IExpr divide(IExpr that) {
		// return this.div(that);
		if (that.isNumber()) {
			return F.eval(F.Times(this, that.inverse()));
		}
		return F.eval(F.Times(this, F.Power(that, F.CN1)));
	}

	@Override
	public boolean isONE() {
		return isOne();
	}

	@Override
	public boolean isUnit() {
		return isOne();
	}

	@Override
	public IExpr remainder(IExpr S) {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public IExpr negate() {
		throw new UnsupportedOperationException(toString());
	}

	@Override
	public IExpr copy() {
		try {
			return (IExpr) clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}

}

 

Ads help maintain this website.