5.6.9. MISOCP Modeling and Optimization in Python¶
In this section, we will use MindOpt Python API to model and solve the mixed-integer second-order cone program in MIQCP Example II.
Import MindOpt Python package:
27"""
Create an optimization model model with the name “MISOCPEx1”:
32 # Step 1. Create a model.
Next, we call Model.addVar() to add five variables. Their lower bounds, upper bounds, types, names, and linear objective coefficients are all specified as arguments.
Note
To mark a variable as integer, set its type to 'I' via the vtype parameter.
38 # Add variables. The linear objective coefficients are specified directly.
39 x = []
40 x.append(model.addVar(lb=0.0, ub=10.0, obj=1.0, vtype='I', name="x0"))
41 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=2.0, vtype='I', name="x1"))
42 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='I', name="x2"))
43 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='C', name="x3"))
The optimization sense is then set to minimization.
46 # Set the optimization sense.
Note
Since the linear objective coefficients (1, 2, 1, 1, 0.5) are passed directly during variable creation via the obj parameter, there is no separate call to Model.setObjective().
We now add the constraints. With the Python API, linear and quadratic expressions can be built naturally using overloaded arithmetic operators.
Constraint c0: \(x_0 + x_1 + 2x_2 + 3x_3 \geq 1\)
Constraint c1: \(x_0 - x_2 + 6x_3 = 1\)
Quadratic (SOCP) Constraint c2: \(x_1^2 + x_2^2 - x_4^2 \leq 0\)
These are added to the model using Model.addConstr():
48
49 # Add constraints. Expressions are built using overloaded operators.
50 # c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
51 model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1.0, "c0")
52
53 # c1: 1 x0 - 1 x2 + 6 x3 = 1
54 model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3] == 1.0, "c1")
55
56 # c2: x_1^2 + x_2^2 - x_4^2 <= 0
Once the model is fully constructed, we call Model.optimize() to solve the problem:
59 # Step 3. Solve the problem.
We can check the solution status via the attribute Status, and retrieve the optimal objective value and solutions via attributes ObjVal and X. For other attribute information, please refer to Attributes.
67 # exist, making it necessary to check the SolCount property.
68 if model.status == MDO.OPTIMAL or model.status == MDO.SUB_OPTIMAL or model.solcount > 0:
69 print(f"Optimal objective value is: {model.objval}")
70 print("Decision variables:")
71 for v in model.getVars():
Finally, we free the model by calling Model.dispose().
84 # Step 5. Free the model.
The complete Python code is shown in mdo_misocp_ex1.py:
1"""
2/**
3 * Description
4 * -----------
5 *
6 * Formulation
7 * -----------
8 *
9 Minimize
10 * obj: 1 x0 + 2 x1 + 1 x2 + 1 x3 + 0.5 x_4
11 *
12 *
13 * Subject To
14 * c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
15 * c1 : 1 x0 - 1 x2 + 6 x3 = 1
16 * c2 : x_1^2 + x_2^2 - x_4^2 <= 0
17 * Bounds
18 * 0 <= x0 <= 10
19 * 0 <= x1
20 * 0 <= x2
21 * 0 <= x3
22 * 0 <= x4
23 * Integer
24 * x0, x1, x2
25 * End
26 */
27"""
28from mindoptpy import *
29
30if __name__ == "__main__":
31
32 # Step 1. Create a model.
33 model = Model("MISOCPEx1")
34
35 try:
36 # Step 2. Input model.
37
38 # Add variables. The linear objective coefficients are specified directly.
39 x = []
40 x.append(model.addVar(lb=0.0, ub=10.0, obj=1.0, vtype='I', name="x0"))
41 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=2.0, vtype='I', name="x1"))
42 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='I', name="x2"))
43 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='C', name="x3"))
44 x.append(model.addVar(lb=0.0, ub=float('inf'), obj=0.5, vtype='C', name="x4"))
45
46 # Set the optimization sense.
47 model.modelSense = MDO.MINIMIZE
48
49 # Add constraints. Expressions are built using overloaded operators.
50 # c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
51 model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1.0, "c0")
52
53 # c1: 1 x0 - 1 x2 + 6 x3 = 1
54 model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3] == 1.0, "c1")
55
56 # c2: x_1^2 + x_2^2 - x_4^2 <= 0
57 model.addConstr(x[1] * x[1] + x[2] * x[2] - x[4] * x[4] <= 0.0, "c2")
58
59 # Step 3. Solve the problem.
60 model.optimize()
61
62 # Step 4. Retrieve model status and solution.
63 # For MIP(MILP, MIQP, MIQCP) problems, if the solving process
64 # terminates early due to reasons such as timeout or interruption,
65 # the model status will indicate termination by timeout (or
66 # interruption, etc.). However, suboptimal solutions may still
67 # exist, making it necessary to check the SolCount property.
68 if model.status == MDO.OPTIMAL or model.status == MDO.SUB_OPTIMAL or model.solcount > 0:
69 print(f"Optimal objective value is: {model.objval}")
70 print("Decision variables:")
71 for v in model.getVars():
72 print(f"{v.VarName} = {v.X}")
73 else:
74 print("No feasible solution.")
75
76 except MindoptError as e:
77 print("Received Mindopt exception.")
78 print(f" - Code : {e.errno}")
79 print(f" - Reason : {e.message}")
80 except Exception as e:
81 print("Received other exception.")
82 print(f" - Reason : {e}")
83 finally:
84 # Step 5. Free the model.
85 model.dispose()