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