Sending and getting requests to the SCSCP server(s), the client operates with processes. Process is an abstraction which in other words may be also called a remote task. It encapsulates an input/output TCP stream (see IsInputOutputTCPStream
(3.1-1)) from the client to the server and the process ID of the CAS running as a server (deduced from the connection initiation message; may be unassigned, if the server CAS did not communicate it).
There are two ways to create processes. One of them is to specify the hostname and port where the SCSCP server is running; in this case a new input/output TCP stream will be created. Another way is first to establish the connection with the SCSCP server using NewSCSCPconnection
(6.1-2) and then keep it alive across multiple remote procedure calls, thus saving time on the DNS lookup and connection initiation. This may give a good speedup in computations with an intensive message exchange. Note that as long as such connection is open, other SCSCP clients will not be able to get through, so if several clients are interchanging with the SCSCP server at the same time, they should not block each other with long-lasting connections.
‣ IsSCSCPconnection | ( filter ) |
This is the category of SCSCP connections. Objects in this category are created using the function NewSCSCPconnection
(6.1-2).
‣ NewSCSCPconnection ( hostname, port ) | ( function ) |
For a string hostname and an integer port, creates an object in the category IsSCSCPconnection
(6.1-1). This object will encapsulate two objects: tcpstream
, which is the input/output TCP stream to hostname:port
, and session_id
, which is the result of calling StartSCSCPsession
(4.1-1) on tcpstream
. The connection will be kept alive across multiple remote procedure calls until it will be closed with CloseSCSCPconnection
(6.1-3).
gap> SetInfoLevel( InfoSCSCP, 2 ); gap> s:=NewSCSCPconnection("localhost",26133); #I Creating a socket ... #I Connecting to a remote socket via TCP/IP ... #I Got connection initiation message #I <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\ 6133:52918" scscp_versions="1.0 1.1 1.2 1.3" ?> #I Requesting version 1.3 from the server ... #I Server confirmed version 1.3 to the client ... < connection to localhost:26133 session_id=localhost:26133:52918 > gap> CloseSCSCPconnection(s);
‣ CloseSCSCPconnection ( s ) | ( function ) |
Returns: nothing
Closes SCSCP connection s, which must be an object in the category IsSCSCPconnection
(6.1-1). Internally, it just calls CloseStream
(Reference: CloseStream) on the underlying input/output TCP stream of s.
gap> SetInfoLevel( InfoSCSCP, 0 ); gap> s:=NewSCSCPconnection("localhost",26133); < connection to localhost:26133 session_id=localhost:26133:52918 > gap> CloseSCSCPconnection(s);
‣ IsProcess | ( filter ) |
This is the category of processes. Processes in this category are created using the function NewProcess
(6.2-2).
‣ NewProcess ( command, listargs, server, port ) | ( function ) |
‣ NewProcess ( command, listargs, connection ) | ( function ) |
Returns: object in the category IsProcess
In the first form, command and server
are strings, listargs is a list of GAP objects and port
is an integer.
In the second form, an SCSCP connection in the category NewSCSCPconnection
(6.1-2) is used instead of server
and port
.
Calls the SCSCP procedure with the name command and the list of arguments listargs at the server and port given by server and port or encapsulated in the connection. Returns an object in the category IsProcess
for the subsequent waiting the result from its underlying stream.
It accepts the following options:
output:="object"
is used to specify that the server must return the actual object evaluated as a result of the procedure call. This is the default action requested by the client if the output
option is omitted.
output:="cookie"
is used to specify that the result of the procedure call should be stored on the server, and the server should return a remote object (see 6.5 ) pointing to that result (that is, a cookie);
output:="nothing"
is used to specify that the server is supposed to reply with a procedure_completed
message carrying no object just to signal that the call was completed successfully (for the compatibility, this will be evaluated to a "procedure completed"
string on the client's side);
cd:="cdname"
is used to specify that the OpenMath symbol corresponding to the first argument command should be looked up in the particular content dictionary cdname
. Otherwise, it will be looked for in the default content dictionary (scscp_transient_1
for the GAP SCSCP server);
debuglevel:=N
is used to obtain additional information attributes together with the result. The GAP SCSCP server does the following: if N=1
, it will report about the CPU time in milliseconds required to compute the result; if N=2
it will additionally report about the amount of memory used by GAP in bytes will be returned (using the output of MemoryUsageByGAPinKbytes
(9.3-4) converted to bytes); if N=3
it will additionally report the amount of memory in bytes used by the resulting object and its subobjects (using the output of MemoryUsage
(Reference: MemoryUsage)).
See CompleteProcess
(6.2-3) and EvaluateBySCSCP
(6.3-1) for examples.
‣ CompleteProcess ( process ) | ( function ) |
Returns: record with components object
and attributes
The function waits, if necessary, until the underlying stream of the process will contain some data, then reads the appropriate OpenMath object from this stream and closes it.
It has the option output
which may have two values:
output:="cookie"
has the same meaning as for the NewProcess
(6.2-2)
output:="tree"
is used to specify that the result obtained from the server should be returned as an XML parsed tree without its evaluation.
In the following example we demonstrate combination of the two previous functions to send request and get result, calling the procedure WS_Factorial
, installed in the previous chapter:
gap> s := NewProcess( "WS_Factorial", [10], "localhost", 26133 ); < process at localhost:26133 pid=52918 > gap> x := CompleteProcess(s); rec( attributes := [ [ "call_id", "localhost:26133:52918:TPNiMjCT" ] ], object := 3628800 )
See more examples in the description of the function EvaluateBySCSCP
(6.3-1), which combines the two previous functions by sending request and getting result in one call.
‣ TerminateProcess ( process ) | ( function ) |
The function is supposed to send an out-of-band
interrupt signal to the server. Current implementation works only when the server is running as localhost
by sending a SIGINT
to the server using its PID contained in the process. It will do nothing if the server is running remotely, as the SCSCP specification allows the server to ignore interrupt messages. Remote interrupts will be introduced in one of the next versions of the package.
‣ EvaluateBySCSCP ( command, listargs, server, port ) | ( function ) |
‣ EvaluateBySCSCP ( command, listargs, connection ) | ( function ) |
Returns: record with components object
and attributes
In the first form, command and server
are strings, listargs is a list of GAP objects and port
is an integer.
In the second form, an SCSCP connection in the category NewSCSCPconnection
(6.1-2) is used instead of server
and port
.
Calls the SCSCP procedure with the name command and the list of arguments listargs at the server and port given by server
and port
or encapsulated in the connection.
Since EvaluateBySCSCP
combines NewProcess
(6.2-2) and CompleteProcess
(6.2-3), it accepts all options which may be used by that functions ( output
, cd
and debuglevel
) with the same meanings.
gap> EvaluateBySCSCP( "WS_Factorial",[10],"localhost",26133); rec( attributes := [ [ "call_id", "localhost:26133:2442:6hMEN40d" ] ], object := 3628800 ) gap> SetInfoLevel(InfoSCSCP,0); gap> EvaluateBySCSCP( "WS_Factorial",[10],"localhost",26133 : output:="cookie" ); rec( attributes := [ [ "call_id", "localhost:26133:2442:jNQG6rml" ] ], object := < remote object scscp://localhost:26133/TEMPVarSCSCP5KZIeiKD > ) gap> EvaluateBySCSCP( "WS_Factorial",[10],"localhost",26133 : output:="nothing" ); rec( attributes := [ [ "call_id", "localhost:26133:2442:9QHQrCjv" ] ], object := "procedure completed" )
Now we demonstrate the procedure GroupIdentificationService
, also given in the previous chapter:
gap> G:=SymmetricGroup(4); Sym( [ 1 .. 4 ] ) gap> gens:=GeneratorsOfGroup(G); [ (1,2,3,4), (1,2) ] gap> EvaluateBySCSCP( "GroupIdentificationService", [ gens ], > "localhost", 26133 : debuglevel:=3 ); rec( attributes := [ [ "call_id", "localhost:26133:2442:xOilXtnw" ], [ "info_runtime", 4 ], [ "info_memory", 2596114432 ], [ "info_message", "Memory usage for the result is 48 bytes" ] ], object := [ 24, 12 ] )
Service provider may suggest to the client to use a counterpart function
gap> IdGroupWS := function( G ) > local H, result; > if not IsPermGroup(G) then > H:= Image( IsomorphismPermGroup( G ) ); > else > H := G; > fi; > result := EvaluateBySCSCP ( "GroupIdentificationService", > [ GeneratorsOfGroup(H) ], "localhost", 26133 ); > return result.object; > end;;
which works exactly like IdGroup
(smallgrp: IdGroup):
gap> G:=DihedralGroup(64); <pc group of size 64 with 6 generators> gap> IdGroupWS(G); [ 64, 52 ]
‣ SwitchSCSCPmodeToBinary ( ) | ( function ) |
‣ SwitchSCSCPmodeToXML ( ) | ( function ) |
Returns: nothing
The OpenMath package supports both binary and XML encodings for OpenMath. To switch between them, use SwitchSCSCPmodeToBinary
and SwitchSCSCPmodeToXML
. When the package is loaded, the mode is initially set to XML. On the clients's side, you can change the mode back and forth as many times as you wish during the same SCSCP session. The server will autodetect the mode and will response in the same format, so one does not need to set the mode on the server's side.
For example, let us create a vector over \(GF(3)\):
gap> x := [ Z(3)^0, Z(3), 0*Z(3) ]; [ Z(3)^0, Z(3), 0*Z(3) ]
The XML OpenMath encoding of such objects is quite bulky:
gap> OMPrint( x ); <OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0"> <OMA> <OMS cd="list1" name="list"/> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>1</OMI> </OMA> <OMA> <OMS cd="arith1" name="times"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> </OMA> </OMOBJ> gap> Length( OMString(x) ); 507
We call the SCSCP procedure Identity
just to test how this object may be sent back and forth. The total length of the procedure call message is 969 symbols:
gap> SetInfoLevel(InfoSCSCP,3); gap> EvaluateBySCSCP("Identity",[x],"localhost",26133); #I Creating a socket ... #I Connecting to a remote socket via TCP/IP ... #I Got connection initiation message #I <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\ 6133:42448" scscp_versions="1.0 1.1 1.2 1.3" ?> #I Requesting version 1.3 from the server ... #I Server confirmed version 1.3 to the client ... #I Composing procedure_call message: <?scscp start ?> <OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0"> <OMATTR> <OMATP> <OMS cd="scscp1" name="call_id"/> <OMSTR>localhost:26133:42448:IOs9ZkBU</OMSTR> <OMS cd="scscp1" name="option_return_object"/> <OMSTR></OMSTR> </OMATP> <OMA> <OMS cd="scscp1" name="procedure_call"/> <OMA> <OMS cd="scscp_transient_1" name="Identity"/> <OMA> <OMS cd="list1" name="list"/> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>1</OMI> </OMA> <OMA> <OMS cd="arith1" name="times"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> </OMA> </OMA> </OMA> </OMATTR> </OMOBJ> <?scscp end ?> #I Total length 969 characters ... rec( attributes := [ [ "call_id", "localhost:26133:42448:IOs9ZkBU" ] ], object := [ Z(3)^0, Z(3), 0*Z(3) ] )
Now we switch to binary mode:
gap> SwitchSCSCPmodeToBinary(); gap> EvaluateBySCSCP("Identity",[x],"localhost",26133); #I Creating a socket ... #I Connecting to a remote socket via TCP/IP ... #I Got connection initiation message #I <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\ 6133:42448" scscp_versions="1.0 1.1 1.2 1.3" ?> #I Requesting version 1.3 from the server ... #I Server confirmed version 1.3 to the client ... #I Composing procedure_call message: 3C3F7363736370207374617274203F3E0A18121408060773637363703163616C6C5F6964061E6C\ 6F63616C686F73743A32363133333A34323434383A3256675A5562755A0806147363736370316F\ 7074696F6E5F72657475726E5F6F626A6563740600151008060E73637363703170726F63656475\ 72655F63616C6C1008110873637363705F7472616E7369656E745F314964656E74697479100805\ 046C697374316C69737410080605617269746831706F7765721008091166696E6669656C643170\ 72696D69746976655F656C656D656E7401031101001110080605617269746831706F7765721008\ 091166696E6669656C64317072696D69746976655F656C656D656E740103110101111008060561\ 726974683174696D65731008091166696E6669656C64317072696D69746976655F656C656D656E\ 7401031101001111111113193C3F736373637020656E64203F3E0A #I Total length 339 bytes #I Request sent ... #I Waiting for reply ... #I <?scscp start ?> #I Got back: object [ Z(3)^0, Z(3), 0*Z(3) ] with attributes [ [ "call_id", "localhost:26133:42448:2VgZUbuZ" ] ] rec( attributes := [ [ "call_id", "localhost:26133:42448:2VgZUbuZ" ] ], object := [ Z(3)^0, Z(3), 0*Z(3) ] ) gap> SetInfoLevel(InfoSCSCP,3);
As we can see, the size of the message is almost three times shorter, and this is not the limit. Switching to binary OpenMath encoding in combination with pickling and unpickling from IO package (see in the last Chapter) and special methods for pickling compressed vectors implemented in the Cvec available in GAP 4.5 allow to dramatically reduce the overhead for vectors and matrices over finite fields, making a roundtrip up to a thousand times faster.
The SCSCP package introduces new kind of objects - remote objects. They provide an opportunity to manipulate with objects on remote services without their actual transmitting over the network. Remote objects store the information that allows to access the original object: the server name and the port number through which the object can be accessed, and the variable name under which it is stored in the remote system. Two remote objects are equal if and only if all these three parameters coincide.
There are two types of remote object which differ by their lifetime:
temporary remote objects which exist only within a single session;
persistent remote objects which stay alive across multiple sessions.
First we show the example of the temporary remote object in a session. The procedure PointImages
returns the set of images of a point \(i\) under the generators of the group \(G\). First we create the symmetric group \(S_3\) on the client and store it remotely on the server (call 1), then we compute set of images for \(i=1,2\) (calls 2,3) and finally demonstrate that we may retrieve the group from the server (call 4):
gap> stream:=InputOutputTCPStream( "localhost", 26133 ); < input/output TCP stream to localhost:26133 > gap> StartSCSCPsession(stream); "localhost:26133:6184" gap> OMPutProcedureCall( stream, "store_session", > rec( object := [ SymmetricGroup(3) ], > attributes := [ [ "call_id", "1" ], > ["option_return_cookie"] ] ) ); true gap> SCSCPwait( stream ); gap> G:=OMGetObjectWithAttributes( stream ).object; < remote object scscp://localhost:26133/TEMPVarSCSCPo3Bc8J75 > gap> OMPutProcedureCall( stream, "PointImages", > rec( object := [ G, 1 ], > attributes := [ [ "call_id", "2" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "2" ] ], object := [ 2 ] ) gap> OMPutProcedureCall( stream, "PointImages", > rec( object := [ G, 2 ], > attributes := [ [ "call_id", "3" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "3" ] ], object := [ 1, 3 ] ) gap> OMPutProcedureCall( stream, "retrieve", > rec( object := [ G ], > attributes := [ [ "call_id", "4" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "4" ] ], object := Group([ (1,2,3), (1,2) ]) ) gap> CloseStream(stream);
After the stream is closed, it is no longer possible to retrieve the group \(G\) again or use it as an argument.
Thus, the usage of remote objects existing during a session reduces the network traffic, since we pass only references instead of actual OpenMath representation of an object. Also, the remote object on the server may accumulate certain information in its properties and attributes, which may not be included in it default OpenMath representation.
Now we show remote objects which remain alive after the session is closed. Such remote objects may be accessed later, for example, by:
subsequent procedure calls from the same instance of GAP or another system;
other instances of GAP or another systems (if the identifier of an object is known)
another SCSCP servers which obtained a reference to such object as an argument of a procedure call.
‣ StoreAsRemoteObjectPersistently ( obj, server, port ) | ( function ) |
‣ StoreAsRemoteObject ( obj, server, port ) | ( function ) |
Returns: remote object
Returns the remote object corresponding to the object created at server:
port from the OpenMath representation of the first argument obj. The second form is just a synonym.
gap> s:=StoreAsRemoteObject( SymmetricGroup(3), "localhost", 26133 ); < remote object scscp://localhost:26133/TEMPVarSCSCPLvIUUtL3 >
Internally, the remote object carries all the information which is required to get access to the original object: its identifier, server and port:
gap> s![1]; "TEMPVarSCSCPLvIUUtL3" gap> s![2]; "localhost" gap> s![3]; 26133
When the remote object is printed in the OpenMath format, we use symbols @
and :
to combine these parameters in the OpenMath reference:
gap> OMPrint(s); <OMOBJ> <OMR href="scscp://localhost:26133/TEMPVarSCSCPLvIUUtL3" /> </OMOBJ>
This allows substitution of remote object as arguments into procedure calls in the same manner like we do this with usual objects:
gap> EvaluateBySCSCP("WS_IdGroup",[s],"localhost",26133); rec( attributes := [ [ "call_id", "localhost:26133:52918:Viq6EWBP" ] ], object := [ 6, 1 ] )
‣ IsRemoteObject | ( filter ) |
This is the category of remote objects.
‣ RemoteObjectsFamily | ( family ) |
This is the family of remote objects.
‣ RetrieveRemoteObject ( remoteobject ) | ( function ) |
Returns: object
This function retrieves the remote object from the remote service in the OpenMath format and constructs it locally. Note, however, that for a complex mathematical object its default OpenMath representation may not contain all information about it which was accumulated during its lifetime on the SCSCP server.
gap> RetrieveRemoteObject(s); Group([ (1,2,3), (1,2) ])
‣ UnbindRemoteObject ( remoteobject ) | ( function ) |
Returns: true
or false
Removes any value currently bound to the global variable determined by remoteobject at the SCSCP server, and returns true
or false
dependently on whether this action was successful or not.
gap> UnbindRemoteObject(s); true
Finally, we show an example when first we create a group on the service running on port 26133, and then identify it on the service running on port 26134:
gap> s:=StoreAsRemoteObject( SymmetricGroup(3), "localhost", 26133 ); < remote object scscp://localhost:26133/TEMPVarSCSCPNqc8Bkan > gap> EvaluateBySCSCP( "WS_IdGroup", [ s ], "localhost", 26134 ); rec( object := [ 6, 1 ], attributes := [ [ "call_id", "localhost:26134:7414" ] ] )
Instead of transmitting the group to the client and then sending it as an argument to the second service, the latter service directly retrieves the group from the first service:
gap> EvaluateBySCSCP("WS_IdGroup",[s],"localhost",26133 : output:="cookie" ); rec( attributes := [ [ "call_id", "localhost:26133:52918:mRU6w471" ] ], object := < remote object scscp://localhost:26133/TEMPVarSCSCPS9SVe9PZ > )
generated by GAPDoc2HTML