/*
* 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.util.NodeComparator.NODE_COMPARATOR;
import org.oakgp.Arguments;
import org.oakgp.Assignments;
import org.oakgp.function.Function;
import org.oakgp.node.FunctionNode;
import org.oakgp.node.Node;
/** Performs multiplication. */
final class Multiply extends ArithmeticOperator {
private final NumberUtils<?> numberUtils;
/** @see NumberUtils#getMultiply() */
Multiply(NumberUtils<?> numberUtils) {
super(numberUtils.getType());
this.numberUtils = numberUtils;
}
/**
* Returns the result of multiplying the two elements of the specified arguments.
*
* @return the result of multiplying {@code arg1} and {@code arg2}
*/
@Override
protected Object evaluate(Node arg1, Node arg2, Assignments assignments) {
return numberUtils.multiply(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 multiplied by zero is zero
// e.g. (* 0 v0) -> 0
return numberUtils.zero();
} 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 (numberUtils.isOne(arg1)) {
// anything multiplied by one is itself
// e.g. (* 1 v0) -> v0
return arg2;
} else if (numberUtils.isOne(arg2)) {
// the earlier ordering or arguments means we should never get here
throw new IllegalArgumentException("arg1 " + arg1 + " arg2 " + arg2);
} else {
if (isConstant(arg1) && numberUtils.isArithmeticExpression(arg2)) {
FunctionNode fn = (FunctionNode) arg2;
Function f = fn.getFunction();
Arguments args = fn.getArguments();
Node fnArg1 = args.firstArg();
Node fnArg2 = args.secondArg();
if (isConstant(fnArg1)) {
if (numberUtils.isAddOrSubtract(f)) {
return new FunctionNode(f, numberUtils.multiply(arg1, fnArg1), new FunctionNode(this, arg1, fnArg2));
} else if (numberUtils.isMultiply(f)) {
return new FunctionNode(this, numberUtils.multiply(arg1, fnArg1), fnArg2);
} else {
throw new IllegalArgumentException();
}
} else if (numberUtils.isAddOrSubtract(f)) {
return new FunctionNode(f, new FunctionNode(this, arg1, fnArg1), new FunctionNode(this, arg1, fnArg2));
}
}
return null;
}
}
@Override
public String getDisplayName() {
return "*";
}
}