001/* 002 * $Id: GroebnerBasePartial.java 5870 2018-07-20 15:56:23Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011 012import org.apache.logging.log4j.Logger; 013import org.apache.logging.log4j.LogManager; 014 015import edu.jas.gb.GroebnerBaseAbstract; 016import edu.jas.gb.GroebnerBaseSeq; 017import edu.jas.poly.GenPolynomial; 018import edu.jas.poly.GenPolynomialRing; 019import edu.jas.poly.OptimizedPolynomialList; 020import edu.jas.poly.PolyUtil; 021import edu.jas.poly.TermOrder; 022import edu.jas.poly.TermOrderOptimization; 023import edu.jas.structure.GcdRingElem; 024import edu.jas.structure.RingFactory; 025 026 027/** 028 * Partial Groebner Bases for subsets of variables. Let <code>pvars</code> be a 029 * subset of variables <code>vars</code> of the polynomial ring K[vars]. Methods 030 * compute Groebner bases with coefficients from K[vars \ pvars] in the 031 * polynomial ring K[vars \ pvars][pvars]. 032 * @param <C> coefficient type 033 * @author Heinz Kredel 034 */ 035 036public class GroebnerBasePartial<C extends GcdRingElem<C>> extends GroebnerBaseAbstract<C> { 037 038 039 private static final Logger logger = LogManager.getLogger(GroebnerBasePartial.class); 040 041 042 //private static final boolean debug = logger.isDebugEnabled(); 043 044 045 /** 046 * Backing Groebner base engine. 047 */ 048 protected GroebnerBaseAbstract<C> bb; 049 050 051 /** 052 * Backing recursive Groebner base engine. 053 */ 054 protected GroebnerBaseAbstract<GenPolynomial<C>> rbb; // can be null 055 056 057 /** 058 * Constructor. 059 */ 060 public GroebnerBasePartial() { 061 this(new GroebnerBaseSeq<C>(), null); 062 } 063 064 065 /** 066 * Constructor. 067 * @param rf coefficient ring factory. 068 */ 069 public GroebnerBasePartial(RingFactory<GenPolynomial<C>> rf) { 070 this(new GroebnerBaseSeq<C>(), new GroebnerBasePseudoRecSeq<C>(rf)); 071 } 072 073 074 /** 075 * Constructor. 076 * @param bb Groebner base engine 077 * @param rbb recursive Groebner base engine 078 */ 079 public GroebnerBasePartial(GroebnerBaseAbstract<C> bb, GroebnerBaseAbstract<GenPolynomial<C>> rbb) { 080 super(); 081 this.bb = bb; 082 this.rbb = rbb; 083 //if (rbb == null) { 084 //logger.warn("no recursive GB given"); 085 //} 086 } 087 088 089 /** 090 * Groebner base using pairlist class. 091 * @param modv module variable number. 092 * @param F polynomial list. 093 * @return GB(F) a Groebner base of F. 094 */ 095 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) { 096 return bb.GB(modv, F); 097 } 098 099 100 /** 101 * Groebner base test. 102 * @param F polynomial list. 103 * @return true, if F is a partial Groebner base, else false. 104 */ 105 public boolean isGBrec(List<GenPolynomial<GenPolynomial<C>>> F) { 106 return isGBrec(0, F); 107 } 108 109 110 /** 111 * Groebner base test. 112 * @param modv module variable number. 113 * @param F polynomial list. 114 * @return true, if F is a partial Groebner base, else false. 115 */ 116 public boolean isGBrec(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 117 if (F == null || F.isEmpty()) { 118 return true; 119 } 120 if (true) { 121 rbb = new GroebnerBasePseudoRecSeq<C>(F.get(0).ring.coFac); 122 } 123 return rbb.isGB(modv, F); 124 } 125 126 127 /** 128 * Partial permuation for specific variables. Computes a permutation perm 129 * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars). 130 * Uses internal (reversed) variable sorting. 131 * @param vars names for all variables. 132 * @param pvars names for main variables, pvars subseteq vars. 133 * @return permutation for vars, such that perm(vars) == pvars ... (vars \ 134 * pvars). 135 */ 136 public static List<Integer> partialPermutation(String[] vars, String[] pvars) { 137 return partialPermutation(vars, pvars, null); 138 //no: return getPermutation(vars,pvars); 139 } 140 141 142 /** 143 * Permutation of variables for elimination. 144 * @param aname variables for the full polynomial ring. 145 * @param ename variables for the elimination ring, subseteq aname. 146 * @return perm({vars \ ename},ename) 147 */ 148 public static List<Integer> getPermutation(String[] aname, String[] ename) { 149 if (aname == null || ename == null) { 150 throw new IllegalArgumentException("aname or ename may not be null"); 151 } 152 List<Integer> perm = new ArrayList<Integer>(aname.length); 153 // add ename permutation 154 for (int i = 0; i < ename.length; i++) { 155 int j = indexOf(ename[i], aname); 156 if (j < 0) { 157 throw new IllegalArgumentException("ename not contained in aname"); 158 } 159 perm.add(j); 160 } 161 //System.out.println("perm_low = " + perm); 162 // add aname \ ename permutation 163 for (int i = 0; i < aname.length; i++) { 164 if (!perm.contains(i)) { 165 perm.add(i); 166 } 167 } 168 //System.out.println("perm_all = " + perm); 169 // reverse permutation indices 170 int n1 = aname.length - 1; 171 List<Integer> perm1 = new ArrayList<Integer>(aname.length); 172 for (Integer k : perm) { 173 perm1.add(n1 - k); 174 } 175 perm = perm1; 176 //System.out.println("perm_inv = " + perm1); 177 Collections.reverse(perm); 178 //System.out.println("perm_rev = " + perm); 179 return perm; 180 } 181 182 183 /** 184 * Index of s in A. 185 * @param s search string 186 * @param A string array 187 * @return i if s == A[i] for some i, else -1. 188 */ 189 public static int indexOf(String s, String[] A) { 190 for (int i = 0; i < A.length; i++) { 191 if (s.equals(A[i])) { 192 return i; 193 } 194 } 195 return -1; 196 } 197 198 199 /** 200 * Partial permuation for specific variables. Computes a permutation perm 201 * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars). 202 * Uses internal (reversed) variable sorting. 203 * @param vars names for all variables. 204 * @param pvars names for main variables, pvars subseteq vars. 205 * @param rvars names for remaining variables, rvars eq { vars \ pvars }. 206 * @return permutation for vars, such that perm(vars) == (pvars, {vars \ 207 * pvars}). 208 */ 209 public static List<Integer> partialPermutation(String[] vars, String[] pvars, String[] rvars) { 210 if (vars == null || pvars == null) { 211 throw new IllegalArgumentException("no variable names found"); 212 } 213 List<String> variables = new ArrayList<String>(vars.length); 214 List<String> pvariables = new ArrayList<String>(pvars.length); 215 for (int i = 0; i < vars.length; i++) { 216 variables.add(vars[i]); 217 } 218 for (int i = 0; i < pvars.length; i++) { 219 pvariables.add(pvars[i]); 220 } 221 if (rvars == null) { 222 rvars = remainingVars(vars, pvars); 223 } 224 List<String> rvariables = new ArrayList<String>(rvars.length); 225 for (int i = 0; i < rvars.length; i++) { 226 rvariables.add(rvars[i]); 227 } 228 if (rvars.length + pvars.length == vars.length) { 229 //System.out.println("pvariables = " + pvariables); 230 return getPermutation(vars, rvars); 231 } 232 logger.info("not implemented for " + variables + " != " + pvariables + " cup " + rvariables); 233 throw new UnsupportedOperationException("not implemented"); 234 /* 235 if (!variables.containsAll(pvariables) || !variables.containsAll(rvariables)) { 236 throw new IllegalArgumentException("partial variables not contained in all variables "); 237 } 238 Collections.reverse(variables); 239 Collections.reverse(pvariables); 240 Collections.reverse(rvariables); 241 System.out.println("variables = " + variables); 242 System.out.println("pvariables = " + pvariables); 243 System.out.println("rvariables = " + rvariables); 244 245 List<Integer> perm = new ArrayList<Integer>(); 246 List<Integer> pv = new ArrayList<Integer>(); 247 for (String s : variables) { 248 int j = pvariables.indexOf(s); 249 if (j >= 0) { 250 perm.add(j); 251 } 252 } 253 int i = pvariables.size(); 254 for (String s : variables) { 255 if (!pvariables.contains(s)) { 256 pv.add(i); 257 } 258 i++; 259 } 260 261 System.out.println("perm, 1 = " + perm); 262 //System.out.println("pv = " + pv); 263 // sort perm according to pvars 264 int ps = perm.size(); // == pvars.length 265 for (int k = 0; k < ps; k++) { 266 for (int j = k + 1; j < ps; j++) { 267 int kk = variables.indexOf(pvariables.get(k)); 268 int jj = variables.indexOf(pvariables.get(j)); 269 if (kk > jj) { // swap 270 int t = perm.get(k); 271 System.out.println("swap " + t + " with " + perm.get(j)); 272 perm.set(k, perm.get(j)); 273 perm.set(j, t); 274 } 275 } 276 } 277 //System.out.println("perm = " + perm); 278 // sort pv according to rvars 279 int rs = pv.size(); // == rvars.length 280 for (int k = 0; k < rs; k++) { 281 for (int j = k + 1; j < rs; j++) { 282 int kk = variables.indexOf(rvariables.get(k)); 283 int jj = variables.indexOf(rvariables.get(j)); 284 if (kk > jj) { // swap 285 int t = pv.get(k); 286 //System.out.println("swap " + t + " with " + perm.get(j)); 287 pv.set(k, pv.get(j)); 288 pv.set(j, t); 289 } 290 } 291 } 292 //System.out.println("pv = " + pv); 293 perm.addAll(pv); 294 System.out.println("perm, 2 = " + perm); 295 return perm; 296 */ 297 } 298 299 300 /** 301 * Partial permuation for specific variables. Computes a permutation perm 302 * for the variables vars, such that perm(vars) == (evars, pvars, (vars \ { 303 * evars, pvars }). Uses internal (reversed) variable sorting. 304 * @param vars names for all variables. 305 * @param evars names for elimination variables, evars subseteq vars. 306 * @param pvars names for main variables, pvars subseteq vars. 307 * @param rvars names for remaining variables, rvars eq {vars \ { evars, 308 * pvars } }. 309 * @return permutation for vars, such that perm(vars) == (evars,pvars, {vars 310 * \ {evars,pvars}}. 311 */ 312 public static List<Integer> partialPermutation(String[] vars, String[] evars, String[] pvars, 313 String[] rvars) { 314 if (vars == null || evars == null || pvars == null) { 315 throw new IllegalArgumentException("not all variable names given"); 316 } 317 String[] uvars; 318 if (rvars != null) { 319 uvars = new String[pvars.length + rvars.length]; 320 for (int i = 0; i < pvars.length; i++) { 321 uvars[i] = pvars[i]; 322 } 323 for (int i = 0; i < rvars.length; i++) { 324 uvars[pvars.length + i] = rvars[i]; 325 } 326 } else { 327 uvars = pvars; 328 } 329 //System.out.println("uvars = " + Arrays.toString(uvars)); 330 List<Integer> perm = partialPermutation(vars, evars, uvars); 331 return perm; 332 } 333 334 335 /** 336 * Remaining variables vars \ pvars. Uses internal (reversed) variable 337 * sorting, original order is preserved. 338 * @param vars names for all variables. 339 * @param pvars names for main variables, pvars subseteq vars. 340 * @return remaining vars = (vars \ pvars). 341 */ 342 public static String[] remainingVars(String[] vars, String[] pvars) { 343 if (vars == null || pvars == null) { 344 throw new IllegalArgumentException("no variable names found"); 345 } 346 List<String> variables = new ArrayList<String>(vars.length); 347 List<String> pvariables = new ArrayList<String>(pvars.length); 348 for (int i = 0; i < vars.length; i++) { 349 variables.add(vars[i]); 350 } 351 for (int i = 0; i < pvars.length; i++) { 352 pvariables.add(pvars[i]); 353 } 354 if (!variables.containsAll(pvariables)) { 355 throw new IllegalArgumentException("partial variables not contained in all variables "); 356 } 357 // variables.setMinus(pvariables) 358 List<String> rvariables = new ArrayList<String>(variables); 359 for (String s : pvariables) { 360 rvariables.remove(s); 361 } 362 int cl = vars.length - pvars.length; 363 String[] rvars = new String[cl]; 364 int i = 0; 365 for (String s : rvariables) { 366 rvars[i++] = s; 367 } 368 return rvars; 369 } 370 371 372 /** 373 * Partial recursive Groebner base for specific variables. Computes Groebner 374 * base in K[vars \ pvars][pvars] with coefficients from K[vars \ pvars]. 375 * @param F polynomial list. 376 * @param pvars names for main variables of partial Groebner base 377 * computation. 378 * @return a container for a partial Groebner base of F wrt pvars. 379 */ 380 public OptimizedPolynomialList<GenPolynomial<C>> partialGBrec(List<GenPolynomial<C>> F, String[] pvars) { 381 if (F == null || F.isEmpty()) { 382 throw new IllegalArgumentException("empty F not allowed"); 383 } 384 GenPolynomialRing<C> fac = F.get(0).ring; 385 String[] vars = fac.getVars(); 386 if (vars == null || pvars == null) { 387 throw new IllegalArgumentException("not all variable names found"); 388 } 389 if (vars.length == pvars.length) { 390 throw new IllegalArgumentException("use non recursive partialGB algorithm"); 391 } 392 // compute permutation (in reverse sorting) 393 List<Integer> perm = partialPermutation(vars, pvars); 394 395 GenPolynomialRing<C> pfac = fac.permutation(perm); 396 if (logger.isInfoEnabled()) { 397 logger.info("pfac = " + pfac); 398 } 399 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 400 //System.out.println("ppolys = " + ppolys); 401 402 int cl = fac.nvar - pvars.length; // > 0 403 int pl = pvars.length; 404 String[] rvars = remainingVars(vars, pvars); 405 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 406 //System.out.println("cfac = " + cfac); 407 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, 408 fac.tord, pvars); 409 if (logger.isInfoEnabled()) { 410 logger.info("rfac = " + rfac); 411 } 412 //System.out.println("rfac = " + rfac); 413 414 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 415 //System.out.println("\nFr = " + Fr); 416 417 if (true) { 418 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 419 } 420 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 421 //System.out.println("\nGr = " + Gr); 422 //perm = perm.subList(0,pl); 423 OptimizedPolynomialList<GenPolynomial<C>> pgb = new OptimizedPolynomialList<GenPolynomial<C>>(perm, 424 rfac, Gr); 425 return pgb; 426 } 427 428 429 /** 430 * Partial Groebner base for specific variables. Computes Groebner base in 431 * K[vars \ pvars][pvars] with coefficients from K[vars \ pvars] but returns 432 * polynomials in K[vars \ pvars, pvars]. 433 * @param F polynomial list. 434 * @param pvars names for main variables of partial Groebner base 435 * computation. 436 * @return a container for a partial Groebner base of F wrt pvars. 437 */ 438 public OptimizedPolynomialList<C> partialGB(List<GenPolynomial<C>> F, String[] pvars) { 439 if (F == null || F.isEmpty()) { 440 throw new IllegalArgumentException("empty F not allowed"); 441 } 442 GenPolynomialRing<C> fac = F.get(0).ring; 443 String[] vars = fac.getVars(); 444 // compute permutation (in reverse sorting) 445 //String[] xvars = remainingVars(vars, pvars); 446 //System.out.println("xvars = " + Arrays.toString(xvars)); 447 448 List<Integer> perm = partialPermutation(vars, pvars); 449 //System.out.println("pGB, perm = " + perm); 450 //System.out.println("pGB, perm,1 = " + getPermutation(vars, xvars)); 451 452 GenPolynomialRing<C> pfac = fac.permutation(perm); 453 if (logger.isInfoEnabled()) { 454 logger.info("pfac = " + pfac); 455 } 456 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 457 //System.out.println("ppolys = " + ppolys); 458 459 int cl = fac.nvar - pvars.length; 460 if (cl == 0) { // non recursive case 461 //GroebnerBaseSeq<C> bb = new GroebnerBaseSeq<C>(); 462 List<GenPolynomial<C>> G = bb.GB(ppolys); 463 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 464 return pgb; 465 } 466 // recursive case 467 int pl = pvars.length; 468 String[] rvars = remainingVars(vars, pvars); 469 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 470 //System.out.println("cfac = " + cfac); 471 472 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, 473 fac.tord, pvars); 474 if (logger.isInfoEnabled()) { 475 logger.info("rfac = " + rfac); 476 } 477 //System.out.println("rfac = " + rfac); 478 479 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 480 //System.out.println("\nFr = " + Fr); 481 482 if (true) { 483 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 484 } 485 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 486 //System.out.println("\nGr = " + Gr); 487 488 List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr); 489 //System.out.println("\nG = " + G); 490 491 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 492 return pgb; 493 } 494 495 496 /** 497 * Partial Groebner base for specific variables. Computes Groebner base with 498 * coefficients from K[pvars] but returns polynomials in K[pvars, evars]. 499 * @param F polynomial list. 500 * @param evars names for upper main variables of partial Groebner base 501 * computation. 502 * @param pvars names for lower main variables of partial Groebner base 503 * computation. 504 * @return a container for a partial Groebner base of F wrt (pvars,evars). 505 */ 506 public OptimizedPolynomialList<C> elimPartialGB(List<GenPolynomial<C>> F, String[] evars, String[] pvars) { 507 if (F == null || F.isEmpty()) { 508 throw new IllegalArgumentException("empty F not allowed"); 509 } 510 GenPolynomialRing<C> fac = F.get(0).ring; 511 String[] vars = fac.getVars(); 512 // compute permutation (in reverse sorting) 513 //System.out.println("vars = " + Arrays.toString(vars)); 514 //System.out.println("evars = " + Arrays.toString(evars)); 515 //System.out.println("pvars = " + Arrays.toString(pvars)); 516 List<Integer> perm = partialPermutation(vars, evars, pvars); 517 //System.out.println("perm = " + perm); 518 519 GenPolynomialRing<C> pfac = fac.permutation(perm); 520 if (logger.isInfoEnabled()) { 521 logger.info("pfac = " + pfac); 522 } 523 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 524 //System.out.println("ppolys = " + ppolys); 525 526 int cl = fac.nvar - evars.length - pvars.length; 527 if (cl == 0) { // non recursive case 528 TermOrder to = pfac.tord; 529 int ev = to.getEvord(); 530 //ev = TermOrder.IGRLEX; 531 TermOrder split = new TermOrder(ev, ev, pfac.nvar, evars.length); 532 pfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars()); 533 if (logger.isInfoEnabled()) { 534 //logger.info("split = " + split); 535 logger.info("pfac = " + pfac); 536 } 537 List<GenPolynomial<C>> Fs = new ArrayList<GenPolynomial<C>>(ppolys.size()); 538 for (GenPolynomial<C> p : ppolys) { 539 Fs.add(pfac.copy(p)); 540 } 541 List<GenPolynomial<C>> G = bb.GB(Fs); 542 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 543 if (logger.isInfoEnabled()) { 544 logger.info("pgb = " + pgb); 545 } 546 return pgb; 547 } 548 logger.warn("not meaningful for elimination " + cl); 549 // recursive case 550 int pl = pvars.length + pvars.length; 551 String[] rvars = remainingVars(vars, evars); 552 rvars = remainingVars(rvars, pvars); 553 String[] uvars = new String[evars.length + pvars.length]; 554 for (int i = 0; i < pvars.length; i++) { 555 uvars[i] = pvars[i]; 556 } 557 for (int i = 0; i < evars.length; i++) { 558 uvars[pvars.length + i] = evars[i]; 559 } 560 561 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 562 //System.out.println("cfac = " + cfac); 563 564 TermOrder to = pfac.tord; 565 int ev = to.getEvord(); 566 TermOrder split = new TermOrder(ev, ev, pl, evars.length); 567 //GenPolynomialRing<C> sfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars()); 568 569 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, split, 570 uvars); 571 //System.out.println("rfac = " + rfac); 572 573 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 574 if (logger.isInfoEnabled()) { 575 logger.info("rfac = " + rfac); 576 logger.info("Fr = " + Fr); 577 } 578 579 if (true) { 580 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 581 } 582 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 583 //System.out.println("\nGr = " + Gr); 584 585 List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr); 586 //System.out.println("\nG = " + G); 587 588 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 589 return pgb; 590 } 591 592}