001/*
002 * $Id: SolvableLocalResidueRing.java 5868 2018-07-20 15:44:13Z kredel $
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                    // } else {
237                    //     int s = p.num.length() + q.num.length() + p.den.length() + q.den.length();
238                    //     if (s > 5) {
239                    //         System.out.println("lr assoc: p = " + p.toScript());
240                    //         System.out.println("lr assoc: q = " + q.toScript());
241                    //         System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript());
242                    //         System.out.println("lr size = " + s);
243                    //      continue;
244                    //     }
245                    }
246                    if (!p.equals(q)) {
247                        if (true || debug) {
248                            System.out.println("lr assoc: p = " + p.toScript());
249                            System.out.println("lr assoc: q = " + q.toScript());
250                            System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript());
251                            logger.info("Xk = " + Xk + ", Xj = " + Xj + ", Xi = " + Xi);
252                            logger.info("p = ( Xk * Xj ) * Xi = " + p);
253                            logger.info("q = Xk * ( Xj * Xi ) = " + q);
254                        }
255                        return false;
256                    }
257                }
258            }
259        }
260        return true;
261    }
262
263
264    /**
265     * Query if this ring is a field.
266     * @return true.
267     */
268    public boolean isField() {
269        if (isField > 0) {
270            return true;
271        }
272        if (isField == 0) {
273            return false;
274        }
275        // not reached
276        return false;
277    }
278
279
280    /**
281     * Characteristic of this ring.
282     * @return characteristic of this ring.
283     */
284    public java.math.BigInteger characteristic() {
285        return ring.characteristic();
286    }
287
288
289    /**
290     * Get a SolvableLocalResidue element from a BigInteger value.
291     * @param a BigInteger.
292     * @return a SolvableLocalResidue.
293     */
294    public SolvableLocalResidue<C> fromInteger(java.math.BigInteger a) {
295        return new SolvableLocalResidue<C>(this, ring.fromInteger(a));
296    }
297
298
299    /**
300     * Get a SolvableLocalResidue element from a long value.
301     * @param a long.
302     * @return a SolvableLocalResidue.
303     */
304    public SolvableLocalResidue<C> fromInteger(long a) {
305        return new SolvableLocalResidue<C>(this, ring.fromInteger(a));
306    }
307
308
309    /**
310     * Get the String representation as RingFactory.
311     */
312    @Override
313    public String toString() {
314        return "SolvableLocalResidueRing[ " + ideal.toString() + " ]";
315    }
316
317
318    /**
319     * Get a scripting compatible string representation.
320     * @return script compatible representation for this ElemFactory.
321     */
322    @Override
323    public String toScript() {
324        // Python case
325        return "SLR(" + ideal.list.toScript() + ")";
326    }
327
328
329    /**
330     * Comparison with any other object.
331     */
332    @Override
333    @SuppressWarnings("unchecked")
334    public boolean equals(Object b) {
335        if (!(b instanceof SolvableLocalResidueRing)) {
336            return false;
337        }
338        SolvableLocalResidueRing<C> a = null;
339        try {
340            a = (SolvableLocalResidueRing<C>) b;
341        } catch (ClassCastException e) {
342        }
343        if (a == null) {
344            return false;
345        }
346        return ring.equals(a.ring);
347    }
348
349
350    /**
351     * Hash code for this quotient ring.
352     */
353    @Override
354    public int hashCode() {
355        int h;
356        h = ideal.hashCode();
357        return h;
358    }
359
360
361    /**
362     * SolvableLocalResidue random.
363     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
364     * @return a random quotient element.
365     */
366    public SolvableLocalResidue<C> random(int n) {
367        GenSolvablePolynomial<C> r = ring.random(n).monic();
368        r = ideal.normalform(r);
369        GenSolvablePolynomial<C> s;
370        do {
371            s = ring.random(n).monic();
372            s = ideal.normalform(s);
373        } while (s.isZERO());
374        return new SolvableLocalResidue<C>(this, r, s, false);
375    }
376
377
378    /**
379     * Generate a random quotient.
380     * @param k bitsize of random coefficients.
381     * @param l number of terms.
382     * @param d maximal degree in each variable.
383     * @param q density of nozero exponents.
384     * @return a random quotient.
385     */
386    public SolvableLocalResidue<C> random(int k, int l, int d, float q) {
387        GenSolvablePolynomial<C> r = ring.random(k, l, d, q).monic();
388        r = ideal.normalform(r);
389        GenSolvablePolynomial<C> s;
390        do {
391            s = ring.random(k, l, d, q).monic();
392            s = ideal.normalform(s);
393        } while (s.isZERO());
394        return new SolvableLocalResidue<C>(this, r, s, false);
395    }
396
397
398    /**
399     * SolvableLocalResidue random.
400     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
401     * @param rnd is a source for random bits.
402     * @return a random quotient element.
403     */
404    public SolvableLocalResidue<C> random(int n, Random rnd) {
405        GenSolvablePolynomial<C> r = ring.random(n, rnd).monic();
406        r = ideal.normalform(r);
407        GenSolvablePolynomial<C> s;
408        do {
409            s = ring.random(n, rnd).monic();
410            s = ideal.normalform(s);
411        } while (s.isZERO());
412        return new SolvableLocalResidue<C>(this, r, s, false);
413    }
414
415
416    /**
417     * Parse SolvableLocalResidue from String. Syntax:
418     * "{ polynomial | polynomial }" or "{ polynomial }" or
419     * " polynomial | polynomial " or " polynomial "
420     * @param s String.
421     * @return SolvableLocalResidue from s.
422     */
423    public SolvableLocalResidue<C> parse(String s) {
424        int i = s.indexOf("{");
425        if (i >= 0) {
426            s = s.substring(i + 1);
427        }
428        i = s.lastIndexOf("}");
429        if (i >= 0) {
430            s = s.substring(0, i);
431        }
432        i = s.indexOf("|");
433        if (i < 0) {
434            GenSolvablePolynomial<C> n = ring.parse(s);
435            return new SolvableLocalResidue<C>(this, n);
436        }
437        String s1 = s.substring(0, i);
438        String s2 = s.substring(i + 1);
439        GenSolvablePolynomial<C> n = ring.parse(s1);
440        GenSolvablePolynomial<C> d = ring.parse(s2);
441        return new SolvableLocalResidue<C>(this, n, d);
442    }
443
444
445    /**
446     * Parse SolvableLocalResidue from Reader.
447     * @param r Reader.
448     * @return next SolvableLocalResidue from r.
449     */
450    public SolvableLocalResidue<C> parse(Reader r) {
451        String s = StringUtil.nextPairedString(r, '{', '}');
452        return parse(s);
453    }
454
455}