Output
Producing formatted output
In some of the previous examples the procedures write and writeln have been used for displaying data, solution values and some accompanying text. To produce better formatted output, these procedures can be combined with the formatting procedure strfmt. In its simplest form, strfmt's second argument indicates the (minimum) space reserved for writing the first argument and its placement within this space (negative values mean left justified printing, positive right justified). When writing a real, a third argument may be used to specify the maximum number of digits after the decimal point.
For example, if file fo.mos contains
model FO parameters r = 1.0 ! A real i = 0 ! An integer end-parameters writeln("i is ", i) writeln("i is ", strfmt(i,6) ) writeln("i is ", strfmt(i,-6) ) writeln("r is ", r) writeln("r is ", strfmt(r,6) ) writeln("r is ",strfmt(r,10,4) ) end-modeland we run Mosel thus:
mosel -s -c "exec fo 'i=123, r=1.234567'"we get output
i is 123 i is 123 i is 123 r is 1.23457 r is 1.23457 r is 1.2346The following example (model transport2.mos) prints out the solution of model `Transport' (Section A transport example) in table format. The reader may be reminded that the objective of this problem is to compute the product flows from a set of plants (PLANT) to a set of sales regions (REGION) so as to minimize the total cost. The solution needs to comply with the capacity limits of the plants (PLANTCAP) and satisfy the demand DEMAND of all regions.
procedure print_table declarations rsum: array(REGION) of integer ! Auxiliary data table for printing psum,prsum,ct,iflow: integer ! Counters end-declarations ! Print heading and the first line of the table writeln("\nProduct Distribution\n--------------------") writeln(strfmt("Sales Region",44)) write(strfmt("",14)) forall(r in REGION) write(strfmt(r,9)) writeln(strfmt("TOTAL",9), " Capacity") ! Print the solution values of the flow variables and ! calculate totals per region and per plant ct:=0 forall(p in PLANT) do ct += 1 if ct=2 then write("Plant ",strfmt(p,-8)) else write(" ",strfmt(p,-8)) end-if psum:=0 forall(r in REGION) do iflow:=integer(getsol(flow(p,r))) psum += iflow rsum(r) += iflow if iflow<>0 then write(strfmt(iflow,9)) else write(" ") end-if end-do writeln(strfmt(psum,9), strfmt(integer(PLANTCAP(p)),9)) end-do ! Print the column totals write("\n", strfmt("TOTAL",-14)) prsum:=0 forall(r in REGION) do prsum += rsum(r); write(strfmt(rsum(r),9)) end-do writeln(strfmt(prsum,9)) ! Print demand of every region write(strfmt("Demand",-14)) forall(r in REGION) write(strfmt(integer(DEMAND(r)),9)) ! Print objective function value writeln("\n\nTotal cost of distribution = ", strfmt(getobjval/1e6,0,3), " million.") end-procedureWith the data from Chapter More advanced modeling features the procedure print_table produces the following output:
Product Distribution -------------------- Sales Region Scotland North SWest SEast Midlands TOTAL Capacity Corby 180 820 2000 3000 3000 Plant Deeside 1530 920 250 2700 2700 Glasgow 2840 1270 4110 4500 Oxford 1500 2000 500 4000 4000 TOTAL 2840 2800 2600 2820 2750 13810 Demand 2840 2800 2600 2820 2750 Total cost of distribution = 81.018 million.File output
If we do not want the output of procedure print_tab in the previous section to be displayed on screen but to be saved in the file out.txt, we simply open the file for writing at the beginning of the procedure by adding
fopen("out.txt",F_OUTPUT)before the first writeln statement, and close it at the end of the procedure, after the last writeln statement with
fclose(F_OUTPUT)If we do not want any existing contents of the file out.txt to be deleted, so that the result table is appended to the end of the file, we need to write the following for opening the file (closing it the same way as before):
fopen("out.txt",F_OUTPUT+F_APPEND)As with input of data from file, there are several ways of outputting data (e.g. solution values) to a file in Mosel. The following example demonstrates three different ways of writing the contents of an array A to a file.
Data input with initializations to
The first method uses the initializations block for creating or updating a file in Mosel's initializations format.
model "Trio output (1)" declarations A: array(-1..1,5..7) of real end-declarations A :: [ 2, 4, 6, 12, 14, 16, 22, 24, 26] ! First method: use an initializations block initializations to "out_1.dat" A as "MYOUT" end-initializations end-modelFile out_1.dat will contain the following:
'MYOUT': [2 4 6 12 14 16 22 24 26]If this file contains already a data entry MYOUT, it is replaced with this output without modifying or deleting any other contents of this file. Otherwise, the output is appended at the end of it.
Data output with writeln
As mentioned above, we may create freely formatted output files by redirecting the output of write and writeln statements to a file:
model "Trio output (2)" declarations A: array(-1..1,5..7) of real end-declarations A :: [ 2, 4, 6, 12, 14, 16, 22, 24, 26] ! Second method: use the built-in writeln function fopen("out_2.dat", F_OUTPUT) forall(i in -1..1, j in 5..7) writeln('A_out(', i, ' and ', j, ') = ', A(i,j)) fclose(F_OUTPUT) end-modelThe nicely formatted output to out_2.dat results in the following:
A_out(-1 and 5) = 2 A_out(-1 and 6) = 4 A_out(-1 and 7) = 6 A_out(0 and 5) = 12 A_out(0 and 6) = 14 A_out(0 and 7) = 16 A_out(1 and 5) = 22 A_out(1 and 6) = 24 A_out(1 and 7) = 26Data output with diskdata
As a third possibility, one may use the diskdata subroutine from module mmetc to write out comma separated value (CSV) files.
model "Trio output (3)" uses "mmetc" declarations A: array(-1..1,5..7) of real end-declarations A :: [ 2, 4, 6, 12, 14, 16, 22, 24, 26] ! Third method: use diskdata diskdata(ETC_OUT+ETC_SPARSE,"out_3.dat", A) end-modelThe output with diskdata simply prints the contents of the array to out_3.dat, with option ETC_SPARSE each entry is preceded by the corresponding indices:
-1,5,2 -1,6,4 -1,7,6 0,5,12 0,6,14 0,7,16 1,5,22 1,6,24 1,7,26Without option ETC_SPARSE out_3.dat looks as follows:
2,4,6 12,14,16 22,24,26Instead of using the diskdata subroutine, we may equally use the diskdata IO driver that is defined by the same module, mmetc. In the example above we replace the diskdata statement by the following initializations to block.
[ initializations to 'mmetc.diskdata:' A as 'sparse,out_3.dat' end-initializationsReal number format
Whenever output is printed (including matrix export to a file) Mosel uses the standard representation of floating point numbers of the operating system (C format %g). This format may apply rounding when printing large numbers or numbers with many decimals. It may therefore sometimes be preferable to change the output format to a fixed format to see the exact results of an optimization run or to produce a matrix output file with greater accuracy. Consider the following example (model numformat.mos):
model "Formatting numbers" parameters a = 12345000.0 b = 12345048.9 c = 12.000045 d = 12.0 end-parameters writeln(a, " ", b, " ", c, " ", d) setparam("REALFMT", "%1.6f") writeln(a, " ", b, " ", c, " ", d) end-modelThis model produces the following output.
1.2345e+07 1.2345e+07 12 12 12345000.000000 12345048.900000 12.000045 12.000000That is, with the default printing format it is not possible to distinguish between a and b or to see that c is not an integer. After setting a fixed format with 6 decimals all these numbers are output with their exact values.
If you have any comments or suggestions about these pages, please send mail to docs@dashoptimization.com.