Revision b2cd05142aa29a4b6a5b26cca08f5791ef9ed6bb authored by Sebastian Gutsche on 18 June 2015, 09:07:29 UTC, committed by Sebastian Gutsche on 18 June 2015, 09:10:31 UTC
1 parent 9cdf527
homalgSendBlocking.gi
#############################################################################
##
## homalgSendBlocking.gi HomalgToCAS package Mohamed Barakat
##
## Copyright 2007-2008 Lehrstuhl B für Mathematik, RWTH Aachen
##
## Implementation stuff to manage the communication.
##
#############################################################################
####################################
#
# methods for operations:
#
####################################
##
InstallGlobalFunction( homalgFlush,
function( arg )
local nargs, verbose, stream, container, weak_pointers, l, pids, R, p, i,
var, active_ring_creation_number, ring_creation_numbers, deleted,
streams;
## the internal garbage collector:
GASMAN( "collect" );
nargs := Length( arg );
verbose := true;
if nargs > 0 and IsStringRep( arg[nargs] ) then
nargs := nargs - 1;
verbose := false;
fi;
## nargs is the number of arguments _without_ an optional last "quiet" string; see above
if nargs = 0 and IsBound( HOMALG_MATRICES.ContainerForWeakPointersOnHomalgExternalRings ) then
container := HOMALG_MATRICES.ContainerForWeakPointersOnHomalgExternalRings;
weak_pointers := container!.weak_pointers;
l := container!.counter;
pids := [ ];
for i in [ 1 .. l ] do
R := ElmWPObj( weak_pointers, i );
if R <> fail then
p := homalgExternalCASystemPID( R );
## do not rely on the (not p in pids) criterion
## for streams with an active ring
if not p in pids or IsBound( homalgStream( R )!.active_ring ) then
Add( pids, p );
## it is now important to pass the ring R and not merely its stream
## to homalgFlush as R might not the currently active ring;
## this is important for computer algebra systems like Singular,
## which have the "feature" that a variable is stored in the ring
## which was active when the variable was assigned...
if verbose then
homalgFlush( R );
else
homalgFlush( R, "quiet" );
fi;
fi;
fi;
od;
deleted := Filtered( [ 1 .. l ], i -> not IsBoundElmWPObj( weak_pointers, i ) );
container!.deleted := deleted;
if IsBound( HOMALG_IO.InformAboutCASystemsWithoutActiveRings )
and HOMALG_IO.InformAboutCASystemsWithoutActiveRings = true then
pids := [ ];
for i in [ 1 .. l ] do
R := ElmWPObj( weak_pointers, i );
if R <> fail then
Add( pids, homalgExternalCASystemPID( R ) );
fi;
od;
pids := DuplicateFreeList( pids );
streams := container!.streams;
l := Length( streams );
deleted := [ ];
for i in [ 1 .. l ] do
if not streams[i].pid in pids then
Add( deleted, streams[i].pid );
fi;
od;
if deleted <> [ ] and verbose then
Print( "the external CASs with pids ", deleted, " have no active rings: they can be terminated by launching TerminateCAS()\n" );
fi;
fi;
elif nargs > 0 then
if IsHomalgExternalRingRep( arg[1] ) then
R := arg[1];
stream := homalgStream( R );
elif IsRecord( arg[1] ) and IsBound( arg[1].lines ) and IsBound( arg[1].pid ) then
stream := arg[1];
else
Error( "the first argument is neither an external ring nor a stream\n" );
fi;
container := stream.homalgExternalObjectsPointingToVariables;
weak_pointers := container!.weak_pointers;
l := container!.counter;
## exclude already deleted external objects:
var := Difference( [ 1 .. l ], container!.deleted );
if IsBound( stream.active_ring ) then
if not IsBound( R ) then
R := stream.active_ring;
fi;
## R is either already the active ring
## or the one we will make active below
active_ring_creation_number := R!.creation_number;
ring_creation_numbers := container!.ring_creation_numbers;
## this is important for computer algebra systems like Singular,
## which have the "feature" that a variable is stored in the ring
## which was active when the variable was assigned...
## mapping all existing variables to the active ring
## -- besides being a bad idea anyway -- would result in various disasters:
## non-zero entries of a matrix over a ring S (e.g. polynomial ring)
## often become zero when the matrix is mapped to another ring (e.g. exterior ring),
## and of course remain zero when the matrix is mapped back to the original ring S.
var := Filtered( var, i -> not IsBoundElmWPObj( weak_pointers, i ) and IsBound( ring_creation_numbers[i] ) and ring_creation_numbers[i] = active_ring_creation_number );
## set the argument to be the active ring
if var <> [ ] and IsHomalgExternalRingRep( R ) and
not IsIdenticalObj( R, stream.active_ring ) then
homalgSendBlocking( "\"we've just reset the ring for garbage collection\"", "need_command", R, HOMALG_IO.Pictograms.initialize );
fi;
## free the entries corresponding to external objects about to be deleted
Perform( var, function( i ) Unbind( ring_creation_numbers[i] ); end );
else
var := Filtered( var, i -> not IsBoundElmWPObj( weak_pointers, i ) );
fi;
l := Length( var );
deleted := Union2( container!.deleted, var );
if IsBound( stream.multiple_delete ) and ( l > 1 or ( not IsBound( stream.delete ) and l > 0 ) ) then
stream.multiple_delete( List( var, v -> Concatenation( stream.variable_name, String( v ) ) ), stream );
container!.deleted := deleted;
elif IsBound( stream.delete ) and l > 0 then
Perform( var, function( p ) stream.delete( Concatenation( stream.variable_name, String( p ) ), stream ); end );
container!.deleted := deleted;
fi;
if IsBound( stream.garbage_collector ) then
## the external garbage collector:
stream.garbage_collector( stream );
if verbose then
Print( "completed garbage collection in the external CAS ", stream.name, " with pid ", stream.pid, "\n" );
fi;
fi;
fi;
end );
##
InstallGlobalFunction( TerminateAllCAS,
function( )
local stream;
for stream in HOMALG_MATRICES.ContainerForWeakPointersOnHomalgExternalRings!.streams do
stream!.TerminateCAS( stream );
od;
end );
##
InstallGlobalFunction( _SetElmWPObj_ForHomalg, ## is not based on homalgFlush for performance reasons
function( stream, ext_obj )
local container, weak_pointers, l, DeletePeriod, var,
active_ring_creation_number, ring_creation_numbers, deleted;
container := stream.homalgExternalObjectsPointingToVariables;
weak_pointers := container!.weak_pointers;
l := container!.counter;
if IsBound( stream.DeletePeriod ) then
if IsBool( stream.DeletePeriod ) then
DeletePeriod := stream.DeletePeriod;
else
DeletePeriod := l mod stream.DeletePeriod = 0;
fi;
else
DeletePeriod := true;
fi;
if DeletePeriod then
## exclude already deleted external objects:
var := Difference( [ 1 .. l ], container!.deleted );
fi;
if IsBound( stream.active_ring ) then
active_ring_creation_number := stream.active_ring!.creation_number;
ring_creation_numbers := container!.ring_creation_numbers;
## set the active ring for the new external object
ring_creation_numbers[l + 1] := active_ring_creation_number;
if DeletePeriod then
## this is important for computer algebra systems like Singular,
## which have the "feature" that a variable is stored in the ring
## which was active when the variable was assigned...
## mapping all existing variables to the active ring
## -- besides being a bad idea anyway -- would result in various disasters:
## non-zero entries of a matrix over a ring S (e.g. polynomial ring)
## often become zero when the matrix is mapped to another ring (e.g. exterior ring),
## and of course remain zero when the matrix is mapped back to the original ring S.
var := Filtered( var, i -> not IsBoundElmWPObj( weak_pointers, i ) and IsBound( ring_creation_numbers[i] ) and ring_creation_numbers[i] = active_ring_creation_number );
## free the entries corresponding to external objects about to be deleted
Perform( var, function( i ) Unbind( ring_creation_numbers[i] ); end );
fi;
else
if DeletePeriod then
var := Filtered( var, i -> not IsBoundElmWPObj( weak_pointers, i ) );
fi;
fi;
l := l + 1;
container!.counter := l;
## sanity check
if not Concatenation( stream.variable_name, String( l ) ) = homalgPointer( ext_obj ) then
Error( "\033[01m\033[5;31;47mexpecting an external object with pointer = ",
Concatenation( stream.variable_name, String( l ) ),
" but recieved one with pointer = ", homalgPointer( ext_obj ), "\033[0m" );
fi;
SetElmWPObj( weak_pointers, l, ext_obj );
if DeletePeriod then
l := Length( var );
deleted := Union2( container!.deleted, var );
if IsBound( stream.multiple_delete ) and ( l > 1 or ( not IsBound( stream.delete ) and l > 0 ) ) then
stream.multiple_delete( List( var, v -> Concatenation( stream.variable_name, String( v ) ) ), stream );
container!.deleted := deleted;
elif IsBound( stream.delete ) and l > 0 then
Perform( var, function( p ) stream.delete( Concatenation( stream.variable_name, String( p ) ), stream ); end );
container!.deleted := deleted;
fi;
## never ever call the internal or the external garbage collector in this procedure
fi;
end );
##
InstallGlobalFunction( homalgCreateStringForExternalCASystem,
function( arg )
local nargs, L, l, stream, break_lists, assignments_pending, used_pointers,
void_matrices, s;
nargs := Length( arg );
## Do not waste time with syntax checks;
## this is not a procedure for end users.
#if nargs = 0 or not IsList( arg[1] ) then
# Error( "the first argument must be a list\n" );
#fi;
L := arg[1];
l := Length( L );
break_lists := false;
if nargs > 1 and IsRecord( arg[2] ) then
stream := arg[2];
if IsBound( stream.break_lists ) and stream.break_lists = true then
break_lists := true;
fi;
fi;
if nargs > 2 and arg[3] = "break_lists" then
break_lists := true;
fi;
assignments_pending := [ ];
used_pointers := [ ];
void_matrices := [ ];
s := List( [ 1 .. l ], function( a )
local o, CAS, stream, statistics_summary, counter, t, ext_obj;
o := L[a];
if IsStringRep( o ) then
return o;
else
if IsHomalgExternalMatrixRep( o ) then
if not ( HasIsVoidMatrix( o ) and IsVoidMatrix( o ) )
or HasEval( o ) then
t := homalgPointer( o ); ## now we enforce evaluation!!!
Add( used_pointers, t );
elif IsBound( o!.void_pointer ) then
t := o!.void_pointer;
Add( used_pointers, t );
else
CAS := homalgExternalCASystem( o );
stream := homalgStream( o );
statistics_summary := stream.StatisticsObject!.summary;
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalVariableCounter" );
## never interchange the previous line with the next one
counter := statistics_summary!.HomalgExternalVariableCounter;
t := Concatenation( stream.variable_name, String( counter ) );
MakeImmutable( t );
## now that we have just increased the variable counter and
## created the new variable we need to *immediately* create
## the enveloping external object and insert it in
## the weak pointer list using _SetElmWPObj_ForHomalg,
## before we start executing commands in the external CAS,
## that might cause an error; the weak pointer list
## which expects the l-th external object (i.e., the one
## with pointer = homalg_variable_l) at the l-th position
## would otherwise run out of sync)
ext_obj := homalgExternalObject( t, CAS, stream );
## the following line relies on the feature, that homalgExternalObjects
## are now assigned homalg_variables strictly sequentially!!!
_SetElmWPObj_ForHomalg( stream, ext_obj );
o!.void_pointer := t;
## do not Add counter directly to container!.assignments_pending
## as possibly remaining Eval's will invoke homalgSendBlocking
## which will move container!.assignments_pending to
## container!.assignments_failed; rather collect them in the variable
## assignments_pending and pass them back to homalgSendBlocking
Add( assignments_pending, counter );
Add( void_matrices, [ o, ext_obj ] );
fi;
elif IsHomalgExternalRingElementRep( o ) or
IsHomalgExternalRingRep( o ) or
IshomalgExternalObjectRep( o ) then
t := homalgPointer( o );
Add( used_pointers, t );
elif IsList( o ) and not IsStringRep( o ) then
if break_lists then
if ForAll( o, IsStringRep ) then
t := JoinStringsWithSeparator( o );
elif ForAll( o, e -> IsHomalgExternalMatrixRep( e ) or IsHomalgExternalRingElementRep( e ) ) then
t := JoinStringsWithSeparator( List( o, homalgPointer ) );
else
t := String( List( o, i -> i ) ); ## get rid of the range representation of lists
t := t{ [ 2 .. Length( t ) - 1 ] };
fi;
else
t := String( List( o, i -> i ) ); ## get rid of the range representation of lists
fi;
else
t := String( o );
fi;
if a < l and not IsStringRep( L[a+1] ) then
t := Concatenation( t, "," );
fi;
return t;
fi;
end );
return [ Flat( s ), assignments_pending, used_pointers, void_matrices ];
end );
##
InstallGlobalFunction( homalgSendBlocking,
function( arg )
local L, nargs, properties, need_command, need_display, need_output, ar,
pictogram, option, break_lists, R, ext_obj, stream, type, prefix,
suffix, e, RP, CAS, PID, container, counter, homalg_variable,
used_pointers, void_matrices, l, eoc, enter, statistics, statistics_summary,
fs, io_info_level, picto, void_matrix, o, max, display_color, esc;
if IsBound( HOMALG_IO.homalgSendBlockingInput ) then
Add( HOMALG_IO.homalgSendBlockingInput, arg );
fi;
Info( InfoHomalgToCAS, 10, "homalgSendBlocking <-- ", arg );
if not IsList( arg[1] ) then
Error( "the first argument must be a list\n" );
elif IsStringRep( arg[1] ) then
L := [ arg[1] ];
else
L := arg[1];
fi;
nargs := Length( arg );
properties := [ ];
need_command := false;
need_display := false;
need_output := false;
for ar in arg{[ 2 .. nargs ]} do ## the order of the following might be important for the performance!!!
if IsList( ar ) and ar <> [ ] and ForAll( ar, IsFilter ) then ## this must come before prefix and suffix
Append( properties, ar );
elif not IsBound( prefix ) and IsList( ar ) and not IsStringRep( ar ) then
prefix := ar;
elif not IsBound( suffix ) and IsList( ar ) and not IsStringRep( ar ) then
suffix := ar;
elif not IsBound( R ) and IsHomalgExternalRingRep( ar ) then
R := ar;
ext_obj := R;
stream := homalgStream( ext_obj );
elif not IsBound( ext_obj ) and IshomalgExternalObjectRep( ar ) then
ext_obj := ar;
stream := homalgStream( ext_obj );
elif not IsBound( R ) and IsHomalgExternalMatrixRep( ar ) then
R := HomalgRing( ar );
ext_obj := R;
stream := homalgStream( ext_obj );
elif not IsBound( ext_obj ) and IsHomalgExternalRingElementRep( ar ) then
R := HomalgRing( ar );
ext_obj := R;
stream := homalgStream( ext_obj );
elif IsRecord( ar ) and IsBound( ar.lines ) and IsBound( ar.pid ) then
if not IsBound( stream ) or not IsBound( ext_obj ) then
stream := ar;
if IsBound( stream.name ) then
ext_obj := homalgExternalObject( "", stream.name, stream );
fi;
fi;
elif not IsBound( pictogram ) and IsStringRep( ar ) and Length( ar ) <= 5 then
pictogram := ar;
elif not IsBound( option ) and IsStringRep( ar ) and Length( ar ) > 5 and ar <> "break_lists" then ## the first occurrence of an option decides
if PositionSublist( LowercaseString( ar ), "command" ) <> fail then
need_command := true;
elif PositionSublist( LowercaseString( ar ), "display" ) <> fail then
need_display := true;
elif PositionSublist( LowercaseString( ar ), "output" ) <> fail then
need_output := true;
else
Error( "option must be one of { \"need_command\", \"need_display\", \"need_output\" }, but received: ", ar, "\n" );
fi;
option := ar;
elif not IsBound( type ) and IsType( ar ) then
type := ar;
elif IsFilter( ar ) then
Add( properties, ar );
elif not IsBound( break_lists ) and ar = "break_lists" then
break_lists := ar;
else
Error( "this argument should be in { IsList, IsStringRep, IsFilter, IsRecord, IshomalgExternalObjectRep, IsHomalgExternalRingElementRep, IsHomalgExternalRingRep, IsHomalgExternalMatrixRep } but recieved: ", ar,"\n" );
fi;
od;
if not IsBound( ext_obj ) then ## R is also not yet defined
e := Filtered( L, a ->
IsHomalgExternalMatrixRep( a ) or
IsHomalgExternalRingElementRep( a ) or
IsHomalgExternalRingRep( a ) or
IshomalgExternalObjectRep( a )
);
if e <> [ ] then
ext_obj := e[1];
for ar in e do
if IsHomalgExternalMatrixRep( ar ) then
R := HomalgRing( ar );
break;
elif IsHomalgExternalRingRep( ar ) then
R := ar;
break;
elif IsHomalgExternalRingElementRep( ar ) then
R := HomalgRing( ar );
break;
fi;
od;
else
Error( "either the list provided by the first argument must contain at least one external matrix or an external ring or one of the remaining arguments must be an external ring or an external object\n" );
fi;
stream := homalgStream( ext_obj );
fi;
if IsBound( R ) then
if IsBound( stream.active_ring )
and not IsIdenticalObj( R, stream.active_ring )
and IsBound( stream.setring )
and IsFunction( stream.setring ) then
stream.setring( R );
if IsBound( stream.setinvol )
and IsFunction( stream.setinvol ) then
stream.setinvol( R );
fi;
fi;
RP := homalgTable( R );
if IsBound(RP!.homalgSendBlocking) then
return RP!.homalgSendBlocking( arg );
fi;
fi;
CAS := homalgExternalCASystem( ext_obj );
PID := homalgExternalCASystemPID( ext_obj );
if not IsBound( break_lists ) then
break_lists := "do_not_break_lists";
fi;
container := stream.homalgExternalObjectsPointingToVariables;
## if a homalgSendBlocking instance finds assignments still pending then
## for sure something went wrong with the previous homalgSendBlocking instance
if container!.assignments_pending <> [ ] then
## for some odd reason assigning to a variable, e.g.,
## assignments_pending := container!.assignments_pending
## and reassigning
## container!.assignments_pending := assignments_pending
## at the end does not work properly
Append( container!.deleted, container!.assignments_pending );
Append( container!.assignments_failed, container!.assignments_pending );
container!.assignments_pending := [ ];
fi;
if IsBound( prefix ) and prefix <> [ ] then
prefix := Concatenation( homalgCreateStringForExternalCASystem( prefix, stream, break_lists )[1], " " );
fi;
if IsBound( suffix ) then
suffix := homalgCreateStringForExternalCASystem( suffix, stream, break_lists )[1];
fi;
## this line may trigger an evaluation which will trigger homalgSendblocking again
L := homalgCreateStringForExternalCASystem( L, stream, break_lists );
## never separate the previous line from the following one!
Append( container!.assignments_pending, L[2] );
## for some odd reason assigning to a variable, e.g.,
## assignments_pending := container!.assignments_pending
## and reassigning
## container!.assignments_pending := assignments_pending
## at the end does not work properly
used_pointers := L[3];
void_matrices := L[4];
L := L[1];
l := Length( L );
if l > 0 and L{[l..l]} = "\n" then
enter := "";
eoc := "";
else
enter := "\n";
if l > 0 and
( ( Length( stream.eoc_verbose ) > 0
and l-Length( stream.eoc_verbose )+1 > 0
and L{[l-Length( stream.eoc_verbose )+1..l]} = stream.eoc_verbose )
or
( l-Length( stream.eoc_quiet )+1 > 0
and L{[l-Length( stream.eoc_quiet )+1..l]} = stream.eoc_quiet ) ) then
eoc := "";
elif not IsBound( option ) then
eoc := stream.eoc_quiet; ## as little back-traffic over the stream as possible
else
if need_command then
eoc := stream.eoc_quiet; ## as little back-traffic over the stream as possible
else
eoc := stream.eoc_verbose;
fi;
fi;
fi;
statistics := stream.StatisticsObject;
statistics_summary := statistics!.summary;
if not IsBound( option ) then
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalVariableCounter" );
## never interchange the previous line with the next one
counter := statistics_summary.HomalgExternalVariableCounter;
homalg_variable := Concatenation( stream.variable_name, String( counter ) );
MakeImmutable( homalg_variable );
## now that we have just increased the variable counter and
## created the new variable we need to *immediately* create
## the enveloping external object and insert it in
## the weak pointer list using _SetElmWPObj_ForHomalg,
## before we start executing commands in the external CAS,
## that might cause an error; the weak pointer list
## which expects the l-th external object (i.e., the one
## with pointer = homalg_variable_l) at the l-th position
## would otherwise run out of sync)
if not IsBound( type ) then
ext_obj := homalgExternalObject( homalg_variable, CAS, stream );
else
ext_obj := homalgExternalObject( homalg_variable, CAS, stream, type );
fi;
## the following line relies on the feature, that homalgExternalObjects
## are now assigned homalg_variables strictly sequentially!!!
_SetElmWPObj_ForHomalg( stream, ext_obj );
## never separate the previous line from the following one!
Add( container!.assignments_pending, counter );
if properties <> [ ] and IshomalgExternalObjectRep( ext_obj ) then
for ar in properties do
Setter( ar )( ext_obj, true );
od;
fi;
if IsBound( prefix ) then
if IsBound( suffix ) then
L := Concatenation( prefix, homalg_variable, suffix, " ", stream.define, " ", L, eoc, enter );
else
L := Concatenation( prefix, homalg_variable, " ", stream.define, " ", L, eoc, enter );
fi;
else
L := Concatenation( homalg_variable, " ", stream.define, " ", L, eoc, enter );
fi;
else
if IsBound( prefix ) then
L := Concatenation( prefix, " ", L, eoc, enter );
else
L := Concatenation( L, eoc, enter );
fi;
if need_command then
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalCommandCounter" );
else
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalOutputCounter" );
fi;
fi;
ConvertToStringRep( L );
if ( IsBound( HOMALG_IO.save_CAS_commands_to_file ) and HOMALG_IO.save_CAS_commands_to_file = true )
or IsBound( stream.CAS_commands_file ) then
if not IsBound( stream.CAS_commands_file ) then
stream.CAS_commands_file := Concatenation( "commands_file_of_", CAS, "_with_PID_", String( PID ) );
fs := IO_File( stream.CAS_commands_file, "w" );
if fs = fail then
Error( "unable to open the file ", stream.CAS_commands_file, " for writing\n" );
fi;
if IO_Close( fs ) = fail then
Error( "unable to close the file ", stream.CAS_commands_file, "\n" );
fi;
fi;
fs := IO_File( stream.CAS_commands_file, "a" );
if IO_WriteFlush( fs, L ) = fail then
Error( "unable to write in the file ", stream.CAS_commands_file, "\n" );
fi;
if IO_Close( fs ) = fail then
Error( "unable to close the file ", stream.CAS_commands_file, "\n" );
fi;
fi;
## <#GAPDoc Label="homalgSendBlocking:view_communication">
## <Description>
## This is the part of the global function <C>homalgSendBlocking</C>
## that controls the visibility of the communication.
## <Listing Type="Code"><![CDATA[
io_info_level := InfoLevel( InfoHomalgToCAS );
if not IsBound( pictogram ) then
pictogram := HOMALG_IO.Pictograms.unknown;
picto := pictogram;
elif io_info_level >= 3 then
picto := pictogram;
## add colors to the pictograms
if pictogram = HOMALG_IO.Pictograms.ReducedEchelonForm and
IsBound( HOMALG_MATRICES.color_BOE ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOE, pictogram, "\033[0m" );
elif pictogram = HOMALG_IO.Pictograms.BasisOfModule and
IsBound( HOMALG_MATRICES.color_BOB ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOB, pictogram, "\033[0m" );
elif pictogram = HOMALG_IO.Pictograms.DecideZero and
IsBound( HOMALG_MATRICES.color_BOD ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOD, pictogram, "\033[0m" );
elif pictogram = HOMALG_IO.Pictograms.SyzygiesGenerators and
IsBound( HOMALG_MATRICES.color_BOH ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOH, pictogram, "\033[0m" );
elif pictogram = HOMALG_IO.Pictograms.BasisCoeff and
IsBound( HOMALG_MATRICES.color_BOC ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOC, pictogram, "\033[0m" );
elif pictogram = HOMALG_IO.Pictograms.DecideZeroEffectively and
IsBound( HOMALG_MATRICES.color_BOP ) then
pictogram := Concatenation( HOMALG_MATRICES.color_BOP, pictogram, "\033[0m" );
elif need_output or need_display then
pictogram := Concatenation( HOMALG_IO.Pictograms.color_need_output,
pictogram, "\033[0m" );
else
pictogram := Concatenation( HOMALG_IO.Pictograms.color_need_command,
pictogram, "\033[0m" );
fi;
else
picto := pictogram;
fi;
if io_info_level >= 3 then
if ( io_info_level >= 7 and not need_display ) or io_info_level >= 8 then
## print the pictogram, the prompt of the external system,
## and the sent command
Info( InfoHomalgToCAS, 7, pictogram, " ", stream.prompt,
L{[ 1 .. Length( L ) - 1 ]} );
elif io_info_level >= 4 then
## print the pictogram and the prompt of the external system
Info( InfoHomalgToCAS, 4, pictogram, " ", stream.prompt, "..." );
else
## print the pictogram only
Info( InfoHomalgToCAS, 3, pictogram );
fi;
fi;
## ]]></Listing>
## </Description>
## <#/GAPDoc>
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalCallCounter" );
IncreaseCounterInObject( statistics, picto );
## always keep the above two lines together
if IsBound( stream!.log_processes ) and stream!.log_processes = true then
l := Length( stream.variable_name );
stream.description_of_last_process :=
[ container!.assignments_pending,
List( used_pointers, a -> Int( a{[ l + 1 .. Length( a ) ]} ) ),
need_output = false,
pictogram
];
fi;
stream.SendBlockingToCAS( stream, L );
if stream.errors <> "" then
if IsBound( stream.only_warning ) and PositionSublist( stream.errors, stream.only_warning ) <> fail then
stream.warnings := stream.errors;
IncreaseExistingCounterInObject( statistics_summary, "HomalgExternalWarningsCounter" );
else
Error( "the external CAS ", CAS, " (running with PID ", PID, ") returned the following error:\n", "\033[01m", stream.errors ,"\033[0m\n" );
fi;
elif IsBound( stream.error_stdout ) and PositionSublist( stream.lines, stream.error_stdout ) <> fail then
Error( "the external CAS ", CAS, " (running with PID ", PID, ") returned the following error:\n", "\033[01m", stream.lines ,"\033[0m\n" );
fi;
for void_matrix in void_matrices do
SetEval( void_matrix[1], void_matrix[2] );
ResetFilterObj( void_matrix[1], IsVoidMatrix );
Unbind( void_matrix[1]!.void_matrix );
od;
## we can now assume that every variable got assigned
container!.assignments_pending := [ ];
max := Maximum( statistics_summary.HomalgBackStreamMaximumLength, Length( stream.lines ) );
if max > statistics_summary.HomalgBackStreamMaximumLength then
statistics_summary.HomalgBackStreamMaximumLength := max;
if HOMALG_IO.SaveHomalgMaximumBackStream = true then
stream.HomalgMaximumBackStream := stream.lines;
fi;
fi;
if IsBound( HOMALG_IO.break_point ) and HOMALG_IO.break_point = statistics_summary.HomalgExternalVariableCounter
and not need_display then
Error( "break_pointing as required at HOMALG_IO.break_point = ", statistics_summary.HomalgExternalVariableCounter, "\n" );
fi;
if not IsBound( option ) then
return ext_obj;
elif need_display then
if IsBound( stream.color_display ) then
display_color := stream.color_display;
esc := "\033[0m";
else
display_color := "";
## esc must be empty, otherwise GAPDoc's TestManualExamples will complain
esc := "";
fi;
if IsBound( stream.trim_display ) and
IsFunction( stream.trim_display ) then
L := stream.trim_display( stream.lines );
else
L := stream.lines;
fi;
return Concatenation( display_color, L, esc, "\n" );
elif IsBound( stream.normalized_white_space ) and
IsFunction( stream.normalized_white_space ) then
## unless meant for display, normalize the white spaces caused by Maple
L := stream.normalized_white_space( stream.lines );
else
L := stream.lines;
fi;
if need_output then
if IsBound( stream.remove_enter ) and stream.remove_enter = true then
RemoveCharacters( L, "\n" );
fi;
RemoveCharacters( L, "\\ " );
Info( InfoHomalgToCAS, 5, "/------------------" );
Info( InfoHomalgToCAS, 5, stream.output_prompt, "\"", L, "\"" );
Info( InfoHomalgToCAS, 5, "\\==================" );
if IsBound( stream.check_output ) and stream.check_output = true
and '\n' in L and not ',' in L then
Error( "\033[01m", "the output received from the external CAS ", CAS, " (running with PID ", PID, ") contains an ENTER = '\\n' but no COMMA = ',' ... this is most probably a mistake!!!", "\033[0m\n" );
fi;
fi;
if not need_command then
return L;
fi;
end );
##
InstallGlobalFunction( homalgDisplay,
function( arg )
local L, ar;
if IsList( arg[1] ) then
L := arg[1];
else
L := [ arg[1] ];
fi;
ar := Concatenation( [ L ], arg{[ 2 .. Length( arg ) ]}, [ "need_display", HOMALG_IO.Pictograms.Display ] );
Print( CallFuncList( homalgSendBlocking, ar ) );
end );
##
InstallGlobalFunction( StringToInt,
function( s )
if s = "" then
Error( "received an empty string while expecting a string containing an integer\n" );
else
return Int( s );
fi;
end );
##
InstallGlobalFunction( StringToIntList,
function( arg )
local l, lint;
if arg[1] = "[]" then
return [ ];
fi;
l := SplitString( arg[1], ",", "[ ]\n" );
lint := List( l, Int );
if fail in lint then
Error( "the first argument is not a string containg a list of integers: ", arg[1], "\n");
fi;
return lint;
end );
##
InstallGlobalFunction( StringToDoubleIntList,
function( s )
local l, lint;
if s = "[]" then
return [ ];
fi;
l := SplitString( s, "", ",[ ]\n" );
lint := List( l, Int );
if fail in lint then
Error( "the first argument is not a string containg a list of list of two integers: ", s, "\n");
fi;
l := Length( lint );
if IsOddInt( l ) then
Error( "expected an even number of integers: ", s, "\n");
fi;
return List( [ 1 .. l/2 ], a -> [ lint[2*a-1], lint[2*a] ] ) ;
end );
####################################
#
# View, Print, and Display methods:
#
####################################
InstallMethod( ViewObj,
"for homalg external objects with an IO stream",
[ IshomalgExternalObjectRep ],
function( o )
Print( "<A homalg external object residing in the CAS " );
if IsBound( homalgStream( o ).color_display ) then
Print( "\033[1m" );
fi;
Print( homalgExternalCASystem( o ), "\033[0m running with pid ", homalgExternalCASystemPID( o ), ">" );
end );
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...