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