source: git/Singular/LIB/fpaprops.lib @ 61fbaf

spielwiese
Last change on this file since 61fbaf was 95f15e, checked in by Karim Abou Zeid <karim23697@…>, 3 years ago
Fix tests. Remove tests for lpGkDim and lpKDim because they are now just aliases for dim and vdim which are already tested.
  • Property mode set to 100644
File size: 39.2 KB
Line 
1////////////////////////////////////////////////////////////////
2version="version fpaprops.lib 4.1.2.0 Feb_2019 "; // $Id$
3category="Noncommutative";
4info="
5LIBRARY: fpaprops.lib   Algorithmic ring-theoretic properties of finitely presented algebras (Letterplace)
6AUTHORS: Karim Abou Zeid,       karim.abou.zeid at rwth-aachen.de
7
8Support: Project II.6 in the transregional collaborative research centre
9SFB-TRR 195 'Symbolic Tools in Mathematics and their Application' of the German DFG
10
11OVERVIEW:
12In this library, algorithms for computing various ring-theoretic properties of
13finitely presented algebras are implemented.
14Applicability: Letterplace rings.
15
16REFERENCES:
17Huishi Li: Groebner bases in ring theory. World Scientific, 2010.
18
19KEYWORDS: finitely presented algebra; ring theory; Letterplace Groebner basis;
20growth of algebra; Gelfand-Kirillov dimension; global homological dimension; semi-prime ideal; Ufnarovski graph
21
22SEE ALSO:  fpadim_lib, freegb_lib
23
24PROCEDURES:
25  lpNoetherian(<GB>);     check whether A/<LM(GB)> is (left/right) Noetherian
26  lpIsSemiPrime(<GB>);    check whether A/<LM(GB)> is semi-prime
27  lpIsPrime(<GB>);        check whether A/<LM(GB)> is prime
28  lpGkDim(<GB>);          alias for dim(<GB>)
29  teach_lpGkDim(<GB>);    deprecated, kept for teaching purposes. use dim(<GB>) instead.
30  lpGlDimBound(<GB>);     compute an upper bound for the global dimension of A/<GB>
31  lpSubstitute();         substitute a variable with polynomials (ring homomorphism)
32  lpCalcSubstDegBound();  utility for lpSubstitute
33";
34
35LIB "fpadim.lib";
36
37/* very fast and cheap test of consistency and functionality
38  DO NOT make it static !
39  after adding the new proc, add it here */
40proc tstfpaprops()
41{
42    example lpNoetherian;
43    example lpIsSemiPrime;
44    example lpIsPrime;
45    example lpGlDimBound;
46    example lpGkDim;
47    example lpSubstitute;
48    example lpCalcSubstDegBound;
49};
50
51
52////////////////////////////////////////////////////////////////////
53proc lpNoetherian(ideal G)
54"USAGE: lpNoetherian(G); G an ideal in a Letterplace ring
55RETURN: int
56      0 not Noetherian
57      1 left Noetherian
58      2 right Noetherian
59      3 Noetherian
60      4 weak Noetherian
61PURPOSE: Check whether the monomial algebra A/<LM(G)> is (left/right) noetherian
62ASSUME: - basering is a Letterplace ring
63      - G is a Groebner basis
64THEORY: lpNoetherian works with the monomial algebra A/<LM(G)>.
65If it gives an affirmative answer for one of the properties, then it
66holds for both A/<LM(G)> and A/<G>. However, a negative answer applies
67only to A/<LM(G)> and not necessarily to A/<G>.
68NOTE: Weak Noetherian means that two-sided ideals in A/<LM(G)> satisfy
69the acc (ascending chain condition).
70"
71{
72  G = lead(G);
73  G = simplify(G, 2+4+8);
74
75  // check special case 1
76  int l = 0;
77  for (int i = 1; i <= size(G); i++) {
78    // find the max degree in G
79    int d = deg(G[i]);
80    if (d > l) {
81      l = d;
82    }
83
84    // also if G is the whole ring
85    if (leadmonom(G[i]) == 1) {
86      ERROR("Noetherianity not defined for 0-ring")
87    }
88    kill d;
89  } kill i;
90  // if longest word has length 1 we handle it as a special case
91  if (l == 1) {
92    int n = lpVarBlockSize(basering); // variable count
93    int ncgenCount = lpNcgenCount(basering);
94    int k = size(G);
95    if (k == n - ncgenCount) { // only the field left
96      return(3); // every field is noetherian
97    }
98    if (k == n - ncgenCount - 1) { // V = {1} with loop
99      return(3);
100    }
101    if (k <= n ncgenCount - 2) { // V = {1} with more than one loop
102      return(0);
103    }
104  }
105
106  intmat UG = lpUfnarovskiGraph(G)[1];
107
108  // check special case 2
109  intmat zero[nrows(UG)][ncols(UG)];
110  if (UG == zero) {
111    return (3);
112  }
113
114  if (!imHasLoops(UG) && imIsUpRightTriangle(topologicalSort(UG))) {
115    // UG is a DAG
116    return (3);
117  }
118
119  // DFS from every vertex, if cycle is found, check every vertex for incoming/outcom
120  intvec visited;
121  visited[ncols(UG)] = 0;
122  int inFlag, outFlag, inOutFlag;
123  for (int v = 1; v <= ncols(UG) && (inFlag + outFlag) != 3; v++) {
124    int inOutFlags = inOutCommingEdgesInCycles(UG, v, visited, 0);
125    if (inOutFlags == 1) {
126      inFlag = 1;
127    }
128    if (inOutFlags == 2) {
129      outFlag = 1;
130    }
131    if (inOutFlags == 3) {
132      inFlag = 1;
133      outFlag = 1;
134    }
135    if (inOutFlags == 4) {
136      inOutFlag = 1;
137    }
138    if (inOutFlags == 5) {
139      inFlag = 1;
140      inOutFlag = 1;
141    }
142    if (inOutFlags == 6) {
143      outFlag = 1;
144      inOutFlag = 1;
145    }
146    if (inOutFlags == 7) {
147      inFlag = 1;
148      outFlag = 1;
149      inOutFlag = 1;
150    }
151    kill inOutFlags;
152  } kill v;
153  int noetherian = 3 - 1*inFlag - 2*outFlag;
154  if (noetherian == 0) {
155    return (4 - 4*inOutFlag); // weak noetherian
156  }
157  return (noetherian);
158}
159example
160{
161  "EXAMPLE:"; echo = 2;
162  ring r = 0,(x,y),dp;
163  def R = freeAlgebra(r, 5);
164  setring R;
165  ideal G = x*x, y*x; // K<x,y>/<xx,yx> is right noetherian
166  lpNoetherian(G);
167}
168
169static proc inOutCommingEdgesInCycles(intmat G, int v, intvec visited, intvec path) {
170  // Mark the current vertex as visited
171  visited[v] = 1;
172
173  // Store the current vertex in path
174  if (path[1] == 0) {
175    path[1] = v;
176  } else {
177    path[size(path) + 1] = v;
178  }
179
180  int inFlag, outFlag, inOutFlag;
181
182  for (int w = 1; w <= ncols(G) && (inFlag + outFlag) != 3; w++) {
183    if (G[v,w] == 1) {
184      if (visited[w] == 1) { // new cycle
185        int tmpInFlag;
186        int tmpOutFlag;
187        if (v == w) { // cycle is a loop
188          for (int u = 1; u <= ncols(G); u++) {
189            if (G[v,u] && u != v) {
190              outFlag = 1;
191              tmpOutFlag = 1;
192            }
193            if (G[u,v] && u != v) {
194              inFlag = 1;
195              tmpInFlag = 1;
196            }
197          } kill u;
198        } else {
199          for (int i = size(path); i >= 1; i--) { // for each vertex in the path
200            // check for neighbors not directly next or prev in cycle
201            for (int u = 1; u <= ncols(G); u++) {
202              if (G[path[i],u] == 1) { // there is an edge to u
203                if (path[i] != v) {
204                  if (u != path[i+1]) { // and u is not the next element in the cycle
205                    outFlag = 1;
206                    tmpOutFlag = 1;
207                  }
208                } else {
209                  if (u != w) {
210                    outFlag = 1;
211                    tmpOutFlag = 1;
212                  }
213                }
214              }
215              if (G[u,path[i]] == 1) { // there is an edge from u
216                if (path[i] != w) {
217                  if (u != path[i-1]) { // and u is not the previous element in the cylce
218                    inFlag = 1;
219                    tmpInFlag = 1;
220                  }
221                } else {
222                  if (u != v) {
223                    inFlag = 1;
224                    tmpInFlag = 1;
225                  }
226                }
227              }
228            } kill u;
229            if (path[i] == w) {
230              break;
231            }
232          } kill i;
233        }
234        if (tmpInFlag > 0 && tmpOutFlag > 0) {
235          // there are both in and outcomming edges in this cycle
236          inOutFlag = 1;
237        }
238        kill tmpInFlag;
239        kill tmpOutFlag;
240      } else {
241        int inOutFlags = inOutCommingEdgesInCycles(G, w, visited, path);
242        if (inOutFlags == 1) {
243          inFlag = 1;
244        }
245        if (inOutFlags == 2) {
246          outFlag = 1;
247        }
248        if (inOutFlags == 3) {
249          inFlag = 1;
250          outFlag = 1;
251        }
252        if (inOutFlags == 4) {
253          inOutFlag = 1;
254        }
255        if (inOutFlags == 5) {
256          inFlag = 1;
257          inOutFlag = 1;
258        }
259        if (inOutFlags == 6) {
260          outFlag = 1;
261          inOutFlag = 1;
262        }
263        if (inOutFlags == 7) {
264          inFlag = 1;
265          outFlag = 1;
266          inOutFlag = 1;
267        }
268        kill inOutFlags;
269      }
270    }
271  } kill w;
272
273  return (1*inFlag + 2*outFlag + 4*inOutFlag);
274}
275
276proc lpIsSemiPrime(ideal G)
277"USAGE: lpIsSemiPrime(G); G an ideal in a Letterplace ring
278RETURN: boolean
279PURPOSE: Check whether A/<LM(G)> is semi-prime ring,
280alternatively whether <LM(G)> is a semi-prime ideal in A.
281ASSUME: - basering is a Letterplace ring
282      - G is a Groebner basis
283THEORY: A (two-sided) ideal I in the ring A is semi-prime, if for any a in A one has
284aAa subseteq I implies a in I.
285NOTE: lpIsSemiPrime works with the monomial algebra A/<LM(G)>.
286A positive answer holds for both A/<LM(G)> and A/<G>, while
287a negative answer applies only to A/<LM(G)> and not necessarily to
288A/<G>.
289"
290{
291    // old theory part: that is when p * (A/<LM(G)>) * p != 0 for all p in (A/<LM(G)> - {0}).
292  G = lead(G);
293  G = simplify(G, 2+4+8);
294
295  // check special case 1
296  int l = 0;
297  for (int i = 1; i <= size(G); i++) {
298    // find the max degree in G
299    int d = deg(G[i]);
300    if (d > l) {
301      l = d;
302    }
303
304    // also if G is the whole ring
305    if (leadmonom(G[i]) == 1) {
306      ERROR("primeness not defined for 0-ring")
307    }
308    kill d;
309  } kill i;
310  // if longest word has length 1 we handle it as a special case
311  if (l == 1) {
312    return(1);
313  }
314
315  list VUG = lpUfnarovskiGraph(G);
316  intmat UG = VUG[1]; // the Ufnarovskij graph
317  ideal V = VUG[2]; // the vertices of UG (standard words with length = l-1)
318
319  list LG = lpId2ivLi(G);
320  list SW = ivStandardWordsUpToLength(LG, maxDeg(G));
321  list LV = lpId2ivLi(V);
322
323  // delete the 0 in SW
324  int indexofzero = ivIndexOf(SW, 0);
325  if (indexofzero > 0) { // should be always true when |SW| > 0
326    SW = delete(SW, indexofzero);
327  }
328
329  // check if each monomial in SW is cyclic
330  for (int i = 1; i <= size(SW); i++) {
331    if (!isCyclicInUfGraph(UG, LV, SW[i])) {
332      return (0);
333    }
334  } kill i;
335
336  return (1);
337}
338example
339{
340  "EXAMPLE:"; echo = 2;
341  ring r = 0,(x1,x2),dp;
342  def R = freeAlgebra(r, 5);
343  setring R;
344  ideal G = x1*x2, x2*x1; // K<x1,x2>/<x1*x2,x2*x1> is semi prime
345  lpIsSemiPrime(G);
346}
347
348// checks whether a monomial is a cyclic monomial
349static proc isCyclicInUfGraph(intmat UG, list LV, intvec u)
350{
351  if (ncols(UG) == 0) {return (0);} // UG is empty
352  if (u == 0) {return (0);} // 0 is never cyclic
353
354  int l = size(LV[1]) + 1;
355
356  int s = size(u);
357  if (s <= l - 1) {
358    for (int i = 1; i <= size(LV); i++) {
359      // for all vertices where u is a suffix
360      if(isSF(u, LV[i])) {
361        if (existsRoute(UG, i, i)) {
362          return (1);
363        }
364      }
365    } kill i;
366  } else { // size(u) > l - 1
367    int m = s - l + 1;
368
369    // there must be a route from v0 to vm
370    intvec v0 = u[1..(l-1)]; // first in route of u
371    intvec vm = u[m+1..m+(l-1)]; // last in route of u
372
373    int iv0 = ivIndexOf(LV, v0);
374    int ivm = ivIndexOf(LV, vm);
375    if (iv0 <= 0 || ivm <= 0) {
376      ERROR("u is not a standard word");
377    }
378
379    return (existsRoute(UG, ivm, iv0));
380  }
381
382  return (0);
383}
384
385proc lpIsPrime(ideal G)
386"USAGE: lpIsPrime(G); G an ideal in a Letterplace ring
387RETURN: boolean
388PURPOSE: Check whether A/<LM(G)> is prime ring,
389alternatively whether <LM(G)> is a prime ideal in A.
390ASSUME: - basering is a Letterplace ring
391      - G is a Groebner basis
392THEORY: A (two-sided) ideal I in the ring A is prime, if for any a,b in A one has
393aAb subseteq I implies a in I or b in I.
394NOTE: lpIsPrime works with the monomial algebra A/<LM(G)>.
395A positive answer holds for both A/<LM(G)> and A/<G>, while
396a negative answer applies only to A/<LM(G)> and not necessarily to A/<G>.
397"
398{
399    // old theory part: that is when p1 * (A/<LM(G)>) * p2 != 0 for all p1, p2 in (A/<LM(G)> - {0}).
400  G = lead(G);
401  G = simplify(G, 2+4+8);
402
403  // check special case 1
404  int l = 0;
405  for (int i = 1; i <= size(G); i++) {
406    // find the max degree in G
407    int d = deg(G[i]);
408    if (d > l) {
409      l = d;
410    }
411
412    // also if G is the whole ring
413    if (leadmonom(G[i]) == 1) {
414      ERROR("primeness not defined for 0-ring")
415    }
416    kill d;
417  } kill i;
418  // if longest word has length 1 we handle it as a special case
419  if (l == 1) {
420    return(1);
421  }
422
423  list VUG = lpUfnarovskiGraph(G);
424  intmat UG = VUG[1]; // the Ufnarovskij graph
425  ideal V = VUG[2]; // the vertices of UG (standard words with length = l-1)
426
427  list LG = lpId2ivLi(G);
428  list LV = lpId2ivLi(V);
429
430  int n = ncols(UG);
431
432  // 1) for each vi vj there exists a route from vi to vj (means UG is connected)
433  for (int i = 1; i <= n; i++) {
434    for (int j = 1; j <= n; j++) {
435      if (!existsRoute(UG, i, j)) {
436        return (0);
437      }
438    } kill j;
439  } kill i;
440
441  // 2) any standard word with length < l-1 is a suffix of a vertex
442  list SW = ivStandardWordsUpToLength(LG, maxDeg(G) - 2); // < maxDeg - 1
443  if (size(SW) > 0 && size(LV) == 0) {return (0);}
444  for (int i = 1; i <= size(SW); i++) {
445    // check if SW[i] is a suffix of some LV
446    for (int j = 1; j <= size(LV); j++) {
447      if (!isSF(SW[i], LV[j])) {
448        if (j == size(LV)) {
449          return (0);
450        }
451      } else {
452        break;
453      }
454    } kill j;
455  } kill i;
456
457  return (1);
458}
459example
460{
461  "EXAMPLE:"; echo = 2;
462  ring r = 0,(x,y),dp;
463  def R = freeAlgebra(r, 5);
464  setring R;
465  ideal G = x*x, y*y; // K<x,y>/<xx,yy> is prime
466  lpIsPrime(G);
467}
468
469static proc existsRoute(intmat G, int v, int u, list #)
470"USAGE: existsRoute(G,v,u); G a graph, v and u vertices
471NOTE: don't pass anything to # (internal use for recursion)
472routes always have at least one edge
473"
474{
475  int n = ncols(G);
476
477  // init visited
478  intvec visited;
479  if (size(#) > 0) {
480    if (v == u) {return (1);} // don't check on first call so |route| >= 1 holds
481    visited = #[1];
482  } else { // first call
483    visited[n] = 0;
484  }
485
486  // mark current vertex as visited
487  visited[v] = 1;
488
489  // recursive DFS
490  for (int i = 1; i <= n; i++) {
491    if (G[v,i] && (!visited[i] || i == u)) { // i == u to allow routes from u to u
492      if (existsRoute(G, i, u, visited)) {
493        return (1);
494      }
495    }
496  } kill i;
497
498  return (0);
499}
500
501static proc UfGraphURTNZDGrowth(intmat UG) {
502  // URTNZD = upper right triangle non zero diagonal
503  for (int i = 1; i <= ncols(UG); i++) {
504    UG[i,i] = 0; // remove all loops
505  } kill i;
506  intmat UGk = UG;
507  intmat zero[nrows(UGk)][ncols(UGk)];
508  int k = 1;
509  while (UGk != zero) {
510    UGk = UGk * UG;
511    k++;
512  }
513  return (k);
514}
515
516static proc imIsUpRightTriangle(intmat M) {
517  for (int i = 1; i <= nrows(M); i++) {
518    for (int j = 1; j < i; j++) {
519      if(M[i,j] != 0) { return (0); }
520    } kill j;
521  } kill i;
522  return (1);
523}
524
525static proc eliminateZerosUpTriangle(intmat G) {
526  // G is expected to be an upper triangle matrix
527  for (int i = ncols(G); i >= 1; i--) { // loop order is important because we delete entries
528    if (G[i,i] == 0) { // i doesn't have a cycle
529      for (int j = 1; j < i; j++) {
530        if (G[j,i] == 1) { // j has an edge to i
531          for (int k = i + 1; k <= nrows(G); k++) {
532            if (G[i,k] == 1) {
533              G[j,k] = G[i,k]; // give j all edges from i
534            }
535          } kill k;
536        }
537      } kill j;
538      G = imDelRowCol(G,i,i); // remove vertex i
539    }
540  } kill i;
541  return (G);
542}
543
544static proc imDelRowCol(intmat M, int row, int col) {
545  // row and col are expected to be > 0
546  int nr = nrows(M);
547  int nc = ncols(M);
548  intmat Mdel[nr - 1][nc - 1];
549  for (int i = 1; i <= nr; i++) {
550    for (int j = 1; j <= nc; j++) {
551      if(i != row && j != col) {
552        int newi = i;
553        int newj = j;
554        if (i > row) { newi = i - 1; }
555        if (j > col) { newj = j - 1; }
556        Mdel[newi,newj] = M[i,j];
557        kill newi; kill newj;
558      }
559    } kill j;
560  } kill i;
561  return (Mdel);
562}
563
564static proc topologicalSort(intmat G) {
565  // NOTE: ignores loops
566  // NOTE: this takes O(|V^3|), can be optimized
567  int n = ncols(G);
568  for (int i = 1; i <= n; i++) { // only use the submat at i
569    // find a vertex v in the submat at i with no incoming edges
570    int v;
571    for (int j = i; j <= n; j++) {
572      int incoming = 0;
573      for (int k = i; k <= n; k++) {
574        if (k != j && G[k,j] == 1) {
575          incoming = 1;
576        }
577      } kill k;
578      if (incoming == 0) {
579        v = j;
580        kill incoming;
581        break;
582      } else {
583        if (j == n) {
584          // G contains at least one cycle, abort
585          return (G);
586        }
587      }
588      kill incoming;
589    } kill j;
590
591    // swap v and i
592    if (v != i) {
593      G = imPermcol(G, v, i);
594      G = imPermrow(G, v, i);
595    }
596    kill v;
597  } kill i;
598  return (G);
599}
600
601static proc imPermcol (intmat A, int c1, int c2)
602{
603  intmat B = A;
604  int k = nrows(B);
605  B[1..k,c1] = A[1..k,c2];
606  B[1..k,c2] = A[1..k,c1];
607  return (B);
608}
609
610static proc imPermrow (intmat A, int r1, int r2)
611{
612  intmat B = A;
613  int k = ncols(B);
614  B[r1,1..k] = A[r2,1..k];
615  B[r2,1..k] = A[r1,1..k];
616  return (B);
617}
618
619static proc UfGraphGrowth(intmat UG)
620{
621  int n = ncols(UG); // number of vertices
622  // iterate through all vertices
623
624  intvec visited = 0:n;
625  intvec cyclic = 0:n;
626  intvec countedCycles = -2:n;
627
628  int maxCycleCount = 0;
629  for (int v = 1; v <= n; v++) {
630    countedCycles = countCycles(UG, v, visited, cyclic, 0, countedCycles);
631    dbprint("counted " + string(countedCycles[v]) + " cycles from vertex " + string(v) + "/" + string(n) + " (cache: " + string(countedCycles) + ")");
632    if (countedCycles[v] == -1) {
633      return(-1);
634    }
635    if (countedCycles[v] > maxCycleCount) {
636      maxCycleCount = countedCycles[v];
637    }
638  } kill v;
639  return (maxCycleCount);
640}
641
642static proc countCycles(intmat G, int v, intvec visited, intvec cyclic, intvec path, intvec countedCycles)
643"USAGE: countCycles(G, v, visited, cyclic, path); G a Graph, v the vertex to
644start. The parameter visited, cyclic and path should be 0.
645RETURN: int
646     Maximal number of distinct cycles
647PURPOSE: Calculate the maximal number of distinct cycles in a single path starting at v
648ASSUME: Basering is a Letterplace ring
649"
650{
651  if (countedCycles[v] > -2) {
652    return (countedCycles);
653  }
654  // Mark the current vertex as visited
655  visited[v] = 1;
656
657  // Store the current vertex in path
658  if (path[1] == 0) {
659    path[1] = v;
660  } else {
661    path[size(path) + 1] = v;
662  }
663
664  int cycles = 0;
665  for (int w = 1; w <= ncols(G); w++) {
666    if (G[v,w] == 1) {
667      if (visited[w] == 1) { // found new cycle
668        // 1. for all vertices in path until w, check if they are cyclic
669        for (int j = size(path); j >= 1; j--) {
670          if(cyclic[path[j]] == 1) {
671            // 1.1 if yes, return -1
672            countedCycles[v] = -1;
673            return (countedCycles);
674          }
675          if (path[j] == w) {
676            break;
677          }
678        } kill j;
679
680        // 2. otherwise cycles++
681        for (int j = size(path); j >= 1; j--) {
682          // 2.2 remove the edges from that cycle and mark the vertices as cyclic
683          if (j == size(path)) { // special case in the first iteration
684            cyclic[v] = 1;
685            G[v, w] = 0;
686          } else {
687            cyclic[path[j]] = 1;
688            G[path[j], path[j+1]] = 0;
689          }
690          if (path[j] == w) {
691            break;
692          }
693        } kill j;
694
695        // 3. countCycles() on all these vertices
696        int maxCycleCount = 0;
697        for (int j = size(path); j >= 1; j--) {
698          countedCycles = countCycles(G, path[j], visited, cyclic, path, countedCycles);
699          if(countedCycles[path[j]] == -1) {
700            countedCycles[v] = -1;
701            return (countedCycles);
702          }
703          if (countedCycles[path[j]] > maxCycleCount) {
704            maxCycleCount = countedCycles[path[j]];
705          }
706          if (path[j] == w) {
707            break;
708          }
709        } kill j;
710        if (maxCycleCount >= cycles) {
711          cycles = maxCycleCount + 1;
712        }
713        kill maxCycleCount;
714      } else {
715        countedCycles = countCycles(G, w, visited, cyclic, path, countedCycles);
716        if (countedCycles[w] == -1) {
717          countedCycles[v] = -1;
718          return (countedCycles);
719        }
720        if (countedCycles[w] > cycles) {
721          cycles = countedCycles[w];
722        }
723      }
724    }
725  } kill w;
726  countedCycles[v] = cycles;
727  return (countedCycles);
728}
729
730// Ufnarovskii graph is now implemented in the dynamic module (freeAlgebra.cc)
731/* proc lpUfnarovskiGraph(ideal G, list #) */
732/* "USAGE: lpUfnarovskiGraph(G); G a set of monomials in a letterplace ring. */
733/* RETURN: intmat or list */
734/* NOTE: lpUfnarovskiGraph(G); returns intmat. lpUfnarovskiGraph(G,1); returns list L with L[1] an intmat and L[2] an ideal. */
735/*       The intmat is the Ufnarovskij Graph and the ideal contains the vertices. */
736/* PURPOSE: Constructs the Ufnarovskij graph induced by G */
737/*       the adjacency matrix of the Ufnarovskij graph induced by G */
738/* ASSUME: - basering is a Letterplace ring */
739/*       - G are the leading monomials of a Groebner basis */
740/* " */
741/* { */
742/*   dbprint("computing maxDeg"); */
743/*   int l = maxDeg(G); */
744/*   if (l - 1 == 0) { */
745/*     // TODO: how should the graph look like when l - 1 = 0 ? */
746/*     ERROR("Ufnarovskij graph not implemented for l = 1"); */
747/*   } */
748/*   int lV = lpVarBlockSize(basering); */
749/*   // TODO: what if l <= 0? */
750/*   dbprint("computing standard words"); */
751/*   ideal SW = lpStandardWords(G, l - 1); // vertices */
752/*   int n = ncols(SW); */
753/*   dbprint("n = " + string(n)); */
754/*   intmat UG[n][n]; // Ufnarovskij graph */
755/*   for (int i = 1; i <= n; i++) { */
756/*     for (int j = 1; j <= n; j++) { */
757/*       dbprint("Ufnarovskii graph: " + string((i-1)*n + j) + "/" + string(n*n) + " entries"); */
758/*       // [Studzinski page 76] */
759/*       poly v = SW[i]; */
760/*       poly w = SW[j]; */
761/*       intvec v_overlap; */
762/*       intvec w_overlap; */
763/*       if (l - 1 > 1) { */
764/*         v_overlap = leadexp(v); */
765/*         w_overlap = leadexp(w); */
766/*         v_overlap = v_overlap[(lV+1) .. (l-1)*lV]; */
767/*         w_overlap = w_overlap[1 .. (l-2)*lV]; */
768/*       } */
769/*       if (v_overlap == w_overlap && !lpLmDivides(G, v * lpVarAt(w, l - 1))) { */
770/*         UG[i,j] = 1; */
771/*       } */
772/*       kill v; kill w; kill v_overlap; kill w_overlap; */
773/*     } kill j; */
774/*   } kill i; */
775/*   if (size(#) > 0) { */
776/*     if (typeof(#[1]) == "int") { */
777/*       if (#[1] != 0) { */
778/*         list ret = UG; */
779/*         ret[2] = SW; // the vertices */
780/*         return (ret); */
781/*       } */
782/*     } */
783/*   } */
784/*   return (UG); */
785/* } */
786/* example */
787/* { */
788/*   "EXAMPLE:"; echo = 2; */
789/*   ring r = 0,(x,y,z),dp; */
790/*   def R = freeAlgebra(r, 5); // constructs a Letterplace ring */
791/*   setring R; // sets basering to Letterplace ring */
792/*   ideal I = x*y, x*z, z*y, z*z; */
793/*   lpUfnarovskiGraph(I); */
794/*   lpUfnarovskiGraph(I,1); */
795/* } */
796
797static proc maxDeg(ideal G)
798{
799  int l = 0;
800  for (int i = 1; i <= size(G); i++) { // find the max degree in G
801    int d = deg(G[i]);
802    if (d > l) {
803      l = d;
804    }
805    kill d;
806  } kill i;
807  return (l);
808}
809
810static proc lpStandardWords(ideal G, int length)
811"ASSUME: G is simplified
812"
813{
814  if (length < 0) {
815    return (delete(ideal(0), 1)); // no standard words
816  }
817
818  ideal words = maxideal(length);
819  for (int i = ncols(words); i >= 1; i--) {
820    if (lpLmDivides(G, words[i])) {
821      words = delete(words, i);
822    }
823  } kill i;
824  return (words);
825}
826
827static proc ivStandardWords(list G, int length)
828"ASSUME: G is simplified
829"
830{
831  if (length <= 0) {
832    list words;
833    if (length == 0 && !ivdivides(G,0)) {
834      words[1] = 0; // iv = 0 means monom = 1
835    }
836    return (words); // no standard words
837  }
838  int nVars = lpVarBlockSize(basering) - lpNcgenCount(basering); // variable count
839  list prevWords = ivStandardWords(G, length - 1);
840  list words;
841  for (int i = 1; i <= nVars; i++) {
842    for (int j = 1; j <= size(prevWords); j++) {
843      intvec word = prevWords[j];
844      word[length] = i;
845      // assumes that G is simplified!
846      if (!ivdivides(G, word)) {
847        words = insert(words, word);
848      }
849      kill word;
850    } kill j;
851  } kill i;
852  return (words);
853}
854
855static proc ivStandardWordsUpToLength(list G, int length)
856"ASSUME: G is simplified
857"
858{
859  list words = ivStandardWords(G,0);
860  if (size(words) == 0) {return (words)}
861  for (int i = 1; i <= length; i++) {
862    words = words + ivStandardWords(G, i);
863  } kill i;
864  return (words);
865}
866
867static proc ivdivides(list G, intvec iv) {
868  for (int k = 1; k <= size(G); k++) {
869    if (isIF(G[k], iv)) {
870      return (1);
871    } else {
872      if (k == size(G)) {
873        return (0);
874      }
875    }
876  } kill k;
877  return (0);
878}
879
880proc lpGkDim(ideal G)
881"USAGE: lpGkDim(G); G an ideal in a letterplace ring
882RETURN: int
883PURPOSE: Determines the Gelfand Kirillov dimension of A/<G>
884       -1 means positive infinite
885ASSUME: - basering is a Letterplace ring
886      - G is a Groebner basis
887NOTE: Alias for dim(G)
888"
889{
890  print("WARNING: `lpGkDim` is deprecated, you can use `dim` instead.");
891  return (dim(G));
892}
893example
894{
895  "EXAMPLE:"; echo = 2;
896  ring r = 0,(x,y,z),dp;
897  ring R = freeAlgebra(r, 5);
898  ideal I = z; // infinite GK dimension (-1)
899  lpGkDim(I);
900  I = x,y,z; I = std(I); // GK dimension 0
901  lpGkDim(I);
902  I = x*y, x*z, z*y, z*z; I = std(I); // GK dimension 2
903  lpGkDim(I);
904  ideal G = y*x - x*y, z*x - x*z, z*y - y*z; G = std(G);
905  G;
906  lpGkDim(G); // GK dimension 3
907}
908
909proc teach_lpGkDim(ideal G)
910"USAGE: teach_lpGkDim(G); G an ideal in a letterplace ring
911RETURN: int
912PURPOSE: Determines the Gelfand Kirillov dimension of A/<G>
913       -1 means positive infinite
914ASSUME: - basering is a Letterplace ring
915      - G is a Groebner basis
916"
917{
918  G = lead(G);
919  G = simplify(G, 2+4+8);
920
921  // check special case 1
922  int l = 0;
923  for (int i = 1; i <= size(G); i++) {
924    // find the max degree in G
925    int d = deg(G[i]);
926    if (d > l) {
927      l = d;
928    }
929
930    // also if G is the whole ring return minus infinity
931    if (leadmonom(G[i]) == 1) {
932      ERROR("GK-Dim not defined for 0-ring")
933    }
934    kill d;
935  } kill i;
936  // if longest word has length 1, or G is the zero ideal, we handle it as a special case
937  if (l == 1 || size(G) == 0) {
938    int n = lpVarBlockSize(basering); // variable count
939    int k = size(G);
940    if (k == n) { // V = {1} no edges
941      return(0);
942    }
943    if (k == n-1) { // V = {1} with loop
944      return(1);
945    }
946    if (k <= n-2) { // V = {1} with more than one loop
947      return(-1);
948    }
949  }
950
951  dbprint("computing Ufnarovskii graph");
952  intmat UG = lpUfnarovskiGraph(G)[1];
953  if (printlevel >= voice + 1) {
954    UG;
955  }
956
957  // check special case 2
958  intmat zero[nrows(UG)][ncols(UG)];
959  if (UG == zero) {
960    return (0);
961  }
962
963  // check special case 3
964  dbprint("topological sorting of Ufnarovskii graph");
965  UG = topologicalSort(UG);
966  if (printlevel >= voice + 1) {
967    UG;
968  }
969
970  dbprint("check if Ufnarovskii graph is DAG");
971  if (imIsUpRightTriangle(UG)) {
972    UG = eliminateZerosUpTriangle(UG);
973    if (ncols(UG) == 0 || nrows(UG) == 0) { // when the diagonal was zero
974      return (0)
975    }
976    dbprint("DAG detected, using URTNZD growth alg");
977    return(UfGraphURTNZDGrowth(UG));
978  }
979
980  // otherwise count cycles in the Ufnarovskij Graph
981  dbprint("not a DAG, using regular growth alg");
982  return(UfGraphGrowth(UG));
983}
984example
985{
986  "EXAMPLE:"; echo = 2;
987  ring r = 0,(x,y,z),dp;
988  def R = freeAlgebra(r, 5); // constructs a Letterplace ring
989  R;
990  setring R; // sets basering to Letterplace ring
991  ideal I = z;//an example of infinite GK dimension
992  teach_lpGkDim(I);
993  I = x,y,z; // gkDim = 0
994  teach_lpGkDim(I);
995  I = x*y, x*z, z*y, z*z;//gkDim = 2
996  teach_lpGkDim(I);
997  ideal G = y*x - x*y, z*x - x*z, z*y - y*z; G = std(G);
998  G;
999  teach_lpGkDim(G); // 3, as expected for K[x,y,z]
1000}
1001
1002proc lpGlDimBound(ideal G)
1003"USAGE: lpGlDimBound(I); I an ideal
1004RETURN: int, an upper bound for the global dimension, -1 means infinity
1005PURPOSE: computing an upper bound for the global dimension
1006ASSUME: - basering is a Letterplace ring, G is a reduced Groebner Basis
1007EXAMPLE: example lpGlDimBound; shows example
1008NOTE: if I = LM(I), then the global dimension is equal the Gelfand
1009    Kirillov dimension if it is finite
1010    Global dimension should be 0 for A/G = K and 1 for A/G = K<x1...xn>
1011"
1012{
1013  G = simplify(G,2); // remove zero generators
1014  // NOTE: Gl should be 0 for A/G = K and 1 for A/G = K<x1...xn>
1015  // G1 contains generators with single variable in LM
1016  ideal G1;
1017  for (int i = 1; i <= size(G); i++) {
1018    if (ord(G[i]) < 2) { // single variable in LM
1019      G1 = insertGenerator(G1,G[i]);
1020    }
1021  } kill i;
1022  G1 = simplify(G1,2); // remove zero generators
1023
1024  // G = NF(G,G1)
1025  for (int i = 1; i <= ncols(G); i++) { // do not use size() here
1026    G[i] = lpNF(G[i],G1);
1027  } kill i;
1028  G = simplify(G,2); // remove zero generators
1029
1030  // delete variables in LM(G1) from the ring
1031  def save = basering;
1032  def R = basering;
1033  if (size(G1) > 0) {
1034    while (size(G1) > 0) {
1035      if (lpVarBlockSize(R) - lpNcgenCount(R) > 1) {
1036        def @R = R - string(G1[1]);
1037        R = @R;
1038        kill @R;
1039        setring R;
1040        /* ring R = lpDelVar(lp2iv(G1[1])[1]); // TODO replace with proper method */
1041        ideal G1 = imap(save,G1);
1042        G1 = simplify(G1, 2); // remove zero generators
1043      } else {
1044        // only the field is left (no variables)
1045        return(0);
1046      }
1047    }
1048    ideal G = imap(save, G); // put this here, because when save == R this call would make G = 0
1049  }
1050
1051  // Li p. 184 if G = LM(G), then I = LM(I) and thus glDim = gkDim if it's finite
1052  for (int i = 1; i <= size(G); i++) {
1053    if (G[i] != lead(G[i])) {
1054      break;
1055    } else {
1056      if (i == size(G)) { // if last iteration
1057        G = twostd(G); // otherwise warning that G is no standard basis
1058        int gkDim = dim(G);
1059        if (gkDim >= 0) {
1060          return (gkDim);
1061        }
1062        kill gkDim;
1063      }
1064    }
1065  } kill i;
1066
1067  intmat GNC = lpGraphOfNChains(G);
1068
1069  // assuming GNC is connected
1070
1071  // TODO: maybe loop+cycle checking could be done more efficiently?
1072  if (!imHasLoops(GNC) && imIsUpRightTriangle(topologicalSort(GNC))) {
1073    // GNC is a DAG
1074    intmat GNCk = GNC;
1075    intmat zero[1][ncols(GNCk)];
1076    int k = 1;
1077    // while first row isn't empty
1078    while (GNCk[1,1..(ncols(GNCk))] != zero[1,1..(ncols(zero))]) {
1079      GNCk = GNCk * GNC;
1080      k++;
1081    }
1082    // k-1 = number of edges in longest path starting from 1
1083    return (k-1);
1084  } else {
1085    // GNC contains loops/cycles => there is always an n-chain
1086    return (-1); // infinity
1087  }
1088}
1089example
1090{
1091  "EXAMPLE:"; echo = 2;
1092  ring r = 0,(x,y),dp;
1093  def R = freeAlgebra(r, 5); // constructs a Letterplace ring
1094  setring R; // sets basering to Letterplace ring
1095  ideal G = x*x, y*y,x*y*x; // it is a monomial Groebner basis
1096  lpGlDimBound(G);
1097  ideal H = y*x - x*y; H = std(H); // H is a Groebner basis
1098  lpGlDimBound(H); // gl dim of K[x,y] is 2, as expected
1099}
1100
1101static proc imHasLoops(intmat A) {
1102  int n = ncols(A);
1103  for (int i = 1; i <= n; i++) {
1104    if (A[i,i] == 1) {
1105      return (1);
1106    }
1107  } kill i;
1108  return (0);
1109}
1110
1111static proc lpGraphOfNChains(ideal G) // G must be reduced
1112{
1113  list LG = lpId2ivLi(lead(G));
1114  int n = lpVarBlockSize(basering);
1115  int degbound = lpDegBound(basering);
1116
1117  list V;
1118  for (int i = 0; i <= n; i++) {
1119    V[i+1] = i; // add 1 and all variables
1120  } kill i;
1121  for (int i = 1; i <= size(LG); i++) {
1122    intvec u = LG[i];
1123    for (int j = 2; j <= size(u); j++) {
1124      intvec v = u[j..size(u)];
1125      if (!contains(V, v)) {
1126        V = insert(V, v, size(V)); // add subword j..size
1127      }
1128      kill v;
1129    } kill j;
1130    kill u;
1131  } kill i;
1132  int nV = size(V);
1133  intmat GNC[nV][nV]; // graph of n-chains
1134
1135  // for vertex 1
1136  for (int i = 2; i <= n + 1; i++) {
1137    GNC[1,i] = 1; // 1 has an edge to all variables
1138  } kill i;
1139
1140  // for the other vertices
1141  for (int i = 2; i <= nV; i++) {
1142    for (int j = 2; j <= nV; j++) {
1143      intvec uv = V[i],V[j];
1144
1145      if (contains(LG, uv)) {
1146        GNC[i,j] = 1;
1147      } else {
1148        // Li p. 177
1149        // search for a right divisor 'w' of uv in G
1150        // then check if G doesn't divide the subword uv-1
1151
1152        // look for a right divisor in LG
1153        for (int k = 1; k <= size(LG); k++) {
1154          if (isSF(LG[k], uv)) {
1155            // w = LG[k]
1156            if(!ivdivides(LG, uv[1..(size(uv)-1)])) {
1157              // G doesn't divide uv-1
1158              GNC[i,j] = 1;
1159              break;
1160            }
1161          }
1162        } kill k;
1163      }
1164      kill uv;
1165    } kill j;
1166  } kill i;
1167
1168  return(GNC);
1169}
1170
1171static proc contains(list L, def item)
1172{
1173  for (int i = 1; i <= size(L); i++) {
1174    if (L[i] == item) {
1175      return (1);
1176    }
1177  } kill i;
1178  return (0);
1179}
1180
1181proc lpSubstitute(poly f, ideal s1, ideal s2, list #)
1182"USAGE: lpSubstitute(f,s1,s2[,G]); f poly, s1 list (ideal) of variables
1183  to replace, s2 list (ideal) of polynomials to replace with, G optional ideal to
1184  reduce with.
1185RETURN: poly, the substituted polynomial
1186ASSUME: - basering is a Letterplace ring
1187      - s1 contains a subset of the set of variables
1188      - s2 and s1 are of the same size
1189      - G is a Groebner basis,
1190      - the current ring has a sufficient degbound (which also can be calculated with lpCalcSubstDegBound())
1191NOTE: the procedure implements the image of a polynomial f
1192under an endomorphism of a free algebra, defined by s1 and s2:
1193variables, not present in s1, are left unchanged;
1194variable s1[k] is mapped to a polynomial s2[k].
1195- An optional ideal G extends the endomorphism as above to the morphism into the factor algebra K<X>/G.
1196EXAMPLE: example lpSubstitute; shows examples
1197"
1198{
1199  ideal G;
1200  if (size(#) > 0) {
1201    if (typeof(#[1])=="ideal") {
1202      G = #[1];
1203    }
1204  }
1205
1206  poly fs;
1207  for (int i = 1; i <= size(f); i++) {
1208    poly fis = leadcoef(f[i]);
1209    intvec ivfi = lp2iv(f[i]);
1210    for (int j = 1; j <= size(ivfi); j++) {
1211      int varindex = ivfi[j];
1212      if (varindex > 0) {
1213        int subindex = lpIndexOf(s1, var(varindex));
1214        if (subindex > 0) {
1215          s2[subindex] = lpNF(s2[subindex],G);
1216          fis = fis * s2[subindex];
1217        } else {
1218          fis = fis * lpNF(iv2lp(varindex),G);
1219        }
1220        /*fis = lpNF(fis,G);*/
1221        kill subindex;
1222      }
1223      kill varindex;
1224    } kill j;
1225    kill ivfi;
1226    fs = fs + fis;
1227    kill fis;
1228  }
1229  kill i;
1230  fs = lpNF(fs, G);
1231  return (fs);
1232}
1233example
1234{
1235  "EXAMPLE:"; echo = 2;
1236  ring r = 0,(x,y,z),dp;
1237  def R = freeAlgebra(r, 4);
1238  setring R;
1239  ideal G = x*y; // optional
1240  poly f = 3*x*x+y*x;
1241  ideal s1 = x, y;
1242  ideal s2 = y*z*z, x; // i.e. x --> yzz and y --> x
1243  // the substitution probably needs a higher degbound
1244  int minDegBound = lpCalcSubstDegBound(f,s1,s2);
1245  minDegBound; // thus the bound needs to be increased
1246  setring r; // back to original r
1247  def R1 = freeAlgebra(r, minDegBound);
1248  setring R1;
1249  lpSubstitute(imap(R,f), imap(R,s1), imap(R,s2));
1250  // the last parameter is optional; above it was G=<xy>
1251  // the output will be reduced with respect to G
1252  lpSubstitute(imap(R,f), imap(R,s1), imap(R,s2), imap(R,G));
1253}
1254
1255// another example:
1256/*
1257  //////// EXAMPLE B ////////
1258  ring r = 0,(x,y,z),dp;
1259  def R = freeAlgebra(r, 4);
1260  setring R;
1261
1262  poly f = 3*x*x+y*x;
1263  poly g = z*x+y;
1264  poly h = 7*x*z+x;
1265  ideal I = f,g,h;
1266  ideal s1 = x, y;
1267  ideal s2 = y*z*z, x;
1268
1269  int minDegBound = lpCalcSubstDegBound(I,s1,s2);
1270  setring r;
1271  def R1 = freeAlgebra(r, minDegBound);
1272  setring R1;
1273
1274  ideal I = imap(R,I);
1275  ideal s1 = imap(R,s1);
1276  ideal s2 = imap(R,s2);
1277  for (int i = 1; i <= size(I); i++) {
1278    lpSubstitute(I[i], s1, s2);
1279  }
1280*/
1281
1282static proc lpIndexOf(ideal I, poly p) {
1283  for (int i = 1; i <= size(I); i++) {
1284    if (I[i] == p) {
1285      return (i);
1286    }
1287  } kill i;
1288  return (-1);
1289}
1290
1291static proc ivIndexOf(list L, intvec iv) {
1292  for (int i = 1; i <= size(L); i++) {
1293    if (L[i] == iv) {
1294      return (i);
1295    }
1296  } kill i;
1297  return (-1);
1298}
1299
1300
1301static proc lpCalcSubstDegBoundSingle(poly f, ideal s1, ideal s2)
1302"USAGE: lpCalcSubstDegBoundSingle(f,s1,s2); f letterplace polynomial, s1 list (ideal) of variables
1303  to replace, s2 list (ideal) of polynomials to replace with
1304RETURN: int, the min degbound required to perform the substitution
1305ASSUME: - basering is a Letterplace ring
1306EXAMPLE: example lpCalcSubstDegBoundSingle; shows examples
1307"
1308{
1309  int maxDegBound = 0;
1310  for (int i = 1; i <= size(f); i++) {
1311    intvec ivfi = lp2iv(f[i]);
1312    int tmpDegBound;
1313    for (int j = 1; j <= size(ivfi); j++) {
1314      int varindex = ivfi[j];
1315      if (varindex > 0) {
1316        int subindex = lpIndexOf(s1, var(varindex));
1317        if (subindex > 0) {
1318          tmpDegBound = tmpDegBound + deg(s2[subindex]);
1319        } else {
1320          tmpDegBound = tmpDegBound + 1;
1321        }
1322        kill subindex;
1323      }
1324      kill varindex;
1325    } kill j;
1326    if (tmpDegBound > maxDegBound) {
1327      maxDegBound = tmpDegBound;
1328    }
1329    kill ivfi; kill tmpDegBound;
1330  } kill i;
1331
1332  // increase degbound by 50% when ideal is provided
1333  // needed for lpNF
1334  maxDegBound = maxDegBound + (maxDegBound div 2);
1335
1336  return (maxDegBound);
1337}
1338example
1339{
1340  // see lpCalcSubstDegBound()
1341}
1342
1343proc lpCalcSubstDegBound(ideal I, ideal s1, ideal s2)
1344"USAGE: lpCalcSubstDegBound(I,s1,s2); I ideal of polynomials, s1 ideal of variables to replace, s2 ideal of polynomials to replace with
1345RETURN: int, the min degbound required to perform all of the substitutions
1346ASSUME: - basering is a Letterplace ring
1347EXAMPLE: example lpCalcSubstDegBound; shows examples
1348NOTE: convenience method
1349"
1350{
1351  int maxDegBound = 0;
1352  for (int i = 1; i <= size(I); i++) {
1353    int tmpDegBound = lpCalcSubstDegBoundSingle(I[i], s1, s2, #);
1354    if (tmpDegBound > maxDegBound) {
1355      maxDegBound = tmpDegBound;
1356    }
1357    kill tmpDegBound;
1358  } kill i;
1359  return (maxDegBound);
1360}
1361example
1362{
1363  "EXAMPLE:"; echo = 2;
1364  ring r = 0,(x,y,z),dp;
1365  def R = freeAlgebra(r, 4);
1366  setring R;
1367  ideal I = 3*x*x+y*x, x*y*x - z;
1368  ideal s1 = x, y; // z --> z
1369  ideal s2 = y*z*z, x; // i.e. x --> yzz and y --> x
1370  // the substitution probably needs a higher degbound
1371  lpCalcSubstDegBound(I,s1,s2);
1372  lpCalcSubstDegBound(I[1],s1,s2);
1373}
1374
1375static proc isSF(intvec S, intvec I)
1376"
1377PURPOSE:
1378checks, if a word S is a suffix of another word I
1379"
1380{
1381  int n = size(S);
1382  if (n <= 0 || S == 0) {return(1);}
1383  int m = size(I);
1384  if (m < n) {return(0);}
1385  intvec IS = I[(m-n+1)..m];
1386  if (IS == S) {return(1);}
1387  else {return(0);}
1388}
1389
1390static proc isIF(intvec IF, intvec I)
1391"
1392PURPOSE:
1393checks, if a word IF is an infix of another word I
1394"
1395{
1396  int n = size(IF);
1397  int m = size(I);
1398
1399  if (n <= 0 || IF == 0) {return(1);}
1400  if (m < n) {return(0);}
1401
1402  for (int i = 0; (n + i) <= m; i++){
1403    intvec IIF = I[(1 + i)..(n + i)];
1404    if (IIF == IF) {
1405      return(1);
1406    }
1407    kill IIF;
1408  } kill i;
1409  return(0);
1410}
1411
1412// no longer working with new interface and new orderings
1413/* // TODO: use original ring attrib to create a new letterplace ring */
1414/* // removes a variable from a letterplace ring (a bit of a hack) */
1415/* static proc lpDelVar(int index) { */
1416/*   int lV = lpVarBlockSize(basering); // number of variables in the main block */
1417/*   int d = lpDegBound(basering); // degree bround */
1418/*   list LR = ringlist(basering); */
1419
1420/*   if (!(index >= 1 && index <= lV)) { return (basering); } // invalid index */
1421
1422/*   // remove from the variable list */
1423/*   for (int i = (d-1)*lV + index; i >= 1; i = i - lV) { */
1424/*     LR[2] = delete(LR[2], i); */
1425/*   } kill i; */
1426
1427/*   // remove from a ordering */
1428/*   intvec aiv = LR[3][1][2]; */
1429/*   aiv = aiv[1..(d*lV-d)]; */
1430/*   LR[3][1][2] = aiv; */
1431
1432/*   // remove block orderings */
1433/*   int del = (lV - index); */
1434/*   int cnt = -1; */
1435/*   for (int i = size(LR[3]); i >= 2; i--) { */
1436/*     if (LR[3][i][2] != 0) { */
1437/*       for (int j = size(LR[3][i][2]); j >= 1; j--) { */
1438/*         cnt++; // next 1 */
1439/*         if (cnt%lV == del) { */
1440/*           // delete */
1441/*           if (size(LR[3][i][2]) > 1) { // if we have more than one element left, delete one */
1442/*             LR[3][i][2] = delete(LR[3][i][2],j); */
1443/*           } else { // otherwise delete the whole block */
1444/*             LR[3] = delete(LR[3], i); */
1445/*             break; */
1446/*           } */
1447/*         } */
1448/*       } kill j; */
1449/*     } */
1450/*   } kill i; */
1451
1452/*   def R = setLetterplaceAttributes(ring(LR),d,lV-1); */
1453/*   return (R); */
1454/* } */
1455/* example */
1456/* { */
1457/*   "EXAMPLE:"; echo = 2; */
1458/*   ring r = 0,(x,y,z),dp; */
1459/*   def A = freeAlgebra(r, 3); */
1460/*   setring A; A; */
1461/*   def R = lpDelVar(2); setring R; R; */
1462/* } */
Note: See TracBrowser for help on using the repository browser.