source: git/Singular/LIB/finvar.lib @ 18dd47

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