package jscl.math;
import jscl.math.function.Constant;
import jscl.mathml.MathML;
import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;
public class ModularInteger extends Generic implements Field {
public static final ModularInteger booleanFactory = new ModularInteger(0, 2);
final int modulo;
final int content;
public ModularInteger(long content, int modulo) {
this.modulo = modulo;
this.content = (int) (content % modulo);
}
public static ModularInteger factory(int modulo) {
return new ModularInteger(0, modulo);
}
public int content() {
return content;
}
public int modulo() {
return modulo;
}
public ModularInteger add(ModularInteger integer) {
return newinstance((long) content + integer.content);
}
@Nonnull
public Generic add(@Nonnull Generic that) {
return add((ModularInteger) that);
}
public ModularInteger subtract(ModularInteger integer) {
return newinstance((long) content + (modulo - integer.content));
}
@Nonnull
public Generic subtract(@Nonnull Generic that) {
return subtract((ModularInteger) that);
}
public ModularInteger multiply(ModularInteger integer) {
return newinstance((long) content * integer.content);
}
@Nonnull
public Generic multiply(@Nonnull Generic that) {
return multiply((ModularInteger) that);
}
@Nonnull
public Generic divide(@Nonnull Generic that) throws NotDivisibleException {
return multiply(that.inverse());
}
public Generic inverse() {
return newinstance(BigInteger.valueOf(content).modInverse(BigInteger.valueOf(modulo)).intValue());
}
public Generic gcd(@Nonnull Generic generic) {
throw new UnsupportedOperationException();
}
@Nonnull
public Generic gcd() {
throw new UnsupportedOperationException();
}
public Generic pow(int exponent) {
throw new UnsupportedOperationException();
}
public Generic negate() {
return newinstance(modulo - content);
}
public int signum() {
return content > 0 ? 1 : 0;
}
public int degree() {
return 0;
}
public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
throw new UnsupportedOperationException();
}
public Generic derivative(@Nonnull Variable variable) {
throw new UnsupportedOperationException();
}
public Generic substitute(@Nonnull Variable variable, Generic generic) {
throw new UnsupportedOperationException();
}
public Generic expand() {
throw new UnsupportedOperationException();
}
public Generic factorize() {
throw new UnsupportedOperationException();
}
public Generic elementary() {
throw new UnsupportedOperationException();
}
public Generic simplify() {
throw new UnsupportedOperationException();
}
public Generic numeric() {
throw new UnsupportedOperationException();
}
public Generic valueOf(Generic generic) {
if (generic instanceof ModularInteger) {
return newinstance(((ModularInteger) generic).content);
} else {
return newinstance(((JsclInteger) generic).content().mod(BigInteger.valueOf(modulo)).intValue());
}
}
public Generic[] sumValue() {
throw new UnsupportedOperationException();
}
public Generic[] productValue() throws NotProductException {
throw new UnsupportedOperationException();
}
public Power powerValue() throws NotPowerException {
throw new UnsupportedOperationException();
}
public Expression expressionValue() throws NotExpressionException {
return Expression.valueOf(integerValue());
}
public JsclInteger integerValue() throws NotIntegerException {
return JsclInteger.valueOf(content);
}
@Override
public double doubleValue() throws NotDoubleException {
return content;
}
@Override
public boolean isInteger() {
return true;
}
public Variable variableValue() throws NotVariableException {
throw new UnsupportedOperationException();
}
public Variable[] variables() {
throw new UnsupportedOperationException();
}
public boolean isPolynomial(@Nonnull Variable variable) {
throw new UnsupportedOperationException();
}
public boolean isConstant(@Nonnull Variable variable) {
throw new UnsupportedOperationException();
}
public int compareTo(ModularInteger integer) {
return content < integer.content ? -1 : content > integer.content ? 1 : 0;
}
public int compareTo(Generic generic) {
if (generic instanceof ModularInteger) {
return compareTo((ModularInteger) generic);
} else if (generic instanceof JsclInteger) {
return compareTo(valueOf(generic));
} else {
throw new UnsupportedOperationException();
}
}
public String toString() {
return "" + content;
}
public String toJava() {
throw new UnsupportedOperationException();
}
public void toMathML(MathML element, Object data) {
throw new UnsupportedOperationException();
}
@Nonnull
@Override
public Set<? extends Constant> getConstants() {
return Collections.emptySet();
}
protected ModularInteger newinstance(long content) {
return new ModularInteger(content, modulo);
}
}