/* * Copyright 2015 S. Webber * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.oakgp.function.math; import static org.oakgp.node.NodeType.isConstant; import static org.oakgp.node.NodeType.isFunction; import static org.oakgp.util.NodeComparator.NODE_COMPARATOR; import org.oakgp.Arguments; import org.oakgp.Assignments; import org.oakgp.node.FunctionNode; import org.oakgp.node.Node; /** Performs addition. */ final class Add extends ArithmeticOperator { private final NumberUtils<?> numberUtils; private final ArithmeticExpressionSimplifier simplifier; /** @see NumberUtils#getAdd() */ Add(NumberUtils<?> numberUtils) { super(numberUtils.getType()); this.numberUtils = numberUtils; this.simplifier = numberUtils.getSimplifier(); } /** * Returns the result of adding the two elements of the specified arguments. * * @return the result of adding {@code arg1} and {@code arg2} */ @Override protected Object evaluate(Node arg1, Node arg2, Assignments assignments) { return numberUtils.add(arg1, arg2, assignments).evaluate(null); } @Override public Node simplify(Arguments arguments) { Node arg1 = arguments.firstArg(); Node arg2 = arguments.secondArg(); if (NODE_COMPARATOR.compare(arg1, arg2) > 0) { // as for addition the order of the arguments is not important, order arguments in a consistent way // e.g. (+ v1 1) -> (+ 1 v1) return new FunctionNode(this, arg2, arg1); } else if (numberUtils.isZero(arg1)) { // anything plus zero is itself // e.g. (+ 0 v0) -> v0 return arg2; } else if (numberUtils.isZero(arg2)) { // the earlier ordering or arguments means we should never get here throw new IllegalArgumentException("arg1 " + arg1 + " arg2 " + arg2); } else if (arg1.equals(arg2)) { // anything plus itself is equal to itself multiplied by two // e.g. (+ x x) -> (* 2 x) return numberUtils.multiplyByTwo(arg1); } else if (isConstant(arg1) && numberUtils.isNegative(arg1)) { // convert addition of negative numbers to subtraction // e.g. (+ -3 x) -> (- x 3) return new FunctionNode(numberUtils.getSubtract(), arg2, numberUtils.negateConstant(arg1)); } else if (isConstant(arg2) && numberUtils.isNegative(arg2)) { // should never get here as, due to the earlier ordering of arguments, // the only time the second argument will be a constant is when the first argument is also a constant - // in which case it would of already been simplified to the result of the addition. // e.g. (+ 2 7) would have already been simplified to 9 before it got this far throw new IllegalArgumentException("arg1 " + arg1 + " arg2 " + arg2); } else if (isConstant(arg1) && isFunction(arg2)) { FunctionNode fn2 = (FunctionNode) arg2; if (isConstant(fn2.getArguments().firstArg()) && numberUtils.isAddOrSubtract(fn2.getFunction())) { return new FunctionNode(fn2.getFunction(), numberUtils.add(arg1, fn2.getArguments().firstArg()), fn2.getArguments().secondArg()); } } return simplifier.simplify(this, arg1, arg2); } @Override public String getDisplayName() { return "+"; } }