source: git/Singular/LIB/finvar.lib @ 29aa4bf

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