source: git/Singular/LIB/finvar.lib @ 731e67e

spielwiese
Last change on this file since 731e67e was 731e67e, checked in by Hans Schönemann <hannes@…>, 18 years ago
*hannes: format, typos in docu git-svn-id: file:///usr/local/Singular/svn/trunk@9316 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 249.7 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="$Id: finvar.lib,v 1.50 2006-07-18 15:48:13 Singular Exp $"
3category="Invariant theory";
4info="
5LIBRARY:  finvar.lib    Invariant Rings of Finite Groups
6AUTHOR: Agnes E. Heydtmann, email: agnes@math.uni-sb.de;
7        Simon A. King, email: king@mfo.de
8OVERVIEW:
9 A library for computing polynomial invariants of finite matrix groups and
10 generators of related varieties. The algorithms are based on B. Sturmfels,
11 G. Kemper and W. Decker et al..
12
13MAIN PROCEDURES:
14 invariant_ring()                  generators of the invariant ring (i.r.)
15 invariant_ring_random()           generators of the i.r., randomized alg.
16 primary_invariants()              primary invariants (p.i.)
17 primary_invariants_random()       primary invariants, randomized alg.
18
19AUXILIARY PROCEDURES:
20 cyclotomic()                      cyclotomic polynomial
21 group_reynolds()                  finite group and Reynolds operator (R.o.)
22 molien()                          Molien series (M.s.)
23 reynolds_molien()                 Reynolds operator and Molien series
24 partial_molien()                  partial expansion of Molien series
25 evaluate_reynolds()               image under the Reynolds operator
26 invariant_basis()                 basis of homogeneous invariants of a degree
27 invariant_basis_reynolds()        as invariant_basis(), with R.o.
28 primary_char0()                   primary invariants (p.i.) in char 0
29 primary_charp()                   primary invariants in char p
30 primary_char0_no_molien()         p.i., char 0, without Molien series
31 primary_charp_no_molien()         p.i., char p, without Molien series
32 primary_charp_without()           p.i., char p, without R.o. or Molien series
33 primary_char0_random()            primary invariants in char 0, randomized
34 primary_charp_random()            primary invariants in char p, randomized
35 primary_char0_no_molien_random()  p.i., char 0, without M.s., randomized
36 primary_charp_no_molien_random()  p.i., char p, without M.s., randomized
37 primary_charp_without_random()    p.i., char p, without R.o. or M.s., random.
38 power_products()                  exponents for power products
39 secondary_char0()                 secondary invariants (s.i.) in char 0
40 irred_secondary_char0()           irreducible secondary invariants in char 0
41 secondary_charp()                 secondary invariants in char p
42 secondary_no_molien()             secondary invariants, without Molien series
43 secondary_and_irreducibles_no_molien() s.i. & irreducible s.i., without M.s.
44 secondary_not_cohen_macaulay()    s.i. when invariant ring not Cohen-Macaulay
45 orbit_variety()                   ideal of the orbit variety
46 rel_orbit_variety()               ideal of a relative orbit variety (new version)
47 relative_orbit_variety()          ideal of a relative orbit variety (old version)
48 image_of_variety()                ideal of the image of a variety
49";
50///////////////////////////////////////////////////////////////////////////////
51// perhaps useful procedures (no help provided):
52// unique()                        is a matrix among other matrices?
53// exponent()                      gives the exponent of a number
54// sort_of_invariant_basis()       lin. ind. invariants of a degree mod p.i.
55// next_vector                     lists all of Z^n with first nonzero entry 1
56// int_number_map                  integers 1..q are maped to q field elements
57// search                          searches a number of p.i., char 0
58// p_search                        searches a number of p.i., char p
59// search_random                   searches a # of p.i., char 0, randomized
60// p_search_random                 searches a # of p.i., char p, randomized
61// concat_intmat                   concatenates two integer matrices
62///////////////////////////////////////////////////////////////////////////////
63
64LIB "matrix.lib";
65LIB "elim.lib";
66LIB "general.lib";
67LIB "algebra.lib";
68
69///////////////////////////////////////////////////////////////////////////////
70// Checks whether the last parameter, being a matrix, is among the previous
71// parameters, also being matrices
72///////////////////////////////////////////////////////////////////////////////
73proc unique (list #)
74{ int s=size(#); def m=#[s];
75  for (int i=1;i<s;i++)
76  { if (#[i]==m)
77    { return(0); }
78  }
79  return(1);
80}
81///////////////////////////////////////////////////////////////////////////////
82
83proc cyclotomic (int i)
84"USAGE:   cyclotomic(i); i integer > 0
85RETURNS: the i-th cyclotomic polynomial (type <poly>) as one in the first ring
86         variable
87THEORY:  x^i-1 is divided by the j-th cyclotomic polynomial where j takes on
88         the value of proper divisors of i
89EXAMPLE: example cyclotomic; shows an example
90"
91{ if (i<=0)
92  { "ERROR:   the input should be > 0.";
93    return();
94  }
95  poly v1=var(1);
96  if (i==1)
97  { return(v1-1);                      // 1-st cyclotomic polynomial
98  }
99  poly min=v1^i-1;
100  matrix s[1][2];
101  min=min/(v1-1);                      // dividing by the 1-st cyclotomic
102                                       // polynomial
103  int j=2;
104  int n;
105  poly c;
106  int flag=1;
107  while(2*j<=i)                        // there are no proper divisors of i
108  { if ((i%j)==0)                      // greater than i/2
109    { if (flag==1)
110      { n=j;                           // n stores the first proper divisor of
111      }                                // i > 1
112      flag=0;
113      c=cyclotomic(j);                 // recursive computation
114      s=min,c;
115      s=matrix(syz(ideal(s)));         // dividing
116      min=s[2,1];
117    }
118    if (n*j==i)                        // the earliest possible point to break
119    { break;
120    }
121    j++;
122  }
123  min=min/leadcoef(min);               // making sure that the leading
124  return(min);                         // coefficient is 1
125}
126example
127{ "EXAMPLE:"; echo=2;
128          ring R=0,(x,y,z),dp;
129          print(cyclotomic(25));
130}
131
132proc group_reynolds (list #)
133"USAGE:   group_reynolds(G1,G2,...[,v]);
134         G1,G2,...: nxn <matrices> generating a finite matrix group, v: an
135         optional <int>
136ASSUME:  n is the number of variables of the basering, g the number of group
137         elements
138RETURN:  a <list>, the first list element will be a gxn <matrix> representing
139         the Reynolds operator if we are in the non-modular case; if the
140         characteristic is >0, minpoly==0 and the finite group non-cyclic the
141         second list element is an <int> giving the lowest common multiple of
142         the matrix group elements' order (used in molien); in general all
143         other list elements are nxn <matrices> listing all elements of the
144         finite group
145DISPLAY: information if v does not equal 0
146THEORY:  The entire matrix group is generated by getting all left products of
147         generators with the new elements from the last run through the loop
148         (or the generators themselves during the first run). All the ones that
149         have been generated before are thrown out and the program terminates
150         when no new elements found in one run. Additionally each time a new
151         group element is found the corresponding ring mapping of which the
152         Reynolds operator is made up is generated. They are stored in the rows
153         of the first return value.
154EXAMPLE: example group_reynolds; shows an example
155"
156{ int ch=char(basering);              // the existance of the Reynolds operator
157                                      // is dependent on the characteristic of
158                                      // the base field
159  int gen_num;                        // number of generators
160 //------------------------ making sure the input is okay ---------------------
161  if (typeof(#[size(#)])=="int")
162  { if (size(#)==1)
163    { "ERROR:   there are no matrices given among the parameters";
164      return();
165    }
166    int v=#[size(#)];
167    gen_num=size(#)-1;
168  }
169  else                                 // last parameter is not <int>
170  { int v=0;                           // no information is default
171    gen_num=size(#);
172  }
173  if (typeof(#[1])<>"matrix")
174  { "ERROR:   The parameters must be a list of matrices and maybe an <int>";
175    return();
176  }
177  int n=nrows(#[1]);
178  if (n<>nvars(basering))
179  { "ERROR:   the number of variables of the basering needs to be the same";
180    "         as the dimension of the matrices";
181    return();
182  }
183  if (n<>ncols(#[1]))
184  { "ERROR:   matrices need to be square and of the same dimensions";
185    return();
186  }
187  matrix vars=matrix(maxideal(1));     // creating an nx1-matrix containing the
188  vars=transpose(vars);                // variables of the ring -
189  matrix REY=#[1]*vars;                // calculating the first ring mapping -
190                                       // REY will contain the Reynolds
191                                       // operator -
192  matrix G(1)=#[1];                    // G(k) are elements of the group -
193  if (ch<>0 && minpoly==0 && gen_num<>1) // finding out of which order the
194  { matrix I=diag(1,n);                  // group element is
195    matrix TEST=G(1);
196    int o1=1;
197    int o2;
198    while (TEST<>I)
199    { TEST=TEST*G(1);
200      o1++;
201    }
202  }
203  int i=1;
204 // -------------- doubles among the generators should be avoided -------------
205  for (int j=2;j<=gen_num;j++)         // this loop adds the parameters to the
206  {                                    // group, leaving out doubles and
207                                       // checking whether the parameters are
208                                       // compatible with the task of the
209                                       // procedure
210    if (not(typeof(#[j])=="matrix"))
211    { "ERROR:   The parameters must be a list of matrices and maybe an <int>";
212      return();
213    }
214    if ((n!=nrows(#[j])) or (n!=ncols(#[j])))
215    { "ERROR:   matrices need to be square and of the same dimensions";
216       return();
217    }
218    if (unique(G(1..i),#[j]))
219    { i++;
220      matrix G(i)=#[j];
221      if (ch<>0 && minpoly==0)         // finding out of which order the group
222      { TEST=G(i);                     // element is
223        o2=1;
224        while (TEST<>I)
225        { TEST=TEST*G(i);
226          o2++;
227        }
228        o1=o1*o2/gcd(o1,o2);           // lowest common multiple of the element
229      }                                // orders -
230      REY=concat(REY,#[j]*vars);       // adding ring homomorphisms to REY
231    }
232  }
233  int g=i;                             // G(1)..G(i) are generators without
234                                       // doubles - g generally is the number
235                                       // of elements in the group so far -
236  j=i;                                 // j is the number of new elements that
237                                       // we use as factors
238  int k, m, l;
239  if (v)
240  { "";
241    "  Generating the entire matrix group and the Reynolds operator...";
242    "";
243  }
244 // -------------- main loop that finds all the group elements ----------------
245  while (1)
246  { l=0;                               // l is the number of products we get in
247                                       // one going
248    for (m=g-j+1;m<=g;m++)
249    { for (k=1;k<=i;k++)
250      { l=l+1;
251        matrix P(l)=G(k)*G(m);         // possible new element
252      }
253    }
254    j=0;
255    for (k=1;k<=l;k++)
256    { if (unique(G(1..g),P(k)))
257      { j++;                           // a new factor for next run
258        g++;
259        matrix G(g)=P(k);              // a new group element -
260        if (ch<>0 && minpoly==0 && i<>1) // finding out of which order the
261        { TEST=G(g);                     //group element is
262          o2=1;
263          while (TEST<>I)
264          { TEST=TEST*G(g);
265            o2++;
266          }
267          o1=o1*o2/gcd(o1,o2);         // lowest common multiple of the element
268        }                              // orders -
269        REY=concat(REY,P(k)*vars);     // adding new mapping to REY
270        if (v)
271        { "  Group element "+string(g)+" has been found.";
272        }
273      }
274      kill P(k);
275    }
276    if (j==0)                          // when we didn't add any new elements
277    { break;                           // in one run through the while loop
278    }                                  // we are done
279  }
280  if (v)
281  { if (g<=i)
282    { "  There are only "+string(g)+" group elements.";
283    }
284    "";
285  }
286  REY=transpose(REY);                 // when we evaluate the Reynolds operator
287                                      // later on, we actually want 1xn
288                                      // matrices
289  if (ch<>0)
290  { if ((g%ch)==0)
291    { if (voice==2)
292      { "WARNING: The characteristic of the coefficient field divides the group order.";
293        "         Proceed without the Reynolds operator!";
294      }
295      else
296      { if (v)
297        { "  The characteristic of the base field divides the group order.";
298          "  We have to continue without Reynolds operator...";
299          "";
300        }
301      }
302      kill REY;
303      matrix REY[1][1]=0;
304      return(REY,G(1..g));
305    }
306    if (minpoly==0)
307    { if (i>1)
308      { return(REY,o1,G(1..g));
309      }
310      return(REY,G(1..g));
311    }
312  }
313  if (v)
314  { "  Done generating the group and the Reynolds operator.";
315    "";
316  }
317  return(REY,G(1..g));
318}
319example
320{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
321         ring R=0,(x,y,z),dp;
322         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
323         list L=group_reynolds(A);
324         print(L[1]);
325         print(L[2..size(L)]);
326}
327
328///////////////////////////////////////////////////////////////////////////////
329// Returns i such that root^i==n, i.e. it heavily relies on the right input.
330///////////////////////////////////////////////////////////////////////////////
331proc exponent(number n, number root)
332{ int i=0;
333   while((n/root^i)<>1)
334   { i++;
335   }
336   return(i);
337}
338///////////////////////////////////////////////////////////////////////////////
339
340proc molien (list #)
341"USAGE:   molien(G1,G2,...[,ringname,lcm,flags]);
342         G1,G2,...: nxn <matrices>, all elements of a finite matrix group,
343         ringname: a <string> giving a name for a new ring of characteristic 0
344         for the Molien series in case of prime characteristic, lcm: an <int>
345         giving the lowest common multiple of the elements' orders in case of
346         prime characteristic, minpoly==0 and a non-cyclic group, flags: an
347         optional <intvec> with three components: if the first element is not
348         equal to 0 characteristic 0 is simulated, i.e. the Molien series is
349         computed as if the base field were characteristic 0 (the user must
350         choose a field of large prime characteristic, e.g. 32003), the second
351         component should give the size of intervals between canceling common
352         factors in the expansion of the Molien series, 0 (the default) means
353         only once after generating all terms, in prime characteristic also a
354         negative number can be given to indicate that common factors should
355         always be canceled when the expansion is simple (the root of the
356         extension field does not occur among the coefficients)
357ASSUME:  n is the number of variables of the basering, G1,G2... are the group
358         elements generated by group_reynolds(), lcm is the second return value
359         of group_reynolds()
360RETURN:  in case of characteristic 0 a 1x2 <matrix> giving enumerator and
361         denominator of Molien series; in case of prime characteristic a ring
362         with the name `ringname` of characteristic 0 is created where the same
363         Molien series (named M) is stored
364DISPLAY: information if the third component of flags does not equal 0
365THEORY:  In characteristic 0 the terms 1/det(1-xE) for all group elements of
366         the Molien series are computed in a straight forward way. In prime
367         characteristic a Brauer lift is involved. The returned matrix gives
368         enumerator and denominator of the expanded version where common
369         factors have been canceled.
370EXAMPLE: example molien; shows an example
371"
372{ def br=basering;                     // the Molien series depends on the
373  int ch=char(br);                     // characteristic of the coefficient
374                                       // field -
375  int g;                               // size of the group
376 //---------------------- making sure the input is okay -----------------------
377  if (typeof(#[size(#)])=="intvec")
378  { if (size(#[size(#)])==3)
379    { int mol_flag=#[size(#)][1];
380      if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
381      { "ERROR:   the second component of <intvec> should be >=0"
382        return();
383      }
384      int interval=#[size(#)][2];
385      int v=#[size(#)][3];
386    }
387    else
388    { "ERROR:   <intvec> should have three components";
389      return();
390    }
391    if (ch<>0)
392    { if (typeof(#[size(#)-1])=="int")
393      { int r=#[size(#)-1];
394        if (typeof(#[size(#)-2])<>"string")
395        { "ERROR:   In characteristic p>0 a <string> must be given for the name of a new";
396          "         ring where the Molien series can be stored";
397          return();
398        }
399        else
400        { if (#[size(#)-2]=="")
401          { "ERROR:   <string> may not be empty";
402            return();
403          }
404          string newring=#[size(#)-2];
405          g=size(#)-3;
406        }
407      }
408      else
409      { if (typeof(#[size(#)-1])<>"string")
410        { "ERROR:   In characteristic p>0 a <string> must be given for the name of a new";
411          "         ring where the Molien series can be stored";
412          return();
413        }
414        else
415        { if (#[size(#)-1]=="")
416          { "ERROR:   <string> may not be empty";
417            return();
418          }
419          string newring=#[size(#)-1];
420          g=size(#)-2;
421          int r=g;
422        }
423      }
424    }
425    else                               // then <string> ist not needed
426    { g=size(#)-1;
427    }
428  }
429  else                                 // last parameter is not <intvec>
430  { int v=0;                           // no information is default
431    int mol_flag=0;                    // computing of Molien series is default
432    int interval=0;
433    if (ch<>0)
434    { if (typeof(#[size(#)])=="int")
435      { int r=#[size(#)];
436        if (typeof(#[size(#)-1])<>"string")
437        { "ERROR:   in characteristic p>0 a <string> must be given for the name of a new";
438          "         ring where the Molien series can be stored";
439            return();
440        }
441        else
442        { if (#[size(#)-1]=="")
443          { "ERROR:   <string> may not be empty";
444            return();
445          }
446          string newring=#[size(#)-1];
447          g=size(#)-2;
448        }
449      }
450      else
451      { if (typeof(#[size(#)])<>"string")
452        { "ERROR:   in characteristic p>0 a <string> must be given for the name of a new";
453          "         ring where the Molien series can be stored";
454          return();
455        }
456        else
457        { if (#[size(#)]=="")
458          { "ERROR:   <string> may not be empty";
459            return();
460          }
461          string newring=#[size(#)];
462          g=size(#)-1;
463          int r=g;
464        }
465      }
466    }
467    else
468    { g=size(#);
469    }
470  }
471  if (ch<>0)
472  { if ((g/r)*r<>g)
473   { "ERROR:   <int> should divide the group order."
474      return();
475    }
476  }
477  if (ch<>0)
478  { if ((g%ch)==0)
479    { if (voice==2)
480      { "WARNING: The characteristic of the coefficient field divides the group";
481        "         order. Proceed without the Molien series!";
482      }
483      else
484      { if (v)
485        { "  The characteristic of the base field divides the group order.";
486          "  We have to continue without Molien series...";
487          "";
488        }
489      }
490    }
491    if (minpoly<>0 && mol_flag==0)
492    { if (voice==2)
493      { "WARNING: It is impossible for this program to calculate the Molien series";
494        "         for finite groups over extension fields of prime characteristic.";
495      }
496      else
497      { if (v)
498        { "  Since it is impossible for this program to calculate the Molien series for";
499          "  invariant rings over extension fields of prime characteristic, we have to";
500          "  continue without it.";
501          "";
502        }
503      }
504      return();
505    }
506  }
507 //----------------------------------------------------------------------------
508  if (not(typeof(#[1])=="matrix"))
509  { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
510    return();
511  }
512  int n=nrows(#[1]);
513  if (n<>nvars(br))
514  { "ERROR:   the number of variables of the basering needs to be the same";
515    "         as the dimension of the square matrices";
516    return();
517  }
518  if (v && voice<>2)
519  { "";
520    "  Generating the Molien series...";
521    "";
522  }
523  if (v && voice==2)
524  { "";
525  }
526 //------------- calculating Molien series in characteristic 0 ----------------
527  if (ch==0)                           // when ch==0 we can calculate the Molien
528  { matrix I=diag(1,n);                // series in any case -
529    poly v1=maxideal(1)[1];            // the Molien series will be in terms of
530                                       // the first variable of the current
531                                       // ring -
532    matrix M[1][2];                    // M will contain the Molien series -
533    M[1,1]=0;                          // M[1,1] will be the numerator -
534    M[1,2]=1;                          // M[1,2] will be the denominator -
535    matrix s;                          // will help us canceling in the
536                                       // fraction
537    poly p;                            // will contain the denominator of the
538                                       // new term of the Molien series
539 //------------ computing 1/det(1+xE) for all E in the group ------------------
540    for (int j=1;j<=g;j++)
541    { if (not(typeof(#[j])=="matrix"))
542      { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
543        return();
544      }
545      if ((n<>nrows(#[j])) or (n<>ncols(#[j])))
546      { "ERROR:   matrices need to be square and of the same dimensions";
547         return();
548      }
549      p=det(I-v1*#[j]);                // denominator of new term -
550      M[1,1]=M[1,1]*p+M[1,2];          // expanding M[1,1]/M[1,2] + 1/p
551      M[1,2]=M[1,2]*p;
552      if (interval<>0)                 // canceling common terms of denominator
553      { if ((j/interval)*interval==j or j==g) // and enumerator -
554        { s=matrix(syz(ideal(M)));     // once gcd() is faster than syz() these
555          M[1,1]=-s[2,1];              // three lines should be replaced by the
556          M[1,2]=s[1,1];               // following three
557          // p=gcd(M[1,1],M[1,2]);
558          // M[1,1]=M[1,1]/p;
559          // M[1,2]=M[1,2]/p;
560        }
561      }
562      if (v)
563      { "  Term "+string(j)+" of the Molien series has been computed.";
564      }
565    }
566    if (interval==0)                   // canceling common terms of denominator
567    {                                  // and enumerator -
568      s=matrix(syz(ideal(M)));         // once gcd() is faster than syz() these
569      M[1,1]=-s[2,1];                  // three lines should be replaced by the
570      M[1,2]=s[1,1];                   // following three
571      // p=gcd(M[1,1],M[1,2]);
572      // M[1,1]=M[1,1]/p;
573      // M[1,2]=M[1,2]/p;
574    }
575    map slead=br,ideal(0);
576    s=slead(M);
577    M[1,1]=1/s[1,1]*M[1,1];           // numerator and denominator have to have
578    M[1,2]=1/s[1,2]*M[1,2];           // a constant term of 1
579    if (v)
580    { "";
581      "  We are done calculating the Molien series.";
582      "";
583    }
584    return(M);
585  }
586 //---- calculating Molien series in prime characteristic with Brauer lift ----
587  if (ch<>0 && mol_flag==0)
588  { if (g<>1)
589    { matrix G(1..g)=#[1..g];
590      if (interval<0)
591      { string Mstring;
592      }
593 //------ preparing everything for Brauer lifts into characteristic 0 ---------
594      ring Q=0,x,dp;                  // we want to extend our ring as well as
595                                      // the ring of rational numbers Q to
596                                      // contain r-th primitive roots of unity
597                                      // in order to factor characteristic
598                                      // polynomials of group elements into
599                                      // linear factors and lift eigenvalues to
600                                      // characteristic 0 -
601      poly minq=cyclotomic(r);        // minq now contains the size-of-group-th
602                                      // cyclotomic polynomial of Q, it is
603                                      // irreducible there
604      ring `newring`=(0,e),x,dp;
605      map f=Q,ideal(e);
606      minpoly=number(f(minq));         // e is now a r-th primitive root of
607                                       // unity -
608      kill Q, f;                       // no longer needed -
609      poly p=1;                        // used to build the denominator of the
610                                       // new term in the Molien series
611      matrix s[1][2];                  // used for canceling -
612      matrix M[1][2]=0,1;              // will contain Molien series -
613      ring v1br=char(br),x,dp;         // we calculate the r-th cyclotomic
614      poly minp=cyclotomic(r);         // polynomial of the base field and pick
615      minp=factorize(minp)[1][2];      // an irreducible factor of it -
616      if (deg(minp)==1)                // in this case the base field contains
617      { ring bre=char(br),x,dp;        // r-th roots of unity already
618        map f1=v1br,ideal(0);
619        number e=-number((f1(minp)));  // e is a r-th primitive root of unity
620      }
621      else
622      { ring bre=(char(br),e),x,dp;
623        map f1=v1br,ideal(e);
624        minpoly=number(f1(minp));      // e is a r-th primitive root of unity
625      }
626      map f2=br,ideal(0);              // we need f2 to map our group elements
627                                       // to this new extension field bre
628      matrix xI=diag(x,n);
629      poly p;                         // used for the characteristic polynomial
630                                      // to factor -
631      list L;                         // will contain the linear factors of the
632      ideal F;                        // characteristic polynomial of the group
633      intvec C;                       // elements and their powers
634      int i, j, k;
635 // -------------- finding all the terms of the Molien series -----------------
636      for (i=1;i<=g;i++)
637      { setring br;
638        if (not(typeof(#[i])=="matrix"))
639        { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
640          return();
641        }
642        if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
643        { "ERROR:   matrices need to be square and of the same dimensions";
644           return();
645        }
646        setring bre;
647        p=det(xI-f2(G(i)));           // characteristic polynomial of G(i)
648        L=factorize(p);
649        F=L[1];
650        C=L[2];
651        for (j=2;j<=ncols(F);j++)
652        { F[j]=-1*(F[j]-x);           // F[j] is now an eigenvalue of G(i),
653                                      // it is a power of a primitive r-th root
654                                      // of unity -
655          k=exponent(number(F[j]),e); // F[j]==e^k
656          setring `newring`;
657          p=p*(1-x*(e^k))^C[j];       // building the denominator of the new
658          setring bre;                // term
659        }
660//         -----------
661//         k=0;
662//         while(k<r)
663//         { map f3=basering,ideal(e^k);
664//           while (f3(p)==0)
665//           { p=p/(x-e^k);
666//             setring `newring`;
667//             p=p*(1-x*(e^k));        // building the denominator of the new
668//             setring bre;
669//           }
670//           kill f3;
671//           if (p==1)
672//           { break;
673//           }
674//           k=k+1;
675//         }
676        setring `newring`;
677        M[1,1]=M[1,1]*p+M[1,2];        // expanding M[1,1]/M[1,2] + 1/p
678        M[1,2]=M[1,2]*p;
679        if (interval<0)
680        { if (i<>g)
681          { Mstring=string(M);
682            for (j=1;j<=size(Mstring);j++)
683            { if (Mstring[j]=="e")
684              { interval=0;
685                break;
686              }
687            }
688          }
689          if (interval<>0)
690          { s=matrix(syz(ideal(M)));   // once gcd() is faster than syz()
691            M[1,1]=-s[2,1];            // these three lines should be
692            M[1,2]=s[1,1];             // replaced by the following three
693            // p=gcd(M[1,1],M[1,2]);
694            // M[1,1]=M[1,1]/p;
695            // M[1,2]=M[1,2]/p;
696          }
697          else
698          { interval=-1;
699          }
700        }
701        else
702        { if (interval<>0)             // canceling common terms of denominator
703          { if ((i/interval)*interval==i or i==g) // and enumerator
704            { s=matrix(syz(ideal(M))); // once gcd() is faster than syz()
705              M[1,1]=-s[2,1];          // these three lines should be
706              M[1,2]=s[1,1];           // replaced by the following three
707              // p=gcd(M[1,1],M[1,2]);
708              // M[1,1]=M[1,1]/p;
709              // M[1,2]=M[1,2]/p;
710            }
711          }
712        }
713        p=1;
714        setring bre;
715        if (v)
716        { "  Term "+string(i)+" of the Molien series has been computed.";
717        }
718      }
719      if (v)
720      { "";
721      }
722      setring `newring`;
723      if (interval==0)                 // canceling common terms of denominator
724      {                                // and enumerator -
725        s=matrix(syz(ideal(M)));       // once gcd() is faster than syz() these
726        M[1,1]=-s[2,1];                // three lines should be replaced by the
727        M[1,2]=s[1,1];                 // following three
728        // p=gcd(M[1,1],M[1,2]);
729        // M[1,1]=M[1,1]/p;
730        // M[1,2]=M[1,2]/p;
731      }
732      map slead=`newring`,ideal(0);
733      s=slead(M);                     // forcing the constant term of numerator
734      M[1,1]=1/s[1,1]*M[1,1];         // and denominator to be 1
735      M[1,2]=1/s[1,2]*M[1,2];
736      kill slead;
737      kill s;
738      kill p;
739    }
740    else                              // if the group only contains an identity
741    { ring `newring`=0,x,dp;          // element, it is very easy to calculate
742      matrix M[1][2]=1,(1-x)^n;       // the Molien series
743    }
744    exportto(Top,`newring`);          // we keep the ring where we computed the
745    export M;                         // Molien series in such that we can
746    setring br;                       // keep it
747    if (v)
748    { "  We are done calculating the Molien series.";
749      "";
750    }
751  }
752  else                                // i.e. char<>0 and mol_flag<>0, the user
753  {                                   // has specified that we are dealing with
754                                      // a ring of large characteristic which
755                                      // can be treated like a ring of
756                                      // characteristic 0; we'll avoid the
757                                      // Brauer lifts
758 //----------------------- simulating characteristic 0 ------------------------
759    string chst=charstr(br);
760    for (int i=1;i<=size(chst);i++)
761    { if (chst[i]==",")
762      { break;
763      }
764    }
765 //----------------- generating ring of characteristic 0 ----------------------
766    if (minpoly==0)
767    { if (i>size(chst))
768      { execute("ring "+newring+"=0,("+varstr(br)+"),("+ordstr(br)+")");
769      }
770      else
771      { chst=chst[i..size(chst)];
772        execute
773        ("ring "+newring+"=(0"+chst+"),("+varstr(br)+"),("+ordstr(br)+")");
774      }
775    }
776    else
777    { string minp=string(minpoly);
778      minp=minp[2..size(minp)-1];
779      chst=chst[i..size(chst)];
780      execute("ring "+newring+"=(0"+chst+"),("+varstr(br)+"),("+ordstr(br)+")");
781      execute("minpoly="+minp);
782    }
783    matrix I=diag(1,n);
784    poly v1=maxideal(1)[1];            // the Molien series will be in terms of
785                                       // the first variable of the current
786                                       // ring -
787    matrix M[1][2];                    // M will contain the Molien series -
788    M[1,1]=0;                          // M[1,1] will be the numerator -
789    M[1,2]=1;                          // M[1,2] will be the denominator -
790    matrix s;                          // will help us canceling in the
791                                       // fraction
792    poly p;                            // will contain the denominator of the
793                                       // new term of the Molien series
794    int j;
795    string links, rechts;
796 //----------------- finding all terms of the Molien series -------------------
797    for (i=1;i<=g;i++)
798    { setring br;
799      if (not(typeof(#[i])=="matrix"))
800      { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
801        return();
802      }
803      if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
804      { "ERROR:   matrices need to be square and of the same dimensions";
805         return();
806      }
807      string stM(i)=string(#[i]);
808      for (j=1;j<=size(stM(i));j++)
809      { if (stM(i)[j]=="
810")
811        { links=stM(i)[1..j-1];
812          rechts=stM(i)[j+1..size(stM(i))];
813          stM(i)=links+rechts;
814        }
815      }
816      setring `newring`;
817      execute("matrix G(i)["+string(n)+"]["+string(n)+"]="+stM(i));
818      p=det(I-v1*G(i));                // denominator of new term -
819      M[1,1]=M[1,1]*p+M[1,2];          // expanding M[1,1]/M[1,2] + 1/p
820      M[1,2]=M[1,2]*p;
821      if (interval<>0)                 // canceling common terms of denominator
822      { if ((i/interval)*interval==i or i==g) // and enumerator
823        {
824          s=matrix(syz(ideal(M)));     // once gcd() is faster than syz() these
825          M[1,1]=-s[2,1];              // three lines should be replaced by the
826          M[1,2]=s[1,1];               // following three
827          // p=gcd(M[1,1],M[1,2]);
828          // M[1,1]=M[1,1]/p;
829          // M[1,2]=M[1,2]/p;
830        }
831      }
832      if (v)
833      { "  Term "+string(i)+" of the Molien series has been computed.";
834      }
835    }
836    if (interval==0)                   // canceling common terms of denominator
837    {                                  // and enumerator -
838      s=matrix(syz(ideal(M)));         // once gcd() is faster than syz() these
839      M[1,1]=-s[2,1];                  // three lines should be replaced by the
840      M[1,2]=s[1,1];                   // following three
841      // p=gcd(M[1,1],M[1,2]);
842      // M[1,1]=M[1,1]/p;
843      // M[1,2]=M[1,2]/p;
844    }
845    map slead=`newring`,ideal(0);
846    s=slead(M);
847    M[1,1]=1/s[1,1]*M[1,1];           // numerator and denominator have to have
848    M[1,2]=1/s[1,2]*M[1,2];           // a constant term of 1
849    if (v)
850    { "";
851      "  We are done calculating the Molien series.";
852      "";
853    }
854    kill G(1..g), s, slead, p, v1, I;
855    export `newring`;                 // we keep the ring where we computed the
856    export M;                         // the Molien series such that we can
857    setring br;                       // keep it
858  }
859}
860example
861{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
862  "         note the case of prime characteristic"; echo=2;
863         ring R=0,(x,y,z),dp;
864         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
865         list L=group_reynolds(A);
866         matrix M=molien(L[2..size(L)]);
867         print(M);
868         ring S=3,(x,y,z),dp;
869         string newring="alksdfjlaskdjf";
870         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
871         list L=group_reynolds(A);
872         molien(L[2..size(L)],newring);
873         setring alksdfjlaskdjf;
874         print(M);
875         setring S;
876         kill alksdfjlaskdjf;
877}
878///////////////////////////////////////////////////////////////////////////////
879
880proc reynolds_molien (list #)
881"USAGE:   reynolds_molien(G1,G2,...[,ringname,flags]);
882         G1,G2,...: nxn <matrices> generating a finite matrix group, ringname:
883         a <string> giving a name for a new ring of characteristic 0 for the
884         Molien series in case of prime characteristic, flags: an optional
885         <intvec> with three components: if the first element is not equal to 0
886         characteristic 0 is simulated, i.e. the Molien series is computed as
887         if the base field were characteristic 0 (the user must choose a field
888         of large prime characteristic, e.g. 32003) the second component should
889         give the size of intervals between canceling common factors in the
890         expansion of the Molien series, 0 (the default) means only once after
891         generating all terms, in prime characteristic also a negative number
892         can be given to indicate that common factors should always be canceled
893         when the expansion is simple (the root of the extension field does not
894         occur among the coefficients)
895ASSUME:  n is the number of variables of the basering, G1,G2... are the group
896         elements generated by group_reynolds(), g is the size of the group
897RETURN:  a gxn <matrix> representing the Reynolds operator is the first return
898         value and in case of characteristic 0 a 1x2 <matrix> giving enumerator
899         and denominator of Molien series is the second one; in case of prime
900         characteristic a ring with the name `ringname` of characteristic 0 is
901         created where the same Molien series (named M) is stored
902DISPLAY: information if the third component of flags does not equal 0
903THEORY:  The entire matrix group is generated by getting all left products of
904         the generators with new elements from the last run through the loop
905         (or the generators themselves during the first run). All the ones that
906         have been generated before are thrown out and the program terminates
907         when are no new elements found in one run. Additionally each time a
908         new group element is found the corresponding ring mapping of which the
909         Reynolds operator is made up is generated. They are stored in the rows
910         of the first return value. In characteristic 0 the terms 1/det(1-xE)
911         is computed whenever a new element E is found. In prime characteristic
912         a Brauer lift is involved and the terms are only computed after the
913         entire matrix group is generated (to avoid the modular case). The
914         returned matrix gives enumerator and denominator of the expanded
915         version where common factors have been canceled.
916EXAMPLE: example reynolds_molien; shows an example
917"
918{ def br=basering;                     // the Molien series depends on the
919  int ch=char(br);                     // characteristic of the coefficient
920                                       // field
921  int gen_num;
922 //------------------- making sure the input is okay --------------------------
923  if (typeof(#[size(#)])=="intvec")
924  { if (size(#[size(#)])==3)
925    { int mol_flag=#[size(#)][1];
926      if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
927      { "ERROR:   the second component of the <intvec> should be >=0";
928        return();
929      }
930      int interval=#[size(#)][2];
931      int v=#[size(#)][3];
932    }
933    else
934    { "ERROR:   <intvec> should have three components";
935      return();
936    }
937    if (ch<>0)
938    { if (typeof(#[size(#)-1])<>"string")
939      { "ERROR:   in characteristic p a <string> must be given for the name";
940        "         of a new ring where the Molien series can be stored";
941        return();
942      }
943      else
944      { if (#[size(#)-1]=="")
945        { "ERROR:   <string> may not be empty";
946          return();
947        }
948        string newring=#[size(#)-1];
949        gen_num=size(#)-2;
950      }
951    }
952    else                               // then <string> ist not needed
953    { gen_num=size(#)-1;
954    }
955  }
956  else                                 // last parameter is not <intvec>
957  { int v=0;                           // no information is default
958    int interval;
959    int mol_flag=0;                    // computing of Molien series is default
960    if (ch<>0)
961    { if (typeof(#[size(#)])<>"string")
962      { "ERROR:   in characteristic p a <string> must be given for the name";
963        "         of a new ring where the Molien series can be stored";
964        return();
965      }
966      else
967      { if (#[size(#)]=="")
968        { "ERROR:   <string> may not be empty";
969          return();
970        }
971        string newring=#[size(#)];
972        gen_num=size(#)-1;
973      }
974    }
975    else
976    { gen_num=size(#);
977    }
978  }
979 // ----------------- computing the terms with Brauer lift --------------------
980  if (ch<>0 && mol_flag==0)
981  { list L=group_reynolds(#[1..gen_num],v);
982    if (L[1]==0)
983    { if (voice==2)
984      { "WARNING: The characteristic of the coefficient field divides the group order.";
985        "         Proceed without the Reynolds operator or the Molien series!";
986        return();
987      }
988      if (v)
989      { "  The characteristic of the base field divides the group order.";
990        "  We have to continue without Reynolds operator or the Molien series...";
991        return();
992      }
993    }
994    if (minpoly<>0)
995    { if (voice==2)
996      { "WARNING: It is impossible for this program to calculate the Molien series";
997        "         for finite groups over extension fields of prime characteristic.";
998        return(L[1]);
999      }
1000      else
1001      { if (v)
1002        { "  Since it is impossible for this program to calculate the Molien series for";
1003          "  invariant rings over extension fields of prime characteristic, we have to";
1004          "  continue without it.";
1005          return(L[1]);
1006        }
1007      }
1008    }
1009    if (typeof(L[2])=="int")
1010    { molien(L[3..size(L)],newring,L[2],intvec(mol_flag,interval,v));
1011    }
1012    else
1013    { molien(L[2..size(L)],newring,intvec(mol_flag,interval,v));
1014    }
1015    return(L[1]);
1016  }
1017 //----------- computing Molien series in the straight forward way ------------
1018  if (ch==0)
1019  { if (typeof(#[1])<>"matrix")
1020    { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
1021      return();
1022    }
1023    int n=nrows(#[1]);
1024    if (n<>nvars(br))
1025    { "ERROR:   the number of variables of the basering needs to be the same";
1026      "         as the dimension of the matrices";
1027      return();
1028    }
1029    if (n<>ncols(#[1]))
1030    { "ERROR:   matrices need to be square and of the same dimensions";
1031      return();
1032    }
1033    matrix vars=matrix(maxideal(1));   // creating an nx1-matrix containing the
1034    vars=transpose(vars);              // variables of the ring -
1035    matrix A(1)=#[1]*vars;             // calculating the first ring mapping -
1036                                       // A(1) will contain the Reynolds
1037                                       // operator -
1038    poly v1=vars[1,1];                 // the Molien series will be in terms of
1039                                       // the first variable of the current
1040                                       // ring
1041    matrix I=diag(1,n);
1042    matrix A(2)[1][2];                 // A(2) will contain the Molien series -
1043    A(2)[1,1]=1;                       // A(2)[1,1] will be the numerator
1044    matrix G(1)=#[1];                  // G(k) are elements of the group -
1045    A(2)[1,2]=det(I-v1*(G(1)));        // A(2)[1,2] will be the denominator -
1046    matrix s;                          // will help us canceling in the
1047                                       // fraction
1048    poly p;                            // will contain the denominator of the
1049                                       // new term of the Molien series
1050    int i=1;
1051    for (int j=2;j<=gen_num;j++)       // this loop adds the parameters to the
1052    {                                  // group, leaving out doubles and
1053                                       // checking whether the parameters are
1054                                       // compatible with the task of the
1055                                       // procedure
1056      if (not(typeof(#[j])=="matrix"))
1057      { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
1058        return();
1059      }
1060      if ((n!=nrows(#[j])) or (n!=ncols(#[j])))
1061      { "ERROR:   matrices need to be square and of the same dimensions";
1062         return();
1063      }
1064      if (unique(G(1..i),#[j]))
1065      { i++;
1066        matrix G(i)=#[j];
1067        A(1)=concat(A(1),#[j]*vars);   // adding ring homomorphisms to A(1) -
1068        p=det(I-v1*#[j]);              // denominator of new term -
1069        A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2]; // expanding A(2)[1,1]/A(2)[1,2] +1/p
1070        A(2)[1,2]=A(2)[1,2]*p;
1071        if (interval<>0)               // canceling common terms of denominator
1072        { if ((i/interval)*interval==i) // and enumerator
1073          {
1074            s=matrix(syz(ideal(A(2)))); // once gcd() is faster than syz() these
1075            A(2)[1,1]=-s[2,1];         // three lines should be replaced by the
1076            A(2)[1,2]=s[1,1];          // following three
1077            // p=gcd(A(2)[1,1],A(2)[1,2]);
1078            // A(2)[1,1]=A(2)[1,1]/p;
1079            // A(2)[1,2]=A(2)[1,2]/p;
1080          }
1081        }
1082      }
1083    }
1084    int g=i;                           // G(1)..G(i) are generators without
1085                                       // doubles - g generally is the number
1086                                       // of elements in the group so far -
1087    j=i;                               // j is the number of new elements that
1088                                       // we use as factors
1089    int k, m, l;
1090    if (v)
1091    { "";
1092      "  Generating the entire matrix group. Whenever a new group element is found,";
1093      "  the corresponding ring homomorphism of the Reynolds operator and the";
1094      "  corresponding term of the Molien series is generated.";
1095      "";
1096    }
1097 //----------- computing 1/det(I-xE) whenever a new element E is found --------
1098    while (1)
1099    { l=0;                             // l is the number of products we get in
1100                                       // one going
1101      for (m=g-j+1;m<=g;m=m+1)
1102      { for (k=1;k<=i;k++)
1103        { l++;
1104          matrix P(l)=G(k)*G(m);       // possible new element
1105        }
1106      }
1107      j=0;
1108      for (k=1;k<=l;k++)
1109      { if (unique(G(1..g),P(k)))
1110        { j++;                         // a new factor for next run
1111          g++;
1112          matrix G(g)=P(k);            // a new group element -
1113          A(1)=concat(A(1),P(k)*vars); // adding new mapping to A(1)
1114          p=det(I-v1*P(k));            // denominator of new term
1115          A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2];
1116          A(2)[1,2]=A(2)[1,2]*p;       // expanding A(2)[1,1]/A(2)[1,2] + 1/p -
1117          if (interval<>0)             // canceling common terms of denominator
1118          { if ((g/interval)*interval==g) // and enumerator
1119            {
1120              s=matrix(syz(ideal(A(2)))); // once gcd() is faster than syz()
1121              A(2)[1,1]=-s[2,1];       // these three lines should be replaced
1122              A(2)[1,2]=s[1,1];        // by the following three
1123              // p=gcd(A(2)[1,1],A(2)[1,2]);
1124              // A(2)[1,1]=A(2)[1,1]/p;
1125              // A(2)[1,2]=A(2)[1,2]/p;
1126            }
1127          }
1128          if (v)
1129          { "  Group element "+string(g)+" has been found.";
1130          }
1131        }
1132        kill P(k);
1133      }
1134      if (j==0)                        // when we didn't add any new elements
1135      { break;                         // in one run through the while loop
1136      }                                // we are done
1137    }
1138    if (v)
1139    { if (g<=i)
1140      { "  There are only "+string(g)+" group elements.";
1141      }
1142      "";
1143    }
1144    A(1)=transpose(A(1));             // when we evaluate the Reynolds operator
1145                                      // later on, we actually want 1xn
1146                                      // matrices
1147    if (interval==0)                  // canceling common terms of denominator
1148    {                                 // and enumerator -
1149      s=matrix(syz(ideal(A(2))));     // once gcd() is faster than syz()
1150      A(2)[1,1]=-s[2,1];              // these three lines should be replaced
1151      A(2)[1,2]=s[1,1];               // by the following three
1152      // p=gcd(A(2)[1,1],A(2)[1,2]);
1153      // A(2)[1,1]=A(2)[1,1]/p;
1154      // A(2)[1,2]=A(2)[1,2]/p;
1155    }
1156    if (interval<>0)                   // canceling common terms of denominator
1157    { if ((g/interval)*interval<>g)    // and enumerator
1158      {
1159        s=matrix(syz(ideal(A(2))));    // once gcd() is faster than syz()
1160        A(2)[1,1]=-s[2,1];             // these three lines should be replaced
1161        A(2)[1,2]=s[1,1];              // by the following three
1162        // p=gcd(A(2)[1,1],A(2)[1,2]);
1163        // A(2)[1,1]=A(2)[1,1]/p;
1164        // A(2)[1,2]=A(2)[1,2]/p;
1165      }
1166    }
1167    map slead=br,ideal(0);
1168    s=slead(A(2));
1169    A(2)[1,1]=1/s[1,1]*A(2)[1,1];     // numerator and denominator have to have
1170    A(2)[1,2]=1/s[1,2]*A(2)[1,2];     // a constant term of 1
1171    if (v)
1172    { "  Now we are done calculating Molien series and Reynolds operator.";
1173      "";
1174    }
1175    return(A(1..2));
1176  }
1177 //------------------------ simulating characteristic 0 -----------------------
1178  else                                 // if ch<>0 and mol_flag<>0
1179  { if (typeof(#[1])<>"matrix")
1180    { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
1181      return();
1182    }
1183    int n=nrows(#[1]);
1184    if (n<>nvars(br))
1185    { "ERROR:   the number of variables of the basering needs to be the same";
1186      "         as the dimension of the matrices";
1187      return();
1188    }
1189    if (n<>ncols(#[1]))
1190    { "ERROR:   matrices need to be square and of the same dimensions";
1191      return();
1192    }
1193    matrix vars=matrix(maxideal(1));   // creating an nx1-matrix containing the
1194    vars=transpose(vars);              // variables of the ring -
1195    matrix A(1)=#[1]*vars;             // calculating the first ring mapping -
1196                                       // A(1) will contain the Reynolds
1197                                       // operator
1198    string chst=charstr(br);
1199    for (int i=1;i<=size(chst);i++)
1200    { if (chst[i]==",")
1201      { break;
1202      }
1203    }
1204    if (minpoly==0)
1205    { if (i>size(chst))
1206      { execute("ring "+newring+"=0,("+varstr(br)+"),("+ordstr(br)+")");
1207      }
1208      else
1209      { chst=chst[i..size(chst)];
1210        execute
1211        ("ring "+newring+"=(0"+chst+"),("+varstr(br)+"),("+ordstr(br)+")");
1212      }
1213    }
1214    else
1215    { string minp=string(minpoly);
1216      minp=minp[2..size(minp)-1];
1217      chst=chst[i..size(chst)];
1218      execute("ring "+newring+"=(0"+chst+"),("+varstr(br)+"),("+ordstr(br)+")");
1219      execute("minpoly="+minp);
1220    }
1221    poly v1=var(1);                    // the Molien series will be in terms of
1222                                       // the first variable of the current
1223                                       // ring
1224    matrix I=diag(1,n);
1225    int o;
1226    setring br;
1227    matrix G(1)=#[1];
1228    string links, rechts;
1229    string stM(1)=string(#[1]);
1230    for (o=1;o<=size(stM(1));o++)
1231    { if (stM(1)[o]=="
1232")
1233      { links=stM(1)[1..o-1];
1234        rechts=stM(1)[o+1..size(stM(1))];
1235        stM(1)=links+rechts;
1236      }
1237    }
1238    setring `newring`;
1239    execute("matrix G(1)["+string(n)+"]["+string(n)+"]="+stM(1));
1240    matrix A(2)[1][2];                 // A(2) will contain the Molien series -
1241    A(2)[1,1]=1;                       // A(2)[1,1] will be the numerator
1242    A(2)[1,2]=det(I-v1*(G(1)));        // A(2)[1,2] will be the denominator -
1243    matrix s;                          // will help us canceling in the
1244                                       // fraction
1245    poly p;                            // will contain the denominator of the
1246                                       // new term of the Molien series
1247    i=1;
1248    for (int j=2;j<=gen_num;j++)       // this loop adds the parameters to the
1249    {                                  // group, leaving out doubles and
1250                                       // checking whether the parameters are
1251                                       // compatible with the task of the
1252                                       // procedure
1253      setring br;
1254      if (not(typeof(#[j])=="matrix"))
1255      { "ERROR:   the parameters must be a list of matrices and maybe an <intvec>";
1256        return();
1257      }
1258      if ((n!=nrows(#[j])) or (n!=ncols(#[j])))
1259      { "ERROR:   matrices need to be square and of the same dimensions";
1260         return();
1261      }
1262      if (unique(G(1..i),#[j]))
1263      { i++;
1264        matrix G(i)=#[j];
1265        A(1)=concat(A(1),G(i)*vars);   // adding ring homomorphisms to A(1)
1266        string stM(i)=string(G(i));
1267        for (o=1;o<=size(stM(i));o++)
1268        { if (stM(i)[o]=="
1269")
1270          { links=stM(i)[1..o-1];
1271            rechts=stM(i)[o+1..size(stM(i))];
1272            stM(i)=links+rechts;
1273          }
1274        }
1275        setring `newring`;
1276        execute("matrix G(i)["+string(n)+"]["+string(n)+"]="+stM(i));
1277        p=det(I-v1*G(i));              // denominator of new term -
1278        A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2]; // expanding A(2)[1,1]/A(2)[1,2] +1/p
1279        A(2)[1,2]=A(2)[1,2]*p;
1280        if (interval<>0)               // canceling common terms of denominator
1281        { if ((i/interval)*interval==i) // and enumerator
1282          {
1283            s=matrix(syz(ideal(A(2)))); // once gcd() is faster than syz() these
1284            A(2)[1,1]=-s[2,1];         // three lines should be replaced by the
1285            A(2)[1,2]=s[1,1];          // following three
1286            // p=gcd(A(2)[1,1],A(2)[1,2]);
1287            // A(2)[1,1]=A(2)[1,1]/p;
1288            // A(2)[1,2]=A(2)[1,2]/p;
1289          }
1290        }
1291        setring br;
1292      }
1293    }
1294    int g=i;                           // G(1)..G(i) are generators without
1295                                       // doubles - g generally is the number
1296                                       // of elements in the group so far -
1297    j=i;                               // j is the number of new elements that
1298                                       // we use as factors
1299    int k, m, l;
1300    if (v)
1301    { "";
1302      "  Generating the entire matrix group. Whenever a new group element is found,";
1303      "  the corresponding ring homomorphism of the Reynolds operator and the";
1304      "  corresponding term of the Molien series is generated.";
1305      "";
1306    }
1307 // taking all elements in a ring of characteristic 0 and computing the terms
1308 // of the Molien series there
1309    while (1)
1310    { l=0;                             // l is the number of products we get in
1311                                       // one going
1312      for (m=g-j+1;m<=g;m++)
1313      { for (k=1;k<=i;k++)
1314        { l++;
1315          matrix P(l)=G(k)*G(m);       // possible new element
1316        }
1317      }
1318      j=0;
1319      for (k=1;k<=l;k++)
1320      { if (unique(G(1..g),P(k)))
1321        { j++;                         // a new factor for next run
1322          g++;
1323          matrix G(g)=P(k);            // a new group element -
1324          A(1)=concat(A(1),G(g)*vars); // adding new mapping to A(1)
1325          string stM(g)=string(G(g));
1326          for (o=1;o<=size(stM(g));o++)
1327          { if (stM(g)[o]=="
1328")
1329            { links=stM(g)[1..o-1];
1330              rechts=stM(g)[o+1..size(stM(g))];
1331              stM(g)=links+rechts;
1332            }
1333          }
1334          setring `newring`;
1335          execute("matrix G(g)["+string(n)+"]["+string(n)+"]="+stM(g));
1336          p=det(I-v1*G(g));            // denominator of new term
1337          A(2)[1,1]=A(2)[1,1]*p+A(2)[1,2];
1338          A(2)[1,2]=A(2)[1,2]*p;       // expanding A(2)[1,1]/A(2)[1,2] + 1/p -
1339          if (interval<>0)             // canceling common terms of denominator
1340          { if ((g/interval)*interval==g) // and enumerator
1341            {
1342              s=matrix(syz(ideal(A(2)))); // once gcd() is faster than syz()
1343              A(2)[1,1]=-s[2,1];       // these three lines should be replaced
1344              A(2)[1,2]=s[1,1];        // by the following three
1345              // p=gcd(A(2)[1,1],A(2)[1,2]);
1346              // A(2)[1,1]=A(2)[1,1]/p;
1347              // A(2)[1,2]=A(2)[1,2]/p;
1348            }
1349          }
1350          if (v)
1351          { "  Group element "+string(g)+" has been found.";
1352          }
1353          setring br;
1354        }
1355        kill P(k);
1356      }
1357      if (j==0)                        // when we didn't add any new elements
1358      { break;                         // in one run through the while loop
1359      }                                // we are done
1360    }
1361    if (v)
1362    { if (g<=i)
1363      { "  There are only "+string(g)+" group elements.";
1364      }
1365      "";
1366    }
1367    A(1)=transpose(A(1));              // when we evaluate the Reynolds operator
1368                                       // later on, we actually want 1xn
1369                                       // matrices
1370    setring `newring`;
1371    if (interval==0)                   // canceling common terms of denominator
1372    {                                  // and enumerator -
1373      s=matrix(syz(ideal(A(2))));      // once gcd() is faster than syz()
1374      A(2)[1,1]=-s[2,1];               // these three lines should be replaced
1375      A(2)[1,2]=s[1,1];                // by the following three
1376      // p=gcd(A(2)[1,1],A(2)[1,2]);
1377      // A(2)[1,1]=A(2)[1,1]/p;
1378      // A(2)[1,2]=A(2)[1,2]/p;
1379    }
1380    if (interval<>0)                   // canceling common terms of denominator
1381    { if ((g/interval)*interval<>g)    // and enumerator
1382      {
1383        s=matrix(syz(ideal(A(2))));    // once gcd() is faster than syz()
1384        A(2)[1,1]=-s[2,1];             // these three lines should be replaced
1385        A(2)[1,2]=s[1,1];              // by the following three
1386        // p=gcd(A(2)[1,1],A(2)[1,2]);
1387        // A(2)[1,1]=A(2)[1,1]/p;
1388        // A(2)[1,2]=A(2)[1,2]/p;
1389      }
1390    }
1391    map slead=`newring`,ideal(0);
1392    s=slead(A(2));
1393    A(2)[1,1]=1/s[1,1]*A(2)[1,1];     // numerator and denominator have to have
1394    A(2)[1,2]=1/s[1,2]*A(2)[1,2];     // a constant term of 1
1395    if (v)
1396    { "  Now we are done calculating Molien series and Reynolds operator.";
1397      "";
1398    }
1399    matrix M=A(2);
1400    kill G(1..g), s, slead, p, v1, I, A(2);
1401    export `newring`;                 // we keep the ring where we computed the
1402    export M;                         // the Molien series such that we can
1403    setring br;                       // keep it
1404    return(A(1));
1405  }
1406}
1407example
1408{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
1409  "         note the case of prime characteristic"; echo=2;
1410         ring R=0,(x,y,z),dp;
1411         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1412         matrix REY,M=reynolds_molien(A);
1413         print(REY);
1414         print(M);
1415         ring S=3,(x,y,z),dp;
1416         string newring="Qadjoint";
1417         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1418         matrix REY=reynolds_molien(A,newring);
1419         print(REY);
1420         setring Qadjoint;
1421         print(M);
1422         setring S;
1423         kill Qadjoint;
1424}
1425///////////////////////////////////////////////////////////////////////////////
1426
1427proc partial_molien (matrix M, int n, list #)
1428"USAGE:   partial_molien(M,n[,p]);
1429         M: a 1x2 <matrix>, n: an <int> indicating  number of terms in the
1430         expansion, p: an optional <poly>
1431ASSUME:  M is the return value of molien or the second return value of
1432         reynolds_molien, p ought to be the second return value of a previous
1433         run of partial_molien and avoids recalculating known terms
1434RETURN:  n terms (type <poly>) of the partial expansion of the Molien series
1435         (first n if there is no third parameter given, otherwise the next n
1436         terms depending on a previous calculation) and an intermediate result
1437         (type <poly>) of the calculation to be used as third parameter in a
1438         next run of partial_molien
1439THEORY:  The following calculation is implemented:
1440@format
1441(1+a1x+a2x^2+...+anx^n)/(1+b1x+b2x^2+...+bmx^m)=(1+(a1-b1)x+...
1442(1+b1x+b2x^2+...+bmx^m)
1443-----------------------
1444   (a1-b1)x+(a2-b2)x^2+...
1445   (a1-b1)x+b1(a1-b1)x^2+...
1446@end format
1447EXAMPLE: example partial_molien; shows an example
1448"
1449{ poly A(2);                           // A(2) will contain the return value of
1450                                       // the intermediate result
1451  if (char(basering)<>0)
1452  { "ERROR:   you have to change to a basering of characteristic 0, one in";
1453    "         which the Molien series is defined";
1454  }
1455  if (ncols(M)==2 && nrows(M)==1 && n>0 && size(#)<2)
1456  { def br=basering;                   // keeping track of the old ring
1457    map slead=br,ideal(0);
1458    matrix s=slead(M);
1459    if (s[1,1]<>1 || s[1,2]<>1)
1460    { "ERROR:   the constant terms of enumerator and denominator are not 1";
1461      return();
1462    }
1463
1464    if (size(#)==0)
1465    { A(2)=M[1,1];                    // if a third parameter is not given, the
1466                                      // intermediate result from the last run
1467                                      // corresponds to the numerator - we need
1468    }                                 // its smallest term
1469    else
1470    { if (typeof(#[1])=="poly")
1471      { A(2)=#[1];                    // if a third term is given we 'start'
1472      }                               // with its smallest term
1473      else
1474      { "ERROR:   <poly> as third parameter expected";
1475        return();
1476      }
1477    }
1478    poly A(1)=M[1,2];                 // denominator of Molien series (for now)
1479    string mp=string(minpoly);
1480    execute("ring R=("+charstr(br)+"),("+varstr(br)+"),ds;");
1481    execute("minpoly=number("+mp+");");
1482    poly A(1)=0;                      // A(1) will contain the sum of n terms -
1483    poly min;                         // min will be our smallest term -
1484    poly A(2)=fetch(br,A(2));         // fetching A(2) and M[1,2] into R
1485    poly den=fetch(br,A(1));
1486    for (int i=1; i<=n; i++)          // getting n terms and adding them up
1487    { min=lead(A(2));
1488      A(1)=A(1)+min;
1489      A(2)=A(2)-min*den;
1490    }
1491    setring br;                       // moving A(1) and A(2) back in the
1492    A(1)=fetch(R,A(1));               // actual ring for output
1493    A(2)=fetch(R,A(2));
1494    return(A(1..2));
1495  }
1496  else
1497  { "ERROR:   the first parameter has to be a 1x2-matrix, i.e. the matrix";
1498    "         returned by the procedure 'reynolds_molien', the second one";
1499    "         should be > 0 and there should be no more than 3 parameters;"
1500    return();
1501  }
1502}
1503example
1504{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1505         ring R=0,(x,y,z),dp;
1506         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1507         matrix REY,M=reynolds_molien(A);
1508         poly p(1..2);
1509         p(1..2)=partial_molien(M,5);
1510         p(1);
1511         p(1..2)=partial_molien(M,5,p(2));
1512         p(1);
1513}
1514///////////////////////////////////////////////////////////////////////////////
1515
1516proc evaluate_reynolds (matrix REY, ideal I)
1517"USAGE:   evaluate_reynolds(REY,I);
1518         REY: a <matrix> representing the Reynolds operator, I: an arbitrary
1519         <ideal>
1520ASSUME:  REY is the first return value of group_reynolds() or reynolds_molien()
1521RETURNS: image of the polynomials defining I under the Reynolds operator
1522         (type <ideal>)
1523NOTE:    the characteristic of the coefficient field of the polynomial ring
1524         should not divide the order of the finite matrix group
1525THEORY:  REY has been constructed in such a way that each row serves as a ring
1526         mapping of which the Reynolds operator is made up.
1527EXAMPLE: example evaluate_reynolds; shows an example
1528"
1529{ def br=basering;
1530  int n=nvars(br);
1531  if (ncols(REY)==n)
1532  { int m=nrows(REY);                  // we need m to 'cut' the ring
1533                                       // homomorphisms 'out' of REY and to
1534                                       // divide by the group order in the end
1535    int num_poly=ncols(I);
1536    matrix MI=matrix(I);
1537    matrix MiI[1][num_poly];
1538    map pREY;
1539    matrix rowREY[1][n];
1540    for (int i=1;i<=m;i++)
1541    { rowREY=REY[i,1..n];
1542      pREY=br,ideal(rowREY);           // f is now the i-th ring homomorphism
1543      MiI=pREY(MI)+MiI;
1544    }
1545    MiI=(1/number(m))*MiI;
1546    return(ideal(MiI));
1547  }
1548  else
1549  { "ERROR:   the number of columns in the <matrix> should be the same as the";
1550    "         number of variables in the basering; in fact it should be first";
1551    "         return value of group_reynolds() or reynolds_molien().";
1552    return();
1553  }
1554}
1555example
1556{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1557         ring R=0,(x,y,z),dp;
1558         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1559         list L=group_reynolds(A);
1560         ideal I=x2,y2,z2;
1561         print(evaluate_reynolds(L[1],I));
1562}
1563///////////////////////////////////////////////////////////////////////////////
1564
1565proc invariant_basis (int g,list #)
1566"USAGE:   invariant_basis(g,G1,G2,...);
1567         g: an <int> indicating of which degree (>0) the homogeneous basis
1568         shoud be, G1,G2,...: <matrices> generating a finite matrix group
1569RETURNS: the basis (type <ideal>) of the space of invariants of degree g
1570THEORY:  A general polynomial of degree g is generated and the generators of
1571         the matrix group applied. The difference ought to be 0 and this way a
1572         system of linear equations is created. It is solved by computing
1573         syzygies.
1574EXAMPLE: example invariant_basis; shows an example
1575"
1576{ if (g<=0)
1577  { "ERROR:   the first parameter should be > 0";
1578    return();
1579  }
1580  def br=basering;
1581  ideal mon=sort(maxideal(g))[1];      // needed for constructing a general
1582  int m=ncols(mon);                    // homogeneous polynomial of degree g
1583  mon=sort(mon,intvec(m..1))[1];
1584  int a=size(#);
1585  int i;
1586  int n=nvars(br);
1587 //---------------------- checking that the input is ok -----------------------
1588  for (i=1;i<=a;i++)
1589  { if (typeof(#[i])=="matrix")
1590    { if (nrows(#[i])==n && ncols(#[i])==n)
1591      { matrix G(i)=#[i];
1592      }
1593      else
1594      { "ERROR:   the number of variables of the base ring needs to be the same";
1595        "         as the dimension of the square matrices";
1596        return();
1597      }
1598    }
1599    else
1600    { "ERROR:   the last parameters should be a list of matrices";
1601      return();
1602    }
1603  }
1604 //----------------------------------------------------------------------------
1605  execute("ring T=("+charstr(br)+"),("+varstr(br)+",p(1..m)),lp;");
1606  // p(1..m) are the general coefficients of the general polynomial of degree g
1607  execute("ideal vars="+varstr(br)+";");
1608  map f;
1609  ideal mon=imap(br,mon);
1610  poly P=0;
1611  for (i=m;i>=1;i--)
1612  { P=P+p(i)*mon[i];                   // P is the general polynomial
1613  }
1614  ideal I;                             // will help substituting variables in P
1615                                       // by linear combinations of variables -
1616  poly Pnew,temp;                      // Pnew is P with substitutions -
1617  matrix S[m*a][m];                    // will contain system of linear
1618                                       // equations
1619  int j,k;
1620 //------------------- building the system of linear equations ----------------
1621  for (i=1;i<=a;i++)
1622  { I=ideal(matrix(vars)*transpose(imap(br,G(i))));
1623    I=I,p(1..m);
1624    f=T,I;
1625    Pnew=f(P);
1626    for (j=1;j<=m;j++)
1627    { temp=P/mon[j]-Pnew/mon[j];
1628      for (k=1;k<=m;k++)
1629      { S[m*(i-1)+j,k]=temp/p(k);
1630      }
1631    }
1632  }
1633 //----------------------------------------------------------------------------
1634  setring br;
1635  map f=T,ideal(0);
1636  matrix S=f(S);
1637  matrix s=matrix(syz(S));             // s contains a basis of the space of
1638                                       // solutions -
1639  ideal I=ideal(matrix(mon)*s);        // I contains a basis of homogeneous
1640  if (I[1]<>0)                         // invariants of degree d
1641  { for (i=1;i<=ncols(I);i++)
1642    { I[i]=I[i]/leadcoef(I[i]);        // setting leading coefficients to 1
1643    }
1644  }
1645  return(I);
1646}
1647example
1648{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1649           ring R=0,(x,y,z),dp;
1650           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1651           print(invariant_basis(2,A));
1652}
1653///////////////////////////////////////////////////////////////////////////////
1654
1655proc invariant_basis_reynolds (matrix REY,int d,list #)
1656"USAGE:   invariant_basis_reynolds(REY,d[,flags]);
1657         REY: a <matrix> representing the Reynolds operator, d: an <int>
1658         indicating of which degree (>0) the homogeneous basis shoud be, flags:
1659         an optional <intvec> with two entries: its first component gives the
1660         dimension of the space (default <0 meaning unknown) and its second
1661         component is used as the number of polynomials that should be mapped
1662         to invariants during one call of evaluate_reynolds if the dimension of
1663         the space is unknown or the number such that number x dimension
1664         polynomials are mapped to invariants during one call of
1665         evaluate_reynolds
1666ASSUME:  REY is the first return value of group_reynolds() or reynolds_molien()
1667         and flags[1] given by partial_molien
1668RETURN:  the basis (type <ideal>) of the space of invariants of degree d
1669THEORY:  Monomials of degree d are mapped to invariants with the Reynolds
1670         operator. A linearly independent set is generated with the help of
1671         minbase.
1672EXAMPLE: example invariant_basis_reynolds; shows an example
1673"
1674{
1675 //---------------------- checking that the input is ok -----------------------
1676  if (d<=0)
1677  { "  ERROR:   the second parameter should be > 0";
1678     return();
1679  }
1680  if (size(#)>1)
1681  { "  ERROR:   there should be at most three parameters";
1682    return();
1683  }
1684  if (size(#)==1)
1685  { if (typeof(#[1])<>"intvec")
1686    { "  ERROR: the third parameter should be of type <intvec>";
1687      return();
1688    }
1689    if (size(#[1])<>2)
1690    { "  ERROR: there should be two components in <intvec>";
1691      return();
1692    }
1693    else
1694    { int cd=#[1][1];
1695      int step_fac=#[1][2];
1696    }
1697    if (step_fac<=0)
1698    { "  ERROR: the second component of <intvec> should be > 0";
1699      return();
1700    }
1701    if (cd==0)
1702    { return(ideal(0));
1703    }
1704  }
1705  else
1706  { int step_fac=1;
1707    int cd=-1;
1708  }
1709  if (ncols(REY)<>nvars(basering))
1710  { "ERROR:   the number of columns in the <matrix> should be the same as the";
1711    "         number of variables in the basering; in fact it should be first";
1712    "         return value of group_reynolds() or reynolds_molien().";
1713    return();
1714  }
1715 //----------------------------------------------------------------------------
1716  ideal mon=sort(maxideal(d))[1];
1717  int DEGB = degBound;
1718  degBound=d;
1719  int j=ncols(mon);
1720  mon=sort(mon,intvec(j..1))[1];
1721  ideal B;                             // will contain the basis
1722  if (cd<0)
1723  { if (step_fac>j)                    // all of mon will be mapped to
1724    { B=evaluate_reynolds(REY,mon);    // invariants at once
1725      B=minbase(B);
1726      degBound=DEGB;
1727      return(B);
1728    }
1729  }
1730  else
1731  { if (step_fac*cd>j)                 // all of mon will be mapped to
1732    { B=evaluate_reynolds(REY,mon);    // invariants at once
1733      B=minbase(B);
1734      degBound=DEGB;
1735      return(B);
1736    }
1737  }
1738  int i,k;
1739  int upper_bound=0;
1740  int lower_bound=0;
1741  ideal part_mon;                      // a part of mon of size step_fac*cd
1742  while (1)
1743  { lower_bound=upper_bound+1;
1744    if (cd<0)
1745    { upper_bound=upper_bound+step_fac;
1746    }
1747    else
1748    { upper_bound=upper_bound+step_fac*cd;
1749    }
1750    if (upper_bound>j)
1751    { upper_bound=j;
1752    }
1753    part_mon=mon[lower_bound..upper_bound];
1754    B=minbase(B+evaluate_reynolds(REY,part_mon));
1755    if ((ncols(B)==cd and B[1]<>0) or upper_bound==j)
1756    { degBound=DEGB;
1757      return(B);
1758    }
1759  }
1760}
1761example
1762{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1763           ring R=0,(x,y,z),dp;
1764           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1765           intvec flags=0,1,0;
1766           matrix REY,M=reynolds_molien(A,flags);
1767           flags=8,6;
1768           print(invariant_basis_reynolds(REY,6,flags));
1769}
1770
1771///////////////////////////////////////////////////////////////////////////////
1772// This procedure generates linearly independent invariant polynomials of
1773// degree d that do not reduce to 0 modulo the primary invariants. It does this
1774// by applying the Reynolds operator to the monomials returned by kbase(sP,d).
1775// The result is used when computing secondary invariants.
1776///////////////////////////////////////////////////////////////////////////////
1777proc sort_of_invariant_basis (ideal sP,matrix REY,int d,int step_fac)
1778{ ideal mon=kbase(sP,d);
1779  int DEGB=degBound;
1780  degBound=d;
1781  int j=ncols(mon);
1782  int i;
1783  mon=sort(mon,intvec(j..1))[1];
1784  ideal B;                             // will contain the "sort of basis"
1785  if (step_fac>j)
1786  { B=compress(evaluate_reynolds(REY,mon));
1787    for (i=1;i<=ncols(B);i++)          // those are taken our that are o mod sP
1788    { if (reduce(B[i],sP)==0)
1789      { B[i]=0;
1790      }
1791    }
1792    B=minbase(B);                     // here are the linearly independent ones
1793    degBound=DEGB;
1794    return(B);
1795  }
1796  int upper_bound=0;
1797  int lower_bound=0;
1798  ideal part_mon;                      // parts of mon
1799  while (1)
1800  { lower_bound=upper_bound+1;
1801    upper_bound=upper_bound+step_fac;
1802    if (upper_bound>j)
1803    { upper_bound=j;
1804    }
1805    part_mon=mon[lower_bound..upper_bound];
1806    part_mon=compress(evaluate_reynolds(REY,part_mon));
1807    for (i=1;i<=ncols(part_mon);i++)
1808    { if (reduce(part_mon[i],sP)==0)
1809      { part_mon[i]=0;
1810      }
1811    }
1812    B=minbase(B+part_mon);            // here are the linearly independent ones
1813    if (upper_bound==j)
1814    { degBound=DEGB;
1815      return(B);
1816    }
1817  }
1818}
1819
1820///////////////////////////////////////////////////////////////////////////////
1821// Procedure returning the succeeding vector after vec. It is used to list
1822// all the vectors of Z^n with first nonzero entry 1. They are listed by
1823// increasing sum of the absolute value of their entries.
1824///////////////////////////////////////////////////////////////////////////////
1825proc next_vector(intmat vec)
1826{ int n=ncols(vec);                    // p: >0, n: <0, p0: >=0, n0: <=0
1827  for (int i=1;i<=n;i++)               // finding out which is the first
1828  { if (vec[1,i]<>0)                   // component <>0
1829    { break;
1830    }
1831  }
1832  intmat new[1][n];
1833  if (i>n)                             // 0,...,0 --> 1,0....,0
1834  { new[1,1]=1;
1835    return(new);
1836  }
1837  if (i==n)                            // 0,...,1 --> 1,1,0,...,0
1838  { new[1,1..2]=1,1;
1839    return(new);
1840  }
1841  if (i==n-1)
1842  { if (vec[1,n]==0)                   // 0,...,0,1,0 --> 0,...,0,1
1843    { new[1,n]=1;
1844      return(new);
1845    }
1846    if (vec[1,n]>0)                    // 0,..,0,1,p --> 0,...,0,1,-p
1847    { new[1,1..n]=vec[1,1..n-1],-vec[1,n];
1848      return(new);
1849    }
1850    new[1,1..2]=1,1-vec[1,n];          // 0,..,0,1,n --> 1,1-n,0,..,0
1851    return(new);
1852  }
1853  if (i>1)
1854  { intmat temp[1][n-i+1]=vec[1,i..n]; // 0,...,0,1,*,...,* --> 1,*,...,*
1855    temp=next_vector(temp);
1856    new[1,i..n]=temp[1,1..n-i+1];
1857    return(new);
1858  }                                    // case left: 1,*,...,*
1859  for (i=2;i<=n;i++)
1860  { if (vec[1,i]>0)                    // make first positive negative and
1861    { vec[1,i]=-vec[1,i];              // return
1862      return(vec);
1863    }
1864    else
1865    { vec[1,i]=-vec[1,i];             // make all negatives before positives
1866    }                                 // positive
1867  }
1868  for (i=2;i<=n-1;i++)                // case: 1,p,...,p after 1,n,...,n
1869  { if (vec[1,i]>0)
1870    { vec[1,2]=vec[1,i]-1;            // shuffleing things around...
1871      if (i>2)                        // same sum of absolute values of entries
1872      { vec[1,i]=0;
1873      }
1874      vec[1,i+1]=vec[1,i+1]+1;
1875      return(vec);
1876    }
1877  }                                    // case left: 1,0,...,0 --> 1,1,0,...,0
1878  new[1,2..3]=1,vec[1,n];              // and: 1,0,...,0,1 --> 0,1,1,0,...,0
1879  return(new);
1880}
1881
1882///////////////////////////////////////////////////////////////////////////////
1883// Maps integers to elements of the base field. It is only called if the base
1884// field is of prime characteristic. If the base field has q elements
1885// (depending on minpoly) 1..q is mapped to those q elements.
1886///////////////////////////////////////////////////////////////////////////////
1887proc int_number_map (int i)
1888{ int p=char(basering);
1889  if (minpoly==0)                      // if no minpoly is given, we have p
1890  { i=i%p;                             // elements in the field
1891    return(number(i));
1892  }
1893  int d=pardeg(minpoly);
1894  if (i<0)
1895  { int bool=1;
1896    i=(-1)*i;
1897  }
1898  i=i%p^d;                            // base field has p^d elements -
1899  number a=par(1);                    // a is the root of the minpoly - we have
1900  number out=0;                       // to construct a linear combination of
1901  int j=1;                            // a^k
1902  int k;
1903  while (1)
1904  { if (i<p^j)                         // finding an upper bound on i
1905    { for (k=0;k<j-1;k++)
1906      { out=out+((i/p^k)%p)*a^k;       // finding how often p^k is contained in
1907      }                                // i
1908      out=out+(i/p^(j-1))*a^(j-1);
1909      if (defined(bool)==voice)
1910      { return((-1)*out);
1911      }
1912      return(out);
1913    }
1914    j++;
1915  }
1916}
1917
1918///////////////////////////////////////////////////////////////////////////////
1919// This procedure finds dif primary invariants in degree d. It returns all
1920// primary invariants found so far. The coefficients lie in a field of
1921// characteristic 0.
1922///////////////////////////////////////////////////////////////////////////////
1923proc search (int n,int d,ideal B,int cd,ideal P,ideal sP,int i,int dif,int dB,ideal CI)
1924{ intmat vec[1][cd];                   // the coefficients for the next
1925                                       // combination -
1926  degBound=0;
1927  poly test_poly;                      // the linear combination to test
1928  int test_dim;
1929  intvec h;                            // Hilbert series
1930  int j=i+1;
1931  matrix tB=transpose(B);
1932  ideal TEST;
1933  while(j<=i+dif)
1934  { CI=CI+ideal(var(j)^d);             // homogeneous polynomial of the same
1935                                       // degree as the one we're looking for is
1936                                       // added
1937    // h=hilb(std(CI),1);
1938    dB=dB+d-1;                         // used as degBound
1939    while(1)
1940    { vec=next_vector(vec);            // next vector
1941      test_poly=(vec*tB)[1,1];
1942      // degBound=dB;
1943      TEST=sP+ideal(test_poly);
1944      attrib(TEST,"isSB",1);
1945      test_dim=dim(TEST);
1946      // degBound=0;
1947      if (n-test_dim==j)               // the dimension has been lowered by one
1948      { sP=TEST;
1949        break;
1950      }
1951      // degBound=dB;
1952      //TEST=std(sP+ideal(test_poly));   // should soon be replaced by next line
1953      TEST=std(sP,test_poly);            // or, better:
1954      //TEST=std(sP,test_poly,h);        // Hilbert driven std-calculation
1955      test_dim=dim(TEST);
1956      // degBound=0;
1957      if (n-test_dim==j)               // the dimension has been lowered by one
1958      { sP=TEST;
1959        break;
1960      }
1961    }
1962    P[j]=test_poly;                    // test_poly ist added to primary
1963    j++;                               // invariants
1964  }
1965  return(P,sP,CI,dB);
1966}
1967
1968///////////////////////////////////////////////////////////////////////////////
1969// This procedure finds at most dif primary invariants in degree d. It returns
1970// all primary invariants found so far. The coefficients lie in the field of
1971// characteristic p>0.
1972///////////////////////////////////////////////////////////////////////////////
1973proc p_search (int n,int d,ideal B,int cd,ideal P,ideal sP,int i,int dif,int dB,ideal CI)
1974{ def br=basering;
1975  degBound=0;
1976  matrix vec(1)[1][cd];                // starting with 0-vector -
1977  intmat new[1][cd];                   // the coefficients for the next
1978                                       // combination -
1979  matrix pnew[1][cd];                  // new needs to be mapped into br -
1980  int counter=1;                       // counts the vectors
1981  int j;
1982  int p=char(br);
1983  if (minpoly<>0)
1984  { int ext_deg=pardeg(minpoly);       // field has p^d elements
1985  }
1986  else
1987  { int ext_deg=1;                     // field has p^d elements
1988  }
1989  poly test_poly;                      // the linear combination to test
1990  int test_dim;
1991  ring R=0,x,dp;                       // just to calculate next variable
1992                                       // bound -
1993  number bound=(number(p)^(ext_deg*cd)-1)/(number(p)^ext_deg-1)+1;
1994                                       // this is how many linearly independent
1995                                       // vectors of size cd exist having
1996                                       // entries in the base field of br
1997  setring br;
1998  intvec h;                            // Hilbert series
1999  int k=i+1;
2000  if (ncols(B)<cd) { B[cd]=0; }
2001  matrix tB=transpose(B);
2002  ideal TEST;
2003  while (k<=i+dif)
2004  { CI=CI+ideal(var(k)^d);             // homogeneous polynomial of the same
2005                                       //degree as the one we're looking for is
2006                                       // added
2007    // h=hilb(std(CI),1);
2008    dB=dB+d-1;                         // used as degBound
2009    setring R;
2010    while (number(counter)<>bound)     // otherwise, we are done
2011    { setring br;
2012      new=next_vector(new);
2013      for (j=1;j<=cd;j++)
2014      { pnew[1,j]=int_number_map(new[1,j]); // mapping an integer into br
2015      }
2016      if (unique(vec(1..counter),pnew)) //checking whether we tried pnew before
2017      { counter++;
2018        matrix vec(counter)=pnew;      // keeping track of the ones we tried -
2019        test_poly=(vec(counter)*tB)[1,1]; // linear combination -
2020        // degBound=dB;
2021        TEST=sP+ideal(test_poly);
2022        attrib(TEST,"isSB",1);
2023        test_dim=dim(TEST);
2024        // degBound=0;
2025        if (n-test_dim==k)             // the dimension has been lowered by one
2026        { sP=TEST;
2027          setring R;
2028          break;
2029        }
2030        // degBound=dB;
2031        //TEST=std(sP+ideal(test_poly)); // should soon to be replaced by next
2032                                       // line
2033        TEST=std(sP,test_poly);        // or, better:
2034        // TEST=std(sP,test_poly,h);      // Hilbert driven std-calculation
2035        test_dim=dim(TEST);
2036        // degBound=0;
2037        if (n-test_dim==k)             // the dimension has been lowered by one
2038        { sP=TEST;
2039          setring R;
2040          break;
2041        }
2042      }
2043      setring R;
2044    }
2045    if (number(counter)<=bound)
2046    { setring br;
2047      P[k]=test_poly;                  // test_poly ist added to primary
2048    }                                  // invariants
2049    else
2050    { setring br;
2051      CI=CI[1..size(CI)-1];
2052      return(P,sP,CI,dB-d+1);
2053    }
2054    k++;
2055  }
2056  return(P,sP,CI,dB);
2057}
2058///////////////////////////////////////////////////////////////////////////////
2059
2060proc primary_char0 (matrix REY,matrix M,list #)
2061"USAGE:   primary_char0(REY,M[,v]);
2062         REY: a <matrix> representing the Reynolds operator, M: a 1x2 <matrix>
2063         representing the Molien series, v: an optional <int>
2064ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
2065         M the one of molien or the second one of reynolds_molien
2066DISPLAY: information about the various stages of the programme if v does not
2067         equal 0
2068RETURN:  primary invariants (type <matrix>) of the invariant ring
2069THEORY:  Bases of homogeneous invariants are generated successively and those
2070         are chosen as primary invariants that lower the dimension of the ideal
2071         generated by the previously found invariants (see paper \"Generating a
2072         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2073         Decker, Heydtmann, Schreyer (1998)).
2074EXAMPLE: example primary_char0; shows an example
2075"
2076{ degBound=0;
2077  if (char(basering)<>0)
2078  { "ERROR:   primary_char0 should only be used with rings of characteristic 0.";
2079    return();
2080  }
2081 //----------------- checking input and setting verbose mode ------------------
2082  if (size(#)>1)
2083  { "ERROR:   primary_char0 can only have three parameters.";
2084    return();
2085  }
2086  if (size(#)==1)
2087  { if (typeof(#[1])<>"int")
2088    { "ERROR:   The third parameter should be of type <int>.";
2089      return();
2090    }
2091    else
2092    { int v=#[1];
2093    }
2094  }
2095  else
2096  { int v=0;
2097  }
2098  int n=nvars(basering);               // n is the number of variables, as well
2099                                       // as the size of the matrices, as well
2100                                       // as the number of primary invariants,
2101                                       // we should get
2102  if (ncols(REY)<>n)
2103  { "ERROR:   First parameter ought to be the Reynolds operator."
2104    return();
2105  }
2106  if (ncols(M)<>2 or nrows(M)<>1)
2107  { "ERROR:   Second parameter ought to be the Molien series."
2108    return();
2109  }
2110 //----------------------------------------------------------------------------
2111  if (v && voice<>2)
2112  { "  We can start looking for primary invariants...";
2113    "";
2114  }
2115  if (v && voice==2)
2116  { "";
2117  }
2118 //------------------------- initializing variables ---------------------------
2119  int dB;
2120  poly p(1..2);                        // p(1) will be used for single terms of
2121                                       // the partial expansion, p(2) to store
2122  p(1..2)=partial_molien(M,1);         // the intermediate result -
2123  poly v1=var(1);                      // we need v1 to split off coefficients
2124                                       // in the partial expansion of M (which
2125                                       // is in terms of the first variable) -
2126  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2127                                       // space of invariants of degree d,
2128                                       // newdim: dimension the ideal generated
2129                                       // the primary invariants plus basis
2130                                       // elements, dif=n-i-newdim, i.e. the
2131                                       // number of new primary invairants that
2132                                       // should be added in this degree -
2133  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2134                                       // Pplus: P+B, CI: a complete
2135                                       // intersection with the same Hilbert
2136                                       // function as P
2137  ideal sP=groebner(P);
2138  dB=1;                                // used as degree bound
2139  int i=0;
2140 //-------------- loop that searches for primary invariants  ------------------
2141  while(1)                             // repeat until n primary invariants are
2142  {                                    // found -
2143    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
2144    d=deg(p(1));                       // degree where we'll search -
2145    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
2146                                       // inviarants of degree d
2147    if (v)
2148    { "  Computing primary invariants in degree "+string(d)+":";
2149    }
2150    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
2151                                       // degree d
2152    if (B[1]<>0)
2153    { Pplus=P+B;
2154      sPplus=groebner(Pplus);
2155      newdim=dim(sPplus);
2156      dif=n-i-newdim;
2157    }
2158    else
2159    { dif=0;
2160    }
2161    if (dif<>0)                        // we have to find dif new primary
2162    {                                  // invariants
2163      if (cd<>dif)
2164      { P,sP,CI,dB=search(n,d,B,cd,P,sP,i,dif,dB,CI); // searching for dif invariants
2165      }                                // i.e. we can take all of B
2166      else
2167      { for(j=i+1;j<=i+dif;j++)
2168        { CI=CI+ideal(var(j)^d);
2169        }
2170        dB=dB+dif*(d-1);
2171        P=Pplus;
2172        sP=sPplus;
2173      }
2174      if (v)
2175      { for (j=1;j<=dif;j++)
2176        { "  We find: "+string(P[i+j]);
2177        }
2178      }
2179      i=i+dif;
2180      if (i==n)                        // found all primary invariants
2181      { if (v)
2182        { "";
2183          "  We found all primary invariants.";
2184          "";
2185        }
2186        return(matrix(P));
2187      }
2188    }                                  // done with degree d
2189  }
2190}
2191example
2192{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
2193         ring R=0,(x,y,z),dp;
2194         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2195         matrix REY,M=reynolds_molien(A);
2196         matrix P=primary_char0(REY,M);
2197         print(P);
2198}
2199///////////////////////////////////////////////////////////////////////////////
2200
2201proc primary_charp (matrix REY,string ring_name,list #)
2202"USAGE:   primary_charp(REY,ringname[,v]);
2203         REY: a <matrix> representing the Reynolds operator, ringname: a
2204         <string> giving the name of a ring where the Molien series is stored,
2205         v: an optional <int>
2206ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
2207         ringname gives the name of a ring of characteristic 0 that has been
2208         created by molien or reynolds_molien
2209DISPLAY: information about the various stages of the programme if v does not
2210         equal 0
2211RETURN:  primary invariants (type <matrix>) of the invariant ring
2212THEORY:  Bases of homogeneous invariants are generated successively and those
2213         are chosen as primary invariants that lower the dimension of the ideal
2214         generated by the previously found invariants (see paper \"Generating a
2215         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2216         Decker, Heydtmann, Schreyer (1998)).
2217EXAMPLE: example primary_charp; shows an example
2218"
2219{ degBound=0;
2220// ---------------- checking input and setting verbose mode -------------------
2221  if (char(basering)==0)
2222  { "ERROR:   primary_charp should only be used with rings of characteristic p>0.";
2223    return();
2224  }
2225  if (size(#)>1)
2226  { "ERROR:   primary_charp can only have three parameters.";
2227    return();
2228  }
2229  if (size(#)==1)
2230  { if (typeof(#[1])<>"int")
2231    { "ERROR:   The third parameter should be of type <int>.";
2232      return();
2233    }
2234    else
2235    { int v=#[1];
2236    }
2237  }
2238  else
2239  { int v=0;
2240  }
2241  def br=basering;
2242  int n=nvars(br);                     // n is the number of variables, as well
2243                                       // as the size of the matrices, as well
2244                                       // as the number of primary invariants,
2245                                       // we should get
2246  if (ncols(REY)<>n)
2247  { "ERROR:   First parameter ought to be the Reynolds operator."
2248    return();
2249  }
2250  if (typeof(`ring_name`)<>"ring")
2251  { "ERROR:   Second parameter ought to the name of a ring where the Molien";
2252    "         is stored.";
2253    return();
2254  }
2255 //----------------------------------------------------------------------------
2256  if (v && voice<>2)
2257  { "  We can start looking for primary invariants...";
2258    "";
2259  }
2260  if (v && voice==2)
2261  { "";
2262  }
2263 //----------------------- initializing variables -----------------------------
2264  int dB;
2265  setring `ring_name`;                 // the Molien series is stores here -
2266  poly p(1..2);                        // p(1) will be used for single terms of
2267                                       // the partial expansion, p(2) to store
2268  p(1..2)=partial_molien(M,1);         // the intermediate result -
2269  poly v1=var(1);                      // we need v1 to split off coefficients
2270                                       // in the partial expansion of M (which
2271                                       // is in terms of the first variable)
2272  setring br;
2273  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2274                                       // space of invariants of degree d,
2275                                       // newdim: dimension the ideal generated
2276                                       // the primary invariants plus basis
2277                                       // elements, dif=n-i-newdim, i.e. the
2278                                       // number of new primary invairants that
2279                                       // should be added in this degree -
2280  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2281                                       // Pplus: P+B, CI: a complete
2282                                       // intersection with the same Hilbert
2283                                       // function as P
2284  ideal sP=groebner(P);
2285  dB=1;                                // used as degree bound
2286  int i=0;
2287 //---------------- loop that searches for primary invariants -----------------
2288  while(1)                             // repeat until n primary invariants are
2289  {                                    // found
2290    setring `ring_name`;
2291    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
2292    d=deg(p(1));                       // degree where we'll search -
2293    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
2294                                       // inviarants of degree d
2295    setring br;
2296    if (v)
2297    { "  Computing primary invariants in degree "+string(d)+":";
2298    }
2299    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
2300                                       // degree d
2301    if (ncols(B)<cd)
2302    {
2303      " warning: expected ",cd," invars, found ",ncols(B);
2304    }
2305    if (B[1]<>0)
2306    { Pplus=P+B;
2307      sPplus=groebner(Pplus);
2308      newdim=dim(sPplus);
2309      dif=n-i-newdim;
2310    }
2311    else
2312    { dif=0;
2313    }
2314    if (dif<>0)                        // we have to find dif new primary
2315    {                                  // invariants
2316      if (cd<>dif)
2317      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2318      }
2319      else                             // i.e. we can take all of B
2320      { for(j=i+1;j>i+dif;j++)
2321        { CI=CI+ideal(var(j)^d);
2322        }
2323        dB=dB+dif*(d-1);
2324        P=Pplus;
2325        sP=sPplus;
2326      }
2327      if (v)
2328      { for (j=1;j<=size(P)-i;j++)
2329        { "  We find: "+string(P[i+j]);
2330        }
2331      }
2332      i=size(P);
2333      if (i==n)                        // found all primary invariants
2334      { if (v)
2335        { "";
2336          "  We found all primary invariants.";
2337          "";
2338        }
2339        return(matrix(P));
2340      }
2341    }                                  // done with degree d
2342  }
2343}
2344example
2345{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
2346         ring R=3,(x,y,z),dp;
2347         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2348         list L=group_reynolds(A);
2349         string newring="alskdfj";
2350         molien(L[2..size(L)],newring);
2351         matrix P=primary_charp(L[1],newring);
2352         kill `newring`;
2353         print(P);
2354}
2355///////////////////////////////////////////////////////////////////////////////
2356
2357proc primary_char0_no_molien (matrix REY, list #)
2358"USAGE:   primary_char0_no_molien(REY[,v]);
2359         REY: a <matrix> representing the Reynolds operator, v: an optional
2360         <int>
2361ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
2362DISPLAY: information about the various stages of the programme if v does not
2363         equal 0
2364RETURN:  primary invariants (type <matrix>) of the invariant ring and an
2365         <intvec> listing some of the degrees where no non-trivial homogeneous
2366         invariants are to be found
2367THEORY:  Bases of homogeneous invariants are generated successively and those
2368         are chosen as primary invariants that lower the dimension of the ideal
2369         generated by the previously found invariants (see paper \"Generating a
2370         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2371         Decker, Heydtmann, Schreyer (1998)).
2372EXAMPLE: example primary_char0_no_molien; shows an example
2373"
2374{ degBound=0;
2375 //-------------- checking input and setting verbose mode ---------------------
2376  if (char(basering)<>0)
2377  { "ERROR:   primary_char0_no_molien should only be used with rings of";
2378    "         characteristic 0.";
2379    return();
2380  }
2381  if (size(#)>1)
2382  { "ERROR:   primary_char0_no_molien can only have two parameters.";
2383    return();
2384  }
2385  if (size(#)==1)
2386  { if (typeof(#[1])<>"int")
2387    { "ERROR:   The second parameter should be of type <int>.";
2388      return();
2389    }
2390    else
2391    { int v=#[1];
2392    }
2393  }
2394  else
2395  { int v=0;
2396  }
2397  int n=nvars(basering);               // n is the number of variables, as well
2398                                       // as the size of the matrices, as well
2399                                       // as the number of primary invariants,
2400                                       // we should get
2401  if (ncols(REY)<>n)
2402  { "ERROR:   First parameter ought to be the Reynolds operator."
2403    return();
2404  }
2405 //----------------------------------------------------------------------------
2406  if (v && voice<>2)
2407  { "  We can start looking for primary invariants...";
2408    "";
2409  }
2410  if (v && voice==2)
2411  { "";
2412  }
2413 //----------------------- initializing variables -----------------------------
2414  int dB;
2415  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2416                                       // space of invariants of degree d,
2417                                       // newdim: dimension the ideal generated
2418                                       // the primary invariants plus basis
2419                                       // elements, dif=n-i-newdim, i.e. the
2420                                       // number of new primary invairants that
2421                                       // should be added in this degree -
2422  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
2423                                       // Pplus: P+B, CI: a complete
2424                                       // intersection with the same Hilbert
2425                                       // function as P
2426  ideal sP=groebner(P);
2427  dB=1;                                // used as degree bound -
2428  d=0;                                 // initializing
2429  int i=0;
2430  intvec deg_vector;
2431 //------------------ loop that searches for primary invariants ---------------
2432  while(1)                             // repeat until n primary invariants are
2433  {                                    // found -
2434    d++;                               // degree where we'll search
2435    if (v)
2436    { "  Computing primary invariants in degree "+string(d)+":";
2437    }
2438    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
2439                                       // degree d
2440    if (B[1]<>0)
2441    { Pplus=P+B;
2442      newdim=dim(groebner(Pplus));
2443      dif=n-i-newdim;
2444    }
2445    else
2446    { dif=0;
2447      deg_vector=deg_vector,d;
2448    }
2449    if (dif<>0)                        // we have to find dif new primary
2450    {                                  // invariants
2451      cd=size(B);
2452      if (cd<>dif)
2453      { P,sP,CI,dB=search(n,d,B,cd,P,sP,i,dif,dB,CI);
2454      }
2455      else                             // i.e. we can take all of B
2456      { for(j=i+1;j<=i+dif;j++)
2457        { CI=CI+ideal(var(j)^d);
2458        }
2459        dB=dB+dif*(d-1);
2460        P=Pplus;
2461        sP=groebner(P);
2462      }
2463      if (v)
2464      { for (j=1;j<=dif;j++)
2465        { "  We find: "+string(P[i+j]);
2466        }
2467      }
2468      i=i+dif;
2469      if (i==n)                        // found all primary invariants
2470      { if (v)
2471        { "";
2472          "  We found all primary invariants.";
2473          "";
2474        }
2475        if (deg_vector==0)
2476        { return(matrix(P));
2477        }
2478        else
2479        { return(matrix(P),compress(deg_vector));
2480        }
2481      }
2482    }                                  // done with degree d
2483    else
2484    { if (v)
2485      { "  None here...";
2486      }
2487    }
2488  }
2489}
2490example
2491{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
2492         ring R=0,(x,y,z),dp;
2493         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2494         list L=group_reynolds(A);
2495         list l=primary_char0_no_molien(L[1]);
2496         print(l[1]);
2497}
2498///////////////////////////////////////////////////////////////////////////////
2499
2500proc primary_charp_no_molien (matrix REY, list #)
2501"USAGE:   primary_charp_no_molien(REY[,v]);
2502         REY: a <matrix> representing the Reynolds operator, v: an optional
2503         <int>
2504ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
2505DISPLAY: information about the various stages of the programme if v does not
2506         equal 0
2507RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
2508         <intvec> listing some of the degrees where no non-trivial homogeneous
2509         invariants are to be found
2510THEORY:  Bases of homogeneous invariants are generated successively and those
2511         are chosen as primary invariants that lower the dimension of the ideal
2512         generated by the previously found invariants (see paper \"Generating a
2513         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2514         Decker, Heydtmann, Schreyer (1998)).
2515EXAMPLE: example primary_charp_no_molien; shows an example
2516"
2517{ degBound=0;
2518 //----------------- checking input and setting verbose mode ------------------
2519  if (char(basering)==0)
2520  { "ERROR:   primary_charp_no_molien should only be used with rings of";
2521    "         characteristic p>0.";
2522    return();
2523  }
2524  if (size(#)>1)
2525  { "ERROR:   primary_charp_no_molien can only have two parameters.";
2526    return();
2527  }
2528  if (size(#)==1)
2529  { if (typeof(#[1])<>"int")
2530    { "ERROR:   The second parameter should be of type <int>.";
2531      return();
2532    }
2533    else
2534    { int v=#[1]; }
2535  }
2536  else
2537  { int v=0;
2538  }
2539  int n=nvars(basering);               // n is the number of variables, as well
2540                                       // as the size of the matrices, as well
2541                                       // as the number of primary invariants,
2542                                       // we should get
2543  if (ncols(REY)<>n)
2544  { "ERROR:   First parameter ought to be the Reynolds operator."
2545    return();
2546  }
2547 //----------------------------------------------------------------------------
2548  if (v && voice<>2)
2549  { "  We can start looking for primary invariants...";
2550    "";
2551  }
2552  if (v && voice==2)
2553  { ""; }
2554 //-------------------- initializing variables --------------------------------
2555  int dB;
2556  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2557                                       // space of invariants of degree d,
2558                                       // newdim: dimension the ideal generated
2559                                       // the primary invariants plus basis
2560                                       // elements, dif=n-i-newdim, i.e. the
2561                                       // number of new primary invairants that
2562                                       // should be added in this degree -
2563  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2564                                       // Pplus: P+B, CI: a complete
2565                                       // intersection with the same Hilbert
2566                                       // function as P
2567  ideal sP=groebner(P);
2568  dB=1;                                // used as degree bound -
2569  d=0;                                 // initializing
2570  int i=0;
2571  intvec deg_vector;
2572 //------------------ loop that searches for primary invariants ---------------
2573  while(1)                             // repeat until n primary invariants are
2574  {                                    // found -
2575    d++;                               // degree where we'll search
2576    if (v)
2577    { "  Computing primary invariants in degree "+string(d)+":";
2578    }
2579    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
2580                                       // degree d
2581    if (B[1]<>0)
2582    { Pplus=P+B;
2583      sPplus=groebner(Pplus);
2584      newdim=dim(sPplus);
2585      dif=n-i-newdim;
2586    }
2587    else
2588    { dif=0;
2589      deg_vector=deg_vector,d;
2590    }
2591    if (dif<>0)                        // we have to find dif new primary
2592    {                                  // invariants
2593      cd=size(B);
2594      if (cd<>dif)
2595      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2596      }
2597      else                             // i.e. we can take all of B
2598      { for(j=i+1;j<=i+dif;j++)
2599        { CI=CI+ideal(var(j)^d);
2600        }
2601        dB=dB+dif*(d-1);
2602        P=Pplus;
2603        sP=sPplus;
2604      }
2605      if (v)
2606      { for (j=1;j<=size(P)-i;j++)
2607        { "  We find: "+string(P[i+j]);
2608        }
2609      }
2610      i=size(P);
2611      if (i==n)                        // found all primary invariants
2612      { if (v)
2613        { "";
2614          "  We found all primary invariants.";
2615          "";
2616        }
2617        if (deg_vector==0)
2618        { return(matrix(P));
2619        }
2620        else
2621        { return(matrix(P),compress(deg_vector));
2622        }
2623      }
2624    }                                  // done with degree d
2625    else
2626    { if (v)
2627      { "  None here...";
2628      }
2629    }
2630  }
2631}
2632example
2633{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
2634         ring R=3,(x,y,z),dp;
2635         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2636         list L=group_reynolds(A);
2637         list l=primary_charp_no_molien(L[1]);
2638         print(l[1]);
2639}
2640///////////////////////////////////////////////////////////////////////////////
2641
2642proc primary_charp_without (list #)
2643"USAGE:   primary_charp_without(G1,G2,...[,v]);
2644         G1,G2,...: <matrices> generating a finite matrix group, v: an optional
2645         <int>
2646DISPLAY: information about the various stages of the programme if v does not
2647         equal 0
2648RETURN:  primary invariants (type <matrix>) of the invariant ring
2649THEORY:  Bases of homogeneous invariants are generated successively and those
2650         are chosen as primary invariants that lower the dimension of the ideal
2651         generated by the previously found invariants (see paper \"Generating a
2652         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2653         Decker, Heydtmann, Schreyer (1998)). No Reynolds
2654         operator or Molien series is used.
2655EXAMPLE: example primary_charp_without; shows an example
2656"
2657{ degBound=0;
2658 //--------------------- checking input and setting verbose mode --------------
2659  if (char(basering)==0)
2660  { "ERROR:   primary_charp_without should only be used with rings of";
2661    "         characteristic 0.";
2662    return();
2663  }
2664  if (size(#)==0)
2665  { "ERROR:   There are no parameters.";
2666    return();
2667  }
2668  if (typeof(#[size(#)])=="int")
2669  { int v=#[size(#)];
2670    int gen_num=size(#)-1;
2671    if (gen_num==0)
2672    { "ERROR:   There are no generators of a finite matrix group given.";
2673      return();
2674    }
2675  }
2676  else
2677  { int v=0;
2678    int gen_num=size(#);
2679  }
2680  int n=nvars(basering);               // n is the number of variables, as well
2681                                       // as the size of the matrices, as well
2682                                       // as the number of primary invariants,
2683                                       // we should get
2684  for (int i=1;i<=gen_num;i++)
2685  { if (typeof(#[i])=="matrix")
2686    { if (nrows(#[i])<>n or ncols(#[i])<>n)
2687      { "ERROR:   The number of variables of the base ring needs to be the same";
2688        "         as the dimension of the square matrices";
2689        return();
2690      }
2691    }
2692    else
2693    { "ERROR:   The first parameters should be a list of matrices";
2694      return();
2695    }
2696  }
2697 //----------------------------------------------------------------------------
2698  if (v && voice==2)
2699  { "";
2700  }
2701 //---------------------------- initializing variables ------------------------
2702  int dB;
2703  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2704                                       // space of invariants of degree d,
2705                                       // newdim: dimension the ideal generated
2706                                       // the primary invariants plus basis
2707                                       // elements, dif=n-i-newdim, i.e. the
2708                                       // number of new primary invairants that
2709                                       // should be added in this degree -
2710  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2711                                       // Pplus: P+B, CI: a complete
2712                                       // intersection with the same Hilbert
2713                                       // function as P
2714  ideal sP=groebner(P);
2715  dB=1;                                // used as degree bound -
2716  d=0;                                 // initializing
2717  i=0;
2718  intvec deg_vector;
2719 //-------------------- loop that searches for primary invariants -------------
2720  while(1)                             // repeat until n primary invariants are
2721  {                                    // found -
2722    d++;                               // degree where we'll search
2723    if (v)
2724    { "  Computing primary invariants in degree "+string(d)+":";
2725    }
2726    B=invariant_basis(d,#[1..gen_num]); // basis of invariants of degree d
2727    if (B[1]<>0)
2728    { Pplus=P+B;
2729      sPplus=groebner(Pplus);
2730      newdim=dim(sPplus);
2731      dif=n-i-newdim;
2732    }
2733    else
2734    { dif=0;
2735      deg_vector=deg_vector,d;
2736    }
2737    if (dif<>0)                        // we have to find dif new primary
2738    {                                  // invariants
2739      cd=size(B);
2740      if (cd<>dif)
2741      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2742      }
2743      else                             // i.e. we can take all of B
2744      { for(j=i+1;j<=i+dif;j++)
2745        { CI=CI+ideal(var(j)^d);
2746        }
2747        dB=dB+dif*(d-1);
2748        P=Pplus;
2749        sP=sPplus;
2750      }
2751      if (v)
2752      { for (j=1;j<=size(P)-i;j++)
2753        { "  We find: "+string(P[i+j]);
2754        }
2755      }
2756      i=size(P);
2757      if (i==n)                        // found all primary invariants
2758      { if (v)
2759        { "";
2760          "  We found all primary invariants.";
2761          "";
2762        }
2763        return(matrix(P));
2764      }
2765    }                                  // done with degree d
2766    else
2767    { if (v)
2768      { "  None here...";
2769      }
2770    }
2771  }
2772}
2773example
2774{ "EXAMPLE:"; echo=2;
2775         ring R=2,(x,y,z),dp;
2776         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2777         matrix P=primary_charp_without(A);
2778         print(P);
2779}
2780///////////////////////////////////////////////////////////////////////////////
2781
2782proc primary_invariants (list #)
2783"USAGE:   primary_invariants(G1,G2,...[,flags]);
2784         G1,G2,...: <matrices> generating a finite matrix group, flags: an
2785         optional <intvec> with three entries, if the first one equals 0 (also
2786         the default), the programme attempts to compute the Molien series and
2787         Reynolds operator, if it equals 1, the programme is told that the
2788         Molien series should not be computed, if it equals -1 characteristic 0
2789         is simulated, i.e. the Molien series is computed as if the base field
2790         were characteristic 0 (the user must choose a field of large prime
2791         characteristic, e.g. 32003) and if the first one is anything else, it
2792         means that the characteristic of the base field divides the group
2793         order, the second component should give the size of intervals between
2794         canceling common factors in the expansion of the Molien series, 0 (the
2795         default) means only once after generating all terms, in prime
2796         characteristic also a negative number can be given to indicate that
2797         common factors should always be canceled when the expansion is simple
2798         (the root of the extension field occurs not among the coefficients)
2799DISPLAY: information about the various stages of the programme if the third
2800         flag does not equal 0
2801RETURN:  primary invariants (type <matrix>) of the invariant ring and if
2802         computable Reynolds operator (type <matrix>) and Molien series (type
2803         <matrix>) or ring name (type string) where the Molien series
2804         can be found in the char p case; if the first flag is 1 and we are in
2805         the non-modular case then an <intvec> is returned giving some of the
2806         degrees where no non-trivial homogeneous invariants can be found
2807THEORY:  Bases of homogeneous invariants are generated successively and those
2808         are chosen as primary invariants that lower the dimension of the ideal
2809         generated by the previously found invariants (see paper \"Generating a
2810         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2811         Decker, Heydtmann, Schreyer (1998)).
2812EXAMPLE: example primary_invariants; shows an example
2813"
2814{
2815 // ----------------- checking input and setting flags ------------------------
2816  if (size(#)==0)
2817  { "ERROR:   There are no parameters.";
2818    return();
2819  }
2820  int ch=char(basering);               // the algorithms depend very much on the
2821                                       // characteristic of the ground field
2822  int n=nvars(basering);               // n is the number of variables, as well
2823                                       // as the size of the matrices, as well
2824                                       // as the number of primary invariants,
2825                                       // we should get
2826  int gen_num;
2827  int mol_flag,v;
2828  if (typeof(#[size(#)])=="intvec")
2829  { if (size(#[size(#)])<>3)
2830    { "ERROR:   <intvec> should have three entries.";
2831      return();
2832    }
2833    gen_num=size(#)-1;
2834    mol_flag=#[size(#)][1];
2835    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag==-1)))
2836    { "ERROR:   the second component of <intvec> should be >=0";
2837      return();
2838    }
2839    int interval=#[size(#)][2];
2840    v=#[size(#)][3];
2841    if (gen_num==0)
2842    { "ERROR:   There are no generators of a finite matrix group given.";
2843      return();
2844    }
2845  }
2846  else
2847  { gen_num=size(#);
2848    mol_flag=0;
2849    int interval=0;
2850    v=0;
2851  }
2852  for (int i=1;i<=gen_num;i++)
2853  { if (typeof(#[i])=="matrix")
2854    { if (nrows(#[i])<>n or ncols(#[i])<>n)
2855      { "ERROR:   The number of variables of the base ring needs to be the same";
2856        "         as the dimension of the square matrices";
2857        return();
2858      }
2859    }
2860    else
2861    { "ERROR:   The first parameters should be a list of matrices";
2862      return();
2863    }
2864  }
2865 //----------------------------------------------------------------------------
2866  if (mol_flag==0)
2867  { if (ch==0)
2868    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(mol_flag,interval,v));
2869                                       // one will contain Reynolds operator and
2870                                       // the other enumerator and denominator
2871                                       // of Molien series
2872      matrix P=primary_char0(REY,M,v);
2873      return(P,REY,M);
2874    }
2875    else
2876    { list L=group_reynolds(#[1..gen_num],v);
2877      if (L[1]<>0)                     // testing whether we are in the modular
2878      { string newring="aksldfalkdsflkj"; // case
2879        if (minpoly==0)
2880        { if (v)
2881          { "  We are dealing with the non-modular case.";
2882          }
2883          if (typeof(L[2])=="int")
2884          { molien(L[3..size(L)],newring,L[2],intvec(mol_flag,interval,v));
2885          }
2886          else
2887          { molien(L[2..size(L)],newring,intvec(mol_flag,interval,v));
2888          }
2889          matrix P=primary_charp(L[1],newring,v);
2890          return(P,L[1],newring);
2891        }
2892        else
2893        { if (v)
2894          { "  Since it is impossible for this programme to calculate the Molien series for";
2895            "  invariant rings over extension fields of prime characteristic, we have to";
2896            "  continue without it.";
2897            "";
2898
2899          }
2900          list l=primary_charp_no_molien(L[1],v);
2901          if (size(l)==2)
2902          { return(l[1],L[1],l[2]);
2903          }
2904          else
2905          { return(l[1],L[1]);
2906          }
2907        }
2908      }
2909      else                             // the modular case
2910      { if (v)
2911        { "  There is also no Molien series, we can make use of...";
2912          "";
2913          "  We can start looking for primary invariants...";
2914          "";
2915        }
2916        return(primary_charp_without(#[1..gen_num],v));
2917      }
2918    }
2919  }
2920  if (mol_flag==1)                     // the user wants no calculation of the
2921  { list L=group_reynolds(#[1..gen_num],v); // Molien series
2922    if (ch==0)
2923    { list l=primary_char0_no_molien(L[1],v);
2924      if (size(l)==2)
2925      { return(l[1],L[1],l[2]);
2926      }
2927      else
2928      { return(l[1],L[1]);
2929      }
2930    }
2931    else
2932    { if (L[1]<>0)                     // testing whether we are in the modular
2933      { list l=primary_charp_no_molien(L[1],v); // case
2934        if (size(l)==2)
2935        { return(l[1],L[1],l[2]);
2936        }
2937        else
2938        { return(l[1],L[1]);
2939        }
2940      }
2941      else                             // the modular case
2942      { if (v)
2943        { "  We can start looking for primary invariants...";
2944          "";
2945        }
2946        return(primary_charp_without(#[1..gen_num],v));
2947      }
2948    }
2949  }
2950  if (mol_flag==-1)
2951  { if (ch==0)
2952    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.";
2953      return();
2954    }
2955    list L=group_reynolds(#[1..gen_num],v);
2956    string newring="aksldfalkdsflkj";
2957    molien(L[2..size(L)],newring,intvec(1,interval,v));
2958    matrix P=primary_charp(L[1],newring,v);
2959    return(P,L[1],newring);
2960  }
2961  else                                 // the user specified that the
2962  { if (ch==0)                         // characteristic divides the group order
2963    { "ERROR:   The characteristic cannot divide the group order when it is 0.";
2964      return();
2965    }
2966    if (v)
2967    { "";
2968    }
2969    return(primary_charp_without(#[1..gen_num],v));
2970  }
2971}
2972example
2973{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
2974  echo=2;
2975         ring R=0,(x,y,z),dp;
2976         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2977         list L=primary_invariants(A);
2978         print(L[1]);
2979}
2980
2981///////////////////////////////////////////////////////////////////////////////
2982// This procedure finds dif primary invariants in degree d. It returns all
2983// primary invariants found so far. The coefficients lie in a field of
2984// characteristic 0.
2985///////////////////////////////////////////////////////////////////////////////
2986proc search_random (int n,int d,ideal B,int cd,ideal P,int i,int dif,int dB,ideal CI,int max)
2987{ string answer;
2988  degBound=0;
2989  int j,k,test_dim,flag;
2990  matrix test_matrix[1][dif];          // the linear combination to test
2991  intvec h;                            // Hilbert series
2992  for (j=i+1;j<=i+dif;j++)
2993  { CI=CI+ideal(var(j)^d);             // homogeneous polynomial of the same
2994                                       // degree as the one we're looking for
2995                                       // is added
2996  }
2997  ideal TEST;
2998  // h=hilb(std(CI),1);
2999  dB=dB+dif*(d-1);                     // used as degBound
3000  while (1)
3001  { test_matrix=matrix(B)*random(max,cd,dif);
3002    // degBound=dB;
3003    TEST=P+ideal(test_matrix);
3004    attrib(TEST,"isSB",1);
3005    test_dim=dim(TEST);
3006    // degBound=0;
3007    if (n-test_dim==i+dif)
3008    { break;
3009    }
3010    // degBound=dB;
3011    test_dim=dim(groebner(TEST));
3012    // test_dim=dim(std(TEST,h));         // Hilbert driven std-calculation
3013    // degBound=0;
3014    if (n-test_dim==i+dif)
3015    { break;
3016    }
3017    else
3018    { "HELP:    The "+string(dif)+" random combination(s) of the "+string(cd)+" basis elements with";
3019      "         coefficients in the range from -"+string(max)+" to "+string(max)+" did not lower the";
3020      "         dimension by "+string(dif)+". You can abort, try again or give a new range:";
3021      answer="";
3022      while (answer<>"n
3023" && answer<>"y
3024")
3025      { "         Do you want to abort (y/n)?";
3026        answer=read("");
3027      }
3028      if (answer=="y
3029")
3030      { flag=1;
3031        break;
3032      }
3033      answer="";
3034      while (answer<>"n
3035" && answer<>"y
3036")
3037      { "         Do you want to try again (y/n)?";
3038        answer=read("");
3039      }
3040      if (answer=="n
3041")
3042      { flag=1;
3043        while (flag)
3044        { "         Give a new <int> > "+string(max)+" that bounds the range of coefficients:";
3045          answer=read("");
3046          for (j=1;j<=size(answer)-1;j++)
3047          { for (k=0;k<=9;k++)
3048            { if (answer[j]==string(k))
3049              { break;
3050              }
3051            }
3052            if (k>9)
3053            { flag=1;
3054              break;
3055            }
3056            flag=0;
3057          }
3058          if (not(flag))
3059          { execute("test_dim="+string(answer[1..size(answer)]));
3060            if (test_dim<=max)
3061            { flag=1;
3062            }
3063            else
3064            { max=test_dim;
3065            }
3066          }
3067        }
3068      }
3069    }
3070  }
3071  if (not(flag))
3072  { P[(i+1)..(i+dif)]=test_matrix[1,1..dif];
3073  }
3074  return(P,CI,dB);
3075}
3076
3077///////////////////////////////////////////////////////////////////////////////
3078// This procedure finds at most dif primary invariants in degree d. It returns
3079// all primary invariants found so far. The coefficients lie in the field of
3080// characteristic p>0.
3081///////////////////////////////////////////////////////////////////////////////
3082proc p_search_random (int n,int d,ideal B,int cd,ideal P,int i,int dif,int dB,ideal CI,int max)
3083{ string answer;
3084  degBound=0;
3085  int j,k,test_dim,flag;
3086  matrix test_matrix[1][dif];          // the linear combination to test
3087  intvec h;                            // Hilbert series
3088  ideal TEST;
3089  while (dif>0)
3090  { for (j=i+1;j<=i+dif;j++)
3091    { CI=CI+ideal(var(j)^d);           // homogeneous polynomial of the same
3092                                       // degree as the one we're looking for
3093                                       // is added
3094    }
3095    // h=hilb(std(CI),1);
3096    dB=dB+dif*(d-1);                   // used as degBound
3097    test_matrix=matrix(B)*random(max,cd,dif);
3098    // degBound=dB;
3099    TEST=P+ideal(test_matrix);
3100    attrib(TEST,"isSB",1);
3101    test_dim=dim(TEST);
3102    // degBound=0;
3103    if (n-test_dim==i+dif)
3104    { break;
3105    }
3106    // degBound=dB;
3107    test_dim=dim(groebner(TEST));
3108    // test_dim=dim(std(TEST,h));         // Hilbert driven std-calculation
3109    // degBound=0;
3110    if (n-test_dim==i+dif)
3111    { break;
3112    }
3113    else
3114    { "HELP:    The "+string(dif)+" random combination(s) of the "+string(cd)+" basis elements with";
3115      "         coefficients in the range from -"+string(max)+" to "+string(max)+" did not lower the";
3116      "         dimension by "+string(dif)+". You can abort, try again, lower the number of";
3117      "         combinations searched for by 1 or give a larger coefficient range:";
3118      answer="";
3119      while (answer<>"n
3120" && answer<>"y
3121")
3122      { "         Do you want to abort (y/n)?";
3123        answer=read("");
3124      }
3125      if (answer=="y
3126")
3127      { flag=1;
3128        break;
3129      }
3130      answer="";
3131      while (answer<>"n
3132" && answer<>"y
3133")
3134      { "         Do you want to try again (y/n)?";
3135        answer=read("");
3136      }
3137      if (answer=="n
3138")
3139      { answer="";
3140        while (answer<>"n
3141" && answer<>"y
3142")
3143        { "         Do you want to lower the number of combinations by 1 (y/n)?";
3144          answer=read("");
3145        }
3146        if (answer=="y
3147")
3148        { dif=dif-1;
3149        }
3150        else
3151        { flag=1;
3152          while (flag)
3153          { "         Give a new <int> > "+string(max)+" that bounds the range of coefficients:";
3154            answer=read("");
3155            for (j=1;j<=size(answer)-1;j++)
3156            { for (k=0;k<=9;k++)
3157              { if (answer[j]==string(k))
3158                { break;
3159                }
3160              }
3161              if (k>9)
3162              { flag=1;
3163                break;
3164              }
3165              flag=0;
3166            }
3167            if (not(flag))
3168            { execute("test_dim="+string(answer[1..size(answer)]));
3169              if (test_dim<=max)
3170              { flag=1;
3171              }
3172              else
3173              { max=test_dim;
3174              }
3175            }
3176          }
3177        }
3178      }
3179    }
3180    CI=CI[1..i];
3181    dB=dB-dif*(d-1);
3182  }
3183  if (dif && not(flag))
3184  { P[(i+1)..(i+dif)]=test_matrix[1,1..dif];
3185  }
3186  if (dif && flag)
3187  { P[n+1]=0;
3188  }
3189  return(P,CI,dB);
3190}
3191///////////////////////////////////////////////////////////////////////////////
3192
3193proc primary_char0_random (matrix REY,matrix M,int max,list #)
3194"USAGE:   primary_char0_random(REY,M,r[,v]);
3195         REY: a <matrix> representing the Reynolds operator, M: a 1x2 <matrix>
3196         representing the Molien series, r: an <int> where -|r| to |r| is the
3197         range of coefficients of the random combinations of bases elements,
3198         v: an optional <int>
3199ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
3200         M the one of molien or the second one of reynolds_molien
3201DISPLAY: information about the various stages of the programme if v does not
3202         equal 0
3203RETURN:  primary invariants (type <matrix>) of the invariant ring
3204THEORY:  Bases of homogeneous invariants are generated successively and random
3205         linear combinations are chosen as primary invariants that lower the
3206         dimension of the ideal generated by the previously found invariants
3207         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3208         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3209EXAMPLE: example primary_char0_random; shows an example
3210"
3211{ degBound=0;
3212  if (char(basering)<>0)
3213  { "ERROR:   primary_char0_random should only be used with rings of";
3214    "         characteristic 0.";
3215    return();
3216  }
3217 //----------------- checking input and setting verbose mode ------------------
3218  if (size(#)>1)
3219  { "ERROR:   primary_char0_random can only have four parameters.";
3220    return();
3221  }
3222  if (size(#)==1)
3223  { if (typeof(#[1])<>"int")
3224    { "ERROR:   The fourth parameter should be of type <int>.";
3225      return();
3226    }
3227    else
3228    { int v=#[1];
3229    }
3230  }
3231  else
3232  { int v=0;
3233  }
3234  int n=nvars(basering);               // n is the number of variables, as well
3235                                       // as the size of the matrices, as well
3236                                       // as the number of primary invariants,
3237                                       // we should get
3238  if (ncols(REY)<>n)
3239  { "ERROR:   First parameter ought to be the Reynolds operator."
3240    return();
3241  }
3242  if (ncols(M)<>2 or nrows(M)<>1)
3243  { "ERROR:   Second parameter ought to be the Molien series."
3244    return();
3245  }
3246 //----------------------------------------------------------------------------
3247  if (v && voice<>2)
3248  { "  We can start looking for primary invariants...";
3249    "";
3250  }
3251  if (v && voice==2)
3252  { "";
3253  }
3254 //------------------------- initializing variables ---------------------------
3255  int dB;
3256  poly p(1..2);                        // p(1) will be used for single terms of
3257                                       // the partial expansion, p(2) to store
3258  p(1..2)=partial_molien(M,1);         // the intermediate result -
3259  poly v1=var(1);                      // we need v1 to split off coefficients
3260                                       // in the partial expansion of M (which
3261                                       // is in terms of the first variable) -
3262  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3263                                       // space of invariants of degree d,
3264                                       // newdim: dimension the ideal generated
3265                                       // the primary invariants plus basis
3266                                       // elements, dif=n-i-newdim, i.e. the
3267                                       // number of new primary invairants that
3268                                       // should be added in this degree -
3269  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3270                                       // Pplus: P+B,CI: a complete
3271                                       // intersection with the same Hilbert
3272                                       // function as P -
3273  dB=1;                                // used as degree bound
3274  int i=0;
3275 //-------------- loop that searches for primary invariants  ------------------
3276  while(1)                             // repeat until n primary invariants are
3277  {                                    // found -
3278    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
3279    d=deg(p(1));                       // degree where we'll search -
3280    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
3281                                       // inviarants of degree d
3282    if (v)
3283    { "  Computing primary invariants in degree "+string(d)+":";
3284    }
3285    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
3286                                       // degree d
3287    if (B[1]<>0)
3288    { Pplus=P+B;
3289      newdim=dim(groebner(Pplus));
3290      dif=n-i-newdim;
3291    }
3292    else
3293    { dif=0;
3294    }
3295    if (dif<>0)                        // we have to find dif new primary
3296    {                                  // invariants
3297      if (cd<>dif)
3298      { P,CI,dB=search_random(n,d,B,cd,P,i,dif,dB,CI,max); // searching for
3299      }                                // dif invariants -
3300      else                             // i.e. we can take all of B
3301      { for(j=i+1;j>i+dif;j++)
3302        { CI=CI+ideal(var(j)^d);
3303        }
3304        dB=dB+dif*(d-1);
3305        P=Pplus;
3306      }
3307      if (ncols(P)==i)
3308      { "WARNING: The return value is not a set of primary invariants, but";
3309        "         polynomials qualifying as the first "+string(i)+" primary invariants.";
3310        return(matrix(P));
3311      }
3312      if (v)
3313      { for (j=1;j<=dif;j++)
3314        { "  We find: "+string(P[i+j]);
3315        }
3316      }
3317      i=i+dif;
3318      if (i==n)                        // found all primary invariants
3319      { if (v)
3320        { "";
3321          "  We found all primary invariants.";
3322          "";
3323        }
3324        return(matrix(P));
3325      }
3326    }                                  // done with degree d
3327  }
3328}
3329example
3330{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
3331         ring R=0,(x,y,z),dp;
3332         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3333         matrix REY,M=reynolds_molien(A);
3334         matrix P=primary_char0_random(REY,M,1);
3335         print(P);
3336}
3337///////////////////////////////////////////////////////////////////////////////
3338
3339proc primary_charp_random (matrix REY,string ring_name,int max,list #)
3340"USAGE:   primary_charp_random(REY,ringname,r[,v]);
3341         REY: a <matrix> representing the Reynolds operator, ringname: a
3342         <string> giving the name of a ring where the Molien series is stored,
3343         r: an <int> where -|r| to |r| is the range of coefficients of the
3344         random combinations of bases elements, v: an optional <int>
3345ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
3346         ringname gives the name of a ring of characteristic 0 that has been
3347         created by molien or reynolds_molien
3348DISPLAY: information about the various stages of the programme if v does not
3349         equal 0
3350RETURN:  primary invariants (type <matrix>) of the invariant ring
3351THEORY:  Bases of homogeneous invariants are generated successively and random
3352         linear combinations are chosen as primary invariants that lower the
3353         dimension of the ideal generated by the previously found invariants
3354         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3355         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3356EXAMPLE: example primary_charp_random; shows an example
3357"
3358{ degBound=0;
3359 // ---------------- checking input and setting verbose mode ------------------
3360  if (char(basering)==0)
3361  { "ERROR:   primary_charp_random should only be used with rings of";
3362    "         characteristic p>0.";
3363    return();
3364  }
3365  if (size(#)>1)
3366  { "ERROR:   primary_charp_random can only have four parameters.";
3367    return();
3368  }
3369  if (size(#)==1)
3370  { if (typeof(#[1])<>"int")
3371    { "ERROR:   The fourth parameter should be of type <int>.";
3372      return();
3373    }
3374    else
3375    { int v=#[1];
3376    }
3377  }
3378  else
3379  { int v=0;
3380  }
3381  def br=basering;
3382  int n=nvars(br);                     // n is the number of variables, as well
3383                                       // as the size of the matrices, as well
3384                                       // as the number of primary invariants,
3385                                       // we should get
3386  if (ncols(REY)<>n)
3387  { "ERROR:   First parameter ought to be the Reynolds operator."
3388    return();
3389  }
3390  if (typeof(`ring_name`)<>"ring")
3391  { "ERROR:   Second parameter ought to the name of a ring where the Molien";
3392    "         is stored.";
3393    return();
3394  }
3395 //----------------------------------------------------------------------------
3396  if (v && voice<>2)
3397  { "  We can start looking for primary invariants...";
3398    "";
3399  }
3400  if (v && voice==2)
3401  { "";
3402  }
3403 //----------------------- initializing variables -----------------------------
3404  int dB;
3405  setring `ring_name`;                 // the Molien series is stores here -
3406  poly p(1..2);                        // p(1) will be used for single terms of
3407                                       // the partial expansion, p(2) to store
3408  p(1..2)=partial_molien(M,1);         // the intermediate result -
3409  poly v1=var(1);                      // we need v1 to split off coefficients
3410                                       // in the partial expansion of M (which
3411                                       // is in terms of the first variable)
3412  setring br;
3413  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3414                                       // space of invariants of degree d,
3415                                       // newdim: dimension the ideal generated
3416                                       // the primary invariants plus basis
3417                                       // elements, dif=n-i-newdim, i.e. the
3418                                       // number of new primary invairants that
3419                                       // should be added in this degree -
3420  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3421                                       // Pplus: P+B, CI: a complete
3422                                       // intersection with the same Hilbert
3423                                       // function as P -
3424  dB=1;                                // used as degree bound
3425  int i=0;
3426 //---------------- loop that searches for primary invariants -----------------
3427  while(1)                             // repeat until n primary invariants are
3428  {                                    // found
3429    setring `ring_name`;
3430    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
3431    d=deg(p(1));                       // degree where we'll search -
3432    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
3433                                       // inviarants of degree d
3434    setring br;
3435    if (v)
3436    { "  Computing primary invariants in degree "+string(d)+":";
3437    }
3438    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
3439                                       // degree d
3440    if (B[1]<>0)
3441    { Pplus=P+B;
3442      newdim=dim(groebner(Pplus));
3443      dif=n-i-newdim;
3444    }
3445    else
3446    { dif=0;
3447    }
3448    if (dif<>0)                        // we have to find dif new primary
3449    {                                  // invariants
3450      if (cd<>dif)
3451      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3452      }
3453      else                             // i.e. we can take all of B
3454      { for(j=i+1;j>i+dif;j++)
3455        { CI=CI+ideal(var(j)^d);
3456        }
3457        dB=dB+dif*(d-1);
3458        P=Pplus;
3459      }
3460      if (ncols(P)==n+1)
3461      { "WARNING: The first return value is not a set of primary invariants,";
3462        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3463        return(matrix(P));
3464      }
3465      if (v)
3466      { for (j=1;j<=size(P)-i;j++)
3467        { "  We find: "+string(P[i+j]);
3468        }
3469      }
3470      i=size(P);
3471      if (i==n)                        // found all primary invariants
3472      { if (v)
3473        { "";
3474          "  We found all primary invariants.";
3475          "";
3476        }
3477        return(matrix(P));
3478      }
3479    }                                  // done with degree d
3480  }
3481}
3482example
3483{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
3484         ring R=3,(x,y,z),dp;
3485         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3486         list L=group_reynolds(A);
3487         string newring="alskdfj";
3488         molien(L[2..size(L)],newring);
3489         matrix P=primary_charp_random(L[1],newring,1);
3490         kill `newring`;
3491         print(P);
3492}
3493///////////////////////////////////////////////////////////////////////////////
3494
3495proc primary_char0_no_molien_random (matrix REY, int max, list #)
3496"USAGE:   primary_char0_no_molien_random(REY,r[,v]);
3497         REY: a <matrix> representing the Reynolds operator, r: an <int> where
3498         -|r| to |r| is the range of coefficients of the random combinations of
3499         bases elements, v: an optional <int>
3500ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
3501DISPLAY: information about the various stages of the programme if v does not
3502         equal 0
3503RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
3504         <intvec> listing some of the degrees where no non-trivial homogeneous
3505         invariants are to be found
3506THEORY:  Bases of homogeneous invariants are generated successively and random
3507         linear combinations are chosen as primary invariants that lower the
3508         dimension of the ideal generated by the previously found invariants
3509         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3510         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3511EXAMPLE: example primary_char0_no_molien_random; shows an example
3512"
3513{ degBound=0;
3514 //-------------- checking input and setting verbose mode ---------------------
3515  if (char(basering)<>0)
3516  { "ERROR:   primary_char0_no_molien_random should only be used with rings of";
3517    "         characteristic 0.";
3518    return();
3519  }
3520  if (size(#)>1)
3521  { "ERROR:   primary_char0_no_molien_random can only have three parameters.";
3522    return();
3523  }
3524  if (size(#)==1)
3525  { if (typeof(#[1])<>"int")
3526    { "ERROR:   The third parameter should be of type <int>.";
3527      return();
3528    }
3529    else
3530    { int v=#[1];
3531    }
3532  }
3533  else
3534  { int v=0;
3535  }
3536  int n=nvars(basering);               // n is the number of variables, as well
3537                                       // as the size of the matrices, as well
3538                                       // as the number of primary invariants,
3539                                       // we should get
3540  if (ncols(REY)<>n)
3541  { "ERROR:   First parameter ought to be the Reynolds operator."
3542    return();
3543  }
3544 //----------------------------------------------------------------------------
3545  if (v && voice<>2)
3546  { "  We can start looking for primary invariants...";
3547    "";
3548  }
3549  if (v && voice==2)
3550  { "";
3551  }
3552 //----------------------- initializing variables -----------------------------
3553  int dB;
3554  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3555                                       // space of invariants of degree d,
3556                                       // newdim: dimension the ideal generated
3557                                       // the primary invariants plus basis
3558                                       // elements, dif=n-i-newdim, i.e. the
3559                                       // number of new primary invairants that
3560                                       // should be added in this degree -
3561  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3562                                       // Pplus: P+B, CI: a complete
3563                                       // intersection with the same Hilbert
3564                                       // function as P -
3565  dB=1;                                // used as degree bound -
3566  d=0;                                 // initializing
3567  int i=0;
3568  intvec deg_vector;
3569 //------------------ loop that searches for primary invariants ---------------
3570  while(1)                             // repeat until n primary invariants are
3571  {                                    // found -
3572    d++;                               // degree where we'll search
3573    if (v)
3574    { "  Computing primary invariants in degree "+string(d)+":";
3575    }
3576    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
3577                                       // degree d
3578    if (B[1]<>0)
3579    { Pplus=P+B;
3580      newdim=dim(groebner(Pplus));
3581      dif=n-i-newdim;
3582    }
3583    else
3584    { dif=0;
3585      deg_vector=deg_vector,d;
3586    }
3587    if (dif<>0)                        // we have to find dif new primary
3588    {                                  // invariants
3589      cd=size(B);
3590      if (cd<>dif)
3591      { P,CI,dB=search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3592      }
3593      else                             // i.e. we can take all of B
3594      { for(j=i+1;j<=i+dif;j++)
3595        { CI=CI+ideal(var(j)^d);
3596        }
3597        dB=dB+dif*(d-1);
3598        P=Pplus;
3599      }
3600      if (ncols(P)==i)
3601      { "WARNING: The first return value is not a set of primary invariants,";
3602        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3603        return(matrix(P));
3604      }
3605      if (v)
3606      { for (j=1;j<=dif;j++)
3607        { "  We find: "+string(P[i+j]);
3608        }
3609      }
3610      i=i+dif;
3611      if (i==n)                        // found all primary invariants
3612      { if (v)
3613        { "";
3614          "  We found all primary invariants.";
3615          "";
3616        }
3617        if (deg_vector==0)
3618        { return(matrix(P));
3619        }
3620        else
3621        { return(matrix(P),compress(deg_vector));
3622        }
3623      }
3624    }                                  // done with degree d
3625    else
3626    { if (v)
3627      { "  None here...";
3628      }
3629    }
3630  }
3631}
3632example
3633{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
3634         ring R=0,(x,y,z),dp;
3635         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3636         list L=group_reynolds(A);
3637         list l=primary_char0_no_molien_random(L[1],1);
3638         print(l[1]);
3639}
3640///////////////////////////////////////////////////////////////////////////////
3641
3642proc primary_charp_no_molien_random (matrix REY, int max, list #)
3643"USAGE:   primary_charp_no_molien_random(REY,r[,v]);
3644         REY: a <matrix> representing the Reynolds operator, r: an <int> where
3645         -|r| to |r| is the range of coefficients of the random combinations of
3646         bases elements, v: an optional <int>
3647ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
3648DISPLAY: information about the various stages of the programme if v does not
3649         equal 0
3650RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
3651         <intvec> listing some of the degrees where no non-trivial homogeneous
3652         invariants are to be found
3653THEORY:  Bases of homogeneous invariants are generated successively and random
3654         linear combinations are chosen as primary invariants that lower the
3655         dimension of the ideal generated by the previously found invariants
3656         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3657         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3658EXAMPLE: example primary_charp_no_molien_random; shows an example
3659"
3660{ degBound=0;
3661 //----------------- checking input and setting verbose mode ------------------
3662  if (char(basering)==0)
3663  { "ERROR:   primary_charp_no_molien_random should only be used with rings of";
3664    "         characteristic p>0.";
3665    return();
3666  }
3667  if (size(#)>1)
3668  { "ERROR:   primary_charp_no_molien_random can only have three parameters.";
3669    return();
3670  }
3671  if (size(#)==1)
3672  { if (typeof(#[1])<>"int")
3673    { "ERROR:   The third parameter should be of type <int>.";
3674      return();
3675    }
3676    else
3677    { int v=#[1];
3678    }
3679  }
3680  else
3681  { int v=0;
3682  }
3683  int n=nvars(basering);               // n is the number of variables, as well
3684                                       // as the size of the matrices, as well
3685                                       // as the number of primary invariants,
3686                                       // we should get
3687  if (ncols(REY)<>n)
3688  { "ERROR:   First parameter ought to be the Reynolds operator."
3689    return();
3690  }
3691 //----------------------------------------------------------------------------
3692  if (v && voice<>2)
3693  { "  We can start looking for primary invariants...";
3694    "";
3695  }
3696  if (v && voice==2)
3697  { "";
3698  }
3699 //-------------------- initializing variables --------------------------------
3700  int dB;
3701  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3702                                       // space of invariants of degree d,
3703                                       // newdim: dimension the ideal generated
3704                                       // the primary invariants plus basis
3705                                       // elements, dif=n-i-newdim, i.e. the
3706                                       // number of new primary invairants that
3707                                       // should be added in this degree -
3708  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3709                                       // Pplus: P+B, CI: a complete
3710                                       // intersection with the same Hilbert
3711                                       // function as P -
3712  dB=1;                                // used as degree bound -
3713  d=0;                                 // initializing
3714  int i=0;
3715  intvec deg_vector;
3716 //------------------ loop that searches for primary invariants ---------------
3717  while(1)                             // repeat until n primary invariants are
3718  {                                    // found -
3719    d++;                               // degree where we'll search
3720    if (v)
3721    { "  Computing primary invariants in degree "+string(d)+":";
3722    }
3723    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
3724                                       // degree d
3725    if (B[1]<>0)
3726    { Pplus=P+B;
3727      newdim=dim(groebner(Pplus));
3728      dif=n-i-newdim;
3729    }
3730    else
3731    { dif=0;
3732      deg_vector=deg_vector,d;
3733    }
3734    if (dif<>0)                        // we have to find dif new primary
3735    {                                  // invariants
3736      cd=size(B);
3737      if (cd<>dif)
3738      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3739      }
3740      else                             // i.e. we can take all of B
3741      { for(j=i+1;j<=i+dif;j++)
3742        { CI=CI+ideal(var(j)^d);
3743        }
3744        dB=dB+dif*(d-1);
3745        P=Pplus;
3746      }
3747      if (ncols(P)==n+1)
3748      { "WARNING: The first return value is not a set of primary invariants,";
3749        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3750        return(matrix(P));
3751      }
3752      if (v)
3753      { for (j=1;j<=size(P)-i;j++)
3754        { "  We find: "+string(P[i+j]);
3755        }
3756      }
3757      i=size(P);
3758      if (i==n)                        // found all primary invariants
3759      { if (v)
3760        { "";
3761          "  We found all primary invariants.";
3762          "";
3763        }
3764        if (deg_vector==0)
3765        { return(matrix(P));
3766        }
3767        else
3768        { return(matrix(P),compress(deg_vector));
3769        }
3770      }
3771    }                                  // done with degree d
3772    else
3773    { if (v)
3774      { "  None here...";
3775      }
3776    }
3777  }
3778}
3779example
3780{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
3781         ring R=3,(x,y,z),dp;
3782         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3783         list L=group_reynolds(A);
3784         list l=primary_charp_no_molien_random(L[1],1);
3785         print(l[1]);
3786}
3787///////////////////////////////////////////////////////////////////////////////
3788
3789proc primary_charp_without_random (list #)
3790"USAGE:   primary_charp_without_random(G1,G2,...,r[,v]);
3791         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
3792         where -|r| to |r| is the range of coefficients of the random
3793         combinations of bases elements, v: an optional <int>
3794DISPLAY: information about the various stages of the programme if v does not
3795         equal 0
3796RETURN:  primary invariants (type <matrix>) of the invariant ring
3797THEORY:  Bases of homogeneous invariants are generated successively and random
3798         linear combinations are chosen as primary invariants that lower the
3799         dimension of the ideal generated by the previously found invariants
3800         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3801         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)). No Reynolds
3802         operator or Molien series is used.
3803EXAMPLE: example primary_charp_without_random; shows an example
3804"
3805{ degBound=0;
3806 //--------------------- checking input and setting verbose mode --------------
3807  if (char(basering)==0)
3808  { "ERROR:   primary_charp_without_random should only be used with rings of";
3809    "         characteristic 0.";
3810    return();
3811  }
3812  if (size(#)<2)
3813  { "ERROR:   There are too few parameters.";
3814    return();
3815  }
3816  if (typeof(#[size(#)])=="int" && typeof(#[size(#)-1])=="int")
3817  { int v=#[size(#)];
3818    int max=#[size(#)-1];
3819    int gen_num=size(#)-2;
3820    if (gen_num==0)
3821    { "ERROR:   There are no generators of a finite matrix group given.";
3822      return();
3823    }
3824  }
3825  else
3826  { if (typeof(#[size(#)])=="int")
3827    { int max=#[size(#)];
3828      int v=0;
3829      int gen_num=size(#)-1;
3830    }
3831    else
3832    { "ERROR:   The last parameter should be an <int>.";
3833      return();
3834    }
3835  }
3836  int n=nvars(basering);               // n is the number of variables, as well
3837                                       // as the size of the matrices, as well
3838                                       // as the number of primary invariants,
3839                                       // we should get
3840  for (int i=1;i<=gen_num;i++)
3841  { if (typeof(#[i])=="matrix")
3842    { if (nrows(#[i])<>n or ncols(#[i])<>n)
3843      { "ERROR:   The number of variables of the base ring needs to be the same";
3844        "         as the dimension of the square matrices";
3845        return();
3846      }
3847    }
3848    else
3849    { "ERROR:   The first parameters should be a list of matrices";
3850      return();
3851    }
3852  }
3853 //----------------------------------------------------------------------------
3854  if (v && voice==2)
3855  { "";
3856  }
3857 //---------------------------- initializing variables ------------------------
3858  int dB;
3859  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3860                                       // space of invariants of degree d,
3861                                       // newdim: dimension the ideal generated
3862                                       // the primary invariants plus basis
3863                                       // elements, dif=n-i-newdim, i.e. the
3864                                       // number of new primary invairants that
3865                                       // should be added in this degree -
3866  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3867                                       // Pplus: P+B, CI: a complete
3868                                       // intersection with the same Hilbert
3869                                       // function as P -
3870  dB=1;                                // used as degree bound -
3871  d=0;                                 // initializing
3872  i=0;
3873  intvec deg_vector;
3874 //-------------------- loop that searches for primary invariants -------------
3875  while(1)                             // repeat until n primary invariants are
3876  {                                    // found -
3877    d++;                               // degree where we'll search
3878    if (v)
3879    { "  Computing primary invariants in degree "+string(d)+":";
3880    }
3881    B=invariant_basis(d,#[1..gen_num]); // basis of invariants of degree d
3882    if (B[1]<>0)
3883    { Pplus=P+B;
3884      newdim=dim(groebner(Pplus));
3885      dif=n-i-newdim;
3886    }
3887    else
3888    { dif=0;
3889      deg_vector=deg_vector,d;
3890    }
3891    if (dif<>0)                        // we have to find dif new primary
3892    {                                  // invariants
3893      cd=size(B);
3894      if (cd<>dif)
3895      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3896      }
3897      else                             // i.e. we can take all of B
3898      { for(j=i+1;j<=i+dif;j++)
3899        { CI=CI+ideal(var(j)^d);
3900        }
3901        dB=dB+dif*(d-1);
3902        P=Pplus;
3903      }
3904      if (ncols(P)==n+1)
3905      { "WARNING: The first return value is not a set of primary invariants,";
3906        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3907        return(matrix(P));
3908      }
3909      if (v)
3910      { for (j=1;j<=size(P)-i;j++)
3911        { "  We find: "+string(P[i+j]);
3912        }
3913      }
3914      i=size(P);
3915      if (i==n)                        // found all primary invariants
3916      { if (v)
3917        { "";
3918          "  We found all primary invariants.";
3919          "";
3920        }
3921        return(matrix(P));
3922      }
3923    }                                  // done with degree d
3924    else
3925    { if (v)
3926      { "  None here...";
3927      }
3928    }
3929  }
3930}
3931example
3932{ "EXAMPLE:"; echo=2;
3933         ring R=2,(x,y,z),dp;
3934         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3935         matrix P=primary_charp_without_random(A,1);
3936         print(P);
3937}
3938///////////////////////////////////////////////////////////////////////////////
3939
3940proc primary_invariants_random (list #)
3941"USAGE:   primary_invariants_random(G1,G2,...,r[,flags]);
3942         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
3943         where -|r| to |r| is the range of coefficients of the random
3944         combinations of bases elements, flags: an optional <intvec> with three
3945         entries, if the first one equals 0 (also the default), the programme
3946         attempts to compute the Molien series and Reynolds operator, if it
3947         equals 1, the programme is told that the Molien series should not be
3948         computed, if it equals -1 characteristic 0 is simulated, i.e. the
3949         Molien series is computed as if the base field were characteristic 0
3950         (the user must choose a field of large prime characteristic, e.g.
3951         32003) and if the first one is anything else, it means that the
3952         characteristic of the base field divides the group order, the second
3953         component should give the size of intervals between canceling common
3954         factors in the expansion of the Molien series, 0 (the default) means
3955         only once after generating all terms, in prime characteristic also a
3956         negative number can be given to indicate that common factors should
3957         always be canceled when the expansion is simple (the root of the
3958         extension field does not occur among the coefficients)
3959DISPLAY: information about the various stages of the programme if the third
3960         flag does not equal 0
3961RETURN:  primary invariants (type <matrix>) of the invariant ring and if
3962         computable Reynolds operator (type <matrix>) and Molien series (type
3963         <matrix>), if the first flag is 1 and we are in the non-modular case
3964         then an <intvec> is returned giving some of the degrees where no
3965         non-trivial homogeneous invariants can be found
3966THEORY:  Bases of homogeneous invariants are generated successively and random
3967         linear combinations are chosen as primary invariants that lower the
3968         dimension of the ideal generated by the previously found invariants
3969         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3970         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3971EXAMPLE: example primary_invariants_random; shows an example
3972"
3973{
3974 // ----------------- checking input and setting flags ------------------------
3975  if (size(#)<2)
3976  { "ERROR:   There are too few parameters.";
3977    return();
3978  }
3979  int ch=char(basering);               // the algorithms depend very much on the
3980                                       // characteristic of the ground field
3981  int n=nvars(basering);               // n is the number of variables, as well
3982                                       // as the size of the matrices, as well
3983                                       // as the number of primary invariants,
3984                                       // we should get
3985  int gen_num;
3986  int mol_flag,v;
3987  if (typeof(#[size(#)])=="intvec" && typeof(#[size(#)-1])=="int")
3988  { if (size(#[size(#)])<>3)
3989    { "ERROR:   <intvec> should have three entries.";
3990      return();
3991    }
3992    gen_num=size(#)-2;
3993    mol_flag=#[size(#)][1];
3994    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
3995    { "ERROR:   the second component of <intvec> should be >=0";
3996      return();
3997    }
3998    int interval=#[size(#)][2];
3999    v=#[size(#)][3];
4000    int max=#[size(#)-1];
4001    if (gen_num==0)
4002    { "ERROR:   There are no generators of a finite matrix group given.";
4003      return();
4004    }
4005  }
4006  else
4007  { if (typeof(#[size(#)])=="int")
4008    { gen_num=size(#)-1;
4009      mol_flag=0;
4010      int interval=0;
4011      v=0;
4012      int max=#[size(#)];
4013    }
4014    else
4015    { "ERROR:   If the two last parameters are not <int> and <intvec>, the last";
4016      "         parameter should be an <int>.";
4017      return();
4018    }
4019  }
4020  for (int i=1;i<=gen_num;i++)
4021  { if (typeof(#[i])=="matrix")
4022    { if (nrows(#[i])<>n or ncols(#[i])<>n)
4023      { "ERROR:   The number of variables of the base ring needs to be the same";
4024        "         as the dimension of the square matrices";
4025        return();
4026      }
4027    }
4028    else
4029    { "ERROR:   The first parameters should be a list of matrices";
4030      return();
4031    }
4032  }
4033 //----------------------------------------------------------------------------
4034  if (mol_flag==0)
4035  { if (ch==0)
4036    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v));
4037                                       // one will contain Reynolds operator and
4038                                       // the other enumerator and denominator
4039                                       // of Molien series
4040      matrix P=primary_char0_random(REY,M,max,v);
4041      return(P,REY,M);
4042    }
4043    else
4044    { list L=group_reynolds(#[1..gen_num],v);
4045      if (L[1]<>0)                     // testing whether we are in the modular
4046      { string newring="aksldfalkdsflkj"; // case
4047        if (minpoly==0)
4048        { if (v)
4049          { "  We are dealing with the non-modular case.";
4050          }
4051          if (typeof(L[2])=="int")
4052          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
4053          }
4054          else
4055          { molien(L[2..size(L)],newring,intvec(0,interval,v));
4056          }
4057          matrix P=primary_charp_random(L[1],newring,max,v);
4058          return(P,L[1],newring);
4059        }
4060        else
4061        { if (v)
4062          { "  Since it is impossible for this programme to calculate the Molien series for";
4063            "  invariant rings over extension fields of prime characteristic, we have to";
4064            "  continue without it.";
4065            "";
4066
4067          }
4068          list l=primary_charp_no_molien_random(L[1],max,v);
4069          if (size(l)==2)
4070          { return(l[1],L[1],l[2]);
4071          }
4072          else
4073          { return(l[1],L[1]);
4074          }
4075        }
4076      }
4077      else                             // the modular case
4078      { if (v)
4079        { "  There is also no Molien series, we can make use of...";
4080          "";
4081          "  We can start looking for primary invariants...";
4082          "";
4083        }
4084        return(primary_charp_without_random(#[1..gen_num],max,v));
4085      }
4086    }
4087  }
4088  if (mol_flag==1)                     // the user wants no calculation of the
4089  { list L=group_reynolds(#[1..gen_num],v); // Molien series
4090    if (ch==0)
4091    { list l=primary_char0_no_molien_random(L[1],max,v);
4092      if (size(l)==2)
4093      { return(l[1],L[1],l[2]);
4094      }
4095      else
4096      { return(l[1],L[1]);
4097      }
4098    }
4099    else
4100    { if (L[1]<>0)                     // testing whether we are in the modular
4101      { list l=primary_charp_no_molien_random(L[1],max,v); // case
4102        if (size(l)==2)
4103        { return(l[1],L[1],l[2]);
4104        }
4105        else
4106        { return(l[1],L[1]);
4107        }
4108      }
4109      else                             // the modular case
4110      { if (v)
4111        { "  We can start looking for primary invariants...";
4112          "";
4113        }
4114        return(primary_charp_without_random(#[1..gen_num],max,v));
4115      }
4116    }
4117  }
4118  if (mol_flag==-1)
4119  { if (ch==0)
4120    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.";
4121      return();
4122    }
4123    list L=group_reynolds(#[1..gen_num],v);
4124    string newring="aksldfalkdsflkj";
4125    if (typeof(L[2])=="int")
4126    { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
4127    }
4128    else
4129    { molien(L[2..size(L)],newring,intvec(0,interval,v));
4130    }
4131    matrix P=primary_charp_random(L[1],newring,max,v);
4132    return(P,L[1],newring);
4133  }
4134  else                                 // the user specified that the
4135  { if (ch==0)                         // characteristic divides the group order
4136    { "ERROR:   The characteristic cannot divide the group order when it is 0.";
4137      return();
4138    }
4139    if (v)
4140    { "";
4141    }
4142    return(primary_charp_without_random(#[1..gen_num],max,v));
4143  }
4144}
4145example
4146{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4147         ring R=0,(x,y,z),dp;
4148         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4149         list L=primary_invariants_random(A,1);
4150         print(L[1]);
4151}
4152///////////////////////////////////////////////////////////////////////////////
4153
4154proc concat_intmat(intmat A,intmat B)
4155{ int n=nrows(A);
4156  int m1=ncols(A);
4157  int m2=ncols(B);
4158  intmat C[n][m1+m2];
4159  C[1..n,1..m1]=A[1..n,1..m1];
4160  C[1..n,m1+1..m1+m2]=B[1..n,1..m2];
4161  return(C);
4162}
4163///////////////////////////////////////////////////////////////////////////////
4164
4165proc power_products(intvec deg_vec,int d)
4166"USAGE:   power_products(dv,d);
4167         dv: an <intvec> giving the degrees of homogeneous polynomials, d: the
4168         degree of the desired power products
4169RETURN:  a size(dv)*m <intmat> where each column ought to be interpreted as
4170         containing the exponents of the corresponding polynomials. The product
4171         of the powers is then homogeneous of degree d.
4172EXAMPLE: example power_products; shows an example
4173"
4174{ ring R=0,x,dp;
4175  if (d<=0)
4176  { "ERROR:   The <int> may not be <= 0";
4177    return();
4178  }
4179  int d_neu,j,nc;
4180  int s=size(deg_vec);
4181  intmat PP[s][1];
4182  intmat TEST[s][1];
4183  for (int i=1;i<=s;i++)
4184  { if (i<0)
4185    { "ERROR:   The entries of <intvec> may not be <= 0";
4186      return();
4187    }
4188    d_neu=d-deg_vec[i];
4189    if (d_neu>0)
4190    { intmat PPd_neu=power_products(intvec(deg_vec[i..s]),d_neu);
4191      if (size(ideal(PPd_neu))<>0)
4192      { nc=ncols(PPd_neu);
4193        intmat PPd_neu_gross[s][nc];
4194        PPd_neu_gross[i..s,1..nc]=PPd_neu[1..s-i+1,1..nc];
4195        for (j=1;j<=nc;j++)
4196        { PPd_neu_gross[i,j]=PPd_neu_gross[i,j]+1;
4197        }
4198        PP=concat_intmat(PP,PPd_neu_gross);
4199        kill PPd_neu_gross;
4200      }
4201      kill PPd_neu;
4202    }
4203    if (d_neu==0)
4204    { intmat PPd_neu[s][1];
4205      PPd_neu[i,1]=1;
4206      PP=concat_intmat(PP,PPd_neu);
4207      kill PPd_neu;
4208    }
4209  }
4210  if (matrix(PP)<>matrix(TEST))
4211  { PP=compress(PP);
4212  }
4213  return(PP);
4214}
4215example
4216{ "EXAMPLE:"; echo=2;
4217         intvec dv=5,5,5,10,10;
4218         print(power_products(dv,10));
4219         print(power_products(dv,7));
4220}
4221///////////////////////////////////////////////////////////////////////////////
4222
4223static proc old_secondary_char0 (matrix P, matrix REY, matrix M, list #)
4224"USAGE:   secondary_char0(P,REY,M[,v]);
4225         P: a 1xn <matrix> with primary invariants,
4226         REY: a gxn <matrix> representing the Reynolds operator,
4227         M: a 1x2 <matrix> giving numerator and denominator of the Molien series,
4228         v: an optional <int>
4229ASSUME:  n is the number of variables of the basering, g the size of the group,
4230         REY is the 1st return value of group_reynolds(), reynolds_molien() or
4231         the second one of primary_invariants(), M the return value of molien()
4232         or the second one of reynolds_molien() or the third one of
4233         primary_invariants()
4234RETURN:  secondary invariants of the invariant ring (type <matrix>) and
4235         irreducible secondary invariants (type <matrix>)
4236DISPLAY: information if v does not equal 0
4237THEORY:  The secondary invariants are calculated by finding a basis (in terms
4238         of monomials) of the basering modulo the primary invariants, mapping
4239         those to invariants with the Reynolds operator and using these images
4240         or their power products such that they are linearly independent modulo
4241         the primary invariants (see paper \"Some Algorithms in Invariant
4242         Theory of Finite Groups\" by Kemper and Steel (1997)).
4243"
4244{ def br=basering;
4245  degBound=0;
4246 //----------------- checking input and setting verbose mode ------------------
4247  if (char(br)<>0)
4248  { "ERROR:   secondary_char0 should only be used with rings of characteristic 0.";
4249    return();
4250  }
4251  int i;
4252  if (size(#)>0)
4253  { if (typeof(#[size(#)])=="int")
4254    { int v=#[size(#)];
4255    }
4256    else
4257    { int v=0;
4258    }
4259  }
4260  else
4261  { int v=0;
4262  }
4263  int n=nvars(br);                     // n is the number of variables, as well
4264                                       // as the size of the matrices, as well
4265                                       // as the number of primary invariants,
4266                                       // we should get
4267  if (ncols(P)<>n)
4268  { "ERROR:   The first parameter ought to be the matrix of the primary";
4269    "         invariants."
4270    return();
4271  }
4272  if (ncols(REY)<>n)
4273  { "ERROR:   The second parameter ought to be the Reynolds operator."
4274    return();
4275  }
4276  if (ncols(M)<>2 or nrows(M)<>1)
4277  { "ERROR:   The third parameter ought to be the Molien series."
4278    return();
4279  }
4280  if (v && voice==2)
4281  { "";
4282  }
4283  int j, m, counter;
4284 //- finding the polynomial giving number and degrees of secondary invariants -
4285  poly p=1;
4286  for (j=1;j<=n;j++)                   // calculating the denominator of the
4287  { p=p*(1-var(1)^deg(P[j]));          // Hilbert series of the ring generated
4288  }                                    // by the primary invariants -
4289  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
4290  s=matrix(syz(ideal(s)));
4291  p=s[2,1];                            // the polynomial telling us where to
4292                                       // search for secondary invariants
4293  map slead=br,ideal(0);
4294  p=1/slead(p)*p;                      // smallest term of p needs to be 1
4295  if (v)
4296  { "  Polynomial telling us where to look for secondary invariants:";
4297    "   "+string(p);
4298    "";
4299  }
4300  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
4301                                       // secondary invariants, we need to find
4302                                       // of a certain degree -
4303  m=nrows(dimmat);                     // m-1 is the highest degree
4304  if (v)
4305  { "  In degree 0 we have: 1";
4306    "";
4307  }
4308 //-------------------------- initializing variables --------------------------
4309  intmat PP;
4310  poly pp;
4311  int k;
4312  intvec deg_vec;
4313  ideal sP=groebner(ideal(P));
4314  ideal TEST,B,IS;
4315  ideal S=1;                           // 1 is the first secondary invariant -
4316 //--------------------- generating secondary invariants ----------------------
4317  for (i=2;i<=m;i++)                   // going through dimmat -
4318  { if (int(dimmat[i,1])<>0)           // when it is == 0 we need to find 0
4319    {                                  // elements in the current degree (i-1)
4320      if (v)
4321      { "  Searching in degree "+string(i-1)+", we need to find "+string(int(dimmat[i,1]))+" invariant(s)...";
4322      }
4323      TEST=sP;
4324      counter=0;                       // we'll count up to degvec[i]
4325      if (IS[1]<>0)
4326      { PP=power_products(deg_vec,i-1); // finding power products of irreducible
4327      }                                // secondary invariants
4328      if (size(ideal(PP))<>0)
4329      { for (j=1;j<=ncols(PP);j++)     // going through all the power products
4330        { pp=1;
4331          for (k=1;k<=nrows(PP);k++)
4332          { pp=pp*IS[1,k]^PP[k,j];
4333          }
4334          if (reduce(pp,TEST)<>0)
4335          { S=S,pp;
4336            counter++;
4337            if (v)
4338            { "  We find: "+string(pp);
4339            }
4340            if (int(dimmat[i,1])<>counter)
4341            { // TEST=std(TEST+ideal(NF(pp,TEST))); // should be replaced by next
4342                                                 // line soon
4343              TEST=std(TEST,pp);
4344            }
4345            else
4346            { break;
4347            }
4348          }
4349        }
4350      }
4351      if (int(dimmat[i,1])<>counter)
4352      { B=sort_of_invariant_basis(sP,REY,i-1,int(dimmat[i,1])*6); // B contains
4353                                       // images of kbase(sP,i-1) under the
4354                                       // Reynolds operator that are linearly
4355                                       // independent and that don't reduce to
4356                                       // 0 modulo sP -
4357        if (counter==0 && ncols(B)==int(dimmat[i,1])) // then we can take all of
4358        { S=S,B;                       // B
4359          IS=IS+B;
4360          if (deg_vec[1]==0)
4361          { deg_vec=i-1;
4362            if (v)
4363            { "  We find: "+string(B[1]);
4364            }
4365            for (j=2;j<=int(dimmat[i,1]);j++)
4366            { deg_vec=deg_vec,i-1;
4367              if (v)
4368              { "  We find: "+string(B[j]);
4369              }
4370            }
4371          }
4372          else
4373          { for (j=1;j<=int(dimmat[i,1]);j++)
4374            { deg_vec=deg_vec,i-1;
4375              if (v)
4376              { "  We find: "+string(B[j]);
4377              }
4378            }
4379          }
4380        }
4381        else
4382        { j=0;                         // j goes through all of B -
4383          while (int(dimmat[i,1])<>counter) // need to find dimmat[i,1]
4384          {                            // invariants that are linearly
4385                                       // independent modulo TEST
4386            j++;
4387            if (reduce(B[j],TEST)<>0)  // B[j] should be added
4388            { S=S,B[j];
4389              IS=IS+ideal(B[j]);
4390              if (deg_vec[1]==0)
4391              { deg_vec[1]=i-1;
4392              }
4393              else
4394              { deg_vec=deg_vec,i-1;
4395              }
4396              counter++;
4397              if (v)
4398              { "  We find: "+string(B[j]);
4399              }
4400              if (int(dimmat[i,1])<>counter)
4401              { //TEST=std(TEST+ideal(NF(B[j],TEST))); // should be replaced by
4402                                                     // next line
4403                TEST=std(TEST,B[j]);
4404              }
4405            }
4406          }
4407        }
4408      }
4409      if (v)
4410      { "";
4411      }
4412    }
4413  }
4414  if (v)
4415  { "  We're done!";
4416    "";
4417  }
4418  return(matrix(S),matrix(IS));
4419}
4420
4421///////////////////////////////////////////////////////////////////////////////
4422
4423
4424proc secondary_char0 (matrix P, matrix REY, matrix M, list #)
4425"
4426USAGE:    secondary_char0(P,REY,M[,v][,\"AH\"]);
4427@*          P: a 1xn <matrix> with homogeneous primary invariants, where
4428               n is the number of variables of the basering;
4429@*          REY: a gxn <matrix> representing the Reynolds operator, where
4430               g the size of the corresponding group;
4431@*          M: a 1x2 <matrix> giving numerator and denominator of the Molien
4432               series;
4433@*          v: an optional <int>;
4434@*          \"AH\": if this string occurs as (optional) parameter, then an
4435               old version of secondary_char0 is used (for downward
4436               compatibility)
4437ASSUME:   REY is the 1st return value of group_reynolds(), reynolds_molien() or
4438          the second one of primary_invariants();
4439@*        M is the return value of molien()
4440          or the second one of reynolds_molien() or the third one of
4441          primary_invariants()
4442RETURN:   Homogeneous secondary invariants and irreducible secondary
4443          invariants of the invariant ring (both type <matrix>)
4444DISPLAY:  Information on the progress of the computations if v is an integer
4445          different from 0.
4446THEORY:   The secondary invariants are calculated by finding a basis (in terms
4447          of monomials) of the basering modulo the primary invariants, mapping
4448          those to invariants with the Reynolds operator. Among these images
4449          or their power products we pick a maximal subset that is linearly
4450          independent modulo the primary invariants (see paper \"Some
4451          Algorithms in Invariant Theory of Finite Groups\" by Kemper and
4452          Steel (1997)). The size of this set can be read off from the
4453          Molien series.
4454NOTE:     Secondary invariants are not uniquely determined by the given data.
4455          Specifically, the output of secondary_char0(P,REY,M,"AH") will
4456          differ from the output of secondary_char0(P,REY,M). However, the
4457          ideal generated by the irreducible homogeneous
4458          secondary invariants will be the same in both cases.
4459@*        There is an internal parameter \"pieces\" that, by default, equals 15.
4460          Setting \"pieces\" to a smaller value might decrease the memory consumption,
4461          but increase the running time.
4462SEE ALSO: irred_secondary_char0;
4463EXAMPLE:  example secondary_char0; shows an example
4464"
4465{ def br=basering;
4466
4467 //----------------- checking input and setting verbose mode ------------------
4468  if (char(br)<>0)
4469  { "ERROR:   secondary_char0 should only be used with rings of characteristic 0.";
4470    return();
4471  }
4472  int i;
4473  if (size(#)>0)
4474  { if (typeof(#[1])=="int")
4475    { int v=#[1];
4476    }
4477    else
4478    { int v=0;
4479    }
4480  }
4481  else
4482  { int v=0;
4483  }
4484  if (size(#)>0)
4485  { if (typeof(#[size(#)])=="string")
4486    { if (#[size(#)]=="AH")
4487      { if (typeof(#[1])=="int")
4488        { matrix S,IS = old_secondary_char0(P,REY,M,#[1]);
4489          return(S,IS);
4490        }
4491        else
4492        { matrix S,IS = old_secondary_char0(P,REY,M);
4493          return(S,IS);
4494        }
4495      }
4496      else
4497      { "ERROR:   If the last optional parameter is a string, it should be \"AH\".";
4498        return(matrix(ideal()),matrix(ideal()));
4499      }
4500    }
4501  }
4502  int n=nvars(br);                // n is the number of variables, as well
4503                                  // as the size of the matrices, as well
4504                                  // as the number of primary invariants,
4505                                  // we should get
4506  if (ncols(P)<>n)
4507  { "ERROR:   The first parameter ought to be the matrix of the primary";
4508    "         invariants.";
4509    return();
4510  }
4511  if (ncols(REY)<>n)
4512  { "ERROR:   The second parameter ought to be the Reynolds operator.";
4513    return();
4514  }
4515  if (ncols(M)<>2 or nrows(M)<>1)
4516  { "ERROR:   The third parameter ought to be the Molien series.";
4517    return();
4518  }
4519  if (v && voice==2)
4520  { "";
4521  }
4522  int j, m, counter, irrcounter;
4523 //- finding the polynomial giving number and degrees of secondary invariants -
4524  poly p=1;
4525  for (j=1;j<=n;j++)                   // calculating the denominator of the
4526  { p=p*(1-var(1)^deg(P[j]));          // Hilbert series of the ring generated
4527  }                                    // by the primary invariants -
4528  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
4529  s=matrix(syz(ideal(s)));
4530  p=s[2,1];                            // the polynomial telling us where to
4531                                       // search for secondary invariants
4532  map slead=br,ideal(0);
4533  p=1/slead(p)*p;                      // smallest [constant] term of
4534                                       // p needs to be 1
4535  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
4536                                       // secondary invariants, we need to find
4537                                       // of a certain degree -
4538  m=nrows(dimmat);                     // m-1 is the highest degree
4539  if (v)
4540  { "We need to find";
4541    for (j=1;j<=m;j++)
4542     { if (int(dimmat[j,1])<>1)
4543       { int(dimmat[j,1]), "secondary invariants in degree",j-1;
4544       }
4545       else
4546       { "1 secondary invariant in degree",j-1;
4547       }
4548     }
4549  }
4550  if (v)
4551  { "  In degree 0 we have: 1";
4552    "";
4553  }
4554 //-------------------------- initializing variables --------------------------
4555  ideal ProdCand;          // contains products of secondary invariants,
4556                           // i.e., candidates for reducible sec. inv.
4557  ideal Mul1,Mul2;
4558
4559  int dgb=degBound;
4560  degBound = 0;
4561  option(redSB);
4562  ideal sP = groebner(ideal(P));
4563  ideal Reductor,SaveRed;  // sP union Reductor is a Groebner basis up to degree i-1
4564  int SizeSave;
4565
4566  list SSort;         // sec. inv. first sorted by degree and then sorted by the
4567                      // minimal degree of a non-constant invariant factor.
4568  list ISSort;        // irr. sec. inv. sorted by degree
4569
4570  poly helpP;
4571  ideal helpI;
4572  ideal Indicator;        // will tell us which candidates for sec. inv. we can choose
4573  ideal ReducedCandidates;
4574  int helpint;
4575  int k,k2,k3,minD;
4576  int ii;
4577  int saveAttr;
4578  ideal B,IS;              // IS will contain all irr. sec. inv.
4579
4580  int pieces = 15;   // If this parameter is small, the memory consumption will decrease.
4581                     // In some cases, a careful choice will speed up computations
4582
4583  for (i=1;i<m;i++)
4584  { SSort[i] = list();
4585    for (k=1;k<=i;k++)
4586    { SSort[i][k]=ideal();
4587      attrib(SSort[i][k],"size",0);
4588    }
4589   }
4590//--------------------- generating secondary invariants ----------------------
4591  for (i=2;i<=m;i++)                   // going through dimmat -
4592  { if (int(dimmat[i,1])<>0)           // when it is == 0 we need to find no
4593    {                                  // elements in the current degree (i-1)
4594      if (v)
4595      { "  Searching in degree "+string(i-1)+", we need to find "+string(int(dimmat[i,1]))+
4596        " invariant(s)...";
4597        "  Looking for Power Products...";
4598      }
4599      counter = 0;                       // we'll count up to dimmat[i,1]
4600      Reductor = ideal(0);
4601      helpint = 0;
4602      SaveRed = Reductor;
4603      SizeSave = 0;
4604      attrib(Reductor,"isSB",1);
4605      attrib(SaveRed,"isSB",1);
4606
4607// We start searching for reducible secondary invariants in degree i-1, i.e., those
4608// that are power products of irreducible secondary invariants.
4609// It suffices to restrict the search at products of one _irreducible_ sec. inv. (Mul1)
4610// with some sec. inv. (Mul2).
4611// Moreover, we avoid to consider power products twice since we take a product
4612// into account only if the minimal degree of a non-constant invariant factor in "Mul2" is not
4613// smaller than the degree of "Mul1".
4614      for (k=1;k<i-1;k++)
4615      { if (int(dimmat[i,1])==counter)
4616        { break;
4617        }
4618        if (typeof(ISSort[k])<>"none")
4619        { Mul1 = ISSort[k];
4620        }
4621        else
4622        { Mul1 = ideal(0);
4623        }
4624        if ((int(dimmat[i-k,1])>0) && (Mul1[1]<>0))
4625        { for (minD=k;minD<i-k;minD++)
4626          { if (int(dimmat[i,1])==counter)
4627            { break;
4628            }
4629            for (k2=1;k2 <= ((attrib(SSort[i-k-1][minD],"size")-1) div pieces)+1; k2++)
4630            { if (int(dimmat[i,1])==counter)
4631              { break;
4632              }
4633              Mul2=ideal(0);
4634              if (attrib(SSort[i-k-1][minD],"size")>=k2*pieces)
4635              { for (k3=1;k3<=pieces;k3++)
4636                { Mul2[k3] = SSort[i-k-1][minD][((k2-1)*pieces)+k3];
4637                }
4638              }
4639              else
4640              { for (k3=1;k3<=(attrib(SSort[i-k-1][minD],"size") mod pieces);k3++)
4641                { Mul2[k3] = SSort[i-k-1][minD][((k2-1)*pieces)+k3];
4642                }
4643              }
4644              ProdCand = Mul1*Mul2;
4645              ReducedCandidates = reduce(ProdCand,sP);
4646                  // sP union SaveRed union Reductor is a homogeneous Groebner basis
4647                  // up to degree i-1.
4648                  // We first reduce by sP (which is fixed, so we can do it once for all),
4649                  // then by SaveRed resp. by Reductor (which is modified during
4650                  // the computations).
4651              Indicator = reduce(ReducedCandidates,SaveRed);
4652                             // If Indicator[ii]==0 then ReducedCandidates it the reduction
4653                             // of an invariant that is in the algebra generated by primary
4654                             // invariants and previously computed secondary invariants.
4655                             // Otherwise ProdCand[ii] can be taken as secondary invariant.
4656          if (size(Indicator)<>0)
4657              { for (ii=1;ii<=ncols(ProdCand);ii++)     // going through all the power products
4658                { helpP = reduce(Indicator[ii],Reductor);
4659                  if (helpP <> 0)
4660                  { counter++;
4661                    saveAttr = attrib(SSort[i-1][k],"size")+1;
4662                    SSort[i-1][k][saveAttr] = ProdCand[ii];
4663                        // By construction, this is a _reducible_ s.i.
4664                    attrib(SSort[i-1][k],"size",saveAttr);
4665                    if (v)
4666                    { "We found",counter, " of", int(dimmat[i,1])," secondaries in degree",i-1;
4667                    }
4668                    if (int(dimmat[i,1])<>counter)
4669                    { helpint++;
4670                      Reductor[helpint] = helpP;
4671                        // Lemma: If G is a homogeneous Groebner basis up to degree i-1 and p is a
4672                        // homogeneous polynomial of degree i-1 then G union NF(p,G) is
4673                        // a homogeneous Groebner basis up to degree i-1.
4674                      attrib(Reductor, "isSB",1);
4675                        // if Reductor becomes too large, we reduce the whole of Indicator by
4676                        // it, save it in SaveRed, and work with a smaller Reductor. This turns
4677                        // out to save a little time.
4678                      if (ncols(Reductor)>100)
4679                      { Indicator=reduce(Indicator,Reductor);
4680                        for (k3=1;k3<=ncols(Reductor);k3++)
4681                        { SaveRed[SizeSave+k3] = Reductor[k3];
4682                        }
4683                        SizeSave=SizeSave+size(Reductor);
4684                        Reductor = ideal(0);
4685                        helpint = 0;
4686                        attrib(SaveRed, "isSB",1);
4687                        attrib(Reductor, "isSB",1);
4688                      }
4689                    }
4690                    else
4691                    { break;
4692                    }
4693                  }
4694                }
4695              }
4696              for (k3=1;k3<=size(Reductor);k3++)
4697              { SaveRed[SizeSave+k3] = Reductor[k3];
4698              }
4699              SizeSave=SizeSave+size(Reductor);
4700              Reductor = ideal(0);
4701              helpint = 0;
4702              attrib(SaveRed, "isSB",1);
4703              attrib(Reductor, "isSB",1);
4704            }
4705          }
4706        }
4707      }
4708
4709      // The remaining sec. inv. are irreducible!
4710      if (int(dimmat[i,1])<>counter)   // need more than all the power products
4711      { if (v)
4712        { "There are irreducible secondary invariants in degree ", i-1," !!";
4713        }
4714        B=sort_of_invariant_basis(sP,REY,i-1,int(dimmat[i,1])*6);
4715                                       // B contains
4716                                       // images of kbase(sP,i-1) under the
4717                                       // Reynolds operator that are linearly
4718                                       // independent and that don't reduce to
4719                                       // 0 modulo sP -
4720        if (counter==0 && ncols(B)==int(dimmat[i,1])) // then we can take all of B
4721        { IS=IS+B;
4722          saveAttr = attrib(SSort[i-1][i-1],"size")+int(dimmat[i,1]);
4723          SSort[i-1][i-1] = SSort[i-1][i-1] + B;
4724          attrib(SSort[i-1][i-1],"size", saveAttr);
4725          if (typeof(ISSort[i-1]) <> "none")
4726          { ISSort[i-1] = ISSort[i-1] + B;
4727          }
4728          else
4729          { ISSort[i-1] = B;
4730          }
4731          if (v) {"  We found: "; print(B);}
4732        }
4733        else
4734        { irrcounter=0;
4735          j=0;                         // j goes through all of B -
4736        // Compare the comments on the computation of reducible sec. inv.!
4737          ReducedCandidates = reduce(B,sP);
4738          Indicator = reduce(ReducedCandidates,SaveRed);
4739          while (int(dimmat[i,1])<>counter)
4740          { j++;
4741            helpP = reduce(Indicator[j],Reductor);
4742            if (helpP <>0)                  // B[j] should be added
4743            { counter++; irrcounter++;
4744              IS=IS,B[j];
4745              saveAttr = attrib(SSort[i-1][i-1],"size")+1;
4746              SSort[i-1][i-1][saveAttr] = B[j];
4747              attrib(SSort[i-1][i-1],"size",saveAttr);
4748              if (typeof(ISSort[i-1]) <> "none")
4749              { ISSort[i-1][irrcounter] = B[j];
4750              }
4751              else
4752              { ISSort[i-1] = ideal(B[j]);
4753              }
4754              if (v)
4755              { "  We found the irreducible sec. inv. "+string(B[j]);
4756              }
4757              helpint++;
4758              Reductor[helpint] = helpP;
4759              attrib(Reductor, "isSB",1);
4760              if (ncols(Reductor)>100)
4761              { Indicator=reduce(Indicator,Reductor);
4762                for (k3=1;k3<=ncols(Reductor);k3++)
4763                { SaveRed[SizeSave+k3] = Reductor[k3];
4764                }
4765                SizeSave=SizeSave+size(Reductor);
4766                Reductor = ideal(0);
4767                helpint = 0;
4768                attrib(SaveRed, "isSB",1);
4769                attrib(Reductor, "isSB",1);
4770              }
4771            }
4772          }
4773        }
4774      }
4775      if (v)
4776      { "";
4777      }
4778    }
4779  }
4780  if (v)
4781  { "  We're done!";
4782    "";
4783  }
4784  degBound = dgb;
4785
4786// Prepare return:
4787  int TotalNumber;
4788  for (k=1;k<=m;k++)
4789  { TotalNumber = TotalNumber + int(dimmat[k,1]);
4790  }
4791  matrix S[1][TotalNumber];
4792  S[1,1]=1;
4793  j=1;
4794  for (k=1;k<m;k++)
4795  { for (k2=1;k2<=k;k2++)
4796    { if (typeof(attrib(SSort[k][k2],"size"))=="int")
4797     {for (i=1;i<=attrib(SSort[k][k2],"size");i++)
4798      { j++;
4799        S[1,j] = SSort[k][k2][i];
4800      }
4801      SSort[k][k2]=ideal();
4802     }
4803    }
4804  }
4805  return(S,matrix(compress(IS)));
4806}
4807
4808
4809example
4810{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4811         ring R=0,(x,y,z),dp;
4812         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4813         list L=primary_invariants(A);
4814         matrix S,IS=secondary_char0(L[1..3],1);
4815         print(S);
4816         print(IS);
4817}
4818//example
4819//{ "EXAMPLE: S. King"; echo=2;
4820//ring r= 0, (V1,V2,V3,V4,V5,V6),dp;
4821//matrix A1[6][6] = 0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0;
4822//matrix A2[6][6] = 0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0;
4823//list L = primary_invariants(A1,A2); // sorry, this takes a while...
4824//matrix S, IS = secondary_char0(L[1],L[2],L[3],1);
4825//S;
4826//IS;
4827//}
4828///////////////////////////////////////////////////////////////////////////////
4829
4830
4831proc irred_secondary_char0 (matrix P, matrix REY, matrix M, list #)
4832"
4833USAGE:    irred_secondary_char0(P,REY,M[,v]);
4834@*          P: a 1xn <matrix> with homogeneous primary invariants, where
4835               n is the number of variables of the basering;
4836@*          REY: a gxn <matrix> representing the Reynolds operator, where
4837               g the size of the corresponding group;
4838@*          M: a 1x2 <matrix> giving numerator and denominator of the
4839               Molien series;
4840@*          v: an optional <int>;
4841RETURN:   Irreducible homogeneous secondary invariants of the invariant ring
4842          (type <matrix>)
4843ASSUME:   REY is the 1st return value of group_reynolds(), reynolds_molien() or
4844          the second one of primary_invariants();
4845          M is the return value of molien() or the second one of
4846          reynolds_molien() or the third one of primary_invariants()
4847DISPLAY:  Information on the progress of computations if v does not equal 0
4848THEORY:   The secondary invariants are calculated by finding a basis (in terms
4849          of monomials) of the basering modulo the primary invariants, mapping
4850          those to invariants with the Reynolds operator. Among these images
4851          or their power products we pick a maximal subset that is linearly
4852          independent modulo the primary invariants (see paper \"Some
4853          Algorithms in Invariant Theory of Finite Groups\" by Kemper and
4854          Steel (1997)). The size of this set can be read off from the
4855          Molien series. Here, only irreducible secondary
4856          invariants are explicitly computed, which saves time and memory.
4857NOTE:     There is an internal parameter \"pieces\" that, by default, equals 15.
4858          Setting \"pieces\" to a smaller value might decrease the memory consumption,
4859          but increase the running time.
4860SEE ALSO: secondary_char0
4861KEYWORDS: irreducible secondary invariant
4862EXAMPLE:  example irred_secondary_char0; shows an example
4863"
4864{ def br=basering;
4865
4866 //----------------- checking input and setting verbose mode ------------------
4867  if (char(br)<>0)
4868  { "ERROR:   irred_secondary_char0 should only be used with rings of characteristic 0.";
4869    return();
4870  }
4871  int i;
4872  if (size(#)>0)
4873  { if (typeof(#[size(#)])=="int")
4874    { int v=#[size(#)];
4875    }
4876    else
4877    { int v=0;
4878    }
4879  }
4880  else
4881  { int v=0;
4882  }
4883  int n=nvars(br);                // n is the number of variables, as well
4884                                  // as the size of the matrices, as well
4885                                  // as the number of primary invariants,
4886                                  // we should get
4887  if (ncols(P)<>n)
4888  { "ERROR:   The first parameter ought to be the matrix of the primary";
4889    "         invariants."
4890    return();
4891  }
4892  if (ncols(REY)<>n)
4893  { "ERROR:   The second parameter ought to be the Reynolds operator."
4894    return();
4895  }
4896  if (ncols(M)<>2 or nrows(M)<>1)
4897  { "ERROR:   The third parameter ought to be the Molien series."
4898    return();
4899  }
4900  if (v && voice==2)
4901  { "";
4902  }
4903  int j, m, counter, irrcounter;
4904 //- finding the polynomial giving number and degrees of secondary invariants -
4905  poly p=1;
4906  for (j=1;j<=n;j++)                   // calculating the denominator of the
4907  { p=p*(1-var(1)^deg(P[j]));          // Hilbert series of the ring generated
4908  }                                    // by the primary invariants -
4909  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
4910  s=matrix(syz(ideal(s)));
4911  p=s[2,1];                            // the polynomial telling us where to
4912                                       // search for secondary invariants
4913  map slead=br,ideal(0);
4914  p=1/slead(p)*p;                      // smallest [constant] term of
4915                                       // p needs to be 1
4916  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
4917                                       // secondary invariants, we need to find
4918                                       // of a certain degree -
4919  m=nrows(dimmat);                     // m-1 is the highest degree
4920  if (v)
4921  { "We need to find";
4922    for (j=1;j<=m;j++)
4923     { if (int(dimmat[j,1])<>1)
4924       { int(dimmat[j,1]), "secondary invariants in degree",j-1;
4925       }
4926       else
4927       { "1 secondary invariant in degree",j-1;
4928       }
4929     }
4930  }
4931  if (v)
4932  { "  In degree 0 we have: 1";
4933    "";
4934  }
4935 //-------------------------- initializing variables --------------------------
4936  ideal ProdCand;          // contains products of secondary invariants,
4937                           // i.e., candidates for reducible sec. inv.
4938
4939  ideal Mul1,Mul2;
4940
4941  int dgb=degBound;
4942  degBound = 0;
4943  option(redSB);
4944  ideal sP = groebner(ideal(P));
4945  ideal Reductor,SaveRed;  // sP union Reductor is a Groebner basis up to degree i-1
4946  int SizeSave;
4947
4948  list RedSSort;           // sec. Inv. reduced by sP, sorted first by degree and then
4949                           // by the minimal degree of a non-constant invariant factor
4950  list RedISSort;          // irr. sec. Inv. reduced by sP, sorted by degree
4951
4952  poly helpP;
4953  ideal helpI;
4954  ideal Indicator;        // will tell us which candidates for sec. inv. we can choose
4955  ideal ReducedCandidates;
4956  int helpint;
4957  int k,k2,k3,minD;
4958  int ii;
4959  int saveAttr;
4960  ideal B,IS;              // IS will contain all irr. sec. inv.
4961
4962  int pieces = 15;   // If this parameter is small, the memory consumption will decrease.
4963                     // In some cases, a careful choice will speed up computations
4964
4965  for (i=1;i<m;i++)
4966  { RedSSort[i] = list();
4967    for (k=1;k<=i;k++)
4968    { RedSSort[i][k]=ideal();
4969      attrib(RedSSort[i][k],"size",0);
4970    }
4971   }
4972//--------------------- generating secondary invariants ----------------------
4973  for (i=2;i<=m;i++)                   // going through dimmat -
4974  { if (int(dimmat[i,1])<>0)           // when it is == 0 we need to find no
4975    {                                  // elements in the current degree (i-1)
4976      if (v)
4977      { "  Searching in degree "+string(i-1)+", we need to find "+
4978        string(int(dimmat[i,1]))+" invariant(s)...";
4979        "  Looking for Power Products...";
4980      }
4981      counter = 0;                       // we'll count up to dimmat[i,1]
4982      Reductor = ideal(0);
4983      helpint = 0;
4984      SaveRed = Reductor;
4985      SizeSave = 0;
4986      attrib(Reductor,"isSB",1);
4987      attrib(SaveRed,"isSB",1);
4988
4989// We start searching for reducible secondary invariants in degree i-1, i.e., those
4990// that are power products of irreducible secondary invariants.
4991// It suffices to restrict the search at products of one _irreducible_ sec. inv. (Mul1)
4992// with some sec. inv. (Mul2).
4993// Moreover, we avoid to consider power products twice since we take a product
4994// into account only if the minimal degree of a non-constant invariant factor in "Mul2" is not
4995// smaller than the degree of "Mul1".
4996// Finally, as we are not interested in the reducible sec. inv., we will only
4997// work with their reduction modulo sP --- this allows to detect a secondary invariant
4998// without to actually compute it!
4999      for (k=1;k<i-1;k++)
5000      { if (int(dimmat[i,1])==counter)
5001        { break;
5002        }
5003        if (typeof(RedISSort[k])<>"none")
5004        { Mul1 = RedISSort[k];
5005        }
5006        else
5007        { Mul1 = ideal(0);
5008        }
5009        if ((int(dimmat[i-k,1])>0) && (Mul1[1]<>0))
5010        { for (minD=k;minD<i-k;minD++)
5011          { if (int(dimmat[i,1])==counter)
5012            { break;
5013            }
5014            for (k2=1;k2 <= ((attrib(RedSSort[i-k-1][minD],"size")-1) div pieces)+1; k2++)
5015            { if (int(dimmat[i,1])==counter)
5016              { break;
5017              }
5018              Mul2=ideal(0);
5019              if (attrib(RedSSort[i-k-1][minD],"size")>=k2*pieces)
5020              { for (k3=1;k3<=pieces;k3++)
5021                { Mul2[k3] = RedSSort[i-k-1][minD][((k2-1)*pieces)+k3];
5022                }
5023              }
5024              else
5025              { for (k3=1;k3<=(attrib(RedSSort[i-k-1][minD],"size") mod pieces);k3++)
5026                { Mul2[k3] = RedSSort[i-k-1][minD][((k2-1)*pieces)+k3];
5027                }
5028              }
5029              ProdCand = Mul1*Mul2;
5030              ReducedCandidates = reduce(ProdCand,sP);
5031                  // sP union SaveRed union Reductor is a homogeneous Groebner basis
5032                  // up to degree i-1.
5033                  // We first reduce by sP (which is fixed, so we can do it once for all),
5034                  // then by SaveRed resp. by Reductor (which is modified during
5035                  // the computations).
5036              Indicator = reduce(ReducedCandidates,SaveRed);
5037                             // If Indicator[ii]==0 then ReducedCandidates it the reduction
5038                             // of an invariant that is in the algebra generated by primary
5039                             // invariants and previously computed secondary invariants.
5040                             // Otherwise ReducedCandidates[ii] is the reduction of an invariant
5041                             // that we can take as secondary invariant.
5042              if (size(Indicator)<>0)
5043              { for (ii=1;ii<=ncols(ProdCand);ii++)     // going through all the power products
5044                { helpP = reduce(Indicator[ii],Reductor);
5045                  if (helpP <> 0)
5046                  { counter++;
5047                    saveAttr = attrib(RedSSort[i-1][k],"size")+1;
5048                    RedSSort[i-1][k][saveAttr] = ReducedCandidates[ii];
5049                        // By construction, this is the reduction of a reducible s.i.
5050                        // of degree i-1.
5051                    attrib(RedSSort[i-1][k],"size",saveAttr);
5052                    if (v)
5053                    { "We found",counter, " of", int(dimmat[i,1])," secondaries in degree",i-1;
5054                    }
5055                    if (int(dimmat[i,1])<>counter)
5056                    { helpint++;
5057                      Reductor[helpint] = helpP;
5058                        // Lemma: If G is a homogeneous Groebner basis up to degree i-1 and p is a
5059                        // homogeneous polynomial of degree i-1 then G union NF(p,G) is
5060                        // a homogeneous Groebner basis up to degree i-1.
5061                      attrib(Reductor, "isSB",1);
5062                        // if Reductor becomes too large, we reduce the whole of Indicator by
5063                        // it, save it in SaveRed, and work with a smaller Reductor. This turns
5064                        // out to save a little time.
5065                      if (ncols(Reductor)>100)
5066                      { Indicator=reduce(Indicator,Reductor);
5067                        for (k3=1;k3<=ncols(Reductor);k3++)
5068                        { SaveRed[SizeSave+k3] = Reductor[k3];
5069                        }
5070                        SizeSave=SizeSave+size(Reductor);
5071                        Reductor = ideal(0);
5072                        helpint = 0;
5073                        attrib(SaveRed, "isSB",1);
5074                        attrib(Reductor, "isSB",1);
5075                      }
5076                    }
5077                    else
5078                    { break;
5079                    }
5080                  }
5081                }
5082              }
5083              for (k3=1;k3<=size(Reductor);k3++)
5084              { SaveRed[SizeSave+k3] = Reductor[k3];
5085              }
5086              SizeSave=SizeSave+size(Reductor);
5087              Reductor = ideal(0);
5088              helpint = 0;
5089              attrib(SaveRed, "isSB",1);
5090              attrib(Reductor, "isSB",1);
5091            }
5092          }
5093        }
5094      }
5095
5096      // The remaining sec. inv. are irreducible!
5097      if (int(dimmat[i,1])<>counter)   // need more than all the power products
5098      { if (v)
5099        { "There are irreducible secondary invariants in degree ", i-1," !!";
5100        }
5101        B=sort_of_invariant_basis(sP,REY,i-1,int(dimmat[i,1])*6);
5102                                       // B is a set of
5103                                       // images of kbase(sP,i-1) under the
5104                                       // Reynolds operator that are linearly
5105                                       // independent and that do not reduce to
5106                                       // 0 modulo sP -
5107        if (counter==0 && ncols(B)==int(dimmat[i,1])) // then we can take all of B
5108        { IS=IS+B;
5109          saveAttr = attrib(RedSSort[i-1][i-1],"size")+int(dimmat[i,1]);
5110          RedSSort[i-1][i-1] = RedSSort[i-1][i-1] + B;
5111          attrib(RedSSort[i-1][i-1],"size", saveAttr);
5112          if (typeof(RedISSort[i-1]) <> "none")
5113          { RedISSort[i-1] = RedISSort[i-1] + B;
5114          }
5115          else
5116          { RedISSort[i-1] = B;
5117          }
5118          if (v) {"  We found: ";print(B);}
5119        }
5120        else
5121        { irrcounter=0;
5122          j=0;                         // j goes through all of B -
5123        // Compare the comments on the computation of reducible sec. inv.!
5124          ReducedCandidates = reduce(B,sP);
5125          Indicator = reduce(ReducedCandidates,SaveRed);
5126          while (int(dimmat[i,1])<>counter)    // need to find dimmat[i,1]
5127          {                                    // invariants that are linearly independent
5128            j++;
5129            helpP = reduce(Indicator[j],Reductor);
5130            if (helpP <>0)                     // B[j] should be added
5131            { counter++; irrcounter++;
5132              IS=IS,B[j];
5133              saveAttr = attrib(RedSSort[i-1][i-1],"size")+1;
5134              RedSSort[i-1][i-1][saveAttr] = ReducedCandidates[j];
5135              attrib(RedSSort[i-1][i-1],"size",saveAttr);
5136              if (typeof(RedISSort[i-1]) <> "none")
5137              { RedISSort[i-1][irrcounter] = ReducedCandidates[j];
5138              }
5139              else
5140              { RedISSort[i-1] = ideal(ReducedCandidates[j]);
5141              }
5142              if (v)
5143              { "  We found the irreducible sec. inv. "+string(B[j]);
5144              }
5145              helpint++;
5146              Reductor[helpint] = helpP;
5147              attrib(Reductor, "isSB",1);
5148              if (ncols(Reductor)>100)
5149              { Indicator=reduce(Indicator,Reductor);
5150                for (k3=1;k3<=ncols(Reductor);k3++)
5151                { SaveRed[SizeSave+k3] = Reductor[k3];
5152                }
5153                SizeSave=SizeSave+size(Reductor);
5154                Reductor = ideal(0);
5155                helpint = 0;
5156                attrib(SaveRed, "isSB",1);
5157                attrib(Reductor, "isSB",1);
5158              }
5159            }
5160          }
5161        }
5162      }
5163      if (v)
5164      { "";
5165      }
5166    }
5167  }
5168  if (v)
5169  { "  We're done!";
5170    "";
5171  }
5172  degBound = dgb;
5173
5174  return(matrix(compress(IS)));
5175}
5176
5177
5178//example
5179//{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5180//         ring R=0,(x,y,z),dp;
5181//         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5182//         list L=primary_invariants(A);
5183//         matrix IS=irred_secondary_char0(L[1..3],1);
5184//         print(IS);
5185//}
5186example
5187{ "EXAMPLE: S. King"; echo=2;
5188ring r= 0, (a,b,c,d,e,f),dp;
5189matrix A1[6][6] = 0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0;
5190matrix A2[6][6] = 0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0;
5191list L = primary_invariants(A1,A2); // sorry, this takes a while...
5192matrix IS = irred_secondary_char0(L[1],L[2],L[3],0);
5193IS;
5194}
5195
5196
5197///////////////////////////////////////////////////////////////////////////////
5198
5199
5200proc secondary_charp (matrix P, matrix REY, string ring_name, list #)
5201"USAGE:   secondary_charp(P,REY,ringname[,v]);
5202         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
5203         representing the Reynolds operator, ringname: a <string> giving the
5204         name of a ring of characteristic 0 where the Molien series is stored,
5205         v: an optional <int>
5206ASSUME:  n is the number of variables of the basering, g the size of the group,
5207         REY is the 1st return value of group_reynolds(), reynolds_molien() or
5208         the second one of primary_invariants(), `ringname` is a ring of
5209         char 0 that has been created by molien() or reynolds_molien() or
5210         primary_invariants()
5211RETURN:  secondary invariants of the invariant ring (type <matrix>) and
5212         irreducible secondary invariants (type <matrix>)
5213DISPLAY: information if v does not equal 0
5214THEORY:  Secondary invariants are calculated by finding a basis (in terms of
5215         monomials) of the basering modulo primary invariants, mapping those
5216         to invariants with the Reynolds operator and using these images or
5217         their power products such that they are linearly independent modulo
5218         the primary invariants (see paper \"Some Algorithms in Invariant
5219         Theory of Finite Groups\" by Kemper and Steel (1997)).
5220EXAMPLE: example secondary_charp; shows an example
5221"
5222{ def br=basering;
5223  degBound=0;
5224 //---------------- checking input and setting verbose mode -------------------
5225  if (char(br)==0)
5226  { "ERROR:   secondary_charp should only be used with rings of characteristic p>0.";
5227    return();
5228  }
5229  int i;
5230  if (size(#)>0)
5231  { if (typeof(#[size(#)])=="int")
5232    { int v=#[size(#)];
5233    }
5234    else
5235    { int v=0;
5236    }
5237  }
5238  else
5239  { int v=0;
5240  }
5241  int n=nvars(br);                     // n is the number of variables, as well
5242                                       // as the size of the matrices, as well
5243                                       // as the number of primary invariants,
5244                                       // we should get
5245  if (ncols(P)<>n)
5246  { "ERROR:   The first parameter ought to be the matrix of the primary";
5247    "         invariants."
5248    return();
5249  }
5250  if (ncols(REY)<>n)
5251  { "ERROR:   The second parameter ought to be the Reynolds operator."
5252    return();
5253  }
5254  if (typeof(`ring_name`)<>"ring")
5255  { "ERROR:   The <string> should give the name of the ring where the Molien."
5256    "         series is stored.";
5257    return();
5258  }
5259  if (v && voice==2)
5260  { "";
5261  }
5262  int j, m, counter, d;
5263  intvec deg_dim_vec;
5264 //- finding the polynomial giving number and degrees of secondary invariants -
5265  for (j=1;j<=n;j++)
5266  { deg_dim_vec[j]=deg(P[j]);
5267  }
5268  setring `ring_name`;
5269  poly p=1;
5270  for (j=1;j<=n;j++)                   // calculating the denominator of the
5271  { p=p*(1-var(1)^deg_dim_vec[j]);     // Hilbert series of the ring generated
5272  }                                    // by the primary invariants -
5273  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
5274  s=matrix(syz(ideal(s)));
5275  p=s[2,1];                            // the polynomial telling us where to
5276                                       // search for secondary invariants
5277  map slead=basering,ideal(0);
5278  p=1/slead(p)*p;                      // smallest term of p needs to be 1
5279  if (v)
5280  { "  Polynomial telling us where to look for secondary invariants:";
5281    "   "+string(p);
5282    "";
5283  }
5284  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
5285                                       // secondary invariants, we need to find
5286                                       // of a certain degree -
5287  m=nrows(dimmat);                     // m-1 is the highest degree
5288  deg_dim_vec=1;
5289  for (j=2;j<=m;j++)
5290  { deg_dim_vec=deg_dim_vec,int(dimmat[j,1]);
5291  }
5292  if (v)
5293  { "  In degree 0 we have: 1";
5294    "";
5295  }
5296 //------------------------ initializing variables ----------------------------
5297  setring br;
5298  intmat PP;
5299  poly pp;
5300  int k;
5301  intvec deg_vec;
5302  ideal sP=groebner(ideal(P));
5303  ideal TEST,B,IS;
5304  ideal S=1;                           // 1 is the first secondary invariant
5305 //------------------- generating secondary invariants ------------------------
5306  for (i=2;i<=m;i++)                   // going through deg_dim_vec -
5307  { if (deg_dim_vec[i]<>0)             // when it is == 0 we need to find 0
5308    {                                  // elements in the current degree (i-1)
5309      if (v)
5310      { "  Searching in degree "+string(i-1)+", we need to find "+string(deg_dim_vec[i])+" invariant(s)...";
5311      }
5312      TEST=sP;
5313      counter=0;                       // we'll count up to degvec[i]
5314      if (IS[1]<>0)
5315      { PP=power_products(deg_vec,i-1); // generating power products of
5316      }                                // irreducible secondary invariants
5317      if (size(ideal(PP))<>0)
5318      { for (j=1;j<=ncols(PP);j++)     // going through all of those
5319        { pp=1;
5320          for (k=1;k<=nrows(PP);k++)
5321          { pp=pp*IS[1,k]^PP[k,j];
5322          }
5323          if (reduce(pp,TEST)<>0)
5324          { S=S,pp;
5325            counter++;
5326            if (v)
5327            { "  We find: "+string(pp);
5328            }
5329            if (deg_dim_vec[i]<>counter)
5330            { //TEST=std(TEST+ideal(NF(pp,TEST))); // should be soon replaced by
5331                                                 // next line
5332              TEST=std(TEST,pp);
5333            }
5334            else
5335            { break;
5336            }
5337          }
5338        }
5339      }
5340      if (deg_dim_vec[i]<>counter)
5341      { B=sort_of_invariant_basis(sP,REY,i-1,deg_dim_vec[i]*6); // B contains
5342                                       // images of kbase(sP,i-1) under the
5343                                       // Reynolds operator that are linearly
5344                                       // independent and that don't reduce to
5345                                       // 0 modulo sP -
5346        if (counter==0 && ncols(B)==deg_dim_vec[i]) // then we can add all of B
5347        { S=S,B;
5348          IS=IS+B;
5349          if (deg_vec[1]==0)
5350          { deg_vec=i-1;
5351            if (v)
5352            { "  We find: "+string(B[1]);
5353            }
5354            for (j=2;j<=deg_dim_vec[i];j++)
5355            { deg_vec=deg_vec,i-1;
5356              if (v)
5357              { "  We find: "+string(B[j]);
5358              }
5359            }
5360          }
5361          else
5362          { for (j=1;j<=deg_dim_vec[i];j++)
5363            { deg_vec=deg_vec,i-1;
5364              if (v)
5365              { "  We find: "+string(B[j]);
5366              }
5367            }
5368          }
5369        }
5370        else
5371        { j=0;                         // j goes through all of B -
5372          while (deg_dim_vec[i]<>counter) // need to find deg_dim_vec[i]
5373          {                            // invariants that are linearly
5374                                       // independent modulo TEST
5375            j++;
5376            if (reduce(B[j],TEST)<>0)   // B[j] should be added
5377            { S=S,B[j];
5378              IS=IS+ideal(B[j]);
5379              if (deg_vec[1]==0)
5380              { deg_vec[1]=i-1;
5381              }
5382              else
5383              { deg_vec=deg_vec,i-1;
5384              }
5385              counter++;
5386              if (v)
5387              { "  We find: "+string(B[j]);
5388              }
5389              if (deg_dim_vec[i]<>counter)
5390              { //TEST=std(TEST+ideal(NF(B[j],TEST))); // should be soon replaced
5391                                                     // by next line
5392                TEST=std(TEST,B[j]);
5393              }
5394            }
5395          }
5396        }
5397      }
5398      if (v)
5399      { "";
5400      }
5401    }
5402  }
5403  if (v)
5404  { "  We're done!";
5405    "";
5406  }
5407  if (ring_name=="aksldfalkdsflkj")
5408  { kill `ring_name`;
5409  }
5410  return(matrix(S),matrix(IS));
5411}
5412example
5413{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
5414         ring R=3,(x,y,z),dp;
5415         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5416         list L=primary_invariants(A);
5417         matrix S,IS=secondary_charp(L[1..size(L)]);
5418         print(S);
5419         print(IS);
5420}
5421///////////////////////////////////////////////////////////////////////////////
5422
5423proc secondary_no_molien (matrix P, matrix REY, list #)
5424"USAGE:   secondary_no_molien(P,REY[,deg_vec,v]);
5425         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
5426         representing the Reynolds operator, deg_vec: an optional <intvec>
5427         listing some degrees where no non-trivial homogeneous invariants can
5428         be found, v: an optional <int>
5429ASSUME:  n is the number of variables of the basering, g the size of the group,
5430         REY is the 1st return value of group_reynolds(), reynolds_molien() or
5431         the second one of primary_invariants(), deg_vec is the second return
5432         value of primary_char0_no_molien(), primary_charp_no_molien(),
5433         primary_char0_no_molien_random() or primary_charp_no_molien_random()
5434RETURN:  secondary invariants of the invariant ring (type <matrix>)
5435DISPLAY: information if v does not equal 0
5436THEORY:  Secondary invariants are calculated by finding a basis (in terms of
5437         monomials) of the basering modulo primary invariants, mapping those to
5438         invariants with the Reynolds operator and using these images as
5439         candidates for secondary invariants.
5440EXAMPLE: example secondary_no_molien; shows an example
5441"
5442{ int i;
5443  degBound=0;
5444 //------------------ checking input and setting verbose ----------------------
5445  if (size(#)==1 or size(#)==2)
5446  { if (typeof(#[size(#)])=="int")
5447    { if (size(#)==2)
5448      { if (typeof(#[size(#)-1])=="intvec")
5449        { intvec deg_vec=#[size(#)-1];
5450        }
5451        else
5452        { "ERROR:   the third parameter should be an <intvec>";
5453          return();
5454        }
5455      }
5456      int v=#[size(#)];
5457    }
5458    else
5459    { if (size(#)==1)
5460      { if (typeof(#[size(#)])=="intvec")
5461        { intvec deg_vec=#[size(#)];
5462          int v=0;
5463        }
5464        else
5465        { "ERROR:   the third parameter should be an <intvec>";
5466          return();
5467        }
5468      }
5469      else
5470      { "ERROR:   wrong list of parameters";
5471        return();
5472      }
5473    }
5474  }
5475  else
5476  { if (size(#)>2)
5477    { "ERROR:   there are too many parameters";
5478      return();
5479    }
5480    int v=0;
5481  }
5482  int n=nvars(basering);               // n is the number of variables, as well
5483                                       // as the size of the matrices, as well
5484                                       // as the number of primary invariants,
5485                                       // we should get
5486  if (ncols(P)<>n)
5487  { "ERROR:   The first parameter ought to be the matrix of the primary";
5488    "         invariants."
5489    return();
5490  }
5491  if (ncols(REY)<>n)
5492  { "ERROR:   The second parameter ought to be the Reynolds operator."
5493    return();
5494  }
5495  if (v && voice==2)
5496  { "";
5497  }
5498  int j, m, d;
5499  int max=1;
5500  for (j=1;j<=n;j++)
5501  { max=max*deg(P[j]);
5502  }
5503  max=max/nrows(REY);
5504  if (v)
5505  { "  We need to find "+string(max)+" secondary invariants.";
5506    "";
5507    "  In degree 0 we have: 1";
5508    "";
5509  }
5510 //------------------------- initializing variables ---------------------------
5511  ideal sP=groebner(ideal(P));
5512  ideal B, TEST;
5513  ideal S=1;                           // 1 is the first secondary invariant
5514  int counter=1;
5515  i=0;
5516  if (defined(deg_vec)<>voice)
5517  { intvec deg_vec;
5518  }
5519  int k=1;
5520 //--------------------- generating secondary invariants ----------------------
5521  while (counter<>max)
5522  { i++;
5523    if (deg_vec[k]<>i)
5524    { if (v)
5525      { "  Searching in degree "+string(i)+"...";
5526      }
5527      B=sort_of_invariant_basis(sP,REY,i,max); // B contains images of
5528                                       // kbase(sP,i) under the Reynolds
5529                                       // operator that are linearly independent
5530                                       // and that don't reduce to 0 modulo sP
5531      TEST=sP;
5532      for (j=1;j<=ncols(B);j++)
5533      {                                // that are linearly independent modulo
5534                                       // TEST
5535        if (reduce(B[j],TEST)<>0)      // B[j] should be added
5536        { S=S,B[j];
5537          counter++;
5538          if (v)
5539          { "  We find: "+string(B[j]);
5540          }
5541          if (counter==max)
5542          { break;
5543          }
5544          else
5545          { if (j<>ncols(B))
5546            { //TEST=std(TEST+ideal(NF(B[j],TEST))); // should soon be replaced by
5547                                                   // next line
5548              TEST=std(TEST,B[j]);
5549            }
5550          }
5551        }
5552      }
5553    }
5554    else
5555    { if (size(deg_vec)==k)
5556      { k=1; }
5557      else
5558      { k++; }
5559    }
5560  }
5561  if (v)
5562  { ""; }
5563  if (v)
5564  { "  We're done!"; ""; }
5565  return(matrix(S));
5566}
5567example
5568{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5569         ring R=0,(x,y,z),dp;
5570         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5571         list L=primary_invariants(A,intvec(1,1,0));
5572         matrix S=secondary_no_molien(L[1..3]);
5573         print(S);
5574}
5575///////////////////////////////////////////////////////////////////////////////
5576
5577proc secondary_and_irreducibles_no_molien (matrix P, matrix REY, list #)
5578"USAGE:   secondary_and_irreducibles_no_molien(P,REY[,v]);
5579         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
5580         representing the Reynolds operator, v: an optional <int>
5581ASSUME:  n is the number of variables of the basering, g the size of the group,
5582         REY is the 1st return value of group_reynolds(), reynolds_molien() or
5583         the second one of primary_invariants()
5584RETURN:  secondary invariants of the invariant ring (type <matrix>) and
5585         irreducible secondary invariants (type <matrix>)
5586DISPLAY: information if v does not equal 0
5587THEORY:  Secondary invariants are calculated by finding a basis (in terms of
5588         monomials) of the basering modulo primary invariants, mapping those to
5589         invariants with the Reynolds operator and using these images or their
5590         power products such that they are linearly independent modulo the
5591         primary invariants (see paper \"Some Algorithms in Invariant Theory of
5592         Finite Groups\" by Kemper and Steel (1997)).
5593EXAMPLE: example secondary_and_irreducibles_no_molien; shows an example
5594"
5595{ int i;
5596  degBound=0;
5597 //--------------------- checking input and setting verbose mode --------------
5598  if (size(#)==1 or size(#)==2)
5599  { if (typeof(#[size(#)])=="int")
5600    { if (size(#)==2)
5601      { if (typeof(#[size(#)-1])=="intvec")
5602        { intvec deg_vec=#[size(#)-1];
5603        }
5604        else
5605        { "ERROR:   the third parameter should be an <intvec>";
5606          return();
5607        }
5608      }
5609      int v=#[size(#)];
5610    }
5611    else
5612    { if (size(#)==1)
5613      { if (typeof(#[size(#)])=="intvec")
5614        { intvec deg_vec=#[size(#)];
5615          int v=0;
5616        }
5617        else
5618        { "ERROR:   the third parameter should be an <intvec>";
5619          return();
5620        }
5621      }
5622      else
5623      { "ERROR:   wrong list of parameters";
5624        return();
5625      }
5626    }
5627  }
5628  else
5629  { if (size(#)>2)
5630    { "ERROR:   there are too many parameters";
5631      return();
5632    }
5633    int v=0;
5634  }
5635  int n=nvars(basering);               // n is the number of variables, as well
5636                                       // as the size of the matrices, as well
5637                                       // as the number of primary invariants,
5638                                       // we should get
5639  if (ncols(P)<>n)
5640  { "ERROR:   The first parameter ought to be the matrix of the primary";
5641    "         invariants."
5642    return();
5643  }
5644  if (ncols(REY)<>n)
5645  { "ERROR:   The second parameter ought to be the Reynolds operator."
5646    return();
5647  }
5648  if (v && voice==2)
5649  { "";
5650  }
5651  int j, m, d;
5652  int max=1;
5653  for (j=1;j<=n;j++)
5654  { max=max*deg(P[j]);
5655  }
5656  max=max/nrows(REY);
5657  if (v)
5658  { "  We need to find "+string(max)+" secondary invariants.";
5659    "";
5660    "  In degree 0 we have: 1";
5661    "";
5662  }
5663 //------------------------ initializing variables ----------------------------
5664  intmat PP;
5665  poly pp;
5666  int k;
5667  intvec irreducible_deg_vec;
5668  ideal sP=groebner(ideal(P));
5669  ideal B,TEST,IS;
5670  ideal S=1;                           // 1 is the first secondary invariant
5671  int counter=1;
5672  i=0;
5673  if (defined(deg_vec)<>voice)
5674  { intvec deg_vec;
5675  }
5676  int l=1;
5677 //------------------- generating secondary invariants ------------------------
5678  while (counter<>max)
5679  { i++;
5680    if (deg_vec[l]<>i)
5681    { if (v)
5682      { "  Searching in degree "+string(i)+"...";
5683      }
5684      TEST=sP;
5685      if (IS[1]<>0)
5686      { PP=power_products(irreducible_deg_vec,i);  // generating all power
5687      }                                // products of irreducible secondary
5688                                       // invariants
5689      if (size(ideal(PP))<>0)
5690      { for (j=1;j<=ncols(PP);j++)     // going through all those power products
5691        { pp=1;
5692          for (k=1;k<=nrows(PP);k++)
5693          { pp=pp*IS[1,k]^PP[k,j];
5694          }
5695          if (reduce(pp,TEST)<>0)
5696          { S=S,pp;
5697            counter++;
5698            if (v)
5699            { "  We find: "+string(pp);
5700            }
5701            if (counter<>max)
5702            { //TEST=std(TEST+ideal(NF(pp,TEST))); // should soon be replaced by
5703                                                 // next line
5704              TEST=std(TEST,pp);
5705            }
5706            else
5707            { break;
5708            }
5709          }
5710        }
5711      }
5712      if (max<>counter)
5713      { B=sort_of_invariant_basis(sP,REY,i,max); // B contains images of
5714                                       // kbase(sP,i) under the Reynolds
5715                                       // operator that are linearly independent
5716                                       // and that don't reduce to 0 modulo sP
5717        for (j=1;j<=ncols(B);j++)
5718        { if (reduce(B[j],TEST)<>0)    // B[j] should be added
5719          { S=S,B[j];
5720            IS=IS+ideal(B[j]);
5721            if (irreducible_deg_vec[1]==0)
5722            { irreducible_deg_vec[1]=i;
5723            }
5724            else
5725            { irreducible_deg_vec=irreducible_deg_vec,i;
5726            }
5727            counter++;
5728            if (v)
5729            { "  We find: "+string(B[j]);
5730            }
5731            if (counter==max)
5732            { break;
5733            }
5734            else
5735            { if (j<>ncols(B))
5736              { //TEST=std(TEST+ideal(NF(B[j],TEST))); // should soon be replaced
5737                                                     // by next line
5738                 TEST=std(TEST,B[j]);
5739              }
5740            }
5741          }
5742        }
5743      }
5744    }
5745    else
5746    { if (size(deg_vec)==l)
5747      { l=1;
5748      }
5749      else
5750      { l++;
5751      }
5752    }
5753  }
5754  if (v)
5755  { "";
5756  }
5757  if (v)
5758  { "  We're done!";
5759    "";
5760  }
5761  return(matrix(S),matrix(IS));
5762}
5763example
5764{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5765         ring R=0,(x,y,z),dp;
5766         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5767         list L=primary_invariants(A,intvec(1,1,0));
5768         matrix S,IS=secondary_and_irreducibles_no_molien(L[1..2]);
5769         print(S);
5770         print(IS);
5771}
5772///////////////////////////////////////////////////////////////////////////////
5773
5774proc secondary_not_cohen_macaulay (matrix P, list #)
5775"USAGE:   secondary_not_cohen_macaulay(P,G1,G2,...[,v]);
5776         P: a 1xn <matrix> with primary invariants, G1,G2,...: nxn <matrices>
5777         generating a finite matrix group, v: an optional <int>
5778ASSUME:  n is the number of variables of the basering
5779RETURN:  secondary invariants of the invariant ring (type <matrix>)
5780DISPLAY: information if v does not equal 0
5781THEORY:  Secondary invariants are generated following \"Generating Invariant
5782         Rings of Finite Groups over Arbitrary Fields\" by Kemper (1996).
5783EXAMPLE: example secondary_not_cohen_macaulay; shows an example
5784"
5785{ int i, j;
5786  degBound=0;
5787  def br=basering;
5788  int n=nvars(br);                     // n is the number of variables, as well
5789                                       // as the size of the matrices, as well
5790                                       // as the number of primary invariants,
5791                                       // we should get -
5792  if (size(#)>0)                       // checking input and setting verbose
5793  { if (typeof(#[size(#)])=="int")
5794    { int gen_num=size(#)-1;
5795      if (gen_num==0)
5796      { "ERROR:   There are no generators of the finite matrix group given.";
5797        return();
5798      }
5799      int v=#[size(#)];
5800      for (i=1;i<=gen_num;i++)
5801      { if (typeof(#[i])<>"matrix")
5802        { "ERROR:   These parameters should be generators of the finite matrix group.";
5803          return();
5804        }
5805        if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
5806        { "ERROR:   matrices need to be square and of the same dimensions";
5807          return();
5808        }
5809      }
5810    }
5811    else
5812    { int v=0;
5813      int gen_num=size(#);
5814      for (i=1;i<=gen_num;i++)
5815      { if (typeof(#[i])<>"matrix")
5816        { "ERROR:   These parameters should be generators of the finite matrix group.";
5817          return();
5818        }
5819        if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
5820        { "ERROR:   matrices need to be square and of the same dimensions";
5821          return();
5822        }
5823      }
5824    }
5825  }
5826  else
5827  { "ERROR:   There are no generators of the finite matrix group given.";
5828    return();
5829  }
5830  if (ncols(P)<>n)
5831  { "ERROR:   The first parameter ought to be the matrix of the primary";
5832    "         invariants."
5833    return();
5834  }
5835  if (v && voice==2)
5836  { "";
5837  }
5838  ring alskdfalkdsj=0,x,dp;
5839  matrix M[1][2]=1,(1-x)^n;            // we look at our primary invariants as
5840  export alskdfalkdsj;
5841  export M;
5842  setring br;                          // such of the subgroup that only
5843  matrix REY=matrix(maxideal(1));      // contains the identity, this means that
5844                                       // ch does not divide the order anymore,
5845                                       // this means that we can make use of the
5846                                       // Molien series again - M[1,1]/M[1,2] is
5847                                       // the Molien series of that group, we
5848                                       // now calculate the secondary invariants
5849                                       // of this subgroup in the usual fashion
5850                                       // where the primary invariants are the
5851                                       // ones from the bigger group
5852  if (v)
5853  { "  The procedure secondary_charp() is called to calculate secondary invariants";
5854    "  of the invariant ring of the trivial group with respect to the primary";
5855    "  invariants found previously.";
5856    "";
5857  }
5858  matrix trivialS, trivialSI=secondary_charp(P,REY,"alskdfalkdsj",v);
5859  kill trivialSI;
5860  kill alskdfalkdsj;
5861  // now we have those secondary invariants
5862  int k=ncols(trivialS);               // k is the number of the secondary
5863                                       // invariants, we just calculated
5864  if (v)
5865  { "  We calculate secondary invariants from the ones found for the trivial";
5866    "  subgroup.";
5867    "";
5868  }
5869  map f;                               // used to let generators act on
5870                                       // secondary invariants with respect to
5871                                       // the trivial group -
5872  matrix M(1)[gen_num][k];             // M(1) will contain a module
5873  ideal B;
5874  for (i=1;i<=gen_num;i++)
5875  { B=ideal(matrix(maxideal(1))*transpose(#[i])); // image of the various
5876                                       // variables under the i-th generator -
5877    f=br,B;                            // the corresponding mapping -
5878    B=f(trivialS)-trivialS;            // these relations should be 0 -
5879    M(1)[i,1..k]=B[1..k];              // we will look for the syzygies of M(1)
5880  }
5881  //intvec save_opts=option(get);
5882  //option(returnSB,redSB);
5883  //module M(2)=syz(M(1));               // nres(M(1),2)[2];
5884  //option(set,save_opts);
5885  module M(2)=nres(M(1),2)[2];
5886  int m=ncols(M(2));                   // number of generators of the module
5887                                       // M(2) -
5888  // the following steps calculates the intersection of the module M(2) with
5889  // the algebra A^k where A denote the subalgebra of the usual polynomial
5890  // ring, generated by the primary invariants
5891  string mp=string(minpoly);           // generating a ring where we can do
5892                                       // elimination
5893  execute("ring R=("+charstr(br)+"),(x(1..n),y(1..n),h),dp;");
5894  execute("minpoly=number("+mp+");");
5895  map f=br,maxideal(1);                // canonical mapping
5896  matrix M[k][m+k*n];
5897  M[1..k,1..m]=matrix(f(M(2)));        // will contain a module -
5898  matrix P=f(P);                       // primary invariants in the new ring
5899  for (i=1;i<=n;i++)
5900  { for (j=1;j<=k;j++)
5901    { M[j,m+(i-1)*k+j]=y(i)-P[1,i];
5902    }
5903  }
5904  M=elim(module(M),1,n);               // eliminating x(1..n), std-calculation
5905                                       // is done internally -
5906  M=homog(module(M),h);                // homogenize for 'minbase'
5907  M=minbase(module(M));
5908  setring br;
5909  ideal substitute=maxideal(1),ideal(P),1;
5910  f=R,substitute;                      // replacing y(1..n) by primary
5911                                       // invariants -
5912  M(2)=f(M);                           // M(2) is the new module
5913  m=ncols(M(2));
5914  matrix S[1][m];
5915  S=matrix(trivialS)*matrix(M(2));     // S now contains the secondary
5916                                       // invariants
5917  for (i=1; i<=m;i++)
5918  { S[1,i]=S[1,i]/leadcoef(S[1,i]);    // making elements nice
5919  }
5920  S=sort(ideal(S))[1];
5921  if (v)
5922  { "  These are the secondary invariants: ";
5923    for (i=1;i<=m;i++)
5924    { "   "+string(S[1,i]);
5925    }
5926    "";
5927    "  We're done!";
5928    "";
5929  }
5930  if ((v or (voice==2)) && (m>1))
5931  { "  WARNING: The invariant ring might not have a Hironaka decomposition";
5932    "           if the characteristic of the coefficient field divides the";
5933    "           group order.";
5934  }
5935  return(S);
5936}
5937example
5938{ "EXAMPLE:"; echo=2;
5939           ring R=2,(x,y,z),dp;
5940           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5941           list L=primary_invariants(A);
5942           matrix S=secondary_not_cohen_macaulay(L[1],A);
5943           print(S);
5944}
5945///////////////////////////////////////////////////////////////////////////////
5946
5947proc invariant_ring (list #)
5948"USAGE:   invariant_ring(G1,G2,...[,flags]);
5949         G1,G2,...: <matrices> generating a finite matrix group, flags: an
5950         optional <intvec> with three entries: if the first one equals 0, the
5951         program attempts to compute the Molien series and Reynolds operator,
5952         if it equals 1, the program is told that the Molien series should not
5953         be computed, if it equals -1 characteristic 0 is simulated, i.e. the
5954         Molien series is computed as if the base field were characteristic 0
5955         (the user must choose a field of large prime characteristic, e.g.
5956         32003) and if the first one is anything else, it means that the
5957         characteristic of the base field divides the group order (i.e. it will
5958         not even be attempted to compute the Reynolds operator or Molien
5959         series), the second component should give the size of intervals
5960         between canceling common factors in the expansion of Molien series, 0
5961         (the default) means only once after generating all terms, in prime
5962         characteristic also a negative number can be given to indicate that
5963         common factors should always be canceled when the expansion is simple
5964         (the root of the extension field occurs not among the coefficients)
5965RETURN:  primary and secondary invariants (both of type <matrix>) generating
5966         the invariant ring with respect to the matrix group generated by the
5967         matrices in the input and irreducible secondary invariants (type
5968         <matrix>) if the Molien series was available
5969DISPLAY: information about the various stages of the program if the third flag
5970         does not equal 0
5971THEORY:  Bases of homogeneous invariants are generated successively and those
5972         are chosen as primary invariants that lower the dimension of the ideal
5973         generated by the previously found invariants (see \"Generating a
5974         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
5975         Decker, Heydtmann, Schreyer (1998)). In the
5976         non-modular case secondary invariants are calculated by finding a
5977         basis (in terms of monomials) of the basering modulo the primary
5978         invariants, mapping to invariants with the Reynolds operator and using
5979         those or their power products such that they are linearly independent
5980         modulo the primary invariants (see \"Some Algorithms in Invariant
5981         Theory of Finite Groups\" by Kemper and Steel (1997)). In the modular
5982         case they are generated according to \"Generating Invariant Rings of
5983         Finite Groups over Arbitrary Fields\" by Kemper (1996).
5984EXAMPLE: example invariant_ring; shows an example
5985"
5986{ if (size(#)==0)
5987  { "ERROR:   There are no generators given.";
5988    return();
5989  }
5990  int ch=char(basering);               // the algorithms depend very much on the
5991                                       // characteristic of the ground field -
5992  int n=nvars(basering);               // n is the number of variables, as well
5993                                       // as the size of the matrices, as well
5994                                       // as the number of primary invariants,
5995                                       // we should get
5996  int gen_num;
5997  int mol_flag, v;
5998 //------------------- checking input and setting flags -----------------------
5999  if (typeof(#[size(#)])=="intvec")
6000  { if (size(#[size(#)])<>3)
6001    { "ERROR:   The <intvec> should have three entries.";
6002      return();
6003    }
6004    gen_num=size(#)-1;
6005    mol_flag=#[size(#)][1];
6006    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
6007    { "ERROR:   the second component of <intvec> should be >=0";
6008      return();
6009    }
6010    int interval=#[size(#)][2];
6011    v=#[size(#)][3];
6012  }
6013  else
6014  { gen_num=size(#);
6015    mol_flag=0;
6016    int interval=0;
6017    v=0;
6018  }
6019 //----------------------------------------------------------------------------
6020  if (mol_flag==0)                     // calculation Molien series will be
6021  { if (ch==0)                         // attempted -
6022    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v)); // one
6023                                       // will contain Reynolds operator and the
6024                                       // other enumerator and denominator of
6025                                       // Molien series
6026      matrix P=primary_char0(REY,M,v);
6027      matrix S,IS=secondary_char0(P,REY,M,v);
6028      return(P,S,IS);
6029    }
6030    else
6031    { list L=group_reynolds(#[1..gen_num],v);
6032      if (L[1]<>0)                     // testing whether we are in the modular
6033      { string newring="aksldfalkdsflkj"; // case
6034        if (minpoly==0)
6035        { if (v)
6036          { "  We are dealing with the non-modular case.";
6037          }
6038          if (typeof(L[2])=="int")
6039          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
6040          }
6041          else
6042          { molien(L[2..size(L)],newring,intvec(0,interval,v));
6043          }
6044          matrix P=primary_charp(L[1],newring,v);
6045          matrix S,IS=secondary_charp(P,L[1],newring,v);
6046          if (defined(aksldfalkdsflkj)==2)
6047          { kill aksldfalkdsflkj;
6048          }
6049          return(P,S,IS);
6050        }
6051        else
6052        { if (v)
6053          { "  Since it is impossible for this programme to calculate the Molien
6054 series for";
6055            "  invariant rings over extension fields of prime characteristic, we
6056 have to";
6057            "  continue without it.";
6058            "";
6059
6060          }
6061          list l=primary_charp_no_molien(L[1],v);
6062          if (size(l)==2)
6063          { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6064          }
6065          else
6066          { matrix S=secondary_no_molien(l[1],L[1],v);
6067          }
6068          return(l[1],S);
6069        }
6070      }
6071      else                             // the modular case
6072      { if (v)
6073        { "  There is also no Molien series or Reynolds operator, we can make use of...";
6074          "";
6075          "  We can start looking for primary invariants...";
6076          "";
6077        }
6078        matrix P=primary_charp_without(#[1..gen_num],v);
6079        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6080        return(P,S);
6081      }
6082    }
6083  }
6084  if (mol_flag==1)                     // the user wants no calculation of the
6085  { list L=group_reynolds(#[1..gen_num],v); // Molien series
6086    if (ch==0)
6087    { list l=primary_char0_no_molien(L[1],v);
6088      if (size(l)==2)
6089      { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6090      }
6091      else
6092      { matrix S=secondary_no_molien(l[1],L[1],v);
6093      }
6094      return(l[1],S);
6095    }
6096    else
6097    { if (L[1]<>0)                     // testing whether we are in the modular
6098      { list l=primary_charp_no_molien(L[1],v); // case
6099        if (size(l)==2)
6100        { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6101        }
6102        else
6103        { matrix S=secondary_no_molien(l[1],L[1],v);
6104        }
6105        return(l[1],S);
6106      }
6107      else                             // the modular case
6108      { if (v)
6109        { "  We can start looking for primary invariants...";
6110          "";
6111        }
6112        matrix P=primary_charp_without(#[1..gen_num],v);
6113        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6114        return(L[1],S);
6115      }
6116    }
6117  }
6118  if (mol_flag==-1)
6119  { if (ch==0)
6120    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.
6121";
6122      return();
6123    }
6124    list L=group_reynolds(#[1..gen_num],v);
6125    string newring="aksldfalkdsflkj";
6126    if (typeof(L[2])=="int")
6127    { molien(L[3..size(L)],newring,L[2],intvec(1,interval,v));
6128    }
6129    else
6130    { molien(L[2..size(L)],newring,intvec(1,interval,v));
6131    }
6132    matrix P=primary_charp(L[1],newring,v);
6133    matrix S,IS=secondary_charp(P,L[1],newring,v);
6134    kill aksldfalkdsflkj;
6135    return(P,S,IS);
6136  }
6137  else                                 // the user specified that the
6138  { if (ch==0)                         // characteristic divides the group order
6139    { "ERROR:   The characteristic cannot divide the group order when it is 0.
6140";
6141      return();
6142    }
6143    if (v)
6144    { "";
6145    }
6146    matrix P=primary_charp_without(#[1..gen_num],v);
6147    matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6148    return(L[1],S);
6149  }
6150}
6151example
6152{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
6153         ring R=0,(x,y,z),dp;
6154         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
6155         matrix P,S,IS=invariant_ring(A);
6156         print(P);
6157         print(S);
6158         print(IS);
6159}
6160///////////////////////////////////////////////////////////////////////////////
6161
6162proc invariant_ring_random (list #)
6163"USAGE:   invariant_ring_random(G1,G2,...,r[,flags]);
6164         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
6165         where -|r| to |r| is the range of coefficients of random
6166         combinations of bases elements that serve as primary invariants,
6167         flags: an optional <intvec> with three entries: if the first equals 0,
6168         the program attempts to compute the Molien series and Reynolds
6169         operator, if it equals 1, the program is told that the Molien series
6170         should not be computed, if it equals -1 characteristic 0 is simulated,
6171         i.e. the Molien series is computed as if the base field were
6172         characteristic 0 (the user must choose a field of large prime
6173         characteristic, e.g.  32003) and if the first one is anything else,
6174         then the characteristic of the base field divides the group order
6175         (i.e. we will not even attempt to compute the Reynolds operator or
6176         Molien series), the second component should give the size of intervals
6177         between canceling common factors in the expansion of the Molien
6178         series, 0 (the default) means only once after generating all terms,
6179         in prime characteristic also a negative number can be given to
6180         indicate that common factors should always be canceled when the
6181         expansion is simple (the root of the extension field does not occur
6182         among the coefficients)
6183RETURN:  primary and secondary invariants (both of type <matrix>) generating
6184         invariant ring with respect to the matrix group generated by the
6185         matrices in the input and irreducible secondary invariants (type
6186         <matrix>) if the Molien series was available
6187DISPLAY: information about the various stages of the program if the third flag
6188         does not equal 0
6189THEORY:  is the same as for invariant_ring except that random combinations of
6190         basis elements are chosen as candidates for primary invariants and
6191         hopefully they lower the dimension of the previously found primary
6192         invariants by the right amount.
6193EXAMPLE: example invariant_ring_random; shows an example
6194"
6195{ if (size(#)<2)
6196  { "ERROR:   There are too few parameters.";
6197    return();
6198  }
6199  int ch=char(basering);               // the algorithms depend very much on the
6200                                       // characteristic of the ground field
6201  int n=nvars(basering);               // n is the number of variables, as well
6202                                       // as the size of the matrices, as well
6203                                       // as the number of primary invariants,
6204                                       // we should get
6205  int gen_num;
6206  int mol_flag, v;
6207 //------------------- checking input and setting flags -----------------------
6208  if (typeof(#[size(#)])=="intvec" && typeof(#[size(#)-1])=="int")
6209  { if (size(#[size(#)])<>3)
6210    { "ERROR:   <intvec> should have three entries.";
6211      return();
6212    }
6213    gen_num=size(#)-2;
6214    mol_flag=#[size(#)][1];
6215    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
6216    { "ERROR:   the second component of <intvec> should be >=0";
6217      return();
6218    }
6219    int interval=#[size(#)][2];
6220    v=#[size(#)][3];
6221    int max=#[size(#)-1];
6222    if (gen_num==0)
6223    { "ERROR:   There are no generators of a finite matrix group given.";
6224      return();
6225    }
6226  }
6227  else
6228  { if (typeof(#[size(#)])=="int")
6229    { gen_num=size(#)-1;
6230      mol_flag=0;
6231      int interval=0;
6232      v=0;
6233      int max=#[size(#)];
6234    }
6235   else
6236    { "ERROR:   If the two last parameters are not <int> and <intvec>, the last";
6237      "         parameter should be an <int>.";
6238      return();
6239    }
6240  }
6241  for (int i=1;i<=gen_num;i++)
6242  { if (typeof(#[i])=="matrix")
6243    { if (nrows(#[i])<>n or ncols(#[i])<>n)
6244      { "ERROR:   The number of variables of the base ring needs to be the same";
6245        "         as the dimension of the square matrices";
6246        return();
6247      }
6248    }
6249    else
6250    { "ERROR:   The first parameters should be a list of matrices";
6251      return();
6252    }
6253  }
6254 //----------------------------------------------------------------------------
6255  if (mol_flag==0)
6256  { if (ch==0)
6257    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v)); // one
6258                                       // will contain Reynolds operator and the
6259                                       // other enumerator and denominator of
6260                                       // Molien series
6261      matrix P=primary_char0_random(REY,M,max,v);
6262      matrix S,IS=secondary_char0(P,REY,M,v);
6263      return(P,S,IS);
6264    }
6265    else
6266    { list L=group_reynolds(#[1..gen_num],v);
6267      if (L[1]<>0)                     // testing whether we are in the modular
6268      { string newring="aksldfalkdsflkj"; // case
6269        if (minpoly==0)
6270        { if (v)
6271          { "  We are dealing with the non-modular case.";
6272          }
6273          if (typeof(L[2])=="int")
6274          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
6275          }
6276          else
6277          { molien(L[2..size(L)],newring,intvec(0,interval,v));
6278          }
6279          matrix P=primary_charp_random(L[1],newring,max,v);
6280          matrix S,IS=secondary_charp(P,L[1],newring,v);
6281          if (voice==2)
6282          { kill aksldfalkdsflkj;
6283          }
6284          return(P,S,IS);
6285        }
6286        else
6287        { if (v)
6288          { "  Since it is impossible for this programme to calculate the Molien
6289 series for";
6290            "  invariant rings over extension fields of prime characteristic, we
6291 have to";
6292            "  continue without it.";
6293            "";
6294
6295          }
6296          list l=primary_charp_no_molien_random(L[1],max,v);
6297          if (size(l)==2)
6298          { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6299          }
6300          else
6301          { matrix S=secondary_no_molien(l[1],L[1],v);
6302          }
6303          return(l[1],S);
6304        }
6305      }
6306      else                             // the modular case
6307      { if (v)
6308        { "  There is also no Molien series, we can make use of...";
6309          "";
6310          "  We can start looking for primary invariants...";
6311          "";
6312        }
6313        matrix P=primary_charp_without_random(#[1..gen_num],max,v);
6314        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6315        return(P,S);
6316      }
6317    }
6318  }
6319  if (mol_flag==1)                     // the user wants no calculation of the
6320  { list L=group_reynolds(#[1..gen_num],v); // Molien series
6321    if (ch==0)
6322    { list l=primary_char0_no_molien_random(L[1],max,v);
6323      if (size(l)==2)
6324      { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6325      }
6326      else
6327      { matrix S=secondary_no_molien(l[1],L[1],v);
6328      }
6329      return(l[1],S);
6330    }
6331    else
6332    { if (L[1]<>0)                     // testing whether we are in the modular
6333      { list l=primary_charp_no_molien_random(L[1],max,v); // case
6334        if (size(l)==2)
6335        { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
6336        }
6337        else
6338        { matrix S=secondary_no_molien(l[1],L[1],v);
6339        }
6340        return(l[1],S);
6341      }
6342      else                             // the modular case
6343      { if (v)
6344        { "  We can start looking for primary invariants...";
6345          "";
6346        }
6347        matrix P=primary_charp_without_random(#[1..gen_num],max,v);
6348        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6349        return(L[1],S);
6350      }
6351    }
6352  }
6353  if (mol_flag==-1)
6354  { if (ch==0)
6355    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.
6356";
6357      return();
6358    }
6359    list L=group_reynolds(#[1..gen_num],v);
6360    string newring="aksldfalkdsflkj";
6361    if (typeof(L[2])=="int")
6362    { molien(L[3..size(L)],newring,L[2],intvec(mol_flag,interval,v));
6363    }
6364    else
6365    { molien(L[2..size(L)],newring,intvec(mol_flag,interval,v));
6366    }
6367    matrix P=primary_charp_random(L[1],newring,max,v);
6368    matrix S,IS=secondary_charp(P,L[1],newring,v);
6369    kill aksldfalkdsflkj;
6370    return(P,S,IS);
6371  }
6372  else                                 // the user specified that the
6373  { if (ch==0)                         // characteristic divides the group order
6374    { "ERROR:   The characteristic cannot divide the group order when it is 0.
6375";
6376      return();
6377    }
6378    if (v)
6379    { "";
6380    }
6381    matrix P=primary_charp_without_random(#[1..gen_num],max,v);
6382    matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
6383    return(L[1],S);
6384  }
6385}
6386example
6387{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
6388         ring R=0,(x,y,z),dp;
6389         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
6390         matrix P,S,IS=invariant_ring_random(A,1);
6391         print(P);
6392         print(S);
6393         print(IS);
6394}
6395///////////////////////////////////////////////////////////////////////////////
6396
6397proc orbit_variety (matrix F,string newring)
6398"USAGE:   orbit_variety(F,s);
6399         F: a 1xm <matrix> defing an invariant ring, s: a <string> giving the
6400         name for a new ring
6401RETURN:  a Groebner basis (type <ideal>, named G) for the ideal defining the
6402         orbit variety (i.e. the syzygy ideal) in the new ring (named `s`)
6403THEORY:  The ideal of algebraic relations of the invariant ring generators is
6404         calculated, then the variables of the original ring are eliminated and
6405         the polynomials that are left over define the orbit variety
6406EXAMPLE: example orbit_variety; shows an example
6407"
6408{ if (newring=="")
6409  { "ERROR:   the second parameter may not be an empty <string>";
6410    return();
6411  }
6412  if (nrows(F)==1)
6413  { def br=basering;
6414    int n=nvars(br);
6415    int m=ncols(F);
6416    string mp=string(minpoly);
6417    execute("ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),dp;");
6418    execute("minpoly=number("+mp+");");
6419    ideal I=ideal(imap(br,F));
6420    for (int i=1;i<=m;i++)
6421    { I[i]=I[i]-y(i);
6422    }
6423    I=elim(I,1,n);
6424    execute("ring "+newring+"=("+charstr(br)+"),(y(1..m)),dp(m);");
6425    execute("minpoly=number("+mp+");");
6426    ideal vars;
6427    for (i=2;i<=n;i++)
6428    { vars[i]=0;
6429    }
6430    vars=vars,y(1..m);
6431    map emb=R,vars;
6432    ideal G=emb(I);
6433    kill emb, vars, R;
6434    keepring `newring`;
6435    return();
6436  }
6437  else
6438  { "ERROR:   the <matrix> may only have one row";
6439    return();
6440  }
6441}
6442example
6443{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
6444         ring R=0,(x,y,z),dp;
6445         matrix F[1][7]=x2+y2,z2,x4+y4,1,x2z-1y2z,xyz,x3y-1xy3;
6446         string newring="E";
6447         orbit_variety(F,newring);
6448         print(G);
6449         basering;
6450}
6451///////////////////////////////////////////////////////////////////////////////
6452
6453static proc degvec(ideal I)
6454"USAGE:  degvec(I);
6455         I an <ideal>.
6456RETURN:  the <intvec> of degrees of the generators of I.
6457"
6458{ intvec v;
6459  for (int j = 1;j<=ncols(I);j++)
6460  { v[j]=deg(I[j]);
6461  }
6462  return(v);
6463}
6464
6465///////////////////////////////////////////////////////////////////////////////
6466
6467proc rel_orbit_variety(ideal I,matrix F,list #)
6468"USAGE:    rel_orbit_variety(I,F[,s]);
6469@*          I: an <ideal> invariant under the action of a group,
6470@*          F: a 1xm <matrix> defining the invariant ring of this group.
6471@*          s: optional <string>; if s is present then (for downward
6472               compatibility) the old procedure <relative_orbit_variety>
6473               is called, and in this case s gives the name of a new <ring>.
6474RETURN:   Without optional s, a list L of two rings is returned.
6475@*        The ring L[1] carries a weighted degree order with variables
6476            y(1..m), the weight of y(k) equal to the degree of the
6477            k-th generators F[1,k] of the invariant ring.
6478            L[1] contains a Groebner basis (type <ideal>, named G) of the
6479            ideal defining the relative orbit variety with  respect to I.
6480@*        The ring L[2] has the variables of the basering together with y(1..m)
6481            and carries a block order: The first block is the order of the
6482            basering, the second is the weighted degree order occuring in L[1].
6483            L[2] contains G and a Groebner basis (type <ideal>, named Conv)
6484            such that if p is any invariant polynomial expressed in the
6485            variables of the basering then reduce(p,Conv) is a polynomial in
6486            the new variables y(1..m) such that evaluation at the generators
6487            of the invariant ring yields p. This can be used to avoid the
6488            application of <algebra_containment>
6489            (see @ref{algebra_containment}).
6490@*        For the case of optional s, see @ref{relative_orbit_variety}.
6491THEORY:   A Groebner basis of the ideal of algebraic relations of the invariant
6492          ring generators is calculated, then one of the basis elements plus
6493          the ideal generators. The variables of the original ring are
6494          eliminated and the polynomials that are left define the relative
6495          orbit variety with respect to I. The elimination is done by a
6496          weighted blockorder that has the advantage of dealing with
6497          quasi-homogeneous ideals.
6498NOTE:     We provide the ring L[1] for the sake of downward compatibility,
6499          since it is closer to the ring returned by relative_orbit_variety
6500          than L[2]. However, L[1] carries a weighted degree order, whereas
6501          the ring returned by relative_orbit_variety is lexicographically
6502          ordered.
6503SEE ALSO: relative_orbit_variety
6504EXAMPLE:  example rel_orbit_variety; shows an example.
6505"
6506{ if (size(#)>0)
6507  { if (typeof(#[1])=="string")
6508    { relative_orbit_variety(I,F,#[1]);
6509      keepring basering;
6510      return();
6511    }
6512    else
6513    { "ERROR:    the third parameter may either be empty or a <string>.";
6514      return();
6515    }
6516  }
6517  degBound=0;
6518  if (nrows(F)==1)
6519  { option(redSB,noredTail);
6520    def br=basering;
6521    int n=nvars(br);
6522    int m=ncols(F);
6523    // In the following ring definition, any elimination order would work.
6524    list rlist = ringlist(br);
6525    int i;
6526    for (i=1;i<=m;i++)
6527    { rlist[2][n+i]="y("+string(i)+")";
6528    }
6529    rlist[3][size(rlist[3])+1] = rlist[3][size(rlist[3])];
6530    rlist[3][size(rlist[3])-1][1] = "wp";
6531    rlist[3][size(rlist[3])-1][2] = degvec(ideal(F));
6532    def newring = ring(rlist);
6533
6534    list smallrlist;
6535    smallrlist[1]=rlist[1];
6536    smallrlist[2]=list();
6537    for (i=1;i<=m;i++)
6538    { smallrlist[2][i]="y("+string(i)+")";
6539    }
6540    smallrlist[3]=list();
6541    smallrlist[3][1]=list();
6542    smallrlist[3][1][1] = "wp";
6543    smallrlist[3][1][2] = degvec(ideal(F));
6544    smallrlist[3][2] = rlist[3][size(rlist[3])];
6545    smallrlist[4] = rlist[4];
6546    def smallring = ring(smallrlist);
6547
6548    setring(newring);
6549    ideal J=ideal(imap(br,F));
6550    ideal I=imap(br,I);
6551    for (i=1;i<=m;i++)
6552    { J[i]=J[i]-y(i);
6553    }
6554    // We chose the weighted block order since this makes J quasi-homogeneous!
6555    ideal Conv=groebner(J);
6556    J=Conv,I;
6557    J=groebner(J);
6558    ideal vars;
6559    vars[n]=0;
6560    vars=vars,y(1..m);
6561    map emb=newring,vars;
6562    ideal G=emb(J);
6563    J=J-G;
6564    for (i=1;i<=ncols(G);i++)
6565    { if (J[i]<>0)
6566      { G[i]=0;
6567      }
6568    }
6569    G=compress(G);
6570    vars=ideal();
6571    for (i=2;i<=n;i++)
6572    { vars[i]=0;
6573    }
6574    vars=vars,y(1..m);
6575    emb=newring,vars;
6576    G=compress(emb(G));
6577    export(G);
6578    export(Conv);
6579
6580    setring(smallring);
6581    ideal G = compress(imap(newring,G));
6582    export(G);
6583
6584    list L;
6585    L[1]=smallring;
6586    L[2]=newring;
6587
6588    dbprint( printlevel-voice+3,"
6589// 'rel_orbit_variety' created a list of two rings.
6590// If L is the name of that list, you can access
6591// the first ring by
6592//   def R = L[1]; setring R;
6593// (similarly for the second ring)");
6594    return(L);
6595  }
6596  else
6597  { "ERROR:   the <matrix> may only have one row";
6598    return();
6599  }
6600}
6601example
6602{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.3:"; echo=2;
6603         ring R=0,(x,y,z),dp;
6604         matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
6605         ideal I=x2+y2+z2-1,x2y+y2z+z2x-2x-2y-2z,xy2+yz2+zx2-2x-2y-2z;
6606         list L = rel_orbit_variety(I,F);
6607         def AllR = L[2];
6608         setring(AllR);
6609         print(G);
6610         print(Conv);
6611         basering;
6612}
6613///////////////////////////////////////////////////////////////////////////////
6614
6615proc relative_orbit_variety(ideal I,matrix F,string newring)
6616"
6617USAGE:   relative_orbit_variety(I,F,s);
6618         I: an <ideal> invariant under the action of a group,
6619@*       F: a 1xm  <matrix> defining the invariant ring of this group,
6620@*       s: a <string> giving a name for a new ring
6621RETURN:  The procedure ends with a new ring named s.
6622         It contains a Groebner basis
6623         (type <ideal>, named G) for the ideal defining the
6624         relative orbit variety with respect to I in the new ring.
6625THEORY:  A Groebner basis of the ideal of algebraic relations of the invariant
6626         ring generators is calculated, then one of the basis elements plus the
6627         ideal generators. The variables of the original ring are eliminated
6628         and the polynomials that are left define the relative orbit variety
6629         with respect to I.
6630NOTE:    This procedure is now replaced by rel_orbit_variety
6631         (see @ref{rel_orbit_variety}), which uses a different elemination
6632         order that should usually allow faster computations.
6633SEE ALSO: rel_orbit_variety
6634EXAMPLE: example relative_orbit_variety; shows an example
6635"
6636{ if (newring=="")
6637  { "ERROR:   the third parameter may not be empty a <string>";
6638    return();
6639  }
6640  degBound=0;
6641  if (nrows(F)==1)
6642  { def br=basering;
6643    int n=nvars(br);
6644    int m=ncols(F);
6645    string mp=string(minpoly);
6646    execute("ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),lp;");
6647    execute("minpoly=number("+mp+");");
6648    ideal J=ideal(imap(br,F));
6649    ideal I=imap(br,I);
6650    for (int i=1;i<=m;i++)
6651    { J[i]=J[i]-y(i);
6652    }
6653    J=std(J);
6654    J=J,I;
6655    option(redSB);
6656    J=std(J);
6657    ideal vars;
6658    //for (i=1;i<=n;i=i+1)
6659    //{ vars[i]=0;
6660    //}
6661    vars[n]=0;
6662    vars=vars,y(1..m);
6663    map emb=R,vars;
6664    ideal G=emb(J);
6665    J=J-G;
6666    for (i=1;i<=ncols(G);i++)
6667    { if (J[i]<>0)
6668      { G[i]=0;
6669      }
6670    }
6671    G=compress(G);
6672    execute("ring "+newring+"=("+charstr(br)+"),(y(1..m)),lp;");
6673    execute("minpoly=number("+mp+");");
6674    ideal vars;
6675    for (i=2;i<=n;i++)
6676    { vars[i]=0;
6677    }
6678    vars=vars,y(1..m);
6679    map emb=R,vars;
6680    ideal G=emb(G);
6681    kill vars, emb;
6682    keepring `newring`;
6683    return();
6684  }
6685  else
6686  { "ERROR:   the <matrix> may only have one row";
6687    return();
6688  }
6689}
6690
6691example
6692{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.3:"; echo=2;
6693         ring R=0,(x,y,z),dp;
6694         matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
6695         ideal I=x2+y2+z2-1,x2y+y2z+z2x-2x-2y-2z,xy2+yz2+zx2-2x-2y-2z;
6696         string newring="E";
6697         relative_orbit_variety(I,F,newring);
6698         print(G);
6699         basering;
6700}
6701
6702///////////////////////////////////////////////////////////////////////////////
6703
6704proc image_of_variety(ideal I,matrix F)
6705"USAGE:   image_of_variety(I,F);
6706@*         I: an arbitray <ideal>,
6707@*       F: a 1xm <matrix> defining an invariant ring of some matrix group
6708RETURN:  The <ideal> defining the image under that group of the variety defined
6709         by I
6710THEORY:  rel_orbit_variety(I,F) is called and the newly introduced
6711@*       variables in the output are replaced by the generators of the
6712@*       invariant ring. This ideal in the original variables defines the image
6713@*       of the variety defined by I
6714EXAMPLE: example image_of_variety; shows an example
6715"
6716{ if (nrows(F)==1)
6717  { def br=basering;
6718    int n=nvars(br);
6719    list L = rel_orbit_variety(I,F);
6720    def newring=L[2];
6721    setring(newring);
6722    ideal F=imap(br,F);
6723    for (int i=1;i<=n;i++)
6724    { F=0,F;
6725    }
6726    map emb2=newring,F;
6727    ideal trafo = compress(emb2(G));
6728    setring br;
6729    return(imap(newring,trafo));
6730  }
6731  else
6732  { "ERROR:   the <matrix> may only have one row";
6733    return();
6734  }
6735}
6736example
6737{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.8:"; echo=2;
6738         ring R=0,(x,y,z),dp;
6739         matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
6740         ideal I=xy;
6741         print(image_of_variety(I,F));
6742}
6743///////////////////////////////////////////////////////////////////////////////
6744
6745
6746
6747
Note: See TracBrowser for help on using the repository browser.