001/*
002 * $Id$
003 */
004
005package edu.jas.application;
006
007
008import java.io.Reader;
009import java.util.ArrayList;
010import java.util.List;
011import java.util.Random;
012
013import org.apache.logging.log4j.Logger;
014import org.apache.logging.log4j.LogManager; 
015
016import edu.jas.gb.SolvableGroebnerBaseAbstract;
017import edu.jas.gbufd.SGBFactory;
018import edu.jas.gbufd.SolvableSyzygyAbstract;
019import edu.jas.gbufd.SolvableSyzygySeq;
020import edu.jas.kern.StringUtil;
021import edu.jas.poly.GenPolynomial;
022import edu.jas.poly.GenSolvablePolynomial;
023import edu.jas.poly.GenSolvablePolynomialRing;
024import edu.jas.poly.PolynomialList;
025import edu.jas.structure.GcdRingElem;
026import edu.jas.structure.QuotPairFactory;
027import edu.jas.structure.RingFactory;
028
029
030/**
031 * SolvableLocalResidue ring factory for SolvableLocalResidue based on
032 * GenSolvablePolynomial with GcdRingElem interface. Objects of this class are
033 * immutable. It represents the "classical quotient ring modulo an ideal".
034 * @author Heinz Kredel
035 */
036public class SolvableLocalResidueRing<C extends GcdRingElem<C>> implements
037                RingFactory<SolvableLocalResidue<C>>,
038                QuotPairFactory<GenPolynomial<C>, SolvableLocalResidue<C>> {
039
040
041    // Can not extend SolvableLocalRing or SolvableQuotientRing 
042    // because of different constructor semantics.
043
044
045    private static final Logger logger = LogManager.getLogger(SolvableLocalResidueRing.class);
046
047
048    private static final boolean debug = logger.isDebugEnabled();
049
050
051    /**
052     * Solvable polynomial ring of the factory.
053     */
054    public final GenSolvablePolynomialRing<C> ring;
055
056
057    /**
058     * Solvable polynomial ideal for the reduction.
059     */
060    public final SolvableIdeal<C> ideal;
061
062
063    /**
064     * Syzygy engine of the factory.
065     */
066    public final SolvableSyzygyAbstract<C> engine;
067
068
069    /**
070     * Groebner base engine.
071     */
072    protected final SolvableGroebnerBaseAbstract<C> bb;
073
074
075    /**
076     * Indicator if this ring is a field.
077     */
078    protected int isField = -1; // initially unknown
079
080
081    /**
082     * The constructor creates a SolvableLocalResidueRing object from a
083     * SolvableIdeal.
084     * @param i ideal in solvable polynomial ring.
085     */
086    public SolvableLocalResidueRing(SolvableIdeal<C> i) {
087        if (i == null) {
088            throw new IllegalArgumentException("ideal may not be null");
089        }
090        ring = i.getRing();
091        ideal = i.GB(); // cheap if isGB
092        if (ideal.isONE()) {
093            throw new IllegalArgumentException("ideal may not be 1");
094        }
095        if (ideal.isMaximal()) {
096            isField = 1;
097            //} else if (ideal.isPrime()) {
098            //    isField = 1;
099        } else {
100            //isField = 0;
101            logger.warn("ideal not maximal and not known to be prime");
102            //throw new IllegalArgumentException("ideal must be prime or maximal");
103        }
104        engine = new SolvableSyzygySeq<C>(ring.coFac);
105        bb = SGBFactory.getImplementation(ring.coFac); //new SolvableGroebnerBaseSeq<C>();
106        logger.debug("solvable local residue ring constructed");
107    }
108
109
110    /**
111     * Factory for base elements.
112     */
113    public GenSolvablePolynomialRing<C> pairFactory() {
114        return ring;
115    }
116
117
118    /**
119     * Create from numerator.
120     */
121    @SuppressWarnings("unchecked")
122    public SolvableLocalResidue<C> create(GenPolynomial<C> n) {
123        return new SolvableLocalResidue<C>(this, (GenSolvablePolynomial<C>) n);
124    }
125
126
127    /**
128     * Create from numerator, denominator pair.
129     */
130    @SuppressWarnings("unchecked")
131    public SolvableLocalResidue<C> create(GenPolynomial<C> n, GenPolynomial<C> d) {
132        return new SolvableLocalResidue<C>(this, (GenSolvablePolynomial<C>) n, (GenSolvablePolynomial<C>) d);
133    }
134
135
136    /**
137     * Is this structure finite or infinite.
138     * @return true if this structure is finite, else false.
139     */
140    public boolean isFinite() {
141        return ring.isFinite() && bb.commonZeroTest(ideal.getList()) <= 0;
142    }
143
144
145    /**
146     * Copy SolvableLocalResidue element c.
147     * @param c
148     * @return a copy of c.
149     */
150    public SolvableLocalResidue<C> copy(SolvableLocalResidue<C> c) {
151        return new SolvableLocalResidue<C>(c.ring, c.num, c.den, true);
152    }
153
154
155    /**
156     * Get the zero element.
157     * @return 0 as SolvableLocalResidue.
158     */
159    public SolvableLocalResidue<C> getZERO() {
160        return new SolvableLocalResidue<C>(this, ring.getZERO());
161    }
162
163
164    /**
165     * Get the one element.
166     * @return 1 as SolvableLocalResidue.
167     */
168    public SolvableLocalResidue<C> getONE() {
169        return new SolvableLocalResidue<C>(this, ring.getONE());
170    }
171
172
173    /**
174     * Get a list of the generating elements.
175     * @return list of generators for the algebraic structure.
176     */
177    public List<SolvableLocalResidue<C>> generators() {
178        List<GenSolvablePolynomial<C>> pgens = PolynomialList.<C> castToSolvableList(ring.generators());
179        List<SolvableLocalResidue<C>> gens = new ArrayList<SolvableLocalResidue<C>>(pgens.size() * 2 - 1);
180        GenSolvablePolynomial<C> one = ring.getONE();
181        for (GenSolvablePolynomial<C> p : pgens) {
182            SolvableLocalResidue<C> q = new SolvableLocalResidue<C>(this, p);
183            if (!q.isZERO() && !gens.contains(q)) {
184                gens.add(q);
185                if (!p.isONE() && !ideal.contains(p)) {
186                    q = new SolvableLocalResidue<C>(this, one, p);
187                    gens.add(q);
188                }
189            }
190        }
191        return gens;
192    }
193
194
195    /**
196     * Query if this ring is commutative.
197     * @return true if this ring is commutative, else false.
198     */
199    public boolean isCommutative() {
200        return ring.isCommutative();
201    }
202
203
204    /**
205     * Query if this ring is associative.
206     * @return true if this ring is associative, else false.
207     */
208    @SuppressWarnings("unused")
209    public boolean isAssociative() {
210        if (!ring.isAssociative()) {
211            return false;
212        }
213        SolvableLocalResidue<C> Xi, Xj, Xk, p, q;
214        List<SolvableLocalResidue<C>> gens = generators();
215        int ngen = gens.size();
216        for (int i = 0; i < ngen; i++) {
217            Xi = gens.get(i);
218            for (int j = i + 1; j < ngen; j++) {
219                Xj = gens.get(j);
220                for (int k = j + 1; k < ngen; k++) {
221                    Xk = gens.get(k);
222                    if (Xi.num.degree() == 0 && Xj.num.degree() == 0 && Xk.num.degree() == 0 &&
223                        Xi.den.degree() == 0 && Xj.den.degree() == 0 && Xk.den.degree() == 0) {
224                        //System.out.println("lr degree == 0");
225                        continue; // skip all base elements
226                    }
227                    try {
228                        p = Xk.multiply(Xj).multiply(Xi);
229                        q = Xk.multiply(Xj.multiply(Xi));
230                    } catch (IllegalArgumentException e) {
231                        e.printStackTrace();
232                        continue; // ignore undefined multiplication
233                    }
234                    if (p.num.equals(q.num) && p.den.equals(q.den)) { // short cut
235                        continue;
236                    }
237                    if (!p.equals(q)) {
238                        //System.out.println("lr assoc: p = " + p.toScript());
239                        //System.out.println("lr assoc: q = " + q.toScript());
240                        //System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript());
241                        logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi);
242                        logger.info("p = ( Xk * Xj ) * Xi = {}", p);
243                        logger.info("q = Xk * ( Xj * Xi ) = {}", q);
244                        return false;
245                    }
246                }
247            }
248        }
249        return true;
250    }
251
252
253    /**
254     * Query if this ring is a field.
255     * @return true.
256     */
257    public boolean isField() {
258        if (isField > 0) {
259            return true;
260        }
261        if (isField == 0) {
262            return false;
263        }
264        // not reached
265        return false;
266    }
267
268
269    /**
270     * Characteristic of this ring.
271     * @return characteristic of this ring.
272     */
273    public java.math.BigInteger characteristic() {
274        return ring.characteristic();
275    }
276
277
278    /**
279     * Get a SolvableLocalResidue element from a BigInteger value.
280     * @param a BigInteger.
281     * @return a SolvableLocalResidue.
282     */
283    public SolvableLocalResidue<C> fromInteger(java.math.BigInteger a) {
284        return new SolvableLocalResidue<C>(this, ring.fromInteger(a));
285    }
286
287
288    /**
289     * Get a SolvableLocalResidue element from a long value.
290     * @param a long.
291     * @return a SolvableLocalResidue.
292     */
293    public SolvableLocalResidue<C> fromInteger(long a) {
294        return new SolvableLocalResidue<C>(this, ring.fromInteger(a));
295    }
296
297
298    /**
299     * Get the String representation as RingFactory.
300     */
301    @Override
302    public String toString() {
303        return "SolvableLocalResidueRing[ " + ideal.toString() + " ]";
304    }
305
306
307    /**
308     * Get a scripting compatible string representation.
309     * @return script compatible representation for this ElemFactory.
310     */
311    @Override
312    public String toScript() {
313        // Python case
314        return "SLR(" + ideal.list.toScript() + ")";
315    }
316
317
318    /**
319     * Comparison with any other object.
320     */
321    @Override
322    @SuppressWarnings("unchecked")
323    public boolean equals(Object b) {
324        if (!(b instanceof SolvableLocalResidueRing)) {
325            return false;
326        }
327        SolvableLocalResidueRing<C> a = null;
328        try {
329            a = (SolvableLocalResidueRing<C>) b;
330        } catch (ClassCastException e) {
331        }
332        if (a == null) {
333            return false;
334        }
335        return ring.equals(a.ring);
336    }
337
338
339    /**
340     * Hash code for this quotient ring.
341     */
342    @Override
343    public int hashCode() {
344        int h;
345        h = ideal.hashCode();
346        return h;
347    }
348
349
350    /**
351     * SolvableLocalResidue random.
352     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
353     * @return a random quotient element.
354     */
355    public SolvableLocalResidue<C> random(int n) {
356        GenSolvablePolynomial<C> r = ring.random(n).monic();
357        r = ideal.normalform(r);
358        GenSolvablePolynomial<C> s;
359        do {
360            s = ring.random(n).monic();
361            s = ideal.normalform(s);
362        } while (s.isZERO());
363        return new SolvableLocalResidue<C>(this, r, s, false);
364    }
365
366
367    /**
368     * Generate a random quotient.
369     * @param k bitsize of random coefficients.
370     * @param l number of terms.
371     * @param d maximal degree in each variable.
372     * @param q density of nozero exponents.
373     * @return a random quotient.
374     */
375    public SolvableLocalResidue<C> random(int k, int l, int d, float q) {
376        GenSolvablePolynomial<C> r = ring.random(k, l, d, q).monic();
377        r = ideal.normalform(r);
378        GenSolvablePolynomial<C> s;
379        do {
380            s = ring.random(k, l, d, q).monic();
381            s = ideal.normalform(s);
382        } while (s.isZERO());
383        return new SolvableLocalResidue<C>(this, r, s, false);
384    }
385
386
387    /**
388     * SolvableLocalResidue random.
389     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
390     * @param rnd is a source for random bits.
391     * @return a random quotient element.
392     */
393    public SolvableLocalResidue<C> random(int n, Random rnd) {
394        GenSolvablePolynomial<C> r = ring.random(n, rnd).monic();
395        r = ideal.normalform(r);
396        GenSolvablePolynomial<C> s;
397        do {
398            s = ring.random(n, rnd).monic();
399            s = ideal.normalform(s);
400        } while (s.isZERO());
401        return new SolvableLocalResidue<C>(this, r, s, false);
402    }
403
404
405    /**
406     * Parse SolvableLocalResidue from String. Syntax:
407     * "{ polynomial | polynomial }" or "{ polynomial }" or
408     * " polynomial | polynomial " or " polynomial "
409     * @param s String.
410     * @return SolvableLocalResidue from s.
411     */
412    public SolvableLocalResidue<C> parse(String s) {
413        int i = s.indexOf("{");
414        if (i >= 0) {
415            s = s.substring(i + 1);
416        }
417        i = s.lastIndexOf("}");
418        if (i >= 0) {
419            s = s.substring(0, i);
420        }
421        i = s.indexOf("|");
422        if (i < 0) {
423            GenSolvablePolynomial<C> n = ring.parse(s);
424            return new SolvableLocalResidue<C>(this, n);
425        }
426        String s1 = s.substring(0, i);
427        String s2 = s.substring(i + 1);
428        GenSolvablePolynomial<C> n = ring.parse(s1);
429        GenSolvablePolynomial<C> d = ring.parse(s2);
430        return new SolvableLocalResidue<C>(this, n, d);
431    }
432
433
434    /**
435     * Parse SolvableLocalResidue from Reader.
436     * @param r Reader.
437     * @return next SolvableLocalResidue from r.
438     */
439    public SolvableLocalResidue<C> parse(Reader r) {
440        String s = StringUtil.nextPairedString(r, '{', '}');
441        return parse(s);
442    }
443
444}