File: Radicals.gi

package info (click to toggle)
gap-radiroot 2.9-1
  • links: PTS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 556 kB
  • sloc: makefile: 117; sh: 12
file content (395 lines) | stat: -rw-r--r-- 13,290 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
#############################################################################
####
##
#W  Radicals.gi               RADIROOT package                Andreas Distler
##
##  Installation file for the main function of the RADIROOT package
##
#Y  2006
##


#############################################################################
##
#F  RR_RootOfUnity( <erw>, <ord> )
##
##  Computes a <ord>-th root of unity built up on the roots of unity
##  that already exists in the field of the record <erw>
##
InstallGlobalFunction( RR_RootOfUnity, function( erw, ord )
    local i, unity, cond, faktor, m;

    Info( InfoRadiroot, 2, "    Finding root of unity" );
    unity := One( erw.K );
    if ord = 1 then
        return unity;
    fi;
    cond := 1;
    m := 1;
    for i in DuplicateFreeList( Factors( ord ) ) do
        # first factor of the i-th cyclotomic polynomial in H
        faktor:=FactorsPolynomialAlgExt(erw.H,
                                        CyclotomicPolynomial(Rationals,i))[1];
        Info( InfoRadiroot, 3,"        Cyclotomic polynomial factor: ",
                              faktor );

        if Degree( faktor ) = i-1 then
	    cond := cond * i; #unity := unity * E( i );
            Info( InfoRadiroot, 4, "            Adjoining ", i,
                                   "-th root of unity" );
	elif Degree( faktor ) = 1 then
	    unity := unity * Image( IsomorphismMatrixField( erw.H ),
                                    -Value( faktor, 0 ) );
            Info( InfoRadiroot, 4, "            Calculate ", i,
                                   "-th root of unity" );
        else
            m := i * m; 
	fi;
    od;

    if  m = 1 then
        return E( cond ) * unity;
    else
        return m * Order( unity );
    fi;
end );


#############################################################################
##
#M  IsSolvablePolynomial( <f> )
#M  IsSolvable( <f> )
##
##  Determines whether the rational polynomial <f> is solvable, e. g. whether
##  its Galois group is solvable
##
InstallMethod( IsSolvablePolynomial, "for a rational polynomial", 
[ IsUnivariateRationalFunction and IsPolynomial ], 0,
function( f )

    if not ForAll( CoefficientsOfUnivariatePolynomial( f ), IsRat ) then
        TryNextMethod( );
    fi;

    f := RR_SimplifiedPolynomial( f );
    return ForAll( Filtered( List( Factors(f), RR_SimplifiedPolynomial ),
                             ff -> Degree(ff) <> 1 ),
                   ff -> IsSolvableGroup( TransitiveGroup( Degree(ff),
                                          GaloisType(ff) ) ) );
end );

InstallMethod( IsSolvable, "rational polynomials", [ IsPolynomial ],
               IsSolvablePolynomial );

#############################################################################
##
#M  IsSeparablePolynomial( <f> )
##
##  Determines whether the rational polynomial <f> is separable, e.g. whether
##  it has single roots only
##
InstallMethod( IsSeparablePolynomial, "for rational polynomial", 
[ IsUnivariateRationalFunction and IsPolynomial ], 0,
function( f )
    if not ForAll( CoefficientsOfUnivariatePolynomial( f ), IsRat ) then
        TryNextMethod( );
    fi;

    return Degree(Gcd( f, Derivative( f ))) = 0;
end );

#############################################################################
##
#M  RootsAsMatrices( <f> )
##
##  return a list of matrices with minimal polynomial <f>. The field 
##  generated by the matrices is a splitting field of <f>. The dimension of 
##  the matrices is equal to the dimension of the splitting field over the
##  Rationals
##
InstallMethod( RootsAsMatrices, "rational polynomials", 
[ IsUnivariateRationalFunction and IsPolynomial ], function( f )
    local L, roots, erw;

    if not ForAll( CoefficientsOfUnivariatePolynomial( f ), IsRat ) then
        TryNextMethod( );
    fi;

    if not IsSeparablePolynomial( f ) then
        Info(InfoWarning, 1, 
             "polynomial is not separable, list contains every root only once");
        # make polynomial separable
        f := f / Gcd( f, Derivative( f ) );    
    fi;

    if HasSplittingField( f ) then
        L := IsomorphicMatrixField( SplittingField( f ));
        roots := Filtered(Basis(L), mat -> Value(f,mat) = 0*One(L));
        if Length( roots ) < Degree( f ) - 1 then
            erw := rec( H := SplittingField( f ), K := L );
            roots:=RR_Roots([[],roots, 
                             List(FactorsPolynomialAlgExt(SplittingField(f),f),
                                  faktor -> -Value( faktor, 0 ) )], 
                            erw);;
        fi;
    else
        erw := RR_Zerfaellungskoerper(f, rec( roots := [ ],
                                              degs := [ ],
                                              coeffs := [ ],
                                              K:=FieldByMatrices([ [[ 1 ]] ]),
                                              H:=Rationals ));;
        L := erw.K;
        roots := RR_Roots( [ [ ], erw.roots[1], erw.roots[2] ], erw );;
     fi;

    Add( roots, 
         -CoefficientsOfUnivariatePolynomial( f )[Degree( f )]*One(L)
         -Sum( roots ) );

    return roots;
end );


#############################################################################
##
#F  RR_Roots( <roots>, <erw> )
##
##  The elements in the list of lists <roots> are in various forms. They are
##  transfered in a matrix representation and returned as duplicate free list
##
InstallGlobalFunction( RR_Roots, function( roots, erw )
    local i, root, B;    

    # Test whether there are already enough roots as matrices
    if Length(roots[1]) + Length(roots[2]) >= Length(roots[3]) then
        return roots[2];
    fi;

    B := EquationOrderBasis( erw.K, PrimitiveElement( erw.K ));

    # kick out known symbolic roots
    for root in Concatenation(roots[1], roots[2]) do
        root := LinearCombination( Basis( erw.H ), Coefficients( B, root ) );
        roots[3] := Difference( roots[3], [ root ] );
    od;

    # compute the other roots
    if roots[1] = [ ] then Unbind(roots[3][Length(roots[3])]); fi; 
    for root in roots[3] do
        Info(InfoRadiroot,3,"        Constructing ",Length(roots[2]),". root");
        Add( roots[2], LinearCombination( B, ExtRepOfObj( root )));
    od;
 
    return roots[2];
end );


#############################################################################
##
#F  RR_SimplifiedPolynomial( <f> )
##
##  returns the polynomial g(x) with g(x^n) = f(x-a) with greatest possible n
##  for the polynomial <f>
##
InstallGlobalFunction( RR_SimplifiedPolynomial, function( f )
    local deg, coeff, gcd, poly;

    deg := Degree( f );

    poly := f / LeadingCoefficient( f );
    poly := Value( poly, UnivariatePolynomial( Rationals,
        [-CoefficientsOfUnivariatePolynomial(poly)[deg] / deg, 1] ) );
    coeff := CoefficientsOfUnivariatePolynomial( poly );
    gcd := Gcd(Filtered( [0..Degree(f)], i -> not coeff[i+1] = 0));
    if gcd = 1 then
        return f / LeadingCoefficient(f);
    fi;

    return UnivariatePolynomial(Rationals,
                                List([0..deg/gcd], i -> coeff[i*gcd+1]));
end );


#############################################################################
##
#F  RootsOfPolynomialAsRadicals( <f>, [ <mode> , <file> ] )
#F  RootsOfPolynomialAsRadicalsNC( <f>, [ <mode> , <file> ] )
##
##  For the irreducible, rational polynomial <f> a representation of the
##  roots as radicals is computed if this is possible, e. g. if the
##  Galois group of <f> is solvable.
##
InstallGlobalFunction( RootsOfPolynomialAsRadicals, function( arg )

    local f;

    f := arg[1];
 
    if Length( arg ) >= 2 and arg[2] = "off" then
        if not IsSeparablePolynomial( f ) then 
            Error( "f must be separable" );
        fi;
        CallFuncList( RootsOfPolynomialAsRadicalsNC, arg );

    else
        # irreducibility test
        if not IsIrreducible( f ) then
            Error( "f must be irreducible" );
        fi;

        # solvibility test
        if not IsSolvable( f ) then
            Info( InfoRadiroot, 1, "Polynomial is not solvable." );
            Info( InfoRadiroot, 3, "        GaloisType is ", GaloisType( f ) );
            return fail;
        fi; 

        Info( InfoRadiroot, 3, "        GaloisType is ", GaloisType( f ) );
        Info( InfoRadiroot, 2, "    Galoisgroup is ",
                               TransitiveGroup( Degree( f ), GaloisType( f )));

        return  CallFuncList( RootsOfPolynomialAsRadicalsNC, arg );
    fi;
end );


InstallGlobalFunction( RootsOfPolynomialAsRadicalsNC, function( arg )
    local erw,elements,lcm,conj,bas,file,dir,poly,B,fix,compser,f,mode,path;

    f := arg[1];

    if 1 = Length( arg ) then
        mode := "dvi";
    else
        mode := arg[2];
    fi;

    while not mode in [ "off", "dvi", "maple", "latex" ] do
        Error( "<mode> has to be a valid option" );
    od;
    
    # normed, simplified polynomial
    if mode <> "off" then
        # irreducibility test
        if not IsIrreducible( f ) then
            Error( "f must be irreducible" );
        fi;
        poly := RR_SimplifiedPolynomial( f );
        Info( InfoRadiroot, 2, "    Normed, simplified Polynomial: ", poly );
    else
        if LeadingCoefficient( f ) <> 1 then
            Error( "f must be a normed polynomial" );
        fi;
        poly := f;
    fi;
   
    Info( InfoRadiroot, 2, "    Construction of the splitting field" );
    erw := RR_Zerfaellungskoerper( poly, rec( roots := [ ],
                                              degs := [ ],
                                              coeffs := [ ],
                                              K:=FieldByMatrices([ [[ 1 ]] ]),
                                              H:=Rationals ));;

    # get all roots, set a basis of the primitive element
    erw.roots := RR_Roots( [ [], erw.roots[1], erw.roots[2] ], erw );;
    Add( erw.roots, 
         -CoefficientsOfUnivariatePolynomial(poly)[Degree(poly)]*One(erw.K)
         -Sum( erw.roots ) );
    SetRootsAsMatrices( poly, erw.roots );

    # get structure of primitive element to use RR_Produkt
    erw.coeffs := Filtered(Coefficients(Basis(erw.K),PrimitiveElement(erw.K)),
                           i -> i <> 0 );

    # for mode "off" it remains to compute the Galois group
    if mode = "off" then
        if not HasGaloisGroupOnRoots( poly ) then
            erw.unity := 1;
            erw.galgrp := RR_ConstructGaloisGroup( erw );
            SetGaloisGroupOnRoots( poly, erw.galgrp );
        fi;
        return;
    fi;

    # try to find root of unity, if fail start all over
    erw.unity := RR_RootOfUnity( erw, DegreeOverPrimeField(erw.K) );
    if IsInt(erw.unity) then 
        erw := RR_SplittField(poly, erw.unity );
        # need roots in bigger field
        erw.roots := RR_Roots( [ [], erw.roots[1], erw.roots[2] ], erw );;
        Add(erw.roots, 
            -CoefficientsOfUnivariatePolynomial(poly)[Degree(poly)]
            *One(erw.K) - Sum( erw.roots ) );
        erw.coeffs := Filtered( Coefficients( Basis( erw.K ),
                                              PrimitiveElement( erw.K )),
                                i -> i <> 0 );
        erw.galgrp := RR_ConstructGaloisGroup( erw );
    elif HasGaloisGroupOnRoots( poly ) then
        erw.galgrp := GaloisGroupOnRoots( poly );
    else
        erw.galgrp := RR_ConstructGaloisGroup( erw );
        SetGaloisGroupOnRoots( poly, erw.galgrp );
    fi;

    Info( InfoRadiroot, 2, "    Galoisgroup as PermGrp is ", erw.galgrp );

    if not IsSolvable( erw.galgrp ) then
        Info( InfoRadiroot, 1, "Polynomial is not solvable." );
        return fail;
    fi; 

    Info(InfoRadiroot,4,"            h := Lcm( Order( Galoisgroup ) ) = ",
                        Product(Unique(Factors(Order(erw.galgrp)))) );
    if IsDiagonalMat( erw.unity ) then
        Info( InfoRadiroot, 3, 
              "        no root of unity in the splitting field"); 
        compser := CompositionSeries( erw.galgrp );
    elif Length( erw.degs ) <> Length( erw.coeffs ) then
        compser := CompositionSeries( erw.galgrp );
    else
        fix := Filtered(AsList(erw.galgrp), 
                        p -> RR_Produkt(erw, erw.unity, p) = erw.unity);
        compser := RR_CompositionSeries( erw.galgrp, AsGroup( fix ));
    fi; 
    erw.K!.cyclics := RR_CyclicElements( erw, compser );;
    Info( InfoRadiroot, 2, "    computed cyclic elements" );

    if 3 = Length( arg ) then
        file := arg[3];
        dir := DirectoryCurrent( );
    else
        dir := DirectoryTemporary( );
        file := "Nst";
    fi;
    if mode <> "maple" then
        if 3 = Length(arg) and IsExistingFile(Concatenation(file, ".tex")) then
            Error( file, ".tex already exists" );
        fi;
        path := RR_TexFile( f, erw, erw.K!.cyclics, dir, 
                            Concatenation( file, ".tex" ) );
        if mode = "dvi" then
            RR_Display( file, dir );
        fi;
    else
        if 3 = Length(arg) and IsExistingFile(file) then
            Error( file, " already exists" );
        fi;
        path := RR_MapleFile( f, erw, erw.K!.cyclics, Filename(dir,file));
    fi;
    return path;

end );


#############################################################################
##
#E