001    /*
002     * $Id: UnivPowerSeries.java 3571 2011-03-18 22:02:51Z kredel $
003     */
004    
005    package edu.jas.ps;
006    
007    
008    import edu.jas.poly.AlgebraicNumber;
009    import edu.jas.poly.ExpVector;
010    import edu.jas.poly.GenPolynomial;
011    import edu.jas.structure.BinaryFunctor;
012    import edu.jas.structure.RingElem;
013    import edu.jas.structure.Selector;
014    import edu.jas.structure.UnaryFunctor;
015    
016    
017    /**
018     * Univariate power series implementation. Uses inner classes and lazy evaluated
019     * generating function for coefficients. All ring element methods use lazy
020     * evaluation except where noted otherwise. Eager evaluated methods are
021     * <code>toString()</code>, <code>compareTo()</code>, <code>equals()</code>,
022     * <code>evaluate()</code>, or they use the <code>order()</code> method, like
023     * <code>signum()</code>, <code>abs()</code>, <code>divide()</code>,
024     * <code>remainder()</code> and <code>gcd()</code>.
025     * @param <C> ring element type
026     * @author Heinz Kredel
027     */
028    
029    public class UnivPowerSeries<C extends RingElem<C>> implements RingElem<UnivPowerSeries<C>> {
030    
031    
032        /**
033         * Power series ring factory.
034         */
035        public final UnivPowerSeriesRing<C> ring;
036    
037    
038        /**
039         * Data structure / generating function for coeffcients. Cannot be final
040         * because of fixPoint, must be accessible in factory.
041         */
042        /*package*/Coefficients<C> lazyCoeffs;
043    
044    
045        /**
046         * Truncation of computations.
047         */
048        private int truncate = 11;
049    
050    
051        /**
052         * Order of power series.
053         */
054        private int order = -1; // == unknown
055    
056    
057        /**
058         * Private constructor.
059         */
060        @SuppressWarnings("unused")
061        private UnivPowerSeries() {
062            throw new IllegalArgumentException("do not use no-argument constructor");
063        }
064    
065    
066        /**
067         * Package constructor. Use in fixPoint only, must be accessible in factory.
068         * @param ring power series ring.
069         */
070        /*package*/UnivPowerSeries(UnivPowerSeriesRing<C> ring) {
071            this.ring = ring;
072            this.lazyCoeffs = null;
073        }
074    
075    
076        /**
077         * Constructor.
078         * @param ring power series ring.
079         * @param lazyCoeffs generating function for coefficients.
080         */
081        public UnivPowerSeries(UnivPowerSeriesRing<C> ring, Coefficients<C> lazyCoeffs) {
082            if (lazyCoeffs == null || ring == null) {
083                throw new IllegalArgumentException("null not allowed: ring = " + ring + ", lazyCoeffs = "
084                                + lazyCoeffs);
085            }
086            this.ring = ring;
087            this.lazyCoeffs = lazyCoeffs;
088            this.truncate = ring.truncate;
089        }
090    
091    
092        /**
093         * Get the corresponding element factory.
094         * @return factory for this Element.
095         * @see edu.jas.structure.Element#factory()
096         */
097        public UnivPowerSeriesRing<C> factory() {
098            return ring;
099        }
100    
101    
102        /**
103         * Clone this power series.
104         * @see java.lang.Object#clone()
105         */
106        @Override
107        public UnivPowerSeries<C> clone() {
108            return new UnivPowerSeries<C>(ring, lazyCoeffs);
109        }
110    
111    
112        /**
113         * String representation of power series.
114         * @see java.lang.Object#toString()
115         */
116        @Override
117        public String toString() {
118            return toString(truncate);
119        }
120    
121    
122        /**
123         * To String with given truncate.
124         * @return string representation of this to given truncate.
125         */
126        public String toString(int truncate) {
127            StringBuffer sb = new StringBuffer();
128            UnivPowerSeries<C> s = this;
129            String var = ring.var;
130            //System.out.println("cache = " + s.coeffCache);
131            for (int i = 0; i < truncate; i++) {
132                C c = s.coefficient(i);
133                int si = c.signum();
134                if (si != 0) {
135                    if (si > 0) {
136                        if (sb.length() > 0) {
137                            sb.append(" + ");
138                        }
139                    } else {
140                        c = c.negate();
141                        sb.append(" - ");
142                    }
143                    if (!c.isONE() || i == 0) {
144                        if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) {
145                            sb.append("{ ");
146                        }
147                        sb.append(c.toString());
148                        if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) {
149                            sb.append(" }");
150                        }
151                        if (i > 0) {
152                            sb.append(" * ");
153                        }
154                    }
155                    if (i == 0) {
156                        //skip; sb.append(" ");
157                    } else if (i == 1) {
158                        sb.append(var);
159                    } else {
160                        sb.append(var + "^" + i);
161                    }
162                    //sb.append(c.toString() + ", ");
163                }
164                //System.out.println("cache = " + s.coeffCache);
165            }
166            if (sb.length() == 0) {
167                sb.append("0");
168            }
169            sb.append(" + BigO(" + var + "^" + truncate + ")");
170            //sb.append("...");
171            return sb.toString();
172        }
173    
174    
175        /**
176         * Get a scripting compatible string representation.
177         * @return script compatible representation for this Element.
178         * @see edu.jas.structure.Element#toScript()
179         */
180        //JAVA6only: @Override
181        public String toScript() {
182            // Python case
183            StringBuffer sb = new StringBuffer("");
184            UnivPowerSeries<C> s = this;
185            String var = ring.var;
186            //System.out.println("cache = " + s.coeffCache);
187            for (int i = 0; i < truncate; i++) {
188                C c = s.coefficient(i);
189                int si = c.signum();
190                if (si != 0) {
191                    if (si > 0) {
192                        if (sb.length() > 0) {
193                            sb.append(" + ");
194                        }
195                    } else {
196                        c = c.negate();
197                        sb.append(" - ");
198                    }
199                    if (!c.isONE() || i == 0) {
200                        if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) {
201                            sb.append("{ ");
202                        }
203                        sb.append(c.toScript());
204                        if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) {
205                            sb.append(" }");
206                        }
207                        if (i > 0) {
208                            sb.append(" * ");
209                        }
210                    }
211                    if (i == 0) {
212                        //skip; sb.append(" ");
213                    } else if (i == 1) {
214                        sb.append(var);
215                    } else {
216                        sb.append(var + "**" + i);
217                    }
218                    //sb.append(c.toString() + ", ");
219                }
220                //System.out.println("cache = " + s.coeffCache);
221            }
222            if (sb.length() == 0) {
223                sb.append("0");
224            }
225            // sb.append("," + truncate + "");
226            return sb.toString();
227        }
228    
229    
230        /**
231         * Get a scripting compatible string representation of the factory.
232         * @return script compatible representation for this ElemFactory.
233         * @see edu.jas.structure.Element#toScriptFactory()
234         */
235        //JAVA6only: @Override
236        public String toScriptFactory() {
237            // Python case
238            return factory().toScript();
239        }
240    
241    
242        /**
243         * Get coefficient.
244         * @param index number of requested coefficient.
245         * @return coefficient at index.
246         */
247        public C coefficient(int index) {
248            if (index < 0) {
249                throw new IndexOutOfBoundsException("negative index not allowed");
250            }
251            //System.out.println("cache = " + coeffCache);
252            return lazyCoeffs.get(index);
253        }
254    
255    
256        /**
257         * Get a GenPolynomial&lt;C&gt; from this.
258         * @return a GenPolynomial&lt;C&gt; from this up to truncate parts.
259         */
260        public GenPolynomial<C> asPolynomial() {
261            GenPolynomial<C> p = ring.polyRing().getZERO();
262            for (int i = 0; i <= truncate; i++) {
263                C c = coefficient(i);
264                ExpVector e = ExpVector.create(1, 0, i);
265                p = p.sum(c, e);
266            }
267            return p;
268        }
269    
270    
271        /**
272         * Leading base coefficient.
273         * @return first coefficient.
274         */
275        public C leadingCoefficient() {
276            return coefficient(0);
277        }
278    
279    
280        /**
281         * Reductum.
282         * @return this - leading monomial.
283         */
284        public UnivPowerSeries<C> reductum() {
285            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
286    
287    
288                @Override
289                public C generate(int i) {
290                    return coefficient(i + 1);
291                }
292            });
293        }
294    
295    
296        /**
297         * Prepend a new leading coefficient.
298         * @param h new coefficient.
299         * @return new power series.
300         */
301        public UnivPowerSeries<C> prepend(final C h) {
302            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
303    
304    
305                @Override
306                public C generate(int i) {
307                    if (i == 0) {
308                        return h;
309                    } else {
310                        return coefficient(i - 1);
311                    }
312                }
313            });
314        }
315    
316    
317        /**
318         * Shift coefficients.
319         * @param k shift index.
320         * @return new power series with coefficient(i) = old.coefficient(i-k).
321         */
322        public UnivPowerSeries<C> shift(final int k) {
323            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
324    
325    
326                @Override
327                public C generate(int i) {
328                    if (i - k < 0) {
329                        return ring.coFac.getZERO();
330                    }
331                    return coefficient(i - k);
332                }
333            });
334        }
335    
336    
337        /**
338         * Select coefficients.
339         * @param sel selector functor.
340         * @return new power series with selected coefficients.
341         */
342        public UnivPowerSeries<C> select(final Selector<? super C> sel) {
343            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
344    
345    
346                @Override
347                public C generate(int i) {
348                    C c = coefficient(i);
349                    if (sel.select(c)) {
350                        return c;
351                    } else {
352                        return ring.coFac.getZERO();
353                    }
354                }
355            });
356        }
357    
358    
359        /**
360         * Shift select coefficients. Not selected coefficients are removed from the
361         * result series.
362         * @param sel selector functor.
363         * @return new power series with shifted selected coefficients.
364         */
365        public UnivPowerSeries<C> shiftSelect(final Selector<? super C> sel) {
366            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
367    
368    
369                int pos = 0;
370    
371    
372                @Override
373                public C generate(int i) {
374                    C c;
375                    if (i > 0) {
376                        c = get(i - 1);
377                    }
378                    do {
379                        c = coefficient(pos++);
380                    } while (!sel.select(c));
381                    return c;
382                }
383            });
384        }
385    
386    
387        /**
388         * Map a unary function to this power series.
389         * @param f evaluation functor.
390         * @return new power series with coefficients f(this(i)).
391         */
392        public UnivPowerSeries<C> map(final UnaryFunctor<? super C, C> f) {
393            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
394    
395    
396                @Override
397                public C generate(int i) {
398                    return f.eval(coefficient(i));
399                }
400            });
401        }
402    
403    
404        /**
405         * Map a binary function to this and another power series.
406         * @param f evaluation functor with coefficients f(this(i),other(i)).
407         * @param ps other power series.
408         * @return new power series.
409         */
410        public <C2 extends RingElem<C2>> UnivPowerSeries<C> zip(final BinaryFunctor<? super C, ? super C2, C> f,
411                        final UnivPowerSeries<C2> ps) {
412            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
413    
414    
415                @Override
416                public C generate(int i) {
417                    return f.eval(coefficient(i), ps.coefficient(i));
418                }
419            });
420        }
421    
422    
423        /**
424         * Sum of two power series.
425         * @param ps other power series.
426         * @return this + ps.
427         */
428        public UnivPowerSeries<C> sum(UnivPowerSeries<C> ps) {
429            return zip(new Sum<C>(), ps);
430        }
431    
432    
433        /**
434         * Subtraction of two power series.
435         * @param ps other power series.
436         * @return this - ps.
437         */
438        public UnivPowerSeries<C> subtract(UnivPowerSeries<C> ps) {
439            return zip(new Subtract<C>(), ps);
440        }
441    
442    
443        /**
444         * Multiply by coefficient.
445         * @param c coefficient.
446         * @return this * c.
447         */
448        public UnivPowerSeries<C> multiply(C c) {
449            return map(new Multiply<C>(c));
450        }
451    
452    
453        /**
454         * Negate.
455         * @return - this.
456         */
457        public UnivPowerSeries<C> negate() {
458            return map(new Negate<C>());
459        }
460    
461    
462        /**
463         * Absolute value.
464         * @return abs(this).
465         */
466        public UnivPowerSeries<C> abs() {
467            if (signum() < 0) {
468                return negate();
469            } else {
470                return this;
471            }
472        }
473    
474    
475        /**
476         * Evaluate at given point.
477         * @return ps(c).
478         */
479        public C evaluate(C e) {
480            C v = coefficient(0);
481            C p = e;
482            for (int i = 1; i < truncate; i++) {
483                C c = coefficient(i).multiply(p);
484                v = v.sum(c);
485                p = p.multiply(e);
486            }
487            return v;
488        }
489    
490    
491        /**
492         * Order.
493         * @return index of first non zero coefficient.
494         */
495        public int order() {
496            if (order < 0) { // compute it
497                for (int i = 0; i <= truncate; i++) {
498                    if (!coefficient(i).isZERO()) {
499                        order = i;
500                        return order;
501                    }
502                }
503                order = truncate + 1;
504            }
505            return order;
506        }
507    
508    
509        /**
510         * Truncate.
511         * @return truncate index of power series.
512         */
513        public int truncate() {
514            return truncate;
515        }
516    
517    
518        /**
519         * Set truncate.
520         * @param t new truncate index.
521         * @return old truncate index of power series.
522         */
523        public int setTruncate(int t) {
524            if (t < 0) {
525                throw new IllegalArgumentException("negative truncate not allowed");
526            }
527            int ot = truncate;
528            truncate = t;
529            return ot;
530        }
531    
532    
533        /**
534         * Signum.
535         * @return sign of first non zero coefficient.
536         */
537        public int signum() {
538            return coefficient(order()).signum();
539        }
540    
541    
542        /**
543         * Compare to. <b>Note: </b> compare only up to truncate.
544         * @return sign of first non zero coefficient of this-ps.
545         */
546        //JAVA6only: @Override
547        public int compareTo(UnivPowerSeries<C> ps) {
548            int m = order();
549            int n = ps.order();
550            int pos = (m <= n) ? m : n;
551            int s = 0;
552            do {
553                s = coefficient(pos).compareTo(ps.coefficient(pos));
554                pos++;
555            } while (s == 0 && pos <= truncate);
556            return s;
557        }
558    
559    
560        /**
561         * Is power series zero. <b>Note: </b> compare only up to truncate.
562         * @return If this is 0 then true is returned, else false.
563         * @see edu.jas.structure.RingElem#isZERO()
564         */
565        public boolean isZERO() {
566            return (compareTo(ring.ZERO) == 0);
567        }
568    
569    
570        /**
571         * Is power series one. <b>Note: </b> compare only up to truncate.
572         * @return If this is 1 then true is returned, else false.
573         * @see edu.jas.structure.RingElem#isONE()
574         */
575        public boolean isONE() {
576            return (compareTo(ring.ONE) == 0);
577        }
578    
579    
580        /**
581         * Comparison with any other object. <b>Note: </b> compare only up to
582         * truncate.
583         * @see java.lang.Object#equals(java.lang.Object)
584         */
585        @Override
586        @SuppressWarnings("unchecked")
587        public boolean equals(Object B) {
588            if (!(B instanceof UnivPowerSeries)) {
589                return false;
590            }
591            UnivPowerSeries<C> a = null;
592            try {
593                a = (UnivPowerSeries<C>) B;
594            } catch (ClassCastException ignored) {
595            }
596            if (a == null) {
597                return false;
598            }
599            return compareTo(a) == 0;
600        }
601    
602    
603        /**
604         * Hash code for this polynomial. <b>Note: </b> only up to truncate.
605         * @see java.lang.Object#hashCode()
606         */
607        @Override
608        public int hashCode() {
609            int h = 0;
610            //h = ( ring.hashCode() << 23 );
611            //h += val.hashCode();
612            for (int i = 0; i <= truncate; i++) {
613                h += coefficient(i).hashCode();
614                h = (h << 23);
615            };
616            return h;
617        }
618    
619    
620        /**
621         * Is unit.
622         * @return true, if this power series is invertible, else false.
623         */
624        public boolean isUnit() {
625            return leadingCoefficient().isUnit();
626        }
627    
628    
629        /**
630         * Multiply by another power series.
631         * @return this * ps.
632         */
633        public UnivPowerSeries<C> multiply(final UnivPowerSeries<C> ps) {
634            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
635    
636    
637                @Override
638                public C generate(int i) {
639                    C c = null; //fac.getZERO();
640                    for (int k = 0; k <= i; k++) {
641                        C m = coefficient(k).multiply(ps.coefficient(i - k));
642                        if (c == null) {
643                            c = m;
644                        } else {
645                            c = c.sum(m);
646                        }
647                    }
648                    return c;
649                }
650            });
651        }
652    
653    
654        /**
655         * Inverse power series.
656         * @return ps with this * ps = 1.
657         */
658        public UnivPowerSeries<C> inverse() {
659            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
660    
661    
662                @Override
663                public C generate(int i) {
664                    C d = leadingCoefficient().inverse(); // may fail
665                    if (i == 0) {
666                        return d;
667                    }
668                    C c = null; //fac.getZERO();
669                    for (int k = 0; k < i; k++) {
670                        C m = get(k).multiply(coefficient(i - k));
671                        if (c == null) {
672                            c = m;
673                        } else {
674                            c = c.sum(m);
675                        }
676                    }
677                    c = c.multiply(d.negate());
678                    return c;
679                }
680            });
681        }
682    
683    
684        /**
685         * Divide by another power series.
686         * @return this / ps.
687         */
688        public UnivPowerSeries<C> divide(UnivPowerSeries<C> ps) {
689            if (ps.isUnit()) {
690                return multiply(ps.inverse());
691            }
692            int m = order();
693            int n = ps.order();
694            if (m < n) {
695                return ring.getZERO();
696            }
697            if (!ps.coefficient(n).isUnit()) {
698                throw new ArithmeticException("division by non unit coefficient " + ps.coefficient(n) + ", n = "
699                                + n);
700            }
701            // now m >= n
702            UnivPowerSeries<C> st, sps, q, sq;
703            if (m == 0) {
704                st = this;
705            } else {
706                st = this.shift(-m);
707            }
708            if (n == 0) {
709                sps = ps;
710            } else {
711                sps = ps.shift(-n);
712            }
713            q = st.multiply(sps.inverse());
714            if (m == n) {
715                sq = q;
716            } else {
717                sq = q.shift(m - n);
718            }
719            return sq;
720        }
721    
722    
723        /**
724         * Power series remainder.
725         * @param ps nonzero power series with invertible leading coefficient.
726         * @return remainder with this = quotient * ps + remainder.
727         */
728        public UnivPowerSeries<C> remainder(UnivPowerSeries<C> ps) {
729            int m = order();
730            int n = ps.order();
731            if (m >= n) {
732                return ring.getZERO();
733            }
734            return this;
735        }
736    
737    
738        /**
739         * Differentiate.
740         * @return differentiate(this).
741         */
742        public UnivPowerSeries<C> differentiate() {
743            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
744    
745    
746                @Override
747                public C generate(int i) {
748                    C v = coefficient(i + 1);
749                    v = v.multiply(ring.coFac.fromInteger(i + 1));
750                    return v;
751                }
752            });
753        }
754    
755    
756        /**
757         * Integrate with given constant.
758         * @param c integration constant.
759         * @return integrate(this).
760         */
761        public UnivPowerSeries<C> integrate(final C c) {
762            return new UnivPowerSeries<C>(ring, new Coefficients<C>() {
763    
764    
765                @Override
766                public C generate(int i) {
767                    if (i == 0) {
768                        return c;
769                    }
770                    C v = coefficient(i - 1);
771                    v = v.divide(ring.coFac.fromInteger(i));
772                    return v;
773                }
774            });
775        }
776    
777    
778        /**
779         * Power series greatest common divisor.
780         * @param ps power series.
781         * @return gcd(this,ps).
782         */
783        public UnivPowerSeries<C> gcd(UnivPowerSeries<C> ps) {
784            if (ps.isZERO()) {
785                return this;
786            }
787            if (this.isZERO()) {
788                return ps;
789            }
790            int m = order();
791            int n = ps.order();
792            int ll = (m < n) ? m : n;
793            return ring.getONE().shift(ll);
794        }
795    
796    
797        /**
798         * Power series extended greatest common divisor. <b>Note:</b> not
799         * implemented.
800         * @param S power series.
801         * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
802         */
803        //SuppressWarnings("unchecked")
804        public UnivPowerSeries<C>[] egcd(UnivPowerSeries<C> S) {
805            throw new UnsupportedOperationException("egcd for power series not implemented");
806        }
807    
808    }
809    
810    
811    /* arithmetic method functors */
812    
813    
814    /**
815     * Internal summation functor.
816     */
817    class Sum<C extends RingElem<C>> implements BinaryFunctor<C, C, C> {
818    
819    
820        public C eval(C c1, C c2) {
821            return c1.sum(c2);
822        }
823    }
824    
825    
826    /**
827     * Internal subtraction functor.
828     */
829    class Subtract<C extends RingElem<C>> implements BinaryFunctor<C, C, C> {
830    
831    
832        public C eval(C c1, C c2) {
833            return c1.subtract(c2);
834        }
835    }
836    
837    
838    /**
839     * Internal scalar multiplication functor.
840     */
841    class Multiply<C extends RingElem<C>> implements UnaryFunctor<C, C> {
842    
843    
844        C x;
845    
846    
847        public Multiply(C x) {
848            this.x = x;
849        }
850    
851    
852        public C eval(C c) {
853            return c.multiply(x);
854        }
855    }
856    
857    
858    /**
859     * Internal negation functor.
860     */
861    class Negate<C extends RingElem<C>> implements UnaryFunctor<C, C> {
862    
863    
864        public C eval(C c) {
865            return c.negate();
866        }
867    }
868    
869    
870    /* only for sequential access:
871    class Abs<C extends RingElem<C>> implements UnaryFunctor<C,C> {
872            int sign = 0;
873            public C eval(C c) {
874                int s = c.signum();
875                if ( s == 0 ) {
876                   return c;
877                }
878                if ( sign > 0 ) {
879                   return c;
880                } else if ( sign < 0 ) {
881                   return c.negate();
882                }
883                // first non zero coefficient:
884                sign = s;
885                if ( s > 0 ) {
886                   return c;
887                }
888                return c.negate();
889            }
890    }
891    */