1############################################################################# 2## 3## This file is part of GAP, a system for computational discrete algebra. 4## This file's authors include Thomas Breuer. 5## 6## Copyright of GAP belongs to its developers, whose names are too numerous 7## to list here. Please refer to the COPYRIGHT file for details. 8## 9## SPDX-License-Identifier: GPL-2.0-or-later 10## 11## This file contains methods for fields consisting of cyclotomics. 12## 13## Note that we must distinguish abelian number fields and fields 14## that consist of cyclotomics. 15## (The image of the natural embedding of the rational number field 16## into a field of rational functions is of course an abelian number field 17## but its elements are not cyclotomics since this would be a property given 18## by their family.) 19## 20 21 22############################################################################# 23## 24#F AbelianNumberFieldByReducedGaloisStabilizerInfo( <F>, <N>, <stab> ) 25## 26## The constructor `FieldByGenerators' calls this function. 27## Since `CyclotomicField' and `AbelianNumberField' generate first the 28## information about conductor and Galois stabilizer, it is useful for them 29## to call this function instead of constructing generators and calling 30## `FieldByGenerators', which would mean to construct <N> and <stab> again. 31## 32InstallGlobalFunction( AbelianNumberFieldByReducedGaloisStabilizerInfo, 33 function( F, N, stab ) 34 35 local D, d; 36 37 D:= Objectify( NewType( CollectionsFamily( CyclotomicsFamily ), 38 IsField 39 and IsFiniteDimensional 40 and IsAbelianNumberField 41 and IsAttributeStoringRep ), 42 rec() ); 43 44 d:= Phi(N) / Length( stab ); 45 46 SetIsCyclotomicField( D, Length( stab ) = 1 ); 47 SetLeftActingDomain( D, F ); 48 SetDegreeOverPrimeField( D, d ); 49 SetGaloisStabilizer( D, stab ); 50 SetConductor( D, N ); 51 SetIsFinite( D, false ); 52 SetSize( D, infinity ); 53 SetDimension( D, d / DegreeOverPrimeField( F ) ); 54 SetPrimeField( D, Rationals ); 55 SetIsWholeFamily( D, false ); 56 57 return D; 58end ); 59 60 61############################################################################# 62## 63#F CyclotomicField( <n> ) . . . . . . . create the <n>-th cyclotomic field 64#F CyclotomicField( <gens> ) 65#F CyclotomicField( <subfield>, <n> ) 66#F CyclotomicField( <subfield>, <gens> ) 67## 68InstallGlobalFunction( CyclotomicField, function ( arg ) 69 70 local F, subfield, xtension; 71 72 # If necessary split the arguments. 73 if Length( arg ) = 1 74 and ( ( IsInt( arg[1] ) and 0 < arg[1] ) or IsList( arg[1] ) ) then 75 76 # CF( <n> ) or CF( <gens> ) 77 subfield:= Rationals; 78 xtension:= arg[1]; 79 80 elif Length( arg ) = 2 81 and IsField( arg[1] ) 82 and ( ( IsInt( arg[2] ) and 0 < arg[2] ) or IsList( arg[2] ) ) then 83 84 # `CF( <subfield>, <n> )' or `CF( <subfield>, <gens> )' 85 subfield:= arg[1]; 86 xtension:= arg[2]; 87 88 else 89 Error("usage: CF( <n> ) or CF( <subfield>, <gens> )"); 90 fi; 91 92 # Replace generators by their conductor. 93 if not IsInt( xtension ) then 94 xtension:= Conductor( xtension ); 95 fi; 96 if xtension mod 2 = 0 and xtension mod 4 <> 0 then 97 xtension:= xtension / 2; 98 fi; 99 100 # The subfield is given by `Rationals' denoting the prime field. 101 if subfield = Rationals then 102 103 # The standard field is required. Look whether it is already stored. 104 # If not, generate it and return it 105 return CYCLOTOMIC_FIELDS( xtension ); 106 107 elif IsAbelianNumberField( subfield ) then 108 109 # CF( subfield, N ) 110 if xtension mod Conductor( subfield ) <> 0 then 111 Error( "<subfield> is not contained in CF( <xtension> )" ); 112 fi; 113 114 else 115 Error( "<subfield> must be `Rationals' or an abelian number field" ); 116 fi; 117 118 F:= AbelianNumberFieldByReducedGaloisStabilizerInfo( subfield, 119 xtension, [ 1 ] ); 120 121 # Return the field. 122 return F; 123end ); 124 125 126############################################################################# 127## 128#F ReducedStabilizerInfo( <N>, <stabilizer> ) 129## 130## is a record with components `N' and `stabilizer', 131## which are minimal with the property that they describe the same abelian 132## number field as the input parameters <N> and <stabilizer>. 133## 134BindGlobal( "ReducedGaloisStabilizerInfo", function( N, stabilizer ) 135 136 local d, 137 gens, 138 NN, 139 aut, 140 pos, 141 i, 142 p; 143 144 if N mod 2 = 0 and N mod 4 <> 0 then 145 N:= N / 2; 146 fi; 147 if N <= 2 then 148 return rec( N:= 1, stabilizer:= [ 1 ] ); 149 fi; 150 151 stabilizer:= Set( stabilizer ); 152 AddSet( stabilizer, 1 ); 153 154 # Compute the elements of the group generated by `stabilizer'. 155 for d in stabilizer do 156 UniteSet( stabilizer, List( stabilizer, x -> ( x * d ) mod N ) ); 157 od; 158 159 # reduce the pair `( N, stabilizer )' such that afterwards `N' 160 # describes the conductor of the required field; 161 162 gens:= GeneratorsPrimeResidues( N ); 163 NN:= 1; 164 if gens.primes[1] = 2 then 165 166 if gens.exponents[1] < 3 then 167 if not gens.generators[1] in stabilizer then 168 NN:= NN * 4; 169 fi; 170 171 else 172 173 # the only case where `gens.generators[i]' is a list; 174 # it contains the generators corresponding to `**' and `*5'; 175 # the first one is irrelevant for the conductor, 176 # except if also the other generator is contained. 177 if gens.generators[1][2] in stabilizer then 178 if not gens.generators[1][1] in stabilizer then 179 NN:= NN * 4; 180 fi; 181 else 182 NN:= NN * 4; 183 aut:= gens.generators[1][2]; 184 while not aut in stabilizer do 185 aut:= ( aut ^ 2 ) mod N; 186 NN:= NN * 2; 187 od; 188 fi; 189 fi; 190 pos:= 2; 191 else 192 pos:= 1; 193 fi; 194 195 for i in [ pos .. Length( gens.primes ) ] do 196 p:= gens.primes[i]; 197 if not gens.generators[i] in stabilizer then 198 NN:= NN * p; 199 aut:= ( gens.generators[i] ^ ( p - 1 ) ) mod N; 200 while not aut in stabilizer do 201 aut:= ( aut ^ p ) mod N; 202 NN:= NN * p; 203 od; 204 fi; 205 od; 206 207 N:= NN; 208 if N <= 2 then 209 stabilizer:= [ 1 ]; 210 N:= 1; 211 else 212 stabilizer:= Set( List( stabilizer, x -> x mod N ) ); 213 fi; 214 215 return rec( N:= N, stabilizer:= stabilizer ); 216end ); 217 218 219############################################################################# 220## 221#F AbelianNumberField( <N>, <stab> ) . . . . create an abelian number field 222## 223## fixed field of the group generated by <stab> (prime residues modulo <N>) 224## in the cyclotomic field with conductor <N>. 225## 226InstallGlobalFunction( AbelianNumberField, function ( N, stabilizer ) 227 228 local pos, # position in a list 229 F; # the field, result 230 231 # Check the arguments. 232 if not ( IsInt( N ) and 0 < N and IsList( stabilizer ) ) then 233 Error( "<N> must be a positive integer, <stabilizer> a list" ); 234 fi; 235 236 # Compute the conductor and the reduced stabilizer. 237 # Thus the Galois stabilizer component of the field will be minimal. 238 stabilizer := ReducedGaloisStabilizerInfo( N, stabilizer ); 239 N := stabilizer.N; 240 stabilizer := stabilizer.stabilizer; 241 242 if stabilizer = [ 1 ] then 243 return CyclotomicField( N ); 244 fi; 245 246 # The standard field is required. Look whether it is already stored. 247 atomic readonly ABELIAN_NUMBER_FIELDS do 248 if IsBound( ABELIAN_NUMBER_FIELDS[1][N] ) then 249 pos:= Position( ABELIAN_NUMBER_FIELDS[1][N], stabilizer ); 250 if pos <> fail then 251 return ABELIAN_NUMBER_FIELDS[2][N][ pos ]; 252 fi; 253 fi; 254 od; 255 256 # Construct the field. 257 F:= AbelianNumberFieldByReducedGaloisStabilizerInfo( Rationals, 258 N, stabilizer ); 259 260 # Store the field. 261 atomic readwrite ABELIAN_NUMBER_FIELDS do 262 if not IsBound( ABELIAN_NUMBER_FIELDS[1][N] ) then 263 ABELIAN_NUMBER_FIELDS[1][N]:= MigrateObj([],ABELIAN_NUMBER_FIELDS); 264 ABELIAN_NUMBER_FIELDS[2][N]:= MigrateObj([],ABELIAN_NUMBER_FIELDS); 265 fi; 266 pos:= Position( ABELIAN_NUMBER_FIELDS[1][N], stabilizer ); 267 if pos <> fail then 268 # someone else constructed it at the same time 269 # return their version 270 return ABELIAN_NUMBER_FIELDS[2][N][ pos ]; 271 fi; 272 Add( ABELIAN_NUMBER_FIELDS[1][N], MakeImmutable(stabilizer) ); 273 Add( ABELIAN_NUMBER_FIELDS[2][N], F ); 274 od; 275 # Return the number field. 276 return F; 277end ); 278 279 280############################################################################# 281## 282#M ViewObj( <F> ) . . . . . . . . . . . . . . view an abelian number field 283## 284InstallMethod( ViewObj, 285 "for abelian number field of cyclotomics", 286 [ IsAbelianNumberField and IsCyclotomicCollection ], 287 function( F ) 288 if IsPrimeField( LeftActingDomain( F ) ) then 289 Print( "NF(", Conductor( F ), ",", 290 GaloisStabilizer( F ), ")" ); 291 else 292 Print( "AsField( ", LeftActingDomain( F ), 293 ", NF(", Conductor( F ), ",", GaloisStabilizer( F ), ") )" ); 294 fi; 295 end ); 296 297InstallMethod( ViewObj, 298 "for cyclotomic field of cyclotomics", 299 [ IsCyclotomicField and IsCyclotomicCollection ], 300 function( F ) 301 if IsPrimeField( LeftActingDomain( F ) ) then 302 Print( "CF(", Conductor( F ), ")" ); 303 else 304 Print( "AsField( ", LeftActingDomain( F ), 305 ", CF(", Conductor( F ), ") )" ); 306 fi; 307 end ); 308 309 310############################################################################# 311## 312#M PrintObj( <F> ) . . . . . . . . . . . . . . print an abelian number field 313## 314InstallMethod( PrintObj, 315 "for abelian number field of cyclotomics", 316 [ IsAbelianNumberField and IsCyclotomicCollection ], 317 function( F ) 318 if IsPrimeField( LeftActingDomain( F ) ) then 319 Print( "NF(", Conductor( F ), ",", 320 GaloisStabilizer( F ), ")" ); 321 else 322 Print( "AsField( ", LeftActingDomain( F ), 323 ", NF(", Conductor( F ), ",", GaloisStabilizer( F ), ") )" ); 324 fi; 325 end ); 326 327InstallMethod( PrintObj, 328 "for cyclotomic field of cyclotomics", 329 [ IsCyclotomicField and IsCyclotomicCollection ], 330 function( F ) 331 if IsPrimeField( LeftActingDomain( F ) ) then 332 Print( "CF(", Conductor( F ), ")" ); 333 else 334 Print( "AsField( ", LeftActingDomain( F ), 335 ", CF(", Conductor( F ), ") )" ); 336 fi; 337 end ); 338 339 340############################################################################# 341## 342#M String( <F> ) . . . . . . . . . . . . . string of an abelian number field 343## 344InstallMethod( String, 345 "for abelian number field of cyclotomics", 346 [ IsAbelianNumberField and IsCyclotomicCollection ], 347 function( F ) 348 if IsPrimeField( LeftActingDomain( F ) ) then 349 return Concatenation( "NF(", String( Conductor( F ) ), ",", 350 String( GaloisStabilizer( F ) ), ")" ); 351 else 352 return Concatenation( "AsField( ", String( LeftActingDomain( F ) ), 353 ", NF(", String( Conductor( F ) ), ",", 354 String( GaloisStabilizer( F ) ), ") )" ); 355 fi; 356 end ); 357 358InstallMethod( String, 359 "for cyclotomic field of cyclotomics", 360 [ IsCyclotomicField and IsCyclotomicCollection ], 361 function( F ) 362 363 local n; 364 365 n:= Conductor( F ); 366 367 if IsPrimeField( LeftActingDomain( F ) ) then 368 if n = 1 then 369 return "Rationals"; 370 elif n = 4 then 371 return "GaussianRationals"; 372 else 373 return Concatenation( "CF(", String( n ), ")" ); 374 fi; 375 elif n = 4 then 376 return Concatenation( "AsField( ", String( LeftActingDomain( F ) ), 377 ", GaussianRationals )" ); 378 else 379 return Concatenation( "AsField( ", String( LeftActingDomain( F ) ), 380 ", CF(", String( n ), ") )" ); 381 fi; 382 end ); 383 384 385############################################################################# 386## 387#M \=( <F1>, <F2> ) . . . . . . . . . . comparison of abelian number fields 388#M \<( <F1>, <F2> ) . . . . . . . . . . comparison of abelian number fields 389## 390## <F1> is smaller than <F2> if and only if <F1> has a smaller conductor, 391## or it has the same conductor as <F2> but its Galois stabilizer component 392## is smaller. 393## 394InstallMethod( \=, 395 "for two abelian number fields", 396 IsIdenticalObj, 397 [ IsAbelianNumberField, IsAbelianNumberField ], 398 function ( F1, F2 ) 399 return Conductor( F1 ) = Conductor( F2 ) 400 and GaloisStabilizer( F1 ) = GaloisStabilizer( F2 ); 401 end ); 402 403InstallMethod( \<, 404 "for two abelian number fields", 405 IsIdenticalObj, 406 [ IsAbelianNumberField, IsAbelianNumberField ], 407 function ( F1, F2 ) 408 return Conductor( F1 ) < Conductor( F2 ) 409 or ( Conductor( F1 ) = Conductor( F2 ) 410 and GaloisStabilizer( F1 ) < GaloisStabilizer( F2 ) ); 411 end ); 412 413 414############################################################################# 415## 416#M \in( <z>, <F> ) . . . . test if <z> lies in the abelian number field <F> 417## 418## check whether <z> is a cyclotomic with conductor contained in the 419## conductor of <F>, and that <z> is fixed by `GaloisStabilizer( <F> )'. 420## 421InstallMethod( \in, 422 "for cyclotomic and abelian number field", 423 IsElmsColls, 424 [ IsCyc, IsAbelianNumberField and IsCyclotomicCollection ], 425 function ( z, F ) 426 return Conductor( F ) mod Conductor( z ) = 0 427 and ForAll( GaloisStabilizer( F ), x -> GaloisCyc( z, x ) = z ); 428 end ); 429 430InstallMethod( \in, 431 "for cyclotomic and cyclotomic field", 432 IsElmsColls, 433 [ IsCyc, IsCyclotomicField and IsCyclotomicCollection ], 434 function ( z, F ) 435 return Conductor( F ) mod Conductor( z ) = 0; 436 end ); 437 438 439############################################################################# 440## 441#M Intersection2( <F>, <G> ) . . . . . intersection of abelian number fields 442## 443InstallMethod( Intersection2, 444 "for two cyclotomic fields of cyclotomics", 445 IsIdenticalObj, 446 [ IsCyclotomicField and IsCyclotomicCollection, 447 IsCyclotomicField and IsCyclotomicCollection ], 448 function ( F, G ) 449 return CyclotomicField( GcdInt( Conductor( F ), Conductor( G ) ) ); 450 end ); 451 452InstallMethod( Intersection2, 453 "for cyclotomic field and abelian number field", 454 IsIdenticalObj, 455 [ IsCyclotomicField and IsCyclotomicCollection, 456 IsAbelianNumberField and IsCyclotomicCollection ], 457 function ( F, G ) 458 459 # intersection of cyclotomic field `F = CF(N)' with number field `G'; 460 # replace `N' by its g.c.d. with the conductor of `G', 461 # and then take the elements of `GaloisStabilizer( G )' modulo `N'. 462 # (If a reduction is necessary, `NF' will do.) 463 464 F:= Gcd( Conductor( F ), Conductor( G ) ); 465 return AbelianNumberField( F, Set( List( GaloisStabilizer( G ), 466 x -> x mod F ) ) ); 467 end ); 468 469InstallMethod( Intersection2, 470 "for abelian number field and cyclotomic field", 471 IsIdenticalObj, 472 [ IsAbelianNumberField and IsCyclotomicCollection, 473 IsCyclotomicField and IsCyclotomicCollection ], 474 function ( G, F ) 475 476 # intersection of cyclotomic field `F = CF(N)' with number field `G'; 477 # replace `N' by its g.c.d. with the conductor of `G', 478 # and then take the elements of `GaloisStabilizer( G )' modulo `N'. 479 # (If a reduction is necessary, `NF' will do.) 480 481 F:= Gcd( Conductor( F ), Conductor( G ) ); 482 return AbelianNumberField( F, Set( List( GaloisStabilizer( G ), 483 x -> x mod F ) ) ); 484 end ); 485 486InstallMethod( Intersection2, 487 "for two abelian number fields", 488 IsIdenticalObj, 489 [ IsAbelianNumberField and IsCyclotomicCollection, 490 IsAbelianNumberField and IsCyclotomicCollection ], 491 function ( F, G ) 492 493 local i, j, N, stab, stabF, stabG; 494 495 # first compute `N' where `CF(N)' contains the intersection; 496 # reduce the elements of the stabilizers modulo `N', i.e. intersect 497 # `F' and `G' with `CF(N)'; 498 # then compute the corresponding stabilizer, i.e. the product of 499 # stabilizers. 500 N:= GcdInt( Conductor( F ), Conductor( G ) ); 501 stabF:= Set( List( GaloisStabilizer( F ), x -> x mod N ) ); 502 stabG:= Set( List( GaloisStabilizer( G ), x -> x mod N ) ); 503 stab:= []; 504 for i in stabF do 505 for j in stabG do 506 AddSet( stab, ( i * j ) mod N ); 507 od; 508 od; 509 510 # (If a reduction is necessary, `NF' will do.) 511 return AbelianNumberField( N, stab ); 512 end ); 513 514 515############################################################################# 516## 517#M GeneratorsOfDivisionRing( <F> ) . field gens. of an abelian number field 518## 519InstallMethod( GeneratorsOfDivisionRing, 520 "for abelian number field of cyclotomics", 521 [ IsAbelianNumberField and IsCyclotomicCollection ], 522 function( F ) 523 local e; 524 e:= E( Conductor( F ) ); 525 return [ Sum( GaloisStabilizer( F ), y -> GaloisCyc( e, y ) ) ]; 526 end ); 527 528 529############################################################################# 530## 531#M Conductor( <F> ) . . . . . . . . . conductor of an abelian number field 532## 533InstallOtherMethod( Conductor, 534 "for abelian number field of cyclotomics", 535 [ IsAbelianNumberField and IsCyclotomicCollection ], 536 F -> Conductor( GeneratorsOfField( F ) ) ); 537 538 539############################################################################# 540## 541#M Subfields( <F> ) . . . . . . . . . subfields of an abelian number field 542## 543## The Galois group of an abelian number field is abelian, 544## so the subfields are in bijection with the conjugacy classes of subgroups 545## of the Galois group. 546## 547InstallMethod( Subfields, 548 "for abelian number field of cyclotomics", 549 [ IsAbelianNumberField and IsCyclotomicCollection ], 550 function( F ) 551 local n, stab; 552 n:= Conductor( F ); 553 stab:= GaloisStabilizer( F ); 554 return Set( List( ConjugacyClassesSubgroups( GaloisGroup( F ) ), 555 x -> AbelianNumberField( n, Union( stab, 556 List( GeneratorsOfGroup( Representative( x ) ), 557 y -> ExponentOfPowering( y ) ) ) ) ) ); 558 end ); 559 560 561############################################################################# 562## 563#M PrimeField( <F> ) . . . . . . . . . . . . . . for an abelian number field 564## 565InstallMethod( PrimeField, 566 "for abelian number field of cyclotomics", 567 [ IsAbelianNumberField and IsCyclotomicCollection ], 568 F -> Rationals ); 569 570 571############################################################################# 572## 573#M FieldExtension( <subfield>, <poly> ) . . extend an abelian number field 574## 575InstallOtherMethod( FieldExtension, 576 "for field of cyclotomics, and univ. polynomial (degree <= 2)", 577#T CollPoly 578 [ IsAbelianNumberField and IsCyclotomicCollection, 579 IsLaurentPolynomial ], 580 function( F, poly ) 581 582 local coeffs, root; 583 584 coeffs:= CoefficientsOfLaurentPolynomial( poly ); 585 coeffs:= ShiftedCoeffs( coeffs[1], coeffs[2] ); 586 587 if not IsSubset( F, coeffs ) then 588 Error( "all coefficients of <poly> must lie in <F>" ); 589 elif 3 < Length( coeffs ) then 590 TryNextMethod(); 591 elif Length( coeffs ) <= 1 then 592 Error( "<poly> must have degree at least 1" ); 593 elif Length( coeffs ) = 2 then 594 595 # `poly' is a linear polynomial. 596 root:= - coeffs[1] / coeffs[2]; 597 F:= AsField( F, F ); 598 599 else 600 601 # `poly' has degree 2. 602 # The roots of `a*x^2 + b*x + c' are 603 # $\frac{ -b \pm \sqrt{ b^2 - 4ac } }{2a}$. 604 root:= coeffs[2]^2 - 4 * coeffs[1] * coeffs[3]; 605 if not IsRat( root ) then 606 TryNextMethod(); 607 fi; 608 root:= ( ER( root ) - coeffs[2] ) / ( 2 * coeffs[3] ); 609 F:= AsField( F, FieldByGenerators( 610 Concatenation( GeneratorsOfField( F ), [ root ] ) ) ); 611 612 fi; 613 614 # Store the defining polynomial, and a root of it in the extension field. 615 SetDefiningPolynomial( F, poly ); 616 SetRootOfDefiningPolynomial( F, root ); 617 618 return F; 619 end ); 620 621 622############################################################################# 623## 624#M Conjugates( <L>, <K>, <z> ) 625## 626InstallMethod( Conjugates, 627 "for two abelian number fields of cyclotomics, and cyclotomic", 628 IsCollsXElms, 629 [ IsAbelianNumberField and IsCyclotomicCollection, 630 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 631 function( L, K, z ) 632 633 local N, gal, gens, conj, pnt; 634 635 N:= Conductor( L ); 636 637 # automorphisms of the conductor 638 gal:= PrimeResidues( N ); 639 640 if not IsPrimeField( K ) then 641 642 # take only the subgroup of `gal' that fixes the subfield pointwise 643 gens:= GeneratorsOfField( K ); 644 gal:= Filtered( gal, 645 x -> ForAll( gens, y -> GaloisCyc( y, x ) = y ) ); 646 fi; 647 648 # get representatives of cosets of the Galois stabilizer 649 conj:= []; 650 gens:= GaloisStabilizer( L ); 651 while gal <> [] do 652 pnt:= gal[1]; 653 Add( conj, GaloisCyc( z, pnt ) ); 654 SubtractSet( gal, List( gens, x -> ( x * pnt ) mod N ) ); 655 od; 656 657 return conj; 658 end ); 659 660InstallMethod( Conjugates, 661 "for cycl. field of cyclotomics, ab. number field, and cyclotomic", 662 IsCollsXElms, 663 [ IsCyclotomicField and IsCyclotomicCollection, 664 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 665 function( L, K, z ) 666 667 local conj, Kgens, i; 668 669 if not z in L then 670 Error( "<z> must lie in <L>" ); 671 fi; 672 673 if IsPrimeField( K ) then 674 conj:= List( PrimeResidues( Conductor( L ) ), 675 i -> GaloisCyc( z, i ) ); 676 else 677 conj:= []; 678 Kgens:= GeneratorsOfField( K ); 679 for i in PrimeResidues( Conductor( L ) ) do 680 if ForAll( Kgens, x -> GaloisCyc( x, i ) = x ) then 681 Add( conj, GaloisCyc( z, i ) ); 682 fi; 683 od; 684 fi; 685 686 return conj; 687 end ); 688 689 690############################################################################# 691## 692#M Norm( <L>, <K>, <z> ) 693## 694InstallMethod( Norm, 695 "for two abelian number fields of cyclotomics, and cyclotomic", 696 IsCollsXElms, 697 [ IsAbelianNumberField and IsCyclotomicCollection, 698 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 699 function( L, K, z ) 700 local N, gal, gens, result, pnt; 701 702 N:= Conductor( L ); 703 704 # automorphisms of the conductor 705 gal:= PrimeResidues( N ); 706 707 if not IsPrimeField( K ) then 708 709 # take only the subgroup of `gal' that fixes the subfield pointwise 710 gens:= GeneratorsOfField( K ); 711 gal:= Filtered( gal, 712 x -> ForAll( gens, y -> GaloisCyc( y, x ) = y ) ); 713 fi; 714 715 # get representatives of cosets of `GaloisStabilizer( L )' 716 result:= 1; 717 gens:= GaloisStabilizer( L ); 718 while gal <> [] do 719 pnt:= gal[1]; 720 result:= result * GaloisCyc( z, pnt ); 721 SubtractSet( gal, List( gens, x -> ( x * pnt ) mod N ) ); 722 od; 723 724 return result; 725 end ); 726 727InstallMethod( Norm, 728 "for cycl. field of cyclotomics, ab. number field, and cyclotomic", 729 IsCollsXElms, 730 [ IsCyclotomicField and IsCyclotomicCollection, 731 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 732 function( L, K, z ) 733 734 local i, result, Kgens; 735 736 result:= 1; 737 if IsPrimeField( K ) then 738 for i in PrimeResidues( Conductor( L ) ) do 739 result:= result * GaloisCyc( z, i ); 740 od; 741 else 742 Kgens:= GeneratorsOfField( K ); 743 for i in PrimeResidues( Conductor( L ) ) do 744 if ForAll( Kgens, x -> GaloisCyc( x, i ) = x ) then 745 result:= result * GaloisCyc( z, i ); 746 fi; 747 od; 748 fi; 749 750 return result; 751 end ); 752 753 754############################################################################# 755## 756#M Trace( <L>, K>, <z> ) 757## 758InstallMethod( Trace, 759 "for two abelian number fields of cyclotomics, and cyclotomic", 760 IsCollsXElms, 761 [ IsAbelianNumberField and IsCyclotomicCollection, 762 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 763 function( L, K, z ) 764 local N, gal, gens, result, pnt; 765 766 N:= Conductor( L ); 767 768 # automorphisms of the conductor 769 gens:= GeneratorsOfField( K ); 770 gal:= PrimeResidues( N ); 771 772 if not IsPrimeField( K ) then 773 774 # take only the subgroup of `gal' that fixes the subfield pointwise 775 gal:= Filtered( gal, 776 x -> ForAll( gens, y -> GaloisCyc( y, x ) = y ) ); 777 fi; 778 779 # get representatives of cosets of `GaloisStabilizer( L )' 780 result:= 0; 781 gens:= GaloisStabilizer( L ); 782 while gal <> [] do 783 pnt:= gal[1]; 784 result:= result + GaloisCyc( z, pnt ); 785 SubtractSet( gal, List( gens, x -> ( x * pnt ) mod N ) ); 786 od; 787 788 return result; 789 end ); 790 791InstallMethod( Trace, 792 "for cycl. field of cyclotomics, ab. number field, and cyclotomic", 793 IsCollsXElms, 794 [ IsCyclotomicField and IsCyclotomicCollection, 795 IsAbelianNumberField and IsCyclotomicCollection, IsCyc ], 796 function( L, K, z ) 797 local i, result, Kgens; 798 result:= 0; 799 if IsPrimeField( K ) then 800 for i in PrimeResidues( Conductor( L ) ) do 801 result:= result + GaloisCyc( z, i ); 802 od; 803 else 804 Kgens:= GeneratorsOfField( K ); 805 for i in PrimeResidues( Conductor( L ) ) do 806 if ForAll( Kgens, x -> GaloisCyc( x, i ) = x ) then 807 result:= result + GaloisCyc( z, i ); 808 fi; 809 od; 810 fi; 811 812 return result; 813 end ); 814 815 816############################################################################# 817## 818#F ZumbroichBase( <n>, <m> ) 819## 820## returns the set of exponents `e' for which `E(n)^e' belongs to the 821## (generalized) Zumbroich base of the cyclotomic field $Q_n$, 822## viewed as vector space over $Q_m$. 823## 824## *Note* that for $n \equiv 2 \bmod 4$ we have 825## `ZumbroichBase( <n>, 1 ) = 2 * ZumbroichBase( <n>/2, 1 )' but 826## `List( ZumbroichBase( <n>, 1 ), x -> E( <n> )^x ) = 827## List( ZumbroichBase( <n>/2, 1 ), x -> E( <n>/2 )^x )'. 828## 829InstallGlobalFunction( ZumbroichBase, function( n, m ) 830 831 local nn, base, basefactor, factsn, exponsn, factsm, exponsm, primes, 832 p, pos, i, k; 833 834 if not n mod m = 0 then 835 Error( "<m> must be a divisor of <n>" ); 836 fi; 837 838 factsn:= Factors(Integers, n ); 839 primes:= Set( factsn ); 840 exponsn:= List( primes, x -> 0 ); # Product(List( [1..Length(primes)], 841 # x->primes[i]^exponsn[i]))=n 842 p:= factsn[1]; 843 pos:= 1; 844 for i in factsn do 845 if i > p then 846 p:= i; 847 pos:= pos + 1; 848 fi; 849 exponsn[ pos ]:= exponsn[ pos ] + 1; 850 od; 851 852 factsm:= Factors(Integers, m ); 853 exponsm:= List( primes, x -> 0 ); # Product(List( [1..Length(primes)], 854 # x->primes[i]^exponsm[i]))=m 855 if m <> 1 then 856 p:= factsm[1]; 857 pos:= Position( primes, p ); 858 for i in factsm do 859 if i > p then 860 p:= i; 861 pos:= Position( primes, p ); 862 fi; 863 exponsm[ pos ]:= exponsm[ pos ] + 1; 864 od; 865 fi; 866 867 base:= [ 0 ]; 868 if n = 1 then 869 return base; 870 fi; 871 872 if primes[1] = 2 then 873 874 # special case: $J_{k,2} = \{ 0, 1 \}$ 875 if exponsm[1] = 0 then exponsm[1]:= 1; fi; # $J_{0,2} = \{ 0 \}$ 876 877 nn:= n / 2^( exponsm[1] + 1 ); 878 879 for k in [ exponsm[1] .. exponsn[1] - 1 ] do 880 Append( base, base + nn ); 881 nn:= nn / 2; 882 od; 883 pos:= 2; 884 else 885 pos:= 1; 886 fi; 887 888 for i in [ pos .. Length( primes ) ] do 889 890 if m mod primes[i] <> 0 then 891 basefactor:= [ 1 .. primes[i] - 1 ] * ( n / primes[i] ); 892 base:= Concatenation( List( base, x -> x + basefactor ) ); 893 exponsm[i]:= 1; 894 fi; 895 896 basefactor:= [ - ( primes[i] - 1 ) / 2 .. ( primes[i] - 1 ) / 2 ] 897 * n / primes[i]^exponsm[i]; 898 899 for k in [ exponsm[i] .. exponsn[i] - 1 ] do 900 basefactor:= basefactor / primes[i]; 901 base:= Concatenation( List( base, x -> x + basefactor ) ); 902 od; 903 od; 904 return Set( List( base, x -> x mod n ) ); 905end ); 906 907 908############################################################################# 909## 910#F LenstraBase( <n>, <stabilizer>, <super>, <m> ) 911## 912## returns a list of lists of integers; each list indexing the exponents of 913## an orbit of a subgroup of <stabilizer> on <n>-th roots of unity. 914## 915## <super> is a list representing a supergroup of <stabilizer> which 916## shall act consistently with the action of <stabilizer>, i.e., each orbit 917## of <supergroup> is a union of orbits of <stabilizer>. 918## 919## ( Shall there be a test if this is possible ? ) 920## 921## <m> is a positive integer. The basis described by the returned list is 922## an integral basis over the cyclotomic field $\Q_m$. 923## 924## *Note* that the elements are in general not sets, since the first element 925## is always an element of `ZumbroichBase( <n>, <m> )'; 926## this property is used by `NF' and `Coefficients'. 927## 928## *Note* that <stabilizer> must not contain the stabilizer of a proper 929## cyclotomic subfield of the <n>-th cyclotomic field. 930## 931## We proceed as follows. 932## 933## Let $n'$ be the biggest divisor of $n$ coprime to $m$. 934## First choose an integral basis $B$ for the extension $\Q_{n'} / \Q$ 935## (equivalently, for $\Q_{n} / \Q_{n/n'}$). 936## For each element of $B$ choose an integral basis for $\Q_{n/n'} / \Q_m$, 937## namely a transversal of $E_m$ in $E_{n/n'}$ where $E_n$ denotes the 938## group of $n$-th roots of unity. 939## 940## The products of elements in these bases form an integral $\Q_m$-basis 941## of $\Q_n$. 942## Now we choose the bases in such a way that ... 943## 944InstallGlobalFunction( LenstraBase, function( n, stabilizer, supergroup, m ) 945 946 local i, 947 k, 948 factors, # factors of `n' 949 primes, # set of prime divisors of `n' 950 coprimes, # set of prime divisors of `n' coprime to `m' 951 nprime, # biggest divisor of `n' coprime to `m' 952 NN, # squarefree part of `n' 953 zumb, # exponents of roots in the basis of `CF(n)' 954 N2, # 2-part of `n' 955 No, # odd part of `n' 956 transversal, # roots in basis of `CF(n/nprime) / CF(m)', 957 # written as `n'-th roots 958 orbits, 959 pnt, 960 orb, 961 d, 962 ppnt, 963 ord, 964 a, 965 neworbits, 966 rep, 967 super, 968 H1; 969 970 # We may assume that either `m' is odd or $4$ divides `m'. 971 if m mod 4 = 2 then 972 m:= m / 2; 973 fi; 974 975 factors := Factors(Integers, n ); 976 primes := Set( factors ); 977 coprimes := Filtered( primes, x -> m mod x <> 0 ); 978 nprime := Product( Filtered( factors, x -> m mod x <> 0 ) ); 979 980 NN:= Product( coprimes ); 981 zumb:= List( ZumbroichBase( nprime, 1 ), x -> x * ( n / nprime ) ); 982 transversal := List( ZumbroichBase( n / nprime, m ), x -> x * nprime ); 983 stabilizer:= Set( stabilizer ); 984 orbits:= []; 985 986 if nprime = NN then 987 988 # $n'$ is squarefree. 989 # We have a normal basis, `stabilizer' acts on `zumb', 990 # we do not consider equivalence classes since they are all trivial, 991 # and `supergroup' is obsolete since `zumb' describes a normal basis. 992 993 # *Note* that if $n'$ is even then `zumb' does not consist of 994 # at least `NN'-th roots! 995 996 while 0 < Length( zumb ) do 997 998 # Compute the orbit of `stabilizer' of a point in `zumb'. 999 pnt:= zumb[1]; 1000 1001 # For each root in `transversal', compute the orbit of `n'-th roots 1002 # under `stabilizer'. 1003 neworbits:= List( transversal, 1004 root -> List( stabilizer, 1005 x -> ( root + pnt ) * x mod n ) ); 1006 SubtractSet( zumb, neworbits[1] ); 1007 Append( orbits, neworbits ); 1008 1009 od; 1010 1011 else 1012 1013 # Let $d(i)$ be the largest squarefree number whose square divides the 1014 # order of $e_{n'}^i$, that is $n' / \gcd( n', i )$. 1015 # Define an equivalence relation on the set $S$ of at least `NN'-th 1016 # roots of unity. 1017 # $i$ and $j$ are equivalent iff $n'$ divides $( i - j ) d(i)$. The 1018 # equivalence class $(i)$ of $i$ is 1019 # $\{ i + k n' / d(i) ; 0 \leq k \< d(i) \}$. 1020 1021 # For the case that `NN' is even, replace those roots in $S$ with order 1022 # not divisible by 4 by their negatives. 1023 # (Equivalently\: Replace *all* elements in $S$ by their negatives.) 1024 1025 # If 8 does not divide $n'$ and $n' \not= 4$, `zumb' is a subset of $S$, 1026 # the intersection of $(i)$ with `zumb' is of order $\varphi( d(i) )$, 1027 # it is a basis for the $Z$--submodule spanned by $(i)$. 1028 # Furthermore, the minimality of `n' yields that `stabilizer' acts fixed 1029 # point freely on the set of equivalence classes. 1030 1031 # More exactly, fixed points occur exactly if there is an element `s' in 1032 # `stabilizer' which is congruent $-1$ modulo `N2' and congruent $+1$ 1033 # modulo `No'. 1034 1035 # The base is constructed as follows\: 1036 # 1037 # Until all classes are touched: 1038 # 1. Take a point `pnt' (in `zumb'). 1039 # 2. Choose a maximal linear independent set `pnts' in the equivalence 1040 # class of `pnt' (the intersection of the class with `zumb'). 1041 # 3. Take the `stabilizer'--orbits of `pnts' as base elements; 1042 # remove the touched equivalence classes. 1043 # 4. For the representatives `rep' in `supergroup'\: 1044 # If `rep' maps `pnt' to an equivalence class that was not yet 1045 # touched, take the `stabilizer'--orbits of the images of `pnts' 1046 # under `rep' as base elements; 1047 # remove the touched equivalence classes. 1048 1049 # Compute nontriv. representatives of `supergroup' over `stabilizer'. 1050 super:= Difference( supergroup, stabilizer ); 1051 supergroup:= []; 1052 while 0 < Length( super ) do 1053 pnt:= super[1]; 1054 Add( supergroup, pnt ); 1055 SubtractSet( super, List( stabilizer, x -> ( x * pnt ) mod n ) ); 1056 od; 1057 1058 # Compute 2-part and odd part of $n'$. 1059 N2 := 1; 1060 No := nprime; 1061 while No mod 2 = 0 do 1062 N2:= N2 * 2; 1063 No:= No / 2; 1064 od; 1065 1066 # Compute the subgroup `H1' of `stabilizer' that acts fixed point 1067 # freely on the set of equivalence classes, 1068 # and the element `a' that (if exists) fixes some classes pointwise. 1069 H1 := []; 1070 a := 0; 1071 for k in stabilizer do 1072 if k mod 4 = 1 then 1073 Add( H1, k ); 1074 elif ( k -1 ) mod No = 0 1075 and ( ( k + 1 ) mod N2 = 0 or ( k + 1 - N2/2 ) mod N2 = 0 ) then 1076 a:= k; 1077 fi; 1078 od; 1079 if a = 0 then 1080 H1:= stabilizer; 1081 fi; 1082 1083 while 0 < Length( zumb ) do 1084 1085 neworbits:= []; 1086 pnt:= zumb[1]; 1087 d:= 1; 1088 ord:= n / GcdInt( n, pnt ); 1089 for i in coprimes do 1090 if ord mod i^2 = 0 then d:= d * i; fi; 1091 od; 1092 1093 if ( a = 0 ) or ( ord mod 8 = 0 ) then 1094 1095 # No `H1'-orbit can be fixed by `a'. 1096 1097 for k in [ 0 .. d-1 ] do 1098 1099 # Loop over the equivalence class of `pnt', 1100 # consider only the points in `zumb'. 1101 1102 ppnt:= pnt + k * n / d; 1103 if ppnt in zumb then 1104 1105 orb:= List( stabilizer, x -> ( ppnt * x ) mod n ); 1106 Append( neworbits, 1107 List( transversal, 1108 root -> List( stabilizer, 1109 x -> ( root + ppnt ) * x mod n ) ) ); 1110 1111 fi; 1112 od; 1113 1114 elif ord mod 4 = 0 then 1115 1116 # `a' maps each point in the orbit of `H1' to its inverse, 1117 # we ignore all these points. 1118 orb:= List( stabilizer, x -> ( pnt * x ) mod n ); 1119 1120 else 1121 1122 # The orbit of `H1' is pointwise fixed by `a'. 1123 for k in [ 0 .. d-1 ] do 1124 ppnt:= pnt + k * n / d; 1125 if ppnt in zumb then 1126 1127 orb:= List( H1, x -> ( ppnt * x ) mod n ); 1128 Append( neworbits, 1129 List( transversal, 1130 root -> List( H1, 1131 x -> ( root + ppnt ) * x mod n ) ) ); 1132 1133 fi; 1134 od; 1135 1136 fi; 1137 1138 # Remove the equivalence classes of all new points from `zumb'. 1139 for pnt in orb do 1140 SubtractSet( zumb, List( [ 0 .. d-1 ], 1141 k -> ( pnt + k * n / d ) mod n ) ); 1142 od; 1143 1144 Append( orbits, neworbits ); 1145 1146 # use `supergroup'\: 1147 # Is there a point in `zumb' that is not equivalent to 1148 # `( pnt * rep ) mod nprime' ? 1149 # (Note that the factor group `supergroup / stabilizer' acts on the 1150 # set of unions of orbits with equivalent elements.) 1151 1152 for rep in supergroup do 1153 1154 # is there an `x' in `zumb' that is equivalent to `pnt * rep' ? 1155 if ForAny( zumb, x -> ( ( x - pnt * rep ) * d ) mod n = 0 ) then 1156 Append( orbits, List( neworbits, 1157 x -> List( x, y -> (y*rep) mod n ) ) ); 1158 for ppnt in orbits[ Length( orbits ) ] do 1159 SubtractSet( zumb, List( [ 0..d-1 ], 1160 k -> ( ppnt + k * n / d ) mod n ) ); 1161 od; 1162 fi; 1163 od; 1164 1165 od; 1166 fi; 1167 1168 # Return the list of orbits. 1169 return orbits; 1170end ); 1171 1172 1173############################################################################# 1174## 1175#R IsCanonicalBasisAbelianNumberFieldRep( <B> ) 1176## 1177## The canonical basis of a number field is defined to be a Lenstra basis 1178## in the case that the subfield is `Rationals'. 1179#T extend this to the case where the subfield is a cyclotomic field! 1180## In all other cases a normal basis is chosen. 1181## 1182DeclareRepresentation( "IsCanonicalBasisAbelianNumberFieldRep", 1183 IsAttributeStoringRep, 1184 [ "coeffslist", "coeffsmat", "lenstrabase", "conductor" ] ); 1185 1186 1187############################################################################# 1188## 1189#R IsCanonicalBasisCyclotomicFieldRep( <B> ) 1190## 1191## The canonical basis of a field extension $F / K$ for a cyclotomic field 1192## $F$ is the Zumbroich basis if $K$ is a cyclotomic field. 1193## Otherwise it is a normal basis. 1194## 1195DeclareRepresentation( "IsCanonicalBasisCyclotomicFieldRep", 1196 IsCanonicalBasisAbelianNumberFieldRep, 1197 [ "zumbroichbase" ] ); 1198 1199 1200############################################################################# 1201## 1202#M CanonicalBasis( <F> ) 1203## 1204## The canonical basis of a number field is defined to be a Lenstra basis 1205## in the case that the subfield is a cyclotomic field. 1206## 1207## In all other cases a normal basis is chosen. 1208## 1209InstallMethod( CanonicalBasis, 1210 "for abelian number field of cyclotomics", 1211 [ IsAbelianNumberField and IsCyclotomicCollection ], 1212 function ( F ) 1213 1214 local N, # conductor of `F' 1215 k, 1216 lenst, 1217 i, 1218 B, 1219 BB, 1220 normalbase, 1221 subbase, 1222 m, 1223 j, 1224 C, 1225 coeffsmat, 1226 val, 1227 l; 1228 1229 # Make the basis object. 1230 B:= Objectify( NewType( FamilyObj( F ), 1231 IsFiniteBasisDefault 1232 and IsCanonicalBasis 1233 and IsCanonicalBasisAbelianNumberFieldRep ), 1234 rec() ); 1235 SetUnderlyingLeftModule( B, F ); 1236 1237 if IsCyclotomicField( LeftActingDomain( F ) ) then 1238 1239 # Compute the standard Lenstra basis and the `coeffslist' component. 1240 # If `GaloisStabilizer( F )' acts fixed point freely on the 1241 # equivalence classes we must change from the Zumbroich basis to a 1242 # `GaloisStabilizer( F )'-normal basis, 1243 # and afterwards choose coefficients with respect to that basis. 1244 # In the case of fixed points, only the subgroup `H1' of index 2 in 1245 # `GaloisStabilizer( F )' acts fixed point freely; 1246 # we change to a `H1'-normal basis, and afterwards choose coefficients. 1247 1248 # For this basis <B> we want a component `coeffslist' such that 1249 # in the special case of a field over the rationals we have 1250 # `CoeffsCyc( z, N ){ <B>!.coeffslist } = Coefficients( <B>, z )'. 1251 1252 N:= Conductor( F ); 1253 lenst:= LenstraBase( N, GaloisStabilizer( F ), GaloisStabilizer( F ), 1254 Conductor( LeftActingDomain( F ) ) ); 1255 1256 # Fill in additional components. 1257 SetBasisVectors( B, List( lenst, 1258 x -> Sum( List( x, y -> E(N)^y ) ) ) ); 1259 B!.coeffslist := MakeImmutable(List( lenst, x -> x[1] + 1 )); 1260 B!.lenstrabase := MakeImmutable(lenst); 1261 B!.conductor := N; 1262#T better compute basis vectors only if necessary 1263#T (in the case of a normal basis the vectors are of course known ...) 1264 SetIsIntegralBasis( B, true ); 1265 1266 else 1267 1268 # A basis of an extension of a number field is a normal basis. 1269#T handle extensions of cycl. fields specially!! 1270 # Coefficients can be computed using a tensor form basis for that 1271 # the base change relative to the Lenstra basis (relative to the 1272 # rationals) is computed. 1273 1274 # Let $(v_1, \ldots, v_m)$ denote a basis of `subfield' and 1275 # $(w_1, \ldots, w_k)$ denote a basis of `F'; 1276 # Define $u_{i+m(j-1)} = v_i w_j$. Then $(u_l; 1\leq l\leq mk)$ 1277 # is a basis of `F' over the rationals. 1278 # First change from the Lenstra basis to this basis; the matrix is `C'. 1279 1280 normalbase:= NormalBase( F ); 1281 subbase:= BasisVectors( CanonicalBasis( LeftActingDomain( F ) ) ); 1282 BB:= CanonicalBasis( AbelianNumberField( Conductor( F ), 1283 GaloisStabilizer( F ) ) ); 1284 m:= Length( subbase ); 1285 k:= Length( normalbase ); 1286 N:= Conductor( normalbase ); 1287 C:= []; 1288 for j in normalbase do 1289 1290 # Compute the Lenstra basis coefficients. 1291 for i in subbase do 1292 Add( C, Coefficients( BB, i*j ) ); 1293 od; 1294 1295 od; 1296 C:= C^(-1); 1297 1298 # Let $(c_1, \ldots, c_{mk})$ denote the coefficients with respect 1299 # to the new base. To achieve `<coeffs> \* normalbase = <z>' we have 1300 # to take $\sum_{i=1}^m c_{i+m(j-1)} v_i$ as $j$--th coefficient: 1301 1302 coeffsmat:= []; 1303 for i in [ 1 .. Length( C ) ] do # for all rows 1304 coeffsmat[i]:= []; 1305 for j in [ 1 .. k ] do 1306 val:= 0; 1307 for l in [ 1 .. m ] do 1308 val:= val + C[i][ m*(j-1)+l ] * subbase[l]; 1309 od; 1310 coeffsmat[i][j]:= val; 1311 od; 1312 od; 1313 1314 # Multiplication of a Lenstra basis coefficient vector with 1315 # `coeffsmat' means first changing to the base of products 1316 # $v_i w_j$ and then summation over the parts of the $v_i$. 1317 1318 SetIsNormalBasis( B, true ); 1319 SetBasisVectors( B, normalbase ); 1320 B!.coeffslist := BB!.coeffslist; 1321 B!.coeffsmat := coeffsmat; 1322 B!.conductor := N; 1323 1324 fi; 1325 1326 # Return the canonical basis. 1327 return B; 1328 end ); 1329 1330 1331############################################################################# 1332## 1333#M Basis( <F> ) 1334## 1335InstallMethod( Basis, 1336 "for abelian number field of cyclotomics (delegate to `CanonicalBasis')", 1337 [ IsAbelianNumberField and IsCyclotomicCollection ], 1338 CANONICAL_BASIS_FLAGS, 1339 CanonicalBasis ); 1340 1341 1342############################################################################# 1343## 1344#M Coefficients( <B>, <z> ) . . . . . for canon. basis of ab. number field 1345## 1346InstallMethod( Coefficients, 1347 "for canonical basis of abelian number field, and cyclotomic", 1348 IsCollsElms, 1349 [ IsBasis and IsCanonicalBasis and IsCanonicalBasisAbelianNumberFieldRep, 1350 IsCyc ], 1351 function ( B, z ) 1352 local V, 1353 F, 1354 coeffs, 1355 n, 1356 m, 1357 zumb, 1358 NN, 1359 Em; 1360 1361 if not z in UnderlyingLeftModule( B ) then 1362 return fail; 1363 fi; 1364 1365 V:= UnderlyingLeftModule( B ); 1366 F:= LeftActingDomain( V ); 1367 1368 # The information about the standard Lenstra basis coefficients 1369 # is stored in `B!.coeffslist'. 1370 if IsPrimeField( F ) then 1371 1372 # Take the relevant sublist, this suffices for extensions 1373 # of the rationals. 1374 coeffs:= CoeffsCyc( z, B!.conductor ){ B!.coeffslist }; 1375 1376 elif IsCyclotomicField( F ) then 1377 1378 # `B' is an integral basis of an extension of a cyclotomic field $\Q_m$, 1379 # the coefficient of the root $\zeta$ is 1380 # $\sum_{\eta\in\B_m} a_{\eta\zeta} \eta$. 1381 1382 coeffs:= CoeffsCyc( z, B!.conductor ); 1383 n:= Conductor( V ); 1384 m:= Conductor( F ); 1385 zumb:= CanonicalBasis( F )!.zumbroichbase; 1386 NN:= n/m; 1387 Em:= E(m); 1388 coeffs:= List( B!.coeffslist, 1389 j->Sum( zumb, k->coeffs[ ((k*NN+j-1) mod n )+1 ]*Em^k ) ); 1390 1391 fi; 1392 1393 if IsBound( B!.coeffsmat ) then 1394 1395 # Compute the coefficients with respect to the field extension. 1396 coeffs:= CoeffsCyc( z, B!.conductor ){ B!.coeffslist } * B!.coeffsmat; 1397 1398 fi; 1399 1400 # Return the coefficients list. 1401 return coeffs; 1402 end ); 1403 1404 1405############################################################################# 1406## 1407#M FieldByGenerators( <cycscoll> ) 1408#M FieldByGenerators( <F>, <cycscoll> ) 1409## 1410InstallOtherMethod( FieldByGenerators, 1411 "for collection of cyclotomics", 1412 [ IsCyclotomicCollection ], 1413 function( gens ) 1414 1415 local N, stab; 1416 1417 N:= Conductor( gens ); 1418 1419 # Handle trivial cases. 1420 if N = 1 then 1421 return Rationals; 1422 elif N = 4 then 1423 return GaussianRationals; 1424 fi; 1425 1426 # Compute the reduced stabilizer info. 1427 stab:= Filtered( PrimeResidues( N ), 1428 x -> ForAll( gens, 1429 gen -> GaloisCyc( gen, x ) = gen ) ); 1430 1431 # Construct and return the field. 1432 return AbelianNumberFieldByReducedGaloisStabilizerInfo( Rationals, N, 1433 stab ); 1434 end ); 1435 1436InstallMethod( FieldByGenerators, 1437 "for field and collection, both collections of cyclotomics", 1438 IsIdenticalObj, 1439 [ IsField and IsCyclotomicCollection, IsCyclotomicCollection ], 1440 function( F, gens ) 1441 1442 local N, stab; 1443 1444 N:= Conductor( gens ); 1445 1446 if F = Rationals then 1447 1448 # Handle trivial cases. 1449 if N = 1 then 1450 return Rationals; 1451 elif N = 4 then 1452 return GaussianRationals; 1453 fi; 1454 1455 else 1456 N:= Lcm( N, Conductor( F ) ); 1457 gens:= Concatenation( gens, GeneratorsOfField( F ) ); 1458 fi; 1459 1460 # Compute the reduced stabilizer info. 1461 stab:= Filtered( PrimeResidues( N ), 1462 x -> ForAll( gens, 1463 gen -> GaloisCyc( gen, x ) = gen ) ); 1464 1465 # Construct and return the field. 1466 return AbelianNumberFieldByReducedGaloisStabilizerInfo( F, N, stab ); 1467 end ); 1468 1469 1470############################################################################# 1471## 1472#M DefaultFieldByGenerators( <cycscoll> ) 1473## 1474InstallMethod( DefaultFieldByGenerators, 1475 "for collection of cyclotomics", 1476 [ IsCyclotomicCollection ], 1477 gens -> CyclotomicField( Conductor( gens ) ) ); 1478 1479 1480############################################################################# 1481## 1482#M CanonicalBasis( <F> ) 1483## 1484## The canonical basis of a field extension $F / K$ for a cyclotomic field 1485## $F$ is the Zumbroich basis if $K$ is a cyclotomic field. 1486## Otherwise it is the first normal basis. 1487## 1488InstallMethod( CanonicalBasis, 1489 "for cyclotomic field of cyclotomics", 1490 [ IsCyclotomicField and IsCyclotomicCollection ], 1491 function( F ) 1492 1493 local n, 1494 m, 1495 B, 1496 subfield, 1497 zumb, 1498 subvectors, 1499 vectors, 1500 i, j, k, l, 1501 C, 1502 coeffsmat, 1503 val; 1504 1505 n:= Conductor( F ); 1506 1507 B:= Objectify( NewType( FamilyObj( F ), 1508 IsFiniteBasisDefault 1509 and IsCanonicalBasis 1510 and IsCanonicalBasisCyclotomicFieldRep ), 1511 rec() ); 1512 SetUnderlyingLeftModule( B, F ); 1513 B!.conductor:= n; 1514 1515 subfield:= LeftActingDomain( F ); 1516 1517 if IsCyclotomicField( subfield ) then 1518 1519 SetIsIntegralBasis( B, true ); 1520 1521 # Construct the Zumbroich basis. 1522 B!.zumbroichbase := MakeImmutable(ZumbroichBase( n, Conductor( subfield ) )); 1523 1524 else 1525 1526 # Compute a normal basis. 1527 1528 # Let $(v_1, \ldots, v_m)$ denote `Basis( F.field ).vectors' and 1529 # $(w_1, \ldots, w_k)$ denote `vectors'. 1530 # Define $u_{i+m(j-1)} = v_i w_j$. Then $(u_l; 1\leq l\leq mk)$ 1531 # is a $Q$-basis of `F'. First change from the Zumbroich basis to 1532 # this basis; the matrix is `C'\: 1533 1534 zumb := ZumbroichBase( n, 1 ) + 1; 1535 subvectors := BasisVectors( Basis( subfield ) ); 1536 vectors := NormalBase( F ); 1537 m:= Length( subvectors ); 1538 k:= Length( vectors ); 1539 C:= []; 1540 for j in vectors do 1541 for i in subvectors do 1542 Add( C, CoeffsCyc( i*j, n ){ zumb } ); 1543 od; 1544 od; 1545 C:= C^(-1); 1546 1547 # Let $(c_1, \ldots, c_{mk})$ denote the coefficients with respect 1548 # to the new basis. 1549 # To achieve `<coeffs> \* BasisVectors( <B> ) = <z>' we have 1550 # to take $\sum_{i=1}^m c_{i+m(j-1)} v_i$ as $j$--th coefficient\: 1551 1552 coeffsmat:= []; 1553 for i in [ 1 .. Length( C ) ] do # for all rows 1554 coeffsmat[i]:= []; 1555 for j in [ 1 .. k ] do 1556 val:= 0; 1557 for l in [ 1 .. m ] do 1558 val:= val + C[i][ m*(j-1)+l ] * subvectors[l]; 1559 od; 1560 coeffsmat[i][j]:= val; 1561 od; 1562 od; 1563 1564 SetBasisVectors( B, vectors ); 1565 SetIsNormalBasis( B, true ); 1566 1567 B!.zumbroichbase := MakeImmutable(zumb - 1); 1568 B!.coeffsmat := MakeImmutable(coeffsmat); 1569 1570 fi; 1571 1572 # Return the basis. 1573 return B; 1574 end ); 1575 1576 1577############################################################################# 1578## 1579#M BasisVectors( <B> ) 1580## 1581InstallMethod( BasisVectors, 1582 "for canon. basis of cyclotomic field of cyclotomics", 1583 [ IsBasis and IsCanonicalBasis and IsCanonicalBasisCyclotomicFieldRep ], 1584 function( B ) 1585 local e; 1586 # Basis vectors are bound if the subfield is not a cycl. field. 1587#T ?? 1588 e:= E( Conductor( UnderlyingLeftModule( B ) ) ); 1589 return List( B!.zumbroichbase, x -> e^x ); 1590 end ); 1591 1592 1593############################################################################# 1594## 1595#M Coefficients( <B>, <z> ) . . . . . . . . for canon. basis of cycl. field 1596## 1597InstallMethod( Coefficients, 1598 "for canonical basis of cyclotomic field, and cyclotomic", 1599 IsCollsElms, 1600 [ IsBasis and IsCanonicalBasis and IsCanonicalBasisCyclotomicFieldRep, 1601 IsCyc ], 1602 function( B, z ) 1603 local N, 1604 coeffs, 1605 F, 1606 m, 1607 zumb, 1608 NN, 1609 Em; 1610 1611 F:= UnderlyingLeftModule( B ); 1612 if not z in F then return fail; fi; 1613 1614 N:= B!.conductor; 1615 1616 # Get the Zumbroich basis representation of <z> in `N'-th roots. 1617 coeffs:= CoeffsCyc( z, N ); 1618 if coeffs = fail then return fail; fi; 1619 1620 F:= LeftActingDomain( F ); 1621 1622 if IsPrimeField( F ) then 1623 1624 # Get the Zumbroich basis coefficients (basis $B_{n,1}$) 1625 coeffs:= coeffs{ B!.zumbroichbase + 1 }; 1626 1627 elif IsCyclotomicField( F ) then 1628 1629 # Get the Zumbroich basis coefficients (basis $B_{n,m}$) directly. 1630 m:= Conductor( F ); 1631 zumb:= CanonicalBasis( F )!.zumbroichbase; 1632 NN:= N/m; 1633 Em:= E(m); 1634 coeffs:= List( B!.zumbroichbase, 1635 j->Sum( zumb, k->coeffs[ ((k*NN+j) mod N )+1 ]*Em^k ) ); 1636 1637 else 1638 1639 # The subfield is not a cyclotomic field. 1640 # The necessary information is stored in `B!.coeffsmat'. 1641 coeffs:= coeffs{ B!.zumbroichbase + 1 } * B!.coeffsmat; 1642 1643 fi; 1644 1645 # Return the list of coefficients. 1646 return coeffs; 1647 end ); 1648 1649 1650############################################################################# 1651## 1652#V Cyclotomics . . . . . . . . . . . . . . . . . . field of all cyclotomics 1653## 1654InstallValue( Cyclotomics, Objectify( NewType( 1655 CollectionsFamily( CyclotomicsFamily ), 1656 IsField and IsAttributeStoringRep ), 1657 rec() ) ); 1658SetName( Cyclotomics, "Cyclotomics" ); 1659SetLeftActingDomain( Cyclotomics, Rationals ); 1660SetIsFiniteDimensional( Cyclotomics, false ); 1661SetIsFinite( Cyclotomics, false ); 1662SetIsWholeFamily( Cyclotomics, true ); 1663SetDegreeOverPrimeField( Cyclotomics, infinity ); 1664SetDimension( Cyclotomics, infinity ); 1665SetRepresentative(Cyclotomics, 0); 1666 1667 1668############################################################################# 1669## 1670## Automorphisms of abelian number fields 1671## 1672 1673 1674############################################################################# 1675## 1676#R IsANFAutomorphismRep( <obj> ) 1677## 1678DeclareRepresentation( "IsANFAutomorphismRep", 1679 IsAttributeStoringRep, [ "galois" ] ); 1680 1681 1682############################################################################# 1683## 1684#P IsANFAutomorphism( <obj> ) 1685## 1686DeclareSynonym( "IsANFAutomorphism", IsANFAutomorphismRep 1687 and IsFieldHomomorphism 1688 and IsMapping 1689 and IsBijective ); 1690 1691 1692############################################################################# 1693## 1694#M ExponentOfPowering( <map> ) 1695## 1696InstallMethod( ExponentOfPowering, 1697 "for an ANFAutomorphism", 1698 [ IsMapping and IsANFAutomorphismRep ], 1699 map -> map!.galois ); 1700 1701InstallMethod( ExponentOfPowering, 1702 "for an identity mapping", 1703 [ IsMapping and IsOne ], 1704 map -> 1 ); 1705 1706InstallMethod( ExponentOfPowering, 1707 "for a mapping (check whether it is the identity mapping)", 1708 [ IsMapping ], 1709 function( map ) 1710 if IsOne( map ) then 1711 return 1; 1712 else 1713 TryNextMethod(); 1714 fi; 1715 end ); 1716 1717 1718############################################################################# 1719## 1720#F ANFAutomorphism( <F>, <k> ) . . automorphism of an abelian number field 1721## 1722InstallGlobalFunction( ANFAutomorphism, function ( F, k ) 1723 1724 local galois, aut; 1725 1726 # check the arguments 1727 if not ( IsAbelianNumberField(F) and IsCyclotomicCollection(F) ) then 1728 Error("<F> must be an abelian number field consisting of cyclotomics"); 1729 elif not IsRat( k ) then 1730 Error( "<k> must be an integer" ); 1731 fi; 1732 if not IsInt( k ) then 1733#T this is a hack ... 1734 k:= k mod Conductor( F ); 1735 fi; 1736 if Gcd( Conductor( F ), k ) <> 1 then 1737 Error( "<k> must be coprime to the conductor of <F>" ); 1738 fi; 1739 1740 # Let $F / K$ be a field extension where $Q_n$ is the conductor of $F$; 1741 # let $S(F)$ be the group of those prime residues mod $n$ that fix $F$ 1742 # pointwise. The Galois group of $F / K$ is in natural correspondence 1743 # to $S(K) / S(F)$. Thus each automorphism of $F / K$ corresponds to 1744 # a coset $c$ of $S(K)$, and it acts on $F$ like each element of $c$. 1745 # The automorphism `ANFAutomorphism( F/K, k )' maps $x\in F / K$ to 1746 # `GaloisCyc( <x>, k )'. 1747 1748 # Choose the smallest representative ... 1749 galois:= Set(List(GaloisStabilizer( F ), x->x*k mod Conductor( F )))[1]; 1750 if galois = 1 then 1751 return IdentityMapping( F ); 1752 fi; 1753 1754 # make the mapping 1755 aut:= Objectify( TypeOfDefaultGeneralMapping( F, F, 1756 IsSPGeneralMapping 1757 and IsANFAutomorphism ), 1758 rec() ); 1759 1760 aut!.galois:= galois; 1761 1762 return aut; 1763end ); 1764 1765 1766############################################################################# 1767## 1768#M \=( <aut1>, <aut2> ) . . . . for automorphisms of abelian number fields 1769#M \=( <id>, <aut> ) . . . . . . for automorphisms of abelian number fields 1770#M \=( <aut>, <id> ) . . . . . . for automorphisms of abelian number fields 1771## 1772InstallMethod( \=, 1773 "for two ANF automorphisms", 1774 IsIdenticalObj, 1775 [ IsFieldHomomorphism and IsANFAutomorphismRep, 1776 IsFieldHomomorphism and IsANFAutomorphismRep ], 1777 function ( aut1, aut2 ) 1778 return Source( aut1 ) = Source( aut2 ) 1779 and aut1!.galois = aut2!.galois; 1780 end ); 1781 1782InstallMethod( \=, 1783 "for identity mapping and ANF automorphism", 1784 IsIdenticalObj, 1785 [ IsMapping and IsOne, 1786 IsFieldHomomorphism and IsANFAutomorphismRep ], 1787 function ( id, aut ) 1788 return Source( id ) = Source( aut ) 1789 and aut!.galois = 1; 1790 end ); 1791 1792InstallMethod( \=, 1793 "for ANF automorphism and identity mapping", 1794 IsIdenticalObj, 1795 [ IsFieldHomomorphism and IsANFAutomorphismRep, 1796 IsMapping and IsOne ], 1797 function ( aut, id ) 1798 return Source( id ) = Source( aut ) 1799 and aut!.galois = 1; 1800 end ); 1801 1802 1803############################################################################# 1804## 1805#M \<( <aut1>, <aut2> ) . . . . for automorphisms of abelian number fields 1806## 1807InstallMethod( \<, 1808 "for two ANF automorphisms", 1809 IsIdenticalObj, 1810 [ IsFieldHomomorphism and IsANFAutomorphismRep, 1811 IsFieldHomomorphism and IsANFAutomorphismRep ], 1812 function ( aut1, aut2 ) 1813 return Source( aut1 ) < Source( aut2 ) 1814 or ( Source( aut1 ) = Source( aut2 ) 1815 and aut1!.galois < aut2!.galois ); 1816 end ); 1817 1818InstallMethod( \<, 1819 "for identity mapping and ANF automorphism", 1820 IsIdenticalObj, 1821 [ IsMapping and IsOne, 1822 IsFieldHomomorphism and IsANFAutomorphismRep ], 1823 function ( id, aut ) 1824 return Source( id ) < Source( aut ) 1825 or ( Source( id ) = Source( aut ) 1826 and 1 < aut!.galois ); 1827 end ); 1828 1829InstallMethod( \<, 1830 "for ANF automorphism and identity mapping", 1831 IsIdenticalObj, 1832 [ IsFieldHomomorphism and IsANFAutomorphismRep, 1833 IsMapping and IsOne ], 1834 function ( aut, id ) 1835 return Source( aut ) < Source( id ); 1836 end ); 1837 1838 1839############################################################################# 1840## 1841#M ImageElm( <aut>, <cyc> ) . . for automorphisms of abelian number fields 1842## 1843InstallMethod( ImageElm, 1844 "for ANF automorphism and scalar", 1845 FamSourceEqFamElm, 1846 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsCyc ], 1847 function ( aut, elm ) 1848 return GaloisCyc( elm, aut!.galois ); 1849 end ); 1850 1851 1852############################################################################# 1853## 1854#M ImagesElm( <aut>, <cyc> ) . . for automorphisms of abelian number fields 1855## 1856InstallMethod( ImagesElm, 1857 "for ANF automorphism and scalar", 1858 FamSourceEqFamElm, 1859 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], 1860 function ( aut, elm ) 1861 return [ GaloisCyc( elm, aut!.galois ) ]; 1862 end ); 1863 1864 1865############################################################################# 1866## 1867#M ImagesSet( <aut>, <field> ) . for automorphisms of abelian number fields 1868## 1869InstallMethod( ImagesSet, 1870 "for ANF automorphism and field", 1871 CollFamSourceEqFamElms, 1872 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsField ], 1873 function ( aut, F ) 1874 return F; 1875 end ); 1876 1877 1878############################################################################# 1879## 1880#M ImagesRepresentative( <aut>, <cyc> ) . . for autom. of ab. number fields 1881## 1882InstallMethod( ImagesRepresentative, 1883 "for ANF automorphism and scalar", 1884 FamSourceEqFamElm, 1885 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], 1886 function ( aut, elm ) 1887 return GaloisCyc( elm, aut!.galois ); 1888 end ); 1889 1890 1891############################################################################# 1892## 1893#M PreImageElm( <aut>, <cyc> ) . . . . . . . for autom. of ab. number fields 1894## 1895InstallMethod( PreImageElm, 1896 "for ANF automorphism and scalar", 1897 FamRangeEqFamElm, 1898 [ IsFieldHomomorphism and IsBijective and IsANFAutomorphismRep, 1899 IsScalar ], 1900 function ( aut, elm ) 1901 return GaloisCyc( elm, ( 1 / aut!.galois ) 1902 mod Conductor( Range( aut ) ) ); 1903 end ); 1904 1905 1906############################################################################# 1907## 1908#M PreImagesElm( <aut>, <cyc> ) . . . . . . for autom. of ab. number fields 1909## 1910InstallMethod( PreImagesElm, 1911 "for ANF automorphism and scalar", 1912 FamRangeEqFamElm, 1913 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], 1914 function ( aut, elm ) 1915 return [ GaloisCyc( elm, ( 1 / aut!.galois ) 1916 mod Conductor( Range( aut ) ) ) ]; 1917 end ); 1918 1919 1920############################################################################# 1921## 1922#M PreImagesSet( <aut>, <field> ) . . . . . for autom. of ab. number fields 1923## 1924InstallMethod( PreImagesSet, 1925 "for ANF automorphism and scalar", 1926 CollFamRangeEqFamElms, 1927 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsField ], 1928 function ( aut, F ) 1929 return F; 1930 end ); 1931 1932 1933############################################################################# 1934## 1935#M PreImagesRepresentative( <aut>, <cyc> ) . for autom. of ab. number fields 1936## 1937InstallMethod( PreImagesRepresentative, 1938 "for ANF automorphism and scalar", 1939 FamRangeEqFamElm, 1940 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], 1941 function ( aut, elm ) 1942 return GaloisCyc( elm, ( 1 / aut!.galois ) 1943 mod Conductor( Range( aut ) ) ); 1944 end ); 1945 1946 1947############################################################################# 1948## 1949#M CompositionMapping2( <aut2>, <aut1> ) . . for autom. of ab. number fields 1950## 1951InstallMethod( CompositionMapping2, 1952 "for two ANF automorphisms", 1953 FamSource1EqFamRange2, 1954 [ IsFieldHomomorphism and IsANFAutomorphismRep, 1955 IsFieldHomomorphism and IsANFAutomorphismRep ], 1956 function ( aut1, aut2 ) 1957 return ANFAutomorphism( Source( aut1 ), aut1!.galois * aut2!.galois ); 1958 end ); 1959 1960 1961############################################################################# 1962## 1963#M InverseGeneralMapping( <aut> ) . . . . . for autom. of ab. number fields 1964## 1965InstallOtherMethod( InverseGeneralMapping, 1966 "for ANF automorphism", 1967 [ IsFieldHomomorphism and IsANFAutomorphismRep ], 1968 aut -> ANFAutomorphism( Source( aut ), 1 / aut!.galois ) ); 1969 1970 1971############################################################################# 1972## 1973#M \^( <aut>, <n> ) . . . . . . . . . . . . for autom. of ab. number fields 1974## 1975InstallMethod( \^, 1976 "for ANF automorphism and integer", 1977 [ IsFieldHomomorphism and IsANFAutomorphismRep, IsInt ], 1978 function ( aut, i ) 1979 return ANFAutomorphism( Source( aut ), aut!.galois^i ); 1980 end ); 1981 1982 1983############################################################################# 1984## 1985#M PrintObj( <aut> ) . . . . . . . . . . . . for autom. of ab. number fields 1986## 1987InstallMethod( PrintObj, 1988 "for ANF automorphism", 1989 [ IsFieldHomomorphism and IsANFAutomorphismRep ], 1990 function ( aut ) 1991 Print( "ANFAutomorphism( ", Source( aut ), ", ", aut!.galois, " )" ); 1992 end ); 1993 1994 1995############################################################################# 1996## 1997#M GaloisGroup( <F> ) . . . . . . . Galois group of an abelian number field 1998## 1999## The required group is a factor group of the Galois group $G$ 2000## of the enveloping cyclotomic field. 2001## So the group $U$ generated by the actions of the generators of $G$ on <F> 2002## is the Galois group of <F>, viewed as field over the rationals. 2003## 2004## If <F> is a field over a proper extension of the rationals then we take 2005## the pointwise stabilizer of the subfield in $U$. 2006## 2007InstallMethod( GaloisGroup, 2008 "for abelian number field ", 2009 [ IsAbelianNumberField ], 2010 function( F ) 2011 local group; 2012 2013 group:= GroupByGenerators( List( Flat( 2014 GeneratorsPrimeResidues( Conductor( F ) ).generators ), 2015 x -> ANFAutomorphism( F, x ) ), 2016 IdentityMapping( F ) ); 2017 2018 if not IsPrimeField( LeftActingDomain( F ) ) then 2019 group:= Stabilizer( group, 2020 GeneratorsOfField( LeftActingDomain( F ) ), OnTuples ); 2021 fi; 2022 2023 return group; 2024end ); 2025 2026 2027InstallMethod( Representative, [IsCyclotomicField], f->0); 2028