source: git/Singular/LIB/finvar.lib @ d0a341

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