/*
 * $Id$
 */

package edu.jas.poly;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.log4j.Logger;

import edu.jas.kern.PrettyPrint;
import edu.jas.structure.RingElem;


/**
 * RelationTable for solvable polynomials. This class maintains the
 * non-commutative multiplication relations of solvable polynomial rings. The
 * table entries are initialized with relations of the form xj *
 * xi = pij. During multiplication the relations are
 * updated by relations of the form xjk *
 * xil = pijkl. If no relation for
 * xj * xi is found in the table, this multiplication is
 * assumed to be commutative xi xj. Can also be used for
 * relations between coefficients and main variables.
 * @author Heinz Kredel
 */

public class RelationTable> implements Serializable {


    /**
     * The data structure for the relations.
     */
    public final Map, List> table;


    /**
     * The factory for the solvable polynomial ring.
     */
    public final GenSolvablePolynomialRing ring;


    /**
     * Usage indicator: table or coeffTable.
     */
    public final boolean coeffTable;


    private static final Logger logger = Logger.getLogger(RelationTable.class);


    private final boolean debug = logger.isDebugEnabled();


    /**
     * Constructor for RelationTable requires ring factory. Note: This
     * constructor is called within the constructor of the ring factory, so
     * methods of this class can only be used after the other constructor has
     * terminated.
     * @param r solvable polynomial ring factory.
     */
    public RelationTable(GenSolvablePolynomialRing r) {
        this(r, false);
    }


    /**
     * Constructor for RelationTable requires ring factory. Note: This
     * constructor is called within the constructor of the ring factory, so
     * methods of this class can only be used after the other constructor has
     * terminated.
     * @param r solvable polynomial ring factory.
     * @param coeffTable indicator for coeffTable.
     */
    public RelationTable(GenSolvablePolynomialRing r, boolean coeffTable) {
        table = new HashMap, List>();
        ring = r;
        if (ring == null) {
            throw new IllegalArgumentException("RelationTable no ring");
        }
        this.coeffTable = coeffTable;
    }


    /**
     * RelationTable equals. Tests same keySets only, not relations itself. Will
     * be improved in the future.
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    @SuppressWarnings("unchecked")
    public boolean equals(Object p) {
        if (!(p instanceof RelationTable)) {
            logger.info("no RelationTable");
            return false;
        }
        RelationTable tab = null;
        try {
            tab = (RelationTable) p;
        } catch (ClassCastException ignored) {
        }
        if (tab == null) {
            return false;
        }
        // not possible because of infinite recursion:
        //if (!ring.equals(tab.ring)) {
        //    logger.info("not same Ring " + ring.toScript() + ", " + tab.ring.toScript());
        //    return false;
        //}
        if (!table.keySet().equals(tab.table.keySet())) {
            logger.info("keySet != :  a = " + table.keySet() + ", b = " + tab.table.keySet());
            return false;
        }
        for (List k : table.keySet()) {
            List a = table.get(k);
            List b = tab.table.get(k);
            // check contents, but only base relations
            Map> t1ex = fromListDeg2(a);
            Map> t2ex = fromListDeg2(b);
            if (!equalMaps(t1ex, t2ex)) {
                //System.out.println("a != b, a = " + t1ex + ", b = " + t2ex);
                return false;
            }
        }
        return true;
    }


    /**
     * Convert mixed list to map for base relations.
     * @param a mixed list
     * @returns a map constructed from the list with deg(key) == 2.
     */
    @SuppressWarnings("unchecked")
    Map> fromListDeg2(List a) {
        Map> tex = new HashMap>();
        Iterator ait = a.iterator();
        while (ait.hasNext()) {
            ExpVectorPair ae = (ExpVectorPair) ait.next();
            if (!ait.hasNext()) {
                break;
            }
            GenPolynomial p = (GenPolynomial) ait.next();
            if (ae.totalDeg() == 2) { // only base relations
                //System.out.println("ae => p: " + ae + " => " + p);
                tex.put(ae, p);
            }
        }
        return tex;
    }


    /**
     * Equals for special maps.
     * @param m1 first map
     * @param m2 second map
     * @returns true if both maps are equal
     */
    @SuppressWarnings("unchecked")
    boolean equalMaps(Map> m1, Map> m2) {
        if (!m1.keySet().equals(m2.keySet())) {
            return false;
        }
        for (ExpVectorPair ep : m1.keySet()) {
            GenPolynomial p1 = m1.get(ep);
            GenPolynomial p2 = m2.get(ep);
            if (p1.compareTo(p2) != 0) { // not working: !p1.equals(p2)) { // TODO
                logger.info("ep = " + ep + ", p1 = " + p1 + ", p2 = " + p2);
                //logger.info("p1.compareTo(p2) = " + p1.compareTo(p2));
                //logger.info("p1.equals(p2) = " + p1.equals(p2));
                return false;
            }
        }
        return true;
    }


    /**
     * Hash code for this relation table.
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        int h;
        h = ring.hashCode();
        h = 31 * h + table.hashCode();
        return h;
    }


    /**
     * Test if the table is empty.
     * @return true if the table is empty, else false.
     */
    public boolean isEmpty() {
        return table.isEmpty();
    }


    /**
     * Get the String representation.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        List v;
        StringBuffer s = new StringBuffer("RelationTable[");
        boolean first = true;
        for (List k : table.keySet()) {
            if (first) {
                first = false;
            } else {
                s.append(", ");
            }
            s.append(k.toString());
            v = table.get(k);
            s.append("=");
            s.append(v.toString());
        }
        s.append("]");
        return s.toString();
    }


    /**
     * Get the String representation.
     * @param vars names for the variables.
     * @see java.lang.Object#toString()
     */
    @SuppressWarnings("unchecked")
    public String toString(String[] vars) {
        if (vars == null) {
            return toString();
        }
        StringBuffer s = new StringBuffer("");
        String[] cvars = null;
        if (coeffTable) {
            if (ring.coFac instanceof GenPolynomialRing) {
                cvars = ((GenPolynomialRing) (Object)ring.coFac).getVars();
            }
            s.append("Coefficient ");
        }
        s.append("RelationTable\n(");
        List v;
        if (PrettyPrint.isTrue()) {
            boolean first = true;
            for (List k : table.keySet()) {
                if (first) {
                    first = false;
                    s.append("\n");
                } else {
                    s.append(",\n");
                }
                v = table.get(k);
                for (Iterator jt = v.iterator(); jt.hasNext();) {
                    ExpVectorPair ep = (ExpVectorPair) jt.next();
                    GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                    if (ep.totalDeg() != 2) { // only base relations
                        continue;
                    }
                    s.append("( " + ep.getFirst().toString(vars) + " ), ");
                    if (cvars == null) {
                        s.append("( " + ep.getSecond().toString(vars) + " ), ");
                    } else {
                        s.append("( " + ep.getSecond().toString(cvars) + " ), ");
                    }
                    s.append("( " + p.toString(vars) + " )");
                    if (jt.hasNext()) {
                        s.append(",\n");
                    }
                }
            }
        } else {
            boolean first = true;
            for (List k : table.keySet()) {
                if (first) {
                    first = false;
                } else {
                    s.append(",\n");
                }
                v = table.get(k);
                for (Iterator jt = v.iterator(); jt.hasNext();) {
                    ExpVectorPair ep = (ExpVectorPair) jt.next();
                    s.append("( " + ep.getFirst().toString(vars) + " ), ");
                    if (coeffTable) {
                        s.append("( " + ep.getSecond().toString(cvars) + " ), ");
                    } else {
                        s.append("( " + ep.getSecond().toString(vars) + " ), ");
                    }
                    GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                    //s.append("( " + p.toString(vars) + " )");
                    s.append(" " + p.toString(vars));
                    if (jt.hasNext()) {
                        s.append(",\n");
                    }
                }
            }
        }
        s.append("\n)\n");
        return s.toString();
    }


    /**
     * Get a scripting compatible string representation.
     * @return script compatible representation for this relation table.
     */
    @SuppressWarnings("unchecked")
    public String toScript() {
        // Python case
        String[] vars = ring.vars;
        String[] cvars = null;
        if (coeffTable) {
            cvars = ((GenPolynomialRing) (Object)ring.coFac).vars;
        }
        List v;
        StringBuffer s = new StringBuffer("[");
        boolean first = true;
        for (List k : table.keySet()) {
            if (first) {
                first = false;
                s.append("");
            } else {
                s.append(", ");
            }
            v = table.get(k);
            for (Iterator jt = v.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                GenPolynomial p = (GenPolynomial) jt.next();
                if (ep.totalDeg() != 2) { // only base relations
                    continue;
                }
                s.append("" + ep.getFirst().toScript(vars) + ", ");
                if (coeffTable) {
                    s.append("" + ep.getSecond().toScript(cvars) + ", ");
                } else {
                    s.append("" + ep.getSecond().toScript(vars) + ", ");
                }
                //s.append("( " + p.toScript() + " )");
                s.append(" " + p.toScript());
                if (jt.hasNext()) {
                    s.append(", ");
                }
            }
        }
        s.append("]");
        return s.toString();
    }


    /**
     * Update or initialize RelationTable with new relation. relation is e * f =
     * p.
     * @param e first term.
     * @param f second term.
     * @param p solvable product polynomial.
     */
    @SuppressWarnings("unchecked")
    public synchronized void update(ExpVector e, ExpVector f, GenSolvablePolynomial p) {
        if (debug) {
            //System.out.println("new relation = " + e + " .*. " + f + " = " + p);
            if (p != null && p.ring.vars != null) {
                logger.info("new relation = " + e.toString(p.ring.vars) + " .*. " + f.toString(p.ring.vars)
                                + " = " + p);
                //logger.info("existing relations = " + toString(p.ring.vars));
            } else {
                logger.info("new relation = " + e + " .*. " + f + " = " + p);
            }
        }
        if (p == null || e == null || f == null) {
            throw new IllegalArgumentException("RelationTable update e|f|p == null");
        }
        if (debug) {
            if (e.totalDeg() == 1 && f.totalDeg() == 1) {
                int[] de = e.dependencyOnVariables();
                int[] df = f.dependencyOnVariables();
                logger.debug("update e ? f " + de[0] + " " + df[0]);
                //int t = ring.tord.getDescendComparator().compare(e,f);
                //System.out.println("update compare(e,f) = " + t);
                if (de[0] == df[0]) { // error 
                    throw new IllegalArgumentException("RelationTable update e==f");
                }
                if (de[0] > df[0]) { // invalid update 
                    logger.error("warning: update e > f " + e + " " + f + " changed");
                    ExpVector tmp = e;
                    e = f;
                    f = tmp;
                    Map.Entry m = p.leadingMonomial();
                    GenPolynomial r = p.subtract(m.getValue(), m.getKey());
                    r = r.negate();
                    p = (GenSolvablePolynomial) r.sum(m.getValue(), m.getKey());
                }
            }
        }
        // test equal HTs for left and right side
        if (!coeffTable) {
            ExpVector ef = e.sum(f);
            ExpVector lp = p.leadingExpVector();
            if (!ef.equals(lp)) { // check for suitable term order
                logger.error("relation term order = " + ring.tord);
                throw new IllegalArgumentException("RelationTable update e*f != lt(p): " + ef + ", lp = "
                                + lp);
            }
        } else {
            ExpVector lp = p.leadingExpVector();
            if (!e.equals(lp)) { // check for suitable term order
                logger.error("relation term order = " + ring.tord);
                throw new IllegalArgumentException("Coefficient RelationTable update e != lt(p): " + e
                                + ", lp = " + lp);
            }
            if (p.leadingBaseCoefficient() instanceof GenPolynomial) {
                lp = ((GenPolynomial) (Object)p.leadingBaseCoefficient()).leadingExpVector();
                if (!f.equals(lp)) { // check for suitable term order
                    logger.error("relation term order = " + ring.tord);
                    logger.error("Coefficient RelationTable update f != lt(lfcd(p)): " + e + ", f = " + f
                                    + ", p = " + p);
                    throw new IllegalArgumentException("Coefficient RelationTable update f != lt(lfcd(p)): "
                                    + e + ", f = " + f + ", p = " + p);
                }
            }
        }
        List key = makeKey(e, f);
        ExpVectorPair evp = new ExpVectorPair(e, f);
        if (key.size() != 2) {
            logger.warn("key = " + key + ", evp = " + evp);
        }
        List part = table.get(key);
        if (part == null) { // initialization only
            part = new LinkedList();
            part.add(evp);
            part.add(p);
            table.put(key, part);
            return;
        }
        Object skip;
        int index = -1;
        synchronized (part) { // with lookup()
            for (ListIterator it = part.listIterator(); it.hasNext();) {
                ExpVectorPair look = (ExpVectorPair) it.next();
                skip = it.next(); // skip poly
                if (look.isMultiple(evp)) {
                    index = it.nextIndex();
                    // last index of or first index of: break
                }
            }
            if (index < 0) {
                index = 0;
            }
            part.add(index, evp);
            part.add(index + 1, p);
        }
        // table.put( key, part ); // required??
    }


    /**
     * Update or initialize RelationTable with new relation. relation is e * f =
     * p.
     * @param E first term polynomial.
     * @param F second term polynomial.
     * @param p solvable product polynomial.
     */
    @SuppressWarnings("unchecked")
    public void update(GenPolynomial E, GenPolynomial F, GenSolvablePolynomial p) {
        if (E.isZERO() || F.isZERO()) {
            throw new IllegalArgumentException("polynomials may not be zero: " + E + ", " + F);
        }
        C ce = E.leadingBaseCoefficient();
        C cf = F.leadingBaseCoefficient();
        if (!ce.isONE()) {
            throw new IllegalArgumentException("lbcf of polynomials must be one: " + ce + ", " + cf
                            + ", p = " + p);
        }
        ExpVector e = E.leadingExpVector();
        ExpVector f = F.leadingExpVector();
        if (coeffTable && f.isZERO() && cf instanceof GenPolynomial) {
            f = ((GenPolynomial) (Object)cf).leadingExpVector();
        }
        //logger.info("update: " + e + " .*. " + f + " = " + p);
        update(e, f, p);
    }


    /**
     * Update or initialize RelationTable with new relation. relation is e * f =
     * p.
     * @param E first term polynomial.
     * @param F second term polynomial.
     * @param p product polynomial.
     */
    public void update(GenPolynomial E, GenPolynomial F, GenPolynomial p) {
        if (p.isZERO()) {
            throw new IllegalArgumentException("polynomial may not be zero: " + p);
        }
        if (p.isONE()) {
            throw new IllegalArgumentException("product of polynomials may not be one: " + p);
        }
        GenSolvablePolynomial sp = new GenSolvablePolynomial(ring, p.val);
        update(E, F, sp);
    }


    /**
     * Update or initialize RelationTable with new relation. relation is e * f =
     * p.
     * @param e first term.
     * @param f second term.
     * @param p solvable product polynomial.
     */
    public void update(ExpVector e, ExpVector f, GenPolynomial p) {
        if (p.isZERO()) {
            throw new IllegalArgumentException("polynomial may not be zero: " + p);
        }
        if (p.isONE()) {
            throw new IllegalArgumentException("product of polynomials may not be one: " + p);
        }
        GenSolvablePolynomial sp = new GenSolvablePolynomial(ring, p.val);
        update(e, f, sp);
    }


    /**
     * Lookup RelationTable for existing relation. Find p with e * f = p. If no
     * relation for e * f is contained in the table then return the symmetric
     * product p = 1 e f.
     * @param e first term.
     * @param f second term.
     * @return t table relation container, contains e' and f' with e f = e'
     *         lt(p) f'.
     */
    @SuppressWarnings("unchecked")
    public TableRelation lookup(ExpVector e, ExpVector f) {
        List key = makeKey(e, f);
        List part = table.get(key);
        if (part == null) { // symmetric product
            GenSolvablePolynomial p = null;
            if (!coeffTable) {
                ExpVector ef = e.sum(f);
                p = new GenSolvablePolynomial(ring, ring.getONECoefficient(), ef);
            } else {
                if (ring.coFac instanceof GenPolynomialRing) {
                    GenPolynomialRing cofac = (GenPolynomialRing) (Object)ring.coFac;
                    //System.out.println("f = " + f + ", e = " + e);
                    GenPolynomial pc = cofac.getZERO().sum(cofac.getONECoefficient(), f);
                    C c = (C) (Object)pc;
                    p = new GenSolvablePolynomial(ring, c, e);
                    //System.out.println("pc = " + pc + ", p = " + p);
                }
            }
            return new TableRelation(null, null, p);
        }
        // no distinction between coefficient f or polynomial f
        ExpVectorPair evp = new ExpVectorPair(e, f);
        ExpVector ep = null;
        ExpVector fp = null;
        ExpVectorPair look = null;
        GenSolvablePolynomial p = null;
        synchronized (part) { // with update()
            for (Iterator it = part.iterator(); it.hasNext();) {
                look = (ExpVectorPair) it.next();
                p = (GenSolvablePolynomial) it.next();
                if (evp.isMultiple(look)) {
                    ep = e.subtract(look.getFirst());
                    fp = f.subtract(look.getSecond());
                    if (ep.isZERO()) {
                        ep = null;
                    }
                    if (fp.isZERO()) {
                        fp = null;
                    }
                    if (debug) {
                        if (p != null && p.ring.vars != null) {
                            logger.info("found relation = " + e.toString(p.ring.vars) + " .*. "
                                            + f.toString(p.ring.vars) + " = " + p);
                        } else {
                            logger.info("found relation = " + e + " .*. " + f + " = " + p);
                        }
                    }
                    return new TableRelation(ep, fp, p);
                }
            }
        }
        // unreacheable code!
        throw new RuntimeException("no entry found in relation table for " + evp);
    }


    /**
     * Construct a key for (e,f).
     * @param e first term.
     * @param f second term.
     * @return k key for (e,f).
     */
    protected List makeKey(ExpVector e, ExpVector f) {
        int[] de = e.dependencyOnVariables();
        int[] df = f.dependencyOnVariables();
        List key = new ArrayList(de.length + df.length);
        for (int i = 0; i < de.length; i++) {
            key.add(Integer.valueOf(de[i]));
        }
        for (int i = 0; i < df.length; i++) {
            key.add(Integer.valueOf(df[i]));
        }
        return key;
    }


    /**
     * Size of the table.
     * @return n number of non-commutative relations.
     */
    public int size() {
        int s = 0;
        if (table == null) {
            return s;
        }
        for (Iterator it = table.values().iterator(); it.hasNext();) {
            List list = it.next();
            s += list.size() / 2;
        }
        return s;
    }


    /**
     * Extend variables. Used e.g. in module embedding. Extend all ExpVectors
     * and polynomials of the given relation table by i elements and put the
     * relations into this table, i.e. this should be empty.
     * @param tab a relation table to be extended and inserted into this.
     */
    @SuppressWarnings("unchecked")
    public void extend(RelationTable tab) {
        if (tab.table.size() == 0) {
            return;
        }
        // assert this.size() == 0
        int i = ring.nvar - tab.ring.nvar;
        int j = 0;
        long k = 0l;
        List val;
        for (List key : tab.table.keySet()) {
            val = tab.table.get(key);
            for (Iterator jt = val.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                ExpVector e = ep.getFirst();
                ExpVector f = ep.getSecond();
                GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                ExpVector ex = e.extend(i, j, k);
                ExpVector fx;
                if (coeffTable) {
                    fx = f;
                } else {
                    fx = f.extend(i, j, k);
                }
                GenSolvablePolynomial px = (GenSolvablePolynomial) p.extend(ring, j, k);
                this.update(ex, fx, px);
            }
        }
        return;
    }


    /**
     * Contract variables. Used e.g. in module embedding. Contract all
     * ExpVectors and polynomials of the given relation table by i elements and
     * put the relations into this table, i.e. this should be empty.
     * @param tab a relation table to be contracted and inserted into this.
     */
    @SuppressWarnings("unchecked")
    public void contract(RelationTable tab) {
        if (tab.table.size() == 0) {
            return;
        }
        // assert this.size() == 0
        int i = tab.ring.nvar - ring.nvar;
        List val;
        for (List key : tab.table.keySet()) {
            val = tab.table.get(key);
            //System.out.println("key = " + key + ", val = " + val);
            for (Iterator jt = val.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                ExpVector e = ep.getFirst();
                ExpVector f = ep.getSecond();
                GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                ExpVector ec = e.contract(i, e.length() - i);
                ExpVector fc;
                if (coeffTable) {
                    fc = f;
                } else {
                    fc = f.contract(i, f.length() - i);
                }
                //System.out.println("ec = " + ec + ", fc = " + fc);
                if (ec.isZERO()) {
                    continue;
                }
                Map> mc = p.contract(ring);
                if (mc.size() != 1) {
                    continue;
                }
                GenPolynomial pc = mc.values().iterator().next();
                this.update(ec, fc, pc);
            }
        }
        return;
    }


    /**
     * Recursive representation. Split all ExpVectors and polynomials of the
     * given relation table to lower elements and upper elements and put the
     * relations into this table or this as coefficient table, i.e. this should
     * be empty.
     * @param tab a relation table to be contracted and inserted into this.
     */
    @SuppressWarnings("unchecked")
    public void recursive(RelationTable tab) { //
        if (tab.table.size() == 0) {
            return;
        }
        //System.out.println("rel ring = " + ring.toScript());
        // assert this.size() == 0
        GenPolynomialRing cring = (GenPolynomialRing) (Object)ring.coFac;
        //System.out.println("cring    = " + cring.toScript());
        GenSolvablePolynomial pc;
        int i = ring.nvar; // tab.ring.nvar -
        for (Object okey : tab.table.keySet()) {
            List key = (List) okey;
            List val = (List) tab.table.get(key);
            //System.out.println("key = " + key + ", val = " + val);
            for (Iterator jt = val.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                ExpVector e = ep.getFirst();
                ExpVector f = ep.getSecond();
                GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                ExpVector ec = e.contract(0, i);
                ExpVector fc;
                if (coeffTable) {
                    fc = f;
                } else {
                    fc = f.contract(0, i);
                }
                //System.out.println("ec = " + ec + ", fc = " + fc);
                if (ec.isZERO()) {
                    continue;
                }
                Map> mc = p.contract(cring);
                //System.out.println("mc = " + mc + ", p = " + p);
                //System.out.println("mc.ring = " + mc.values().iterator().next().ring.toScript());
                if (mc.size() == 1) { // < 1 only for p == 0
                    pc = (GenSolvablePolynomial) mc.values().iterator().next();
                    this.update(ec, fc, pc);
                } else { // construct recursive polynomial
                    GenSolvablePolynomial qr = ring.getZERO();
                    for (Map.Entry> mce : mc.entrySet()) {
                        ExpVector g = mce.getKey();
                        GenPolynomial q = mce.getValue();
                        C cq = (C) (Object)q;
                        GenSolvablePolynomial qp = new GenSolvablePolynomial(ring, cq, g);
                        qr = (GenSolvablePolynomial) qr.sum(qp);
                    }
                    if (coeffTable) {
                        fc = ((GenPolynomial) (Object)qr.leadingBaseCoefficient()).leadingExpVector();
                    }
                    if (fc.isZERO()) {
                        continue;
                    }
                    //System.out.println("ec = " + ec + ", fc = " + fc + ", qr = " + qr);
                    if (coeffTable) {
                        logger.info("coeffTable: adding " + qr);
                    } else {
                        logger.info("no coeffTable: adding " + qr);
                    }
                    this.update(ec, fc, qr);
                }
            }
        }
        return;
    }


    /**
     * Reverse variables and relations. Used e.g. in opposite rings. Reverse all
     * ExpVectors and polynomials of the given relation table and put the
     * modified relations into this table, i.e. this should be empty.
     * @param tab a relation table to be reverted and inserted into this.
     */
    @SuppressWarnings("unchecked")
    public void reverse(RelationTable tab) {
        if (tab.table.size() == 0) {
            return;
        }
        // assert this.size() == 0
        if (table.size() != 0) {
            logger.error("reverse table not empty");
        }
        int k = -1;
        if (ring.tord.getEvord2() != 0 && ring.partial) {
            k = ring.tord.getSplit();
        }
        logger.debug("k split = " + k);
        //System.out.println("k split = " + k );
        for (List key : tab.table.keySet()) {
            List val = tab.table.get(key);
            for (Iterator jt = val.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                ExpVector e = ep.getFirst();
                ExpVector f = ep.getSecond();
                GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                //logger.info("e pre reverse = " + e );
                //logger.info("f pre reverse = " + f );
                //logger.info("p pre reverse = " + p );
                ExpVector ex;
                ExpVector fx;
                GenSolvablePolynomial px;
                boolean change = true; // if relevant vars reversed
                if (k >= 0) {
                    ex = e.reverse(k);
                    if (coeffTable) {
                        fx = f;
                    } else {
                        fx = f.reverse(k);
                    }
                    int[] ed = ex.dependencyOnVariables(); // = e
                    if (ed.length == 0 || ed[0] >= k) { // k >= 0
                        change = false;
                    }
                    //int[] fd = fx.dependencyOnVariables(); // = f
                    //if (fd.length == 0 || fd[0] >= k) { // k >= 0
                    //    change = false;
                    //}
                } else {
                    ex = e.reverse();
                    if (coeffTable) {
                        fx = f;
                    } else {
                        fx = f.reverse();
                    }
                }
                px = (GenSolvablePolynomial) p.reverse(ring);
                //System.out.println("change = " + change );
                if (!change) {
                    this.update(e, f, px); // same order
                } else {
                    if (coeffTable) {
                        this.update(ex, fx, px); // same order
                    } else {
                        this.update(fx, ex, px); // opposite order
                    }
                }
            }
        }
        return;
    }


    /**
     * Convert relation table to list of polynomial triples.
     * @return rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations.
     */
    @SuppressWarnings("unchecked")
    public List> relationList() {
        List> rels = new ArrayList>();
        C one = ring.getONECoefficient();
        GenPolynomialRing cofac = null;
        if (coeffTable) {
            cofac = (GenPolynomialRing) (Object)ring.coFac; // up cast
        }
        for (List k : table.keySet()) {
            List v = table.get(k);
            for (Iterator jt = v.iterator(); jt.hasNext();) {
                ExpVectorPair ep = (ExpVectorPair) jt.next();
                ExpVector e = ep.getFirst();
                GenSolvablePolynomial pe = new GenSolvablePolynomial(ring, one, e);
                ExpVector f = ep.getSecond();
                GenSolvablePolynomial pf = null;
                if (coeffTable) {
                    GenPolynomial cpf = cofac.getONE().multiply(f);
                    C cf = (C) (Object)cpf; // down cast
                    pf = new GenSolvablePolynomial(ring, cf);
                } else {
                    pf = new GenSolvablePolynomial(ring, one, f);
                }
                GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next();
                rels.add(pe);
                rels.add(pf);
                rels.add(p);
            }
        }
        return rels;
    }


    /**
     * Add list of polynomial triples as relations.
     * @param rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations.
     *            Note: Only because of type erasure, aequivalent to
     *            addRelations().
     */
    @SuppressWarnings("unchecked")
    public void addSolvRelations(List> rel) {
        PolynomialList Prel = new PolynomialList(ring, rel);
        addRelations(Prel.getList());
    }


    /**
     * Add list of polynomial triples as relations.
     * @param rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations.
     */
    @SuppressWarnings("unchecked")
    public void addRelations(List> rel) {
        if (rel == null || rel.isEmpty()) {
            return;
        }
        Iterator> relit = rel.iterator();
        while (relit.hasNext()) {
            GenPolynomial E = relit.next();
            if (!relit.hasNext()) {
                throw new IllegalArgumentException("F and poly part missing");
            }
            GenPolynomial F = relit.next();
            if (!relit.hasNext()) {
                throw new IllegalArgumentException("poly part missing");
            }
            GenPolynomial P = relit.next();
            if (coeffTable && F.isConstant()) {
                F = (GenPolynomial) (Object)F.leadingBaseCoefficient(); // up cast
            }
            update(E, F, P);
        }
        return;
    }

}

 

Ads help maintain this website.