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