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