How can I correctly retrieve/save the relaxed variables values associated with the best bound?
AnsweredHello everyone,
Gurobi 10.0.0 (win64) logging started Mon Nov 21 12:27:41 2022
Set parameter LogFile to value "IHLP.txt"
Gurobi Optimizer version 10.0.0 build v10.0.0rc2 (win64)
CPU model: AMD Ryzen 7 5700G with Radeon Graphics, instruction set [SSE2|AVX|AVX2]
Thread count: 8 physical cores, 16 logical processors, using up to 16 threads
Optimize a model with 2039 rows, 685 columns and 10222 nonzeros
Model fingerprint: 0x9f0dcc97
Variable types: 450 continuous, 235 integer (235 binary)
Coefficient statistics:
Matrix range [1e+00, 7e+01]
Objective range [8e+01, 2e+03]
Bounds range [1e+00, 1e+00]
RHS range [1e+00, 2e+02]
Presolve removed 656 rows and 78 columns
Presolve time: 0.02s
Presolved: 1383 rows, 607 columns, 6375 nonzeros
Variable types: 372 continuous, 235 integer (235 binary)
Root relaxation: objective 5.687528e+04, 1181 iterations, 0.03 seconds (0.06 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 56875.2786 0 103 - 56875.2786 - - 0s
0 0 64145.9785 0 121 - 64145.9785 - - 0s
0 0 64874.6793 0 71 - 64874.6793 - - 0s
0 0 66011.5827 0 67 - 66011.5827 - - 0s
0 2 66278.6128 0 68 - 66278.6128 - - 0s
Cutting planes:
User: 6
Lazy constraints: 8
Explored 1 nodes (2788 simplex iterations) in 0.41 seconds (0.36 work units)
Thread count was 16 (of 16 available processors)
Solution count 0
Node limit reached
Best objective -, best bound 6.655654040023e+04, gap -
User-callback calls 379, time in user-callback 0.14 sec
I'm currently working within the root \(NODCNT = 1\) and would like to know how to properly save the relaxed variable values associated with the best bound. So far I have the following snippet of code to do so
def Callback(m, where):
if where == GRB.Callback.MIPNODE and m.cbGet(GRB.Callback.MIPNODE_NODCNT) >= 0 and m.cbGet(GRB.Callback.MIPNODE_STATUS) == 2:
cbz = m.cbGetNodeRel(m._z)
cbY = m.cbGetNodeRel(m._Y)
cbX1 = m.cbGetNodeRel(m._X1)
cbX2 = m.cbGetNodeRel(m._X2)
cbH1 = m.cbGetNodeRel(m._H1)
cbH2 = m.cbGetNodeRel(m._H2)
cbF = m.cbGetNodeRel(m._F)
cbH0 = m.cbGetNodeRel(m._F0)
with open('Last_Relaxed_Solution.txt',mode = 'w') as file:
file.write('Bound Value:{:.2f}\n'.format(m.cbGet(GRB.Callback.MIPNODE_OBJBND)))
for i in V:
file.write('{:.0f}:{:.3f}\n'.format(i,cbz[i]))
file.write('\n')
for (i,j) in m._A:
if i < j and cbX1[i,j]+cbY[i,j]+cbX2[i,j] >= m._IntFeasTol:
file.write('{}\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}\n'.format((i,j),cbX1[i,j],cbY[i,j],cbX2[i,j],cbX1[i,j]+cbX2[i,j]+cbY[i,j]))
if i > j and cbX1[i,j]+cbY[j,i]+cbX2[i,j] >= m._IntFeasTol:
file.write('{}\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}\n'.format((i,j),cbX1[i,j],cbY[j,i],cbX2[i,j],cbX1[i,j]+cbX2[i,j]+cbY[j,i]))
At first I thought this was working well but then I realized that the bound and the variable values that are being saved correspond to the bound 66011.5827 instead of 6.655654040023e+04, also, why isn't that bound being printed in the log since it's better than 66278.6128?
Bound Value:66011.58
1 0.933
3 0.386
4 0.307
5 0.216
6 0.747
8 0.389
9 0.022
(0, 1) 0.933 0.000 0.000
(0, 3) 0.078 -0.000 -0.000
(0, 4) 0.307 -0.000 0.000
(0, 5) 0.216 0.000 0.000
(0, 6) 0.747 0.000 0.000
(0, 8) 0.368 -0.000 0.000
(0, 9) 0.022 -0.000 0.000
(1, 0) 0.000 0.000 0.933
(1, 2) 0.000 -0.000 0.933
(1, 3) 0.000 0.318 -0.000
(1, 4) 0.067 0.240 0.693
(1, 5) 0.067 0.149 0.784
(1, 6) 0.000 0.747 -0.000
(1, 8) -0.000 0.389 0.544
(1, 9) 0.000 0.022 -0.000
(2, 1) 0.933 -0.000 0.000
(2, 5) 0.216 -0.000 0.000
(2, 8) 0.389 -0.000 -0.000
(3, 0) 0.000 -0.000 0.078
(3, 1) -0.000 0.318 -0.000
(3, 4) 0.307 -0.000 0.386
(3, 5) 0.216 -0.000 -0.000
(3, 6) 0.427 0.321 0.065
(3, 7) 0.000 -0.000 0.386
(3, 8) 0.389 -0.000 0.386
(3, 9) 0.000 0.022 0.160
(4, 0) 0.000 -0.000 0.307
(4, 1) 0.693 0.240 0.067
(4, 3) 0.386 -0.000 0.307
(4, 5) 0.216 -0.000 0.307
(4, 6) 0.625 0.122 0.186
(4, 7) -0.000 0.000 0.307
(4, 8) 0.389 -0.000 0.307
(4, 9) -0.000 0.022 0.286
(5, 0) -0.000 0.000 0.216
(5, 1) 0.784 0.149 0.067
(5, 2) 0.000 -0.000 0.216
(5, 3) 0.000 -0.000 0.216
(5, 4) 0.307 -0.000 0.216
(5, 6) 0.000 0.216 -0.000
(5, 7) 0.000 0.000 0.195
(5, 8) 0.389 -0.000 0.216
(5, 9) -0.000 0.022 0.000
(6, 0) 0.000 0.000 0.747
(6, 1) -0.000 0.747 -0.000
(6, 3) 0.065 0.321 0.427
(6, 4) 0.186 0.122 0.625
(6, 5) -0.000 0.216 0.000
(6, 7) 0.000 -0.000 0.747
(6, 8) 0.000 0.389 0.000
(6, 9) 0.022 -0.000 0.747
(7, 3) 0.386 -0.000 0.000
(7, 4) 0.307 0.000 -0.000
(7, 5) 0.195 0.000 0.000
(7, 6) 0.747 -0.000 0.000
(7, 8) 0.389 0.000 -0.000
(8, 0) 0.000 -0.000 0.368
(8, 1) 0.544 0.389 0.000
(8, 2) 0.000 -0.000 0.389
(8, 3) 0.386 -0.000 0.389
(8, 4) 0.307 -0.000 0.389
(8, 5) 0.216 -0.000 0.389
(8, 6) 0.000 0.389 -0.000
(8, 7) -0.000 0.000 0.389
(8, 9) -0.000 0.022 0.000
(9, 0) 0.000 -0.000 0.022
(9, 1) 0.000 0.022 0.000
(9, 3) 0.160 0.022 0.000
(9, 4) 0.286 0.022 -0.000
(9, 5) 0.000 0.022 0.000
(9, 6) 0.747 -0.000 0.022
(9, 8) 0.000 0.022 0.000
-
Hi Nicolas,
Sorry for the late reply.
At first I thought this was working well but then I realized that the bound and the variable values that are being saved correspond to the bound 66011.5827 instead of 6.655654040023e+04, also, why isn't that bound being printed in the log since it's better than 66278.6128?
Callbacks are only called from the main thread. Thus, it is possible that a helper thread was able to improve the dual bound but it was not synced with the main thread yet and the optimization has been terminated due to hitting the nodecount limit. The best bound is then collected from all helper threads and reported in the log but without calling the callback again because the nodecount termination criterion is already met.
You could avoid this behavior by setting Threads=1. This however might hurt performance and has to be decided depending on your application. If it is for research only, then setting Threads=1 is definitely reasonable.
Best regards,
Jaromił0
Please sign in to leave a comment.
Comments
1 comment