001    /*
002     * $Id: UnivPowerSeriesRing.java 3337 2010-09-27 21:05:17Z kredel $
003     */
004    
005    package edu.jas.ps;
006    
007    
008    import java.io.Reader;
009    import java.util.ArrayList;
010    import java.util.HashMap;
011    import java.util.List;
012    import java.util.Random;
013    
014    import edu.jas.poly.GenPolynomial;
015    import edu.jas.poly.GenPolynomialRing;
016    import edu.jas.poly.Monomial;
017    import edu.jas.structure.RingElem;
018    import edu.jas.structure.RingFactory;
019    
020    
021    /**
022     * Univariate power series ring implementation. Uses lazy evaluated generating
023     * function for coefficients.
024     * @param <C> ring element type
025     * @author Heinz Kredel
026     */
027    
028    public class UnivPowerSeriesRing<C extends RingElem<C>> implements RingFactory<UnivPowerSeries<C>> {
029    
030    
031        /**
032         * A default random sequence generator.
033         */
034        protected final static Random random = new Random();
035    
036    
037        /**
038         * Default truncate.
039         */
040        public final static int DEFAULT_TRUNCATE = 11;
041    
042    
043        /**
044         * Truncate.
045         */
046        int truncate;
047    
048    
049        /**
050         * Default variable name.
051         */
052        public final static String DEFAULT_NAME = "x";
053    
054    
055        /**
056         * Variable name.
057         */
058        String var;
059    
060    
061        /**
062         * Coefficient ring factory.
063         */
064        public final RingFactory<C> coFac;
065    
066    
067        /**
068         * The constant power series 1 for this ring.
069         */
070        public final UnivPowerSeries<C> ONE;
071    
072    
073        /**
074         * The constant power series 0 for this ring.
075         */
076        public final UnivPowerSeries<C> ZERO;
077    
078    
079        /**
080         * No argument constructor.
081         */
082        @SuppressWarnings("unused")
083        private UnivPowerSeriesRing() {
084            throw new IllegalArgumentException("do not use no-argument constructor");
085        }
086    
087    
088        /**
089         * Constructor.
090         * @param coFac coefficient ring factory.
091         */
092        public UnivPowerSeriesRing(RingFactory<C> coFac) {
093            this(coFac, DEFAULT_TRUNCATE, DEFAULT_NAME);
094        }
095    
096    
097        /**
098         * Constructor.
099         * @param coFac coefficient ring factory.
100         * @param truncate index of truncation.
101         */
102        public UnivPowerSeriesRing(RingFactory<C> coFac, int truncate) {
103            this(coFac, truncate, DEFAULT_NAME);
104        }
105    
106    
107        /**
108         * Constructor.
109         * @param coFac coefficient ring factory.
110         * @param name of the variable.
111         */
112        public UnivPowerSeriesRing(RingFactory<C> coFac, String name) {
113            this(coFac, DEFAULT_TRUNCATE, name);
114        }
115    
116    
117        /**
118         * Constructor.
119         * @param pfac polynomial ring factory.
120         */
121        public UnivPowerSeriesRing(GenPolynomialRing<C> pfac) {
122            this(pfac.coFac, DEFAULT_TRUNCATE, pfac.getVars()[0]);
123        }
124    
125    
126        /**
127         * Constructor.
128         * @param cofac coefficient ring factory.
129         * @param truncate index of truncation.
130         * @param name of the variable.
131         */
132        public UnivPowerSeriesRing(RingFactory<C> cofac, int truncate, String name) {
133            this.coFac = cofac;
134            this.truncate = truncate;
135            this.var = name;
136            this.ONE = new UnivPowerSeries<C>(this, new Coefficients<C>() {
137    
138    
139                @Override
140                public C generate(int i) {
141                    if (i == 0) {
142                        return coFac.getONE();
143                    }
144                    return coFac.getZERO();
145                }
146            });
147            this.ZERO = new UnivPowerSeries<C>(this, new Coefficients<C>() {
148    
149    
150                @Override
151                public C generate(int i) {
152                    return coFac.getZERO();
153                }
154            });
155        }
156    
157    
158        /**
159         * Fixed point construction.
160         * @param map a mapping of power series.
161         * @return fix point wrt map.
162         */
163        // Cannot be a static method because a power series ring is required.
164        public UnivPowerSeries<C> fixPoint(UnivPowerSeriesMap<C> map) {
165            UnivPowerSeries<C> ps1 = new UnivPowerSeries<C>(this);
166            UnivPowerSeries<C> ps2 = map.map(ps1);
167            ps1.lazyCoeffs = ps2.lazyCoeffs;
168            return ps2;
169        }
170    
171    
172        /**
173         * To String.
174         * @return string representation of this.
175         */
176        @Override
177        public String toString() {
178            StringBuffer sb = new StringBuffer();
179            String scf = coFac.getClass().getSimpleName();
180            sb.append(scf + "((" + var + "))");
181            return sb.toString();
182        }
183    
184    
185        /**
186         * Get a scripting compatible string representation.
187         * @return script compatible representation for this ElemFactory.
188         * @see edu.jas.structure.ElemFactory#toScript()
189         */
190        //JAVA6only: @Override
191        public String toScript() {
192            // Python case
193            StringBuffer s = new StringBuffer("PS(");
194            String f = null;
195            try {
196                f = ((RingElem<C>) coFac).toScriptFactory(); // sic
197            } catch (Exception e) {
198                f = coFac.toScript();
199            }
200            s.append(f + ",\"" + var + "\"," + truncate + ")");
201            return s.toString();
202        }
203    
204    
205        /**
206         * Comparison with any other object.
207         * @see java.lang.Object#equals(java.lang.Object)
208         */
209        @Override
210        @SuppressWarnings("unchecked")
211        public boolean equals(Object B) {
212            if (!(B instanceof UnivPowerSeriesRing)) {
213                return false;
214            }
215            UnivPowerSeriesRing<C> a = null;
216            try {
217                a = (UnivPowerSeriesRing<C>) B;
218            } catch (ClassCastException ignored) {
219            }
220            if (var.equals(a.var)) {
221                return true;
222            }
223            return false;
224        }
225    
226    
227        /**
228         * Hash code for this .
229         * @see java.lang.Object#hashCode()
230         */
231        @Override
232        public int hashCode() {
233            int h = 0;
234            h = (var.hashCode() << 27);
235            h += truncate;
236            return h;
237        }
238    
239    
240        /**
241         * Get the zero element.
242         * @return 0 as UnivPowerSeries<C>.
243         */
244        public UnivPowerSeries<C> getZERO() {
245            return ZERO;
246        }
247    
248    
249        /**
250         * Get the one element.
251         * @return 1 as UnivPowerSeries<C>.
252         */
253        public UnivPowerSeries<C> getONE() {
254            return ONE;
255        }
256    
257    
258        /**
259         * Get a list of the generating elements.
260         * @return list of generators for the algebraic structure.
261         * @see edu.jas.structure.ElemFactory#generators()
262         */
263        public List<UnivPowerSeries<C>> generators() {
264            List<C> rgens = coFac.generators();
265            List<UnivPowerSeries<C>> gens = new ArrayList<UnivPowerSeries<C>>(rgens.size());
266            for (final C cg : rgens) {
267                UnivPowerSeries<C> g = new UnivPowerSeries<C>(this, new Coefficients<C>() {
268    
269    
270                    @Override
271                    public C generate(int i) {
272                        if (i == 0) {
273                            return cg;
274                        }
275                        return coFac.getZERO();
276                    }
277                });
278                gens.add(g);
279            }
280            gens.add(ONE.shift(1));
281            return gens;
282        }
283    
284    
285        /**
286         * Is this structure finite or infinite.
287         * @return true if this structure is finite, else false.
288         * @see edu.jas.structure.ElemFactory#isFinite()
289         */
290        public boolean isFinite() {
291            return false;
292        }
293    
294    
295        /**
296         * Get the power series of the exponential function.
297         * @return exp(x) as UnivPowerSeries<C>.
298         */
299        public UnivPowerSeries<C> getEXP() {
300            return fixPoint(new UnivPowerSeriesMap<C>() {
301    
302    
303                public UnivPowerSeries<C> map(UnivPowerSeries<C> e) {
304                    return e.integrate(coFac.getONE());
305                }
306            });
307        }
308    
309    
310        /**
311         * Get the power series of the sinus function.
312         * @return sin(x) as UnivPowerSeries<C>.
313         */
314        public UnivPowerSeries<C> getSIN() {
315            return fixPoint(new UnivPowerSeriesMap<C>() {
316    
317    
318                public UnivPowerSeries<C> map(UnivPowerSeries<C> s) {
319                    return s.negate().integrate(coFac.getONE()).integrate(coFac.getZERO());
320                }
321            });
322        }
323    
324    
325        /**
326         * Get the power series of the cosine function.
327         * @return cos(x) as UnivPowerSeries<C>.
328         */
329        public UnivPowerSeries<C> getCOS() {
330            return fixPoint(new UnivPowerSeriesMap<C>() {
331    
332    
333                public UnivPowerSeries<C> map(UnivPowerSeries<C> c) {
334                    return c.negate().integrate(coFac.getZERO()).integrate(coFac.getONE());
335                }
336            });
337        }
338    
339    
340        /**
341         * Get the power series of the tangens function.
342         * @return tan(x) as UnivPowerSeries<C>.
343         */
344        public UnivPowerSeries<C> getTAN() {
345            return fixPoint(new UnivPowerSeriesMap<C>() {
346    
347    
348                public UnivPowerSeries<C> map(UnivPowerSeries<C> t) {
349                    return t.multiply(t).sum(getONE()).integrate(coFac.getZERO());
350                }
351            });
352        }
353    
354    
355        /**
356         * Solve an ordinary differential equation. y' = f(y) with y(0) = c.
357         * @param f a UnivPowerSeries<C>.
358         * @param c integration constant.
359         * @return f.integrate(c).
360         */
361        public UnivPowerSeries<C> solveODE(final UnivPowerSeries<C> f, final C c) {
362            return f.integrate(c);
363        }
364    
365    
366        /**
367         * Is commutative.
368         * @return true, if this ring is commutative, else false.
369         */
370        public boolean isCommutative() {
371            return coFac.isCommutative();
372        }
373    
374    
375        /**
376         * Query if this ring is associative.
377         * @return true if this ring is associative, else false.
378         */
379        public boolean isAssociative() {
380            return coFac.isAssociative();
381        }
382    
383    
384        /**
385         * Query if this ring is a field.
386         * @return false.
387         */
388        public boolean isField() {
389            return false;
390        }
391    
392    
393        /**
394         * Characteristic of this ring.
395         * @return characteristic of this ring.
396         */
397        public java.math.BigInteger characteristic() {
398            return coFac.characteristic();
399        }
400    
401    
402        /**
403         * Get a (constant) UnivPowerSeries&lt;C&gt; from a long value.
404         * @param a long.
405         * @return a UnivPowerSeries&lt;C&gt;.
406         */
407        public UnivPowerSeries<C> fromInteger(long a) {
408            return ONE.multiply(coFac.fromInteger(a));
409        }
410    
411    
412        /**
413         * Get a (constant) UnivPowerSeries&lt;C&gt; from a java.math.BigInteger.
414         * @param a BigInteger.
415         * @return a UnivPowerSeries&lt;C&gt;.
416         */
417        public UnivPowerSeries<C> fromInteger(java.math.BigInteger a) {
418            return ONE.multiply(coFac.fromInteger(a));
419        }
420    
421    
422        /**
423         * Get the corresponding GenPolynomialRing&lt;C&gt;.
424         * @return GenPolynomialRing&lt;C&gt;.
425         */
426        public GenPolynomialRing<C> polyRing() {
427            return new GenPolynomialRing<C>(coFac, 1, new String[] { var });
428        }
429    
430    
431        /**
432         * Get a UnivPowerSeries&lt;C&gt; from a GenPolynomial&lt;C&gt;.
433         * @param a GenPolynomial&lt;C&gt;.
434         * @return a UnivPowerSeries&lt;C&gt;.
435         */
436        public UnivPowerSeries<C> fromPolynomial(GenPolynomial<C> a) {
437            if (a == null || a.isZERO()) {
438                return ZERO;
439            }
440            if (a.isONE()) {
441                return ONE;
442            }
443            if (a.ring.nvar != 1) {
444                throw new IllegalArgumentException("only for univariate polynomials");
445            }
446            HashMap<Integer, C> cache = new HashMap<Integer, C>(a.length());
447            for (Monomial<C> m : a) {
448                long e = m.exponent().getVal(0);
449                cache.put((int) e, m.coefficient());
450            }
451            return new UnivPowerSeries<C>(this, new Coefficients<C>(cache) {
452    
453    
454                @Override
455                public C generate(int i) {
456                    // cached coefficients returned by get
457                    return coFac.getZERO();
458                }
459            });
460        }
461    
462    
463        /**
464         * Generate a random power series with k = 5, d = 0.7.
465         * @return a random power series.
466         */
467        public UnivPowerSeries<C> random() {
468            return random(5, 0.7f, random);
469        }
470    
471    
472        /**
473         * Generate a random power series with d = 0.7.
474         * @param k bitsize of random coefficients.
475         * @return a random power series.
476         */
477        public UnivPowerSeries<C> random(int k) {
478            return random(k, 0.7f, random);
479        }
480    
481    
482        /**
483         * Generate a random power series with d = 0.7.
484         * @param k bit-size of random coefficients.
485         * @param rnd is a source for random bits.
486         * @return a random power series.
487         */
488        public UnivPowerSeries<C> random(int k, Random rnd) {
489            return random(k, 0.7f, rnd);
490        }
491    
492    
493        /**
494         * Generate a random power series.
495         * @param k bit-size of random coefficients.
496         * @param d density of non-zero coefficients.
497         * @return a random power series.
498         */
499        public UnivPowerSeries<C> random(int k, float d) {
500            return random(k, d, random);
501        }
502    
503    
504        /**
505         * Generate a random power series.
506         * @param k bit-size of random coefficients.
507         * @param d density of non-zero coefficients.
508         * @param rnd is a source for random bits.
509         * @return a random power series.
510         */
511        public UnivPowerSeries<C> random(final int k, final float d, final Random rnd) {
512            return new UnivPowerSeries<C>(this, new Coefficients<C>() {
513    
514    
515                @Override
516                public C generate(int i) {
517                    // cached coefficients returned by get
518                    C c;
519                    float f = rnd.nextFloat();
520                    if (f < d) {
521                        c = coFac.random(k, rnd);
522                    } else {
523                        c = coFac.getZERO();
524                    }
525                    return c;
526                }
527            });
528        }
529    
530    
531        /**
532         * Copy power series.
533         * @param c a power series.
534         * @return a copy of c.
535         */
536        public UnivPowerSeries<C> copy(UnivPowerSeries<C> c) {
537            return new UnivPowerSeries<C>(this, c.lazyCoeffs);
538        }
539    
540    
541        /**
542         * Parse a power series. <b>Note:</b> not implemented.
543         * @param s String.
544         * @return power series from s.
545         */
546        public UnivPowerSeries<C> parse(String s) {
547            throw new UnsupportedOperationException("parse for power series not implemented");
548        }
549    
550    
551        /**
552         * Parse a power series. <b>Note:</b> not implemented.
553         * @param r Reader.
554         * @return next power series from r.
555         */
556        public UnivPowerSeries<C> parse(Reader r) {
557            throw new UnsupportedOperationException("parse for power series not implemented");
558        }
559    
560    
561        /**
562         * Taylor power series.
563         * @param f function.
564         * @param a expansion point.
565         * @return Taylor series of f.
566         */
567        public UnivPowerSeries<C> seriesOfTaylor(final TaylorFunction<C> f, final C a) {
568            return new UnivPowerSeries<C>(this, new Coefficients<C>() {
569    
570    
571                TaylorFunction<C> der = f;
572    
573    
574                long k = 0;
575    
576    
577                long n = 1;
578    
579    
580                @Override
581                public C generate(int i) {
582                    C c;
583                    if (i == 0) {
584                        c = der.evaluate(a);
585                        der = der.deriviative();
586                        return c;
587                    }
588                    if (i > 0) {
589                        c = get(i - 1); // ensure deriv is updated
590                    }
591                    k++;
592                    n *= k;
593                    c = der.evaluate(a);
594                    //System.out.println("n = " + n + ", i = " +i);
595                    c = c.divide(coFac.fromInteger(n));
596                    der = der.deriviative();
597                    return c;
598                }
599            });
600        }
601    
602    }