source: git/Singular/LIB/finvar.lib @ 425a9d

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