source: git/Singular/LIB/finvar.lib @ 6d37e8

spielwiese
Last change on this file since 6d37e8 was 51d95b, checked in by Mathias Schulze <mschulze@…>, 23 years ago
*mschulze: modified procedure descriptions git-svn-id: file:///usr/local/Singular/svn/trunk@5177 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 213.6 KB
Line 
1// last change: 98/11/05
2///////////////////////////////////////////////////////////////////////////////
3version="$Id: finvar.lib,v 1.32 2001-02-02 16:28:58 mschulze Exp $"
4category="Invariant theory";
5info="
6LIBRARY:  finvar.lib    Invariant Rings of Finite Groups
7AUTHOR: Agnes E. Heydtmann, email: agnes@math.uni-sb.de
8
9OVERVIEW:
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
20AUXILIARY 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
193  { matrix I=diag(1,n);                  // group 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
260        { TEST=G(g);                     //group 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@format
1440(1+a1x+a2x^2+...+anx^n)/(1+b1x+b2x^2+...+bmx^m)=(1+(a1-b1)x+...
1441(1+b1x+b2x^2+...+bmx^m)
1442-----------------------
1443   (a1-b1)x+(a2-b2)x^2+...
1444   (a1-b1)x+b1(a1-b1)x^2+...
1445@end format
1446EXAMPLE: example partial_molien; shows an example
1447"
1448{ poly A(2);                           // A(2) will contain the return value of
1449                                       // the intermediate result
1450  if (char(basering)<>0)
1451  { "ERROR:   you have to change to a basering of characteristic 0, one in";
1452    "         which the Molien series is defined";
1453  }
1454  if (ncols(M)==2 && nrows(M)==1 && n>0 && size(#)<2)
1455  { def br=basering;                   // keeping track of the old ring
1456    map slead=br,ideal(0);
1457    matrix s=slead(M);
1458    if (s[1,1]<>1 || s[1,2]<>1)
1459    { "ERROR:   the constant terms of enumerator and denominator are not 1";
1460      return();
1461    }
1462
1463    if (size(#)==0)
1464    { A(2)=M[1,1];                    // if a third parameter is not given, the
1465                                      // intermediate result from the last run
1466                                      // corresponds to the numerator - we need
1467    }                                 // its smallest term
1468    else
1469    { if (typeof(#[1])=="poly")
1470      { A(2)=#[1];                    // if a third term is given we 'start'
1471      }                               // with its smallest term
1472      else
1473      { "ERROR:   <poly> as third parameter expected";
1474        return();
1475      }
1476    }
1477    poly A(1)=M[1,2];                 // denominator of Molien series (for now)
1478    string mp=string(minpoly);
1479    execute("ring R=("+charstr(br)+"),("+varstr(br)+"),ds;");
1480    execute("minpoly=number("+mp+");");
1481    poly A(1)=0;                      // A(1) will contain the sum of n terms -
1482    poly min;                         // min will be our smallest term -
1483    poly A(2)=fetch(br,A(2));         // fetching A(2) and M[1,2] into R
1484    poly den=fetch(br,A(1));
1485    for (int i=1; i<=n; i++)          // getting n terms and adding them up
1486    { min=lead(A(2));
1487      A(1)=A(1)+min;
1488      A(2)=A(2)-min*den;
1489    }
1490    setring br;                       // moving A(1) and A(2) back in the
1491    A(1)=fetch(R,A(1));               // actual ring for output
1492    A(2)=fetch(R,A(2));
1493    return(A(1..2));
1494  }
1495  else
1496  { "ERROR:   the first parameter has to be a 1x2-matrix, i.e. the matrix";
1497    "         returned by the procedure 'reynolds_molien', the second one";
1498    "         should be > 0 and there should be no more than 3 parameters;"
1499    return();
1500  }
1501}
1502example
1503{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1504         ring R=0,(x,y,z),dp;
1505         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1506         matrix REY,M=reynolds_molien(A);
1507         poly p(1..2);
1508         p(1..2)=partial_molien(M,5);
1509         p(1);
1510         p(1..2)=partial_molien(M,5,p(2));
1511         p(1);
1512}
1513///////////////////////////////////////////////////////////////////////////////
1514
1515proc evaluate_reynolds (matrix REY, ideal I)
1516"USAGE:   evaluate_reynolds(REY,I);
1517         REY: a <matrix> representing the Reynolds operator, I: an arbitrary
1518         <ideal>
1519ASSUME:  REY is the first return value of group_reynolds() or reynolds_molien()
1520RETURNS: image of the polynomials defining I under the Reynolds operator
1521         (type <ideal>)
1522NOTE:    the characteristic of the coefficient field of the polynomial ring
1523         should not divide the order of the finite matrix group
1524THEORY:  REY has been constructed in such a way that each row serves as a ring
1525         mapping of which the Reynolds operator is made up.
1526EXAMPLE: example evaluate_reynolds; shows an example
1527"
1528{ def br=basering;
1529  int n=nvars(br);
1530  if (ncols(REY)==n)
1531  { int m=nrows(REY);                  // we need m to 'cut' the ring
1532                                       // homomorphisms 'out' of REY and to
1533                                       // divide by the group order in the end
1534    int num_poly=ncols(I);
1535    matrix MI=matrix(I);
1536    matrix MiI[1][num_poly];
1537    map pREY;
1538    matrix rowREY[1][n];
1539    for (int i=1;i<=m;i++)
1540    { rowREY=REY[i,1..n];
1541      pREY=br,ideal(rowREY);           // f is now the i-th ring homomorphism
1542      MiI=pREY(MI)+MiI;
1543    }
1544    MiI=(1/number(m))*MiI;
1545    return(ideal(MiI));
1546  }
1547  else
1548  { "ERROR:   the number of columns in the <matrix> should be the same as the";
1549    "         number of variables in the basering; in fact it should be first";
1550    "         return value of group_reynolds() or reynolds_molien().";
1551    return();
1552  }
1553}
1554example
1555{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1556         ring R=0,(x,y,z),dp;
1557         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1558         list L=group_reynolds(A);
1559         ideal I=x2,y2,z2;
1560         print(evaluate_reynolds(L[1],I));
1561}
1562///////////////////////////////////////////////////////////////////////////////
1563
1564proc invariant_basis (int g,list #)
1565"USAGE:   invariant_basis(g,G1,G2,...);
1566         g: an <int> indicating of which degree (>0) the homogeneous basis
1567         shoud be, G1,G2,...: <matrices> generating a finite matrix group
1568RETURNS: the basis (type <ideal>) of the space of invariants of degree g
1569THEORY:  A general polynomial of degree g is generated and the generators of
1570         the matrix group applied. The difference ought to be 0 and this way a
1571         system of linear equations is created. It is solved by computing
1572         syzygies.
1573EXAMPLE: example invariant_basis; shows an example
1574"
1575{ if (g<=0)
1576  { "ERROR:   the first parameter should be > 0";
1577    return();
1578  }
1579  def br=basering;
1580  ideal mon=sort(maxideal(g))[1];      // needed for constructing a general
1581  int m=ncols(mon);                    // homogeneous polynomial of degree g
1582  mon=sort(mon,intvec(m..1))[1];
1583  int a=size(#);
1584  int i;
1585  int n=nvars(br);
1586 //---------------------- checking that the input is ok -----------------------
1587  for (i=1;i<=a;i++)
1588  { if (typeof(#[i])=="matrix")
1589    { if (nrows(#[i])==n && ncols(#[i])==n)
1590      { matrix G(i)=#[i];
1591      }
1592      else
1593      { "ERROR:   the number of variables of the base ring needs to be the same";
1594        "         as the dimension of the square matrices";
1595        return();
1596      }
1597    }
1598    else
1599    { "ERROR:   the last parameters should be a list of matrices";
1600      return();
1601    }
1602  }
1603 //----------------------------------------------------------------------------
1604  execute("ring T=("+charstr(br)+"),("+varstr(br)+",p(1..m)),lp;");
1605  // p(1..m) are the general coefficients of the general polynomial of degree g
1606  execute("ideal vars="+varstr(br)+";");
1607  map f;
1608  ideal mon=imap(br,mon);
1609  poly P=0;
1610  for (i=m;i>=1;i--)
1611  { P=P+p(i)*mon[i];                   // P is the general polynomial
1612  }
1613  ideal I;                             // will help substituting variables in P
1614                                       // by linear combinations of variables -
1615  poly Pnew,temp;                      // Pnew is P with substitutions -
1616  matrix S[m*a][m];                    // will contain system of linear
1617                                       // equations
1618  int j,k;
1619 //------------------- building the system of linear equations ----------------
1620  for (i=1;i<=a;i++)
1621  { I=ideal(matrix(vars)*transpose(imap(br,G(i))));
1622    I=I,p(1..m);
1623    f=T,I;
1624    Pnew=f(P);
1625    for (j=1;j<=m;j++)
1626    { temp=P/mon[j]-Pnew/mon[j];
1627      for (k=1;k<=m;k++)
1628      { S[m*(i-1)+j,k]=temp/p(k);
1629      }
1630    }
1631  }
1632 //----------------------------------------------------------------------------
1633  setring br;
1634  map f=T,ideal(0);
1635  matrix S=f(S);
1636  matrix s=matrix(syz(S));             // s contains a basis of the space of
1637                                       // solutions -
1638  ideal I=ideal(matrix(mon)*s);        // I contains a basis of homogeneous
1639  if (I[1]<>0)                         // invariants of degree d
1640  { for (i=1;i<=ncols(I);i++)
1641    { I[i]=I[i]/leadcoef(I[i]);        // setting leading coefficients to 1
1642    }
1643  }
1644  return(I);
1645}
1646example
1647{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1648           ring R=0,(x,y,z),dp;
1649           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1650           print(invariant_basis(2,A));
1651}
1652///////////////////////////////////////////////////////////////////////////////
1653
1654proc invariant_basis_reynolds (matrix REY,int d,list #)
1655"USAGE:   invariant_basis_reynolds(REY,d[,flags]);
1656         REY: a <matrix> representing the Reynolds operator, d: an <int>
1657         indicating of which degree (>0) the homogeneous basis shoud be, flags:
1658         an optional <intvec> with two entries: its first component gives the
1659         dimension of the space (default <0 meaning unknown) and its second
1660         component is used as the number of polynomials that should be mapped
1661         to invariants during one call of evaluate_reynolds if the dimension of
1662         the space is unknown or the number such that number x dimension
1663         polynomials are mapped to invariants during one call of
1664         evaluate_reynolds
1665ASSUME:  REY is the first return value of group_reynolds() or reynolds_molien()
1666         and flags[1] given by partial_molien
1667RETURN:  the basis (type <ideal>) of the space of invariants of degree d
1668THEORY:  Monomials of degree d are mapped to invariants with the Reynolds
1669         operator. A linearly independent set is generated with the help of
1670         minbase.
1671EXAMPLE: example invariant_basis_reynolds; shows an example
1672"
1673{
1674 //---------------------- checking that the input is ok -----------------------
1675  if (d<=0)
1676  { "  ERROR:   the second parameter should be > 0";
1677     return();
1678  }
1679  if (size(#)>1)
1680  { "  ERROR:   there should be at most three parameters";
1681    return();
1682  }
1683  if (size(#)==1)
1684  { if (typeof(#[1])<>"intvec")
1685    { "  ERROR: the third parameter should be of type <intvec>";
1686      return();
1687    }
1688    if (size(#[1])<>2)
1689    { "  ERROR: there should be two components in <intvec>";
1690      return();
1691    }
1692    else
1693    { int cd=#[1][1];
1694      int step_fac=#[1][2];
1695    }
1696    if (step_fac<=0)
1697    { "  ERROR: the second component of <intvec> should be > 0";
1698      return();
1699    }
1700    if (cd==0)
1701    { return(ideal(0));
1702    }
1703  }
1704  else
1705  { int step_fac=1;
1706    int cd=-1;
1707  }
1708  if (ncols(REY)<>nvars(basering))
1709  { "ERROR:   the number of columns in the <matrix> should be the same as the";
1710    "         number of variables in the basering; in fact it should be first";
1711    "         return value of group_reynolds() or reynolds_molien().";
1712    return();
1713  }
1714 //----------------------------------------------------------------------------
1715  ideal mon=sort(maxideal(d))[1];
1716  int DEGB = degBound;
1717  degBound=d;
1718  int j=ncols(mon);
1719  mon=sort(mon,intvec(j..1))[1];
1720  ideal B;                             // will contain the basis
1721  if (cd<0)
1722  { if (step_fac>j)                    // all of mon will be mapped to
1723    { B=evaluate_reynolds(REY,mon);    // invariants at once
1724      B=minbase(B);
1725      degBound=DEGB;
1726      return(B);
1727    }
1728  }
1729  else
1730  { if (step_fac*cd>j)                 // all of mon will be mapped to
1731    { B=evaluate_reynolds(REY,mon);    // invariants at once
1732      B=minbase(B);
1733      degBound=DEGB;
1734      return(B);
1735    }
1736  }
1737  int i,k;
1738  int upper_bound=0;
1739  int lower_bound=0;
1740  ideal part_mon;                      // a part of mon of size step_fac*cd
1741  while (1)
1742  { lower_bound=upper_bound+1;
1743    if (cd<0)
1744    { upper_bound=upper_bound+step_fac;
1745    }
1746    else
1747    { upper_bound=upper_bound+step_fac*cd;
1748    }
1749    if (upper_bound>j)
1750    { upper_bound=j;
1751    }
1752    part_mon=mon[lower_bound..upper_bound];
1753    B=minbase(B+evaluate_reynolds(REY,part_mon));
1754    if ((ncols(B)==cd and B[1]<>0) or upper_bound==j)
1755    { degBound=DEGB;
1756      return(B);
1757    }
1758  }
1759}
1760example
1761{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
1762           ring R=0,(x,y,z),dp;
1763           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
1764           intvec flags=0,1,0;
1765           matrix REY,M=reynolds_molien(A,flags);
1766           flags=8,6;
1767           print(invariant_basis_reynolds(REY,6,flags));
1768}
1769
1770///////////////////////////////////////////////////////////////////////////////
1771// This procedure generates linearly independent invariant polynomials of
1772// degree d that do not reduce to 0 modulo the primary invariants. It does this
1773// by applying the Reynolds operator to the monomials returned by kbase(sP,d).
1774// The result is used when computing secondary invariants.
1775///////////////////////////////////////////////////////////////////////////////
1776proc sort_of_invariant_basis (ideal sP,matrix REY,int d,int step_fac)
1777{ ideal mon=kbase(sP,d);
1778  int DEGB=degBound;
1779  degBound=d;
1780  int j=ncols(mon);
1781  int i;
1782  mon=sort(mon,intvec(j..1))[1];
1783  ideal B;                             // will contain the "sort of basis"
1784  if (step_fac>j)
1785  { B=compress(evaluate_reynolds(REY,mon));
1786    for (i=1;i<=ncols(B);i++)          // those are taken our that are o mod sP
1787    { if (reduce(B[i],sP)==0)
1788      { B[i]=0;
1789      }
1790    }
1791    B=minbase(B);                     // here are the linearly independent ones
1792    degBound=DEGB;
1793    return(B);
1794  }
1795  int upper_bound=0;
1796  int lower_bound=0;
1797  ideal part_mon;                      // parts of mon
1798  while (1)
1799  { lower_bound=upper_bound+1;
1800    upper_bound=upper_bound+step_fac;
1801    if (upper_bound>j)
1802    { upper_bound=j;
1803    }
1804    part_mon=mon[lower_bound..upper_bound];
1805    part_mon=compress(evaluate_reynolds(REY,part_mon));
1806    for (i=1;i<=ncols(part_mon);i++)
1807    { if (reduce(part_mon[i],sP)==0)
1808      { part_mon[i]=0;
1809      }
1810    }
1811    B=minbase(B+part_mon);            // here are the linearly independent ones
1812    if (upper_bound==j)
1813    { degBound=DEGB;
1814      return(B);
1815    }
1816  }
1817}
1818
1819///////////////////////////////////////////////////////////////////////////////
1820// Procedure returning the succeeding vector after vec. It is used to list
1821// all the vectors of Z^n with first nonzero entry 1. They are listed by
1822// increasing sum of the absolute value of their entries.
1823///////////////////////////////////////////////////////////////////////////////
1824proc next_vector(intmat vec)
1825{ int n=ncols(vec);                    // p: >0, n: <0, p0: >=0, n0: <=0
1826  for (int i=1;i<=n;i++)               // finding out which is the first
1827  { if (vec[1,i]<>0)                   // component <>0
1828    { break;
1829    }
1830  }
1831  intmat new[1][n];
1832  if (i>n)                             // 0,...,0 --> 1,0....,0
1833  { new[1,1]=1;
1834    return(new);
1835  }
1836  if (i==n)                            // 0,...,1 --> 1,1,0,...,0
1837  { new[1,1..2]=1,1;
1838    return(new);
1839  }
1840  if (i==n-1)
1841  { if (vec[1,n]==0)                   // 0,...,0,1,0 --> 0,...,0,1
1842    { new[1,n]=1;
1843      return(new);
1844    }
1845    if (vec[1,n]>0)                    // 0,..,0,1,p --> 0,...,0,1,-p
1846    { new[1,1..n]=vec[1,1..n-1],-vec[1,n];
1847      return(new);
1848    }
1849    new[1,1..2]=1,1-vec[1,n];          // 0,..,0,1,n --> 1,1-n,0,..,0
1850    return(new);
1851  }
1852  if (i>1)
1853  { intmat temp[1][n-i+1]=vec[1,i..n]; // 0,...,0,1,*,...,* --> 1,*,...,*
1854    temp=next_vector(temp);
1855    new[1,i..n]=temp[1,1..n-i+1];
1856    return(new);
1857  }                                    // case left: 1,*,...,*
1858  for (i=2;i<=n;i++)
1859  { if (vec[1,i]>0)                    // make first positive negative and
1860    { vec[1,i]=-vec[1,i];              // return
1861      return(vec);
1862    }
1863    else
1864    { vec[1,i]=-vec[1,i];             // make all negatives before positives
1865    }                                 // positive
1866  }
1867  for (i=2;i<=n-1;i++)                // case: 1,p,...,p after 1,n,...,n
1868  { if (vec[1,i]>0)
1869    { vec[1,2]=vec[1,i]-1;            // shuffleing things around...
1870      if (i>2)                        // same sum of absolute values of entries
1871      { vec[1,i]=0;
1872      }
1873      vec[1,i+1]=vec[1,i+1]+1;
1874      return(vec);
1875    }
1876  }                                    // case left: 1,0,...,0 --> 1,1,0,...,0
1877  new[1,2..3]=1,vec[1,n];              // and: 1,0,...,0,1 --> 0,1,1,0,...,0
1878  return(new);
1879}
1880
1881///////////////////////////////////////////////////////////////////////////////
1882// Maps integers to elements of the base field. It is only called if the base
1883// field is of prime characteristic. If the base field has q elements
1884// (depending on minpoly) 1..q is mapped to those q elements.
1885///////////////////////////////////////////////////////////////////////////////
1886proc int_number_map (int i)
1887{ int p=char(basering);
1888  if (minpoly==0)                      // if no minpoly is given, we have p
1889  { i=i%p;                             // elements in the field
1890    return(number(i));
1891  }
1892  int d=pardeg(minpoly);
1893  if (i<0)
1894  { int bool=1;
1895    i=(-1)*i;
1896  }
1897  i=i%p^d;                            // base field has p^d elements -
1898  number a=par(1);                    // a is the root of the minpoly - we have
1899  number out=0;                       // to construct a linear combination of
1900  int j=1;                            // a^k
1901  int k;
1902  while (1)
1903  { if (i<p^j)                         // finding an upper bound on i
1904    { for (k=0;k<j-1;k++)
1905      { out=out+((i/p^k)%p)*a^k;       // finding how often p^k is contained in
1906      }                                // i
1907      out=out+(i/p^(j-1))*a^(j-1);
1908      if (defined(bool)==voice)
1909      { return((-1)*out);
1910      }
1911      return(out);
1912    }
1913    j++;
1914  }
1915}
1916
1917///////////////////////////////////////////////////////////////////////////////
1918// This procedure finds dif primary invariants in degree d. It returns all
1919// primary invariants found so far. The coefficients lie in a field of
1920// characteristic 0.
1921///////////////////////////////////////////////////////////////////////////////
1922proc search (int n,int d,ideal B,int cd,ideal P,ideal sP,int i,int dif,int dB,ideal CI)
1923{ intmat vec[1][cd];                   // the coefficients for the next
1924                                       // combination -
1925  degBound=0;
1926  poly test_poly;                      // the linear combination to test
1927  int test_dim;
1928  intvec h;                            // Hilbert series
1929  int j=i+1;
1930  matrix tB=transpose(B);
1931  ideal TEST;
1932  while(j<=i+dif)
1933  { CI=CI+ideal(var(j)^d);             // homogeneous polynomial of the same
1934                                       // degree as the one we're looking for is
1935                                       // added
1936    // h=hilb(std(CI),1);
1937    dB=dB+d-1;                         // used as degBound
1938    while(1)
1939    { vec=next_vector(vec);            // next vector
1940      test_poly=(vec*tB)[1,1];
1941      // degBound=dB;
1942      TEST=sP+ideal(test_poly);
1943      attrib(TEST,"isSB",1);
1944      test_dim=dim(TEST);
1945      // degBound=0;
1946      if (n-test_dim==j)               // the dimension has been lowered by one
1947      { sP=TEST;
1948        break;
1949      }
1950      // degBound=dB;
1951      TEST=std(sP+ideal(test_poly));   // should soon be replaced by next line
1952      // TEST=std(sP,test_poly,h);        // Hilbert driven std-calculation
1953      test_dim=dim(TEST);
1954      // degBound=0;
1955      if (n-test_dim==j)               // the dimension has been lowered by one
1956      { sP=TEST;
1957        break;
1958      }
1959    }
1960    P[j]=test_poly;                    // test_poly ist added to primary
1961    j++;                               // invariants
1962  }
1963  return(P,sP,CI,dB);
1964}
1965
1966///////////////////////////////////////////////////////////////////////////////
1967// This procedure finds at most dif primary invariants in degree d. It returns
1968// all primary invariants found so far. The coefficients lie in the field of
1969// characteristic p>0.
1970///////////////////////////////////////////////////////////////////////////////
1971proc p_search (int n,int d,ideal B,int cd,ideal P,ideal sP,int i,int dif,int dB,ideal CI)
1972{ def br=basering;
1973  degBound=0;
1974  matrix vec(1)[1][cd];                // starting with 0-vector -
1975  intmat new[1][cd];                   // the coefficients for the next
1976                                       // combination -
1977  matrix pnew[1][cd];                  // new needs to be mapped into br -
1978  int counter=1;                       // counts the vectors
1979  int j;
1980  int p=char(br);
1981  if (minpoly<>0)
1982  { int ext_deg=pardeg(minpoly);       // field has p^d elements
1983  }
1984  else
1985  { int ext_deg=1;                     // field has p^d elements
1986  }
1987  poly test_poly;                      // the linear combination to test
1988  int test_dim;
1989  ring R=0,x,dp;                       // just to calculate next variable
1990                                       // bound -
1991  number bound=(number(p)^(ext_deg*cd)-1)/(number(p)^ext_deg-1)+1;
1992                                       // this is how many linearly independent
1993                                       // vectors of size cd exist having
1994                                       // entries in the base field of br
1995  setring br;
1996  intvec h;                            // Hilbert series
1997  int k=i+1;
1998  matrix tB=transpose(B);
1999  ideal TEST;
2000  while (k<=i+dif)
2001  { CI=CI+ideal(var(k)^d);             // homogeneous polynomial of the same
2002                                       //degree as the one we're looking for is
2003                                       // added
2004    // h=hilb(std(CI),1);
2005    dB=dB+d-1;                         // used as degBound
2006    setring R;
2007    while (number(counter)<>bound)     // otherwise, we are done
2008    { setring br;
2009      new=next_vector(new);
2010      for (j=1;j<=cd;j++)
2011      { pnew[1,j]=int_number_map(new[1,j]); // mapping an integer into br
2012      }
2013      if (unique(vec(1..counter),pnew)) //checking whether we tried pnew before
2014      { counter++;
2015        matrix vec(counter)=pnew;      // keeping track of the ones we tried -
2016        test_poly=(vec(counter)*tB)[1,1]; // linear combination -
2017        // degBound=dB;
2018        TEST=sP+ideal(test_poly);
2019        attrib(TEST,"isSB",1);
2020        test_dim=dim(TEST);
2021        // degBound=0;
2022        if (n-test_dim==k)             // the dimension has been lowered by one
2023        { sP=TEST;
2024          setring R;
2025          break;
2026        }
2027        // degBound=dB;
2028        TEST=std(sP+ideal(test_poly)); // should soon to be replaced by next
2029                                       // line
2030        // TEST=std(sP,test_poly,h);      // Hilbert driven std-calculation
2031        test_dim=dim(TEST);
2032        // degBound=0;
2033        if (n-test_dim==k)             // the dimension has been lowered by one
2034        { sP=TEST;
2035          setring R;
2036          break;
2037        }
2038      }
2039      setring R;
2040    }
2041    if (number(counter)<=bound)
2042    { setring br;
2043      P[k]=test_poly;                  // test_poly ist added to primary
2044    }                                  // invariants
2045    else
2046    { setring br;
2047      CI=CI[1..size(CI)-1];
2048      return(P,sP,CI,dB-d+1);
2049    }
2050    k++;
2051  }
2052  return(P,sP,CI,dB);
2053}
2054///////////////////////////////////////////////////////////////////////////////
2055
2056proc primary_char0 (matrix REY,matrix M,list #)
2057"USAGE:   primary_char0(REY,M[,v]);
2058         REY: a <matrix> representing the Reynolds operator, M: a 1x2 <matrix>
2059         representing the Molien series, v: an optional <int>
2060ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
2061         M the one of molien or the second one of reynolds_molien
2062DISPLAY: information about the various stages of the programme if v does not
2063         equal 0
2064RETURN:  primary invariants (type <matrix>) of the invariant ring
2065THEORY:  Bases of homogeneous invariants are generated successively and those
2066         are chosen as primary invariants that lower the dimension of the ideal
2067         generated by the previously found invariants (see paper \"Generating a
2068         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2069         Decker, Heydtmann, Schreyer (1998)).
2070EXAMPLE: example primary_char0; shows an example
2071"
2072{ degBound=0;
2073  if (char(basering)<>0)
2074  { "ERROR:   primary_char0 should only be used with rings of characteristic 0.";
2075    return();
2076  }
2077 //----------------- checking input and setting verbose mode ------------------
2078  if (size(#)>1)
2079  { "ERROR:   primary_char0 can only have three parameters.";
2080    return();
2081  }
2082  if (size(#)==1)
2083  { if (typeof(#[1])<>"int")
2084    { "ERROR:   The third parameter should be of type <int>.";
2085      return();
2086    }
2087    else
2088    { int v=#[1];
2089    }
2090  }
2091  else
2092  { int v=0;
2093  }
2094  int n=nvars(basering);               // n is the number of variables, as well
2095                                       // as the size of the matrices, as well
2096                                       // as the number of primary invariants,
2097                                       // we should get
2098  if (ncols(REY)<>n)
2099  { "ERROR:   First parameter ought to be the Reynolds operator."
2100    return();
2101  }
2102  if (ncols(M)<>2 or nrows(M)<>1)
2103  { "ERROR:   Second parameter ought to be the Molien series."
2104    return();
2105  }
2106 //----------------------------------------------------------------------------
2107  if (v && voice<>2)
2108  { "  We can start looking for primary invariants...";
2109    "";
2110  }
2111  if (v && voice==2)
2112  { "";
2113  }
2114 //------------------------- initializing variables ---------------------------
2115  int dB;
2116  poly p(1..2);                        // p(1) will be used for single terms of
2117                                       // the partial expansion, p(2) to store
2118  p(1..2)=partial_molien(M,1);         // the intermediate result -
2119  poly v1=var(1);                      // we need v1 to split off coefficients
2120                                       // in the partial expansion of M (which
2121                                       // is in terms of the first variable) -
2122  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2123                                       // space of invariants of degree d,
2124                                       // newdim: dimension the ideal generated
2125                                       // the primary invariants plus basis
2126                                       // elements, dif=n-i-newdim, i.e. the
2127                                       // number of new primary invairants that
2128                                       // should be added in this degree -
2129  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2130                                       // Pplus: P+B, CI: a complete
2131                                       // intersection with the same Hilbert
2132                                       // function as P
2133  ideal sP=std(P);
2134  dB=1;                                // used as degree bound
2135  int i=0;
2136 //-------------- loop that searches for primary invariants  ------------------
2137  while(1)                             // repeat until n primary invariants are
2138  {                                    // found -
2139    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
2140    d=deg(p(1));                       // degree where we'll search -
2141    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
2142                                       // inviarants of degree d
2143    if (v)
2144    { "  Computing primary invariants in degree "+string(d)+":";
2145    }
2146    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
2147                                       // degree d
2148    if (B[1]<>0)
2149    { Pplus=P+B;
2150      sPplus=std(Pplus);
2151      newdim=dim(sPplus);
2152      dif=n-i-newdim;
2153    }
2154    else
2155    { dif=0;
2156    }
2157    if (dif<>0)                        // we have to find dif new primary
2158    {                                  // invariants
2159      if (cd<>dif)
2160      { P,sP,CI,dB=search(n,d,B,cd,P,sP,i,dif,dB,CI); // searching for dif invariants
2161      }                                // i.e. we can take all of B
2162      else
2163      { for(j=i+1;j>i+dif;j++)
2164        { CI=CI+ideal(var(j)^d);
2165        }
2166        dB=dB+dif*(d-1);
2167        P=Pplus;
2168        sP=sPplus;
2169      }
2170      if (v)
2171      { for (j=1;j<=dif;j++)
2172        { "  We find: "+string(P[i+j]);
2173        }
2174      }
2175      i=i+dif;
2176      if (i==n)                        // found all primary invariants
2177      { if (v)
2178        { "";
2179          "  We found all primary invariants.";
2180          "";
2181        }
2182        return(matrix(P));
2183      }
2184    }                                  // done with degree d
2185  }
2186}
2187example
2188{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
2189         ring R=0,(x,y,z),dp;
2190         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2191         matrix REY,M=reynolds_molien(A);
2192         matrix P=primary_char0(REY,M);
2193         print(P);
2194}
2195///////////////////////////////////////////////////////////////////////////////
2196
2197proc primary_charp (matrix REY,string ring_name,list #)
2198"USAGE:   primary_charp(REY,ringname[,v]);
2199         REY: a <matrix> representing the Reynolds operator, ringname: a
2200         <string> giving the name of a ring where the Molien series is stored,
2201         v: an optional <int>
2202ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
2203         ringname gives the name of a ring of characteristic 0 that has been
2204         created by molien or reynolds_molien
2205DISPLAY: information about the various stages of the programme if v does not
2206         equal 0
2207RETURN:  primary invariants (type <matrix>) of the invariant ring
2208THEORY:  Bases of homogeneous invariants are generated successively and those
2209         are chosen as primary invariants that lower the dimension of the ideal
2210         generated by the previously found invariants (see paper \"Generating a
2211         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2212         Decker, Heydtmann, Schreyer (1998)).
2213EXAMPLE: example primary_charp; shows an example
2214"
2215{ degBound=0;
2216// ---------------- checking input and setting verbose mode -------------------
2217  if (char(basering)==0)
2218  { "ERROR:   primary_charp should only be used with rings of characteristic p>0.";
2219    return();
2220  }
2221  if (size(#)>1)
2222  { "ERROR:   primary_charp can only have three parameters.";
2223    return();
2224  }
2225  if (size(#)==1)
2226  { if (typeof(#[1])<>"int")
2227    { "ERROR:   The third parameter should be of type <int>.";
2228      return();
2229    }
2230    else
2231    { int v=#[1];
2232    }
2233  }
2234  else
2235  { int v=0;
2236  }
2237  def br=basering;
2238  int n=nvars(br);                     // n is the number of variables, as well
2239                                       // as the size of the matrices, as well
2240                                       // as the number of primary invariants,
2241                                       // we should get
2242  if (ncols(REY)<>n)
2243  { "ERROR:   First parameter ought to be the Reynolds operator."
2244    return();
2245  }
2246  if (typeof(`ring_name`)<>"ring")
2247  { "ERROR:   Second parameter ought to the name of a ring where the Molien";
2248    "         is stored.";
2249    return();
2250  }
2251 //----------------------------------------------------------------------------
2252  if (v && voice<>2)
2253  { "  We can start looking for primary invariants...";
2254    "";
2255  }
2256  if (v && voice==2)
2257  { "";
2258  }
2259 //----------------------- initializing variables -----------------------------
2260  int dB;
2261  setring `ring_name`;                 // the Molien series is stores here -
2262  poly p(1..2);                        // p(1) will be used for single terms of
2263                                       // the partial expansion, p(2) to store
2264  p(1..2)=partial_molien(M,1);         // the intermediate result -
2265  poly v1=var(1);                      // we need v1 to split off coefficients
2266                                       // in the partial expansion of M (which
2267                                       // is in terms of the first variable)
2268  setring br;
2269  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2270                                       // space of invariants of degree d,
2271                                       // newdim: dimension the ideal generated
2272                                       // the primary invariants plus basis
2273                                       // elements, dif=n-i-newdim, i.e. the
2274                                       // number of new primary invairants that
2275                                       // should be added in this degree -
2276  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2277                                       // Pplus: P+B, CI: a complete
2278                                       // intersection with the same Hilbert
2279                                       // function as P
2280  ideal sP=std(P);
2281  dB=1;                                // used as degree bound
2282  int i=0;
2283 //---------------- loop that searches for primary invariants -----------------
2284  while(1)                             // repeat until n primary invariants are
2285  {                                    // found
2286    setring `ring_name`;
2287    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
2288    d=deg(p(1));                       // degree where we'll search -
2289    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
2290                                       // inviarants of degree d
2291    setring br;
2292    if (v)
2293    { "  Computing primary invariants in degree "+string(d)+":";
2294    }
2295    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
2296                                       // degree d
2297    if (B[1]<>0)
2298    { Pplus=P+B;
2299      sPplus=std(Pplus);
2300      newdim=dim(sPplus);
2301      dif=n-i-newdim;
2302    }
2303    else
2304    { dif=0;
2305    }
2306    if (dif<>0)                        // we have to find dif new primary
2307    {                                  // invariants
2308      if (cd<>dif)
2309      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2310      }
2311      else                             // i.e. we can take all of B
2312      { for(j=i+1;j>i+dif;j++)
2313        { CI=CI+ideal(var(j)^d);
2314        }
2315        dB=dB+dif*(d-1);
2316        P=Pplus;
2317        sP=sPplus;
2318      }
2319      if (v)
2320      { for (j=1;j<=size(P)-i;j++)
2321        { "  We find: "+string(P[i+j]);
2322        }
2323      }
2324      i=size(P);
2325      if (i==n)                        // found all primary invariants
2326      { if (v)
2327        { "";
2328          "  We found all primary invariants.";
2329          "";
2330        }
2331        return(matrix(P));
2332      }
2333    }                                  // done with degree d
2334  }
2335}
2336example
2337{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
2338         ring R=3,(x,y,z),dp;
2339         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2340         list L=group_reynolds(A);
2341         string newring="alskdfj";
2342         molien(L[2..size(L)],newring);
2343         matrix P=primary_charp(L[1],newring);
2344         if(system("with","Namespaces")) { kill Top::`newring`; }
2345         kill `newring`;
2346         print(P);
2347}
2348///////////////////////////////////////////////////////////////////////////////
2349
2350proc primary_char0_no_molien (matrix REY, list #)
2351"USAGE:   primary_char0_no_molien(REY[,v]);
2352         REY: a <matrix> representing the Reynolds operator, v: an optional
2353         <int>
2354ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
2355DISPLAY: information about the various stages of the programme if v does not
2356         equal 0
2357RETURN:  primary invariants (type <matrix>) of the invariant ring and an
2358         <intvec> listing some of the degrees where no non-trivial homogeneous
2359         invariants are to be found
2360THEORY:  Bases of homogeneous invariants are generated successively and those
2361         are chosen as primary invariants that lower the dimension of the ideal
2362         generated by the previously found invariants (see paper \"Generating a
2363         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2364         Decker, Heydtmann, Schreyer (1998)).
2365EXAMPLE: example primary_char0_no_molien; shows an example
2366"
2367{ degBound=0;
2368 //-------------- checking input and setting verbose mode ---------------------
2369  if (char(basering)<>0)
2370  { "ERROR:   primary_char0_no_molien should only be used with rings of";
2371    "         characteristic 0.";
2372    return();
2373  }
2374  if (size(#)>1)
2375  { "ERROR:   primary_char0_no_molien can only have two parameters.";
2376    return();
2377  }
2378  if (size(#)==1)
2379  { if (typeof(#[1])<>"int")
2380    { "ERROR:   The second parameter should be of type <int>.";
2381      return();
2382    }
2383    else
2384    { int v=#[1];
2385    }
2386  }
2387  else
2388  { int v=0;
2389  }
2390  int n=nvars(basering);               // n is the number of variables, as well
2391                                       // as the size of the matrices, as well
2392                                       // as the number of primary invariants,
2393                                       // we should get
2394  if (ncols(REY)<>n)
2395  { "ERROR:   First parameter ought to be the Reynolds operator."
2396    return();
2397  }
2398 //----------------------------------------------------------------------------
2399  if (v && voice<>2)
2400  { "  We can start looking for primary invariants...";
2401    "";
2402  }
2403  if (v && voice==2)
2404  { "";
2405  }
2406 //----------------------- initializing variables -----------------------------
2407  int dB;
2408  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2409                                       // space of invariants of degree d,
2410                                       // newdim: dimension the ideal generated
2411                                       // the primary invariants plus basis
2412                                       // elements, dif=n-i-newdim, i.e. the
2413                                       // number of new primary invairants that
2414                                       // should be added in this degree -
2415  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
2416                                       // Pplus: P+B, CI: a complete
2417                                       // intersection with the same Hilbert
2418                                       // function as P
2419  ideal sP=std(P);
2420  dB=1;                                // used as degree bound -
2421  d=0;                                 // initializing
2422  int i=0;
2423  intvec deg_vector;
2424 //------------------ loop that searches for primary invariants ---------------
2425  while(1)                             // repeat until n primary invariants are
2426  {                                    // found -
2427    d++;                               // degree where we'll search
2428    if (v)
2429    { "  Computing primary invariants in degree "+string(d)+":";
2430    }
2431    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
2432                                       // degree d
2433    if (B[1]<>0)
2434    { Pplus=P+B;
2435      newdim=dim(std(Pplus));
2436      dif=n-i-newdim;
2437    }
2438    else
2439    { dif=0;
2440      deg_vector=deg_vector,d;
2441    }
2442    if (dif<>0)                        // we have to find dif new primary
2443    {                                  // invariants
2444      cd=size(B);
2445      if (cd<>dif)
2446      { P,sP,CI,dB=search(n,d,B,cd,P,sP,i,dif,dB,CI);
2447      }
2448      else                             // i.e. we can take all of B
2449      { for(j=i+1;j<=i+dif;j++)
2450        { CI=CI+ideal(var(j)^d);
2451        }
2452        dB=dB+dif*(d-1);
2453        P=Pplus;
2454        sP=std(P);
2455      }
2456      if (v)
2457      { for (j=1;j<=dif;j++)
2458        { "  We find: "+string(P[i+j]);
2459        }
2460      }
2461      i=i+dif;
2462      if (i==n)                        // found all primary invariants
2463      { if (v)
2464        { "";
2465          "  We found all primary invariants.";
2466          "";
2467        }
2468        if (deg_vector==0)
2469        { return(matrix(P));
2470        }
2471        else
2472        { return(matrix(P),compress(deg_vector));
2473        }
2474      }
2475    }                                  // done with degree d
2476    else
2477    { if (v)
2478      { "  None here...";
2479      }
2480    }
2481  }
2482}
2483example
2484{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
2485         ring R=0,(x,y,z),dp;
2486         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2487         list L=group_reynolds(A);
2488         list l=primary_char0_no_molien(L[1]);
2489         print(l[1]);
2490}
2491///////////////////////////////////////////////////////////////////////////////
2492
2493proc primary_charp_no_molien (matrix REY, list #)
2494"USAGE:   primary_charp_no_molien(REY[,v]);
2495         REY: a <matrix> representing the Reynolds operator, v: an optional
2496         <int>
2497ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
2498DISPLAY: information about the various stages of the programme if v does not
2499         equal 0
2500RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
2501         <intvec> listing some of the degrees where no non-trivial homogeneous
2502         invariants are to be found
2503THEORY:  Bases of homogeneous invariants are generated successively and those
2504         are chosen as primary invariants that lower the dimension of the ideal
2505         generated by the previously found invariants (see paper \"Generating a
2506         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2507         Decker, Heydtmann, Schreyer (1998)).
2508EXAMPLE: example primary_charp_no_molien; shows an example
2509"
2510{ degBound=0;
2511 //----------------- checking input and setting verbose mode ------------------
2512  if (char(basering)==0)
2513  { "ERROR:   primary_charp_no_molien should only be used with rings of";
2514    "         characteristic p>0.";
2515    return();
2516  }
2517  if (size(#)>1)
2518  { "ERROR:   primary_charp_no_molien can only have two parameters.";
2519    return();
2520  }
2521  if (size(#)==1)
2522  { if (typeof(#[1])<>"int")
2523    { "ERROR:   The second parameter should be of type <int>.";
2524      return();
2525    }
2526    else
2527    { int v=#[1];
2528    }
2529  }
2530  else
2531  { int v=0;
2532  }
2533  int n=nvars(basering);               // n is the number of variables, as well
2534                                       // as the size of the matrices, as well
2535                                       // as the number of primary invariants,
2536                                       // we should get
2537  if (ncols(REY)<>n)
2538  { "ERROR:   First parameter ought to be the Reynolds operator."
2539    return();
2540  }
2541 //----------------------------------------------------------------------------
2542  if (v && voice<>2)
2543  { "  We can start looking for primary invariants...";
2544    "";
2545  }
2546  if (v && voice==2)
2547  { "";
2548  }
2549 //-------------------- initializing variables --------------------------------
2550  int dB;
2551  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2552                                       // space of invariants of degree d,
2553                                       // newdim: dimension the ideal generated
2554                                       // the primary invariants plus basis
2555                                       // elements, dif=n-i-newdim, i.e. the
2556                                       // number of new primary invairants that
2557                                       // should be added in this degree -
2558  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2559                                       // Pplus: P+B, CI: a complete
2560                                       // intersection with the same Hilbert
2561                                       // function as P
2562  ideal sP=std(P);
2563  dB=1;                                // used as degree bound -
2564  d=0;                                 // initializing
2565  int i=0;
2566  intvec deg_vector;
2567 //------------------ loop that searches for primary invariants ---------------
2568  while(1)                             // repeat until n primary invariants are
2569  {                                    // found -
2570    d++;                               // degree where we'll search
2571    if (v)
2572    { "  Computing primary invariants in degree "+string(d)+":";
2573    }
2574    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
2575                                       // degree d
2576    if (B[1]<>0)
2577    { Pplus=P+B;
2578      sPplus=std(Pplus);
2579      newdim=dim(sPplus);
2580      dif=n-i-newdim;
2581    }
2582    else
2583    { dif=0;
2584      deg_vector=deg_vector,d;
2585    }
2586    if (dif<>0)                        // we have to find dif new primary
2587    {                                  // invariants
2588      cd=size(B);
2589      if (cd<>dif)
2590      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2591      }
2592      else                             // i.e. we can take all of B
2593      { for(j=i+1;j<=i+dif;j++)
2594        { CI=CI+ideal(var(j)^d);
2595        }
2596        dB=dB+dif*(d-1);
2597        P=Pplus;
2598        sP=sPplus;
2599      }
2600      if (v)
2601      { for (j=1;j<=size(P)-i;j++)
2602        { "  We find: "+string(P[i+j]);
2603        }
2604      }
2605      i=size(P);
2606      if (i==n)                        // found all primary invariants
2607      { if (v)
2608        { "";
2609          "  We found all primary invariants.";
2610          "";
2611        }
2612        if (deg_vector==0)
2613        { return(matrix(P));
2614        }
2615        else
2616        { return(matrix(P),compress(deg_vector));
2617        }
2618      }
2619    }                                  // done with degree d
2620    else
2621    { if (v)
2622      { "  None here...";
2623      }
2624    }
2625  }
2626}
2627example
2628{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
2629         ring R=3,(x,y,z),dp;
2630         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2631         list L=group_reynolds(A);
2632         list l=primary_charp_no_molien(L[1]);
2633         print(l[1]);
2634}
2635///////////////////////////////////////////////////////////////////////////////
2636
2637proc primary_charp_without (list #)
2638"USAGE:   primary_charp_without(G1,G2,...[,v]);
2639         G1,G2,...: <matrices> generating a finite matrix group, v: an optional
2640         <int>
2641DISPLAY: information about the various stages of the programme if v does not
2642         equal 0
2643RETURN:  primary invariants (type <matrix>) of the invariant ring
2644THEORY:  Bases of homogeneous invariants are generated successively and those
2645         are chosen as primary invariants that lower the dimension of the ideal
2646         generated by the previously found invariants (see paper \"Generating a
2647         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2648         Decker, Heydtmann, Schreyer (1998)). No Reynolds
2649         operator or Molien series is used.
2650EXAMPLE: example primary_charp_without; shows an example
2651"
2652{ degBound=0;
2653 //--------------------- checking input and setting verbose mode --------------
2654  if (char(basering)==0)
2655  { "ERROR:   primary_charp_without should only be used with rings of";
2656    "         characteristic 0.";
2657    return();
2658  }
2659  if (size(#)==0)
2660  { "ERROR:   There are no parameters.";
2661    return();
2662  }
2663  if (typeof(#[size(#)])=="int")
2664  { int v=#[size(#)];
2665    int gen_num=size(#)-1;
2666    if (gen_num==0)
2667    { "ERROR:   There are no generators of a finite matrix group given.";
2668      return();
2669    }
2670  }
2671  else
2672  { int v=0;
2673    int gen_num=size(#);
2674  }
2675  int n=nvars(basering);               // n is the number of variables, as well
2676                                       // as the size of the matrices, as well
2677                                       // as the number of primary invariants,
2678                                       // we should get
2679  for (int i=1;i<=gen_num;i++)
2680  { if (typeof(#[i])=="matrix")
2681    { if (nrows(#[i])<>n or ncols(#[i])<>n)
2682      { "ERROR:   The number of variables of the base ring needs to be the same";
2683        "         as the dimension of the square matrices";
2684        return();
2685      }
2686    }
2687    else
2688    { "ERROR:   The first parameters should be a list of matrices";
2689      return();
2690    }
2691  }
2692 //----------------------------------------------------------------------------
2693  if (v && voice==2)
2694  { "";
2695  }
2696 //---------------------------- initializing variables ------------------------
2697  int dB;
2698  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
2699                                       // space of invariants of degree d,
2700                                       // newdim: dimension the ideal generated
2701                                       // the primary invariants plus basis
2702                                       // elements, dif=n-i-newdim, i.e. the
2703                                       // number of new primary invairants that
2704                                       // should be added in this degree -
2705  ideal P,Pplus,sPplus,CI,B;           // P: will contain primary invariants,
2706                                       // Pplus: P+B, CI: a complete
2707                                       // intersection with the same Hilbert
2708                                       // function as P
2709  ideal sP=std(P);
2710  dB=1;                                // used as degree bound -
2711  d=0;                                 // initializing
2712  i=0;
2713  intvec deg_vector;
2714 //-------------------- loop that searches for primary invariants -------------
2715  while(1)                             // repeat until n primary invariants are
2716  {                                    // found -
2717    d++;                               // degree where we'll search
2718    if (v)
2719    { "  Computing primary invariants in degree "+string(d)+":";
2720    }
2721    B=invariant_basis(d,#[1..gen_num]); // basis of invariants of degree d
2722    if (B[1]<>0)
2723    { Pplus=P+B;
2724      sPplus=std(Pplus);
2725      newdim=dim(sPplus);
2726      dif=n-i-newdim;
2727    }
2728    else
2729    { dif=0;
2730      deg_vector=deg_vector,d;
2731    }
2732    if (dif<>0)                        // we have to find dif new primary
2733    {                                  // invariants
2734      cd=size(B);
2735      if (cd<>dif)
2736      { P,sP,CI,dB=p_search(n,d,B,cd,P,sP,i,dif,dB,CI);
2737      }
2738      else                             // i.e. we can take all of B
2739      { for(j=i+1;j<=i+dif;j++)
2740        { CI=CI+ideal(var(j)^d);
2741        }
2742        dB=dB+dif*(d-1);
2743        P=Pplus;
2744        sP=sPplus;
2745      }
2746      if (v)
2747      { for (j=1;j<=size(P)-i;j++)
2748        { "  We find: "+string(P[i+j]);
2749        }
2750      }
2751      i=size(P);
2752      if (i==n)                        // found all primary invariants
2753      { if (v)
2754        { "";
2755          "  We found all primary invariants.";
2756          "";
2757        }
2758        return(matrix(P));
2759      }
2760    }                                  // done with degree d
2761    else
2762    { if (v)
2763      { "  None here...";
2764      }
2765    }
2766  }
2767}
2768example
2769{ "EXAMPLE:"; echo=2;
2770         ring R=2,(x,y,z),dp;
2771         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2772         matrix P=primary_charp_without(A);
2773         print(P);
2774}
2775///////////////////////////////////////////////////////////////////////////////
2776
2777proc primary_invariants (list #)
2778"USAGE:   primary_invariants(G1,G2,...[,flags]);
2779         G1,G2,...: <matrices> generating a finite matrix group, flags: an
2780         optional <intvec> with three entries, if the first one equals 0 (also
2781         the default), the programme attempts to compute the Molien series and
2782         Reynolds operator, if it equals 1, the programme is told that the
2783         Molien series should not be computed, if it equals -1 characteristic 0
2784         is simulated, i.e. the Molien series is computed as if the base field
2785         were characteristic 0 (the user must choose a field of large prime
2786         characteristic, e.g. 32003) and if the first one is anything else, it
2787         means that the characteristic of the base field divides the group
2788         order, the second component should give the size of intervals between
2789         canceling common factors in the expansion of the Molien series, 0 (the
2790         default) means only once after generating all terms, in prime
2791         characteristic also a negative number can be given to indicate that
2792         common factors should always be canceled when the expansion is simple
2793         (the root of the extension field occurs not among the coefficients)
2794DISPLAY: information about the various stages of the programme if the third
2795         flag does not equal 0
2796RETURN:  primary invariants (type <matrix>) of the invariant ring and if
2797         computable Reynolds operator (type <matrix>) and Molien series (type
2798         <matrix>) or ring name (type string) where the Molien series
2799         can be found in the char p case; if the first flag is 1 and we are in
2800         the non-modular case then an <intvec> is returned giving some of the
2801         degrees where no non-trivial homogeneous invariants can be found
2802THEORY:  Bases of homogeneous invariants are generated successively and those
2803         are chosen as primary invariants that lower the dimension of the ideal
2804         generated by the previously found invariants (see paper \"Generating a
2805         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
2806         Decker, Heydtmann, Schreyer (1998)).
2807EXAMPLE: example primary_invariants; shows an example
2808"
2809{
2810 // ----------------- checking input and setting flags ------------------------
2811  if (size(#)==0)
2812  { "ERROR:   There are no parameters.";
2813    return();
2814  }
2815  int ch=char(basering);               // the algorithms depend very much on the
2816                                       // characteristic of the ground field
2817  int n=nvars(basering);               // n is the number of variables, as well
2818                                       // as the size of the matrices, as well
2819                                       // as the number of primary invariants,
2820                                       // we should get
2821  int gen_num;
2822  int mol_flag,v;
2823  if (typeof(#[size(#)])=="intvec")
2824  { if (size(#[size(#)])<>3)
2825    { "ERROR:   <intvec> should have three entries.";
2826      return();
2827    }
2828    gen_num=size(#)-1;
2829    mol_flag=#[size(#)][1];
2830    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag==-1)))
2831    { "ERROR:   the second component of <intvec> should be >=0";
2832      return();
2833    }
2834    int interval=#[size(#)][2];
2835    v=#[size(#)][3];
2836    if (gen_num==0)
2837    { "ERROR:   There are no generators of a finite matrix group given.";
2838      return();
2839    }
2840  }
2841  else
2842  { gen_num=size(#);
2843    mol_flag=0;
2844    int interval=0;
2845    v=0;
2846  }
2847  for (int i=1;i<=gen_num;i++)
2848  { if (typeof(#[i])=="matrix")
2849    { if (nrows(#[i])<>n or ncols(#[i])<>n)
2850      { "ERROR:   The number of variables of the base ring needs to be the same";
2851        "         as the dimension of the square matrices";
2852        return();
2853      }
2854    }
2855    else
2856    { "ERROR:   The first parameters should be a list of matrices";
2857      return();
2858    }
2859  }
2860 //----------------------------------------------------------------------------
2861  if (mol_flag==0)
2862  { if (ch==0)
2863    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(mol_flag,interval,v));
2864                                       // one will contain Reynolds operator and
2865                                       // the other enumerator and denominator
2866                                       // of Molien series
2867      matrix P=primary_char0(REY,M,v);
2868      return(P,REY,M);
2869    }
2870    else
2871    { list L=group_reynolds(#[1..gen_num],v);
2872      if (L[1]<>0)                     // testing whether we are in the modular
2873      { string newring="aksldfalkdsflkj"; // case
2874        if (minpoly==0)
2875        { if (v)
2876          { "  We are dealing with the non-modular case.";
2877          }
2878          if (typeof(L[2])=="int")
2879          { molien(L[3..size(L)],newring,L[2],intvec(mol_flag,interval,v));
2880          }
2881          else
2882          { molien(L[2..size(L)],newring,intvec(mol_flag,interval,v));
2883          }
2884          matrix P=primary_charp(L[1],newring,v);
2885          return(P,L[1],newring);
2886        }
2887        else
2888        { if (v)
2889          { "  Since it is impossible for this programme to calculate the Molien series for";
2890            "  invariant rings over extension fields of prime characteristic, we have to";
2891            "  continue without it.";
2892            "";
2893
2894          }
2895          list l=primary_charp_no_molien(L[1],v);
2896          if (size(l)==2)
2897          { return(l[1],L[1],l[2]);
2898          }
2899          else
2900          { return(l[1],L[1]);
2901          }
2902        }
2903      }
2904      else                             // the modular case
2905      { if (v)
2906        { "  There is also no Molien series, we can make use of...";
2907          "";
2908          "  We can start looking for primary invariants...";
2909          "";
2910        }
2911        return(primary_charp_without(#[1..gen_num],v));
2912      }
2913    }
2914  }
2915  if (mol_flag==1)                     // the user wants no calculation of the
2916  { list L=group_reynolds(#[1..gen_num],v); // Molien series
2917    if (ch==0)
2918    { list l=primary_char0_no_molien(L[1],v);
2919      if (size(l)==2)
2920      { return(l[1],L[1],l[2]);
2921      }
2922      else
2923      { return(l[1],L[1]);
2924      }
2925    }
2926    else
2927    { if (L[1]<>0)                     // testing whether we are in the modular
2928      { list l=primary_charp_no_molien(L[1],v); // case
2929        if (size(l)==2)
2930        { return(l[1],L[1],l[2]);
2931        }
2932        else
2933        { return(l[1],L[1]);
2934        }
2935      }
2936      else                             // the modular case
2937      { if (v)
2938        { "  We can start looking for primary invariants...";
2939          "";
2940        }
2941        return(primary_charp_without(#[1..gen_num],v));
2942      }
2943    }
2944  }
2945  if (mol_flag==-1)
2946  { if (ch==0)
2947    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.";
2948      return();
2949    }
2950    list L=group_reynolds(#[1..gen_num],v);
2951    string newring="aksldfalkdsflkj";
2952    molien(L[2..size(L)],newring,intvec(1,interval,v));
2953    matrix P=primary_charp(L[1],newring,v);
2954    return(P,L[1],newring);
2955  }
2956  else                                 // the user specified that the
2957  { if (ch==0)                         // characteristic divides the group order
2958    { "ERROR:   The characteristic cannot divide the group order when it is 0.";
2959      return();
2960    }
2961    if (v)
2962    { "";
2963    }
2964    return(primary_charp_without(#[1..gen_num],v));
2965  }
2966}
2967example
2968{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:";
2969  echo=2;
2970         ring R=0,(x,y,z),dp;
2971         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
2972         list L=primary_invariants(A);
2973         print(L[1]);
2974}
2975
2976///////////////////////////////////////////////////////////////////////////////
2977// This procedure finds dif primary invariants in degree d. It returns all
2978// primary invariants found so far. The coefficients lie in a field of
2979// characteristic 0.
2980///////////////////////////////////////////////////////////////////////////////
2981proc search_random (int n,int d,ideal B,int cd,ideal P,int i,int dif,int dB,ideal CI,int max)
2982{ string answer;
2983  degBound=0;
2984  int j,k,test_dim,flag;
2985  matrix test_matrix[1][dif];          // the linear combination to test
2986  intvec h;                            // Hilbert series
2987  for (j=i+1;j<=i+dif;j++)
2988  { CI=CI+ideal(var(j)^d);             // homogeneous polynomial of the same
2989                                       // degree as the one we're looking for
2990                                       // is added
2991  }
2992  ideal TEST;
2993  // h=hilb(std(CI),1);
2994  dB=dB+dif*(d-1);                     // used as degBound
2995  while (1)
2996  { test_matrix=matrix(B)*random(max,cd,dif);
2997    // degBound=dB;
2998    TEST=P+ideal(test_matrix);
2999    attrib(TEST,"isSB",1);
3000    test_dim=dim(TEST);
3001    // degBound=0;
3002    if (n-test_dim==i+dif)
3003    { break;
3004    }
3005    // degBound=dB;
3006    test_dim=dim(std(TEST));
3007    // test_dim=dim(std(TEST,h));         // Hilbert driven std-calculation
3008    // degBound=0;
3009    if (n-test_dim==i+dif)
3010    { break;
3011    }
3012    else
3013    { "HELP:    The "+string(dif)+" random combination(s) of the "+string(cd)+" basis elements with";
3014      "         coefficients in the range from -"+string(max)+" to "+string(max)+" did not lower the";
3015      "         dimension by "+string(dif)+". You can abort, try again or give a new range:";
3016      answer="";
3017      while (answer<>"n
3018" && answer<>"y
3019")
3020      { "         Do you want to abort (y/n)?";
3021        answer=read("");
3022      }
3023      if (answer=="y
3024")
3025      { flag=1;
3026        break;
3027      }
3028      answer="";
3029      while (answer<>"n
3030" && answer<>"y
3031")
3032      { "         Do you want to try again (y/n)?";
3033        answer=read("");
3034      }
3035      if (answer=="n
3036")
3037      { flag=1;
3038        while (flag)
3039        { "         Give a new <int> > "+string(max)+" that bounds the range of coefficients:";
3040          answer=read("");
3041          for (j=1;j<=size(answer)-1;j++)
3042          { for (k=0;k<=9;k++)
3043            { if (answer[j]==string(k))
3044              { break;
3045              }
3046            }
3047            if (k>9)
3048            { flag=1;
3049              break;
3050            }
3051            flag=0;
3052          }
3053          if (not(flag))
3054          { execute("test_dim="+string(answer[1..size(answer)]));
3055            if (test_dim<=max)
3056            { flag=1;
3057            }
3058            else
3059            { max=test_dim;
3060            }
3061          }
3062        }
3063      }
3064    }
3065  }
3066  if (not(flag))
3067  { P[(i+1)..(i+dif)]=test_matrix[1,1..dif];
3068  }
3069  return(P,CI,dB);
3070}
3071
3072///////////////////////////////////////////////////////////////////////////////
3073// This procedure finds at most dif primary invariants in degree d. It returns
3074// all primary invariants found so far. The coefficients lie in the field of
3075// characteristic p>0.
3076///////////////////////////////////////////////////////////////////////////////
3077proc p_search_random (int n,int d,ideal B,int cd,ideal P,int i,int dif,int dB,ideal CI,int max)
3078{ string answer;
3079  degBound=0;
3080  int j,k,test_dim,flag;
3081  matrix test_matrix[1][dif];          // the linear combination to test
3082  intvec h;                            // Hilbert series
3083  ideal TEST;
3084  while (dif>0)
3085  { for (j=i+1;j<=i+dif;j++)
3086    { CI=CI+ideal(var(j)^d);           // homogeneous polynomial of the same
3087                                       // degree as the one we're looking for
3088                                       // is added
3089    }
3090    // h=hilb(std(CI),1);
3091    dB=dB+dif*(d-1);                   // used as degBound
3092    test_matrix=matrix(B)*random(max,cd,dif);
3093    // degBound=dB;
3094    TEST=P+ideal(test_matrix);
3095    attrib(TEST,"isSB",1);
3096    test_dim=dim(TEST);
3097    // degBound=0;
3098    if (n-test_dim==i+dif)
3099    { break;
3100    }
3101    // degBound=dB;
3102    test_dim=dim(std(TEST));
3103    // test_dim=dim(std(TEST,h));         // Hilbert driven std-calculation
3104    // degBound=0;
3105    if (n-test_dim==i+dif)
3106    { break;
3107    }
3108    else
3109    { "HELP:    The "+string(dif)+" random combination(s) of the "+string(cd)+" basis elements with";
3110      "         coefficients in the range from -"+string(max)+" to "+string(max)+" did not lower the";
3111      "         dimension by "+string(dif)+". You can abort, try again, lower the number of";
3112      "         combinations searched for by 1 or give a larger coefficient range:";
3113      answer="";
3114      while (answer<>"n
3115" && answer<>"y
3116")
3117      { "         Do you want to abort (y/n)?";
3118        answer=read("");
3119      }
3120      if (answer=="y
3121")
3122      { flag=1;
3123        break;
3124      }
3125      answer="";
3126      while (answer<>"n
3127" && answer<>"y
3128")
3129      { "         Do you want to try again (y/n)?";
3130        answer=read("");
3131      }
3132      if (answer=="n
3133")
3134      { answer="";
3135        while (answer<>"n
3136" && answer<>"y
3137")
3138        { "         Do you want to lower the number of combinations by 1 (y/n)?";
3139          answer=read("");
3140        }
3141        if (answer=="y
3142")
3143        { dif=dif-1;
3144        }
3145        else
3146        { flag=1;
3147          while (flag)
3148          { "         Give a new <int> > "+string(max)+" that bounds the range of coefficients:";
3149            answer=read("");
3150            for (j=1;j<=size(answer)-1;j++)
3151            { for (k=0;k<=9;k++)
3152              { if (answer[j]==string(k))
3153                { break;
3154                }
3155              }
3156              if (k>9)
3157              { flag=1;
3158                break;
3159              }
3160              flag=0;
3161            }
3162            if (not(flag))
3163            { execute("test_dim="+string(answer[1..size(answer)]));
3164              if (test_dim<=max)
3165              { flag=1;
3166              }
3167              else
3168              { max=test_dim;
3169              }
3170            }
3171          }
3172        }
3173      }
3174    }
3175    CI=CI[1..i];
3176    dB=dB-dif*(d-1);
3177  }
3178  if (dif && not(flag))
3179  { P[(i+1)..(i+dif)]=test_matrix[1,1..dif];
3180  }
3181  if (dif && flag)
3182  { P[n+1]=0;
3183  }
3184  return(P,CI,dB);
3185}
3186///////////////////////////////////////////////////////////////////////////////
3187
3188proc primary_char0_random (matrix REY,matrix M,int max,list #)
3189"USAGE:   primary_char0_random(REY,M,r[,v]);
3190         REY: a <matrix> representing the Reynolds operator, M: a 1x2 <matrix>
3191         representing the Molien series, r: an <int> where -|r| to |r| is the
3192         range of coefficients of the random combinations of bases elements,
3193         v: an optional <int>
3194ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
3195         M the one of molien or the second one of reynolds_molien
3196DISPLAY: information about the various stages of the programme if v does not
3197         equal 0
3198RETURN:  primary invariants (type <matrix>) of the invariant ring
3199THEORY:  Bases of homogeneous invariants are generated successively and random
3200         linear combinations are chosen as primary invariants that lower the
3201         dimension of the ideal generated by the previously found invariants
3202         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3203         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3204EXAMPLE: example primary_char0_random; shows an example
3205"
3206{ degBound=0;
3207  if (char(basering)<>0)
3208  { "ERROR:   primary_char0_random should only be used with rings of";
3209    "         characteristic 0.";
3210    return();
3211  }
3212 //----------------- checking input and setting verbose mode ------------------
3213  if (size(#)>1)
3214  { "ERROR:   primary_char0_random can only have four parameters.";
3215    return();
3216  }
3217  if (size(#)==1)
3218  { if (typeof(#[1])<>"int")
3219    { "ERROR:   The fourth parameter should be of type <int>.";
3220      return();
3221    }
3222    else
3223    { int v=#[1];
3224    }
3225  }
3226  else
3227  { int v=0;
3228  }
3229  int n=nvars(basering);               // n is the number of variables, as well
3230                                       // as the size of the matrices, as well
3231                                       // as the number of primary invariants,
3232                                       // we should get
3233  if (ncols(REY)<>n)
3234  { "ERROR:   First parameter ought to be the Reynolds operator."
3235    return();
3236  }
3237  if (ncols(M)<>2 or nrows(M)<>1)
3238  { "ERROR:   Second parameter ought to be the Molien series."
3239    return();
3240  }
3241 //----------------------------------------------------------------------------
3242  if (v && voice<>2)
3243  { "  We can start looking for primary invariants...";
3244    "";
3245  }
3246  if (v && voice==2)
3247  { "";
3248  }
3249 //------------------------- initializing variables ---------------------------
3250  int dB;
3251  poly p(1..2);                        // p(1) will be used for single terms of
3252                                       // the partial expansion, p(2) to store
3253  p(1..2)=partial_molien(M,1);         // the intermediate result -
3254  poly v1=var(1);                      // we need v1 to split off coefficients
3255                                       // in the partial expansion of M (which
3256                                       // is in terms of the first variable) -
3257  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3258                                       // space of invariants of degree d,
3259                                       // newdim: dimension the ideal generated
3260                                       // the primary invariants plus basis
3261                                       // elements, dif=n-i-newdim, i.e. the
3262                                       // number of new primary invairants that
3263                                       // should be added in this degree -
3264  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3265                                       // Pplus: P+B,CI: a complete
3266                                       // intersection with the same Hilbert
3267                                       // function as P -
3268  dB=1;                                // used as degree bound
3269  int i=0;
3270 //-------------- loop that searches for primary invariants  ------------------
3271  while(1)                             // repeat until n primary invariants are
3272  {                                    // found -
3273    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
3274    d=deg(p(1));                       // degree where we'll search -
3275    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
3276                                       // inviarants of degree d
3277    if (v)
3278    { "  Computing primary invariants in degree "+string(d)+":";
3279    }
3280    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
3281                                       // degree d
3282    if (B[1]<>0)
3283    { Pplus=P+B;
3284      newdim=dim(std(Pplus));
3285      dif=n-i-newdim;
3286    }
3287    else
3288    { dif=0;
3289    }
3290    if (dif<>0)                        // we have to find dif new primary
3291    {                                  // invariants
3292      if (cd<>dif)
3293      { P,CI,dB=search_random(n,d,B,cd,P,i,dif,dB,CI,max); // searching for
3294      }                                // dif invariants -
3295      else                             // i.e. we can take all of B
3296      { for(j=i+1;j>i+dif;j++)
3297        { CI=CI+ideal(var(j)^d);
3298        }
3299        dB=dB+dif*(d-1);
3300        P=Pplus;
3301      }
3302      if (ncols(P)==i)
3303      { "WARNING: The return value is not a set of primary invariants, but";
3304        "         polynomials qualifying as the first "+string(i)+" primary invariants.";
3305        return(matrix(P));
3306      }
3307      if (v)
3308      { for (j=1;j<=dif;j++)
3309        { "  We find: "+string(P[i+j]);
3310        }
3311      }
3312      i=i+dif;
3313      if (i==n)                        // found all primary invariants
3314      { if (v)
3315        { "";
3316          "  We found all primary invariants.";
3317          "";
3318        }
3319        return(matrix(P));
3320      }
3321    }                                  // done with degree d
3322  }
3323}
3324example
3325{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
3326         ring R=0,(x,y,z),dp;
3327         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3328         matrix REY,M=reynolds_molien(A);
3329         matrix P=primary_char0_random(REY,M,1);
3330         print(P);
3331}
3332///////////////////////////////////////////////////////////////////////////////
3333
3334proc primary_charp_random (matrix REY,string ring_name,int max,list #)
3335"USAGE:   primary_charp_random(REY,ringname,r[,v]);
3336         REY: a <matrix> representing the Reynolds operator, ringname: a
3337         <string> giving the name of a ring where the Molien series is stored,
3338         r: an <int> where -|r| to |r| is the range of coefficients of the
3339         random combinations of bases elements, v: an optional <int>
3340ASSUME:  REY is the first return value of group_reynolds or reynolds_molien and
3341         ringname gives the name of a ring of characteristic 0 that has been
3342         created by molien or reynolds_molien
3343DISPLAY: information about the various stages of the programme if v does not
3344         equal 0
3345RETURN:  primary invariants (type <matrix>) of the invariant ring
3346THEORY:  Bases of homogeneous invariants are generated successively and random
3347         linear combinations are chosen as primary invariants that lower the
3348         dimension of the ideal generated by the previously found invariants
3349         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3350         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3351EXAMPLE: example primary_charp_random; shows an example
3352"
3353{ degBound=0;
3354 // ---------------- checking input and setting verbose mode ------------------
3355  if (char(basering)==0)
3356  { "ERROR:   primary_charp_random should only be used with rings of";
3357    "         characteristic p>0.";
3358    return();
3359  }
3360  if (size(#)>1)
3361  { "ERROR:   primary_charp_random can only have four parameters.";
3362    return();
3363  }
3364  if (size(#)==1)
3365  { if (typeof(#[1])<>"int")
3366    { "ERROR:   The fourth parameter should be of type <int>.";
3367      return();
3368    }
3369    else
3370    { int v=#[1];
3371    }
3372  }
3373  else
3374  { int v=0;
3375  }
3376  def br=basering;
3377  int n=nvars(br);                     // n is the number of variables, as well
3378                                       // as the size of the matrices, as well
3379                                       // as the number of primary invariants,
3380                                       // we should get
3381  if (ncols(REY)<>n)
3382  { "ERROR:   First parameter ought to be the Reynolds operator."
3383    return();
3384  }
3385  if (typeof(`ring_name`)<>"ring")
3386  { "ERROR:   Second parameter ought to the name of a ring where the Molien";
3387    "         is stored.";
3388    return();
3389  }
3390 //----------------------------------------------------------------------------
3391  if (v && voice<>2)
3392  { "  We can start looking for primary invariants...";
3393    "";
3394  }
3395  if (v && voice==2)
3396  { "";
3397  }
3398 //----------------------- initializing variables -----------------------------
3399  int dB;
3400  setring `ring_name`;                 // the Molien series is stores here -
3401  poly p(1..2);                        // p(1) will be used for single terms of
3402                                       // the partial expansion, p(2) to store
3403  p(1..2)=partial_molien(M,1);         // the intermediate result -
3404  poly v1=var(1);                      // we need v1 to split off coefficients
3405                                       // in the partial expansion of M (which
3406                                       // is in terms of the first variable)
3407  setring br;
3408  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3409                                       // space of invariants of degree d,
3410                                       // newdim: dimension the ideal generated
3411                                       // the primary invariants plus basis
3412                                       // elements, dif=n-i-newdim, i.e. the
3413                                       // number of new primary invairants that
3414                                       // should be added in this degree -
3415  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3416                                       // Pplus: P+B, CI: a complete
3417                                       // intersection with the same Hilbert
3418                                       // function as P -
3419  dB=1;                                // used as degree bound
3420  int i=0;
3421 //---------------- loop that searches for primary invariants -----------------
3422  while(1)                             // repeat until n primary invariants are
3423  {                                    // found
3424    setring `ring_name`;
3425    p(1..2)=partial_molien(M,1,p(2));  // next term of the partial expansion -
3426    d=deg(p(1));                       // degree where we'll search -
3427    cd=int(coef(p(1),v1)[2,1]);        // dimension of the homogeneous space of
3428                                       // inviarants of degree d
3429    setring br;
3430    if (v)
3431    { "  Computing primary invariants in degree "+string(d)+":";
3432    }
3433    B=invariant_basis_reynolds(REY,d,intvec(cd,6)); // basis of invariants of
3434                                       // degree d
3435    if (B[1]<>0)
3436    { Pplus=P+B;
3437      newdim=dim(std(Pplus));
3438      dif=n-i-newdim;
3439    }
3440    else
3441    { dif=0;
3442    }
3443    if (dif<>0)                        // we have to find dif new primary
3444    {                                  // invariants
3445      if (cd<>dif)
3446      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3447      }
3448      else                             // i.e. we can take all of B
3449      { for(j=i+1;j>i+dif;j++)
3450        { CI=CI+ideal(var(j)^d);
3451        }
3452        dB=dB+dif*(d-1);
3453        P=Pplus;
3454      }
3455      if (ncols(P)==n+1)
3456      { "WARNING: The first return value is not a set of primary invariants,";
3457        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3458        return(matrix(P));
3459      }
3460      if (v)
3461      { for (j=1;j<=size(P)-i;j++)
3462        { "  We find: "+string(P[i+j]);
3463        }
3464      }
3465      i=size(P);
3466      if (i==n)                        // found all primary invariants
3467      { if (v)
3468        { "";
3469          "  We found all primary invariants.";
3470          "";
3471        }
3472        return(matrix(P));
3473      }
3474    }                                  // done with degree d
3475  }
3476}
3477example
3478{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
3479         ring R=3,(x,y,z),dp;
3480         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3481         list L=group_reynolds(A);
3482         string newring="alskdfj";
3483         molien(L[2..size(L)],newring);
3484         matrix P=primary_charp_random(L[1],newring,1);
3485         if(system("with","Namespaces")) { kill Top::`newring`; }
3486         kill `newring`;
3487         print(P);
3488}
3489///////////////////////////////////////////////////////////////////////////////
3490
3491proc primary_char0_no_molien_random (matrix REY, int max, list #)
3492"USAGE:   primary_char0_no_molien_random(REY,r[,v]);
3493         REY: a <matrix> representing the Reynolds operator, r: an <int> where
3494         -|r| to |r| is the range of coefficients of the random combinations of
3495         bases elements, v: an optional <int>
3496ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
3497DISPLAY: information about the various stages of the programme if v does not
3498         equal 0
3499RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
3500         <intvec> listing some of the degrees where no non-trivial homogeneous
3501         invariants are to be found
3502THEORY:  Bases of homogeneous invariants are generated successively and random
3503         linear combinations are chosen as primary invariants that lower the
3504         dimension of the ideal generated by the previously found invariants
3505         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3506         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3507EXAMPLE: example primary_char0_no_molien_random; shows an example
3508"
3509{ degBound=0;
3510 //-------------- checking input and setting verbose mode ---------------------
3511  if (char(basering)<>0)
3512  { "ERROR:   primary_char0_no_molien_random should only be used with rings of";
3513    "         characteristic 0.";
3514    return();
3515  }
3516  if (size(#)>1)
3517  { "ERROR:   primary_char0_no_molien_random can only have three parameters.";
3518    return();
3519  }
3520  if (size(#)==1)
3521  { if (typeof(#[1])<>"int")
3522    { "ERROR:   The third parameter should be of type <int>.";
3523      return();
3524    }
3525    else
3526    { int v=#[1];
3527    }
3528  }
3529  else
3530  { int v=0;
3531  }
3532  int n=nvars(basering);               // n is the number of variables, as well
3533                                       // as the size of the matrices, as well
3534                                       // as the number of primary invariants,
3535                                       // we should get
3536  if (ncols(REY)<>n)
3537  { "ERROR:   First parameter ought to be the Reynolds operator."
3538    return();
3539  }
3540 //----------------------------------------------------------------------------
3541  if (v && voice<>2)
3542  { "  We can start looking for primary invariants...";
3543    "";
3544  }
3545  if (v && voice==2)
3546  { "";
3547  }
3548 //----------------------- initializing variables -----------------------------
3549  int dB;
3550  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3551                                       // space of invariants of degree d,
3552                                       // newdim: dimension the ideal generated
3553                                       // the primary invariants plus basis
3554                                       // elements, dif=n-i-newdim, i.e. the
3555                                       // number of new primary invairants that
3556                                       // should be added in this degree -
3557  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3558                                       // Pplus: P+B, CI: a complete
3559                                       // intersection with the same Hilbert
3560                                       // function as P -
3561  dB=1;                                // used as degree bound -
3562  d=0;                                 // initializing
3563  int i=0;
3564  intvec deg_vector;
3565 //------------------ loop that searches for primary invariants ---------------
3566  while(1)                             // repeat until n primary invariants are
3567  {                                    // found -
3568    d++;                               // degree where we'll search
3569    if (v)
3570    { "  Computing primary invariants in degree "+string(d)+":";
3571    }
3572    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
3573                                       // degree d
3574    if (B[1]<>0)
3575    { Pplus=P+B;
3576      newdim=dim(std(Pplus));
3577      dif=n-i-newdim;
3578    }
3579    else
3580    { dif=0;
3581      deg_vector=deg_vector,d;
3582    }
3583    if (dif<>0)                        // we have to find dif new primary
3584    {                                  // invariants
3585      cd=size(B);
3586      if (cd<>dif)
3587      { P,CI,dB=search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3588      }
3589      else                             // i.e. we can take all of B
3590      { for(j=i+1;j<=i+dif;j++)
3591        { CI=CI+ideal(var(j)^d);
3592        }
3593        dB=dB+dif*(d-1);
3594        P=Pplus;
3595      }
3596      if (ncols(P)==i)
3597      { "WARNING: The first return value is not a set of primary invariants,";
3598        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3599        return(matrix(P));
3600      }
3601      if (v)
3602      { for (j=1;j<=dif;j++)
3603        { "  We find: "+string(P[i+j]);
3604        }
3605      }
3606      i=i+dif;
3607      if (i==n)                        // found all primary invariants
3608      { if (v)
3609        { "";
3610          "  We found all primary invariants.";
3611          "";
3612        }
3613        if (deg_vector==0)
3614        { return(matrix(P));
3615        }
3616        else
3617        { return(matrix(P),compress(deg_vector));
3618        }
3619      }
3620    }                                  // done with degree d
3621    else
3622    { if (v)
3623      { "  None here...";
3624      }
3625    }
3626  }
3627}
3628example
3629{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
3630         ring R=0,(x,y,z),dp;
3631         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3632         list L=group_reynolds(A);
3633         list l=primary_char0_no_molien_random(L[1],1);
3634         print(l[1]);
3635}
3636///////////////////////////////////////////////////////////////////////////////
3637
3638proc primary_charp_no_molien_random (matrix REY, int max, list #)
3639"USAGE:   primary_charp_no_molien_random(REY,r[,v]);
3640         REY: a <matrix> representing the Reynolds operator, r: an <int> where
3641         -|r| to |r| is the range of coefficients of the random combinations of
3642         bases elements, v: an optional <int>
3643ASSUME:  REY is the first return value of group_reynolds or reynolds_molien
3644DISPLAY: information about the various stages of the programme if v does not
3645         equal 0
3646RETURN:  primary invariants (type <matrix>) of the invariant ring  and an
3647         <intvec> listing some of the degrees where no non-trivial homogeneous
3648         invariants are to be found
3649THEORY:  Bases of homogeneous invariants are generated successively and random
3650         linear combinations are chosen as primary invariants that lower the
3651         dimension of the ideal generated by the previously found invariants
3652         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3653         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3654EXAMPLE: example primary_charp_no_molien_random; shows an example
3655"
3656{ degBound=0;
3657 //----------------- checking input and setting verbose mode ------------------
3658  if (char(basering)==0)
3659  { "ERROR:   primary_charp_no_molien_random should only be used with rings of";
3660    "         characteristic p>0.";
3661    return();
3662  }
3663  if (size(#)>1)
3664  { "ERROR:   primary_charp_no_molien_random can only have three parameters.";
3665    return();
3666  }
3667  if (size(#)==1)
3668  { if (typeof(#[1])<>"int")
3669    { "ERROR:   The third parameter should be of type <int>.";
3670      return();
3671    }
3672    else
3673    { int v=#[1];
3674    }
3675  }
3676  else
3677  { int v=0;
3678  }
3679  int n=nvars(basering);               // n is the number of variables, as well
3680                                       // as the size of the matrices, as well
3681                                       // as the number of primary invariants,
3682                                       // we should get
3683  if (ncols(REY)<>n)
3684  { "ERROR:   First parameter ought to be the Reynolds operator."
3685    return();
3686  }
3687 //----------------------------------------------------------------------------
3688  if (v && voice<>2)
3689  { "  We can start looking for primary invariants...";
3690    "";
3691  }
3692  if (v && voice==2)
3693  { "";
3694  }
3695 //-------------------- initializing variables --------------------------------
3696  int dB;
3697  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3698                                       // space of invariants of degree d,
3699                                       // newdim: dimension the ideal generated
3700                                       // the primary invariants plus basis
3701                                       // elements, dif=n-i-newdim, i.e. the
3702                                       // number of new primary invairants that
3703                                       // should be added in this degree -
3704  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3705                                       // Pplus: P+B, CI: a complete
3706                                       // intersection with the same Hilbert
3707                                       // function as P -
3708  dB=1;                                // used as degree bound -
3709  d=0;                                 // initializing
3710  int i=0;
3711  intvec deg_vector;
3712 //------------------ loop that searches for primary invariants ---------------
3713  while(1)                             // repeat until n primary invariants are
3714  {                                    // found -
3715    d++;                               // degree where we'll search
3716    if (v)
3717    { "  Computing primary invariants in degree "+string(d)+":";
3718    }
3719    B=invariant_basis_reynolds(REY,d,intvec(-1,6)); // basis of invariants of
3720                                       // degree d
3721    if (B[1]<>0)
3722    { Pplus=P+B;
3723      newdim=dim(std(Pplus));
3724      dif=n-i-newdim;
3725    }
3726    else
3727    { dif=0;
3728      deg_vector=deg_vector,d;
3729    }
3730    if (dif<>0)                        // we have to find dif new primary
3731    {                                  // invariants
3732      cd=size(B);
3733      if (cd<>dif)
3734      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3735      }
3736      else                             // i.e. we can take all of B
3737      { for(j=i+1;j<=i+dif;j++)
3738        { CI=CI+ideal(var(j)^d);
3739        }
3740        dB=dB+dif*(d-1);
3741        P=Pplus;
3742      }
3743      if (ncols(P)==n+1)
3744      { "WARNING: The first return value is not a set of primary invariants,";
3745        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3746        return(matrix(P));
3747      }
3748      if (v)
3749      { for (j=1;j<=size(P)-i;j++)
3750        { "  We find: "+string(P[i+j]);
3751        }
3752      }
3753      i=size(P);
3754      if (i==n)                        // found all primary invariants
3755      { if (v)
3756        { "";
3757          "  We found all primary invariants.";
3758          "";
3759        }
3760        if (deg_vector==0)
3761        { return(matrix(P));
3762        }
3763        else
3764        { return(matrix(P),compress(deg_vector));
3765        }
3766      }
3767    }                                  // done with degree d
3768    else
3769    { if (v)
3770      { "  None here...";
3771      }
3772    }
3773  }
3774}
3775example
3776{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
3777         ring R=3,(x,y,z),dp;
3778         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3779         list L=group_reynolds(A);
3780         list l=primary_charp_no_molien_random(L[1],1);
3781         print(l[1]);
3782}
3783///////////////////////////////////////////////////////////////////////////////
3784
3785proc primary_charp_without_random (list #)
3786"USAGE:   primary_charp_without_random(G1,G2,...,r[,v]);
3787         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
3788         where -|r| to |r| is the range of coefficients of the random
3789         combinations of bases elements, v: an optional <int>
3790DISPLAY: information about the various stages of the programme if v does not
3791         equal 0
3792RETURN:  primary invariants (type <matrix>) of the invariant ring
3793THEORY:  Bases of homogeneous invariants are generated successively and random
3794         linear combinations are chosen as primary invariants that lower the
3795         dimension of the ideal generated by the previously found invariants
3796         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3797         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)). No Reynolds
3798         operator or Molien series is used.
3799EXAMPLE: example primary_charp_without_random; shows an example
3800"
3801{ degBound=0;
3802 //--------------------- checking input and setting verbose mode --------------
3803  if (char(basering)==0)
3804  { "ERROR:   primary_charp_without_random should only be used with rings of";
3805    "         characteristic 0.";
3806    return();
3807  }
3808  if (size(#)<2)
3809  { "ERROR:   There are too few parameters.";
3810    return();
3811  }
3812  if (typeof(#[size(#)])=="int" && typeof(#[size(#)-1])=="int")
3813  { int v=#[size(#)];
3814    int max=#[size(#)-1];
3815    int gen_num=size(#)-2;
3816    if (gen_num==0)
3817    { "ERROR:   There are no generators of a finite matrix group given.";
3818      return();
3819    }
3820  }
3821  else
3822  { if (typeof(#[size(#)])=="int")
3823    { int max=#[size(#)];
3824      int v=0;
3825      int gen_num=size(#)-1;
3826    }
3827    else
3828    { "ERROR:   The last parameter should be an <int>.";
3829      return();
3830    }
3831  }
3832  int n=nvars(basering);               // n is the number of variables, as well
3833                                       // as the size of the matrices, as well
3834                                       // as the number of primary invariants,
3835                                       // we should get
3836  for (int i=1;i<=gen_num;i++)
3837  { if (typeof(#[i])=="matrix")
3838    { if (nrows(#[i])<>n or ncols(#[i])<>n)
3839      { "ERROR:   The number of variables of the base ring needs to be the same";
3840        "         as the dimension of the square matrices";
3841        return();
3842      }
3843    }
3844    else
3845    { "ERROR:   The first parameters should be a list of matrices";
3846      return();
3847    }
3848  }
3849 //----------------------------------------------------------------------------
3850  if (v && voice==2)
3851  { "";
3852  }
3853 //---------------------------- initializing variables ------------------------
3854  int dB;
3855  int j,d,cd,newdim,dif;               // d: current degree, cd: dimension of
3856                                       // space of invariants of degree d,
3857                                       // newdim: dimension the ideal generated
3858                                       // the primary invariants plus basis
3859                                       // elements, dif=n-i-newdim, i.e. the
3860                                       // number of new primary invairants that
3861                                       // should be added in this degree -
3862  ideal P,Pplus,CI,B;                  // P: will contain primary invariants,
3863                                       // Pplus: P+B, CI: a complete
3864                                       // intersection with the same Hilbert
3865                                       // function as P -
3866  dB=1;                                // used as degree bound -
3867  d=0;                                 // initializing
3868  i=0;
3869  intvec deg_vector;
3870 //-------------------- loop that searches for primary invariants -------------
3871  while(1)                             // repeat until n primary invariants are
3872  {                                    // found -
3873    d++;                               // degree where we'll search
3874    if (v)
3875    { "  Computing primary invariants in degree "+string(d)+":";
3876    }
3877    B=invariant_basis(d,#[1..gen_num]); // basis of invariants of degree d
3878    if (B[1]<>0)
3879    { Pplus=P+B;
3880      newdim=dim(std(Pplus));
3881      dif=n-i-newdim;
3882    }
3883    else
3884    { dif=0;
3885      deg_vector=deg_vector,d;
3886    }
3887    if (dif<>0)                        // we have to find dif new primary
3888    {                                  // invariants
3889      cd=size(B);
3890      if (cd<>dif)
3891      { P,CI,dB=p_search_random(n,d,B,cd,P,i,dif,dB,CI,max);
3892      }
3893      else                             // i.e. we can take all of B
3894      { for(j=i+1;j<=i+dif;j++)
3895        { CI=CI+ideal(var(j)^d);
3896        }
3897        dB=dB+dif*(d-1);
3898        P=Pplus;
3899      }
3900      if (ncols(P)==n+1)
3901      { "WARNING: The first return value is not a set of primary invariants,";
3902        "         but polynomials qualifying as the first "+string(i)+" primary invariants.";
3903        return(matrix(P));
3904      }
3905      if (v)
3906      { for (j=1;j<=size(P)-i;j++)
3907        { "  We find: "+string(P[i+j]);
3908        }
3909      }
3910      i=size(P);
3911      if (i==n)                        // found all primary invariants
3912      { if (v)
3913        { "";
3914          "  We found all primary invariants.";
3915          "";
3916        }
3917        return(matrix(P));
3918      }
3919    }                                  // done with degree d
3920    else
3921    { if (v)
3922      { "  None here...";
3923      }
3924    }
3925  }
3926}
3927example
3928{ "EXAMPLE:"; echo=2;
3929         ring R=2,(x,y,z),dp;
3930         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
3931         matrix P=primary_charp_without_random(A,1);
3932         print(P);
3933}
3934///////////////////////////////////////////////////////////////////////////////
3935
3936proc primary_invariants_random (list #)
3937"USAGE:   primary_invariants_random(G1,G2,...,r[,flags]);
3938         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
3939         where -|r| to |r| is the range of coefficients of the random
3940         combinations of bases elements, flags: an optional <intvec> with three
3941         entries, if the first one equals 0 (also the default), the programme
3942         attempts to compute the Molien series and Reynolds operator, if it
3943         equals 1, the programme is told that the Molien series should not be
3944         computed, if it equals -1 characteristic 0 is simulated, i.e. the
3945         Molien series is computed as if the base field were characteristic 0
3946         (the user must choose a field of large prime characteristic, e.g.
3947         32003) and if the first one is anything else, it means that the
3948         characteristic of the base field divides the group order, the second
3949         component should give the size of intervals between canceling common
3950         factors in the expansion of the Molien series, 0 (the default) means
3951         only once after generating all terms, in prime characteristic also a
3952         negative number can be given to indicate that common factors should
3953         always be canceled when the expansion is simple (the root of the
3954         extension field does not occur among the coefficients)
3955DISPLAY: information about the various stages of the programme if the third
3956         flag does not equal 0
3957RETURN:  primary invariants (type <matrix>) of the invariant ring and if
3958         computable Reynolds operator (type <matrix>) and Molien series (type
3959         <matrix>), if the first flag is 1 and we are in the non-modular case
3960         then an <intvec> is returned giving some of the degrees where no
3961         non-trivial homogeneous invariants can be found
3962THEORY:  Bases of homogeneous invariants are generated successively and random
3963         linear combinations are chosen as primary invariants that lower the
3964         dimension of the ideal generated by the previously found invariants
3965         (see \"Generating a Noetherian Normalization of the Invariant Ring of
3966         a Finite Group\" by Decker, Heydtmann, Schreyer (1998)).
3967EXAMPLE: example primary_invariants_random; shows an example
3968"
3969{
3970 // ----------------- checking input and setting flags ------------------------
3971  if (size(#)<2)
3972  { "ERROR:   There are too few parameters.";
3973    return();
3974  }
3975  int ch=char(basering);               // the algorithms depend very much on the
3976                                       // characteristic of the ground field
3977  int n=nvars(basering);               // n is the number of variables, as well
3978                                       // as the size of the matrices, as well
3979                                       // as the number of primary invariants,
3980                                       // we should get
3981  int gen_num;
3982  int mol_flag,v;
3983  if (typeof(#[size(#)])=="intvec" && typeof(#[size(#)-1])=="int")
3984  { if (size(#[size(#)])<>3)
3985    { "ERROR:   <intvec> should have three entries.";
3986      return();
3987    }
3988    gen_num=size(#)-2;
3989    mol_flag=#[size(#)][1];
3990    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
3991    { "ERROR:   the second component of <intvec> should be >=0";
3992      return();
3993    }
3994    int interval=#[size(#)][2];
3995    v=#[size(#)][3];
3996    int max=#[size(#)-1];
3997    if (gen_num==0)
3998    { "ERROR:   There are no generators of a finite matrix group given.";
3999      return();
4000    }
4001  }
4002  else
4003  { if (typeof(#[size(#)])=="int")
4004    { gen_num=size(#)-1;
4005      mol_flag=0;
4006      int interval=0;
4007      v=0;
4008      int max=#[size(#)];
4009    }
4010    else
4011    { "ERROR:   If the two last parameters are not <int> and <intvec>, the last";
4012      "         parameter should be an <int>.";
4013      return();
4014    }
4015  }
4016  for (int i=1;i<=gen_num;i++)
4017  { if (typeof(#[i])=="matrix")
4018    { if (nrows(#[i])<>n or ncols(#[i])<>n)
4019      { "ERROR:   The number of variables of the base ring needs to be the same";
4020        "         as the dimension of the square matrices";
4021        return();
4022      }
4023    }
4024    else
4025    { "ERROR:   The first parameters should be a list of matrices";
4026      return();
4027    }
4028  }
4029 //----------------------------------------------------------------------------
4030  if (mol_flag==0)
4031  { if (ch==0)
4032    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v));
4033                                       // one will contain Reynolds operator and
4034                                       // the other enumerator and denominator
4035                                       // of Molien series
4036      matrix P=primary_char0_random(REY,M,max,v);
4037      return(P,REY,M);
4038    }
4039    else
4040    { list L=group_reynolds(#[1..gen_num],v);
4041      if (L[1]<>0)                     // testing whether we are in the modular
4042      { string newring="aksldfalkdsflkj"; // case
4043        if (minpoly==0)
4044        { if (v)
4045          { "  We are dealing with the non-modular case.";
4046          }
4047          if (typeof(L[2])=="int")
4048          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
4049          }
4050          else
4051          { molien(L[2..size(L)],newring,intvec(0,interval,v));
4052          }
4053          matrix P=primary_charp_random(L[1],newring,max,v);
4054          return(P,L[1],newring);
4055        }
4056        else
4057        { if (v)
4058          { "  Since it is impossible for this programme to calculate the Molien series for";
4059            "  invariant rings over extension fields of prime characteristic, we have to";
4060            "  continue without it.";
4061            "";
4062
4063          }
4064          list l=primary_charp_no_molien_random(L[1],max,v);
4065          if (size(l)==2)
4066          { return(l[1],L[1],l[2]);
4067          }
4068          else
4069          { return(l[1],L[1]);
4070          }
4071        }
4072      }
4073      else                             // the modular case
4074      { if (v)
4075        { "  There is also no Molien series, we can make use of...";
4076          "";
4077          "  We can start looking for primary invariants...";
4078          "";
4079        }
4080        return(primary_charp_without_random(#[1..gen_num],max,v));
4081      }
4082    }
4083  }
4084  if (mol_flag==1)                     // the user wants no calculation of the
4085  { list L=group_reynolds(#[1..gen_num],v); // Molien series
4086    if (ch==0)
4087    { list l=primary_char0_no_molien_random(L[1],max,v);
4088      if (size(l)==2)
4089      { return(l[1],L[1],l[2]);
4090      }
4091      else
4092      { return(l[1],L[1]);
4093      }
4094    }
4095    else
4096    { if (L[1]<>0)                     // testing whether we are in the modular
4097      { list l=primary_charp_no_molien_random(L[1],max,v); // case
4098        if (size(l)==2)
4099        { return(l[1],L[1],l[2]);
4100        }
4101        else
4102        { return(l[1],L[1]);
4103        }
4104      }
4105      else                             // the modular case
4106      { if (v)
4107        { "  We can start looking for primary invariants...";
4108          "";
4109        }
4110        return(primary_charp_without_random(#[1..gen_num],max,v));
4111      }
4112    }
4113  }
4114  if (mol_flag==-1)
4115  { if (ch==0)
4116    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.";
4117      return();
4118    }
4119    list L=group_reynolds(#[1..gen_num],v);
4120    string newring="aksldfalkdsflkj";
4121    if (typeof(L[2])=="int")
4122    { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
4123    }
4124    else
4125    { molien(L[2..size(L)],newring,intvec(0,interval,v));
4126    }
4127    matrix P=primary_charp_random(L[1],newring,max,v);
4128    return(P,L[1],newring);
4129  }
4130  else                                 // the user specified that the
4131  { if (ch==0)                         // characteristic divides the group order
4132    { "ERROR:   The characteristic cannot divide the group order when it is 0.";
4133      return();
4134    }
4135    if (v)
4136    { "";
4137    }
4138    return(primary_charp_without_random(#[1..gen_num],max,v));
4139  }
4140}
4141example
4142{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4143         ring R=0,(x,y,z),dp;
4144         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4145         list L=primary_invariants_random(A,1);
4146         print(L[1]);
4147}
4148///////////////////////////////////////////////////////////////////////////////
4149
4150proc concat_intmat(intmat A,intmat B)
4151{ int n=nrows(A);
4152  int m1=ncols(A);
4153  int m2=ncols(B);
4154  intmat C[n][m1+m2];
4155  C[1..n,1..m1]=A[1..n,1..m1];
4156  C[1..n,m1+1..m1+m2]=B[1..n,1..m2];
4157  return(C);
4158}
4159///////////////////////////////////////////////////////////////////////////////
4160
4161proc power_products(intvec deg_vec,int d)
4162"USAGE:   power_products(dv,d);
4163         dv: an <intvec> giving the degrees of homogeneous polynomials, d: the
4164         degree of the desired power products
4165RETURN:  a size(dv)*m <intmat> where each column ought to be interpreted as
4166         containing the exponents of the corresponding polynomials. The product
4167         of the powers is then homogeneous of degree d.
4168EXAMPLE: example power_products; shows an example
4169"
4170{ ring R=0,x,dp;
4171  if (d<=0)
4172  { "ERROR:   The <int> may not be <= 0";
4173    return();
4174  }
4175  int d_neu,j,nc;
4176  int s=size(deg_vec);
4177  intmat PP[s][1];
4178  intmat TEST[s][1];
4179  for (int i=1;i<=s;i++)
4180  { if (i<0)
4181    { "ERROR:   The entries of <intvec> may not be <= 0";
4182      return();
4183    }
4184    d_neu=d-deg_vec[i];
4185    if (d_neu>0)
4186    { intmat PPd_neu=power_products(intvec(deg_vec[i..s]),d_neu);
4187      if (size(ideal(PPd_neu))<>0)
4188      { nc=ncols(PPd_neu);
4189        intmat PPd_neu_gross[s][nc];
4190        PPd_neu_gross[i..s,1..nc]=PPd_neu[1..s-i+1,1..nc];
4191        for (j=1;j<=nc;j++)
4192        { PPd_neu_gross[i,j]=PPd_neu_gross[i,j]+1;
4193        }
4194        PP=concat_intmat(PP,PPd_neu_gross);
4195        kill PPd_neu_gross;
4196      }
4197      kill PPd_neu;
4198    }
4199    if (d_neu==0)
4200    { intmat PPd_neu[s][1];
4201      PPd_neu[i,1]=1;
4202      PP=concat_intmat(PP,PPd_neu);
4203      kill PPd_neu;
4204    }
4205  }
4206  if (matrix(PP)<>matrix(TEST))
4207  { PP=compress(PP);
4208  }
4209  return(PP);
4210}
4211example
4212{ "EXAMPLE:"; echo=2;
4213         intvec dv=5,5,5,10,10;
4214         print(power_products(dv,10));
4215         print(power_products(dv,7));
4216}
4217///////////////////////////////////////////////////////////////////////////////
4218
4219proc secondary_char0 (matrix P, matrix REY, matrix M, list #)
4220"USAGE:   secondary_char0(P,REY,M[,v]);
4221         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
4222         representing the Reynolds operator, M: a 1x2 <matrix> giving numerator
4223         and denominator of the Molien series, v: an optional <int>
4224ASSUME:  n is the number of variables of the basering, g the size of the group,
4225         REY is the 1st return value of group_reynolds(), reynolds_molien() or
4226         the second one of primary_invariants(), M the return value of molien()
4227         or the second one of reynolds_molien() or the third one of
4228         primary_invariants()
4229RETURN:  secondary invariants of the invariant ring (type <matrix>) and
4230         irreducible secondary invariants (type <matrix>)
4231DISPLAY: information if v does not equal 0
4232THEORY:  The secondary invariants are calculated by finding a basis (in terms
4233         of monomials) of the basering modulo the primary invariants, mapping
4234         those to invariants with the Reynolds operator and using these images
4235         or their power products such that they are linearly independent modulo
4236         the primary invariants (see paper \"Some Algorithms in Invariant
4237         Theory of Finite Groups\" by Kemper and Steel (1997)).
4238EXAMPLE: example secondary_char0; shows an example
4239"
4240{ def br=basering;
4241  degBound=0;
4242 //----------------- checking input and setting verbose mode ------------------
4243  if (char(br)<>0)
4244  { "ERROR:   secondary_char0 should only be used with rings of characteristic 0.";
4245    return();
4246  }
4247  int i;
4248  if (size(#)>0)
4249  { if (typeof(#[size(#)])=="int")
4250    { int v=#[size(#)];
4251    }
4252    else
4253    { int v=0;
4254    }
4255  }
4256  else
4257  { int v=0;
4258  }
4259  int n=nvars(br);                     // n is the number of variables, as well
4260                                       // as the size of the matrices, as well
4261                                       // as the number of primary invariants,
4262                                       // we should get
4263  if (ncols(P)<>n)
4264  { "ERROR:   The first parameter ought to be the matrix of the primary";
4265    "         invariants."
4266    return();
4267  }
4268  if (ncols(REY)<>n)
4269  { "ERROR:   The second parameter ought to be the Reynolds operator."
4270    return();
4271  }
4272  if (ncols(M)<>2 or nrows(M)<>1)
4273  { "ERROR:   The third parameter ought to be the Molien series."
4274    return();
4275  }
4276  if (v && voice==2)
4277  { "";
4278  }
4279  int j, m, counter;
4280 //- finding the polynomial giving number and degrees of secondary invariants -
4281  poly p=1;
4282  for (j=1;j<=n;j++)                   // calculating the denominator of the
4283  { p=p*(1-var(1)^deg(P[j]));          // Hilbert series of the ring generated
4284  }                                    // by the primary invariants -
4285  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
4286  s=matrix(syz(ideal(s)));
4287  p=s[2,1];                            // the polynomial telling us where to
4288                                       // search for secondary invariants
4289  map slead=br,ideal(0);
4290  p=1/slead(p)*p;                      // smallest term of p needs to be 1
4291  if (v)
4292  { "  Polynomial telling us where to look for secondary invariants:";
4293    "   "+string(p);
4294    "";
4295  }
4296  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
4297                                       // secondary invariants, we need to find
4298                                       // of a certain degree -
4299  m=nrows(dimmat);                     // m-1 is the highest degree
4300  if (v)
4301  { "  In degree 0 we have: 1";
4302    "";
4303  }
4304 //-------------------------- initializing variables --------------------------
4305  intmat PP;
4306  poly pp;
4307  int k;
4308  intvec deg_vec;
4309  ideal sP=std(ideal(P));
4310  ideal TEST,B,IS;
4311  ideal S=1;                           // 1 is the first secondary invariant -
4312 //--------------------- generating secondary invariants ----------------------
4313  for (i=2;i<=m;i++)                   // going through dimmat -
4314  { if (int(dimmat[i,1])<>0)           // when it is == 0 we need to find 0
4315    {                                  // elements in the current degree (i-1)
4316      if (v)
4317      { "  Searching in degree "+string(i-1)+", we need to find "+string(int(dimmat[i,1]))+" invariant(s)...";
4318      }
4319      TEST=sP;
4320      counter=0;                       // we'll count up to degvec[i]
4321      if (IS[1]<>0)
4322      { PP=power_products(deg_vec,i-1); // finding power products of irreducible
4323      }                                // secondary invariants
4324      if (size(ideal(PP))<>0)
4325      { for (j=1;j<=ncols(PP);j++)     // going through all the power products
4326        { pp=1;
4327          for (k=1;k<=nrows(PP);k++)
4328          { pp=pp*IS[1,k]^PP[k,j];
4329          }
4330          if (reduce(pp,TEST)<>0)
4331          { S=S,pp;
4332            counter++;
4333            if (v)
4334            { "  We find: "+string(pp);
4335            }
4336            if (int(dimmat[i,1])<>counter)
4337            { TEST=std(TEST+ideal(NF(pp,TEST))); // should be replaced by next
4338                                                 // line soon
4339            // TEST=std(TEST,NF(pp,TEST));
4340            }
4341            else
4342            { break;
4343            }
4344          }
4345        }
4346      }
4347      if (int(dimmat[i,1])<>counter)
4348      { B=sort_of_invariant_basis(sP,REY,i-1,int(dimmat[i,1])*6); // B contains
4349                                       // images of kbase(sP,i-1) under the
4350                                       // Reynolds operator that are linearly
4351                                       // independent and that don't reduce to
4352                                       // 0 modulo sP -
4353        if (counter==0 && ncols(B)==int(dimmat[i,1])) // then we can take all of
4354        { S=S,B;                       // B
4355          IS=IS+B;
4356          if (deg_vec[1]==0)
4357          { deg_vec=i-1;
4358            if (v)
4359            { "  We find: "+string(B[1]);
4360            }
4361            for (j=2;j<=int(dimmat[i,1]);j++)
4362            { deg_vec=deg_vec,i-1;
4363              if (v)
4364              { "  We find: "+string(B[j]);
4365              }
4366            }
4367          }
4368          else
4369          { for (j=1;j<=int(dimmat[i,1]);j++)
4370            { deg_vec=deg_vec,i-1;
4371              if (v)
4372              { "  We find: "+string(B[j]);
4373              }
4374            }
4375          }
4376        }
4377        else
4378        { j=0;                         // j goes through all of B -
4379          while (int(dimmat[i,1])<>counter) // need to find dimmat[i,1]
4380          {                            // invariants that are linearly
4381                                       // independent modulo TEST
4382            j++;
4383            if (reduce(B[j],TEST)<>0)  // B[j] should be added
4384            { S=S,B[j];
4385              IS=IS+ideal(B[j]);
4386              if (deg_vec[1]==0)
4387              { deg_vec[1]=i-1;
4388              }
4389              else
4390              { deg_vec=deg_vec,i-1;
4391              }
4392              counter++;
4393              if (v)
4394              { "  We find: "+string(B[j]);
4395              }
4396              if (int(dimmat[i,1])<>counter)
4397              { TEST=std(TEST+ideal(NF(B[j],TEST))); // should be replaced by
4398                                                     // next line
4399              // TEST=std(TEST,NF(B[j],TEST));
4400              }
4401            }
4402          }
4403        }
4404      }
4405      if (v)
4406      { "";
4407      }
4408    }
4409  }
4410  if (v)
4411  { "  We're done!";
4412    "";
4413  }
4414  return(matrix(S),matrix(IS));
4415}
4416example
4417{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4418         ring R=0,(x,y,z),dp;
4419         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4420         list L=primary_invariants(A);
4421         matrix S,IS=secondary_char0(L[1..3]);
4422         print(S);
4423         print(IS);
4424}
4425///////////////////////////////////////////////////////////////////////////////
4426
4427proc secondary_charp (matrix P, matrix REY, string ring_name, list #)
4428"USAGE:   secondary_charp(P,REY,ringname[,v]);
4429         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
4430         representing the Reynolds operator, ringname: a <string> giving the
4431         name of a ring of characteristic 0 where the Molien series is stored,
4432         v: an optional <int>
4433ASSUME:  n is the number of variables of the basering, g the size of the group,
4434         REY is the 1st return value of group_reynolds(), reynolds_molien() or
4435         the second one of primary_invariants(), `ringname` is a ring of
4436         char 0 that has been created by molien() or reynolds_molien() or
4437         primary_invariants()
4438RETURN:  secondary invariants of the invariant ring (type <matrix>) and
4439         irreducible secondary invariants (type <matrix>)
4440DISPLAY: information if v does not equal 0
4441THEORY:  Secondary invariants are calculated by finding a basis (in terms of
4442         monomials) of the basering modulo primary invariants, mapping those
4443         to invariants with the Reynolds operator and using these images or
4444         their power products such that they are linearly independent modulo
4445         the primary invariants (see paper \"Some Algorithms in Invariant
4446         Theory of Finite Groups\" by Kemper and Steel (1997)).
4447EXAMPLE: example secondary_charp; shows an example
4448"
4449{ def br=basering;
4450  degBound=0;
4451 //---------------- checking input and setting verbose mode -------------------
4452  if (char(br)==0)
4453  { "ERROR:   secondary_charp should only be used with rings of characteristic p>0.";
4454    return();
4455  }
4456  int i;
4457  if (size(#)>0)
4458  { if (typeof(#[size(#)])=="int")
4459    { int v=#[size(#)];
4460    }
4461    else
4462    { int v=0;
4463    }
4464  }
4465  else
4466  { int v=0;
4467  }
4468  int n=nvars(br);                     // n is the number of variables, as well
4469                                       // as the size of the matrices, as well
4470                                       // as the number of primary invariants,
4471                                       // we should get
4472  if (ncols(P)<>n)
4473  { "ERROR:   The first parameter ought to be the matrix of the primary";
4474    "         invariants."
4475    return();
4476  }
4477  if (ncols(REY)<>n)
4478  { "ERROR:   The second parameter ought to be the Reynolds operator."
4479    return();
4480  }
4481  if (typeof(`ring_name`)<>"ring")
4482  { "ERROR:   The <string> should give the name of the ring where the Molien."
4483    "         series is stored.";
4484    return();
4485  }
4486  if (v && voice==2)
4487  { "";
4488  }
4489  int j, m, counter, d;
4490  intvec deg_dim_vec;
4491 //- finding the polynomial giving number and degrees of secondary invariants -
4492  for (j=1;j<=n;j++)
4493  { deg_dim_vec[j]=deg(P[j]);
4494  }
4495  setring `ring_name`;
4496  poly p=1;
4497  for (j=1;j<=n;j++)                   // calculating the denominator of the
4498  { p=p*(1-var(1)^deg_dim_vec[j]);     // Hilbert series of the ring generated
4499  }                                    // by the primary invariants -
4500  matrix s[1][2]=M[1,1]*p,M[1,2];      // s is used for canceling
4501  s=matrix(syz(ideal(s)));
4502  p=s[2,1];                            // the polynomial telling us where to
4503                                       // search for secondary invariants
4504  map slead=basering,ideal(0);
4505  p=1/slead(p)*p;                      // smallest term of p needs to be 1
4506  if (v)
4507  { "  Polynomial telling us where to look for secondary invariants:";
4508    "   "+string(p);
4509    "";
4510  }
4511  matrix dimmat=coeffs(p,var(1));      // dimmat will contain the number of
4512                                       // secondary invariants, we need to find
4513                                       // of a certain degree -
4514  m=nrows(dimmat);                     // m-1 is the highest degree
4515  deg_dim_vec=1;
4516  for (j=2;j<=m;j++)
4517  { deg_dim_vec=deg_dim_vec,int(dimmat[j,1]);
4518  }
4519  if (v)
4520  { "  In degree 0 we have: 1";
4521    "";
4522  }
4523 //------------------------ initializing variables ----------------------------
4524  setring br;
4525  intmat PP;
4526  poly pp;
4527  int k;
4528  intvec deg_vec;
4529  ideal sP=std(ideal(P));
4530  ideal TEST,B,IS;
4531  ideal S=1;                           // 1 is the first secondary invariant
4532 //------------------- generating secondary invariants ------------------------
4533  for (i=2;i<=m;i++)                   // going through deg_dim_vec -
4534  { if (deg_dim_vec[i]<>0)             // when it is == 0 we need to find 0
4535    {                                  // elements in the current degree (i-1)
4536      if (v)
4537      { "  Searching in degree "+string(i-1)+", we need to find "+string(deg_dim_vec[i])+" invariant(s)...";
4538      }
4539      TEST=sP;
4540      counter=0;                       // we'll count up to degvec[i]
4541      if (IS[1]<>0)
4542      { PP=power_products(deg_vec,i-1); // generating power products of
4543      }                                // irreducible secondary invariants
4544      if (size(ideal(PP))<>0)
4545      { for (j=1;j<=ncols(PP);j++)     // going through all of those
4546        { pp=1;
4547          for (k=1;k<=nrows(PP);k++)
4548          { pp=pp*IS[1,k]^PP[k,j];
4549          }
4550          if (reduce(pp,TEST)<>0)
4551          { S=S,pp;
4552            counter++;
4553            if (v)
4554            { "  We find: "+string(pp);
4555            }
4556            if (deg_dim_vec[i]<>counter)
4557            { TEST=std(TEST+ideal(NF(pp,TEST))); // should be soon replaced by
4558                                                 // next line
4559            // TEST=std(TEST,NF(pp,TEST));
4560            }
4561            else
4562            { break;
4563            }
4564          }
4565        }
4566      }
4567      if (deg_dim_vec[i]<>counter)
4568      { B=sort_of_invariant_basis(sP,REY,i-1,deg_dim_vec[i]*6); // B contains
4569                                       // images of kbase(sP,i-1) under the
4570                                       // Reynolds operator that are linearly
4571                                       // independent and that don't reduce to
4572                                       // 0 modulo sP -
4573        if (counter==0 && ncols(B)==deg_dim_vec[i]) // then we can add all of B
4574        { S=S,B;
4575          IS=IS+B;
4576          if (deg_vec[1]==0)
4577          { deg_vec=i-1;
4578            if (v)
4579            { "  We find: "+string(B[1]);
4580            }
4581            for (j=2;j<=deg_dim_vec[i];j++)
4582            { deg_vec=deg_vec,i-1;
4583              if (v)
4584              { "  We find: "+string(B[j]);
4585              }
4586            }
4587          }
4588          else
4589          { for (j=1;j<=deg_dim_vec[i];j++)
4590            { deg_vec=deg_vec,i-1;
4591              if (v)
4592              { "  We find: "+string(B[j]);
4593              }
4594            }
4595          }
4596        }
4597        else
4598        { j=0;                         // j goes through all of B -
4599          while (deg_dim_vec[i]<>counter) // need to find deg_dim_vec[i]
4600          {                            // invariants that are linearly
4601                                       // independent modulo TEST
4602            j++;
4603            if (reduce(B[j],TEST)<>0)   // B[j] should be added
4604            { S=S,B[j];
4605              IS=IS+ideal(B[j]);
4606              if (deg_vec[1]==0)
4607              { deg_vec[1]=i-1;
4608              }
4609              else
4610              { deg_vec=deg_vec,i-1;
4611              }
4612              counter++;
4613              if (v)
4614              { "  We find: "+string(B[j]);
4615              }
4616              if (deg_dim_vec[i]<>counter)
4617              { TEST=std(TEST+ideal(NF(B[j],TEST))); // should be soon replaced
4618                                                     // by next line
4619              // TEST=std(TEST,NF(B[j],TEST));
4620              }
4621            }
4622          }
4623        }
4624      }
4625      if (v)
4626      { "";
4627      }
4628    }
4629  }
4630  if (v)
4631  { "  We're done!";
4632    "";
4633  }
4634  if (ring_name=="aksldfalkdsflkj")
4635  { kill `ring_name`;
4636  }
4637  return(matrix(S),matrix(IS));
4638}
4639example
4640{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7 (changed into char 3)"; echo=2;
4641         ring R=3,(x,y,z),dp;
4642         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4643         list L=primary_invariants(A);
4644         matrix S,IS=secondary_charp(L[1..size(L)]);
4645         print(S);
4646         print(IS);
4647}
4648///////////////////////////////////////////////////////////////////////////////
4649
4650proc secondary_no_molien (matrix P, matrix REY, list #)
4651"USAGE:   secondary_no_molien(P,REY[,deg_vec,v]);
4652         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
4653         representing the Reynolds operator, deg_vec: an optional <intvec>
4654         listing some degrees where no non-trivial homogeneous invariants can
4655         be found, v: an optional <int>
4656ASSUME:  n is the number of variables of the basering, g the size of the group,
4657         REY is the 1st return value of group_reynolds(), reynolds_molien() or
4658         the second one of primary_invariants(), deg_vec is the second return
4659         value of primary_char0_no_molien(), primary_charp_no_molien(),
4660         primary_char0_no_molien_random() or primary_charp_no_molien_random()
4661RETURN:  secondary invariants of the invariant ring (type <matrix>)
4662DISPLAY: information if v does not equal 0
4663THEORY:  Secondary invariants are calculated by finding a basis (in terms of
4664         monomials) of the basering modulo primary invariants, mapping those to
4665         invariants with the Reynolds operator and using these images as
4666         candidates for secondary invariants.
4667EXAMPLE: example secondary_no_molien; shows an example
4668"
4669{ int i;
4670  degBound=0;
4671 //------------------ checking input and setting verbose ----------------------
4672  if (size(#)==1 or size(#)==2)
4673  { if (typeof(#[size(#)])=="int")
4674    { if (size(#)==2)
4675      { if (typeof(#[size(#)-1])=="intvec")
4676        { intvec deg_vec=#[size(#)-1];
4677        }
4678        else
4679        { "ERROR:   the third parameter should be an <intvec>";
4680          return();
4681        }
4682      }
4683      int v=#[size(#)];
4684    }
4685    else
4686    { if (size(#)==1)
4687      { if (typeof(#[size(#)])=="intvec")
4688        { intvec deg_vec=#[size(#)];
4689          int v=0;
4690        }
4691        else
4692        { "ERROR:   the third parameter should be an <intvec>";
4693          return();
4694        }
4695      }
4696      else
4697      { "ERROR:   wrong list of parameters";
4698        return();
4699      }
4700    }
4701  }
4702  else
4703  { if (size(#)>2)
4704    { "ERROR:   there are too many parameters";
4705      return();
4706    }
4707    int v=0;
4708  }
4709  int n=nvars(basering);               // n is the number of variables, as well
4710                                       // as the size of the matrices, as well
4711                                       // as the number of primary invariants,
4712                                       // we should get
4713  if (ncols(P)<>n)
4714  { "ERROR:   The first parameter ought to be the matrix of the primary";
4715    "         invariants."
4716    return();
4717  }
4718  if (ncols(REY)<>n)
4719  { "ERROR:   The second parameter ought to be the Reynolds operator."
4720    return();
4721  }
4722  if (v && voice==2)
4723  { "";
4724  }
4725  int j, m, d;
4726  int max=1;
4727  for (j=1;j<=n;j++)
4728  { max=max*deg(P[j]);
4729  }
4730  max=max/nrows(REY);
4731  if (v)
4732  { "  We need to find "+string(max)+" secondary invariants.";
4733    "";
4734    "  In degree 0 we have: 1";
4735    "";
4736  }
4737 //------------------------- initializing variables ---------------------------
4738  ideal sP=std(ideal(P));
4739  ideal B, TEST;
4740  ideal S=1;                           // 1 is the first secondary invariant
4741  int counter=1;
4742  i=0;
4743  if (defined(deg_vec)<>voice)
4744  { intvec deg_vec;
4745  }
4746  int k=1;
4747 //--------------------- generating secondary invariants ----------------------
4748  while (counter<>max)
4749  { i++;
4750    if (deg_vec[k]<>i)
4751    { if (v)
4752      { "  Searching in degree "+string(i)+"...";
4753      }
4754      B=sort_of_invariant_basis(sP,REY,i,max); // B contains images of
4755                                       // kbase(sP,i) under the Reynolds
4756                                       // operator that are linearly independent
4757                                       // and that don't reduce to 0 modulo sP
4758      TEST=sP;
4759      for (j=1;j<=ncols(B);j++)
4760      {                                // that are linearly independent modulo
4761                                       // TEST
4762        if (reduce(B[j],TEST)<>0)      // B[j] should be added
4763        { S=S,B[j];
4764          counter++;
4765          if (v)
4766          { "  We find: "+string(B[j]);
4767          }
4768          if (counter==max)
4769          { break;
4770          }
4771          else
4772          { if (j<>ncols(B))
4773            { TEST=std(TEST+ideal(NF(B[j],TEST))); // should soon be replaced by
4774                                                   // next line
4775            // TEST=std(TEST,NF(B[j],TEST));
4776            }
4777          }
4778        }
4779      }
4780    }
4781    else
4782    { if (size(deg_vec)==k)
4783      { k=1;
4784      }
4785      else
4786      { k++;
4787      }
4788    }
4789  }
4790  if (v)
4791  { "";
4792  }
4793  if (v)
4794  { "  We're done!";
4795    "";
4796  }
4797  return(matrix(S));
4798}
4799example
4800{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4801         ring R=0,(x,y,z),dp;
4802         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4803         list L=primary_invariants(A,intvec(1,1,0));
4804         matrix S=secondary_no_molien(L[1..3]);
4805         print(S);
4806}
4807///////////////////////////////////////////////////////////////////////////////
4808
4809proc secondary_and_irreducibles_no_molien (matrix P, matrix REY, list #)
4810"USAGE:   secondary_and_irreducibles_no_molien(P,REY[,v]);
4811         P: a 1xn <matrix> with primary invariants, REY: a gxn <matrix>
4812         representing the Reynolds operator, v: an optional <int>
4813ASSUME:  n is the number of variables of the basering, g the size of the group,
4814         REY is the 1st return value of group_reynolds(), reynolds_molien() or
4815         the second one of primary_invariants()
4816RETURN:  secondary invariants of the invariant ring (type <matrix>) and
4817         irreducible secondary invariants (type <matrix>)
4818DISPLAY: information if v does not equal 0
4819THEORY:  Secondary invariants are calculated by finding a basis (in terms of
4820         monomials) of the basering modulo primary invariants, mapping those to
4821         invariants with the Reynolds operator and using these images or their
4822         power products such that they are linearly independent modulo the
4823         primary invariants (see paper \"Some Algorithms in Invariant Theory of
4824         Finite Groups\" by Kemper and Steel (1997)).
4825EXAMPLE: example secondary_and_irreducibles_no_molien; shows an example
4826"
4827{ int i;
4828  degBound=0;
4829 //--------------------- checking input and setting verbose mode --------------
4830  if (size(#)==1 or size(#)==2)
4831  { if (typeof(#[size(#)])=="int")
4832    { if (size(#)==2)
4833      { if (typeof(#[size(#)-1])=="intvec")
4834        { intvec deg_vec=#[size(#)-1];
4835        }
4836        else
4837        { "ERROR:   the third parameter should be an <intvec>";
4838          return();
4839        }
4840      }
4841      int v=#[size(#)];
4842    }
4843    else
4844    { if (size(#)==1)
4845      { if (typeof(#[size(#)])=="intvec")
4846        { intvec deg_vec=#[size(#)];
4847          int v=0;
4848        }
4849        else
4850        { "ERROR:   the third parameter should be an <intvec>";
4851          return();
4852        }
4853      }
4854      else
4855      { "ERROR:   wrong list of parameters";
4856        return();
4857      }
4858    }
4859  }
4860  else
4861  { if (size(#)>2)
4862    { "ERROR:   there are too many parameters";
4863      return();
4864    }
4865    int v=0;
4866  }
4867  int n=nvars(basering);               // n is the number of variables, as well
4868                                       // as the size of the matrices, as well
4869                                       // as the number of primary invariants,
4870                                       // we should get
4871  if (ncols(P)<>n)
4872  { "ERROR:   The first parameter ought to be the matrix of the primary";
4873    "         invariants."
4874    return();
4875  }
4876  if (ncols(REY)<>n)
4877  { "ERROR:   The second parameter ought to be the Reynolds operator."
4878    return();
4879  }
4880  if (v && voice==2)
4881  { "";
4882  }
4883  int j, m, d;
4884  int max=1;
4885  for (j=1;j<=n;j++)
4886  { max=max*deg(P[j]);
4887  }
4888  max=max/nrows(REY);
4889  if (v)
4890  { "  We need to find "+string(max)+" secondary invariants.";
4891    "";
4892    "  In degree 0 we have: 1";
4893    "";
4894  }
4895 //------------------------ initializing variables ----------------------------
4896  intmat PP;
4897  poly pp;
4898  int k;
4899  intvec irreducible_deg_vec;
4900  ideal sP=std(ideal(P));
4901  ideal B,TEST,IS;
4902  ideal S=1;                           // 1 is the first secondary invariant
4903  int counter=1;
4904  i=0;
4905  if (defined(deg_vec)<>voice)
4906  { intvec deg_vec;
4907  }
4908  int l=1;
4909 //------------------- generating secondary invariants ------------------------
4910  while (counter<>max)
4911  { i++;
4912    if (deg_vec[l]<>i)
4913    { if (v)
4914      { "  Searching in degree "+string(i)+"...";
4915      }
4916      TEST=sP;
4917      if (IS[1]<>0)
4918      { PP=power_products(irreducible_deg_vec,i);  // generating all power
4919      }                                // products of irreducible secondary
4920                                       // invariants
4921      if (size(ideal(PP))<>0)
4922      { for (j=1;j<=ncols(PP);j++)     // going through all those power products
4923        { pp=1;
4924          for (k=1;k<=nrows(PP);k++)
4925          { pp=pp*IS[1,k]^PP[k,j];
4926          }
4927          if (reduce(pp,TEST)<>0)
4928          { S=S,pp;
4929            counter++;
4930            if (v)
4931            { "  We find: "+string(pp);
4932            }
4933            if (counter<>max)
4934            { TEST=std(TEST+ideal(NF(pp,TEST))); // should soon be replaced by
4935                                                 // next line
4936            // TEST=std(TEST,NF(pp,TEST));
4937            }
4938            else
4939            { break;
4940            }
4941          }
4942        }
4943      }
4944      if (max<>counter)
4945      { B=sort_of_invariant_basis(sP,REY,i,max); // B contains images of
4946                                       // kbase(sP,i) under the Reynolds
4947                                       // operator that are linearly independent
4948                                       // and that don't reduce to 0 modulo sP
4949        for (j=1;j<=ncols(B);j++)
4950        { if (reduce(B[j],TEST)<>0)    // B[j] should be added
4951          { S=S,B[j];
4952            IS=IS+ideal(B[j]);
4953            if (irreducible_deg_vec[1]==0)
4954            { irreducible_deg_vec[1]=i;
4955            }
4956            else
4957            { irreducible_deg_vec=irreducible_deg_vec,i;
4958            }
4959            counter++;
4960            if (v)
4961            { "  We find: "+string(B[j]);
4962            }
4963            if (counter==max)
4964            { break;
4965            }
4966            else
4967            { if (j<>ncols(B))
4968              { TEST=std(TEST+ideal(NF(B[j],TEST))); // should soon be replaced
4969                                                     // by next line
4970              // TEST=std(TEST,NF(B[j],TEST));
4971              }
4972            }
4973          }
4974        }
4975      }
4976    }
4977    else
4978    { if (size(deg_vec)==l)
4979      { l=1;
4980      }
4981      else
4982      { l++;
4983      }
4984    }
4985  }
4986  if (v)
4987  { "";
4988  }
4989  if (v)
4990  { "  We're done!";
4991    "";
4992  }
4993  return(matrix(S),matrix(IS));
4994}
4995example
4996{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
4997         ring R=0,(x,y,z),dp;
4998         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
4999         list L=primary_invariants(A,intvec(1,1,0));
5000         matrix S,IS=secondary_and_irreducibles_no_molien(L[1..2]);
5001         print(S);
5002         print(IS);
5003}
5004///////////////////////////////////////////////////////////////////////////////
5005
5006proc secondary_not_cohen_macaulay (matrix P, list #)
5007"USAGE:   secondary_not_cohen_macaulay(P,G1,G2,...[,v]);
5008         P: a 1xn <matrix> with primary invariants, G1,G2,...: nxn <matrices>
5009         generating a finite matrix group, v: an optional <int>
5010ASSUME:  n is the number of variables of the basering
5011RETURN:  secondary invariants of the invariant ring (type <matrix>)
5012DISPLAY: information if v does not equal 0
5013THEORY:  Secondary invariants are generated following \"Generating Invariant
5014         Rings of Finite Groups over Arbitrary Fields\" by Kemper (1996).
5015EXAMPLE: example secondary_not_cohen_macaulay; shows an example
5016"
5017{ int i, j;
5018  degBound=0;
5019  def br=basering;
5020  int n=nvars(br);                     // n is the number of variables, as well
5021                                       // as the size of the matrices, as well
5022                                       // as the number of primary invariants,
5023                                       // we should get -
5024  if (size(#)>0)                       // checking input and setting verbose
5025  { if (typeof(#[size(#)])=="int")
5026    { int gen_num=size(#)-1;
5027      if (gen_num==0)
5028      { "ERROR:   There are no generators of the finite matrix group given.";
5029        return();
5030      }
5031      int v=#[size(#)];
5032      for (i=1;i<=gen_num;i++)
5033      { if (typeof(#[i])<>"matrix")
5034        { "ERROR:   These parameters should be generators of the finite matrix group.";
5035          return();
5036        }
5037        if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
5038        { "ERROR:   matrices need to be square and of the same dimensions";
5039          return();
5040        }
5041      }
5042    }
5043    else
5044    { int v=0;
5045      int gen_num=size(#);
5046      for (i=1;i<=gen_num;i++)
5047      { if (typeof(#[i])<>"matrix")
5048        { "ERROR:   These parameters should be generators of the finite matrix group.";
5049          return();
5050        }
5051        if ((n<>nrows(#[i])) or (n<>ncols(#[i])))
5052        { "ERROR:   matrices need to be square and of the same dimensions";
5053          return();
5054        }
5055      }
5056    }
5057  }
5058  else
5059  { "ERROR:   There are no generators of the finite matrix group given.";
5060    return();
5061  }
5062  if (ncols(P)<>n)
5063  { "ERROR:   The first parameter ought to be the matrix of the primary";
5064    "         invariants."
5065    return();
5066  }
5067  if (v && voice==2)
5068  { "";
5069  }
5070  ring alskdfalkdsj=0,x,dp;
5071  matrix M[1][2]=1,(1-x)^n;            // we look at our primary invariants as
5072  export alskdfalkdsj;
5073  export M;
5074  setring br;                          // such of the subgroup that only
5075  matrix REY=matrix(maxideal(1));      // contains the identity, this means that
5076                                       // ch does not divide the order anymore,
5077                                       // this means that we can make use of the
5078                                       // Molien series again - M[1,1]/M[1,2] is
5079                                       // the Molien series of that group, we
5080                                       // now calculate the secondary invariants
5081                                       // of this subgroup in the usual fashion
5082                                       // where the primary invariants are the
5083                                       // ones from the bigger group
5084  if (v)
5085  { "  The procedure secondary_charp() is called to calculate secondary invariants";
5086    "  of the invariant ring of the trivial group with respect to the primary";
5087    "  invariants found previously.";
5088    "";
5089  }
5090  matrix trivialS, trivialSI=secondary_charp(P,REY,"alskdfalkdsj",v);
5091  kill trivialSI;
5092  kill alskdfalkdsj;
5093  // now we have those secondary invariants
5094  int k=ncols(trivialS);               // k is the number of the secondary
5095                                       // invariants, we just calculated
5096  if (v)
5097  { "  We calculate secondary invariants from the ones found for the trivial";
5098    "  subgroup.";
5099    "";
5100  }
5101  map f;                               // used to let generators act on
5102                                       // secondary invariants with respect to
5103                                       // the trivial group -
5104  matrix M(1)[gen_num][k];             // M(1) will contain a module
5105  ideal B;
5106  for (i=1;i<=gen_num;i++)
5107  { B=ideal(matrix(maxideal(1))*transpose(#[i])); // image of the various
5108                                       // variables under the i-th generator -
5109    f=br,B;                            // the corresponding mapping -
5110    B=f(trivialS)-trivialS;            // these relations should be 0 -
5111    M(1)[i,1..k]=B[1..k];              // we will look for the syzygies of M(1)
5112  }
5113  //intvec save_opts=option(get);
5114  //option(returnSB,redSB);
5115  //module M(2)=syz(M(1));               // nres(M(1),2)[2];
5116  //option(set,save_opts);
5117  module M(2)=nres(M(1),2)[2];
5118  int m=ncols(M(2));                   // number of generators of the module
5119                                       // M(2) -
5120  // the following steps calculates the intersection of the module M(2) with
5121  // the algebra A^k where A denote the subalgebra of the usual polynomial
5122  // ring, generated by the primary invariants
5123  string mp=string(minpoly);           // generating a ring where we can do
5124                                       // elimination
5125  execute("ring R=("+charstr(br)+"),(x(1..n),y(1..n),h),dp;");
5126  execute("minpoly=number("+mp+");");
5127  map f=br,maxideal(1);                // canonical mapping
5128  matrix M[k][m+k*n];
5129  M[1..k,1..m]=matrix(f(M(2)));        // will contain a module -
5130  matrix P=f(P);                       // primary invariants in the new ring
5131  for (i=1;i<=n;i++)
5132  { for (j=1;j<=k;j++)
5133    { M[j,m+(i-1)*k+j]=y(i)-P[1,i];
5134    }
5135  }
5136  M=elim(module(M),1,n);               // eliminating x(1..n), std-calculation
5137                                       // is done internally -
5138  M=homog(module(M),h);                // homogenize for 'minbase'
5139  M=minbase(module(M));
5140  setring br;
5141  ideal substitute=maxideal(1),ideal(P),1;
5142  f=R,substitute;                      // replacing y(1..n) by primary
5143                                       // invariants -
5144  M(2)=f(M);                           // M(2) is the new module
5145  m=ncols(M(2));
5146  matrix S[1][m];
5147  S=matrix(trivialS)*matrix(M(2));     // S now contains the secondary
5148                                       // invariants
5149  for (i=1; i<=m;i++)
5150  { S[1,i]=S[1,i]/leadcoef(S[1,i]);    // making elements nice
5151  }
5152  S=sort(ideal(S))[1];
5153  if (v)
5154  { "  These are the secondary invariants: ";
5155    for (i=1;i<=m;i++)
5156    { "   "+string(S[1,i]);
5157    }
5158    "";
5159    "  We're done!";
5160    "";
5161  }
5162  if ((v or (voice==2)) && (m>1))
5163  { "  WARNING: The invariant ring might not have a Hironaka decomposition";
5164    "           if the characteristic of the coefficient field divides the";
5165    "           group order.";
5166  }
5167  return(S);
5168}
5169example
5170{ "EXAMPLE:"; echo=2;
5171           ring R=2,(x,y,z),dp;
5172           matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5173           list L=primary_invariants(A);
5174           matrix S=secondary_not_cohen_macaulay(L[1],A);
5175           print(S);
5176}
5177///////////////////////////////////////////////////////////////////////////////
5178
5179proc invariant_ring (list #)
5180"USAGE:   invariant_ring(G1,G2,...[,flags]);
5181         G1,G2,...: <matrices> generating a finite matrix group, flags: an
5182         optional <intvec> with three entries: if the first one equals 0, the
5183         program attempts to compute the Molien series and Reynolds operator,
5184         if it equals 1, the program is told that the Molien series should not
5185         be computed, if it equals -1 characteristic 0 is simulated, i.e. the
5186         Molien series is computed as if the base field were characteristic 0
5187         (the user must choose a field of large prime characteristic, e.g.
5188         32003) and if the first one is anything else, it means that the
5189         characteristic of the base field divides the group order (i.e. it will
5190         not even be attempted to compute the Reynolds operator or Molien
5191         series), the second component should give the size of intervals
5192         between canceling common factors in the expansion of Molien series, 0
5193         (the default) means only once after generating all terms, in prime
5194         characteristic also a negative number can be given to indicate that
5195         common factors should always be canceled when the expansion is simple
5196         (the root of the extension field occurs not among the coefficients)
5197RETURN:  primary and secondary invariants (both of type <matrix>) generating
5198         the invariant ring with respect to the matrix group generated by the
5199         matrices in the input and irreducible secondary invariants (type
5200         <matrix>) if the Molien series was available
5201DISPLAY: information about the various stages of the program if the third flag
5202         does not equal 0
5203THEORY:  Bases of homogeneous invariants are generated successively and those
5204         are chosen as primary invariants that lower the dimension of the ideal
5205         generated by the previously found invariants (see \"Generating a
5206         Noetherian Normalization of the Invariant Ring of a Finite Group\" by
5207         Decker, Heydtmann, Schreyer (1998)). In the
5208         non-modular case secondary invariants are calculated by finding a
5209         basis (in terms of monomials) of the basering modulo the primary
5210         invariants, mapping to invariants with the Reynolds operator and using
5211         those or their power products such that they are linearly independent
5212         modulo the primary invariants (see \"Some Algorithms in Invariant
5213         Theory of Finite Groups\" by Kemper and Steel (1997)). In the modular
5214         case they are generated according to \"Generating Invariant Rings of
5215         Finite Groups over Arbitrary Fields\" by Kemper (1996).
5216EXAMPLE: example invariant_ring; shows an example
5217"
5218{ if (size(#)==0)
5219  { "ERROR:   There are no generators given.";
5220    return();
5221  }
5222  int ch=char(basering);               // the algorithms depend very much on the
5223                                       // characteristic of the ground field -
5224  int n=nvars(basering);               // n is the number of variables, as well
5225                                       // as the size of the matrices, as well
5226                                       // as the number of primary invariants,
5227                                       // we should get
5228  int gen_num;
5229  int mol_flag, v;
5230 //------------------- checking input and setting flags -----------------------
5231  if (typeof(#[size(#)])=="intvec")
5232  { if (size(#[size(#)])<>3)
5233    { "ERROR:   The <intvec> should have three entries.";
5234      return();
5235    }
5236    gen_num=size(#)-1;
5237    mol_flag=#[size(#)][1];
5238    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
5239    { "ERROR:   the second component of <intvec> should be >=0";
5240      return();
5241    }
5242    int interval=#[size(#)][2];
5243    v=#[size(#)][3];
5244  }
5245  else
5246  { gen_num=size(#);
5247    mol_flag=0;
5248    int interval=0;
5249    v=0;
5250  }
5251 //----------------------------------------------------------------------------
5252  if (mol_flag==0)                     // calculation Molien series will be
5253  { if (ch==0)                         // attempted -
5254    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v)); // one
5255                                       // will contain Reynolds operator and the
5256                                       // other enumerator and denominator of
5257                                       // Molien series
5258      matrix P=primary_char0(REY,M,v);
5259      matrix S,IS=secondary_char0(P,REY,M,v);
5260      return(P,S,IS);
5261    }
5262    else
5263    { list L=group_reynolds(#[1..gen_num],v);
5264      if (L[1]<>0)                     // testing whether we are in the modular
5265      { string newring="aksldfalkdsflkj"; // case
5266        if (minpoly==0)
5267        { if (v)
5268          { "  We are dealing with the non-modular case.";
5269          }
5270          if (typeof(L[2])=="int")
5271          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
5272          }
5273          else
5274          { molien(L[2..size(L)],newring,intvec(0,interval,v));
5275          }
5276          matrix P=primary_charp(L[1],newring,v);
5277          matrix S,IS=secondary_charp(P,L[1],newring,v);
5278          if (defined(aksldfalkdsflkj)==2)
5279          { kill aksldfalkdsflkj;
5280          }
5281          return(P,S,IS);
5282        }
5283        else
5284        { if (v)
5285          { "  Since it is impossible for this programme to calculate the Molien
5286 series for";
5287            "  invariant rings over extension fields of prime characteristic, we
5288 have to";
5289            "  continue without it.";
5290            "";
5291
5292          }
5293          list l=primary_charp_no_molien(L[1],v);
5294          if (size(l)==2)
5295          { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5296          }
5297          else
5298          { matrix S=secondary_no_molien(l[1],L[1],v);
5299          }
5300          return(l[1],S);
5301        }
5302      }
5303      else                             // the modular case
5304      { if (v)
5305        { "  There is also no Molien series or Reynolds operator, we can make use of...";
5306          "";
5307          "  We can start looking for primary invariants...";
5308          "";
5309        }
5310        matrix P=primary_charp_without(#[1..gen_num],v);
5311        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5312        return(P,S);
5313      }
5314    }
5315  }
5316  if (mol_flag==1)                     // the user wants no calculation of the
5317  { list L=group_reynolds(#[1..gen_num],v); // Molien series
5318    if (ch==0)
5319    { list l=primary_char0_no_molien(L[1],v);
5320      if (size(l)==2)
5321      { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5322      }
5323      else
5324      { matrix S=secondary_no_molien(l[1],L[1],v);
5325      }
5326      return(l[1],S);
5327    }
5328    else
5329    { if (L[1]<>0)                     // testing whether we are in the modular
5330      { list l=primary_charp_no_molien(L[1],v); // case
5331        if (size(l)==2)
5332        { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5333        }
5334        else
5335        { matrix S=secondary_no_molien(l[1],L[1],v);
5336        }
5337        return(l[1],S);
5338      }
5339      else                             // the modular case
5340      { if (v)
5341        { "  We can start looking for primary invariants...";
5342          "";
5343        }
5344        matrix P=primary_charp_without(#[1..gen_num],v);
5345        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5346        return(L[1],S);
5347      }
5348    }
5349  }
5350  if (mol_flag==-1)
5351  { if (ch==0)
5352    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.
5353";
5354      return();
5355    }
5356    list L=group_reynolds(#[1..gen_num],v);
5357    string newring="aksldfalkdsflkj";
5358    if (typeof(L[2])=="int")
5359    { molien(L[3..size(L)],newring,L[2],intvec(1,interval,v));
5360    }
5361    else
5362    { molien(L[2..size(L)],newring,intvec(1,interval,v));
5363    }
5364    matrix P=primary_charp(L[1],newring,v);
5365    matrix S,IS=secondary_charp(P,L[1],newring,v);
5366    kill aksldfalkdsflkj;
5367    return(P,S,IS);
5368  }
5369  else                                 // the user specified that the
5370  { if (ch==0)                         // characteristic divides the group order
5371    { "ERROR:   The characteristic cannot divide the group order when it is 0.
5372";
5373      return();
5374    }
5375    if (v)
5376    { "";
5377    }
5378    matrix P=primary_charp_without(#[1..gen_num],v);
5379    matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5380    return(L[1],S);
5381  }
5382}
5383example
5384{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5385         ring R=0,(x,y,z),dp;
5386         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5387         matrix P,S,IS=invariant_ring(A);
5388         print(P);
5389         print(S);
5390         print(IS);
5391}
5392///////////////////////////////////////////////////////////////////////////////
5393
5394proc invariant_ring_random (list #)
5395"USAGE:   invariant_ring_random(G1,G2,...,r[,flags]);
5396         G1,G2,...: <matrices> generating a finite matrix group, r: an <int>
5397         where -|r| to |r| is the range of coefficients of random
5398         combinations of bases elements that serve as primary invariants,
5399         flags: an optional <intvec> with three entries: if the first equals 0,
5400         the program attempts to compute the Molien series and Reynolds
5401         operator, if it equals 1, the program is told that the Molien series
5402         should not be computed, if it equals -1 characteristic 0 is simulated,
5403         i.e. the Molien series is computed as if the base field were
5404         characteristic 0 (the user must choose a field of large prime
5405         characteristic, e.g.  32003) and if the first one is anything else,
5406         then the characteristic of the base field divides the group order
5407         (i.e. we will not even attempt to compute the Reynolds operator or
5408         Molien series), the second component should give the size of intervals
5409         between canceling common factors in the expansion of the Molien
5410         series, 0 (the default) means only once after generating all terms,
5411         in prime characteristic also a negative number can be given to
5412         indicate that common factors should always be canceled when the
5413         expansion is simple (the root of the extension field does not occur
5414         among the coefficients)
5415RETURN:  primary and secondary invariants (both of type <matrix>) generating
5416         invariant ring with respect to the matrix group generated by the
5417         matrices in the input and irreducible secondary invariants (type
5418         <matrix>) if the Molien series was available
5419DISPLAY: information about the various stages of the program if the third flag
5420         does not equal 0
5421THEORY:  is the same as for invariant_ring except that random combinations of
5422         basis elements are chosen as candidates for primary invariants and
5423         hopefully they lower the dimension of the previously found primary
5424         invariants by the right amount.
5425EXAMPLE: example invariant_ring_random; shows an example
5426"
5427{ if (size(#)<2)
5428  { "ERROR:   There are too few parameters.";
5429    return();
5430  }
5431  int ch=char(basering);               // the algorithms depend very much on the
5432                                       // characteristic of the ground field
5433  int n=nvars(basering);               // n is the number of variables, as well
5434                                       // as the size of the matrices, as well
5435                                       // as the number of primary invariants,
5436                                       // we should get
5437  int gen_num;
5438  int mol_flag, v;
5439 //------------------- checking input and setting flags -----------------------
5440  if (typeof(#[size(#)])=="intvec" && typeof(#[size(#)-1])=="int")
5441  { if (size(#[size(#)])<>3)
5442    { "ERROR:   <intvec> should have three entries.";
5443      return();
5444    }
5445    gen_num=size(#)-2;
5446    mol_flag=#[size(#)][1];
5447    if (#[size(#)][2]<0 && (ch==0 or (ch<>0 && mol_flag<>0)))
5448    { "ERROR:   the second component of <intvec> should be >=0";
5449      return();
5450    }
5451    int interval=#[size(#)][2];
5452    v=#[size(#)][3];
5453    int max=#[size(#)-1];
5454    if (gen_num==0)
5455    { "ERROR:   There are no generators of a finite matrix group given.";
5456      return();
5457    }
5458  }
5459  else
5460  { if (typeof(#[size(#)])=="int")
5461    { gen_num=size(#)-1;
5462      mol_flag=0;
5463      int interval=0;
5464      v=0;
5465      int max=#[size(#)];
5466    }
5467   else
5468    { "ERROR:   If the two last parameters are not <int> and <intvec>, the last";
5469      "         parameter should be an <int>.";
5470      return();
5471    }
5472  }
5473  for (int i=1;i<=gen_num;i++)
5474  { if (typeof(#[i])=="matrix")
5475    { if (nrows(#[i])<>n or ncols(#[i])<>n)
5476      { "ERROR:   The number of variables of the base ring needs to be the same";
5477        "         as the dimension of the square matrices";
5478        return();
5479      }
5480    }
5481    else
5482    { "ERROR:   The first parameters should be a list of matrices";
5483      return();
5484    }
5485  }
5486 //----------------------------------------------------------------------------
5487  if (mol_flag==0)
5488  { if (ch==0)
5489    { matrix REY,M=reynolds_molien(#[1..gen_num],intvec(0,interval,v)); // one
5490                                       // will contain Reynolds operator and the
5491                                       // other enumerator and denominator of
5492                                       // Molien series
5493      matrix P=primary_char0_random(REY,M,max,v);
5494      matrix S,IS=secondary_char0(P,REY,M,v);
5495      return(P,S,IS);
5496    }
5497    else
5498    { list L=group_reynolds(#[1..gen_num],v);
5499      if (L[1]<>0)                     // testing whether we are in the modular
5500      { string newring="aksldfalkdsflkj"; // case
5501        if (minpoly==0)
5502        { if (v)
5503          { "  We are dealing with the non-modular case.";
5504          }
5505          if (typeof(L[2])=="int")
5506          { molien(L[3..size(L)],newring,L[2],intvec(0,interval,v));
5507          }
5508          else
5509          { molien(L[2..size(L)],newring,intvec(0,interval,v));
5510          }
5511          matrix P=primary_charp_random(L[1],newring,max,v);
5512          matrix S,IS=secondary_charp(P,L[1],newring,v);
5513          if (voice==2)
5514          { kill aksldfalkdsflkj;
5515          }
5516          return(P,S,IS);
5517        }
5518        else
5519        { if (v)
5520          { "  Since it is impossible for this programme to calculate the Molien
5521 series for";
5522            "  invariant rings over extension fields of prime characteristic, we
5523 have to";
5524            "  continue without it.";
5525            "";
5526
5527          }
5528          list l=primary_charp_no_molien_random(L[1],max,v);
5529          if (size(l)==2)
5530          { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5531          }
5532          else
5533          { matrix S=secondary_no_molien(l[1],L[1],v);
5534          }
5535          return(l[1],S);
5536        }
5537      }
5538      else                             // the modular case
5539      { if (v)
5540        { "  There is also no Molien series, we can make use of...";
5541          "";
5542          "  We can start looking for primary invariants...";
5543          "";
5544        }
5545        matrix P=primary_charp_without_random(#[1..gen_num],max,v);
5546        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5547        return(P,S);
5548      }
5549    }
5550  }
5551  if (mol_flag==1)                     // the user wants no calculation of the
5552  { list L=group_reynolds(#[1..gen_num],v); // Molien series
5553    if (ch==0)
5554    { list l=primary_char0_no_molien_random(L[1],max,v);
5555      if (size(l)==2)
5556      { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5557      }
5558      else
5559      { matrix S=secondary_no_molien(l[1],L[1],v);
5560      }
5561      return(l[1],S);
5562    }
5563    else
5564    { if (L[1]<>0)                     // testing whether we are in the modular
5565      { list l=primary_charp_no_molien_random(L[1],max,v); // case
5566        if (size(l)==2)
5567        { matrix S=secondary_no_molien(l[1],L[1],l[2],v);
5568        }
5569        else
5570        { matrix S=secondary_no_molien(l[1],L[1],v);
5571        }
5572        return(l[1],S);
5573      }
5574      else                             // the modular case
5575      { if (v)
5576        { "  We can start looking for primary invariants...";
5577          "";
5578        }
5579        matrix P=primary_charp_without_random(#[1..gen_num],max,v);
5580        matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5581        return(L[1],S);
5582      }
5583    }
5584  }
5585  if (mol_flag==-1)
5586  { if (ch==0)
5587    { "ERROR:   Characteristic 0 can only be simulated in characteristic p>>0.
5588";
5589      return();
5590    }
5591    list L=group_reynolds(#[1..gen_num],v);
5592    string newring="aksldfalkdsflkj";
5593    if (typeof(L[2])=="int")
5594    { molien(L[3..size(L)],newring,L[2],intvec(mol_flag,interval,v));
5595    }
5596    else
5597    { molien(L[2..size(L)],newring,intvec(mol_flag,interval,v));
5598    }
5599    matrix P=primary_charp_random(L[1],newring,max,v);
5600    matrix S,IS=secondary_charp(P,L[1],newring,v);
5601    kill aksldfalkdsflkj;
5602    return(P,S,IS);
5603  }
5604  else                                 // the user specified that the
5605  { if (ch==0)                         // characteristic divides the group order
5606    { "ERROR:   The characteristic cannot divide the group order when it is 0.
5607";
5608      return();
5609    }
5610    if (v)
5611    { "";
5612    }
5613    matrix P=primary_charp_without_random(#[1..gen_num],max,v);
5614    matrix S=secondary_not_cohen_macaulay(P,#[1..gen_num],v);
5615    return(L[1],S);
5616  }
5617}
5618example
5619{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5620         ring R=0,(x,y,z),dp;
5621         matrix A[3][3]=0,1,0,-1,0,0,0,0,-1;
5622         matrix P,S,IS=invariant_ring_random(A,1);
5623         print(P);
5624         print(S);
5625         print(IS);
5626}
5627///////////////////////////////////////////////////////////////////////////////
5628
5629proc orbit_variety (matrix F,string newring)
5630"USAGE:   orbit_variety(F,s);
5631         F: a 1xm <matrix> defing an invariant ring, s: a <string> giving the
5632         name for a new ring
5633RETURN:  a Groebner basis (type <ideal>, named G) for the ideal defining the
5634         orbit variety (i.e. the syzygy ideal) in the new ring (named `s`)
5635THEORY:  The ideal of algebraic relations of the invariant ring generators is
5636         calculated, then the variables of the original ring are eliminated and
5637         the polynomials that are left over define the orbit variety
5638EXAMPLE: example orbit_variety; shows an example
5639"
5640{ if (newring=="")
5641  { "ERROR:   the second parameter may not be an empty <string>";
5642    return();
5643  }
5644  if (nrows(F)==1)
5645  { def br=basering;
5646    int n=nvars(br);
5647    int m=ncols(F);
5648    string mp=string(minpoly);
5649    execute("ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),dp;");
5650    execute("minpoly=number("+mp+");");
5651    ideal I=ideal(imap(br,F));
5652    for (int i=1;i<=m;i++)
5653    { I[i]=I[i]-y(i);
5654    }
5655    I=elim(I,1,n);
5656    execute("ring "+newring+"=("+charstr(br)+"),(y(1..m)),dp(m);");
5657    execute("minpoly=number("+mp+");");
5658    ideal vars;
5659    for (i=2;i<=n;i++)
5660    { vars[i]=0;
5661    }
5662    vars=vars,y(1..m);
5663    map emb=R,vars;
5664    ideal G=emb(I);
5665    kill emb, vars, R;
5666    keepring `newring`;
5667    return();
5668  }
5669  else
5670  { "ERROR:   the <matrix> may only have one row";
5671    return();
5672  }
5673}
5674example
5675{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.3.7:"; echo=2;
5676         ring R=0,(x,y,z),dp;
5677         matrix F[1][7]=x2+y2,z2,x4+y4,1,x2z-1y2z,xyz,x3y-1xy3;
5678         string newring="E";
5679         orbit_variety(F,newring);
5680         print(G);
5681         basering;
5682}
5683///////////////////////////////////////////////////////////////////////////////
5684
5685proc relative_orbit_variety(ideal I,matrix F,string newring)
5686"USAGE:   relative_orbit_variety(I,F,s);
5687         I: an <ideal> invariant under the action of a group, F: a 1xm
5688         <matrix> defining the invariant ring of this group, s: a <string>
5689         giving a name for a new ring
5690RETURN:  a Groebner basis (type <ideal>, named G) for the ideal defining the
5691         relative orbit variety with respect to I in the new ring (named s)
5692THEORY:  A Groebner basis of the ideal of algebraic relations of the invariant
5693         ring generators is calculated, then one of the basis elements plus the
5694         ideal generators. The variables of the original ring are eliminated
5695         and the polynomials that are left define the relative orbit variety
5696         with respect to I.
5697EXAMPLE: example relative_orbit_variety; shows an example
5698"
5699{ if (newring=="")
5700  { "ERROR:   the third parameter may not be empty a <string>";
5701    return();
5702  }
5703  degBound=0;
5704  if (nrows(F)==1)
5705  { def br=basering;
5706    int n=nvars(br);
5707    int m=ncols(F);
5708    string mp=string(minpoly);
5709    execute("ring R=("+charstr(br)+"),("+varstr(br)+",y(1..m)),lp;");
5710    execute("minpoly=number("+mp+");");
5711    ideal J=ideal(imap(br,F));
5712    ideal I=imap(br,I);
5713    for (int i=1;i<=m;i++)
5714    { J[i]=J[i]-y(i);
5715    }
5716    J=std(J);
5717    J=J,I;
5718    option(redSB);
5719    J=std(J);
5720    ideal vars;
5721    //for (i=1;i<=n;i=i+1)
5722    //{ vars[i]=0;
5723    //}
5724    vars[n]=0;
5725    vars=vars,y(1..m);
5726    map emb=R,vars;
5727    ideal G=emb(J);
5728    J=J-G;
5729    for (i=1;i<=ncols(G);i++)
5730    { if (J[i]<>0)
5731      { G[i]=0;
5732      }
5733    }
5734    G=compress(G);
5735    execute("ring "+newring+"=("+charstr(br)+"),(y(1..m)),lp;");
5736    execute("minpoly=number("+mp+");");
5737    ideal vars;
5738    for (i=2;i<=n;i++)
5739    { vars[i]=0;
5740    }
5741    vars=vars,y(1..m);
5742    map emb=R,vars;
5743    ideal G=emb(G);
5744    kill vars, emb;
5745    keepring `newring`;
5746    return();
5747  }
5748  else
5749  { "ERROR:   the <matrix> may only have one row";
5750    return();
5751  }
5752}
5753example
5754{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.3:"; echo=2;
5755         ring R=0,(x,y,z),dp;
5756         matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
5757         ideal I=x2+y2+z2-1,x2y+y2z+z2x-2x-2y-2z,xy2+yz2+zx2-2x-2y-2z;
5758         string newring="E";
5759         relative_orbit_variety(I,F,newring);
5760         print(G);
5761         basering;
5762}
5763///////////////////////////////////////////////////////////////////////////////
5764
5765proc image_of_variety(ideal I,matrix F)
5766"USAGE:   image_of_variety(I,F);
5767         I: an arbitray <ideal>, F: a 1xm <matrix> defining an invariant ring
5768         of a some matrix group
5769RETURN:  the <ideal> defining the image under that group of the variety defined
5770         by I
5771THEORY:  relative_orbit_variety(I,F,s) is called and the newly introduced
5772         variables in the output are replaced by the generators of the
5773         invariant ring. This ideal in the original variables defines the image
5774         of the variety defined by I
5775EXAMPLE: example image_of_variety; shows an example
5776"
5777{ if (nrows(F)==1)
5778  { def br=basering;
5779    int n=nvars(br);
5780    string newring="E";
5781    relative_orbit_variety(I,F,newring);
5782    execute("ring R=("+charstr(br)+"),("+varstr(br)+","+varstr(E)+"),lp;");
5783    ideal F=imap(br,F);
5784    for (int i=1;i<=n;i++)
5785    { F=0,F;
5786    }
5787    setring br;
5788    map emb2=E,F;
5789    return(compress(emb2(G)));
5790  }
5791  else
5792  { "ERROR:   the <matrix> may only have one row";
5793    return();
5794  }
5795}
5796example
5797{ "EXAMPLE: Sturmfels: Algorithms in Invariant Theory 2.6.8:"; echo=2;
5798         ring R=0,(x,y,z),dp;
5799         matrix F[1][3]=x+y+z,xy+xz+yz,xyz;
5800         ideal I=xy;
5801         print(image_of_variety(I,F));
5802}
5803///////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.