001/* 002 * $Id: FactorAbstract.java 5980 2019-04-17 19:45:07Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.Map; 011import java.util.SortedMap; 012import java.util.SortedSet; 013import java.util.TreeMap; 014import java.util.TreeSet; 015 016import org.apache.logging.log4j.Logger; 017import org.apache.logging.log4j.LogManager; 018 019import edu.jas.kern.TimeStatus; 020import edu.jas.kern.StringUtil; 021import edu.jas.poly.ExpVector; 022import edu.jas.poly.GenPolynomial; 023import edu.jas.poly.GenPolynomialRing; 024import edu.jas.poly.OptimizedPolynomialList; 025import edu.jas.poly.PolyUtil; 026import edu.jas.poly.TermOrderOptimization; 027import edu.jas.poly.TermOrderByName; 028import edu.jas.structure.GcdRingElem; 029import edu.jas.structure.RingFactory; 030import edu.jas.util.KsubSet; 031 032 033/** 034 * Abstract factorization algorithms class. This class contains implementations 035 * of all methods of the <code>Factorization</code> interface, except the method 036 * for factorization of a squarefree polynomial. The methods to obtain 037 * squarefree polynomials delegate the computation to the 038 * <code>GreatestCommonDivisor</code> classes and are included for convenience. 039 * @param <C> coefficient type 040 * @author Heinz Kredel 041 * @see edu.jas.ufd.FactorFactory 042 */ 043 044public abstract class FactorAbstract<C extends GcdRingElem<C>> implements Factorization<C> { 045 046 047 private static final Logger logger = LogManager.getLogger(FactorAbstract.class); 048 049 050 private static final boolean debug = logger.isDebugEnabled(); 051 052 053 /** 054 * Gcd engine for base coefficients. 055 */ 056 protected final GreatestCommonDivisorAbstract<C> engine; 057 058 059 /** 060 * Squarefree decompositon engine for base coefficients. 061 */ 062 protected final SquarefreeAbstract<C> sengine; 063 064 065 /** 066 * No argument constructor. 067 */ 068 protected FactorAbstract() { 069 throw new IllegalArgumentException("don't use this constructor"); 070 } 071 072 073 /** 074 * Constructor. 075 * @param cfac coefficient ring factory. 076 */ 077 public FactorAbstract(RingFactory<C> cfac) { 078 engine = GCDFactory.<C> getProxy(cfac); 079 //engine = GCDFactory.<C> getImplementation(cfac); 080 sengine = SquarefreeFactory.<C> getImplementation(cfac); 081 } 082 083 084 /** 085 * Get the String representation. 086 * @see java.lang.Object#toString() 087 */ 088 @Override 089 public String toString() { 090 return getClass().getName(); 091 } 092 093 094 /** 095 * GenPolynomial test if is irreducible. 096 * @param P GenPolynomial. 097 * @return true if P is irreducible, else false. 098 */ 099 public boolean isIrreducible(GenPolynomial<C> P) { 100 if (!isSquarefree(P)) { 101 return false; 102 } 103 List<GenPolynomial<C>> F = factorsSquarefree(P); 104 if (F.size() == 1) { 105 return true; 106 } else if (F.size() > 2) { 107 return false; 108 } else { //F.size() == 2 109 boolean cnst = false; 110 for (GenPolynomial<C> p : F) { 111 if (p.isConstant()) { 112 cnst = true; 113 } 114 } 115 return cnst; 116 } 117 } 118 119 120 /** 121 * GenPolynomial test if a non trivial factorization exsists. 122 * @param P GenPolynomial. 123 * @return true if P is reducible, else false. 124 */ 125 public boolean isReducible(GenPolynomial<C> P) { 126 return !isIrreducible(P); 127 } 128 129 130 /** 131 * GenPolynomial test if is squarefree. 132 * @param P GenPolynomial. 133 * @return true if P is squarefree, else false. 134 */ 135 public boolean isSquarefree(GenPolynomial<C> P) { 136 return sengine.isSquarefree(P); 137 } 138 139 140 /** 141 * GenPolynomial factorization of a multivariate squarefree polynomial, 142 * using Kronecker substitution and variable order optimization. 143 * @param P squarefree and primitive! (respectively monic) multivariate 144 * GenPolynomial over the ring C. 145 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 146 */ 147 public List<GenPolynomial<C>> factorsSquarefreeOptimize(GenPolynomial<C> P) { 148 GenPolynomialRing<C> pfac = P.ring; 149 if (pfac.nvar <= 1) { 150 return baseFactorsSquarefree(P); 151 } 152 List<GenPolynomial<C>> topt = new ArrayList<GenPolynomial<C>>(1); 153 topt.add(P); 154 OptimizedPolynomialList<C> opt = TermOrderOptimization.<C> optimizeTermOrder(pfac, topt); 155 P = opt.list.get(0); 156 logger.info("optimized polynomial: " + P); 157 List<Integer> iperm = TermOrderOptimization.inversePermutation(opt.perm); 158 logger.info("optimize perm: " + opt.perm + ", de-optimize perm: " + iperm); 159 160 ExpVector degv = P.degreeVector(); 161 int[] donv = degv.dependencyOnVariables(); 162 List<GenPolynomial<C>> facs = null; 163 if (degv.length() == donv.length) { // all variables appear 164 logger.info("do.full factorsSquarefreeKronecker: " + P); 165 facs = factorsSquarefreeKronecker(P); 166 } else { // not all variables appear, remove unused variables 167 GenPolynomial<C> pu = PolyUtil.<C> removeUnusedUpperVariables(P); 168 //GenPolynomial<C> pl = PolyUtil.<C> removeUnusedLowerVariables(pu); // not useful after optimize 169 logger.info("do.sparse factorsSquarefreeKronecker: " + pu); 170 facs = factorsSquarefreeKronecker(pu); // pl 171 List<GenPolynomial<C>> fs = new ArrayList<GenPolynomial<C>>(facs.size()); 172 GenPolynomialRing<C> pf = P.ring; 173 //GenPolynomialRing<C> pfu = pu.ring; 174 for (GenPolynomial<C> p : facs) { 175 //GenPolynomial<C> pel = p.extendLower(pfu, 0, 0L); 176 GenPolynomial<C> pe = p.extend(pf, 0, 0L); // pel 177 fs.add(pe); 178 } 179 //System.out.println("fs = " + fs); 180 facs = fs; 181 } 182 List<GenPolynomial<C>> iopt = TermOrderOptimization.<C> permutation(iperm, pfac, facs); 183 logger.info("de-optimized polynomials: " + iopt); 184 facs = normalizeFactorization(iopt); 185 return facs; 186 } 187 188 189 /** 190 * GenPolynomial factorization of a squarefree polynomial, using Kronecker 191 * substitution. 192 * @param P squarefree and primitive! (respectively monic) GenPolynomial. 193 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 194 */ 195 @Override 196 public List<GenPolynomial<C>> factorsSquarefree(GenPolynomial<C> P) { 197 if (P != null && P.ring.nvar > 1) { 198 logger.warn("no multivariate factorization for " + P.toScript() + ": falling back to Kronecker algorithm in " + P.ring.toScript()); 199 //if (P.ring.characteristic().signum() == 0) { 200 // throw new IllegalArgumentException("P.ring.characteristic().signum() == 0"); 201 //} 202 //throw new RuntimeException("get stack trace"); 203 } 204 //if (logger.isInfoEnabled()) { 205 // logger.info(StringUtil.selectStackTrace("edu\\.jas.*")); 206 //} 207 return factorsSquarefreeKronecker(P); 208 //return factorsSquarefreeOptimize(P); // test only 209 } 210 211 212 /** 213 * GenPolynomial factorization of a squarefree polynomial, using Kronecker 214 * substitution. 215 * @param P squarefree and primitive! (respectively monic) GenPolynomial. 216 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 217 */ 218 public List<GenPolynomial<C>> factorsSquarefreeKronecker(GenPolynomial<C> P) { 219 if (P == null) { 220 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 221 } 222 GenPolynomialRing<C> pfac = P.ring; 223 if (pfac.nvar == 1) { 224 return baseFactorsSquarefree(P); 225 } 226 List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>(); 227 if (P.isZERO()) { 228 return factors; 229 } 230 if (P.degreeVector().totalDeg() <= 1L) { 231 factors.add(P); 232 return factors; 233 } 234 long d = P.degree() + 1L; 235 GenPolynomial<C> kr = PolyUfdUtil.<C> substituteKronecker(P, d); 236 GenPolynomialRing<C> ufac = kr.ring; 237 ufac.setVars(ufac.newVars("zz")); // side effects 238 logger.info("deg(subs(P,d=" + d + ")) = " + kr.degree(0) + ", original degrees: " + P.degreeVector()); 239 if (debug) { 240 logger.info("subs(P,d=" + d + ") = " + kr); 241 //System.out.println("subs(P,d=" + d + ") = " + kr); 242 } 243 if (kr.degree(0) > 100) { 244 logger.warn("Kronecker substitution has to high degree " + kr.degree(0)); 245 TimeStatus.checkTime("degree > 100"); 246 } 247 248 // factor Kronecker polynomial 249 List<GenPolynomial<C>> ulist = new ArrayList<GenPolynomial<C>>(); 250 // kr might not be squarefree so complete factor univariate 251 SortedMap<GenPolynomial<C>, Long> slist = baseFactors(kr); 252 if (debug && !isFactorization(kr, slist)) { 253 logger.warn("kr = " + kr); 254 logger.warn("slist = " + slist); 255 throw new ArithmeticException("no factorization"); 256 } 257 for (Map.Entry<GenPolynomial<C>, Long> me : slist.entrySet()) { 258 GenPolynomial<C> g = me.getKey(); 259 long e = me.getValue(); // slist.get(g); 260 for (int i = 0; i < e; i++) { // is this really required? yes! 261 ulist.add(g); 262 } 263 } 264 //System.out.println("ulist = " + ulist); 265 if (ulist.size() == 1 && ulist.get(0).degree() == P.degree()) { 266 factors.add(P); 267 return factors; 268 } 269 //wrong: List<GenPolynomial<C>> klist = PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d); 270 //System.out.println("back(klist) = " + PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d)); 271 if (logger.isInfoEnabled()) { 272 logger.info("ulist = " + ulist); 273 //System.out.println("ulist = " + ulist); 274 } 275 // combine trial factors 276 int dl = ulist.size() - 1; //(ulist.size() + 1) / 2; 277 //System.out.println("dl = " + dl); 278 int ti = 0; 279 GenPolynomial<C> u = P; 280 long deg = (u.degree() + 1L) / 2L; // max deg 281 ExpVector evl = u.leadingExpVector(); 282 ExpVector evt = u.trailingExpVector(); 283 //System.out.println("deg = " + deg); 284 for (int j = 1; j <= dl; j++) { 285 KsubSet<GenPolynomial<C>> ps = new KsubSet<GenPolynomial<C>>(ulist, j); 286 for (List<GenPolynomial<C>> flist : ps) { 287 //System.out.println("flist = " + flist); 288 GenPolynomial<C> utrial = ufac.getONE(); 289 for (int k = 0; k < flist.size(); k++) { 290 utrial = utrial.multiply(flist.get(k)); 291 } 292 GenPolynomial<C> trial = PolyUfdUtil.<C> backSubstituteKronecker(pfac, utrial, d); 293 ti++; 294 if (ti % 2000 == 0) { 295 logger.warn("ti(" + ti + ") "); 296 TimeStatus.checkTime(ti + " % 2000 == 0"); 297 } 298 if (!evl.multipleOf(trial.leadingExpVector())) { 299 continue; 300 } 301 if (!evt.multipleOf(trial.trailingExpVector())) { 302 continue; 303 } 304 if (trial.degree() > deg || trial.isConstant()) { 305 continue; 306 } 307 trial = trial.monic(); 308 if (ti % 15000 == 0) { 309 logger.warn("\ndl = " + dl + ", deg(u) = " + deg); 310 logger.warn("ulist = " + ulist); 311 logger.warn("kr = " + kr); 312 logger.warn("u = " + u); 313 logger.warn("trial = " + trial); 314 } 315 GenPolynomial<C> rem = PolyUtil.<C> baseSparsePseudoRemainder(u, trial); 316 //System.out.println(" rem = " + rem); 317 if (rem.isZERO()) { 318 logger.info("trial = " + trial); 319 //System.out.println("trial = " + trial); 320 factors.add(trial); 321 u = PolyUtil.<C> basePseudoDivide(u, trial); //u = u.divide( trial ); 322 evl = u.leadingExpVector(); 323 evt = u.trailingExpVector(); 324 if (u.isConstant()) { 325 j = dl + 1; 326 break; 327 } 328 //if (ulist.removeAll(flist)) { // wrong 329 ulist = removeOnce(ulist, flist); 330 //System.out.println("new ulist = " + ulist); 331 dl = (ulist.size() + 1) / 2; 332 j = 0; // since j++ 333 break; 334 } 335 } 336 } 337 if (!u.isONE() && !u.equals(P)) { 338 logger.info("rest u = " + u); 339 factors.add(u); 340 } 341 if (factors.size() == 0) { 342 logger.info("irred P = " + P); 343 factors.add(P); // == u 344 } 345 return normalizeFactorization(factors); 346 } 347 348 349 /** 350 * Remove one occurrence of elements. 351 * @param a list of objects. 352 * @param b list of objects. 353 * @return remove every element of b from a, but only one occurrence. 354 * <b>Note:</b> not available in java.util. 355 */ 356 static <T> List<T> removeOnce(List<T> a, List<T> b) { 357 List<T> res = new ArrayList<T>(); 358 res.addAll(a); 359 for (T e : b) { 360 @SuppressWarnings("unused") 361 boolean t = res.remove(e); 362 } 363 return res; 364 } 365 366 367 /** 368 * Univariate GenPolynomial factorization ignoring multiplicities. 369 * @param P GenPolynomial in one variable. 370 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some 371 * e_i. 372 */ 373 public List<GenPolynomial<C>> baseFactorsRadical(GenPolynomial<C> P) { 374 return new ArrayList<GenPolynomial<C>>(baseFactors(P).keySet()); 375 } 376 377 378 /** 379 * Univariate GenPolynomial factorization. 380 * @param P GenPolynomial in one variable. 381 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 382 * p_i**e_i. 383 */ 384 public SortedMap<GenPolynomial<C>, Long> baseFactors(GenPolynomial<C> P) { 385 if (P == null) { 386 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 387 } 388 GenPolynomialRing<C> pfac = P.ring; 389 SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator()); 390 if (P.isZERO()) { 391 return factors; 392 } 393 if (pfac.nvar > 1) { 394 throw new IllegalArgumentException(this.getClass().getName() + " only for univariate polynomials"); 395 } 396 if (P.isConstant()) { 397 factors.put(P, 1L); 398 return factors; 399 } 400 C c; 401 if (pfac.coFac.isField()) { //pfac.characteristic().signum() > 0 402 c = P.leadingBaseCoefficient(); 403 } else { 404 c = engine.baseContent(P); 405 // move sign to the content 406 if (P.signum() < 0 && c.signum() > 0) { 407 c = c.negate(); 408 //P = P.negate(); 409 } 410 } 411 if (!c.isONE()) { 412 GenPolynomial<C> pc = pfac.getONE().multiply(c); 413 factors.put(pc, 1L); 414 P = P.divide(c); // make primitive or monic 415 } 416 if (logger.isInfoEnabled()) { 417 logger.info("base facs for P = " + P); 418 //System.out.println(StringUtil.selectStackTrace("edu\\.jas.*")); 419 } 420 SortedMap<GenPolynomial<C>, Long> facs = sengine.baseSquarefreeFactors(P); 421 if (facs == null || facs.size() == 0) { 422 facs = new TreeMap<GenPolynomial<C>, Long>(); 423 facs.put(P, 1L); 424 } 425 if (logger.isInfoEnabled() 426 && (facs.size() > 1 || (facs.size() == 1 && facs.get(facs.firstKey()) > 1))) { 427 logger.info("squarefree facs = " + facs); 428 //System.out.println("sfacs = " + facs); 429 //boolean tt = isFactorization(P,facs); 430 //System.out.println("sfacs tt = " + tt); 431 } 432 for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) { 433 GenPolynomial<C> g = me.getKey(); 434 Long k = me.getValue(); //facs.get(g); 435 //System.out.println("g = " + g); 436 if (pfac.coFac.isField() && !g.leadingBaseCoefficient().isONE()) { 437 g = g.monic(); // how can this happen? 438 logger.warn("squarefree facs mon = " + g); 439 } 440 if (g.degree(0) <= 1) { 441 if (!g.isONE()) { 442 factors.put(g, k); 443 } 444 } else { 445 List<GenPolynomial<C>> sfacs = baseFactorsSquarefree(g); 446 if (debug) { 447 logger.info("factors of squarefree = " + sfacs); 448 //System.out.println("sfacs = " + sfacs); 449 } 450 for (GenPolynomial<C> h : sfacs) { 451 Long j = factors.get(h); // evtl. constants 452 if (j != null) { 453 k += j; 454 } 455 if (!h.isONE()) { 456 factors.put(h, k); 457 } 458 } 459 } 460 } 461 //System.out.println("factors = " + factors); 462 return factors; 463 } 464 465 466 /** 467 * Univariate GenPolynomial factorization of a squarefree polynomial. 468 * @param P squarefree and primitive! GenPolynomial in one variable. 469 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i. 470 */ 471 public abstract List<GenPolynomial<C>> baseFactorsSquarefree(GenPolynomial<C> P); 472 473 474 /** 475 * GenPolynomial factorization ignoring multiplicities. 476 * @param P GenPolynomial. 477 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some 478 * e_i. 479 */ 480 public List<GenPolynomial<C>> factorsRadical(GenPolynomial<C> P) { 481 return new ArrayList<GenPolynomial<C>>(factors(P).keySet()); 482 } 483 484 485 /** 486 * GenPolynomial list factorization ignoring multiplicities. 487 * @param L list of GenPolynomials. 488 * @return [p_1, ..., p_k] with p = prod_{i=1,...,k} p_i**{e_i} for some e_i 489 * for all p in L. 490 */ 491 public List<GenPolynomial<C>> factorsRadical(List<GenPolynomial<C>> L) { 492 SortedSet<GenPolynomial<C>> facs = new TreeSet<GenPolynomial<C>>(); 493 for (GenPolynomial<C> p : L) { 494 List<GenPolynomial<C>> fs = factorsRadical(p); 495 facs.addAll(fs); 496 } 497 return new ArrayList<GenPolynomial<C>>(facs); 498 } 499 500 501 /** 502 * GenPolynomial factorization. 503 * @param P GenPolynomial. 504 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 505 * p_i**e_i. 506 */ 507 public SortedMap<GenPolynomial<C>, Long> factors(GenPolynomial<C> P) { 508 if (P == null) { 509 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 510 } 511 GenPolynomialRing<C> pfac = P.ring; 512 if (pfac.nvar == 1) { 513 return baseFactors(P); 514 } 515 SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator()); 516 if (P.isZERO()) { 517 return factors; 518 } 519 if (P.isConstant()) { 520 factors.put(P, 1L); 521 return factors; 522 } 523 if (!pfac.tord.equals(TermOrderByName.INVLEX)) { 524 logger.warn("wrong term order " + pfac.tord + ", factorization may not be correct, better use " + TermOrderByName.INVLEX); 525 } 526 C c; 527 if (pfac.coFac.isField()) { 528 c = P.leadingBaseCoefficient(); 529 } else { 530 c = engine.baseContent(P); 531 // move sign to the content 532 if (P.signum() < 0 && c.signum() > 0) { 533 c = c.negate(); 534 //P = P.negate(); 535 } 536 } 537 if (!c.isONE()) { 538 GenPolynomial<C> pc = pfac.getONE().multiply(c); 539 factors.put(pc, 1L); 540 P = P.divide(c); // make base primitive or base monic 541 } 542 if (logger.isInfoEnabled()) { 543 logger.info("base primitive part P = " + P); 544 } 545 GenPolynomial<C>[] cpp = engine.contentPrimitivePart(P); 546 GenPolynomial<C> pc = cpp[0]; 547 if (!pc.isONE()) { 548 SortedMap<GenPolynomial<C>, Long> rec = factors(pc); // recursion 549 for (Map.Entry<GenPolynomial<C>, Long> me : rec.entrySet()) { 550 GenPolynomial<C> g = me.getKey(); 551 Long d = me.getValue(); 552 GenPolynomial<C> pn = g.extend(pfac,0,0L); 553 factors.put(pn,d); 554 } 555 if (logger.isInfoEnabled()) { 556 logger.info("content factors = " + factors); 557 } 558 } 559 P = cpp[1]; 560 if (logger.isInfoEnabled()) { 561 logger.info("primitive part P = " + P); 562 } 563 if (P.isONE()) { 564 return factors; 565 } 566 SortedMap<GenPolynomial<C>, Long> facs = sengine.squarefreeFactors(P); 567 if (facs == null || facs.size() == 0) { 568 facs = new TreeMap<GenPolynomial<C>, Long>(); 569 facs.put(P, 1L); 570 throw new RuntimeException("this should not happen, facs is empty: " + facs); 571 } 572 if (logger.isInfoEnabled()) { 573 if (facs.size() > 1) { 574 logger.info("squarefree mfacs = " + facs); 575 } else if (facs.size() == 1 && facs.get(facs.firstKey()) > 1L) { 576 logger.info("squarefree #mfacs 1-n = " + facs); 577 } else { 578 logger.info("squarefree #mfacs 1-1 = " + facs); 579 } 580 } 581 for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) { 582 GenPolynomial<C> g = me.getKey(); 583 if (g.isONE()) { // skip 1 584 continue; 585 } 586 Long d = me.getValue(); // facs.get(g); 587 List<GenPolynomial<C>> sfacs = factorsSquarefree(g); 588 if (logger.isInfoEnabled()) { 589 logger.info("factors of squarefree ^" + d + " = " + sfacs); 590 //System.out.println("sfacs = " + sfacs); 591 } 592 for (GenPolynomial<C> h : sfacs) { 593 long dd = d; 594 Long j = factors.get(h); // evtl. constants 595 if (j != null) { 596 dd += j; 597 } 598 factors.put(h, dd); 599 } 600 } 601 //System.out.println("factors = " + factors); 602 return factors; 603 } 604 605 606 /** 607 * GenPolynomial greatest squarefree divisor. Delegates computation to a 608 * GreatestCommonDivisor class. 609 * @param P GenPolynomial. 610 * @return squarefree(P). 611 */ 612 public GenPolynomial<C> squarefreePart(GenPolynomial<C> P) { 613 return sengine.squarefreePart(P); 614 } 615 616 617 /** 618 * GenPolynomial primitive part. Delegates computation to a 619 * GreatestCommonDivisor class. 620 * @param P GenPolynomial. 621 * @return primitivePart(P). 622 */ 623 public GenPolynomial<C> primitivePart(GenPolynomial<C> P) { 624 return engine.primitivePart(P); 625 } 626 627 628 /** 629 * GenPolynomial base primitive part. Delegates computation to a 630 * GreatestCommonDivisor class. 631 * @param P GenPolynomial. 632 * @return basePrimitivePart(P). 633 */ 634 public GenPolynomial<C> basePrimitivePart(GenPolynomial<C> P) { 635 return engine.basePrimitivePart(P); 636 } 637 638 639 /** 640 * GenPolynomial squarefree factorization. Delegates computation to a 641 * GreatestCommonDivisor class. 642 * @param P GenPolynomial. 643 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 644 * p_i**e_i. 645 */ 646 public SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P) { 647 return sengine.squarefreeFactors(P); 648 } 649 650 651 /** 652 * GenPolynomial is factorization. 653 * @param P GenPolynomial. 654 * @param F = [p_1,...,p_k]. 655 * @return true if P = prod_{i=1,...,r} p_i, else false. 656 */ 657 public boolean isFactorization(GenPolynomial<C> P, List<GenPolynomial<C>> F) { 658 return sengine.isFactorization(P, F); 659 // test irreducible 660 } 661 662 663 /** 664 * GenPolynomial is factorization. 665 * @param P GenPolynomial. 666 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 667 * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. 668 */ 669 public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) { 670 return sengine.isFactorization(P, F); 671 // test irreducible 672 } 673 674 675 /** 676 * Degree of a factorization. 677 * @param F a factors map [p_1 -> e_1, ..., p_k -> e_k]. 678 * @return sum_{i=1,...,k} degree(p_i)*e_i. 679 */ 680 public long factorsDegree(SortedMap<GenPolynomial<C>, Long> F) { 681 long d = 0; 682 for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) { 683 GenPolynomial<C> p = me.getKey(); 684 long e = me.getValue(); //F.get(p); 685 d += p.degree() * e; 686 } 687 return d; 688 } 689 690 691 /** 692 * GenPolynomial is factorization. 693 * @param P GenPolynomial. 694 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 695 * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. 696 */ 697 public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P, 698 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) { 699 return sengine.isRecursiveFactorization(P, F); 700 // test irreducible 701 } 702 703 704 /** 705 * Recursive GenPolynomial factorization of a squarefree polynomial. 706 * @param P squarefree recursive GenPolynomial. 707 * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. 708 */ 709 public List<GenPolynomial<GenPolynomial<C>>> recursiveFactorsSquarefree(GenPolynomial<GenPolynomial<C>> P) { 710 if (P == null) { 711 throw new IllegalArgumentException(this.getClass().getName() + " P == null"); 712 } 713 List<GenPolynomial<GenPolynomial<C>>> factors = new ArrayList<GenPolynomial<GenPolynomial<C>>>(); 714 if (P.isZERO()) { 715 return factors; 716 } 717 if (P.isONE()) { 718 factors.add(P); 719 return factors; 720 } 721 GenPolynomialRing<GenPolynomial<C>> pfac = P.ring; 722 GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac; 723 GenPolynomialRing<C> ifac = qi.extend(pfac.getVars()); 724 GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P); 725 //System.out.println("Pi = " + Pi); 726 727 C ldcf = Pi.leadingBaseCoefficient(); 728 if (!ldcf.isONE() && ldcf.isUnit()) { 729 //System.out.println("ldcf = " + ldcf); 730 Pi = Pi.monic(); 731 } 732 733 // factor in C[x_1,...,x_n,y_1,...,y_m] 734 List<GenPolynomial<C>> ifacts = factorsSquarefree(Pi); 735 if (logger.isInfoEnabled()) { 736 logger.info("ifacts = " + ifacts); 737 } 738 if (ifacts.size() <= 1) { 739 factors.add(P); 740 return factors; 741 } 742 if (!ldcf.isONE() && ldcf.isUnit()) { 743 GenPolynomial<C> r = ifacts.get(0); 744 ifacts.remove(r); 745 r = r.multiply(ldcf); 746 ifacts.add(0, r); 747 } 748 List<GenPolynomial<GenPolynomial<C>>> rfacts = PolyUtil.<C> recursive(pfac, ifacts); 749 //System.out.println("rfacts = " + rfacts); 750 if (logger.isDebugEnabled()) { 751 logger.info("recfacts = " + rfacts); 752 } 753 factors.addAll(rfacts); 754 return factors; 755 } 756 757 758 /** 759 * Recursive GenPolynomial factorization. 760 * @param P recursive GenPolynomial. 761 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 762 * p_i**e_i. 763 */ 764 public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveFactors(GenPolynomial<GenPolynomial<C>> P) { 765 if (P == null) { 766 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 767 } 768 GenPolynomialRing<GenPolynomial<C>> pfac = P.ring; 769 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>( 770 pfac.getComparator()); 771 if (P.isZERO()) { 772 return factors; 773 } 774 if (P.isONE()) { 775 factors.put(P, 1L); 776 return factors; 777 } 778 GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac; 779 GenPolynomialRing<C> ifac = qi.extend(pfac.getVars()); 780 GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P); 781 //System.out.println("Pi = " + Pi); 782 783 C ldcf = Pi.leadingBaseCoefficient(); 784 if (!ldcf.isONE() && ldcf.isUnit()) { 785 //System.out.println("ldcf = " + ldcf); 786 Pi = Pi.monic(); 787 } 788 789 // factor in C[x_1,...,x_n,y_1,...,y_m] 790 SortedMap<GenPolynomial<C>, Long> dfacts = factors(Pi); 791 if (logger.isInfoEnabled()) { 792 logger.info("dfacts = " + dfacts); 793 } 794 if (!ldcf.isONE() && ldcf.isUnit()) { 795 GenPolynomial<C> r = dfacts.firstKey(); 796 Long E = dfacts.remove(r); 797 r = r.multiply(ldcf); 798 dfacts.put(r, E); 799 } 800 for (Map.Entry<GenPolynomial<C>, Long> me : dfacts.entrySet()) { 801 GenPolynomial<C> f = me.getKey(); 802 Long E = me.getValue(); //dfacts.get(f); 803 GenPolynomial<GenPolynomial<C>> rp = PolyUtil.<C> recursive(pfac, f); 804 factors.put(rp, E); 805 } 806 //System.out.println("rfacts = " + rfacts); 807 if (logger.isInfoEnabled()) { 808 logger.info("recursive factors = " + factors); 809 } 810 return factors; 811 } 812 813 814 /** 815 * Normalize factorization. p'_i > 0 for i > 1 and p'_1 != 1 if k > 816 * 1. 817 * @param F = [p_1,...,p_k]. 818 * @return F' = [p'_1,...,p'_k]. 819 */ 820 public List<GenPolynomial<C>> normalizeFactorization(List<GenPolynomial<C>> F) { 821 if (F == null || F.size() <= 1) { 822 return F; 823 } 824 List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.size()); 825 GenPolynomial<C> f0 = F.get(0); 826 for (int i = 1; i < F.size(); i++) { 827 GenPolynomial<C> fi = F.get(i); 828 if (fi.signum() < 0) { 829 fi = fi.negate(); 830 f0 = f0.negate(); 831 } 832 Fp.add(fi); 833 } 834 if (!f0.isONE()) { 835 Fp.add(0, f0); 836 } 837 return Fp; 838 } 839}