GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
############################################################################# ## ## HomalgToCAS.gi HomalgToCAS package Mohamed Barakat ## ## Copyright 2007-2010 Lehrstuhl B für Mathematik, RWTH Aachen ## ## Implementation stuff for HomalgToCAS. ## ############################################################################# #################################### # # global variables: # #################################### # a central place for configuration variables: InstallValue( HOMALG_IO, rec( show_banners := true, variable_name := "homalg_variable_", InformAboutCASystemsWithoutActiveRings := true, SaveHomalgMaximumBackStream := false, color_display := false, DirectoryForTemporaryFiles := "/tmp/", DoNotFigureOutAnAlternativeDirectoryForTemporaryFiles := false, DoNotDeleteTemporaryFiles := false, ListOfAlternativeDirectoryForTemporaryFiles := [ "/tmp/", "/dev/shm/", "/var/tmp/", "./" ], FileNameCounter := 1, DeletePeriod := 500, PID := IO_getpid(), save_CAS_commands_to_file := false, suppress_CAS := false, suppress_PID := false, ## <#GAPDoc Label="Pictograms"> ## <ManSection> ## <Var Name="HOMALG_IO.Pictograms"/> ## <Description> ## The record of pictograms is a component of the record <C>HOMALG_IO</C>. ## <Listing Type="Code"><![CDATA[ Pictograms := rec( ## ## colors: ## ## pictogram color of a "need_command" or assignment operation: color_need_command := "\033[1;33;44m", ## pictogram color of a "need_output" or "need_display" operation: color_need_output := "\033[1;34;43m", ## ## good morning computer algebra system: ## ## initialize: initialize := "ini", ## define macros: define := "def", ## get time: time := ":ms", ## memory usage: memory := "mem", ## unknown: unknown := "???", ## ## external garbage collection: ## ## delete a variable: delete := "xxx", ## delete serveral variables: multiple_delete := "XXX", ## trigger the garbage collector: garbage_collector := "grb", ## ## create lists: ## ## define a list: CreateList := "lst", ## ## create rings: ## ## define a ring: CreateHomalgRing := "R:=", ## get the names of the "variables" defining the ring: variables := "var", ## define zero: Zero := "0:=", ## define one: One := "1:=", ## define minus one: MinusOne := "-:=", ## ## mandatory ring operations: ## ## get the name of an element: ## (important if the CAS pretty-prints ring elements, ## we need names that can be used as input!) ## (install a method instead of a homalgTable entry) homalgSetName := "\"a\"", ## a = 0 ? IsZero := "a=0", ## a = 1 ? IsOne := "a=1", ## substract two ring elements ## (needed by SimplerEquivalentMatrix in case ## CopyRow/ColumnToIdentityMatrix are not defined): Minus := "a-b", ## divide the element a by the unit u ## (needed by SimplerEquivalentMatrix in case ## DivideEntryByUnit is not defined): DivideByUnit := "a/u", ## important ring operations: ## (important for performance since existing ## fallback methods cause a lot of traffic): ## is u a unit? ## (mainly needed by the fallback methods for matrices, see below): IsUnit := "?/u", ## ## optional ring operations: ## ## copy an element: CopyElement := "a>a", ## add two ring elements: Sum := "a+b", ## multiply two ring elements: Product := "a*b", ## the (greatest) common divisor: Gcd := "gcd", ## cancel the (greatest) common divisor: CancelGcd := "ccd", ## random polynomial: RandomPol := "rpl", ## numerator: Numerator := "num", ## denominator: Denominator := "den", ## evaluate polynomial: Evaluate := "evl", ## degree of a multivariate polynomial DegreeOfRingElement := "deg", ## is irreducible: IsIrreducible := "irr", ## ## create matrices: ## ## define a matrix: HomalgMatrix := "A:=", ## copy a matrix: CopyMatrix := "A>A", ## load a matrix from file: LoadHomalgMatrixFromFile := "A<<", ## save a matrix to file: SaveHomalgMatrixToFile := "A>>", ## get a matrix entry as a string: MatElm := "<ij", ## set a matrix entry from a string: SetMatElm := ">ij", ## add to a matrix entry from a string: AddToMatElm := "+ij", ## get a list of the matrix entries as a string: GetListOfHomalgMatrixAsString := "\"A\"", ## get a listlist of the matrix entries as a string: GetListListOfHomalgMatrixAsString := "\"A\"", ## get a "sparse" list of the matrix entries as a string: GetSparseListOfHomalgMatrixAsString := ".A.", ## assign a "sparse" list of matrix entries to a variable: sparse := "spr", ## list of assumed inequalities: Inequalities := "<>0", ## list of assumed inequalities: MaximalIndependentSet := "idp", ## ## mandatory matrix operations: ## ## test if a matrix is the zero matrix: ## CAUTION: the external system must be able to check ## if the matrix is zero modulo possible ring relations ## only known to the external system! IsZeroMatrix := "A=0", ## number of rows: NrRows := "#==", ## number of columns: NrColumns := "#||", ## determinant of a matrix over a (commutative) ring: Determinant := "det", ## create a zero matrix: ZeroMatrix := "(0)", ## create a initial zero matrix: InitialMatrix := "[0]", ## create an identity matrix: IdentityMatrix := "(1)", ## create an initial identity matrix: InitialIdentityMatrix := "[1]", ## "transpose" a matrix (with "the" involution of the ring): Involution := "A^*", ## get certain rows of a matrix: CertainRows := "===", ## get certain columns of a matrix: CertainColumns := "|||", ## stack to matrices vertically: UnionOfRows := "A_B", ## glue to matrices horizontally: UnionOfColumns := "A|B", ## create a block diagonal matrix: DiagMat := "A\\B", ## the Kronecker (tensor) product of two matrices: KroneckerMat := "AoB", ## multiply a ring element with a matrix: MulMat := "a*A", ## multiply a matrix with a ring element: MulMatRight := "A*a", ## add two matrices: AddMat := "A+B", ## substract two matrices: SubMat := "A-B", ## multiply two matrices: Compose := "A*B", ## pullback a matrix by a ring map: Pullback := "pbk", ## ## important matrix operations: ## (important for performance since existing ## fallback methods cause a lot of traffic): ## ## test if two matrices are equal: ## CAUTION: the external system must be able to check ## equality of the two matrices modulo possible ring relations ## only known to the external system! AreEqualMatrices := "A=B", ## test if a matrix is the identity matrix: IsIdentityMatrix := "A=1", ## test if a matrix is diagonal (needed by the display method): IsDiagonalMatrix := "A=\\", ## get the positions of the zero rows: ZeroRows := "0==", ## get the positions of the zero columns: ZeroColumns := "0||", ## get "column-independent" unit positions ## (needed by ReducedBasisOfModule): GetColumnIndependentUnitPositions := "ciu", ## get "row-independent" unit positions ## (needed by ReducedBasisOfModule): GetRowIndependentUnitPositions := "riu", ## get the position of the "first" unit in the matrix ## (needed by SimplerEquivalentMatrix): GetUnitPosition := "gup", ## position of the first non-zero entry per row PositionOfFirstNonZeroEntryPerRow := "fnr", ## position of the first non-zero entry per column PositionOfFirstNonZeroEntryPerColumn := "fnc", ## indicator matrix of non-zero entries IndicatorMatrixOfNonZeroEntries := "<>0", ## transposed matrix: TransposedMatrix := "^tr", ## divide an entry of a matrix by a unit ## (needed by SimplerEquivalentMatrix in case ## DivideRow/ColumnByUnit are not defined): DivideEntryByUnit := "ij/", ## divide a row by a unit ## (needed by SimplerEquivalentMatrix): DivideRowByUnit := "-/u", ## divide a column by a unit ## (needed by SimplerEquivalentMatrix): DivideColumnByUnit := "|/u", ## divide a row by a unit ## (needed by SimplerEquivalentMatrix): CopyRowToIdentityMatrix := "->-", ## divide a column by a unit ## (needed by SimplerEquivalentMatrix): CopyColumnToIdentityMatrix := "|>|", ## set a column (except a certain row) to zero ## (needed by SimplerEquivalentMatrix): SetColumnToZero := "|=0", ## get the positions of the rows with a single one ## (needed by SimplerEquivalentMatrix): GetCleanRowsPositions := "crp", ## convert a single row matrix into a matrix ## with specified number of rows/columns ## (needed by the display methods for homomorphisms): ConvertRowToMatrix := "-%A", ## convert a single column matrix into a matrix ## with specified number of rows/columns ## (needed by the display methods for homomorphisms): ConvertColumnToMatrix := "|%A", ## convert a matrix into a single row matrix: ConvertMatrixToRow := "A%-", ## convert a matrix into a single column matrix: ConvertMatrixToColumn := "A%|", ## ## basic matrix operations: ## ## compute a (r)educed (e)chelon (f)orm: ReducedEchelonForm := "ref", ## compute a "(bas)is" of a given set of module elements: BasisOfModule := "bas", ## compute a reduced "(Bas)is" of a given set of module elements: ReducedBasisOfModule := "Bas", ## (d)e(c)ide the ideal/submodule membership problem, ## i.e. if an element is (0) modulo the ideal/submodule: DecideZero := "dc0", ## compute a generating set of (syz)ygies: SyzygiesGenerators := "syz", ## compute a generating set of reduced (Syz)ygies: ReducedSyzygiesGenerators := "Syz", ## compute a (R)educed (E)chelon (F)orm ## together with the matrix of coefficients: ReducedEchelonFormC := "REF", ## compute a "(BAS)is" of a given set of module elements ## together with the matrix of coefficients: BasisCoeff := "BAS", ## (D)e(C)ide the ideal/submodule membership problem, ## i.e. write an element effectively as (0) modulo the ideal/submodule: DecideZeroEffectively := "DC0", ## ## optional matrix operations: ## ## Hilbert-Poincare series of a module: HilbertPoincareSeries := "HPs", ## Hilbert polynomial of a module: HilbertPolynomial := "Hil", ## affine dimension of a module: AffineDimension := "dim", ## affine degree of a module: AffineDegree := "adg", ## the constant term of the hilbert polynomial: ConstantTermOfHilbertPolynomial := "P_0", ## primary decomposition: PrimaryDecomposition := "YxZ", ## eliminate variables: Eliminate := "eli", ## leading module: LeadingModule := "led", ## the i-th monomial matrix MonomialMatrix := "mon", ## matrix of symbols: MatrixOfSymbols := "smb", ## leading module: ## coefficients: Coefficients := "cfs", ## ## optional module operations: ## ## compute a better equivalent matrix ## (field -> row+col Gauss, PIR -> Smith, Dedekind domain -> Krull, etc ...): BestBasis := "(\\)", ## compute elementary divisors: ElementaryDivisors := "div", ## ## for the eye: ## ## display objects: Display := "dsp", ## the LaTeX code of the mathematical entity: homalgLaTeX := "TeX", ) ## ]]></Listing> ## </Description> ## </ManSection> ## <#/GAPDoc> ) ); #################################### # # global functions and operations: # #################################### ## InstallGlobalFunction( homalgTime, function( arg ) local nargs, st, object, stream, t; nargs := Length( arg ); if nargs = 0 then return homalgTotalRuntimes( ); elif nargs = 1 then st := arg[1]; if IsInt( st ) then return homalgTotalRuntimes( ) - st; fi; return homalgTime( st, 0 ); fi; ## we now know thar nargs > 1 object := arg[1]; if IsRecord( object ) then if not ( IsBound( object.lines ) and IsBound( object.pid ) ) then Error( "the first argument is a record but not a stream\n" ); fi; stream := object; else stream := homalgStream( object ); fi; t := arg[2]; if not IsInt( t ) then Error( "the second argument must be an integer\n" ); fi; if not IsBound( stream.time ) then Error( "the stream does not include a component called \"time\"\n" ); fi; return stream.time( stream, t ); end ); ## InstallGlobalFunction( homalgMemoryUsage, function( arg ) local nargs, o, object, stream; nargs := Length( arg ); if nargs = 0 then Error( "empty input\n" ); elif nargs = 1 then o := arg[1]; return homalgMemoryUsage( o, 0 ); fi; ## we now know thar nargs > 1 object := arg[1]; if IsRecord( object ) then if not ( IsBound( object.lines ) and IsBound( object.pid ) ) then Error( "the first argument is a record but not a stream\n" ); fi; stream := object; else stream := homalgStream( object ); fi; o := arg[2]; if not IsInt( o ) then Error( "the second argument must be an integer\n" ); fi; if not IsBound( stream.memory_usage ) then Error( "the stream does not include a component called \"memory_usage\"\n" ); fi; return stream.memory_usage( stream, o ); end ); ## InstallGlobalFunction( FigureOutAnAlternativeDirectoryForTemporaryFiles, function( arg ) local nargs, file, list, separator, pos_sep, l, directory, filename, fs; nargs := Length( arg ); if nargs = 0 then Error( "empty input" ); fi; file := arg[1]; if IsBound( HOMALG_IO.ListOfAlternativeDirectoryForTemporaryFiles ) then list := HOMALG_IO.ListOfAlternativeDirectoryForTemporaryFiles; else list := [ "/tmp/", "/dev/shm/", "/var/tmp/" ]; fi; ## figure out the directory separtor: if IsBound( GAPInfo.UserHome ) then separator := GAPInfo.UserHome[1]; else separator := '/'; fi; if nargs > 1 then pos_sep := PositionProperty( Reversed( file ), c -> c = separator ); if pos_sep <> fail then l := Length( file ); file := file{[ l - pos_sep + 2 .. l ]}; fi; fi; for directory in list do if directory[Length( directory )] <> separator then filename := Concatenation( directory, [ separator ], file ); else filename := Concatenation( directory, file ); fi; fs := IO_File( filename, "w" ); if fs <> fail then IO_Close( fs ); if nargs > 1 and arg[2] = "with_filename" then return filename; else return directory; fi; fi; od; return fail; end ); ## <#GAPDoc Label="homalgIOMode"> ## <ManSection> ## <Func Arg="str[, str2[, str3]]" Name="homalgIOMode"/> ## <Description> ## This function sets different modes which influence how much of the communication becomes visible. ## Handling the string <A>str</A> is <E>not</E> case-sensitive. <C>homalgIOMode</C> invokes ## the global function <C>homalgMode</C> defined in the &homalg; package with an <Q>appropriate</Q> argument (see code below). ## Alternatively, if a second or more strings are given, then <C>homalgMode</C> is invoked with the remaining strings ## <A>str2</A>, <A>str3</A>, ... at the end. In particular, you can use <C>homalgIOMode</C>( <A>str</A>, "" ) to reset the effect ## of invoking <C>homalgMode</C>. ## <Table Align="l|c|l"> ## <Row> ## <Item><A>str</A></Item> ## <Item><A>str</A> (long form)</Item> ## <Item>mode description</Item> ## </Row> ## <HorLine/> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>""</Item> ## <Item>""</Item> ## <Item>the default mode, i.e. the communication protocol won't be visible</Item> ## </Row> ## <Row> ## <Item></Item> ## <Item></Item> ## <Item>(<C>homalgIOMode</C>( ) is a short form for <C>homalgIOMode</C>( "" ))</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>"a"</Item> ## <Item>"all"</Item> ## <Item>combine the modes "debug" and "file"</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>"b"</Item> ## <Item>"basic"</Item> ## <Item>the same as "picto" + <C>homalgMode</C>( "basic" )</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>"d"</Item> ## <Item>"debug"</Item> ## <Item>view the complete communication protocol</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>"f"</Item> ## <Item>"file"</Item> ## <Item>dump the communication protocol into a file with the name</Item> ## </Row> ## <Row> ## <Item></Item> ## <Item></Item> ## <Item><C>Concatenation</C>( "commands_file_of_", CAS, "_with_PID_", PID )</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <Row> ## <Item>"p"</Item> ## <Item>"picto"</Item> ## <Item>view the abbreviated communication protocol</Item> ## </Row> ## <Row> ## <Item></Item> ## <Item></Item> ## <Item>using the preassigned pictograms</Item> ## </Row> ## <Row><Item></Item><Item></Item><Item></Item></Row> ## <HorLine/> ## </Table> ## All modes other than the "default"-mode only set their specific values and leave ## the other values untouched, which allows combining them to some extent. This also means that ## in order to get from one mode to a new mode (without the aim to combine them) ## one needs to reset to the "default"-mode first. <Br/><Br/> ## <E>Caution</E>: ## <List> ## <Item>In case you choose one of the modes "file" or "all" you might want to set ## the global variable <C>HOMALG_IO.DoNotDeleteTemporaryFiles</C> := <C>true</C>; ## this is only important if during the computations some matrices get converted via files ## (using <C>ConvertHomalgMatrixViaFile</C>), as reading these files will be part of the protocol!</Item> ## <Item>It makes sense for the dumped communication protocol to be (re)executed with the respective external system, ## only in case the latter is deterministic (i.e. same-input-same-output).</Item> ## </List> ## <Listing Type="Code"><![CDATA[ InstallGlobalFunction( homalgIOMode, function( arg ) local nargs, mode, s; nargs := Length( arg ); if nargs = 0 or ( IsString( arg[1] ) and arg[1] = "" ) then mode := "default"; elif IsString( arg[1] ) then ## now we know, the string is not empty s := arg[1]; if LowercaseString( s{[1]} ) = "a" then mode := "all"; elif LowercaseString( s{[1]} ) = "b" then mode := "basic"; elif LowercaseString( s{[1]} ) = "d" then mode := "debug"; elif LowercaseString( s{[1]} ) = "f" then mode := "file"; elif LowercaseString( s{[1]} ) = "p" then mode := "picto"; else mode := ""; fi; else Error( "the first argument must be a string\n" ); fi; if mode = "default" then ## reset to the default values HOMALG_IO.color_display := false; HOMALG_IO.show_banners := true; HOMALG_IO.save_CAS_commands_to_file := false; HOMALG_IO.DoNotDeleteTemporaryFiles := false; HOMALG_IO.SaveHomalgMaximumBackStream := false; HOMALG_IO.InformAboutCASystemsWithoutActiveRings := true; SetInfoLevel( InfoHomalgToCAS, 1 ); homalgMode( ); elif mode = "all" then homalgIOMode( "debug" ); homalgIOMode( "file" ); elif mode = "basic" then HOMALG_IO.color_display := true; HOMALG_IO.show_banners := true; SetInfoLevel( InfoHomalgToCAS, 4 ); homalgMode( "basic" ); ## use homalgIOMode( "basic", "" ) to reset elif mode = "debug" then HOMALG_IO.color_display := true; HOMALG_IO.show_banners := true; SetInfoLevel( InfoHomalgToCAS, 8 ); homalgMode( "debug" ); ## use homalgIOMode( "debug", "" ) to reset elif mode = "file" then HOMALG_IO.save_CAS_commands_to_file := true; elif mode = "picto" then HOMALG_IO.color_display := true; HOMALG_IO.show_banners := true; SetInfoLevel( InfoHomalgToCAS, 4 ); homalgMode( "logic" ); ## use homalgIOMode( "picto", "" ) to reset fi; if nargs > 1 and IsString( arg[2] ) then CallFuncList( homalgMode, arg{[ 2 .. nargs ]} ); fi; end ); ## ]]></Listing> ## </Description> ## <#Include Label="homalgSendBlocking:view_communication"> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( ApplyCommandToString, function( arg ) local nargs, cmd, str, separator, directory, pointer, pid, file, filename, fs, output; nargs := Length( arg ); if nargs = 0 then Error( "no arguments provided\n" ); elif IsString( arg[1] ) then cmd := arg[1]; else Error( "the first argument is not a string\n" ); fi; if nargs = 1 then elif IsString( arg[2] ) then str := arg[2]; else Error( "the second argument is not a string\n" ); fi; ## figure out the directory separtor: if IsBound( GAPInfo.UserHome ) then separator := GAPInfo.UserHome[1]; else separator := '/'; fi; if IsBound( HOMALG_IO.DirectoryForTemporaryFiles ) then directory := HOMALG_IO.DirectoryForTemporaryFiles; if directory[Length(directory)] <> separator then directory[Length(directory) + 1] := separator; fi; else directory := ""; fi; if IsBound( HOMALG_IO.FileNameCounter ) then pointer := Concatenation( "homalg_file_", String( HOMALG_IO.FileNameCounter ) ); HOMALG_IO.FileNameCounter := HOMALG_IO.FileNameCounter + 1; else Error( "HOMALG_IO.FileNameCounter is not bound, filename creation for internal object failed.\n" ); fi; if not IsBound( HOMALG_IO.PID ) or not IsInt( HOMALG_IO.PID ) then HOMALG_IO.PID := 99999; #this is not the real PID! fi; pid := Concatenation( "_PID_", String( HOMALG_IO.PID ) ); file := Concatenation( pointer, pid ); filename := Concatenation( directory, file ); if IsBound( str ) then cmd := Filename( DirectoriesSystemPrograms(), cmd ); Exec( Concatenation( "echo ", str, " | ", cmd, " ", " > ", filename ) ); else Exec( Concatenation( cmd, " ", " > ", filename ) ); fi; fs := IO_File( filename, "r" ); if fs = fail then Error( "unable to open the file ", filename, " for reading\n" ); fi; output := IO_ReadUntilEOF( fs ); if IO_Close( fs ) = fail then Error( "unable to close the file ", filename, "\n" ); fi; if not ( IsBound( HOMALG_IO.DoNotDeleteTemporaryFiles ) and HOMALG_IO.DoNotDeleteTemporaryFiles = true ) then Exec( Concatenation( "/bin/rm -f \"", filename, "\"" ) ); fi; return output; end ); ## InstallMethod( ShaSum, "for a string", [ IsString ], function( str ) local sha; sha := ApplyCommandToString( "shasum", str ); NormalizeWhitespace( sha ); return sha{[ 1 .. Length( sha ) - 2 ]}; end ); ## InstallGlobalFunction( GetTimeOfDay, function( arg ) local t; t := ApplyCommandToString( "date +\"%Y-%m-%d:%H:%M:%S,%N\"" ); NormalizeWhitespace( t ); return t; end ); ## InstallGlobalFunction( FingerprintOfGapProcess, function( arg ) local f; f := rec( Version := GAPInfo.Version, BuildDateTime := GAPInfo.BuildDateTime, Architecture := GAPInfo.Architecture, PID := IO_getpid(), TimeOfDay := GetTimeOfDay() ); if Length( arg ) > 0 then if Length( arg ) = 1 then f.ID := arg[1]; else f.ID := arg; fi; fi; return f; end );