001/*
002 * $Id: GenWordPolynomialRing.java 5888 2018-07-29 20:58:45Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import java.io.Reader;
009import java.io.IOException;
010import java.io.StringReader;
011import java.math.BigInteger;
012import java.util.ArrayList;
013import java.util.List;
014import java.util.Arrays;
015import java.util.Map;
016import java.util.Random;
017
018import org.apache.logging.log4j.Logger;
019import org.apache.logging.log4j.LogManager; 
020
021import edu.jas.kern.PreemptStatus;
022import edu.jas.kern.Scripting;
023import edu.jas.structure.RingElem;
024import edu.jas.structure.RingFactory;
025
026
027/**
028 * GenWordPolynomialRing generic polynomial factory implementing RingFactory;
029 * Factory for non-commutative string polynomials over C.
030 * @param <C> coefficient type
031 * @author Heinz Kredel
032 */
033
034public final class GenWordPolynomialRing<C extends RingElem<C>> implements RingFactory<GenWordPolynomial<C>>
035/*, Iterable<GenWordPolynomial<C>>*/{
036
037
038    /**
039     * The factory for the coefficients.
040     */
041    public final RingFactory<C> coFac;
042
043
044    /**
045     * The factory for the alphabet.
046     */
047    public final WordFactory alphabet;
048
049
050    /**
051     * The constant polynomial 0 for this ring.
052     */
053    public final GenWordPolynomial<C> ZERO;
054
055
056    /**
057     * The constant polynomial 1 for this ring.
058     */
059    public final GenWordPolynomial<C> ONE;
060
061
062    /**
063     * The constant empty word exponent for this ring.
064     */
065    public final Word wone;
066
067
068    /**
069     * A default random sequence generator.
070     */
071    final static Random random = new Random();
072
073
074    /**
075     * Indicator if this ring is a field.
076     */
077    private int isField = -1; // initially unknown
078
079
080    /**
081     * Log4j logger object.
082     */
083    private static final Logger logger = LogManager.getLogger(GenWordPolynomialRing.class);
084
085
086    /**
087     * Flag to enable if preemptive interrrupt is checked.
088     */
089    final boolean checkPreempt = PreemptStatus.isAllowed();
090
091
092    /**
093     * The constructor creates a polynomial factory object with the default term
094     * order.
095     * @param cf factory for coefficients of type C.
096     * @param wf factory for strings.
097     */
098    public GenWordPolynomialRing(RingFactory<C> cf, WordFactory wf) {
099        coFac = cf;
100        alphabet = wf;
101        ZERO = new GenWordPolynomial<C>(this);
102        C coeff = coFac.getONE();
103        wone = wf.getONE();
104        ONE = new GenWordPolynomial<C>(this, coeff, wone);
105    }
106
107
108    /**
109     * The constructor creates a polynomial factory object.
110     * @param cf factory for coefficients of type C.
111     * @param s array of variable names.
112     */
113    public GenWordPolynomialRing(RingFactory<C> cf, String[] s) {
114        this(cf, new WordFactory(s));
115    }
116
117
118    /**
119     * The constructor creates a polynomial factory object.
120     * @param cf factory for coefficients of type C.
121     * @param s string of single letter variable names.
122     */
123    public GenWordPolynomialRing(RingFactory<C> cf, String s) {
124        this(cf, new WordFactory(s));
125    }
126
127
128    /**
129     * The constructor creates a polynomial factory object.
130     * @param cf factory for coefficients of type C.
131     * @param o other polynomial ring.
132     */
133    public GenWordPolynomialRing(RingFactory<C> cf, GenWordPolynomialRing o) {
134        this(cf, o.alphabet);
135    }
136
137
138    /**
139     * The constructor creates a polynomial factory object.
140     * @param fac polynomial ring.
141     */
142    public GenWordPolynomialRing(GenPolynomialRing<C> fac) {
143        this(fac.coFac, new WordFactory(fac.vars));
144    }
145
146
147    /**
148     * Copy this factory.
149     * @return a clone of this.
150     */
151    public GenWordPolynomialRing<C> copy() {
152        return new GenWordPolynomialRing<C>(coFac, this);
153    }
154
155
156    /**
157     * Get the String representation.
158     * @see java.lang.Object#toString()
159     */
160    @Override
161    public String toString() {
162        StringBuffer s = new StringBuffer();
163        s.append("WordPolyRing(");
164        if (coFac instanceof RingElem) {
165            s.append(((RingElem<C>) coFac).toScriptFactory());
166        } else {
167            s.append(coFac.toString().trim());
168        }
169        s.append(",");
170        s.append(alphabet.toString());
171        s.append(")");
172        return s.toString();
173    }
174
175
176    /**
177     * Get a scripting compatible string representation.
178     * @return script compatible representation for this Element.
179     * @see edu.jas.structure.Element#toScript()
180     */
181    @Override
182    public String toScript() {
183        StringBuffer s = new StringBuffer();
184        switch (Scripting.getLang()) {
185        case Ruby:
186            s.append("WordPolyRing.new(");
187            break;
188        case Python:
189        default:
190            s.append("WordPolyRing(");
191        }
192        if (coFac instanceof RingElem) {
193            s.append(((RingElem<C>) coFac).toScriptFactory());
194        } else {
195            s.append(coFac.toScript().trim());
196        }
197        s.append(",");
198        s.append(alphabet.toScript());
199        s.append(")");
200        return s.toString();
201    }
202
203
204    /**
205     * Extend variables. Used e.g. in module embedding. Extend number of
206     * variables by i.
207     * @param i number of variables to extend.
208     * @return extended word polynomial ring factory.
209     */
210    public GenWordPolynomialRing<C> extend(int i) {
211        // add module variable names
212        String[] v = GenPolynomialRing.newVars("t", i);
213        return extend(v);
214    }
215
216
217    /**
218     * Extend variables. Extend number of variables by length(vn). 
219     * @param vn names for extended variables.
220     * @return extended polynomial ring factory.
221     */
222    public GenWordPolynomialRing<C> extend(String[] vn) {
223        WordFactory wfe = alphabet.extend(vn);
224        return new GenWordPolynomialRing<C>(coFac, wfe);
225    }
226
227
228    /**
229     * Comparison with any other object.
230     * @see java.lang.Object#equals(java.lang.Object)
231     */
232    @Override
233    @SuppressWarnings("unchecked")
234    public boolean equals(Object other) {
235        if (other == null) {
236            return false;
237        }
238        if (!(other instanceof GenWordPolynomialRing)) {
239            return false;
240        }
241        GenWordPolynomialRing<C> oring = (GenWordPolynomialRing<C>) other;
242        if (!coFac.equals(oring.coFac)) {
243            return false;
244        }
245        if (!alphabet.equals(oring.alphabet)) {
246            return false;
247        }
248        return true;
249    }
250
251
252    /**
253     * Hash code for this polynomial ring.
254     * @see java.lang.Object#hashCode()
255     */
256    @Override
257    public int hashCode() {
258        int h;
259        h = (coFac.hashCode() << 11);
260        h += alphabet.hashCode();
261        return h;
262    }
263
264
265    /**
266     * Get the variable names.
267     * @return vars.
268     */
269    public String[] getVars() {
270        return alphabet.getVars(); // Java-5: Arrays.copyOf(vars,vars.length);
271    }
272
273
274    /**
275     * Get the zero element from the coefficients.
276     * @return 0 as C.
277     */
278    public C getZEROCoefficient() {
279        return coFac.getZERO();
280    }
281
282
283    /**
284     * Get the one element from the coefficients.
285     * @return 1 as C.
286     */
287    public C getONECoefficient() {
288        return coFac.getONE();
289    }
290
291
292    /**
293     * Get the zero element.
294     * @return 0 as GenWordPolynomial<C>.
295     */
296    public GenWordPolynomial<C> getZERO() {
297        return ZERO;
298    }
299
300
301    /**
302     * Get the one element.
303     * @return 1 as GenWordPolynomial<C>.
304     */
305    public GenWordPolynomial<C> getONE() {
306        return ONE;
307    }
308
309
310    /**
311     * Query if this ring is commutative.
312     * @return true if this ring is commutative, else false.
313     */
314    public boolean isCommutative() {
315        return coFac.isCommutative() && alphabet.isFinite();
316    }
317
318
319    /**
320     * Query if this ring is associative.
321     * @return true if this ring is associative, else false.
322     */
323    public boolean isAssociative() {
324        return coFac.isAssociative();
325    }
326
327
328    /**
329     * Is this structure finite or infinite.
330     * @return true if this structure is finite, else false.
331     * @see edu.jas.structure.ElemFactory#isFinite()
332     */
333    public boolean isFinite() {
334        return alphabet.isFinite() && coFac.isFinite();
335    }
336
337
338    /**
339     * Query if this ring is a field.
340     * @return false.
341     */
342    public boolean isField() {
343        if (isField > 0) {
344            return true;
345        }
346        if (isField == 0) {
347            return false;
348        }
349        if (coFac.isField() && alphabet.isFinite()) {
350            isField = 1;
351            return true;
352        }
353        isField = 0;
354        return false;
355    }
356
357
358    /**
359     * Characteristic of this ring.
360     * @return characteristic of this ring.
361     */
362    public java.math.BigInteger characteristic() {
363        return coFac.characteristic();
364    }
365
366
367    /**
368     * Get a (constant) GenWordPolynomial&lt;C&gt; element from a coefficient
369     * value.
370     * @param a coefficient.
371     * @return a GenWordPolynomial&lt;C&gt;.
372     */
373    public GenWordPolynomial<C> valueOf(C a) {
374        return new GenWordPolynomial<C>(this, a);
375    }
376
377
378    /**
379     * Get a GenWordPolynomial&lt;C&gt; element from a word.
380     * @param e word.
381     * @return a GenWordPolynomial&lt;C&gt;.
382     */
383    public GenWordPolynomial<C> valueOf(Word e) {
384        return valueOf(coFac.getONE(), e);
385    }
386
387
388    /**
389     * Get a GenWordPolynomial&lt;C&gt; element from an ExpVector.
390     * @param e exponent vector.
391     * @return a GenWordPolynomial&lt;C&gt;.
392     */
393    public GenWordPolynomial<C> valueOf(ExpVector e) {
394        return valueOf(coFac.getONE(), e);
395    }
396
397
398    /**
399     * Get a GenWordPolynomial&lt;C&gt; element from a coeffcient and a word.
400     * @param a coefficient.
401     * @param e word.
402     * @return a GenWordPolynomial&lt;C&gt;.
403     */
404    public GenWordPolynomial<C> valueOf(C a, Word e) {
405        return new GenWordPolynomial<C>(this, a, e);
406    }
407
408
409    /**
410     * Get a GenWordPolynomial&lt;C&gt; element from a coeffcient and an ExpVector.
411     * @param a coefficient.
412     * @param e exponent vector.
413     * @return a GenWordPolynomial&lt;C&gt;.
414     */
415    public GenWordPolynomial<C> valueOf(C a, ExpVector e) {
416        return new GenWordPolynomial<C>(this, a, alphabet.valueOf(e));
417    }
418
419
420    /**
421     * Get a GenWordPolynomial&lt;C&gt; element from a GenPolynomial&lt;C&gt;.
422     * @param a GenPolynomial.
423     * @return a GenWordPolynomial&lt;C&gt;.
424     */
425    public GenWordPolynomial<C> valueOf(GenPolynomial<C> a) {
426        if (a.isZERO()) {
427            return getZERO();
428        }
429        if (a.isONE()) {
430            return getONE();
431        }
432        GenWordPolynomial<C> p = this.getZERO().copy();
433        for (Map.Entry<ExpVector, C> m : a.val.entrySet()) {
434            C c = m.getValue();
435            ExpVector e = m.getKey();
436            Word w = alphabet.valueOf(e);
437            p.doPutToMap(w, c);
438        }
439        return p;
440    }
441
442
443   /**
444     * Get a GenWordPolynomial&lt;C&gt; element from a GenWordPolynomial&lt;C&gt;.
445     * @param a GenWordPolynomial.
446     * @return a GenWordPolynomial&lt;C&gt;.
447     */
448    public GenWordPolynomial<C> valueOf(GenWordPolynomial<C> a) {
449        if (a.isZERO()) {
450            return getZERO();
451        }
452        if (a.isONE()) {
453            return getONE();
454        }
455        GenWordPolynomial<C> p = this.getZERO().copy();
456        for (Map.Entry<Word, C> m : a.val.entrySet()) {
457            C c = m.getValue();
458            Word e = m.getKey();
459            Word w = alphabet.valueOf(e);
460            p.doPutToMap(w, c);
461        }
462        return p;
463    }
464
465
466    /**
467     * Get a list of GenWordPolynomial&lt;C&gt; element from a list of
468     * GenPolynomial&lt;C&gt;.
469     * @param A GenPolynomial list.
470     * @return a GenWordPolynomial&lt;C&gt; list.
471     */
472    public List<GenWordPolynomial<C>> valueOf(List<GenPolynomial<C>> A) {
473        List<GenWordPolynomial<C>> B = new ArrayList<GenWordPolynomial<C>>(A.size());
474        if (A.isEmpty()) {
475            return B;
476        }
477        for (GenPolynomial<C> a : A) {
478            GenWordPolynomial<C> b = valueOf(a);
479            B.add(b);
480        }
481        return B;
482    }
483
484
485    /**
486     * Get a (constant) GenWordPolynomial&lt;C&gt; element from a long value.
487     * @param a long.
488     * @return a GenWordPolynomial&lt;C&gt;.
489     */
490    public GenWordPolynomial<C> fromInteger(long a) {
491        return new GenWordPolynomial<C>(this, coFac.fromInteger(a), wone);
492    }
493
494
495    /**
496     * Get a (constant) GenWordPolynomial&lt;C&gt; element from a BigInteger
497     * value.
498     * @param a BigInteger.
499     * @return a GenWordPolynomial&lt;C&gt;.
500     */
501    public GenWordPolynomial<C> fromInteger(BigInteger a) {
502        return new GenWordPolynomial<C>(this, coFac.fromInteger(a), wone);
503    }
504
505
506    /**
507     * Random polynomial. Generates a random polynomial.
508     * @param n number of terms.
509     * @return a random polynomial.
510     */
511    public GenWordPolynomial<C> random(int n) {
512        return random(n, random);
513    }
514
515
516    /**
517     * Random polynomial. Generates a random polynomial with k = 5, l = n, d =
518     * 3.
519     * @param n number of terms.
520     * @param rnd is a source for random bits.
521     * @return a random polynomial.
522     */
523    public GenWordPolynomial<C> random(int n, Random rnd) {
524        return random(5, n, 3, rnd);
525    }
526
527
528    /**
529     * Generate a random polynomial.
530     * @param k bitsize of random coefficients.
531     * @param l number of terms.
532     * @param d maximal length of a random word.
533     * @return a random polynomial.
534     */
535    public GenWordPolynomial<C> random(int k, int l, int d) {
536        return random(k, l, d, random);
537    }
538
539
540    /**
541     * Generate a random polynomial.
542     * @param k bitsize of random coefficients.
543     * @param l number of terms.
544     * @param d maximal length of a random word.
545     * @param rnd is a source for random bits.
546     * @return a random polynomial.
547     */
548    public GenWordPolynomial<C> random(int k, int l, int d, Random rnd) {
549        GenWordPolynomial<C> r = getZERO(); //.clone() or copy( ZERO ); 
550        // add l random coeffs and words of maximal length d
551        for (int i = 0; i < l; i++) {
552            int di = Math.abs(rnd.nextInt() % d);
553            Word e = alphabet.random(di, rnd);
554            C a = coFac.random(k, rnd);
555            r = r.sum(a, e); // somewhat inefficient but clean
556            //System.out.println("e = " + e + " a = " + a);
557        }
558        return r;
559    }
560
561
562    /**
563     * Copy polynomial c.
564     * @param c polynomial to copy.
565     * @return a copy of c.
566     */
567    public GenWordPolynomial<C> copy(GenWordPolynomial<C> c) {
568        return new GenWordPolynomial<C>(this, c.val);
569    }
570
571
572    /**
573     * Parse a polynomial with the use of GenWordPolynomialTokenizer.
574     * @param s String.
575     * @return GenWordPolynomial from s.
576     */
577    public GenWordPolynomial<C> parse(String s) {
578        String val = s;
579        if (!s.contains("|")) {
580            val = val.replace("{", "").replace("}", "");
581        }
582        return parse(new StringReader(val));
583    }
584
585
586    /**
587     * Parse a polynomial with the use of GenWordPolynomialTokenizer.
588     * @param r Reader.
589     * @return next GenWordPolynomial from r.
590     */
591    @SuppressWarnings("unchecked")
592    public GenWordPolynomial<C> parse(Reader r) {
593        if (alphabet.length() <= 4) { // todo, hack for commuative like cases
594            GenPolynomialRing<C> cr = new GenPolynomialRing<C>(coFac, alphabet.getVars() );
595            GenPolynomialTokenizer pt = new GenPolynomialTokenizer(cr, r);
596            GenPolynomial<C> p = cr.getZERO();
597            try {
598                  p = pt.nextPolynomial();
599            } catch (IOException e) {
600                  logger.error(e.toString() + " parse " + this);
601            }
602            GenWordPolynomial<C> wp = this.valueOf(p);
603            return wp;
604        }
605        logger.error("parse not implemented");
606        throw new UnsupportedOperationException("not implemented");
607    }
608
609
610    /**
611     * Generate univariate polynomial in a given variable.
612     * @param i the index of the variable.
613     * @return X_i as univariate polynomial.
614     */
615    public GenWordPolynomial<C> univariate(int i) {
616        GenWordPolynomial<C> p = getZERO();
617        List<Word> wgen = alphabet.generators();
618        if (0 <= i && i < wgen.size()) {
619            C one = coFac.getONE();
620            Word f = wgen.get(i);
621            p = p.sum(one, f);
622        }
623        return p;
624    }
625
626
627    /**
628     * Generate commute polynomial in two variables.
629     * @param i the index of the first variable.
630     * @param j the index of the second variable.
631     * @return X_i * x_j - X_j * X_i as polynomial.
632     */
633    public GenWordPolynomial<C> commute(int i, int j) {
634        GenWordPolynomial<C> p = getZERO();
635        List<Word> wgen = alphabet.generators();
636        if (0 <= i && i < wgen.size() && 0 <= j && j < wgen.size()) {
637            C one = coFac.getONE();
638            Word f = wgen.get(i);
639            Word e = wgen.get(j);
640            p = p.sum(one, e.multiply(f));
641            p = p.subtract(one, f.multiply(e));
642            if (i > j) {
643                p = p.negate();
644            }
645        }
646        return p;
647    }
648
649
650    /**
651     * Generate commute polynomials for given variable.
652     * @param i the index of the variable.
653     * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials.
654     */
655    public List<GenWordPolynomial<C>> commute(int i) {
656        int n = alphabet.length();
657        List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n-1);
658        for ( int j = 0; j < n; j++ ) {
659            if (i != j) {
660                pols.add(commute(i,j));
661            }
662        }
663        return pols;
664    }
665
666
667    /**
668     * Generate commute polynomials for all variables.
669     * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials.
670     */
671    public List<GenWordPolynomial<C>> commute() {
672        int n = alphabet.length();
673        List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n*(n-1));
674        for ( int i = 0; i < n; i++ ) {
675             pols.addAll( commute(i) );
676        }
677        return pols;
678    }
679
680
681    /**
682     * Generate list of univariate polynomials in all variables.
683     * @return List(X_1,...,X_n) a list of univariate polynomials.
684     */
685    public List<GenWordPolynomial<C>> univariateList() {
686        int n = alphabet.length();
687        List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n);
688        for (int i = 0; i < n; i++) {
689            GenWordPolynomial<C> p = univariate(i);
690            pols.add(p);
691        }
692        return pols;
693    }
694
695
696    /**
697     * Get the generating elements <b>excluding</b> the generators for the
698     * coefficient ring.
699     * @return a list of generating elements for this ring.
700     */
701    public List<GenWordPolynomial<C>> getGenerators() {
702        List<GenWordPolynomial<C>> univs = univariateList();
703        List<GenWordPolynomial<C>> gens = new ArrayList<GenWordPolynomial<C>>(univs.size() + 1);
704        gens.add(getONE());
705        gens.addAll(univs);
706        return gens;
707    }
708
709
710    /**
711     * Get a list of all generating elements.
712     * @return list of generators for the algebraic structure.
713     * @see edu.jas.structure.ElemFactory#generators()
714     */
715    public List<GenWordPolynomial<C>> generators() {
716        List<C> cogens = coFac.generators();
717        List<GenWordPolynomial<C>> univs = univariateList();
718        List<GenWordPolynomial<C>> gens = new ArrayList<GenWordPolynomial<C>>(univs.size() + cogens.size());
719        for (C c : cogens) {
720            gens.add(getONE().multiply(c));
721        }
722        gens.addAll(univs);
723        return gens;
724    }
725
726}