source: git/Singular/LIB/fpaprops.lib @ 42d919

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