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