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