The MapleNet Compute Engine Application
Programming Interface
Copyright ©Maplesoft, a division of Waterloo Maple Inc. 2019

The MapleNet Compute Engine Application
Programming Interface
Copyright
Maplesoft, MapleNet, and Maple are all trademarks of Waterloo Maple Inc.
©Maplesoft, a division of Waterloo Maple Inc. 2019. All rights reserved.
No part of this book may be reproduced, stored in a retrieval system, ortranscribed, in any form or by any means – electronic, mechanical, photocopying, recording, or otherwise. Information in this document is subject tochange without notice and does not represent a commitment on the part ofthe vendor. The software described in this document is furnished under alicense agreement and may be used or copied only in accordance with theagreement. It is against the law to copy the software on any medium except
as specifically allowed in the agreement.

1

MapleNet Compute Engine Application
Programming Interface

MapleNet can be used to harness the mathematical expertise and computational power of the Maple engine to build a range of services that can runon anything from a mobile device to the cloud. This document contains thefollowing:• A detailed description of the MapleNet compute engine API• An example communicating with MapleNet from Python

1.1

Communicating with MapleNet

MapleNet uses Google’s Protocol Buffers[1] as the interchange format of messages between itself and clients. Protocol buffer enables MapleNet to communicate with clients written in a variety of languages via an independent
manner that is simple and efficient in terms of both size and time. Given theprotocol buffer definition file listed in Appendix 1.2 a user could compile it togenerate accessors in C++, Python, JavaScript and many other programming
languages. A detailed description of compiling a protocol buffer definition isalso included in the Appendix.
Communication with MapleNet is achieved through the Request andReply protocol buffer message types as defined in Listings 1 and 2 respectively.
Listing 1: Protocol buffer definition of a MapleNet Request message.
message OutputOptions {enum Type {TEXT = 0 ;MATHML = 1 ;}optional Type type = 1}

[ default = TEXT ];message Command {oneof command{string maple = 1 ;}}1message PlotOptions {enum Type {IMAGE = 0 ;PROTOBUFFER = 1 ;}optional Type type = 1
optional uint32 pixel_width = 2
optional uint32 pixel_height = 3}

[ default = IMAGE ];[ default = 4 0 0 ];[ default = 4 0 0 ];message Session {optional string id = 1 ;optional uint32 timeout = 2 ;}message Request {repeated Command commands = 1 ;optional Session session = 2 ;optional PlotOptions plot_options = 3 ;optional OutputOptions output_options = 4 ;}The commands field of the Request message conveys the Maple statements
to be evaluated. Multiple statements can be embedded in a single string or
as individual strings in the protocol buffers list structure. For example, allthree of the following lists of commands will return the same results:• ["a:=bˆ2; b:=4; a;"]• ["a:=bˆ2; b:=4;", "a;"]• ["a:=bˆ2;", "b:=4;", "a;"]MapleNet will parse the commands list into individual Maple statements
to be evaluated. The outputs generated by each input statement are returnedin a manner that is easy to associate.
Request messages contain options that specify the format of the output
generated by MapleNet. The OutputOptions message defines an enumeration, Type, that dictates if simple text (TEXT) or MathML (MATHML) output
should be returned. Furthermore, the PlotOptions message dictates if aGIF image (IMAGE) should be returned for plots generated by Maple or ifa protocol buffer encoded plot structure (PROTOBUFFER). PlotOptions also
allow the user to specify the size of the plot by the width and height fields.
2

Listing 2: Protobuffer definition of a compute service Reply message.
message Result
oneof Typestringstring}}{{text = 1 ;mathml = 2 ;message MCSEvent {oneof event {Command command = 1 ;string input = 2 ;Result result = 3 ;string printf = 4 ;string pretty_print = 5 ;string lprint = 6 ;string error = 7 ;string warning = 8 ;string server_error = 9 ;bytes image_plot = 1 0 ;MapleCloud . Plot plot = 1 1 ;}}message Reply {optional Request request = 1 ;repeated MCSEvent event_stream = 2 ;}The MCSEvent message type is the central element of a Reply message.
It is modeled as an event stream where each MCSEvent.command is parsed bythe Maple engine into individual statements and reported as MCSEvent.input
events. Each MCSEvent.input event when evaluated can generate multiple
output events that are encapsulated as one of the following event types:
result [Result] The result returned by the Maple engine in either text ormathml depending which is selected by setting the value of the typefield in the Request message.
printf [string] Output from a call to printf().
pretty_print [string] Output from a call to print().
3lprint [string] Output from a call to lprint().
error [string] Evaluation of the input statement caused the Maple engine
to return an error. Refer to the Maple help system to diagnose thespecific error (https://www.maplesoft.com/support/help/).
warning [string] As above, but a warning.
server_error [string] An error generated by MapleNet and not the Maple
engine. This is typically due to a malformed Request message or aninternal server error.
image_plot [bytes] A GIF image is generated for each Maple plot() call.
plot [MapleCloud.Plot] A protocol buffer encoded Maple plot data structure. Currently, this is for for internal use only.
For example, the sequence of Maple code,
pow := proc( b, n ) prod := b^n; return prod; end proc; pow(2,4);
would cause the following Request message to be generated (as reported fromC++ with a call to DebugString()):
commands {maple: "pow := proc( b, n ) prod := b^n; return prod; end proc;
pow(2,4);"}
plot_options {type: IMAGE}
output_options {type: TEXT}
MapleNet will parse the string in the commands.maple field into two individual Maple statements; the definition of the procedure pow and the call toit, pow(2,4). MapleNet will then schedule evaluation of the statements on
an idle engine from a pool of available Maple compute engines. The Reply
message that MapleNet would respond with is the following1
In the following examples long commands are broken across multiple lines. The \character is used to indicate the continuation of the command on the next line. This is supported in many terminals so copying and pasting the entire command should work. If that
does not work, duplicating the command as a single line by omitting these characters andjoining the argument should also work.
14

request{
commands {maple: "pow := proc( b, n ) prod := b^n; return prod; end proc; \pow(2,4);"}
plot_options {type: IMAGE}
output_options {type: TEXT}}
event_stream {command {maple: "pow := proc( b, n ) prod := b^n; return prod; end proc; \pow(2,4);"}}
event_stream {input: "pow := proc( b, n ) prod := b^n; return prod; end proc;"}
event_stream {warning: "‘prod‘ is implicitly declared local to procedure ‘pow‘"}
event_stream {result {text: "pow := proc (b, n) local prod; prod := b^n; \return prod end proc"}}
event_stream {input: "pow(2,4);"}
event_stream {result {text: "16"}}5

To eliminate ambiguity each Reply message contains a copy of the original
Request message that MapleNet received.
The principle element of the Reply message is the event_stream list.
This records the temporal series of typed events that were generated by
the Maple engine while evaluating the commands submitted in the Request
message. For example, upon commencing evaluation of the previous Request
message the command string is the initial event injected into the stream. After which the first parsed statement to be evaluated from the command stringis injected as an event_stream.input event (the procedure definition). Following each input event a series of output events resulting from the evaluationof the input statement are reported 2 . Two events are generated by the procedure definition. First, a warning is reported by the Maple engine that thevariable prod is not defined and will be interpreted as being locally defined inpow (the declaration was purposely omitted to illustrate that a single input
statement can generate multiple output events). The second output event
reported in the event_stream is the result of instantiating the procedurepow. Aside from multithreaded examples all output events from an input
statement are reported after the given event_stream.input and before thenext input statement is listed in the event stream. Accordingly, the second
input statement parsed from the command string is now reported in the event
stream, the call to pow(2,4). Finally, the result of “16” which is the result
from of evaluating the procedure pow with arguments (2,4) is evident in thestream.

1.2

Python Interaction

This section presents a simple Python client script that receives some Maple
code as user input, sends a Request message to MapleNet for it to evaluate,
waits for the Reply message and then reports the results. The complete
source for the example can be found in<MapleNetInstallDir>/examples/pythonMNSEx.py. For convenience, thenecessary code generated by the protocol buffer compiler is also included in
the examples directory.
Note that the output generated by statements terminated with “:” are omitted as
defined by the Maple programming language
2

6

Listing 3: A python example that communicates with MapleNet via theRequest and Reply messages to evaluate Maple code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
495051# !/ usr / bin / python
import argparse
import httplib
import urlparse# Import the protobuffer definitions of the Reply and Request messages .
import M a p l e C o m p u t e S e r v i c e _ p b 2 as MCS
class ComputeEngine :# Create a connection to MapleNet at serverURL ( http :// host : port )def __init__ ( self , serverURL ) :urldata = urlparse . urlsplit ( serverURL )self . connection = httplib . HTTP Connecti on ( urldata . hostname , urldata .
port )# Create a M a p l e C o m p u t e S e r v i c e . Request protobuffer message that can# be sent to MapleNet for evaluation .
def f o r m a t M C S M e s s a g e ( self , commands ) :mcsMsg = MCS . Request ()mcsMsg . plot_options . type = MCS . PlotOptions . IMAGE
mcsMsg . output_o ptions . type = MCS . OutputOptions . TEXT
mapleCommand = mcsMsg . commands . add ()mapleCommand . maple = commands
msgStr = mcsMsg . S e r i a l i z e T o S t r i n g ()return msgStr# Retrieve the M a p l e C o m p u t e S e r v i c e . Reply message returned from MapleNet .
def getMCSReply ( self ) :response = self . connection . getresponse () . read ()mcsMsg = MCS . Reply ()mcsMsg . P ar se Fr o mS tr in g ( response )return mcsMsg# Request that MapleNet evaluate the passed in commands .
def mcsEval ( self , commands ) :msg = self . f o r m a t M C S M e s s a g e ( commands )self . connection . request ( " POST " , " / maplenet / mnserver / mcs / " , msg )return self . getMCSReply ()# Fetch the passed in URL where MapleNet is running .
parser = argparse . A rgumentP arser ( prog = " pythonMNSEx " , description = ’A python
example interacting with MapleNet . ’ )parser . add_argument ( ’ -- mns ’ , default = " http :// localhost :8080 " )args = parser . parse_args ( )# Establish a connection to MapleNet .
compute = ComputeEngine ( args . mns )while True :commands = raw_input ( " \ n \ nEnter Maple statements ( press Enter toevaluate , ^ c to quit ) : " )# Request that MapleNet evaluate the commands entered .

7

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

reply = compute . mcsEval ( commands )# Print the reply from MapleNet .
for e in reply . event_stream :if e . HasField ( " input " ) :print ( " > {0: s } " . format ( e . input ) )elif e . HasField ( " result " ) :if e . result . HasField ( " text " ) :print ( " \ t \ t \ t {0: s } " . format ( e . result . text ) )elif e . result . HasField ( " mathml " ) :print ( " \ t \ t \ t {0: s } " . format ( e . result . mathml ) )elif e . HasField ( " debug " ) :print ( " DGB > {0: s } " . format ( e . debug ) )elif e . HasField ( " printf " ) :print ( " {0: s } " . format ( e . printf ) )elif e . HasField ( " pretty_print " ) :print ( " \ t \ t \ t {0: s } " . format ( e . pretty_print ) )elif e . HasField ( " lprint " ) :print ( " {0: s } " . format ( e . lprint ) )elif e . HasField ( " error " ) :print ( " {0: s } " . format ( e . error ) )elif e . HasField ( " warning " ) :print ( " {0: s } " . format ( e . warning ) )elif e . HasField ( " server_error " ) :print ( " {0: s } " . format ( e . server_error ) )The functions of interest in the example are formatMCSMessage(),getMCSReply(), and mcsEval(). The function formatMCSMessage() onlines 16-25 illustrates the creation of a Request message to be sent to MapleNet.
On line 19 a new Request message is allocated followed by initialization of
the output option fields. The Maple code to evaluate is then added to thecommands.maple field and finally the message is serialized in preparation fortransmission to MapleNet.
Sending the Request message to an instance of MapleNet (running on
port 8080 of the localhost) is accomplished in the function mcsEval. To
connect to a server running on a different host the –mns option can be passed
to the script. First a Request message is created and then on line 37 it isposted to the endpoint /maplenet/mnserver/mcs. Finally, it waits for a
Reply message to be return from MapleNet.
Another sequence of code to take of note of is lines 55 to 76. Here we see anexample of indexing into the event_stream inside of a Reply message. This
follows the idiom of checking for the existence of a field via the HasField()
method prior to attempting to access the date field.

8References[1] Google.
Protocol Buffers Version 2 Language Specification.
https://developers.google.com/protocol-buffers/docs/
reference/proto2-sp%ec/.

Appendix
MapleNet Protocol Buffer Definition
This section provides the full protocol buffer definition of theMapleComputeService.Request and MapleComputeService.Reply message
types as well as instructions on how to compile and incorporate them into
an application.
The first step in using the message types is to download and install
Google’s protocol buffer that is available athttps://developers.google.com/protocol-buffers/. After doing so, youwill be able to use the protocol buffer compiler, protoc, to compile the definition files located in <MapleNetInstallDir>/include/. For example, thefollowing command can be used to compile all of the files in the include directory and place the output in the user created directories cppBuildDir andpythonBuildDir.
sh-4.1$ mkdir cppBuildDir pythonBuildDir
sh-4.1$ protoc --proto_path=<MapleNetInstallDir>/include/ \--cpp_out=cppBuildDir \--python_out=pythonBuildDir \<MapleNetInstallDir>/include/*.proto
This will generate both C++ and Python source files that can be incorporated into user applications that interact with MapleNet. Note thatyou will need to add the generated source located in cppBuildDir andpythonBuildDir to your build infrastructure.
Referring to the Python example previously discussed in Listing 3, online 7 the message types defined in the generated source file
MapleComputeService_pb2.py are imported for use within the client.
9Complete definition of the protocol buffer Request and Reply messages.
syntax = " proto 2 " ;package M ap l e Co m p ut e S e rv i c e . Compute ;option go_package = " maplenetserver / m a pl e c om p u te s e rv i c e " ;import " Plot . proto " ;message OutputOptions {enum Type {TEXT = 0 ;MATHML = 1 ;}optional Type type = 1}

[ default = TEXT ];message Command {oneof command {string maple = 1 ;}}message PlotOptions {enum Type {IMAGE = 0 ;PROTOBUFFER = 1 ;}optional Type type = 1
optional uint32 pixel_width = 2
optional uint32 pixel_height = 3}

[ default = IMAGE ];[ default = 4 0 0 ];[ default = 4 0 0 ];message Session {optional string id = 1 ;optional uint32 timeout = 2 ;}message Request {repeated Command commands = 1 ;optional Session session = 2 ;optional PlotOptions plot_options = 3 ;optional OutputOptions output_options = 4 ;}message Result {oneof Type {10string text = 1 ;string mathml = 2 ;}}message MCSEvent {oneof event {Command command = 1 ;string input = 2 ;Result result = 3 ;string printf = 4 ;string pretty_print = 5 ;string lprint = 6 ;string error = 7 ;string warning = 8 ;string server_error = 9 ;bytes image_plot = 1 0 ;MapleCloud . Plot plot = 1 1 ;}}message Reply {optional Request request = 1 ;repeated MCSEvent event_stream = 2 ;}11