source: git/Singular/LIB/finvar.lib @ 3c8425

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