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