package jscl.math;
import jscl.math.polynomial.Basis;
import jscl.math.polynomial.Monomial;
import jscl.math.polynomial.Ordering;
import jscl.math.polynomial.Polynomial;
import jscl.util.ArrayComparator;
import jscl.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Factorization {
private static final String ter = "t";
Polynomial factory;
Generic result;
Factorization(Polynomial factory) {
this.factory = factory;
}
public static Generic compute(Generic generic) {
try {
return GenericVariable.content(factorize(generic.integerValue()));
} catch (NotIntegerException e) {
Factorization f = new Factorization(Polynomial.factory(generic.variables(), Monomial.iteratorOrdering, -1));
f.computeValue(generic);
return f.getValue();
}
}
static Generic factorize(JsclInteger integer) {
Generic n[] = integer.gcdAndNormalize();
Generic s = n[1];
Generic a = JsclInteger.valueOf(1);
Generic p = JsclInteger.valueOf(2);
while (s.compareTo(JsclInteger.valueOf(1)) > 0) {
Generic q[] = s.divideAndRemainder(p);
if (q[0].compareTo(p) < 0) {
p = s;
q = s.divideAndRemainder(p);
}
if (q[1].signum() == 0) {
a = a.multiply(expression(p, true));
s = q[0];
} else p = p.add(JsclInteger.valueOf(1));
}
return a.multiply(n[0]);
}
static Polynomial[] remainder(Polynomial s, Polynomial p, Generic t[]) {
Polynomial zero = s.valueOf(JsclInteger.valueOf(0));
Generic a[] = Basis.augment(t, s.remainderUpToCoefficient(p).elements());
Variable unk[] = Basis.augmentUnknown(new Variable[]{}, p.elements());
{
Variable u = unk[unk.length - 1];
System.arraycopy(unk, 0, unk, 1, unk.length - 1);
unk[0] = u;
}
Generic be[][] = Linearization.compute(Basis.compute(a, unk, Monomial.lexicographic, 0, Basis.DEGREE).elements(), unk);
for (int i = 0; i < be.length; i++) {
Polynomial r = substitute(p, be[i], unk);
try {
return new Polynomial[]{zero, r, s.divide(r)};
} catch (NotDivisibleException e) {
}
}
return new Polynomial[]{s, zero, zero};
}
static Polynomial substitute(Polynomial p, Generic a[], Variable unk[]) {
Generic s[] = new Generic[]{p.genericValue()};
return p.valueOf(Basis.compute(Basis.augment(a, s), Basis.augmentUnknown(unk, s)).elements()[0]);
}
static Polynomial polynomial(Polynomial s, Monomial monomial[]) {
Polynomial p = s.valueOf(JsclInteger.valueOf(0));
Iterator it = monomial[1].iterator(monomial[0]);
for (int i = 0; it.hasNext(); i++) {
Monomial m = (Monomial) it.next();
Variable t = it.hasNext() ? new TechnicalVariable(ter, new int[]{i}) : new TechnicalVariable(ter);
p = p.add(p.valueOf(m).multiply(t.expressionValue()));
}
return p;
}
static Generic[] terminator(Polynomial polynomial) {
Generic t[] = new Generic[2];
t[1] = terminator(polynomial.head().coef().abs(), new TechnicalVariable(ter), false);
t[0] = terminator(polynomial.tail().coef(), new TechnicalVariable(ter, new int[]{0}), true);
return t;
}
static Generic terminator(Generic generic, Variable var, boolean tail) {
Generic x = var.expressionValue();
Generic a = JsclInteger.valueOf(1);
Iterator it = IntegerDivisor.create(generic.integerValue());
while (it.hasNext()) {
Generic s = (Generic) it.next();
a = a.multiply(x.subtract(s));
if (!tail) a = a.multiply(x.add(s));
}
return a;
}
static Generic expression(Generic generic) {
return expression(generic, false);
}
static Generic expression(Generic generic, boolean integer) {
if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return generic;
else return GenericVariable.valueOf(generic, integer).expressionValue();
}
static String toString(Monomial monomial[]) {
return "{" + monomial[0] + ", " + monomial[1] + "}";
}
void computeValue(Generic generic) {
Debug.println("factorization");
Polynomial n[] = factory.valueOf(generic).gcdAndNormalize();
Monomial m = n[1].monomialGcd();
Polynomial s = n[1].divide(m);
Generic a = JsclInteger.valueOf(1);
Divisor d[] = new Divisor[2];
Monomial p[] = new Monomial[2];
Monomial q[] = new Monomial[2];
d[1] = new Divisor(s.head().monomial());
loop:
while (d[1].hasNext()) {
p[1] = (Monomial) d[1].next();
q[1] = d[1].complementary();
d[0] = new Divisor(s.tail().monomial());
while (d[0].hasNext()) {
p[0] = (Monomial) d[0].next();
q[0] = d[0].complementary();
if (p[1].compareTo(p[0]) <= 0) continue loop;
Debug.println(toString(p) + " * " + toString(q) + " = " + s);
if (ArrayComparator.comparator.compare(q, p) < 0) {
a = a.multiply(expression(s.genericValue()));
break loop;
} else {
Debug.increment();
Polynomial r[] = remainder(s, polynomial(s, p), terminator(s));
Debug.decrement();
if (r[0].signum() == 0) {
a = a.multiply(expression(r[1].genericValue()));
s = r[2];
d[1].divide();
d[0].divide();
continue loop;
}
}
}
}
result = a.multiply(n[0].multiply(m).genericValue());
}
Generic getValue() {
return GenericVariable.content(result, true);
}
}
class Linearization {
Variable unknown[];
List result = new ArrayList();
Linearization(Variable unknown[]) {
this.unknown = unknown;
}
static Generic[][] compute(Generic generic[], Variable unknown[]) {
Linearization l = new Linearization(unknown);
Debug.println("linearization");
Debug.increment();
l.process(generic);
Debug.decrement();
return l.getValue();
}
static Polynomial[] linearize(Polynomial polynomial, Variable variable) {
List l = new ArrayList();
Generic x = variable.expressionValue();
Polynomial s = polynomial;
try {
Polynomial r = s.valueOf(x);
s = s.divide(r);
l.add(r);
while (true) s = s.divide(r);
} catch (NotDivisibleException e) {
}
IntegerDivisor d[] = new IntegerDivisor[2];
Generic p[] = new Generic[2];
Generic q[] = new Generic[2];
d[1] = IntegerDivisor.create(JsclInteger.valueOf(1));
loop:
while (d[1].hasNext()) {
p[1] = (Generic) d[1].next();
q[1] = d[1].integer(d[1].complementary());
d[0] = IntegerDivisor.create(s.tail().coef().integerValue());
while (d[0].hasNext()) {
p[0] = (Generic) d[0].next();
q[0] = d[0].integer(d[0].complementary());
if (ArrayComparator.comparator.compare(q, p) < 0) break loop;
for (int i = 0; i < 2; i++) {
Polynomial r = s.valueOf(i == 0 ? p[1].multiply(x).subtract(p[0]) : p[1].multiply(x).add(p[0]));
for (boolean flag = true; true; flag = false) {
try {
s = s.divide(r);
} catch (NotDivisibleException e) {
break;
}
d[1].divide();
d[0].divide();
if (flag) l.add(r);
}
}
}
}
return (Polynomial[]) ArrayUtils.toArray(l, new Polynomial[l.size()]);
}
void process(Generic generic[]) {
boolean flag = true;
for (int i = 0; i < generic.length; i++) {
Generic s = generic[i];
Variable va[] = s.variables();
if (va.length == 1) {
Variable t = va[0];
Polynomial p = Polynomial.factory(t).valueOf(s);
if (p.degree() > 1) {
flag = false;
Polynomial r[] = linearize(p, t);
for (int j = 0; j < r.length; j++) {
process(Basis.compute(Basis.augment(new Generic[]{r[j].genericValue()}, generic), unknown).elements());
}
}
} else flag = false;
}
if (flag) result.add(generic);
}
Generic[][] getValue() {
return (Generic[][]) ArrayUtils.toArray(result, new Generic[result.size()][]);
}
}
class Divisor implements Iterator {
Monomial monomial;
Monomial current;
Iterator iterator;
Divisor(Monomial monomial) {
this.monomial = monomial;
iterator = monomial.divisor();
}
Monomial complementary() {
return monomial.divide(current);
}
void divide() {
monomial = complementary();
iterator = monomial.divisor(current);
}
public boolean hasNext() {
return iterator.hasNext();
}
public Object next() {
return current = (Monomial) iterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
class IntegerDivisor extends Divisor {
IntegerDivisor(Generic generic, Variable unknown[], Ordering ordering) {
super(Polynomial.factory(unknown, ordering).valueOf(generic).head().monomial());
}
static IntegerDivisor create(JsclInteger integer) {
Generic a = Factorization.factorize(integer);
return new IntegerDivisor(a, a.variables(), Monomial.iteratorOrdering);
}
public Object next() {
return integer((Monomial) super.next());
}
Generic integer(Monomial monomial) {
return Expression.valueOf(Literal.valueOf(monomial)).expand();
}
}