source: git/Singular/LIB/finvar.lib @ 4d68980

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