001/* 002 * $Id$ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.Collection; 010import java.util.List; 011import java.util.Map; 012import java.util.SortedMap; 013import java.util.TreeMap; 014 015import org.apache.logging.log4j.LogManager; 016import org.apache.logging.log4j.Logger; 017 018import edu.jas.arith.BigInteger; 019import edu.jas.arith.BigRational; 020import edu.jas.poly.AlgebraicNumber; 021import edu.jas.poly.AlgebraicNumberRing; 022import edu.jas.poly.ExpVector; 023import edu.jas.poly.GenPolynomial; 024import edu.jas.poly.GenPolynomialRing; 025import edu.jas.poly.PolyUtil; 026import edu.jas.poly.TermOrderByName; 027import edu.jas.ps.UnivPowerSeries; 028import edu.jas.ps.UnivPowerSeriesRing; 029import edu.jas.structure.GcdRingElem; 030import edu.jas.structure.Power; 031import edu.jas.structure.RingElem; 032import edu.jas.structure.RingFactory; 033import edu.jas.structure.UnaryFunctor; 034import edu.jas.util.ListUtil; 035 036 037/** 038 * Polynomial ufd utilities. For example conversion between different 039 * representations and Kronecker substitution. 040 * @author Heinz Kredel 041 */ 042 043public class PolyUfdUtil { 044 045 046 private static final Logger logger = LogManager.getLogger(PolyUfdUtil.class); 047 048 049 private static final boolean debug = logger.isDebugEnabled(); 050 051 052 /** 053 * Factors of Quotient rational function. 054 * @param A rational function to be factored. 055 * @return list of irreducible rational function parts. 056 */ 057 public static <C extends GcdRingElem<C>> SortedMap<Quotient<C>, Long> factors(Quotient<C> A) { 058 SortedMap<Quotient<C>, Long> factors = new TreeMap<Quotient<C>, Long>(); 059 if (A == null || A.isZERO()) { 060 return factors; 061 } 062 if (A.abs().isONE()) { 063 factors.put(A, 1L); 064 return factors; 065 } 066 QuotientRing<C> qfac = A.ring; 067 GenPolynomialRing<C> fac = qfac.ring; 068 FactorAbstract<C> eng = FactorFactory.<C> getImplementation(fac.coFac); 069 GenPolynomial<C> n = A.num; 070 SortedMap<GenPolynomial<C>, Long> numfactors = eng.factors(n); 071 for (Map.Entry<GenPolynomial<C>, Long> me : numfactors.entrySet()) { 072 GenPolynomial<C> f = me.getKey(); 073 Long e = me.getValue(); 074 Quotient<C> q = new Quotient<C>(qfac, f); 075 factors.put(q, e); 076 } 077 GenPolynomial<C> d = A.den; 078 if (d.isONE()) { 079 return factors; 080 } 081 GenPolynomial<C> one = fac.getONE(); 082 SortedMap<GenPolynomial<C>, Long> denfactors = eng.factors(d); 083 for (Map.Entry<GenPolynomial<C>, Long> me : denfactors.entrySet()) { 084 GenPolynomial<C> f = me.getKey(); 085 Long e = me.getValue(); 086 Quotient<C> q = new Quotient<C>(qfac, one, f); 087 factors.put(q, e); 088 } 089 return factors; 090 } 091 092 093 /** 094 * Quotient is (squarefree) factorization. 095 * @param P Quotient. 096 * @param F = [p_1 -> e_1, ..., p_k -> e_k]. 097 * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. 098 */ 099 public static <C extends GcdRingElem<C>> boolean isFactorization(Quotient<C> P, 100 SortedMap<Quotient<C>, Long> F) { 101 if (P == null || F == null) { 102 throw new IllegalArgumentException("P and F may not be null"); 103 } 104 if (P.isZERO() && F.size() == 0) { 105 return true; 106 } 107 Quotient<C> t = P.ring.getONE(); 108 for (Map.Entry<Quotient<C>, Long> me : F.entrySet()) { 109 Quotient<C> f = me.getKey(); 110 Long E = me.getValue(); 111 long e = E.longValue(); 112 Quotient<C> g = f.power(e); 113 t = t.multiply(g); 114 } 115 boolean f = P.equals(t) || P.equals(t.negate()); 116 if (!f) { 117 P = P.monic(); 118 t = t.monic(); 119 f = P.equals(t) || P.equals(t.negate()); 120 if (f) { 121 return f; 122 } 123 logger.info("no factorization(map): F = {}, P = {}, t = {}", F, P, t); 124 } 125 return f; 126 } 127 128 129 /** 130 * Integral polynomial from rational function coefficients. Represent as 131 * polynomial with integral polynomial coefficients by multiplication with 132 * the lcm of the numerators of the rational function coefficients. 133 * @param fac result polynomial factory. 134 * @param A polynomial with rational function coefficients to be converted. 135 * @return polynomial with integral polynomial coefficients. 136 */ 137 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> integralFromQuotientCoefficients( 138 GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<Quotient<C>> A) { 139 GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy(); 140 if (A == null || A.isZERO()) { 141 return B; 142 } 143 GenPolynomial<C> c = null; 144 GenPolynomial<C> d; 145 GenPolynomial<C> x; 146 GreatestCommonDivisor<C> ufd = new GreatestCommonDivisorSubres<C>(); 147 int s = 0; 148 // lcm of denominators 149 for (Quotient<C> y : A.getMap().values()) { 150 x = y.den; 151 // c = lcm(c,x) 152 if (c == null) { 153 c = x; 154 s = x.signum(); 155 } else { 156 d = ufd.gcd(c, x); 157 c = c.multiply(x.divide(d)); 158 } 159 } 160 if (s < 0) { 161 c = c.negate(); 162 } 163 for (Map.Entry<ExpVector, Quotient<C>> y : A.getMap().entrySet()) { 164 ExpVector e = y.getKey(); 165 Quotient<C> a = y.getValue(); 166 // p = n*(c/d) 167 GenPolynomial<C> b = c.divide(a.den); 168 GenPolynomial<C> p = a.num.multiply(b); 169 //B = B.sum( p, e ); // inefficient 170 B.doPutToMap(e, p); 171 } 172 return B; 173 } 174 175 176 /** 177 * Integral polynomial from rational function coefficients. Represent as 178 * polynomial with integral polynomial coefficients by multiplication with 179 * the lcm of the numerators of the rational function coefficients. 180 * @param fac result polynomial factory. 181 * @param L list of polynomial with rational function coefficients to be 182 * converted. 183 * @return list of polynomials with integral polynomial coefficients. 184 */ 185 public static <C extends GcdRingElem<C>> List<GenPolynomial<GenPolynomial<C>>> integralFromQuotientCoefficients( 186 GenPolynomialRing<GenPolynomial<C>> fac, Collection<GenPolynomial<Quotient<C>>> L) { 187 if (L == null) { 188 return null; 189 } 190 List<GenPolynomial<GenPolynomial<C>>> list = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size()); 191 for (GenPolynomial<Quotient<C>> p : L) { 192 list.add(integralFromQuotientCoefficients(fac, p)); 193 } 194 return list; 195 } 196 197 198 /** 199 * Rational function from integral polynomial coefficients. Represent as 200 * polynomial with type Quotient<C> coefficients. 201 * @param fac result polynomial factory. 202 * @param A polynomial with integral polynomial coefficients to be 203 * converted. 204 * @return polynomial with type Quotient<C> coefficients. 205 */ 206 public static <C extends GcdRingElem<C>> GenPolynomial<Quotient<C>> quotientFromIntegralCoefficients( 207 GenPolynomialRing<Quotient<C>> fac, GenPolynomial<GenPolynomial<C>> A) { 208 GenPolynomial<Quotient<C>> B = fac.getZERO().copy(); 209 if (A == null || A.isZERO()) { 210 return B; 211 } 212 RingFactory<Quotient<C>> cfac = fac.coFac; 213 QuotientRing<C> qfac = (QuotientRing<C>) cfac; 214 for (Map.Entry<ExpVector, GenPolynomial<C>> y : A.getMap().entrySet()) { 215 ExpVector e = y.getKey(); 216 GenPolynomial<C> a = y.getValue(); 217 Quotient<C> p = new Quotient<C>(qfac, a); // can not be zero 218 if (!p.isZERO()) { 219 //B = B.sum( p, e ); // inefficient 220 B.doPutToMap(e, p); 221 } 222 } 223 return B; 224 } 225 226 227 /** 228 * Rational function from integral polynomial coefficients. Represent as 229 * polynomial with type Quotient<C> coefficients. 230 * @param fac result polynomial factory. 231 * @param L list of polynomials with integral polynomial coefficients to be 232 * converted. 233 * @return list of polynomials with type Quotient<C> coefficients. 234 */ 235 public static <C extends GcdRingElem<C>> List<GenPolynomial<Quotient<C>>> quotientFromIntegralCoefficients( 236 GenPolynomialRing<Quotient<C>> fac, Collection<GenPolynomial<GenPolynomial<C>>> L) { 237 if (L == null) { 238 return null; 239 } 240 List<GenPolynomial<Quotient<C>>> list = new ArrayList<GenPolynomial<Quotient<C>>>(L.size()); 241 for (GenPolynomial<GenPolynomial<C>> p : L) { 242 list.add(quotientFromIntegralCoefficients(fac, p)); 243 } 244 return list; 245 } 246 247 248 /** 249 * From BigInteger coefficients. Represent as polynomial with type 250 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 251 * @param fac result polynomial factory. 252 * @param A polynomial with GenPolynomial<BigInteger> coefficients to 253 * be converted. 254 * @return polynomial with type GenPolynomial<C> coefficients. 255 */ 256 public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> fromIntegerCoefficients( 257 GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<GenPolynomial<BigInteger>> A) { 258 GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy(); 259 if (A == null || A.isZERO()) { 260 return B; 261 } 262 RingFactory<GenPolynomial<C>> cfac = fac.coFac; 263 GenPolynomialRing<C> rfac = (GenPolynomialRing<C>) cfac; 264 for (Map.Entry<ExpVector, GenPolynomial<BigInteger>> y : A.getMap().entrySet()) { 265 ExpVector e = y.getKey(); 266 GenPolynomial<BigInteger> a = y.getValue(); 267 GenPolynomial<C> p = PolyUtil.<C> fromIntegerCoefficients(rfac, a); 268 if (!p.isZERO()) { 269 //B = B.sum( p, e ); // inefficient 270 B.doPutToMap(e, p); 271 } 272 } 273 return B; 274 } 275 276 277 /** 278 * From BigInteger coefficients. Represent as polynomial with type 279 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 280 * @param fac result polynomial factory. 281 * @param L polynomial list with GenPolynomial<BigInteger> 282 * coefficients to be converted. 283 * @return polynomial list with polynomials with type GenPolynomial<C> 284 * coefficients. 285 */ 286 public static <C extends RingElem<C>> List<GenPolynomial<GenPolynomial<C>>> fromIntegerCoefficients( 287 GenPolynomialRing<GenPolynomial<C>> fac, 288 List<GenPolynomial<GenPolynomial<BigInteger>>> L) { 289 List<GenPolynomial<GenPolynomial<C>>> K = null; 290 if (L == null) { 291 return K; 292 } 293 K = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size()); 294 if (L.size() == 0) { 295 return K; 296 } 297 for (GenPolynomial<GenPolynomial<BigInteger>> a : L) { 298 GenPolynomial<GenPolynomial<C>> b = fromIntegerCoefficients(fac, a); 299 K.add(b); 300 } 301 return K; 302 } 303 304 305 //------------------------------ 306 307 308 /** 309 * BigInteger from BigRational coefficients. Represent as polynomial with 310 * type GenPolynomial<BigInteger> coefficients. 311 * @param fac result polynomial factory. 312 * @param A polynomial with GenPolynomial<BigRational> coefficients to 313 * be converted. 314 * @return polynomial with type GenPolynomial<BigInteger> 315 * coefficients. 316 */ 317 public static GenPolynomial<GenPolynomial<BigInteger>> integerFromRationalCoefficients( 318 GenPolynomialRing<GenPolynomial<BigInteger>> fac, 319 GenPolynomial<GenPolynomial<BigRational>> A) { 320 GenPolynomial<GenPolynomial<BigInteger>> B = fac.getZERO().copy(); 321 if (A == null || A.isZERO()) { 322 return B; 323 } 324 java.math.BigInteger gcd = null; 325 java.math.BigInteger lcm = null; 326 int sLCM = 0; 327 int sGCD = 0; 328 // lcm of all denominators 329 for (GenPolynomial<BigRational> av : A.getMap().values()) { 330 for (BigRational y : av.getMap().values()) { 331 java.math.BigInteger numerator = y.numerator(); 332 java.math.BigInteger denominator = y.denominator(); 333 // lcm = lcm(lcm,x) 334 if (lcm == null) { 335 lcm = denominator; 336 sLCM = denominator.signum(); 337 } else { 338 java.math.BigInteger d = lcm.gcd(denominator); 339 lcm = lcm.multiply(denominator.divide(d)); 340 } 341 // gcd = gcd(gcd,x) 342 if (gcd == null) { 343 gcd = numerator; 344 sGCD = numerator.signum(); 345 } else { 346 gcd = gcd.gcd(numerator); 347 } 348 } 349 //System.out.println("gcd = " + gcd + ", lcm = " + lcm); 350 } 351 if (sLCM < 0) { 352 lcm = lcm.negate(); 353 } 354 if (sGCD < 0) { 355 gcd = gcd.negate(); 356 } 357 //System.out.println("gcd** = " + gcd + ", lcm = " + lcm); 358 RingFactory<GenPolynomial<BigInteger>> cfac = fac.coFac; 359 GenPolynomialRing<BigInteger> rfac = (GenPolynomialRing<BigInteger>) cfac; 360 for (Map.Entry<ExpVector, GenPolynomial<BigRational>> y : A.getMap().entrySet()) { 361 ExpVector e = y.getKey(); 362 GenPolynomial<BigRational> a = y.getValue(); 363 // common denominator over all coefficients 364 GenPolynomial<BigInteger> p = PolyUtil.integerFromRationalCoefficients(rfac, gcd, lcm, a); 365 if (!p.isZERO()) { 366 //B = B.sum( p, e ); // inefficient 367 B.doPutToMap(e, p); 368 } 369 } 370 return B; 371 } 372 373 374 /** 375 * BigInteger from BigRational coefficients. Represent as polynomial with 376 * type GenPolynomial<BigInteger> coefficients. 377 * @param fac result polynomial factory. 378 * @param L polynomial list with GenPolynomial<BigRational> 379 * coefficients to be converted. 380 * @return polynomial list with polynomials with type 381 * GenPolynomial<BigInteger> coefficients. 382 */ 383 public static List<GenPolynomial<GenPolynomial<BigInteger>>> integerFromRationalCoefficients( 384 GenPolynomialRing<GenPolynomial<BigInteger>> fac, 385 List<GenPolynomial<GenPolynomial<BigRational>>> L) { 386 List<GenPolynomial<GenPolynomial<BigInteger>>> K = null; 387 if (L == null) { 388 return K; 389 } 390 K = new ArrayList<GenPolynomial<GenPolynomial<BigInteger>>>(L.size()); 391 if (L.isEmpty()) { 392 return K; 393 } 394 for (GenPolynomial<GenPolynomial<BigRational>> a : L) { 395 GenPolynomial<GenPolynomial<BigInteger>> b = integerFromRationalCoefficients(fac, a); 396 K.add(b); 397 } 398 return K; 399 } 400 401 402 /** 403 * Introduce lower variable. Represent as polynomial with type 404 * GenPolynomial<C> coefficients. 405 * @param rfac result polynomial factory. 406 * @param A polynomial to be extended. 407 * @return polynomial with type GenPolynomial<C> coefficients. 408 */ 409 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> introduceLowerVariable( 410 GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<C> A) { 411 if (A == null || rfac == null) { 412 return null; 413 } 414 GenPolynomial<GenPolynomial<C>> Pc = rfac.getONE().multiply(A); 415 if (Pc.isZERO()) { 416 return Pc; 417 } 418 Pc = PolyUtil.<C> switchVariables(Pc); 419 return Pc; 420 } 421 422 423 /** 424 * From AlgebraicNumber coefficients. Represent as polynomial with type 425 * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. 426 * @param rfac result polynomial factory. 427 * @param A polynomial with AlgebraicNumber coefficients to be converted. 428 * @param k for (y-k x) substitution. 429 * @return polynomial with type GenPolynomial<C> coefficients. 430 */ 431 public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> substituteFromAlgebraicCoefficients( 432 GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<AlgebraicNumber<C>> A, long k) { 433 if (A == null || rfac == null) { 434 return null; 435 } 436 if (A.isZERO()) { 437 return rfac.getZERO(); 438 } 439 // setup x - k alpha 440 GenPolynomialRing<AlgebraicNumber<C>> apfac = A.ring; 441 GenPolynomial<AlgebraicNumber<C>> x = apfac.univariate(0); 442 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) A.ring.coFac; 443 AlgebraicNumber<C> alpha = afac.getGenerator(); 444 AlgebraicNumber<C> ka = afac.fromInteger(k); 445 GenPolynomial<AlgebraicNumber<C>> s = x.subtract(ka.multiply(alpha)); // x - k alpha 446 //System.out.println("x - k alpha = " + s); 447 //System.out.println("s.ring = " + s.ring.toScript()); 448 if (debug) { 449 logger.info("x - k alpha: {}", s); 450 } 451 // substitute, convert and switch 452 //System.out.println("Asubs = " + A); 453 GenPolynomial<AlgebraicNumber<C>> B; 454 if (s.ring.nvar <= 1) { 455 B = PolyUtil.<AlgebraicNumber<C>> substituteMain(A, s); 456 } else { 457 B = PolyUtil.<AlgebraicNumber<C>> substituteUnivariateMult(A, s); 458 } 459 //System.out.println("Bsubs = " + B); 460 GenPolynomial<GenPolynomial<C>> Pc = PolyUtil.<C> fromAlgebraicCoefficients(rfac, B); // Q[alpha][x] 461 //System.out.println("Pc[a,x] = " + Pc); 462 Pc = PolyUtil.<C> switchVariables(Pc); // Q[x][alpha] 463 //System.out.println("Pc[x,a] = " + Pc); 464 return Pc; 465 } 466 467 468 /** 469 * Convert to AlgebraicNumber coefficients. Represent as polynomial with 470 * AlgebraicNumber<C> coefficients, C is e.g. ModInteger or BigRational. 471 * @param pfac result polynomial factory. 472 * @param A polynomial with GenPolynomial<BigInteger> coefficients to 473 * be converted. 474 * @param k for (y-k x) substitution. 475 * @return polynomial with AlgebraicNumber<C> coefficients. 476 */ 477 public static <C extends GcdRingElem<C>> GenPolynomial<AlgebraicNumber<C>> substituteConvertToAlgebraicCoefficients( 478 GenPolynomialRing<AlgebraicNumber<C>> pfac, GenPolynomial<C> A, long k) { 479 if (A == null || pfac == null) { 480 return null; 481 } 482 if (A.isZERO()) { 483 return pfac.getZERO(); 484 } 485 // convert to Q(alpha)[x] 486 GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<C> convertToAlgebraicCoefficients(pfac, A); 487 // setup x .+. k alpha for back substitution 488 GenPolynomial<AlgebraicNumber<C>> x = pfac.univariate(0); 489 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac; 490 AlgebraicNumber<C> alpha = afac.getGenerator(); 491 AlgebraicNumber<C> ka = afac.fromInteger(k); 492 GenPolynomial<AlgebraicNumber<C>> s = x.sum(ka.multiply(alpha)); // x + k alpha 493 // substitute 494 //System.out.println("s.ring = " + s.ring.toScript()); 495 GenPolynomial<AlgebraicNumber<C>> N; 496 if (s.ring.nvar <= 1) { 497 N = PolyUtil.<AlgebraicNumber<C>> substituteMain(B, s); 498 } else { 499 N = PolyUtil.<AlgebraicNumber<C>> substituteUnivariateMult(B, s); 500 } 501 return N; 502 } 503 504 505 /** 506 * Norm of a polynomial with AlgebraicNumber coefficients. 507 * @param A uni or multivariate polynomial from 508 * GenPolynomial<AlgebraicNumber<C>>. 509 * @param k for (y - k x) substitution. 510 * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing<C>. 511 */ 512 public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A, 513 long k) { 514 if (A == null) { 515 return null; 516 } 517 GenPolynomialRing<AlgebraicNumber<C>> pfac = A.ring; // Q(alpha)[x] 518 //if (pfac.nvar > 1) { 519 // throw new IllegalArgumentException("only for univariate polynomials"); 520 //} 521 AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac; 522 GenPolynomial<C> agen = afac.modul; 523 GenPolynomialRing<C> cfac = afac.ring; 524 if (A.isZERO()) { 525 return cfac.getZERO(); 526 } 527 AlgebraicNumber<C> ldcf = A.leadingBaseCoefficient(); 528 if (!ldcf.isONE()) { 529 A = A.monic(); 530 } 531 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pfac); 532 //System.out.println("rfac = " + rfac.toScript()); 533 534 // transform minimal polynomial to bi-variate polynomial 535 GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, agen); 536 537 // transform to bi-variate polynomial, 538 // switching varaible sequence from Q[alpha][x] to Q[X][alpha] 539 GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> substituteFromAlgebraicCoefficients(rfac, A, k); 540 Pc = PolyUtil.<C> monic(Pc); 541 //System.out.println("Pc = " + Pc.toScript() + " :: " + Pc.ring.toScript()); 542 543 GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>( /*cfac.coFac*/); 544 // = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( cfac.coFac ); 545 546 GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveUnivariateResultant(Pc, Ac); 547 //System.out.println("Rc = " + Rc.toScript()); 548 GenPolynomial<C> res = Rc.leadingBaseCoefficient(); 549 res = res.monic(); 550 return res; 551 } 552 553 554 /** 555 * Norm of a polynomial with AlgebraicNumber coefficients. 556 * @param A polynomial from GenPolynomial<AlgebraicNumber<C>>. 557 * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y]. 558 */ 559 public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A) { 560 return norm(A, 0L); 561 } 562 563 564 /** 565 * Ensure that the field property is determined. Checks if modul is 566 * irreducible and modifies the algebraic number ring. 567 * @param afac algebraic number ring. 568 */ 569 public static <C extends GcdRingElem<C>> void ensureFieldProperty(AlgebraicNumberRing<C> afac) { 570 if (afac.getField() != -1) { 571 return; 572 } 573 if (!afac.ring.coFac.isField()) { 574 afac.setField(false); 575 return; 576 } 577 Factorization<C> mf = FactorFactory.<C> getImplementation(afac.ring); 578 if (mf.isIrreducible(afac.modul)) { 579 afac.setField(true); 580 } else { 581 afac.setField(false); 582 } 583 } 584 585 586 /** 587 * Construct a random irreducible univariate polynomial of degree d. 588 * @param cfac coefficient polynomial ring. 589 * @param degree of random polynomial. 590 * @return irreducible univariate polynomial. 591 */ 592 public static <C extends GcdRingElem<C>> GenPolynomial<C> randomIrreduciblePolynomial(RingFactory<C> cfac, 593 int degree) { 594 if (!cfac.isField()) { 595 throw new IllegalArgumentException("coefficient ring must be a field " + cfac); 596 } 597 GenPolynomialRing<C> ring = new GenPolynomialRing<C>(cfac, 1, TermOrderByName.INVLEX); 598 return randomIrreduciblePolynomial(ring, degree); 599 } 600 601 602 /** 603 * Construct a random irreducible univariate polynomial of degree d. 604 * @param ring coefficient ring. 605 * @param degree of random polynomial. 606 * @return irreducible univariate polynomial. 607 */ 608 public static <C extends GcdRingElem<C>> GenPolynomial<C> randomIrreduciblePolynomial( 609 GenPolynomialRing<C> ring, int degree) { 610 if (!ring.coFac.isField()) { 611 throw new IllegalArgumentException("coefficient ring must be a field " + ring.coFac); 612 } 613 Factorization<C> eng = FactorFactory.<C> getImplementation(ring); 614 GenPolynomial<C> mod = ring.getZERO(); 615 int k = ring.coFac.characteristic().bitLength(); // log 616 if (k < 3) { 617 k = 7; 618 } 619 int l = degree / 2 + 2; 620 int d = degree + 1; 621 float q = 0.55f; 622 for (;;) { 623 mod = ring.random(k, l, d, q).monic(); 624 if (mod.degree() != degree) { 625 mod = mod.sum(ring.univariate(0, degree)); 626 } 627 if (mod.trailingBaseCoefficient().isZERO()) { 628 mod = mod.sum(ring.getONE()); 629 } 630 //System.out.println("algebriacNumberField: mod = " + mod + ", k = " + k); 631 if (eng.isIrreducible(mod)) { 632 break; 633 } 634 } 635 return mod; 636 } 637 638 639 /** 640 * Construct an algebraic number field of degree d. Uses a random 641 * irreducible polynomial of degree d as modulus of the algebraic number 642 * ring. 643 * @param cfac coefficient ring. 644 * @param degree of random polynomial. 645 * @return algebraic number field. 646 */ 647 public static <C extends GcdRingElem<C>> AlgebraicNumberRing<C> algebraicNumberField(RingFactory<C> cfac, 648 int degree) { 649 GenPolynomial<C> mod = randomIrreduciblePolynomial(cfac, degree); 650 AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(mod, true); 651 return afac; 652 } 653 654 655 /** 656 * Construct an algebraic number field of degree d. Uses a random 657 * irreducible polynomial of degree d as modulus of the algebraic number 658 * ring. 659 * @param ring coefficient polynomial ring. 660 * @param degree of random polynomial. 661 * @return algebraic number field. 662 */ 663 public static <C extends GcdRingElem<C>> AlgebraicNumberRing<C> algebraicNumberField( 664 GenPolynomialRing<C> ring, int degree) { 665 GenPolynomial<C> mod = randomIrreduciblePolynomial(ring, degree); 666 AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(mod, true); 667 return afac; 668 } 669 670 671 /** 672 * Construct Berlekamp Q matrix. 673 * @param A univariate modular polynomial. 674 * @return Q matrix. 675 */ 676 public static <C extends GcdRingElem<C>> ArrayList<ArrayList<C>> constructQmatrix(GenPolynomial<C> A) { 677 ArrayList<ArrayList<C>> Q = new ArrayList<ArrayList<C>>(); 678 if (A == null || A.isZERO()) { 679 return Q; 680 } 681 GenPolynomialRing<C> pfac = A.ring; 682 //System.out.println("pfac = " + pfac.toScript()); 683 java.math.BigInteger q = pfac.coFac.characteristic(); //.longValueExact(); 684 int lq = q.bitLength(); //Power.logarithm(2, q); 685 if (pfac.coFac instanceof AlgebraicNumberRing) { 686 lq = (int) ((AlgebraicNumberRing) pfac.coFac).extensionDegree(); 687 q = q.pow(lq); //Power.power(q, lq); 688 } 689 logger.info("Q matrix for cfac = {}", q); 690 long d = A.degree(0); 691 GenPolynomial<C> x = pfac.univariate(0); 692 //System.out.println("x = " + x.toScript()); 693 GenPolynomial<C> r = pfac.getONE(); 694 //System.out.println("r = " + r.toScript()); 695 List<GenPolynomial<C>> Qp = new ArrayList<GenPolynomial<C>>(); 696 Qp.add(r); 697 GenPolynomial<C> pow = Power.<GenPolynomial<C>> modPositivePower(x, q, A); 698 //System.out.println("pow = " + pow.toScript()); 699 Qp.add(pow); 700 r = pow; 701 for (int i = 2; i < d; i++) { 702 r = r.multiply(pow).remainder(A); 703 Qp.add(r); 704 } 705 //System.out.println("Qp = " + Qp); 706 UnivPowerSeriesRing<C> psfac = new UnivPowerSeriesRing<C>(pfac); 707 //System.out.println("psfac = " + psfac.toScript()); 708 for (GenPolynomial<C> p : Qp) { 709 UnivPowerSeries<C> ps = psfac.fromPolynomial(p); 710 //System.out.println("ps = " + ps.toScript()); 711 ArrayList<C> pr = new ArrayList<C>(); 712 for (int i = 0; i < d; i++) { 713 C c = ps.coefficient(i); 714 pr.add(c); 715 } 716 Q.add(pr); 717 } 718 //System.out.println("Q = " + Q); 719 return Q; 720 } 721 722 723 /** 724 * Polynomial suitable evaluation points. deg(B) = deg(A(x_1,...)) and B is 725 * also squarefree. 726 * @param A squarefree polynomial in r variables. 727 * @return L list of evaluation points and a squarefree univariate 728 * Polynomial B = A(x_1,L_1,...L_{r-2}). 729 * @see "sacring.SACPFAC.mi#IPCEVP from SAC2/MAS" 730 */ 731 @SuppressWarnings("unchecked") 732 public static <C extends GcdRingElem<C>> EvalPoints<C> evaluationPoints(GenPolynomial<C> A) { 733 ArrayList<C> L = new ArrayList<C>(); 734 if (A == null) { 735 throw new IllegalArgumentException("A is null"); 736 } 737 GenPolynomialRing<C> pfac = A.ring; 738 if (pfac.nvar <= 1) { 739 return new EvalPoints<C>(A, A, L); 740 } 741 GenPolynomial<C> B = A; 742 if (A.isZERO() || A.isONE()) { 743 return new EvalPoints<C>(A, A, L); 744 } 745 SquarefreeAbstract<C> sengine = SquarefreeFactory.<C> getImplementation(pfac.coFac); 746 //long dega = A.degree(0); 747 GenPolynomialRing<C> rpfac = pfac; 748 GenPolynomial<C> ape = A; 749 C one = pfac.coFac.getONE(); 750 C ll = pfac.coFac.getZERO(); 751 for (int i = pfac.nvar; i > 1; i--) { 752 //System.out.println("rpfac = " + rpfac.toScript()); 753 GenPolynomialRing<GenPolynomial<C>> rfac = rpfac.recursive(1); 754 GenPolynomialRing<C> cpfac = (GenPolynomialRing) rfac.coFac; 755 GenPolynomial<GenPolynomial<C>> ap = PolyUtil.<C> recursive(rfac, ape); 756 //System.out.println("ap = " + ap); 757 long degd = ape.degree(rpfac.nvar - 2); 758 boolean unlucky = true; 759 long s = 0; 760 C Vi = null; 761 while (unlucky) { 762 //System.out.println("ll = " + ll); 763 Vi = ll; 764 if (ll.signum() > 0) { 765 ll = ll.negate(); 766 } else { 767 ll = one.subtract(ll); 768 } 769 ape = PolyUtil.<C> evaluateMainRecursive(cpfac, ap, Vi); 770 //System.out.println("ape = " + ape); 771 //long degp = ape.degree(0); 772 long degc = ape.degree(cpfac.nvar - 1); 773 //System.out.println("degc = " + degc + ", degd = " + degd); 774 if (degd != degc) { 775 continue; 776 } 777 if (!sengine.isSquarefree(ape)) { 778 //System.out.println("not squarefree"); 779 continue; 780 } 781 //System.out.println("isSquarefree"); 782 //ap = ape; 783 unlucky = false; 784 if (s++ > 300l) { 785 throw new RuntimeException(s + " evaluations not squarefree: " + Vi + ", " + ape); 786 //break; 787 } 788 } 789 L.add(Vi); 790 rpfac = cpfac; 791 } 792 B = ape; 793 return new EvalPoints<C>(A, B, L); 794 } 795 796 797 /** 798 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a 799 * univariate polynomial. 800 * @param A polynomial to be converted. 801 * @return a univariate polynomial. 802 */ 803 public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A) { 804 if (A == null) { 805 return A; 806 } 807 long d = A.degree() + 1L; 808 return substituteKronecker(A, d); 809 } 810 811 812 /** 813 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a 814 * univariate polynomial. 815 * @param A polynomial to be converted. 816 * @return a univariate polynomial. 817 */ 818 public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A, 819 long d) { 820 if (A == null) { 821 return A; 822 } 823 RingFactory<C> cfac = A.ring.coFac; 824 GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1); 825 GenPolynomial<C> B = ufac.getZERO().copy(); 826 if (A.isZERO()) { 827 return B; 828 } 829 for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) { 830 ExpVector e = y.getKey(); 831 C a = y.getValue(); 832 long f = 0L; 833 long h = 1L; 834 for (int i = 0; i < e.length(); i++) { 835 long j = e.getVal(i) * h; 836 f += j; 837 h *= d; 838 } 839 ExpVector g = ExpVector.create(1, 0, f); 840 B.doPutToMap(g, a); 841 } 842 return B; 843 } 844 845 846 /** 847 * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct 848 * univariate polynomials. 849 * @param A list of polynomials to be converted. 850 * @return a list of univariate polynomials. 851 */ 852 public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> substituteKronecker( 853 List<GenPolynomial<C>> A, int d) { 854 if (A == null || A.get(0) == null) { 855 return null; 856 } 857 return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new SubstKronecker<C>(d)); 858 } 859 860 861 /** 862 * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a 863 * multivariate polynomial. 864 * @param A polynomial to be converted. 865 * @param fac result polynomial factory. 866 * @return a multivariate polynomial. 867 */ 868 public static <C extends GcdRingElem<C>> GenPolynomial<C> backSubstituteKronecker( 869 GenPolynomialRing<C> fac, GenPolynomial<C> A, long d) { 870 if (A == null) { 871 return A; 872 } 873 if (fac == null) { 874 throw new IllegalArgumentException("null factory not allowed "); 875 } 876 int n = fac.nvar; 877 GenPolynomial<C> B = fac.getZERO().copy(); 878 if (A.isZERO()) { 879 return B; 880 } 881 for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) { 882 ExpVector e = y.getKey(); 883 C a = y.getValue(); 884 long f = e.getVal(0); 885 ExpVector g = ExpVector.create(n); 886 for (int i = 0; i < n; i++) { 887 long j = f % d; 888 f /= d; 889 g = g.subst(i, j); 890 } 891 B.doPutToMap(g, a); 892 } 893 return B; 894 } 895 896 897 /** 898 * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct 899 * multivariate polynomials. 900 * @param A list of polynomials to be converted. 901 * @param fac result polynomial factory. 902 * @return a list of multivariate polynomials. 903 */ 904 public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> backSubstituteKronecker( 905 GenPolynomialRing<C> fac, List<GenPolynomial<C>> A, long d) { 906 return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new BackSubstKronecker<C>(fac, d)); 907 } 908 909} 910 911 912/** 913 * Kronecker substitutuion functor. 914 */ 915class SubstKronecker<C extends GcdRingElem<C>> implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> { 916 917 918 final long d; 919 920 921 public SubstKronecker(long d) { 922 this.d = d; 923 } 924 925 926 public GenPolynomial<C> eval(GenPolynomial<C> c) { 927 if (c == null) { 928 return null; 929 } 930 return PolyUfdUtil.<C> substituteKronecker(c, d); 931 } 932} 933 934 935/** 936 * Kronecker back substitutuion functor. 937 */ 938class BackSubstKronecker<C extends GcdRingElem<C>> 939 implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> { 940 941 942 final long d; 943 944 945 final GenPolynomialRing<C> fac; 946 947 948 public BackSubstKronecker(GenPolynomialRing<C> fac, long d) { 949 this.d = d; 950 this.fac = fac; 951 } 952 953 954 public GenPolynomial<C> eval(GenPolynomial<C> c) { 955 if (c == null) { 956 return null; 957 } 958 return PolyUfdUtil.<C> backSubstituteKronecker(fac, c, d); 959 } 960}