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