source: git/Singular/LIB/finvar.lib @ 7c5f9d2

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