Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  field.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Martin Schönert.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##
##  This file contains generic methods for division rings.
##


#############################################################################
##
#M  DivisionRingByGenerators( <gens> )  . . . . . . . . . .  for a collection
#M  DivisionRingByGenerators( <F>, <gens> )   . . for div.ring and collection
##
InstallOtherMethod( DivisionRingByGenerators,
    "for a collection",
    [ IsCollection ],
    coll -> DivisionRingByGenerators(
        FieldOverItselfByGenerators( [ One( Representative( coll ) ) ] ),
        coll ) );

InstallMethod( DivisionRingByGenerators,
    "for a division ring, and a collection",
    IsIdenticalObj,
    [ IsDivisionRing, IsCollection ],
    function( F, gens )
    local D;
    D:= Objectify( NewType( FamilyObj( gens ),
                            IsField and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( D, F );
    SetGeneratorsOfDivisionRing( D, AsList( gens ) );
    return D;
    end );


#############################################################################
##
#M  FieldOverItselfByGenerators( <gens> )
##
InstallMethod( FieldOverItselfByGenerators,
    "for a collection",
    [ IsCollection ],
    function( gens )
    local F;
    if IsEmpty( gens ) then
      Error( "need at least one element" );
    fi;
    F:= Objectify( NewType( FamilyObj( gens ),
                            IsField and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( F, F );
    SetGeneratorsOfDivisionRing( F, gens );
    return F;
    end );


#############################################################################
##
#M  DefaultFieldByGenerators( <gens> )  . . . . . . . . . .  for a collection
##
InstallMethod( DefaultFieldByGenerators,
    "for a collection",
    [ IsCollection ],
    DivisionRingByGenerators );


#############################################################################
##
#F  Field( <z>, ... ) . . . . . . . . . field generated by a list of elements
#F  Field( [ <z>, ... ] )
#F  Field( <F>, [ <z>, ... ] )
##
InstallGlobalFunction( Field, function ( arg )
    local   F;          # field containing the elements of <arg>, result

    # special case for one square matrix
    if    Length(arg) = 1
        and IsMatrix( arg[1] ) and Length( arg[1] ) = Length( arg[1][1] )
    then
        F := FieldByGenerators( arg );

    # special case for list of elements
    elif Length(arg) = 1  and IsList(arg[1])  then
        F := FieldByGenerators( arg[1] );

    # special case for subfield and generators
    elif Length(arg) = 2  and IsField(arg[1])  then
        F := FieldByGenerators( arg[1], arg[2] );

    # other cases
    else
        F := FieldByGenerators( arg );
    fi;

    # return the field
    return F;
end );


#############################################################################
##
#F  DefaultField( <z>, ... )  . . . . . default field containing a collection
##
InstallGlobalFunction( DefaultField, function ( arg )
    local   F;          # field containing the elements of <arg>, result

    # special case for one square matrix
    if    Length(arg) = 1
        and IsMatrix( arg[1] ) and Length( arg[1] ) = Length( arg[1][1] )
    then
        F := DefaultFieldByGenerators( arg );

    # special case for list of elements
    elif Length(arg) = 1  and IsList(arg[1])  then
        F := DefaultFieldByGenerators( arg[1] );

    # other cases
    else
        F := DefaultFieldByGenerators( arg );
    fi;

    # return the default field
    return F;
end );


#############################################################################
##
#F  Subfield( <F>, <gens> ) . . . . . . . subfield of <F> generated by <gens>
#F  SubfieldNC( <F>, <gens> )
##
InstallGlobalFunction( Subfield, function( F, gens )
    local S;
    if IsEmpty( gens ) then
      return PrimeField( F );
    elif     IsHomogeneousList( gens )
         and IsIdenticalObj( FamilyObj( F ), FamilyObj( gens ) )
         and ForAll( gens, g -> g in F ) then
      S:= FieldByGenerators( LeftActingDomain( F ), gens );
      SetParent( S, F );
      return S;
    fi;
    Error( "<gens> must be a list of elements in <F>" );
end );

InstallGlobalFunction( SubfieldNC, function( F, gens )
    local S;
    if IsEmpty( gens ) then
      S:= Objectify( NewType( FamilyObj( F ),
                              IsDivisionRing and IsAttributeStoringRep ),
                     rec() );
      SetLeftActingDomain( S, F );
      SetGeneratorsOfDivisionRing( S, AsList( gens ) );
    else
      S:= DivisionRingByGenerators( LeftActingDomain( F ), gens );
    fi;
    SetParent( S, F );
    return S;
end );


#############################################################################
##
#M  ClosureDivisionRing( <D>, <d> ) . . . . . . . . . closure with an element
##
InstallMethod( ClosureDivisionRing,
    "for a division ring and a scalar",
    IsCollsElms,
    [ IsDivisionRing, IsScalar ],
    function( D, d )

    # if possible test if the element lies in the division ring already,
    if     HasGeneratorsOfDivisionRing( D )
       and d in GeneratorsOfDivisionRing( D ) then
      return D;

    # otherwise make a new division ring
    else
      return DivisionRingByGenerators( LeftActingDomain( D ),
                 Concatenation( GeneratorsOfDivisionRing( D ), [ d ] ) );
    fi;
    end );


InstallMethod( ClosureDivisionRing,
    "for a division ring containing the whole family, and a scalar",
    IsCollsElms,
    [ IsDivisionRing and IsWholeFamily, IsScalar ],
    SUM_FLAGS, # we can't be better than this
    ReturnFirst);

#############################################################################
##
#M  ClosureDivisionRing( <D>, <C> ) . . . . . . . .  closure of division ring
##
InstallMethod( ClosureDivisionRing,
    "for division ring and collection of elements",
    IsIdenticalObj,
    [ IsDivisionRing, IsCollection ],
    function( D, C )
    local   d;          # one generator

    if IsDivisionRing( C ) then
      if not IsSubset( LeftActingDomain( D ), LeftActingDomain( C ) ) then
        C:= AsDivisionRing( Intersection( LeftActingDomain( C ),
                                          LeftActingDomain( D ) ), C );
      fi;
      C:= GeneratorsOfDivisionRing( C );
    elif not IsList( C ) then
      TryNextMethod();
    fi;

    for d in C do
      D:= ClosureDivisionRing( D, d );
    od;

    return D;
    end );

InstallMethod( ClosureDivisionRing,
    "for division ring and empty list",
    [ IsDivisionRing, IsList and IsEmpty ],
    ReturnFirst);


#############################################################################
##
#M  ViewObj( <F> )  . . . . . . . . . . . . . . . . . . . . . .  view a field
##
InstallMethod( ViewObj,
    "for a field",
    [ IsField ],
    function( F )
    if HasSize( F ) and IsInt( Size( F ) ) then
      Print( "<field of size ", String(Size( F )), ">" );
    else
      Print( "<field in characteristic ", Characteristic( F ), ">" );
    fi;
    end );


#############################################################################
##
#M  ViewString( <F> ) . . . . . . . . . . . . . . . . . . . . .  view a field
##
InstallMethod( ViewString,
    "for a field",
    [ IsField ],
    function( F )
    if HasSize( F ) and IsInt( Size( F ) ) then
      return Concatenation("<field of size ", String(Size( F )), ">" );
    else
      return Concatenation( "<field in characteristic ",
                            String(Characteristic( F )), ">" );
    fi;
    end );


#############################################################################
##
#M  PrintObj( <F> ) . . . . . . . . . . . . . . . . . . . . . . print a field
##
InstallMethod( PrintObj,
    "for a field with known generators",
    [ IsField and HasGeneratorsOfField ],
    function( F )
      if IsIdenticalObj(F,LeftActingDomain(F)) or
        IsPrimeField( LeftActingDomain( F ) ) then
      Print( "Field( ", GeneratorsOfField( F ), " )" );
    elif F = LeftActingDomain( F ) then
      Print( "FieldOverItselfByGenerators( ",
             GeneratorsOfField( F ), " )" );
    else
      Print( "AsField( ", LeftActingDomain( F ),
             ", Field( ", GeneratorsOfField( F ), " ) )" );
    fi;
    end );

InstallMethod( PrintObj,
    "for a field",
    [ IsField ],
    function( F )
    if IsPrimeField( LeftActingDomain( F ) ) then
      Print( "Field( ... )" );
    elif F = LeftActingDomain( F ) then
      Print( "AsField( ~, ... )" );
    else
      Print( "AsField( ", LeftActingDomain( F ), ", ... )" );
    fi;
    end );


#############################################################################
##
#M  IsTrivial( <F> )  . . . . . . . . . . . . . . . . . . for a division ring
##
InstallMethod( IsTrivial,
    "for a division ring",
    [ IsDivisionRing ],
    ReturnFalse );


#############################################################################
##
#M  PrimeField( <F> ) . . . . . . . . . . . . . . . . . . for a division ring
##
InstallMethod( PrimeField,
    "for a division ring",
    [ IsDivisionRing ],
    function( F )
    local P;
    P:= Field( One( F ) );
    UseSubsetRelation( F, P );
    SetIsPrimeField( P, true );
    return P;
    end );

InstallMethod( PrimeField,
    "for a prime field",
    [ IsField and IsPrimeField ],
    IdFunc );


#############################################################################
##
#M  IsPrimeField( <F> ) . . . . . . . . . . . . . . . . . for a division ring
##
InstallMethod( IsPrimeField,
    "for a division ring",
    [ IsDivisionRing ],
    F -> DegreeOverPrimeField( F ) = 1 );


#############################################################################
##
#M  IsNumberField( <F> )  . . . . . . . . . . . . . . . . . . . . for a field
##
InstallMethod( IsNumberField,
    "for a field",
    [ IsField ],
    F -> Characteristic( F ) = 0 and IsInt( DegreeOverPrimeField( F ) ) );


#############################################################################
##
#M  IsAbelianNumberField( <F> ) . . . . . . . . . . . . . . . . . for a field
##
InstallMethod( IsAbelianNumberField,
    "for a field",
    [ IsField ],
    F -> IsNumberField( F ) and IsCommutative( GaloisGroup(
                                         AsField( PrimeField( F ), F ) ) ) );


#############################################################################
##
#M  IsCyclotomicField( <F> )  . . . . . . . . . . . . . . . . . . for a field
##
InstallMethod( IsCyclotomicField,
    "for a field",
    [ IsField ],
    F ->     IsAbelianNumberField( F )
         and Conductor( F ) = DegreeOverPrimeField( F ) );


#############################################################################
##
#M  IsNormalBasis( <B> )  . . . . . . . . . . . . .  for a basis (of a field)
##
InstallMethod( IsNormalBasis,
    "for a basis of a field",
    [ IsBasis ],
    function( B )
    local vectors;
    if not IsField( UnderlyingLeftModule( B ) ) then
      Error( "<B> must be a basis of a field" );
    fi;
    vectors:= BasisVectors( B );
    return Set( vectors )
           = Set( Conjugates( UnderlyingLeftModule( B ), vectors[1] ) );
    end );


#############################################################################
##
#M  GeneratorsOfDivisionRing( <F> ) . . . . . . . . . . . . for a prime field
##
InstallMethod( GeneratorsOfDivisionRing,
    "for a prime field",
    [ IsField and IsPrimeField ],
    F -> [ One( F ) ] );


#############################################################################
##
#M  DegreeOverPrimeField( <F> ) . . . . . . . . . . . . . . for a prime field
##
InstallImmediateMethod( DegreeOverPrimeField, IsPrimeField, 20, F -> 1 );


#############################################################################
##
#M  NormalBase( <F> ) . . . . . . . . . .  for a field in characteristic zero
#M  NormalBase( <F>, <elm> )  . . . . . .  for a field in characteristic zero
##
##  For fields in characteristic zero, a normal basis is computed
##  as described on p.~65~f.~in~\cite{Art68}.
##  Let $\Phi$ denote the polynomial of the field extension $L/L^{\prime}$,
##  $\Phi^{\prime}$ its derivative and $\alpha$ one of its roots;
##  then for all except finitely many elements $z \in L^{\prime}$,
##  the conjugates of $\frac{\Phi(z)}{(z-\alpha)\cdot\Phi^{\prime}(\alpha)}$
##  form a normal basis of $L/L^{\prime}$.
##
##  When `NormalBase' is called for a field <F> in characteristic zero and
##  an element <elm>,
##  $z$ is chosen as <elm>, $<elm> + 1$, $<elm> + 2$, \ldots,
##  until a normal basis is found.
##  The default of <elm> is the identity of <F>.
##
InstallMethod( NormalBase,
    "for a field (in characteristic zero)",
    [ IsField ],
    F -> NormalBase( F, One( F ) ) );

InstallMethod( NormalBase,
    "for a field (in characteristic zero), and a scalar",
    [ IsField, IsScalar ],
    function( F, z )

    local alpha, poly, i, val, normal;

    # Check the arguments.
    if Characteristic( F ) <> 0 then
      TryNextMethod();
    elif not z in F then
      Error( "<z> must be an element in <F>" );
    fi;

    # Get a primitive element `alpha'.
    alpha:= PrimitiveElement( F );

    # Construct the polynomial
    # $\prod_{\sigma\in `Gal( alpha )'\setminus \{1\} } (x-\sigma(`alpha') )
    # for the primitive element `alpha'.
    poly:= [ 1 ];
    for i in Difference( Conjugates( F, alpha ), [ alpha ] ) do
      poly:= ProductCoeffs( poly, [ -i, 1 ] );
#T ?
    od;

    # For the denominator, evaluate `poly' at `a'.
    val:= Inverse( ValuePol( poly, alpha ) );

    # There are only finitely many values `x' in the subfield
    # for which `poly(x) * val' is not an element of a normal basis.
    repeat
      normal:= Conjugates( F, ValuePol( poly, z ) * val );
      z:= z + 1;
    until RankMat( List( normal, COEFFS_CYC ) ) = Dimension( F );

    # Return the result.
    return normal;
    end );


#############################################################################
##
#M  PrimitiveElement( <D> ) . . . . . . . . . . . . . . . for a division ring
##
InstallMethod( PrimitiveElement,
    "for a division ring",
    [ IsDivisionRing ],
    function( D )
    D:= GeneratorsOfDivisionRing( D );
    if Length( D ) = 1 then
      return D[1];
    else
      TryNextMethod();
    fi;
    end );


#############################################################################
##
#M  Representative( <D> ) . . . . . for a division ring with known generators
##
InstallMethod( Representative,
    "for a division ring with known generators",
    [ IsDivisionRing and HasGeneratorsOfDivisionRing ],
    RepresentativeFromGenerators( GeneratorsOfDivisionRing ) );


#############################################################################
##
#M  Enumerator( <F> ) . . . . . . . . . .  elements of a (finite) prime field
#M  EnumeratorSorted( <F> ) . . . . . . .  elements of a (finite) prime field
##
##  We install a special method only for (finite) prime fields,
##  since the other cases are handled by the vector space methods.
##
BindGlobal( "EnumeratorOfPrimeField", function( F )
    local one;
    one:= One( F );
    if   Size( F ) <= MAXSIZE_GF_INTERNAL then
      return AsSSortedListList( List( [ 0 .. Size( F ) - 1 ], i -> i * one ) );
    elif IsZmodnZObj( one ) then
      return EnumeratorOfZmodnZ( F );
    fi;
    TryNextMethod();
end );

InstallMethod( Enumerator,
    "for a finite prime field",
    [ IsField and IsPrimeField and IsFinite ],
    EnumeratorOfPrimeField );

InstallMethod( EnumeratorSorted,
    "for a finite prime field",
    [ IsField and IsPrimeField and IsFinite ],
    EnumeratorOfPrimeField );

InstallMethod( AsList,
    "for a finite prime field",
    [ IsField and IsPrimeField and IsFinite ],
    F -> AsList( Enumerator( F ) ) );


#############################################################################
##
#M  IsSubset( <D>, <F> )  . . . . . . . . . . . . . .  for two division rings
##
##  We have to be careful not to run into an infinite recursion in the case
##  that <F> is equal to its left acting domain.
##  Also we must be aware of situations where the left acting domains are
##  in a family different from that of the fields themselves,
##  for example <D> could be given as a field over a field that is really
##  a subset of <D>, whereas the left acting domain of <F> is not a subset
##  of <F>.
##
BindGlobal( "DivisionRing_IsSubset", function( D, F )
    local CF;

    # Special case for when F equals the cyclotomics (and hence is infinite
    # dimensional over its left acting domain).
    if IsIdenticalObj(F, Cyclotomics) then
      return IsIdenticalObj(D, Cyclotomics);
    fi;

    CF:= LeftActingDomain( F );

    if not IsSubset( D, GeneratorsOfDivisionRing( F ) ) then
      return false;
    elif IsSubset( LeftActingDomain( D ), CF ) or IsPrimeField( CF ) then
      return true;
    elif FamilyObj( F ) = FamilyObj( CF ) then
      return IsSubset( D, CF );
    else
      CF:= AsDivisionRing( PrimeField( CF ), CF );
      return IsSubset( D, List( GeneratorsOfDivisionRing( CF ),
                                x -> x * One( F ) ) );
    fi;
end );

InstallMethod( IsSubset,
    "for two division rings",
    IsIdenticalObj,
    [ IsDivisionRing, IsDivisionRing ],
    DivisionRing_IsSubset );


#############################################################################
##
#M  \=( <D>, <F> )  . . . . . . . . . . . . . . . . .  for two division rings
##
InstallMethod( \=,
    "for two division rings",
    IsIdenticalObj,
    [ IsDivisionRing, IsDivisionRing ],
    function( D, F )
    return DivisionRing_IsSubset( D, F ) and DivisionRing_IsSubset( F, D );
    end );


#############################################################################
##
#M  AsDivisionRing( <C> ) . . . . . . . . . . . . . . . . .  for a collection
##
InstallMethod( AsDivisionRing,
    "for a collection",
    [ IsCollection ],
    function( C )

    local one, F;

    # A division ring contains at least two elements.
    if IsEmpty( C ) or IsTrivial( C ) then
      return fail;
    fi;

    # Construct the prime field.
    one:= One( Representative( C ) );
    if one = fail then
      return fail;
    fi;
    F:= FieldOverItselfByGenerators( [ one ] );

    # Delegate to the two-argument version.
    return AsDivisionRing( F, C );
    end );


#############################################################################
##
#M  AsDivisionRing( <F>, <C> )  . . . . for a division ring, and a collection
##
InstallMethod( AsDivisionRing,
    "for a division ring, and a collection",
    IsIdenticalObj,
    [ IsDivisionRing, IsCollection ],
    function( F, C )

    local D;

    if not IsSubset( C, F ) then
      return fail;
    fi;

    D:= DivisionRingByGenerators( F, C );
    if D <> C then
      return fail;
    fi;

    return D;
    end );


#############################################################################
##
#M  AsDivisionRing( <F>, <D> )  . . . . . . . . . . .  for two division rings
##
InstallMethod( AsDivisionRing,
    "for two division rings",
    IsIdenticalObj,
    [ IsDivisionRing, IsDivisionRing ],
    function( F, D )
    local E;

    if   F = LeftActingDomain( D ) then
      return D;
    elif not IsSubset( D, F ) then
      return fail;
    fi;

    E:= DivisionRingByGenerators( F, GeneratorsOfDivisionRing( D ) );

    UseIsomorphismRelation( D, E );
    UseSubsetRelation( D, E );

    return E;
    end );


#############################################################################
##
#M  AsLeftModule( <F1>, <F2> )  . . . . . . . . . . .  for two division rings
##
##  View the division ring <F2> as vector space over the division ring <F1>.
##
InstallMethod( AsLeftModule,
    "for two division rings",
    IsIdenticalObj,
    [ IsDivisionRing, IsDivisionRing ],
    AsDivisionRing );


#############################################################################
##
#M  Conjugates( <F>, <z> )  . . . . . . . . . . conjugates of a field element
#M  Conjugates( <z> ) . . . . . . . . . . . . . conjugates of a field element
##
InstallMethod( Conjugates,
    "for a scalar (delegate to version with default field)",
    [ IsScalar ],
    z -> Conjugates( DefaultField( z ), z ) );

InstallMethod( Conjugates,
    "for a field and a scalar (delegate to version with two fields)",
    IsCollsElms,
    [ IsField, IsScalar ],
    function( F, z )
    return Conjugates( F, LeftActingDomain( F ), z );
    end );


#############################################################################
##
#M  Conjugates( <L>, <K>, <z> ) . .  for a field elm. (use `TracePolynomial')
##
InstallMethod( Conjugates,
    "for two fields and a scalar (call `TracePolynomial')",
    IsCollsXElms,
    [ IsField, IsField, IsScalar ],
    function( L, K, z )

    local pol, lin, conj, mult, i;

    # Check whether `Conjugates' is allowed to call `MinimalPolynomial'.
    if IsFieldControlledByGaloisGroup( L ) then
      TryNextMethod();
    fi;

    # Compute the roots in `L' of the minimal polynomial of `z' over `K'.
    pol:= MinimalPolynomial( K, z );
    lin:= List( Filtered( Factors( L, pol ),
                          x -> DegreeOfLaurentPolynomial( x ) = 1 ),
                CoefficientsOfUnivariatePolynomial );
    lin:= List( lin, x -> AdditiveInverse( lin[1] / lin[2] ) );

    # Take the roots with the appropriate multiplicity.
    conj:= [];
    mult:= DegreeOverPrimeField( L ) / DegreeOverPrimeField( K );
    mult:= mult / DegreeOfLaurentPolynomial( pol );
    for i in [ 1 .. mult ] do
      Append( conj, lin );
    od;

    return conj;
    end );


#############################################################################
##
#M  Conjugates( <L>, <K>, <z> ) . . . for a field element (use `GaloisGroup')
##
InstallMethod( Conjugates,
    "for two fields and a scalar (call `GaloisGroup')",
    IsCollsXElms,
    [ IsFieldControlledByGaloisGroup, IsField, IsScalar ],
    function( L, K, z )
    local   cnjs,       # conjugates of <z> in <F>, result
            aut;        # automorphism of <F>

    # Check the arguments.
    if not z in L then
      Error( "<z> must lie in <L>" );
    fi;

    # Compute the conjugates simply by applying all the automorphisms.
    cnjs:= [];
    for aut in GaloisGroup( AsField( L, K ) ) do
      Add( cnjs, z ^ aut );
    od;

    # Return the conjugates.
    return cnjs;
    end );


#############################################################################
##
#M  Norm( <F>, <z> )  . . . . . . . . . . . . . . . . norm of a field element
#M  Norm( <z> ) . . . . . . . . . . . . . . . . . . . norm of a field element
##
InstallMethod( Norm,
    "for a scalar (delegate to version with default field)",
    [ IsScalar ],
    z -> Norm( DefaultField( z ), z ) );

InstallMethod( Norm,
    "for a field and a scalar (delegate to version with two fields)",
    IsCollsElms,
    [ IsField, IsScalar ],
    function( F, z )
    return Norm( F, LeftActingDomain( F ), z );
    end );


#############################################################################
##
#M  Norm( <L>, <K>, <z> ) . . . .  norm of a field element (use `Conjugates')
##
InstallMethod( Norm,
    "for two fields and a scalar (use `Conjugates')",
    IsCollsXElms,
    [ IsFieldControlledByGaloisGroup, IsField, IsScalar ],
    function( L, K, z )
    return Product( Conjugates( L, K, z ) );
    end );


#############################################################################
##
#M  Norm( <L>, <K>, <z> ) . . .  norm of a field element (use the trace pol.)
##
InstallMethod( Norm,
    "for two fields and a scalar (use the trace pol.)",
    IsCollsXElms,
    [ IsField, IsField, IsScalar ],
    function( L, K, z )
    local coeffs;
    coeffs:= CoefficientsOfUnivariatePolynomial(
                 TracePolynomial( L, K, z, 1 ) );
    return (-1)^(Length( coeffs )-1) * coeffs[1];
    end );


#############################################################################
##
#M  Trace( <z> )  . . . . . . . . . . . . . . . . .  trace of a field element
#M  Trace( <F>, <z> ) . . . . . . . . . . . . . . .  trace of a field element
##
InstallMethod( Trace,
    "for a scalar (delegate to version with default field)",
    [ IsScalar ],
    z -> Trace( DefaultField( z ), z ) );

InstallMethod( Trace,
    "for a field and a scalar (delegate to version with two fields)",
    IsCollsElms,
    [ IsField, IsScalar ],
    function( F, z )
    return Trace( F, LeftActingDomain( F ), z );
    end );


#############################################################################
##
#M  Trace( <L>, <K>, <z> )  . . . trace of a field element (use `Conjugates')
##
InstallMethod( Trace,
    "for two fields and a scalar (use `Conjugates')",
    IsCollsXElms,
    [ IsFieldControlledByGaloisGroup, IsField, IsScalar ],
    function( L, K, z )
    return Sum( Conjugates( L, K, z ) );
    end );


#############################################################################
##
#M  Trace( <L>, <K>, <z> )  . . trace of a field element (use the trace pol.)
##
InstallMethod( Trace,
    "for two fields and a scalar (use the trace pol.)",
    IsCollsXElms,
    [ IsField, IsField, IsScalar ],
    function( L, K, z )
    local coeffs;
    coeffs:= CoefficientsOfUnivariatePolynomial(
                 TracePolynomial( L, K, z, 1 ) );
    return AdditiveInverse( coeffs[ Length( coeffs ) - 1 ] );
    end );


#############################################################################
##
#M  MinimalPolynomial( <F>, <z>, <nr> )
##
##  If the default field of <z> knows how to get the Galois group then
##  we compute the conjugates and from them the minimal polynomial.
##  Otherwise we solve an equation system.
##
##  Note that the family predicate `IsCollsElmsX' expresses that <z> may lie
##  in an extension field of <F>;
##  this guarantees that the method is *not* applicable for the case that <z>
##  is a matrix.
##
InstallMethod( MinimalPolynomial,
    "for field, scalar, and indet. number",
    IsCollsElmsX,
    [ IsField, IsScalar,IsPosInt ],
    function( F, z, ind )

    local L, coe, deg, zero, con, i, B, pow, mat, MB;

    # Construct a basis of a field in which the computations happen.
    # (This need not be the smallest such field.)
    L:= DefaultField( z );

    if IsFieldControlledByGaloisGroup( L ) then

      # We may call `Conjugates'.

      coe:= [ One( F ) ];
      deg:= 0;
      zero:= Zero( F );
      for con in Conjugates( Field( F, [ z ] ), z ) do
        coe[deg+2]:= coe[deg+1];
        for i in [ deg+1, deg .. 2 ] do
          coe[i]:= coe[i-1] - con * coe[i];
        od;
        coe[1]:= zero - con * coe[1];
        deg:= deg + 1;
      od;

    else

      # Solve an equation system.

      B:= Basis( L );

      # Compute coefficients of the powers of `z' until
      # the rows are linearly dependent.
      pow:= One( F );
      coe:= Coefficients( B, pow );
      mat:= [ coe ];
      MB:= MutableBasis( F, [ coe ] );
      repeat
        CloseMutableBasis( MB, coe );
        pow:= pow * z;
        coe:= Coefficients( B, pow );
        Add( mat, coe );
      until IsContainedInSpan( MB, coe );

      # The coefficients of the minimal polynomial
      # are given by the linear relation.
      coe:= NullspaceMat( mat )[1];
      coe:= Inverse( Last(coe) ) * coe;

    fi;

    # Construct the polynomial.
    return UnivariatePolynomial( F, coe, ind );
    end );


#############################################################################
##
#M  TracePolynomial( <L>, <K>, <z> )
#M  TracePolynomial( <L>, <K>, <z>, <ind> )
##
InstallMethod( TracePolynomial,
    "using minimal polynomial",
    IsCollsXElmsX,
    [ IsField, IsField, IsScalar, IsPosInt ],
    function( L, K, z, ind )

    local minpol, mult;

    minpol:= MinimalPolynomial( K, z, ind );
    mult:= DegreeOverPrimeField( L ) / DegreeOverPrimeField( K );
    mult:= mult / DegreeOfLaurentPolynomial( minpol );

    return minpol ^ mult;
    end );

InstallMethod( TracePolynomial,
    "add default indet. 1",
    IsCollsXElms,
    [ IsField, IsField, IsScalar ],
    function( L, K, z )
    return TracePolynomial( L, K, z, 1 );
    end );


#############################################################################
##
#M  CharacteristicPolynomial( <L>, <K>, <z> )
#M  CharacteristicPolynomial( <L>, <K>, <z>, <ind> )
##
InstallOtherMethod( CharacteristicPolynomial,
    "call `TracePolynomial'",
    IsCollsXElms,
    [ IsField, IsField, IsScalar ],
    function( L, K, z )
    return TracePolynomial( L, K, z, 1 );
    end );

InstallOtherMethod( CharacteristicPolynomial,
    "call `TracePolynomial'",
    IsCollsXElmsX,
    [ IsField, IsField, IsScalar, IsPosInt ],
    TracePolynomial );


#############################################################################
##
#M  NiceFreeLeftModuleInfo( <V> )
#M  NiceVector( <V>, <v> )
#M  UglyVector( <V>, <r> )
##
InstallHandlingByNiceBasis( "IsFieldElementsSpace", rec(
    detect := function( F, gens, V, zero )
      return     IsScalarCollection( V )
             and IsIdenticalObj( FamilyObj( F ), FamilyObj( V ) )
             and IsDivisionRing( F );
      end,

    NiceFreeLeftModuleInfo := function( V )
      local lad, gens;

      # Compute the default field of the vector space generators,
      # and a basis of this field (over the left acting domain of `V').
      lad:= LeftActingDomain( V );
      if not IsIdenticalObj( FamilyObj( V ), FamilyObj( lad ) ) then
        TryNextMethod();
      fi;
      return Basis( AsField( lad,
                        ClosureField( lad, GeneratorsOfLeftModule( V ) ) ) );
      end,

    NiceVector := function( V, v )
      return Coefficients( NiceFreeLeftModuleInfo( V ), v );
      end,

    UglyVector := function( V, r )
      local B;
      B:= NiceFreeLeftModuleInfo( V );
      if Length( r ) <> Length( B ) then
        return fail;
      fi;
      return LinearCombination( B, r );
      end ) );


#############################################################################
##
#M  Quotient( <F>, <r>, <s> ) . . . . . . . . quotient of elements in a field
##
InstallMethod( Quotient,
    "for a division ring, and two ring elements",
    IsCollsElmsElms,
    [ IsDivisionRing, IsRingElement, IsRingElement ],
    function ( F, r, s )
    if IsZero(s) then
        return fail;
    fi;
    return r/s;
    end );


#############################################################################
##
#M  IsUnit( <F>, <r> )  . . . . . . . . . . check for being a unit in a field
##
InstallMethod( IsUnit,
    "for a division ring, and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsRingElement ],
    function ( F, r )
    return not IsZero( r ) and r in F;
    end );


#############################################################################
##
#M  Units( <F> )
##
InstallMethod( Units,
    "for a division ring",
    [ IsDivisionRing ],
    function( D )
    if IsFinite( D ) then
      return Difference( AsList( D ), [ Zero( D ) ] );
    else
      TryNextMethod();
    fi;
    end );


#############################################################################
##
#M  PrimitiveRoot( <F> )  . . . . . . . . . . . .  for finite prime field <F>
##
##  For a fields of prime order $p$, the multiplicative group corresponds to
##  the group of residues modulo $p$, via `Int'.
##  A primitive root is obtained as `PrimitiveRootMod( $p$ )' times the
##  identity of <F>.
##
InstallMethod( PrimitiveRoot,
    "for a finite prime field",
    [ IsField and IsFinite ],
    function( F )
    if not IsPrimeField( F ) then
      TryNextMethod();
    fi;
    return PrimitiveRootMod( Size( F ) ) * One( F );
    end );


#############################################################################
##
#M  EuclideanDegree( Integers, <n> )  . . . . . . . . . . . . . absolute value
##
InstallMethod( EuclideanDegree,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsRingElement ],
    function ( F, r )
    if not r in F then
      TryNextMethod(); # FIXME: or error?
    fi;
    return 0;
    end );


#############################################################################
##
#M  QuotientRemainder( Integers, <n>, <m> ) . . . . . . . . . . . quo and rem
##
InstallMethod( QuotientRemainder,
    "for a division ring, and two ring elements",
    IsCollsElmsElms,
    [ IsDivisionRing, IsRingElement, IsRingElement ],
    function ( F, r, s )
    if not r in F then
      TryNextMethod(); # FIXME: or error?
    fi;
    return [ r/s, Zero(F) ];
    end );

#############################################################################
##
#M  Factors( Integers, <n> )  . . . . . . . . . . factorization of an integer
##
InstallMethod( Factors,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsRingElement ],
    function ( F, r )
    if not r in F then
      TryNextMethod(); # FIXME: or error?
    fi;
    return [ r ];
    end );


#############################################################################
##
#M  IsAssociated( <F>, <r>, <s> ) . . . . . . check associatedness in a field
##
InstallMethod( IsAssociated,
    "for a division ring, and two ring elements",
    IsCollsElmsElms,
    [ IsDivisionRing, IsRingElement, IsRingElement ],
    function ( F, r, s )
    return IsZero( r ) = IsZero( s );
    end );


#############################################################################
##
#M  StandardAssociate( <F>, <x> ) . . . . . . . standard associate in a field
##
InstallMethod( StandardAssociate,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsScalar ],
    function ( R, r )
    if IsZero( r ) then
        return Zero( R );
    else
        return One( R );
    fi;
    end );


#############################################################################
##
#M  StandardAssociateUnit( <F>, <x> )
##
InstallMethod( StandardAssociateUnit,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsScalar ],
    function ( R, r )
    if IsZero( r ) then
        return One( R );
    else
        return r^-1;
    fi;
    end );


#############################################################################
##
#M  IsIrreducibleRingElement( <F>, <x> )
##
InstallMethod(IsIrreducibleRingElement,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsScalar ],
    function ( F, r )
    if not r in F then
      TryNextMethod(); # FIXME: or error?
    fi;
    # field elements are either zero or a unit
    return false;
    end );


#############################################################################
##
#M  IsPrime( <F>, <x> )
##
InstallMethod(IsPrime,
    "for a division ring and a ring element",
    IsCollsElms,
    [ IsDivisionRing, IsScalar ],
    function ( F, r )
    if not r in F then
      TryNextMethod(); # FIXME: or error?
    fi;
    # field elements are either zero or a unit
    return false;
    end );


#############################################################################
##
##  Field homomorphisms
##

#############################################################################
##
#M  IsFieldHomomorphism( <map> )
##
InstallMethod( IsFieldHomomorphism,
    [ IsGeneralMapping ],
    map -> IsRingHomomorphism( map ) and IsField( Source( map ) ) );


#############################################################################
##
#M  KernelOfAdditiveGeneralMapping( <fldhom> )  . .  for a field homomorphism
##
InstallMethod( KernelOfAdditiveGeneralMapping,
    "for a field homomorphism",
    [ IsFieldHomomorphism ],
#T higher rank?
#T (is this method ever used?)
    function ( hom )
    if ForAll( GeneratorsOfDivisionRing( Source( hom ) ),
               x -> IsZero( ImagesRepresentative( hom, x ) ) ) then
      return Source( hom );
    else
      return TrivialSubadditiveMagmaWithZero( Source( hom ) );
    fi;
    end );


#############################################################################
##
#M  IsInjective( <fldhom> ) . . . . . . . . . . . .  for a field homomorphism
##
InstallMethod( IsInjective,
    "for a field homomorphism",
    [ IsFieldHomomorphism ],
    hom -> Size( KernelOfAdditiveGeneralMapping( hom ) ) = 1 );


#############################################################################
##
#M  IsSurjective( <fldhom> )  . . . . . . . . . . .  for a field homomorphism
##
InstallMethod( IsSurjective,
    "for a field homomorphism",
    [ IsFieldHomomorphism ],
    function ( hom )
    if IsFinite( Range( hom ) ) then
      return Size( Range( hom ) ) = Size( Image( hom ) );
    else
      TryNextMethod();
    fi;
    end );


#############################################################################
##
#M  \=( <hom1>, <hom2> )  . . . . . . . . . comparison of field homomorphisms
##
InstallMethod( \=,
    "for two field homomorphisms",
    IsIdenticalObj,
    [ IsFieldHomomorphism, IsFieldHomomorphism ],
    function ( hom1, hom2 )

    # maybe the properties we already know determine the result
    if ( HasIsInjective( hom1 ) and HasIsInjective( hom2 )
         and IsInjective( hom1 ) <> IsInjective( hom2 ) )
    or ( HasIsSurjective( hom1 ) and HasIsSurjective( hom2 )
         and IsSurjective( hom1 ) <> IsSurjective( hom2 ) ) then
        return false;

    # otherwise we must really test the equality
    else
        return Source( hom1 ) = Source( hom2 )
            and Range( hom1 ) = Range( hom2 )
            and ForAll( GeneratorsOfField( Source( hom1 ) ),
                   elm -> Image(hom1,elm) = Image(hom2,elm) );
    fi;
    end );


#############################################################################
##
#M  ImagesSet( <hom>, <elms> ) . . images of a set under a field homomorphism
##
InstallMethod( ImagesSet,
    "for field homomorphism and field",
    CollFamSourceEqFamElms,
    [ IsFieldHomomorphism, IsField ],
    function ( hom, elms )
    elms:= FieldByGenerators( List( GeneratorsOfField( elms ),
               gen -> ImagesRepresentative( hom, gen ) ) );
    UseSubsetRelation( Range( hom ), elms );
    return elms;
    end );


#############################################################################
##
#M  PreImagesElm( <hom>, <elm> )  . . . . . . . . . . . .  preimage of an elm
##
InstallMethod( PreImagesElm,
    "for field homomorphism and element",
    FamRangeEqFamElm,
    [ IsFieldHomomorphism, IsObject ],
    function ( hom, elm )
    if IsInjective( hom ) = 1 then
      return [ PreImagesRepresentative( hom, elm ) ];
    elif IsZero( elm ) then
      return Source( hom );
    else
      return [];
    fi;
    end );


#############################################################################
##
#M  PreImagesSet( <hom>, <elm> )  . . . . . . . . . . . . . preimage of a set
##
InstallMethod( PreImagesSet,
    "for field homomorphism and field",
    CollFamRangeEqFamElms,
    [ IsFieldHomomorphism, IsField ],
    function ( hom, elms )
    elms:= FieldByGenerators( List( GeneratorsOfField( elms ),
               gen -> PreImagesRepresentative( hom, gen ) ) );
    UseSubsetRelation( Source( hom ), elms );
    return elms;
    end );

[ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge