1 // (C) Copyright Francois Margot and Carnegie Mellon University 2011
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License (EPL).
4 //
5 // Authors :
6 // Francois Margot, Tepper School of Business, Carnegie Mellon University,
7 //
8 // Date : 3/31/2011
9 
10 #include<cstdio>
11 #include<cstdlib>
12 #include<cstring>
13 #include<cmath>
14 
15 #include "CoinHelperFunctions.hpp"
16 
17 #include "CouenneProblem.hpp"
18 #include "CouenneRecordBestSol.hpp"
19 
20 using namespace Couenne;
21 
22 //#define TRACE
23 
24 /*************************************************************/
25 /** Default constructor. */
CouenneRecordBestSol()26 CouenneRecordBestSol::CouenneRecordBestSol() {
27 
28   cardInitDom = -1;
29   initIsInt = NULL;
30   initDomLb = NULL;
31   initDomUb = NULL;
32 
33   hasSol = false;
34   cardSol = -1;
35   sol = NULL;
36   val = -1;
37   maxViol = -1;
38 
39   cardModSol = -1;
40   modSol = NULL;
41   modSolVal = -1;
42   modSolMaxViol = -1;
43 }
44 
45 /*************************************************************/
46 // copy constructor
CouenneRecordBestSol(const CouenneRecordBestSol & other)47 CouenneRecordBestSol::CouenneRecordBestSol(const CouenneRecordBestSol &other) {
48 
49   cardInitDom = other.cardInitDom;
50   if(cardInitDom > -1) {
51     initIsInt = new bool[other.cardInitDom];
52     initDomLb = new CouNumber[other.cardInitDom];
53     initDomUb = new CouNumber[other.cardInitDom];
54 
55     CoinCopyN(other.initIsInt, cardInitDom, initIsInt);
56     CoinCopyN(other.initDomLb, cardInitDom, initDomLb);
57     CoinCopyN(other.initDomUb, cardInitDom, initDomUb);
58   }
59   else {
60     initIsInt = NULL;
61     initDomLb = NULL;
62     initDomUb = NULL;
63   }
64 
65   for(unsigned int i=0; i<other.listInt.size(); i++) {
66     listInt.push_back(other.listInt[i]);
67   }
68 
69   hasSol = other.hasSol;
70   cardSol = other.cardSol;
71   val = other.val;
72   maxViol = other.maxViol;
73 
74   if(other.sol != NULL) {
75     sol = new double[other.cardSol];
76     CoinCopyN(other.sol, cardSol, sol);
77   }
78   else {
79     sol = NULL;
80   }
81 
82   if (other.modSol != NULL) {
83     modSol = new double[other.cardSol];
84     CoinCopyN(other.modSol, cardSol, modSol);
85   }
86   else {
87     modSol = NULL;
88   }
89   cardModSol = other.cardModSol;
90   modSolVal = other.modSolVal;
91   modSolMaxViol = other.modSolMaxViol;
92 }
93 
94 /*************************************************************/
95 /** Destructor. */
~CouenneRecordBestSol()96 CouenneRecordBestSol::~CouenneRecordBestSol(){
97 
98   if(cardInitDom > -1) {
99     delete[] initIsInt;
100     delete[] initDomLb;
101     delete[] initDomUb;
102   }
103 
104   if(sol != NULL) {
105     delete[] sol;
106   }
107 
108   if(modSol != NULL) {
109     delete[] modSol;
110   }
111 }
112 
113 /*****************************************************************************/
setInitIsInt(const bool * givenIsInt,const int givenCard)114 void CouenneRecordBestSol::setInitIsInt(const bool *givenIsInt,
115 					const int givenCard) {
116 
117   if(initIsInt == NULL) {
118     if(cardInitDom == -1) {
119       cardInitDom = givenCard;
120     }
121     if(givenCard != cardInitDom) {
122       printf("### ERROR: CouenneRecordBestSol::setInitIsInt(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
123       exit(1);
124     }
125     initIsInt = new bool[givenCard];
126   }
127   else {
128     if(givenCard != cardInitDom) {
129       printf("### ERROR: CouenneRecordBestSol::setInitIsInt(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
130       exit(1);
131     }
132   }
133   CoinCopyN(givenIsInt, givenCard, initIsInt);
134 
135   listInt.empty();
136   for(int i=0; i<givenCard; i++) {
137     if(initIsInt[i]) {
138       listInt.push_back(i);
139     }
140   }
141 } /* setInitIsInt */
142 
143 /*****************************************************************************/
setInitDomLb(const CouNumber * givenLb,const int givenCard)144 void CouenneRecordBestSol::setInitDomLb(const CouNumber *givenLb,
145 					const int givenCard) {
146   if(initDomLb == NULL) {
147     if(cardInitDom == -1) {
148       cardInitDom = givenCard;
149     }
150     if(givenCard != cardInitDom) {
151       printf("### ERROR: CouenneRecordBestSol::setInitDomLb(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
152       exit(1);
153     }
154     initDomLb = new CouNumber[givenCard];
155   }
156   else {
157     if(givenCard != cardInitDom) {
158       printf("### ERROR: CouenneRecordBestSol::setInitDomLb(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
159       exit(1);
160     }
161   }
162   CoinCopyN(givenLb, givenCard, initDomLb);
163 } /* setInitDomLb */
164 
165 /*****************************************************************************/
setInitDomUb(const CouNumber * givenUb,const int givenCard)166 void CouenneRecordBestSol::setInitDomUb(const CouNumber *givenUb,
167 					const int givenCard) {
168   if(initDomUb == NULL) {
169     if(cardInitDom == -1) {
170       cardInitDom = givenCard;
171     }
172     if(givenCard != cardInitDom) {
173       printf("### ERROR: CouenneRecordBestSol::setInitDomUb(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
174       exit(1);
175     }
176     initDomUb = new CouNumber[givenCard];
177   }
178   else {
179     if(givenCard != cardInitDom) {
180       printf("### ERROR: CouenneRecordBestSol::setInitDomUb(): cardInitDom: %d  givenCard: %d\n", cardInitDom, givenCard);
181       exit(1);
182     }
183   }
184   CoinCopyN(givenUb, givenCard, initDomUb);
185 } /* setInitDomUb */
186 
187 /*****************************************************************************/
setHasSol(const bool givenHasSol)188 void CouenneRecordBestSol::setHasSol(const bool givenHasSol) {
189   hasSol = givenHasSol;
190 }
191 
192 /*****************************************************************************/
setCardSol(const int givenCard)193 void CouenneRecordBestSol::setCardSol(const int givenCard) {
194   cardSol = givenCard;
195 }
196 
197 /*****************************************************************************/
setSol(const double * givenSol,const int givenCard,const double givenMaxViol)198 void CouenneRecordBestSol::setSol(const double *givenSol, const int givenCard,
199                                   const double givenMaxViol) {
200   if(sol == NULL) {
201     cardSol = givenCard;
202     sol = new double[givenCard];
203     if(modSol == NULL) {
204       modSol = new double[givenCard];
205     }
206   }
207   else {
208     if(givenCard != cardSol) {
209       //printf("CouenneRecordBestSol::setSol(): ### ERROR: givenCard: %d  cardSol: %d", givenCard, cardSol);
210       //exit(1);
211 
212 	double *newSol = new double [givenCard];
213 	CoinCopyN (givenSol, givenCard, newSol);
214 	delete [] modSol;
215 	modSol = newSol;
216 	cardSol = givenCard;
217     }
218   }
219   CoinCopyN(givenSol, givenCard, sol);
220   maxViol = givenMaxViol;
221 
222 #ifdef TRACE
223   printf("CouenneRecordBestSol::setSol(): New solution set\n");
224 #endif
225 
226 } /* setSol */
227 
228 /*****************************************************************************/
setVal(const double givenVal)229 void CouenneRecordBestSol::setVal(const double givenVal) {
230 
231 #ifdef TRACE
232   printf("CouenneRecordBestSol::setVal(): set to %10.6f\n", givenVal);
233 #endif
234 
235   val = givenVal;
236   hasSol = true;
237 }
238 
239 /*****************************************************************************/
update(const double * givenSol,const int givenCard,const double givenVal,const double givenMaxViol)240 void CouenneRecordBestSol::update(const double *givenSol, const int givenCard,
241 			   const double givenVal, const double givenMaxViol) {
242   if (!hasSol || (givenVal < val)) {
243     setSol(givenSol, givenCard, givenMaxViol);
244     setVal(givenVal);
245   }
246 } /* update */
247 
248 /*****************************************************************************/
update()249 void CouenneRecordBestSol::update() {
250   if(modSol == NULL) {
251     printf(" CouenneRecordBestSol::update(): ### ERROR: modSol == NULL\n");
252     exit(1);
253   }
254 
255   update(modSol, cardModSol, modSolVal, modSolMaxViol);
256 } /* update */
257 
258 /*****************************************************************************/
compareAndSave(const double * solA,const double solAVal,const double solAMaxViol,const bool solAIsFeas,const double * solB,const double solBVal,const double solBMaxViol,const bool solBIsFeas,const int cardSol,const double precision)259 int CouenneRecordBestSol::compareAndSave(const double *solA, const double solAVal, const double solAMaxViol, const bool solAIsFeas,
260 					 const double *solB, const double solBVal, const double solBMaxViol, const bool solBIsFeas,
261 					 const int cardSol,
262 					 const double precision) {
263   int retval = -2;
264   if(solBIsFeas) {
265     if(solAIsFeas) {
266       if(solAVal < solBVal - precision) {
267 	retval = 0;
268       }
269       else {
270 	retval = 1;
271       }
272     }
273     else {
274       retval = 1;
275     }
276   }
277   else {
278     if(solAIsFeas) {
279       retval = 0;
280     }
281     else { // both solutions are infeasible; select the one with min viol.
282       if(solAVal < 1e49) {
283 	if(solBVal < 1e49) {
284 	  if(solAMaxViol < solBMaxViol) {
285 	    retval = 0;
286 	  }
287 	  else {
288 	    retval = 1;
289 	  }
290 	}
291 	else {
292 	  retval = 0;
293 	}
294       }
295       else {
296 	if(solBVal < 1e49) {
297 	  retval = 1;
298 	}
299 	else {
300 	  retval = -1;
301 	}
302       }
303     }
304   }
305 
306   switch (retval) {
307     case 0: update(solA, cardSol, solAVal, solAMaxViol); break;
308     case 1: update(solB, cardSol, solBVal, solBMaxViol); break;
309     case -1: break;
310     default: printf("CouenneRecordBestSol::compareAndSave(): ### ERROR: retval: %d\n",
311 		    retval); break;
312   }
313 
314   return(retval);
315 } /* compareAndSave */
316 
317 /*****************************************************************************/
getModSol(const int expectedCard)318 double * CouenneRecordBestSol::getModSol(const int expectedCard) {
319   if(modSol == NULL) {
320     cardModSol = expectedCard;
321     modSol = new double[expectedCard];
322   }
323   else {
324     if(expectedCard != cardModSol) {
325       printf("CouenneRecordBestSol::getModSol(): ### ERROR: expectedCard: %d  cardModSol: %d", expectedCard, cardModSol);
326       exit(1);
327     }
328   }
329   return modSol;
330 } /* getModSol */
331 
332 /*****************************************************************************/
setModSol(const double * givenModSol,const int givenModCard,const double givenModVal,const double givenModMaxViol)333 void CouenneRecordBestSol::setModSol(const double *givenModSol,
334 			      const int givenModCard,
335 			      const double givenModVal,
336 			      const double givenModMaxViol) {
337 
338   if(givenModSol != NULL) {
339     if(modSol == NULL) {
340       cardModSol = givenModCard;
341       modSol = new double[givenModCard];
342     }
343     else {
344       if(givenModCard != cardModSol) {
345 	// printf("CouenneRecordBestSol::setModSol(): ### ERROR: givenModCard: %d  cardModSol: %d", givenModCard, cardModSol);
346 	// exit(1);
347 
348 	double *newModSol = new double [givenModCard];
349 	CoinCopyN (givenModSol, givenModCard, newModSol);
350 	delete [] modSol;
351 	modSol = newModSol;
352 	cardModSol = givenModCard;
353       }
354     }
355     CoinCopyN(givenModSol, givenModCard, modSol);
356   }
357   modSolVal = givenModVal;
358   modSolMaxViol = givenModMaxViol;
359 } /* setModSol */
360 
361 /*****************************************************************************/
printSol(FILE * fsol) const362 void CouenneRecordBestSol::printSol(FILE *fsol) const {
363 
364   if(sol != NULL) {
365     fprintf(fsol, "%d\n", cardSol);
366     for(int i=0; i<cardSol; i++) {
367       fprintf(fsol, " %12.8f", sol[i]);
368       if(i % 10 == 9) {
369 	fprintf(fsol, "\n");
370       }
371     }
372     if(cardSol % 10 != 0) {
373       fprintf(fsol, "\n");
374     }
375     fprintf(fsol, "Value: %16.14g\n", val);
376     fprintf(fsol, "Tolerance: %16.14g\n", maxViol);
377   }
378 } /* printSol */
379