|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Thomas Breuer, Frank Celler.
##
## 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 deals with cyclotomics.
##
#############################################################################
##
#C IsCyclotomic( <obj> ) . . . . . . . . . . . . category of all cyclotomics
#C IsCyc( <obj> )
##
## <#GAPDoc Label="IsCyclotomic">
## <ManSection>
## <Filt Name="IsCyclotomic" Arg='obj' Type='Category'/>
## <Filt Name="IsCyc" Arg='obj' Type='Category'/>
##
## <Description>
## <Index Key="CyclotomicsFamily"><C>CyclotomicsFamily</C></Index>
## Every object in the family <C>CyclotomicsFamily</C> lies in the category
## <Ref Filt="IsCyclotomic"/>.
## This covers integers, rationals, proper cyclotomics, the object
## <Ref Var="infinity"/>,
## and unknowns (see Chapter <Ref Chap="Unknowns"/>).
## All these objects except <Ref Var="infinity"/> and unknowns
## lie also in the category <Ref Filt="IsCyc"/>,
## <Ref Var="infinity"/> lies in (and can be detected from) the category
## <Ref Filt="IsInfinity"/>,
## and unknowns lie in <Ref Filt="IsUnknown"/>.
## <P/>
## <Example><![CDATA[
## gap> IsCyclotomic(0); IsCyclotomic(1/2*E(3)); IsCyclotomic( infinity );
## true
## true
## true
## gap> IsCyc(0); IsCyc(1/2*E(3)); IsCyc( infinity );
## true
## true
## false
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategory( "IsCyclotomic",
IsScalar and IsAssociativeElement and IsCommutativeElement
and IsAdditivelyCommutativeElement and IsZDFRE);
DeclareCategoryKernel( "IsCyc", IsCyclotomic, IS_CYC );
#############################################################################
##
#C IsCyclotomicCollection . . . . . . category of collection of cyclotomics
#C IsCyclotomicCollColl . . . . . . . category of collection of collection
#C IsCyclotomicCollCollColl . . . . category of collection of coll of coll
##
## <ManSection>
## <Filt Name="IsCyclotomicCollection" Arg='obj' Type='Category'/>
## <Filt Name="IsCyclotomicCollColl" Arg='obj' Type='Category'/>
## <Filt Name="IsCyclotomicCollCollColl" Arg='obj' Type='Category'/>
##
## <Description>
## </Description>
## </ManSection>
##
DeclareCategoryCollections( "IsCyclotomic" );
DeclareCategoryCollections( "IsCyclotomicCollection" );
DeclareCategoryCollections( "IsCyclotomicCollColl" );
#############################################################################
##
#C IsRat( <obj> )
##
## <#GAPDoc Label="IsRat">
## <ManSection>
## <Filt Name="IsRat" Arg='obj' Type='Category'/>
##
## <Description>
## <Index Subkey="for a rational">test</Index>
## Every rational number lies in the category <Ref Filt="IsRat"/>,
## which is a subcategory of <Ref Filt="IsCyc"/>.
## <P/>
## <Example><![CDATA[
## gap> IsRat( 2/3 );
## true
## gap> IsRat( 17/-13 );
## true
## gap> IsRat( 11 );
## true
## gap> IsRat( IsRat ); # `IsRat' is a function, not a rational
## false
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategoryKernel( "IsRat", IsCyc, IS_RAT );
#############################################################################
##
#C IsInt( <obj> )
##
## <#GAPDoc Label="IsInt">
## <ManSection>
## <Filt Name="IsInt" Arg='obj' Type='Category'/>
##
## <Description>
## Every rational integer lies in the category <Ref Filt="IsInt"/>,
## which is a subcategory of <Ref Filt="IsRat"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategoryKernel( "IsInt", IsRat, IS_INT );
#############################################################################
##
#C IsPosRat( <obj> )
##
## <#GAPDoc Label="IsPosRat">
## <ManSection>
## <Filt Name="IsPosRat" Arg='obj' Type='Category'/>
##
## <Description>
## Every positive rational number lies in the category
## <Ref Filt="IsPosRat"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategory( "IsPosRat", IsRat );
#############################################################################
##
#C IsPosInt( <obj> )
##
## <#GAPDoc Label="IsPosInt">
## <ManSection>
## <Filt Name="IsPosInt" Arg='obj' Type='Category'/>
##
## <Description>
## Every positive integer lies in the category <Ref Filt="IsPosInt"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareSynonym( "IsPosInt", IsInt and IsPosRat );
#############################################################################
##
#C IsNegRat( <obj> )
##
## <#GAPDoc Label="IsNegRat">
## <ManSection>
## <Filt Name="IsNegRat" Arg='obj' Type='Category'/>
##
## <Description>
## Every negative rational number lies in the category
## <Ref Filt="IsNegRat"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategory( "IsNegRat", IsRat );
#############################################################################
##
#C IsNegInt( <obj> )
##
## <ManSection>
## <Filt Name="IsNegInt" Arg='obj' Type='Category'/>
##
## <Description>
## Every negative integer lies in the category <Ref Func="IsNegInt"/>.
## </Description>
## </ManSection>
##
DeclareSynonym( "IsNegInt", IsInt and IsNegRat );
#############################################################################
##
#C IsZeroCyc( <obj> )
##
## <ManSection>
## <Filt Name="IsZeroCyc" Arg='obj' Type='Category'/>
##
## <Description>
## Only the zero <C>0</C> of the cyclotomics lies in the category
## <Ref Func="IsZeroCyc"/>.
## </Description>
## </ManSection>
##
DeclareCategory( "IsZeroCyc", IsInt and IsZero );
#############################################################################
##
#V CyclotomicsFamily . . . . . . . . . . . . . . . . . family of cyclotomics
##
## <ManSection>
## <Var Name="CyclotomicsFamily"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "CyclotomicsFamily",
NewFamily( "CyclotomicsFamily",
IsCyclotomic,CanEasilySortElements,
CanEasilySortElements ) );
#############################################################################
##
#R IsSmallIntRep . . . . . . . . . . . . . . . . . . small internal integer
##
## <ManSection>
## <Filt Name="IsSmallIntRep" Arg='obj' Type='Representation'/>
##
## <Description>
## </Description>
## </ManSection>
##
DeclareRepresentation( "IsSmallIntRep", IsInternalRep );
#############################################################################
##
#V TYPE_INT_SMALL_ZERO . . . . . . . . . . . . . . type of the internal zero
##
## <ManSection>
## <Var Name="TYPE_INT_SMALL_ZERO"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_INT_SMALL_ZERO", NewType( CyclotomicsFamily,
IsInt and IsZeroCyc and IsSmallIntRep ) );
#############################################################################
##
#V TYPE_INT_SMALL_NEG . . . . . . type of a small negative internal integer
##
## <ManSection>
## <Var Name="TYPE_INT_SMALL_NEG"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_INT_SMALL_NEG", NewType( CyclotomicsFamily,
IsInt and IsNegRat and IsSmallIntRep ) );
#############################################################################
##
#V TYPE_INT_SMALL_POS . . . . . . type of a small positive internal integer
##
## <ManSection>
## <Var Name="TYPE_INT_SMALL_POS"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_INT_SMALL_POS", NewType( CyclotomicsFamily,
IsPosInt and IsSmallIntRep ) );
#############################################################################
##
#V TYPE_INT_LARGE_NEG . . . . . . type of a large negative internal integer
##
## <ManSection>
## <Var Name="TYPE_INT_LARGE_NEG"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_INT_LARGE_NEG", NewType( CyclotomicsFamily,
IsInt and IsNegRat and IsInternalRep ) );
#############################################################################
##
#V TYPE_INT_LARGE_POS . . . . . . type of a large positive internal integer
##
## <ManSection>
## <Var Name="TYPE_INT_LARGE_POS"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_INT_LARGE_POS", NewType( CyclotomicsFamily,
IsPosInt and IsInternalRep ) );
#############################################################################
##
#V TYPE_RAT_NEG . . . . . . . . . . . type of a negative internal rational
##
## <ManSection>
## <Var Name="TYPE_RAT_NEG"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_RAT_NEG", NewType( CyclotomicsFamily,
IsRat and IsNegRat and IsInternalRep ) );
#############################################################################
##
#V TYPE_RAT_POS . . . . . . . . . . . type of a positive internal rational
##
## <ManSection>
## <Var Name="TYPE_RAT_POS"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_RAT_POS", NewType( CyclotomicsFamily,
IsRat and IsPosRat and IsInternalRep ) );
#############################################################################
##
#V TYPE_CYC . . . . . . . . . . . . . . . . type of an internal cyclotomics
##
## <ManSection>
## <Var Name="TYPE_CYC"/>
##
## <Description>
## </Description>
## </ManSection>
##
BIND_GLOBAL( "TYPE_CYC",
NewType( CyclotomicsFamily, IsCyc and IsInternalRep ) );
#############################################################################
##
#v One( CyclotomicsFamily )
#v Zero( CyclotomicsFamily )
#v Characteristic( CyclotomicsFamily )
##
SetOne( CyclotomicsFamily, 1 );
SetZero( CyclotomicsFamily, 0 );
SetCharacteristic( CyclotomicsFamily, 0 );
#############################################################################
##
#v IsUFDFamily( CyclotomicsFamily )
##
SetFilterObj( CyclotomicsFamily, IsUFDFamily );
#############################################################################
##
#F E( <n> )
##
## <#GAPDoc Label="E">
## <ManSection>
## <Oper Name="E" Arg='n'/>
##
## <Description>
## <Index>roots of unity</Index>
## <Ref Oper="E"/> returns the primitive <A>n</A>-th root of unity
## <M>e_n = \exp(2\pi i/n)</M>.
## Cyclotomics are usually entered as sums of roots of unity,
## with rational coefficients,
## and irrational cyclotomics are displayed in such a way.
## (For special cyclotomics, see <Ref Sect="ATLAS Irrationalities"/>.)
## <P/>
## <Example><![CDATA[
## gap> E(9); E(9)^3; E(6); E(12) / 3;
## -E(9)^4-E(9)^7
## E(3)
## -E(3)^2
## -1/3*E(12)^7
## ]]></Example>
## <P/>
## A particular basis is used to express cyclotomics,
## see <Ref Sect="Integral Bases of Abelian Number Fields"/>;
## note that <C>E(9)</C> is <E>not</E> a basis element,
## as the above example shows.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
#############################################################################
##
#C IsInfinity( <obj> ) . . . . . . . . . . . . . . . . category of infinity
#V infinity . . . . . . . . . . . . . . . . . . . . . . the value infinity
#C IsNegInfinity( <obj> ) . . . . . . . . . . category of negative infinity
#V -infinity . . . . . . . . . . . . . . . . . . . . . . the value -infinity
## <#GAPDoc Label="IsInfinity">
## <ManSection>
## <Filt Name="IsInfinity" Arg='obj' Type='Category'/>
## <Filt Name="IsNegInfinity" Arg='obj' Type='Category'/>
## <Var Name="infinity"/>
## <Var Name="-infinity"/>
##
## <Description>
## <Ref Var="infinity"/> and <Ref Var="-infinity"/> are special &GAP; objects
## that lie in <C>CyclotomicsFamily</C>.
## They are larger or smaller than all other objects in this family
## respectively.
## <Ref Var="infinity"/> is mainly used as return value of operations such
## as <Ref Attr="Size"/>
## and <Ref Attr="Dimension"/> for infinite and infinite dimensional domains,
## respectively.
## <P/>
## Some arithmetic operations are provided for convenience when using
## <Ref Var="infinity"/> and <Ref Var="-infinity"/> as top and bottom element
## respectively.
## <Example><![CDATA[
## gap> -infinity + 1;
## -infinity
## gap> infinity + infinity;
## infinity
## ]]></Example>
## Often it is useful to distinguish <Ref Var="infinity"/>
## from <Q>proper</Q> cyclotomics.
## For that, <Ref Var="infinity"/> lies in the category
## <Ref Filt="IsInfinity"/> but not in <Ref Filt="IsCyc"/>,
## and the other cyclotomics lie in the category <Ref Filt="IsCyc"/> but not
## in <Ref Filt="IsInfinity"/>.
## <P/>
## <Example><![CDATA[
## gap> s:= Size( Rationals );
## infinity
## gap> s = infinity; IsCyclotomic( s ); IsCyc( s ); IsInfinity( s );
## true
## true
## false
## true
## gap> s in Rationals; s > 17;
## false
## true
## gap> Set( [ s, 2, s, E(17), s, 19 ] );
## [ 2, 19, E(17), infinity ]
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategory( "IsInfinity", IsCyclotomic );
UNBIND_GLOBAL( "infinity" );
BIND_GLOBAL( "infinity",
Objectify( NewType( CyclotomicsFamily, IsInfinity
and IsPositionalObjectRep ), [] ) );
if IsHPCGAP then
MakeReadOnlyObj(infinity);
fi;
InstallMethod( PrintObj,
"for infinity",
[ IsInfinity ], function( obj ) Print( "infinity" ); end );
InstallMethod( \=,
"for cyclotomic and `infinity'",
IsIdenticalObj, [ IsCyclotomic, IsInfinity ], ReturnFalse );
InstallMethod( \=,
"for `infinity' and cyclotomic",
IsIdenticalObj, [ IsInfinity, IsCyclotomic ], ReturnFalse );
InstallMethod( \<,
"for cyclotomic and `infinity'",
IsIdenticalObj, [ IsCyclotomic, IsInfinity ], ReturnTrue );
InstallMethod( \<,
"for `infinity' and cyclotomic",
IsIdenticalObj, [ IsInfinity, IsCyclotomic ], ReturnFalse );
DeclareCategory( "IsNegInfinity", IsCyclotomic );
BIND_GLOBAL( "Ninfinity",
Objectify( NewType( CyclotomicsFamily, IsNegInfinity
and IsPositionalObjectRep ), [] ) );
if IsHPCGAP then
MakeReadOnlyObj(Ninfinity);
fi;
InstallMethod( PrintObj,
"for -infinity",
[ IsNegInfinity ], function( obj ) Print( "-infinity" ); end );
InstallMethod( \=,
"for cyclotomic and `-infinity'",
IsIdenticalObj, [ IsCyclotomic, IsNegInfinity ], ReturnFalse );
InstallMethod( \=,
"for `-infinity' and cyclotomic",
IsIdenticalObj, [ IsNegInfinity, IsCyclotomic ], ReturnFalse );
InstallMethod( \<,
"for cyclotomic and `-infinity'",
IsIdenticalObj, [ IsCyclotomic, IsNegInfinity ], ReturnFalse );
InstallMethod( \<,
"for `-infinity' and cyclotomic",
IsIdenticalObj, [ IsNegInfinity, IsCyclotomic ], ReturnTrue );
InstallMethod( AdditiveInverseOp,
"for `infinity'",
[ IsInfinity ], x -> Ninfinity );
InstallMethod( AdditiveInverseOp,
"for `-infinity'",
[ IsNegInfinity ], x -> infinity );
InstallMethod( \+,
"for `infinity' and cyclotomic",
IsIdenticalObj, [ IsInfinity, IsCyc ], function(x,y) return infinity; end );
InstallMethod( \+,
"for cyclotomic and `infinity'",
IsIdenticalObj, [ IsCyc, IsInfinity ], function(x,y) return infinity; end );
InstallMethod( \+,
"for `infinity' and `infinity'",
IsIdenticalObj, [ IsInfinity, IsInfinity ], function(x,y) return infinity; end );
InstallMethod( \+,
"for `-infinity' and cyclotomic",
IsIdenticalObj, [ IsNegInfinity, IsCyc ], function(x,y) return -infinity; end );
InstallMethod( \+,
"for cyclotomic and `-infinity'",
IsIdenticalObj, [ IsCyc, IsNegInfinity ], function(x,y) return -infinity; end );
InstallMethod( \+,
"for `-infinity' and `-infinity'",
IsIdenticalObj, [ IsNegInfinity, IsNegInfinity ], function(x,y) return -infinity; end );
#############################################################################
##
#P IsIntegralCyclotomic( <obj> ) . . . . . . . . . . . integral cyclotomics
##
## <#GAPDoc Label="IsIntegralCyclotomic">
## <ManSection>
## <Prop Name="IsIntegralCyclotomic" Arg='obj'/>
##
## <Description>
## A cyclotomic is called <E>integral</E> or a <E>cyclotomic integer</E>
## if all coefficients of its minimal polynomial over the rationals are
## integers.
## Since the underlying basis of the external representation of cyclotomics
## is an integral basis
## (see <Ref Sect="Integral Bases of Abelian Number Fields"/>),
## the subring of cyclotomic integers in a cyclotomic field is formed
## by those cyclotomics for which the external representation is a list of
## integers.
## For example, square roots of integers are cyclotomic integers
## (see <Ref Sect="ATLAS Irrationalities"/>),
## any root of unity is a cyclotomic integer,
## character values are always cyclotomic integers,
## but all rationals which are not integers are not cyclotomic integers.
## <P/>
## <Example><![CDATA[
## gap> r:= ER( 5 ); # The square root of 5 ...
## E(5)-E(5)^2-E(5)^3+E(5)^4
## gap> IsIntegralCyclotomic( r ); # ... is a cyclotomic integer.
## true
## gap> r2:= 1/2 * r; # This is not a cyclotomic integer, ...
## 1/2*E(5)-1/2*E(5)^2-1/2*E(5)^3+1/2*E(5)^4
## gap> IsIntegralCyclotomic( r2 );
## false
## gap> r3:= 1/2 * r - 1/2; # ... but this is one.
## E(5)+E(5)^4
## gap> IsIntegralCyclotomic( r3 );
## true
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareProperty( "IsIntegralCyclotomic", IsObject );
DeclareSynonymAttr( "IsCycInt", IsIntegralCyclotomic );
InstallMethod( IsIntegralCyclotomic,
"for an internally represented cyclotomic",
[ IsInternalRep ],
IS_CYC_INT );
#############################################################################
##
#A Conductor( <cyc> ) . . . . . . . . . . . . . . . . . . for a cyclotomic
#A Conductor( <C> ) . . . . . . . . . . . . for a collection of cyclotomics
##
## <#GAPDoc Label="Conductor">
## <ManSection>
## <Attr Name="Conductor" Arg='cyc' Label="for a cyclotomic"/>
## <Attr Name="Conductor" Arg='C' Label="for a collection of cyclotomics"/>
##
## <Description>
## For an element <A>cyc</A> of a cyclotomic field,
## <Ref Attr="Conductor" Label="for a cyclotomic"/>
## returns the smallest integer <M>n</M> such that <A>cyc</A> is contained
## in the <M>n</M>-th cyclotomic field.
## For a collection <A>C</A> of cyclotomics (for example a dense list of
## cyclotomics or a field of cyclotomics),
## <Ref Attr="Conductor" Label="for a collection of cyclotomics"/> returns
## the smallest integer <M>n</M> such that all elements of <A>C</A>
## are contained in the <M>n</M>-th cyclotomic field.
## <P/>
## <Example><![CDATA[
## gap> Conductor( 0 ); Conductor( E(10) ); Conductor( E(12) );
## 1
## 5
## 12
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareAttributeKernel( "Conductor", IsCyc, CONDUCTOR );
DeclareAttribute( "Conductor", IsCyclotomicCollection );
#T also for matrices, matrix groups etc. of cyclotomics?
#############################################################################
##
#O GaloisCyc( <cyc>, <k> ) . . . . . . . . . . . . . . . . Galois conjugate
#O GaloisCyc( <list>, <k> ) . . . . . . . . . . . list of Galois conjugates
##
## <#GAPDoc Label="GaloisCyc">
## <ManSection>
## <Oper Name="GaloisCyc" Arg='cyc, k' Label="for a cyclotomic"/>
## <Oper Name="GaloisCyc" Arg='list, k' Label="for a list of cyclotomics"/>
##
## <Description>
## For a cyclotomic <A>cyc</A> and an integer <A>k</A>,
## <Ref Oper="GaloisCyc" Label="for a cyclotomic"/> returns the cyclotomic
## obtained by raising the roots of unity in the Zumbroich basis
## representation of <A>cyc</A> to the <A>k</A>-th power.
## If <A>k</A> is coprime to the integer <M>n</M>,
## <C>GaloisCyc( ., <A>k</A> )</C> acts as a Galois automorphism
## of the <M>n</M>-th cyclotomic field
## (see <Ref Sect="Galois Groups of Abelian Number Fields"/>);
## to get the Galois automorphisms themselves,
## use <Ref Attr="GaloisGroup" Label="of field"/>.
## <P/>
## The <E>complex conjugate</E> of <A>cyc</A> is
## <C>GaloisCyc( <A>cyc</A>, -1 )</C>,
## which can also be computed using <Ref Attr="ComplexConjugate"/>.
## <P/>
## For a list or matrix <A>list</A> of cyclotomics,
## <Ref Oper="GaloisCyc" Label="for a list of cyclotomics"/> returns
## the list obtained by applying
## <Ref Oper="GaloisCyc" Label="for a cyclotomic"/> to the entries of
## <A>list</A>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareOperationKernel( "GaloisCyc", [ IsCyc, IsInt ], GALOIS_CYC );
DeclareOperation( "GaloisCyc", [ IsCyclotomicCollection, IsInt ] );
DeclareOperation( "GaloisCyc", [ IsCyclotomicCollColl, IsInt ] );
InstallMethod( GaloisCyc,
"for a list of cyclotomics, and an integer",
[ IsList and IsCyclotomicCollection, IsInt ],
function( list, k )
return List( list, entry -> GaloisCyc( entry, k ) );
end );
InstallMethod( GaloisCyc,
"for a list of lists of cyclotomics, and an integer",
[ IsList and IsCyclotomicCollColl, IsInt ],
function( list, k )
return List( list, entry -> GaloisCyc( entry, k ) );
end );
#############################################################################
##
#F NumeratorRat( <rat> ) . . . . . . . . . . numerator of internal rational
##
## <#GAPDoc Label="NumeratorRat">
## <ManSection>
## <Func Name="NumeratorRat" Arg='rat'/>
##
## <Description>
## <Index Subkey="of a rational">numerator</Index>
## <Ref Func="NumeratorRat"/> returns the numerator of the rational
## <A>rat</A>.
## Because the numerator holds the sign of the rational it may be any
## integer.
## Integers are rationals with denominator <M>1</M>,
## thus <Ref Func="NumeratorRat"/> is the identity function for integers.
## <P/>
## <Example><![CDATA[
## gap> NumeratorRat( 2/3 );
## 2
## gap> # numerator and denominator are made relatively prime:
## gap> NumeratorRat( 66/123 );
## 22
## gap> NumeratorRat( 17/-13 ); # numerator holds the sign of the rational
## -17
## gap> NumeratorRat( 11 ); # integers are rationals with denominator 1
## 11
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "NumeratorRat", NUMERATOR_RAT );
#############################################################################
##
#F DenominatorRat( <rat> ) . . . . . . . . denominator of internal rational
##
## <#GAPDoc Label="DenominatorRat">
## <ManSection>
## <Func Name="DenominatorRat" Arg='rat'/>
##
## <Description>
## <Index Subkey="of a rational">denominator</Index>
## <Ref Func="DenominatorRat"/> returns the denominator of the rational
## <A>rat</A>.
## Because the numerator holds the sign of the rational the denominator is
## always a positive integer.
## Integers are rationals with the denominator 1,
## thus <Ref Func="DenominatorRat"/> returns 1 for integers.
## <P/>
## <Example><![CDATA[
## gap> DenominatorRat( 2/3 );
## 3
## gap> # numerator and denominator are made relatively prime:
## gap> DenominatorRat( 66/123 );
## 41
## gap> # the denominator holds the sign of the rational:
## gap> DenominatorRat( 17/-13 );
## 13
## gap> DenominatorRat( 11 ); # integers are rationals with denominator 1
## 1
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "DenominatorRat", DENOMINATOR_RAT );
#############################################################################
##
#F QuoInt( <n>, <m> ) . . . . . . . . . . . . quotient of internal integers
##
## <#GAPDoc Label="QuoInt">
## <ManSection>
## <Func Name="QuoInt" Arg='n, m'/>
##
## <Description>
## <Index>integer part of a quotient</Index>
## <Ref Func="QuoInt"/> returns the integer part of the quotient of its
## integer operands.
## <P/>
## If <A>n</A> and <A>m</A> are positive, <Ref Func="QuoInt"/> returns
## the largest positive integer <M>q</M> such that
## <M>q * <A>m</A> \leq <A>n</A></M>.
## If <A>n</A> or <A>m</A> or both are negative the absolute value of the
## integer part of the quotient is the quotient of the absolute values of
## <A>n</A> and <A>m</A>,
## and the sign of it is the product of the signs of <A>n</A> and <A>m</A>.
## <P/>
## <Ref Func="QuoInt"/> is used in a method for the general operation
## <Ref Oper="EuclideanQuotient"/>.
## <Example><![CDATA[
## gap> QuoInt(5,3); QuoInt(-5,3); QuoInt(5,-3); QuoInt(-5,-3);
## 1
## -1
## -1
## 1
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "QuoInt", QUO_INT );
#############################################################################
##
#F RemInt( <n>, <m> ) . . . . . . . . . . . remainder of internal integers
##
## <#GAPDoc Label="RemInt">
## <ManSection>
## <Func Name="RemInt" Arg='n, m'/>
##
## <Description>
## <Index>remainder of a quotient</Index>
## <Ref Func="RemInt"/> returns the remainder of its two integer operands.
## <P/>
## If <A>m</A> is not equal to zero, <Ref Func="RemInt"/> returns
## <C><A>n</A> - <A>m</A> * QuoInt( <A>n</A>, <A>m</A> )</C>.
## Note that the rules given for <Ref Func="QuoInt"/> imply that the return
## value of <Ref Func="RemInt"/> has the same sign as <A>n</A>
## and its absolute value is strictly less than the absolute value
## of <A>m</A>.
## Note also that the return value equals <C><A>n</A> mod <A>m</A></C>
## when both <A>n</A> and <A>m</A> are nonnegative.
## Dividing by <C>0</C> signals an error.
## <P/>
## <Ref Func="RemInt"/> is used in a method for the general operation
## <Ref Oper="EuclideanRemainder"/>.
## <Example><![CDATA[
## gap> RemInt(5,3); RemInt(-5,3); RemInt(5,-3); RemInt(-5,-3);
## 2
## -2
## 2
## -2
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "RemInt", REM_INT );
#############################################################################
##
#F GcdInt( <m>, <n> ) . . . . . . . . . . . . . . gcd of internal integers
##
## <#GAPDoc Label="GcdInt">
## <ManSection>
## <Func Name="GcdInt" Arg='m, n'/>
##
## <Description>
## <Ref Func="GcdInt"/> returns the greatest common divisor
## of its two integer operands <A>m</A> and <A>n</A>, i.e.,
## the greatest integer that divides both <A>m</A> and <A>n</A>.
## The greatest common divisor is never negative, even if the arguments are.
## We define
## <C>GcdInt( <A>m</A>, 0 ) = GcdInt( 0, <A>m</A> ) = AbsInt( <A>m</A> )</C>
## and <C>GcdInt( 0, 0 ) = 0</C>.
## <P/>
## <Ref Func="GcdInt"/> is a method used by the general function
## <Ref Func="Gcd" Label="for (a ring and) several elements"/>.
## <P/>
## <Example><![CDATA[
## gap> GcdInt( 123, 66 );
## 3
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "GcdInt", GCD_INT );
#############################################################################
##
#m Order( <cyc> ) . . . . . . . . . . . . . . . . . order of an alg. number
##
## If <cyc> is not a cyclotomic integer then its order is infinity.
## Otherwise, <cyc> is a root of unity iff its absolute value is $1$.
## (This follows from the more general theorem that an algebraic integer is
## a root of unity iff all its algebraic conjugates have absolute value $1$;
## note that we assume that <cyc> lies in a cyclotomic field,
## so the Galois group of the field extension is abelian.)
##
## This method is thought for cyclotomics for which it is cheap to decide
## whether they are algebraic integers, and to compute the conductor;
## both conditions hold for internally represented cyclotomics,
## since they are represented w.r.t. an integral basis of the smallest
## possible cyclotomic field.
##
InstallMethod( Order,
"for a cyclotomic",
[ IsCyc ],
function ( cyc )
local n;
# Check that the argument is a root of unity.
if cyc = 0 then
Error( "argument must be nonzero" );
elif not IsIntegralCyclotomic( cyc )
or cyc * GaloisCyc( cyc, -1 ) <> 1 then
return infinity;
fi;
# Let $n$ be the conductor of `cyc'.
# The roots of unity in the $n$-th cyclotomic field are exactly the
# $n$-th roots if $n$ is even, and the $2 n$-th roots if $n$ is odd.
n:= Conductor( cyc );
if n mod 2 = 0 or cyc^n = 1 then
return n;
else
Assert( 1, cyc^n = -1 );
return 2*n;
fi;
end );
#############################################################################
##
#M Int( <int> ) . . . . . . . . . . . . . . . . . . . . . . for an integer
#M Int( <rat> ) . . . . . . . . . . . . convert a rational into an integer
#M Int( <cyc> ) . . . . . . . . . . . . . cyclotomic integer near to <cyc>
##
## <#GAPDoc Label="Int:cyclotomics">
## <ManSection>
## <Meth Name="Int" Arg='cyc' Label="for a cyclotomic"/>
##
## <Description>
## The operation <Ref Meth="Int" Label="for a cyclotomic"/>
## can be used to find a cyclotomic integer near to an arbitrary cyclotomic,
## by applying <Ref Attr="Int"/> to the coefficients.
## <P/>
## <Example><![CDATA[
## gap> Int( E(5)+1/2*E(5)^2 ); Int( 2/3*E(7)-3/2*E(4) );
## E(5)
## -E(4)
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( Int,
"for an integer",
[ IsInt ],
IdFunc );
InstallMethod( Int,
"for a rational",
[ IsRat ],
obj -> QuoInt( NumeratorRat( obj ), DenominatorRat( obj ) ) );
InstallMethod( Int,
"for a cyclotomic",
[ IsCyc ],
cyc -> CycList( List( COEFFS_CYC( cyc ), Int ) ) );
#############################################################################
##
#M String( <int> ) . . . . . . . . . . . . . . . . . . . . . for an integer
#M String( <rat> ) . . . . . . . . . . . . convert a rational into a string
#M String( <cyc> ) . . . . . . . . . . . . convert cyclotomic into a string
#M String( <infinity> ) . . . . . . . . . . . . . . . . . . for `infinity'
##
## <#GAPDoc Label="String:cyclotomics">
## <ManSection>
## <Meth Name="String" Arg='cyc' Label="for a cyclotomic"/>
##
## <Description>
## The operation <Ref Meth="String" Label="for a cyclotomic"/>
## returns for a cyclotomic <A>cyc</A> a string corresponding to the way
## the cyclotomic is printed by <Ref Oper="ViewObj"/> and
## <Ref Oper="PrintObj"/>.
## <P/>
## <Example><![CDATA[
## gap> String( E(5)+1/2*E(5)^2 ); String( 17/3 );
## "E(5)+1/2*E(5)^2"
## "17/3"
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( String,
"for an integer",
[ IsInt ],
function(a)
local sign, halflen, b, q, qr, s1, s2, pad;
# "small" numbers
if Log2Int(a) < 5000 then
# kernel method
return STRING_INT(a);
fi;
# sign
if a < 0 then
sign := "-";
a := -a;
else
sign := "";
fi;
# recursion
halflen := QuoInt(Log2Int(a)*100, 664);
b := 10^halflen;
q := QUO_INT(a, b);
qr := [q, a-q*b]; #QuotientRemainder(a, 10^halflen);
if qr[1] = 0 then
s1 := "";
else
s1 := String(qr[1]);
fi;
s2 := String(qr[2]);
pad := ListWithIdenticalEntries(halflen-Length(s2), '0');
return Concatenation(sign,s1,pad,s2);
end);
InstallMethod( String,
"for a rational",
[ IsRat ],
function ( rat )
local str;
str := String( NumeratorRat( rat ) );
if DenominatorRat( rat ) <> 1 then
str := Concatenation( str, "/", String( DenominatorRat( rat ) ) );
fi;
ConvertToStringRep( str );
return str;
end );
InstallMethod( String,
"for a cyclotomic",
[ IsCyc ],
function( cyc )
local i, j, En, coeffs, str;
# get the coefficients
coeffs := COEFFS_CYC( cyc );
# get the root as a string
En := Concatenation( "E(", String( Length( coeffs ) ), ")" );
# print the first non zero coefficient
i := 1;
while coeffs[i] = 0 do i:= i+1; od;
if i = 1 then
str := ShallowCopy( String( coeffs[1] ) );
elif coeffs[i] = -1 then
str := Concatenation( "-", En );
elif coeffs[i] = 1 then
str := ShallowCopy( En );
else
str := Concatenation( String( coeffs[i] ), "*", En );
fi;
if 2 < i then
Add( str, '^' );
Append( str, String(i-1) );
fi;
# print the other coefficients
for j in [i+1..Length(coeffs)] do
if coeffs[j] = 1 then
Add( str, '+' );
Append( str, En );
elif coeffs[j] = -1 then
Add( str, '-' );
Append( str, En );
elif 0 < coeffs[j] then
Add( str, '+' );
Append( str, String( coeffs[j] ) );
Add( str, '*' );
Append( str, En );
elif coeffs[j] < 0 then
Append( str, String( coeffs[j] ) );
Add( str, '*' );
Append( str, En );
fi;
if 2 < j and coeffs[j] <> 0 then
Add( str, '^' );
Append( str, String( j-1 ) );
fi;
od;
# Convert to string representation.
ConvertToStringRep( str );
# Return the string.
return str;
end );
InstallMethod( String,
"for infinity",
[ IsInfinity ],
x -> "infinity" );
InstallMethod( String,
"for -infinity",
[ IsNegInfinity ],
x -> "-infinity" );
[ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet)
]
|