001/* 002 * $Id$ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.Arrays; 010import java.util.Iterator; 011import java.util.List; 012 013import org.apache.logging.log4j.Logger; 014import org.apache.logging.log4j.LogManager; 015 016import edu.jas.gb.SolvableExtendedGB; 017import edu.jas.gb.SolvableGroebnerBase; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.poly.GenSolvablePolynomial; 020import edu.jas.poly.GenSolvablePolynomialRing; 021import edu.jas.poly.ModuleList; 022import edu.jas.poly.PolynomialList; 023import edu.jas.structure.GcdRingElem; 024import edu.jas.structure.RingFactory; 025 026 027/** 028 * Syzygy sequential class for solvable polynomials. Implements Syzygy 029 * computations and tests with Groebner bases. 030 * @param <C> coefficient type 031 * @author Heinz Kredel 032 */ 033 034public class SolvableSyzygySeq<C extends GcdRingElem<C>> extends SolvableSyzygyAbstract<C> { 035 036 037 private static final Logger logger = LogManager.getLogger(SolvableSyzygySeq.class); 038 039 040 private static final boolean debug = logger.isDebugEnabled(); 041 042 043 private static boolean assertEnabled = false; 044 045 046 static { 047 assert assertEnabled = true; // official hack to check assertions enabled 048 } 049 050 051 /** 052 * Groebner basis engine. 053 */ 054 protected SolvableGroebnerBase<C> sbb; 055 056 057 /* 058 * Module Groebner basis engine. 059 //protected ModSolvableGroebnerBase<C> msbb; 060 */ 061 062 063 /** 064 * Constructor. 065 * @param cf coefficient ring. 066 */ 067 public SolvableSyzygySeq(RingFactory<C> cf) { 068 sbb = SGBFactory.getImplementation(cf); 069 //msbb = new ModSolvableGroebnerBaseSeq<C>(cf); 070 } 071 072 073 /** 074 * Resolution of a module. Only with direct GBs. 075 * @param M a module list of a Groebner basis. 076 * @return a resolution of M. 077 */ 078 public List<SolvResPart<C>> resolution(ModuleList<C> M) { 079 List<SolvResPart<C>> R = new ArrayList<SolvResPart<C>>(); 080 ModuleList<C> MM = M; 081 ModuleList<C> GM; 082 ModuleList<C> Z; 083 while (true) { 084 GM = sbb.leftGB(MM); 085 Z = leftZeroRelations(GM); 086 R.add(new SolvResPart<C>(MM, GM, Z)); 087 if (Z == null || Z.list == null || Z.list.size() == 0) { 088 break; 089 } 090 MM = Z; 091 } 092 return R; 093 } 094 095 096 /** 097 * Resolution of a polynomial list. Only with direct GBs. 098 * @param F a polynomial list of a Groebner basis. 099 * @return a resolution of F. 100 */ 101 @SuppressWarnings("unchecked") 102 public List/*<SolvResPart<C>|SolvResPolPart<C>>*/resolution(PolynomialList<C> F) { 103 List<List<GenSolvablePolynomial<C>>> Z; 104 ModuleList<C> Zm; 105 List<GenSolvablePolynomial<C>> G; 106 PolynomialList<C> Gl; 107 108 G = sbb.leftGB(F.castToSolvableList()); 109 Z = leftZeroRelations(G); 110 Gl = new PolynomialList<C>((GenSolvablePolynomialRing<C>) F.ring, G); 111 Zm = new ModuleList<C>((GenSolvablePolynomialRing<C>) F.ring, Z); 112 113 List R = resolution(Zm); 114 R.add(0, new SolvResPolPart<C>(F, Gl, Zm)); 115 return R; 116 } 117 118 119 /** 120 * Resolution of a module. 121 * @param M a module list of an arbitrary basis. 122 * @return a resolution of M. 123 */ 124 public List<SolvResPart<C>> resolutionArbitrary(ModuleList<C> M) { 125 List<SolvResPart<C>> R = new ArrayList<SolvResPart<C>>(); 126 ModuleList<C> MM = M; 127 ModuleList<C> GM = null; 128 ModuleList<C> Z; 129 while (true) { 130 //GM = sbb.leftGB(MM); 131 Z = leftZeroRelationsArbitrary(MM); 132 R.add(new SolvResPart<C>(MM, GM, Z)); 133 if (Z == null || Z.list == null || Z.list.size() == 0) { 134 break; 135 } 136 MM = Z; 137 } 138 return R; 139 } 140 141 142 /** 143 * Resolution of a polynomial list. 144 * @param F a polynomial list of an arbitrary basis. 145 * @return a resolution of F. 146 */ 147 @SuppressWarnings("unchecked") 148 public List/*<SolvResPart<C>|SolvResPolPart<C>>*/resolutionArbitrary(PolynomialList<C> F) { 149 List<List<GenSolvablePolynomial<C>>> Z; 150 ModuleList<C> Zm; 151 PolynomialList<C> Gl = null; 152 //List<GenSolvablePolynomial<C>> G = sbb.leftGB( F.castToSolvableList() ); 153 //Gl = new PolynomialList<C>((GenSolvablePolynomialRing<C>)F.ring, G); 154 Z = leftZeroRelationsArbitrary(F.castToSolvableList()); 155 Zm = new ModuleList<C>((GenSolvablePolynomialRing<C>) F.ring, Z); 156 157 List R = resolutionArbitrary(Zm); 158 R.add(0, new SolvResPolPart<C>(F, Gl, Zm)); 159 return R; 160 } 161 162 163 /** 164 * Left syzygy module from arbitrary base. 165 * @param modv number of module variables. 166 * @param F a solvable polynomial list. 167 * @return syz(F), a basis for the module of left syzygies for F. 168 */ 169 @SuppressWarnings("unchecked") 170 public List<List<GenSolvablePolynomial<C>>> leftZeroRelationsArbitrary(int modv, 171 List<GenSolvablePolynomial<C>> F) { 172 if (F == null) { 173 return null; //leftZeroRelations( modv, F ); 174 } 175 if (F.size() <= 1) { 176 return leftZeroRelations(modv, F); 177 } 178 final int lenf = F.size(); 179 SolvableExtendedGB<C> exgb = sbb.extLeftGB(modv, F); 180 if (debug) { 181 logger.info("exgb = {}", exgb); 182 } 183 if (assertEnabled) { 184 logger.info("check1 exgb start"); 185 if (!sbb.isLeftReductionMatrix(exgb)) { 186 logger.error("is reduction matrix ? false"); 187 } 188 logger.info("check1 exgb end"); 189 } 190 List<GenSolvablePolynomial<C>> G = exgb.G; 191 List<List<GenSolvablePolynomial<C>>> G2F = exgb.G2F; 192 List<List<GenSolvablePolynomial<C>>> F2G = exgb.F2G; 193 194 List<List<GenSolvablePolynomial<C>>> sg = leftZeroRelations(modv, G); 195 GenSolvablePolynomialRing<C> ring = G.get(0).ring; 196 ModuleList<C> S = new ModuleList<C>(ring, sg); 197 if (debug) { 198 logger.info("syz = {}", S); 199 } 200 if (assertEnabled) { 201 logger.info("check2 left syz start"); 202 if (!isLeftZeroRelation(sg, G)) { 203 logger.error("is syzygy ? false"); 204 } 205 logger.info("check2 left syz end"); 206 } 207 208 List<List<GenSolvablePolynomial<C>>> sf; 209 sf = new ArrayList<List<GenSolvablePolynomial<C>>>(sg.size()); 210 //List<GenPolynomial<C>> row; 211 212 for (List<GenSolvablePolynomial<C>> r : sg) { 213 Iterator<GenSolvablePolynomial<C>> it = r.iterator(); 214 Iterator<List<GenSolvablePolynomial<C>>> jt = G2F.iterator(); 215 216 List<GenSolvablePolynomial<C>> rf; 217 rf = new ArrayList<GenSolvablePolynomial<C>>(lenf); 218 for (int m = 0; m < lenf; m++) { 219 rf.add(ring.getZERO()); 220 } 221 while (it.hasNext() && jt.hasNext()) { 222 GenSolvablePolynomial<C> si = it.next(); 223 List<GenSolvablePolynomial<C>> ai = jt.next(); 224 //System.out.println("si = " + si); 225 //System.out.println("ai = " + ai); 226 if (si == null || ai == null) { 227 continue; 228 } 229 // pi has wrong type: 230 List<GenPolynomial<C>> pi = blas.scalarProduct(si, PolynomialList.<C> castToList(ai)); 231 //System.out.println("pi = " + pi); 232 rf = PolynomialList.<C> castToSolvableList(blas.vectorAdd(PolynomialList.<C> castToList(rf), 233 pi)); 234 } 235 if (it.hasNext() || jt.hasNext()) { 236 logger.error("leftZeroRelationsArbitrary wrong sizes"); 237 } 238 //System.out.println("\nrf = " + rf + "\n"); 239 sf.add(rf); 240 } 241 if (assertEnabled) { 242 logger.info("check3 left syz start"); 243 if (!isLeftZeroRelation(sf, F)) { 244 logger.error("is partial syz sf ? false"); 245 } 246 logger.info("check3 left syz end"); 247 } 248 249 List<List<GenSolvablePolynomial<C>>> M; 250 M = new ArrayList<List<GenSolvablePolynomial<C>>>(lenf); 251 for (List<GenSolvablePolynomial<C>> r : F2G) { 252 Iterator<GenSolvablePolynomial<C>> it = r.iterator(); 253 Iterator<List<GenSolvablePolynomial<C>>> jt = G2F.iterator(); 254 255 List<GenSolvablePolynomial<C>> rf; 256 rf = new ArrayList<GenSolvablePolynomial<C>>(lenf); 257 for (int m = 0; m < lenf; m++) { 258 rf.add(ring.getZERO()); 259 } 260 while (it.hasNext() && jt.hasNext()) { 261 GenSolvablePolynomial<C> si = it.next(); 262 List<GenSolvablePolynomial<C>> ai = jt.next(); 263 //System.out.println("si = " + si); 264 //System.out.println("ai = " + ai); 265 if (si == null || ai == null) { 266 continue; 267 } 268 //pi has wrong type, should be: List<GenSolvablePolynomial<C>> 269 List<GenPolynomial<C>> pi = blas.scalarProduct(si, PolynomialList.<C> castToList(ai)); 270 //System.out.println("pi = " + pi); 271 rf = PolynomialList.<C> castToSolvableList(blas.vectorAdd(PolynomialList.<C> castToList(rf), 272 pi)); 273 } 274 if (it.hasNext() || jt.hasNext()) { 275 logger.error("zeroRelationsArbitrary wrong sizes"); 276 } 277 //System.out.println("\nMg Mf = " + rf + "\n"); 278 M.add(rf); 279 } 280 //ModuleList<C> ML = new ModuleList<C>( ring, M ); 281 //System.out.println("syz ML = " + ML); 282 // debug only: 283 //List<GenSolvablePolynomial<C>> F2 = new ArrayList<GenSolvablePolynomial<C>>( F.size() ); 284 /* not true in general 285 List<GenPolynomial<C>> Fp = PolynomialList.<C>castToList(F); 286 for ( List<GenSolvablePolynomial<C>> rr: M ) { 287 GenSolvablePolynomial<C> rrg = PolynomialList.<C>castToSolvableList(blas.scalarProduct(Fp,PolynomialList.<C>castToList(rr))); 288 F2.add( rrg ); 289 } 290 PolynomialList<C> pF = new PolynomialList<C>( ring, F ); 291 PolynomialList<C> pF2 = new PolynomialList<C>( ring, F2 ); 292 if ( ! pF.equals( pF2 ) ) { 293 logger.error("is FAB = F ? false"); 294 //System.out.println("pF = " + pF.list.size()); 295 //System.out.println("pF2 = " + pF2.list.size()); 296 } 297 */ 298 int sflen = sf.size(); 299 List<List<GenSolvablePolynomial<C>>> M2; 300 M2 = new ArrayList<List<GenSolvablePolynomial<C>>>(lenf); 301 int i = 0; 302 for (List<GenSolvablePolynomial<C>> ri : M) { 303 List<GenSolvablePolynomial<C>> r2i; 304 r2i = new ArrayList<GenSolvablePolynomial<C>>(ri.size()); 305 int j = 0; 306 for (GenSolvablePolynomial<C> rij : ri) { 307 GenSolvablePolynomial<C> p = null; 308 if (i == j) { 309 p = (GenSolvablePolynomial<C>) ring.getONE().subtract(rij); 310 } else { 311 if (rij != null) { 312 p = (GenSolvablePolynomial<C>) rij.negate(); 313 } 314 } 315 r2i.add(p); 316 j++; 317 } 318 M2.add(r2i); 319 if (!blas.isZero(PolynomialList.<C> castToList(r2i))) { 320 sf.add(r2i); 321 } 322 i++; 323 } 324 ModuleList<C> M2L = new ModuleList<C>(ring, M2); 325 if (debug) { 326 logger.debug("syz M2L = {}", M2L); 327 } 328 329 if (debug) { 330 ModuleList<C> SF = new ModuleList<C>(ring, sf); 331 logger.debug("syz sf = {}", SF); 332 logger.debug("#syz {}, {}", sflen, sf.size()); 333 } 334 if (assertEnabled) { 335 logger.info("check4 left syz start"); 336 if (!isLeftZeroRelation(sf, F)) { 337 logger.error("is syz sf ? false"); 338 } 339 logger.info("check4 left syz end"); 340 } 341 return sf; 342 } 343 344 345 /** 346 * Left Ore condition. Generators for the left Ore condition of two solvable 347 * polynomials. 348 * @param a solvable polynomial 349 * @param b solvable polynomial 350 * @return [p,q] with p*a = q*b 351 */ 352 @SuppressWarnings({ "cast", "unchecked" }) 353 public GenSolvablePolynomial<C>[] leftOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) { 354 if (a == null || a.isZERO() || b == null || b.isZERO()) { 355 throw new IllegalArgumentException("a and b must be non zero"); 356 } 357 GenSolvablePolynomialRing<C> pfac = a.ring; 358 GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2]; 359 if (a.equals(b)) { 360 oc[0] = pfac.getONE(); 361 oc[1] = pfac.getONE(); 362 return oc; 363 } 364 if (a.equals(b.negate())) { 365 oc[0] = pfac.getONE(); 366 oc[1] = (GenSolvablePolynomial<C>) pfac.getONE().negate(); 367 return oc; 368 } 369 if (a.isConstant()) { 370 if (pfac.coFac.isCommutative()) { // ?? 371 oc[0] = b; 372 oc[1] = a; 373 return oc; 374 } 375 C c = a.leadingBaseCoefficient().inverse(); 376 oc[0] = b.multiply(c); // was Left 377 oc[1] = pfac.getONE(); 378 return oc; 379 } 380 if (b.isConstant()) { 381 if (pfac.coFac.isCommutative()) { // ?? 382 oc[0] = b; 383 oc[1] = a; 384 return oc; 385 } 386 oc[0] = pfac.getONE(); 387 C c = b.leadingBaseCoefficient().inverse(); 388 oc[1] = a.multiply(c); // was Left 389 return oc; 390 } 391 logger.info("computing left Ore condition: {}, {}", a, b); 392 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(2); 393 F.add(a); 394 F.add(b); 395 List<List<GenSolvablePolynomial<C>>> Gz = leftZeroRelationsArbitrary(F); 396 /* 397 if (Gz.size() < 0) { // always false 398 //System.out.println("Gz = " + Gz); 399 ModuleList<C> M = new ModuleList<C>(pfac, Gz); 400 ModuleList<C> GM = sbb.leftGB(M); 401 //System.out.println("GM = " + GM); 402 Gz = GM.castToSolvableList(); 403 } 404 */ 405 List<GenSolvablePolynomial<C>> G1 = null; 406 GenSolvablePolynomial<C> g1 = null; 407 for (List<GenSolvablePolynomial<C>> Gi : Gz) { 408 //System.out.println("Gil = " + Gi); 409 if (Gi.get(0).isZERO()) { 410 continue; 411 } 412 if (G1 == null) { 413 G1 = Gi; 414 } 415 if (g1 == null) { 416 g1 = G1.get(0); 417 } else if (g1.compareTo(Gi.get(0)) > 0) { //g1.degree() > Gi.get(0).degree() 418 G1 = Gi; 419 g1 = G1.get(0); 420 } 421 } 422 oc[0] = g1; //G1.get(0); 423 oc[1] = (GenSolvablePolynomial<C>) G1.get(1).negate(); 424 //logger.info("Ore multiple: {}, {}", oc[0].multiply(a), Arrays.toString(oc)); 425 return oc; 426 } 427 428 429 /** 430 * Right Ore condition. Generators for the right Ore condition of two 431 * solvable polynomials. 432 * @param a solvable polynomial 433 * @param b solvable polynomial 434 * @return [p,q] with a*p = b*q 435 */ 436 @SuppressWarnings({ "cast", "unchecked" }) 437 public GenSolvablePolynomial<C>[] rightOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) { 438 if (a == null || a.isZERO() || b == null || b.isZERO()) { 439 throw new IllegalArgumentException("a and b must be non zero"); 440 } 441 GenSolvablePolynomialRing<C> pfac = a.ring; 442 GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2]; 443 if (a.equals(b)) { 444 oc[0] = pfac.getONE(); 445 oc[1] = pfac.getONE(); 446 return oc; 447 } 448 if (a.isConstant()) { 449 if (pfac.coFac.isCommutative()) { // ?? 450 oc[0] = b; 451 oc[1] = a; 452 return oc; 453 } 454 C c = a.leadingBaseCoefficient().inverse(); 455 oc[0] = b.multiplyLeft(c); 456 oc[1] = pfac.getONE(); 457 return oc; 458 } 459 if (b.isConstant()) { 460 if (pfac.coFac.isCommutative()) { // ?? 461 oc[0] = b; 462 oc[1] = a; 463 return oc; 464 } 465 oc[0] = pfac.getONE(); 466 C c = b.leadingBaseCoefficient().inverse(); 467 oc[1] = a.multiplyLeft(c); 468 return oc; 469 } 470 logger.info("computing right Ore condition: {}, {}", a, b); 471 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(2); 472 F.add(a); 473 F.add(b); 474 List<List<GenSolvablePolynomial<C>>> Gz = rightZeroRelationsArbitrary(F); 475 List<GenSolvablePolynomial<C>> G1 = null; 476 GenSolvablePolynomial<C> g1 = null; 477 for (List<GenSolvablePolynomial<C>> Gi : Gz) { 478 //System.out.println("Gir = " + Gi); 479 if (Gi.get(0).isZERO()) { 480 continue; 481 } 482 if (G1 == null) { 483 G1 = Gi; 484 } 485 if (g1 == null) { 486 g1 = G1.get(0); 487 } else if (g1.compareTo(Gi.get(0)) > 0) { 488 G1 = Gi; 489 g1 = G1.get(0); 490 } 491 } 492 oc[0] = G1.get(0); 493 oc[1] = (GenSolvablePolynomial<C>) G1.get(1).negate(); 494 //logger.info("Ore multiple: {}, {}", a.multiply(oc[0]), Arrays.toString(oc)); 495 return oc; 496 } 497 498 499 /** 500 * Left simplifier. Method of Apel & Lassner (1987). 501 * @param a solvable polynomial 502 * @param b solvable polynomial 503 * @return [p,q] with a/b = p/q and q is minimal and monic 504 */ 505 @Override 506 @SuppressWarnings({ "unchecked" }) 507 public GenSolvablePolynomial<C>[] leftSimplifier(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) { 508 if (a == null || a.isZERO() || b == null || b.isZERO()) { 509 throw new IllegalArgumentException("a and b must be non zero"); 510 } 511 GenSolvablePolynomial<C>[] oc = null; 512 if (a.isConstant() || b.isConstant()) { 513 oc = new GenSolvablePolynomial[] { a, b }; 514 return oc; 515 } 516 if (a.totalDegree() > 3 || b.totalDegree() > 3) { // how avoid too long running GBs ? 517 //if (a.totalDegree() + b.totalDegree() > 6) { 518 // && a.length() < 10 && b.length() < 10 519 logger.info("skipping simplifier GB computation: degs = {}, {}", a.totalDegree(), b.totalDegree()); 520 oc = new GenSolvablePolynomial[] { a, b }; 521 return oc; 522 } 523 //GenSolvablePolynomialRing<C> pfac = a.ring; 524 oc = rightOreCond(a, b); 525 logger.info("oc = {}", Arrays.toString(oc)); // + ", a = {}, b = {}", a, b); 526 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(oc.length); 527 // opposite order and undo negation 528 F.add((GenSolvablePolynomial<C>) oc[1].negate()); 529 F.add(oc[0]); 530 //logger.info("F = {}", F); 531 List<List<GenSolvablePolynomial<C>>> Gz = leftZeroRelationsArbitrary(F); 532 //logger.info("Gz: {}", Gz); 533 List<GenSolvablePolynomial<C>> G1 = new ArrayList<GenSolvablePolynomial<C>>(Gz.size()); 534 List<GenSolvablePolynomial<C>> G2 = new ArrayList<GenSolvablePolynomial<C>>(Gz.size()); 535 for (List<GenSolvablePolynomial<C>> ll : Gz) { 536 if (!ll.get(0).isZERO()) { // && !ll.get(1).isZERO() 537 G1.add(ll.get(0)); // denominators 538 G2.add(ll.get(1)); // numerators 539 } 540 } 541 logger.info("G1(den): {}, G2(num): {}", G1, G2); 542 SolvableExtendedGB<C> exgb = sbb.extLeftGB(G1); 543 logger.info("exgb.F: {}, exgb.G: {}", exgb.F, exgb.G); 544 List<GenSolvablePolynomial<C>> G = exgb.G; 545 int m = 0; 546 GenSolvablePolynomial<C> min = null; 547 for (int i = 0; i < G.size(); i++) { 548 if (min == null) { 549 min = G.get(i); 550 m = i; 551 } else if (min.compareTo(G.get(i)) > 0) { 552 min = G.get(i); 553 m = i; 554 } 555 } 556 //wrong: blas.scalarProduct(G2,exgb.G2F.get(m)); 557 GenSolvablePolynomial<C> min2 = (GenSolvablePolynomial<C>) blas.scalarProduct( 558 PolynomialList.<C> castToList(exgb.G2F.get(m)), PolynomialList.<C> castToList(G2)); 559 logger.info("min(den): {}, min(num): {}, m = {}, {}", min, min2, m, exgb.G2F.get(m)); 560 // opposite order 561 GenSolvablePolynomial<C> n = min2; // nominator 562 GenSolvablePolynomial<C> d = min; // denominator 563 // normalize 564 if (d.signum() < 0) { 565 n = (GenSolvablePolynomial<C>) n.negate(); 566 d = (GenSolvablePolynomial<C>) d.negate(); 567 } 568 C lc = d.leadingBaseCoefficient(); 569 if (!lc.isONE() && lc.isUnit()) { 570 lc = lc.inverse(); 571 n = n.multiplyLeft(lc); 572 d = d.multiplyLeft(lc); 573 } 574 if (debug) { 575 int t = compare(a, b, n, d); 576 if (t != 0) { 577 oc[0] = a; // nominator 578 oc[1] = b; // denominator 579 throw new RuntimeException("simp wrong, giving up: t = " + t); 580 //logger.error("simp wrong, giving up: t = {}", t); 581 //return oc; 582 } 583 } 584 oc[0] = n; // nominator 585 oc[1] = d; // denominator 586 return oc; 587 } 588 589}