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<C> from a long value. 409 * @param a long. 410 * @return a UnivPowerSeries<C>. 411 */ 412 public UnivPowerSeries<C> fromInteger(long a) { 413 return ONE.multiply(coFac.fromInteger(a)); 414 } 415 416 417 /** 418 * Get a (constant) UnivPowerSeries<C> from a java.math.BigInteger. 419 * @param a BigInteger. 420 * @return a UnivPowerSeries<C>. 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<C>. 429 * @return GenPolynomialRing<C>. 430 */ 431 public GenPolynomialRing<C> polyRing() { 432 return new GenPolynomialRing<C>(coFac, 1, new String[] { var }); 433 } 434 435 436 /** 437 * Get a UnivPowerSeries<C> from a GenPolynomial<C>. 438 * @param a GenPolynomial<C>. 439 * @return a UnivPowerSeries<C>. 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<C> from a GenVector<C>. 470 * @param a GenVector<C>. 471 * @return a UnivPowerSeries<C>. 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}