source: git/Singular/LIB/finvar.lib @ 400884

spielwiese
Last change on this file since 400884 was b182ed, checked in by Hans Schönemann <hannes@…>, 27 years ago
* hannes: changed doc2tex to include @/{/} in Libs (LIB/finvar.lib doc/doc2tex.c doc/singular.doc) added tex.lib git-svn-id: file:///usr/local/Singular/svn/trunk@486 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 140.7 KB
Line 
1// $Header: /exports/cvsroot-2/cvsroot/Singular/LIB/finvar.lib,v 1.2 1997-07-03 15:49:54 Singular Exp $
2////////////////////////////////////////////////////////////////////////////////
3// send bugs and comments to agnes@math.uni-sb.de
4LIBRARY:  finvar.lib             LIBRARY TO CALCULATE INVARIANT RINGS & MORE
5                                   by Agnes Eileen Heydtmann, send bugs and
6                                   comments to agnes@math.uni-sb.de
7
8  rey_mol(G1,G2,...[,int]);      Reynolds operator and Molien series of the
9                                 finite matrix group generated by G1,G2,...
10  part_mol(M,n[,p]);             n terms of partial expansion of Molien series M
11  eval_rey(RO,p);                evaluate poly p under Reynolds operator RO
12  rad_con(p,I);                  check radical containment of poly p in ideal I
13  inv_basis(deg,G1,G2,...);      basis of space of homogeneous invariants of
14                                 degree deg under the finite matrix group
15                                 generated by G1,G2,...
16  inv_basis_rey(RO,deg[,dim]);   basis of space of homogeneous invariants of
17                                 degree deg and optionally dimension dim with
18                                 help of Reynolds operator
19  inv_ring_s(G1,G2,...[,intvec]); generators of the invariant ring (primary
20                                 invariants according to Sturmfels)
21  inv_ring_k(G1,G2,...[,intvec]); generators of the invariant ring (combination
22                                 of algorithms by Kemper and Sturmfels for
23                                 primary invariants)
24  algebra_con(p,F);              check whether poly p is contained in invariant
25                                 ring generated by entries in F
26  module_con(f,P,S);             representing f in the Hironaka decomposition of
27                                 the invariant ring into primary invariants P
28                                 and secondary ones S
29  orbit_var(F,s);                orbit variety of a finite matrix group whose
30                                 invariant ring is generated by entries in F
31  rel_orbit_var(I,F,s);          relative orbit variety with respect to
32                                 invariant ideal I under finite matrix group,
33                                 its invariant ring is generated by entries in F
34  im_of_var(I,F);                image of variety defined by ideal I under
35                                 finite matrix group whose invariant ring is
36                                 generated by entries in F
37
38////////////////////////////////////////////////////////////////////////////////
39LIB "matrix.lib";
40LIB "elim.lib";
41LIB "general.lib";
42////////////////////////////////////////////////////////////////////////////////
43
44////////////////////////////////////////////////////////////////////////////////
45// sign of integer a, returning 1 or -1 respectively
46////////////////////////////////////////////////////////////////////////////////
47proc sign(int i)
48  USAGE:   sign(<int>);
49  RETURN:  the sign of an integer (return type <int>)
50  EXAMPLE: example sign; shows an example.
51{ if (i>=0)
52  { return(1);
53  }
54  else
55  { return(-1);
56  }
57}
58example
59{ "  EXAMPLE:";
60  echo=2;
61           int i=-3;
62           int j=3;
63           sign(i);
64           sign(j);
65}
66
67////////////////////////////////////////////////////////////////////////////////
68// absolute value of integer a
69////////////////////////////////////////////////////////////////////////////////
70proc abs (int i)
71  USAGE:   abs(<int>);
72  RETURN:  the absolute value of an integer (return type <int>)
73  EXAMPLE: example abs; shows an example.
74{ return(i*sign(i));
75}
76example
77{ "  EXAMPLE:";
78  echo=2;
79           int i=-3;
80           int j=3;
81           abs(i);
82           abs(j);
83}
84
85////////////////////////////////////////////////////////////////////////////////
86// Checks whether the last argument, being a matrix, is among the previous
87// arguments, also being matrices
88////////////////////////////////////////////////////////////////////////////////
89proc unique (list #)
90{ for (int i=1;i<size(#);i=i+1)
91  { if (#[i]==#[size(#)])
92    { return(0);
93    }
94  }
95  return(1);
96}
97
98////////////////////////////////////////////////////////////////////////////////
99// Computes the cyclotomic polynomial recursively, by dividing x^m-1 by the
100// cyclotomic polynomial of proper divisors of m
101////////////////////////////////////////////////////////////////////////////////
102proc cycle (int m)
103  USAGE:   cycle(<int>);
104  RETURNS: the cyclotomic polynomial (type <poly>) as one in the first ring
105           variable
106  EXAMPLE: example cycle; shows an example
107{ poly v1=var(1);
108  if (m==1)
109  { return(v1-1);                      // 1-st cyclotomic polynomial
110  }
111  poly min=v1^m-1;
112  matrix s[1][2]=min,v1-1;             // dividing by the 1-st cyclotomic
113  s=matrix(syz(ideal(s)));             // polynomial
114  min=s[2,1];
115  int i=2;
116  int n;
117  poly c;
118  int flag=1;
119  while(2*i<=m)                        // there are no proper divisors of m
120  { if ((m%i)==0)                      // greater than m/2
121    { if (flag==1)
122      { n=i;                           // n stores the first proper divisor of
123      }                                // m>1
124      flag=0;
125      c=cycle(i);                      // recursive computation
126      s=min,c;
127      s=matrix(syz(ideal(s)));         // dividing
128      min=s[2,1];
129    }
130    if (n*i==m)                        // the earliest possible point to break
131    { break;
132    }
133    i=i+1;
134  }
135  min=min/leadcoef(min);               // making sure that leading coefficient
136  return(min);                         // is 1
137}
138example
139{ echo=2;
140          ring R=0,(x,y,z),dp;
141          print(cycle(25));
142}
143
144////////////////////////////////////////////////////////////////////////////////
145// Returns i such that root^i==n, i.e. it heavily relies on the right input.
146////////////////////////////////////////////////////////////////////////////////
147proc power(number n, number root)
148{ int i=0;
149   while((n/root^i)<>1)
150   { i=i+1;
151   }
152   return(i);
153}
154
155////////////////////////////////////////////////////////////////////////////////
156// Generates the Molien series when the characteristic of the base field is p>0
157// and p does not divide the group order. Input is the entire group and a name
158// for a new ring.
159////////////////////////////////////////////////////////////////////////////////
160proc p_molien(list #)
161{ def br=basering;                     // keeping track of the base ring since
162  int n=nvars(br);                     // we have to go into an extension of the
163  int g=size(#)-2;                     // basefield -
164  matrix G(1..g)=#[1..g];              // rewriting the group elements
165  string newring=#[g+1];
166  int flag=#[g+2];
167  if (g<>1)
168  { ring Q=0,x,dp;                     // we want to extend our ring as well as
169                                       // the ring of rational numbers Q to
170                                       // contain g-th primitive roots of unity
171                                       // in order to factor characteristic
172                                       // polynomials of group elements into
173                                       // linear factors and lift eigenvalues to
174                                       // characteristic 0 -
175    poly minq=cycle(g);                // minq now contains the size-of-group-th
176                                       // cyclotomic polynomial of Q, it is
177                                       // irreducible there
178    ring `newring`=(0,e),x,dp;
179    map f=Q,ideal(e);
180    minpoly=number(f(minq));           // e is now a g-th primitive root of
181                                       // unity -
182    kill Q, f;                         // no longer needed -
183    poly p=1;                          // used to build the denominator of the
184                                       // new term in the Molien series
185    matrix s[1][2];                    // used for canceling -
186    matrix M[1][2]=0,1;                // will contain Molien series -
187    ring v1br=char(br),x,dp;           // we calculate the g-th cyclotomic
188    poly minp=cycle(g);                // polynomial of the base field and pick
189    minp=factorize(minp)[1][2];        // an irreducible factor of it -
190    if (deg(minp)==1)                  // in this case the base field contains
191    { ring bre=char(br),x,dp;          // g-th roots of unity already
192      map f1=v1br,ideal(0);
193      number e=-number((f1(minp)));    // e is a g-th primitive root of unity
194    }
195    else
196    { ring bre=(char(br),e),x,dp;
197      map f1=v1br,ideal(e);
198      minpoly=number(f1(minp));        // e is a g-th primitive root of unity
199    }
200    map f2=br,ideal(0);                // we need f2 to map our group elements
201                                       // to this new extension field bre
202    matrix I=unitmat(n);
203    poly p;                            // used for the characteristic polynomial
204                                       // to factor -
205    list L;                            // will contain the linear factors of the
206    ideal F;                           // characteristic polynomial of the group
207    intvec C;                          // elements and their powers
208    int i, j, k;
209    for (i=1;i<=g;i=i+1)
210    { p=det(x*I-f2(G(i)));             // characteristic polynomial of G(i)
211      L=factorize(p);
212      F=L[1];
213      C=L[2];
214      for (j=2;j<=ncols(F);j=j+1)
215      { F[j]=-1*(F[j]-x);              // F[j] is now an eigenvalue of G(i),
216                                       // it is a power of a primitive g-th root
217                                       // of unity -
218        k=power(number(F[j]),e);       // F[j]==e^k
219        setring `newring`;
220        p=p*(1-x*(e^k))^C[j];          // building the denominator of the new
221        setring bre;                   // term
222      }
223      setring `newring`;
224      M[1,1]=M[1,1]*p+M[1,2];          // expanding M[1,1]/M[1,2] + 1/p
225      M[1,2]=M[1,2]*p;
226      p=1;
227      s=matrix(syz(ideal(M)));         // canceling common terms of denominator
228      M[1,1]=-s[2,1];                  // and enumerator
229      M[1,2]=s[1,1];
230      setring bre;
231      if (flag)
232      { "  Term "+string(i)+" has been computed.";
233      }
234    }
235    if (flag)
236    { "";
237    }
238    setring `newring`;
239    map slead=`newring`,ideal(0);
240    s=slead(M);                        // forcing the constant term of numerator
241    M[1,1]=1/s[1,1]*M[1,1];            // and denominator to be 1
242    M[1,2]=1/s[1,2]*M[1,2];
243    kill slead;
244    kill s;
245    kill p;
246  }
247  else                                 // if the group only contains an identity
248  { ring `newring`=0,x,dp;             // element, it is very easy to calculate
249    matrix M[1][2]=1,(1-x)^n;          // the Molien series
250  }
251  // keepring `newring`;
252  export `newring`;                    // TTO we keep the ring where we computed
253                                       // the Molien series
254  export M;                            // TTO so that we can keep the Molien
255                                       // series
256  setring br;
257}
258
259////////////////////////////////////////////////////////////////////////////////
260// This procedure calculates all members of a finite matrix group in terms of
261// the given generators. In one run trough the main loop, all left products of
262// the generators with the new elements from the last run through the loop (or
263// the generators themselves in the first run) will be formed. After that the
264// newly generated elements will be added to the group and the loop starts over
265// again unless no elements were added.
266// Additionally, every time a new matrix is added to the group, its
267// corresponding ring mapping in the Reynolds operator and if the
268// characteristic is 0, its corresponding summand of the Molien series is
269// calculated.
270// When the characteristic of the basefield is p>0 such that it does not
271// divide the group order, the Molien series is calculated at the end of the
272// procedure.
273// No matter when the Molien series is calculated, the procedure expands after
274// every step to obtain a rational function.
275// The first result of the procedure is the Reynolds operator, presented in
276// form of a matrix; each row can be transformed into an ideal and from
277// there can be used as a ring homomorphism via the command 'map'.
278// If the characteristic is 0, the second result is a matrix, containing
279// enumerator and denominator (with no common divisor) of the final
280// rational function representing the Molien series.
281// When the characteristic of the basefield is p>0 such that it does not
282// divide the group order, the Molien series is returned in a ring of
283// characteristic 0. It names was specified in the list of parameters.
284////////////////////////////////////////////////////////////////////////////////
285proc rey_mol (list #)
286  USAGE:   rey_mol(<generators of a finite matrix group>[,<string>,<int>]);
287           if the characteristic of the coefficient field is prime, <string>
288           has to contain the name for a new polynomials ring with coefficient
289           field of characteristic 0 that stores the Molien series - if <int> is
290           not not equal to 0, some information will be printed during the run
291  RETURNS: if the characteristic is 0: Reynolds operator (type <matrix>), Molien
292           series (type <matrix> with two components, first being the numerator,
293           second the denominator)
294           if the characteristic is p>0 not dividing the group order: Reynolds
295           operator (type <matrix>) - the Molien series will directly be stored
296           under the name M (type <matrix>) in the ring `<string>`
297           if the characteristic is p>0 dividing the group order: Reynolds
298           operator (type <matrix>)
299  EXAMPLE: example rey_mol; shows an example
300{ def br=basering;                     // the Molien series depends on the
301  int ch=char(br);                     // characteristic of the coefficient
302  int flag;                            // field -
303  if (ch<>0)                           // making sure the input is 'correct'...
304  { if (typeof(#[size(#)])=="string")
305    { flag=size(#)-1;
306      string newring=#[size(#)];
307      int v=0;                         // no information is default
308    }
309    else
310    { if (typeof(#[size(#)-1])=="string")
311      { flag=size(#)-2;
312        string newring=#[size(#)-1];
313        if (typeof(#[size(#)])<>"int")
314        { "  ERROR:   if the second last parameter is <string>, the last must be";
315          "           of type <int>";
316          return();
317        }
318        int v=#[size(#)];
319      }
320      else
321      { "  ERROR:   in characteristic p a <string> must be given for the name";
322        "           of a new ring";
323        return();
324      }
325    }
326    if (newring=="")
327    { "  ERROR:   <string> may not be empty";
328      return();
329    }
330  }
331  else
332  { if (typeof(#[size(#)])=="int")
333    { flag=size(#)-1;
334      int v=#[size(#)];
335    }
336    else
337    { flag=size(#);
338      int v=0;                         // no information is default
339    }
340  }
341  if (typeof(#[1])<>"matrix")
342  { "  ERROR:   the parameters must be a list of matrices and optionally";
343    "           a <string> and an <int>";
344    return();
345  }
346  int n=nrows(#[1]);
347  if (n<>nvars(br))
348  { "  ERROR:   the number of variables of the basering needs to be the same";
349    "           as the dimension of the matrices";
350    return();
351  }
352  if (n<>ncols(#[1]))
353  { "  ERROR:   matrices need to be square and of the same dimensions";
354    return();
355  }
356  matrix vars=matrix(maxideal(1));     // creating an nx1-matrix containing the
357  vars=transpose(vars);                // variables of the ring -
358  matrix A(1)=#[1]*vars;               // calculating the first ring mapping -
359                                       // A(1) will contain the Reynolds
360                                       // operator -
361  if (ch==0)                           // when ch==0 we can calculate the Molien
362  { matrix I=diag(1,n);                // series in any case -
363    poly v1=vars[1,1];                 // the Molien series will be in terms of
364                                       // the first variable of the current
365                                       // ring -
366    matrix A(2)[1][2];                 // A(2) will contain the Molien series -
367    A(2)[1,1]=1;                       // A(2)[1,1] will be the numerator
368    A(2)[1,2]=det(I-v1*(#[1]));        // A(2)[1,2] will be the denominator -
369    matrix s;                          // will help us canceling in the
370                                       // fraction
371  }
372  matrix G(1)=#[1];                    // G(k) are elements of the group -
373  poly p;                              // will contain the denominator of the
374                                       // new term of the Molien series
375  int i=1;
376  for (int j=2;j<=flag;j=j+1)          // this loop adds the arguments to the
377  {                                    // group, leaving out doubles and
378                                       // checking whether the arguments are
379                                       // compatible with the task of the
380                                       // procedure
381    if (not(typeof(#[j])=="matrix"))
382    { "  ERROR:   the parameters must be a list of matrices and optionally";
383      "           a <string> and an <int>";
384      return();
385    }
386    if ((n!=nrows(#[j])) or (n!=ncols(#[j])))
387    { "  ERROR:   matrices need to be square and of the same dimensions";
388       return();
389    }
390    if (unique(G(1..i),#[j]))
391    { i=i+1;
392      matrix G(i)=#[j];
393      A(1)=concat(A(1),#[j]*vars);     // adding ring homomorphisms to A(1)
394      if (ch==0)
395      { p=det(I-v1*#[j]);              // denominator of new term -
396        A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2]; // expanding A(2)[1,1]/A(2)[1,2] + 1/p
397        A(2)[1,2]=A(2)[1,2]*p;
398        s=matrix(syz(ideal(A(2))));    // canceling common factors
399        A(2)[1,1]=-s[2,1];
400        A(2)[1,2]=s[1,1];
401      }
402    }
403  }
404  int g=i;                             // G(1)..G(i) are generators without
405                                       // doubles - g generally is the number
406                                       // of elements in the group so far -
407  j=i;                                 // j is the number of new elements that
408                                       // we use as factors -
409  int k, m, l;
410  if (v)
411  { if (ch==0)
412    { "";
413      "  Generating the entire matrix group, Reynolds operator and Molien series...";
414      "";
415    }
416    else
417    { "";
418      "  Generating the entire matrix group and Reynolds operator...";
419      "  If the characteristic of the basefield divides the order of the";
420      "  group the result will be useless.";
421      "";
422    }
423  }
424  while (1)
425  { l=0;   // l is the number of products we get in one going
426    for (m=g-j+1;m<=g;m=m+1)
427    { for (k=1;k<=i;k=k+1)
428      { l=l+1;
429        matrix P(l)=G(k)*G(m);         // possible new element
430      }
431    }
432    j=0;
433    for (k=1;k<=l;k=k+1)
434    { if (unique(G(1..g),P(k)))
435      { j=j+1;                         // a new factor for next run
436        g=g+1;
437        matrix G(g)=P(k);              // a new group element -
438        A(1)=concat(A(1),P(k)*vars);   // adding new mapping to A(1)
439        if (ch==0)
440        { p=det(I-v1*P(k));            // denominator of new term -
441          A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2];
442          A(2)[1,2]=A(2)[1,2]*p;       // expanding A(2)[1,1]/A(2)[1,2] + 1/p -
443          s=matrix(syz(ideal(A(2))));  // canceling common factors
444          A(2)[1,1]=-s[2,1];
445          A(2)[1,2]=s[1,1];
446        }
447        if (v)
448        { "  Group element "+string(g)+" has been found.";
449        }
450      }
451      kill P(k);
452    }
453    if (j==0)                          // when we didn't add any new elements
454    { break; }                         // in one run through the while loop
455  }                                    // we are done -
456  if (v)
457  { if (g<=i)
458    { "  There are only "+string(g)+" group elements.";
459    }
460    "";
461  }
462  A(1)=transpose(A(1));                // when we evaluate the Reynolds operator
463                                       // later on, we actually want 1xn
464                                       // matrices
465  if (ch<>0 && minpoly==0)
466  { if ((g%ch)<>0)
467    { if (v)
468      { "  Generating Molien series...";
469        "";
470      }
471      p_molien(G(1..g),newring,v);     // the procedure that defines a ring of
472                                       // characteristic 0 and calculates the
473                                       // Molien series in it
474      if (v)
475      { "  Now we are done calculating Molien series and Reynolds operator.";
476        "";
477      }
478      return(A(1));
479    }
480  }
481  if (ch<>0 && minpoly<>0)
482  { if ((g%ch)<>0)
483    { if (voice==2)
484      { "  WARNING: It is impossible for this program to calculate the Molien series";
485        "           for finite groups over extension fields of prime characteristic.";
486      }
487      else
488      { if (v)
489        { "  Since it is impossible for this program to calculate the Molien series for";
490          "  invariant rings over extension fields of prime characteristic, we have to";
491          "  continue without it. The Reynolds operator is available, however.";
492          "";
493        }
494      }
495      return(A(1));
496    }
497  }
498  if (ch<>0)
499  { if ((g%ch)==0)
500    { if (voice==2)
501      { A(1)=0;
502        "  WARNING: The characteristic of the coefficient field divides the group";
503        "           order. Proceed without the Molien series or Reynolds operator!";
504      }
505      else
506      { if (v)
507        { "  The characteristic of the base field divides the group order.";
508          "  We have to continue without Molien series and without Reynolds";
509          "  operator..";
510          "";
511        }
512      }
513      return(A(1));
514    }
515  }
516  if (ch==0)
517  { map slead=br,ideal(0);
518    s=slead(A(2));
519    A(2)[1,1]=1/s[1,1]*A(2)[1,1];      // numerator and denominator have to have
520    A(2)[1,2]=1/s[1,2]*A(2)[1,2];      // a constant term of 1
521    if (v)
522    { "  Now we are done calculating Molien series and Reynolds operator.";
523      "";
524    }
525    return(A(1..2));
526  }
527}
528example
529{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
530  "           note the case of prime characteristic";
531  echo=2;
532           ring R=0,(x,y,z),dp;
533           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
534           matrix RM(1..2);
535           RM(1..2)=rey_mol(A);
536           print(RM(1..2));
537           ring S=3,(x,y,z),dp;
538           string newring="Qadjoint";
539           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
540           matrix REY=rey_mol(A,newring);
541           print(REY);
542           setring Qadjoint;
543           M;
544           setring S;
545           kill Qadjoint;
546}
547
548////////////////////////////////////////////////////////////////////////////////
549// This procedure implements the following calculation:
550// (1+a[1]x+a[2]x2+...+a[n]xn)/(1+b[1]x+b[2]x2+...+b[m]xm)=(1+(a[1]-b[1])x+...
551// (1+b[1]x+b[2]x2+...+b[m]xm)
552// ---------------------------
553//    (a[1]-b[1])x+(a[2]-b[2])x2+...
554//    (a[1]-b[1])x+b[1](a[1]-b[1])x2+...
555////////////////////////////////////////////////////////////////////////////////
556proc part_mol (matrix M, int n, list #)
557  USAGE:   part_mol(M,n[,p]); M <matrix> (return value of 'rey_mol'), n <int>,
558           indicating  number of terms in the expansion, p <poly> optionally, it
559           ought to be the second return value of a previous run of 'part_mol'
560           and avoids recalculating known terms
561  RETURNS: n terms of partial expansion of the Molien series (type <poly>)
562           (first n if there is no third argument given, otherwise the next n
563           terms depending on a previous calculation) and an intermediate result
564           (type <poly>) of the calculation to be used as third argument in a
565           next run
566  EXAMPLE: example part_mol; shows an example
567{ poly A(2);                           // A(2) will contain the return value of
568                                       // the intermediate result
569  if (char(basering)<>0)
570  { "  ERROR:   you have to change to a basering of characteristic 0, one in";
571    "           which the Molien series is defined";
572  }
573  if (ncols(M)==2 && nrows(M)==1 && n>0 && size(#)<2)
574  { def br=basering;                   // keeping track of the old ring
575    map slead=br,ideal(0);
576    matrix s=slead(M);
577    if (s[1,1]<>1 || s[1,2]<>1)
578    { "  ERROR:   the constant terms of enumerator and denominator are not 1";
579      return();
580    }
581
582    if (size(#)==0)
583    { A(2)=M[1,1];                     // if a third argument is not given, the
584                                       // intermediate result from the last run
585                                       // corresponds to the numerator - we need
586    }                                  // its smallest term
587    else
588    { if (typeof(#[1])=="poly")
589      { A(2)=#[1];                     // if a third term is given we 'start'
590      }                                // with its smallest term
591      else
592      { "  ERROR:   <poly> as third argument expected";
593        return();
594      }
595    }
596    poly A(1)=M[1,2];                  // denominator of Molien series
597                                       // (for now) -
598    string mp=string(minpoly);
599    execute "ring R=("+charstr(br)+"),("+varstr(br)+"),ds;";
600    execute "minpoly=number("+mp+");";
601    poly A(1)=0;                       // A(1) will contain the sum of n terms -
602    poly min;                          // min will be our smallest term -
603    poly A(2)=fetch(br,A(2));          // fetching A(2) and M[1,2] into R
604    poly den=fetch(br,A(1));
605    for (int i=1; i<=n; i=i+1)         // getting n terms and adding them up
606    { min=lead(A(2));
607      A(1)=A(1)+min;
608      A(2)=A(2)-min*den;
609    }
610    setring br;                        // moving A(1) and A(2) back in the
611    A(1)=fetch(R,A(1));                // actual ring for output
612    A(2)=fetch(R,A(2));
613    return(A(1..2));
614  }
615  else
616  { "  ERROR:   the first argument has to be a 1x2-matrix, i.e. the matrix";
617    "           returned by the procedure 'rey_mol', the second one";
618    "           should be > 0 and there should be no more than 3 arguments;"
619    return();
620  }
621}
622example
623{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
624  echo=2;
625           ring R=0,(x,y,z),dp;
626           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
627           matrix B(1..2);
628           B(1..2)=rey_mol(A);
629           poly C(1..2);
630           C(1..2)=part_mol(B(2),5);
631           C(1);
632           C(1..2)=part_mol(B(2),5,C(2));
633           C(1);
634}
635
636////////////////////////////////////////////////////////////////////////////////
637// RO will simply be cut into pieces and each row will act as a ring
638// mapping of which the Reynolds operator is made up.
639////////////////////////////////////////////////////////////////////////////////
640proc eval_rey (matrix RO, poly f)
641  USAGE:   eval_rey(RO,f); RO <matrix> (result of rey_mol),
642           f <poly>
643  RETURNS: image of f under the Reynolds operator (type <poly>)
644  NOTE:    the characteristic of the coefficient field of the polynomial ring
645           should not divide the order of the finite matrix group
646  EXAMPLE: example eval_rey; shows an example
647{ def br=basering;
648  int n=nvars(br);
649  if (ncols(RO)==n)
650  { int m;                             // we need m to 'cut' the ring
651                                       // homomorphisms 'out' of RO and to
652    m=nrows(RO);                       // divide by the group order in the end
653    poly p=0;
654    map pRO;
655    matrix RH[1][n];
656    for (int i=1;i<=m;i=i+1)
657    { RH=RO[i,1..n];
658      pRO=br,ideal(RH);                // f is now the i-th ring homomorphism
659      p=pRO(f)+p;
660    }
661    p=(1/poly(m))*p;
662    return(p);
663  }
664  else
665  { "  ERROR:   the number of columns in the matrix, being the first argument";
666    "           should be the same as number of variables in the basering, in";
667    "           fact it should be the matrix returned by 'rey_mol'";
668    return();
669  }
670}
671example
672{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
673  echo=2;
674           ring R=0,(x,y,z),dp;
675           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
676           matrix B(1..2);
677           B(1..2)=rey_mol(A);
678           poly p=x2;
679           eval_rey(B(1),p);
680}
681
682////////////////////////////////////////////////////////////////////////////////
683// Input: <ideal>=<f1,f2,...,fm> and <polynomial> g
684// Question: Does g lie in the radical of <ideal>?
685// Solution: Compute a standard basis G for <f1,f2,...,fm,gz-1> where z is a new
686//           variable. Then g is contained in the radical of <ideal> <=> 1 is
687//           generator in G.
688////////////////////////////////////////////////////////////////////////////////
689proc rad_con (poly g,ideal I)
690  USAGE:   rad_con(<poly>,<ideal>);
691  RETURNS: 1 (TRUE) (type <int>) if <poly> is contained in the radical of
692           <ideal>, 0 (FALSE) (type <int>) otherwise
693  EXAMPLE: example rad_con; shows an example
694{ def br=basering;
695  int n=nvars(br);
696  int dB=degBound;
697  degBound=0;
698  string mp=string(minpoly);
699  execute "ring R=("+charstr(br)+"),(x(1..n),z),dp;";
700  execute "minpoly=number("+mp+");";
701  ideal irrel=x(1..n);
702  map f=br,irrel;
703  poly p=f(g);
704  ideal J=f(I)+ideal(p*z-1);
705  J=std(J);
706  degBound=dB;
707  if (J[1]==1)
708  { return(1);
709  }
710  else
711  { return(0);
712  }
713}
714example
715{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7.";
716  echo=2;
717           ring R=0,(x,y,z),dp;
718           ideal I=x2+y2,z2;
719           poly f=x4+y4;
720           rad_con(f,I);
721           ideal J=x2+y2,z2,x4+y4;
722           poly g=z;
723           rad_con(g,I);
724}
725
726////////////////////////////////////////////////////////////////////////////////
727// This procedure generates a basis of invariant polynomials in degree g. The
728// way this works, is that we look how the generators act on a general
729// polynomial of degree g - it turns out that one simply has to solve a system
730// of linear equations.
731////////////////////////////////////////////////////////////////////////////////
732proc inv_basis (int g, list #)
733  USAGE:   inv_basis(<int>,<generators of a finite matrix group>); <int>
734           indicates in which degree (>0) we are looking for invariants
735  RETURNS: the basis (type <ideal>) of the space of invariants of degree <int_1>
736  EXAMPLE: example inv_basis; shows an example
737{ if (g<=0)
738  { "  ERROR:   the first argument should be > 0";
739    return();
740  }
741  def br=basering;
742  ideal mon=sort(maxideal(g))[1];      // needed for constructing a general
743  int m=ncols(mon);                    // homogeneous polynomial of degree d
744  int a=size(#);
745  int i;
746  int n=nvars(br);
747  for (i=1;i<=a;i=i+1)                 // checking that input is ok
748  { if (typeof(#[i])=="matrix")
749    { if (nrows(#[i])==n && ncols(#[i])==n)
750      { matrix G(i)=#[i];
751      }
752      else
753      { "  ERROR:   the number of variables of the base ring needs to be the same";
754        "           as the dimension of the square matrices";
755        return();
756      }
757    }
758    else
759    { "  ERROR:   the last arguments should be a list of matrices";
760      return();
761    }
762  }
763  ideal vars_old=maxideal(1);
764  execute "ring T=("+charstr(br)+"),("+varstr(br)+",p(1..m)),lp;";
765  ideal vars=imap(br,vars_old);
766  // p(1..m) are general coefficients of
767  // the general polynomial
768  map f;
769  ideal mon=imap(br,mon);
770  poly P=0;
771  for (i=m;i>=1;i=i-1)
772  { P=P+p(i)*mon[i];                   // P is the general polynomial
773  }
774  ideal I;                             // will help substituting variables in P
775                                       // by linear combinations of variables -
776  poly Pnew, temp;                     // Pnew is P with substitutions -
777  matrix S[m*a][m];                    // will contain system of linear
778                                       // equations
779  int j, k;
780  for (i=1;i<=a;i=i+1)                 // building system of linear equations
781  { I=ideal(matrix(vars)*transpose(imap(br,G(i))));
782    I=I,p(1..m);
783    f=T,I;
784    Pnew=f(P);
785    for (j=1;j<=m;j=j+1)
786    { temp=P/mon[j]-Pnew/mon[j];
787      for (k=1;k<=m;k=k+1)
788      { S[m*(i-1)+j,k]=temp/p(k);
789      }
790    }
791  }
792  setring br;
793  map f=T,ideal(0);
794  matrix S=f(S);
795  matrix s=matrix(syz(S));             // s contains a basis of the space of
796                                       // solutions -
797  ideal I=ideal(matrix(mon)*s);        // I contains a basis of homogeneous
798  if (I[1]<>0)                         // invariants of degree d
799  { for (i=1;i<=ncols(I);i=i+1)
800    { I[i]=I[i]/leadcoef(I[i]);        // setting leading coefficients to 1
801    }
802  }
803  return(I);
804}
805example
806{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
807  echo=2;
808             ring R=0,(x,y,z),dp;
809             matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
810             print(inv_basis(2,A));
811}
812
813////////////////////////////////////////////////////////////////////////////////
814// This procedure generates invariant polynomials of degree g via the Reynolds
815// operator and checks by calculating syzygies whether they are linearly
816// independent. If they are the first column of syzygies does not contain any
817// constant polynomials. If a third argument of type <int> is given, the
818// program stopes once that many linearly independent polynomials have been
819// found.
820////////////////////////////////////////////////////////////////////////////////
821proc inv_basis_rey (matrix RO, int g, list #)
822  USAGE:   inv_basis_rey(<matrix>,<int_1>[,<int_2>]); <matrix> should be the
823           Reynolds operator which is the first return value of rey_mol, <int_1>           indicates the degree of the invariants and <int_2> optionally the
824           dimension of the space which is known from 'part_mol'
825  RETURNS: the basis <ideal> of the space of invariants of degree <int_1>
826  EXAMPLE: example inv_basis_rey; shows an example
827{ if (g<=0)
828  { "  ERROR:   the second argument should be > 0";
829     return();
830  }
831  if (size(#)>0)
832  { if (typeof(#[1])<>"int")
833    { "  ERROR: the third argument should be of type <int>";
834      return();
835    }
836    if (#[1]<0)
837    { "  ERROR: the third argument should be and <int> >= 0";
838      return();
839    }
840  }
841  int i, k;
842  ideal mon=sort(maxideal(g))[1];
843  int j=ncols(mon);
844  matrix S[ncols(mon)][1];             // will contain linear systems of
845  int counter=0;                       // equations -
846  degBound=g;                          // syzygies of higher degree need not be
847                                       // computed -
848  poly imRO;                           // image of Reynolds operator -
849  ideal B;                             // will contain the basis
850  for (i=j;i>0;i=i-1)
851  { imRO=eval_rey(RO,mon[i]);
852    if (imRO<>0)                       // the first candidate<>0 will definitely
853    { if (counter==0)                  // be in the basis
854      { B[1]=imRO;
855        B[1]=B[1]/leadcoef(B[1]);
856        counter=counter+1;
857      }
858      else                             // other candidates have to be checked
859      { B=B,imRO;                      // for linear independence
860        S=syz(B);
861        k=1;
862        while(k<>counter+2)
863        { if (S[k,1]==0)               // checking whether there are constant
864          { k=k+1;                     // entries <>0 in S
865          }
866          else
867          { break;
868          }
869        }
870        if (k==counter+2)              // this means that the loop was not
871        { counter=counter+1;           // broken, we can keep B[counter]
872          B[counter]=B[counter]/leadcoef(B[counter]);
873        }
874        else                           // we have to get rid of B[counter]
875        { B[counter+1]=0;
876          B=compress(B);
877        }
878      }
879    }
880    if (size(#)>0)
881    { if (counter==#[1])               // we have found enough elements (if the
882      { break;                         // user entered the right dim...
883      }
884    }
885  }
886  degBound=0;
887  return(B);
888}
889example
890{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
891  echo=2;
892             ring R=0,(x,y,z),dp;
893             matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
894             matrix B(1..2);
895             B(1..2)=rey_mol(A);
896             print(inv_basis_rey(B(1),6,8));
897}
898
899////////////////////////////////////////////////////////////////////////////////
900// Procedure returning the succeeding vector after vec. It is used to list
901// all the vectors of Z^n with first nonzero entry 1. They are listed by
902// increasing sum of the absolute value of their entries.
903////////////////////////////////////////////////////////////////////////////////
904proc nextvec(intmat vec)
905{ int n=ncols(vec);                    // p: >0, n: <0, p0: >=0, n0: <=0
906  for (int i=1;i<=n;i=i+1)             // finding out which is the first
907  { if (vec[1,i]<>0)                   // component <>0
908    { break;
909    }
910  }
911  intmat new[1][n];
912  if (i>n)                             // 0,...,0 --> 1,0....,0
913  { new[1,1]=1;
914    return(new);
915  }
916  if (i==n)                            // 0,...,1 --> 1,1,0,...,0
917  { new[1,1..2]=1,1;
918    return(new);
919  }
920  if (i==n-1)
921  { if (vec[1,n]==0)                   // 0,...,0,1,0 --> 0,...,0,1
922    { new[1,n]=1;
923      return(new);
924    }
925    if (vec[1,n]>0)                    // 0,..,0,1,p --> 0,...,0,1,-p
926    { new[1,1..n]=vec[1,1..n-1],-vec[1,n];
927      return(new);
928    }
929    new[1,1..2]=1,1-vec[1,n];          // 0,..,0,1,n --> 1,1-n,0,..,0
930    return(new);
931  }
932  if (i>1)
933  { intmat temp[1][n-i+1]=vec[1,i..n]; // 0,...,0,1,*,...,* --> 1,*,...,*
934    temp=nextvec(temp);
935    new[1,i..n]=temp[1,1..n-i+1];
936    return(new);
937  }                                    // case left: 1,*,...,*
938  for (i=2;i<=n;i=i+1)
939  { if (vec[1,i]>0)                    // make first positive negative and
940    { vec[1,i]=-vec[1,i];              // return
941      return(vec);
942    }
943    else
944    { vec[1,i]=-vec[1,i];              // make all negatives before positives
945    }                                  // positive
946  }
947  for (i=2;i<=n-1;i=i+1)               // case: 1,p,...,p after 1,n,...,n
948  { if (vec[1,i]>0)
949    { vec[1,2]=vec[1,i]-1;             // shuffleing things around...
950      if (i>2)                         // same sum of absolute values of entries
951      { vec[1,i]=0;
952      }
953      vec[1,i+1]=vec[1,i+1]+1;
954      return(vec);
955    }
956  }                                    // case left: 1,0,...,0 --> 1,1,0,...,0
957  new[1,2..3]=1,vec[1,n];              // and: 1,0,...,0,1 --> 0,1,1,0,...,0
958  return(new);
959}
960
961////////////////////////////////////////////////////////////////////////////////
962// Input is a list of nxm-matrices with n<m and rank n. Procedure checks whether
963// the space generated by the rows of the last matrix lies in any of the spaces
964// generated by other matrices' rows. Returns a boolean answer.
965////////////////////////////////////////////////////////////////////////////////
966proc space_con (list #)
967{ matrix H;
968  int n=nrows(#[1]);
969  for (int i=1;i<size(#);i=i+1)
970  { H=transpose(#[i]);
971    H=concat(H,transpose(#[size(#)])); // concatenating works column-wise -
972    H=bareiss(transpose(H));           // bareiss works row-wise -
973    if (ncols(compress(transpose(H)))==n)  // means that the last rows of the
974    { return(1);                       // matrix were in the span of the rows of
975    }                                  // #[i]
976  }
977  return(0);
978}
979
980////////////////////////////////////////////////////////////////////////////////
981// Maps integers to elements of the base field. It is only called if the base
982// field is of prime characteristic. If the base field has q elements (depending
983// on minpoly) 1..q is mapped to those q elements.
984////////////////////////////////////////////////////////////////////////////////
985proc intnumap (int i)
986{ int p=char(basering);
987  if (minpoly==0)                      // if no minpoly is given, we have p
988  { i=i%p;                             // elements in the field
989    return(number(i));
990  }
991  int d=pardeg(minpoly);
992  if (i<0)
993  { int bool=1;
994    i=(-1)*i;
995  }
996  i=i%p^d;                             // base field has p^d elements
997  number a=par(1);                     // a is the root of the minpoly, we have
998  number out=0;                        // to construct a linear combination of
999  int j=1;                             // a^k
1000  int k;
1001  while (1)
1002  { if (i<p^j)                         // finding an upper bound on i
1003    { for (k=0;k<j-1;k=k+1)
1004      { out=out+((i/p^k)%p)*a^k;       // finding how often p^k is contained in
1005      }                                // i
1006      out=out+(i/p^(j-1))*a^(j-1);
1007      if (defined(bool)=voice)
1008      { return((-1)*out);
1009      }
1010      return(out);
1011    }
1012    j=j+1;
1013  }
1014}
1015
1016////////////////////////////////////////////////////////////////////////////////
1017// Attempting to construct n=[number of variables in the base ring] linear
1018// combinations of the m>n entries in Q such that the ideal generated by these
1019// combinations is of dimension 0. It is then a Noetherian normalization of the
1020// invariant ring. In characteristic 0 the existence of such a linear
1021// combination is ensured.
1022////////////////////////////////////////////////////////////////////////////////
1023proc noethernorm(ideal Q)
1024{ def br=basering;
1025  int lcm=deg(Q[1]);                   // will contain lowest common multiple of
1026  int ch=char(br);                     // degrees of polynomials in Q
1027  int n=nvars(br);
1028  int i, j;
1029  intvec degvec;
1030  int m=ncols(Q);
1031  degvec[1]=lcm;
1032  for (i=2;i<=m;i=i+1)
1033  { degvec[i]=deg(Q[i]);
1034    lcm=lcm*degvec[i]/gcd(lcm,degvec[i]); // lcm is now the least common
1035  }                                    // multiple of the first i elements of Q
1036  ideal A(1)=Q;
1037  for (i=1;i<=m;i=i+1)
1038  { A(1)[i]=(A(1)[i])^(lcm/degvec[i]); // now all elements in A(1) are of the
1039  }                                    // same degree, they are the elements of
1040                                       // Q raised to a power -
1041  matrix T[n][1];                      // will contain the n linear combinations
1042  matrix I[n][n]=unitmat(n);
1043  matrix H(1)[n][m];
1044  H(1)[1..n,1..n]=I[1..n,1..n];        // H(1) will be the first matrix, we try
1045  kill I;
1046  if ((n%2)==0)                        // H(1) ought to be of the form:
1047  { j=int(n)/int(2);                   // 1,0,...,0,0,1,0,...,0
1048  }                                    // 0,0,...,0,1,0,0,...,0
1049  else                                 //      .           .
1050  { j=int(n-1)/int(2);                 //      .           .
1051  }                                    //      .           .
1052  for (i=1;i<=j;i=i+1)                 // 1,0,...,0,0,0,0,...,0
1053  { H(1)=permcol(H(1),i,n-i+1);
1054  }
1055  H(1)[1,1]=1;
1056  int c=1;
1057  intmat vec[1][n*m];
1058  vec[1,1..n*m]=int(H(1)[1..n,1..m]);  // we rewrite H(1) as a vector
1059  while (1)
1060  { T=H(c)*transpose(matrix(A(1)));
1061    Q=ideal(T);
1062    attrib(Q,"isSB",1);
1063    if (dim(Q)>0)
1064    { if (dim(std(Q))==0)              // we found n linear combinations
1065      { A(1)=T;
1066        break;
1067      }
1068    }
1069    else                               // we found n linear combinations
1070    { A(1)=T;
1071      break;
1072    }
1073    matrix H(c+1)[n][m];               // we have to find a new matrix
1074    while(1)                           // generating n linear combinations
1075    { vec=nextvec(vec);
1076      if (ch==0)
1077      { H(c+1)[1..n,1..m]=vec[1,1..n*m];
1078      }
1079      else
1080      { for (i=1;i<=n;i=i+1)
1081        { for (j=1;j<=m;j=j+1)
1082          { H(c+1)[i,j]=intnumap(vec[1,(i-1)*m+j]); // mapping integers to the
1083          }                            // field
1084        }
1085      }
1086      if (minor(H(c+1),n)[1]<>0 && not(space_con(H(1..c+1)))) // if the ideal
1087      { c=c+1;                         // generated by the minors is not the 0
1088        break;                         // ideal and if the span of rows of
1089      }                                // H(c+1) is not in the span of rows
1090                                       // previously tried, then we found a new
1091                                       // interesting matrix
1092    }
1093  }
1094  if (ch==0)
1095  { poly p(1)=(1-var(1)^lcm)^n;        // since all elements are of degree
1096                                       // lcm, the denominator of the Hilbert
1097                                       // series of the ring generated by the
1098                                       // primary invariants equals p(1)
1099    return(A(1),p(1));
1100  }
1101  else
1102  { if (defined(Qa))                   // here is where we store Molien series
1103    { setring Qa;
1104      poly p(1)=(1-x^lcm)^n;           // since all elements are of degree
1105                                       // lcm, the denominator of the Hilbert
1106                                       // series of the ring generated by the
1107                                       // primary invariants equals p(1)
1108      setring br;
1109      return(A(1),p(1));
1110    }
1111    else
1112    { return(A(1));
1113    }
1114  }
1115}
1116
1117////////////////////////////////////////////////////////////////////////////////
1118// Computing the entire matrix group from generators and returning its
1119// cardinality.
1120////////////////////////////////////////////////////////////////////////////////
1121proc group (list #)
1122{ matrix G(1)=#[1];                    // first group element
1123  int i=1;
1124  for (int j=2;j<=size(#);j=j+1)       // throwing out doubles among the
1125  { if (unique(G(1..i),#[j]))          // generators
1126    { i=i+1;
1127      matrix G(i)=#[j];
1128    }
1129  }
1130  int g=i;                             // g: elements in the group so far, i:
1131  j=i;                                 // generators, j: new ones used as
1132  int m, k, l;                         // as factors, l: counting possible new
1133                                       // new elements
1134  while (1)
1135  { l=0;
1136    for (m=g-j+1;m<=g;m=m+1)
1137    { for (k=1;k<=i;k=k+1)
1138      { l=l+1;
1139        matrix P(l)=G(k)*G(m);         // possible new element
1140      }
1141    }
1142    j=0;
1143    for (k=1;k<=l;k=k+1)               // checking whether the P(k) are new
1144    { if (unique(G(1..g),P(k)))
1145      { j=j+1;
1146        g=g+1;
1147        matrix G(g)=P(k);              // adding new elements -
1148      }
1149      kill P(k);
1150    }
1151    if (j==0)                          // when we didn't add any new elements
1152    { break;                           // in one run through the while loop, we
1153    }                                  // are done
1154  }
1155  return(g);
1156}
1157
1158////////////////////////////////////////////////////////////////////////////////
1159// If the characteristic of the base field is zero or prime not dividing the
1160// order of the group G, one can compute secondary invariants (free module
1161// generators) even without the Molien series. In other words, when the user
1162// enters a flag that tells the procedures inv_ring_s or inv_ring_k not to compute
1163// the Molien series, it the number of group elements will be computed (with
1164// group). If the characteristic is 0 or prime not dividing the order of the
1165// group, there are deg(P[1])*...*deg(P[n])/|G| free module generators where P
1166// contains the primary invariants. sec_minus_mol computes these secondary
1167// invariants by going through the various spaces of homogeneous invariants
1168// successively, starting with degree 1.
1169// list # is made of of various things. The last component is an integer, saying
1170// how many of the immediately preceding elements are bases of various vector
1171// spaces of homogeneous invariants. Before these bases, is a boolean variable.
1172// if it is 0, the preceding elements are group generators (we will use
1173// inv_basis), if it is 0, the Reynolds operator is passed on (and we can use
1174// inv_basis_rey).
1175// sP is the standard basis of the ideal generated by primary invariants in P. g
1176// is the cardinality of the group. v is the verbose-level.
1177////////////////////////////////////////////////////////////////////////////////
1178proc sec_minus_mol (ideal P, ideal sP, int g, int v, list#)
1179{ def br=basering;
1180  int n=nvars(br);
1181  int d=1;
1182  int r=size(#)-#[size(#)]-1;
1183  for (int i=r+1;i<size(#);i=i+1)
1184  { ideal B(i-r)=#[i];                 // rewriting the bases
1185  }
1186  for (i=1;i<=n;i=i+1)
1187  { d=d*deg(P[i]);                     // building the product of the degrees of
1188  }                                    // primary invariants -
1189  int bound=d/g;                       // number of secondary invariants
1190  if (v)
1191  { "  The invariant ring is Cohen-Macaulay.";
1192    "  We need to find "+string(d)+"/"+string(g)+"="+string(bound)+" secondary invariants.";
1193    "";
1194  }
1195  if (bound==1)                        // in this case, it is quick
1196  { if (v)
1197    { "  In degree 0 we have: 1";
1198      "";
1199      "  We're done!";
1200      "";
1201    }
1202    return(matrix(1));
1203  }
1204  qring Qring=sP;                      // secondary invariants are linearly
1205                                       // independent modulo the ideal generated
1206                                       // by primary invariants -
1207  ideal Smod;                          // stores secondary invariants modulo sP
1208                                       // that are homogeneous of the same
1209                                       // degree -
1210  ideal Bmod;                          // basis of homogeneous invariants modulo
1211                                       // sP -
1212  ideal sSmod;                         // standard basis of Smod modulo sP
1213  setring br;
1214  matrix S[1][bound]=1;                // stores all secondary invariants
1215  if (v)
1216  { "  In degree 0 we have: 1";
1217    "";
1218  }
1219  int counter=1;                       // counts secondary invariants -
1220  d=1;                                 // the degree of homogeneous invariants
1221  int degcounter=0;                    // counts secondary invariants of degree
1222                                       // d -
1223  int bool=1;                          // decides when std needs to be computed
1224  while (counter<>bound)
1225  { if (v)
1226    { "  Searching in degree "+string(d)+"...";
1227    }
1228    if (d>#[size(#)])                  // we need to compute basis of degree d
1229    {                                  // in this case -
1230      if (#[r])                        // in this case, we have the Reynolds
1231      { ideal B(d)=inv_basis_rey(#[r-1],d); // operator
1232      }
1233      else
1234      { ideal B(d)=inv_basis(d,#[1..r-1]);
1235      }
1236    }
1237    if (B(d)[1]<>0)                    // we only need to look for secondary
1238    { setring Qring;                   // invariants in this degre if B is not
1239      Smod=0;                          // the zero ideal
1240      Bmod=fetch(br,B(d));
1241      for (i=1;i<=ncols(Bmod);i=i+1)
1242      { if (degcounter<>0)
1243        { if (reduce(Bmod[i],std(ideal(0)))<>0) // in this case B[i] might be
1244          {                            // qualify as secondary invariant -
1245            if (bool)                  // compute a standard basis only if a new
1246            { sSmod=std(Smod);         // secondary invariant has been found in
1247            }                          // the last run -
1248            if (reduce(Bmod[i],sSmod)<>0) // if Bmod[i] is not contained in Smod
1249            { counter=counter+1;       // B[i] qualifies as secondary invariant
1250              degcounter=degcounter+1;
1251              Smod[degcounter]=Bmod[i];
1252              setring br;
1253              S[1,counter]=B(d)[i];
1254              if (v)
1255              { "           "+string(B(d)[i]);
1256              }
1257              bool=1;                  // we have to compute std next time
1258              setring Qring;
1259              if (counter==bound)      // in this case, we're done
1260              { break;
1261              }
1262            }
1263            else                       // next time, we don't need to compute
1264            { bool=0;                  // standard basis
1265            }
1266          }
1267        }
1268        else
1269        { if (reduce(Bmod[i],std(ideal(0)))<>0)
1270          { Smod[1]=Bmod[i];           // here we just add Bmod[i] without
1271            setring br;                // having to check linear independence
1272            counter=counter+1;
1273            degcounter=degcounter+1;
1274            S[1,counter]=B(d)[i];
1275            if (v)
1276            { "  We find: "+string(B(d)[i]);
1277            }
1278            setring Qring;
1279            bool=1;                    // next time, we have to compute std
1280            if (counter==bound)
1281            { break;
1282            }
1283          }
1284        }
1285      }
1286    }
1287    if (v and degcounter<>0)
1288    { "";
1289    }
1290    degcounter=0;
1291    setring br;
1292    d=d+1;                             // go to next degree
1293  }
1294  if (v)
1295  { "  We're done!";
1296  }
1297  return(S);
1298}
1299
1300////////////////////////////////////////////////////////////////////////////////
1301// inv_ring_s calculates the primary and secondary invariants of the invariant
1302// ring with respect to a finite matrix group G. The primary invariants generate
1303// an invariant subring, lets say R, and the secondary invariants generate the
1304// invariant ring as an R-module. If the characteristic of the base field is
1305// zero or prime not dividing the group order, the secondary invariants are free
1306// generators and we have the Hironaka decomposition of the invariant ring.
1307// Otherwise the secondary invariants are possible not free generators.
1308// The procedure is based on the algorithms given by Sturmfels in "Algorithms
1309// in Invariant Theory" except for the one computing secondary invariants when
1310// the characteristic divides the group order which is based on Kemper's
1311// "Calculating Invariants Rings of Finite Groups over Arbitrary Fields".
1312////////////////////////////////////////////////////////////////////////////////
1313proc inv_ring_s (list #)
1314  USAGE:   inv_ring_s(<generators of a finite matrix group>[,<intvec>]);
1315           <intvec> has to contain 2 flags; if the first one equals 0, the
1316           program attempts to compute the Molien series and Reynolds operator,
1317           if it equals 1, the program is told that the characteristic of the
1318           base field divides the group order, if it is anything else the Molien
1319           series and Reynolds operator will not be computed; if the second flag
1320           does not equal 0, information about the various stages of the program
1321           will be printed while running
1322  RETURNS: generators of the invariant ring with respect to the matrix group
1323           generated by the matrices in the input; there are two return values
1324           of type <matrix>, the first containing primary invariants and the
1325           second secondary invariants, i.e. module generators over a Noetherian
1326           normalization
1327  EXAMPLE: example inv_ring_s; shows an example
1328{ def br=basering;
1329  int ch=char(br);                     // the algorithms depend very much on the
1330                                       // characteristic of the ground field
1331  int dB=degBound;
1332  degBound=0;
1333  int n=nvars(br);                     // n is the number of variables, as well
1334                                       // as the size of the matrices, as well
1335                                       // as the number of primary invariants,
1336                                       // we have to find
1337  if (typeof(#[size(#)])=="intvec")
1338  { if (size(#[size(#)])<>2)
1339    { "  ERROR:   <intvec> must have exactly two entires";
1340      return();
1341    }
1342    intvec flagvec=#[size(#)];
1343    if (flagvec[1]==0)
1344    { if (ch==0)
1345      { matrix R(1..2);                // one will contain Reynolds operator and
1346                                       // the other enumerator and denominator
1347                                       // of Molien series
1348        R(1..2)=rey_mol(#[1..size(#)-1],flagvec[2]);
1349      }
1350      else
1351      { string newring="Qa";
1352        matrix R(1)=rey_mol(#[1..size(#)-1],newring,flagvec[2]); // will contain
1353                                       // Reynolds operator, if Molien series
1354      }                                // can be computed, it will be stored in
1355                                       // the new ring Qa
1356    }
1357    else
1358    { for (int i=1;i<=size(#)-1;i=i+1) // checking whether the input is ok
1359      { if (not(typeof(#[i])=="matrix"))
1360        { "  ERROR:   the parameters must be a list of matrices and optionally";
1361          "           an <intvec>";
1362          return();
1363        }
1364        if (n<>ncols(#[i]) || n<>nrows(#[i]))
1365        { "  ERROR:   matrices need to be square and of the same dimensions as";
1366          "           the number of variables of the basering";
1367          return();
1368        }
1369      }
1370      kill i;
1371    }
1372  }
1373  else
1374  { if (typeof(#[size(#)])<>"matrix")
1375    { "  ERROR:   the parameters must be a list of matrices and optionally";
1376      "           an <intvec>";
1377      return();
1378    }
1379    if (ch==0)
1380    { matrix R(1..2);                  // will contain Reynolds operator and
1381                                       // enumerator and denominator of Molien
1382                                       // series
1383      R(1..2)=rey_mol(#[1..size(#)]);
1384    }
1385    else
1386    { string newring="Qa";             // we might need as a new ring of
1387                                       // characteristic 0 where we store the
1388                                       // Molien series -
1389      matrix R(1)=rey_mol(#[1..size(#)],newring); // will contain
1390                                       // Reynolds operator
1391    }
1392    intvec flagvec=0,0;                // default flags, no info
1393  }
1394  ideal Q=0;                           // will contain the candidates for
1395                                       // primary invariants -
1396  if (flagvec[1]==0 && flagvec[2])
1397  { "  We can start looking for primary invariants...";
1398    "";
1399  }
1400  else
1401  { if (flagvec[1] && flagvec[2])
1402    { "";
1403      "  We start by looking for primary invariants...";
1404      "";
1405    }
1406  }
1407  if ((ch==0 || defined(Qa)) && flagvec[1]==0) // i.e. we can use Molien series
1408  { if (ch==0)
1409    { poly p(1..2);                    // p(1) will be used for single terms of
1410                                       // the partial expansion, p(2) to store
1411      p(1..2)=part_mol(R(2),1);        // the intermediate result -
1412      poly v1=var(1);                  // we need v1 to split off coefficients
1413                                       // in the partial expansion of M (which
1414                                       // is in terms of the first variable) -
1415      poly d;                          // for splitting off the coefficient in
1416                                       // in one term of the partial expansion,
1417                                       // i.e. it stores the dimension of the
1418                                       // current homogeneous subspace
1419    }
1420    else
1421    { setring Qa;                      // Qa is where the Molien series is
1422                                       // stored -
1423      poly p(1..2);                    // p(1) will be used for single terms of
1424                                       // the partial expansion, p(2) to store
1425      p(1..2)=part_mol(M,1);           // the intermediate result -
1426      poly d;                          // stores the dimension of the current
1427                                       // homogeneous subspace
1428      setring br;
1429    }
1430    int g, di, counter, i, j, bool;    // g: current degree, di: d as integer,
1431                                       // counter: counts candidates in degree
1432                                       // g, i,j: going through monomials of
1433                                       // degree g, bool: indicating when the
1434                                       // ideal generated by the candidates
1435                                       // has dimension 0 -
1436    ideal mon;                         // will contain monomials of degree g -
1437    poly imRO;                         // the image of the Reynolds operator -
1438    while(1)                           // repeat until we reach dimension 0
1439    { if (ch==0)
1440      { p(1..2)=part_mol(R(2),1,p(2)); // 1 term of the partial expansion -
1441        g=deg(p(1));                   // current degree -
1442        d=coef(p(1),v1)[2,1];          // dimension of invariant space of degree
1443                                       // g -
1444        di=int(d);                     // just a type cast
1445      }
1446      else
1447      { setring Qa;
1448        p(1..2)=part_mol(M,1,p(2));    // 1 term of the partial expansion -
1449        g=deg(p(1));                   // current degree -
1450        d=coef(p(1),x)[2,1];           // dimension of invariant space of degree
1451                                       // g -
1452        di=int(d);                     // just a type cast
1453        setring br;
1454      }
1455      if (flagvec[2])
1456      { "  Searching for candidates in degree "+string(g)+":";
1457        "  There is/are "+string(di)+" linearly independent invariant(s) to choose from...";
1458      }
1459      mon=sort(maxideal(g))[1];        // all monomials of degree g -
1460      j=ncols(mon);
1461      counter=0;                       // we have 0 candidates of degree g so
1462                                       // far
1463      for (i=j;i>=1;i=i-1)
1464      { imRO=eval_rey(R(1),mon[i]);
1465        if (imRO<>0)
1466        { if (Q[1]==0)                 // if imRO is the first non-zero
1467          { counter=1;                 // invariant we find, the rad_con
1468            Q[1]=imRO/leadcoef(imRO);  // question is trivial and we just
1469            if (flagvec[2])            // include imRO
1470            { "  Found: "+string(Q[1]);
1471            }
1472            if (counter==di)           // if counter is up to di==d, we can
1473            { break;                   // leave the for-loop
1474            }
1475          }
1476          else
1477          { if (not(rad_con(imRO,Q)))  // if imRO is not contained in the
1478            { counter=counter+1;       // radical of Q, we add it to the
1479              Q=Q,imRO/leadcoef(imRO); // generators of Q
1480              if (flagvec[2])
1481              { "  Found: "+string(Q[ncols(Q)]);
1482              }
1483            }
1484              if (ncols(Q)>=n)         // when we have n or more candidates, we
1485              { attrib(Q,"isSB",1);    // test if dim(Q)==0, Singular might
1486              if (dim(Q)==0)           // recognize this property even if Q is
1487              { bool=1;                // no standard basis, but that is not
1488                break;                 // guaranteed -
1489              }                        // if dim(Q) is 0, we can construct a
1490              else                     // set of primary invariants from the
1491              { if (dim(std(Q))==0)    // generators of Q and we can leave both
1492                { bool=1;              // the for- and the while-loop
1493                  break;
1494                }
1495              }
1496              }
1497            if (counter==di)           // if counter is up to di, we can leave
1498            { break;                   // the for-loop
1499            }
1500          }
1501        }
1502      }
1503      if (n==1 or bool)                // if n=1, we're done when we've found
1504      { break;                         // the first
1505      }
1506    }
1507    if (flagvec[2])
1508    { "";
1509    }
1510    int m=ncols(Q);                    // m tells us if we found too many
1511                                       // candidates -
1512    ideal P=Q;                         // will eventually contain the primary
1513                                       // invariants -
1514    if (n<m)                           // the number of primary invariants
1515    { counter=m;                       // should be the same as the number of
1516      for (i=m-1;i>=1;i=i-1)           // variables in the basering; we are
1517      {                                // checking whether we can leave out some
1518        Q[i]=0;                        // candidates and still have full
1519                                       // radical -
1520        attrib(Q,"isSB",1);
1521        if (dim(Q)==0)                 // we're going backwards through the
1522        { P[i]=0;                      // candidates to throw out large degrees
1523          counter=counter-1;
1524        }
1525        else
1526        { if (dim(std(Q))==0)
1527          { P[i]=0;
1528            counter=counter-1;
1529          }
1530        }
1531        if (counter==n)
1532        { break;
1533        }
1534        Q=P;
1535      }
1536      P=compress(P);
1537      m=counter;
1538      if (m==n)
1539      { Q=std(P);                      // standard basis for computing secondary
1540                                       // invariants
1541      }
1542    }
1543    else                               // we need the standard basis of P to be
1544    { Q=std(P);                        // able to do calculations modulo primary
1545    }                                  // invariants
1546    intvec degvec;
1547    if (n<m)
1548    { if (flagvec[2] and ch==0)
1549      { "  We have too many candidates for primary invariants and have to find a";
1550        "  Noetherian normalization.";
1551        "";
1552      }
1553      if (ch<>0)
1554      { "  We have too many candidates for primary invariants and have to attempt";
1555        "  to construct a Noetherian normalization as linear combinations of powers";
1556        "  of the candidates. Careful! Termination is not guaranteed!";
1557        "";
1558      }
1559      P,p(1)=noethernorm(P);           // p(1) is the denominator of the Hilbert
1560                                       // series with respect to primary
1561                                       // invariants from P -
1562      Q=std(P);                        // we need to do calculations modulo
1563                                       // primary invariants -
1564      for (j=1;j<=n;j=j+1)             // we set the leading coefficients of the
1565      { P[j]=P[j]/leadcoef(P[j]);      // primary invariants to 1
1566      }
1567    }
1568    else                               // this is when m==n without Noetherian
1569    {                                  // normalization
1570      if (ch==0)
1571      { p(1)=1;
1572        for (j=1;j<=n;j=j+1)           // calculating the denominator of the
1573        { p(1)=p(1)*(1-v1^deg(P[j]));  // Hilbert series of the ring generated
1574        }                              // by the primary invariants
1575      }
1576      else
1577      { for (j=1;j<=n;j=j+1)           // degrees have to be taken in a ring
1578        { degvec[j]=deg(P[j]);         // of characteristic 0
1579          }
1580        setring Qa;
1581        p(1)=1;
1582          for (j=1;j<=n;j=j+1)         // calculating the denominator of the
1583          { p(1)=p(1)*(1-x^degvec[j]); // Hilbert series of the ring
1584          }                            // generated by the primary invariants
1585          setring br;
1586      }
1587    }
1588    if (flagvec[2])
1589    { "  These are the primary invariants: ";
1590      for (i=1;i<=n;i=i+1)
1591      { "   "+string(P[i]);
1592      }
1593      "";
1594    }
1595    if (ch==0)
1596    { matrix s[1][2]=R(2)[1,1]*p(1),R(2)[1,2]; // used for canceling
1597      s=matrix(syz(ideal(s)));
1598      p(1)=s[2,1];                     // the polynomial telling us where to
1599                                       // search for secondary invariants
1600      map slead=br,ideal(0);
1601      p(1)=1/slead(p(1))*p(1);         // smallest term of p(1) needs to be 1
1602      if (flagvec[2])
1603      { "  Polynomial telling us where to look for secondary invariants:";
1604        "   "+string(p(1));
1605        "";
1606      }
1607      matrix dimmat=coeffs(p(1),v1);   // dimmat will contain the number of
1608                                       // secondary invariants, we need to find
1609                                       // of a certain degree -
1610      m=nrows(dimmat);                 // m-1 is the highest degree
1611      degvec=0;
1612      for (j=1;j<=m;j=j+1)
1613      { if (dimmat[j,1]<>0)
1614        { degvec[j]=int(dimmat[j,1]);  // degvec contains the degrees of
1615        }                              // secondary invariants
1616      }
1617    }
1618    else
1619    { setring Qa;
1620      matrix s[1][2]=M[1,1]*p(1),M[1,2]; // used for canceling
1621      s=matrix(syz(ideal(s)));
1622      p(1)=s[2,1];                     // the polynomial telling us where to
1623                                       // search for secondary invariants
1624      map slead=Qa,ideal(0);
1625      p(1)=1/slead(p(1))*p(1);         // smallest term of p(1) needs to be 1
1626      if (flagvec[2])
1627      { "  Polynomial telling us where to look for secondary invariants:";
1628        "   "+string(p(1));
1629        "";
1630      }
1631      matrix dimmat=coeffs(p(1),x);    // dimmat will contain the number
1632                                       // of secondary invariants, we need
1633                                       // to find of a certain degree -
1634      m=nrows(dimmat);                 // m-1 is the highest
1635      degvec=0;
1636      for (j=1;j<=m;j=j+1)
1637      { if (dimmat[j,1]<>0)
1638        { degvec[j]=int(dimmat[j,1]);  // degvec[j] contains the number of
1639        }                              // secondary invariants of degree j-1
1640      }
1641      setring br;
1642      kill Qa;                         // all the information needed from Qa is
1643    }                                  // stored in dimmat -
1644    qring Qring=Q;                     // we need to do calculations modulo the
1645                                       // ideal generated by the primary
1646                                       // invariants, its standard basis is
1647                                       // stored in Q -
1648    poly imROmod;                      // imRO reduced -
1649    ideal Smod, sSmod;                 // secondary invariants of one degree
1650                                       // reduced and their standard basis
1651    setring br;
1652    kill Q;                            // Q might be big and isn't needed
1653                                       // anymore -
1654    ideal S=1;                         // secondary invariants, 1 definitely is
1655                                       // one
1656    if (flagvec[2])
1657    { "  Proceeding to look for secondary invariants...";
1658      "";
1659      "  In degree 0 we have: 1";
1660      "";
1661    }
1662    bool=0;                            // indicates when std-calculation is
1663                                       // necessary -
1664    for (i=2;i<=m;i=i+1)               // walking through degvec -
1665    { if (degvec[i]<>0)                // when it is == 0 we need to find 0
1666      {                                // elements of the degree i-1
1667        if (flagvec[2])
1668        { "  Searching in degree "+string(i-1)+", we need to find "+string(degvec[i])+" invariant(s)...";
1669        }
1670        mon=sort(maxideal(i-1))[1];    // all monomials of degree i-1 -
1671        counter=0;                     // we'll count up to degvec[i] -
1672        j=ncols(mon);                  // we'll go through mon from the end
1673        setring Qring;
1674        Smod=0;
1675        setring br;
1676        while (degvec[i]<>counter)     // we need to find degvec[i] linearly
1677        {                              // independent (in Qring) invariants -
1678          imRO=eval_rey(R(1),mon[j]);  // generating invariants
1679          setring Qring;
1680          imROmod=fetch(br,imRO);      // reducing the invariants
1681          if (reduce(imROmod,std(ideal(0)))<>poly(0) and counter<>0)
1682          {                            // if the first one is true and the
1683                                       // second false, imRO is the first
1684                                       // secondary invariant of that degree
1685                                       // that we want to add and we need not
1686                                       // check linear independence
1687            if (bool)
1688            { sSmod=std(Smod);
1689            }
1690            if (reduce(imROmod,sSmod)<>0)
1691            { Smod=Smod,imROmod;
1692              setring br;              // we make its leading coefficient to be
1693              imRO=imRO/leadcoef(imRO); // 1
1694              S=S,imRO;
1695              counter=counter+1;
1696              if (flagvec[2])
1697              { "           "+string(imRO);
1698              }
1699              bool=1;                  // next time we need to recalculate std
1700            }
1701            else
1702            { bool=0;                  // std-calculation is unnecessary
1703              setring br;
1704            }
1705          }
1706          else
1707          { if (reduce(imROmod,std(ideal(0)))<>poly(0) and counter==0)
1708            { Smod[1]=imROmod;         // here we just add imRO(mod) without
1709              setring br;              // having to check linear independence
1710              imRO=imRO/leadcoef(imRO);
1711              S=S,imRO;
1712              counter=counter+1;
1713              bool=1;                  // next time we need to calculate std
1714              if (flagvec[2])
1715              { "  We find: "+string(imRO);
1716              }
1717            }
1718            else
1719            { setring br;
1720            }
1721          }
1722          j=j-1;                       // going to next monomial
1723        }
1724        if (flagvec[2])
1725        { "";
1726        }
1727      }
1728    }
1729    degBound=dB;
1730    if (flagvec[2])
1731    { "  We're done!";
1732      "";
1733    }
1734    matrix FI(1)=matrix(P);
1735    matrix FI(2)=matrix(S);
1736    return(FI(1..2));
1737  }
1738                                       // this case is entered when either the
1739                                       // characteristic<>0 divides the group
1740                                       // order or when the Molien series could
1741                                       // not or has not been computed -
1742  if (flagvec[1]==0)                   // indicates that it has been attempted
1743  {                                    // to compute the Reynolds operator
1744                                       // etc. -
1745    int g=nrows(R(1));                 // order of the group -
1746    int flag=((g%ch)==0);              // flag is 1 if the characteristic
1747                                       // divides the order, it is 0 if it does
1748                                       // not -
1749    if (typeof(#[size(#)])=="intvec")  // getting a hold of the generators of
1750    { int gennum=size(#)-1;            // the group
1751    }
1752    else
1753    { int gennum=size(#);
1754    }
1755  }
1756  else
1757  { int flag=2;                        // flag is 2 if we don't know yet whether
1758    int gennum=size(#)-1;              // the group order is divisible by the
1759  }                                    // characteristic -
1760  int d=1;                             // d is set to the current degree, since
1761                                       // we know nothing about the finite
1762                                       // matrix group (via Molien series) we
1763                                       // have to start with degree 1 -
1764  int counter;                         // counts candidates for primary
1765                                       // invariants -
1766  int i, di, bool;
1767  while (1)
1768  { if (flagvec[2])
1769    { "  Searching for candidates in degree "+string(d)+":";
1770    }
1771    if (flag)                          // in this case we can not make use of
1772    {                                  // the Reynolds operator -
1773      ideal B(d)=inv_basis(d,#[1..gennum]); // we create a basis of the vector
1774                                       // space of all invariant polynomials of
1775    }                                  // degree d
1776    else
1777    {                                  // here the characteristic<>0 does not
1778      ideal B(d)=inv_basis_rey(R(1),d); // divide the group order, i.e. the
1779    }                                  // Reynolds operator can be used to
1780                                       // calculate a basis of the vector space
1781                                       // of all invariant polynomials of degree
1782                                       // d -
1783    di=ncols(B(d));                    // dimension of the homogeneous space -
1784    if (B(d)[1]<>0)                    // otherwise the space is empty
1785    { if (flagvec[2])
1786      { "  There is/are "+string(di)+" linearly independent invariant(s) to choose from...";
1787      }
1788      if (counter==0)                  // we have no candidates for primary
1789      {                                // invariants yet, i.e. don't have to
1790        Q[1]=B(d)[1];                  // check for radical containment
1791        if (flagvec[2])
1792        { "  Found: "+string(Q[1]);
1793        }
1794        i=2;                           // proceed with the second element of
1795        counter=1;                     // B(d)
1796        if (n==1)
1797        { break;
1798        }
1799      }
1800      else
1801      { i=1;                           // proceed with the first element of B(d)
1802      }
1803      while (i<=di)                    // goes through all polynomials in B(d) -
1804      { if (not(rad_con(B(d)[i],Q)))   // B(d)[i] is not in the radical of Q
1805        { counter=counter+1;
1806          Q=Q,B(d)[i];                 // including candidate
1807          if (flagvec[2])
1808          { "  Found: "+string(Q[counter]);
1809          }
1810          if (counter>=n)
1811          { attrib(Q,"isSB",1);
1812            if (dim(Q)==0)
1813            { bool=1;                  // when the dimension is 0, we're done
1814              break;                   // but this can only be when counter>=n
1815            }
1816            else
1817            { if (dim(std(Q))==0)
1818              { bool=1;                // bool indicates whether we are done
1819                break;
1820              }
1821            }
1822          }
1823        }
1824        i=i+1;                         // going to next element in basis
1825      }
1826      if (bool)
1827      { break;
1828      }
1829    }
1830    else
1831    { if (flagvec[2])
1832      { "  The space is 0-dimensional.";
1833      }
1834    }
1835    d=d+1;                             // up to the next degree
1836  }
1837  if (flagvec[2])
1838  { "";
1839  }
1840  int j;
1841  ideal P=Q;                           // P will contain primary invariants -
1842  if (n<counter)                       // we have too many candidates -
1843  { for (i=counter-1;i>=1;i=i-1)       // we take a look whether we can leave
1844    { Q[i]=0;                          // out some candidates, but have full
1845                                       // radical
1846      attrib(Q,"isSB",1);
1847      if (dim(Q)==0)                   // we're going backwards through the
1848      { P[i]=0;                        // candidates to throw out large degrees
1849        counter=counter-1;
1850      }
1851      else
1852      { if (dim(std(Q))==0)
1853        { P[i]=0;
1854          counter=counter-1;
1855        }
1856      }
1857      if (counter==n)
1858      { break;
1859      }
1860      Q=P;
1861    }
1862    P=compress(P);
1863    if (counter==n)
1864    { Q=std(P);
1865    }
1866  }
1867  else
1868  { Q=std(P);                          // we need to do calculations modulo
1869  }                                    // primary invariants
1870  if (n<counter)
1871  { if (flagvec[2] and ch==0)
1872    { "  We have too many candidates for primary invariants and have to find a";
1873      "  Noetherian normalization.";
1874      "";
1875    }
1876    if (ch<>0)
1877    { "  We have too many candidates for primary invariants and have to attempt";
1878      "  to construct a Noetherian normalization as linear combinations of powers";
1879      "  of the candidates. Careful! Termination is not guaranteed!";
1880      "";
1881    }
1882    P=noethernorm(P);
1883    for (j=1;j<=n;j=j+1)               // we set the lead coefficients of the
1884    { P[j]=P[j]/leadcoef(P[j]);        // primary invariants to be 1
1885    }
1886    Q=std(P);
1887  }
1888  if (flagvec[2])
1889  { "  These are the primary invariants: ";
1890    for (i=1;i<=n;i=i+1)
1891    { "   "+string(P[i]);
1892    }
1893    "";
1894    "  Proceeding to look for secondary invariants...";
1895  }
1896  // we can now proceed to calculate secondary invariants, we face the fact
1897  // that we can make no use of a Molien series - however, if the
1898  // characteristic does not divide the group order, we can make use of the
1899  // fact that the secondary invariants are free module generators and that we
1900  // need deg(P[1])*...*deg(P[n])/(cardinality of the group) of them
1901  if (flagvec[1]<>0 and flagvec[1]<>1)
1902  { int g=group(#[1..size(#)-1]);      // computing group order
1903    if (ch==0)
1904    { matrix FI(2)=sec_minus_mol(P,Q,g,flagvec[2],#[1..size(#)-1],0,B(1..d),d);
1905      matrix FI(1)=matrix(P);
1906      return(FI(1..2));
1907    }
1908    if (g%ch<>0)
1909    { matrix FI(2)=sec_minus_mol(P,Q,g,flagvec[2],#[1..size(#)-1],0,B(1..d),d);
1910      matrix FI(1)=matrix(P);
1911      return(FI(1..2));
1912    }
1913  }
1914  else
1915  { if (flag==0)                       // this is the case where we have a
1916    {                                  // nonzero minpoly, but the
1917                                       // characteristic does not divide the
1918                                       // group order
1919      matrix FI(2)=sec_minus_mol(P,Q,g,flagvec[2],R(1),1,B(1..d),d);
1920      matrix FI(1)=matrix(P);
1921      return(FI(1..2));
1922    }
1923  }
1924  if (flagvec[2])
1925  { "  Since the characteristic of the base field divides the group order, we do not";
1926    "  know whether the invariant ring is Cohen-Macaulay. We have to use Kemper's";
1927    "  algorithm and compute secondary invariants with respect to the trivial";
1928    "  subgroup of the given group.";
1929    "";
1930
1931  }
1932  // we are using Kemper's algorithm with the trivial subgroup
1933  ring QQ=0,x,ds;                      // we lock at our primary invariants as
1934  ideal M=(1-x)^n;                     // such of the subgroup that only
1935                                       // contains the identity, this means that
1936                                       // ch does not divide the order anymore,
1937                                       // this means that we can make use of the
1938                                       // Molien series again - 1/M[1] is the
1939                                       // Molien series of that group, we now
1940                                       // calculate the secondary invariants of
1941                                       // this subgroup in the usual fashion
1942                                       // where the primary invariants are the
1943                                       // ones from the bigger group
1944  setring br;
1945  intvec degvec;                       // for the degrees of the primary
1946                                       // invariants -
1947  for (i=1;i<=n;i=i+1)                 // finding the degrees of these
1948  { degvec[i]=deg(P[i]);
1949  }
1950  setring QQ;                          // calculating the polynomial indicating
1951  M[2]=1;                              // where to search for secondary
1952  for (i=1;i<=n;i=i+1)                 // invariants (of the trivial subgroup)
1953  { M[2]=M[2]*(1-x^degvec[i]);
1954  }
1955  M=matrix(syz(M))[1,1];
1956  M[1]=M[1]/leadcoef(M[1]);
1957  if (flagvec[2])
1958  { "  Polynomial telling us where to look for these secondary invariants:";
1959    "   "+string(M[1]);
1960    "";
1961  }
1962  matrix dimmat=coeffs(M[1],x);        // storing the number of secondary
1963                                       // invariants we need in a certain
1964                                       // degree -
1965  int m=nrows(dimmat);                 // m-1 is the highest degree where we
1966                                       // need to search
1967  degvec=0;
1968  for (i=1;i<=m;i=i+1)                 // degvec will contain all the
1969  { if (dimmat[i,1]<>0)                // information about where to find
1970    { degvec[i]=int(dimmat[i,1]);      // secondary invariants, it is filled
1971    }                                  // with integers and therefore visible in
1972  }                                    // all rings
1973  kill QQ;
1974  setring br;
1975  ideal S=1;                           // 1 is a secondary invariant always -
1976  if (flagvec[2])
1977  { "  In degree 0 we have: 1";
1978    "";
1979  }
1980  ideal B;                             // basis of homogeneous invariants of a
1981                                       // certain degree with respect to the
1982                                       // trivial subgroup - i.e. all monomials
1983                                       // of that degree -
1984  qring Qring=Q;                       // need to do computations modulo primary
1985                                       // invariants -
1986  ideal Smod, sSmod, Bmod;             // Smod: secondary invariants of one
1987                                       // degree modulo Q, sSmod: standard basis
1988                                       // of the latter, Bmod: B modulo Q
1989  setring br;
1990  kill Q;                              // might be large
1991  int k;
1992  bool=0;                              // indicates when we need to do standard
1993                                       // basis computation -
1994  for (i=2;i<=m;i=i+1)                 // going through all entries of degvec
1995  { if (degvec[i]<>0)
1996    { B=sort(maxideal(i-1))[1];        // basis of the space of invariants (with
1997                                       // respect to the matrix subgroup
1998                                       // containing only the identity) of
1999                                       // degree i-1 -
2000      if (flagvec[2])
2001      { "  Searching in degree "+string(i-1)+", we need to find "+string(degvec[i])+" invariant(s)...";
2002      }
2003      counter=0;                       // we have 0 secondary invariants of
2004                                       // degree i-1
2005      setring Qring;
2006      Bmod=fetch(br,B);                // basis modulo primary invariants
2007      Smod=0;
2008      j=ncols(Bmod);                   // going backwards through Bmod
2009      while (degvec[i]<>counter)
2010      { if (reduce(Bmod[j],std(ideal(0)))<>0 && counter<>0)
2011        { if (bool)
2012          { sSmod=std(Smod);
2013          }
2014          if (reduce(Bmod[j],sSmod)<>0) // Bmod[j] qualifies as secondary
2015          { Smod=Smod,Bmod[j];         // invariant
2016            setring br;
2017            S=S,B[j];
2018            counter=counter+1;
2019            if (flagvec[2])
2020            { "           "+string(B[j]);
2021            }
2022            setring Qring;
2023            bool=1;                    // need to calculate std of Smod next
2024          }                            // time
2025          else
2026          { bool=0;                    // no std calculation necessary
2027          }
2028        }
2029        else
2030        { if (reduce(Bmod[j],std(ideal(0)))<>0 && counter==0)
2031          { Smod[1]=Bmod[j];           // in this case, we may just add B[j]
2032            setring br;
2033            S=S,B[j];
2034            if (flagvec[2])
2035            { "  We find: "+string(B[j]);
2036            }
2037            counter=counter+1;
2038            bool=1;                    // need to calculate std of Smod next
2039            setring Qring;             // time
2040          }
2041        }
2042        j=j-1;                         // next basis element
2043      }
2044      setring br;
2045    }
2046  }
2047  // now we have those secondary invariants
2048  k=ncols(S);                          // k: number of the secondary invariants,
2049                                       // we just calculated
2050  if (flagvec[2])
2051  { "";
2052    "  We calculate secondary invariants from the ones found for the trivial";
2053    "  subgroup.";
2054    "";
2055  }
2056  map f;                               // used to let generators act on
2057                                       // secondary invariants with respect to
2058                                       // the trivial group -
2059  matrix M(1)[gennum][k];              // M(1) will contain a module
2060  for (i=1;i<=gennum;i=i+1)
2061  { B=ideal(matrix(maxideal(1))*transpose(#[i])); // image of the various
2062                                       // variables under the i-th generator -
2063    f=br,B;                            // the corresponding mapping -
2064    B=f(S)-S;                          // these relations should be 0 -
2065    M(1)[i,1..k]=B[1..k];              // we will look for the syzygies of M(1)
2066  }
2067  module M(2)=res(M(1),2)[2];
2068  m=ncols(M(2));                       // number of generators of the module
2069                                       // M(2) -
2070  // the following steps calculates the intersection of the module M(2) with the
2071  // algebra A^k where A denote the subalgebra of the usual polynomial ring,
2072  // generated by the primary invariants
2073  string mp=string(minpoly);           // generating a ring where we can do
2074                                       // elimination
2075  execute "ring R=("+charstr(br)+"),(x(1..n),y(1..n),h),dp";
2076  execute "minpoly=number("+mp+");";
2077  map f=br,maxideal(1);                // canonical mapping
2078  matrix M[k][m+k*n];
2079  M[1..k,1..m]=matrix(f(M(2)));        // will contain a module -
2080  ideal P=f(P);                        // primary invariants in the new ring -
2081  for (i=1;i<=n;i=i+1)                 // constructing a module
2082  { for (j=1;j<=k;j=j+1)
2083    { M[j,m+(i-1)*k+j]=y(i)-P[i];
2084    }
2085  }
2086  M=elim(module(M),1,n);               // eliminating x(1..n), std-calculation
2087                                       // is done internally
2088  M=homog(module(M),h);                // homogenize for 'minbase'
2089  M=minbase(module(M));
2090  setring br;
2091  //execute "ideal v="+varstr(br)+",P,1"; // dehomogenizing -
2092  ideal v=maxideal(1),P,1;
2093  f=R,v;                               // replacing y(1..n) by primary
2094                                       // invariants -
2095  M(2)=f(M);                           // M(2) is the new module -
2096  matrix FI(1)=matrix(P);              // getting primary invariants ready for
2097                                       // output
2098  m=ncols(M(2));
2099  matrix FI(2)[1][m];
2100  FI(2)=matrix(S)*matrix(M(2));        // FI(2) contains the real secondary
2101                                       // invariants
2102  for (i=1; i<=m;i=i+1)
2103  { FI(2)[1,i]=FI(2)[1,i]/leadcoef(FI(2)[1,i]); // making elements nice
2104  }
2105  FI(2)=sort(ideal(FI(2)))[1];
2106  if (flagvec[2])
2107  { "  These are the secondary invariants: ";
2108    for (i=1;i<=m;i=i+1)
2109    { "   "+string(FI(2)[1,i]);
2110    }
2111    "";
2112    "  We're done!";
2113    "";
2114  }
2115  if ((flagvec[2] or (voice==2)) && flagvec[1]==1 && (m>1))
2116  { "  WARNING: The invariant ring might not have a Hironaka decomposition";
2117    "           if the characteristic of the coefficient field divides the";
2118    "           group order.";
2119  }
2120  else
2121  { if ((flagvec[2] or (voice==2)) and (m>1))
2122    { "  WARNING: The invariant ring might not have a Hironaka decomposition!";
2123      "           This is because the characteristic of the coefficient field";
2124      "           divides the group order.";
2125    }
2126  }
2127  degBound=dB;
2128  return(FI(1..2));
2129}
2130example
2131{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
2132  echo=2;
2133           ring R=0,(x,y,z),dp;
2134           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2135           matrix B(1..2);
2136           B(1..2)=inv_ring_s(A);
2137           print(B(1..2));
2138}
2139
2140////////////////////////////////////////////////////////////////////////////////
2141// This procedure finds a linear combination of the generators in B such that it
2142// lowers the dimension of the ideal generated by the primary invariants found
2143// so far when added to the ideal. The coefficients lie in a field of
2144// characteristic 0.
2145////////////////////////////////////////////////////////////////////////////////
2146proc combi (ideal B,int b,ideal P,int d)
2147{
2148  intmat vec[1][b];                    // the zero vector -
2149  matrix t[1][1];                      // the linear combination
2150  while(1)
2151  { vec=nextvec(vec);                  // next vector
2152    t=vec*transpose(matrix(B));
2153    if (d-1==dim(std(P+ideal(t[1,1])))) // indicates that it was not necessary
2154    { return(t[1,1]);                  // to break out of the for-loop
2155    }
2156  }
2157}
2158
2159////////////////////////////////////////////////////////////////////////////////
2160// This procedure trys to find a linear combination of the generators in B such
2161// that it lowers the dimension of the ideal generated by the primary invariants
2162// found so far when added to the ideal. The coefficients lie in a finite field.
2163// It is not clear whether such a combination exists. In the worst case, all
2164// possibilities are tried.
2165////////////////////////////////////////////////////////////////////////////////
2166proc p_combi (ideal B, int b, ideal P, int di)
2167{ def br=basering;
2168  matrix vec(1)[1][b];                 // starting with 0-vector -
2169  intmat new[1][b];                    // new vector in characteristic 0 -
2170  matrix pnew[1][b];                   // new needs to be mapped into br -
2171  int counter=1;                       // we count how many vectors we try
2172  int i;
2173  int p=char(br);
2174  if (minpoly<>0)
2175  { int d=pardeg(minpoly);             // field has p^d elements
2176  }
2177  else
2178  { int d=1;                           // field has p^d elements
2179  }
2180  matrix t[1][1];                      // the linear combination
2181  ring R=0,x,dp;
2182  int bound=int((number(p)^(d*b)-1)/(number(p)^d-1)+1); // this is how many
2183                                       // linearly independent vectors of size
2184                                       // b exist having entries in the base
2185                                       // field of br
2186  setring br;
2187  while (counter<>bound)               // otherwise, we are done
2188  { new=nextvec(new);
2189    for (i=1;i<=b;i=i+1)
2190    { pnew[1,i]=intnumap(new[1,i]);    // mapping an integer into br
2191    }
2192    if (unique(vec(1..counter),pnew))  // checking whether we tried pnew before
2193    { counter=counter+1;
2194      matrix vec(counter)=pnew;        // keeping track of the ones we tried -
2195      t=vec(counter)*transpose(matrix(B)); // linear combination -
2196      if (di-1==dim(std(P+ideal(t[1,1])))) // indicates that it was not
2197      { return(t[1,1]);                // necessary to break out of the for-loop
2198      }
2199    }
2200  }
2201  return(0);
2202}
2203
2204////////////////////////////////////////////////////////////////////////////////
2205// Finds out whether any basis element of the space of homogenous invariants of
2206// degree g (of dimension di) is not contained in the radical of P (of the ideal
2207// generated by the primary invariants found so far). It uses the Reynolds
2208// operator. It is used to indicate when we need to check whether nontrivial
2209// linear combinations of basis elements exists that lower the dimension of P
2210// when added.
2211////////////////////////////////////////////////////////////////////////////////
2212proc search (matrix RO, ideal P, int g, int di)
2213{ ideal B=inv_basis_rey(RO,g,di);      // basis of homogeneous invariants of
2214                                       // degree g
2215  int mdi=ncols(B);
2216  int bool=0;
2217  for (int i=1;i<=mdi;i=i+1)
2218  { if (not(rad_con(B[i],P)))          // indicating that we need to try and
2219    { bool=1;                          // find a linear combination of basis
2220    }                                  // elements in B
2221    else
2222    { B[i]=0;                          // getting rid of the ones that are fully
2223    }                                  // contained in the radical anyway
2224  }
2225  return(bool,compress(B));            // recycle B
2226}
2227
2228////////////////////////////////////////////////////////////////////////////////
2229// Finds out whether any generator in B of some space of homogenous invariants
2230// is not contained in the radical of P (of the ideal generated by the primary
2231// invariants found so far). It is used to indicate when we need to check
2232// whether nontrivial linear combinations of basis elements exists that lower
2233// the dimension of P when added.
2234////////////////////////////////////////////////////////////////////////////////
2235proc searchalt (ideal B, ideal P)
2236{ int mdi=ncols(B);
2237  int bool=0;
2238  for (int i=1;i<=mdi;i=i+1)
2239  { if (not(rad_con(B[i],P)))          // indicating that we need to try and
2240    { bool=1;                          // find a linear combination of basis
2241    }                                  // elements in B
2242    else
2243    { B[i]=0;                          // getting rid of the ones that are fully
2244    }                                  // contained in the radical anyway
2245  }
2246  return(bool,compress(B));
2247}
2248
2249////////////////////////////////////////////////////////////////////////////////
2250// 'inv_ring_k' and 'inv_ring_s' only differ in the way they are calculating the
2251// primary invariants. 'inv_ring_k' tries to find a set of primary invariants of
2252// possibly low degree. It does this by checking whether there is a linear
2253// combination of basis elements of a space of homogeneous invariants in a
2254// certain degree, such that the dimension of the variety generated by the
2255// primary invariant falls each time a new primary invariant is added. And this
2256// way we are done looking for primary invariants precisely when n (the number
2257// of variables of the basering) invariants are generated.
2258////////////////////////////////////////////////////////////////////////////////
2259proc inv_ring_k (list #)
2260  USAGE:   inv_ring_k(<generators of a finite matrix group>[,<intvec>]);
2261           <intvec> has to contain 2 flags; if the first one equals 0, the
2262           program attempts to compute the Molien series and Reynolds operator,
2263           if it equals 1, the program is told that the characteristic of the
2264           base field divides the group order, if it is anything else the Molien
2265           series and Reynolds operator will not be computed; if the second flag
2266           does not equal 0, information about the various stages of the program
2267           will be printed while running
2268  RETURNS: generators of the invariant ring with respect to the matrix group
2269           generated by the matrices in the input; there are two return values
2270           of type <matrix>, the first containing primary invariants and the
2271           second secondary invariants, i.e. module generators over a Noetherian
2272           normalization
2273  EXAMPLE: example inv_ring_k; shows an example
2274{ def br=basering;
2275  int ch=char(br);                     // the algorithms depend very much on the
2276                                       // characteristic of the ground field
2277  int dB=degBound;
2278  degBound=0;
2279  int n=nvars(br);                     // n is the number of variables, as well
2280                                       // as the size of the matrices, as well
2281                                       // as the number of primary invariants,
2282                                       // we should get
2283  if (typeof(#[size(#)])=="intvec")
2284  { if (size(#[size(#)])<>2)
2285    { "  ERROR:   <intvec> must have exactly two entires";
2286      return();
2287    }
2288    intvec flagvec=#[size(#)];
2289    if (flagvec[1]==0)
2290    { if (ch==0)
2291      { matrix R(1..2);                // one will contain Reynolds operator and
2292                                       // the other enumerator and denominator
2293                                       // of Molien series
2294        R(1..2)=rey_mol(#[1..size(#)-1],flagvec[2]);
2295      }
2296      else
2297      { string newring="Qa";
2298        matrix R(1)=rey_mol(#[1..size(#)-1],newring,flagvec[2]); // will contain
2299      }                                // Reynolds operator, if Molien series
2300    }                                  // can be computed, it will be stored in
2301                                       // the new ring Qa
2302    else
2303    { for (int i=1;i<=size(#)-1;i=i+1)
2304      { if (not(typeof(#[i])=="matrix"))
2305        { "  ERROR:   the parameters must be a list of matrices and optionally";
2306          "           an <intvec>";
2307          return();
2308        }
2309        if (n<>ncols(#[i]) || n<>nrows(#[i]))
2310        { "  ERROR:   matrices need to be square and of the same dimensions as";
2311          "           the number of variables of the basering";
2312          return();
2313        }
2314      }
2315      kill i;
2316    }
2317  }
2318  else
2319  { if (typeof(#[size(#)])<>"matrix")
2320    { "  ERROR:   the parameters must be a list of matrices and optionally";
2321      "           an <intvec>";
2322      return();
2323    }
2324    if (ch==0)
2325    { matrix R(1..2);                  // will contain Reynolds operator and
2326                                       // enumerator and denominator of Molien
2327                                       // series
2328      R(1..2)=rey_mol(#[1..size(#)]);
2329    }
2330    else
2331    { string newring="Qa";             // we might need as a new ring of
2332                                       // characteristic 0 where we store the
2333                                       // Molien series -
2334      matrix R(1)=rey_mol(#[1..size(#)],newring); // will contain
2335                                       // Reynolds operator
2336    }
2337    intvec flagvec=0,0;
2338  }
2339  ideal P=0;                           // will contain primary invariants
2340  if (flagvec[1]==0 && flagvec[2])
2341  { "  We can start looking for primary invariants...";
2342    "";
2343  }
2344  else
2345  { if (flagvec[1] && flagvec[2])
2346    { "";
2347      "  We start by looking for primary invariants...";
2348      "";
2349    }
2350  }
2351  if ((ch==0 || defined(Qa)) && flagvec[1]==0) // i.e. we can use Molien series
2352  { if (ch==0)
2353    { poly p(1..2);                    // p(1) will be used for single terms of
2354                                       // the partial expansion, p(2) to store
2355      p(1..2)=part_mol(R(2),1);        // the intermediate result -
2356      poly v1=var(1);                  // we need v1 to split off coefficients
2357                                       // in the partial expansion of M (which
2358                                       // is in terms of the first variable) -
2359      poly d;                          // for splitting off the coefficient in
2360                                       // in one term of the partial expansion,
2361                                       // i.e. it stores the dimension of the
2362                                       // current homogeneous subspace
2363    }
2364    else
2365    { setring Qa;                      // Qa is where the Molien series is
2366                                       // stored -
2367      poly p(1..2);                    // p(1) will be used for single terms of
2368                                       // the partial expansion, p(2) to store
2369      p(1..2)=part_mol(M,1);           // the intermediate result -
2370      poly d;                          // stores the dimension of the current
2371                                       // homogeneous subspace
2372      setring br;
2373    }
2374    int g, di, counter, i, j, m, bool; // g: current degree, di: d as integer,
2375                                       // counter: counts primary invariants in
2376                                       // degree g, i,j: going through monomials
2377                                       // of degree g, m: counting primary
2378                                       // invariants, bool: indicates whether
2379                                       // the case occurred that a new
2380                                       // polynomial did not lower the
2381                                       // dimension of the ideal generated by
2382                                       // previously found invariants -
2383    poly imRO;                         // the image of the Reynolds operator -
2384    ideal mon;                         // will contain monomials of degree g -
2385    while(1)                           // repeat until n polynomials are found
2386    { if (ch==0)
2387      { p(1..2)=part_mol(R(2),1,p(2)); // 1 term of the partial expansion -
2388        g=deg(p(1));                   // current degree -
2389        d=coef(p(1),v1)[2,1];          // dimension of invariant space of degree
2390                                       // g -
2391        di=int(d);                     // just a type cast
2392      }
2393      else
2394      {  setring Qa;
2395         p(1..2)=part_mol(M,1,p(2));   // 1 term of the partial expansion -
2396         g=deg(p(1));                  // current degree -
2397         d=coef(p(1),x)[2,1];          // dimension of invariant space of degree
2398                                       // g -
2399         di=int(d);                    // just a type cast
2400         setring br;
2401      }
2402      if (flagvec[2])
2403      { "  Searching for primary invariants in degree "+string(g)+":";
2404        "  There is/are "+string(di)+" linearly independent invariant(s) to choose from...";
2405      }
2406      mon=sort(maxideal(g))[1];        // all monomials of degree g -
2407      j=ncols(mon);
2408      counter=0;                       // we have 0 candidates of degree g so
2409                                       // far
2410      for (i=j;i>=1;i=i-1)
2411      { imRO=eval_rey(R(1),mon[i]);
2412        if (reduce(imRO,std(P))<>0)
2413        { if (P[1]==0)                 // if imRO is the first non-zero
2414          { counter=1;                 // invariant we find, the dim question is
2415            m=1;                       // trivial and we just include imRO
2416            P[1]=imRO/leadcoef(imRO);
2417            if (flagvec[2])
2418            { "  We find: "+string(P[1]);
2419            }
2420            if (counter==di)           // if counter is up to di==d, we can
2421            { break;                   // leave the for-loop
2422            }
2423          }
2424          else
2425          { P=P,imRO;                  // we add imRO to the generators of P
2426            attrib(P,"isSB",1);
2427            if (n-m-1<dim(P))          // here we are checking whether the
2428            { if (n-m-1<dim(std(P)))   // dimension is really going down with
2429              { P[m+1]=0;              // the new polynomial -
2430                P=compress(P);         // if the dimension does not go down
2431                                       // we get rid of imRO again -
2432                bool=1;                // we will have to go into the procedure
2433                                       // search later
2434              }
2435              else                     // we can keep imRO -
2436              { counter=counter+1;
2437                m=m+1;
2438                P[m]=P[m]/leadcoef(P[m]); // making m-th primary invariant
2439                if (flagvec[2])        // nice
2440                { if (counter<>1)
2441                  { "           "+string(P[m]);
2442                  }
2443                  else
2444                  { "  We find: "+string(P[m]);
2445                  }
2446                }
2447              }
2448            }
2449            else                       // we can keep imRO -
2450            { counter=counter+1;
2451              m=m+1;
2452              P[m]=P[m]/leadcoef(P[m]); // making m-th primary invariant
2453              if (flagvec[2])
2454              { if (counter<>1)
2455                { "           "+string(P[m]);
2456                }
2457                else
2458                { "  We find: "+string(P[m]);
2459                }
2460              }
2461            }
2462            if (n==m or (counter==di)) // if counter==di, we can leave the for
2463            { break;                   // loop; if n==m, we can leave both loops
2464            }
2465          }
2466        }
2467      }
2468      if (n==1 or n==m)
2469      { break;
2470      }
2471      if (bool)
2472      { if (not(defined(B)==voice))
2473        { ideal B;                     // will contain a subset of a basis of
2474          int T;                       // homogeneous invariants of degree g
2475          ideal Palt;                  // such that none is contained in the
2476          poly lin;                    // radical of P -
2477        }
2478        bool,B=search(R(1),P,g,di);    // checking whether we need to consider
2479                                       // nontrivial linear combinations of
2480                                       // basis elements of degree g
2481        di=ncols(B);
2482        counter=0;
2483      }
2484      if (bool && (di>1))              // indicates that some invariants are not
2485      {                                // in the radical, but don't lower the
2486                                       // dimension, if there is one element in
2487                                       // B, then there exists no linear
2488                                       // combination that lowers the dimension
2489        Palt=P,B;
2490        T=n-m-dim(std(Palt));
2491        while ((counter<>T) && (m<>n)) // runs until we are sure that there are
2492        {                              // no more primary invariant of this
2493                                       // degree -
2494                                       // otherwise we have to try and build a
2495                                       // sum of the basis elements of this
2496                                       // degree -
2497          if (ch==0)                   // we have to distinguish prime and non
2498          {                            // prime characteristic, in infinite
2499                                       // fields a (non-)solution is guaranteed
2500                                       // and here a systematic way of finding
2501                                       // such a solution is implemented -
2502            lin=combi(B,di,P,n-m);     // combi finds a combination
2503          }
2504          else
2505          { lin=p_combi(B,di,P,n-m);   // the subroutine p_combi finds out
2506                                       // whether there is a combination of the
2507                                       // basis elements at all such that it
2508                                       // lowers the dimension of P when added -
2509            if (lin==0)                // if the 0-polynomial is returned, it
2510            { break;                   // means that there was no combination -
2511            }
2512          }
2513          m=m+1;
2514          P[m]=lin;                    // we did find the combination lin
2515          if (flagvec[2])
2516          { "  We find: "+string(P[m]);
2517          }
2518          counter=counter+1;
2519        }
2520      }
2521      bool=0;
2522      if (m==n)                        // found all primary invariants
2523      { break;
2524      }
2525      if (flagvec[2])
2526      { "";
2527      }
2528    }
2529  }
2530  else
2531  {                                    // this case is entered when either the
2532                                       // characteristic<>0 divides the group
2533                                       // order or when the Molien series could
2534                                       // not or has not been computed -
2535    if (flagvec[1]==0)                 // indicates that the group order is
2536    { int g=nrows(R(1));               // known, here it is set to g -
2537      int flag=((g%ch)==0);            // flag is 1 if the characteristic
2538                                       // divides the order, it is 0 if it does
2539                                       // not -
2540      if (typeof(#[size(#)])=="intvec") // getting ahold of the generators of
2541      { int gennum=size(#)-1;          // the generators of the group
2542      }
2543      else
2544      { int gennum=size(#);
2545      }
2546    }
2547    else
2548    { int flag=2;                      // flag is 2 if we don't know yet whether
2549      int gennum=size(#)-1;            // the group order is divisible by the
2550    }                                  // characteristic -
2551    int d=1;                           // d is set to the current degree, since
2552                                       // we know nothing about the finite
2553                                       // matrix group (via Molien series) we
2554                                       // have to start with degree 1
2555    int j, counter, i, di, bool;       // counter: counts primary invariants,
2556                                       // i: goes through basis elements, di:
2557                                       // dimension of current space, bool:
2558                                       // indicates that the case occurred that
2559                                       // a basis element did not lower the
2560                                       // dimension, but was not in the radical
2561    while (1)
2562    { if (flagvec[2])
2563      { "  Searching for primary invariants in degree "+string(d)+":";
2564      }
2565      if (flag)                        // in this case we can not make use of
2566      {                                // the Reynolds operator -
2567        ideal B(d)=inv_basis(d,#[1..gennum]); // we create a basis of the vector
2568      }                                // space of all invariant polynomials of
2569                                       // degree d
2570      else
2571      {                                // here the characteristic<>0 does not
2572        ideal B(d)=inv_basis_rey(R(1),d); // divide the group order, i.e. the
2573      }                                // Reynolds operator can be used to
2574                                       // calculate a basis of the vector space
2575                                       // of all invariant polynomials of degree
2576                                       // d -
2577      di=ncols(B(d));
2578      if (B(d)[1]<>0)                  // otherwise the space is empty -
2579      { if (flagvec[2])
2580        { "  There is/are "+string(di)+" linearly independent invariant(s) to choose from...";
2581        }
2582        if (counter==0)                // we have no candidates for primary
2583        {                              // invariants yet, i.e. don't have to
2584          P[1]=B(d)[1];                // check for radical containment
2585          if (flagvec[2])
2586          { "  We find: "+string(P[1]);
2587          }
2588          i=2;                         // go to second basis element
2589          counter=1;
2590        }
2591        else
2592        { i=1;                         // go to first basis element
2593        }
2594        while (i<=di)                  // goes through all polynomials in B(d) -
2595        { P=P,B(d)[i];                 // adding candidate -
2596          attrib(P,"isSB",1);          // checking dimension -
2597          if (n-counter-1<dim(P))
2598          { if (n-counter-1<dim(std(P))) // in this case B(d)[i] would not lower
2599            { P[counter+1]=0;          // the dimension and we get rid of it
2600              P=compress(P);
2601              bool=1;
2602            }
2603            else                       // indicates that B(d)[i] qualifies
2604            { counter=counter+1;
2605              if (flagvec[2])
2606              { "  We find: "+string(P[counter]);
2607              }
2608              if (counter==n)          // in that case, we're done
2609              { break;
2610              }
2611            }
2612          }
2613          else                         // indicates that B(d)[i] qualifies
2614          { counter=counter+1;
2615            if (flagvec[2])
2616            { "  We find: "+string(P[counter]);
2617            }
2618            if (counter==n)            // in that case, we're done
2619            { break;
2620            }
2621          }
2622          i=i+1;                       // go to next basis element
2623        }
2624        if (counter==n)                // we're done
2625        { break;
2626        }
2627        if (bool)
2628        { if (not(defined(Ba)==voice))
2629          { ideal Ba;
2630            int T;
2631            ideal Palt;
2632            poly lin;
2633          }
2634          bool,Ba=searchalt(B(d),P);   // Ba will now contain a subset of
2635                                       // a basis of homogeneous invariants of
2636                                       // degree d such that none is contained
2637                                       // in the radical of P
2638          di=ncols(Ba);
2639        }
2640        if (bool && (di>1))            // this meant that we have to use
2641        {                              // Kemper's method, if there is one
2642                                       // element in Ba then there exists no
2643                                       // linear combination that lowers the
2644                                       // dimension
2645          Palt=P,Ba;
2646          T=n-counter-dim(std(Palt));
2647          while (counter<>n)           // runs until we are sure that there are
2648          {                            // no more primary invariant of this
2649                                       // degree -
2650                                       // otherwise we have to try and build a
2651                                       // sum of the basis elements of this
2652                                       // degree -
2653            if (ch==0)                 // we have to distinguish prime and non
2654            {                          // prime characteristic, in infinite
2655                                       // fields a (non-)solution is guaranteed
2656                                       // and here a systematic way of finding
2657                                       // such a solution is implemented -
2658              lin=combi(Ba,di,P,counter); // combi finds a combination
2659            }
2660            else
2661            { lin=p_combi(Ba,di,P,counter); // the subroutine p_combi finds out
2662                                       // whether there is a combination of the
2663                                       // basis elements at all such that it
2664                                       // lowers the dimension of P when added -
2665              if (lin==0)              // if the 0-polynomial is returned, it
2666              { break;
2667              }
2668            }
2669            counter=counter+1;         // otherwise, we did find a combination
2670            P[counter]=lin;
2671            if (flagvec[2])
2672            { "  We find: "+string(P[counter]);
2673            }
2674          }
2675        }
2676        bool=0;
2677        if (counter==n)                // found all primary invariants
2678        { break;
2679        }
2680        if (flagvec[2])
2681        { "";
2682        }
2683      }
2684      else
2685      { if (flagvec[2])
2686        { "  The space is 0-dimensional.";
2687        }
2688      }
2689      d=d+1;                           // up to the next degree
2690    }
2691  }
2692  if ((ch==0 || defined(Qa)) && flagvec[1]==0)
2693  { if (flagvec[2])
2694    { "";
2695    }
2696    ideal Q=std(P);                    // P contains the primary invariants -
2697    intvec degvec;                     // will contain the degrees of secondary
2698                                       // invariants -
2699    if (ch==0)                         // Molien series is stored in basering
2700    { p(1)=1;
2701      for (j=1;j<=n;j=j+1)             // calculating the denominator of the
2702      { p(1)=p(1)*(1-v1^deg(P[j]));    // Hilbert series of the ring generated
2703      }                                // generated by the primary invariants -
2704      matrix s[1][2]=R(2)[1,1]*p(1),R(2)[1,2]; // used for canceling
2705      s=matrix(syz(ideal(s)));
2706      p(1)=s[2,1];                     // the polynomial telling us where to
2707                                       // search for secondary invariants
2708      map slead=br,ideal(0);
2709      p(1)=1/slead(p(1))*p(1);         // smallest term of p(1) needs to be 1 -
2710      if (flagvec[2])
2711      { "  Polynomial telling us where to look for secondary invariants:";
2712        "   "+string(p(1));
2713        "";
2714      }
2715      matrix dimmat=coeffs(p(1),v1);   // dimmat will contain the number of
2716                                       // secondary invariants, we need to find
2717                                       // of a certain degree -
2718      m=nrows(dimmat);                 // m-1 is the highest degree
2719      degvec=0;
2720      for (j=1;j<=m;j=j+1)
2721      { if (dimmat[j,1]<>0)
2722        { degvec[j]=int(dimmat[j,1]);  // degvec[j] now contains the number of
2723        }                              // secondary invariants of degree j-1
2724      }
2725    }
2726    else
2727    { for (j=1;j<=n;j=j+1)             // degrees have to be taken in a ring of
2728      { degvec[j]=deg(P[j]);           // characteristic 0
2729      }
2730      setring Qa;
2731      p(1)=1;
2732      for (j=1;j<=n;j=j+1)             // calculating the denominator of the
2733      { p(1)=p(1)*(1-x^degvec[j]);     // Hilbert series of the ring generated
2734      }                                // by the primary invariants -
2735      matrix s[1][2]=M[1,1]*p(1),M[1,2]; // used for canceling
2736      s=matrix(syz(ideal(s)));
2737      p(1)=s[2,1];                     // the polynomial telling us where to
2738                                       // search for secondary invariants
2739      map slead=Qa,ideal(0);
2740      p(1)=1/slead(p(1))*p(1);         // smallest term of p(1) needs to be 1
2741      if (flagvec[2])
2742      { "  Polynomial telling us where to look for secondary invariants:";
2743        "   "+string(p(1));
2744        "";
2745      }
2746      matrix dimmat=coeffs(p(1),x);    // dimmat will contain the number of
2747                                       // secondary invariants, we need to find
2748                                       // find of a certain degree -
2749      m=nrows(dimmat);                 // m-1 actually is the highest degree
2750      degvec=0;
2751      for (j=1;j<=m;j=j+1)
2752      { if (dimmat[j,1]<>0)
2753        { degvec[j]=int(dimmat[j,1]);  // degvec[j-1] contains the number of
2754        }                              // secondary invariants of degree j-1
2755      }
2756      setring br;
2757      kill Qa;                         // all the information needed for Qa is
2758    }                                  // stored in degvec and dimmat -
2759    qring Qring=Q;                     // we need to do calculations modulo the
2760                                       // ideal generated by the elements of P,
2761                                       // its standard basis is stored in Q -
2762    poly imROmod;                      // imRO reduced -
2763    ideal Smod, sSmod;                 // secondary invariants of one degree
2764                                       // reduced and their standard basis
2765    setring br;
2766    kill Q;                            // Q might be big and isn't needed
2767                                       // anymore
2768    if (flagvec[2])
2769    { "  Proceeding to look for secondary invariants...";
2770      "";
2771      "  In degree 0 we have: 1";
2772      "";
2773    }
2774    bool=0;                            // indicates when standard basis
2775                                       // calculation is necessary -
2776    ideal S=1;                         // 1 definitely is a secondary invariant
2777    for (i=2;i<=m;i=i+1)               // walking through degvec -
2778    { if (degvec[i]<>0)                // when it is == 0 we need to find 0
2779      {                                // elements of the current degree being
2780                                       // i-1 -
2781        if (flagvec[2])
2782        { "  Searching in degree "+string(i-1)+", we need to find "+string(degvec[i,1])+" invariant(s)...";
2783        }
2784        mon=sort(maxideal(i-1))[1];    // all monomials of degree i-1 -
2785        counter=0;                     // we'll count up to degvec[i] -
2786        j=ncols(mon);                  // we'll go through mon from the end
2787        setring Qring;
2788        Smod=0;
2789        setring br;
2790        while (degvec[i]<>counter)     // need to find degvec[i] linearly
2791        {                              // independent (in Qring) invariants -
2792          imRO=eval_rey(R(1),mon[j]);  // generating invariants
2793          setring Qring;
2794          imROmod=fetch(br,imRO);      // reducing the invariants
2795          if (reduce(imROmod,std(ideal(0)))<>poly(0) and counter<>0)
2796          {                            // if the first condition is true and the
2797                                       // second false, imROmod is the first
2798                                       // secondary invariant of that degree
2799                                       // that we want to add and we need not
2800                                       // check linear independence
2801            if (bool)
2802            { sSmod=std(Smod);
2803            }
2804            if (reduce(imROmod,sSmod)<>0)
2805            { Smod=Smod,imROmod;
2806              setring br;              // we make its leading coefficient to be
2807              imRO=imRO/leadcoef(imRO); // 1
2808              S=S,imRO;
2809              if (flagvec[2])
2810              { "           "+string(imRO);
2811              }
2812              counter=counter+1;
2813              bool=1;                  // next time we need to recalculate std
2814            }
2815            else
2816            { bool=0;                  // std-calculation is unnecessary
2817              setring br;
2818            }
2819          }
2820          else
2821          { if (reduce(imROmod,std(ideal(0)))<>poly(0) and counter==0)
2822            { Smod[1]=imROmod;         // here we just add imRO(mod) without
2823              setring br;              // having to check linear independence
2824              imRO=imRO/leadcoef(imRO);
2825              S=S,imRO;
2826              counter=counter+1;
2827              bool=1;                  // next time we need to calculate std
2828              if (flagvec[2])
2829              { "  We find: "+string(imRO);
2830              }
2831            }
2832            else
2833            { setring br;
2834            }
2835          }
2836          j=j-1;                       // going to next monomial
2837        }
2838        if (flagvec[2])
2839        { "";
2840        }
2841      }
2842    }
2843    degBound=dB;
2844    if (flagvec[2])
2845    { "  We're done!";
2846      "";
2847    }
2848    matrix FI(1)=matrix(P);
2849    matrix FI(2)=matrix(S);
2850    return(FI(1..2));
2851  }
2852  else
2853  { if (flagvec[2])
2854    { "";
2855      "  Proceeding to look for secondary invariants...";
2856    }
2857    // we can now proceed to calculate secondary invariants, the problem
2858    // we face again is that we can make no use of a Molien series - however,
2859    // if the characteristic does not divide the group order, we can still make
2860    // use of the fact that the secondary invariants are free module generators
2861    // and that we need deg(P[1])*...*deg(P[n])/(cardinality of the group) of
2862    // them
2863    matrix FI(1)=matrix(P);            // primary invariants, ready for output -
2864    P=std(P);                          // for calculations module primary
2865                                       // invariants
2866    if (flagvec[1]<>0 and flagvec[1]<>1)
2867    { int g=group(#[1..size(#)-1]);    // computing group order
2868      if (ch==0)
2869      { matrix FI(2)=sec_minus_mol(ideal(FI(1)),P,g,flagvec[2],#[1..size(#)-1],0,B(1..d),d);
2870        return(FI(1..2));
2871      }
2872      if (g%ch<>0)
2873      { matrix FI(2)=sec_minus_mol(ideal(FI(1)),P,g,flagvec[2],#[1..size(#)-1],0,B(1..d),d);
2874          return(FI(1..2));
2875      }
2876    }
2877    else
2878    { if (flag==0)                     // this is the case where we have a
2879      {                                // nonzero minpoly, but the
2880                                       // characteristic does not divide the
2881                                       // group order
2882        matrix FI(2)=sec_minus_mol(ideal(FI(1)),P,g,flagvec[2],R(1),1,B(1..d),d);
2883        return(FI(1..2));
2884      }
2885    }
2886    if (flagvec[2])
2887    { "  Since the characteristic of the base field divides the group order, we do not";
2888      "  know whether the invariant ring is Cohen-Macaulay. We have to use Kemper's";
2889      "  algorithm and compute secondary invariants with respect to the trivial";
2890      "  subgroup of the given group.";
2891      "";
2892
2893    }
2894    // are using Kemper's algorithm with the trivial subgroup
2895    ring QQ=0,x,dp;
2896    ideal M=(1-x)^n;                   // we look at our primary invariants as
2897                                       // such of the subgroup that only
2898                                       // contains the identity, this means that
2899                                       // ch does not divide the order anymore,
2900                                       // this means that we can make use of the
2901                                       // Molien series again - 1/M[1] is the
2902                                       // Molien series of that group, we now
2903                                       // calculate the secondary invariants of
2904                                       // this subgroup in the usual fashion
2905                                       // where the primary invariants are the
2906                                       // ones from the bigger group
2907    setring br;
2908    intvec degvec;                     // for the degrees of the primary
2909                                       // invariants -
2910    for (i=1;i<=n;i=i+1)               // finding the degrees of these
2911    { degvec[i]=deg(FI(1)[1,i]);
2912    }
2913    setring QQ;                        // calculating the polynomial indicating
2914    M[2]=1;                            // where to search for secondary
2915    for (i=1;i<=n;i=i+1)               // invariants (of the trivial subgroup)
2916    { M[2]=M[2]*(1-x^degvec[i]);
2917    }
2918    M=matrix(syz(M))[1,1];
2919    M[1]=M[1]/leadcoef(M[1]);
2920    if (flagvec[2])
2921    { "  Polynomial telling us where to look for these secondary invariants:";
2922      "   "+string(M[1]);
2923      "";
2924    }
2925    matrix dimmat=coeffs(M[1],x);      // storing the number of secondary
2926                                       // invariants we need in a certain
2927    int m=nrows(dimmat);               // m-1 is the highest degree where we
2928                                       // need to search
2929    degvec=0;
2930    for (i=1;i<=m;i=i+1)               // degvec will contain all the
2931    { if (dimmat[i,1]<>0)              // information about where to find
2932      { degvec[i]=int(dimmat[i,1]);    // secondary invariants, it is filled
2933      }                                // with integers and therefore visible in
2934    }                                  // all rings
2935    kill QQ;
2936    setring br;
2937    ideal B;
2938    ideal S=1;                         // 1 is a secondary invariant always
2939    if (flagvec[2])
2940    { "  In degree 0 we have: 1";
2941      "";
2942    }
2943    qring Qring=P;
2944    ideal Smod, Bmod, sSmod;           // Smod: secondary invariants of one
2945                                       // degree modulo P, sSmod: standard basis
2946                                       // of the latter, Bmod: B modulo P
2947    setring br;
2948    kill P;                            // might be large
2949    if (flagvec[1]==1)
2950    { int g;
2951    }
2952    for (i=2;i<=m;i=i+1)               // going through all entries of degvec
2953    { if (degvec[i]<>0)
2954      { B=sort(maxideal(i-1))[1];      // basis of the space of invariants (with
2955                                       // respect to the matrix subgroup
2956                                       // containing only the identity) of
2957                                       // degree i-1 -
2958        if (flagvec[2])
2959        { "  Searching in degree "+string(i-1)+", we need to find "+string(degvec[i])+" invariant(s)...";
2960        }
2961        counter=0;                     // we have 0 secondary invariants of
2962                                       // degree i-1 so far
2963        setring Qring;
2964        Bmod=fetch(br,B);              // basis modulo primary invariants
2965        Smod=0;
2966        j=ncols(Bmod);                 // going backwards through Bmod
2967        while (degvec[i]<>counter)
2968        { if (reduce(Bmod[j],std(ideal(0)))<>0 && counter<>0)
2969          { if (bool)
2970            { sSmod=std(Smod);
2971            }
2972            if (reduce(Bmod[j],sSmod)<>0) // Bmod[j] qualifies as secondary
2973            { Smod=Smod,Bmod[j];       // invariant
2974              setring br;
2975              S=S,B[j];
2976              counter=counter+1;
2977              if (flagvec[2])
2978              { "           "+string(B[j]);
2979              }
2980              setring Qring;
2981              bool=1;                  // need to calculate std of Smod next
2982            }                          // time
2983            else
2984            { bool=0;
2985            }
2986          }
2987          else
2988          { if (reduce(Bmod[j],std(ideal(0)))<>0 && counter==0)
2989            { Smod[1]=Bmod[j];         // in this case, we may just add B[j]
2990              setring br;
2991              S=S,B[j];
2992              if (flagvec[2])
2993              { "  We find: "+string(B[j]);
2994              }
2995              counter=counter+1;
2996              bool=1;                  // need to calculate std of Smod next
2997              setring Qring;           // time
2998            }
2999          }
3000          j=j-1;                       // next basis element
3001        }
3002        setring br;
3003      }
3004    }
3005    // now we have those secondary invariants
3006    int k=ncols(S);                    // k is the number of the secondary
3007                                       // invariants, we just calculated
3008    if (flagvec[2])
3009    { "";
3010      "  We calculate secondary invariants from the ones found for the trivial";
3011      "  subgroup.";
3012      "";
3013    }
3014    map f;                             // used to let generators act on
3015                                       // secondary invariants with respect to
3016                                       // the trivial group -
3017    matrix M(1)[gennum][k];            // M(1) will contain a module
3018    for (i=1;i<=gennum;i=i+1)
3019    { B=ideal(matrix(maxideal(1))*transpose(#[i])); // image of the various
3020                                       // variables under the i-th generator -
3021      f=br,B;                          // the corresponding mapping -
3022      B=f(S)-S;                        // these relations should be 0 -
3023      M(1)[i,1..k]=B[1..k];            // we will look for the syzygies of M(1)
3024    }
3025    module M(2)=res(M(1),2)[2];
3026    m=ncols(M(2));                     // number of generators of the module
3027                                       // M(2) -
3028    // the following steps calculates the intersection of the module M(2) with
3029    // the algebra A^k where A denote the subalgebra of the usual polynomial
3030    // ring, generated by the primary invariants
3031    string mp=string(minpoly);         // generating a ring where we can do
3032                                       // elimination
3033    execute "ring R=("+charstr(br)+"),(x(1..n),y(1..n),h),dp;";
3034    execute "minpoly=number("+mp+");";
3035    map f=br,maxideal(1);              // canonical mapping
3036    matrix M[k][m+k*n];
3037    M[1..k,1..m]=matrix(f(M(2)));      // will contain a module -
3038    matrix FI(1)=f(FI(1));             // primary invariants in the new ring
3039    for (i=1;i<=n;i=i+1)
3040    { for (j=1;j<=k;j=j+1)
3041      { M[j,m+(i-1)*k+j]=y(i)-FI(1)[1,i];
3042      }
3043    }
3044    M=elim(module(M),1,n);             // eliminating x(1..n), std-calculation
3045                                       // is done internally -
3046    M=homog(module(M),h);              // homogenize for 'minbase'
3047    M=minbase(module(M));
3048    setring br;
3049    //execute "ideal v="+varstr(br)+",ideal(FI(1)),1";
3050    ideal v=maxideal(1),ideal(FI(1)),1;
3051    f=R,v;                             // replacing y(1..n) by primary
3052                                       // invariants -
3053    M(2)=f(M);                         // M(2) is the new module -
3054    m=ncols(M(2));
3055    matrix FI(2)[1][m];
3056    FI(2)=matrix(S)*matrix(M(2));      // FI(2) now contains the secondary
3057                                       // invariants
3058    for (i=1; i<=m;i=i+1)
3059    { FI(2)[1,i]=FI(2)[1,i]/leadcoef(FI(2)[1,i]); // making elements nice
3060    }
3061    FI(2)=sort(ideal(FI(2)))[1];
3062    if (flagvec[2])
3063    { "  These are the secondary invariants: ";
3064      for (i=1;i<=m;i=i+1)
3065      { "   "+string(FI(2)[1,i]);
3066      }
3067      "";
3068      "  We're done!";
3069      "";
3070    }
3071    if ((flagvec[2] or (voice==2)) && flagvec[1]==1 && (m>1))
3072    { "  WARNING: The invariant ring might not have a Hironaka decomposition";
3073      "           if the characteristic of the coefficient field divides the";
3074      "           group order.";
3075    }
3076    else
3077    { if ((flagvec[2] or (voice==2)) and (m>1))
3078      { "  WARNING: The invariant ring might not have a Hironaka decomposition!"
3079;
3080        "           This is because the characteristic of the coefficient field"
3081;
3082        "           divides the group order.";
3083      }
3084    }
3085    degBound=dB;
3086    return(FI(1..2));
3087  }
3088}
3089example
3090{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
3091  echo=2;
3092           ring R=0,(x,y,z),dp;
3093           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3094           matrix B(1..2);
3095           B(1..2)=inv_ring_k(A);
3096           print(B(1..2));
3097}
3098
3099////////////////////////////////////////////////////////////////////////////////
3100// The procedure introduces m new variables y(i), m being the number of
3101// generators {f_1,...,f_m} of the subring in the variables x(1),...,x(n).
3102// A Groebner basis of {f_1-y(1),...,f_m-y(m)} is computed with respect to
3103// the product ordering of x^a*y^b > y^d*y^e if x^a > x^d or else if y^b > y^e.
3104// f reduces to a polynomial only in the y(i) <=> p is contained in the subring
3105// generated by the polynomials in F.
3106////////////////////////////////////////////////////////////////////////////////
3107proc algebra_con (poly p, matrix F)
3108  USAGE:   algebra_con(<poly>,<matrix>); <poly> is arbitrary in the basering,
3109           <matrix> defines a subring of the basering
3110  RETURNS: if <poly> is contained in the ring, 1 (TRUE) (type <int>) is
3111           returned as well as a comment showing a representation of <poly>
3112           where y(i) represents the i-th element in <matrix>. 0 (type <int>)
3113           is returned if <poly> is not contained
3114  EXAMPLE: example algebra_con; shows an example
3115{ if (nrows(F)==1)
3116  { def br=basering;
3117    int n=nvars(br);
3118    int m=ncols(F);
3119    ring R=0,(x(1..n),y(1..m)),(dp(n),dp(m));
3120    ideal vars=x(1..n);
3121    map emb=br,vars;
3122    ideal F=ideal(emb(F));
3123    ideal check=emb(p);
3124    for (int i=1;i<=m;i=i+1)
3125    { F[i]=F[i]-y(i);
3126    }
3127    F=std(F);
3128    check[1]=reduce(check[1],F);
3129    F=elim(check,1,n);
3130    if (F[1]<>0)
3131    { "\/\/ "+string(check);
3132      return(1);
3133    }
3134    else
3135    { return(0);
3136    }
3137  }
3138  else
3139  { "  ERROR:   <matrix> may only have one row";
3140    return();
3141  }
3142}
3143example
3144{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
3145  echo=2;
3146           ring R=0,(x,y,z),dp;
3147           matrix F[1][7]=x2+y2,z2,x4+y4,x4+y4,1,x2z-1y2z,xyz,x3y-1xy3;
3148           poly p1=(x2z-1y2z)*z2;
3149           algebra_con(p1,F);
3150           poly p2=z;
3151           algebra_con(p2,F);
3152}
3153
3154////////////////////////////////////////////////////////////////////////////////
3155// The procedure introduces n+m new variables y(i) and z(j), n being the number
3156// of primary generators {p_1,...,p_n} and m the number of secondary ones
3157// {s_1,...,s_m} in the variables x(1),...,x(n). A Groebner basis of
3158// {p_1-y(1),...,p_n-y(n),s_1-z(1),...,s_m-z(m)} is computed with respect to the
3159// product ordering of x^a*y^b*z^c > x^d*y^e*z^f if x^a > x^d with respect
3160// to the purely lexicographical ordering or else if z^c > z^f with respect
3161// to the degree lexicographical ordering or else if y^b > y^e with respect
3162// to the purely lexicographical ordering again. f reduces to a polynomial
3163// only in y(i) and z(j) (more specifically, linear in the z(j)) <=> f is
3164// contained in the Cohen-Macaulay ring.
3165////////////////////////////////////////////////////////////////////////////////
3166proc module_con(poly f, matrix P, matrix S)
3167  USAGE:   module_con(<poly>,<matrix_1>,<matrix_2>); <poly> is arbitrary in
3168           the basering, <matrix_1> should represent the primary generators of
3169           a Cohen-Macaulay ring, <matrix_2> the secondary ones
3170  RETURNS: if <poly> is contained in the ring, 1 (TRUE) (type <int>) is
3171           returned as well as a comment showing the unique representation
3172           of <poly> with respect to a Hironaka decomposition; y(i) represents
3173           the i-th element in <matrix_2> and z(j) represents the j-th element
3174           in <matrix_1>. 0 (type <int>) is returned if <poly> is not contained.
3175  EXAMPLE: example module_con; shows an example
3176{ def br=basering;
3177  int n=nvars(br);
3178  if (ncols(P)==n and nrows(P)==1 and nrows(S)==1)
3179  { int m=ncols(S);
3180    ring R=0,(x(1..n),y(1..m),z(1..n)),(lp(n),dp(m),lp(n));
3181    ideal vars=x(1..n);
3182    map emb=br,vars;
3183    matrix P=emb(P);
3184    matrix S=emb(S);
3185    ideal check=emb(f);
3186    ideal I;
3187    for (int i=1;i<=m;i=i+1)
3188    { I[i]=S[1,i]-y(i);
3189    }
3190    for (i=1;i<=n;i=i+1)
3191    { I[n+i]=P[1,i]-z(i);
3192    }
3193    I=std(I);
3194    check[1]=reduce(check[1],I);
3195    I=elim(check,1,n);                 // checking whether all variables from
3196    if (I[1]<>0)                       // the former ring have disappeared
3197    { "\/\/ "+string(check);
3198      return(1);
3199    }
3200    else
3201    { return(0);
3202    }
3203  }
3204  else
3205  { "  ERROR:   <matrix_1> must have the same number of columns as the basering";
3206    "           and both <matrix_1> and <matrix_2> may only have one row";
3207    return();
3208  }
3209}
3210example
3211{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
3212  echo=2;
3213           ring R=0,(x,y,z),dp;
3214           matrix P[1][3]=x2+y2,z2,x4+y4;
3215           matrix S[1][4]=1,x2z-1y2z,xyz,x3y-1xy3;
3216           poly p1=(x2z-1y2z)*xyz;
3217           module_con(p1,P,S);
3218           poly p2=z;
3219           module_con(p2,P,S);
3220}
3221
3222////////////////////////////////////////////////////////////////////////////////
3223// 'orbit_var' calculates the syzygy ideal of the generators of the
3224// invariant ring, then eliminates the variables of the original ring and
3225// the polynomials that are left over define the orbit variety
3226////////////////////////////////////////////////////////////////////////////////
3227proc orbit_var (matrix F,string newring)
3228  USAGE:   orbit_var(<matrix>,<string>); <matrix> defines an invariant ring,
3229           <string> is the name for a new ring
3230  RETURN:  a Groebner basis (type <ideal>, named G) for the ideal defining the
3231           orbit variety (i.e. the syzygy ideal) in the new ring (named
3232           <string>)
3233  EXAMPLE: example orbit_var; shows an example
3234{ if (newring=="")
3235  { "  ERROR:   the second argument may not be an empty <string>";
3236    return();
3237  }
3238  if (nrows(F)==1)
3239  { def br=basering;
3240    int n=nvars(br);
3241    int m=ncols(F);
3242    string mp=string(minpoly);
3243    execute "ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),dp;";
3244    execute "minpoly=number("+mp+");";
3245    ideal I=ideal(imap(br,F));
3246    for (int i=1;i<=m;i=i+1)
3247    { I[i]=I[i]-y(i);
3248    }
3249    I=elim(I,1,n);
3250    execute "ring "+newring+"=("+charstr(br)+"),(y(1..m)),dp(m);";
3251    execute "minpoly=number("+mp+");";
3252    ideal vars;
3253    for (i=2;i<=n;i=i+1)
3254    { vars[i]=0;
3255    }
3256    vars=vars,y(1..m);
3257    map emb=R,vars;
3258    ideal G=emb(I);
3259    kill emb, vars, R;
3260    keepring `newring`;
3261    // execute "keepring "+newring+";";
3262    return();
3263  }
3264  else
3265  { "  ERROR:   the <matrix> may only have one row";
3266    return();
3267  }
3268}
3269example
3270{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
3271  echo=2;
3272           ring R=0,(x,y,z),dp;
3273           matrix F[1][7]=x2+y2,z2,x4+y4,1,x2z-1y2z,xyz,x3y-1xy3;
3274           string newring="E";
3275           orbit_var(F,newring);
3276           print(G);
3277           basering;
3278}
3279
3280////////////////////////////////////////////////////////////////////////////////
3281// Let f1,...,fm be generators of the invariant ring, y1,...,ym new variables
3282// and h1,...,hk generators of I. 'rel_orbit_var'  computes a standard basis of
3283// the ideal generated by f1-y1,...,fm-ym with respect to a pure lexicographic
3284// order. Further, a standard basis of the the ideal generated by the elements
3285// of the previously found standard basis and h1,...,hk is found. Eliminating
3286// the original variables yields generators of the relative orbit variety with
3287// respect to I.
3288////////////////////////////////////////////////////////////////////////////////
3289proc rel_orbit_var(ideal I,matrix F, string newring)
3290  USAGE:   rel_orbit_var(<ideal>,<matrix>,<string>); <ideal> defines an
3291           ideal invariant under the action of a group, <matrix> defines the
3292           invariant ring of this group, <string> is a name for a new ring
3293  RETURN:  a Groebner basis (type <ideal>, named G) for the ideal defining the
3294           relative orbit variety with respect to <ideal> in the new ring (named
3295           <string>)
3296  EXAMPLE: example rel_orbit_var; shows an example
3297{ if (newring=="")
3298  { "  ERROR:   the third argument may not be empty a <string>";
3299    return();
3300  }
3301  if (nrows(F)==1)
3302  { def br=basering;
3303    int n=nvars(br);
3304    int m=ncols(F);
3305    string mp=string(minpoly);
3306    execute "ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),lp;";
3307    execute "minpoly=number("+mp+");";
3308    ideal J=ideal(imap(br,F));
3309    ideal I=imap(br,I);
3310    for (int i=1;i<=m;i=i+1)
3311    { J[i]=J[i]-y(i);
3312    }
3313    J=std(J);
3314    J=J,I;
3315    option(redSB);
3316    J=std(J);
3317    ideal vars;
3318    //for (i=1;i<=n;i=i+1)
3319    //{ vars[i]=0;
3320    //}
3321    vars[n]=0;
3322    vars=vars,y(1..m);
3323    map emb=R,vars;
3324    ideal G=emb(J);
3325    J=J-G;
3326    for (i=1;i<=ncols(G);i=i+1)
3327    { if (J[i]<>0)
3328      { G[i]=0;
3329      }
3330    }
3331    G=compress(G);
3332    execute "ring "+newring+"=("+charstr(br)+"),(y(1..m)),lp;";
3333    execute "minpoly=number("+mp+");";
3334    ideal vars;
3335    for (i=2;i<=n;i=i+1)
3336    { vars[i]=0;
3337    }
3338    vars=vars,y(1..m);
3339    map emb=R,vars;
3340    ideal G=emb(G);
3341    kill vars, emb;
3342    keepring `newring`;
3343    // execute "keepring "+newring+";";
3344    return();
3345  }
3346  else
3347  { "  ERROR:   the <matrix> may only have one row";
3348    return();
3349  }
3350}
3351example
3352{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.3:";
3353  echo=2;
3354           ring R=0,(x,y,z),dp;
3355           matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
3356           ideal I=x2+y2+z2-1,x2y+y2z+z2x-2x-2y-2z,xy2+yz2+zx2-2x-2y-2z;
3357           string newring="E";
3358           rel_orbit_var(I,F,newring);
3359           print(G);
3360           basering;
3361}
3362
3363////////////////////////////////////////////////////////////////////////////////
3364// Let f1,...,fm be generators of the invariant ring, y1,...,ym new variables
3365// and h1,...,hk generators of I. 'im_of_var' calls 'rel_orbit_var' with input
3366// I, F and the string newring. In the output the variables y1,...,ym are
3367// replaced by f1,...,fm. The result is the output of 'im_of_var' and defines
3368// the variety under the matrix group.
3369////////////////////////////////////////////////////////////////////////////////
3370proc im_of_var(ideal I,matrix F)
3371  USAGE:   im_of_var(<ideal>,<matrix>); <ideal> is arbitrary, <matrix>
3372           defines an invariant ring of a certain matrix group
3373  RETURN:  the <ideal> defining the image of the variety defined by the input
3374           ideal with respect to that group
3375  EXAMPLE: example im_of_var; shows an example
3376{ if (nrows(F)==1)
3377  { def br=basering;
3378    int n=nvars(br);
3379    string newring="E";
3380    rel_orbit_var(I,F,newring);
3381    execute "ring R=("+charstr(br)+"),("+varstr(br)+","+varstr(E)+"),lp;";
3382    ideal F=imap(br,F);
3383    for (int i=1;i<=n;i=i+1)
3384    { F=0,F;
3385    }
3386    setring br;
3387    map emb2=E,F;
3388    return(compress(emb2(G)));
3389  }
3390  else
3391  { "  ERROR:   the <matrix> may only have one row";
3392    return();
3393  }
3394}
3395example
3396{ "  EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.8:";
3397  echo=2;
3398           ring R=0,(x,y,z),dp;
3399           matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
3400           ideal I=xy;
3401           print(im_of_var(I,F));
3402}
Note: See TracBrowser for help on using the repository browser.