package jscl.math.function;
import jscl.math.Generic;
import jscl.math.NotIntegrableException;
import jscl.math.Variable;
import jscl.mathml.MathML;
import jscl.util.ArrayComparator;
import javax.annotation.Nonnull;
public class ImplicitFunction extends Function {
private int derivations[];
private Generic subscripts[];
public ImplicitFunction(String name, Generic parameter[], int derivations[], Generic subscripts[]) {
super(name, parameter);
this.derivations = derivations;
this.subscripts = subscripts;
}
static int compareDerivation(int c1[], int c2[]) {
int n = c1.length;
for (int i = n - 1; i >= 0; i--) {
if (c1[i] < c2[i]) return -1;
else if (c1[i] > c2[i]) return 1;
}
return 0;
}
public Generic antiDerivative(int n) throws NotIntegrableException {
int c[] = new int[derivations.length];
for (int i = 0; i < c.length; i++) {
if (i == n) {
if (derivations[i] > 0) c[i] = derivations[i] - 1;
else throw new NotIntegrableException(this);
} else c[i] = derivations[i];
}
return new ImplicitFunction(name, parameters, c, subscripts).selfExpand();
}
public Generic derivative(int n) {
int c[] = new int[derivations.length];
for (int i = 0; i < c.length; i++) {
if (i == n) c[i] = derivations[i] + 1;
else c[i] = derivations[i];
}
return new ImplicitFunction(name, parameters, c, subscripts).selfExpand();
}
public Generic selfExpand() {
return expressionValue();
}
public Generic selfElementary() {
return expressionValue();
}
public Generic selfSimplify() {
return expressionValue();
}
/*@Override
public Generic numeric() {
return evaluateNumerically();
}*/
public Generic selfNumeric() {
throw new ArithmeticException();
/*Function function = FunctionsRegistry.getInstance().get(this.name);
Generic result;
if ( function == null ) {
throw new ArithmeticException();
} else {
function.setParameters(this.parameters);
result = function;
for (int derivation : derivations) {
for ( int i = 0; i < derivation; i++ ) {
result = result.derivative(derivation);
}
}
result = result.numeric();
}
return result;*/
}
public int compareTo(Variable that) {
if (this == that) return 0;
int c = comparator.compare(this, that);
if (c < 0) return -1;
else if (c > 0) return 1;
else {
ImplicitFunction v = (ImplicitFunction) that;
c = name.compareTo(v.name);
if (c < 0) return -1;
else if (c > 0) return 1;
else {
c = ArrayComparator.comparator.compare(subscripts, v.subscripts);
if (c < 0) return -1;
else if (c > 0) return 1;
else {
c = compareDerivation(derivations, v.derivations);
if (c < 0) return -1;
else if (c > 0) return 1;
else return ArrayComparator.comparator.compare(parameters, v.parameters);
}
}
}
}
public String toString() {
final StringBuilder result = new StringBuilder();
int n = 0;
for (int derivation : derivations) {
n += derivation;
}
result.append(name);
for (Generic aSubscript : subscripts) {
result.append("[").append(aSubscript).append("]");
}
if (n == 0) {
// do nothing
} else if (parameters.length == 1 && n <= Constant.PRIME_CHARS) {
result.append(Constant.primeChars(n));
} else {
result.append(derivationToString());
}
result.append("(");
for (int i = 0; i < parameters.length; i++) {
result.append(parameters[i]).append(i < parameters.length - 1 ? ", " : "");
}
result.append(")");
return result.toString();
}
String derivationToString() {
StringBuilder buffer = new StringBuilder();
buffer.append("{");
for (int i = 0; i < derivations.length; i++) {
buffer.append(derivations[i]).append(i < derivations.length - 1 ? ", " : "");
}
buffer.append("}");
return buffer.toString();
}
public String toJava() {
final StringBuilder result = new StringBuilder();
int n = 0;
for (int derivation : derivations) {
n += derivation;
}
result.append(name);
if (n == 0) {
// do nothing
} else if (parameters.length == 1 && n <= Constant.PRIME_CHARS) {
result.append(Constant.underscores(n));
} else {
result.append(derivationToJava());
}
result.append("(");
for (int i = 0; i < parameters.length; i++) {
result.append(parameters[i].toJava()).append(i < parameters.length - 1 ? ", " : "");
}
result.append(")");
for (Generic subscript : subscripts) {
result.append("[").append(subscript.integerValue().intValue()).append("]");
}
return result.toString();
}
String derivationToJava() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < derivations.length; i++) {
buffer.append("_").append(derivations[i]);
}
return buffer.toString();
}
public void toMathML(MathML element, Object data) {
MathML e1;
int exponent = data instanceof Integer ? (Integer) data : 1;
if (exponent == 1) bodyToMathML(element);
else {
e1 = element.element("msup");
bodyToMathML(e1);
MathML e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(exponent)));
e1.appendChild(e2);
element.appendChild(e1);
}
e1 = element.element("mfenced");
for (Generic parameter : parameters) {
parameter.toMathML(e1, null);
}
element.appendChild(e1);
}
void bodyToMathML(MathML element) {
int n = 0;
for (int derivation : derivations) {
n += derivation;
}
if (subscripts.length == 0) {
if (n == 0) {
nameToMathML(element);
} else {
MathML e1 = element.element("msup");
nameToMathML(e1);
derivationToMathML(e1, n);
element.appendChild(e1);
}
} else {
if (n == 0) {
MathML e1 = element.element("msub");
nameToMathML(e1);
MathML e2 = element.element("mrow");
for (Generic subscript : subscripts) {
subscript.toMathML(e2, null);
}
e1.appendChild(e2);
element.appendChild(e1);
} else {
MathML e1 = element.element("msubsup");
nameToMathML(e1);
MathML e2 = element.element("mrow");
for (Generic subscript : subscripts) {
subscript.toMathML(e2, null);
}
e1.appendChild(e2);
derivationToMathML(e1, n);
element.appendChild(e1);
}
}
}
void derivationToMathML(MathML element, int n) {
if (parameters.length == 1 && n <= Constant.PRIME_CHARS) {
Constant.primeCharsToMathML(element, n);
} else {
MathML e1 = element.element("mfenced");
for (int derivation : derivations) {
MathML e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(derivation)));
e1.appendChild(e2);
}
element.appendChild(e1);
}
}
@Nonnull
public Variable newInstance() {
return new ImplicitFunction(name, new Generic[parameters.length], derivations, subscripts);
}
}