package jscl.math;
import jscl.JsclMathEngine;
import jscl.math.function.Constant;
import jscl.math.function.Constants;
import jscl.math.function.IConstant;
import jscl.math.numeric.*;
import jscl.mathml.MathML;
import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;
public final class NumericWrapper extends Generic implements INumeric<NumericWrapper> {
@Nonnull
private final Numeric content;
public NumericWrapper(@Nonnull JsclInteger integer) {
content = Real.valueOf(integer.content().doubleValue());
}
public NumericWrapper(@Nonnull Rational rational) {
content = Real.valueOf(rational.numerator().doubleValue() / rational.denominator().doubleValue());
}
public NumericWrapper(@Nonnull JsclVector vector) {
final Numeric elements[] = new Numeric[vector.rows];
for (int i = 0; i < vector.rows; i++) {
elements[i] = ((NumericWrapper) vector.elements[i].numeric()).content();
}
content = new Vector(elements);
}
public NumericWrapper(@Nonnull Matrix matrix) {
final Numeric elements[][] = new Numeric[matrix.rows][matrix.cols];
for (int i = 0; i < matrix.rows; i++) {
for (int j = 0; j < matrix.cols; j++) {
elements[i][j] = ((NumericWrapper) matrix.elements[i][j].numeric()).content();
}
}
content = new jscl.math.numeric.Matrix(elements);
}
public NumericWrapper(@Nonnull Constant constant) {
final IConstant constantFromRegistry = JsclMathEngine.getInstance().getConstantsRegistry().get(constant.getName());
if (constantFromRegistry != null) {
if (constantFromRegistry.getName().equals(Constants.I.getName())) {
content = Complex.I;
} else {
if (constantFromRegistry.getValue() != null) {
final Double value = constantFromRegistry.getDoubleValue();
if (value == null) {
throw new ArithmeticException("Constant " + constant.getName() + " has invalid definition: " + constantFromRegistry.getValue());
} else {
content = Real.valueOf(value);
}
} else {
throw new ArithmeticException("Could not create numeric wrapper: constant in registry doesn't have specified value: " + constant.getName());
}
}
} else {
throw new ArithmeticException("Could not create numeric wrapper: constant is not registered in constants registry: " + constant.getName());
}
}
public NumericWrapper(@Nonnull Numeric numeric) {
content = numeric;
}
public static Generic root(int subscript, Generic parameter[]) {
Numeric param[] = new Numeric[parameter.length];
for (int i = 0; i < param.length; i++) param[i] = ((NumericWrapper) parameter[i]).content;
return new NumericWrapper(Numeric.root(subscript, param));
}
public Numeric content() {
return content;
}
public NumericWrapper add(NumericWrapper wrapper) {
return new NumericWrapper(content.add(wrapper.content));
}
@Nonnull
public Generic add(@Nonnull Generic that) {
if (that instanceof Expression) {
return that.add(this);
} else if (that instanceof NumericWrapper) {
return add((NumericWrapper) that);
} else {
return add(valueOf(that));
}
}
public NumericWrapper subtract(NumericWrapper wrapper) {
return new NumericWrapper(content.subtract(wrapper.content));
}
@Nonnull
public Generic subtract(@Nonnull Generic that) {
if (that instanceof Expression) {
return that.add(this);
} else if (that instanceof NumericWrapper) {
return subtract((NumericWrapper) that);
} else {
return subtract(valueOf(that));
}
}
public NumericWrapper multiply(NumericWrapper wrapper) {
return new NumericWrapper(content.multiply(wrapper.content));
}
@Nonnull
public Generic multiply(@Nonnull Generic that) {
if (that instanceof Expression) {
return that.add(this);
} else if (that instanceof NumericWrapper) {
return multiply((NumericWrapper) that);
} else {
return multiply(valueOf(that));
}
}
public NumericWrapper divide(NumericWrapper wrapper) throws ArithmeticException {
return new NumericWrapper(content.divide(wrapper.content));
}
@Nonnull
public Generic divide(@Nonnull Generic that) throws NotDivisibleException {
if (that instanceof Expression) {
return that.add(this);
} else if (that instanceof NumericWrapper) {
return divide((NumericWrapper) that);
} else {
return divide(valueOf(that));
}
}
public Generic gcd(@Nonnull Generic generic) {
return null;
}
@Nonnull
public Generic gcd() {
return null;
}
@Nonnull
public NumericWrapper abs() {
return new NumericWrapper(content.abs());
}
@Nonnull
public NumericWrapper negate() {
return new NumericWrapper(content.negate());
}
public int signum() {
return content.signum();
}
public int degree() {
return 0;
}
public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
return null;
}
public Generic derivative(@Nonnull Variable variable) {
return null;
}
public Generic substitute(@Nonnull Variable variable, Generic generic) {
return this;
}
public Generic expand() {
return this;
}
public Generic factorize() {
return this;
}
public Generic elementary() {
return this;
}
public Generic simplify() {
return this;
}
public Generic numeric() {
return this;
}
public NumericWrapper valueOf(NumericWrapper wrapper) {
return new NumericWrapper(content.valueOf(wrapper.content));
}
public Generic valueOf(@Nonnull Generic generic) {
if (generic instanceof NumericWrapper) {
return valueOf((NumericWrapper) generic);
} else if (generic instanceof JsclInteger) {
return new NumericWrapper((JsclInteger) generic);
} else {
throw new ArithmeticException("Could not create numeric wrapper for class: " + generic.getClass());
}
}
public Generic[] sumValue() {
return null;
}
public Generic[] productValue() throws NotProductException {
return null;
}
public Power powerValue() throws NotPowerException {
return null;
}
public Expression expressionValue() throws NotExpressionException {
throw new NotExpressionException();
}
public JsclInteger integerValue() throws NotIntegerException {
if (content instanceof Real) {
double doubleValue = content.doubleValue();
if (Math.floor(doubleValue) == doubleValue) {
return JsclInteger.valueOf((int) doubleValue);
} else {
throw NotIntegerException.get();
}
} else {
throw NotIntegerException.get();
}
}
@Override
public double doubleValue() throws NotDoubleException {
return content.doubleValue();
}
@Override
public boolean isInteger() {
if (content instanceof Real) {
double value = ((Real) content).doubleValue();
return Math.floor(value) == value;
}
return false;
}
public Variable variableValue() throws NotVariableException {
throw new NotVariableException();
}
public Variable[] variables() {
return new Variable[0];
}
public boolean isPolynomial(@Nonnull Variable variable) {
return true;
}
public boolean isConstant(@Nonnull Variable variable) {
return true;
}
@Nonnull
public NumericWrapper sgn() {
return new NumericWrapper(content.sgn());
}
@Nonnull
public NumericWrapper ln() {
return new NumericWrapper(content.ln());
}
@Nonnull
public NumericWrapper lg() {
return new NumericWrapper(content.lg());
}
@Nonnull
public NumericWrapper exp() {
return new NumericWrapper(content.exp());
}
@Nonnull
public NumericWrapper inverse() {
return new NumericWrapper(content.inverse());
}
@Nonnull
public NumericWrapper pow(int exponent) {
return new NumericWrapper(content.pow(exponent));
}
public Generic pow(Generic generic) {
return new NumericWrapper(content.pow(((NumericWrapper) generic).content));
}
@Nonnull
public NumericWrapper sqrt() {
return new NumericWrapper(content.sqrt());
}
@Nonnull
public NumericWrapper nThRoot(int n) {
return new NumericWrapper(content.nThRoot(n));
}
public Generic conjugate() {
return new NumericWrapper(content.conjugate());
}
@Nonnull
public NumericWrapper acos() {
return new NumericWrapper(content.acos());
}
@Nonnull
public NumericWrapper asin() {
return new NumericWrapper(content.asin());
}
@Nonnull
public NumericWrapper atan() {
return new NumericWrapper(content.atan());
}
@Nonnull
public NumericWrapper acot() {
return new NumericWrapper(content.acot());
}
@Nonnull
public NumericWrapper cos() {
return new NumericWrapper(content.cos());
}
@Nonnull
public NumericWrapper sin() {
return new NumericWrapper(content.sin());
}
@Nonnull
public NumericWrapper tan() {
return new NumericWrapper(content.tan());
}
@Nonnull
public NumericWrapper cot() {
return new NumericWrapper(content.cot());
}
@Nonnull
public NumericWrapper acosh() {
return new NumericWrapper(content.acosh());
}
@Nonnull
public NumericWrapper asinh() {
return new NumericWrapper(content.asinh());
}
@Nonnull
public NumericWrapper atanh() {
return new NumericWrapper(content.atanh());
}
@Nonnull
public NumericWrapper acoth() {
return new NumericWrapper(content.acoth());
}
@Nonnull
public NumericWrapper cosh() {
return new NumericWrapper(content.cosh());
}
@Nonnull
public NumericWrapper sinh() {
return new NumericWrapper(content.sinh());
}
@Nonnull
public NumericWrapper tanh() {
return new NumericWrapper(content.tanh());
}
@Nonnull
public NumericWrapper coth() {
return new NumericWrapper(content.coth());
}
public int compareTo(NumericWrapper wrapper) {
return content.compareTo(wrapper.content);
}
public int compareTo(Generic generic) {
if (generic instanceof NumericWrapper) {
return compareTo((NumericWrapper) generic);
} else {
return compareTo(valueOf(generic));
}
}
public String toString() {
return content.toString();
}
public String toJava() {
return "JsclDouble.valueOf(" + ((Real) content).doubleValue() + ")";
}
public void toMathML(MathML element, Object data) {
int exponent = data instanceof Integer ? (Integer) data : 1;
if (exponent == 1) bodyToMathML(element);
else {
MathML e1 = element.element("msup");
bodyToMathML(e1);
MathML e2 = element.element("mn");
e2.appendChild(element.text(String.valueOf(exponent)));
e1.appendChild(e2);
element.appendChild(e1);
}
}
@Nonnull
@Override
public Set<? extends Constant> getConstants() {
return Collections.emptySet();
}
void bodyToMathML(MathML element) {
MathML e1 = element.element("mn");
e1.appendChild(element.text(String.valueOf(new Double(((Real) content).doubleValue()))));
element.appendChild(e1);
}
@Override
public BigInteger toBigInteger() {
return content.toBigInteger();
}
@Nonnull
public static Generic valueOf(long value) {
return new NumericWrapper(new JsclInteger(BigInteger.valueOf(value)));
}
@Nonnull
public static Generic valueOf(double value) {
return new NumericWrapper(Real.valueOf(value));
}
}