• No results found

Multiple models and parallel solving with mmjobs

In document Xpress-Mosel User guide (Page 145-148)

The module mmjobs makes it possible to exchange information between models running

concurrently. Its functionality includes facilities for model management (e.g. compiling, running, or interrupting a model from within a second model), synchronization of concurrent models based on event queues, and a shared memory IO driver for an efficient exchange of data between models that are executed concurrently.

Several complete examples (including examples of Benders decomposition and Dantzig-Wolfe decomposition) of the use of module mmjobs are described in the whitepaperMultiple models and parallel solving with Moselthat is provided as a part of the Xpress documentation and also on the’Whitepapers’ pageof theXpress website. We show here how to use the basic

functionality for executing a model from a second model.

17.2.1

Running a model from another model

As a test case, we shall once more work with model prime.mos from Section8.2. In the first instance, we now show how to compile and run this model from a second model, runprime.mos:

model "Run model prime" uses "mmjobs" declarations modPrime: Model event: Event end-declarations ! Compile ’prime.mos’ if compile("prime.mos")<>0 then exit(1); end-if

load(modPrime, "prime.bim") ! Load bim file

run(modPrime, "LIMIT=50000") ! Start execution and

wait(2) ! wait 2 seconds for an event

if isqueueempty then ! No event has been sent... writeln("Model too slow: stopping it!")

stop(modPrime) ! ... stop the model,

wait ! ... and wait for the termination event end-if

! An event is available: model finished event:=getnextevent

writeln("Exit status: ", getvalue(event)) writeln("Exit code : ", getexitcode(modPrime))

unload(modPrime) ! Unload the submodel end-model

The compile command generates the BIM file for the given submodel; the command load loads the binary file into Mosel; and finally we start the model with the command run. The run command is not used in its basic version (single argument with the model reference): here its second argument sets a new value for the parameter LIMIT of the submodel.

In addition to the standard compile–load–run sequence, the model above shows some basic features of interaction with the submodel: if the submodel has not terminated after 2 seconds (that is, if it has not sent a termination message) it is stopped by the master model. After termination of the submodel (either by finishing its calculations within less than 2 seconds or stopped by the master model) its termination status and the exit value are retrieved (functions getvalueand getexitcode). Unloading a submodel explicitly as shown here is only really necessary in larger applications that continue after the termination of the submodel, so as to free the memory used by it.

Note: our example model shows an important property of submodels—they are running in

parallel to the master model and also to any other submodels that may have been started from the master model. It is therefore essential to insert wait at appropriate places to coordinate the execution of the different models.

17.2.2

Compiling to memory

The model shown in the previous section compiles and runs a submodel. The default compilation of a Mosel file filename.mos generates a binary model file filename.bim. To avoid the

generation of physical BIM files for submodels we may compile the submodel to memory, making use of the concept of I/O drivers introduced in Section17.1.

Compiling a submodel to memory is done by replacing the standard compile and load commands by the following lines (model runprime2.mos):

if compile("","prime.mos","shmem:bim")<>0 then exit(1)

end-if

load(modPrime,"shmem:bim") ! Load bim file from memory... fdelete("shmem:bim") ! ... and release the memory block

The full version of compile takes three arguments: the compilation flags (e.g., use "g" for debugging), the model file name, and the output file name (here a label prefixed by the name of the shared memory driver). Having loaded the model we may free the memory used by the compiled model with a call to fdelete (this subroutine is provided by the module mmsystem).

17.2.3

Exchanging data between models

When working with submodels we are usually not just interested in executing the submodels, we also wish to retrieve their results in the master model. This is done most efficiently by exchanging data in (shared) memory as shown in the model runprimeio.mos below. Besides the retrieval and printout of the solution we have replaced the call to stop by sending the event STOPMOD to the submodel: instead of simply terminating the submodel this event will make it interrupt its calculations and write out the current solution. Once the submodel has terminated (after sending the STOPMOD event we wait for the model’s termination message) we may read its solution from memory, using the initializations block with the drivers raw (binary format) and shmem (read from shared memory).

model "Run model primeio" uses "mmjobs"

declarations modPrime: Model

NumP: integer ! Number of prime numbers found SetP: set of integer ! Set of prime numbers

STOPMOD = 2 end-declarations

! Compile ’prime.mos’

if compile("primeio.mos")<>0 then exit(1); end-if

load(modPrime, "primeio.bim") ! Load bim file

! Disable model output setdefstream(modPrime,"","null:","null:")

run(modPrime, "LIMIT=35000") ! Start execution and

wait(2) ! wait 2 seconds for an event

if isqueueempty then ! No event has been sent... writeln("Model too slow: stopping it!")

send(modPrime, STOPMOD, 0) ! ... stop the model, then wait wait

end-if

initializations from "raw:"

NumP as "shmem:NumP" SetP as "shmem:SPrime" end-initializations

writeln(SetP) ! Output the result writeln(" (", NumP, " prime numbers.)")

unload(modPrime) end-model

We now have to modify the submodel (file primeio.mos) correspondingly: it needs to intercept the ‘STOPMOD’ event interrupting the calculations (via an additional test isqueueempty for the repeat-untilloop) and write out the solution to memory in the end:

model "Prime IO" uses "mmjobs"

parameters

LIMIT=100 ! Search for prime numbers in 2..LIMIT end-parameters

declarations

SNumbers: set of integer ! Set of numbers to be checked SPrime: set of integer ! Set of prime numbers

STOPMOD = 2 end-declarations

SNumbers:={2..LIMIT}

writeln("Prime numbers between 2 and ", LIMIT, ":")

n:=2 repeat

while (not(n in SNumbers)) n+=1

SPrime += {n} ! n is a prime number i:=n

while (i<=LIMIT) do ! Remove n and all its multiples SNumbers-= {i}

i+=n end-do

until (SNumbers={} or not isqueueempty)

NumP:= getsize(SPrime)

initializations to "raw:"

NumP as "shmem:NumP" SPrime as "shmem:SPrime" end-initializations

end-model

Note: since the condition isqueueempty is tested only once per iteration of the repeat-until

loop, the termination of the submodel is not immediate for large values of LIMIT. If you wish to

run this model with very large values, please see Section15.2for an improved implementation of the prime number algorithm that considerably reduces its execution time.

In document Xpress-Mosel User guide (Page 145-148)