001/* 002 * $Id: SquarefreeAbstract.java 5963 2018-11-11 12:42:14Z 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.TreeMap; 013 014import org.apache.logging.log4j.Logger; 015import org.apache.logging.log4j.LogManager; 016 017import edu.jas.poly.GenPolynomial; 018import edu.jas.poly.GenPolynomialRing; 019import edu.jas.poly.PolyUtil; 020import edu.jas.structure.GcdRingElem; 021import edu.jas.structure.RingFactory; 022 023 024/** 025 * Abstract squarefree decomposition class. 026 * @author Heinz Kredel 027 */ 028 029public abstract class SquarefreeAbstract<C extends GcdRingElem<C>> implements Squarefree<C> { 030 031 032 private static final Logger logger = LogManager.getLogger(SquarefreeAbstract.class); 033 034 035 /** 036 * GCD engine for respective base coefficients. 037 */ 038 protected final GreatestCommonDivisorAbstract<C> engine; 039 040 041 /** 042 * Constructor. 043 */ 044 public SquarefreeAbstract(GreatestCommonDivisorAbstract<C> engine) { 045 this.engine = engine; 046 } 047 048 049 /** 050 * GenPolynomial polynomial greatest squarefree divisor. 051 * @param P GenPolynomial. 052 * @return squarefree(pp(P)). 053 */ 054 public abstract GenPolynomial<C> baseSquarefreePart(GenPolynomial<C> P); 055 056 057 /** 058 * GenPolynomial polynomial squarefree factorization. 059 * @param A GenPolynomial. 060 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 061 * p_i^{e_i} and p_i squarefree. 062 */ 063 public abstract SortedMap<GenPolynomial<C>, Long> baseSquarefreeFactors(GenPolynomial<C> A); 064 065 066 /** 067 * GenPolynomial recursive polynomial greatest squarefree divisor. 068 * @param P recursive univariate GenPolynomial. 069 * @return squarefree(pp(P)). 070 */ 071 public abstract GenPolynomial<GenPolynomial<C>> recursiveUnivariateSquarefreePart( 072 GenPolynomial<GenPolynomial<C>> P); 073 074 075 /** 076 * GenPolynomial recursive univariate polynomial squarefree factorization. 077 * @param P recursive univariate GenPolynomial. 078 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 079 * p_i^{e_i} and p_i squarefree. 080 */ 081 public abstract SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveUnivariateSquarefreeFactors( 082 GenPolynomial<GenPolynomial<C>> P); 083 084 085 /** 086 * GenPolynomial greatest squarefree divisor. 087 * @param P GenPolynomial. 088 * @return squarefree(P) a primitive respectively monic polynomial. 089 */ 090 public abstract GenPolynomial<C> squarefreePart(GenPolynomial<C> P); 091 092 093 /** 094 * GenPolynomial test if is squarefree. 095 * @param P GenPolynomial. 096 * @return true if P is squarefree, else false. 097 */ 098 public boolean isSquarefree(GenPolynomial<C> P) { 099 GenPolynomial<C> S = squarefreePart(P); 100 GenPolynomial<C> Ps = P; 101 if (P.ring.coFac.isField()) { 102 Ps = Ps.monic(); 103 } else { 104 Ps = engine.basePrimitivePart(Ps); 105 } 106 boolean f = Ps.equals(S); 107 return f; 108 } 109 110 111 /** 112 * GenPolynomial list test if squarefree. 113 * @param L list of GenPolynomial. 114 * @return true if each P in L is squarefree, else false. 115 */ 116 public boolean isSquarefree(List<GenPolynomial<C>> L) { 117 if (L == null || L.isEmpty()) { 118 return true; 119 } 120 for (GenPolynomial<C> P : L) { 121 if (!isSquarefree(P)) { 122 return false; 123 } 124 } 125 return true; 126 } 127 128 129 /** 130 * Recursive GenPolynomial test if is squarefree. 131 * @param P recursive univariate GenPolynomial. 132 * @return true if P is squarefree, else false. 133 */ 134 public boolean isRecursiveSquarefree(GenPolynomial<GenPolynomial<C>> P) { 135 GenPolynomial<GenPolynomial<C>> S = recursiveUnivariateSquarefreePart(P); 136 boolean f = P.equals(S); 137 if (!f) { 138 logger.info("not Squarefree, S != P: " + P + " != " + S); 139 } 140 return f; 141 } 142 143 144 /** 145 * GenPolynomial squarefree factorization. 146 * @param P GenPolynomial. 147 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 148 * p_i^{e_i} and p_i squarefree. 149 */ 150 public abstract SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P); 151 152 153 /** 154 * GenPolynomial squarefree and co-prime list. 155 * @param A list of GenPolynomials. 156 * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant 157 * a in A there exists b in B with b|a and each b in B is 158 * squarefree. B does not contain zero or constant polynomials. 159 */ 160 public List<GenPolynomial<C>> coPrimeSquarefree(List<GenPolynomial<C>> A) { 161 if (A == null || A.isEmpty()) { 162 return A; 163 } 164 List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>(); 165 for (GenPolynomial<C> g : A) { 166 SortedMap<GenPolynomial<C>, Long> sm = squarefreeFactors(g); 167 S.addAll(sm.keySet()); 168 } 169 List<GenPolynomial<C>> B = engine.coPrime(S); 170 return B; 171 } 172 173 174 /** 175 * GenPolynomial squarefree and co-prime list. 176 * @param a polynomial. 177 * @param P squarefree co-prime list of GenPolynomials. 178 * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a 179 * there exists b in P with b|a. B does not contain zero or constant 180 * polynomials. 181 */ 182 public List<GenPolynomial<C>> coPrimeSquarefree(GenPolynomial<C> a, List<GenPolynomial<C>> P) { 183 if (a == null || a.isZERO() || a.isConstant()) { 184 return P; 185 } 186 SortedMap<GenPolynomial<C>, Long> sm = squarefreeFactors(a); 187 List<GenPolynomial<C>> B = P; 188 for (GenPolynomial<C> f : sm.keySet()) { 189 B = engine.coPrime(f, B); 190 } 191 return B; 192 } 193 194 195 /** 196 * Test if list of GenPolynomials is squarefree and co-prime. 197 * @param B list of GenPolynomials. 198 * @return true, if for all b != c in B gcd(b,c) = 1 and each b in B is 199 * squarefree, else false. 200 */ 201 public boolean isCoPrimeSquarefree(List<GenPolynomial<C>> B) { 202 if (B == null || B.isEmpty()) { 203 return true; 204 } 205 if (!engine.isCoPrime(B)) { 206 return false; 207 } 208 return isSquarefree(B); 209 } 210 211 212 /** 213 * Normalize factorization. p'_i > 0 for i > 1 and p'_1 != 1 if k > 214 * 1. 215 * @param F = [p_1->e_1;, ..., p_k->e_k]. 216 * @return F' = [p'_1->e_1, ..., p'_k->e_k]. 217 */ 218 public SortedMap<GenPolynomial<C>, Long> normalizeFactorization(SortedMap<GenPolynomial<C>, Long> F) { 219 if (F == null || F.size() <= 1) { 220 return F; 221 } 222 List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.keySet()); 223 GenPolynomial<C> f0 = Fp.get(0); 224 if (f0.ring.characteristic().signum() != 0) { // only ordered coefficients 225 return F; 226 } 227 long e0 = F.get(f0); 228 SortedMap<GenPolynomial<C>, Long> Sp = new TreeMap<GenPolynomial<C>, Long>(); 229 for (int i = 1; i < Fp.size(); i++) { 230 GenPolynomial<C> fi = Fp.get(i); 231 long ei = F.get(fi); 232 if (fi.signum() < 0) { 233 //System.out.println("e0 = " + e0 + ", f0 = " + f0); 234 //System.out.println("ei = " + ei + ", fi = " + fi); 235 if (ei % 2 != 0 && e0 % 2 != 0) { // bug 236 fi = fi.negate(); 237 f0 = f0.negate(); 238 } 239 } 240 Sp.put(fi, ei); 241 } 242 if (!f0.isONE()) { 243 Sp.put(f0, e0); 244 } 245 return Sp; 246 } 247 248 249 /** 250 * GenPolynomial is (squarefree) factorization. 251 * @param P GenPolynomial. 252 * @param F = [p_1,...,p_k]. 253 * @return true if P = prod_{i=1,...,r} p_i, else false. 254 */ 255 public boolean isFactorization(GenPolynomial<C> P, List<GenPolynomial<C>> F) { 256 if (P == null || F == null) { 257 throw new IllegalArgumentException("P and F may not be null"); 258 } 259 GenPolynomial<C> t = P.ring.getONE(); 260 for (GenPolynomial<C> f : F) { 261 t = t.multiply(f); 262 } 263 boolean f = P.equals(t) || P.equals(t.negate()); 264 if (!f) { 265 logger.info("no factorization(list): F = " + F + ", P = " + P + ", t = " + t); 266 } 267 return f; 268 } 269 270 271 /** 272 * Count number of factors in a (squarefree) factorization. 273 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 274 * @return sum_{i=1,...,k} e_i. 275 */ 276 public long factorCount(SortedMap<GenPolynomial<C>, Long> F) { 277 if (F == null || F.isEmpty()) { 278 return 0L; 279 } 280 long f = 0L; 281 for (Long e : F.values()) { 282 f += e; 283 } 284 return f; 285 } 286 287 288 /** 289 * GenPolynomial is (squarefree) factorization. 290 * @param P GenPolynomial. 291 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 292 * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. 293 */ 294 public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) { 295 if (P == null || F == null) { 296 throw new IllegalArgumentException("P and F may not be null"); 297 } 298 if (P.isZERO() && F.size() == 0) { 299 return true; 300 } 301 GenPolynomial<C> t = P.ring.getONE(); 302 for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) { 303 GenPolynomial<C> f = me.getKey(); 304 Long E = me.getValue(); 305 long e = E.longValue(); 306 GenPolynomial<C> g = f.power(e); 307 t = t.multiply(g); 308 } 309 boolean f = P.equals(t) || P.equals(t.negate()); 310 if (!f) { 311 P = P.monic(); 312 t = t.monic(); 313 f = P.equals(t) || P.equals(t.negate()); 314 if (f) { 315 return f; 316 } 317 logger.info("no factorization(map): F = " + F + ", P = " + P + ", t = " + t); 318 //RuntimeException e = new RuntimeException("fac-map"); 319 //e.printStackTrace(); 320 //throw e; 321 } 322 return f; 323 } 324 325 326 /** 327 * GenPolynomial is (squarefree) factorization. 328 * @param P GenPolynomial. 329 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 330 * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. 331 */ 332 public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P, 333 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) { 334 if (P == null || F == null) { 335 throw new IllegalArgumentException("P and F may not be null"); 336 } 337 if (P.isZERO() && F.size() == 0) { 338 return true; 339 } 340 GenPolynomial<GenPolynomial<C>> t = P.ring.getONE(); 341 for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> me : F.entrySet()) { 342 GenPolynomial<GenPolynomial<C>> f = me.getKey(); 343 Long E = me.getValue(); // F.get(f); 344 long e = E.longValue(); 345 GenPolynomial<GenPolynomial<C>> g = f.power(e); 346 t = t.multiply(g); 347 } 348 boolean f = P.equals(t) || P.equals(t.negate()); 349 if (!f) { 350 GenPolynomialRing<C> cf = (GenPolynomialRing<C>) P.ring.coFac; 351 GreatestCommonDivisorAbstract<C> engine = GCDFactory.getProxy(cf.coFac); 352 GenPolynomial<GenPolynomial<C>> Pp = engine.recursivePrimitivePart(P); 353 Pp = PolyUtil.<C> monic(Pp); 354 GenPolynomial<GenPolynomial<C>> tp = engine.recursivePrimitivePart(t); 355 tp = PolyUtil.<C> monic(tp); 356 f = Pp.equals(tp) || Pp.equals(tp.negate()); 357 if (f) { 358 return f; 359 } 360 logger.info("no factorization(map): F = " + F + ", P = " + P + ", t = " + t 361 + ", Pp = " + Pp + ", tp = " + tp); 362 //RuntimeException e = new RuntimeException("fac-map"); 363 //e.printStackTrace(); 364 //throw e; 365 } 366 return f; 367 } 368 369 370 /** 371 * GenPolynomial recursive polynomial greatest squarefree divisor. 372 * @param P recursive GenPolynomial. 373 * @return squarefree(pp(P)). 374 */ 375 public GenPolynomial<GenPolynomial<C>> recursiveSquarefreePart(GenPolynomial<GenPolynomial<C>> P) { 376 if (P == null || P.isZERO()) { 377 return P; 378 } 379 if (P.ring.nvar <= 1) { 380 return recursiveUnivariateSquarefreePart(P); 381 } 382 // distributed polynomials squarefree part 383 GenPolynomialRing<GenPolynomial<C>> rfac = P.ring; 384 RingFactory<GenPolynomial<C>> rrfac = rfac.coFac; 385 GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac; 386 GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar); 387 GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P); 388 GenPolynomial<C> Dd = squarefreePart(Pd); 389 // convert to recursive 390 GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd); 391 return C; 392 } 393 394 395 /** 396 * GenPolynomial recursive polynomial squarefree factorization. 397 * @param P recursive GenPolynomial. 398 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 399 * p_i^{e_i} and p_i squarefree. 400 */ 401 public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveSquarefreeFactors( 402 GenPolynomial<GenPolynomial<C>> P) { 403 SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors; 404 factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>(); 405 if (P == null || P.isZERO()) { 406 return factors; 407 } 408 if (P.ring.nvar <= 1) { 409 return recursiveUnivariateSquarefreeFactors(P); 410 } 411 // distributed polynomials squarefree part 412 GenPolynomialRing<GenPolynomial<C>> rfac = P.ring; 413 RingFactory<GenPolynomial<C>> rrfac = rfac.coFac; 414 GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac; 415 GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar); 416 GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P); 417 SortedMap<GenPolynomial<C>, Long> dfacs = squarefreeFactors(Pd); 418 // convert to recursive 419 for (Map.Entry<GenPolynomial<C>, Long> Dm : dfacs.entrySet()) { 420 GenPolynomial<C> Dd = Dm.getKey(); 421 Long e = Dm.getValue(); 422 GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd); 423 factors.put(C, e); 424 } 425 return factors; 426 } 427 428 429 /** 430 * Univariate GenPolynomial partial fraction decomposition. 431 * @param A univariate GenPolynomial. 432 * @param D sorted map [d_1 -> e_1, ..., d_k -> e_k] with d_i 433 * squarefree. 434 * @return [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] with A/prod(D) = A0 + sum( 435 * sum ( Aij/di^j ) ) with deg(Aij) < deg(di). 436 */ 437 public List<List<GenPolynomial<C>>> basePartialFraction(GenPolynomial<C> A, 438 SortedMap<GenPolynomial<C>, Long> D) { 439 if (D == null || A == null) { 440 throw new IllegalArgumentException("null A or D not allowed"); 441 } 442 List<List<GenPolynomial<C>>> pf = new ArrayList<List<GenPolynomial<C>>>(D.size() + 1); 443 if (D.size() == 0) { 444 return pf; 445 } 446 //List<GenPolynomial<C>> fi; 447 if (A.isZERO()) { 448 for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { 449 long e = me.getValue(); 450 int e1 = (int) e + 1; 451 List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(e1); 452 for (int i = 0; i < e1; i++) { 453 fi.add(A); 454 } 455 pf.add(fi); 456 } 457 List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1); 458 fi.add(A); 459 pf.add(0, fi); 460 return pf; 461 } 462 // A != 0, D != empty 463 List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size()); 464 for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { 465 GenPolynomial<C> d = me.getKey(); 466 long e = me.getValue(); //D.get(d); 467 GenPolynomial<C> f = d.power(e); 468 Dp.add(f); 469 } 470 List<GenPolynomial<C>> F = engine.basePartialFraction(A, Dp); 471 //System.out.println("fraction list = " + F.size()); 472 GenPolynomial<C> A0 = F.remove(0); 473 List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1); 474 fi.add(A0); 475 pf.add(fi); 476 int i = 0; 477 for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order 478 GenPolynomial<C> d = me.getKey(); 479 long e = me.getValue(); 480 int ei = (int) e; 481 GenPolynomial<C> gi = F.get(i); // assume fixed sequence order 482 List<GenPolynomial<C>> Fi = engine.basePartialFraction(gi, d, ei); 483 pf.add(Fi); 484 i++; 485 } 486 return pf; 487 } 488 489 490 /** 491 * Test for Univariate GenPolynomial partial fraction decomposition. 492 * @param A univariate GenPolynomial. 493 * @param D sorted map [d_1 -> e_1, ..., d_k -> e_k] with d_i 494 * squarefree. 495 * @param F a list of lists [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] 496 * @return true, if A/prod(D) = A0 + sum( sum ( Aij/di^j ) ), else false. 497 */ 498 public boolean isBasePartialFraction(GenPolynomial<C> A, SortedMap<GenPolynomial<C>, Long> D, 499 List<List<GenPolynomial<C>>> F) { 500 if (D == null || A == null || F == null) { 501 throw new IllegalArgumentException("null A, D or F not allowed"); 502 } 503 if (D.isEmpty() && F.isEmpty()) { 504 return true; 505 } 506 if (D.isEmpty() || F.isEmpty()) { 507 return false; 508 } 509 List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size()); 510 for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { 511 GenPolynomial<C> d = me.getKey(); 512 long e = me.getValue(); // D.get(d); 513 GenPolynomial<C> f = d.power(e); 514 Dp.add(f); 515 } 516 List<GenPolynomial<C>> fi = F.get(0); 517 if (fi.size() != 1) { 518 logger.info("size(fi) != 1 " + fi); 519 return false; 520 } 521 boolean t; 522 GenPolynomial<C> A0 = fi.get(0); 523 //System.out.println("A0 = " + A0); 524 List<GenPolynomial<C>> Qp = new ArrayList<GenPolynomial<C>>(D.size() + 1); 525 Qp.add(A0); 526 527 // List<GenPolynomial<C>> Fp = engine.basePartialFraction(A,Dp); 528 // System.out.println("fraction list = " + F.size()); 529 // t = engine.isBasePartialFraction(A,Dp,Fp); 530 // if ( ! t ) { 531 // System.out.println("not recursion isPartFrac = " + Fp); 532 // return false; 533 // } 534 // GenPolynomial<C> A0p = Fp.remove(0); 535 // if ( ! A0.equals(A0p) ) { 536 // System.out.println("A0 != A0p " + A0p); 537 // return false; 538 // } 539 540 int i = 0; 541 for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order 542 GenPolynomial<C> d = me.getKey(); 543 long e = me.getValue(); 544 int ei = (int) e; 545 List<GenPolynomial<C>> Fi = F.get(i + 1); // assume fixed sequence order 546 547 // GenPolynomial<C> pi = Fp.get(i); // assume fixed sequence order 548 // t = engine.isBasePartialFraction(pi,d,ei,Fi); 549 // if ( ! t ) { 550 // System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei); 551 // System.out.println("not isPartFrac exp = " + Fi); 552 // return false; 553 // } 554 555 GenPolynomial<C> qi = engine.basePartialFractionValue(d, ei, Fi); 556 Qp.add(qi); 557 558 // t = qi.equals(pi); 559 // if ( ! t ) { 560 // System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei + ", qi = " + qi); 561 // } 562 563 i++; 564 } 565 566 t = engine.isBasePartialFraction(A, Dp, Qp); 567 if (!t) { 568 System.out.println("not final isPartFrac " + Qp); 569 } 570 return t; 571 } 572 573 574 /** 575 * Coefficients greatest squarefree divisor. 576 * @param P coefficient. 577 * @return squarefree part of P. 578 */ 579 public C squarefreePart(C P) { 580 if (P == null) { 581 return null; 582 } 583 C s = null; 584 SortedMap<C, Long> factors = squarefreeFactors(P); 585 //if (logger.isWarnEnabled()) { 586 // logger.warn("sqfPart, better use sqfFactors, factors = " + factors); 587 //} 588 for (C sp : factors.keySet()) { 589 if (s == null) { 590 s = sp; 591 } else { 592 s = s.multiply(sp); 593 } 594 } 595 return s; 596 } 597 598 599 /** 600 * Coefficients squarefree factorization. 601 * @param P coefficient. 602 * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} 603 * p_i^{e_i} and p_i squarefree. 604 */ 605 public abstract SortedMap<C, Long> squarefreeFactors(C P); 606 /* not possible: 607 { 608 if (P == null) { 609 return null; 610 } 611 SortedMap<C, Long> factors = new TreeMap<C, Long>(); 612 SquarefreeAbstract<C> reng = SquarefreeFactory.getImplementation((RingFactory<C>) P.factory()); 613 System.out.println("fcp,reng = " + reng); 614 SortedMap<C, Long> rfactors = reng.squarefreeFactors(P); 615 for (C c : rfactors.keySet()) { 616 if (!c.isONE()) { 617 C cr = (C) (Object) c; 618 Long rk = rfactors.get(c); 619 factors.put(cr, rk); 620 } 621 } 622 623 return factors; 624 } 625 */ 626 627}