Solver input matrices for MILP
AnsweredIs there a way to get the final A, b, c, u, l matrices/vectors which are the results of a MILP model? Say for example you model the unit commitment problem as done here. Is there a way to get the corresponding A, b, c, u, l matrices/vectors out of this model so to have the problem as the following:
| Objective: | minimize cT x |
| Constraints: | A x = b (linear constraints) |
| l ≤ x ≤ u (bound constraints) | |
| some or all xj must take integer values (integrality constraints) |
Does gurobi provide those information?
Cheers,
Mohammadreza
-
Official comment
This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum. Or why not try our AI Gurobot?. -
Hi Mohammadreza,
You can use the Model methods getA() and getObjective() to get the constraint matrix and the objective. You can use this code to get the right-hand sides and constraint senses and the variable bounds and the corresponding variable types:
m.getAttr('RHS', m.getConstrs())
m.getAttr('Sense', m.getConstrs())
m.getAttr('LB', m.getVars())
m.getAttr('UB', m.getVars())
m.getAttr('VType', m.getVars())Cheers,
Matthias0 -
Hi Mathias
Thanks for your comments.
Something which is very strange is that if I call getAttr() codes before calling getA() the results is empty (for all) but if I them after getA(), I get the correct results. What I mean is that
RHS = model.getAttr('RHS')
Sense = model.getAttr('Sense')
LB = model.getAttr('LB')
UB = model.getAttr('UB')
VType = model.getAttr('VType')results in all variables being empty but just calling A = model.getA() before this piece of code results in the correct values for RHS, Sense, LB, UB and VType. Is this expected or a bug?
Cheers,
Mohammadreza
0 -
Hi Mohammadreza,
You need to call model.update() before querying these values. This is done automatically during model.optimize(), so you will only see this behavior if you try to get the values right after constructing the model.
Cheers,
Matthias0 -
Hi Matthias
May I ask if the A, and RHS matrix/vectors provided by getA(), RHS = model.getAttr('RHS'), already includes the bound constraints l ≤ x ≤ u (bound constraints) or they need to be imposed independently?
Cheers,
Mohammadreza
0 -
Hi Mohammadreza,
Variable bounds are not part of the constraint matrix A - this would just blow up the dimensions of this matrix. You would need to query them separately. In general, you should also define variable bounds not as constraints but instead use the proper functions to set the bounds per variable.
I suggest running a small toy problem with all kinds of variable and constraint types to see how this is working.
Cheers,
Matthias0 -
Hi Matthias
Thanks for the clarification. For some reasons, I am not able to recover the solution to the original model by using the extracted data from the model. Here is a pseudo code:
A = model.getA()
c = model.getAttr('Obj')
c = np.asarray(c)
b = model.getAttr('RHS', model.getConstrs())
b = np.asarray(b)
Sense = model.getAttr('Sense', model.getConstrs())
LB = model.getAttr('LB', model.getVars())
UB = model.getAttr('UB', model.getVars())
Vtype = model.getAttr('Vtype', model.getVars())This gives me the required data to create a standard MILP model as follow:
model1 = Model('MILP_MAT')
x = model1.addMVar(len(Vtype), vtype=Vtype)
model1.addMConstrs(A, x ,Sense, np.reshape(np.array(b),(b.shape[0],)))
model1.addConstr(x<=np.array(UB))
model1.addConstr(x>=np.array(LB))
model1.setObjective(c.T @ x)
model1.optimize()What I am expecting is to get the same solutions out of the two models, the original model (model) and the model constructed using extracted matrices/vectors. But, for some reason, I don't get the same solution:
difference = np.linalg.norm(np.sort(np.array(model1.x))-np.sort(np.array(model.x)))
The variable difference is not even close to zero in my case. I thought maybe the order of variables might not be the same and compared the sorted solutions.
Any ideas where I am doing wrong?
Cheers,
Mohammadreza
0 -
Further to my earlier comment, I forgot to mention that the objective value returned by the two models are identical.
0 -
It sounds like your problem has multiple optimal solutions. Gurobi is only guaranteed to return the same solution if the two models are exactly the same (see Is Gurobi Optimizer Deterministic?) and the models are solved with exactly the same parameters.
One difference between the two models is how you define the variable bounds. Based on the code you posted, you define the variable bounds for \( \texttt{model} \) using the LB and UB variable attributes. For \( \texttt{model1} \), you instead add the bounds as separate constraints:
model1.addConstr(x<=np.array(UB))
model1.addConstr(x>=np.array(LB))This can lead to Gurobi taking a different path to find the solution. Try setting variable bounds through the LB and UB attributes instead:
x = model1.addMVar(len(Vtype), lb=np.array(UB), ub=np.array(UB), vtype=Vtype)
If this doesn't help, use Model.write() to write out MPS files for your two models. In order for Gurobi to solve the two models exactly the same way, the contents of the two MPS files should be exactly the same.
0
Post is closed for comments.
Comments
9 comments