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