001 /* 002 * $Id: ElementaryIntegration.java 3356 2010-10-23 16:41:01Z kredel $ 003 */ 004 005 package edu.jas.integrate; 006 007 008 import java.util.ArrayList; 009 import java.util.List; 010 import java.util.SortedMap; 011 012 import org.apache.log4j.Logger; 013 014 import edu.jas.poly.AlgebraicNumber; 015 import edu.jas.poly.AlgebraicNumberRing; 016 import edu.jas.poly.GenPolynomial; 017 import edu.jas.poly.GenPolynomialRing; 018 import edu.jas.poly.PolyUtil; 019 import edu.jas.structure.GcdRingElem; 020 import edu.jas.structure.Power; 021 import edu.jas.structure.RingFactory; 022 import edu.jas.ufd.FactorAbstract; 023 import edu.jas.ufd.FactorFactory; 024 import edu.jas.ufd.GCDFactory; 025 import edu.jas.ufd.GreatestCommonDivisorAbstract; 026 import edu.jas.ufd.GreatestCommonDivisorSubres; 027 import edu.jas.ufd.PolyUfdUtil; 028 import edu.jas.ufd.Quotient; 029 import edu.jas.ufd.QuotientRing; 030 import edu.jas.ufd.SquarefreeAbstract; 031 import edu.jas.ufd.SquarefreeFactory; 032 033 034 /** 035 * Methods related to elementary integration. In particular there are methods 036 * for Hermite reduction and Rothstein-Trager integration of the logarithmic 037 * part. 038 * 039 * @author Axel Kramer 040 * @author Heinz Kredel 041 * @param <C> coefficient type 042 */ 043 044 public class ElementaryIntegration<C extends GcdRingElem<C>> { 045 046 047 private static final Logger logger = Logger.getLogger(ElementaryIntegration.class); 048 049 050 private final boolean debug = logger.isDebugEnabled(); 051 052 053 /** 054 * Engine for factorization. 055 */ 056 public final FactorAbstract<C> irr; 057 058 059 /** 060 * Engine for squarefree decomposition. 061 */ 062 public final SquarefreeAbstract<C> sqf; 063 064 065 /** 066 * Engine for greatest common divisors. 067 */ 068 public final GreatestCommonDivisorAbstract<C> ufd; 069 070 071 /** 072 * Constructor. 073 */ 074 public ElementaryIntegration(RingFactory<C> br) { 075 ufd = GCDFactory.<C> getProxy(br); 076 sqf = SquarefreeFactory.<C> getImplementation(br); 077 irr = /*(FactorAbsolute<C>)*/FactorFactory.<C> getImplementation(br); 078 } 079 080 081 /** 082 * Integration of a rational function. 083 * 084 * @param r rational function 085 * @return Integral container, such that integrate(r) = sum_i(g_i) + sum_j( 086 * an_j log(hd_j) ) 087 */ 088 public QuotIntegral<C> integrate(Quotient<C> r) { 089 Integral<C> integral = integrate(r.num, r.den); 090 return new QuotIntegral<C>(r.ring, integral); 091 } 092 093 094 /** 095 * Integration of a rational function. 096 * 097 * @param a numerator 098 * @param d denominator 099 * @return Integral container, such that integrate(a/d) = sum_i(gn_i/gd_i) + 100 * integrate(h0) + sum_j( an_j log(hd_j) ) 101 */ 102 public Integral<C> integrate(GenPolynomial<C> a, GenPolynomial<C> d) { 103 if (d == null || a == null || d.isZERO()) { 104 throw new IllegalArgumentException("zero or null not allowed"); 105 } 106 if (a.isZERO()) { 107 return new Integral<C>(a, d, a); 108 } 109 if (d.isONE()) { 110 GenPolynomial<C> pi = PolyUtil.<C> baseIntegral(a); 111 return new Integral<C>(a, d, pi); 112 } 113 GenPolynomialRing<C> pfac = d.ring; 114 if (pfac.nvar > 1) { 115 throw new IllegalArgumentException("only for univariate polynomials " + pfac); 116 } 117 if (!pfac.coFac.isField()) { 118 throw new IllegalArgumentException("only for field coefficients " + pfac); 119 } 120 121 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(a, d); 122 GenPolynomial<C> p = qr[0]; 123 GenPolynomial<C> r = qr[1]; 124 125 GenPolynomial<C> c = ufd.gcd(r, d); 126 if (!c.isONE()) { 127 r = PolyUtil.<C> basePseudoQuotientRemainder(r, c)[0]; 128 d = PolyUtil.<C> basePseudoQuotientRemainder(d, c)[0]; 129 } 130 List<GenPolynomial<C>>[] ih = integrateHermite(r, d); 131 List<GenPolynomial<C>> rat = ih[0]; 132 List<GenPolynomial<C>> log = ih[1]; 133 134 GenPolynomial<C> pp = log.remove(0); 135 p = p.sum(pp); 136 GenPolynomial<C> pi = PolyUtil.<C> baseIntegral(p); 137 138 if (debug) { 139 logger.debug("pi = " + pi); 140 logger.debug("rat = " + rat); 141 logger.debug("log = " + log); 142 } 143 if (log.size() == 0) { 144 return new Integral<C>(a, d, pi, rat); 145 } 146 147 List<LogIntegral<C>> logi = new ArrayList<LogIntegral<C>>(log.size() / 2); 148 for (int i = 0; i < log.size(); i++) { 149 GenPolynomial<C> ln = log.get(i++); 150 GenPolynomial<C> ld = log.get(i); 151 LogIntegral<C> pf = integrateLogPart(ln, ld); 152 logi.add(pf); 153 } 154 if (debug) { 155 logger.debug("logi = " + logi); 156 } 157 return new Integral<C>(a, d, pi, rat, logi); 158 } 159 160 161 /** 162 * Integration of the rational part, Hermite reduction step. 163 * 164 * @param a numerator 165 * @param d denominator, gcd(a,d) == 1 166 * @return [ [ gn_i, gd_i ], [ h0, hn_j, hd_j ] ] such that integrate(a/d) = 167 * sum_i(gn_i/gd_i) + integrate(h0) + sum_j( integrate(hn_j/hd_j) ) 168 */ 169 public List<GenPolynomial<C>>[] integrateHermite(GenPolynomial<C> a, GenPolynomial<C> d) { 170 if (d == null || d.isZERO()) { 171 throw new IllegalArgumentException("d == null or d == 0"); 172 } 173 if (a == null || a.isZERO()) { 174 throw new IllegalArgumentException("a == null or a == 0"); 175 } 176 177 // get squarefree decomposition 178 SortedMap<GenPolynomial<C>, Long> sfactors = sqf.squarefreeFactors(d); 179 180 List<GenPolynomial<C>> D = new ArrayList<GenPolynomial<C>>(sfactors.keySet()); 181 List<GenPolynomial<C>> DP = new ArrayList<GenPolynomial<C>>(); 182 for (GenPolynomial<C> f : D) { 183 long e = sfactors.get(f); 184 GenPolynomial<C> dp = Power.<GenPolynomial<C>> positivePower(f, e); 185 DP.add(dp); 186 } 187 //System.out.println("D: " + D); 188 //System.out.println("DP: " + DP); 189 190 // get partial fraction decompostion 191 List<GenPolynomial<C>> Ai = ufd.basePartialFraction(a, DP); 192 //System.out.println("Ai: " + Ai); 193 194 List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(); 195 List<GenPolynomial<C>> H = new ArrayList<GenPolynomial<C>>(); 196 H.add(Ai.remove(0)); // P 197 198 GenPolynomialRing<C> fac = d.ring; 199 int i = 0; 200 for (GenPolynomial<C> v : D) { 201 //System.out.println("V:" + v.toString()); 202 GenPolynomial<C> Ak = Ai.get(i++); 203 //System.out.println("Ak: " + Ak.toString()); 204 int k = sfactors.get(v).intValue(); // assert low power 205 for (int j = k - 1; j >= 1; j--) { 206 //System.out.println("Step(" + k + "," + j + ")"); 207 GenPolynomial<C> DV_dx = PolyUtil.<C> baseDeriviative(v); 208 GenPolynomial<C> Aik = Ak.divide(fac.fromInteger(-j)); 209 GenPolynomial<C>[] BC = ufd.baseGcdDiophant(DV_dx, v, Aik); 210 GenPolynomial<C> b = BC[0]; 211 GenPolynomial<C> c = BC[1]; 212 GenPolynomial<C> vj = Power.<GenPolynomial<C>> positivePower(v, j); 213 G.add(b); // B 214 G.add(vj); // v^j 215 Ak = fac.fromInteger(-j).multiply(c).subtract(PolyUtil.<C> baseDeriviative(b)); 216 //System.out.println("B: " + b.toString()); 217 //System.out.println("C: " + c.toString()); 218 } 219 //System.out.println("V:" + v.toString()); 220 //System.out.println("Ak: " + Ak.toString()); 221 if (!Ak.isZERO()) { 222 H.add(Ak); // A_k 223 H.add(v); // v 224 } 225 } 226 List<GenPolynomial<C>>[] ret = (List<GenPolynomial<C>>[]) new List[2]; 227 ret[0] = G; 228 ret[1] = H; 229 return ret; 230 } 231 232 233 /** 234 * Univariate GenPolynomial integration of the logaritmic part, 235 * Rothstein-Trager algorithm. 236 * @param A univariate GenPolynomial, deg(A) < deg(P). 237 * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1. 238 * @return logarithmic part container. 239 */ 240 public LogIntegral<C> integrateLogPart(GenPolynomial<C> A, GenPolynomial<C> P) { 241 if (P == null || P.isZERO()) { 242 throw new IllegalArgumentException(" P == null or P == 0"); 243 } 244 if (A == null || A.isZERO()) { 245 throw new IllegalArgumentException(" A == null or A == 0"); 246 } 247 //System.out.println("\nP_base_algeb_part = " + P); 248 GenPolynomialRing<C> pfac = P.ring; // K[x] 249 if (pfac.nvar > 1) { 250 throw new IllegalArgumentException("only for univariate polynomials " + pfac); 251 } 252 if (!pfac.coFac.isField()) { 253 throw new IllegalArgumentException("only for field coefficients " + pfac); 254 } 255 List<C> cfactors = new ArrayList<C>(); 256 List<GenPolynomial<C>> cdenom = new ArrayList<GenPolynomial<C>>(); 257 List<AlgebraicNumber<C>> afactors = new ArrayList<AlgebraicNumber<C>>(); 258 List<GenPolynomial<AlgebraicNumber<C>>> adenom = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>(); 259 260 // P linear 261 if (P.degree(0) <= 1) { 262 cfactors.add(A.leadingBaseCoefficient()); 263 cdenom.add(P); 264 return new LogIntegral<C>(A, P, cfactors, cdenom, afactors, adenom); 265 } 266 List<GenPolynomial<C>> Pfac = irr.baseFactorsSquarefree(P); 267 //System.out.println("\nPfac = " + Pfac); 268 269 List<GenPolynomial<C>> Afac = ufd.basePartialFraction(A, Pfac); 270 271 GenPolynomial<C> A0 = Afac.remove(0); 272 if (!A0.isZERO()) { 273 throw new RuntimeException(" A0 != 0: deg(A)>= deg(P)"); 274 } 275 276 // algebraic and linear factors 277 int i = 0; 278 for (GenPolynomial<C> pi : Pfac) { 279 GenPolynomial<C> ai = Afac.get(i++); 280 if (pi.degree(0) <= 1) { 281 cfactors.add(ai.leadingBaseCoefficient()); 282 cdenom.add(pi); 283 continue; 284 } 285 LogIntegral<C> pf = integrateLogPartIrreducible(ai, pi); 286 cfactors.addAll(pf.cfactors); 287 cdenom.addAll(pf.cdenom); 288 afactors.addAll(pf.afactors); 289 adenom.addAll(pf.adenom); 290 } 291 return new LogIntegral<C>(A, P, cfactors, cdenom, afactors, adenom); 292 } 293 294 295 /** 296 * Univariate GenPolynomial integration of the logaritmic part, 297 * Rothstein-Trager algorithm. 298 * @param A univariate GenPolynomial, deg(A) < deg(P). 299 * @param P univariate irreducible GenPolynomial. // gcd(A,P) == 1 automatic 300 * @return logarithmic part container. 301 */ 302 public LogIntegral<C> integrateLogPartIrreducible(GenPolynomial<C> A, GenPolynomial<C> P) { 303 if (P == null || P.isZERO()) { 304 throw new IllegalArgumentException("P == null or P == 0"); 305 } 306 //System.out.println("\nP_base_algeb_part = " + P); 307 GenPolynomialRing<C> pfac = P.ring; // K[x] 308 if (pfac.nvar > 1) { 309 throw new IllegalArgumentException("only for univariate polynomials " + pfac); 310 } 311 if (!pfac.coFac.isField()) { 312 throw new IllegalArgumentException("only for field coefficients " + pfac); 313 } 314 List<C> cfactors = new ArrayList<C>(); 315 List<GenPolynomial<C>> cdenom = new ArrayList<GenPolynomial<C>>(); 316 List<AlgebraicNumber<C>> afactors = new ArrayList<AlgebraicNumber<C>>(); 317 List<GenPolynomial<AlgebraicNumber<C>>> adenom = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>(); 318 319 // P linear 320 if (P.degree(0) <= 1) { 321 cfactors.add(A.leadingBaseCoefficient()); 322 cdenom.add(P); 323 return new LogIntegral<C>(A, P, cfactors, cdenom, afactors, adenom); 324 } 325 326 // deriviative 327 GenPolynomial<C> Pp = PolyUtil.<C> baseDeriviative(P); 328 //no: Pp = Pp.monic(); 329 //System.out.println("\nP = " + P); 330 //System.out.println("Pp = " + Pp); 331 332 // Q[t] 333 String[] vars = new String[] { "t" }; 334 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(pfac.coFac, 1, pfac.tord, vars); 335 GenPolynomial<C> t = cfac.univariate(0); 336 //System.out.println("t = " + t); 337 338 // Q[x][t] 339 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(pfac, cfac); // sic 340 //System.out.println("rfac = " + rfac.toScript()); 341 342 // transform polynomials to bi-variate polynomial 343 GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, A); 344 //System.out.println("Ac = " + Ac); 345 GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> introduceLowerVariable(rfac, P); 346 //System.out.println("Pc = " + Pc); 347 GenPolynomial<GenPolynomial<C>> Pcp = PolyUfdUtil.<C> introduceLowerVariable(rfac, Pp); 348 //System.out.println("Pcp = " + Pcp); 349 350 // Q[t][x] 351 GenPolynomialRing<GenPolynomial<C>> rfac1 = Pc.ring; 352 //System.out.println("rfac1 = " + rfac1.toScript()); 353 354 // A - t P' 355 GenPolynomial<GenPolynomial<C>> tc = rfac1.getONE().multiply(t); 356 //System.out.println("tc = " + tc); 357 GenPolynomial<GenPolynomial<C>> At = Ac.subtract(tc.multiply(Pcp)); 358 //System.out.println("At = " + At); 359 360 GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>(); 361 // = GCDFactory.<C>getImplementation( cfac.coFac ); 362 GreatestCommonDivisorAbstract<AlgebraicNumber<C>> aengine = null; 363 364 GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveResultant(Pc, At); 365 //System.out.println("Rc = " + Rc); 366 GenPolynomial<C> res = Rc.leadingBaseCoefficient(); 367 //no: res = res.monic(); 368 //System.out.println("\nres = " + res); 369 370 SortedMap<GenPolynomial<C>, Long> resfac = irr.baseFactors(res); 371 //System.out.println("resfac = " + resfac + "\n"); 372 373 for (GenPolynomial<C> r : resfac.keySet()) { 374 //System.out.println("\nr(t) = " + r); 375 if (r.isConstant()) { 376 continue; 377 } 378 //vars = new String[] { "z_" + Math.abs(r.hashCode() % 1000) }; 379 vars = pfac.newVars("z_"); 380 pfac = pfac.clone(); 381 vars = pfac.setVars(vars); 382 r = pfac.copy(r); // hack to exchange the variables 383 //System.out.println("r(z_) = " + r); 384 AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(r, true); // since irreducible 385 logger.debug("afac = " + afac.toScript()); 386 AlgebraicNumber<C> a = afac.getGenerator(); 387 //no: a = a.negate(); 388 //System.out.println("a = " + a); 389 390 // K(alpha)[x] 391 GenPolynomialRing<AlgebraicNumber<C>> pafac = new GenPolynomialRing<AlgebraicNumber<C>>(afac, 392 Pc.ring); 393 //System.out.println("pafac = " + pafac.toScript()); 394 395 // convert to K(alpha)[x] 396 GenPolynomial<AlgebraicNumber<C>> Pa = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, P); 397 //System.out.println("Pa = " + Pa); 398 GenPolynomial<AlgebraicNumber<C>> Pap = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, Pp); 399 //System.out.println("Pap = " + Pap); 400 GenPolynomial<AlgebraicNumber<C>> Aa = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, A); 401 //System.out.println("Aa = " + Aa); 402 403 // A - a P' 404 GenPolynomial<AlgebraicNumber<C>> Ap = Aa.subtract(Pap.multiply(a)); 405 //System.out.println("Ap = " + Ap); 406 407 if (aengine == null) { 408 aengine = GCDFactory.<AlgebraicNumber<C>> getImplementation(afac); 409 } 410 GenPolynomial<AlgebraicNumber<C>> Ga = aengine.baseGcd(Pa, Ap); 411 //System.out.println("Ga = " + Ga); 412 if (Ga.isConstant()) { 413 //System.out.println("warning constant gcd ignored"); 414 continue; 415 } 416 afactors.add(a); 417 adenom.add(Ga); 418 // special quadratic case 419 if (P.degree(0) == 2 && Ga.degree(0) == 1) { 420 GenPolynomial<AlgebraicNumber<C>>[] qra = PolyUtil 421 .<AlgebraicNumber<C>> basePseudoQuotientRemainder(Pa, Ga); 422 GenPolynomial<AlgebraicNumber<C>> Qa = qra[0]; 423 if (!qra[1].isZERO()) { 424 throw new ArithmeticException("remainder not zero"); 425 } 426 //System.out.println("Qa = " + Qa); 427 afactors.add(a.negate()); 428 adenom.add(Qa); 429 } 430 // todo: eventually implement special cases deg = 3, 4 431 } 432 return new LogIntegral<C>(A, P, cfactors, cdenom, afactors, adenom); 433 } 434 435 436 /** 437 * Derivation of a univariate rational function. 438 * 439 * @param r rational function 440 * @return dr/dx 441 */ 442 public Quotient<C> deriviative(Quotient<C> r) { 443 GenPolynomial<C> num = r.num; 444 GenPolynomial<C> den = r.den; 445 GenPolynomial<C> nump = PolyUtil.<C> baseDeriviative(num); 446 if (den.isONE()) { 447 return new Quotient<C>(r.ring, nump, den); 448 } 449 GenPolynomial<C> denp = PolyUtil.<C> baseDeriviative(den); 450 451 GenPolynomial<C> n = den.multiply(nump).subtract(num.multiply(denp)); 452 GenPolynomial<C> d = den.multiply(den); 453 454 Quotient<C> der = new Quotient<C>(r.ring, n, d); 455 return der; 456 } 457 458 459 /** 460 * Test of integration of a rational function. 461 * 462 * @param ri integral 463 * @return true, if ri is an integral, else false. 464 */ 465 public boolean isIntegral(QuotIntegral<C> ri) { 466 Quotient<C> r = ri.quot; 467 QuotientRing<C> qr = r.ring; 468 Quotient<C> i = r.ring.getZERO(); 469 for (Quotient<C> q : ri.rational) { 470 Quotient<C> qd = deriviative(q); 471 i = i.sum(qd); 472 } 473 if (ri.logarithm.size() == 0) { 474 return r.equals(i); 475 } 476 for (LogIntegral<C> li : ri.logarithm) { 477 Quotient<C> q = new Quotient<C>(qr, li.num, li.den); 478 i = i.sum(q); 479 } 480 boolean t = r.equals(i); 481 if (!t) { 482 return false; 483 } 484 for (LogIntegral<C> li : ri.logarithm) { 485 t = isIntegral(li); 486 if (!t) { 487 return false; 488 } 489 } 490 return true; 491 } 492 493 494 /** 495 * Test of integration of the logarithmic part of a rational function. 496 * 497 * @param rl logarithmic part of an integral 498 * @return true, if rl is an integral, else false. 499 */ 500 public boolean isIntegral(LogIntegral<C> rl) { 501 QuotientRing<C> qr = new QuotientRing<C>(rl.den.ring); 502 Quotient<C> r = new Quotient<C>(qr, rl.num, rl.den); 503 504 Quotient<C> i = qr.getZERO(); 505 int j = 0; 506 for (GenPolynomial<C> d : rl.cdenom) { 507 GenPolynomial<C> dp = PolyUtil.<C> baseDeriviative(d); 508 dp = dp.multiply(rl.cfactors.get(j++)); 509 Quotient<C> f = new Quotient<C>(qr, dp, d); 510 i = i.sum(f); 511 } 512 if (rl.afactors.size() == 0) { 513 return r.equals(i); 514 } 515 r = r.subtract(i); 516 QuotientRing<AlgebraicNumber<C>> aqr = new QuotientRing<AlgebraicNumber<C>>(rl.adenom.get(0).ring); 517 Quotient<AlgebraicNumber<C>> ai = aqr.getZERO(); 518 519 GenPolynomial<AlgebraicNumber<C>> aqn = PolyUtil.<C> convertToAlgebraicCoefficients(aqr.ring, r.num); 520 GenPolynomial<AlgebraicNumber<C>> aqd = PolyUtil.<C> convertToAlgebraicCoefficients(aqr.ring, r.den); 521 Quotient<AlgebraicNumber<C>> ar = new Quotient<AlgebraicNumber<C>>(aqr, aqn, aqd); 522 523 j = 0; 524 for (GenPolynomial<AlgebraicNumber<C>> d : rl.adenom) { 525 GenPolynomial<AlgebraicNumber<C>> dp = PolyUtil.<AlgebraicNumber<C>> baseDeriviative(d); 526 dp = dp.multiply(rl.afactors.get(j++)); 527 Quotient<AlgebraicNumber<C>> f = new Quotient<AlgebraicNumber<C>>(aqr, dp, d); 528 ai = ai.sum(f); 529 } 530 boolean t = ar.equals(ai); 531 if (t) { 532 return true; 533 } 534 logger.warn("log integral not verified"); 535 //System.out.println("r = " + r); 536 //System.out.println("afactors = " + rl.afactors); 537 //System.out.println("adenom = " + rl.adenom); 538 //System.out.println("ar = " + ar); 539 //System.out.println("ai = " + ai); 540 return true; 541 } 542 543 }