raw: binary data format of the host application
The raw I/O driver provides an implementation of the initializations block in binary mode: instead of translating information from/to text format, data is kept in its raw representation. The following example shows how to use this driver in combination with the mem driver to exchange arrays of data between a model and an application through memory. As shown in the previous section, we may work with a separate model file (this example) or alternatively include the model source directly in the model.
#include <stdio.h> #include "xprm_mc.h" const struct { /* Initial values for array 'data': */ const char *ind; /* index name */ double val,wght; /* value and weight data entries */ } data[]={{"camera",15,2}, {"necklace",100,20}, {"vase",90,20}, {"picture",60,30}, {"tv",40,40}, {"video",15,30}, {"chest",10,60}, {"brick",1,10}}; double solution[8]; /* Array for solution values */ int main() { XPRMmodel mod; int result; XPRMalltypes rvalue, itemname; XPRMset set; char bimfile[2000]; /* Buffer to store BIM file */ size_t bimfile_size; /* Buffer to store actual size of BIM file */ char bimfile_name[64]; /* File name of BIM file */ char data_name[40]; /* File name of initial values for 'data' */ char solution_name[40]; /* File name of solution values */ char params[96]; /* Parameter string for model execution */ XPRMinit(); /* Initialize Mosel */ /* Prepare file name for compilation using 'mem' driver: */ /* "mem:base address/size[/actual size pointer]" */ bimfile_size=0; sprintf(bimfile_name, "mem:%p/%d/%p", bimfile, (int)sizeof(bimfile), &bimfile_size); /* Compile model file to memory */ XPRMcompmod(NULL, "burglar2r.mos", bimfile_name, "Knapsack example"); printf("BIM file uses %lu bytes of memory.\n", bimfile_size); /* Load a BIM file from memory */ mod=XPRMloadmod(bimfile_name, NULL); /* Prepare file names for 'initializations' using the 'raw' driver: */ /* "rawoption[,...],filename" */ /* (Here, 'filename' uses the 'mem' driver, data is stored in memory) */ /* Options for 'raw': */ /* 'slength=0': strings are represented by pointers to null terminated */ /* arrays of characters (C-string) instead of fixed size arrays*/ /* 'noindex': only array values are expected - no indices requested */ sprintf(data_name, "slength=0,mem:%p/%d", data, (int)sizeof(data)); sprintf(solution_name, "noindex,mem:%p/%d", solution, (int)sizeof(solution)); /* Pass file names as execution param.s */ sprintf(params, "DATA='%s',SOL='%s'", data_name, solution_name); XPRMrunmod(mod, &result, params); /* Run the model */ /* Display solutions values obtained from the model */ printf("Objective: %g\n", XPRMgetobjval(mod)); XPRMfindident(mod, "ITEMS", &rvalue); /* Get the model object 'ITEMS' */ set = rvalue.set; for(i=0;i<8;i++) printf(" take(%s): %g\n", XPRMgetelsetval(set, i+1, &itemname)->string, solution[i]); return 0; }
The input data in the C code above is stored and communicated to the model in sparse format, that is, each data item with its index tuple. For retrieving and saving the solution data this example uses dense format, that is, just the data items without explicitly specifying the indices. To obtain a printout with the (string) index names, we retrieve separately the set of indices from the Mosel model. Alternatively, we could also use sparse format for the solution data similarly to the input data, in which case we did not have to retrieve the index set separately.
The model file burglar2r.mos of this example is very similar to the model versions for the odbc and diskdata I/O drivers in Section Data source access from Mosel models. The only changes made are to the name of the I/O driver and to the strings DATA and SOL for the data source and the destination of results respectively.
model Burglar2r uses 'mmxprs' parameters IODRV = 'raw:' DATA='' SOL='' WTMAX = 102 ! Maximum weight allowed end-parameters declarations ITEMS: set of string ! Index set for items VALUE: array(ITEMS) of real ! Value of items WEIGHT: array(ITEMS) of real ! Weight of items SOLTAKE: array(ITEMS) of real ! Solution values end-declarations initialisations from IODRV [VALUE,WEIGHT] as DATA end-initialisations declarations take: array(ITEMS) of mpvar ! 1 if we take item i; 0 otherwise end-declarations ! Objective: maximize total value MaxVal:= sum(i in ITEMS) VALUE(i)*take(i) ! Weight restriction sum(i in ITEMS) WEIGHT(i)*take(i) <= WTMAX ! All variables are 0/1 forall(i in ITEMS) take(i) is_binary maximize(MaxVal) ! Solve the problem ! Solution output forall(i in ITEMS) SOLTAKE(i):= getsol(take(i)) initialisations to IODRV SOLTAKE as SOL end-initialisations end-model
The example above uses sparse data format, that is, every data entry comprises its index (or index tuple) and the actual value (or list of values in our case). A model version using dense data format, so communicating just the data values without the indices, is described in Chapter 13.4.1 `Exchanging data between an application and a modelDense arrays' of the `Mosel User Guide'.
The raw format communicates data via fixed-size memory blocks. Greater flexibility through dynamic sizing of the data structures can be achieved by using the callback functionality provided through the driver cb (see Section cb: output to callback functions below and the examples of Chapters 13.4.3 and 14.1.7.3 `Exchanging data between an application and a model Dynamic data' of the `Mosel User Guide' for C and Java examples respectively).
Java version of the example
With the Mosel Java libraries, we replace the C driver raw by the Java binary format I/O driver jraw. Just as in the C version, we have stored the model data in a single structure containing the string index and the two data values for 'weight' and 'value' of every item. Mosel returns the solution into a second structure that also stores index and data values.
// Class to store initial values for array 'data' public static class MyData { public String ind; // index name public double val,wght; // value and weight data entries MyData(String i, double v, double w) { ind=i; val=v; wght=w; } } // Class to receive solution values public static class MySol { public String ind; // index name public double val; // solution value } public static void main(String[] args) throws Exception { XPRM mosel; XPRMModel mod; MyData data[]={new MyData("camera",15,2), new MyData("necklace",100,20), new MyData("vase",90,20), new MyData("picture",60,30), new MyData("tv",40,40), new MyData("video",15,30), new MyData("chest",10,60), new MyData("brick",1,10)}; MySol[] solution=new MySol[8]; for(int i=0;i<8;i++) solution[i] = new MySol(); mosel = new XPRM(); // Initialize Mosel mosel.compile("burglar2r.mos"); // Compile & load the model mod = mosel.loadModel("burglar2r.bim"); // Associate the Java objects with names in Mosel mosel.bind("dt", data); mosel.bind("sol", solution); // File names are passed through execution parameters mod.execParams = "DATA='dt(ind,val,wght)',SOL='sol(ind,val)',IODRV='jraw:'"; mod.run(); // Run the model if(mod.getProblemStatus()!=mod.PB_OPTIMAL) System.exit(1); // Stop if no solution found // Display solution values obtained from the model System.out.println("Objective value: " + mod.getObjectiveValue()); for(int i=0;i<8;i++) System.out.println(" take(" + solution[i].ind + "): " + solution[i].val); mod.reset(); // Reset the model }
A model version using dense data format is discussed in Chapter 14.1.7.1 `Exchanging data between an application and a modelDense arrays' of the `Mosel User Guide'.
.NET version of the example
The .NET version of our program is again very similar to its Java version. We now use the I/O driver dotnetraw in the place of jraw.
// Arrays containing initialization data for the model static double[] vdata = new double[] {15,100,90,60,40,15,10, 1}; // VALUE static double[] wdata = new double[] { 2, 20,20,30,40,30,60,10}; // WEIGHT // Structure to store initial values for the array 'data' class MyData { public string ind; public double val; public double wght; public MyData(string i, double v, double w) { this.ind = i; this.val = v; this.wght = w; } } // Structure to receive solution values class MySol { public string ind; public double val; } // The initial values for the array 'data' private static MyData[] data = new MyData[] { new MyData("camera",15,2), new MyData("necklace",100,20), new MyData("vase",90,20), new MyData("picture",60,30), new MyData("tv",40,40), new MyData("video",15,30), new MyData("chest",10,60), new MyData("brick",1,10) }; // Main entry point for the application static void Main(string[] args) { // Initialize Mosel XPRM mosel = XPRM.Init(); // Compile and load the Mosel model XPRMModel model = mosel.CompileAndLoad("burglar2r.mos"); // Associate the .NET object with a name in Mosel model.Bind("dt", data); // Create a new array for solution data and bind that to the name 'SOL' MySol[] solution=new MySol[8]; for(int i=0;i<8;i++) solution[i] = new MySol(); mosel.Bind("sol", solution); // Pass data location as a parameter to the model model.ExecParams = "DATA='dt(ind,val,wght)',SOL='sol(ind,val)',IODRV='dotnetraw:'"; // Run the model model.Run(); // Print the solution Console.WriteLine("Objective value: {0}", model.ObjectiveValue); for(int i=0;i<8;i++) Console.Write(" take({0}): {1}", solution[i].ind, solution[i].val); Console.WriteLine(); }
mmjobs version of the example
When running a Mosel model from another model, the two models can exchange data in memory using the binary format defined by raw. Given the restrictions of the raw format (each 'file' only contains a single data array, composite Mosel data structures are not supported) we recommend however to give preference to the more flexible binary format defined by the bin driver that supports the full set of data structures of initializations blocks (see Section bin: using Mosel's binary format below). Here is an example of a Mosel model reading and writing data to memory in binary format using bin.
model "Run model burglar IO" uses "mmjobs" declarations modBurg: Model ! Submodel ISet,SSet: set of string ! Index set for data arrays V,W: array(ISet) of real ! Data arrays Solution: array(SSet) of real ! Solution values end-declarations V:: (["camera","necklace","vase","picture","tv","video","chest","brick"]) [15, 100, 90, 60, 40, 15, 10, 1] W:: (["camera","necklace","vase","picture","tv","video","chest","brick"]) [ 2, 20, 20, 30, 40, 30, 60, 10] ! Compile the model, save bim in memory if compile("burglar2r.mos")<>0 then exit(1); end-if load(modBurg, "burglar2r.bim") ! Load the bim file setdefstream(modBurg, F_OUTPUT, "null:") ! Disable output from submodel ! Save data in shared memory IODRV:="bin:shmem:burgdata" initializations to IODRV [V,W] as "Burgdata" end-initializations ! Start model execution, setting parameters run(modBurg, "IODRV='" +IODRV + "',DATA='Burgdata',SOL='Solution'") wait ! Wait for model termination dropnextevent ! Ignore termination event message ! Retrieve solution from shared memory initializations from IODRV Solution end-initializations forall(i in SSet) writeln(" take(", i, "): ", Solution(i)) end-model
The relevant part of the model above look as follows with the raw I/O driver.
! Save data in shared memory IODRV:="raw:" initializations to IODRV [V,W] as "shmem:Burgdata" end-initializations ! Start model execution, setting parameters run(modBurg, "IODRV='" +IODRV + "',DATA='shmem:Burgdata',SOL='shmem:SolTake'") wait ! Wait for model termination dropnextevent ! Ignore termination event message ! Retrieve solution from shared memory initializations from IODRV Solution as "shmem:SolTake" end-initializations