001/* 002 * $Id$ 003 */ 004 005package edu.jas.gb; 006 007 008import java.util.ArrayList; 009import java.util.LinkedList; 010import java.util.List; 011import java.util.Map; 012 013import org.apache.logging.log4j.LogManager; 014import org.apache.logging.log4j.Logger; 015 016import edu.jas.poly.ExpVector; 017import edu.jas.poly.GenPolynomial; 018import edu.jas.poly.GenPolynomialRing; 019import edu.jas.poly.ModuleList; 020import edu.jas.poly.Monomial; 021import edu.jas.poly.PolynomialList; 022import edu.jas.structure.RingElem; 023 024 025/** 026 * Polynomial Reduction abstract class. Implements common S-Polynomial, 027 * normalform, criterion 4 module criterion and irreducible set. 028 * @param <C> coefficient type 029 * @author Heinz Kredel 030 */ 031 032public abstract class ReductionAbstract<C extends RingElem<C>> implements Reduction<C> { 033 034 035 private static final Logger logger = LogManager.getLogger(ReductionAbstract.class); 036 037 038 private static final boolean debug = logger.isDebugEnabled(); 039 040 041 /** 042 * Constructor. 043 */ 044 public ReductionAbstract() { 045 } 046 047 048 /** 049 * S-Polynomial. 050 * @param A polynomial. 051 * @param B polynomial. 052 * @return spol(A,B) the S-polynomial of A and B. 053 */ 054 @Override 055 public GenPolynomial<C> SPolynomial(GenPolynomial<C> A, GenPolynomial<C> B) { 056 if (B == null || B.isZERO()) { 057 if (A == null) { 058 return B; 059 } 060 return A.ring.getZERO(); 061 } 062 if (A == null || A.isZERO()) { 063 return B.ring.getZERO(); 064 } 065 if (debug) { 066 if (!A.ring.equals(B.ring)) { 067 logger.error("rings not equal {}, {}", A.ring, B.ring); 068 } 069 } 070 Map.Entry<ExpVector, C> ma = A.leadingMonomial(); 071 Map.Entry<ExpVector, C> mb = B.leadingMonomial(); 072 073 ExpVector e = ma.getKey(); 074 ExpVector f = mb.getKey(); 075 076 ExpVector g = e.lcm(f); 077 ExpVector e1 = g.subtract(e); 078 ExpVector f1 = g.subtract(f); 079 080 C a = ma.getValue(); 081 C b = mb.getValue(); 082 083 //Cp = b e1 * A - a f1 * B; 084 GenPolynomial<C> Cp = A.scaleSubtractMultiple(b, e1, a, f1, B); 085 return Cp; 086 } 087 088 089 /** 090 * S-Polynomial with recording. 091 * @param S recording matrix, is modified. <b>Note</b> the negative 092 * S-polynomial is recorded as required by all applications. 093 * @param i index of A in basis list. 094 * @param A a polynomial. 095 * @param j index of B in basis list. 096 * @param B a polynomial. 097 * @return Spol(A, B), the S-Polynomial for A and B. 098 */ 099 @Override 100 public GenPolynomial<C> SPolynomial(List<GenPolynomial<C>> S, int i, GenPolynomial<C> A, int j, 101 GenPolynomial<C> B) { 102 if (debug) { 103 if (B == null || B.isZERO()) { 104 throw new ArithmeticException("Spol B is zero"); 105 } 106 if (A == null || A.isZERO()) { 107 throw new ArithmeticException("Spol A is zero"); 108 } 109 if (!A.ring.equals(B.ring)) { 110 logger.error("rings not equal {}, {}", A.ring, B.ring); 111 } 112 if ((S.get(i) != null && !S.get(i).isZERO()) || (S.get(j) != null && !S.get(j).isZERO())) { 113 throw new IllegalArgumentException("S(i), S(j): " + S.get(i) + ", " + S.get(j)); 114 } 115 } 116 Map.Entry<ExpVector, C> ma = A.leadingMonomial(); 117 Map.Entry<ExpVector, C> mb = B.leadingMonomial(); 118 119 ExpVector e = ma.getKey(); 120 ExpVector f = mb.getKey(); 121 122 ExpVector g = e.lcm(f); 123 ExpVector e1 = g.subtract(e); 124 ExpVector f1 = g.subtract(f); 125 126 C a = ma.getValue(); 127 C b = mb.getValue(); 128 129 //Cp = b e1 * A - a f1 * B; 130 GenPolynomial<C> Cp = A.scaleSubtractMultiple(b, e1, a, f1, B); 131 132 GenPolynomial<C> zero = A.ring.getZERO(); 133 GenPolynomial<C> As = zero.sum(b.negate(), e1); /*not correct .negate()*/ 134 GenPolynomial<C> Bs = zero.sum(a, f1); /*correct .negate()*/ 135 S.set(i, As); 136 S.set(j, Bs); 137 return Cp; 138 } 139 140 141 /** 142 * Module criterium. 143 * @param modv number of module variables. 144 * @param A polynomial. 145 * @param B polynomial. 146 * @return true if the module S-polynomial(i,j) is required. 147 */ 148 @Override 149 public boolean moduleCriterion(int modv, GenPolynomial<C> A, GenPolynomial<C> B) { 150 if (modv == 0) { 151 return true; 152 } 153 ExpVector ei = A.leadingExpVector(); 154 ExpVector ej = B.leadingExpVector(); 155 return moduleCriterion(modv, ei, ej); 156 } 157 158 159 /** 160 * Module criterium. 161 * @param modv number of module variables. 162 * @param ei ExpVector. 163 * @param ej ExpVector. 164 * @return true if the module S-polynomial(i,j) is required. 165 */ 166 @Override 167 public boolean moduleCriterion(int modv, ExpVector ei, ExpVector ej) { 168 if (modv == 0) { 169 return true; 170 } 171 if (ei.invLexCompareTo(ej, 0, modv) != 0) { 172 return false; // skip pair 173 } 174 return true; 175 } 176 177 178 /** 179 * GB criterium 4. Use only for commutative polynomial rings. 180 * @param A polynomial. 181 * @param B polynomial. 182 * @param e = lcm(ht(A),ht(B)) 183 * @return true if the S-polynomial(i,j) is required, else false. 184 */ 185 @Override 186 public boolean criterion4(GenPolynomial<C> A, GenPolynomial<C> B, ExpVector e) { 187 if (logger.isInfoEnabled()) { 188 if (!A.ring.equals(B.ring)) { 189 logger.error("rings not equal {}, {}", A.ring, B.ring); 190 } 191 if (!A.ring.isCommutative()) { //B instanceof GenSolvablePolynomial ) { 192 logger.error("GBCriterion4 not applicabable to non-commutative polynomials"); 193 return true; 194 } 195 } 196 ExpVector ei = A.leadingExpVector(); 197 ExpVector ej = B.leadingExpVector(); 198 return criterion4(ei, ej, e); 199 } 200 201 202 /** 203 * GB criterium 4. Use only for commutative polynomial rings. 204 * @param ei exponent vector. 205 * @param ej exponent vector. 206 * @param e = lcm(ei,ej) 207 * @return true if the S-polynomial(i,j) is required, else false. 208 */ 209 @Override 210 public boolean criterion4(ExpVector ei, ExpVector ej, ExpVector e) { 211 ExpVector g = ei.sum(ej); 212 ExpVector h = g.subtract(e); 213 int s = h.signum(); 214 return s != 0; 215 } 216 217 218 /** 219 * GB criterium 4. 220 * @param A polynomial. 221 * @param B polynomial. 222 * @return true if the S-polynomial(i,j) is required, else false. 223 */ 224 @Override 225 public boolean criterion4(GenPolynomial<C> A, GenPolynomial<C> B) { 226 if (logger.isInfoEnabled()) { 227 if (!A.ring.isCommutative() || !B.ring.isCommutative()) { // A instanceof GenSolvablePolynomial 228 logger.error("GBCriterion4 not applicabable to non-commutative polynomials"); 229 return true; 230 } 231 } 232 ExpVector ei = A.leadingExpVector(); 233 ExpVector ej = B.leadingExpVector(); 234 ExpVector e = ei.lcm(ej); 235 return criterion4(ei, ej, e); 236 } 237 238 239 /** 240 * Normalform with respect to marked head terms. 241 * @param Mp leading monomial list. 242 * @param Pp polynomial list. 243 * @param Ap polynomial. 244 * @return nf(Ap) with respect to Mp+Pp. 245 */ 246 public GenPolynomial<C> normalformMarked(List<Monomial<C>> Mp, List<GenPolynomial<C>> Pp, 247 GenPolynomial<C> Ap) { 248 throw new UnsupportedOperationException("not implemented: " + Mp + " " + Pp + " " + Ap); 249 } 250 251 252 /** 253 * Normalform Set. 254 * @param Ap polynomial list. 255 * @param Pp polynomial list. 256 * @return list of nf(a) with respect to Pp for all a in Ap. 257 */ 258 @Override 259 public List<GenPolynomial<C>> normalform(List<GenPolynomial<C>> Pp, List<GenPolynomial<C>> Ap) { 260 if (Pp == null || Pp.isEmpty()) { 261 return Ap; 262 } 263 if (Ap == null || Ap.isEmpty()) { 264 return Ap; 265 } 266 ArrayList<GenPolynomial<C>> red = new ArrayList<GenPolynomial<C>>(); 267 for (GenPolynomial<C> A : Ap) { 268 A = normalform(Pp, A); 269 red.add(A); 270 } 271 return red; 272 } 273 274 275 /** 276 * Module normalform set. 277 * @param Ap module list. 278 * @param Pp module list. 279 * @return list of nf(a) with respect to Pp for all a in Ap. 280 */ 281 public ModuleList<C> normalform(ModuleList<C> Pp, ModuleList<C> Ap) { 282 return normalform(Pp, Ap, false); 283 } 284 285 286 /** 287 * Module normalform set. 288 * @param Ap module list. 289 * @param Pp module list. 290 * @param top true for TOP term order, false for POT term order. 291 * @return list of nf(a) with respect to Pp for all a in Ap. 292 */ 293 public ModuleList<C> normalform(ModuleList<C> Pp, ModuleList<C> Ap, boolean top) { 294 if (Pp == null || Pp.isEmpty()) { 295 return Ap; 296 } 297 if (Ap == null || Ap.isEmpty()) { 298 return Ap; 299 } 300 int modv = Pp.cols; 301 GenPolynomialRing<C> pfac = Pp.ring.extend(modv, top); 302 logger.debug("extended ring = {}", pfac); 303 //System.out.println("extended ring = " + pfac); 304 PolynomialList<C> P = Pp.getPolynomialList(pfac); 305 PolynomialList<C> A = Ap.getPolynomialList(pfac); 306 307 List<GenPolynomial<C>> red = normalform(P.list, A.list); 308 PolynomialList<C> Fr = new PolynomialList<C>(P.ring, red); 309 ModuleList<C> Nr = Fr.getModuleList(modv); 310 return Nr; 311 } 312 313 314 /** 315 * Is top reducible. 316 * @param A polynomial. 317 * @param P polynomial list. 318 * @return true if A is top reducible with respect to P. 319 */ 320 @Override 321 public boolean isTopReducible(List<GenPolynomial<C>> P, GenPolynomial<C> A) { 322 if (P == null || P.isEmpty()) { 323 return false; 324 } 325 if (A == null || A.isZERO()) { 326 return false; 327 } 328 boolean mt = false; 329 ExpVector e = A.leadingExpVector(); 330 for (GenPolynomial<C> p : P) { 331 mt = e.multipleOf(p.leadingExpVector()); 332 if (mt) { 333 return true; 334 } 335 } 336 return false; 337 } 338 339 340 /** 341 * Is reducible. 342 * @param Ap polynomial. 343 * @param Pp polynomial list. 344 * @return true if Ap is reducible with respect to Pp. 345 */ 346 @Override 347 public boolean isReducible(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) { 348 return !isNormalform(Pp, Ap); 349 } 350 351 352 /** 353 * Is in Normalform. 354 * @param Ap polynomial. 355 * @param Pp polynomial list. 356 * @return true if Ap is in normalform with respect to Pp. 357 */ 358 @SuppressWarnings("unchecked") 359 @Override 360 public boolean isNormalform(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) { 361 if (Pp == null || Pp.isEmpty()) { 362 return true; 363 } 364 if (Ap == null || Ap.isZERO()) { 365 return true; 366 } 367 int l; 368 GenPolynomial<C>[] P; 369 synchronized (Pp) { 370 l = Pp.size(); 371 P = new GenPolynomial[l]; 372 //P = Pp.toArray(); 373 for (int i = 0; i < Pp.size(); i++) { 374 P[i] = Pp.get(i); 375 } 376 } 377 ExpVector[] htl = new ExpVector[l]; 378 GenPolynomial<C>[] p = new GenPolynomial[l]; 379 Map.Entry<ExpVector, C> m; 380 int i; 381 int j = 0; 382 for (i = 0; i < l; i++) { 383 p[i] = P[i]; 384 m = p[i].leadingMonomial(); 385 if (m != null) { 386 p[j] = p[i]; 387 htl[j] = m.getKey(); 388 j++; 389 } 390 } 391 l = j; 392 boolean mt = false; 393 for (ExpVector e : Ap.getMap().keySet()) { 394 for (i = 0; i < l; i++) { 395 mt = e.multipleOf(htl[i]); 396 if (mt) { 397 return false; 398 } 399 } 400 } 401 return true; 402 } 403 404 405 /** 406 * Is in Normalform. 407 * @param Pp polynomial list. 408 * @return true if each Ap in Pp is in normalform with respect to Pp\{Ap}. 409 */ 410 @Override 411 public boolean isNormalform(List<GenPolynomial<C>> Pp) { 412 if (Pp == null || Pp.isEmpty()) { 413 return true; 414 } 415 GenPolynomial<C> Ap; 416 List<GenPolynomial<C>> P = new LinkedList<GenPolynomial<C>>(Pp); 417 int s = P.size(); 418 for (int i = 0; i < s; i++) { 419 Ap = P.remove(i); 420 if (!isNormalform(P, Ap)) { 421 return false; 422 } 423 P.add(Ap); 424 } 425 return true; 426 } 427 428 429 /** 430 * Irreducible set. 431 * @param Pp polynomial list. 432 * @return a list P of monic polynomials which are in normalform wrt. P and 433 * with ideal(Pp) = ideal(P). 434 */ 435 @Override 436 public List<GenPolynomial<C>> irreducibleSet(List<GenPolynomial<C>> Pp) { 437 ArrayList<GenPolynomial<C>> P = new ArrayList<GenPolynomial<C>>(); 438 for (GenPolynomial<C> a : Pp) { 439 if (a.length() != 0) { 440 a = a.monic(); 441 if (a.isONE()) { 442 P.clear(); 443 P.add(a); 444 return P; 445 } 446 P.add(a); 447 } 448 } 449 int l = P.size(); 450 if (l <= 1) 451 return P; 452 453 int irr = 0; 454 ExpVector e; 455 ExpVector f; 456 GenPolynomial<C> a; 457 logger.debug("irr = "); 458 while (irr != l) { 459 //it = P.listIterator(); 460 //a = P.get(0); //it.next(); 461 a = P.remove(0); 462 e = a.leadingExpVector(); 463 a = normalform(P, a); 464 logger.debug(String.valueOf(irr)); 465 if (a.length() == 0) { 466 l--; 467 if (l <= 1) { 468 return P; 469 } 470 } else { 471 f = a.leadingExpVector(); 472 if (f.signum() == 0) { 473 P = new ArrayList<GenPolynomial<C>>(); 474 P.add(a.monic()); 475 return P; 476 } 477 if (e.equals(f)) { 478 irr++; 479 } else { 480 irr = 0; 481 a = a.monic(); 482 } 483 P.add(a); 484 } 485 } 486 //System.out.println(); 487 return P; 488 } 489 490 491 /** 492 * Is reduction of normal form. 493 * @param row recording matrix. 494 * @param Pp a polynomial list for reduction. 495 * @param Ap a polynomial. 496 * @param Np = nf(Pp,Ap), a normal form of Ap wrt. Pp. 497 * @return true, if Ap == sum( row[i]*Pp[i] ) + Np, else false. //?? 498 */ 499 @Override 500 public boolean isReductionNF(List<GenPolynomial<C>> row, List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap, 501 GenPolynomial<C> Np) { 502 if (row == null && Pp == null) { 503 if (Ap == null) { 504 return Np == null || Np.isZERO(); 505 } 506 if (Np == null) { 507 return Ap == null || Ap.isZERO(); 508 } 509 return Ap.equals(Np); 510 } 511 if (row == null || Pp == null) { 512 return false; 513 } 514 if (row.size() < Pp.size()) { 515 logger.debug("#r < #p = {}, {}", row.size(), Pp.size()); 516 } 517 GenPolynomial<C> t = Np; 518 //System.out.println("t0 = " + t ); 519 GenPolynomial<C> r; 520 GenPolynomial<C> p; 521 int mm = Math.min(row.size(), Pp.size()); 522 for (int m = 0; m < mm; m++) { 523 r = row.get(m); 524 p = Pp.get(m); 525 if (r != null && p != null) { 526 if (t == null) { 527 t = r.multiply(p); 528 } else { 529 t = t.sum(r.multiply(p)); 530 } 531 } 532 //System.out.println("r = " + r ); 533 //System.out.println("p = " + p ); 534 } 535 //System.out.println("t+ = " + t); 536 if (t == null) { // then also Np == null 537 if (Ap == null) { 538 return true; 539 } 540 return Ap.isZERO(); 541 } 542 r = t.subtract(Ap); 543 //System.out.println("NF_r = " + r); 544 boolean z = r.isZERO(); 545 if (!z) { 546 logger.info("a, n = {}, {}", Ap, Np); 547 logger.info("t, t-a = {}, {}", t, r); 548 logger.info("row = {}", row); 549 logger.info("Pp = {}", Pp); 550 } 551 return z; 552 } 553}