001/* 002 * $Id: SolvableGroebnerBaseSeq.java 4104 2012-08-18 10:00:59Z kredel $ 003 */ 004 005package edu.jas.gb; 006 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.ListIterator; 011 012import org.apache.log4j.Logger; 013 014import edu.jas.poly.ExpVector; 015import edu.jas.poly.GenPolynomial; 016import edu.jas.poly.GenSolvablePolynomial; 017import edu.jas.poly.GenSolvablePolynomialRing; 018import edu.jas.poly.PolynomialList; 019import edu.jas.structure.RingElem; 020 021 022/** 023 * Solvable Groebner bases sequential algorithms. Implements common left, right 024 * and twosided Groebner bases and left, right and twosided GB tests. 025 * @param <C> coefficient type 026 * @author Heinz Kredel. 027 */ 028 029public class SolvableGroebnerBaseSeq<C extends RingElem<C>> extends SolvableGroebnerBaseAbstract<C> { 030 031 032 private static final Logger logger = Logger.getLogger(SolvableGroebnerBaseSeq.class); 033 034 035 private final boolean debug = logger.isDebugEnabled(); 036 037 038 /** 039 * Constructor. 040 */ 041 public SolvableGroebnerBaseSeq() { 042 super(); 043 } 044 045 046 /** 047 * Constructor. 048 * @param sred Solvable reduction engine 049 * @param pl pair selection strategy 050 */ 051 public SolvableGroebnerBaseSeq(SolvableReduction<C> sred, PairList<C> pl) { 052 super(sred, pl); 053 } 054 055 056 /** 057 * Left Groebner base using pairlist class. 058 * @param modv number of module variables. 059 * @param F solvable polynomial list. 060 * @return leftGB(F) a left Groebner base of F. 061 */ 062 @SuppressWarnings("unchecked") 063 public List<GenSolvablePolynomial<C>> leftGB(int modv, List<GenSolvablePolynomial<C>> F) { 064 List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>(); 065 PairList<C> pairlist = null; 066 int l = F.size(); 067 // ListIterator it = F.listIterator(); 068 for (GenSolvablePolynomial<C> p : F) { 069 // p = (SolvablePolynomial) it.next(); 070 if (p.length() > 0) { 071 p = (GenSolvablePolynomial<C>) p.monic(); 072 if (p.isONE()) { 073 G.clear(); 074 G.add(p); 075 return G; // since no threads are activated 076 } 077 G.add(p); 078 if (pairlist == null) { 079 //pairlist = new OrderedPairlist<C>( modv, p.ring ); 080 pairlist = strategy.create(modv, p.ring); 081 } 082 // putOne not required 083 pairlist.put(p); 084 } else { 085 l--; 086 } 087 } 088 if (l <= 1) { 089 return G; // since no threads are activated 090 } 091 092 GenSolvablePolynomial<C> pi, pj, S, H; 093 Pair<C> pair; 094 while (pairlist.hasNext()) { 095 pair = pairlist.removeNext(); 096 if (pair == null) { 097 continue; 098 } 099 pi = (GenSolvablePolynomial<C>) pair.pi; 100 pj = (GenSolvablePolynomial<C>) pair.pj; 101 if (debug) { 102 logger.info("pi = " + pi); 103 logger.info("pj = " + pj); 104 } 105 106 S = sred.leftSPolynomial(pi, pj); 107 if (S.isZERO()) { 108 pair.setZero(); 109 continue; 110 } 111 if (debug) { 112 logger.info("ht(S) = " + S.leadingExpVector()); 113 } 114 115 H = sred.leftNormalform(G, S); 116 if (H.isZERO()) { 117 pair.setZero(); 118 continue; 119 } 120 if (debug) { 121 logger.info("ht(H) = " + H.leadingExpVector()); 122 } 123 124 H = (GenSolvablePolynomial<C>) H.monic(); 125 if (H.isONE()) { 126 G.clear(); 127 G.add(H); 128 return G; // since no threads are activated 129 } 130 if (debug) { 131 logger.info("H = " + H); 132 } 133 if (H.length() > 0) { 134 l++; 135 G.add(H); 136 pairlist.put(H); 137 } 138 } 139 logger.debug("#sequential list = " + G.size()); 140 G = leftMinimalGB(G); 141 logger.info("" + pairlist); 142 return G; 143 } 144 145 146 /** 147 * Solvable Extended Groebner base using critical pair class. 148 * @param modv module variable number. 149 * @param F solvable polynomial list. 150 * @return a container for an extended left Groebner base of F. 151 */ 152 @SuppressWarnings("unchecked") 153 public SolvableExtendedGB<C> extLeftGB(int modv, List<GenSolvablePolynomial<C>> F) { 154 155 List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>(); 156 List<List<GenSolvablePolynomial<C>>> F2G = new ArrayList<List<GenSolvablePolynomial<C>>>(); 157 List<List<GenSolvablePolynomial<C>>> G2F = new ArrayList<List<GenSolvablePolynomial<C>>>(); 158 PairList<C> pairlist = null; 159 boolean oneInGB = false; 160 int len = F.size(); 161 162 List<GenSolvablePolynomial<C>> row = null; 163 List<GenSolvablePolynomial<C>> rows = null; 164 List<GenSolvablePolynomial<C>> rowh = null; 165 GenSolvablePolynomialRing<C> ring = null; 166 GenSolvablePolynomial<C> H; 167 GenSolvablePolynomial<C> p; 168 169 int nzlen = 0; 170 for (GenSolvablePolynomial<C> f : F) { 171 if (f.length() > 0) { 172 nzlen++; 173 } 174 if (ring == null) { 175 ring = f.ring; 176 } 177 } 178 GenSolvablePolynomial<C> mone = ring.getONE(); //.negate(); 179 int k = 0; 180 ListIterator<GenSolvablePolynomial<C>> it = F.listIterator(); 181 while (it.hasNext()) { 182 p = it.next(); 183 if (p.length() > 0) { 184 row = new ArrayList<GenSolvablePolynomial<C>>(nzlen); 185 for (int j = 0; j < nzlen; j++) { 186 row.add(null); 187 } 188 //C c = p.leadingBaseCoefficient(); 189 //c = c.inverse(); 190 //p = p.multiply( c ); 191 row.set(k, mone); //.multiply(c) ); 192 k++; 193 if (p.isUnit()) { 194 G.clear(); 195 G.add(p); 196 G2F.clear(); 197 G2F.add(row); 198 oneInGB = true; 199 break; 200 } 201 G.add(p); 202 G2F.add(row); 203 if (pairlist == null) { 204 //pairlist = new CriticalPairList<C>( modv, p.ring ); 205 pairlist = strategy.create(modv, p.ring); 206 } 207 // putOne not required 208 pairlist.put(p); 209 } else { 210 len--; 211 } 212 } 213 SolvableExtendedGB<C> exgb; 214 if (len <= 1 || oneInGB) { 215 // adjust F2G 216 for (GenSolvablePolynomial<C> f : F) { 217 row = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 218 for (int j = 0; j < G.size(); j++) { 219 row.add(null); 220 } 221 H = sred.leftNormalform(row, G, f); 222 if (!H.isZERO()) { 223 logger.error("nonzero H = " + H); 224 } 225 F2G.add(row); 226 } 227 exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F); 228 //System.out.println("exgb 1 = " + exgb); 229 return exgb; 230 } 231 232 Pair<C> pair; 233 int i, j; 234 GenSolvablePolynomial<C> pi; 235 GenSolvablePolynomial<C> pj; 236 GenSolvablePolynomial<C> S; 237 GenSolvablePolynomial<C> x; 238 GenSolvablePolynomial<C> y; 239 //GenPolynomial<C> z; 240 while (pairlist.hasNext() && !oneInGB) { 241 pair = pairlist.removeNext(); 242 if (pair == null) { 243 //pairlist.update(); // ? 244 continue; 245 } 246 i = pair.i; 247 j = pair.j; 248 pi = (GenSolvablePolynomial<C>) pair.pi; 249 pj = (GenSolvablePolynomial<C>) pair.pj; 250 if (debug) { 251 logger.info("i, pi = " + i + ", " + pi); 252 logger.info("j, pj = " + j + ", " + pj); 253 } 254 255 rows = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 256 for (int m = 0; m < G.size(); m++) { 257 rows.add(null); 258 } 259 S = sred.leftSPolynomial(rows, i, pi, j, pj); 260 if (debug) { 261 logger.debug("is reduction S = " + sred.isLeftReductionNF(rows, G, ring.getZERO(), S)); 262 } 263 if (S.isZERO()) { 264 pair.setZero(); 265 //pairlist.update( pair, S ); 266 // do not add to G2F 267 continue; 268 } 269 if (debug) { 270 logger.debug("ht(S) = " + S.leadingExpVector()); 271 } 272 273 rowh = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 274 for (int m = 0; m < G.size(); m++) { 275 rowh.add(null); 276 } 277 H = sred.leftNormalform(rowh, G, S); 278 if (debug) { 279 //System.out.println("H = " + H); 280 logger.debug("is reduction H = " + sred.isLeftReductionNF(rowh, G, S, H)); 281 } 282 if (H.isZERO()) { 283 pair.setZero(); 284 //pairlist.update( pair, H ); 285 // do not add to G2F 286 continue; 287 } 288 if (debug) { 289 logger.debug("ht(H) = " + H.leadingExpVector()); 290 } 291 292 row = new ArrayList<GenSolvablePolynomial<C>>(G.size() + 1); 293 for (int m = 0; m < G.size(); m++) { 294 x = rows.get(m); 295 if (x != null) { 296 //System.out.println("ms = " + m + " " + x); 297 x = (GenSolvablePolynomial<C>) x.negate(); 298 } 299 y = rowh.get(m); 300 if (y != null) { 301 y = (GenSolvablePolynomial<C>) y.negate(); 302 //System.out.println("mh = " + m + " " + y); 303 } 304 if (x == null) { 305 x = y; 306 } else { 307 x = (GenSolvablePolynomial<C>) x.sum(y); 308 } 309 //System.out.println("mx = " + m + " " + x); 310 row.add(x); 311 } 312 if (debug) { 313 logger.debug("is reduction 0+sum(row,G) == H : " 314 + sred.isLeftReductionNF(row, G, H, ring.getZERO())); 315 } 316 row.add(null); 317 318 319 // H = H.monic(); 320 C c = H.leadingBaseCoefficient(); 321 c = c.inverse(); 322 H = H.multiply(c); 323 // 1*c*row, leads to wrong method dispatch: 324 row = PolynomialList.<C> castToSolvableList(blas.scalarProduct(mone.multiply(c), 325 PolynomialList.<C> castToList(row))); 326 row.set(G.size(), mone); 327 if (H.isONE()) { 328 // pairlist.record( pair, H ); 329 // G.clear(); 330 G.add(H); 331 G2F.add(row); 332 oneInGB = true; 333 break; 334 } 335 if (debug) { 336 logger.debug("H = " + H); 337 } 338 G.add(H); 339 //pairlist.update( pair, H ); 340 pairlist.put(H); 341 G2F.add(row); 342 } 343 if (debug) { 344 exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F); 345 logger.info("exgb unnorm = " + exgb); 346 } 347 G2F = normalizeMatrix(F.size(), G2F); 348 if (debug) { 349 exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F); 350 logger.info("exgb nonmin = " + exgb); 351 boolean t2 = isLeftReductionMatrix(exgb); 352 logger.debug("exgb t2 = " + t2); 353 } 354 exgb = minimalSolvableExtendedGB(F.size(), G, G2F); 355 G = exgb.G; 356 G2F = exgb.G2F; 357 logger.debug("#sequential list = " + G.size()); 358 logger.info("" + pairlist); 359 // setup matrices F and F2G 360 for (GenSolvablePolynomial<C> f : F) { 361 row = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 362 for (int m = 0; m < G.size(); m++) { 363 row.add(null); 364 } 365 H = sred.leftNormalform(row, G, f); 366 if (!H.isZERO()) { 367 logger.error("nonzero H = " + H); 368 } 369 F2G.add(row); 370 } 371 return new SolvableExtendedGB<C>(F, G, F2G, G2F); 372 } 373 374 375 /** 376 * Twosided Groebner base using pairlist class. 377 * @param modv number of module variables. 378 * @param Fp solvable polynomial list. 379 * @return tsGB(Fp) a twosided Groebner base of Fp. 380 */ 381 @SuppressWarnings("unchecked") 382 public List<GenSolvablePolynomial<C>> twosidedGB(int modv, List<GenSolvablePolynomial<C>> Fp) { 383 if (Fp == null || Fp.size() == 0) { // 0 not 1 384 return new ArrayList<GenSolvablePolynomial<C>>(); 385 } 386 GenSolvablePolynomialRing<C> fac = Fp.get(0).ring; // assert != null 387 //List<GenSolvablePolynomial<C>> X = generateUnivar( modv, Fp ); 388 List<GenSolvablePolynomial<C>> X = fac.univariateList(modv); 389 //System.out.println("X univ = " + X); 390 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(Fp.size() * (1 + X.size())); 391 F.addAll(Fp); 392 GenSolvablePolynomial<C> p, x, q; 393 for (int i = 0; i < Fp.size(); i++) { 394 p = Fp.get(i); 395 for (int j = 0; j < X.size(); j++) { 396 x = X.get(j); 397 q = p.multiply(x); 398 q = sred.leftNormalform(F, q); 399 if (!q.isZERO()) { 400 F.add(q); 401 } 402 } 403 } 404 //System.out.println("F generated = " + F); 405 List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>(); 406 PairList<C> pairlist = null; 407 int l = F.size(); 408 ListIterator<GenSolvablePolynomial<C>> it = F.listIterator(); 409 while (it.hasNext()) { 410 p = it.next(); 411 if (p.length() > 0) { 412 p = (GenSolvablePolynomial<C>) p.monic(); 413 if (p.isONE()) { 414 G.clear(); 415 G.add(p); 416 return G; // since no threads are activated 417 } 418 G.add(p); 419 if (pairlist == null) { 420 // pairlist = new OrderedPairlist<C>( modv, p.ring ); 421 pairlist = strategy.create(modv, p.ring); 422 } 423 // putOne not required 424 pairlist.put(p); 425 } else { 426 l--; 427 } 428 } 429 //System.out.println("G to check = " + G); 430 if (l <= 1) { // 1 ok 431 return G; // since no threads are activated 432 } 433 434 Pair<C> pair; 435 GenSolvablePolynomial<C> pi, pj, S, H; 436 while (pairlist.hasNext()) { 437 pair = pairlist.removeNext(); 438 if (pair == null) { 439 continue; 440 } 441 442 pi = (GenSolvablePolynomial<C>) pair.pi; 443 pj = (GenSolvablePolynomial<C>) pair.pj; 444 if (debug) { 445 logger.debug("pi = " + pi); 446 logger.debug("pj = " + pj); 447 } 448 449 S = sred.leftSPolynomial(pi, pj); 450 if (S.isZERO()) { 451 pair.setZero(); 452 continue; 453 } 454 if (debug) { 455 logger.debug("ht(S) = " + S.leadingExpVector()); 456 } 457 458 H = sred.leftNormalform(G, S); 459 if (H.isZERO()) { 460 pair.setZero(); 461 continue; 462 } 463 if (debug) { 464 logger.debug("ht(H) = " + H.leadingExpVector()); 465 } 466 467 H = (GenSolvablePolynomial<C>) H.monic(); 468 if (H.isONE()) { 469 G.clear(); 470 G.add(H); 471 return G; // since no threads are activated 472 } 473 if (debug) { 474 logger.debug("H = " + H); 475 } 476 if (H.length() > 0) { 477 l++; 478 G.add(H); 479 pairlist.put(H); 480 for (int j = 0; j < X.size(); j++) { 481 l++; 482 x = X.get(j); 483 p = H.multiply(x); 484 p = sred.leftNormalform(G, p); 485 if (!p.isZERO()) { 486 p = (GenSolvablePolynomial<C>) p.monic(); 487 if (p.isONE()) { 488 G.clear(); 489 G.add(p); 490 return G; // since no threads are activated 491 } 492 G.add(p); 493 pairlist.put(p); 494 } 495 } 496 } 497 } 498 logger.debug("#sequential list = " + G.size()); 499 G = leftMinimalGB(G); 500 logger.info("" + pairlist); 501 return G; 502 } 503 504 505 /** 506 * Normalize M. Make all rows the same size and make certain column elements 507 * zero. 508 * @param M a reduction matrix. 509 * @return normalized M. 510 */ 511 public List<List<GenSolvablePolynomial<C>>> normalizeMatrix(int flen, 512 List<List<GenSolvablePolynomial<C>>> M) { 513 if (M == null) { 514 return M; 515 } 516 if (M.size() == 0) { 517 return M; 518 } 519 List<List<GenSolvablePolynomial<C>>> N = new ArrayList<List<GenSolvablePolynomial<C>>>(); 520 List<List<GenSolvablePolynomial<C>>> K = new ArrayList<List<GenSolvablePolynomial<C>>>(); 521 int len = M.get(M.size() - 1).size(); // longest row 522 // pad / extend rows 523 for (List<GenSolvablePolynomial<C>> row : M) { 524 List<GenSolvablePolynomial<C>> nrow = new ArrayList<GenSolvablePolynomial<C>>(row); 525 for (int i = row.size(); i < len; i++) { 526 nrow.add(null); 527 } 528 N.add(nrow); 529 } 530 // System.out.println("norm N fill = " + N); 531 // make zero columns 532 int k = flen; 533 for (int i = 0; i < N.size(); i++) { // 0 534 List<GenSolvablePolynomial<C>> row = N.get(i); 535 if (debug) { 536 logger.info("row = " + row); 537 } 538 K.add(row); 539 if (i < flen) { // skip identity part 540 continue; 541 } 542 List<GenSolvablePolynomial<C>> xrow; 543 GenSolvablePolynomial<C> a; 544 //System.out.println("norm i = " + i); 545 for (int j = i + 1; j < N.size(); j++) { 546 List<GenSolvablePolynomial<C>> nrow = N.get(j); 547 //System.out.println("nrow j = " +j + ", " + nrow); 548 if (k < nrow.size()) { // always true 549 a = nrow.get(k); 550 //System.out.println("k, a = " + k + ", " + a); 551 if (a != null && !a.isZERO()) { // a*row + nrow, leads to wrong method dispatch 552 List<GenPolynomial<C>> yrow = blas.scalarProduct(a, 553 PolynomialList.<C> castToList(row)); 554 yrow = blas.vectorAdd(yrow, PolynomialList.<C> castToList(nrow)); 555 xrow = PolynomialList.<C> castToSolvableList(yrow); 556 N.set(j, xrow); 557 } 558 } 559 } 560 k++; 561 } 562 //System.out.println("norm K reduc = " + K); 563 // truncate 564 N.clear(); 565 for (List<GenSolvablePolynomial<C>> row : K) { 566 List<GenSolvablePolynomial<C>> tr = new ArrayList<GenSolvablePolynomial<C>>(); 567 for (int i = 0; i < flen; i++) { 568 tr.add(row.get(i)); 569 } 570 N.add(tr); 571 } 572 K = N; 573 //System.out.println("norm K trunc = " + K); 574 return K; 575 } 576 577 578 /** 579 * Test if M is a left reduction matrix. 580 * @param exgb an SolvableExtendedGB container. 581 * @return true, if exgb contains a left reduction matrix, else false. 582 */ 583 @Override 584 public boolean isLeftReductionMatrix(SolvableExtendedGB<C> exgb) { 585 if (exgb == null) { 586 return true; 587 } 588 return isLeftReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F); 589 } 590 591 592 /** 593 * Minimal solvable extended groebner basis. 594 * @param Gp a left Groebner base. 595 * @param M a left reduction matrix, is modified. 596 * @return a (partially) reduced left Groebner base of Gp in a container. 597 */ 598 public SolvableExtendedGB<C> minimalSolvableExtendedGB(int flen, List<GenSolvablePolynomial<C>> Gp, 599 List<List<GenSolvablePolynomial<C>>> M) { 600 if (Gp == null) { 601 return null; //new SolvableExtendedGB<C>(null,Gp,null,M); 602 } 603 if (Gp.size() <= 1) { 604 return new SolvableExtendedGB<C>(null, Gp, null, M); 605 } 606 List<GenSolvablePolynomial<C>> G; 607 List<GenSolvablePolynomial<C>> F; 608 G = new ArrayList<GenSolvablePolynomial<C>>(Gp); 609 F = new ArrayList<GenSolvablePolynomial<C>>(Gp.size()); 610 611 List<List<GenSolvablePolynomial<C>>> Mg; 612 List<List<GenSolvablePolynomial<C>>> Mf; 613 Mg = new ArrayList<List<GenSolvablePolynomial<C>>>(M.size()); 614 Mf = new ArrayList<List<GenSolvablePolynomial<C>>>(M.size()); 615 List<GenSolvablePolynomial<C>> row; 616 for (List<GenSolvablePolynomial<C>> r : M) { 617 // must be copied also 618 row = new ArrayList<GenSolvablePolynomial<C>>(r); 619 Mg.add(row); 620 } 621 row = null; 622 623 GenSolvablePolynomial<C> a; 624 ExpVector e; 625 ExpVector f; 626 GenSolvablePolynomial<C> p; 627 boolean mt; 628 ListIterator<GenSolvablePolynomial<C>> it; 629 ArrayList<Integer> ix = new ArrayList<Integer>(); 630 ArrayList<Integer> jx = new ArrayList<Integer>(); 631 int k = 0; 632 //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() ); 633 while (G.size() > 0) { 634 a = G.remove(0); 635 e = a.leadingExpVector(); 636 637 it = G.listIterator(); 638 mt = false; 639 while (it.hasNext() && !mt) { 640 p = it.next(); 641 f = p.leadingExpVector(); 642 mt = e.multipleOf(f); 643 } 644 it = F.listIterator(); 645 while (it.hasNext() && !mt) { 646 p = it.next(); 647 f = p.leadingExpVector(); 648 mt = e.multipleOf(f); 649 } 650 //System.out.println("k, mt = " + k + ", " + mt); 651 if (!mt) { 652 F.add(a); 653 ix.add(k); 654 } else { // drop polynomial and corresponding row and column 655 // F.add( a.ring.getZERO() ); 656 jx.add(k); 657 } 658 k++; 659 } 660 if (debug) { 661 logger.debug("ix, #M, jx = " + ix + ", " + Mg.size() + ", " + jx); 662 } 663 int fix = -1; // copied polys 664 // copy Mg to Mf as indicated by ix 665 for (int i = 0; i < ix.size(); i++) { 666 int u = ix.get(i); 667 if (u >= flen && fix == -1) { 668 fix = Mf.size(); 669 } 670 //System.out.println("copy u, fix = " + u + ", " + fix); 671 if (u >= 0) { 672 row = Mg.get(u); 673 Mf.add(row); 674 } 675 } 676 if (F.size() <= 1 || fix == -1) { 677 return new SolvableExtendedGB<C>(null, F, null, Mf); 678 } 679 // must return, since extended normalform has not correct order of polys 680 /* 681 G = F; 682 F = new ArrayList<GenSolvablePolynomial<C>>( G.size() ); 683 List<GenSolvablePolynomial<C>> temp; 684 k = 0; 685 final int len = G.size(); 686 while ( G.size() > 0 ) { 687 a = G.remove(0); 688 if ( k >= fix ) { // dont touch copied polys 689 row = Mf.get( k ); 690 //System.out.println("doing k = " + k + ", " + a); 691 // must keep order, but removed polys missing 692 temp = new ArrayList<GenPolynomial<C>>( len ); 693 temp.addAll( F ); 694 temp.add( a.ring.getZERO() ); // ?? 695 temp.addAll( G ); 696 //System.out.println("row before = " + row); 697 a = sred.leftNormalform( row, temp, a ); 698 //System.out.println("row after = " + row); 699 } 700 F.add( a ); 701 k++; 702 } 703 // does Mf need renormalization? 704 */ 705 return new SolvableExtendedGB<C>(null, F, null, Mf); 706 } 707 708}