001/* 002 * $Id: PolyGBUtil.java 5935 2018-09-30 11:47:20Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.logging.log4j.Logger; 012import org.apache.logging.log4j.LogManager; 013 014import edu.jas.gb.GroebnerBaseAbstract; 015import edu.jas.gb.SolvableGroebnerBaseAbstract; 016import edu.jas.gb.SolvableGroebnerBaseSeq; 017import edu.jas.gb.SolvableReductionAbstract; 018import edu.jas.gb.SolvableReductionSeq; 019import edu.jas.gb.WordGroebnerBaseAbstract; 020import edu.jas.gb.WordGroebnerBaseSeq; 021import edu.jas.poly.ExpVector; 022import edu.jas.poly.GenPolynomial; 023import edu.jas.poly.GenPolynomialRing; 024import edu.jas.poly.GenSolvablePolynomial; 025import edu.jas.poly.GenSolvablePolynomialRing; 026import edu.jas.poly.WordFactory; 027import edu.jas.poly.GenWordPolynomial; 028import edu.jas.poly.GenWordPolynomialRing; 029import edu.jas.poly.PolyUtil; 030import edu.jas.structure.GcdRingElem; 031import edu.jas.structure.RingElem; 032 033 034/** 035 * Package gbufd utilities. 036 * @author Heinz Kredel 037 */ 038 039public class PolyGBUtil { 040 041 042 private static final Logger logger = LogManager.getLogger(PolyGBUtil.class); 043 044 045 private static final boolean debug = logger.isDebugEnabled(); 046 047 048 /** 049 * Test for resultant. 050 * @param A generic polynomial. 051 * @param B generic polynomial. 052 * @param r generic polynomial. 053 * @return true if res(A,B) isContained in ideal(A,B), else false. 054 */ 055 public static <C extends GcdRingElem<C>> boolean isResultant(GenPolynomial<C> A, GenPolynomial<C> B, 056 GenPolynomial<C> r) { 057 if (r == null || r.isZERO()) { 058 return true; 059 } 060 GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(r.ring.coFac); 061 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(2); 062 F.add(A); 063 F.add(B); 064 List<GenPolynomial<C>> G = bb.GB(F); 065 //System.out.println("G = " + G); 066 GenPolynomial<C> n = bb.red.normalform(G, r); 067 //System.out.println("n = " + n); 068 return n.isZERO(); 069 } 070 071 072 /** 073 * Top pseudo reduction wrt the main variables. 074 * @param P generic polynomial. 075 * @param A list of generic polynomials sorted according to appearing main 076 * variables. 077 * @return top pseudo remainder of P wrt. A for the appearing variables. 078 */ 079 public static <C extends RingElem<C>> GenPolynomial<C> topPseudoRemainder(List<GenPolynomial<C>> A, 080 GenPolynomial<C> P) { 081 if (A == null || A.isEmpty()) { 082 return P.monic(); 083 } 084 if (P.isZERO()) { 085 return P; 086 } 087 //System.out.println("remainder, P = " + P); 088 GenPolynomialRing<C> pfac = A.get(0).ring; 089 if (pfac.nvar <= 1) { // recursion base 090 GenPolynomial<C> R = PolyUtil.<C> baseSparsePseudoRemainder(P, A.get(0)); 091 return R.monic(); 092 } 093 // select polynomials according to the main variable 094 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 095 GenPolynomial<C> Q = A.get(0); // wrong, must eventually search polynomial 096 GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac, Q); 097 GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P); 098 GenPolynomial<GenPolynomial<C>> rr; 099 if (qr.isONE()) { 100 return P.ring.getZERO(); 101 } 102 if (qr.degree(0) > 0) { 103 rr = PolyUtil.<C> recursiveSparsePseudoRemainder(pr, qr); 104 //System.out.println("remainder, pr = " + pr); 105 //System.out.println("remainder, qr = " + qr); 106 //System.out.println("remainder, rr = " + rr); 107 } else { 108 rr = pr; 109 } 110 if (rr.degree(0) > 0) { 111 GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr); 112 return R.monic(); 113 // not further reduced wrt. other variables = top-reduction only 114 } 115 List<GenPolynomial<C>> zeroDeg = zeroDegrees(A); 116 GenPolynomial<C> R = topPseudoRemainder(zeroDeg, rr.leadingBaseCoefficient()); 117 R = R.extend(pfac, 0, 0L); 118 return R.monic(); 119 } 120 121 122 /** 123 * Top coefficient pseudo remainder of the leading coefficient of P wrt A in 124 * the main variables. 125 * @param P generic polynomial in n+1 variables. 126 * @param A list of generic polynomials in n variables sorted according to 127 * appearing main variables. 128 * @return pseudo remainder of the leading coefficient of P wrt A. 129 */ 130 public static <C extends RingElem<C>> GenPolynomial<C> topCoefficientPseudoRemainder( 131 List<GenPolynomial<C>> A, GenPolynomial<C> P) { 132 if (A == null || A.isEmpty()) { 133 return P.monic(); 134 } 135 if (P.isZERO()) { 136 return P; 137 } 138 GenPolynomialRing<C> pfac = P.ring; 139 GenPolynomialRing<C> pfac1 = A.get(0).ring; 140 if (pfac1.nvar <= 1) { // recursion base 141 GenPolynomial<C> a = A.get(0); 142 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(pfac.nvar - 1); 143 GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P); 144 // ldcf(P,x_m) = q a + r 145 GenPolynomial<GenPolynomial<C>> rr = PolyGBUtil.<C> coefficientPseudoRemainderBase(pr, a); 146 GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr); 147 return R.monic(); 148 } 149 // select polynomials according to the main variable 150 GenPolynomialRing<GenPolynomial<C>> rfac1 = pfac1.recursive(1); 151 int nv = pfac.nvar - pfac1.nvar; 152 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1 + nv); 153 GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> rfac2 = rfac.recursive(nv); 154 if (debug) { 155 logger.info("rfac =" + rfac); 156 } 157 GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P); 158 GenPolynomial<GenPolynomial<GenPolynomial<C>>> pr2 = PolyUtil.<GenPolynomial<C>> recursive(rfac2, pr); 159 //System.out.println("recursion, pr2 = " + pr2); 160 GenPolynomial<C> Q = A.get(0); 161 GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac1, Q); 162 GenPolynomial<GenPolynomial<GenPolynomial<C>>> rr; 163 if (qr.isONE()) { 164 return P.ring.getZERO(); 165 } 166 if (qr.degree(0) > 0) { 167 // pseudo remainder: ldcf(P,x_m) = a q + r 168 rr = PolyGBUtil.<C> coefficientPseudoRemainder(pr2, qr); 169 //System.out.println("recursion, qr = " + qr); 170 //System.out.println("recursion, pr = " + pr2); 171 //System.out.println("recursion, rr = " + rr); 172 } else { 173 rr = pr2; 174 } 175 // reduction wrt. the other variables 176 List<GenPolynomial<C>> zeroDeg = zeroDegrees(A); 177 GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<GenPolynomial<C>> distribute(rfac, rr); 178 GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, Rr); 179 R = topCoefficientPseudoRemainder(zeroDeg, R); 180 return R.monic(); 181 } 182 183 184 /** 185 * Polynomial leading coefficient pseudo remainder. 186 * @param P generic polynomial in n+1 variables. 187 * @param A generic polynomial in n variables. 188 * @return pseudo remainder of the leading coefficient of P wrt A, with 189 * ldcf(A)<sup>m'</sup> P = quotient * A + remainder. 190 */ 191 public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<GenPolynomial<C>>> coefficientPseudoRemainder( 192 GenPolynomial<GenPolynomial<GenPolynomial<C>>> P, GenPolynomial<GenPolynomial<C>> A) { 193 if (A == null || A.isZERO()) { // findbugs 194 throw new ArithmeticException(P + " division by zero " + A); 195 } 196 if (A.isONE()) { 197 return P.ring.getZERO(); 198 } 199 if (P.isZERO() || P.isONE()) { 200 return P; 201 } 202 GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> pfac = P.ring; 203 GenPolynomialRing<GenPolynomial<C>> afac = A.ring; // == pfac.coFac 204 GenPolynomial<GenPolynomial<GenPolynomial<C>>> r = P; 205 GenPolynomial<GenPolynomial<C>> h; 206 GenPolynomial<GenPolynomial<GenPolynomial<C>>> hr; 207 GenPolynomial<GenPolynomial<C>> ldcf = P.leadingBaseCoefficient(); 208 long m = ldcf.degree(0); 209 long n = A.degree(0); 210 GenPolynomial<C> c = A.leadingBaseCoefficient(); 211 GenPolynomial<GenPolynomial<C>> cc = afac.getZERO().sum(c); 212 //System.out.println("cc = " + cc); 213 ExpVector e = A.leadingExpVector(); 214 for (long i = m; i >= n; i--) { 215 if (r.isZERO()) { 216 return r; 217 } 218 GenPolynomial<GenPolynomial<C>> p = r.leadingBaseCoefficient(); 219 ExpVector g = r.leadingExpVector(); 220 long k = p.degree(0); 221 if (i == k) { 222 GenPolynomial<C> pl = p.leadingBaseCoefficient(); 223 ExpVector f = p.leadingExpVector(); 224 f = f.subtract(e); 225 r = r.multiply(cc); // coeff cc 226 h = A.multiply(pl, f); // coeff ac 227 hr = new GenPolynomial<GenPolynomial<GenPolynomial<C>>>(pfac, h, g); 228 r = r.subtract(hr); 229 } else { 230 r = r.multiply(cc); 231 } 232 //System.out.println("r = " + r); 233 } 234 if (r.degree(0) < P.degree(0)) { // recursion for degree 235 r = coefficientPseudoRemainder(r, A); 236 } 237 return r; 238 } 239 240 241 /** 242 * Polynomial leading coefficient pseudo remainder, base case. 243 * @param P generic polynomial in 1+1 variables. 244 * @param A generic polynomial in 1 variable. 245 * @return pseudo remainder of the leading coefficient of P wrt. A, with 246 * ldcf(A)<sup>m'</sup> P = quotient * A + remainder. 247 */ 248 public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> coefficientPseudoRemainderBase( 249 GenPolynomial<GenPolynomial<C>> P, GenPolynomial<C> A) { 250 if (A == null || A.isZERO()) { // findbugs 251 throw new ArithmeticException(P + " division by zero " + A); 252 } 253 if (A.isONE()) { 254 return P.ring.getZERO(); 255 } 256 if (P.isZERO() || P.isONE()) { 257 return P; 258 } 259 GenPolynomialRing<GenPolynomial<C>> pfac = P.ring; 260 GenPolynomialRing<C> afac = A.ring; // == pfac.coFac 261 GenPolynomial<GenPolynomial<C>> r = P; 262 GenPolynomial<C> h; 263 GenPolynomial<GenPolynomial<C>> hr; 264 GenPolynomial<C> ldcf = P.leadingBaseCoefficient(); 265 long m = ldcf.degree(0); 266 long n = A.degree(0); 267 C c = A.leadingBaseCoefficient(); 268 GenPolynomial<C> cc = afac.getZERO().sum(c); 269 //System.out.println("cc = " + cc); 270 ExpVector e = A.leadingExpVector(); 271 for (long i = m; i >= n; i--) { 272 if (r.isZERO()) { 273 return r; 274 } 275 GenPolynomial<C> p = r.leadingBaseCoefficient(); 276 ExpVector g = r.leadingExpVector(); 277 long k = p.degree(0); 278 if (i == k) { 279 C pl = p.leadingBaseCoefficient(); 280 ExpVector f = p.leadingExpVector(); 281 f = f.subtract(e); 282 r = r.multiply(cc); // coeff cc 283 h = A.multiply(pl, f); // coeff ac 284 hr = new GenPolynomial<GenPolynomial<C>>(pfac, h, g); 285 r = r.subtract(hr); 286 } else { 287 r = r.multiply(cc); 288 } 289 //System.out.println("r = " + r); 290 } 291 if (r.degree(0) < P.degree(0)) { // recursion for degree 292 r = coefficientPseudoRemainderBase(r, A); 293 } 294 return r; 295 } 296 297 298 /** 299 * Extract polynomials with degree zero in the main variable. 300 * @param A list of generic polynomials in n variables. 301 * @return Z = [a_i] with deg(a_i,x_n) = 0 and in n-1 variables. 302 */ 303 public static <C extends RingElem<C>> List<GenPolynomial<C>> zeroDegrees(List<GenPolynomial<C>> A) { 304 if (A == null || A.isEmpty()) { 305 return A; 306 } 307 GenPolynomialRing<C> pfac = A.get(0).ring; 308 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 309 List<GenPolynomial<C>> zeroDeg = new ArrayList<GenPolynomial<C>>(A.size()); 310 for (int i = 0; i < A.size(); i++) { 311 GenPolynomial<C> q = A.get(i); 312 GenPolynomial<GenPolynomial<C>> fr = PolyUtil.<C> recursive(rfac, q); 313 if (fr.degree(0) == 0) { 314 zeroDeg.add(fr.leadingBaseCoefficient()); 315 } 316 } 317 return zeroDeg; 318 } 319 320 321 /** 322 * Intersection. Generators for the intersection of ideals. 323 * @param pfac polynomial ring 324 * @param A list of polynomials 325 * @param B list of polynomials 326 * @return generators for (A \cap B) 327 */ 328 public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> intersect(GenPolynomialRing<C> pfac, 329 List<GenPolynomial<C>> A, List<GenPolynomial<C>> B) { 330 if (A == null || A.isEmpty()) { // (0) 331 return B; 332 } 333 if (B == null || B.isEmpty()) { // (0) 334 return A; 335 } 336 int s = A.size() + B.size(); 337 List<GenPolynomial<C>> c = new ArrayList<GenPolynomial<C>>(s); 338 GenPolynomialRing<C> tfac = pfac.extend(1); 339 // term order is also adjusted 340 for (GenPolynomial<C> p : A) { 341 p = p.extend(tfac, 0, 1L); // t*p 342 c.add(p); 343 } 344 for (GenPolynomial<C> p : B) { 345 GenPolynomial<C> q = p.extend(tfac, 0, 1L); 346 GenPolynomial<C> r = p.extend(tfac, 0, 0L); 347 p = r.subtract(q); // (1-t)*p 348 c.add(p); 349 } 350 GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(tfac.coFac); 351 logger.warn("intersect computing GB"); 352 List<GenPolynomial<C>> G = bb.GB(c); 353 if (debug) { 354 logger.debug("intersect GB = " + G); 355 } 356 List<GenPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G); 357 return I; 358 } 359 360 361 /** 362 * Intersection. Generators for the intersection of ideals. 363 * @param pfac solvable polynomial ring 364 * @param A list of polynomials 365 * @param B list of polynomials 366 * @return generators for (A \cap B) 367 */ 368 public static <C extends GcdRingElem<C>> List<GenSolvablePolynomial<C>> intersect( 369 GenSolvablePolynomialRing<C> pfac, List<GenSolvablePolynomial<C>> A, 370 List<GenSolvablePolynomial<C>> B) { 371 if (A == null || A.isEmpty()) { // (0) 372 return B; 373 } 374 if (B == null || B.isEmpty()) { // (0) 375 return A; 376 } 377 int s = A.size() + B.size(); 378 List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s); 379 GenSolvablePolynomialRing<C> tfac = pfac.extend(1); 380 // term order is also adjusted 381 for (GenSolvablePolynomial<C> p : A) { 382 p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L); // t*p 383 c.add(p); 384 } 385 for (GenSolvablePolynomial<C> p : B) { 386 GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L); 387 GenSolvablePolynomial<C> r = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L); 388 p = (GenSolvablePolynomial<C>) r.subtract(q); // (1-t)*p 389 c.add(p); 390 } 391 SolvableGroebnerBaseAbstract<C> sbb = SGBFactory.<C> getImplementation(tfac.coFac); 392 //new SolvableGroebnerBaseSeq<C>(); 393 logger.warn("intersect computing GB"); 394 List<GenSolvablePolynomial<C>> g = sbb.leftGB(c); 395 //List<GenSolvablePolynomial<C>> g = sbb.twosidedGB(c); 396 if (debug) { 397 logger.debug("intersect GB = " + g); 398 } 399 List<GenSolvablePolynomial<C>> I = PolyUtil.<C> intersect(pfac, g); 400 return I; 401 } 402 403 404 /** 405 * Intersection. Generators for the intersection of word ideals. 406 * @param pfac word polynomial ring 407 * @param A list of word polynomials 408 * @param B list of word polynomials 409 * @return generators for (A \cap B) if it exists 410 */ 411 public static <C extends GcdRingElem<C>> List<GenWordPolynomial<C>> intersect(GenWordPolynomialRing<C> pfac, 412 List<GenWordPolynomial<C>> A, List<GenWordPolynomial<C>> B) { 413 if (A == null || A.isEmpty()) { // (0) 414 return B; 415 } 416 if (B == null || B.isEmpty()) { // (0) 417 return A; 418 } 419 int s = A.size() + B.size(); 420 List<GenWordPolynomial<C>> L = new ArrayList<GenWordPolynomial<C>>(s); 421 GenWordPolynomialRing<C> tfac = pfac.extend(1); 422 List<GenWordPolynomial<C>> gens = tfac.univariateList(); 423 //System.out.println("gens = " + gens); 424 GenWordPolynomial<C> t = gens.get(gens.size()-1); 425 //System.out.println("t = " + t); 426 // make t commute with other variables 427 for (GenWordPolynomial<C> p : gens) { 428 if (t == p) { 429 continue; 430 } 431 GenWordPolynomial<C> c = t.multiply(p).subtract(p.multiply(t)); // t p - p t 432 L.add(c); 433 } 434 for (GenWordPolynomial<C> p : A) { 435 p = tfac.valueOf(p).multiply(t); // t p 436 L.add(p); 437 } 438 for (GenWordPolynomial<C> p : B) { 439 GenWordPolynomial<C> q = tfac.valueOf(p).multiply(t); 440 GenWordPolynomial<C> r = tfac.valueOf(p); 441 p = r.subtract(q); // (1-t) p 442 L.add(p); 443 } 444 //System.out.println("L = " + L); 445 WordGroebnerBaseAbstract<C> bb = new WordGroebnerBaseSeq<C>(); 446 logger.warn("intersect computing GB"); 447 List<GenWordPolynomial<C>> G = bb.GB(L); 448 //System.out.println("G = " + G); 449 if (debug) { 450 logger.debug("intersect GB = " + G); 451 } 452 List<GenWordPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G); 453 return I; 454 } 455 456 457 /** 458 * Solvable quotient and remainder via reduction. 459 * @param n first solvable polynomial. 460 * @param d second solvable polynomial. 461 * @return [ n/d, n - (n/d)*d ] 462 */ 463 @SuppressWarnings("unchecked") 464 public static <C extends GcdRingElem<C>> GenSolvablePolynomial<C>[] quotientRemainder( 465 GenSolvablePolynomial<C> n, GenSolvablePolynomial<C> d) { 466 GenSolvablePolynomial<C>[] res = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2]; 467 if (d.isZERO()) { 468 throw new RuntimeException("division by zero: " + n + "/" + d); 469 } 470 if (n.isZERO()) { 471 res[0] = n; 472 res[1] = n; 473 return res; 474 } 475 GenSolvablePolynomialRing<C> r = n.ring; 476 if (d.isONE()) { 477 res[0] = n; 478 res[1] = r.getZERO(); 479 return res; 480 } 481 // divide 482 List<GenSolvablePolynomial<C>> Q = new ArrayList<GenSolvablePolynomial<C>>(1); 483 Q.add(r.getZERO()); 484 List<GenSolvablePolynomial<C>> D = new ArrayList<GenSolvablePolynomial<C>>(1); 485 D.add(d); 486 SolvableReductionAbstract<C> sred = new SolvableReductionSeq<C>(); 487 res[1] = sred.rightNormalform(Q, D, n); // left 488 res[0] = Q.get(0); 489 return res; 490 } 491 492}