coin-or / Couenne

Convex Over and Under Envelopes for Nonlinear Estimation
Eclipse Public License 1.0
72 stars 8 forks source link

optimal solution wrong when using CPLEX as LP solver (optimal values is ok) #21

Open svigerske opened 5 years ago

svigerske commented 5 years ago

Issue created by migration from Trac.

Original creator: @svigerske

Original creation time: 2012-07-20 18:56:36

Assignee: somebody

Version:

Hi,

with the attached instance, Couenne seems to report a wrong optimal solution.

The problem as printed by Couenne (problem_print_level 3) is

min (((150*((-4+x_0)^2))+(390*((-10+x_1)^2))+(240*((-7+x_2)^2))+(70*((-3+x_3)^2))+(150*((-10+x_4)^2))+(390*((-15+x_5)^2))+(240*((-9+x_6)^2))+(70*((-3+x_7)^2)))+300*x_104+240*x_105+210*x_106+100*x_107+150*x_108+120*x_109+300*x_110+240*x_111+210*x_112+100*x_113
+150*x_114+120*x_115)
constraints:
-0 <= (x_104+x_1-x_0)
-0 <= (x_105+x_2-x_0)
-0 <= (x_106+x_3-x_0)
-0 <= (x_107+x_2-x_1)
-0 <= (x_108+x_3-x_1)
-0 <= (x_109+x_3-x_2)
-0 <= (x_104-x_1+x_0)
-0 <= (x_105-x_2+x_0)
-0 <= (x_106-x_3+x_0)
-0 <= (x_107-x_2+x_1)
-0 <= (x_108-x_3+x_1)
-0 <= (x_109-x_3+x_2)
-0 <= (x_110+x_5-x_4)
-0 <= (x_111+x_6-x_4)
-0 <= (x_112+x_7-x_4)
-0 <= (x_113+x_6-x_5)
-0 <= (x_114+x_7-x_5)
-0 <= (x_115+x_7-x_6)
-0 <= (x_110-x_5+x_4)
-0 <= (x_111-x_6+x_4)
-0 <= (x_112-x_7+x_4)
-0 <= (x_113-x_6+x_5)
-0 <= (x_114-x_7+x_5)
-0 <= (x_115-x_7+x_6)
(-x_17-x_14-x_11-x_8+x_0) = -0
(-x_18-x_15-x_12-x_9+x_0) = -0
(-x_19-x_16-x_13-x_10+x_0) = -0
(-x_29-x_26-x_23-x_20+x_1) = -0
(-x_30-x_27-x_24-x_21+x_1) = -0
(-x_31-x_28-x_25-x_22+x_1) = -0
(-x_41-x_38-x_35-x_32+x_2) = -0
(-x_42-x_39-x_36-x_33+x_2) = -0
(-x_43-x_40-x_37-x_34+x_2) = -0
(-x_53-x_50-x_47-x_44+x_3) = -0
(-x_54-x_51-x_48-x_45+x_3) = -0
(-x_55-x_52-x_49-x_46+x_3) = -0
(-x_65-x_62-x_59-x_56+x_4) = -0
(-x_66-x_63-x_60-x_57+x_4) = -0
(-x_67-x_64-x_61-x_58+x_4) = -0
(-x_77-x_74-x_71-x_68+x_5) = -0
(-x_78-x_75-x_72-x_69+x_5) = -0
(-x_79-x_76-x_73-x_70+x_5) = -0
(-x_89-x_86-x_83-x_80+x_6) = -0
(-x_90-x_87-x_84-x_81+x_6) = -0
(-x_91-x_88-x_85-x_82+x_6) = -0
(-x_101-x_98-x_95-x_92+x_7) = -0
(-x_102-x_99-x_96-x_93+x_7) = -0
(-x_103-x_100-x_97-x_94+x_7) = -0
(-27.5*y_116+x_8) <= -0
(-27.5*y_117+x_9) <= -0
(-27.5*y_118+x_10) <= -0
(-27.5*y_122+x_11) <= -0
(-27.5*y_123+x_12) <= -0
(-27.5*y_124+x_13) <= -0
(-27.5*y_128+x_14) <= -0
(-27.5*y_129+x_15) <= -0
(-27.5*y_130+x_16) <= -0
(-27.5*y_134+x_17) <= -0
(-27.5*y_135+x_18) <= -0
(-27.5*y_136+x_19) <= -0
(-27.5*y_116+x_20) <= -0
(-26.5*y_119+x_21) <= -0
(-26.5*y_120+x_22) <= -0
(-27.5*y_122+x_23) <= -0
(-26.5*y_125+x_24) <= -0
(-26.5*y_126+x_25) <= -0
(-27.5*y_128+x_26) <= -0
(-26.5*y_131+x_27) <= -0
(-26.5*y_132+x_28) <= -0
(-27.5*y_134+x_29) <= -0
(-26.5*y_137+x_30) <= -0
(-26.5*y_138+x_31) <= -0
(-27.5*y_117+x_32) <= -0
(-26.5*y_119+x_33) <= -0
(-28.5*y_121+x_34) <= -0
(-27.5*y_123+x_35) <= -0
(-26.5*y_125+x_36) <= -0
(-28.5*y_127+x_37) <= -0
(-27.5*y_129+x_38) <= -0
(-26.5*y_131+x_39) <= -0
(-28.5*y_133+x_40) <= -0
(-27.5*y_135+x_41) <= -0
(-26.5*y_137+x_42) <= -0
(-28.5*y_139+x_43) <= -0
(-27.5*y_118+x_44) <= -0
(-26.5*y_120+x_45) <= -0
(-28.5*y_121+x_46) <= -0
(-27.5*y_124+x_47) <= -0
(-26.5*y_126+x_48) <= -0
(-28.5*y_127+x_49) <= -0
(-27.5*y_130+x_50) <= -0
(-26.5*y_132+x_51) <= -0
(-28.5*y_133+x_52) <= -0
(-27.5*y_136+x_53) <= -0
(-26.5*y_138+x_54) <= -0
(-28.5*y_139+x_55) <= -0
(-27*y_116+x_56) <= -0
(-27*y_117+x_57) <= -0
(-27*y_118+x_58) <= -0
(-27*y_122+x_59) <= -0
(-27*y_123+x_60) <= -0
(-27*y_124+x_61) <= -0
(-27*y_128+x_62) <= -0
(-27*y_129+x_63) <= -0
(-27*y_130+x_64) <= -0
(-27*y_134+x_65) <= -0
(-27*y_135+x_66) <= -0
(-27*y_136+x_67) <= -0
(-27*y_116+x_68) <= -0
(-27.5*y_119+x_69) <= -0
(-27.5*y_120+x_70) <= -0
(-27*y_122+x_71) <= -0
(-27.5*y_125+x_72) <= -0
(-27.5*y_126+x_73) <= -0
(-27*y_128+x_74) <= -0
(-27.5*y_131+x_75) <= -0
(-27.5*y_132+x_76) <= -0
(-27*y_134+x_77) <= -0
(-27.5*y_137+x_78) <= -0
(-27.5*y_138+x_79) <= -0
(-27*y_117+x_80) <= -0
(-27.5*y_119+x_81) <= -0
(-28.5*y_121+x_82) <= -0
(-27*y_123+x_83) <= -0
(-27.5*y_125+x_84) <= -0
(-28.5*y_127+x_85) <= -0
(-27*y_129+x_86) <= -0
(-27.5*y_131+x_87) <= -0
(-28.5*y_133+x_88) <= -0
(-27*y_135+x_89) <= -0
(-27.5*y_137+x_90) <= -0
(-28.5*y_139+x_91) <= -0
(-27*y_118+x_92) <= -0
(-27.5*y_120+x_93) <= -0
(-28.5*y_121+x_94) <= -0
(-27*y_124+x_95) <= -0
(-27.5*y_126+x_96) <= -0
(-28.5*y_127+x_97) <= -0
(-27*y_130+x_98) <= -0
(-27.5*y_132+x_99) <= -0
(-28.5*y_133+x_100) <= -0
(-27*y_136+x_101) <= -0
(-27.5*y_138+x_102) <= -0
(-28.5*y_139+x_103) <= -0
(6*y_116-x_20+x_8) <= -0
(4*y_117-x_32+x_9) <= -0
(3.5*y_118-x_44+x_10) <= -0
(5*y_119-x_33+x_21) <= -0
(4.5*y_120-x_45+x_22) <= -0
(2.5*y_121-x_46+x_34) <= -0
(6*y_122+x_23-x_11) <= -0
(4*y_123+x_35-x_12) <= -0
(3.5*y_124+x_47-x_13) <= -0
(5*y_125+x_36-x_24) <= -0
(4.5*y_126+x_48-x_25) <= -0
(2.5*y_127+x_49-x_37) <= -0
(5.5*y_128-x_74+x_62) <= -0
(4.5*y_129-x_86+x_63) <= -0
(4.5*y_130-x_98+x_64) <= -0
(4*y_131-x_87+x_75) <= -0
(4*y_132-x_99+x_76) <= -0
(3*y_133-x_100+x_88) <= -0
(5.5*y_134+x_77-x_65) <= -0
(4.5*y_135+x_89-x_66) <= -0
(4.5*y_136+x_101-x_67) <= -0
(4*y_137+x_90-x_78) <= -0
(4*y_138+x_102-x_79) <= -0
(3*y_139+x_103-x_91) <= -0
(y_134+y_128+y_122+y_116) = 1
(y_135+y_129+y_123+y_117) = 1
(y_136+y_130+y_124+y_118) = 1
(y_137+y_131+y_125+y_119) = 1
(y_138+y_132+y_126+y_120) = 1
(y_139+y_133+y_127+y_121) = 1
variables:
x_0 [ 2.5 , 27.5 ]
x_1 [ 3.5 , 26.5 ]
x_2 [ 1.5 , 28.5 ]
x_3 [ 1 , 29 ]
x_4 [ 3 , 27 ]
x_5 [ 2.5 , 27.5 ]
x_6 [ 1.5 , 28.5 ]
x_7 [ 1.5 , 28.5 ]
x_8 [ 0 , inf ]
x_9 [ 0 , inf ]
x_10 [ 0 , inf ]
x_11 [ 0 , inf ]
x_12 [ 0 , inf ]
x_13 [ 0 , inf ]
x_14 [ 0 , inf ]
x_15 [ 0 , inf ]
x_16 [ 0 , inf ]
x_17 [ 0 , inf ]
x_18 [ 0 , inf ]
x_19 [ 0 , inf ]
x_20 [ 0 , inf ]
x_21 [ 0 , inf ]
x_22 [ 0 , inf ]
x_23 [ 0 , inf ]
x_24 [ 0 , inf ]
x_25 [ 0 , inf ]
x_26 [ 0 , inf ]
x_27 [ 0 , inf ]
x_28 [ 0 , inf ]
x_29 [ 0 , inf ]
x_30 [ 0 , inf ]
x_31 [ 0 , inf ]
x_32 [ 0 , inf ]
x_33 [ 0 , inf ]
x_34 [ 0 , inf ]
x_35 [ 0 , inf ]
x_36 [ 0 , inf ]
x_37 [ 0 , inf ]
x_38 [ 0 , inf ]
x_39 [ 0 , inf ]
x_40 [ 0 , inf ]
x_41 [ 0 , inf ]
x_42 [ 0 , inf ]
x_43 [ 0 , inf ]
x_44 [ 0 , inf ]
x_45 [ 0 , inf ]
x_46 [ 0 , inf ]
x_47 [ 0 , inf ]
x_48 [ 0 , inf ]
x_49 [ 0 , inf ]
x_50 [ 0 , inf ]
x_51 [ 0 , inf ]
x_52 [ 0 , inf ]
x_53 [ 0 , inf ]
x_54 [ 0 , inf ]
x_55 [ 0 , inf ]
x_56 [ 0 , inf ]
x_57 [ 0 , inf ]
x_58 [ 0 , inf ]
x_59 [ 0 , inf ]
x_60 [ 0 , inf ]
x_61 [ 0 , inf ]
x_62 [ 0 , inf ]
x_63 [ 0 , inf ]
x_64 [ 0 , inf ]
x_65 [ 0 , inf ]
x_66 [ 0 , inf ]
x_67 [ 0 , inf ]
x_68 [ 0 , inf ]
x_69 [ 0 , inf ]
x_70 [ 0 , inf ]
x_71 [ 0 , inf ]
x_72 [ 0 , inf ]
x_73 [ 0 , inf ]
x_74 [ 0 , inf ]
x_75 [ 0 , inf ]
x_76 [ 0 , inf ]
x_77 [ 0 , inf ]
x_78 [ 0 , inf ]
x_79 [ 0 , inf ]
x_80 [ 0 , inf ]
x_81 [ 0 , inf ]
x_82 [ 0 , inf ]
x_83 [ 0 , inf ]
x_84 [ 0 , inf ]
x_85 [ 0 , inf ]
x_86 [ 0 , inf ]
x_87 [ 0 , inf ]
x_88 [ 0 , inf ]
x_89 [ 0 , inf ]
x_90 [ 0 , inf ]
x_91 [ 0 , inf ]
x_92 [ 0 , inf ]
x_93 [ 0 , inf ]
x_94 [ 0 , inf ]
x_95 [ 0 , inf ]
x_96 [ 0 , inf ]
x_97 [ 0 , inf ]
x_98 [ 0 , inf ]
x_99 [ 0 , inf ]
x_100 [ 0 , inf ]
x_101 [ 0 , inf ]
x_102 [ 0 , inf ]
x_103 [ 0 , inf ]
x_104 [ 0 , inf ]
x_105 [ 0 , inf ]
x_106 [ 0 , inf ]
x_107 [ 0 , inf ]
x_108 [ 0 , inf ]
x_109 [ 0 , inf ]
x_110 [ 0 , inf ]
x_111 [ 0 , inf ]
x_112 [ 0 , inf ]
x_113 [ 0 , inf ]
x_114 [ 0 , inf ]
x_115 [ 0 , inf ]
y_116 binary
y_117 binary
y_118 binary
y_119 binary
y_120 binary
y_121 binary
y_122 binary
y_123 binary
y_124 binary
y_125 binary
y_126 binary
y_127 binary
y_128 binary
y_129 binary
y_130 binary
y_131 binary
y_132 binary
y_133 binary
y_134 binary
y_135 binary
y_136 binary
y_137 binary
y_138 binary
y_139 binary

I added the lines

for( int i = 0; i < bb.model().getNumCols(); ++i )
  if( bb.model().bestSolution()[i] != 0.0 )
    printf("%3d: %10g\n", i, bb.model().bestSolution()[i]);

in BonCouenne.cpp:356 and with lp_solver cplex I get

couenne: Optimal

    "Finished"
  0:        2.5
  1:        3.5
  2:        1.5
  3:          1
  4:          3
  5:        2.5
  6:        1.5
  7:        1.5
211:          1
212:          1
213:          1
214:          1
215:          1
216:          1

Thus, all continuous variables seem to be at their lower bound, which violates a linear constraint like (-x_17-x_14-x_11-x_8+x_0) = -0. Only the binary decisions seem to be correct.

With CLP as LP solver, I get

  0:    3.63524
  1:    9.63524
  2:    7.63524
  3:    3.63524
  4:    9.95435
  5:     14.295
  6:    9.45834
  7:    5.45435
  8:    3.63524
  9:    3.63524
 19:    3.63524
 20:    9.63524
 25:    9.63524
 30:    9.63524
 32:    7.63524
 37:    7.63524
 42:    7.63524
 48:    3.63524
 49:    3.63524
 53:    3.63524
 56:    9.95435
 57:    9.95435
 67:    9.95435
 68:     14.295
 73:     14.295
 78:     14.295
 80:    9.45834
 85:    9.45834
 90:    9.45834
 96:    5.45435
 97:    5.45435
101:    5.45435
104:          6
105:          4
107:          2
108:          6
109:          4
110:    4.34067
111:   0.496006
112:        4.5
113:    4.83668
114:    8.84067
115:    4.00399
116:          1
117:          1
126:          1
127:          1
136:          1
137:          1
140:   -0.36476
141:   -0.36476
142:    0.63524
143:    0.63524
144: -0.0456505
145:  -0.704977
146:   0.458344
147:    2.45435
148:    0.13305
149:    0.13305
150:   0.403529
151:   0.403529
152: 0.00208391
153:   0.496992
154:   0.210079
155:    6.02383
156:    9859.66
160:          4
161:         12
162:          8
164:   0.992012
165:          9
166:    9.67336
167:    17.6813
168:    8.00799
171:   -18.8648
172:   -23.8648
177:   -17.0457
179:    -13.205
182:   -18.0417
184:   -21.5457
197:       -1.5
198:       -1.5
208:   -0.83668
211:          1
212:          1
213:          1
214:          1
215:          1
216:          1

Btw, for running with CPLEX, I had to allow a small gap tolerance (e.g., 1%) to have it terminate timely.

I used CPLEX 12.4.

Stefan

svigerske commented 5 years ago

Attachment SLay04H.nl by @svigerske created at 2012-07-20 18:56:52

svigerske commented 5 years ago

Comment by @merraksh created at 2012-07-22 14:34:42

First, please note that there is a more robust way to save a solution, which uses the class CouenneRecordBestSol. This is in BonCouenne.cpp at the line:

CouenneRecordBestSol *rs = cp->getRecordBestSol();

I'm not sure whether the lines you added obtain the same effect, but you may want to check the content of *rs first.

Second, I cannot compare the .sol files as they are saved in binary format. The objective function value seems to be correct though: with both stable/0.4 and trunk and using an empty couenne.opt file (apart from the line lp_solver cplex), the version with Cplex finds a solution of value 9859.6599 and that with CLP finds one with value 9859.6596.

One puzzling part is that the debug version, with Cplex, has a false assert: in the trunk version it is due to an integer tolerance missed (whether by a solution returned by the LP solver I don't know), while in the stable/0.4 it is a "basis != __null" assert. When not using the debug version Cplex complains about some contradictory bounds on quite a few variables.

Regards, Pietro

svigerske commented 5 years ago

Comment by @svigerske created at 2012-07-22 15:19:27

I also get the correct optimal value, but the returned solution does not correspond to it.

In my original interface, I also use this CouenneRecordBestSol workaround, but it still gives an incorrect solution point.

Do you get a correct solution when using Couenne with CPLEX?

svigerske commented 5 years ago

Attachment cplex.txt by @merraksh created at 2012-07-23 11:00:15

last line of output when using different LP solvers.

svigerske commented 5 years ago

Comment by @merraksh created at 2012-07-23 11:06:49

I'm attaching the output I get when adding the following two lines right after BonCouenne.cpp:254:

  for (int i=0; i < rs -> getCardSol(); ++i)
    printf ("[%d %g] ", i, couenneSol [i]);

This will print out as the last line of output, and is exactly the same for Cplex and Clp. Note that I also get a couple of Cplex errors as follows:

CPX0000  CPLEX Error  1262: No basis exists.
svigerske commented 5 years ago

Comment by @svigerske created at 2012-07-23 13:48:51

Hi,

OK, it seems like I can reproduce this.

But why I get a garbage solution from bb.bestSolution(), where bb is a CouenneBab object?

From looking at the code I thought that CouenneBab::bestSolution() has extra been overwritten to take this CouenneRecordBestSol into account:

const double * CouenneBab::bestSolution() const {
  if(!problem_ ||
     !(problem_ -> getRecordBestSol ()) ||
     !(problem_ -> getRecordBestSol () -> getHasSol()) ||
     (((fabs (bestObj_) < COUENNE_INFINITY / 1e4) &&
       (problem_ -> getRecordBestSol () -> getVal () > bestObj_))))
    return bestSolution_;
  return problem_ -> getRecordBestSol () -> getSol ();
}

It's probably because the solution stored in CouenneBab has the same objective (and thus is not considered worse than the one in CouenneRecordBestSol).

But why the object stores an infeasible point in bestSolution_ at all?

Stefan

svigerske commented 5 years ago

Comment by @merraksh created at 2012-07-25 17:14:13

Cbc and Couenne have different points of access to the problem and its solutions, hence it might happen that Couenne finds a solution that does not get saved in Cbc (this is more likely to happen) or viceversa. This is why solutions are compared at the end, after the branch and bound.

It seems though that bestSolution_ contains an infeasible solution when using OsiCpx, if I understand your query. I have no idea why that happens. Could it be that OsiClp and OsiCpx have different ways to store a solution?

Pietro