001/* 002 * $Id: FactorAbstract.java 5778 2017-11-16 22:17:43Z 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 static 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 (P != null && P.ring.nvar > 1) { 196 logger.warn("no multivariate factorization for " + P.ring.toScript() + ": falling back to Kronecker algorithm"); 197 //if (P.ring.characteristic().signum() == 0) { 198 // throw new IllegalArgumentException(this.getClass().getName() + " P.ring.characteristic().signum() == 0"); 199 //} 200 } 201 //if (logger.isInfoEnabled()) { 202 // logger.info(StringUtil.selectStackTrace("edu\\.jas.*")); 203 //} 204 return factorsSquarefreeKronecker(P); 205 //return factorsSquarefreeOptimize(P); // test only 206 } 207 208 209 /** 210 * GenPolynomial factorization of a squarefree polynomial, using Kronecker 211 * substitution. 212 * @param P squarefree and primitive! (respectively monic) GenPolynomial. 213 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 214 */ 215 public List<GenPolynomial<C>> factorsSquarefreeKronecker(GenPolynomial<C> P) { 216 if (P == null) { 217 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 218 } 219 GenPolynomialRing<C> pfac = P.ring; 220 if (pfac.nvar == 1) { 221 return baseFactorsSquarefree(P); 222 } 223 List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>(); 224 if (P.isZERO()) { 225 return factors; 226 } 227 if (P.degreeVector().totalDeg() <= 1L) { 228 factors.add(P); 229 return factors; 230 } 231 long d = P.degree() + 1L; 232 GenPolynomial<C> kr = PolyUfdUtil.<C> substituteKronecker(P, d); 233 GenPolynomialRing<C> ufac = kr.ring; 234 ufac.setVars(ufac.newVars("zz")); // side effects 235 logger.info("deg(subs(P,d=" + d + ")) = " + kr.degree(0) + ", original degrees: " + P.degreeVector()); 236 if (debug) { 237 logger.info("subs(P,d=" + d + ") = " + kr); 238 //System.out.println("subs(P,d=" + d + ") = " + kr); 239 } 240 if (kr.degree(0) > 100) { 241 logger.warn("Kronecker substitution has to high degree"); 242 TimeStatus.checkTime("degree > 100"); 243 } 244 245 // factor Kronecker polynomial 246 List<GenPolynomial<C>> ulist = new ArrayList<GenPolynomial<C>>(); 247 // kr might not be squarefree so complete factor univariate 248 SortedMap<GenPolynomial<C>, Long> slist = baseFactors(kr); 249 if (debug && !isFactorization(kr, slist)) { 250 System.out.println("kr = " + kr); 251 System.out.println("slist = " + slist); 252 throw new ArithmeticException("no factorization"); 253 } 254 for (Map.Entry<GenPolynomial<C>, Long> me : slist.entrySet()) { 255 GenPolynomial<C> g = me.getKey(); 256 long e = me.getValue(); // slist.get(g); 257 for (int i = 0; i < e; i++) { // is this really required? yes! 258 ulist.add(g); 259 } 260 } 261 //System.out.println("ulist = " + ulist); 262 if (ulist.size() == 1 && ulist.get(0).degree() == P.degree()) { 263 factors.add(P); 264 return factors; 265 } 266 //wrong: List<GenPolynomial<C>> klist = PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d); 267 //System.out.println("back(klist) = " + PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d)); 268 if (logger.isInfoEnabled()) { 269 logger.info("ulist = " + ulist); 270 //System.out.println("ulist = " + ulist); 271 } 272 // combine trial factors 273 int dl = ulist.size() - 1; //(ulist.size() + 1) / 2; 274 //System.out.println("dl = " + dl); 275 int ti = 0; 276 GenPolynomial<C> u = P; 277 long deg = (u.degree() + 1L) / 2L; // max deg 278 ExpVector evl = u.leadingExpVector(); 279 ExpVector evt = u.trailingExpVector(); 280 //System.out.println("deg = " + deg); 281 for (int j = 1; j <= dl; j++) { 282 KsubSet<GenPolynomial<C>> ps = new KsubSet<GenPolynomial<C>>(ulist, j); 283 for (List<GenPolynomial<C>> flist : ps) { 284 //System.out.println("flist = " + flist); 285 GenPolynomial<C> utrial = ufac.getONE(); 286 for (int k = 0; k < flist.size(); k++) { 287 utrial = utrial.multiply(flist.get(k)); 288 } 289 GenPolynomial<C> trial = PolyUfdUtil.<C> backSubstituteKronecker(pfac, utrial, d); 290 ti++; 291 if (ti % 2000 == 0) { 292 System.out.print("ti(" + ti + ") "); 293 TimeStatus.checkTime(ti + " % 2000 == 0"); 294 } 295 if (!evl.multipleOf(trial.leadingExpVector())) { 296 continue; 297 } 298 if (!evt.multipleOf(trial.trailingExpVector())) { 299 continue; 300 } 301 if (trial.degree() > deg || trial.isConstant()) { 302 continue; 303 } 304 trial = trial.monic(); 305 if (ti % 15000 == 0) { 306 System.out.println("\ndl = " + dl + ", deg(u) = " + deg); 307 System.out.println("ulist = " + ulist); 308 System.out.println("kr = " + kr); 309 System.out.println("u = " + u); 310 System.out.println("trial = " + trial); 311 } 312 GenPolynomial<C> rem = PolyUtil.<C> baseSparsePseudoRemainder(u, trial); 313 //System.out.println(" rem = " + rem); 314 if (rem.isZERO()) { 315 logger.info("trial = " + trial); 316 //System.out.println("trial = " + trial); 317 factors.add(trial); 318 u = PolyUtil.<C> basePseudoDivide(u, trial); //u = u.divide( trial ); 319 evl = u.leadingExpVector(); 320 evt = u.trailingExpVector(); 321 if (u.isConstant()) { 322 j = dl + 1; 323 break; 324 } 325 //if (ulist.removeAll(flist)) { // wrong 326 ulist = removeOnce(ulist, flist); 327 //System.out.println("new ulist = " + ulist); 328 dl = (ulist.size() + 1) / 2; 329 j = 0; // since j++ 330 break; 331 } 332 } 333 } 334 if (!u.isONE() && !u.equals(P)) { 335 logger.info("rest u = " + u); 336 factors.add(u); 337 } 338 if (factors.size() == 0) { 339 logger.info("irred P = " + P); 340 factors.add(P); // == u 341 } 342 return normalizeFactorization(factors); 343 } 344 345 346 /** 347 * Remove one occurrence of elements. 348 * @param a list of objects. 349 * @param b list of objects. 350 * @return remove every element of b from a, but only one occurrence. 351 * <b>Note:</b> not available in java.util. 352 */ 353 static <T> List<T> removeOnce(List<T> a, List<T> b) { 354 List<T> res = new ArrayList<T>(); 355 res.addAll(a); 356 for (T e : b) { 357 @SuppressWarnings("unused") 358 boolean t = res.remove(e); 359 } 360 return res; 361 } 362 363 364 /** 365 * Univariate GenPolynomial factorization ignoring multiplicities. 366 * @param P GenPolynomial in one variable. 367 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some 368 * e_i. 369 */ 370 public List<GenPolynomial<C>> baseFactorsRadical(GenPolynomial<C> P) { 371 return new ArrayList<GenPolynomial<C>>(baseFactors(P).keySet()); 372 } 373 374 375 /** 376 * Univariate GenPolynomial factorization. 377 * @param P GenPolynomial in one variable. 378 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 379 * p_i**e_i. 380 */ 381 public SortedMap<GenPolynomial<C>, Long> baseFactors(GenPolynomial<C> P) { 382 if (P == null) { 383 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 384 } 385 GenPolynomialRing<C> pfac = P.ring; 386 SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator()); 387 if (P.isZERO()) { 388 return factors; 389 } 390 if (pfac.nvar > 1) { 391 throw new IllegalArgumentException(this.getClass().getName() + " only for univariate polynomials"); 392 } 393 if (P.isConstant()) { 394 factors.put(P, 1L); 395 return factors; 396 } 397 C c; 398 if (pfac.coFac.isField()) { //pfac.characteristic().signum() > 0 399 c = P.leadingBaseCoefficient(); 400 } else { 401 c = engine.baseContent(P); 402 // move sign to the content 403 if (P.signum() < 0 && c.signum() > 0) { 404 c = c.negate(); 405 //P = P.negate(); 406 } 407 } 408 if (!c.isONE()) { 409 GenPolynomial<C> pc = pfac.getONE().multiply(c); 410 factors.put(pc, 1L); 411 P = P.divide(c); // make primitive or monic 412 } 413 if (logger.isInfoEnabled()) { 414 logger.info("base facs for P = " + P); 415 //System.out.println(StringUtil.selectStackTrace("edu\\.jas.*")); 416 } 417 SortedMap<GenPolynomial<C>, Long> facs = sengine.baseSquarefreeFactors(P); 418 if (facs == null || facs.size() == 0) { 419 facs = new TreeMap<GenPolynomial<C>, Long>(); 420 facs.put(P, 1L); 421 } 422 if (logger.isInfoEnabled() 423 && (facs.size() > 1 || (facs.size() == 1 && facs.get(facs.firstKey()) > 1))) { 424 logger.info("squarefree facs = " + facs); 425 //System.out.println("sfacs = " + facs); 426 //boolean tt = isFactorization(P,facs); 427 //System.out.println("sfacs tt = " + tt); 428 } 429 for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) { 430 GenPolynomial<C> g = me.getKey(); 431 Long k = me.getValue(); //facs.get(g); 432 //System.out.println("g = " + g); 433 if (pfac.coFac.isField() && !g.leadingBaseCoefficient().isONE()) { 434 g = g.monic(); // how can this happen? 435 logger.warn("squarefree facs mon = " + g); 436 } 437 if (g.degree(0) <= 1) { 438 if (!g.isONE()) { 439 factors.put(g, k); 440 } 441 } else { 442 List<GenPolynomial<C>> sfacs = baseFactorsSquarefree(g); 443 if (debug) { 444 logger.info("factors of squarefree = " + sfacs); 445 //System.out.println("sfacs = " + sfacs); 446 } 447 for (GenPolynomial<C> h : sfacs) { 448 Long j = factors.get(h); // evtl. constants 449 if (j != null) { 450 k += j; 451 } 452 if (!h.isONE()) { 453 factors.put(h, k); 454 } 455 } 456 } 457 } 458 //System.out.println("factors = " + factors); 459 return factors; 460 } 461 462 463 /** 464 * Univariate GenPolynomial factorization of a squarefree polynomial. 465 * @param P squarefree and primitive! GenPolynomial in one variable. 466 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i. 467 */ 468 public abstract List<GenPolynomial<C>> baseFactorsSquarefree(GenPolynomial<C> P); 469 470 471 /** 472 * GenPolynomial factorization ignoring multiplicities. 473 * @param P GenPolynomial. 474 * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some 475 * e_i. 476 */ 477 public List<GenPolynomial<C>> factorsRadical(GenPolynomial<C> P) { 478 return new ArrayList<GenPolynomial<C>>(factors(P).keySet()); 479 } 480 481 482 /** 483 * GenPolynomial list factorization ignoring multiplicities. 484 * @param L list of GenPolynomials. 485 * @return [p_1, ..., p_k] with p = prod_{i=1,...,k} p_i**{e_i} for some e_i 486 * for all p in L. 487 */ 488 public List<GenPolynomial<C>> factorsRadical(List<GenPolynomial<C>> L) { 489 SortedSet<GenPolynomial<C>> facs = new TreeSet<GenPolynomial<C>>(); 490 for (GenPolynomial<C> p : L) { 491 List<GenPolynomial<C>> fs = factorsRadical(p); 492 facs.addAll(fs); 493 } 494 return new ArrayList<GenPolynomial<C>>(facs); 495 } 496 497 498 /** 499 * GenPolynomial factorization. 500 * @param P GenPolynomial. 501 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 502 * p_i**e_i. 503 */ 504 public SortedMap<GenPolynomial<C>, Long> factors(GenPolynomial<C> P) { 505 if (P == null) { 506 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 507 } 508 GenPolynomialRing<C> pfac = P.ring; 509 if (pfac.nvar == 1) { 510 return baseFactors(P); 511 } 512 SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator()); 513 if (P.isZERO()) { 514 return factors; 515 } 516 if (P.isConstant()) { 517 factors.put(P, 1L); 518 return factors; 519 } 520 C c; 521 if (pfac.coFac.isField()) { 522 c = P.leadingBaseCoefficient(); 523 } else { 524 c = engine.baseContent(P); 525 // move sign to the content 526 if (P.signum() < 0 && c.signum() > 0) { 527 c = c.negate(); 528 //P = P.negate(); 529 } 530 } 531 if (!c.isONE()) { 532 GenPolynomial<C> pc = pfac.getONE().multiply(c); 533 factors.put(pc, 1L); 534 P = P.divide(c); // make base primitive or base monic 535 } 536 if (logger.isInfoEnabled()) { 537 logger.info("base primitive part P = " + P); 538 } 539 GenPolynomial<C>[] cpp = engine.contentPrimitivePart(P); 540 GenPolynomial<C> pc = cpp[0]; 541 if (!pc.isONE()) { 542 SortedMap<GenPolynomial<C>, Long> rec = factors(pc); // recursion 543 for (Map.Entry<GenPolynomial<C>, Long> me : rec.entrySet()) { 544 GenPolynomial<C> g = me.getKey(); 545 Long d = me.getValue(); 546 GenPolynomial<C> pn = g.extend(pfac,0,0L); 547 factors.put(pn,d); 548 } 549 if (logger.isInfoEnabled()) { 550 logger.info("content factors = " + factors); 551 } 552 } 553 P = cpp[1]; 554 if (logger.isInfoEnabled()) { 555 logger.info("primitive part P = " + P); 556 } 557 if (P.isONE()) { 558 return factors; 559 } 560 SortedMap<GenPolynomial<C>, Long> facs = sengine.squarefreeFactors(P); 561 if (facs == null || facs.size() == 0) { 562 facs = new TreeMap<GenPolynomial<C>, Long>(); 563 facs.put(P, 1L); 564 throw new RuntimeException("this should not happen, facs is empty: " + facs); 565 } 566 if (logger.isInfoEnabled()) { 567 if (facs.size() > 1) { 568 logger.info("squarefree mfacs = " + facs); 569 } else if (facs.size() == 1 && facs.get(facs.firstKey()) > 1L) { 570 logger.info("squarefree #mfacs 1-n = " + facs); 571 } else { 572 logger.info("squarefree #mfacs 1-1 = " + facs); 573 } 574 } 575 for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) { 576 GenPolynomial<C> g = me.getKey(); 577 if (g.isONE()) { // skip 1 578 continue; 579 } 580 Long d = me.getValue(); // facs.get(g); 581 List<GenPolynomial<C>> sfacs = factorsSquarefree(g); 582 if (logger.isInfoEnabled()) { 583 logger.info("factors of squarefree ^" + d + " = " + sfacs); 584 //System.out.println("sfacs = " + sfacs); 585 } 586 for (GenPolynomial<C> h : sfacs) { 587 long dd = d; 588 Long j = factors.get(h); // evtl. constants 589 if (j != null) { 590 dd += j; 591 } 592 factors.put(h, dd); 593 } 594 } 595 //System.out.println("factors = " + factors); 596 return factors; 597 } 598 599 600 /** 601 * GenPolynomial greatest squarefree divisor. Delegates computation to a 602 * GreatestCommonDivisor class. 603 * @param P GenPolynomial. 604 * @return squarefree(P). 605 */ 606 public GenPolynomial<C> squarefreePart(GenPolynomial<C> P) { 607 return sengine.squarefreePart(P); 608 } 609 610 611 /** 612 * GenPolynomial primitive part. Delegates computation to a 613 * GreatestCommonDivisor class. 614 * @param P GenPolynomial. 615 * @return primitivePart(P). 616 */ 617 public GenPolynomial<C> primitivePart(GenPolynomial<C> P) { 618 return engine.primitivePart(P); 619 } 620 621 622 /** 623 * GenPolynomial base primitive part. Delegates computation to a 624 * GreatestCommonDivisor class. 625 * @param P GenPolynomial. 626 * @return basePrimitivePart(P). 627 */ 628 public GenPolynomial<C> basePrimitivePart(GenPolynomial<C> P) { 629 return engine.basePrimitivePart(P); 630 } 631 632 633 /** 634 * GenPolynomial squarefree factorization. Delegates computation to a 635 * GreatestCommonDivisor class. 636 * @param P GenPolynomial. 637 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 638 * p_i**e_i. 639 */ 640 public SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P) { 641 return sengine.squarefreeFactors(P); 642 } 643 644 645 /** 646 * GenPolynomial is factorization. 647 * @param P GenPolynomial. 648 * @param F = [p_1,...,p_k]. 649 * @return true if P = prod_{i=1,...,r} p_i, else false. 650 */ 651 public boolean isFactorization(GenPolynomial<C> P, List<GenPolynomial<C>> F) { 652 return sengine.isFactorization(P, F); 653 // test irreducible 654 } 655 656 657 /** 658 * GenPolynomial is factorization. 659 * @param P GenPolynomial. 660 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 661 * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. 662 */ 663 public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) { 664 return sengine.isFactorization(P, F); 665 // test irreducible 666 } 667 668 669 /** 670 * Degree of a factorization. 671 * @param F a factors map [p_1 -> e_1, ..., p_k -> e_k]. 672 * @return sum_{i=1,...,k} degree(p_i)*e_i. 673 */ 674 public long factorsDegree(SortedMap<GenPolynomial<C>, Long> F) { 675 long d = 0; 676 for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) { 677 GenPolynomial<C> p = me.getKey(); 678 long e = me.getValue(); //F.get(p); 679 d += p.degree() * e; 680 } 681 return d; 682 } 683 684 685 /** 686 * GenPolynomial is factorization. 687 * @param P GenPolynomial. 688 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 689 * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. 690 */ 691 public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P, 692 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) { 693 return sengine.isRecursiveFactorization(P, F); 694 // test irreducible 695 } 696 697 698 /** 699 * Recursive GenPolynomial factorization of a squarefree polynomial. 700 * @param P squarefree recursive GenPolynomial. 701 * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. 702 */ 703 public List<GenPolynomial<GenPolynomial<C>>> recursiveFactorsSquarefree(GenPolynomial<GenPolynomial<C>> P) { 704 if (P == null) { 705 throw new IllegalArgumentException(this.getClass().getName() + " P == null"); 706 } 707 List<GenPolynomial<GenPolynomial<C>>> factors = new ArrayList<GenPolynomial<GenPolynomial<C>>>(); 708 if (P.isZERO()) { 709 return factors; 710 } 711 if (P.isONE()) { 712 factors.add(P); 713 return factors; 714 } 715 GenPolynomialRing<GenPolynomial<C>> pfac = P.ring; 716 GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac; 717 GenPolynomialRing<C> ifac = qi.extend(pfac.getVars()); 718 GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P); 719 //System.out.println("Pi = " + Pi); 720 721 C ldcf = Pi.leadingBaseCoefficient(); 722 if (!ldcf.isONE() && ldcf.isUnit()) { 723 //System.out.println("ldcf = " + ldcf); 724 Pi = Pi.monic(); 725 } 726 727 // factor in C[x_1,...,x_n,y_1,...,y_m] 728 List<GenPolynomial<C>> ifacts = factorsSquarefree(Pi); 729 if (logger.isInfoEnabled()) { 730 logger.info("ifacts = " + ifacts); 731 } 732 if (ifacts.size() <= 1) { 733 factors.add(P); 734 return factors; 735 } 736 if (!ldcf.isONE() && ldcf.isUnit()) { 737 GenPolynomial<C> r = ifacts.get(0); 738 ifacts.remove(r); 739 r = r.multiply(ldcf); 740 ifacts.add(0, r); 741 } 742 List<GenPolynomial<GenPolynomial<C>>> rfacts = PolyUtil.<C> recursive(pfac, ifacts); 743 //System.out.println("rfacts = " + rfacts); 744 if (logger.isDebugEnabled()) { 745 logger.info("recfacts = " + rfacts); 746 } 747 factors.addAll(rfacts); 748 return factors; 749 } 750 751 752 /** 753 * Recursive GenPolynomial factorization. 754 * @param P recursive GenPolynomial. 755 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 756 * p_i**e_i. 757 */ 758 public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveFactors(GenPolynomial<GenPolynomial<C>> P) { 759 if (P == null) { 760 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 761 } 762 GenPolynomialRing<GenPolynomial<C>> pfac = P.ring; 763 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>( 764 pfac.getComparator()); 765 if (P.isZERO()) { 766 return factors; 767 } 768 if (P.isONE()) { 769 factors.put(P, 1L); 770 return factors; 771 } 772 GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac; 773 GenPolynomialRing<C> ifac = qi.extend(pfac.getVars()); 774 GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P); 775 //System.out.println("Pi = " + Pi); 776 777 C ldcf = Pi.leadingBaseCoefficient(); 778 if (!ldcf.isONE() && ldcf.isUnit()) { 779 //System.out.println("ldcf = " + ldcf); 780 Pi = Pi.monic(); 781 } 782 783 // factor in C[x_1,...,x_n,y_1,...,y_m] 784 SortedMap<GenPolynomial<C>, Long> dfacts = factors(Pi); 785 if (logger.isInfoEnabled()) { 786 logger.info("dfacts = " + dfacts); 787 } 788 if (!ldcf.isONE() && ldcf.isUnit()) { 789 GenPolynomial<C> r = dfacts.firstKey(); 790 Long E = dfacts.remove(r); 791 r = r.multiply(ldcf); 792 dfacts.put(r, E); 793 } 794 for (Map.Entry<GenPolynomial<C>, Long> me : dfacts.entrySet()) { 795 GenPolynomial<C> f = me.getKey(); 796 Long E = me.getValue(); //dfacts.get(f); 797 GenPolynomial<GenPolynomial<C>> rp = PolyUtil.<C> recursive(pfac, f); 798 factors.put(rp, E); 799 } 800 //System.out.println("rfacts = " + rfacts); 801 if (logger.isInfoEnabled()) { 802 logger.info("recursive factors = " + factors); 803 } 804 return factors; 805 } 806 807 808 /** 809 * Normalize factorization. p'_i > 0 for i > 1 and p'_1 != 1 if k > 810 * 1. 811 * @param F = [p_1,...,p_k]. 812 * @return F' = [p'_1,...,p'_k]. 813 */ 814 public List<GenPolynomial<C>> normalizeFactorization(List<GenPolynomial<C>> F) { 815 if (F == null || F.size() <= 1) { 816 return F; 817 } 818 List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.size()); 819 GenPolynomial<C> f0 = F.get(0); 820 for (int i = 1; i < F.size(); i++) { 821 GenPolynomial<C> fi = F.get(i); 822 if (fi.signum() < 0) { 823 fi = fi.negate(); 824 f0 = f0.negate(); 825 } 826 Fp.add(fi); 827 } 828 if (!f0.isONE()) { 829 Fp.add(0, f0); 830 } 831 return Fp; 832 } 833}