package jscl.math.polynomial.groebner;
import jscl.math.Debug;
import jscl.math.Generic;
import jscl.math.polynomial.Basis;
import jscl.math.polynomial.Monomial;
import jscl.math.polynomial.Ordering;
import jscl.math.polynomial.Polynomial;
import jscl.util.ArrayUtils;
import java.util.*;
public class Standard {
final int flags;
final Comparator comparator;
final Map pairs;
final List polys = new ArrayList();
final Map removed = new TreeMap();
int npairs;
int npolys;
Standard(int flags) {
this.flags = flags;
pairs = new TreeMap(comparator = (flags & Basis.SUGAR) > 0 ? Sugar.comparator : Natural.comparator);
}
public static Basis compute(Basis basis) {
return compute(basis, 0);
}
public static Basis compute(Basis basis, int flags) {
return compute(basis, flags, (flags & Basis.INSTRUMENTED) > 0);
}
static Basis compute(Basis basis, int flags, boolean instrumented) {
Standard a = instrumented ? new Instrumented(flags) : algorithm(basis.ordering(), flags);
a.computeValue(basis);
basis = basis.valueof(a.elements());
if (instrumented) return compute(basis, flags, false);
return basis;
}
static Standard algorithm(Ordering ordering, int flags) {
switch (flags & Basis.ALGORITHM) {
case Basis.F4:
return new F4(ordering, flags);
case Basis.BLOCK:
return new Block(ordering, flags);
default:
return new Standard(flags);
}
}
static Polynomial reduce(Pair pair, Collection ideal) {
Debug.println(pair);
return s_polynomial(pair.polynomial[0], pair.polynomial[1]).reduce(ideal, false).normalize().freeze();
}
static Polynomial s_polynomial(Polynomial p1, Polynomial p2) {
Monomial m1 = p1.head().monomial();
Monomial m2 = p2.head().monomial();
Monomial m = m1.gcd(m2);
m1 = m1.divide(m);
m2 = m2.divide(m);
return p1.multiply(m2).reduce(p1.head().coef(), m1, p2);
}
void computeValue(Basis basis) {
Debug.println(basis);
populate(basis);
npolys = 0;
compute();
remove();
reduce();
Debug.println("signature = (" + npairs + ", " + npolys + ", " + polys.size() + ")");
}
void populate(Basis basis) {
List list = new ArrayList();
Generic a[] = basis.elements();
for (int i = 0; i < a.length; i++) list.add(basis.polynomial(a[i]));
add(list);
}
void add(List list) {
Iterator it = list.iterator();
while (it.hasNext()) {
Polynomial p = (Polynomial) it.next();
if (p.signum() != 0) add(p);
}
}
void compute() {
Debug.println("evaluate");
while (!pairs.isEmpty()) {
Pair pa = (Pair) pairs.keySet().iterator().next();
process(pa);
remove(pa);
}
}
void process(Pair pair) {
if (criterion(pair)) return;
Polynomial p = reduce(pair, polys);
if (p.signum() != 0) add(p);
npairs++;
}
void remove(Pair pair) {
pairs.remove(pair);
if (pair.reduction) removed.put(pair.principal, null);
}
void add(Polynomial polynomial) {
polynomial.setIndex(polys.size());
Debug.println("(" + polynomial.head().monomial() + ", " + polynomial.index() + ")");
if ((flags & Basis.GM_SETTING) > 0) makePairsGM(polynomial);
else makePairs(polynomial);
polys.add(polynomial);
npolys++;
}
boolean criterion(Pair pair) {
return (flags & Basis.GM_SETTING) > 0 ? false : b_criterion(pair);
}
void makePairs(Polynomial polynomial) {
Iterator it = polys.iterator();
while (it.hasNext()) {
Polynomial p = (Polynomial) it.next();
Pair pa = new Pair(p, polynomial);
if (!pa.coprime) pairs.put(pa, null);
}
}
boolean b_criterion(Pair pair) {
Iterator it = polys.iterator();
while (it.hasNext()) {
Polynomial p = (Polynomial) it.next();
if (pair.scm.multiple(p.head().monomial())) {
Pair pa1 = new Pair(sort(pair.polynomial[0], p));
Pair pa2 = new Pair(sort(pair.polynomial[1], p));
if (considered(pa1) && considered(pa2)) return true;
}
}
return false;
}
boolean considered(Pair pair) {
return !pairs.containsKey(pair);
}
Polynomial[] sort(Polynomial p1, Polynomial p2) {
return p1.index() < p2.index() ? new Polynomial[]{p1, p2} : new Polynomial[]{p2, p1};
}
void makePairsGM(Polynomial polynomial) {
List list = new ArrayList();
Iterator it = pairs.keySet().iterator();
while (it.hasNext()) {
Pair pa = (Pair) it.next();
Pair p1 = new Pair(new Polynomial[]{pa.polynomial[0], polynomial});
Pair p2 = new Pair(new Polynomial[]{pa.polynomial[1], polynomial});
if (multiple(pa, p1) && multiple(pa, p2)) list.add(pa);
}
int n = list.size();
for (int i = 0; i < n; i++) {
Pair pa = (Pair) list.get(i);
remove(pa);
}
Map map = new TreeMap((flags & Basis.SUGAR) > 0 && (flags & Basis.FUSSY) > 0 ? Sugar.comparator : Natural.comparator);
it = polys.iterator();
while (it.hasNext()) {
Polynomial p = (Polynomial) it.next();
Pair pa = new Pair(p, polynomial);
pairs.put(pa, null);
map.put(pa, null);
}
list = ArrayUtils.toList(map.keySet());
n = list.size();
for (int i = 0; i < n; i++) {
Pair pa = (Pair) list.get(i);
for (int j = i + 1; j < n; j++) {
Pair pa2 = (Pair) list.get(j);
if (pa2.scm.multiple(pa.scm)) remove(pa2);
}
if (pa.coprime) remove(pa);
}
}
boolean multiple(Pair p1, Pair p2) {
return p1.scm.multiple(p2.scm, true) && ((flags & Basis.SUGAR) > 0 && (flags & Basis.FUSSY) > 0 ? Sugar.comparator.compare(p1, p2) > 0 : true);
}
void remove() {
Iterator it = polys.iterator();
while (it.hasNext()) if (removed.containsKey(it.next())) it.remove();
}
void reduce() {
Debug.println("reduce");
Map map = new TreeMap();
int size = polys.size();
for (int i = 0; i < size; i++) {
Polynomial p = (Polynomial) polys.get(i);
polys.set(i, p = p.reduce(polys, true).normalize().freeze());
Debug.println("(" + p.head().monomial() + ")");
map.put(p, null);
}
polys.clear();
polys.addAll(map.keySet());
}
Generic[] elements() {
int size = polys.size();
Generic a[] = new Generic[size];
for (int i = 0; i < size; i++) {
a[i] = ((Polynomial) polys.get(i)).genericValue();
}
return a;
}
}