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

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