001/* 002 * $Id: MultiVarPowerSeries.java 5934 2018-09-30 11:23:44Z kredel $ 003 */ 004 005package edu.jas.ps; 006 007 008import java.util.BitSet; 009import java.util.HashMap; 010import java.util.HashSet; 011import java.util.Iterator; 012import java.util.List; 013import java.util.Map; 014import java.util.Set; 015import java.util.TreeMap; 016 017import edu.jas.poly.AlgebraicNumber; 018import edu.jas.poly.ExpVector; 019import edu.jas.poly.GenPolynomial; 020import edu.jas.structure.BinaryFunctor; 021import edu.jas.structure.RingElem; 022import edu.jas.structure.Selector; 023import edu.jas.structure.UnaryFunctor; 024import edu.jas.util.MapEntry; 025 026 027/** 028 * Multivariate power series implementation. Uses inner classes and lazy 029 * evaluated generating function for coefficients. All ring element methods use 030 * lazy evaluation except where noted otherwise. Eager evaluated methods are 031 * <code>toString()</code>, <code>compareTo()</code>, <code>equals()</code>, 032 * <code>evaluate()</code>, or methods which use the <code>order()</code> or 033 * <code>orderExpVector()</code> methods, like <code>signum()</code>, 034 * <code>abs()</code>, <code>divide()</code>, <code>remainder()</code> and 035 * <code>gcd()</code>. <b>Note: </b> Currently the term order is fixed to the 036 * order defined by the iterator over exponent vectors in class 037 * <code>ExpVectorIterator</code>. 038 * @param <C> ring element type 039 * @author Heinz Kredel 040 */ 041 042public class MultiVarPowerSeries<C extends RingElem<C>> implements RingElem<MultiVarPowerSeries<C>> { 043 044 045 /** 046 * Power series ring factory. 047 */ 048 public final MultiVarPowerSeriesRing<C> ring; 049 050 051 /** 052 * Data structure / generating function for coeffcients. Cannot be final 053 * because of fixPoint, must be accessible in factory. 054 */ 055 /*package*/MultiVarCoefficients<C> lazyCoeffs; 056 057 058 /** 059 * Truncation of computations. 060 */ 061 private int truncate; 062 063 064 /** 065 * Order of power series. 066 */ 067 private int order = -1; // == unknown 068 069 070 /** 071 * ExpVector of order of power series. 072 */ 073 private ExpVector evorder = null; // == unknown 074 075 076 /** 077 * Private constructor. 078 */ 079 @SuppressWarnings("unused") 080 private MultiVarPowerSeries() { 081 throw new IllegalArgumentException("do not use no-argument constructor"); 082 } 083 084 085 /** 086 * Package constructor. Use in fixPoint only, must be accessible in factory. 087 * @param ring power series ring. 088 */ 089 /*package*/ MultiVarPowerSeries(MultiVarPowerSeriesRing<C> ring) { 090 this.ring = ring; 091 this.lazyCoeffs = null; 092 this.truncate = ring.truncate; 093 } 094 095 096 /** 097 * Constructor. 098 * @param ring power series ring. 099 * @param lazyCoeffs generating function for coefficients. 100 */ 101 public MultiVarPowerSeries(MultiVarPowerSeriesRing<C> ring, MultiVarCoefficients<C> lazyCoeffs) { 102 this(ring, lazyCoeffs, ring.truncate); 103 } 104 105 106 /** 107 * Constructor. 108 * @param ring power series ring. 109 * @param lazyCoeffs generating function for coefficients. 110 * @param trunc truncate parameter for this power series. 111 */ 112 public MultiVarPowerSeries(MultiVarPowerSeriesRing<C> ring, MultiVarCoefficients<C> lazyCoeffs, 113 int trunc) { 114 if (lazyCoeffs == null || ring == null) { 115 throw new IllegalArgumentException( 116 "null not allowed: ring = " + ring + ", lazyCoeffs = " + lazyCoeffs); 117 } 118 this.ring = ring; 119 this.lazyCoeffs = lazyCoeffs; 120 this.truncate = Math.min(trunc, ring.truncate); 121 } 122 123 124 /** 125 * Get the corresponding element factory. 126 * @return factory for this Element. 127 * @see edu.jas.structure.Element#factory() 128 */ 129 public MultiVarPowerSeriesRing<C> factory() { 130 return ring; 131 } 132 133 134 /** 135 * Clone this power series. 136 * @see java.lang.Object#clone() 137 */ 138 @Override 139 public MultiVarPowerSeries<C> copy() { 140 return new MultiVarPowerSeries<C>(ring, lazyCoeffs); 141 } 142 143 144 /** 145 * String representation of power series. 146 * @see java.lang.Object#toString() 147 */ 148 @Override 149 public String toString() { 150 return toString(truncate); 151 } 152 153 154 /** 155 * To String with given truncate. 156 * @param trunc truncate parameter for this power series. 157 * @return string representation of this to given truncate. 158 */ 159 public String toString(int trunc) { 160 StringBuffer sb = new StringBuffer(); 161 MultiVarPowerSeries<C> s = this; 162 String[] vars = ring.vars; 163 //System.out.println("cache1 = " + s.lazyCoeffs.coeffCache); 164 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, trunc)) { 165 C c = s.coefficient(i); 166 //System.out.println("i = " + i + ", c = " +c); 167 int si = c.signum(); 168 if (si != 0) { 169 if (si > 0) { 170 if (sb.length() > 0) { 171 sb.append(" + "); 172 } 173 } else { 174 c = c.negate(); 175 sb.append(" - "); 176 } 177 if (!c.isONE() || i.isZERO()) { 178 if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { 179 sb.append("{ "); 180 } 181 sb.append(c.toString()); 182 if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { 183 sb.append(" }"); 184 } 185 if (!i.isZERO()) { 186 sb.append(" * "); 187 } 188 } 189 if (i.isZERO()) { 190 //skip; sb.append(" "); 191 } else { 192 sb.append(i.toString(vars)); 193 } 194 //sb.append(c.toString() + ", "); 195 } 196 //System.out.println("cache = " + s.coeffCache); 197 } 198 if (sb.length() == 0) { 199 sb.append("0"); 200 } 201 sb.append(" + BigO( (" + ring.varsToString() + ")^" + (trunc + 1) + "(" + (ring.truncate + 1) 202 + ") )"); 203 //sb.append("..."); 204 //System.out.println("cache2 = " + s.lazyCoeffs.coeffCache); 205 return sb.toString(); 206 } 207 208 209 /** 210 * Get a scripting compatible string representation. 211 * @return script compatible representation for this Element. 212 * @see edu.jas.structure.Element#toScript() 213 */ 214 @Override 215 public String toScript() { 216 // Python case 217 StringBuffer sb = new StringBuffer(""); 218 MultiVarPowerSeries<C> s = this; 219 String[] vars = ring.vars; 220 //System.out.println("cache = " + s.coeffCache); 221 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { 222 C c = s.coefficient(i); 223 int si = c.signum(); 224 if (si != 0) { 225 if (si > 0) { 226 if (sb.length() > 0) { 227 sb.append(" + "); 228 } 229 } else { 230 c = c.negate(); 231 sb.append(" - "); 232 } 233 if (!c.isONE() || i.isZERO()) { 234 if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { 235 sb.append("( "); 236 } 237 sb.append(c.toScript()); 238 if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { 239 sb.append(" )"); 240 } 241 if (!i.isZERO()) { 242 sb.append(" * "); 243 } 244 } 245 if (i.isZERO()) { 246 //skip; sb.append(" "); 247 } else { 248 sb.append(i.toScript(vars)); 249 } 250 //sb.append(c.toString() + ", "); 251 } 252 //System.out.println("cache = " + s.coeffCache); 253 } 254 if (sb.length() == 0) { 255 sb.append("0"); 256 } 257 sb.append(" + BigO( (" + ring.varsToString() + ")**" + (truncate + 1) + " )"); 258 // sb.append("," + truncate + ""); 259 return sb.toString(); 260 } 261 262 263 /** 264 * Get a scripting compatible string representation of the factory. 265 * @return script compatible representation for this ElemFactory. 266 * @see edu.jas.structure.Element#toScriptFactory() 267 */ 268 @Override 269 public String toScriptFactory() { 270 // Python case 271 return factory().toScript(); 272 } 273 274 275 /** 276 * Get coefficient. 277 * @param index number of requested coefficient. 278 * @return coefficient at index. 279 */ 280 public C coefficient(ExpVector index) { 281 if (index == null) { 282 throw new IndexOutOfBoundsException("null index not allowed"); 283 } 284 return lazyCoeffs.get(index); 285 } 286 287 288 /** 289 * Homogeneous part. 290 * @param tdeg requested degree. 291 * @return polynomial part of given degree. 292 */ 293 public GenPolynomial<C> homogeneousPart(long tdeg) { 294 return lazyCoeffs.getHomPart(tdeg); 295 } 296 297 298 /** 299 * Get a GenPolynomial<C> from this. 300 * @return a GenPolynomial<C> from this up to truncate homogeneous 301 * parts. 302 */ 303 public GenPolynomial<C> asPolynomial() { 304 GenPolynomial<C> p = homogeneousPart(0L); 305 for (int i = 1; i <= truncate; i++) { 306 p = p.sum(homogeneousPart(i)); 307 } 308 return p; 309 } 310 311 312 /** 313 * Leading base coefficient. 314 * @return first coefficient. 315 */ 316 public C leadingCoefficient() { 317 return coefficient(ring.EVZERO); 318 } 319 320 321 /** 322 * Reductum. 323 * @param r variable for taking the reductum. 324 * @return this - leading monomial in the direction of r. 325 */ 326 public MultiVarPowerSeries<C> reductum(final int r) { 327 if (r < 0 || ring.nvar < r) { 328 throw new IllegalArgumentException("variable index out of bound"); 329 } 330 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 331 332 333 @Override 334 public C generate(ExpVector i) { 335 ExpVector e = i.subst(r, i.getVal(r) + 1); 336 return coefficient(e); 337 } 338 }); 339 } 340 341 342 /** 343 * Prepend a new leading coefficient. 344 * @param r variable for the direction. 345 * @param h new coefficient. 346 * @return new power series. 347 */ 348 public MultiVarPowerSeries<C> prepend(final C h, final int r) { 349 if (r < 0 || ring.nvar < r) { 350 throw new IllegalArgumentException("variable index out of bound"); 351 } 352 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 353 354 355 @Override 356 public C generate(ExpVector i) { 357 if (i.isZERO()) { 358 return h; 359 } 360 ExpVector e = i.subst(r, i.getVal(r) - 1); 361 if (e.signum() < 0) { 362 return pfac.coFac.getZERO(); 363 } 364 return coefficient(e); 365 } 366 }); 367 } 368 369 370 /** 371 * Shift coefficients. 372 * @param k shift index. 373 * @param r variable for the direction. 374 * @return new power series with coefficient(i) = old.coefficient(i-k). 375 */ 376 public MultiVarPowerSeries<C> shift(final int k, final int r) { 377 if (r < 0 || ring.nvar < r) { 378 throw new IllegalArgumentException("variable index out of bound"); 379 } 380 int nt = Math.min(truncate + k, ring.truncate); 381 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 382 383 384 @Override 385 public C generate(ExpVector i) { 386 long d = i.getVal(r); 387 if (d - k < 0) { 388 return ring.coFac.getZERO(); 389 } 390 ExpVector e = i.subst(r, i.getVal(r) - k); 391 return coefficient(e); 392 } 393 }, nt); 394 } 395 396 397 /** 398 * Reductum. 399 * @return this - leading monomial. 400 */ 401 public MultiVarPowerSeries<C> reductum() { 402 Map.Entry<ExpVector, C> m = orderMonomial(); 403 if (m == null) { 404 return ring.getZERO(); 405 } 406 ExpVector e = m.getKey(); 407 long d = e.totalDeg(); 408 MultiVarCoefficients<C> mc = lazyCoeffs; 409 HashMap<Long, GenPolynomial<C>> cc = new HashMap<Long, GenPolynomial<C>>(mc.coeffCache); 410 GenPolynomial<C> p = cc.get(d); 411 if (p != null && !p.isZERO()) { 412 p = p.subtract(m.getValue(), e); // p contains this term after orderMonomial() 413 cc.put(d, p); 414 } 415 HashSet<ExpVector> z = new HashSet<ExpVector>(mc.zeroCache); 416 if (!mc.homCheck.get((int) d)) { 417 z.add(e); 418 //System.out.println("e = " + e); 419 } 420 421 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(mc.pfac, cc, z, mc.homCheck) { 422 423 424 @Override 425 public C generate(ExpVector i) { 426 return coefficient(i); 427 } 428 }); 429 } 430 431 432 /** 433 * Shift coefficients. Multiply by exponent vector. 434 * @param k shift ExpVector. 435 * @return new power series with coefficient(i) = old.coefficient(i-k). 436 */ 437 public MultiVarPowerSeries<C> shift(final ExpVector k) { 438 if (k == null) { 439 throw new IllegalArgumentException("null ExpVector not allowed"); 440 } 441 if (k.signum() == 0) { 442 return this; 443 } 444 int nt = Math.min(truncate + (int) k.totalDeg(), ring.truncate); 445 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 446 447 448 @Override 449 public C generate(ExpVector i) { 450 ExpVector d = i.subtract(k); 451 if (d.signum() < 0) { 452 return ring.coFac.getZERO(); 453 } 454 return coefficient(d); 455 } 456 }, nt); 457 } 458 459 460 /** 461 * Multiply by exponent vector and coefficient. 462 * @param k shift ExpVector. 463 * @param c coefficient multiplier. 464 * @return new power series with coefficient(i) = old.coefficient(i-k)*c. 465 */ 466 public MultiVarPowerSeries<C> multiply(final C c, final ExpVector k) { 467 if (k == null) { 468 throw new IllegalArgumentException("null ExpVector not allowed"); 469 } 470 if (k.signum() == 0) { 471 return this.multiply(c); 472 } 473 if (c.signum() == 0) { 474 return ring.getZERO(); 475 } 476 int nt = Math.min(ring.truncate, truncate + (int) k.totalDeg()); 477 478 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 479 480 481 @Override 482 public C generate(ExpVector i) { 483 ExpVector d = i.subtract(k); 484 if (d.signum() < 0) { 485 return ring.coFac.getZERO(); 486 } 487 long tdegd = d.totalDeg(); 488 if (lazyCoeffs.homCheck.get((int) tdegd)) { 489 GenPolynomial<C> p = homogeneousPart(tdegd).multiply(c, k); 490 long tdegi = i.totalDeg(); 491 coeffCache.put(tdegi, p); // overwrite 492 homCheck.set((int) tdegi); 493 C b = p.coefficient(i); 494 //System.out.println("b = " + b + ", i = " + i + ", tdegi = " + tdegi+ ", tdegd = " + tdegd); 495 //System.out.println("p = " + p + ", i = " + i); 496 return b; 497 } 498 return coefficient(d).multiply(c); 499 } 500 }, nt); 501 } 502 503 504 /** 505 * Sum monomial. 506 * @param m ExpVector , coeffcient pair 507 * @return this + ONE.multiply(m.coefficient,m.exponent). 508 */ 509 public MultiVarPowerSeries<C> sum(Map.Entry<ExpVector, C> m) { 510 if (m == null) { 511 throw new IllegalArgumentException("null Map.Entry not allowed"); 512 } 513 return sum(m.getValue(), m.getKey()); 514 } 515 516 517 /** 518 * Sum exponent vector and coefficient. 519 * @param k ExpVector. 520 * @param c coefficient. 521 * @return this + ONE.multiply(c,k). 522 */ 523 public MultiVarPowerSeries<C> sum(final C c, final ExpVector k) { 524 if (k == null) { 525 throw new IllegalArgumentException("null ExpVector not allowed"); 526 } 527 if (c.signum() == 0) { 528 return this; 529 } 530 long d = k.totalDeg(); 531 MultiVarCoefficients<C> mc = lazyCoeffs; 532 HashMap<Long, GenPolynomial<C>> cc = new HashMap<Long, GenPolynomial<C>>(mc.coeffCache); 533 GenPolynomial<C> p = cc.get(d); 534 if (p == null) { 535 p = mc.pfac.getZERO(); 536 } 537 p = p.sum(c, k); 538 //System.out.println("p = " + p); 539 cc.put(d, p); 540 HashSet<ExpVector> z = new HashSet<ExpVector>(mc.zeroCache); 541 //System.out.println("z = " + z); 542 if (p.coefficient(k).isZERO() && !mc.homCheck.get((int) d)) { 543 z.add(k); 544 } 545 546 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(mc.pfac, cc, z, mc.homCheck) { 547 548 549 @Override 550 public C generate(ExpVector i) { 551 return coefficient(i); 552 } 553 }); 554 } 555 556 557 /** 558 * Subtract exponent vector and coefficient. 559 * @param k ExpVector. 560 * @param c coefficient. 561 * @return this - ONE.multiply(c,k). 562 */ 563 public MultiVarPowerSeries<C> subtract(final C c, final ExpVector k) { 564 if (k == null) { 565 throw new IllegalArgumentException("null ExpVector not allowed"); 566 } 567 if (c.signum() == 0) { 568 return this; 569 } 570 long d = k.totalDeg(); 571 MultiVarCoefficients<C> mc = lazyCoeffs; 572 HashMap<Long, GenPolynomial<C>> cc = new HashMap<Long, GenPolynomial<C>>(mc.coeffCache); 573 GenPolynomial<C> p = cc.get(d); 574 if (p == null) { 575 p = mc.pfac.getZERO(); 576 } 577 p = p.subtract(c, k); 578 cc.put(d, p); 579 HashSet<ExpVector> z = new HashSet<ExpVector>(mc.zeroCache); 580 //System.out.println("z = " + z); 581 if (p.coefficient(k).isZERO() && !mc.homCheck.get((int) d)) { 582 z.add(k); 583 } 584 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(mc.pfac, cc, z, mc.homCheck) { 585 586 587 @Override 588 public C generate(ExpVector i) { 589 return coefficient(i); 590 } 591 }); 592 } 593 594 595 /** 596 * Sum exponent vector and coefficient. 597 * @param mvc cached coefficients. 598 * @return this + mvc. 599 */ 600 public MultiVarPowerSeries<C> sum(MultiVarCoefficients<C> mvc) { 601 MultiVarCoefficients<C> mc = lazyCoeffs; 602 TreeMap<Long, GenPolynomial<C>> cc = new TreeMap<Long, GenPolynomial<C>>(mc.coeffCache); 603 TreeMap<Long, GenPolynomial<C>> ccv = new TreeMap<Long, GenPolynomial<C>>(mvc.coeffCache); 604 long d1 = (cc.size() > 0 ? cc.lastKey() : 0); 605 long d2 = (ccv.size() > 0 ? ccv.lastKey() : 0); 606 HashSet<ExpVector> z = new HashSet<ExpVector>(mc.zeroCache); 607 z.addAll(mvc.zeroCache); 608 long d = Math.max(d1, d2); 609 BitSet hc = new BitSet((int) d); 610 for (long i = 0; i <= d; i++) { 611 GenPolynomial<C> p1 = cc.get(i); 612 GenPolynomial<C> p2 = mvc.coeffCache.get(i); 613 if (p1 == null) { 614 p1 = mc.pfac.getZERO(); 615 } 616 if (p2 == null) { 617 p2 = mc.pfac.getZERO(); 618 } 619 GenPolynomial<C> p = p1.sum(p2); 620 //System.out.println("p = " + p); 621 cc.put(i, p); 622 if (mc.homCheck.get((int) i) && mvc.homCheck.get((int) i)) { 623 hc.set((int) i); 624 } else { 625 Set<ExpVector> ev = new HashSet<ExpVector>(p1.getMap().keySet()); 626 ev.addAll(p2.getMap().keySet()); 627 ev.removeAll(p.getMap().keySet()); 628 z.addAll(ev); 629 } 630 } 631 //System.out.println("cc = " + cc); 632 633 return new MultiVarPowerSeries<C>(ring, 634 new MultiVarCoefficients<C>(mc.pfac, new HashMap<Long, GenPolynomial<C>>(cc), z, hc) { 635 636 637 @Override 638 public C generate(ExpVector i) { 639 return coefficient(i); 640 } 641 }); 642 } 643 644 645 /** 646 * Select coefficients. 647 * @param sel selector functor. 648 * @return new power series with selected coefficients. 649 */ 650 public MultiVarPowerSeries<C> select(final Selector<? super C> sel) { 651 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 652 653 654 @Override 655 public C generate(ExpVector i) { 656 C c = coefficient(i); 657 if (sel.select(c)) { 658 return c; 659 } 660 return ring.coFac.getZERO(); 661 } 662 }); 663 } 664 665 666 /** 667 * Shift select coefficients. Not selected coefficients are removed from the 668 * result series. 669 * @param sel selector functor. 670 * @return new power series with shifted selected coefficients. 671 */ 672 public MultiVarPowerSeries<C> shiftSelect(final Selector<? super C> sel) { 673 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 674 675 676 ExpVectorIterable ib = new ExpVectorIterable(ring.nvar, true, truncate); 677 678 679 Iterator<ExpVector> pos = ib.iterator(); 680 681 682 @Override 683 public C generate(ExpVector i) { 684 C c; 685 if (i.signum() > 0) { 686 int[] deps = i.dependencyOnVariables(); 687 ExpVector x = i.subst(deps[0], i.getVal(deps[0]) - 1L); 688 c = get(x); // ensure all coefficients are generated 689 } 690 do { 691 c = null; 692 if (pos.hasNext()) { 693 ExpVector e = pos.next(); 694 c = coefficient(e); 695 } else { 696 break; 697 } 698 } while (!sel.select(c)); 699 if (c == null) { // not correct because not known 700 c = ring.coFac.getZERO(); 701 } 702 return c; 703 } 704 }); 705 } 706 707 708 /** 709 * Map a unary function to this power series. 710 * @param f evaluation functor. 711 * @return new power series with coefficients f(this(i)). 712 */ 713 public MultiVarPowerSeries<C> map(final UnaryFunctor<? super C, C> f) { 714 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 715 716 717 @Override 718 public C generate(ExpVector i) { 719 return f.eval(coefficient(i)); 720 } 721 }); 722 } 723 724 725 /** 726 * Map a binary function to this and another power series. 727 * @param f evaluation functor with coefficients f(this(i),other(i)). 728 * @param ps other power series. 729 * @return new power series. 730 */ 731 public MultiVarPowerSeries<C> zip(final BinaryFunctor<? super C, ? super C, C> f, 732 final MultiVarPowerSeries<C> ps) { 733 int m = Math.min(ring.truncate, Math.max(truncate, ps.truncate())); 734 735 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 736 737 738 @Override 739 public C generate(ExpVector i) { 740 return f.eval(coefficient(i), ps.coefficient(i)); 741 } 742 }, m); 743 } 744 745 746 /** 747 * Sum of two power series, using zip(). 748 * @param ps other power series. 749 * @return this + ps. 750 */ 751 public MultiVarPowerSeries<C> sumZip(MultiVarPowerSeries<C> ps) { 752 return zip(new BinaryFunctor<C, C, C>() { 753 754 755 @Override 756 public C eval(C c1, C c2) { 757 return c1.sum(c2); 758 } 759 }, ps); 760 } 761 762 763 /** 764 * Subtraction of two power series, using zip(). 765 * @param ps other power series. 766 * @return this - ps. 767 */ 768 public MultiVarPowerSeries<C> subtractZip(MultiVarPowerSeries<C> ps) { 769 return zip(new BinaryFunctor<C, C, C>() { 770 771 772 @Override 773 public C eval(C c1, C c2) { 774 return c1.subtract(c2); 775 } 776 }, ps); 777 } 778 779 780 /** 781 * Multiply by coefficient. 782 * @param a coefficient. 783 * @return this * a. 784 */ 785 public MultiVarPowerSeries<C> multiply(final C a) { 786 if (a.isZERO()) { 787 return ring.getZERO(); 788 } 789 if (a.isONE()) { 790 return this; 791 } 792 return map(new UnaryFunctor<C, C>() { 793 794 795 @Override 796 public C eval(C c) { 797 return c.multiply(a); 798 } 799 }); 800 } 801 802 803 /** 804 * Monic. 805 * @return 1/orderCoeff() * this. 806 */ 807 public MultiVarPowerSeries<C> monic() { 808 ExpVector e = orderExpVector(); 809 if (e == null) { 810 return this; 811 } 812 C a = coefficient(e); 813 if (a.isONE()) { 814 return this; 815 } 816 if (a.isZERO()) { // sic 817 return this; 818 } 819 final C b = a.inverse(); 820 return map(new UnaryFunctor<C, C>() { 821 822 823 @Override 824 public C eval(C c) { 825 return b.multiply(c); 826 } 827 }); 828 } 829 830 831 /** 832 * Negate. 833 * @return - this. 834 */ 835 public MultiVarPowerSeries<C> negate() { 836 return map(new UnaryFunctor<C, C>() { 837 838 839 @Override 840 public C eval(C c) { 841 return c.negate(); 842 } 843 }); 844 } 845 846 847 /** 848 * Absolute value. 849 * @return abs(this). 850 */ 851 public MultiVarPowerSeries<C> abs() { 852 if (signum() < 0) { 853 return negate(); 854 } 855 return this; 856 } 857 858 859 /** 860 * Evaluate at given point. 861 * @return ps(a). 862 */ 863 public C evaluate(List<C> a) { 864 C v = ring.coFac.getZERO(); 865 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { 866 C c = coefficient(i); 867 if (c.isZERO()) { 868 continue; 869 } 870 c = c.multiply(i.evaluate(ring.coFac, a)); 871 v = v.sum(c); 872 } 873 return v; 874 } 875 876 877 /** 878 * Order. 879 * @return index of first non zero coefficient. 880 */ 881 public int order() { 882 if (order >= 0) { 883 return order; 884 } 885 // must compute it 886 GenPolynomial<C> p = null; 887 int t = 0; 888 while (lazyCoeffs.homCheck.get(t)) { 889 p = lazyCoeffs.coeffCache.get((long) t); 890 if (p == null || p.isZERO()) { // ?? 891 t++; 892 continue; 893 } 894 order = t; 895 evorder = p.trailingExpVector(); 896 //System.out.println("order = " + t); 897 return order; 898 } 899 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { 900 if (!coefficient(i).isZERO()) { 901 order = (int) i.totalDeg(); //ord; 902 evorder = i; 903 //System.out.println("order = " + order + ", evorder = " + evorder); 904 return order; 905 } 906 } 907 order = truncate + 1; 908 // evorder is null 909 return order; 910 } 911 912 913 /** 914 * Order ExpVector. 915 * @return ExpVector of first non zero coefficient. 916 */ 917 public ExpVector orderExpVector() { 918 //int x = 919 order(); // ensure evorder is set 920 return evorder; 921 } 922 923 924 /** 925 * Order monomial. 926 * @return first map entry or null. 927 */ 928 public Map.Entry<ExpVector, C> orderMonomial() { 929 ExpVector e = orderExpVector(); 930 if (e == null) { 931 return null; 932 } 933 //JAVA6only: 934 //return new AbstractMap.SimpleImmutableEntry<ExpVector, C>(e, coefficient(e)); 935 return new MapEntry<ExpVector, C>(e, coefficient(e)); 936 } 937 938 939 /** 940 * Truncate. 941 * @return truncate index of power series. 942 */ 943 public int truncate() { 944 return truncate; 945 } 946 947 948 /** 949 * Set truncate. 950 * @param t new truncate index. 951 * @return old truncate index of power series. 952 */ 953 public int setTruncate(int t) { 954 if (t < 0) { 955 throw new IllegalArgumentException("negative truncate not allowed"); 956 } 957 int ot = truncate; 958 if (order >= 0) { 959 if (order > truncate) { 960 order = -1; // reset 961 evorder = null; 962 } 963 } 964 truncate = t; 965 return ot; 966 } 967 968 969 /** 970 * Ecart. 971 * @return ecart. 972 */ 973 public long ecart() { 974 ExpVector e = orderExpVector(); 975 if (e == null) { 976 return 0L; 977 } 978 long d = e.totalDeg(); 979 long hd = d; 980 for (long i = d + 1L; i <= truncate; i++) { 981 if (!homogeneousPart(i).isZERO()) { 982 hd = i; 983 } 984 } 985 //System.out.println("d = " + d + ", hd = " + hd + ", coeffCache = " + lazyCoeffs.coeffCache + ", this = " + this); 986 return hd - d; 987 } 988 989 990 /** 991 * Signum. 992 * @return sign of first non zero coefficient. 993 */ 994 public int signum() { 995 ExpVector ev = orderExpVector(); 996 if (ev != null) { 997 return coefficient(ev).signum(); 998 } 999 return 0; 1000 } 1001 1002 1003 /** 1004 * Compare to. <b>Note: </b> compare only up to max(truncates). 1005 * @return sign of first non zero coefficient of this-ps. 1006 */ 1007 @Override 1008 public int compareTo(MultiVarPowerSeries<C> ps) { 1009 final int m = truncate(); 1010 final int n = ps.truncate(); 1011 final int pos = Math.min(ring.truncate, Math.min(m, n)); 1012 int s = 0; 1013 //System.out.println("coeffCache_c1 = " + lazyCoeffs.coeffCache); 1014 //System.out.println("coeffCache_c2 = " + ps.lazyCoeffs.coeffCache); 1015 // test homogeneous parts first is slower 1016 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, pos)) { 1017 s = coefficient(i).compareTo(ps.coefficient(i)); 1018 if (s != 0) { 1019 //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); 1020 return s; 1021 } 1022 } 1023 for (int j = pos + 1; j <= Math.min(ring.truncate, Math.max(m, n)); j++) { 1024 for (ExpVector i : new ExpVectorIterable(ring.nvar, j)) { 1025 s = coefficient(i).compareTo(ps.coefficient(i)); 1026 //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); 1027 if (s != 0) { 1028 //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); 1029 return s; 1030 } 1031 } 1032 } 1033 return s; 1034 } 1035 1036 1037 /** 1038 * Is power series zero. <b>Note: </b> compare only up to truncate. 1039 * @return If this is 0 then true is returned, else false. 1040 * @see edu.jas.structure.RingElem#isZERO() 1041 */ 1042 public boolean isZERO() { 1043 return (signum() == 0); 1044 } 1045 1046 1047 /** 1048 * Is power series one. <b>Note: </b> compare only up to truncate. 1049 * @return If this is 1 then true is returned, else false. 1050 * @see edu.jas.structure.RingElem#isONE() 1051 */ 1052 public boolean isONE() { 1053 if (!leadingCoefficient().isONE()) { 1054 return false; 1055 } 1056 return (compareTo(ring.ONE) == 0); 1057 //return reductum().isZERO(); 1058 } 1059 1060 1061 /** 1062 * Comparison with any other object. <b>Note: </b> compare only up to 1063 * truncate. 1064 * @see java.lang.Object#equals(java.lang.Object) 1065 */ 1066 @Override 1067 @SuppressWarnings("unchecked") 1068 public boolean equals(Object B) { 1069 if (B == null) { 1070 return false; 1071 } 1072 if (!(B instanceof MultiVarPowerSeries)) { 1073 return false; 1074 } 1075 MultiVarPowerSeries<C> a = (MultiVarPowerSeries<C>) B; 1076 return compareTo(a) == 0; 1077 } 1078 1079 1080 /** 1081 * Hash code for this polynomial. <b>Note: </b> only up to truncate. 1082 * @see java.lang.Object#hashCode() 1083 */ 1084 @Override 1085 public int hashCode() { 1086 int h = 0; 1087 //h = ( ring.hashCode() << 23 ); 1088 //h += val.hashCode(); 1089 for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { 1090 C c = coefficient(i); 1091 if (!c.isZERO()) { 1092 h += i.hashCode(); 1093 h = (h << 23); 1094 } 1095 h += c.hashCode(); 1096 h = (h << 23); 1097 } 1098 return h; 1099 } 1100 1101 1102 /** 1103 * Is unit. 1104 * @return true, if this power series is invertible, else false. 1105 */ 1106 public boolean isUnit() { 1107 return leadingCoefficient().isUnit(); 1108 } 1109 1110 1111 /** 1112 * Sum a another power series. 1113 * @param ps other power series. 1114 * @return this + ps. 1115 */ 1116 public MultiVarPowerSeries<C> sum(final MultiVarPowerSeries<C> ps) { 1117 //final MultiVarPowerSeries<C> ps1 = this; // method name was ambiguous in generate 1118 int nt = Math.min(ring.truncate, Math.max(truncate(), ps.truncate())); 1119 1120 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1121 1122 1123 @Override 1124 public C generate(ExpVector e) { 1125 long tdeg = e.totalDeg(); 1126 if (lazyCoeffs.homCheck.get((int) tdeg)) { 1127 // generate respective homogeneous polynomial 1128 GenPolynomial<C> p = homogeneousPart(tdeg).sum(ps.homogeneousPart(tdeg)); 1129 coeffCache.put(tdeg, p); // overwrite 1130 homCheck.set((int) tdeg); 1131 C c = p.coefficient(e); 1132 //System.out.println("c = " + c + ", e = " + e + ", tdeg = " + tdeg); 1133 return c; 1134 } 1135 return coefficient(e).sum(ps.coefficient(e)); 1136 } 1137 }, nt); 1138 } 1139 1140 1141 /** 1142 * Subtract a another power series. 1143 * @param ps other power series. 1144 * @return this - ps. 1145 */ 1146 public MultiVarPowerSeries<C> subtract(final MultiVarPowerSeries<C> ps) { 1147 //final MultiVarPowerSeries<C> ps1 = this; // method name was ambiguous in generate 1148 int nt = Math.min(ring.truncate, Math.max(truncate(), ps.truncate())); 1149 1150 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1151 1152 1153 @Override 1154 public C generate(ExpVector e) { 1155 long tdeg = e.totalDeg(); 1156 if (lazyCoeffs.homCheck.get((int) tdeg)) { 1157 // generate respective homogeneous polynomial 1158 GenPolynomial<C> p = homogeneousPart(tdeg).subtract(ps.homogeneousPart(tdeg)); 1159 coeffCache.put(tdeg, p); // overwrite 1160 homCheck.set((int) tdeg); 1161 C c = p.coefficient(e); 1162 //System.out.println("p = " + p + ", e = " + e + ", tdeg = " + tdeg); 1163 return c; 1164 } 1165 return coefficient(e).subtract(ps.coefficient(e)); 1166 } 1167 }, nt); 1168 } 1169 1170 1171 /** 1172 * Multiply by another power series. 1173 * @param ps other power series. 1174 * @return this * ps. 1175 */ 1176 public MultiVarPowerSeries<C> multiply(final MultiVarPowerSeries<C> ps) { 1177 //final MultiVarPowerSeries<C> ps1 = this; // method name was ambiguous in generate 1178 int nt = Math.min(ring.truncate, truncate() + ps.truncate()); 1179 1180 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1181 1182 1183 @Override 1184 public C generate(ExpVector e) { 1185 long tdeg = e.totalDeg(); 1186 // generate respective homogeneous polynomial 1187 GenPolynomial<C> p = null; //fac.getZERO(); 1188 for (int k = 0; k <= tdeg; k++) { 1189 GenPolynomial<C> m = homogeneousPart(k).multiply(ps.homogeneousPart(tdeg - k)); 1190 if (p == null) { 1191 p = m; 1192 } else { 1193 p = p.sum(m); 1194 } 1195 } 1196 coeffCache.put(tdeg, p); // overwrite 1197 homCheck.set((int) tdeg); 1198 C c = p.coefficient(e); 1199 return c; 1200 } 1201 }, nt); 1202 } 1203 1204 1205 /** 1206 * Inverse power series. 1207 * @return ps with this * ps = 1. 1208 */ 1209 public MultiVarPowerSeries<C> inverse() { 1210 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1211 1212 1213 @Override 1214 public C generate(ExpVector e) { 1215 long tdeg = e.totalDeg(); 1216 C d = leadingCoefficient().inverse(); // may fail 1217 if (tdeg == 0) { 1218 return d; 1219 } 1220 GenPolynomial<C> p = null; //fac.getZERO(); 1221 for (int k = 0; k < tdeg; k++) { 1222 GenPolynomial<C> m = getHomPart(k).multiply(homogeneousPart(tdeg - k)); 1223 if (p == null) { 1224 p = m; 1225 } else { 1226 p = p.sum(m); 1227 } 1228 } 1229 p = p.multiply(d.negate()); 1230 //System.out.println("tdeg = " + tdeg + ", p = " + p); 1231 coeffCache.put(tdeg, p); // overwrite 1232 homCheck.set((int) tdeg); 1233 C c = p.coefficient(e); 1234 return c; 1235 } 1236 }); 1237 } 1238 1239 1240 /** 1241 * Divide by another power series. 1242 * @param ps nonzero power series with invertible coefficient. 1243 * @return this / ps. 1244 */ 1245 public MultiVarPowerSeries<C> divide(MultiVarPowerSeries<C> ps) { 1246 if (ps.isUnit()) { 1247 return multiply(ps.inverse()); 1248 } 1249 int m = order(); 1250 int n = ps.order(); 1251 if (m < n) { 1252 return ring.getZERO(); 1253 } 1254 ExpVector em = orderExpVector(); 1255 ExpVector en = ps.orderExpVector(); 1256 if (!ps.coefficient(en).isUnit()) { 1257 throw new ArithmeticException("division by non unit coefficient " + ps.coefficient(ps.evorder) 1258 + ", evorder = " + ps.evorder); 1259 } 1260 // now m >= n 1261 MultiVarPowerSeries<C> st, sps, q, sq; 1262 if (m == 0) { 1263 st = this; 1264 } else { 1265 st = this.shift(em.negate()); 1266 } 1267 if (n == 0) { 1268 sps = ps; 1269 } else { 1270 sps = ps.shift(en.negate()); 1271 } 1272 q = st.multiply(sps.inverse()); 1273 sq = q.shift(em.subtract(en)); 1274 return sq; 1275 } 1276 1277 1278 /** 1279 * Power series remainder. 1280 * @param ps nonzero power series with invertible leading coefficient. 1281 * @return remainder with this = quotient * ps + remainder. 1282 */ 1283 public MultiVarPowerSeries<C> remainder(MultiVarPowerSeries<C> ps) { 1284 int m = order(); 1285 int n = ps.order(); 1286 if (m >= n) { 1287 return ring.getZERO(); 1288 } 1289 return this; 1290 } 1291 1292 1293 /** 1294 * Quotient and remainder by division of this by S. 1295 * @param S a MultiVarPowerSeries 1296 * @return [this/S, this - (this/S)*S]. 1297 */ 1298 @SuppressWarnings("unchecked") 1299 public MultiVarPowerSeries<C>[] quotientRemainder(MultiVarPowerSeries<C> S) { 1300 return new MultiVarPowerSeries[] { divide(S), remainder(S) }; 1301 } 1302 1303 1304 /** 1305 * Differentiate with respect to variable r. 1306 * @param r variable for the direction. 1307 * @return differentiate(this). 1308 */ 1309 public MultiVarPowerSeries<C> differentiate(final int r) { 1310 if (r < 0 || ring.nvar < r) { 1311 throw new IllegalArgumentException("variable index out of bound"); 1312 } 1313 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1314 1315 1316 @Override 1317 public C generate(ExpVector i) { 1318 long d = i.getVal(r); 1319 ExpVector e = i.subst(r, d + 1); 1320 C v = coefficient(e); 1321 v = v.multiply(ring.coFac.fromInteger(d + 1)); 1322 return v; 1323 } 1324 }); 1325 } 1326 1327 1328 /** 1329 * Integrate with respect to variable r and with given constant. 1330 * @param c integration constant. 1331 * @param r variable for the direction. 1332 * @return integrate(this). 1333 */ 1334 public MultiVarPowerSeries<C> integrate(final C c, final int r) { 1335 if (r < 0 || ring.nvar < r) { 1336 throw new IllegalArgumentException("variable index out of bound"); 1337 } 1338 int nt = Math.min(ring.truncate, truncate + 1); 1339 return new MultiVarPowerSeries<C>(ring, new MultiVarCoefficients<C>(ring) { 1340 1341 1342 @Override 1343 public C generate(ExpVector i) { 1344 if (i.isZERO()) { 1345 return c; 1346 } 1347 long d = i.getVal(r); 1348 if (d > 0) { 1349 ExpVector e = i.subst(r, d - 1); 1350 C v = coefficient(e); 1351 v = v.divide(ring.coFac.fromInteger(d)); 1352 return v; 1353 } 1354 return ring.coFac.getZERO(); 1355 } 1356 }, nt); 1357 } 1358 1359 1360 /** 1361 * Power series greatest common divisor. 1362 * @param ps power series. 1363 * @return gcd(this,ps). 1364 */ 1365 public MultiVarPowerSeries<C> gcd(MultiVarPowerSeries<C> ps) { 1366 if (ps.isZERO()) { 1367 return this; 1368 } 1369 if (this.isZERO()) { 1370 return ps; 1371 } 1372 ExpVector em = orderExpVector(); 1373 ExpVector en = ps.orderExpVector(); 1374 return ring.getONE().shift(em.gcd(en)); 1375 } 1376 1377 1378 /** 1379 * Power series extended greatest common divisor. <b>Note:</b> not 1380 * implemented. 1381 * @param S power series. 1382 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 1383 */ 1384 //SuppressWarnings("unchecked") 1385 public MultiVarPowerSeries<C>[] egcd(MultiVarPowerSeries<C> S) { 1386 throw new UnsupportedOperationException("egcd for power series not implemented"); 1387 } 1388 1389}