source: git/Singular/LIB/finvar.lib @ 3684b5

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