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_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, 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_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, 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_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, 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, MDO_REAL_ATTR_LHS, 0,          1.0));
 79    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, MDO_REAL_ATTR_RHS, 0, MDO_INFINITY));
 80    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, MDO_REAL_ATTR_LHS, 1,          1.0));
 81    MDO_CHECK_CALL(Mdo_setRealAttrIndex(model, MDO_REAL_ATTR_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, MDO_REAL_ATTR_PRIMAL_OBJ_VAL, &val));
 97        printf("Optimizer terminated with an OPTIMAL status.\n");
 98        printf(" - Primal objective : %e.\n", val);
 99        MDO_CHECK_CALL(Mdo_getRealAttrArray(model, MDO_REAL_ATTR_PRIMAL_SOLN, 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    
 15#ifdef WIN32
 16#define MY_FOLDER "C:/Users/kuoling.huang/research/MDO/xxx/"
 17#else
 18#define MY_FOLDER "/Users/Shared/Research/MDO/xxx/"
 19#endif
 20
 21/* Macro to check the return code */
 22#define MDO_CHECK_CALL(MDO_CALL)                                    \
 23    code = MDO_CALL;                                                \
 24    if (code != MDO_OKAY)                                           \
 25    {                                                               \
 26        Mdo_explainResult(model, code, str);                        \
 27        Mdo_freeMdl(&model);                                        \
 28        fprintf(stderr, "===================================\n");   \
 29        fprintf(stderr, "Error   : code <%d>\n", code);             \
 30        fprintf(stderr, "Reason  : %s\n", str);                     \
 31        fprintf(stderr, "===================================\n");   \
 32        return (int)code;                                           \
 33    }
 34
 35int main(void)
 36{
 37    /* Variables. */
 38    char str[1024] = { "\0" };
 39    MdoMdl * model = NULL;
 40    MdoResult code = MDO_OKAY;
 41    MdoStatus status = MDO_UNKNOWN;
 42    int i, j, c, r, e;
 43
 44    const int csr_bgn[] = {0, 4, 7};
 45    const int csr_indices[] = 
 46    {
 47        0,   1,   2,   3,
 48        0,        2,   3  
 49    };
 50    const double csr_values[] = 
 51    {
 52        1.0, 1.0,  2.0, 3.0,
 53        1.0,      -1.0, 6.0
 54    };
 55
 56    const int csc_bgn[] = {0, 2, 3, 5, 7};
 57    const int csc_indices[] = 
 58    {
 59        0,  1,
 60        0,
 61        0,  1,
 62        0,  1
 63    };
 64    const double csc_values[] = 
 65    {
 66        1.0,   1.0,
 67        1.0, 
 68        2.0,  -1.0, 
 69        3.0,   6.0
 70    };
 71
 72    const double lhss[] = { 1, 1            };
 73    const double rhss[] = { 1, MDO_INFINITY };
 74    const char* row_names[] = { "cc0", NULL };
 75
 76    const double lbs[] =  {  0.0,          0.0,          0.0,          0.0 };
 77    const double ubs[] =  { 10.0, MDO_INFINITY, MDO_INFINITY, MDO_INFINITY };
 78    const double objs[] = {  1.0,          1.0,          1.0,          1.0 };
 79    const char* col_names[] = { "xx0", "", "xx2", NULL };
 80      
 81    /*------------------------------------------------------------------*/
 82    /* Step 1. Create a model and change the parameters.                */
 83    /*------------------------------------------------------------------*/
 84    printf(" Create a model and change the parameters.\n\n");
 85    /* Create an empty model. */
 86    MDO_CHECK_CALL(Mdo_createMdl(&model));
 87
 88    /*------------------------------------------------------------------*/
 89    /* Step 2. Input model.                                             */
 90    /*------------------------------------------------------------------*/
 91    printf("\nStep 2. Input model.\n\n");    
 92    /* The following three input methods will all result in the same model. */
 93#if 0
 94    /* Method 1. */
 95    /* Change to minimization problem. */
 96    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_YES));
 97    
 98    /* Add variables. */
 99    for (i = 0; i < 4; ++i)
100    {
101        MDO_CHECK_CALL(Mdo_addCol(model, lbs[i], ubs[i], objs[i], 0, NULL, NULL, col_names[i], MDO_NO));    
102    }    
103    /* Add two constraints. 
104     * The coefficients of the constraint matrix are inputted in a row-wise order.
105     */
106    MDO_CHECK_CALL(Mdo_addRows(model, 2, lhss, rhss, csr_bgn, csr_indices, csr_values, row_names));
107#endif
108#if 0
109    /* Method 2. */
110    /* Change to minimization problem. */
111    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_YES));
112    
113    /* Add variables and constraints. 
114     * The coefficients of the constraint matrix are inputted in a column-wise order.
115     */ 
116    MDO_CHECK_CALL(Mdo_addCols(model, 4, lbs, ubs, objs, csc_bgn, csc_indices, csc_values, col_names, NULL));    
117    
118    /* Change LHS values and RHS values. */
119    MDO_CHECK_CALL(Mdo_setRealAttrArray(model, MDO_REAL_ATTR_LHS, 0, 2, lhss));
120    MDO_CHECK_CALL(Mdo_setRealAttrArray(model, MDO_REAL_ATTR_RHS, 0, 2, rhss));
121#endif    
122#if 1
123    /* Method 3. */
124    /* Add four variables and two constraints in one shot.
125     * The coefficients of the constraint matrix are inputted in a column-wise order.
126     */
127    MDO_CHECK_CALL(Mdo_loadModel(model, 4, 2, csc_bgn, csc_indices, csc_values, 
128        lbs, ubs, objs, NULL, 0.0, MDO_YES, lhss, rhss, col_names, row_names));
129#endif
130    MdoI32 idx[2] = { 0, 1 };
131    MdoReal tmp[2];
132    Mdo_getLhss(model, 2, idx, tmp);
133    for (int i = 0; i < 2; ++i)
134    {
135        printf("%d has LHS = %e\n", i, tmp[i]);
136    }
137    Mdo_getRhss(model, 2, idx, tmp);
138    for (int i = 0; i < 2; ++i)
139    {
140        printf("%d has RHS = %e\n", i, tmp[i]);
141    }
142
143    /*------------------------------------------------------------------*/
144    /* Step 3. Solve the problem and populate the result.               */
145    /*------------------------------------------------------------------*/
146    printf("\nStep 3. Solve the problem and populate the result.\n\n");
147    Mdo_setIntParam(model, MDO_INT_PARAM_METHOD, 2);
148    Mdo_setIntParam(model, MDO_INT_PARAM_NUM_THREADS, 1);
149
150    /* Solve the problem. */
151    MDO_CHECK_CALL(Mdo_solveProb(model));
152    Mdo_displayResults(model);
153#ifdef WRITE_LP    
154    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step3.lp"));   
155#endif
156
157
158    Mdo_setIntParam(model, MDO_INT_PARAM_PRESOLVE, 0);
159    double newobj[4];
160    int indices[] = { 0, 1, 2, 3 };
161    MDO_CHECK_CALL(Mdo_getObjs(model, 4, indices, newobj));
162    for (int j = 0; j < 4; ++j)
163    {
164        newobj[j] = -newobj[j];
165    }
166#if 0
167    Mdo_setMaxObjSense(model);
168    MDO_CHECK_CALL(Mdo_setObjs(model, 4, indices, newobj));
169#else
170    MDO_CHECK_CALL(Mdo_loadModel(model, 4, 2, csc_bgn, csc_indices, csc_values,
171        lbs, ubs, newobj, NULL, 0.0, MDO_YES, lhss, rhss, col_names, row_names));
172#endif
173
174    MDO_CHECK_CALL(Mdo_solveProb(model));
175    Mdo_displayResults(model);
176#ifdef WRITE_LP    
177    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step3-1.lp"));
178#endif
179
180
181    /*------------------------------------------------------------------*/
182    /* Step 4. Add another two variables and then resolve the problem.  */
183    /*------------------------------------------------------------------*/
184    printf("\nStep 4. Add another two variables and then resolve the problem.\n\n");
185    /* Add another two variables. */    
186    double lbs2[] =  { 0,            -2           };
187    double ubs2[] =  { MDO_INFINITY, MDO_INFINITY };
188    double objs2[] = { 1,            -1           };
189
190    int col_bgn[] = {0, 2, 4 };
191    int col_indices[] =   
192    {
193        0, 1, 
194        0, 1
195    };
196    double col_values[] = 
197    {
198        1, 2, 
199        3, 4
200    };
201    const char * col_names2[] = { "y1", "y2" };
202    
203    MDO_CHECK_CALL(Mdo_addCols(model, 2, lbs2, ubs2, objs2, col_bgn, col_indices, col_values, NULL/*col_names2*/, NULL));
204        
205    /* Solve the problem. */
206    MDO_CHECK_CALL(Mdo_solveProb(model));
207    Mdo_displayResults(model);
208#ifdef WRITE_LP
209    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step4.lp"));   
210#endif
211      
212    /*------------------------------------------------------------------*/
213    /* Step 5. Add another two constraints and then resolve the problem.*/
214    /*------------------------------------------------------------------*/
215    printf("\nStep 5. Add another two constraints and then resolve the problem.\n\n");
216    int bgn2[] = {0, 3, 6};
217    int indices2[] = 
218    {
219        0,   1,        3,
220        0,        2,   3  
221    };
222    double values2[] = 
223    {
224        1.0, 1.0,      -2.0,
225        1.0,      -2.0, 6.0
226    };    
227    
228    const double lhss2[] = { 0, 1            };
229    const double rhss2[] = { 2, MDO_INFINITY };
230
231    const char* row_names2[] = { "cc2", "" };
232    
233    /* Add two constraints. */
234    MDO_CHECK_CALL(Mdo_addRows(model, 2, lhss2, rhss2, bgn2, indices2, values2, row_names2));
235 
236    /* Solve the problem. */
237    MDO_CHECK_CALL(Mdo_solveProb(model));
238    Mdo_displayResults(model);
239#ifdef WRITE_LP    
240    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step5.lp"));   
241#endif
242
243    /*------------------------------------------------------------------*/
244    /* Step 6. Obtain optimal basis.                                    */
245    /*------------------------------------------------------------------*/       
246    printf("\nStep 6. Obtain optimal basis.\n\n");
247    int * row_basis = (int *)calloc(4, sizeof(int));
248    int * col_basis = (int *)calloc(6, sizeof(int));    
249    MDO_CHECK_CALL(Mdo_getIntAttrArray(model, MDO_INT_ATTR_ROW_BASIS, 0, 4, row_basis));
250    MDO_CHECK_CALL(Mdo_getIntAttrArray(model, MDO_INT_ATTR_COL_BASIS, 0, 6, col_basis));
251    /*
252     * isFree = 0,
253     * basic = 1,
254     * atUpperBound = 2,
255     * atLowerBound = 3,
256     * superBasic = 4,
257     * isFixed = 5,
258     */
259    for (i = 0; i < 4; ++i)
260    {
261        printf("Row [%d] status: %d\n", i, row_basis[i]);
262    }
263    for (j = 0; j < 6; ++j)
264    {
265        printf("Col [%d] status: %d\n", j, col_basis[j]);
266    }
267#ifdef WRITE_LP   
268    MDO_CHECK_CALL(Mdo_writeSoln(model, MY_FOLDER "Step6.bas"));   
269    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER "Step6.lp"));   
270#endif
271
272    /*------------------------------------------------------------------*/
273    /* Step 7. Warm-start Simplex.                                      */
274    /*------------------------------------------------------------------*/       
275    printf("\nStep 7. Warm-start Simplex.\n\n");
276
277    /* Change the objective coefficients. */
278    int obj_indices[] =   { 1, 2 };
279    double obj_values[] = { 3, -3 };
280    MDO_CHECK_CALL(Mdo_setObjs(model, 2, obj_indices, obj_values));
281   
282    /* Load the basis. */
283    MDO_CHECK_CALL(Mdo_setIntAttrArray(model, MDO_INT_ATTR_ROW_BASIS, 0, 4, row_basis));
284    MDO_CHECK_CALL(Mdo_setIntAttrArray(model, MDO_INT_ATTR_COL_BASIS, 0, 6, col_basis));
285
286    /* Solve the problem. */
287    printf("Resolve with warm-start basis.\n");
288    Mdo_setIntParam(model, MDO_INT_PARAM_PRESOLVE, 0);
289    Mdo_setIntParam(model, MDO_INT_PARAM_METHOD, 0);
290    MDO_CHECK_CALL(Mdo_solveProb(model));
291    Mdo_displayResults(model);
292
293    free(row_basis);
294    free(col_basis);
295
296    /*------------------------------------------------------------------*/
297    /* Step 8. Model query.                                             */
298    /*------------------------------------------------------------------*/    
299    printf("\nStep 8. Model query.\n\n");
300    /* Query 1: Retrieve first two rows. */
301    printf("Query 1: Retrieve first two rows.\n");
302    int row_indices[2] = {0, 1};
303    int real_size;
304    /* Step 8.1. Get the total number of NNZs first. */
305    MDO_CHECK_CALL(Mdo_getRows(model, 2, row_indices, NULL, NULL, NULL, 0, &real_size)); 
306    int bgn3[2 + 1]; 
307    int * indices3 = (int *)calloc(real_size, sizeof(int));
308    double * values3 = (double *)calloc(real_size, sizeof(double));  
309    printf("Number of nonzeros = %d.\n", real_size);
310    
311    /* Step 8.2. Retrieve the rows. */
312    MDO_CHECK_CALL(Mdo_getRows(model, 2, row_indices, bgn3, indices3, values3, real_size, &real_size)); 
313    for (r = 0; r < 2; ++r)
314    {
315        for (e = bgn3[r]; e < bgn3[r + 1]; ++e)
316        {
317            printf("Element[%d, %d] = %e\n", row_indices[r], indices3[e], values3[e]);
318        }
319    }
320    free(indices3);
321    free(values3); 
322    
323    /* Query 2: Retrieve column 3 and column 5. */
324    printf("Query 2: Retrieve column 3 and column 5.\n");
325    int col_indices2[2] = {3, 5};
326    /* Step 8.3. Get the total number of NNZs first. */
327    MDO_CHECK_CALL(Mdo_getCols(model, 2, col_indices2, NULL, NULL, NULL, 0, &real_size)); 
328    int bgn4[2 + 1]; 
329    int * indices4 = (int *)calloc(real_size, sizeof(int));
330    double * values4 = (double *)calloc(real_size, sizeof(double));  
331    printf("Number of nonzeros = %d.\n", real_size);    
332    
333    /* Step 8.4. Retrieve the columns. */
334    MDO_CHECK_CALL(Mdo_getCols(model, 2, col_indices2, bgn4, indices4, values4, real_size, &real_size)); 
335    for (c = 0; c < 2; ++c)
336    {
337        for (e = bgn4[c]; e < bgn4[c + 1]; ++e)
338        {
339            printf("Element[%d, %d] = %e\n", indices4[e], col_indices2[c], values4[e]);
340        }
341    }
342    free(indices4);
343    free(values4); 
344
345    /*------------------------------------------------------------------*/
346    /* Step 9. Change row/col name and then delete rows and columns.    */
347    /*------------------------------------------------------------------*/
348    char buf[256];
349    int itmp;
350    MDO_CHECK_CALL(Mdo_getRowName(model, 1, buf, 256, &itmp));
351    printf("Row 1 has name = %s\n", buf);
352    snprintf(buf, 256, "row_%d", 999);
353    itmp = 1;
354    char * pbuf[] = { buf };
355    MDO_CHECK_CALL(Mdo_setRowNames(model, 1, &itmp, pbuf));
356    MDO_CHECK_CALL(Mdo_getRowName(model, 1, buf, 256, &itmp));
357    printf("Updated Row 1 has name = %s (idx: %d)\n", buf, Mdo_getRowIndex(model, buf));
358    printf("Unknown index = %d\n", Mdo_getRowIndex(model, ""));
359
360    MDO_CHECK_CALL(Mdo_getColName(model, 1, buf, 256, &itmp));
361    printf("Col 1 has name = %s\n", buf);
362    snprintf(buf, 256, "col_%d", 999);
363    itmp = 1;
364    MDO_CHECK_CALL(Mdo_setColNames(model, 1, &itmp, pbuf));
365    MDO_CHECK_CALL(Mdo_getColName(model, 1, buf, 256, &itmp));
366    printf("Updated Col has name = %s (idx: %d)\n", buf, Mdo_getColIndex(model, buf));
367    printf("Unknown index = %d\n", Mdo_getColIndex(model, ""));
368
369
370#ifdef WRITE_LP    
371    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step9.lp"));
372#endif
373
374    int delrow[2] = { 3, 1 };
375    MDO_CHECK_CALL(Mdo_deleteRows(model, 2, delrow));
376#ifdef WRITE_LP    
377    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step9_delrow1.lp"));
378#endif
379    int delcol[2] = { 1, 3 };
380    MDO_CHECK_CALL(Mdo_deleteCols(model, 2, delcol));
381#ifdef WRITE_LP    
382    MDO_CHECK_CALL(Mdo_writeProb(model, MY_FOLDER"Step9_delcol1.lp"));
383#endif
384
385    /*------------------------------------------------------------------*/
386    /* Step 10. Free the model.                                         */
387    /*------------------------------------------------------------------*/
388    printf("\nStep 10. Free the model.n\n");
389    /* Free the model. */
390    Mdo_freeMdl(&model);
391
392    return (int)code;
393}