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