package ec.app.semanticGP.func.numeric;

import ec.gp.semantic.DoubleSemantics;
import ec.gp.semantic.ISemantics;
import ec.gp.semantic.func.BinaryNode;

public class Pow extends BinaryNode<Double> {

	private static final String POW = "^";

	@Override
	protected ISemantics execute(ISemantics... arguments) {
		double[] arg0 = (double[]) arguments[0].getValue();
		double[] arg1 = (double[]) arguments[1].getValue();
		double[] semantics = new double[arg0.length];

		for (int i = 0; i < semantics.length; ++i) {
			semantics[i] = Math.pow(arg0[i], arg1[i]);
		}

		return new DoubleSemantics(semantics);
	}

	@Override
	public Double[] invert(Double output, int missingArgIdx, Double... restOfArguments) {
		double inv;

		switch (missingArgIdx) {
			case 0:
				if (restOfArguments[0] == 0.0) {
					if (output == 1.0)
						return Inversions.DONT_CARE; // don't care
					else
						return Inversions.INCONSISTENT; // inconsistent
				}

				inv = Math.pow(output, 1.0 / restOfArguments[0]);

				if (Double.isNaN(inv))
					return Inversions.INCONSISTENT; // inconsistent

				return new Double[]{inv};
			case 1:
			default:
				if ((restOfArguments[0] == 0.0 && output == 0.0) || (restOfArguments[0] == 1.0 && output == 1.0))
					return Inversions.DONT_CARE; //don't care
				else if (restOfArguments[0] > 0.0 && output > 0.0)
					return new Double[]{Math.log(output) / Math.log(restOfArguments[0])};
				else if (output < 0.0 && Math.rint(restOfArguments[0]) == restOfArguments[0])
					return new Double[]{-Math.log(-output) / Math.log(Math.abs(restOfArguments[0]))};
				return Inversions.INCONSISTENT; // inconsistent
		}
	}

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

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

}
