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