5.2.7. MILP Warmstart

When solving MILP problems, MindOpt provides methods to load an initial solution into the optimization model. Such an approach can often accelerate the solving process, known as the warm-start.

MindOpt provides two methods to warm start an optimization model: setting the Start attribute of variables or reading the solution from a .mst file. MindOpt supports not only warm starting by a complete solution but also accepts a partial solution. This means that users are allowed to specify values for only a subset of variables.

When warm-start is successfully enabled, MindOpt will show messages such as “accept new sol: obj 1 bnd vio 0 int vio 0 mipgap 1 time 0” to indicate an initial solution with objective value 1 is loaded. Otherwise, a warming message “initial solution is not accepted” will be displayed.

5.2.7.1. Set Variable Attribute Start

Warm-start can be enabled via setting the variable attribute Start. Calling methods in different programming languages are listed as follows:

Language

Method

C

MDOsetdblattrarray()

C++

MDOVar::set()

JAVA

MDOVar::setAttr()

Python

Var::setAttr()

Taking C language as an example:

67    /* Add variables. */
68    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0,         10.0, MDO_INTEGER, "x0"));
69    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 2.0, 0, MDO_INFINITY, MDO_INTEGER, "x1"));
70    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_INTEGER, "x2"));
71    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x3"));
72
73    /* Add constraints. */
74    CHECK_RESULT(MDOaddconstr(m, 4, row1_idx, row1_val, MDO_GREATER_EQUAL, 1.0, "c0"));
75    CHECK_RESULT(MDOaddconstr(m, 3, row2_idx, row2_val, MDO_EQUAL,         1.0, "c1"));
76
77    /* Add an initial solution */
78    int var_idx_start = 0;
79    int var_num = 4;
80    double var_val[] = { 1.0, 0.0, 0.0, 0.0 };

Complete example codes are provided in MdoMiloWarmstart.c.

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Mixed Integer Linear optimization (row-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Minimize
 11 *    obj: 1 x0 + 2 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 *  Integers
 21 *    x0 x1 x2
 22 *  End
 23 */
 24
 25#include <stdio.h>
 26#include <stdlib.h>
 27#include "Mindopt.h"
 28
 29/* Macro to check the return code */
 30#define RELEASE_MEMORY  \
 31    MDOfreemodel(m);    \
 32    MDOfreeenv(env);
 33#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d\n", res); exit(res); } }
 34#define MODEL_NAME  "MILP_WARMSTART"
 35#define MODEL_SENSE "ModelSense"
 36#define SOL_COUNT   "SolCount"
 37#define STATUS      "Status"
 38#define OBJ_VAL     "ObjVal"
 39#define X           "X"
 40
 41int main(void)
 42{
 43    /* Variables. */
 44    MDOenv *env;
 45    MDOmodel *m;
 46    double obj, x;
 47    int i, solcount, status;
 48
 49    /* Model data. */
 50    int    row1_idx[] = { 0,   1,   2,   3   };
 51    double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
 52    int    row2_idx[] = { 0,    2,   3   };
 53    double row2_val[] = { 1.0, -1.0, 6.0 };
 54
 55    /*------------------------------------------------------------------*/
 56    /* Step 1. Create a model and change the parameters.                */
 57    /*------------------------------------------------------------------*/
 58    CHECK_RESULT(MDOemptyenv(&env));
 59    CHECK_RESULT(MDOstartenv(env));
 60    CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));
 61
 62    /*------------------------------------------------------------------*/
 63    /* Step 2. Input model.                                             */
 64    /*------------------------------------------------------------------*/
 65    /* Change to minimization problem. */
 66    CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MINIMIZE));
 67
 68    /* Add variables. */
 69    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0,         10.0, MDO_INTEGER, "x0"));
 70    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 2.0, 0, MDO_INFINITY, MDO_INTEGER, "x1"));
 71    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_INTEGER, "x2"));
 72    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x3"));
 73
 74    /* Add constraints. */
 75    CHECK_RESULT(MDOaddconstr(m, 4, row1_idx, row1_val, MDO_GREATER_EQUAL, 1.0, "c0"));
 76    CHECK_RESULT(MDOaddconstr(m, 3, row2_idx, row2_val, MDO_EQUAL,         1.0, "c1"));
 77
 78    /* Add an initial solution */
 79    int var_idx_start = 0;
 80    int var_num = 4;
 81    double var_val[] = { 1.0, 0.0, 0.0, 0.0 };
 82    CHECK_RESULT(MDOsetdblattrarray(m, "Start", var_idx_start, var_num, &(*var_val)));
 83
 84    /*------------------------------------------------------------------*/
 85    /* Step 3. Solve the problem .                                      */
 86    /*------------------------------------------------------------------*/
 87    CHECK_RESULT(MDOoptimize(m));
 88
 89    /*------------------------------------------------------------------*/
 90    /* Step 4. Retrive model status and objective.                      */
 91    /* For MIP(MILP,MIQP, MIQCP) problems, if the solving process       */
 92    /* terminates early due to reasons such as timeout or interruption, */
 93    /* the model status will indicate termination by timeout (or        */
 94    /* interruption, etc.). However, suboptimal solutions may still     */
 95    /* exist, making it necessary to check the SolCount property.       */
 96    /*------------------------------------------------------------------*/
 97    CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
 98    CHECK_RESULT(MDOgetintattr(m, SOL_COUNT, &solcount));
 99    if (status == MDO_OPTIMAL || status == MDO_SUB_OPTIMAL || solcount != 0)
100    {
101        CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
102        printf("The optimal objective value is %f\n", obj);
103        for (int i = 0; i < 4; ++i) 
104        {
105            CHECK_RESULT(MDOgetdblattrelement(m, X, i, &x));
106            printf("x[%d] = %f\n", i, x);
107        }
108    } 
109    else 
110    {
111        printf("No feasible solution.\n");
112    }
113
114
115    /*------------------------------------------------------------------*/
116    /* Step 4. Free the model.                                          */
117    /*------------------------------------------------------------------*/
118    RELEASE_MEMORY;
119
120    return 0;
121}

Taking C++ as an example:

47        /* Add variables. */
48        std::vector<MDOVar> x;
49        x.push_back(model.addVar(0.0, 10.0,         1.0, MDO_INTEGER, "x0"));
50        x.push_back(model.addVar(0.0, MDO_INFINITY, 2.0, MDO_INTEGER, "x1"));
51        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_INTEGER, "x2"));
52        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_CONTINUOUS,"x3"));
53
54        /* Add constraints. */
55        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], MDO_GREATER_EQUAL, 1.0, "c0");
56        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3], MDO_EQUAL, 1.0, "c1");
57
58        /* Add an initial solution */
59        x[0].set(MDO_DoubleAttr_Start, 1);
60        x[1].set(MDO_DoubleAttr_Start, 0);
61        x[2].set(MDO_DoubleAttr_Start, 0);
62        x[3].set(MDO_DoubleAttr_Start, 0); 

Complete example codes are provided in MdoMiloWarmstart.cpp.

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Mixed Integer Linear optimization (row-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Minimize
 11 *    obj: 1 x0 + 2 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 *  Integers
 21 *    x0 x1 x2
 22 *  End
 23 */
 24
 25#include <iostream>
 26#include <vector>
 27#include "MindoptCpp.h"
 28
 29using namespace std;
 30
 31int main(void)
 32{
 33    /*------------------------------------------------------------------*/
 34    /* Step 1. Create a model and change the parameters.                */
 35    /*------------------------------------------------------------------*/
 36    MDOEnv env = MDOEnv();
 37    MDOModel model = MDOModel(env);
 38
 39    try
 40    {
 41        /*------------------------------------------------------------------*/
 42        /* Step 2. Input model.                                             */
 43        /*------------------------------------------------------------------*/
 44        /* Change to minimization problem. */
 45        model.set(MDO_IntAttr_ModelSense, MDO_MINIMIZE);
 46
 47        /* Add variables. */
 48        std::vector<MDOVar> x;
 49        x.push_back(model.addVar(0.0, 10.0,         1.0, MDO_INTEGER, "x0"));
 50        x.push_back(model.addVar(0.0, MDO_INFINITY, 2.0, MDO_INTEGER, "x1"));
 51        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_INTEGER, "x2"));
 52        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_CONTINUOUS,"x3"));
 53
 54        /* Add constraints. */
 55        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], MDO_GREATER_EQUAL, 1.0, "c0");
 56        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3], MDO_EQUAL, 1.0, "c1");
 57
 58        /* Add an initial solution */
 59        x[0].set(MDO_DoubleAttr_Start, 1);
 60        x[1].set(MDO_DoubleAttr_Start, 0);
 61        x[2].set(MDO_DoubleAttr_Start, 0);
 62        x[3].set(MDO_DoubleAttr_Start, 0); 
 63
 64        /*------------------------------------------------------------------*/
 65        /* Step 3. Solve the problem.                                       */
 66        /*------------------------------------------------------------------*/
 67        model.optimize();
 68
 69        /*------------------------------------------------------------------*/
 70        /* Step 4. Retrive model status and objective.                      */
 71        /* For MIP(MILP,MIQP, MIQCP) problems, if the solving process       */
 72        /* terminates early due to reasons such as timeout or interruption, */
 73        /* the model status will indicate termination by timeout (or        */
 74        /* interruption, etc.). However, suboptimal solutions may still     */
 75        /* exist, making it necessary to check the SolCount property.       */
 76        /*------------------------------------------------------------------*/
 77        if (model.get(MDO_IntAttr_Status) == MDO_OPTIMAL || model.get(MDO_IntAttr_Status) == MDO_SUB_OPTIMAL ||
 78            model.get(MDO_IntAttr_SolCount) != 0)
 79        {
 80            cout << "Optimal objective value is: " << model.get(MDO_DoubleAttr_ObjVal) << "." << endl;
 81            cout << "Decision variables:" << endl;
 82            int i = 0;
 83            for (auto v : x)
 84            {
 85                cout << "x[" << i << "] = " << v.get(MDO_DoubleAttr_X) << endl;
 86            }
 87        }
 88        else
 89        {
 90            cout<< "No feasible solution." << endl;
 91        }
 92    } 
 93    catch (MDOException& e) 
 94    { 
 95        cout << "Error code = " << e.getErrorCode() << endl;
 96        cout << e.getMessage() << endl;
 97    } 
 98    catch (...) 
 99    { 
100        cout << "Error during optimization." << endl;
101    }
102
103    return static_cast<int>(MDO_OKAY);
104}

5.2.7.2. Read A .mst File

Warm-Start can be enabled via a .mst file. Calling methods in different programming languages are listed as follows:

Language

Method

C

MDOread()

C++

MDOModel::read()

JAVA

MDOModel::read()

Python

Model::read()

A .mst file consists of multiple lines in the format of “variable value”. Here is an example:

1x0 1
2x1 0
3x2 0

MindOpt reads a .mst file and automatically sets the initial values of variables, eliminating the need for users to manually specify the Start attribute of variables. Users can list the initial values of all variables in the .mst file or only for a subset of variables. If the same variable appears multiple times in the file, the last assignment is used.

Note

When using the write function in MindOpt to save a solution to a .mst file, all continuous variables will be ignored. If users want to save the value of all variables, it is recommended to save the solution to a .sol file.

Taking Python as an example, read an initial solution from a .mst file:

38        # Add variables.
39        x = []
40        x.append(model.addVar(0.0,         10.0, 1.0, 'I', "x0"))
41        x.append(model.addVar(0.0, float('inf'), 2.0, 'I', "x1"))
42        x.append(model.addVar(0.0, float('inf'), 1.0, 'I', "x2"))
43        x.append(model.addVar(0.0, float('inf'), 1.0, 'C', "x3"))
44
45        # Read an initial solution from mst file
46        model.read("solution.mst")
47
48        # Add constraints.
49        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1, "c0")
50        model.addConstr(1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3] == 1, "c1")
51
52        # Step 3. Solve the problem and populate optimization result.
53        model.optimize() 

Complete example codes are provided in mdo_milo_ws.py.

 1"""
 2/**
 3 *  Description
 4 *  -----------
 5 *
 6 *  Mixed Integer Linear optimization (row-wise input).
 7 *
 8 *  Formulation
 9 *  -----------
10 *
11 *  Minimize
12 *    obj: 1 x0 + 2 x1 + 1 x2 + 1 x3
13 *  Subject To
14 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
15 *   c1 : 1 x0 - 1 x2 + 6 x3 = 1
16 *  Bounds
17 *    0 <= x0 <= 10
18 *    0 <= x1
19 *    0 <= x2
20 *    0 <= x3
21 *  Integers
22 *    x0 x1 x2
23 *  End
24 */
25"""
26from mindoptpy import *
27
28if __name__ == "__main__":
29
30    # Step 1. Create a model.
31    model = Model("MILP_WS")
32
33    try:
34        # Step 2. Input model.
35        # Change to minimization problem.
36        model.modelsense = MDO.MINIMIZE
37        
38        # Add variables.
39        x = []
40        x.append(model.addVar(0.0,         10.0, 1.0, 'I', "x0"))
41        x.append(model.addVar(0.0, float('inf'), 2.0, 'I', "x1"))
42        x.append(model.addVar(0.0, float('inf'), 1.0, 'I', "x2"))
43        x.append(model.addVar(0.0, float('inf'), 1.0, 'C', "x3"))
44
45        # Read an initial solution from mst file
46        model.read("solution.mst")
47
48        # Add constraints.
49        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1, "c0")
50        model.addConstr(1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3] == 1, "c1")
51
52        # Step 3. Solve the problem and populate optimization result.
53        model.optimize() 
54
55        # Step 4. Retrive model status and objective.
56        # For MIP(MILP,MIQP, MIQCP) problems, if the solving process
57        # terminates early due to reasons such as timeout or interruption,
58        # the model status will indicate termination by timeout (or
59        # interruption, etc.). However, suboptimal solutions may still
60        # exist, making it necessary to check the SolCount property.
61        if model.status == MDO.OPTIMAL or model.status == MDO.SUB_OPTIMAL or model.solcount !=0:
62            print(f"Optimal objective value is: {model.objval}")
63            print("Decision variables: ")
64            for v in x:
65                print(f"x[{v.VarName}] = {v.X}")
66        else:
67            print("No feasible solution.")
68    except MindoptError as e:
69        print("Received Mindopt exception.")
70        print(" - Code          : {}".format(e.errno))
71        print(" - Reason        : {}".format(e.message))
72    except Exception as e:
73        print("Received other exception.")
74        print(" - Reason        : {}".format(e))
75    finally:
76        # Step 4. Free the model.
77        model.dispose()