001/* 002 * $Id: HenselUtil.java 5842 2018-05-21 13:23:49Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.log4j.Logger; 012 013import edu.jas.arith.BigInteger; 014import edu.jas.arith.ModInteger; 015import edu.jas.arith.ModIntegerRing; 016import edu.jas.arith.ModLongRing; 017import edu.jas.arith.Modular; 018import edu.jas.arith.ModularRingFactory; 019import edu.jas.poly.ExpVector; 020import edu.jas.poly.GenPolynomial; 021import edu.jas.poly.GenPolynomialRing; 022import edu.jas.poly.Monomial; 023import edu.jas.poly.PolyUtil; 024import edu.jas.structure.GcdRingElem; 025import edu.jas.structure.RingFactory; 026 027 028/** 029 * Hensel utilities for ufd. 030 * @author Heinz Kredel 031 */ 032 033public class HenselUtil { 034 035 036 private static final Logger logger = Logger.getLogger(HenselUtil.class); 037 038 039 private static final boolean debug = logger.isDebugEnabled(); 040 041 042 /** 043 * Modular Hensel lifting algorithm on coefficients. Let p = 044 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 045 * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See Algorithm 6.1. in 046 * Geddes et.al.. Linear version, as it does not lift S A + T B == 1 mod 047 * p^{e+1}. 048 * @param C GenPolynomial 049 * @param A GenPolynomial 050 * @param B other GenPolynomial 051 * @param S GenPolynomial 052 * @param T GenPolynomial 053 * @param M bound on the coefficients of A1 and B1 as factors of C. 054 * @return [A1,B1,Am,Bm] = lift(C,A,B), with C = A1 * B1 mod p^e, Am = A1 055 * mod p^e, Bm = B1 mod p^e . 056 */ 057 @SuppressWarnings("unchecked") 058 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHensel( 059 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B, 060 GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException { 061 if (C == null || C.isZERO()) { 062 return new HenselApprox<MOD>(C, C, A, B); 063 } 064 if (A == null || A.isZERO() || B == null || B.isZERO()) { 065 throw new IllegalArgumentException("A and B must be nonzero"); 066 } 067 GenPolynomialRing<BigInteger> fac = C.ring; 068 if (fac.nvar != 1) { // assert ? 069 throw new IllegalArgumentException("polynomial ring not univariate"); 070 } 071 // setup factories 072 GenPolynomialRing<MOD> pfac = A.ring; 073 RingFactory<MOD> p = pfac.coFac; 074 RingFactory<MOD> q = p; 075 ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p; 076 ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q; 077 BigInteger Qi = Q.getIntegerModul(); 078 BigInteger M2 = M.multiply(M.fromInteger(2)); 079 BigInteger Mq = Qi; 080 081 // normalize c and a, b factors, assert p is prime 082 GenPolynomial<BigInteger> Ai; 083 GenPolynomial<BigInteger> Bi; 084 BigInteger c = C.leadingBaseCoefficient(); 085 C = C.multiply(c); // sic 086 MOD a = A.leadingBaseCoefficient(); 087 if (!a.isONE()) { // A = A.monic(); 088 A = A.divide(a); 089 S = S.multiply(a); 090 } 091 MOD b = B.leadingBaseCoefficient(); 092 if (!b.isONE()) { // B = B.monic(); 093 B = B.divide(b); 094 T = T.multiply(b); 095 } 096 MOD cm = P.fromInteger(c.getVal()); 097 A = A.multiply(cm); 098 B = B.multiply(cm); 099 T = T.divide(cm); 100 S = S.divide(cm); 101 Ai = PolyUtil.integerFromModularCoefficients(fac, A); 102 Bi = PolyUtil.integerFromModularCoefficients(fac, B); 103 // replace leading base coefficients 104 ExpVector ea = Ai.leadingExpVector(); 105 ExpVector eb = Bi.leadingExpVector(); 106 Ai.doPutToMap(ea, c); 107 Bi.doPutToMap(eb, c); 108 109 // polynomials mod p 110 GenPolynomial<MOD> Ap; 111 GenPolynomial<MOD> Bp; 112 GenPolynomial<MOD> A1p = A; 113 GenPolynomial<MOD> B1p = B; 114 GenPolynomial<MOD> Ep; 115 116 // polynomials over the integers 117 GenPolynomial<BigInteger> E; 118 GenPolynomial<BigInteger> Ea; 119 GenPolynomial<BigInteger> Eb; 120 GenPolynomial<BigInteger> Ea1; 121 GenPolynomial<BigInteger> Eb1; 122 123 while (Mq.compareTo(M2) < 0) { 124 // compute E=(C-AB)/q over the integers 125 E = C.subtract(Ai.multiply(Bi)); 126 if (E.isZERO()) { 127 logger.info("leaving on zero E"); 128 break; 129 } 130 try { 131 E = E.divide(Qi); 132 } catch (RuntimeException e) { 133 // useful in debuging 134 //System.out.println("C = " + C ); 135 //System.out.println("Ai = " + Ai ); 136 //System.out.println("Bi = " + Bi ); 137 //System.out.println("E = " + E ); 138 //System.out.println("Qi = " + Qi ); 139 throw e; 140 } 141 // E mod p 142 Ep = PolyUtil.<MOD> fromIntegerCoefficients(pfac, E); 143 //logger.info("Ep = " + Ep); 144 145 // construct approximation mod p 146 Ap = S.multiply(Ep); // S,T ++ T,S 147 Bp = T.multiply(Ep); 148 GenPolynomial<MOD>[] QR; 149 QR = Ap.quotientRemainder(B); 150 GenPolynomial<MOD> Qp; 151 GenPolynomial<MOD> Rp; 152 Qp = QR[0]; 153 Rp = QR[1]; 154 A1p = Rp; 155 B1p = Bp.sum(A.multiply(Qp)); 156 157 // construct q-adic approximation, convert to integer 158 Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); 159 Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); 160 Ea1 = Ea.multiply(Qi); 161 Eb1 = Eb.multiply(Qi); 162 163 Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required 164 Eb = Bi.sum(Ea1); //-------------------------- 165 assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0)); 166 //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug 167 // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); 168 //} 169 170 // prepare for next iteration 171 Mq = Qi; 172 Qi = Q.getIntegerModul().multiply(P.getIntegerModul()); 173 // Q = new ModIntegerRing(Qi.getVal()); 174 if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { 175 Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); 176 } else { 177 Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); 178 } 179 Ai = Ea; 180 Bi = Eb; 181 } 182 GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>(); 183 184 // remove normalization 185 BigInteger ai = ufd.baseContent(Ai); 186 Ai = Ai.divide(ai); 187 BigInteger bi = null; 188 try { 189 bi = c.divide(ai); 190 Bi = Bi.divide(bi); // divide( c/a ) 191 } catch (RuntimeException e) { 192 //System.out.println("C = " + C ); 193 //System.out.println("Ai = " + Ai ); 194 //System.out.println("Bi = " + Bi ); 195 //System.out.println("c = " + c ); 196 //System.out.println("ai = " + ai ); 197 //System.out.println("bi = " + bi ); 198 //System.out.println("no exact lifting possible " + e); 199 throw new NoLiftingException("no exact lifting possible " + e); 200 } 201 return new HenselApprox<MOD>(Ai, Bi, A1p, B1p); 202 } 203 204 205 /** 206 * Modular Hensel lifting algorithm on coefficients. Let p = 207 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 208 * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and 209 * algorithms 3.5.{5,6} in Cohen. 210 * @param C GenPolynomial 211 * @param A GenPolynomial 212 * @param B other GenPolynomial 213 * @param M bound on the coefficients of A1 and B1 as factors of C. 214 * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. 215 */ 216 @SuppressWarnings("unchecked") 217 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHensel( 218 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B) 219 throws NoLiftingException { 220 if (C == null || C.isZERO()) { 221 return new HenselApprox<MOD>(C, C, A, B); 222 } 223 if (A == null || A.isZERO() || B == null || B.isZERO()) { 224 throw new IllegalArgumentException("A and B must be nonzero"); 225 } 226 GenPolynomialRing<BigInteger> fac = C.ring; 227 if (fac.nvar != 1) { // assert ? 228 throw new IllegalArgumentException("polynomial ring not univariate"); 229 } 230 // one Hensel step on part polynomials 231 try { 232 GenPolynomial<MOD>[] gst = A.egcd(B); 233 if (!gst[0].isONE()) { 234 throw new NoLiftingException( 235 "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); 236 } 237 GenPolynomial<MOD> s = gst[1]; 238 GenPolynomial<MOD> t = gst[2]; 239 HenselApprox<MOD> ab = HenselUtil.<MOD> liftHensel(C, M, A, B, s, t); 240 return ab; 241 } catch (ArithmeticException e) { 242 throw new NoLiftingException("coefficient error " + e); 243 } 244 } 245 246 247 /** 248 * Modular quadratic Hensel lifting algorithm on coefficients. Let p = 249 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 250 * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in 251 * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it 252 * also lifts S A + T B == 1 mod p^{e+1}. 253 * @param C GenPolynomial 254 * @param A GenPolynomial 255 * @param B other GenPolynomial 256 * @param S GenPolynomial 257 * @param T GenPolynomial 258 * @param M bound on the coefficients of A1 and B1 as factors of C. 259 * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. 260 */ 261 @SuppressWarnings("unchecked") 262 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadratic( 263 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B, 264 GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException { 265 if (C == null || C.isZERO()) { 266 return new HenselApprox<MOD>(C, C, A, B); 267 } 268 if (A == null || A.isZERO() || B == null || B.isZERO()) { 269 throw new IllegalArgumentException("A and B must be nonzero"); 270 } 271 GenPolynomialRing<BigInteger> fac = C.ring; 272 if (fac.nvar != 1) { // assert ? 273 throw new IllegalArgumentException("polynomial ring not univariate"); 274 } 275 // setup factories 276 GenPolynomialRing<MOD> pfac = A.ring; 277 RingFactory<MOD> p = pfac.coFac; 278 RingFactory<MOD> q = p; 279 ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p; 280 ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q; 281 BigInteger Qi = Q.getIntegerModul(); 282 BigInteger M2 = M.multiply(M.fromInteger(2)); 283 BigInteger Mq = Qi; 284 GenPolynomialRing<MOD> qfac; 285 qfac = new GenPolynomialRing<MOD>(Q, pfac); 286 287 // normalize c and a, b factors, assert p is prime 288 GenPolynomial<BigInteger> Ai; 289 GenPolynomial<BigInteger> Bi; 290 BigInteger c = C.leadingBaseCoefficient(); 291 C = C.multiply(c); // sic 292 MOD a = A.leadingBaseCoefficient(); 293 if (!a.isONE()) { // A = A.monic(); 294 A = A.divide(a); 295 S = S.multiply(a); 296 } 297 MOD b = B.leadingBaseCoefficient(); 298 if (!b.isONE()) { // B = B.monic(); 299 B = B.divide(b); 300 T = T.multiply(b); 301 } 302 MOD cm = P.fromInteger(c.getVal()); 303 A = A.multiply(cm); 304 B = B.multiply(cm); 305 T = T.divide(cm); 306 S = S.divide(cm); 307 Ai = PolyUtil.integerFromModularCoefficients(fac, A); 308 Bi = PolyUtil.integerFromModularCoefficients(fac, B); 309 // replace leading base coefficients 310 ExpVector ea = Ai.leadingExpVector(); 311 ExpVector eb = Bi.leadingExpVector(); 312 Ai.doPutToMap(ea, c); 313 Bi.doPutToMap(eb, c); 314 315 // polynomials mod p 316 GenPolynomial<MOD> Ap; 317 GenPolynomial<MOD> Bp; 318 GenPolynomial<MOD> A1p = A; 319 GenPolynomial<MOD> B1p = B; 320 GenPolynomial<MOD> Ep; 321 GenPolynomial<MOD> Sp = S; 322 GenPolynomial<MOD> Tp = T; 323 324 // polynomials mod q 325 GenPolynomial<MOD> Aq; 326 GenPolynomial<MOD> Bq; 327 //GenPolynomial<MOD> Eq; 328 329 // polynomials over the integers 330 GenPolynomial<BigInteger> E; 331 GenPolynomial<BigInteger> Ea; 332 GenPolynomial<BigInteger> Eb; 333 GenPolynomial<BigInteger> Ea1; 334 GenPolynomial<BigInteger> Eb1; 335 GenPolynomial<BigInteger> Si; 336 GenPolynomial<BigInteger> Ti; 337 338 Si = PolyUtil.integerFromModularCoefficients(fac, S); 339 Ti = PolyUtil.integerFromModularCoefficients(fac, T); 340 341 Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai); 342 Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi); 343 344 while (Mq.compareTo(M2) < 0) { 345 // compute E=(C-AB)/q over the integers 346 E = C.subtract(Ai.multiply(Bi)); 347 if (E.isZERO()) { 348 logger.info("leaving on zero E"); 349 break; 350 } 351 E = E.divide(Qi); 352 // E mod p 353 Ep = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E); 354 //logger.info("Ep = " + Ep + ", qfac = " + qfac); 355 //if (Ep.isZERO()) { 356 //System.out.println("leaving on zero error"); 357 //??logger.info("leaving on zero Ep"); 358 //??break; 359 //} 360 361 // construct approximation mod p 362 Ap = Sp.multiply(Ep); // S,T ++ T,S 363 Bp = Tp.multiply(Ep); 364 GenPolynomial<MOD>[] QR; 365 //logger.info("Ap = " + Ap + ", Bp = " + Bp + ", fac(Ap) = " + Ap.ring); 366 QR = Ap.quotientRemainder(Bq); 367 GenPolynomial<MOD> Qp; 368 GenPolynomial<MOD> Rp; 369 Qp = QR[0]; 370 Rp = QR[1]; 371 //logger.info("Qp = " + Qp + ", Rp = " + Rp); 372 A1p = Rp; 373 B1p = Bp.sum(Aq.multiply(Qp)); 374 375 // construct q-adic approximation, convert to integer 376 Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); 377 Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); 378 Ea1 = Ea.multiply(Qi); 379 Eb1 = Eb.multiply(Qi); 380 Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required 381 Eb = Bi.sum(Ea1); //-------------------------- 382 assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0)); 383 //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug 384 // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); 385 //} 386 Ai = Ea; 387 Bi = Eb; 388 389 // gcd representation factors error -------------------------------- 390 // compute E=(1-SA-TB)/q over the integers 391 E = fac.getONE(); 392 E = E.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi)); 393 E = E.divide(Qi); 394 // E mod q 395 Ep = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E); 396 //logger.info("Ep2 = " + Ep); 397 398 // construct approximation mod q 399 Ap = Sp.multiply(Ep); // S,T ++ T,S 400 Bp = Tp.multiply(Ep); 401 QR = Bp.quotientRemainder(Aq); // Ai == A mod p ? 402 Qp = QR[0]; 403 Rp = QR[1]; 404 B1p = Rp; 405 A1p = Ap.sum(Bq.multiply(Qp)); 406 407 //if (debug) { 408 // Eq = A1p.multiply(Aq).sum(B1p.multiply(Bq)).subtract(Ep); 409 // if (!Eq.isZERO()) { 410 // System.out.println("A*A1p+B*B1p-Ep2 != 0 " + Eq); 411 // throw new RuntimeException("A*A1p+B*B1p-Ep2 != 0 mod " + Q.getIntegerModul()); 412 // } 413 //} 414 415 // construct q-adic approximation, convert to integer 416 Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); 417 Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); 418 Ea1 = Ea.multiply(Qi); 419 Eb1 = Eb.multiply(Qi); 420 Ea = Si.sum(Ea1); // Eb1 and Ea1 are required 421 Eb = Ti.sum(Eb1); //-------------------------- 422 Si = Ea; 423 Ti = Eb; 424 425 // prepare for next iteration 426 Mq = Qi; 427 Qi = Q.getIntegerModul().multiply(Q.getIntegerModul()); 428 if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { 429 Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); 430 } else { 431 Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); 432 } 433 //Q = new ModIntegerRing(Qi.getVal()); 434 //System.out.println("Q = " + Q + ", from Q = " + Mq); 435 436 qfac = new GenPolynomialRing<MOD>(Q, pfac); 437 438 Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai); 439 Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi); 440 Sp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Si); 441 Tp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ti); 442 //if (debug) { 443 // E = Ai.multiply(Si).sum(Bi.multiply(Ti)); 444 // Eq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E); 445 // if (!Eq.isONE()) { 446 // System.out.println("Ai*Si+Bi*Ti=1 " + Eq); 447 // throw new RuntimeException("Ai*Si+Bi*Ti != 1 mod " + Q.getIntegerModul()); 448 // } 449 //} 450 } 451 GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>(); 452 453 // remove normalization if possible 454 BigInteger ai = ufd.baseContent(Ai); 455 Ai = Ai.divide(ai); 456 BigInteger bi = null; 457 try { 458 bi = c.divide(ai); 459 Bi = Bi.divide(bi); // divide( c/a ) 460 } catch (RuntimeException e) { 461 //System.out.println("C = " + C ); 462 //System.out.println("Ai = " + Ai ); 463 //System.out.println("Bi = " + Bi ); 464 //System.out.println("c = " + c ); 465 //System.out.println("ai = " + ai ); 466 //System.out.println("bi = " + bi ); 467 //System.out.println("no exact lifting possible " + e); 468 throw new NoLiftingException("no exact lifting possible " + e); 469 } 470 return new HenselApprox<MOD>(Ai, Bi, A1p, B1p); 471 } 472 473 474 /** 475 * Modular quadratic Hensel lifting algorithm on coefficients. Let p = 476 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 477 * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and 478 * algorithms 3.5.{5,6} in Cohen. Quadratic version. 479 * @param C GenPolynomial 480 * @param A GenPolynomial 481 * @param B other GenPolynomial 482 * @param M bound on the coefficients of A1 and B1 as factors of C. 483 * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. 484 */ 485 @SuppressWarnings("unchecked") 486 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadratic( 487 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B) 488 throws NoLiftingException { 489 if (C == null || C.isZERO()) { 490 return new HenselApprox<MOD>(C, C, A, B); 491 } 492 if (A == null || A.isZERO() || B == null || B.isZERO()) { 493 throw new IllegalArgumentException("A and B must be nonzero"); 494 } 495 GenPolynomialRing<BigInteger> fac = C.ring; 496 if (fac.nvar != 1) { // assert ? 497 throw new IllegalArgumentException("polynomial ring not univariate"); 498 } 499 // one Hensel step on part polynomials 500 try { 501 GenPolynomial<MOD>[] gst = A.egcd(B); 502 if (!gst[0].isONE()) { 503 throw new NoLiftingException( 504 "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); 505 } 506 GenPolynomial<MOD> s = gst[1]; 507 GenPolynomial<MOD> t = gst[2]; 508 HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, A, B, s, t); 509 return ab; 510 } catch (ArithmeticException e) { 511 throw new NoLiftingException("coefficient error " + e); 512 } 513 } 514 515 516 /** 517 * Modular Hensel lifting algorithm on coefficients. Let p = 518 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 519 * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and 520 * algorithms 3.5.{5,6} in Cohen. Quadratic version. 521 * @param C GenPolynomial 522 * @param A GenPolynomial 523 * @param B other GenPolynomial 524 * @param M bound on the coefficients of A1 and B1 as factors of C. 525 * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. 526 */ 527 @SuppressWarnings("unchecked") 528 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadraticFac( 529 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B) 530 throws NoLiftingException { 531 if (C == null || C.isZERO()) { 532 throw new IllegalArgumentException("C must be nonzero"); 533 } 534 if (A == null || A.isZERO() || B == null || B.isZERO()) { 535 throw new IllegalArgumentException("A and B must be nonzero"); 536 } 537 GenPolynomialRing<BigInteger> fac = C.ring; 538 if (fac.nvar != 1) { // assert ? 539 throw new IllegalArgumentException("polynomial ring not univariate"); 540 } 541 // one Hensel step on part polynomials 542 try { 543 GenPolynomial<MOD>[] gst = A.egcd(B); 544 if (!gst[0].isONE()) { 545 throw new NoLiftingException( 546 "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); 547 } 548 GenPolynomial<MOD> s = gst[1]; 549 GenPolynomial<MOD> t = gst[2]; 550 HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadraticFac(C, M, A, B, s, t); 551 return ab; 552 } catch (ArithmeticException e) { 553 throw new NoLiftingException("coefficient error " + e); 554 } 555 } 556 557 558 /** 559 * Modular Hensel lifting algorithm on coefficients. Let p = 560 * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p 561 * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in 562 * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it 563 * also lifts S A + T B == 1 mod p^{e+1}. 564 * @param C primitive GenPolynomial 565 * @param A GenPolynomial 566 * @param B other GenPolynomial 567 * @param S GenPolynomial 568 * @param T GenPolynomial 569 * @param M bound on the coefficients of A1 and B1 as factors of C. 570 * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. 571 */ 572 @SuppressWarnings("unchecked") 573 public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadraticFac( 574 GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B, 575 GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException { 576 //System.out.println("*** version for factorization *** "); 577 //GenPolynomial<BigInteger>[] AB = new GenPolynomial[2]; 578 if (C == null || C.isZERO()) { 579 throw new IllegalArgumentException("C must be nonzero"); 580 } 581 if (A == null || A.isZERO() || B == null || B.isZERO()) { 582 throw new IllegalArgumentException("A and B must be nonzero"); 583 } 584 GenPolynomialRing<BigInteger> fac = C.ring; 585 if (fac.nvar != 1) { // assert ? 586 throw new IllegalArgumentException("polynomial ring not univariate"); 587 } 588 // setup factories 589 GenPolynomialRing<MOD> pfac = A.ring; 590 RingFactory<MOD> p = pfac.coFac; 591 RingFactory<MOD> q = p; 592 ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p; 593 ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q; 594 BigInteger PP = Q.getIntegerModul(); 595 BigInteger Qi = PP; 596 BigInteger M2 = M.multiply(M.fromInteger(2)); 597 if (debug) { 598 //System.out.println("M2 = " + M2); 599 logger.debug("M2 = " + M2); 600 } 601 BigInteger Mq = Qi; 602 GenPolynomialRing<MOD> qfac; 603 qfac = new GenPolynomialRing<MOD>(Q, pfac); // mod p 604 GenPolynomialRing<MOD> mfac; 605 BigInteger Mi = Q.getIntegerModul().multiply(Q.getIntegerModul()); 606 ModularRingFactory<MOD> Qmm; 607 // = new ModIntegerRing(Mi.getVal()); 608 if (ModLongRing.MAX_LONG.compareTo(Mi.getVal()) > 0) { 609 Qmm = (ModularRingFactory) new ModLongRing(Mi.getVal()); 610 } else { 611 Qmm = (ModularRingFactory) new ModIntegerRing(Mi.getVal()); 612 } 613 mfac = new GenPolynomialRing<MOD>(Qmm, qfac); // mod p^e 614 MOD Qm = Qmm.fromInteger(Qi.getVal()); 615 616 // partly normalize c and a, b factors, assert p is prime 617 GenPolynomial<BigInteger> Ai; 618 GenPolynomial<BigInteger> Bi; 619 BigInteger c = C.leadingBaseCoefficient(); 620 C = C.multiply(c); // sic 621 MOD a = A.leadingBaseCoefficient(); 622 if (!a.isONE()) { // A = A.monic(); 623 A = A.divide(a); 624 S = S.multiply(a); 625 } 626 MOD b = B.leadingBaseCoefficient(); 627 if (!b.isONE()) { // B = B.monic(); 628 B = B.divide(b); 629 T = T.multiply(b); 630 } 631 MOD cm = P.fromInteger(c.getVal()); 632 if (cm.isZERO()) { 633 System.out.println("c = " + c); 634 System.out.println("P = " + P); 635 throw new ArithmeticException("c mod p == 0 not meaningful"); 636 } 637 // mod p 638 A = A.multiply(cm); 639 S = S.divide(cm); 640 B = B.multiply(cm); 641 T = T.divide(cm); 642 Ai = PolyUtil.integerFromModularCoefficients(fac, A); 643 Bi = PolyUtil.integerFromModularCoefficients(fac, B); 644 // replace leading base coefficients 645 ExpVector ea = Ai.leadingExpVector(); 646 ExpVector eb = Bi.leadingExpVector(); 647 Ai.doPutToMap(ea, c); 648 Bi.doPutToMap(eb, c); 649 650 // polynomials mod p 651 GenPolynomial<MOD> Ap; 652 GenPolynomial<MOD> Bp; 653 GenPolynomial<MOD> A1p = A; 654 GenPolynomial<MOD> B1p = B; 655 GenPolynomial<MOD> Sp = S; 656 GenPolynomial<MOD> Tp = T; 657 658 // polynomials mod q 659 GenPolynomial<MOD> Aq; 660 GenPolynomial<MOD> Bq; 661 662 // polynomials mod p^e 663 GenPolynomial<MOD> Cm; 664 GenPolynomial<MOD> Am; 665 GenPolynomial<MOD> Bm; 666 GenPolynomial<MOD> Em; 667 GenPolynomial<MOD> Emp; 668 GenPolynomial<MOD> Sm; 669 GenPolynomial<MOD> Tm; 670 GenPolynomial<MOD> Ema; 671 GenPolynomial<MOD> Emb; 672 GenPolynomial<MOD> Ema1; 673 GenPolynomial<MOD> Emb1; 674 675 // polynomials over the integers 676 GenPolynomial<BigInteger> Ei; 677 GenPolynomial<BigInteger> Si; 678 GenPolynomial<BigInteger> Ti; 679 680 Si = PolyUtil.integerFromModularCoefficients(fac, S); 681 Ti = PolyUtil.integerFromModularCoefficients(fac, T); 682 683 Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai); 684 Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi); 685 686 // polynomials mod p^e 687 Cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C); 688 Am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ai); 689 Bm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Bi); 690 Sm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si); 691 Tm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti); 692 //System.out.println("Cm = " + Cm); 693 //System.out.println("Am = " + Am); 694 //System.out.println("Bm = " + Bm); 695 //System.out.println("Ai = " + Ai); 696 //System.out.println("Bi = " + Bi); 697 //System.out.println("mfac = " + mfac); 698 699 while (Mq.compareTo(M2) < 0) { 700 // compute E=(C-AB)/p mod p^e 701 if (debug) { 702 //System.out.println("mfac = " + Cm.ring); 703 logger.debug("mfac = " + Cm.ring); 704 } 705 Em = Cm.subtract(Am.multiply(Bm)); 706 //System.out.println("Em = " + Em); 707 if (Em.isZERO()) { 708 if (C.subtract(Ai.multiply(Bi)).isZERO()) { 709 logger.info("leaving on zero E"); 710 break; 711 } 712 } 713 // Em = Em.divide( Qm ); 714 Ei = PolyUtil.integerFromModularCoefficients(fac, Em); 715 Ei = Ei.divide(Qi); 716 //System.out.println("Ei = " + Ei); 717 718 // Ei mod p 719 Emp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ei); 720 // Emp = PolyUtil.<MOD>fromIntegerCoefficients(qfac, 721 // PolyUtil.integerFromModularCoefficients(fac,Em) ); 722 //System.out.println("Emp = " + Emp); 723 //logger.info("Emp = " + Emp); 724 if (Emp.isZERO()) { 725 if (C.subtract(Ai.multiply(Bi)).isZERO()) { 726 logger.info("leaving on zero Emp"); 727 break; 728 } 729 } 730 731 // construct approximation mod p 732 Ap = Sp.multiply(Emp); // S,T ++ T,S 733 Bp = Tp.multiply(Emp); 734 GenPolynomial<MOD>[] QR = null; 735 QR = Ap.quotientRemainder(Bq); // Bq ! 736 GenPolynomial<MOD> Qp = QR[0]; 737 GenPolynomial<MOD> Rp = QR[1]; 738 A1p = Rp; 739 B1p = Bp.sum(Aq.multiply(Qp)); // Aq ! 740 //System.out.println("A1p = " + A1p); 741 //System.out.println("B1p = " + B1p); 742 743 // construct q-adic approximation 744 Ema = PolyUtil.<MOD> fromIntegerCoefficients(mfac, 745 PolyUtil.integerFromModularCoefficients(fac, A1p)); 746 Emb = PolyUtil.<MOD> fromIntegerCoefficients(mfac, 747 PolyUtil.integerFromModularCoefficients(fac, B1p)); 748 //System.out.println("Ema = " + Ema); 749 //System.out.println("Emb = " + Emb); 750 Ema1 = Ema.multiply(Qm); 751 Emb1 = Emb.multiply(Qm); 752 Ema = Am.sum(Emb1); // Eb1 and Ea1 are required 753 Emb = Bm.sum(Ema1); //-------------------------- 754 assert (Ema.degree(0) + Emb.degree(0) <= Cm.degree(0)); 755 //if ( Ema.degree(0)+Emb.degree(0) > Cm.degree(0) ) { // debug 756 // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); 757 //} 758 Am = Ema; 759 Bm = Emb; 760 Ai = PolyUtil.integerFromModularCoefficients(fac, Am); 761 Bi = PolyUtil.integerFromModularCoefficients(fac, Bm); 762 //System.out.println("Am = " + Am); 763 //System.out.println("Bm = " + Bm); 764 //System.out.println("Ai = " + Ai); 765 //System.out.println("Bi = " + Bi + "\n"); 766 767 // gcd representation factors error -------------------------------- 768 // compute E=(1-SA-TB)/p mod p^e 769 Em = mfac.getONE(); 770 Em = Em.subtract(Sm.multiply(Am)).subtract(Tm.multiply(Bm)); 771 //System.out.println("Em = " + Em); 772 // Em = Em.divide( Pm ); 773 774 Ei = PolyUtil.integerFromModularCoefficients(fac, Em); 775 Ei = Ei.divide(Qi); 776 //System.out.println("Ei = " + Ei); 777 // Ei mod p 778 Emp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ei); 779 //Emp = PolyUtil.<MOD>fromIntegerCoefficients(qfac, 780 // PolyUtil.integerFromModularCoefficients(fac,Em) ); 781 //System.out.println("Emp = " + Emp); 782 783 // construct approximation mod p 784 Ap = Sp.multiply(Emp); // S,T ++ T,S // Ep Eqp 785 Bp = Tp.multiply(Emp); // Ep Eqp 786 QR = Bp.quotientRemainder(Aq); // Ap Aq ! // Ai == A mod p ? 787 Qp = QR[0]; 788 Rp = QR[1]; 789 B1p = Rp; 790 A1p = Ap.sum(Bq.multiply(Qp)); 791 //System.out.println("A1p = " + A1p); 792 //System.out.println("B1p = " + B1p); 793 794 // construct p^e-adic approximation 795 Ema = PolyUtil.<MOD> fromIntegerCoefficients(mfac, 796 PolyUtil.integerFromModularCoefficients(fac, A1p)); 797 Emb = PolyUtil.<MOD> fromIntegerCoefficients(mfac, 798 PolyUtil.integerFromModularCoefficients(fac, B1p)); 799 Ema1 = Ema.multiply(Qm); 800 Emb1 = Emb.multiply(Qm); 801 Ema = Sm.sum(Ema1); // Emb1 and Ema1 are required 802 Emb = Tm.sum(Emb1); //-------------------------- 803 Sm = Ema; 804 Tm = Emb; 805 Si = PolyUtil.integerFromModularCoefficients(fac, Sm); 806 Ti = PolyUtil.integerFromModularCoefficients(fac, Tm); 807 //System.out.println("Sm = " + Sm); 808 //System.out.println("Tm = " + Tm); 809 //System.out.println("Si = " + Si); 810 //System.out.println("Ti = " + Ti + "\n"); 811 812 // prepare for next iteration 813 Qi = Q.getIntegerModul().multiply(Q.getIntegerModul()); 814 Mq = Qi; 815 //lmfac = mfac; 816 // Q = new ModIntegerRing(Qi.getVal()); 817 if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { 818 Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); 819 } else { 820 Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); 821 } 822 qfac = new GenPolynomialRing<MOD>(Q, pfac); 823 BigInteger Qmmi = Qmm.getIntegerModul().multiply(Qmm.getIntegerModul()); 824 //Qmm = new ModIntegerRing(Qmmi.getVal()); 825 if (ModLongRing.MAX_LONG.compareTo(Qmmi.getVal()) > 0) { 826 Qmm = (ModularRingFactory) new ModLongRing(Qmmi.getVal()); 827 } else { 828 Qmm = (ModularRingFactory) new ModIntegerRing(Qmmi.getVal()); 829 } 830 mfac = new GenPolynomialRing<MOD>(Qmm, qfac); 831 Qm = Qmm.fromInteger(Qi.getVal()); 832 833 Cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C); 834 Am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ai); 835 Bm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Bi); 836 Sm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si); 837 Tm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti); 838 839 assert (isHenselLift(C, Mi, PP, Ai, Bi)); 840 Mi = Mi.fromInteger(Qmm.getIntegerModul().getVal()); 841 842 Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai); 843 Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi); 844 Sp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Si); 845 Tp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ti); 846 847 //System.out.println("Am = " + Am); 848 //System.out.println("Bm = " + Bm); 849 //System.out.println("Sm = " + Sm); 850 //System.out.println("Tm = " + Tm); 851 //System.out.println("mfac = " + mfac); 852 //System.out.println("Qmm = " + Qmm + ", M2 = " + M2 + ", Mq = " + Mq + "\n"); 853 } 854 //System.out.println("*Ai = " + Ai); 855 //System.out.println("*Bi = " + Bi); 856 857 Em = Cm.subtract(Am.multiply(Bm)); 858 if (!Em.isZERO()) { 859 System.out.println("Em = " + Em); 860 //throw new NoLiftingException("no exact lifting possible"); 861 } 862 // remove normalization not possible when not exact factorization 863 GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>(); 864 // remove normalization if possible 865 BigInteger ai = ufd.baseContent(Ai); 866 Ai = Ai.divide(ai); // Ai=pp(Ai) 867 BigInteger[] qr = c.quotientRemainder(ai); 868 BigInteger bi = null; 869 boolean exact = true; 870 if (qr[1].isZERO()) { 871 bi = qr[0]; 872 try { 873 Bi = Bi.divide(bi); // divide( c/a ) 874 } catch (RuntimeException e) { 875 System.out.println("*catch: no exact factorization: " + bi + ", e = " + e); 876 exact = false; 877 } 878 } else { 879 System.out.println("*remainder: no exact factorization: q = " + qr[0] + ", r = " + qr[1]); 880 exact = false; 881 } 882 if (!exact) { 883 System.out.println("*Ai = " + Ai); 884 System.out.println("*ai = " + ai); 885 System.out.println("*Bi = " + Bi); 886 System.out.println("*bi = " + bi); 887 System.out.println("*c = " + c); 888 throw new NoLiftingException("no exact lifting possible"); 889 } 890 return new HenselApprox<MOD>(Ai, Bi, Aq, Bq); 891 } 892 893 894 /** 895 * Modular Hensel lifting test. Let p be a prime number and assume C == 896 * prod_{0,...,n-1} g_i mod p with gcd(g_i,g_j) == 1 mod p for i != j. 897 * @param C GenPolynomial 898 * @param G = [g_0,...,g_{n-1}] list of GenPolynomial 899 * @param M bound on the coefficients of g_i as factors of C. 900 * @param p prime number. 901 * @return true if C = prod_{0,...,n-1} g_i mod p^e, else false. 902 */ 903 public static//<MOD extends GcdRingElem<MOD> & Modular> 904 boolean isHenselLift(GenPolynomial<BigInteger> C, BigInteger M, BigInteger p, 905 List<GenPolynomial<BigInteger>> G) { 906 if (C == null || C.isZERO()) { 907 return false; 908 } 909 GenPolynomialRing<BigInteger> pfac = C.ring; 910 ModIntegerRing pm = new ModIntegerRing(p.getVal(), true); 911 GenPolynomialRing<ModInteger> mfac = new GenPolynomialRing<ModInteger>(pm, pfac); 912 913 // check mod p 914 GenPolynomial<ModInteger> cl = mfac.getONE(); 915 GenPolynomial<ModInteger> hlp; 916 for (GenPolynomial<BigInteger> hl : G) { 917 //System.out.println("hl = " + hl); 918 hlp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, hl); 919 //System.out.println("hl mod p = " + hlp); 920 cl = cl.multiply(hlp); 921 } 922 GenPolynomial<ModInteger> cp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, C); 923 if (!cp.equals(cl)) { 924 System.out.println("Hensel precondition wrong!"); 925 if (debug) { 926 System.out.println("cl = " + cl); 927 System.out.println("cp = " + cp); 928 System.out.println("mon(cl) = " + cl.monic()); 929 System.out.println("mon(cp) = " + cp.monic()); 930 System.out.println("cp-cl = " + cp.subtract(cl)); 931 System.out.println("M = " + M + ", p = " + p); 932 } 933 return false; 934 } 935 936 // check mod p^e 937 BigInteger mip = p; 938 while (mip.compareTo(M) < 0) { 939 mip = mip.multiply(mip); // p 940 } 941 // mip = mip.multiply(p); 942 pm = new ModIntegerRing(mip.getVal(), false); 943 mfac = new GenPolynomialRing<ModInteger>(pm, pfac); 944 cl = mfac.getONE(); 945 for (GenPolynomial<BigInteger> hl : G) { 946 //System.out.println("hl = " + hl); 947 hlp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, hl); 948 //System.out.println("hl mod p^e = " + hlp); 949 cl = cl.multiply(hlp); 950 } 951 cp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, C); 952 if (!cp.equals(cl)) { 953 System.out.println("Hensel post condition wrong!"); 954 System.out.println("cl = " + cl); 955 System.out.println("cp = " + cp); 956 System.out.println("cp-cl = " + cp.subtract(cl)); 957 System.out.println("M = " + M + ", p = " + p + ", p^e = " + mip); 958 return false; 959 } 960 return true; 961 } 962 963 964 /** 965 * Modular Hensel lifting test. Let p be a prime number and assume C == A * 966 * B mod p with gcd(A,B) == 1 mod p. 967 * @param C GenPolynomial 968 * @param A GenPolynomial 969 * @param B GenPolynomial 970 * @param M bound on the coefficients of A and B as factors of C. 971 * @param p prime number. 972 * @return true if C = A * B mod p**e, else false. 973 */ 974 public static//<MOD extends GcdRingElem<MOD> & Modular> 975 boolean isHenselLift(GenPolynomial<BigInteger> C, BigInteger M, BigInteger p, GenPolynomial<BigInteger> A, 976 GenPolynomial<BigInteger> B) { 977 List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2); 978 G.add(A); 979 G.add(B); 980 return isHenselLift(C, M, p, G); 981 } 982 983 984 /** 985 * Modular Hensel lifting test. Let p be a prime number and assume C == A * 986 * B mod p with gcd(A,B) == 1 mod p. 987 * @param C GenPolynomial 988 * @param Ha Hensel approximation. 989 * @param M bound on the coefficients of A and B as factors of C. 990 * @param p prime number. 991 * @return true if C = A * B mod p^e, else false. 992 */ 993 public static <MOD extends GcdRingElem<MOD> & Modular> boolean isHenselLift(GenPolynomial<BigInteger> C, 994 BigInteger M, BigInteger p, HenselApprox<MOD> Ha) { 995 List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2); 996 G.add(Ha.A); 997 G.add(Ha.B); 998 return isHenselLift(C, M, p, G); 999 } 1000 1001 1002 /** 1003 * Constructing and lifting algorithm for extended Euclidean relation. Let p 1004 * = A.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. 1005 * @param A modular GenPolynomial 1006 * @param B modular GenPolynomial 1007 * @param k desired approximation exponent p^k. 1008 * @return [s,t] with s A + t B = 1 mod p^k. 1009 */ 1010 @SuppressWarnings("unchecked") 1011 public static <MOD extends GcdRingElem<MOD> & Modular> GenPolynomial<MOD>[] liftExtendedEuclidean( 1012 GenPolynomial<MOD> A, GenPolynomial<MOD> B, long k) throws NoLiftingException { 1013 if (A == null || A.isZERO() || B == null || B.isZERO()) { 1014 throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B); 1015 } 1016 GenPolynomialRing<MOD> fac = A.ring; 1017 if (fac.nvar != 1) { // assert ? 1018 throw new IllegalArgumentException("polynomial ring not univariate"); 1019 } 1020 // start with extended Euclidean relation mod p 1021 GenPolynomial<MOD>[] gst = null; 1022 try { 1023 gst = A.egcd(B); 1024 if (!gst[0].isONE()) { 1025 throw new NoLiftingException( 1026 "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); 1027 } 1028 } catch (ArithmeticException e) { 1029 throw new NoLiftingException("coefficient error " + e); 1030 } 1031 GenPolynomial<MOD> S = gst[1]; 1032 GenPolynomial<MOD> T = gst[2]; 1033 //System.out.println("eeS = " + S + ": " + S.ring.coFac); 1034 //System.out.println("eeT = " + T + ": " + T.ring.coFac); 1035 1036 // setup integer polynomial ring 1037 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1038 GenPolynomial<BigInteger> one = ifac.getONE(); 1039 GenPolynomial<BigInteger> Ai = PolyUtil.integerFromModularCoefficients(ifac, A); 1040 GenPolynomial<BigInteger> Bi = PolyUtil.integerFromModularCoefficients(ifac, B); 1041 GenPolynomial<BigInteger> Si = PolyUtil.integerFromModularCoefficients(ifac, S); 1042 GenPolynomial<BigInteger> Ti = PolyUtil.integerFromModularCoefficients(ifac, T); 1043 //System.out.println("Ai = " + Ai); 1044 //System.out.println("Bi = " + Bi); 1045 //System.out.println("Si = " + Si); 1046 //System.out.println("Ti = " + Ti); 1047 1048 // approximate mod p^i 1049 ModularRingFactory<MOD> mcfac = (ModularRingFactory<MOD>) fac.coFac; 1050 BigInteger p = mcfac.getIntegerModul(); 1051 BigInteger modul = p; 1052 GenPolynomialRing<MOD> mfac; // = new GenPolynomialRing<MOD>(mcfac, fac); 1053 for (int i = 1; i < k; i++) { 1054 // e = 1 - s a - t b in Z[x] 1055 GenPolynomial<BigInteger> e = one.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi)); 1056 //System.out.println("\ne = " + e); 1057 if (e.isZERO()) { 1058 logger.info("leaving on zero e in liftExtendedEuclidean"); 1059 break; 1060 } 1061 e = e.divide(modul); 1062 // move to Z_p[x] and compute next approximation 1063 GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(fac, e); 1064 //System.out.println("c = " + c + ": " + c.ring.coFac); 1065 GenPolynomial<MOD> s = S.multiply(c); 1066 GenPolynomial<MOD> t = T.multiply(c); 1067 //System.out.println("s = " + s + ": " + s.ring.coFac); 1068 //System.out.println("t = " + t + ": " + t.ring.coFac); 1069 1070 GenPolynomial<MOD>[] QR = s.quotientRemainder(B); // watch for ordering 1071 GenPolynomial<MOD> q = QR[0]; 1072 s = QR[1]; 1073 t = t.sum(q.multiply(A)); 1074 //System.out.println("s = " + s + ": " + s.ring.coFac); 1075 //System.out.println("t = " + t + ": " + t.ring.coFac); 1076 1077 GenPolynomial<BigInteger> si = PolyUtil.integerFromModularCoefficients(ifac, s); 1078 GenPolynomial<BigInteger> ti = PolyUtil.integerFromModularCoefficients(ifac, t); 1079 //System.out.println("si = " + si); 1080 //System.out.println("ti = " + si); 1081 // add approximation to solution 1082 Si = Si.sum(si.multiply(modul)); 1083 Ti = Ti.sum(ti.multiply(modul)); 1084 //System.out.println("Si = " + Si); 1085 //System.out.println("Ti = " + Ti); 1086 modul = modul.multiply(p); 1087 //System.out.println("modul = " + modul + ", " + p + "^" + k + ", p^k = " + p.power(k)); 1088 } 1089 //System.out.println("Si = " + Si + ", Ti = " + Ti); 1090 // setup ring mod p^i 1091 if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { 1092 mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); 1093 } else { 1094 mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); 1095 } 1096 //System.out.println("mcfac = " + mcfac); 1097 mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1098 S = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si); 1099 T = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti); 1100 //System.out.println("S = " + S + ": " + S.ring.coFac); 1101 //System.out.println("T = " + T + ": " + T.ring.coFac); 1102 if (debug) { 1103 List<GenPolynomial<MOD>> AP = new ArrayList<GenPolynomial<MOD>>(); 1104 AP.add(B); 1105 AP.add(A); 1106 List<GenPolynomial<MOD>> SP = new ArrayList<GenPolynomial<MOD>>(); 1107 SP.add(S); 1108 SP.add(T); 1109 if (!HenselUtil.<MOD> isExtendedEuclideanLift(AP, SP)) { 1110 System.out.println("isExtendedEuclideanLift: false"); 1111 } 1112 } 1113 @SuppressWarnings("cast") 1114 GenPolynomial<MOD>[] rel = (GenPolynomial<MOD>[]) new GenPolynomial[2]; 1115 rel[0] = S; 1116 rel[1] = T; 1117 return rel; 1118 } 1119 1120 1121 /** 1122 * Constructing and lifting algorithm for extended Euclidean relation. Let p 1123 * = A_i.ring.coFac.modul() and assume gcd(A_i,A_j) == 1 mod p, i != j. 1124 * @param A list of modular GenPolynomials 1125 * @param k desired approximation exponent p^k. 1126 * @return [s_0,...,s_n-1] with sum_i s_i * B_i = 1 mod p^k, with B_i = 1127 * prod_{i!=j} A_j. 1128 */ 1129 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftExtendedEuclidean( 1130 List<GenPolynomial<MOD>> A, long k) throws NoLiftingException { 1131 if (A == null || A.size() <= 1) { 1132 throw new IllegalArgumentException("A must be non null and non empty"); 1133 } 1134 GenPolynomialRing<MOD> fac = A.get(0).ring; 1135 if (fac.nvar != 1) { // assert ? 1136 throw new IllegalArgumentException("polynomial ring not univariate"); 1137 } 1138 GenPolynomial<MOD> zero = fac.getZERO(); 1139 int r = A.size(); 1140 List<GenPolynomial<MOD>> Q = new ArrayList<GenPolynomial<MOD>>(r); 1141 for (int i = 0; i < r; i++) { 1142 Q.add(zero); 1143 } 1144 //System.out.println("A = " + A); 1145 Q.set(r - 2, A.get(r - 1)); 1146 for (int j = r - 3; j >= 0; j--) { 1147 GenPolynomial<MOD> q = A.get(j + 1).multiply(Q.get(j + 1)); 1148 Q.set(j, q); 1149 } 1150 //System.out.println("Q = " + Q); 1151 List<GenPolynomial<MOD>> B = new ArrayList<GenPolynomial<MOD>>(r + 1); 1152 List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(r); 1153 for (int i = 0; i < r; i++) { 1154 B.add(zero); 1155 lift.add(zero); 1156 } 1157 GenPolynomial<MOD> one = fac.getONE(); 1158 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1159 B.add(0, one); 1160 //System.out.println("B(0) = " + B.get(0)); 1161 GenPolynomial<MOD> b = one; 1162 for (int j = 0; j < r - 1; j++) { 1163 //System.out.println("Q("+(j)+") = " + Q.get(j)); 1164 //System.out.println("A("+(j)+") = " + A.get(j)); 1165 //System.out.println("B("+(j)+") = " + B.get(j)); 1166 List<GenPolynomial<MOD>> S = liftDiophant(Q.get(j), A.get(j), B.get(j), k); 1167 //System.out.println("\nSb = " + S); 1168 b = S.get(0); 1169 GenPolynomial<MOD> bb = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1170 PolyUtil.integerFromModularCoefficients(ifac, b)); 1171 B.set(j + 1, bb); 1172 lift.set(j, S.get(1)); 1173 //System.out.println("B("+(j+1)+") = " + B.get(j+1)); 1174 if (debug) { 1175 logger.info("lift(" + j + ") = " + lift.get(j)); 1176 } 1177 } 1178 //System.out.println("liftb = " + lift); 1179 lift.set(r - 1, b); 1180 if (debug) { 1181 logger.info("lift(" + (r - 1) + ") = " + b); 1182 } 1183 //System.out.println("B("+(r-1)+") = " + B.get(r-1) + " : " + B.get(r-1).ring.coFac + ", b = " + b + " : " + b.ring.coFac); 1184 //System.out.println("B = " + B); 1185 //System.out.println("liftb = " + lift); 1186 return lift; 1187 } 1188 1189 1190 /** 1191 * Modular diophantine equation solution and lifting algorithm. Let p = 1192 * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. 1193 * @param A modular GenPolynomial, mod p^k 1194 * @param B modular GenPolynomial, mod p^k 1195 * @param C modular GenPolynomial, mod p^k 1196 * @param k desired approximation exponent p^k. 1197 * @return [s, t] with s A' + t B' = C mod p^k, with A' = B, B' = A. 1198 */ 1199 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant( 1200 GenPolynomial<MOD> A, GenPolynomial<MOD> B, GenPolynomial<MOD> C, long k) 1201 throws NoLiftingException { 1202 if (A == null || A.isZERO() || B == null || B.isZERO()) { 1203 throw new IllegalArgumentException( 1204 "A and B must be nonzero, A = " + A + ", B = " + B + ", C = " + C); 1205 } 1206 List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>(); 1207 GenPolynomialRing<MOD> fac = C.ring; 1208 if (fac.nvar != 1) { // assert ? 1209 throw new IllegalArgumentException("polynomial ring not univariate"); 1210 } 1211 //System.out.println("C = " + C); 1212 GenPolynomial<MOD> zero = fac.getZERO(); 1213 for (int i = 0; i < 2; i++) { 1214 sol.add(zero); 1215 } 1216 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1217 for (Monomial<MOD> m : C) { 1218 //System.out.println("monomial = " + m); 1219 long e = m.e.getVal(0); 1220 List<GenPolynomial<MOD>> S = liftDiophant(A, B, e, k); 1221 //System.out.println("Se = " + S); 1222 MOD a = m.c; 1223 //System.out.println("C.fac = " + fac.toScript()); 1224 a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal()); 1225 int i = 0; 1226 for (GenPolynomial<MOD> d : S) { 1227 //System.out.println("d = " + d); 1228 d = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1229 PolyUtil.integerFromModularCoefficients(ifac, d)); 1230 d = d.multiply(a); 1231 d = sol.get(i).sum(d); 1232 //System.out.println("d = " + d); 1233 sol.set(i++, d); 1234 } 1235 //System.out.println("sol = " + sol + ", for " + m); 1236 } 1237 if (debug) { 1238 //GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1239 A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); 1240 B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); 1241 C = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C)); 1242 GenPolynomial<MOD> y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1))); 1243 if (!y.equals(C)) { 1244 System.out.println("A = " + A + ", B = " + B); 1245 System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1)); 1246 System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac); 1247 } 1248 } 1249 return sol; 1250 } 1251 1252 1253 /** 1254 * Modular diophantine equation solution and lifting algorithm. Let p = 1255 * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A. 1256 * @param A list of modular GenPolynomials, mod p^k 1257 * @param C modular GenPolynomial, mod p^k 1258 * @param k desired approximation exponent p^k. 1259 * @return [s_1,..., s_n] with sum_i s_i A_i' = C mod p^k, with Ai' = 1260 * prod_{j!=i} A_j. 1261 */ 1262 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant( 1263 List<GenPolynomial<MOD>> A, GenPolynomial<MOD> C, long k) throws NoLiftingException { 1264 if (false && A.size() <= 2) { 1265 return HenselUtil.<MOD> liftDiophant(A.get(0), A.get(1), C, k); 1266 } 1267 List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>(); 1268 GenPolynomialRing<MOD> fac = C.ring; 1269 if (fac.nvar != 1) { // assert ? 1270 throw new IllegalArgumentException("polynomial ring not univariate"); 1271 } 1272 //System.out.println("C = " + C); 1273 GenPolynomial<MOD> zero = fac.getZERO(); 1274 for (int i = 0; i < A.size(); i++) { 1275 sol.add(zero); 1276 } 1277 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1278 for (Monomial<MOD> m : C) { 1279 //System.out.println("monomial = " + m); 1280 long e = m.e.getVal(0); 1281 List<GenPolynomial<MOD>> S = liftDiophant(A, e, k); 1282 //System.out.println("Se = " + S); 1283 MOD a = m.c; 1284 //System.out.println("C.fac = " + fac.toScript()); 1285 a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal()); 1286 int i = 0; 1287 for (GenPolynomial<MOD> d : S) { 1288 //System.out.println("d = " + d); 1289 d = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1290 PolyUtil.integerFromModularCoefficients(ifac, d)); 1291 d = d.multiply(a); 1292 d = sol.get(i).sum(d); 1293 //System.out.println("d = " + d); 1294 sol.set(i++, d); 1295 } 1296 //System.out.println("sol = " + sol + ", for " + m); 1297 } 1298 /* 1299 if (true || debug) { 1300 //GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1301 A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); 1302 B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); 1303 C = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C)); 1304 GenPolynomial<MOD> y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1))); 1305 if (!y.equals(C)) { 1306 System.out.println("A = " + A + ", B = " + B); 1307 System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1)); 1308 System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac); 1309 } 1310 } 1311 */ 1312 return sol; 1313 } 1314 1315 1316 /** 1317 * Modular diophantine equation solution and lifting algorithm. Let p = 1318 * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. 1319 * @param A modular GenPolynomial 1320 * @param B modular GenPolynomial 1321 * @param e exponent for x^e 1322 * @param k desired approximation exponent p^k. 1323 * @return [s, t] with s A' + t B' = x^e mod p^k, with A' = B, B' = A. 1324 */ 1325 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant( 1326 GenPolynomial<MOD> A, GenPolynomial<MOD> B, long e, long k) throws NoLiftingException { 1327 if (A == null || A.isZERO() || B == null || B.isZERO()) { 1328 throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B); 1329 } 1330 List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>(); 1331 GenPolynomialRing<MOD> fac = A.ring; 1332 if (fac.nvar != 1) { // assert ? 1333 throw new IllegalArgumentException("polynomial ring not univariate"); 1334 } 1335 // lift EE relation to p^k 1336 GenPolynomial<MOD>[] lee = liftExtendedEuclidean(B, A, k); 1337 GenPolynomial<MOD> s1 = lee[0]; 1338 GenPolynomial<MOD> s2 = lee[1]; 1339 if (e == 0L) { 1340 sol.add(s1); 1341 sol.add(s2); 1342 //System.out.println("sol@0 = " + sol); 1343 return sol; 1344 } 1345 fac = s1.ring; 1346 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1347 A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); 1348 B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); 1349 1350 // this is the wrong sequence: 1351 // GenPolynomial<MOD> xe = fac.univariate(0,e); 1352 // GenPolynomial<MOD> q = s1.multiply(xe); 1353 // GenPolynomial<MOD>[] QR = q.quotientRemainder(B); 1354 // q = QR[0]; 1355 // GenPolynomial<MOD> r1 = QR[1]; 1356 // GenPolynomial<MOD> r2 = s2.multiply(xe).sum( q.multiply(A) ); 1357 1358 GenPolynomial<MOD> xe = fac.univariate(0, e); 1359 GenPolynomial<MOD> q = s1.multiply(xe); 1360 GenPolynomial<MOD>[] QR = q.quotientRemainder(A); 1361 q = QR[0]; 1362 //System.out.println("ee coeff qr = " + Arrays.toString(QR)); 1363 GenPolynomial<MOD> r1 = QR[1]; 1364 GenPolynomial<MOD> r2 = s2.multiply(xe).sum(q.multiply(B)); 1365 //System.out.println("r1 = " + r1 + ", r2 = " + r2); 1366 sol.add(r1); 1367 sol.add(r2); 1368 //System.out.println("sol@"+ e + " = " + sol); 1369 if (debug) { 1370 GenPolynomial<MOD> y = B.multiply(r1).sum(A.multiply(r2)); 1371 if (!y.equals(xe)) { 1372 System.out.println("A = " + A + ", B = " + B); 1373 System.out.println("r1 = " + r1 + ", r2 = " + r2); 1374 System.out.println("Error: A*r1 + B*r2 = " + y); 1375 } 1376 } 1377 return sol; 1378 } 1379 1380 1381 /** 1382 * Modular diophantine equation solution and lifting algorithm. Let p = 1383 * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A. 1384 * @param A list of modular GenPolynomials 1385 * @param e exponent for x^e 1386 * @param k desired approximation exponent p^k. 1387 * @return [s_1,..., s_n] with sum_i s_i A_i' = x^e mod p^k, with Ai' = 1388 * prod_{j!=i} A_j. 1389 */ 1390 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant( 1391 List<GenPolynomial<MOD>> A, long e, long k) throws NoLiftingException { 1392 if (false && A.size() <= 2) { 1393 return HenselUtil.<MOD> liftDiophant(A.get(0), A.get(1), e, k); 1394 } 1395 List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>(); 1396 GenPolynomialRing<MOD> fac = A.get(0).ring; 1397 if (fac.nvar != 1) { // assert ? 1398 throw new IllegalArgumentException("polynomial ring not univariate"); 1399 } 1400 // lift EE relation to p^k 1401 List<GenPolynomial<MOD>> lee = liftExtendedEuclidean(A, k); 1402 if (e == 0L) { 1403 //System.out.println("sol@0 = " + sol); 1404 return lee; 1405 } 1406 fac = lee.get(0).ring; 1407 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1408 List<GenPolynomial<MOD>> S = new ArrayList<GenPolynomial<MOD>>(lee.size()); 1409 for (GenPolynomial<MOD> a : lee) { 1410 a = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, a)); 1411 S.add(a); 1412 } 1413 GenPolynomial<MOD> xe = fac.univariate(0, e); 1414 //List<GenPolynomial<MOD>> Sr = new ArrayList<GenPolynomial<MOD>>(lee.size()); 1415 int i = 0; 1416 for (GenPolynomial<MOD> s : S) { 1417 GenPolynomial<MOD> q = s.multiply(xe); 1418 GenPolynomial<MOD> r = q.remainder(A.get(i++)); 1419 //System.out.println("r = " + r); 1420 sol.add(r); 1421 } 1422 //System.out.println("sol@"+ e + " = " + sol); 1423 /* 1424 if (true || debug) { 1425 GenPolynomial<MOD> y = B.multiply(r1).sum(A.multiply(r2)); 1426 if (!y.equals(xe)) { 1427 System.out.println("A = " + A + ", B = " + B); 1428 System.out.println("r1 = " + r1 + ", r2 = " + r2); 1429 System.out.println("Error: A*r1 + B*r2 = " + y); 1430 } 1431 } 1432 */ 1433 return sol; 1434 } 1435 1436 1437 /** 1438 * Modular Diophant relation lifting test. 1439 * @param A modular GenPolynomial 1440 * @param B modular GenPolynomial 1441 * @param C modular GenPolynomial 1442 * @param S1 modular GenPolynomial 1443 * @param S2 modular GenPolynomial 1444 * @return true if A*S1 + B*S2 = C, else false. 1445 */ 1446 public static <MOD extends GcdRingElem<MOD> & Modular> boolean isDiophantLift(GenPolynomial<MOD> A, 1447 GenPolynomial<MOD> B, GenPolynomial<MOD> S1, GenPolynomial<MOD> S2, 1448 GenPolynomial<MOD> C) { 1449 GenPolynomialRing<MOD> fac = C.ring; 1450 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1451 GenPolynomial<MOD> a = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1452 PolyUtil.integerFromModularCoefficients(ifac, A)); 1453 GenPolynomial<MOD> b = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1454 PolyUtil.integerFromModularCoefficients(ifac, B)); 1455 GenPolynomial<MOD> s1 = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1456 PolyUtil.integerFromModularCoefficients(ifac, S1)); 1457 GenPolynomial<MOD> s2 = PolyUtil.<MOD> fromIntegerCoefficients(fac, 1458 PolyUtil.integerFromModularCoefficients(ifac, S2)); 1459 GenPolynomial<MOD> t = a.multiply(s1).sum(b.multiply(s2)); 1460 if (t.equals(C)) { 1461 return true; 1462 } 1463 if (debug) { 1464 System.out.println("a = " + a); 1465 System.out.println("b = " + b); 1466 System.out.println("s1 = " + s1); 1467 System.out.println("s2 = " + s2); 1468 System.out.println("t = " + t); 1469 System.out.println("C = " + C); 1470 } 1471 return false; 1472 } 1473 1474 1475 /** 1476 * Modular extended Euclidean relation lifting test. 1477 * @param A list of GenPolynomials 1478 * @param S = [s_0,...,s_{n-1}] list of GenPolynomial 1479 * @return true if prod_{0,...,n-1} s_i * B_i = 1 mod p^e, with B_i = 1480 * prod_{i!=j} A_j, else false. 1481 */ 1482 public static <MOD extends GcdRingElem<MOD> & Modular> boolean isExtendedEuclideanLift( 1483 List<GenPolynomial<MOD>> A, List<GenPolynomial<MOD>> S) { 1484 GenPolynomialRing<MOD> fac = A.get(0).ring; 1485 GenPolynomial<MOD> C = fac.getONE(); 1486 return isDiophantLift(A, S, C); 1487 } 1488 1489 1490 /** 1491 * Modular Diophant relation lifting test. 1492 * @param A list of GenPolynomials 1493 * @param S = [s_0,...,s_{n-1}] list of GenPolynomials 1494 * @param C = GenPolynomial 1495 * @return true if prod_{0,...,n-1} s_i * B_i = C mod p^k, with B_i = 1496 * prod_{i!=j} A_j, else false. 1497 */ 1498 public static <MOD extends GcdRingElem<MOD> & Modular> boolean isDiophantLift(List<GenPolynomial<MOD>> A, 1499 List<GenPolynomial<MOD>> S, GenPolynomial<MOD> C) { 1500 GenPolynomialRing<MOD> fac = A.get(0).ring; 1501 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1502 List<GenPolynomial<MOD>> B = new ArrayList<GenPolynomial<MOD>>(A.size()); 1503 int i = 0; 1504 for (GenPolynomial<MOD> ai : A) { 1505 GenPolynomial<MOD> b = fac.getONE(); 1506 int j = 0; 1507 for (GenPolynomial<MOD> aj : A) { 1508 if (i != j /*!ai.equals(aj)*/) { 1509 b = b.multiply(aj); 1510 } 1511 j++; 1512 } 1513 //System.out.println("b = " + b); 1514 b = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b)); 1515 B.add(b); 1516 i++; 1517 } 1518 //System.out.println("B = " + B); 1519 // check mod p^e 1520 GenPolynomial<MOD> t = fac.getZERO(); 1521 i = 0; 1522 for (GenPolynomial<MOD> a : B) { 1523 GenPolynomial<MOD> b = S.get(i++); 1524 b = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b)); 1525 GenPolynomial<MOD> s = a.multiply(b); 1526 t = t.sum(s); 1527 } 1528 if (!t.equals(C)) { 1529 if (debug) { 1530 System.out.println("no diophant lift!"); 1531 System.out.println("A = " + A); 1532 System.out.println("B = " + B); 1533 System.out.println("S = " + S); 1534 System.out.println("C = " + C); 1535 System.out.println("t = " + t); 1536 } 1537 return false; 1538 } 1539 return true; 1540 } 1541 1542 1543 /** 1544 * Modular Hensel lifting algorithm on coefficients. Let p = 1545 * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with 1546 * gcd(f_i,f_j) == 1 mod p for i != j 1547 * @param C monic integer polynomial 1548 * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials. 1549 * @param k approximation exponent. 1550 * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k. 1551 */ 1552 @SuppressWarnings("unchecked") 1553 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHenselMonic( 1554 GenPolynomial<BigInteger> C, List<GenPolynomial<MOD>> F, long k) 1555 throws NoLiftingException { 1556 if (C == null || C.isZERO() || F == null || F.size() == 0) { 1557 throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); 1558 } 1559 GenPolynomialRing<BigInteger> fac = C.ring; 1560 if (fac.nvar != 1) { // assert ? 1561 throw new IllegalArgumentException("polynomial ring not univariate"); 1562 } 1563 List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(F.size()); 1564 GenPolynomialRing<MOD> pfac = F.get(0).ring; 1565 RingFactory<MOD> pcfac = pfac.coFac; 1566 ModularRingFactory<MOD> PF = (ModularRingFactory<MOD>) pcfac; 1567 BigInteger P = PF.getIntegerModul(); 1568 int n = F.size(); 1569 if (n == 1) { // lift F_0, this case will probably never be used 1570 GenPolynomial<MOD> f = F.get(0); 1571 ModularRingFactory<MOD> mcfac; 1572 if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) { 1573 mcfac = (ModularRingFactory) new ModLongRing(P.getVal()); 1574 } else { 1575 mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal()); 1576 } 1577 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1578 f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f)); 1579 lift.add(f); 1580 return lift; 1581 } 1582 // if (n == 2) { // only one step 1583 // HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, F.get(0), F.get(1)); 1584 // lift.add(ab.Am); 1585 // lift.add(ab.Bm); 1586 // return lift; 1587 // } 1588 1589 // setup integer polynomial ring 1590 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1591 List<GenPolynomial<BigInteger>> Fi = PolyUtil.integerFromModularCoefficients(ifac, F); 1592 //System.out.println("Fi = " + Fi); 1593 1594 List<GenPolynomial<MOD>> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this 1595 //System.out.println("Sext = " + S); 1596 if (debug) { 1597 logger.info("EE lift = " + S); 1598 // adjust coefficients 1599 List<GenPolynomial<MOD>> Sx = PolyUtil.fromIntegerCoefficients(pfac, 1600 PolyUtil.integerFromModularCoefficients(ifac, S)); 1601 try { 1602 boolean il = HenselUtil.<MOD> isExtendedEuclideanLift(F, Sx); 1603 //System.out.println("islift = " + il); 1604 } catch (RuntimeException e) { 1605 e.printStackTrace(); 1606 } 1607 } 1608 List<GenPolynomial<BigInteger>> Si = PolyUtil.integerFromModularCoefficients(ifac, S); 1609 //System.out.println("Si = " + Si); 1610 //System.out.println("C = " + C); 1611 1612 // approximate mod p^i 1613 ModularRingFactory<MOD> mcfac = PF; 1614 BigInteger p = mcfac.getIntegerModul(); 1615 BigInteger modul = p; 1616 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1617 List<GenPolynomial<MOD>> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si); 1618 //System.out.println("Sp = " + Sp); 1619 for (int i = 1; i < k; i++) { 1620 //System.out.println("i = " + i); 1621 GenPolynomial<BigInteger> e = fac.getONE(); 1622 for (GenPolynomial<BigInteger> fi : Fi) { 1623 e = e.multiply(fi); 1624 } 1625 e = C.subtract(e); 1626 //System.out.println("\ne = " + e); 1627 if (e.isZERO()) { 1628 logger.info("leaving on zero e"); 1629 break; 1630 } 1631 try { 1632 e = e.divide(modul); 1633 } catch (RuntimeException ex) { 1634 ex.printStackTrace(); 1635 throw ex; 1636 } 1637 //System.out.println("e = " + e); 1638 // move to in Z_p[x] 1639 GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(mfac, e); 1640 //System.out.println("c = " + c + ": " + c.ring.coFac); 1641 1642 List<GenPolynomial<MOD>> s = new ArrayList<GenPolynomial<MOD>>(S.size()); 1643 int j = 0; 1644 for (GenPolynomial<MOD> f : Sp) { 1645 f = f.multiply(c); 1646 //System.out.println("f = " + f + " : " + f.ring.coFac); 1647 //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac); 1648 f = f.remainder(F.get(j++)); 1649 //System.out.println("f = " + f + " : " + f.ring.coFac); 1650 s.add(f); 1651 } 1652 //System.out.println("s = " + s); 1653 List<GenPolynomial<BigInteger>> si = PolyUtil.integerFromModularCoefficients(ifac, s); 1654 //System.out.println("si = " + si); 1655 1656 List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size()); 1657 j = 0; 1658 for (GenPolynomial<BigInteger> f : Fi) { 1659 f = f.sum(si.get(j++).multiply(modul)); 1660 Fii.add(f); 1661 } 1662 //System.out.println("Fii = " + Fii); 1663 Fi = Fii; 1664 modul = modul.multiply(p); 1665 if (i >= k - 1) { 1666 logger.info("e != 0 for k = " + k); 1667 } 1668 } 1669 // setup ring mod p^k 1670 modul = p.power(k); 1671 if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { 1672 mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); 1673 } else { 1674 mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); 1675 } 1676 //System.out.println("mcfac = " + mcfac); 1677 mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1678 lift = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Fi); 1679 //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac); 1680 return lift; 1681 } 1682 1683 1684 /** 1685 * Modular Hensel lifting algorithm on coefficients. Let p = 1686 * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with 1687 * gcd(f_i,f_j) == 1 mod p for i != j 1688 * @param C integer polynomial 1689 * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials. 1690 * @param k approximation exponent. 1691 * @param g leading coefficient. 1692 * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k. 1693 */ 1694 @SuppressWarnings("unchecked") 1695 public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHensel( 1696 GenPolynomial<BigInteger> C, List<GenPolynomial<MOD>> F, long k, BigInteger g) 1697 throws NoLiftingException { 1698 if (C == null || C.isZERO() || F == null || F.size() == 0) { 1699 throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); 1700 } 1701 GenPolynomialRing<BigInteger> fac = C.ring; 1702 if (fac.nvar != 1) { // assert ? 1703 throw new IllegalArgumentException("polynomial ring not univariate"); 1704 } 1705 List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(F.size()); 1706 GenPolynomialRing<MOD> pfac = F.get(0).ring; 1707 RingFactory<MOD> pcfac = pfac.coFac; 1708 ModularRingFactory<MOD> PF = (ModularRingFactory<MOD>) pcfac; 1709 BigInteger P = PF.getIntegerModul(); 1710 int n = F.size(); 1711 if (n == 1) { // lift F_0, this case will probably never be used 1712 GenPolynomial<MOD> f = F.get(0); 1713 ModularRingFactory<MOD> mcfac; 1714 if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) { 1715 mcfac = (ModularRingFactory) new ModLongRing(P.getVal()); 1716 } else { 1717 mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal()); 1718 } 1719 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1720 f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f)); 1721 lift.add(f); 1722 return lift; 1723 } 1724 // if (n == 2) { // only one step 1725 // HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, F.get(0), F.get(1)); 1726 // lift.add(ab.Am); 1727 // lift.add(ab.Bm); 1728 // return lift; 1729 // } 1730 1731 // normalize C and F_i factors 1732 BigInteger cc = g; //C.leadingBaseCoefficient(); // == g ?? 1733 for (int i = 1; i < F.size(); i++) { // #F-1 1734 C = C.multiply(cc); // sic 1735 } 1736 MOD cm = PF.fromInteger(cc.getVal()); 1737 List<GenPolynomial<MOD>> Fp = new ArrayList<GenPolynomial<MOD>>(F.size()); 1738 for (GenPolynomial<MOD> fm : F) { 1739 GenPolynomial<MOD> am = fm.monic(); 1740 am = am.multiply(cm); 1741 Fp.add(am); 1742 } 1743 F = Fp; 1744 1745 // setup integer polynomial ring 1746 GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac); 1747 List<GenPolynomial<BigInteger>> Fi = PolyUtil.integerFromModularCoefficients(ifac, F); 1748 //System.out.println("Fi = " + Fi); 1749 1750 // inplace modify polynomials, replace leading coefficient 1751 for (GenPolynomial<BigInteger> ai : Fi) { 1752 if (ai.isZERO()) { 1753 continue; 1754 } 1755 ExpVector ea = ai.leadingExpVector(); 1756 ai.doPutToMap(ea, cc); 1757 } 1758 //System.out.println("Fi = " + Fi); 1759 1760 List<GenPolynomial<MOD>> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this 1761 //System.out.println("Sext = " + S); 1762 if (debug) { 1763 logger.info("EE lift = " + S); 1764 // adjust coefficients 1765 List<GenPolynomial<MOD>> Sx = PolyUtil.fromIntegerCoefficients(pfac, 1766 PolyUtil.integerFromModularCoefficients(ifac, S)); 1767 try { 1768 boolean il = HenselUtil.<MOD> isExtendedEuclideanLift(F, Sx); 1769 //System.out.println("islift = " + il); 1770 } catch (RuntimeException e) { 1771 e.printStackTrace(); 1772 } 1773 } 1774 List<GenPolynomial<BigInteger>> Si = PolyUtil.integerFromModularCoefficients(ifac, S); 1775 //System.out.println("Si = " + Si); 1776 //System.out.println("C = " + C); 1777 1778 // approximate mod p^i 1779 ModularRingFactory<MOD> mcfac = PF; 1780 BigInteger p = mcfac.getIntegerModul(); 1781 BigInteger modul = p; 1782 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1783 List<GenPolynomial<MOD>> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si); 1784 //System.out.println("Sp = " + Sp); 1785 for (int i = 1; i < k; i++) { 1786 //System.out.println("i = " + i); 1787 GenPolynomial<BigInteger> e = fac.getONE(); 1788 for (GenPolynomial<BigInteger> fi : Fi) { 1789 e = e.multiply(fi); 1790 } 1791 e = C.subtract(e); 1792 //System.out.println("\ne = " + e); 1793 if (e.isZERO()) { 1794 logger.info("leaving on zero e"); 1795 break; 1796 } 1797 try { 1798 e = e.divide(modul); 1799 } catch (RuntimeException ex) { 1800 ex.printStackTrace(); 1801 throw ex; 1802 } 1803 //System.out.println("e = " + e); 1804 // move to in Z_p[x] 1805 GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(mfac, e); 1806 //System.out.println("c = " + c + ": " + c.ring.coFac); 1807 1808 List<GenPolynomial<MOD>> s = new ArrayList<GenPolynomial<MOD>>(S.size()); 1809 int j = 0; 1810 for (GenPolynomial<MOD> f : Sp) { 1811 f = f.multiply(c); 1812 //System.out.println("f = " + f + " : " + f.ring.coFac); 1813 //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac); 1814 f = f.remainder(F.get(j++)); 1815 //System.out.println("f = " + f + " : " + f.ring.coFac); 1816 s.add(f); 1817 } 1818 //System.out.println("s = " + s); 1819 List<GenPolynomial<BigInteger>> si = PolyUtil.integerFromModularCoefficients(ifac, s); 1820 //System.out.println("si = " + si); 1821 1822 List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size()); 1823 j = 0; 1824 for (GenPolynomial<BigInteger> f : Fi) { 1825 f = f.sum(si.get(j++).multiply(modul)); 1826 Fii.add(f); 1827 } 1828 //System.out.println("Fii = " + Fii); 1829 Fi = Fii; 1830 modul = modul.multiply(p); 1831 if (i >= k - 1) { 1832 logger.info("e != 0 for k = " + k); 1833 } 1834 } 1835 //System.out.println("Fi = " + Fi); 1836 // remove normalization 1837 GreatestCommonDivisorAbstract<BigInteger> ufd = GCDFactory.getImplementation(cc); 1838 //BigInteger ai = ufd.baseContent(Fi.get(0)); 1839 //System.out.println("ai = " + ai + ", cc = " + cc); 1840 List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size()); 1841 //int j = 0; 1842 for (GenPolynomial<BigInteger> bi : Fi) { 1843 GenPolynomial<BigInteger> ci = null; 1844 //if ( j++ == 0 ) { 1845 // ci = bi.divide(ai); 1846 //} else { 1847 // BigInteger i = cc.divide(ai); 1848 // ci = bi.divide(i); 1849 //} 1850 ci = ufd.basePrimitivePart(bi); // ?? 1851 //System.out.println("bi = " + bi + ", ci = " + ci); 1852 Fii.add(ci); 1853 } 1854 Fi = Fii; 1855 1856 // setup ring mod p^k 1857 modul = p.power(k); 1858 if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { 1859 mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); 1860 } else { 1861 mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); 1862 } 1863 //System.out.println("mcfac = " + mcfac); 1864 mfac = new GenPolynomialRing<MOD>(mcfac, fac); 1865 lift = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Fi); 1866 //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac); 1867 return lift; 1868 } 1869 1870}