package jscl.math.function;
import jscl.math.Generic;
import jscl.math.JsclInteger;
import jscl.math.NotIntegrableException;
import jscl.math.Variable;
import jscl.math.operator.AbstractFunction;
import jscl.text.ParserUtils;
import org.solovyev.common.math.MathEntity;
import javax.annotation.Nonnull;
public abstract class Function extends AbstractFunction {
protected Function(String name, Generic parameters[]) {
super(name, parameters);
}
public int getMinParameters() {
return 1;
}
@Override
public void copy(@Nonnull MathEntity that) {
super.copy(that);
if (that instanceof Function) {
if (((Function) that).parameters != null) {
this.parameters = ParserUtils.copyOf(((Function) that).parameters);
} else {
this.parameters = null;
}
}
}
public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
final int parameter = getParameterForAntiDerivation(variable);
if (parameter < 0) {
throw new NotIntegrableException(this);
} else {
return antiDerivative(parameter);
}
}
protected int getParameterForAntiDerivation(@Nonnull Variable variable) {
int result = -1;
for (int i = 0; i < parameters.length; i++) {
if (result == -1 && parameters[i].isIdentity(variable)) {
// found!
result = i;
} else if (!parameters[i].isConstant(variable)) {
result = -1;
break;
}
}
return result;
}
public abstract Generic antiDerivative(int n) throws NotIntegrableException;
@Nonnull
public Generic derivative(@Nonnull Variable variable) {
if (isIdentity(variable)) {
return JsclInteger.valueOf(1);
} else {
Generic result = JsclInteger.valueOf(0);
for (int i = 0; i < parameters.length; i++) {
// chain rule: f(x) = g(h(x)) => f'(x) = g'(h(x)) * h'(x)
// hd = h'(x)
// gd = g'(x)
final Generic hd = parameters[i].derivative(variable);
final Generic gd = this.derivative(i);
result = result.add(hd.multiply(gd));
}
return result;
}
}
public abstract Generic derivative(int n);
public boolean isConstant(Variable variable) {
boolean result = !isIdentity(variable);
if (result) {
for (Generic parameter : parameters) {
if (!parameter.isConstant(variable)) {
result = false;
break;
}
}
}
return result;
}
}