001/* 002 * $Id: MultiVarPowerSeriesRing.java 6001 2020-03-22 11:30:33Z axelclk $ 003 */ 004 005package edu.jas.ps; 006 007 008import java.io.Reader; 009import java.util.ArrayList; 010import java.util.Arrays; 011import java.util.BitSet; 012import java.util.HashMap; 013import java.util.List; 014import java.util.Random; 015import java.util.function.Function; 016 017import edu.jas.kern.PrettyPrint; 018import edu.jas.poly.ExpVector; 019import edu.jas.poly.GenPolynomial; 020import edu.jas.poly.GenPolynomialRing; 021import edu.jas.poly.Monomial; 022import edu.jas.structure.RingElem; 023import edu.jas.structure.RingFactory; 024import edu.jas.structure.UnaryFunctor; 025import edu.jas.util.ListUtil; 026 027 028/** 029 * Multivariate power series ring implementation. Uses lazy evaluated generating 030 * function for coefficients. 031 * @param <C> ring element type 032 * @author Heinz Kredel 033 */ 034 035public class MultiVarPowerSeriesRing<C extends RingElem<C>> implements RingFactory<MultiVarPowerSeries<C>> { 036 037 038 /** 039 * A default random sequence generator. 040 */ 041 protected final static Random random = new Random(); 042 043 044 /** 045 * Default truncate. 046 */ 047 public final static int DEFAULT_TRUNCATE = 7; 048 049 050 /** 051 * Truncate. 052 */ 053 int truncate; 054 055 056 /** 057 * Zero ExpVector. 058 */ 059 public final ExpVector EVZERO; 060 061 062 /** 063 * Coefficient ring factory. 064 */ 065 public final RingFactory<C> coFac; 066 067 068 /** 069 * The number of variables. 070 */ 071 public final int nvar; 072 073 074 /** 075 * The names of the variables. This value can be modified. 076 */ 077 protected String[] vars; 078 079 080 /** 081 * The constant power series 1 for this ring. 082 */ 083 public final MultiVarPowerSeries<C> ONE; 084 085 086 /** 087 * The constant power series 0 for this ring. 088 */ 089 public final MultiVarPowerSeries<C> ZERO; 090 091 092 /** 093 * No argument constructor. 094 */ 095 @SuppressWarnings("unused") 096 private MultiVarPowerSeriesRing() { 097 throw new IllegalArgumentException("do not use no-argument constructor"); 098 } 099 100 101 /** 102 * Constructor. 103 * @param fac polynomial ring factory. 104 */ 105 public MultiVarPowerSeriesRing(GenPolynomialRing<C> fac) { 106 this(fac.coFac, fac.nvar, fac.getVars()); 107 } 108 109 110 /** 111 * Constructor. 112 * @param coFac coefficient ring factory. 113 */ 114 public MultiVarPowerSeriesRing(RingFactory<C> coFac, int nv) { 115 this(coFac, nv, DEFAULT_TRUNCATE); 116 } 117 118 119 /** 120 * Constructor. 121 * @param coFac coefficient ring factory. 122 * @param truncate index of truncation. 123 */ 124 public MultiVarPowerSeriesRing(RingFactory<C> coFac, int nv, int truncate) { 125 this(coFac, nv, truncate, null); 126 } 127 128 129 /** 130 * Constructor. 131 * @param coFac coefficient ring factory. 132 * @param names of the variables. 133 */ 134 public MultiVarPowerSeriesRing(RingFactory<C> coFac, String[] names) { 135 this(coFac, names.length, DEFAULT_TRUNCATE, names); 136 } 137 138 139 /** 140 * Constructor. 141 * @param cofac coefficient ring factory. 142 * @param nv number of variables. 143 * @param names of the variables. 144 */ 145 public MultiVarPowerSeriesRing(RingFactory<C> cofac, int nv, String[] names) { 146 this(cofac, nv, DEFAULT_TRUNCATE, names); 147 } 148 149 150 /** 151 * Constructor. 152 * @param cofac coefficient ring factory. 153 * @param truncate index of truncation. 154 * @param names of the variables. 155 */ 156 public MultiVarPowerSeriesRing(RingFactory<C> cofac, int nv, int truncate, String[] names) { 157 this.coFac = cofac; 158 this.nvar = nv; 159 this.truncate = truncate; 160 if (names == null) { 161 vars = null; 162 } else { 163 vars = Arrays.copyOf(names, names.length); // > Java-5 164 } 165 if (vars == null) { 166 if (PrettyPrint.isTrue()) { 167 vars = GenPolynomialRing.newVars("x", nvar); 168 } 169 } else { 170 if (vars.length != nvar) { 171 throw new IllegalArgumentException("incompatible variable size " + vars.length + ", " + nvar); 172 } 173 // GenPolynomialRing.addVars(vars); 174 } 175 EVZERO = ExpVector.create(nvar); 176 ONE = new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 177 178 179 @Override 180 public C generate(ExpVector i) { 181 if (i.isZERO()) { 182 return coFac.getONE(); 183 } 184 return coFac.getZERO(); 185 } 186 }); 187 ZERO = new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 188 189 190 @Override 191 public C generate(ExpVector i) { 192 return coFac.getZERO(); 193 } 194 }); 195 } 196 197 198 /** 199 * Fixed point construction. 200 * @param map a mapping of power series. 201 * @return fix point wrt map. 202 */ 203 // Cannot be a static method because a power series ring is required. 204 public MultiVarPowerSeries<C> fixPoint(MultiVarPowerSeriesMap<C> map) { 205 MultiVarPowerSeries<C> ps1 = new MultiVarPowerSeries<C>(this); 206 MultiVarPowerSeries<C> ps2 = map.map(ps1); 207 ps1.lazyCoeffs = ps2.lazyCoeffs; 208 return ps2; 209 } 210 211 212 /** 213 * To String. 214 * @return string representation of this. 215 */ 216 @Override 217 public String toString() { 218 StringBuffer sb = new StringBuffer(); 219 String scf = coFac.getClass().getSimpleName(); 220 sb.append(scf + "((" + varsToString() + "))"); 221 return sb.toString(); 222 } 223 224 225 /** 226 * Get a String representation of the variable names. 227 * @return names separated by commas. 228 */ 229 public String varsToString() { 230 if (vars == null) { 231 return "#" + nvar; 232 } 233 return ExpVector.varsToString(vars); 234 //return Arrays.toString(vars); 235 } 236 237 238 /** 239 * Get the variable names. 240 * @return names. 241 */ 242 public String[] getVars() { 243 return Arrays.copyOf(vars, vars.length); // > Java-5 244 } 245 246 247 /** 248 * Get a scripting compatible string representation. 249 * @return script compatible representation for this ElemFactory. 250 * @see edu.jas.structure.ElemFactory#toScript() 251 */ 252 @Override 253 public String toScript() { 254 // Python case 255 StringBuffer s = new StringBuffer("MPS("); 256 String f = null; 257 try { 258 f = ((RingElem<C>) coFac).toScriptFactory(); // sic 259 } catch (Exception e) { 260 f = coFac.toScript(); 261 } 262 s.append(f + ",\"" + varsToString() + "\"," + truncate + ")"); 263 return s.toString(); 264 } 265 266 267 /** 268 * Comparison with any other object. 269 * @see java.lang.Object#equals(java.lang.Object) 270 */ 271 @Override 272 @SuppressWarnings("unchecked") 273 public boolean equals(Object B) { 274 MultiVarPowerSeriesRing<C> a = null; 275 try { 276 a = (MultiVarPowerSeriesRing<C>) B; 277 } catch (ClassCastException ignored) { 278 } 279 if (a == null) { 280 return false; 281 } 282 if (!coFac.equals(a.coFac)) { 283 return false; 284 } 285 if (Arrays.deepEquals(vars, a.vars)) { 286 return true; 287 } 288 return false; 289 } 290 291 292 /** 293 * Hash code for this . 294 * @see java.lang.Object#hashCode() 295 */ 296 @Override 297 public int hashCode() { 298 int h = coFac.hashCode(); 299 h = h << 7; 300 h += (Arrays.hashCode(vars) << 17); 301 h += truncate; 302 return h; 303 } 304 305 306 /** 307 * Get the zero element. 308 * @return 0 as MultiVarPowerSeries<C>. 309 */ 310 public MultiVarPowerSeries<C> getZERO() { 311 return ZERO; 312 } 313 314 315 /** 316 * Get the one element. 317 * @return 1 as MultiVarPowerSeries<C>. 318 */ 319 public MultiVarPowerSeries<C> getONE() { 320 return ONE; 321 } 322 323 324 /** 325 * Get a list of the generating elements. 326 * @return list of generators for the algebraic structure. 327 * @see edu.jas.structure.ElemFactory#generators() 328 */ 329 public List<MultiVarPowerSeries<C>> generators() { 330 List<C> rgens = coFac.generators(); 331 List<MultiVarPowerSeries<C>> gens = new ArrayList<MultiVarPowerSeries<C>>(rgens.size()); 332 for (final C cg : rgens) { 333 MultiVarPowerSeries<C> g = new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 334 335 336 @Override 337 public C generate(ExpVector i) { 338 if (i.isZERO()) { 339 return cg; 340 } 341 return coFac.getZERO(); 342 } 343 }); 344 gens.add(g); 345 } 346 for (int i = 0; i < nvar; i++) { 347 gens.add(ONE.shift(1, nvar - 1 - i)); 348 } 349 return gens; 350 } 351 352 353 /** 354 * Is this structure finite or infinite. 355 * @return true if this structure is finite, else false. 356 * @see edu.jas.structure.ElemFactory#isFinite() 357 */ 358 public boolean isFinite() { 359 return false; 360 } 361 362 363 /** 364 * Truncate. 365 * @return truncate index of power series. 366 */ 367 public int truncate() { 368 return truncate; 369 } 370 371 372 /** 373 * Set truncate. 374 * @param t new truncate index. 375 * @return old truncate index of power series. 376 */ 377 public int setTruncate(int t) { 378 if (t < 0) { 379 throw new IllegalArgumentException("negative truncate not allowed"); 380 } 381 int ot = truncate; 382 truncate = t; 383 ONE.setTruncate(t); 384 ZERO.setTruncate(t); 385 return ot; 386 } 387 388 389 /** 390 * Get the power series of the exponential function. 391 * @param r variable for the direction. 392 * @return exp(x_r) as MultiVarPowerSeries<C>. 393 */ 394 public MultiVarPowerSeries<C> getEXP(final int r) { 395 return fixPoint(new MultiVarPowerSeriesMap<C>() { 396 397 398 public MultiVarPowerSeries<C> map(MultiVarPowerSeries<C> e) { 399 return e.integrate(coFac.getONE(), r); 400 } 401 }); 402 } 403 404 405 /** 406 * Get the power series of the sinus function. 407 * @param r variable for the direction. 408 * @return sin(x_r) as MultiVarPowerSeries<C>. 409 */ 410 public MultiVarPowerSeries<C> getSIN(final int r) { 411 return fixPoint(new MultiVarPowerSeriesMap<C>() { 412 413 414 public MultiVarPowerSeries<C> map(MultiVarPowerSeries<C> s) { 415 return s.negate().integrate(coFac.getONE(), r).integrate(coFac.getZERO(), r); 416 } 417 }); 418 } 419 420 421 /** 422 * Get the power series of the cosinus function. 423 * @param r variable for the direction. 424 * @return cos(x_r) as MultiVarPowerSeries<C>. 425 */ 426 public MultiVarPowerSeries<C> getCOS(final int r) { 427 return fixPoint(new MultiVarPowerSeriesMap<C>() { 428 429 430 public MultiVarPowerSeries<C> map(MultiVarPowerSeries<C> c) { 431 return c.negate().integrate(coFac.getZERO(), r).integrate(coFac.getONE(), r); 432 } 433 }); 434 } 435 436 437 /** 438 * Get the power series of the tangens function. 439 * @param r variable for the direction. 440 * @return tan(x_r) as MultiVarPowerSeries<C>. 441 */ 442 public MultiVarPowerSeries<C> getTAN(final int r) { 443 return fixPoint(new MultiVarPowerSeriesMap<C>() { 444 445 446 public MultiVarPowerSeries<C> map(MultiVarPowerSeries<C> t) { 447 return t.multiply(t).sum(getONE()).integrate(coFac.getZERO(), r); 448 } 449 }); 450 } 451 452 453 /** 454 * Solve an partial differential equation. y_r' = f(y_r) with y_r(0) = c. 455 * @param f a MultiVarPowerSeries<C>. 456 * @param c integration constant. 457 * @param r variable for the direction. 458 * @return f.integrate(c). 459 */ 460 public MultiVarPowerSeries<C> solvePDE(MultiVarPowerSeries<C> f, C c, int r) { 461 return f.integrate(c, r); 462 } 463 464 465 /** 466 * Query if this ring is commuative. 467 * @return true, if this ring is commutative, else false. 468 */ 469 public boolean isCommutative() { 470 return coFac.isCommutative(); 471 } 472 473 474 /** 475 * Query if this ring is associative. 476 * @return true if this ring is associative, else false. 477 */ 478 public boolean isAssociative() { 479 return coFac.isAssociative(); 480 } 481 482 483 /** 484 * Query if this ring is a field. 485 * @return true if this ring is a field, else false. 486 */ 487 public boolean isField() { 488 return (nvar == 0) && coFac.isField(); //false; 489 } 490 491 492 /** 493 * Characteristic of this ring. 494 * @return characteristic of this ring. 495 */ 496 public java.math.BigInteger characteristic() { 497 return coFac.characteristic(); 498 } 499 500 501 /** 502 * Get a (constant) MultiVarPowerSeries<C> from a long value. 503 * @param a long. 504 * @return a MultiVarPowerSeries<C>. 505 */ 506 public MultiVarPowerSeries<C> fromInteger(final long a) { 507 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 508 509 510 @Override 511 public C generate(ExpVector i) { 512 if (i.isZERO()) { 513 return coFac.fromInteger(a); 514 } 515 return coFac.getZERO(); 516 } 517 }); 518 } 519 520 521 /** 522 * Get a (constant) MultiVarPowerSeries<C> from a 523 * java.math.BigInteger. 524 * @param a BigInteger. 525 * @return a MultiVarPowerSeries<C>. 526 */ 527 public MultiVarPowerSeries<C> fromInteger(final java.math.BigInteger a) { 528 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 529 530 531 @Override 532 public C generate(ExpVector i) { 533 if (i.isZERO()) { 534 return coFac.fromInteger(a); 535 } 536 return coFac.getZERO(); 537 } 538 }); 539 } 540 541 542 /** 543 * Get the corresponding GenPolynomialRing<C>. 544 * @return GenPolynomialRing<C>. 545 */ 546 public GenPolynomialRing<C> polyRing() { 547 return new GenPolynomialRing<C>(coFac, nvar, vars); 548 } 549 550 551 /** 552 * Get a MultiVarPowerSeries<C> from a GenPolynomial<C>. 553 * @param a GenPolynomial<C>. 554 * @return a MultiVarPowerSeries<C>. 555 */ 556 public MultiVarPowerSeries<C> fromPolynomial(GenPolynomial<C> a) { 557 if (a == null || a.isZERO()) { 558 return ZERO; 559 } 560 if (a.isONE()) { 561 return ONE; 562 } 563 GenPolynomialRing<C> pfac = polyRing(); 564 HashMap<Long, GenPolynomial<C>> cache = new HashMap<Long, GenPolynomial<C>>(); 565 int mt = 0; 566 for (Monomial<C> m : a) { 567 ExpVector e = m.exponent(); 568 long t = e.totalDeg(); 569 mt = Math.max(mt, (int) t); 570 GenPolynomial<C> p = cache.get(t); 571 if (p == null) { 572 p = pfac.getZERO().copy(); 573 cache.put(t, p); 574 } 575 p.doPutToMap(e, m.coefficient()); 576 } 577 mt++; 578 if (mt > truncate()) { 579 setTruncate(mt); 580 } 581 BitSet check = new BitSet(); 582 for (int i = 0; i <= truncate(); i++) { 583 check.set(i); 584 if (cache.get((long) i) == null) { 585 GenPolynomial<C> p = pfac.getZERO().copy(); 586 cache.put((long) i, p); 587 //System.out.println("p zero for deg i = " + i); 588 } 589 } 590 591 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(pfac, cache, check) { 592 593 594 @Override 595 public C generate(ExpVector e) { 596 // cached coefficients returned by get 597 return coFac.getZERO(); 598 } 599 }); 600 } 601 602 603 /** 604 * Get a list of MultiVarPowerSeries<C> from a list of 605 * GenPolynomial<C>. 606 * @param A list of GenPolynomial<C>. 607 * @return a list of MultiVarPowerSeries<C>. 608 */ 609 public List<MultiVarPowerSeries<C>> fromPolynomial(List<GenPolynomial<C>> A) { 610 return ListUtil.<GenPolynomial<C>, MultiVarPowerSeries<C>> map(A, 611 new UnaryFunctor<GenPolynomial<C>, MultiVarPowerSeries<C>>() { 612 613 614 public MultiVarPowerSeries<C> eval(GenPolynomial<C> c) { 615 return fromPolynomial(c); 616 } 617 }); 618 } 619 620 621 /** 622 * Get a MultiVarPowerSeries<C> from a univariate power series. 623 * @param ps UnivPowerSeries<C>. 624 * @param r variable for the direction. 625 * @return a MultiVarPowerSeries<C>. 626 */ 627 public MultiVarPowerSeries<C> fromPowerSeries(final UnivPowerSeries<C> ps, final int r) { 628 if (ps == null) { 629 return ZERO; 630 } 631 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 632 633 634 @Override 635 public C generate(ExpVector i) { 636 if (i.isZERO()) { 637 return ps.coefficient(0); 638 } 639 int[] dep = i.dependencyOnVariables(); 640 if (dep.length != 1) { 641 return coFac.getZERO(); 642 } 643 if (dep[0] != r) { 644 return coFac.getZERO(); 645 } 646 int j = (int) i.getVal(r); 647 if (j > 0) { 648 return ps.coefficient(j); 649 } 650 return coFac.getZERO(); 651 } 652 }); 653 } 654 655 656 /** 657 * Generate a random power series with k = 5, d = 0.7. 658 * @return a random power series. 659 */ 660 public MultiVarPowerSeries<C> random() { 661 return random(5, 0.7f, random); 662 } 663 664 665 /** 666 * Generate a random power series with d = 0.7. 667 * @param k bit-size of random coefficients. 668 * @return a random power series. 669 */ 670 public MultiVarPowerSeries<C> random(int k) { 671 return random(k, 0.7f, random); 672 } 673 674 675 /** 676 * Generate a random power series with d = 0.7. 677 * @param k bit-size of random coefficients. 678 * @param rnd is a source for random bits. 679 * @return a random power series. 680 */ 681 public MultiVarPowerSeries<C> random(int k, Random rnd) { 682 return random(k, 0.7f, rnd); 683 } 684 685 686 /** 687 * Generate a random power series. 688 * @param k bit-size of random coefficients. 689 * @param d density of non-zero coefficients. 690 * @return a random power series. 691 */ 692 public MultiVarPowerSeries<C> random(int k, float d) { 693 return random(k, d, random); 694 } 695 696 697 /** 698 * Generate a random power series. 699 * @param k bit-size of random coefficients. 700 * @param d density of non-zero coefficients. 701 * @param rnd is a source for random bits. 702 * @return a random power series. 703 */ 704 public MultiVarPowerSeries<C> random(final int k, final float d, final Random rnd) { 705 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 706 707 708 @Override 709 public C generate(ExpVector i) { 710 // cached coefficients returned by get 711 C c; 712 float f = rnd.nextFloat(); 713 if (f < d) { 714 c = coFac.random(k, rnd); 715 } else { 716 c = coFac.getZERO(); 717 } 718 return c; 719 } 720 }); 721 } 722 723 724 /** 725 * Generate a power series via lambda expression. 726 * @param gener lambda expression. 727 * @return a generated power series. 728 */ 729 public MultiVarPowerSeries<C> generate(final Function<ExpVector, C> gener) { 730 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 731 732 733 @Override 734 public C generate(ExpVector i) { 735 // cached coefficients returned by get 736 C c = gener.apply(i); 737 return c; 738 } 739 }); 740 } 741 742 743 /** 744 * Copy power series. 745 * @param c a power series. 746 * @return a copy of c. 747 */ 748 public MultiVarPowerSeries<C> copy(MultiVarPowerSeries<C> c) { 749 return new MultiVarPowerSeries<C>(this, c.lazyCoeffs); 750 } 751 752 753 /** 754 * Parse a power series. <b>Note:</b> not implemented. 755 * @param s String. 756 * @return power series from s. 757 */ 758 public MultiVarPowerSeries<C> parse(String s) { 759 throw new UnsupportedOperationException("parse for power series not implemented"); 760 } 761 762 763 /** 764 * Parse a power series. <b>Note:</b> not implemented. 765 * @param r Reader. 766 * @return next power series from r. 767 */ 768 public MultiVarPowerSeries<C> parse(Reader r) { 769 throw new UnsupportedOperationException("parse for power series not implemented"); 770 } 771 772 773 /** 774 * Taylor power series. 775 * @param f function. 776 * @param a expansion point. 777 * @return Taylor series of f. 778 */ 779 public MultiVarPowerSeries<C> seriesOfTaylor(final TaylorFunction<C> f, final List<C> a) { 780 return new MultiVarPowerSeries<C>(this, new MultiVarCoefficients<C>(this) { 781 782 783 TaylorFunction<C> der = f; 784 785 786 // Map<ExpVextor,TaylorFunction<C>> pderCache = ... 787 final List<C> v = a; 788 789 790 @Override 791 public C generate(ExpVector i) { 792 C c; 793 int s = i.signum(); 794 if (s == 0) { 795 c = der.evaluate(v); 796 return c; 797 } 798 TaylorFunction<C> pder = der.deriviative(i); 799 if (pder.isZERO()) { 800 return coFac.getZERO(); 801 } 802 c = pder.evaluate(v); 803 if (c.isZERO()) { 804 return c; 805 } 806 long f = pder.getFacul(); 807 c = c.divide(coFac.fromInteger(f)); 808 return c; 809 } 810 }); 811 } 812 813}