[Home] DMelt member access. Java source code: edu.jas.ufd.HenselUtil
/*
* $Id$
*/
package edu.jas.ufd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.Logger;
import edu.jas.arith.BigInteger;
import edu.jas.arith.ModInteger;
import edu.jas.arith.ModIntegerRing;
import edu.jas.arith.ModLongRing;
import edu.jas.arith.Modular;
import edu.jas.arith.ModularRingFactory;
import edu.jas.poly.ExpVector;
import edu.jas.poly.GenPolynomial;
import edu.jas.poly.GenPolynomialRing;
import edu.jas.poly.Monomial;
import edu.jas.poly.PolyUtil;
import edu.jas.structure.GcdRingElem;
import edu.jas.structure.RingFactory;
import edu.jas.structure.Power;
/**
* Hensel utilities for ufd.
* @author Heinz Kredel
*/
public class HenselUtil {
private static final Logger logger = Logger.getLogger(HenselUtil.class);
private static final boolean debug = logger.isDebugEnabled();
/**
* Modular Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See Algorithm 6.1. in
* Geddes et.al.. Linear version, as it does not lift S A + T B == 1 mod
* p^{e+1}.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param S GenPolynomial
* @param T GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1,Am,Bm] = lift(C,A,B), with C = A1 * B1 mod p^e, Am = A1
* mod p^e, Bm = B1 mod p^e .
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHensel(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B,
GenPolynomial S, GenPolynomial T) throws NoLiftingException {
if (C == null || C.isZERO()) {
return new HenselApprox(C, C, A, B);
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// setup factories
GenPolynomialRing pfac = A.ring;
RingFactory p = pfac.coFac;
RingFactory q = p;
ModularRingFactory P = (ModularRingFactory) p;
ModularRingFactory Q = (ModularRingFactory) q;
BigInteger Qi = Q.getIntegerModul();
BigInteger M2 = M.multiply(M.fromInteger(2));
BigInteger Mq = Qi;
// normalize c and a, b factors, assert p is prime
GenPolynomial Ai;
GenPolynomial Bi;
BigInteger c = C.leadingBaseCoefficient();
C = C.multiply(c); // sic
MOD a = A.leadingBaseCoefficient();
if (!a.isONE()) { // A = A.monic();
A = A.divide(a);
S = S.multiply(a);
}
MOD b = B.leadingBaseCoefficient();
if (!b.isONE()) { // B = B.monic();
B = B.divide(b);
T = T.multiply(b);
}
MOD cm = P.fromInteger(c.getVal());
A = A.multiply(cm);
B = B.multiply(cm);
T = T.divide(cm);
S = S.divide(cm);
Ai = PolyUtil.integerFromModularCoefficients(fac, A);
Bi = PolyUtil.integerFromModularCoefficients(fac, B);
// replace leading base coefficients
ExpVector ea = Ai.leadingExpVector();
ExpVector eb = Bi.leadingExpVector();
Ai.doPutToMap(ea, c);
Bi.doPutToMap(eb, c);
// polynomials mod p
GenPolynomial Ap;
GenPolynomial Bp;
GenPolynomial A1p = A;
GenPolynomial B1p = B;
GenPolynomial Ep;
// polynomials over the integers
GenPolynomial E;
GenPolynomial Ea;
GenPolynomial Eb;
GenPolynomial Ea1;
GenPolynomial Eb1;
while (Mq.compareTo(M2) < 0) {
// compute E=(C-AB)/q over the integers
E = C.subtract(Ai.multiply(Bi));
if (E.isZERO()) {
logger.info("leaving on zero E");
break;
}
try {
E = E.divide(Qi);
} catch (RuntimeException e) {
// useful in debuging
//System.out.println("C = " + C );
//System.out.println("Ai = " + Ai );
//System.out.println("Bi = " + Bi );
//System.out.println("E = " + E );
//System.out.println("Qi = " + Qi );
throw e;
}
// E mod p
Ep = PolyUtil. fromIntegerCoefficients(pfac, E);
//logger.info("Ep = " + Ep);
// construct approximation mod p
Ap = S.multiply(Ep); // S,T ++ T,S
Bp = T.multiply(Ep);
GenPolynomial[] QR;
QR = Ap.quotientRemainder(B);
GenPolynomial Qp;
GenPolynomial Rp;
Qp = QR[0];
Rp = QR[1];
A1p = Rp;
B1p = Bp.sum(A.multiply(Qp));
// construct q-adic approximation, convert to integer
Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
Ea1 = Ea.multiply(Qi);
Eb1 = Eb.multiply(Qi);
Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required
Eb = Bi.sum(Ea1); //--------------------------
assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0));
//if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug
// throw new RuntimeException("deg(A)+deg(B) > deg(C)");
//}
// prepare for next iteration
Mq = Qi;
Qi = Q.getIntegerModul().multiply(P.getIntegerModul());
// Q = new ModIntegerRing(Qi.getVal());
if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
} else {
Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
}
Ai = Ea;
Bi = Eb;
}
GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive();
// remove normalization
BigInteger ai = ufd.baseContent(Ai);
Ai = Ai.divide(ai);
BigInteger bi = null;
try {
bi = c.divide(ai);
Bi = Bi.divide(bi); // divide( c/a )
} catch (RuntimeException e) {
//System.out.println("C = " + C );
//System.out.println("Ai = " + Ai );
//System.out.println("Bi = " + Bi );
//System.out.println("c = " + c );
//System.out.println("ai = " + ai );
//System.out.println("bi = " + bi );
//System.out.println("no exact lifting possible " + e);
throw new NoLiftingException("no exact lifting possible " + e);
}
return new HenselApprox(Ai, Bi, A1p, B1p);
}
/**
* Modular Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
* algorithms 3.5.{5,6} in Cohen.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHensel(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B)
throws NoLiftingException {
if (C == null || C.isZERO()) {
return new HenselApprox(C, C, A, B);
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// one Hensel step on part polynomials
try {
GenPolynomial[] gst = A.egcd(B);
if (!gst[0].isONE()) {
throw new NoLiftingException("A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
}
GenPolynomial s = gst[1];
GenPolynomial t = gst[2];
HenselApprox ab = HenselUtil. liftHensel(C, M, A, B, s, t);
return ab;
} catch (ArithmeticException e) {
throw new NoLiftingException("coefficient error " + e);
}
}
/**
* Modular quadratic Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in
* Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it
* also lifts S A + T B == 1 mod p^{e+1}.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param S GenPolynomial
* @param T GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHenselQuadratic(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B,
GenPolynomial S, GenPolynomial T) throws NoLiftingException {
if (C == null || C.isZERO()) {
return new HenselApprox(C, C, A, B);
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// setup factories
GenPolynomialRing pfac = A.ring;
RingFactory p = pfac.coFac;
RingFactory q = p;
ModularRingFactory P = (ModularRingFactory) p;
ModularRingFactory Q = (ModularRingFactory) q;
BigInteger Qi = Q.getIntegerModul();
BigInteger M2 = M.multiply(M.fromInteger(2));
BigInteger Mq = Qi;
GenPolynomialRing qfac;
qfac = new GenPolynomialRing(Q, pfac);
// normalize c and a, b factors, assert p is prime
GenPolynomial Ai;
GenPolynomial Bi;
BigInteger c = C.leadingBaseCoefficient();
C = C.multiply(c); // sic
MOD a = A.leadingBaseCoefficient();
if (!a.isONE()) { // A = A.monic();
A = A.divide(a);
S = S.multiply(a);
}
MOD b = B.leadingBaseCoefficient();
if (!b.isONE()) { // B = B.monic();
B = B.divide(b);
T = T.multiply(b);
}
MOD cm = P.fromInteger(c.getVal());
A = A.multiply(cm);
B = B.multiply(cm);
T = T.divide(cm);
S = S.divide(cm);
Ai = PolyUtil.integerFromModularCoefficients(fac, A);
Bi = PolyUtil.integerFromModularCoefficients(fac, B);
// replace leading base coefficients
ExpVector ea = Ai.leadingExpVector();
ExpVector eb = Bi.leadingExpVector();
Ai.doPutToMap(ea, c);
Bi.doPutToMap(eb, c);
// polynomials mod p
GenPolynomial Ap;
GenPolynomial Bp;
GenPolynomial A1p = A;
GenPolynomial B1p = B;
GenPolynomial Ep;
GenPolynomial Sp = S;
GenPolynomial Tp = T;
// polynomials mod q
GenPolynomial Aq;
GenPolynomial Bq;
GenPolynomial Eq;
// polynomials over the integers
GenPolynomial E;
GenPolynomial Ea;
GenPolynomial Eb;
GenPolynomial Ea1;
GenPolynomial Eb1;
GenPolynomial Si;
GenPolynomial Ti;
Si = PolyUtil.integerFromModularCoefficients(fac, S);
Ti = PolyUtil.integerFromModularCoefficients(fac, T);
Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai);
Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi);
while (Mq.compareTo(M2) < 0) {
// compute E=(C-AB)/q over the integers
E = C.subtract(Ai.multiply(Bi));
if (E.isZERO()) {
logger.info("leaving on zero E");
break;
}
E = E.divide(Qi);
// E mod p
Ep = PolyUtil. fromIntegerCoefficients(qfac, E);
//logger.info("Ep = " + Ep + ", qfac = " + qfac);
//if (Ep.isZERO()) {
//System.out.println("leaving on zero error");
//??logger.info("leaving on zero Ep");
//??break;
//}
// construct approximation mod p
Ap = Sp.multiply(Ep); // S,T ++ T,S
Bp = Tp.multiply(Ep);
GenPolynomial[] QR;
//logger.info("Ap = " + Ap + ", Bp = " + Bp + ", fac(Ap) = " + Ap.ring);
QR = Ap.quotientRemainder(Bq);
GenPolynomial Qp;
GenPolynomial Rp;
Qp = QR[0];
Rp = QR[1];
//logger.info("Qp = " + Qp + ", Rp = " + Rp);
A1p = Rp;
B1p = Bp.sum(Aq.multiply(Qp));
// construct q-adic approximation, convert to integer
Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
Ea1 = Ea.multiply(Qi);
Eb1 = Eb.multiply(Qi);
Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required
Eb = Bi.sum(Ea1); //--------------------------
assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0));
//if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug
// throw new RuntimeException("deg(A)+deg(B) > deg(C)");
//}
Ai = Ea;
Bi = Eb;
// gcd representation factors error --------------------------------
// compute E=(1-SA-TB)/q over the integers
E = fac.getONE();
E = E.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi));
E = E.divide(Qi);
// E mod q
Ep = PolyUtil. fromIntegerCoefficients(qfac, E);
//logger.info("Ep2 = " + Ep);
// construct approximation mod q
Ap = Sp.multiply(Ep); // S,T ++ T,S
Bp = Tp.multiply(Ep);
QR = Bp.quotientRemainder(Aq); // Ai == A mod p ?
Qp = QR[0];
Rp = QR[1];
B1p = Rp;
A1p = Ap.sum(Bq.multiply(Qp));
if (false && debug) {
Eq = A1p.multiply(Aq).sum(B1p.multiply(Bq)).subtract(Ep);
if (!Eq.isZERO()) {
System.out.println("A*A1p+B*B1p-Ep2 != 0 " + Eq);
throw new RuntimeException("A*A1p+B*B1p-Ep2 != 0 mod " + Q.getIntegerModul());
}
}
// construct q-adic approximation, convert to integer
Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
Ea1 = Ea.multiply(Qi);
Eb1 = Eb.multiply(Qi);
Ea = Si.sum(Ea1); // Eb1 and Ea1 are required
Eb = Ti.sum(Eb1); //--------------------------
Si = Ea;
Ti = Eb;
// prepare for next iteration
Mq = Qi;
Qi = Q.getIntegerModul().multiply(Q.getIntegerModul());
if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
} else {
Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
}
//Q = new ModIntegerRing(Qi.getVal());
//System.out.println("Q = " + Q + ", from Q = " + Mq);
qfac = new GenPolynomialRing(Q, pfac);
Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai);
Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi);
Sp = PolyUtil. fromIntegerCoefficients(qfac, Si);
Tp = PolyUtil. fromIntegerCoefficients(qfac, Ti);
if (false && debug) {
E = Ai.multiply(Si).sum(Bi.multiply(Ti));
Eq = PolyUtil. fromIntegerCoefficients(qfac, E);
if (!Eq.isONE()) {
System.out.println("Ai*Si+Bi*Ti=1 " + Eq);
throw new RuntimeException("Ai*Si+Bi*Ti != 1 mod " + Q.getIntegerModul());
}
}
}
GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive();
// remove normalization if possible
BigInteger ai = ufd.baseContent(Ai);
Ai = Ai.divide(ai);
BigInteger bi = null;
try {
bi = c.divide(ai);
Bi = Bi.divide(bi); // divide( c/a )
} catch (RuntimeException e) {
//System.out.println("C = " + C );
//System.out.println("Ai = " + Ai );
//System.out.println("Bi = " + Bi );
//System.out.println("c = " + c );
//System.out.println("ai = " + ai );
//System.out.println("bi = " + bi );
//System.out.println("no exact lifting possible " + e);
throw new NoLiftingException("no exact lifting possible " + e);
}
return new HenselApprox(Ai, Bi, A1p, B1p);
}
/**
* Modular quadratic Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
* algorithms 3.5.{5,6} in Cohen. Quadratic version.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHenselQuadratic(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B)
throws NoLiftingException {
if (C == null || C.isZERO()) {
return new HenselApprox(C, C, A, B);
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// one Hensel step on part polynomials
try {
GenPolynomial[] gst = A.egcd(B);
if (!gst[0].isONE()) {
throw new NoLiftingException("A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
}
GenPolynomial s = gst[1];
GenPolynomial t = gst[2];
HenselApprox ab = HenselUtil. liftHenselQuadratic(C, M, A, B, s, t);
return ab;
} catch (ArithmeticException e) {
throw new NoLiftingException("coefficient error " + e);
}
}
/**
* Modular Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
* algorithms 3.5.{5,6} in Cohen. Quadratic version.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHenselQuadraticFac(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B)
throws NoLiftingException {
if (C == null || C.isZERO()) {
throw new IllegalArgumentException("C must be nonzero");
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// one Hensel step on part polynomials
try {
GenPolynomial[] gst = A.egcd(B);
if (!gst[0].isONE()) {
throw new NoLiftingException("A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
}
GenPolynomial s = gst[1];
GenPolynomial t = gst[2];
HenselApprox ab = HenselUtil. liftHenselQuadraticFac(C, M, A, B, s, t);
return ab;
} catch (ArithmeticException e) {
throw new NoLiftingException("coefficient error " + e);
}
}
/**
* Modular Hensel lifting algorithm on coefficients. Let p =
* A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
* with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in
* Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it
* also lifts S A + T B == 1 mod p^{e+1}.
* @param C primitive GenPolynomial
* @param A GenPolynomial
* @param B other GenPolynomial
* @param S GenPolynomial
* @param T GenPolynomial
* @param M bound on the coefficients of A1 and B1 as factors of C.
* @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
*/
@SuppressWarnings("unchecked")
public static & Modular> HenselApprox liftHenselQuadraticFac(
GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B,
GenPolynomial S, GenPolynomial T) throws NoLiftingException {
//System.out.println("*** version for factorization *** ");
//GenPolynomial[] AB = new GenPolynomial[2];
if (C == null || C.isZERO()) {
throw new IllegalArgumentException("C must be nonzero");
}
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero");
}
GenPolynomialRing fac = C.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// setup factories
GenPolynomialRing pfac = A.ring;
RingFactory p = pfac.coFac;
RingFactory q = p;
ModularRingFactory P = (ModularRingFactory) p;
ModularRingFactory Q = (ModularRingFactory) q;
BigInteger PP = Q.getIntegerModul();
BigInteger Qi = PP;
BigInteger M2 = M.multiply(M.fromInteger(2));
if (debug) {
//System.out.println("M2 = " + M2);
logger.debug("M2 = " + M2);
}
BigInteger Mq = Qi;
GenPolynomialRing qfac;
qfac = new GenPolynomialRing(Q, pfac); // mod p
GenPolynomialRing mfac;
BigInteger Mi = Q.getIntegerModul().multiply(Q.getIntegerModul());
ModularRingFactory Qmm;
// = new ModIntegerRing(Mi.getVal());
if (ModLongRing.MAX_LONG.compareTo(Mi.getVal()) > 0) {
Qmm = (ModularRingFactory) new ModLongRing(Mi.getVal());
} else {
Qmm = (ModularRingFactory) new ModIntegerRing(Mi.getVal());
}
mfac = new GenPolynomialRing(Qmm, qfac); // mod p^e
MOD Qm = Qmm.fromInteger(Qi.getVal());
// partly normalize c and a, b factors, assert p is prime
GenPolynomial Ai;
GenPolynomial Bi;
BigInteger c = C.leadingBaseCoefficient();
C = C.multiply(c); // sic
MOD a = A.leadingBaseCoefficient();
if (!a.isONE()) { // A = A.monic();
A = A.divide(a);
S = S.multiply(a);
}
MOD b = B.leadingBaseCoefficient();
if (!b.isONE()) { // B = B.monic();
B = B.divide(b);
T = T.multiply(b);
}
MOD cm = P.fromInteger(c.getVal());
if (cm.isZERO()) {
System.out.println("c = " + c);
System.out.println("P = " + P);
throw new ArithmeticException("c mod p == 0 not meaningful");
}
// mod p
A = A.multiply(cm);
S = S.divide(cm);
B = B.multiply(cm);
T = T.divide(cm);
Ai = PolyUtil.integerFromModularCoefficients(fac, A);
Bi = PolyUtil.integerFromModularCoefficients(fac, B);
// replace leading base coefficients
ExpVector ea = Ai.leadingExpVector();
ExpVector eb = Bi.leadingExpVector();
Ai.doPutToMap(ea, c);
Bi.doPutToMap(eb, c);
// polynomials mod p
GenPolynomial Ap;
GenPolynomial Bp;
GenPolynomial A1p = A;
GenPolynomial B1p = B;
GenPolynomial Sp = S;
GenPolynomial Tp = T;
// polynomials mod q
GenPolynomial Aq;
GenPolynomial Bq;
// polynomials mod p^e
GenPolynomial Cm;
GenPolynomial Am;
GenPolynomial Bm;
GenPolynomial Em;
GenPolynomial Emp;
GenPolynomial Sm;
GenPolynomial Tm;
GenPolynomial Ema;
GenPolynomial Emb;
GenPolynomial Ema1;
GenPolynomial Emb1;
// polynomials over the integers
GenPolynomial Ei;
GenPolynomial Si;
GenPolynomial Ti;
Si = PolyUtil.integerFromModularCoefficients(fac, S);
Ti = PolyUtil.integerFromModularCoefficients(fac, T);
Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai);
Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi);
// polynomials mod p^e
Cm = PolyUtil. fromIntegerCoefficients(mfac, C);
Am = PolyUtil. fromIntegerCoefficients(mfac, Ai);
Bm = PolyUtil. fromIntegerCoefficients(mfac, Bi);
Sm = PolyUtil. fromIntegerCoefficients(mfac, Si);
Tm = PolyUtil. fromIntegerCoefficients(mfac, Ti);
//System.out.println("Cm = " + Cm);
//System.out.println("Am = " + Am);
//System.out.println("Bm = " + Bm);
//System.out.println("Ai = " + Ai);
//System.out.println("Bi = " + Bi);
//System.out.println("mfac = " + mfac);
while (Mq.compareTo(M2) < 0) {
// compute E=(C-AB)/p mod p^e
if (debug) {
//System.out.println("mfac = " + Cm.ring);
logger.debug("mfac = " + Cm.ring);
}
Em = Cm.subtract(Am.multiply(Bm));
//System.out.println("Em = " + Em);
if (Em.isZERO()) {
if (C.subtract(Ai.multiply(Bi)).isZERO()) {
logger.info("leaving on zero E");
break;
}
}
// Em = Em.divide( Qm );
Ei = PolyUtil.integerFromModularCoefficients(fac, Em);
Ei = Ei.divide(Qi);
//System.out.println("Ei = " + Ei);
// Ei mod p
Emp = PolyUtil. fromIntegerCoefficients(qfac, Ei);
// Emp = PolyUtil.fromIntegerCoefficients(qfac,
// PolyUtil.integerFromModularCoefficients(fac,Em) );
//System.out.println("Emp = " + Emp);
//logger.info("Emp = " + Emp);
if (Emp.isZERO()) {
if (C.subtract(Ai.multiply(Bi)).isZERO()) {
logger.info("leaving on zero Emp");
break;
}
}
// construct approximation mod p
Ap = Sp.multiply(Emp); // S,T ++ T,S
Bp = Tp.multiply(Emp);
GenPolynomial[] QR = null;
QR = Ap.quotientRemainder(Bq); // Bq !
GenPolynomial Qp = QR[0];
GenPolynomial Rp = QR[1];
A1p = Rp;
B1p = Bp.sum(Aq.multiply(Qp)); // Aq !
//System.out.println("A1p = " + A1p);
//System.out.println("B1p = " + B1p);
// construct q-adic approximation
Ema = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac,
A1p));
Emb = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac,
B1p));
//System.out.println("Ema = " + Ema);
//System.out.println("Emb = " + Emb);
Ema1 = Ema.multiply(Qm);
Emb1 = Emb.multiply(Qm);
Ema = Am.sum(Emb1); // Eb1 and Ea1 are required
Emb = Bm.sum(Ema1); //--------------------------
assert (Ema.degree(0) + Emb.degree(0) <= Cm.degree(0));
//if ( Ema.degree(0)+Emb.degree(0) > Cm.degree(0) ) { // debug
// throw new RuntimeException("deg(A)+deg(B) > deg(C)");
//}
Am = Ema;
Bm = Emb;
Ai = PolyUtil.integerFromModularCoefficients(fac, Am);
Bi = PolyUtil.integerFromModularCoefficients(fac, Bm);
//System.out.println("Am = " + Am);
//System.out.println("Bm = " + Bm);
//System.out.println("Ai = " + Ai);
//System.out.println("Bi = " + Bi + "\n");
// gcd representation factors error --------------------------------
// compute E=(1-SA-TB)/p mod p^e
Em = mfac.getONE();
Em = Em.subtract(Sm.multiply(Am)).subtract(Tm.multiply(Bm));
//System.out.println("Em = " + Em);
// Em = Em.divide( Pm );
Ei = PolyUtil.integerFromModularCoefficients(fac, Em);
Ei = Ei.divide(Qi);
//System.out.println("Ei = " + Ei);
// Ei mod p
Emp = PolyUtil. fromIntegerCoefficients(qfac, Ei);
//Emp = PolyUtil.fromIntegerCoefficients(qfac,
// PolyUtil.integerFromModularCoefficients(fac,Em) );
//System.out.println("Emp = " + Emp);
// construct approximation mod p
Ap = Sp.multiply(Emp); // S,T ++ T,S // Ep Eqp
Bp = Tp.multiply(Emp); // Ep Eqp
QR = Bp.quotientRemainder(Aq); // Ap Aq ! // Ai == A mod p ?
Qp = QR[0];
Rp = QR[1];
B1p = Rp;
A1p = Ap.sum(Bq.multiply(Qp));
//System.out.println("A1p = " + A1p);
//System.out.println("B1p = " + B1p);
// construct p^e-adic approximation
Ema = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac,
A1p));
Emb = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac,
B1p));
Ema1 = Ema.multiply(Qm);
Emb1 = Emb.multiply(Qm);
Ema = Sm.sum(Ema1); // Emb1 and Ema1 are required
Emb = Tm.sum(Emb1); //--------------------------
Sm = Ema;
Tm = Emb;
Si = PolyUtil.integerFromModularCoefficients(fac, Sm);
Ti = PolyUtil.integerFromModularCoefficients(fac, Tm);
//System.out.println("Sm = " + Sm);
//System.out.println("Tm = " + Tm);
//System.out.println("Si = " + Si);
//System.out.println("Ti = " + Ti + "\n");
// prepare for next iteration
Qi = Q.getIntegerModul().multiply(Q.getIntegerModul());
Mq = Qi;
//lmfac = mfac;
// Q = new ModIntegerRing(Qi.getVal());
if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
} else {
Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
}
qfac = new GenPolynomialRing(Q, pfac);
BigInteger Qmmi = Qmm.getIntegerModul().multiply(Qmm.getIntegerModul());
//Qmm = new ModIntegerRing(Qmmi.getVal());
if (ModLongRing.MAX_LONG.compareTo(Qmmi.getVal()) > 0) {
Qmm = (ModularRingFactory) new ModLongRing(Qmmi.getVal());
} else {
Qmm = (ModularRingFactory) new ModIntegerRing(Qmmi.getVal());
}
mfac = new GenPolynomialRing(Qmm, qfac);
Qm = Qmm.fromInteger(Qi.getVal());
Cm = PolyUtil. fromIntegerCoefficients(mfac, C);
Am = PolyUtil. fromIntegerCoefficients(mfac, Ai);
Bm = PolyUtil. fromIntegerCoefficients(mfac, Bi);
Sm = PolyUtil. fromIntegerCoefficients(mfac, Si);
Tm = PolyUtil. fromIntegerCoefficients(mfac, Ti);
assert (isHenselLift(C, Mi, PP, Ai, Bi));
Mi = Mi.fromInteger(Qmm.getIntegerModul().getVal());
Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai);
Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi);
Sp = PolyUtil. fromIntegerCoefficients(qfac, Si);
Tp = PolyUtil. fromIntegerCoefficients(qfac, Ti);
//System.out.println("Am = " + Am);
//System.out.println("Bm = " + Bm);
//System.out.println("Sm = " + Sm);
//System.out.println("Tm = " + Tm);
//System.out.println("mfac = " + mfac);
//System.out.println("Qmm = " + Qmm + ", M2 = " + M2 + ", Mq = " + Mq + "\n");
}
//System.out.println("*Ai = " + Ai);
//System.out.println("*Bi = " + Bi);
Em = Cm.subtract(Am.multiply(Bm));
if (!Em.isZERO()) {
System.out.println("Em = " + Em);
//throw new NoLiftingException("no exact lifting possible");
}
// remove normalization not possible when not exact factorization
GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive();
// remove normalization if possible
BigInteger ai = ufd.baseContent(Ai);
Ai = Ai.divide(ai); // Ai=pp(Ai)
BigInteger[] qr = c.quotientRemainder(ai);
BigInteger bi = null;
boolean exact = true;
if (qr[1].isZERO()) {
bi = qr[0];
try {
Bi = Bi.divide(bi); // divide( c/a )
} catch (RuntimeException e) {
System.out.println("*catch: no exact factorization: " + bi + ", e = " + e);
exact = false;
}
} else {
System.out.println("*remainder: no exact factorization: q = " + qr[0] + ", r = " + qr[1]);
exact = false;
}
if (!exact) {
System.out.println("*Ai = " + Ai);
System.out.println("*ai = " + ai);
System.out.println("*Bi = " + Bi);
System.out.println("*bi = " + bi);
System.out.println("*c = " + c);
throw new NoLiftingException("no exact lifting possible");
}
return new HenselApprox(Ai, Bi, Aq, Bq);
}
/**
* Modular Hensel lifting test. Let p be a prime number and assume C ==
* prod_{0,...,n-1} g_i mod p with gcd(g_i,g_j) == 1 mod p for i != j.
* @param C GenPolynomial
* @param G = [g_0,...,g_{n-1}] list of GenPolynomial
* @param M bound on the coefficients of g_i as factors of C.
* @param p prime number.
* @return true if C = prod_{0,...,n-1} g_i mod p^e, else false.
*/
public static// & Modular>
boolean isHenselLift(GenPolynomial C, BigInteger M, BigInteger p,
List> G) {
if (C == null || C.isZERO()) {
return false;
}
GenPolynomialRing pfac = C.ring;
ModIntegerRing pm = new ModIntegerRing(p.getVal(), true);
GenPolynomialRing mfac = new GenPolynomialRing(pm, pfac);
// check mod p
GenPolynomial cl = mfac.getONE();
GenPolynomial hlp;
for (GenPolynomial hl : G) {
//System.out.println("hl = " + hl);
hlp = PolyUtil. fromIntegerCoefficients(mfac, hl);
//System.out.println("hl mod p = " + hlp);
cl = cl.multiply(hlp);
}
GenPolynomial cp = PolyUtil. fromIntegerCoefficients(mfac, C);
if (!cp.equals(cl)) {
System.out.println("Hensel precondition wrong!");
if (debug) {
System.out.println("cl = " + cl);
System.out.println("cp = " + cp);
System.out.println("mon(cl) = " + cl.monic());
System.out.println("mon(cp) = " + cp.monic());
System.out.println("cp-cl = " + cp.subtract(cl));
System.out.println("M = " + M + ", p = " + p);
}
return false;
}
// check mod p^e
BigInteger mip = p;
while (mip.compareTo(M) < 0) {
mip = mip.multiply(mip); // p
}
// mip = mip.multiply(p);
pm = new ModIntegerRing(mip.getVal(), false);
mfac = new GenPolynomialRing(pm, pfac);
cl = mfac.getONE();
for (GenPolynomial hl : G) {
//System.out.println("hl = " + hl);
hlp = PolyUtil. fromIntegerCoefficients(mfac, hl);
//System.out.println("hl mod p^e = " + hlp);
cl = cl.multiply(hlp);
}
cp = PolyUtil. fromIntegerCoefficients(mfac, C);
if (!cp.equals(cl)) {
System.out.println("Hensel post condition wrong!");
System.out.println("cl = " + cl);
System.out.println("cp = " + cp);
System.out.println("cp-cl = " + cp.subtract(cl));
System.out.println("M = " + M + ", p = " + p + ", p^e = " + mip);
return false;
}
return true;
}
/**
* Modular Hensel lifting test. Let p be a prime number and assume C == A *
* B mod p with gcd(A,B) == 1 mod p.
* @param C GenPolynomial
* @param A GenPolynomial
* @param B GenPolynomial
* @param M bound on the coefficients of A and B as factors of C.
* @param p prime number.
* @return true if C = A * B mod p**e, else false.
*/
public static// & Modular>
boolean isHenselLift(GenPolynomial C, BigInteger M, BigInteger p,
GenPolynomial A, GenPolynomial B) {
List> G = new ArrayList>(2);
G.add(A);
G.add(B);
return isHenselLift(C, M, p, G);
}
/**
* Modular Hensel lifting test. Let p be a prime number and assume C == A *
* B mod p with gcd(A,B) == 1 mod p.
* @param C GenPolynomial
* @param Ha Hensel approximation.
* @param M bound on the coefficients of A and B as factors of C.
* @param p prime number.
* @return true if C = A * B mod p^e, else false.
*/
public static & Modular> boolean isHenselLift(GenPolynomial C,
BigInteger M, BigInteger p, HenselApprox Ha) {
List> G = new ArrayList>(2);
G.add(Ha.A);
G.add(Ha.B);
return isHenselLift(C, M, p, G);
}
/**
* Constructing and lifting algorithm for extended Euclidean relation. Let p
* = A.ring.coFac.modul() and assume gcd(A,B) == 1 mod p.
* @param A modular GenPolynomial
* @param B modular GenPolynomial
* @param k desired approximation exponent p^k.
* @return [s,t] with s A + t B = 1 mod p^k.
*/
@SuppressWarnings("unchecked")
public static & Modular> GenPolynomial[] liftExtendedEuclidean(
GenPolynomial A, GenPolynomial B, long k) throws NoLiftingException {
if (A == null || A.isZERO() || B == null || B.isZERO()) {
throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B);
}
GenPolynomialRing fac = A.ring;
if (fac.nvar != 1) { // todo assert
throw new IllegalArgumentException("polynomial ring not univariate");
}
// start with extended Euclidean relation mod p
GenPolynomial[] gst = null;
try {
gst = A.egcd(B);
if (!gst[0].isONE()) {
throw new NoLiftingException("A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
}
} catch (ArithmeticException e) {
throw new NoLiftingException("coefficient error " + e);
}
GenPolynomial S = gst[1];
GenPolynomial T = gst[2];
//System.out.println("eeS = " + S + ": " + S.ring.coFac);
//System.out.println("eeT = " + T + ": " + T.ring.coFac);
// setup integer polynomial ring
GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac);
GenPolynomial one = ifac.getONE();
GenPolynomial Ai = PolyUtil.integerFromModularCoefficients(ifac, A);
GenPolynomial Bi = PolyUtil.integerFromModularCoefficients(ifac, B);
GenPolynomial Si = PolyUtil.integerFromModularCoefficients(ifac, S);
GenPolynomial Ti = PolyUtil.integerFromModularCoefficients(ifac, T);
//System.out.println("Ai = " + Ai);
//System.out.println("Bi = " + Bi);
//System.out.println("Si = " + Si);
//System.out.println("Ti = " + Ti);
// approximate mod p^i
ModularRingFactory mcfac = (ModularRingFactory) fac.coFac;
BigInteger p = mcfac.getIntegerModul();
BigInteger modul = p;
GenPolynomialRing mfac; // = new GenPolynomialRing(mcfac, fac);
for (int i = 1; i < k; i++) {
// e = 1 - s a - t b in Z[x]
GenPolynomial e = one.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi));
//System.out.println("\ne = " + e);
if (e.isZERO()) {
logger.info("leaving on zero e in liftExtendedEuclidean");
break;
}
e = e.divide(modul);
// move to Z_p[x] and compute next approximation
GenPolynomial c = PolyUtil. fromIntegerCoefficients(fac, e);
//System.out.println("c = " + c + ": " + c.ring.coFac);
GenPolynomial s = S.multiply(c);
GenPolynomial t = T.multiply(c);
//System.out.println("s = " + s + ": " + s.ring.coFac);
//System.out.println("t = " + t + ": " + t.ring.coFac);
GenPolynomial[] QR = s.quotientRemainder(B); // watch for ordering
GenPolynomial