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

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