gt: 		if (t0.isIdeal() && t1.isIdeal())
context: /*******************************************************************************
   * Copyright (c) 2013 Stephen F. Siegel, University of Delaware.
   * 
   * This file is part of SARL.
   * 
   * SARL is free software: you can redistribute it and/or modify it under
   * the terms of the GNU Lesser General Public License as published by the
   * Free Software Foundation, either version 3 of the License, or (at your
   * option) any later version.
   * 
   * SARL is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
   * License for more details.
   * 
   * You should have received a copy of the GNU Lesser General Public
   * License along with SARL. If not, see <http://www.gnu.org/licenses/>.
   ******************************************************************************/
  package edu.udel.cis.vsl.sarl.expr.common;
  
  import java.util.Collection;
  import java.util.Comparator;
  
  import edu.udel.cis.vsl.sarl.IF.SARLInternalException;
  import edu.udel.cis.vsl.sarl.IF.expr.BooleanExpression;
  import edu.udel.cis.vsl.sarl.IF.expr.NumericExpression;
  import edu.udel.cis.vsl.sarl.IF.expr.NumericSymbolicConstant;
  import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression.SymbolicOperator;
  import edu.udel.cis.vsl.sarl.IF.number.Number;
  import edu.udel.cis.vsl.sarl.IF.number.NumberFactory;
  import edu.udel.cis.vsl.sarl.IF.number.RationalNumber;
  import edu.udel.cis.vsl.sarl.IF.object.IntObject;
  import edu.udel.cis.vsl.sarl.IF.object.NumberObject;
  import edu.udel.cis.vsl.sarl.IF.object.StringObject;
  import edu.udel.cis.vsl.sarl.IF.object.SymbolicObject;
  import edu.udel.cis.vsl.sarl.IF.type.SymbolicIntegerType;
  import edu.udel.cis.vsl.sarl.IF.type.SymbolicRealType;
  import edu.udel.cis.vsl.sarl.IF.type.SymbolicType;
  import edu.udel.cis.vsl.sarl.collections.IF.CollectionFactory;
  import edu.udel.cis.vsl.sarl.expr.IF.BooleanExpressionFactory;
  import edu.udel.cis.vsl.sarl.expr.IF.NumericExpressionFactory;
  import edu.udel.cis.vsl.sarl.object.IF.ObjectFactory;
  import edu.udel.cis.vsl.sarl.type.IF.SymbolicTypeFactory;
  
  /**
   * Given a numeric factory that deals with expressions of ideal type, and a
   * numeric factory that deals with expressions of herbrand type, this factory
   * puts them together to work on any numeric type.
   * 
   * @author siegel
   * 
   */
  public class CommonNumericExpressionFactory implements NumericExpressionFactory {
  
  	private NumericExpressionFactory idealFactory;
  
  	private NumericExpressionFactory herbrandFactory;
  
  	private SymbolicTypeFactory typeFactory;
  
  	private CollectionFactory collectionFactory;
  
  	private SymbolicRealType herbrandRealType, idealRealType;
  
  	private SymbolicIntegerType herbrandIntegerType, idealIntegerType;
  
  	private BooleanExpressionFactory booleanFactory;
  
  	private ObjectFactory objectFactory;
  
  	private NumberFactory numberFactory;
  
  	private Comparator<NumericExpression> comparator;
  
  	/**
  	 * Constructor that creates a CommonNumericExpressionFactory.
  	 * 
  	 * @param idealFactory
  	 * @param herbrandFactory
  	 * 
  	 * @return CommonNumericExpressionFactory
  	 */
  	public CommonNumericExpressionFactory(
  			NumericExpressionFactory idealFactory,
  			NumericExpressionFactory herbrandFactory) {
  		this.idealFactory = idealFactory;
  		this.herbrandFactory = herbrandFactory;
  		this.booleanFactory = idealFactory.booleanFactory();
  		this.typeFactory = idealFactory.typeFactory();
  		this.objectFactory = typeFactory.objectFactory();
  		this.collectionFactory = idealFactory.collectionFactory();
  		this.numberFactory = idealFactory.numberFactory();
  		this.herbrandRealType = typeFactory.herbrandRealType();
  		this.herbrandIntegerType = typeFactory.herbrandIntegerType();
  		this.idealRealType = typeFactory.realType();
  		this.idealIntegerType = typeFactory.integerType();
  		this.comparator = new CommonNumericComparator(
  				idealFactory.comparator(), herbrandFactory.comparator());
  	}
  
  	// Helpers...
  
  	/**
  	 * Private method that casts NumericExpression to Ideal type.
  	 * 
  	 * @param arg
  	 * 
  	 * @return NumericExpression
  	 */
  	private NumericExpression castToIdeal(NumericExpression arg) {
  		SymbolicType oldType = arg.type();
  
  		if (oldType.isIdeal())
  			return arg;
  		else {
  			if (arg.operator() == SymbolicOperator.CONCRETE) {
  				SymbolicObject object = arg.argument(0);
  
  				if (object instanceof NumberObject)
  					return idealFactory.number((NumberObject) object);
  			}
  			return idealFactory
  					.expression(SymbolicOperator.CAST,
  							oldType.isInteger() ? idealIntegerType
  									: idealRealType, arg);
  		}
  	}
  
  	/**
  	 * Private method that casts NumericExpression to Herbrand type.
  	 * 
  	 * @param arg
  	 * 
  	 * @return NumericExpression
  	 */
  	private NumericExpression castToHerbrand(NumericExpression arg) {
  		SymbolicType oldType = arg.type();
  
  		if (oldType.isHerbrand())
  			return arg;
  		else {
  			if (arg.operator() == SymbolicOperator.CONCRETE) {
  				SymbolicObject object = arg.argument(0);
  
  				if (object instanceof NumberObject)
  					return herbrandFactory.number((NumberObject) object);
  			}
  			return herbrandFactory.expression(SymbolicOperator.CAST, oldType
  					.isInteger() ? herbrandIntegerType : herbrandRealType, arg);
  		}
  	}
  
  	// Exported methods....
  
  	/**
  	 * Getter method that returns idealFactory.
  	 * 
  	 * @return idealFactory
  	 */
  	public NumericExpressionFactory idealFactory() {
  		return idealFactory;
  	}
  
  	/**
  	 * Getter method that returns herbrandFactory.
  	 * 
  	 * @return herbrandFactory
  	 */
  	public NumericExpressionFactory herbrandFactory() {
  		return herbrandFactory;
  	}
  
  	/**
  	 * Method that initializes this CommonNumericExpressionFactory
  	 * 
  	 */
  	@Override
  	public void init() {
  		idealFactory.init();
  		herbrandFactory.init();
  	}
  
  	/**
  	 * Getter method that returns booleanFactory.
  	 * 
  	 * @return BooleanExpressionFactory
  	 */
  	@Override
  	public BooleanExpressionFactory booleanFactory() {
  		return booleanFactory;
  	}
  
  	/**
  	 * Getter method that returns numberFactory.
  	 * 
  	 * @return NumberFactory
  	 */
  	@Override
  	public NumberFactory numberFactory() {
  		return numberFactory;
  	}
  
  	/**
  	 * Getter method that returns objectFacotry.
  	 * 
  	 * @return ObjectFactory
  	 */
  	@Override
  	public ObjectFactory objectFactory() {
  		return objectFactory;
  	}
  
  	/**
  	 * Getter method that returns typeFactory.
  	 * 
  	 * @return SymbolicTypeFactory
  	 */
  	@Override
  	public SymbolicTypeFactory typeFactory() {
  		return typeFactory;
  	}
  
  	/**
  	 * Getter method that returns collectionFactory.
  	 * 
  	 * @return CollectionFactory
  	 */
  	@Override
  	public CollectionFactory collectionFactory() {
  		return collectionFactory;
  	}
  
  	/**
  	 * Getter method that returns comparator.
  	 * 
  	 * @return Comparator<NumericExpression>
  	 */
  	@Override
  	public Comparator<NumericExpression> comparator() {
  		return comparator;
  	}
  
  	/**
  	 * Returns the ideal number. If you want it to be Herbrand you need to cast
  	 * it to the appropriate Herbrand type.
  	 * 
  	 * @param numberObject
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression number(NumberObject numberObject) {
  		return idealFactory.number(numberObject);
  	}
  
  	/**
  	 * Method that returns NumericSymbolicConstant.
  	 * 
  	 * @param name
  	 * @param type
  	 * 
  	 * @return NumericSymbolicConstant
  	 */
  	@Override
  	public NumericSymbolicConstant symbolicConstant(StringObject name,
  			SymbolicType type) {
  		if (type.isIdeal())
  			return idealFactory.symbolicConstant(name, type);
  		else
  			return herbrandFactory.symbolicConstant(name, type);
  	}
  
  	/**
  	 * One of several methods that create a NumericExpression.
  	 * 
  	 * @param operator
  	 * @param numericType
  	 * @param arguments
  	 * 	arguments is a Collection<SymbolicObject>
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression expression(SymbolicOperator operator,
  			SymbolicType numericType, Collection<SymbolicObject> arguments) {
  		if (numericType.isIdeal())
  			return idealFactory.expression(operator, numericType, arguments);
  		else
  			return herbrandFactory.expression(operator, numericType, arguments);
  	}
  
  	/**
  	 * One of several methods that create a NumericExpression.
  	 * 
  	 * @param operator
  	 * @param numericType
  	 * @param arguments
  	 * 	arguments is a SymbolicObject array
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression expression(SymbolicOperator operator,
  			SymbolicType numericType, SymbolicObject[] arguments) {
  		if (numericType.isIdeal())
  			return idealFactory.expression(operator, numericType, arguments);
  		else
  			return herbrandFactory.expression(operator, numericType, arguments);
  	}
  
  	/**
  	 * One of several methods that create a NumericExpression.
  	 * 
  	 * @param operator
  	 * @param numericType
  	 * @param arg0
  	 * 	arg0 is a SymbolicObject
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression expression(SymbolicOperator operator,
  			SymbolicType numericType, SymbolicObject arg0) {
  		if (numericType.isIdeal())
  			return idealFactory.expression(operator, numericType, arg0);
  		else
  			return herbrandFactory.expression(operator, numericType, arg0);
  	}
  
  	/**
  	 * One of several methods that create a NumericExpression.
  	 * 
  	 * @param operator
  	 * @param numericType
  	 * @param arg0
  	 * 	arg0 is a SymbolicObject
  	 * @param arg1
  	 * 	arg1 is a SymbolicObject
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression expression(SymbolicOperator operator,
  			SymbolicType numericType, SymbolicObject arg0, SymbolicObject arg1) {
  		if (numericType.isIdeal())
  			return idealFactory.expression(operator, numericType, arg0, arg1);
  		else
  			return herbrandFactory
  					.expression(operator, numericType, arg0, arg1);
  	}
  
  	/**
  	 * One of several methods that create a NumericExpression.
  	 * 
  	 * @param operator
  	 * @param numericType
  	 * @param arg0
  	 * 	arg0 is a SymbolicObject
  	 * @param arg1
  	 * 	arg1 is a SymbolicObject
  	 * @param arg2
  	 * 	arg2 is a SymbolicObject
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression expression(SymbolicOperator operator,
  			SymbolicType numericType, SymbolicObject arg0, SymbolicObject arg1,
  			SymbolicObject arg2) {
  		if (numericType.isIdeal())
  			return idealFactory.expression(operator, numericType, arg0, arg1,
  					arg2);
  		else
  			return herbrandFactory.expression(operator, numericType, arg0,
  					arg1, arg2);
  	}
  
  	/**
  	 * Method that returns zeroInt NumericExpression.
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression zeroInt() {
  		return idealFactory.zeroInt();
  	}
  
  	/**
  	 * Method that returns zeroReal NumericExpression.
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression zeroReal() {
  		return idealFactory.zeroReal();
  	}
  
  	/**
  	 * Method that returns oneInt NumericExpression.
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression oneInt() {
  		return idealFactory.oneInt();
  	}
  
  	/**
  	 * Method that returns oneReal NumericExpression.
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression oneReal() {
  		return idealFactory.oneReal();
  	}
  
  	/**
  	 * Method that adds two NumericExpressions.
  	 * 
  	 * @param arg0
  	 * 	arg0 is a NumericExpression
  	 * @param arg1
  	 * 	arg1 is a NumericExpression
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression add(NumericExpression arg0, NumericExpression arg1) {
  		SymbolicType t0 = arg0.type(), t1 = arg1.type();
  
  		if (t0.isIdeal() && t1.isIdeal())
  			return idealFactory.add(arg0, arg1);
  		else
  			return herbrandFactory.add(castToHerbrand(arg0),
  					castToHerbrand(arg1));
  	}
  
  	/**
  	 * Method that subtracts a NumericExpression from another NumericExpression.
  	 * 
  	 * @param arg0
  	 * 	arg0 is a NumericExpression
  	 * @param arg1
  	 * 	arg1 is a NumericExpression
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression subtract(NumericExpression arg0,
  			NumericExpression arg1) {
  		SymbolicType t0 = arg0.type(), t1 = arg1.type();
  
  		if (t0.isIdeal() && t1.isIdeal())
  			return idealFactory.subtract(arg0, arg1);
  		else
  			return herbrandFactory.subtract(castToHerbrand(arg0),
  					castToHerbrand(arg1));
  	}
  
  	/**
  	 * Method that multiplies two NumericExpressions.
  	 * 
  	 * @param arg0
  	 * 	arg0 is a NumericExpression
  	 * @param arg1
  	 * 	arg1 is a NumericExpression
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression multiply(NumericExpression arg0,
  			NumericExpression arg1) {
  		SymbolicType t0 = arg0.type(), t1 = arg1.type();
  
  		if (t0.isIdeal() && t1.isIdeal())
  			return idealFactory.multiply(arg0, arg1);
  		else
  			return herbrandFactory.multiply(castToHerbrand(arg0),
  					castToHerbrand(arg1));
  	}
  
  	/**
  	 * Method that divides one numeric expression by another.
  	 * 
  	 * @param arg0
  	 * 	arg0 is a NumericExpression
  	 * @param arg1
  	 * 	arg1 is a NumericExpression
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression divide(NumericExpression arg0,
  			NumericExpression arg1) {
  		SymbolicType t0 = arg0.type(), t1 = arg1.type();
  
  		if (t0.isIdeal() && t1.isIdeal())
  			return idealFactory.divide(arg0, arg1);
  		else
  			return herbrandFactory.divide(castToHerbrand(arg0),
  					castToHerbrand(arg1));
  	}
  
  	/**
  	 * Method that returns modulo arg1 of arg0.
  	 * 
  	 * @param arg0
  	 * 	arg0 is a NumericExpression
  	 * @param arg1 is a NumericExpression
  	 * 
  	 * @return NumericExpression
  	 */
  	@Override
  	public NumericExpression modulo(NumericExpression arg0,
  			NumericExpression arg1) {
  		SymbolicType t0 = arg0.type(), t1 = arg1.type();
  
  