CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Views: 418346
#############################################################################
##
##  MAGMA.gi                  RingsForHomalg package         Mohamed Barakat
##                                                            Simon Goertzen
##                                                          Markus Kirschmer
##
##  Copyright 2007-2008 Lehrstuhl B für Mathematik, RWTH Aachen
##
##  Implementation stuff for the external computer algebra system MAGMA.
##
#############################################################################

####################################
#
# global variables:
#
####################################

InstallValue( HOMALG_IO_MAGMA,
        rec(
            cas := "magma",		## normalized name on which the user should have no control
            name := "MAGMA",
            executable := [ "magma" ],	## this list is processed from left to right
            options := [ ],
            BUFSIZE := 1024,
            READY := "!$%&/(",
            CUT_POS_BEGIN := 1,		## these are the most
            CUT_POS_END := 2,		## delicate values!
            eoc_verbose := ";",
            eoc_quiet := ";",
            remove_enter := true,	## a MAGMA specific
            error_stdout := " error",	## a MAGMA specific
            setring := _MAGMA_SetRing,	## a MAGMA specific
            define := ":=",
            delete := function( var, stream ) homalgSendBlocking( [ "delete ", var ], "need_command", stream, HOMALG_IO.Pictograms.delete ); end,
            multiple_delete := _MAGMA_multiple_delete,
            prompt := "\033[01mmagma>\033[0m ",
            output_prompt := "\033[1;31;47m<magma\033[0m ",
            display_color := "\033[0;30;47m",
            InitializeCASMacros := InitializeMAGMAMacros,
            time := function( stream, t ) return Int( homalgSendBlocking( [ "Floor( Cputime() * 1000 )" ], "need_output", stream, HOMALG_IO.Pictograms.time ) ) - t; end,
           )
);

HOMALG_IO_MAGMA.READY_LENGTH := Length( HOMALG_IO_MAGMA.READY );

####################################
#
# representations:
#
####################################

# a new subrepresentation of the representation IshomalgExternalRingObjectRep:
DeclareRepresentation( "IsHomalgExternalRingObjectInMAGMARep",
        IshomalgExternalRingObjectRep,
        [  ] );

# a new subrepresentation of the representation IsHomalgExternalRingRep:
DeclareRepresentation( "IsHomalgExternalRingInMAGMARep",
        IsHomalgExternalRingRep,
        [  ] );

####################################
#
# families and types:
#
####################################

# a new type:
BindGlobal( "TheTypeHomalgExternalRingObjectInMAGMA",
        NewType( TheFamilyOfHomalgRings,
                IsHomalgExternalRingObjectInMAGMARep ) );

# a new type:
BindGlobal( "TheTypeHomalgExternalRingInMAGMA",
        NewType( TheFamilyOfHomalgRings,
                IsHomalgExternalRingInMAGMARep ) );

####################################
#
# global functions:
#
####################################

##
InstallGlobalFunction( _MAGMA_SetRing,
  function( R )
    local stream, param, indets;
    
    stream := homalgStream( R );
    
    ## since _MAGMA_SetRing might be called from homalgSendBlocking,
    ## we first set the new active ring to avoid infinite loops:
    stream.active_ring := R;
    
    if HasRationalParameters( R ) then
        param := RationalParameters( R );
        param := List( param, String );
        param := JoinStringsWithSeparator( param );
        if HasIsFreePolynomialRing( R ) and HasCoefficientsRing( R ) then
            homalgSendBlocking( [ "_<", param, "> := BaseRing(", R, ")" ], "need_command", "break_lists", HOMALG_IO.Pictograms.initialize );
        else
            homalgSendBlocking( [ "_<", param, "> := ", R ], "need_command", "break_lists", HOMALG_IO.Pictograms.initialize );
        fi;
    fi;
    
    if HasCoefficientsRing( R ) then
        indets := Indeterminates( R );
        indets := List( indets, String );
        indets := JoinStringsWithSeparator( indets );
        homalgSendBlocking( [ "_<", indets, "> := ", R ], "need_command", "break_lists", HOMALG_IO.Pictograms.initialize );
    fi;
    
    if IsBound( HOMALG_IO_MAGMA.setring_post ) then
        homalgSendBlocking( HOMALG_IO_MAGMA.setring_post, "need_command", stream, HOMALG_IO.Pictograms.initialize );
    fi;
    
end );

##
InstallGlobalFunction( _MAGMA_multiple_delete,
  function( var_list, stream )
    local num, l, i, str;
    
    num := 100;
    
    l := Length( var_list );
    
    i := 1;
    
    if l - i < num then
        str := [ "delete ", var_list ];
    else
        while true do
            str := [ "delete ", var_list{[ i .. i + num - 1 ]} ];
            homalgSendBlocking( str, "need_command", stream, "break_lists", HOMALG_IO.Pictograms.multiple_delete );
            i := i + num;
            if l - i < num then
                break;
            fi;
        od;
        str := [ "delete ", var_list{[ i .. l ]} ];
    fi;
    
    homalgSendBlocking( str, "need_command", stream, "break_lists", HOMALG_IO.Pictograms.multiple_delete );
    
end );

##
InstallValue( MAGMAMacros,
        rec(
            
    _order := [
               "MyRowspace",
               "BasisOfRowModule",
               "BasisOfRowsCoeff",
               "DecideZeroRows",
               "DecideZeroRowsEffectively",
               "SyzygiesGeneratorsOfRows",
               "RelativeSyzygiesGeneratorsOfRows",
               ],
    
    IsDiagonalMatrix := "\n\
IsDiagonalMatrix := function(M)\n\
  for i:= 1 to Min(Nrows(M),Ncols(M)) do M[i,i]:= 0; end for;\n\
  return IsZero(M);\n\
end function;\n\n",
    
    ZeroRows := "\n\
ZeroRows := function(M)\n\
  return [i: i in [ 1 .. Nrows(M) ] | IsZero(M[i]) ];\n\
end function;\n\n",
    
    ZeroColumns := "\n\
ZeroColumns := function(M)\n\
  return [i: i in [ 1 .. Ncols(M) ] | IsZero(ColumnSubmatrixRange(M,i,i)) ];\n\
end function;\n\n",
    
    GetColumnIndependentUnitPositions := "\n\
GetColumnIndependentUnitPositions:= function(M, pos_list)\n\
  rest := [ 1..Ncols(M) ];\n\
  pos := [ ];\n\
  for i in [ 1 .. Nrows(M) ] do\n\
     for r in Reverse(rest) do\n\
       if [ i, r ] notin pos_list and IsUnit(M[i, r]) then\n\
         Append( ~pos, [ i, r ] );\n\
         rest:= [ x: x in rest | IsZero(M[i, x]) ];\n\
         break;\n\
       end if;\n\
    end for;\n\
  end for;\n\
  return pos;\n\
end function;\n\n",
    
    GetRowIndependentUnitPositions := "\n\
GetRowIndependentUnitPositions:= function(M, pos_list)\n\
  rest := [ 1..Nrows(M) ];\n\
  pos := [ ];\n\
  for j in [ 1 .. Ncols(M) ] do\n\
     for r in Reverse(rest) do\n\
       if [ j, r ] notin pos_list and IsUnit(M[r, j]) then\n\
         Append( ~pos, [ j, r ] );\n\
         rest:= [ x: x in rest | IsZero(M[x, j]) ];\n\
         break;\n\
       end if;\n\
    end for;\n\
  end for;\n\
  return pos;\n\
end function;\n\n",
    
    GetUnitPosition := "\n\
GetUnitPosition:= function(M, pos_list)\n\
  collist:= [ x : x in [1 .. Ncols(M)] | x notin pos_list ];\n\
  ok:= exists(l){ [i, j]: i in [1 .. Nrows(M) ], j in collist | IsUnit( M[i, j] ) };\n\
  return ok select l else \"fail\";\n\
end function;\n\n",
    
    PositionOfFirstNonZeroEntryPerRow := "\n\
PositionOfFirstNonZeroEntryPerRow := function(M)\n\
  X:= [];\n\
  for i in [1..Nrows(M)] do\n\
    Append(~X, Depth(M[i]));\n\
  end for;\n\
  if exists{ x : x in X | x ne X[1] } then\n\
    return X;\n\
  else\n\
    return X[1];\n\
  end if;\n\
end function;\n\n",
    
    PositionOfFirstNonZeroEntryPerColumn := "\n\
PositionOfFirstNonZeroEntryPerColumn := function(M)\n\
  X:= [];\n\
  m:= Nrows(M);\n\
  for j in [1..Ncols(M)] do\n\
    if exists(i){ i: i in [1..m] | not IsZero(M[i,j]) } then\n\
      Append(~X, i);\n\
    else\n\
      Append(~X, 0);\n\
    end if;\n\
  end for;\n\
  if exists{ x : x in X | x ne X[1] } then\n\
    return X;\n\
  else\n\
    return X[1];\n\
  end if;\n\
end function;\n\n",
    
    DivideRowByUnit := "\n\
DivideRowByUnit:= procedure( ~M, i, u, j )\n\
  R := BaseRing(M);\n\
  M[i] *:= 1/(R ! u);\n\
  // to be sure:\n\
  if j gt 0 then\n\
    M[i, j]:= R ! 1;\n\
  end if;\n\
end procedure;\n\n",
    
    DivideColumnByUnit := "\n\
DivideColumnByUnit:= procedure( ~M, j, u, i )\n\
  R := BaseRing(M);\n\
  uinv:= 1/(R ! u);\n\
  for a in [ 1 .. Nrows(M) ] do\n\
    M[a, j] *:= uinv;\n\
  end for;\n\
  // to be sure:\n\
  if i gt 0 then\n\
    M[i, j]:= R ! 1;\n\
  end if;\n\
end procedure;\n\n",
    
    CopyRowToIdentityMatrix := "\n\
CopyRowToIdentityMatrix := procedure( M, i, ~I, j, e)\n\
  I[j]:= M[i];\n\
  if e eq -1 then I[j] *:= -1; end if;\n\
  I[j,j]:= 1;\n\
end procedure;\n\n",

    CopyRowToIdentityMatrix2 := "\n\
CopyRowToIdentityMatrix2 := procedure( M, i, ~I1, ~I2, j)\n\
  I1[j]:= -M[i];\n\
  I1[j,j]:= 1;\n\
  I2[j]:= M[i];\n\
  I2[j,j]:= 1;\n\
end procedure;\n\n",

    CopyColumnToIdentityMatrix := "\n\
CopyColumnToIdentityMatrix := procedure( M, j, ~I, i , e)\n\
  rowlist:= [ 1..i-1 ] cat [ i+1 .. Nrows(M)];\n\
  if e eq 1 then\n\
    for k in rowlist do\n\
      I[k,i] := M[k,j];\n\
    end for;\n\
  else\n\
    for k in rowlist do\n\
      I[k,i] := -M[k,j];\n\
    end for;\n\
  end if;\n\
end procedure;\n\n",
    
    CopyColumnToIdentityMatrix2 := "\n\
CopyColumnToIdentityMatrix2 := procedure( M, j, ~I1, ~I2, i )\n\
  rowlist:= [ 1..i-1 ] cat [ i+1 .. Nrows(M)];\n\
  for k in rowlist do\n\
    x:= M[k,j];\n\
    I1[k,i] := -x;\n\
    I2[k,i] := x;\n\
  end for;\n\
end procedure;\n\n",
    
    SetColumnToZero := "\n\
SetColumnToZero:= procedure( ~M, i, j )\n\
  rowlist:= [ 1..i-1 ] cat [ i+1 .. Nrows(M)];\n\
  for k in rowlist do\n\
    M[k,j]:= 0;\n\
  end for;\n\
end procedure;\n\n",
    
    GetCleanRowsPositions := "\n\
GetCleanRowsPositions:= function( M, clean_columns )\n\
  clean_rows := [ ];\n\
  m := Nrows( M );\n\
  for j in clean_columns do\n\
    for i in [ 1 .. m ] do\n\
      if IsOne(M[i, j]) then\n\
        Append( ~clean_rows, i );\n\
        break;\n\
       end if;\n\
     end for;\n\
  end for;\n\
  return clean_rows;\n\
end function;\n\n",
    
    MyRowspace := "\n\
MyRowspace := function(M)\n\
  if Type(BaseRing(M)) eq AlgExt then\n\
    return sub< Module(BaseRing(M), Ncols(M)) | RowSequence(M) >;\n\
  end if;\n\
  if Type(M) eq AlgMatElt then\n\
    return Rowspace(RMatrixSpace( BaseRing(M), Nrows(M), Ncols(M)) ! M);\n\
  else\n\
    return Rowspace(M);\n\
  end if;\n\
end function;\n\n",
    
    BasisOfRowModule := "\n\
BasisOfRowModule := function(M)\n\
  S := MyRowspace(M);\n\
  Groebner(S);\n\
  return BasisMatrix(S);\n\
end function;\n\n",
    
    BasisOfColumnModule := "\n\
BasisOfColumnModule := function(M)\n\
  return Transpose(BasisOfRowModule(Transpose(M)));\n\
end function;\n\n",
   
    PartiallyReducedBasisOfRowModule := "\n\
PartiallyReducedBasisOfRowModule := function(M)\n\
  S := MyRowspace(M);\n\
  //Groebner(S);\n\
  return Matrix( BaseRing(M), Degree(S), &cat [Eltseq(x) : x in MinimalBasis(S)] );\n\
end function;\n\n\
\n\
PartiallyReducedBasisOfColumnModule := function(M)\n\
  return Transpose(PartiallyReducedBasisOfRowModule(Transpose(M)));\n\
end function;\n\n",
    
    BasisOfRowsCoeff := "\n\
BasisOfRowsCoeff:= function(M)\n\
  B := BasisOfRowModule(M);\n\
  T := Solution(M, B);\n\
  return B, T;\n\
end function;\n\n",
    
    BasisOfColumnsCoeff := "\n\
BasisOfColumnsCoeff:= function(M)\n\
  B, T := BasisOfRowsCoeff(Transpose(M));\n\
  return Transpose(B), Transpose(T);\n\
end function;\n\n",
    
    DecideZeroRows := "\n\
DecideZeroRows:= function(A, B)\n\
  S := MyRowspace(B);\n\
  F := Generic(S);\n\
  return Matrix( [Eltseq(NormalForm(F ! A[i], S)): i in [1..Nrows(A)]] );\n\
end function;\n\n",
    
    DecideZeroColumns := "\n\
DecideZeroColumns:= function(A, B)\n\
  return Transpose(DecideZeroRows(Transpose(A),Transpose(B)));\n\
end function;\n\n",
    
    DecideZeroRowsEffectively := "\n\
DecideZeroRowsEffectively:= function(A, B)\n\
  S := MyRowspace(B);\n\
  F := Generic(S);\n\
  M := Matrix( [Eltseq(NormalForm(F ! A[i], S)): i in [1..Nrows(A)]] );\n\
  return M, Solution( B, M-A );\n\
end function;\n\n",
    
    DecideZeroColumnsEffectively := "\n\
DecideZeroColumnsEffectively:= function(A, B)\n\
  M, T := DecideZeroRowsEffectively(Transpose(A),Transpose(B));\n\
  return Transpose(M), Transpose(T);\n\
end function;\n\n",
    
    SyzygiesGeneratorsOfRows := "\n\
SyzygiesGeneratorsOfRows:= function(M)\n\
    S := MyRowspace(M);\n\
    SM := SyzygyModule(S);\n\
  return Matrix( BaseRing(M), Degree(SM), &cat [Eltseq(x) : x in Basis(SM)] );\n\
end function;\n\n",
    
    SyzygiesGeneratorsOfColumns := "\n\
SyzygiesGeneratorsOfColumns:= function(M)\n\
  return Transpose(SyzygiesGeneratorsOfRows(Transpose(M)));\n\
end function;\n\n",

    RelativeSyzygiesGeneratorsOfRows := "\n\
RelativeSyzygiesGeneratorsOfRows:= function(M1, M2)\n\
  S := MyRowspace( VerticalJoin(M1, M2) );\n\
  SM := SyzygyModule(S);\n\
  SM := MyRowspace( ColumnSubmatrix( BasisMatrix(SM), 1, Nrows(M1) ) );\n\
  return Matrix( BaseRing(M1), Degree(SM), &cat [Eltseq(x) : x in MinimalBasis(SM)] );\n\
end function;\n\n",
    
    RelativeSyzygiesGeneratorsOfColumns := "\n\
RelativeSyzygiesGeneratorsOfColumns:= function(M1, M2)\n\
  return Transpose(RelativeSyzygiesGeneratorsOfRows(Transpose(M1),Transpose(M2)));\n\
end function;\n\n",

    imap := "\n\
function imap(M, R)\n\
S:= BaseRing(Parent(M));\n\
if {Type(S), Type(R)} subset {RngMPol, RngUPol, FldFunRat} then\n\
  N:= []; V:= []; B:= R;\n\
  while Type(B) in {RngMPol, RngUPol, FldFunRat} do\n\
    N cat:= Names(B);\n\
    V cat:= [ R | B.i: i in [1..NumberOfNames(B)] ];\n\
    B:= BaseRing(B);\n\
  end while;\n\
  error if #Set(N) ne #N, \"variable name used twice!\";\n\
  Images:= [ i eq 0 select R ! 0 else V[i] where i:= Index(N, n) : n in Names(S)];\n\
  h:= hom< S -> R | Images >;\n\
  return ChangeRing(M, h);\n\
end if;\n\
return ChangeRing(M, R);\n\
end function;\n\n",

    DegreeOfRingElement := "\n\
// a work around of a bug noticed by Markus L.-H. in the 64bit Magma V2.17-2\n\
if Degree(PolynomialRing(Rationals(),2)!0) eq 0 then\n\
Deg:= function(r,R)\n\
  a := R!r;\n\
  if a eq 0 then return -1; end if; return Degree(a);\n\
end function;\n\
Deg2:= function(r,R,v)\n\
  a := R!r;\n\
  if a eq 0 then return -1; end if; return Degree(a,v);\n\
end function;\n\
else\n\
Deg:= function(r,R)\n\
  return Degree(R!r);\n\
end function;\n\
Deg2:= function(r,R,v)\n\
  return Degree(R!r,v);\n\
end function;\n\
end if;\n\n",
    
    MonomialsUnivariate := "\n\
MonomialsUnivariate :=\n\
func<f,x| [x^(i-1): i in [1..#C] | C[i] ne 0] where C:=Coefficients(f,x)>;\n\n",
    
    )
);

##   
InstallGlobalFunction( InitializeMAGMAMacros,
  function( stream )
    
    homalgSendBlocking( "SetHistorySize(0);\n\n", "need_command", stream, HOMALG_IO.Pictograms.initialize );

    return InitializeMacros( MAGMAMacros, stream );
    
end );

####################################
#
# constructor functions and methods:
#
####################################

##
InstallGlobalFunction( RingForHomalgInMAGMA,
  function( arg )
    local nargs, ar, R;
    
    nargs := Length( arg );
    
    ar := [ arg[1] ];
    
    Add( ar, TheTypeHomalgExternalRingObjectInMAGMA );
    
    if nargs > 1 then
        Append( ar, arg{[ 2 .. nargs ]} );
    fi;
    
    ar := [ ar, TheTypeHomalgExternalRingInMAGMA ];
    
    Add( ar, "HOMALG_IO_MAGMA" );
    
    R := CallFuncList( CreateHomalgExternalRing, ar );
    
    _MAGMA_SetRing( R );
    
    LetWeakPointerListOnExternalObjectsContainRingCreationNumbers( R );
    
    return R;
    
end );

##
InstallGlobalFunction( HomalgRingOfIntegersInMAGMA,
  function( arg )
    local nargs, l, c, d, R;
    
    nargs := Length( arg );
    
    if nargs > 0 and IsInt( arg[1] ) and arg[1] <> 0 then
	l := 2;
        ## characteristic:
        c := AbsInt( arg[1] );
        if IsPrime( c ) then
            if nargs > 1 and IsPosInt( arg[2] ) then
                d := arg[2];
                l := 3;
            else
                d := 1;
            fi;
            R := [ [ "GaloisField(", c, d, ")" ], [ ], [ "<Z", c, "_", d, ">" ] ];
        else
            R := [ [ "IntegerRing(", c, ")" ] ];
        fi;
    else
        if nargs > 0 and arg[1] = 0 then
            l := 2;
        else
            l := 1;
        fi;
        ## characteristic:
        c := 0;
        R := [ [ "IntegerRing()" ] ];
    fi;
    
    if not ( IsZero( c ) or IsPrime( c ) ) then
        Error( "the ring Z/", c, "Z (", c, " non-prime) is not yet supported for MAGMA!\nYou can use the generic residue class ring constructor '/' provided by homalg after defining the ambient ring (over the integers)\nfor help type: ?homalg: constructor for residue class rings\n" );
    fi;
    
    R := Concatenation( R, [ IsPrincipalIdealRing ], arg{[ l .. nargs ]} );
    
    R := CallFuncList( RingForHomalgInMAGMA, R );
    
    if IsBound( d ) and d > 1 then
        R!.NameOfPrimitiveElement := Concatenation( "Z", String( c ), "_", String( d ) );
        SetIsFieldForHomalg( R, true );
        SetRingProperties( R, c, d );
        SetName( R, Concatenation( "GF(", String( c ), "^", String( d ), ")" ) );
    else
        SetIsResidueClassRingOfTheIntegers( R, true );
        SetRingProperties( R, c );
    fi;
    
    return R;
    
end );

##
InstallMethod( HomalgRingOfIntegersInUnderlyingCAS,
        "for an integer and homalg ring in MAGMA",
        [ IsInt, IsHomalgExternalRingInMAGMARep ],
        
  HomalgRingOfIntegersInMAGMA );

##
InstallGlobalFunction( HomalgFieldOfRationalsInMAGMA,
  function( arg )
    local nargs, param, minimal_polynomial, Q, R;
    
    nargs := Length( arg );
    
    if nargs > 0 and IsString( arg[1] ) then
        
        param := ParseListOfIndeterminates( SplitString( arg[1], "," ) );
        
        arg := arg{[ 2 .. nargs ]};
        
        if nargs > 1 and IsString( arg[1] ) then
            minimal_polynomial := arg[1];
            arg := arg{[ 2 .. nargs - 1 ]};
        fi;
        
        Q := CallFuncList( HomalgFieldOfRationalsInMAGMA, arg );
        
        R := Q * param;
        
        R := homalgSendBlocking( [ "FieldOfFractions(", R, ")" ], TheTypeHomalgExternalRingObjectInMAGMA, [ IsPrincipalIdealRing ], HOMALG_IO.Pictograms.CreateHomalgRing );
        
        R := CreateHomalgExternalRing( R, TheTypeHomalgExternalRingInMAGMA );
        
    else
        
        R := "Rationals()";
        
        R := Concatenation( [ R ], [ IsPrincipalIdealRing ], arg );
        
        R := CallFuncList( RingForHomalgInMAGMA, R );
        
    fi;
    
    if IsBound( param ) then
        
        param := List( param, function( a ) local r; r := HomalgExternalRingElement( a, R ); SetName( r, a ); return r; end );
        
        SetRationalParameters( R, param );
        
        SetIsFieldForHomalg( R, true );
        
        SetCoefficientsRing( R, Q );
        
    else
        
        SetIsRationalsForHomalg( R, true );
        
    fi;
    
    SetRingProperties( R, 0 );
    
    return R;
    
end );

##
InstallGlobalFunction( HomalgCyclotomicFieldInMAGMA,
  function( arg )
    local degree, var, R;
    
    if Length( arg ) < 2 then
        
        Error( "too few arguments" );
        
    fi;
    
    degree := arg[ 1 ];
    
    var := arg[ 2 ];
    
    arg := arg{ [ 3 .. Length( arg )] };
    
    if not IsInt( degree ) or degree < 2 or not IsString( var ) then
        
        Error( "input must be an integer > 1 and a string\n" );
        
        return;
        
    fi;
    
    R := [ [ "CyclotomicField(", String( degree ), ")" ], [ ], [ "<", var, ">" ] ];
    
    R := Concatenation( R, [ IsPrincipalIdealRing ], arg );
    
    R := CallFuncList( RingForHomalgInMAGMA, R );
    
    SetName( R, Concatenation( "Q[", var, "]" ) );
    
    SetIsRationalsForHomalg( R, false );
    
    SetIsFieldForHomalg( R, true );
    
    return R;
    
end );

##
InstallMethod( FieldOfFractions,
        "for homalg rings in MAGMA",
        [ IsHomalgExternalRingInMAGMARep and IsIntegersForHomalg ],
        
  function( ZZ )
    
    return HomalgFieldOfRationalsInMAGMA( ZZ );
    
end );

##
InstallMethod( PolynomialRing,
        "for homalg rings in MAGMA",
        [ IsHomalgExternalRingInMAGMARep, IsList ],
        
  function( R, indets )
    local ar, r, var, nr_var, properties, ext_obj, S, l;
    
    ar := _PrepareInputForPolynomialRing( R, indets );
    
    r := ar[1];
    var := ar[2];	## all indeterminates, relative and base
    nr_var := ar[3];	## the number of relative indeterminates
    properties := ar[4];
    
    ## create the new ring
    if Length( var ) = 1 and HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) then
        ext_obj := homalgSendBlocking( [ "PolynomialRing(", r, ")" ], [ ], [ "<", var, ">" ], TheTypeHomalgExternalRingObjectInMAGMA, properties, "break_lists", HOMALG_IO.Pictograms.CreateHomalgRing );
    else
        ext_obj := homalgSendBlocking( [ "PolynomialRing(", r, Length( var ), ",\"grevlex\")" ], [ ], [ "<", var, ">" ], TheTypeHomalgExternalRingObjectInMAGMA, properties, "break_lists", HOMALG_IO.Pictograms.CreateHomalgRing );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInMAGMA );
    
    var := List( var, a -> HomalgExternalRingElement( a, S ) );
    
    Perform( var, Name );
    
    SetIsFreePolynomialRing( S, true );
    
    if HasIndeterminatesOfPolynomialRing( R ) and IndeterminatesOfPolynomialRing( R ) <> [ ] then
        SetBaseRing( S, R );
        l := Length( var );
        SetRelativeIndeterminatesOfPolynomialRing( S, var{[ l - nr_var + 1 .. l ]} );
    fi;
    
    SetRingProperties( S, r, var );
    
    return S;
    
end );

##
InstallMethod( ExteriorRing,
        "for homalg rings in MAGMA",
        [ IsHomalgExternalRingInMAGMARep, IsHomalgExternalRingInMAGMARep, IsHomalgExternalRingInMAGMARep, IsList ],
        
  function( R, Coeff, Base, indets )
    local ar, var, anti, comm, r, ext_obj, S;
    
    ar := _PrepareInputForExteriorRing( R, Base, indets );
    
    var := ar[3];
    anti := ar[4];
    comm := ar[5];
    
    ## create the new ring
    r := CoefficientsRing( R );
    
    ext_obj := homalgSendBlocking( [ "ExteriorAlgebra(", r, Length( anti ), ",\"grevlex\")" ], [ ], [ "<", anti, ">" ], TheTypeHomalgExternalRingObjectInMAGMA, "break_lists", HOMALG_IO.Pictograms.CreateHomalgRing );
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInMAGMA );
    
    anti := List( anti , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( anti, Name );
    
    comm := List( comm , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( comm, Name );
    
    SetIsExteriorRing( S, true );
    
    SetBaseRing( S, Base );
    
    SetRingProperties( S, R, anti );
    
    return S;
    
end );

##
InstallMethod( AddRationalParameters,
        "for MAGMA rings",
        [ IsHomalgExternalRingInMAGMARep and IsFieldForHomalg, IsList ],
        
  function( R, param )
    local c, par;
    
    if IsString( param ) then
        param := [ param ];
    fi;
    
    param := List( param, String );
    
    c := Characteristic( R );
    
    if HasRationalParameters( R ) then
        par := RationalParameters( R );
        par := List( par, String );
    else
        par := [ ];
    fi;
    
    par := Concatenation( par, param );
    par := JoinStringsWithSeparator( par );
    
    ## TODO: take care of the rest
    if c = 0 then
        return HomalgFieldOfRationalsInMAGMA( par, R );
    fi;
    
    return HomalgRingOfIntegersInMAGMA( c, par, R );
    
end );

##
InstallMethod( AddRationalParameters,
        "for MAGMA rings",
        [ IsHomalgExternalRingInMAGMARep and IsFreePolynomialRing, IsList ],
        
  function( R, param )
    local c, par, indets, r;
    
    if IsString( param ) then
        param := [ param ];
    fi;
    
    param := List( param, String );
    
    c := Characteristic( R );
    
    if HasRationalParameters( R ) then
        par := RationalParameters( R );
        par := List( par, String );
    else
        par := [ ];
    fi;
    
    par := Concatenation( par, param );
    par := JoinStringsWithSeparator( par );
    
    indets := Indeterminates( R );
    indets := List( indets, String );
    
    r := CoefficientsRing( R );
    
    if not IsFieldForHomalg( r ) then
        Error( "the coefficients ring is not a field\n" );
    fi;
    
    ## TODO: take care of the rest
    if c = 0 then
        return HomalgFieldOfRationalsInMAGMA( par, r ) * indets;
    fi;
    
    return HomalgRingOfIntegersInMAGMA( c, par, r ) * indets;
    
end );

##
InstallMethod( SetMatElm,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep and IsMutable, IsPosInt, IsPosInt, IsString, IsHomalgExternalRingInMAGMARep ],
        
  function( M, r, c, s, R )
    
    homalgSendBlocking( [ M, "[", r, c, "]:=", s ], "need_command", HOMALG_IO.Pictograms.SetMatElm );
    
end );

##
InstallMethod( AddToMatElm,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep and IsMutable, IsPosInt, IsPosInt, IsHomalgExternalRingElementRep, IsHomalgExternalRingInMAGMARep ],
        
  function( M, r, c, a, R )
    
    homalgSendBlocking( [ M, "[", r, c, "]:=", a, "+", M, "[", r, c, "]" ], "need_command", HOMALG_IO.Pictograms.AddToMatElm );
    
end );

##
InstallMethod( CreateHomalgMatrixFromString,
        "constructor for homalg external matrices in MAGMA",
        [ IsString, IsHomalgExternalRingInMAGMARep ],
        
  function( S, R )
    local ext_obj;
    
    ext_obj := homalgSendBlocking( [ "Matrix(", R, ",", S, ")" ], HOMALG_IO.Pictograms.HomalgMatrix );
    
    return HomalgMatrix( ext_obj, R );
    
end );

##
InstallMethod( CreateHomalgMatrixFromString,
        "constructor for homalg external matrices in MAGMA",
        [ IsString, IsInt, IsInt, IsHomalgExternalRingInMAGMARep ],
  function( S, r, c, R )
    
    local ext_obj;
    
    ext_obj := homalgSendBlocking( [ "Matrix(", R, r, c, ",", S, ")" ], HOMALG_IO.Pictograms.HomalgMatrix );
    
    return HomalgMatrix( ext_obj, r, c, R );
    
end );

##
InstallMethod( CreateHomalgBlockDiagonalMatrixFromStringList,
        "constructor for homalg external matrices in MAGMA",
        [ IsList, IsList, IsList, IsHomalgExternalRingInMAGMARep ],
  function( S, r, c, R )
    local l, ext_obj;
    
    l := Length( S );
    
    ext_obj := Concatenation( List( [ 1 .. l - 1 ], i -> [ "Matrix(", R, r[i], c[i], ",", S[i], ")," ] ) );
    
    Append( ext_obj, [ "Matrix(", R, r[l], c[l], ",", S[l], ")" ] );
    
    ext_obj := Concatenation( [ "DiagonalJoin(<" ], ext_obj, [ ">)" ] );
    
    ext_obj := homalgSendBlocking( ext_obj, HOMALG_IO.Pictograms.HomalgMatrix );
    
    return HomalgMatrix( ext_obj, r, c, R );
    
end );

##
InstallMethod( CreateHomalgMatrixFromSparseString,
        "constructor for homalg external matrices in MAGMA",
        [ IsString, IsInt, IsInt, IsHomalgExternalRingInMAGMARep ],
        
  function( S, r, c, R )
    local M, s;
    
    M := HomalgVoidMatrix( r, c, R );
    
    s := homalgSendBlocking( S, R, HOMALG_IO.Pictograms.sparse );
    
    homalgSendBlocking( [ M, " := Matrix(SparseMatrix(", R, r, c, ", [car<Integers(), Integers(), ", R, "> | <a,b,c> where a,b,c:= Explode(e): e in ", s, "] ))" ] , "need_command", HOMALG_IO.Pictograms.HomalgMatrix );
    
    return M;
    
end );

##
InstallMethod( MatElmAsString,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep, IsPosInt, IsPosInt, IsHomalgExternalRingInMAGMARep ],
        
  function( M, r, c, R )
    
    return homalgSendBlocking( [ M, "[", r, c, "]" ], "need_output", HOMALG_IO.Pictograms.MatElm );
    
end );

##
InstallMethod( MatElm,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep, IsPosInt, IsPosInt, IsHomalgExternalRingInMAGMARep ],
        
  function( M, r, c, R )
    local Mrc;
    
    Mrc := homalgSendBlocking( [ M, "[", r, c, "]" ], HOMALG_IO.Pictograms.MatElm );
    
    return HomalgExternalRingElement( Mrc, R );
    
end );

##
InstallMethod( GetListOfHomalgMatrixAsString,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInMAGMARep ],
        
  function( M, R )
    
    return homalgSendBlocking( [ "Eltseq(", M, ")" ], "need_output", HOMALG_IO.Pictograms.GetListOfHomalgMatrixAsString );
    
end );

##
InstallMethod( GetListListOfHomalgMatrixAsString,
        "for external matrices",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInMAGMARep ],
        
  function( M, R )
    
    return homalgSendBlocking( [ "RowSequence(", M, ")" ], "need_output", HOMALG_IO.Pictograms.GetListListOfHomalgMatrixAsString );
    
end );

##
InstallMethod( GetSparseListOfHomalgMatrixAsString,
        "for homalg external matrices in MAGMA",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInMAGMARep ],
        
  function( M, R )
    
    return homalgSendBlocking( [ "[ [s[1], s[2], m[s[1], s[2] ] ] : s in Support(m)] where m:=", M ], "need_output", HOMALG_IO.Pictograms.GetSparseListOfHomalgMatrixAsString );
    
end );

##
InstallMethod( SaveHomalgMatrixToFile,
        "for homalg external matrices in MAGMA",
        [ IsString, IsHomalgMatrix, IsHomalgExternalRingInMAGMARep ],
        
  function( filename, M, R )
    local mode, command;
    
    if not IsBound( M!.SaveAs ) then
        mode := "ListList";
    else
        mode := M!.SaveAs; #not yet supported
    fi;
    
    if mode = "ListList" then
        command := [ "_str := [ Sprint( RowSequence(", M, ")[x]) : x in [1..", NrRows( M ), "]]; ",
                     "_fs := Open(\"", filename, "\",\"w\"); ",
                     "Put( _fs, Sprint(_str) ); Flush( _fs ); delete( _fs )" ];
        
        homalgSendBlocking( command, "need_command", HOMALG_IO.Pictograms.SaveHomalgMatrixToFile );
        
    fi;
    
    return true;
    
end );

##
InstallMethod( LoadHomalgMatrixFromFile,
        "for external rings in MAGMA",
        [ IsString, IsHomalgExternalRingInMAGMARep ],
        
  function( filename, R )
    local mode, command, M;
    
    if not IsBound( R!.LoadAs ) then
        mode := "ListList";
    else
        mode := R!.LoadAs; #not yet supported
    fi;
    
    M := HomalgVoidMatrix( R );
    
    if mode = "ListList" then
        
        command := [ M, ":= Matrix(", R, ", eval( Read( \"", filename ,"\" ) ) )" ];
        
        homalgSendBlocking( command, "need_command", HOMALG_IO.Pictograms.LoadHomalgMatrixFromFile );
        
    fi;
    
    return M;
    
end );

####################################
#
# View, Print, and Display methods:
#
####################################

##
InstallMethod( DisplayRing,
        "for homalg rings in MAGMA",
        [ IsHomalgExternalRingInMAGMARep ], 1,
        
  function( o )
    
    homalgDisplay( o );
    
end );