5.2. C 语言的建模和优化

在本节中,我们将使用 MindOpt C 语言的 API 来建模以及求解 线性规划问题示例 中的问题。

5.2.1. 按行输入:MdoLoEx1

首先,引入头文件:

23#include "Mindopt.h"

并创建优化模型:

52    /*------------------------------------------------------------------*/
53    /* Step 1. Create a model and change the parameters.                */
54    /*------------------------------------------------------------------*/
55    /* Create an empty model. */
56    MDO_CHECK_CALL(Mdo_createMdl(&model));

接下来,我们通过 Mdo_setIntAttr() 将目标函数设置为 最小化 ,并调用 Mdo_addCol() 来添加四个优化变量,定义其下界、上界、名称和类型(关于 Mdo_setIntAttr()Mdo_addCol() 的详细使用方式,请参考 C 接口函数):

58    /*------------------------------------------------------------------*/
59    /* Step 2. Input model.                                             */
60    /*------------------------------------------------------------------*/
61    /* Change to minimization problem. */
62    Mdo_setIntAttr(model, "MinSense", MDO_YES);
63
64    /* Add variables. */
65    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, 10.0,         1.0, 0, NULL, NULL, "x0", MDO_NO));
66    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x1", MDO_NO));
67    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x2", MDO_NO));
68    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x3", MDO_NO));

Note

矩阵的非零元将在后面按 输入;因此,Mdo_addCol() 中,按 输入非零元的相关参数 sizeindicesvalue 分别用 0NULLNULL 代替(换句话说,此时问题无约束)。

以下我们将开始添加线性约束中的的非零元及其上下界,我们使用以下四列数组来定义线性约束;其中, row1_idxrow2_idx 分别表示第一和第二个约束中非零元素的位置(索引),而 row1_valrow2_val 则是与之相对应的非零数值。

47    const int    row1_idx[] = { 0,   1,   2,   3   };
48    const double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
49    const int    row2_idx[] = { 0,    2,   3   };
50    const double row2_val[] = { 1.0, -1.0, 6.0 };

我们调用 Mdo_addRow() 将输入约束:

70    /* Add constraints.
71     * Note that the nonzero elements are inputted in a row-wise order here.
72     */
73    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, MDO_INFINITY, 4, row1_idx, row1_val, "c0"));
74    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0,          3, row2_idx, row2_val, "c1"));

问题输入完成后,再调用 Mdo_solveProb() 求解优化问题,并通过 Mdo_displayResults() 查看优化结果:

76    /*------------------------------------------------------------------*/
77    /* Step 3. Solve the problem and populate the result.               */
78    /*------------------------------------------------------------------*/
79    /* Solve the problem. */
80    MDO_CHECK_CALL(Mdo_solveProb(model));
81    Mdo_displayResults(model);

最后,调用 Mdo_freeMdl() 来释放内存:

84    /*------------------------------------------------------------------*/
85    /* Step 4. Free the model.                                          */
86    /*------------------------------------------------------------------*/
87    /* Free the model. */
88    Mdo_freeMdl(&model);

MdoLoEx1.c 提供了完整源代码:

 1/**
 2 *  Description
 3 *  -----------
 4 *
 5 *  Linear optimization (row-wise input).
 6 *
 7 *  Formulation
 8 *  -----------
 9 *
10 *  Minimize
11 *    obj: 1 x0 + 1 x1 + 1 x2 + 1 x3
12 *  Subject To
13 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
14 *   c1 : 1 x0 - 1 x2 + 6 x3 = 1
15 *  Bounds
16 *    0 <= x0 <= 10
17 *    0 <= x1
18 *    0 <= x2
19 *    0 <= x3
20 *  End
21 */
22#include <stdio.h>
23#include "Mindopt.h"
24
25/* Macro to check the return code */
26#define MDO_CHECK_CALL(MDO_CALL)                                    \
27    code = MDO_CALL;                                                \
28    if (code != MDO_OKAY)                                           \
29    {                                                               \
30        Mdo_explainResult(model, code, str);                        \
31        Mdo_freeMdl(&model);                                        \
32        fprintf(stderr, "===================================\n");   \
33        fprintf(stderr, "Error   : code <%d>\n", code);             \
34        fprintf(stderr, "Reason  : %s\n", str);                     \
35        fprintf(stderr, "===================================\n");   \
36        return (int)code;                                           \
37    }
38
39int main(void)
40{
41    /* Variables. */
42    char str[1024] = { "\0" };
43    MdoMdl * model = NULL;
44    MdoResult code = MDO_OKAY;
45    MdoStatus status = MDO_UNKNOWN;
46
47    const int    row1_idx[] = { 0,   1,   2,   3   };
48    const double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
49    const int    row2_idx[] = { 0,    2,   3   };
50    const double row2_val[] = { 1.0, -1.0, 6.0 };
51
52    /*------------------------------------------------------------------*/
53    /* Step 1. Create a model and change the parameters.                */
54    /*------------------------------------------------------------------*/
55    /* Create an empty model. */
56    MDO_CHECK_CALL(Mdo_createMdl(&model));
57
58    /*------------------------------------------------------------------*/
59    /* Step 2. Input model.                                             */
60    /*------------------------------------------------------------------*/
61    /* Change to minimization problem. */
62    Mdo_setIntAttr(model, "MinSense", MDO_YES);
63
64    /* Add variables. */
65    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, 10.0,         1.0, 0, NULL, NULL, "x0", MDO_NO));
66    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x1", MDO_NO));
67    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x2", MDO_NO));
68    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x3", MDO_NO));
69
70    /* Add constraints.
71     * Note that the nonzero elements are inputted in a row-wise order here.
72     */
73    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, MDO_INFINITY, 4, row1_idx, row1_val, "c0"));
74    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0,          3, row2_idx, row2_val, "c1"));
75
76    /*------------------------------------------------------------------*/
77    /* Step 3. Solve the problem and populate the result.               */
78    /*------------------------------------------------------------------*/
79    /* Solve the problem. */
80    MDO_CHECK_CALL(Mdo_solveProb(model));
81    Mdo_displayResults(model);
82 
83    /*------------------------------------------------------------------*/
84    /* Step 4. Free the model.                                          */
85    /*------------------------------------------------------------------*/
86    /* Free the model. */
87    Mdo_freeMdl(&model);
88       
89    return (int)code;
90}

5.2.2. 按列输入:MdoLoEx2

在下面的代码中,我们依然对上述问题进行建模,但改以 按列排列 的方式输入矩阵的非零元。换句话说,在增加一个新变量的同时,亦输入各约束在此列中相对应的非零元;一旦输入所有变量及非零元后,再修改线性约束的下界(left-hand-side;LHS)和上界(right-hand-side;RHS)。

此外,我们还调用 Mdo_getStatus() 来检查求解器的优化状态,并通过 Mdo_getRealAttr()Mdo_getRealAttrArray() 来获取目标值和最优解( Mdo_getRealAttr()Mdo_getRealAttrArray() 的详细使用方式,请参考 C 接口函数 )。

MdoLoEx2.c 提供了完整源代码:

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Linear optimization (column-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Minimize
 11 *    obj: 1 x0 + 1 x1 + 1 x2 + 1 x3
 12 *  Subject To
 13 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
 14 *   c1 : 1 x0 - 1 x2 + 6 x3 = 1
 15 *  Bounds
 16 *    0 <= x0 <= 10
 17 *    0 <= x1
 18 *    0 <= x2
 19 *    0 <= x3
 20 *  End
 21 */
 22#include <stdio.h>
 23#include "Mindopt.h"
 24
 25/* Macro to check the return code */
 26#define MDO_CHECK_CALL(MDO_CALL)                                    \
 27    code = MDO_CALL;                                                \
 28    if (code != MDO_OKAY)                                           \
 29    {                                                               \
 30        Mdo_explainResult(model, code, str);                        \
 31        Mdo_freeMdl(&model);                                        \
 32        fprintf(stderr, "===================================\n");   \
 33        fprintf(stderr, "Error   : code <%d>\n", code);             \
 34        fprintf(stderr, "Reason  : %s\n", str);                     \
 35        fprintf(stderr, "===================================\n");   \
 36        return (int)code;                                           \
 37    }
 38
 39int main(void)
 40{
 41    /* Variables. */
 42    char str[1024] = { "\0" };
 43    MdoMdl * model = NULL;
 44    MdoResult code = MDO_OKAY;
 45    MdoStatus status = MDO_UNKNOWN;
 46    double val, soln[4];
 47    int j;
 48    const int     col1_idx[] = { 0,    1   };
 49    const double  col1_val[] = { 1.0,  1.0 };
 50    const int     col2_idx[] = { 0         };
 51    const double  col2_val[] = { 1.0       };
 52    const int     col3_idx[] = { 0,    1   };
 53    const double  col3_val[] = { 2.0, -1.0 };
 54    const int     col4_idx[] = { 0,    1   };
 55    const double  col4_val[] = { 3.0,  6.0 };
 56
 57    /*------------------------------------------------------------------*/
 58    /* Step 1. Create a model and change the parameters.                */
 59    /*------------------------------------------------------------------*/
 60    /* Create an empty model. */
 61    MDO_CHECK_CALL(Mdo_createMdl(&model));
 62    
 63    /*------------------------------------------------------------------*/
 64    /* Step 2. Input model.                                             */
 65    /*------------------------------------------------------------------*/
 66    /* Change to minimization problem. */
 67    Mdo_setIntAttr(model, "MinSense", MDO_YES);
 68
 69    /* Add variables. 
 70     * Note that the nonzero elements are inputted in a column-wise order here.
 71     */
 72    MDO_CHECK_CALL(Mdo_addCol(model, 0.0,         10.0, 1.0, 2, col1_idx, col1_val, "x0", MDO_NO));
 73    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 1, col2_idx, col2_val, "x1", MDO_NO));
 74    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 2, col3_idx, col3_val, "x2", MDO_NO));
 75    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 2, col4_idx, col4_val, "x3", MDO_NO));
 76
 77    /* Change the LHS value and RHS value of the constraints. */
 78    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, "LHS", 0,          1.0));
 79    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, "RHS", 0, MDO_INFINITY));
 80    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, "LHS", 1,          1.0));
 81    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, "RHS", 1,          1.0));
 82    
 83    /*------------------------------------------------------------------*/
 84    /* Step 3. Solve the problem and populate the result.               */
 85    /*------------------------------------------------------------------*/
 86    /* Solve the problem. */
 87    MDO_CHECK_CALL(Mdo_solveProb(model));
 88    Mdo_displayResults(model);
 89
 90    switch (Mdo_getStatus(model))
 91    {
 92    case MDO_UNKNOWN:
 93        printf("Optimizer terminated with an UNKNOWN status.\n");
 94        break;
 95    case MDO_OPTIMAL:
 96        MDO_CHECK_CALL(Mdo_getRealAttr(model, "PrimalObjVal", &val));
 97        printf("Optimizer terminated with an OPTIMAL status.\n");
 98        printf(" - Primal objective : %e.\n", val);
 99        MDO_CHECK_CALL(Mdo_getRealAttrArray(model, "PrimalSoln", 0, 4, soln));
100        for (j = 0; j < 4; ++j)
101        {
102            printf("x[%d] = %e\n", j, soln[j]);
103        }
104        break;
105    case MDO_INFEASIBLE:
106        printf("Optimizer terminated with an INFEASIBLE status.\n");
107        break;
108    case MDO_UNBOUNDED:
109        printf("Optimizer terminated with an UNBOUNDED status.\n");
110        break;
111    case MDO_INF_OR_UBD:
112        printf("Optimizer terminated with an INFEASIBLE or UNBOUNDED status.\n");
113        break;
114    }
115
116    /*------------------------------------------------------------------*/
117    /* Step 4. Free the model.                                          */
118    /*------------------------------------------------------------------*/
119    /* Free the model. */
120    Mdo_freeMdl(&model);
121       
122    return (int)code;
123}

5.2.3. 进阶使用示例:MdoLoEx3

在下面的代码中,我们展示了其他进阶 API 的使用方式,如:输入模型、修改模型、获取基解、热启动的例子;关于 API 的完整使用方法,请参考 接口的定义与调用规范

MdoLoEx3.c

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Linear optimization.
  6 *   - Row input.
  7 *   - Column input.
  8 *   - Query.
  9 */
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include "Mindopt.h"
 13
 14#define WRITE_LP 1
 15#define MY_FOLDER "./"
 16
 17/* Macro to check the return code */
 18#define MDO_CHECK_CALL(MDO_CALL)                                    \
 19    code = MDO_CALL;                                                \
 20    if (code != MDO_OKAY)                                           \
 21    {                                                               \
 22        Mdo_explainResult(model, code, str);                        \
 23        Mdo_freeMdl(&model);                                        \
 24        fprintf(stderr, "===================================\n");   \
 25        fprintf(stderr, "Error   : code <%d>\n", code);             \
 26        fprintf(stderr, "Reason  : %s\n", str);                     \
 27        fprintf(stderr, "===================================\n");   \
 28        return (int)code;                                           \
 29    }
 30
 31int main(void)
 32{
 33    /* Variables. */
 34    char str[1024] = { "\0" };
 35    MdoMdl * model = NULL;
 36    MdoResult code = MDO_OKAY;
 37    MdoStatus status = MDO_UNKNOWN;
 38    int i, j, c, r, e;
 39
 40    const int csr_bgn[] = {0, 4, 7};
 41    const int csr_indices[] = 
 42    {
 43        0,   1,   2,   3,
 44        0,        2,   3  
 45    };
 46    const double csr_values[] = 
 47    {
 48        1.0, 1.0,  2.0, 3.0,
 49        1.0,      -1.0, 6.0
 50    };
 51
 52    const int csc_bgn[] = {0, 2, 3, 5, 7};
 53    const int csc_indices[] = 
 54    {
 55        0,  1,
 56        0,
 57        0,  1,
 58        0,  1
 59    };
 60    const double csc_values[] = 
 61    {
 62        1.0,   1.0,
 63        1.0, 
 64        2.0,  -1.0, 
 65        3.0,   6.0
 66    };
 67
 68    const double lhss[] = { 1, 1            };
 69    const double rhss[] = { 1, MDO_INFINITY };
 70    const char* row_names[] = { "c0", "c1" };
 71
 72    const double lbs[] =  {  0.0,          0.0,          0.0,          0.0 };
 73    const double ubs[] =  { 10.0, MDO_INFINITY, MDO_INFINITY, MDO_INFINITY };
 74    const double objs[] = {  1.0,          1.0,          1.0,          1.0 };
 75    const char* col_names[] = { "x0", "x1", "x2", "x3" };
 76      
 77    /*------------------------------------------------------------------*/
 78    /* Step 1. Create a model and change the parameters.                */
 79    /*------------------------------------------------------------------*/
 80    printf(" Create a model and change the parameters.\n\n");
 81    /* Create an empty model. */
 82    MDO_CHECK_CALL(Mdo_createMdl(&model));
 83
 84    /*------------------------------------------------------------------*/
 85    /* Step 2. Input model.                                             */
 86    /*------------------------------------------------------------------*/
 87    printf("\nStep 2. Input model.\n\n");    
 88    /* The following three input methods will all result in the same model. */
 89#if 0
 90    /* Method 1. */
 91    /* Change to minimization problem. */
 92    MDO_CHECK_CALL(Mdo_setIntAttr(model, "MinSense", MDO_YES));
 93    
 94    /* Add variables. */
 95    for (i = 0; i < 4; ++i)
 96    {
 97        MDO_CHECK_CALL(Mdo_addCol(model, lbs[i], ubs[i], objs[i], 0, NULL, NULL, col_names[i], MDO_NO));    
 98    }    
 99    /* Add two constraints. 
100     * The coefficients of the constraint matrix are inputted in a row-wise order.
101     */
102    MDO_CHECK_CALL(Mdo_addRows(model, 2, lhss, rhss, csr_bgn, csr_indices, csr_values, row_names));
103#endif
104#if 0
105    /* Method 2. */
106    /* Change to minimization problem. */
107    MDO_CHECK_CALL(Mdo_setIntAttr(model, "MinSense", MDO_YES));
108    
109    /* Add variables and constraints. 
110     * The coefficients of the constraint matrix are inputted in a column-wise order.
111     */ 
112    MDO_CHECK_CALL(Mdo_addCols(model, 4, lbs, ubs, objs, csc_bgn, csc_indices, csc_values, col_names, NULL));    
113    
114    /* Change LHS values and RHS values. */
115    MDO_CHECK_CALL(Mdo_setRealAttrArray(model, "LHS", 0, 2, lhss));
116    MDO_CHECK_CALL(Mdo_setRealAttrArray(model, "RHS", 0, 2, rhss));
117#endif    
118#if 1
119    /* Method 3. */
120    /* Add four variables and two constraints in one shot.
121     * The coefficients of the constraint matrix are inputted in a column-wise order.
122     */
123    MDO_CHECK_CALL(Mdo_loadModel(model, 4, 2, csc_bgn, csc_indices, csc_values, 
124        lbs, ubs, objs, NULL, 0.0, MDO_YES, lhss, rhss, col_names, row_names));
125#endif
126    
127    /*------------------------------------------------------------------*/
128    /* Step 3. Solve the problem and populate the result.               */
129    /*------------------------------------------------------------------*/
130    printf("\nStep 3. Solve the problem and populate the result.\n\n");
131    /* Solve the problem. */
132    MDO_CHECK_CALL(Mdo_solveProb(model));
133    Mdo_displayResults(model);
134#ifdef WRITE_LP    
135    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step3.lp"));   
136#endif
137    
138    /*------------------------------------------------------------------*/
139    /* Step 4. Add another two variables and then resolve the problem.  */
140    /*------------------------------------------------------------------*/
141    printf("\nStep 4. Add another two variables and then resolve the problem.\n\n");
142    /* Add another two variables. */    
143    double lbs2[] =  { 0,            -2           };
144    double ubs2[] =  { MDO_INFINITY, MDO_INFINITY };
145    double objs2[] = { 1,            -1           };
146
147    int col_bgn[] = {0, 2, 4 };
148    int col_indices[] =   
149    {
150        0, 1, 
151        0, 1
152    };
153    double col_values[] = 
154    {
155        1, 2, 
156        3, 4
157    };
158    const char * col_names2[] = { "y1", "y2" };
159    
160    MDO_CHECK_CALL(Mdo_addCols(model, 2, lbs2, ubs2, objs2, col_bgn, col_indices, col_values, col_names2, NULL));
161        
162    /* Solve the problem. */
163    MDO_CHECK_CALL(Mdo_solveProb(model));
164    Mdo_displayResults(model);
165#ifdef WRITE_LP
166    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step4.lp"));   
167#endif
168      
169    /*------------------------------------------------------------------*/
170    /* Step 5. Add another two constraints and then resolve the problem.*/
171    /*------------------------------------------------------------------*/
172    printf("\nStep 5. Add another two constraints and then resolve the problem.\n\n");
173    int bgn2[] = {0, 3, 6};
174    int indices2[] = 
175    {
176        0,   1,        3,
177        0,        2,   3  
178    };
179    double values2[] = 
180    {
181        1.0, 1.0,      -2.0,
182        1.0,      -2.0, 6.0
183    };    
184    
185    const double lhss2[] = { 0, 1            };
186    const double rhss2[] = { 2, MDO_INFINITY };
187
188    const char* row_names2[] = { "C2", "C3" };
189    
190    /* Add two constraints. */
191    MDO_CHECK_CALL(Mdo_addRows(model, 2, lhss2, rhss2, bgn2, indices2, values2, row_names2));
192 
193    /* Solve the problem. */
194    MDO_CHECK_CALL(Mdo_solveProb(model));
195    Mdo_displayResults(model);
196#ifdef WRITE_LP    
197    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step5.lp"));   
198#endif
199
200    /*------------------------------------------------------------------*/
201    /* Step 6. Obtain optimal basis.                                    */
202    /*------------------------------------------------------------------*/       
203    printf("\nStep 6. Obtain optimal basis.\n\n");
204    int * row_basis = (int *)calloc(4, sizeof(int));
205    int * col_basis = (int *)calloc(6, sizeof(int));    
206    MDO_CHECK_CALL(Mdo_getIntAttrArray(model, "RowBasis", 0, 4, row_basis));
207    MDO_CHECK_CALL(Mdo_getIntAttrArray(model, "ColBasis", 0, 6, col_basis));
208    /*
209     * isFree = 0,
210     * basic = 1,
211     * atUpperBound = 2,
212     * atLowerBound = 3,
213     * superBasic = 4,
214     * isFixed = 5,
215     */
216    for (i = 0; i < 4; ++i)
217    {
218        printf("Row [%d] status: %d\n", i, row_basis[i]);
219    }
220    for (j = 0; j < 6; ++j)
221    {
222        printf("Col [%d] status: %d\n", j, col_basis[j]);
223    }
224#ifdef WRITE_LP   
225    MDO_CHECK_CALL(Mdo_writeSoln(model, MY_FOLDER "Step6.bas"));   
226    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER "Step6.lp"));   
227#endif
228
229    /*------------------------------------------------------------------*/
230    /* Step 7. Warm-start Simplex.                                      */
231    /*------------------------------------------------------------------*/       
232    printf("\nStep 7. Warm-start Simplex.\n\n");
233
234    /* Change the objective coefficients. */
235    int obj_indices[] =   { 1, 2 };
236    double obj_values[] = { 3, -3 };
237    MDO_CHECK_CALL(Mdo_setObjs(model, 2, obj_indices, obj_values));
238
239    /* Load the basis. */
240    MDO_CHECK_CALL(Mdo_setIntAttrArray(model, "RowBasis", 0, 4, row_basis));
241    MDO_CHECK_CALL(Mdo_setIntAttrArray(model, "ColBasis", 0, 6, col_basis));
242
243    /* Solve the problem. */
244    Mdo_setIntParam(model, "Method", 0);
245    MDO_CHECK_CALL(Mdo_solveProb(model));
246    Mdo_displayResults(model);
247
248    free(row_basis);
249    free(col_basis);
250
251    /*------------------------------------------------------------------*/
252    /* Step 8. Model query.                                             */
253    /*------------------------------------------------------------------*/    
254    printf("\nStep 8. Model query.\n\n");
255    /* Query 1: Retrieve first two rows. */
256    printf("Query 1: Retrieve first two rows.\n");
257    int row_indices[2] = {0, 1};
258    int real_size;
259    /* Step 8.1. Get the total number of NNZs first. */
260    MDO_CHECK_CALL(Mdo_getRows(model, 2, row_indices, NULL, NULL, NULL, 0, &real_size)); 
261    int bgn3[2 + 1]; 
262    int * indices3 = (int *)calloc(real_size, sizeof(int));
263    double * values3 = (double *)calloc(real_size, sizeof(double));  
264    printf("Number of nonzeros = %d.\n", real_size);
265    
266    /* Step 8.2. Retrieve the rows. */
267    MDO_CHECK_CALL(Mdo_getRows(model, 2, row_indices, bgn3, indices3, values3, real_size, &real_size)); 
268    for (r = 0; r < 2; ++r)
269    {
270        for (e = bgn3[r]; e < bgn3[r + 1]; ++e)
271        {
272            printf("Element[%d, %d] = %e\n", row_indices[r], indices3[e], values3[e]);
273        }
274    }
275    free(indices3);
276    free(values3); 
277    
278    /* Query 2: Retrieve column 3 and column 5. */
279    printf("Query 2: Retrieve column 3 and column 5.\n");
280    int col_indices2[2] = {3, 5};
281    /* Step 8.3. Get the total number of NNZs first. */
282    MDO_CHECK_CALL(Mdo_getCols(model, 2, col_indices2, NULL, NULL, NULL, 0, &real_size)); 
283    int bgn4[2 + 1]; 
284    int * indices4 = (int *)calloc(real_size, sizeof(int));
285    double * values4 = (double *)calloc(real_size, sizeof(double));  
286    printf("Number of nonzeros = %d.\n", real_size);    
287    
288    /* Step 8.4. Retrieve the columns. */
289    MDO_CHECK_CALL(Mdo_getCols(model, 2, col_indices2, bgn4, indices4, values4, real_size, &real_size)); 
290    for (c = 0; c < 2; ++c)
291    {
292        for (e = bgn4[c]; e < bgn4[c + 1]; ++e)
293        {
294            printf("Element[%d, %d] = %e\n", indices4[e], col_indices2[c], values4[e]);
295        }
296    }
297    free(indices4);
298    free(values4); 
299
300    /*------------------------------------------------------------------*/
301    /* Step 9. Free the model.                                          */
302    /*------------------------------------------------------------------*/
303    printf("\nStep 9. Free the model.n\n");
304    /* Free the model. */
305    Mdo_freeMdl(&model);
306       
307    return (int)code;
308}