001/* 002 * $Id: PolyUfdUtil.java 4125 2012-08-19 19:05:22Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.Collection; 010import java.util.List; 011import java.util.Map; 012 013import org.apache.log4j.Logger; 014 015import edu.jas.arith.BigInteger; 016import edu.jas.poly.AlgebraicNumber; 017import edu.jas.poly.AlgebraicNumberRing; 018import edu.jas.poly.ExpVector; 019import edu.jas.poly.GenPolynomial; 020import edu.jas.poly.GenPolynomialRing; 021import edu.jas.poly.PolyUtil; 022import edu.jas.structure.GcdRingElem; 023import edu.jas.structure.RingElem; 024import edu.jas.structure.RingFactory; 025import edu.jas.structure.UnaryFunctor; 026import edu.jas.util.ListUtil; 027 028 029/** 030 * Polynomial ufd utilities, like conversion between different representations 031 * and Hensel lifting. 032 * @author Heinz Kredel 033 */ 034 035public class PolyUfdUtil { 036 037 038 private static final Logger logger = Logger.getLogger(PolyUfdUtil.class); 039 040 041 private static boolean debug = logger.isDebugEnabled(); 042 043 044 /** 045 * Integral polynomial from rational function coefficients. Represent as 046 * polynomial with integral polynomial coefficients by multiplication with 047 * the lcm of the numerators of the rational function coefficients. 048 * @param fac result polynomial factory. 049 * @param A polynomial with rational function coefficients to be converted. 050 * @return polynomial with integral polynomial coefficients. 051 */ 052 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> integralFromQuotientCoefficients( 053 GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<Quotient<C>> A) { 054 GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy(); 055 if (A == null || A.isZERO()) { 056 return B; 057 } 058 GenPolynomial<C> c = null; 059 GenPolynomial<C> d; 060 GenPolynomial<C> x; 061 GreatestCommonDivisor<C> ufd = new GreatestCommonDivisorSubres<C>(); 062 int s = 0; 063 // lcm of denominators 064 for (Quotient<C> y : A.getMap().values()) { 065 x = y.den; 066 // c = lcm(c,x) 067 if (c == null) { 068 c = x; 069 s = x.signum(); 070 } else { 071 d = ufd.gcd(c, x); 072 c = c.multiply(x.divide(d)); 073 } 074 } 075 if (s < 0) { 076 c = c.negate(); 077 } 078 for (Map.Entry<ExpVector, Quotient<C>> y : A.getMap().entrySet()) { 079 ExpVector e = y.getKey(); 080 Quotient<C> a = y.getValue(); 081 // p = n*(c/d) 082 GenPolynomial<C> b = c.divide(a.den); 083 GenPolynomial<C> p = a.num.multiply(b); 084 //B = B.sum( p, e ); // inefficient 085 B.doPutToMap(e, p); 086 } 087 return B; 088 } 089 090 091 /** 092 * Integral polynomial from rational function coefficients. Represent as 093 * polynomial with integral polynomial coefficients by multiplication with 094 * the lcm of the numerators of the rational function coefficients. 095 * @param fac result polynomial factory. 096 * @param L list of polynomial with rational function coefficients to be 097 * converted. 098 * @return list of polynomials with integral polynomial coefficients. 099 */ 100 public static <C extends GcdRingElem<C>> List<GenPolynomial<GenPolynomial<C>>> integralFromQuotientCoefficients( 101 GenPolynomialRing<GenPolynomial<C>> fac, Collection<GenPolynomial<Quotient<C>>> L) { 102 if (L == null) { 103 return null; 104 } 105 List<GenPolynomial<GenPolynomial<C>>> list = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size()); 106 for (GenPolynomial<Quotient<C>> p : L) { 107 list.add(integralFromQuotientCoefficients(fac, p)); 108 } 109 return list; 110 } 111 112 113 /** 114 * Rational function from integral polynomial coefficients. Represent as 115 * polynomial with type Quotient<C> coefficients. 116 * @param fac result polynomial factory. 117 * @param A polynomial with integral polynomial coefficients to be 118 * converted. 119 * @return polynomial with type Quotient<C> coefficients. 120 */ 121 public static <C extends GcdRingElem<C>> GenPolynomial<Quotient<C>> quotientFromIntegralCoefficients( 122 GenPolynomialRing<Quotient<C>> fac, GenPolynomial<GenPolynomial<C>> A) { 123 GenPolynomial<Quotient<C>> B = fac.getZERO().copy(); 124 if (A == null || A.isZERO()) { 125 return B; 126 } 127 RingFactory<Quotient<C>> cfac = fac.coFac; 128 QuotientRing<C> qfac = (QuotientRing<C>) cfac; 129 for (Map.Entry<ExpVector, GenPolynomial<C>> y : A.getMap().entrySet()) { 130 ExpVector e = y.getKey(); 131 GenPolynomial<C> a = y.getValue(); 132 Quotient<C> p = new Quotient<C>(qfac, a); // can not be zero 133 if (!p.isZERO()) { 134 //B = B.sum( p, e ); // inefficient 135 B.doPutToMap(e, p); 136 } 137 } 138 return B; 139 } 140 141 142 /** 143 * Rational function from integral polynomial coefficients. Represent as 144 * polynomial with type Quotient<C> coefficients. 145 * @param fac result polynomial factory. 146 * @param L list of polynomials with integral polynomial coefficients to be 147 * converted. 148 * @return list of polynomials with type Quotient<C> coefficients. 149 */ 150 public static <C extends GcdRingElem<C>> List<GenPolynomial<Quotient<C>>> quotientFromIntegralCoefficients( 151 GenPolynomialRing<Quotient<C>> fac, Collection<GenPolynomial<GenPolynomial<C>>> L) { 152 if (L == null) { 153 return null; 154 } 155 List<GenPolynomial<Quotient<C>>> list = new ArrayList<GenPolynomial<Quotient<C>>>(L.size()); 156 for (GenPolynomial<GenPolynomial<C>> p : L) { 157 list.add(quotientFromIntegralCoefficients(fac, p)); 158 } 159 return list; 160 } 161 162 163 /** 164 * From BigInteger coefficients. Represent as polynomial with type 165 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 166 * @param fac result polynomial factory. 167 * @param A polynomial with GenPolynomial<BigInteger> coefficients to 168 * be converted. 169 * @return polynomial with type GenPolynomial<C> coefficients. 170 */ 171 public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> fromIntegerCoefficients( 172 GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<GenPolynomial<BigInteger>> A) { 173 GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy(); 174 if (A == null || A.isZERO()) { 175 return B; 176 } 177 RingFactory<GenPolynomial<C>> cfac = fac.coFac; 178 GenPolynomialRing<C> rfac = (GenPolynomialRing<C>) cfac; 179 for (Map.Entry<ExpVector, GenPolynomial<BigInteger>> y : A.getMap().entrySet()) { 180 ExpVector e = y.getKey(); 181 GenPolynomial<BigInteger> a = y.getValue(); 182 GenPolynomial<C> p = PolyUtil.<C> fromIntegerCoefficients(rfac, a); 183 if (!p.isZERO()) { 184 //B = B.sum( p, e ); // inefficient 185 B.doPutToMap(e, p); 186 } 187 } 188 return B; 189 } 190 191 192 /** 193 * From BigInteger coefficients. Represent as polynomial with type 194 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 195 * @param fac result polynomial factory. 196 * @param L polynomial list with GenPolynomial<BigInteger> 197 * coefficients to be converted. 198 * @return polynomial list with polynomials with type GenPolynomial<C> 199 * coefficients. 200 */ 201 public static <C extends RingElem<C>> List<GenPolynomial<GenPolynomial<C>>> fromIntegerCoefficients( 202 GenPolynomialRing<GenPolynomial<C>> fac, List<GenPolynomial<GenPolynomial<BigInteger>>> L) { 203 List<GenPolynomial<GenPolynomial<C>>> K = null; 204 if (L == null) { 205 return K; 206 } 207 K = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size()); 208 if (L.size() == 0) { 209 return K; 210 } 211 for (GenPolynomial<GenPolynomial<BigInteger>> a : L) { 212 GenPolynomial<GenPolynomial<C>> b = fromIntegerCoefficients(fac, a); 213 K.add(b); 214 } 215 return K; 216 } 217 218 219 /** 220 * Introduce lower variable. Represent as polynomial with type 221 * GenPolynomial<C> coefficients. 222 * @param rfac result polynomial factory. 223 * @param A polynomial to be extended. 224 * @return polynomial with type GenPolynomial<C> coefficients. 225 */ 226 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> introduceLowerVariable( 227 GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<C> A) { 228 if (A == null || rfac == null) { 229 return null; 230 } 231 GenPolynomial<GenPolynomial<C>> Pc = rfac.getONE().multiply(A); 232 if (Pc.isZERO()) { 233 return Pc; 234 } 235 Pc = PolyUtil.<C> switchVariables(Pc); 236 return Pc; 237 } 238 239 240 /** 241 * From AlgebraicNumber coefficients. Represent as polynomial with type 242 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 243 * @param rfac result polynomial factory. 244 * @param A polynomial with AlgebraicNumber coefficients to be converted. 245 * @param k for (y-k x) substitution. 246 * @return polynomial with type GenPolynomial<C> coefficients. 247 */ 248 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> substituteFromAlgebraicCoefficients( 249 GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<AlgebraicNumber<C>> A, long k) { 250 if (A == null || rfac == null) { 251 return null; 252 } 253 if (A.isZERO()) { 254 return rfac.getZERO(); 255 } 256 // setup x - k alpha 257 GenPolynomialRing<AlgebraicNumber<C>> apfac = A.ring; 258 GenPolynomial<AlgebraicNumber<C>> x = apfac.univariate(0); 259 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) A.ring.coFac; 260 AlgebraicNumber<C> alpha = afac.getGenerator(); 261 AlgebraicNumber<C> ka = afac.fromInteger(k); 262 GenPolynomial<AlgebraicNumber<C>> s = x.subtract(ka.multiply(alpha)); // x - k alpha 263 if (debug) { 264 logger.info("x - k alpha: " + s); 265 } 266 // substitute, convert and switch 267 GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<AlgebraicNumber<C>> substituteMain(A, s); 268 GenPolynomial<GenPolynomial<C>> Pc = PolyUtil.<C> fromAlgebraicCoefficients(rfac, B); // Q[alpha][x] 269 Pc = PolyUtil.<C> switchVariables(Pc); // Q[x][alpha] 270 return Pc; 271 } 272 273 274 /** 275 * Convert to AlgebraicNumber coefficients. Represent as polynomial with 276 * AlgebraicNumber<C> coefficients, C is e.g. ModInteger or BigRational. 277 * @param pfac result polynomial factory. 278 * @param A polynomial with GenPolynomial<BigInteger> coefficients to 279 * be converted. 280 * @param k for (y-k x) substitution. 281 * @return polynomial with AlgebraicNumber<C> coefficients. 282 */ 283 public static <C extends GcdRingElem<C>> GenPolynomial<AlgebraicNumber<C>> substituteConvertToAlgebraicCoefficients( 284 GenPolynomialRing<AlgebraicNumber<C>> pfac, GenPolynomial<C> A, long k) { 285 if (A == null || pfac == null) { 286 return null; 287 } 288 if (A.isZERO()) { 289 return pfac.getZERO(); 290 } 291 // convert to Q(alpha)[x] 292 GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<C> convertToAlgebraicCoefficients(pfac, A); 293 // setup x .+. k alpha for back substitution 294 GenPolynomial<AlgebraicNumber<C>> x = pfac.univariate(0); 295 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac; 296 AlgebraicNumber<C> alpha = afac.getGenerator(); 297 AlgebraicNumber<C> ka = afac.fromInteger(k); 298 GenPolynomial<AlgebraicNumber<C>> s = x.sum(ka.multiply(alpha)); // x + k alpha 299 // substitute 300 GenPolynomial<AlgebraicNumber<C>> N = PolyUtil.<AlgebraicNumber<C>> substituteMain(B, s); 301 return N; 302 } 303 304 305 /** 306 * Norm of a polynomial with AlgebraicNumber coefficients. 307 * @param A polynomial from GenPolynomial<AlgebraicNumber<C>>. 308 * @param k for (y - k x) substitution. 309 * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing<C>. 310 */ 311 public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A, long k) { 312 if (A == null) { 313 return null; 314 } 315 GenPolynomialRing<AlgebraicNumber<C>> pfac = A.ring; // Q(alpha)[x] 316 if (pfac.nvar > 1) { 317 throw new IllegalArgumentException("only for univariate polynomials"); 318 } 319 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac; 320 GenPolynomial<C> agen = afac.modul; 321 GenPolynomialRing<C> cfac = afac.ring; 322 if (A.isZERO()) { 323 return cfac.getZERO(); 324 } 325 AlgebraicNumber<C> ldcf = A.leadingBaseCoefficient(); 326 if (!ldcf.isONE()) { 327 A = A.monic(); 328 } 329 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pfac); 330 331 // transform minimal polynomial to bi-variate polynomial 332 GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, agen); 333 //System.out.println("Ac = " + Ac.toScript()); 334 335 // transform to bi-variate polynomial, 336 // switching varaible sequence from Q[alpha][x] to Q[X][alpha] 337 GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> substituteFromAlgebraicCoefficients(rfac, A, k); 338 Pc = PolyUtil.<C> monic(Pc); 339 //System.out.println("Pc = " + Pc.toScript()); 340 341 GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>( /*cfac.coFac*/); 342 // = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( cfac.coFac ); 343 344 GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveUnivariateResultant(Pc, Ac); 345 //System.out.println("Rc = " + Rc.toScript()); 346 GenPolynomial<C> res = Rc.leadingBaseCoefficient(); 347 res = res.monic(); 348 return res; 349 } 350 351 352 /** 353 * Norm of a polynomial with AlgebraicNumber coefficients. 354 * @param A polynomial from GenPolynomial<AlgebraicNumber<C>>. 355 * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y]. 356 */ 357 public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A) { 358 return norm(A, 0L); 359 } 360 361 362 /** 363 * Ensure that the field property is determined. Checks if modul is 364 * irreducible and modifies the algebraic number ring. 365 * @param afac algebraic number ring. 366 */ 367 public static <C extends GcdRingElem<C>> void ensureFieldProperty(AlgebraicNumberRing<C> afac) { 368 if (afac.getField() != -1) { 369 return; 370 } 371 if (!afac.ring.coFac.isField()) { 372 afac.setField(false); 373 return; 374 } 375 Factorization<C> mf = FactorFactory.<C> getImplementation(afac.ring); 376 if (mf.isIrreducible(afac.modul)) { 377 afac.setField(true); 378 } else { 379 afac.setField(false); 380 } 381 } 382 383 384 /** 385 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a 386 * univariate polynomial. 387 * @param A polynomial to be converted. 388 * @return a univariate polynomial. 389 */ 390 public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A) { 391 if (A == null) { 392 return A; 393 } 394 long d = A.degree() + 1L; 395 return substituteKronecker(A, d); 396 } 397 398 399 /** 400 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a 401 * univariate polynomial. 402 * @param A polynomial to be converted. 403 * @return a univariate polynomial. 404 */ 405 public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A, long d) { 406 if (A == null) { 407 return A; 408 } 409 RingFactory<C> cfac = A.ring.coFac; 410 GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1); 411 GenPolynomial<C> B = ufac.getZERO().copy(); 412 if (A.isZERO()) { 413 return B; 414 } 415 for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) { 416 ExpVector e = y.getKey(); 417 C a = y.getValue(); 418 long f = 0L; 419 long h = 1L; 420 for (int i = 0; i < e.length(); i++) { 421 long j = e.getVal(i) * h; 422 f += j; 423 h *= d; 424 } 425 ExpVector g = ExpVector.create(1, 0, f); 426 B.doPutToMap(g, a); 427 } 428 return B; 429 } 430 431 432 /** 433 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a 434 * univariate polynomials. 435 * @param A list of polynomials to be converted. 436 * @return a list of univariate polynomials. 437 */ 438 public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> substituteKronecker( 439 List<GenPolynomial<C>> A, int d) { 440 if (A == null || A.get(0) == null) { 441 return null; 442 } 443 return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new SubstKronecker<C>(d)); 444 } 445 446 447 /** 448 * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a 449 * multivariate polynomial. 450 * @param A polynomial to be converted. 451 * @param fac result polynomial factory. 452 * @return a multivariate polynomial. 453 */ 454 public static <C extends GcdRingElem<C>> GenPolynomial<C> backSubstituteKronecker( 455 GenPolynomialRing<C> fac, GenPolynomial<C> A, long d) { 456 if (A == null) { 457 return A; 458 } 459 if (fac == null) { 460 throw new IllegalArgumentException("null factory not allowed "); 461 } 462 int n = fac.nvar; 463 GenPolynomial<C> B = fac.getZERO().copy(); 464 if (A.isZERO()) { 465 return B; 466 } 467 for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) { 468 ExpVector e = y.getKey(); 469 C a = y.getValue(); 470 long f = e.getVal(0); 471 ExpVector g = ExpVector.create(n); 472 for (int i = 0; i < n; i++) { 473 long j = f % d; 474 f /= d; 475 g = g.subst(i, j); 476 } 477 B.doPutToMap(g, a); 478 } 479 return B; 480 } 481 482 483 /** 484 * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a 485 * multivariate polynomials. 486 * @param A list of polynomials to be converted. 487 * @param fac result polynomial factory. 488 * @return a list of multivariate polynomials. 489 */ 490 public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> backSubstituteKronecker( 491 GenPolynomialRing<C> fac, List<GenPolynomial<C>> A, long d) { 492 return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new BackSubstKronecker<C>(fac, d)); 493 } 494 495} 496 497 498/** 499 * Kronecker substitutuion functor. 500 */ 501class SubstKronecker<C extends GcdRingElem<C>> implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> { 502 503 504 final long d; 505 506 507 public SubstKronecker(long d) { 508 this.d = d; 509 } 510 511 512 public GenPolynomial<C> eval(GenPolynomial<C> c) { 513 if (c == null) { 514 return null; 515 } 516 return PolyUfdUtil.<C> substituteKronecker(c, d); 517 } 518} 519 520 521/** 522 * Kronecker back substitutuion functor. 523 */ 524class BackSubstKronecker<C extends GcdRingElem<C>> implements 525 UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> { 526 527 528 final long d; 529 530 531 final GenPolynomialRing<C> fac; 532 533 534 public BackSubstKronecker(GenPolynomialRing<C> fac, long d) { 535 this.d = d; 536 this.fac = fac; 537 } 538 539 540 public GenPolynomial<C> eval(GenPolynomial<C> c) { 541 if (c == null) { 542 return null; 543 } 544 return PolyUfdUtil.<C> backSubstituteKronecker(fac, c, d); 545 } 546}