001/* 002 * $Id$ 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 permutation 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 permutation 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 {} != {} cup {}", variables, pvariables, 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 permutation 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 logger.info("pfac = {}", pfac); 397 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 398 //System.out.println("ppolys = " + ppolys); 399 400 int cl = fac.nvar - pvars.length; // > 0 401 int pl = pvars.length; 402 String[] rvars = remainingVars(vars, pvars); 403 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 404 //System.out.println("cfac = " + cfac); 405 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, 406 fac.tord, pvars); 407 logger.info("rfac = {}", rfac); 408 //System.out.println("rfac = " + rfac); 409 410 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 411 //System.out.println("\nFr = " + Fr); 412 413 if (true) { 414 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 415 } 416 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 417 //System.out.println("\nGr = " + Gr); 418 //perm = perm.subList(0,pl); 419 OptimizedPolynomialList<GenPolynomial<C>> pgb = new OptimizedPolynomialList<GenPolynomial<C>>(perm, 420 rfac, Gr); 421 return pgb; 422 } 423 424 425 /** 426 * Partial Groebner base for specific variables. Computes Groebner base in 427 * K[vars \ pvars][pvars] with coefficients from K[vars \ pvars] but returns 428 * polynomials in K[vars \ pvars, pvars]. 429 * @param F polynomial list. 430 * @param pvars names for main variables of partial Groebner base 431 * computation. 432 * @return a container for a partial Groebner base of F wrt pvars. 433 */ 434 public OptimizedPolynomialList<C> partialGB(List<GenPolynomial<C>> F, String[] pvars) { 435 if (F == null || F.isEmpty()) { 436 throw new IllegalArgumentException("empty F not allowed"); 437 } 438 GenPolynomialRing<C> fac = F.get(0).ring; 439 String[] vars = fac.getVars(); 440 // compute permutation (in reverse sorting) 441 //String[] xvars = remainingVars(vars, pvars); 442 //System.out.println("xvars = " + Arrays.toString(xvars)); 443 444 List<Integer> perm = partialPermutation(vars, pvars); 445 //System.out.println("pGB, perm = " + perm); 446 //System.out.println("pGB, perm,1 = " + getPermutation(vars, xvars)); 447 448 GenPolynomialRing<C> pfac = fac.permutation(perm); 449 logger.info("pfac = {}", pfac); 450 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 451 //System.out.println("ppolys = " + ppolys); 452 453 int cl = fac.nvar - pvars.length; 454 if (cl == 0) { // non recursive case 455 //GroebnerBaseSeq<C> bb = new GroebnerBaseSeq<C>(); 456 List<GenPolynomial<C>> G = bb.GB(ppolys); 457 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 458 return pgb; 459 } 460 // recursive case 461 int pl = pvars.length; 462 String[] rvars = remainingVars(vars, pvars); 463 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 464 //System.out.println("cfac = " + cfac); 465 466 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, 467 fac.tord, pvars); 468 logger.info("rfac = {}", rfac); 469 470 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 471 //System.out.println("\nFr = " + Fr); 472 473 if (true) { 474 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 475 } 476 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 477 //System.out.println("\nGr = " + Gr); 478 479 List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr); 480 //System.out.println("\nG = " + G); 481 482 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 483 return pgb; 484 } 485 486 487 /** 488 * Partial Groebner base for specific variables. Computes Groebner base with 489 * coefficients from K[pvars] but returns polynomials in K[pvars, evars]. 490 * @param F polynomial list. 491 * @param evars names for upper main variables of partial Groebner base 492 * computation. 493 * @param pvars names for lower main variables of partial Groebner base 494 * computation. 495 * @return a container for a partial Groebner base of F wrt (pvars,evars). 496 */ 497 public OptimizedPolynomialList<C> elimPartialGB(List<GenPolynomial<C>> F, String[] evars, String[] pvars) { 498 if (F == null || F.isEmpty()) { 499 throw new IllegalArgumentException("empty F not allowed"); 500 } 501 GenPolynomialRing<C> fac = F.get(0).ring; 502 String[] vars = fac.getVars(); 503 // compute permutation (in reverse sorting) 504 //System.out.println("vars = " + Arrays.toString(vars)); 505 //System.out.println("evars = " + Arrays.toString(evars)); 506 //System.out.println("pvars = " + Arrays.toString(pvars)); 507 List<Integer> perm = partialPermutation(vars, evars, pvars); 508 //System.out.println("perm = " + perm); 509 510 GenPolynomialRing<C> pfac = fac.permutation(perm); 511 logger.info("pfac = {}", pfac); 512 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F); 513 //System.out.println("ppolys = " + ppolys); 514 515 int cl = fac.nvar - evars.length - pvars.length; 516 if (cl == 0) { // non recursive case 517 TermOrder to = pfac.tord; 518 int ev = to.getEvord(); 519 //ev = TermOrder.IGRLEX; 520 TermOrder split = new TermOrder(ev, ev, pfac.nvar, evars.length); 521 pfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars()); 522 //logger.info("split = {}", split); 523 logger.info("pfac = {}", pfac); 524 List<GenPolynomial<C>> Fs = new ArrayList<GenPolynomial<C>>(ppolys.size()); 525 for (GenPolynomial<C> p : ppolys) { 526 Fs.add(pfac.copy(p)); 527 } 528 List<GenPolynomial<C>> G = bb.GB(Fs); 529 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 530 logger.info("pgb = {}", pgb); 531 return pgb; 532 } 533 logger.warn("not meaningful for elimination {}", cl); 534 // recursive case 535 int pl = pvars.length + pvars.length; 536 String[] rvars = remainingVars(vars, evars); 537 rvars = remainingVars(rvars, pvars); 538 String[] uvars = new String[evars.length + pvars.length]; 539 for (int i = 0; i < pvars.length; i++) { 540 uvars[i] = pvars[i]; 541 } 542 for (int i = 0; i < evars.length; i++) { 543 uvars[pvars.length + i] = evars[i]; 544 } 545 546 GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars); 547 //System.out.println("cfac = " + cfac); 548 549 TermOrder to = pfac.tord; 550 int ev = to.getEvord(); 551 TermOrder split = new TermOrder(ev, ev, pl, evars.length); 552 //GenPolynomialRing<C> sfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars()); 553 554 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, split, 555 uvars); 556 List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys); 557 logger.info("rfac = {}", rfac); 558 logger.info("Fr = {}", Fr); 559 560 if (true) { 561 rbb = new GroebnerBasePseudoRecSeq<C>(cfac); 562 } 563 List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr); 564 //System.out.println("\nGr = " + Gr); 565 566 List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr); 567 //System.out.println("\nG = " + G); 568 569 OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G); 570 return pgb; 571 } 572 573}