001/* 002 * $Id$ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.Iterator; 010import java.util.List; 011import java.util.SortedSet; 012import java.util.TreeSet; 013 014import org.apache.logging.log4j.LogManager; 015import org.apache.logging.log4j.Logger; 016 017import edu.jas.arith.ModLongRing; 018import edu.jas.arith.ModularRingFactory; 019import edu.jas.poly.AlgebraicNumberRing; 020import edu.jas.poly.GenPolynomial; 021import edu.jas.poly.GenPolynomialRing; 022import edu.jas.poly.PolyUtil; 023import edu.jas.structure.GcdRingElem; 024import edu.jas.structure.Power; 025import edu.jas.structure.RingFactory; 026import edu.jas.vector.GenMatrix; 027import edu.jas.vector.GenMatrixRing; 028import edu.jas.vector.GenVector; 029import edu.jas.vector.GenVectorModul; 030import edu.jas.vector.LinAlg; 031 032 033/** 034 * Modular coefficients Berlekamp factorization algorithms. This class 035 * implements Berlekamp, Cantor and Zassenhaus factorization methods for 036 * polynomials over (prime) modular integers. 037 * @author Heinz Kredel 038 */ 039 040public class FactorModularBerlekamp<MOD extends GcdRingElem<MOD>> extends FactorAbsolute<MOD> { 041 042 043 private static final Logger logger = LogManager.getLogger(FactorModularBerlekamp.class); 044 045 046 //private static final boolean debug = logger.isDebugEnabled(); 047 048 049 /** 050 * No argument constructor, do not use. 051 */ 052 @SuppressWarnings({ "unchecked", "unused" }) 053 private FactorModularBerlekamp() { 054 this((RingFactory<MOD>) (Object) new ModLongRing(13, true)); // hack, 13 unimportant 055 } 056 057 058 /** 059 * Constructor. 060 * @param cfac coefficient ring factory. 061 */ 062 public FactorModularBerlekamp(RingFactory<MOD> cfac) { 063 super(cfac); 064 } 065 066 067 /** 068 * GenPolynomial base factorization of a squarefree polynomial. 069 * @param P squarefree and monic! GenPolynomial. 070 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 071 */ 072 @Override 073 public List<GenPolynomial<MOD>> baseFactorsSquarefree(GenPolynomial<MOD> P) { 074 if (P == null) { 075 throw new IllegalArgumentException("P == null not allowed"); 076 } 077 //ModularRingFactory cfac = (ModularRingFactory) P.ring.coFac; 078 long q = P.ring.coFac.characteristic().longValueExact(); 079 if (q < 100) { // todo, 32003 too high 080 return baseFactorsSquarefreeSmallPrime(P); 081 } 082 return baseFactorsSquarefreeBigPrime(P); 083 } 084 085 086 /** 087 * GenPolynomial base factorization of a squarefree polynomial. Small prime 088 * version of Berlekamps algorithm. 089 * @param P squarefree and monic! GenPolynomial. 090 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 091 */ 092 @SuppressWarnings("unchecked") 093 public List<GenPolynomial<MOD>> baseFactorsSquarefreeSmallPrime(GenPolynomial<MOD> P) { 094 if (P == null) { 095 throw new IllegalArgumentException("P == null"); 096 } 097 List<GenPolynomial<MOD>> factors = new ArrayList<GenPolynomial<MOD>>(); 098 if (P.isZERO()) { 099 return factors; 100 } 101 GenPolynomialRing<MOD> pfac = P.ring; 102 if (pfac.nvar > 1) { 103 throw new IllegalArgumentException("only for univariate polynomials"); 104 } 105 if (!P.leadingBaseCoefficient().isONE()) { 106 throw new IllegalArgumentException("ldcf(P) != 1: " + P); 107 } 108 if (P.isONE() || P.degree(0) <= 1) { 109 factors.add(P); 110 return factors; 111 } 112 ArrayList<ArrayList<MOD>> Q = PolyUfdUtil.<MOD> constructQmatrix(P); 113 //System.out.println("Q = " + Q); 114 int n = Q.size(); 115 int m = Q.get(0).size(); 116 GenMatrixRing<MOD> mfac = new GenMatrixRing<MOD>(pfac.coFac, n, m); 117 GenMatrix<MOD> Qm = new GenMatrix<MOD>(mfac, Q); 118 GenMatrix<MOD> Qm1 = Qm.subtract(mfac.getONE()); 119 //System.out.println("Qm1 = " + Qm1); 120 LinAlg<MOD> lu = new LinAlg<MOD>(); 121 List<GenVector<MOD>> Nsb = lu.nullSpaceBasis(Qm1); 122 logger.info("Nsb = {}", Nsb); 123 int k = Nsb.size(); 124 if (k == 1) { 125 factors.add(P); 126 return factors; 127 } 128 //int d = (int) P.degree(0); 129 GenMatrix<MOD> Ns = mfac.fromVectors(Nsb); 130 GenMatrix<MOD> L1 = Ns.negate(); //mfac.getONE().subtract(Ns); 131 //System.out.println("L1 = " + L1); 132 List<GenPolynomial<MOD>> trials = new ArrayList<GenPolynomial<MOD>>(); 133 for (int i = 0; i < L1.ring.rows; i++) { 134 GenVector<MOD> rv = L1.getRow(i); 135 GenPolynomial<MOD> rp = pfac.fromVector(rv); 136 if (!rp.isONE()) { 137 trials.add(rp); 138 } 139 } 140 logger.info("#ofFactors k = {}", k); 141 logger.info("trials = {}", trials); 142 factors.add(P); 143 for (GenPolynomial<MOD> t : trials) { 144 if (factors.size() == k) { 145 break; 146 } 147 //System.out.println("t = " + t); 148 // depth first search, since Iterator is finite 149 GenPolynomial<MOD> a = factors.remove(0); 150 //System.out.println("a = " + a); 151 MOD s = null; 152 Iterator<MOD> eit = null; 153 if (pfac.coFac instanceof ModularRingFactory) { 154 eit = ((ModularRingFactory) pfac.coFac).iterator(); 155 } else if (pfac.coFac instanceof AlgebraicNumberRing) { 156 eit = ((AlgebraicNumberRing) pfac.coFac).iterator(); 157 } else { 158 throw new IllegalArgumentException("no iterator for: " + pfac.coFac); 159 } 160 //System.out.println("eit = " + eit); 161 while (eit.hasNext()) { 162 s = eit.next(); 163 //System.out.println("s = " + s); 164 GenPolynomial<MOD> v = t.subtract(s); 165 GenPolynomial<MOD> g = v.gcd(a); 166 if (g.isONE() || g.equals(a)) { 167 continue; 168 } 169 factors.add(g); 170 a = a.divide(g); 171 logger.info("s = {}, g = {}, a = {}", s, g, a); 172 if (a.isONE()) { 173 break; 174 } 175 } 176 if (!a.isONE()) { 177 factors.add(a); 178 } 179 } 180 //System.out.println("factors = " + factors); 181 factors = PolyUtil.<MOD> monic(factors); 182 SortedSet<GenPolynomial<MOD>> ss = new TreeSet<GenPolynomial<MOD>>(factors); 183 //System.out.println("sorted = " + ss); 184 factors.clear(); 185 factors.addAll(ss); 186 return factors; 187 } 188 189 190 /** 191 * GenPolynomial base factorization of a squarefree polynomial. Big prime 192 * version of Berlekamps algorithm. 193 * @param P squarefree and monic! GenPolynomial. 194 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 195 */ 196 public List<GenPolynomial<MOD>> baseFactorsSquarefreeBigPrime(GenPolynomial<MOD> P) { 197 if (P == null) { 198 throw new IllegalArgumentException("P == null"); 199 } 200 List<GenPolynomial<MOD>> factors = new ArrayList<GenPolynomial<MOD>>(); 201 if (P.isZERO()) { 202 return factors; 203 } 204 GenPolynomialRing<MOD> pfac = P.ring; 205 if (pfac.nvar > 1) { 206 throw new IllegalArgumentException("only for univariate polynomials"); 207 } 208 if (!P.leadingBaseCoefficient().isONE()) { 209 throw new IllegalArgumentException("ldcf(P) != 1: " + P); 210 } 211 if (P.isONE() || P.degree(0) <= 1) { 212 factors.add(P); 213 return factors; 214 } 215 ArrayList<ArrayList<MOD>> Q = PolyUfdUtil.<MOD> constructQmatrix(P); 216 //System.out.println("Q = " + Q); 217 int n = Q.size(); 218 int m = Q.get(0).size(); 219 GenMatrixRing<MOD> mfac = new GenMatrixRing<MOD>(pfac.coFac, n, m); 220 GenMatrix<MOD> Qm = new GenMatrix<MOD>(mfac, Q); 221 GenMatrix<MOD> Qm1 = Qm.subtract(mfac.getONE()); 222 //System.out.println("Qm1 = " + Qm1); 223 LinAlg<MOD> lu = new LinAlg<MOD>(); 224 List<GenVector<MOD>> Nsb = lu.nullSpaceBasis(Qm1); 225 logger.info("Nsb = {}", Nsb); 226 int k = Nsb.size(); 227 if (k == 1) { 228 factors.add(P); 229 return factors; 230 } 231 //int d = (int) P.degree(0); 232 GenMatrix<MOD> Ns = mfac.fromVectors(Nsb); 233 GenMatrix<MOD> L1 = Ns.negate(); //mfac.getONE().subtract(Ns); 234 //System.out.println("L1 = " + L1); 235 List<GenPolynomial<MOD>> trials = new ArrayList<GenPolynomial<MOD>>(); 236 for (int i = 0; i < L1.ring.rows; i++) { 237 GenVector<MOD> rv = L1.getRow(i); 238 GenPolynomial<MOD> rp = pfac.fromVector(rv); 239 trials.add(rp); 240 } 241 logger.info("#ofFactors k = {}", k); 242 logger.info("trials = {}", trials); 243 factors.add(P); 244 GenVectorModul<MOD> vfac = new GenVectorModul<MOD>(pfac.coFac, k); 245 //long q = pfac.coFac.characteristic().longValueExact(); 246 //long lq = Power.logarithm(2, q); 247 java.math.BigInteger q = pfac.coFac.characteristic(); //.longValueExact(); 248 int lq = q.bitLength(); //Power.logarithm(2, q); 249 if (pfac.coFac instanceof AlgebraicNumberRing) { 250 lq = (int) ((AlgebraicNumberRing) pfac.coFac).extensionDegree(); 251 q = q.pow(lq); //Power.power(q, lq); 252 } 253 logger.info("char = {}, q = {}, lq = {}", pfac.coFac.characteristic(), q, lq); 254 do { 255 // breadth first search, since some a might be irreducible 256 GenPolynomial<MOD> a = factors.remove(0); 257 //System.out.println("a = " + a); 258 if (a.degree(0) <= 1) { 259 factors.add(a); 260 continue; 261 } 262 GenVector<MOD> rv = vfac.random(8, 0.95f); 263 //System.out.println("rv = " + rv.toScript()); 264 GenPolynomial<MOD> rpol = pfac.getZERO(); 265 int i = 0; 266 for (GenPolynomial<MOD> t : trials) { 267 MOD c = rv.get(i++); 268 GenPolynomial<MOD> s = t.multiply(c); 269 rpol = rpol.sum(s); 270 } 271 rpol = rpol.monic(); 272 if (rpol.isONE()) { 273 factors.add(a); 274 continue; 275 } 276 //System.out.println("rpol = " + rpol.toScript()); 277 if (!q.testBit(0)) { // q % 2 == 0 278 long e = lq - 1; 279 //System.out.println("q = " + q + ", e = " + e); 280 GenPolynomial<MOD> pow = rpol; 281 GenPolynomial<MOD> v = rpol; 282 for (int l = 1; l < e; l++) { 283 pow = pow.multiply(pow).remainder(a); 284 v = v.sum(pow); 285 } 286 rpol = v.remainder(a).monic(); // automatic monic 287 //System.out.println("sum_l rpol^l = " + rpol.toScript()); 288 } else { 289 //long e = (q - 1) / 2; 290 java.math.BigInteger e = q.subtract(java.math.BigInteger.ONE).shiftRight(1); 291 //System.out.println("q = " + q + ", e = " + e); 292 GenPolynomial<MOD> pow = Power.<GenPolynomial<MOD>> modPositivePower(rpol, e, a); 293 rpol = pow.subtract(pfac.getONE()).monic(); 294 //System.out.println("rpol^e-1 = " + rpol.toScript()); 295 } 296 if (rpol.isZERO() || rpol.isONE()) { 297 factors.add(a); 298 continue; 299 } 300 GenPolynomial<MOD> g = rpol.gcd(a); 301 if (g.isONE()) { 302 factors.add(a); 303 continue; 304 } 305 factors.add(g); 306 //System.out.println("a = " + a); 307 a = a.divide(g); 308 logger.info("rv = {}, g = {}, a/g = {}", rv, g, a); 309 if (!a.isONE()) { 310 factors.add(a); 311 } 312 //System.out.println("factors = " + factors); 313 } while (factors.size() < k); 314 315 //System.out.println("factors = " + factors); 316 factors = PolyUtil.<MOD> monic(factors); 317 SortedSet<GenPolynomial<MOD>> ss = new TreeSet<GenPolynomial<MOD>>(factors); 318 //System.out.println("sorted = " + ss); 319 factors.clear(); 320 factors.addAll(ss); 321 return factors; 322 } 323 324}