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