1 | // Copyright (C) 2006, International Business Machines |
2 | // Corporation and others. All Rights Reserved. |
3 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
4 | |
5 | #include <string> |
6 | #include <cassert> |
7 | #include <cfloat> |
8 | #include <cmath> |
9 | #include "CoinPragma.hpp" |
10 | #include "OsiSolverInterface.hpp" |
11 | #include "OsiAuxInfo.hpp" |
12 | #include "OsiSolverBranch.hpp" |
13 | #include "CoinWarmStartBasis.hpp" |
14 | #include "CoinPackedMatrix.hpp" |
15 | #include "CoinTime.hpp" |
16 | #include "CoinSort.hpp" |
17 | #include "CoinFinite.hpp" |
18 | #include "OsiChooseVariable.hpp" |
19 | using namespace std; |
20 | |
21 | OsiChooseVariable::OsiChooseVariable() : |
22 | goodObjectiveValue_(COIN_DBL_MAX), |
23 | upChange_(0.0), |
24 | downChange_(0.0), |
25 | goodSolution_(NULL), |
26 | list_(NULL), |
27 | useful_(NULL), |
28 | solver_(NULL), |
29 | status_(-1), |
30 | bestObjectIndex_(-1), |
31 | bestWhichWay_(-1), |
32 | firstForcedObjectIndex_(-1), |
33 | firstForcedWhichWay_(-1), |
34 | numberUnsatisfied_(0), |
35 | numberStrong_(0), |
36 | numberOnList_(0), |
37 | numberStrongDone_(0), |
38 | numberStrongIterations_(0), |
39 | numberStrongFixed_(0), |
40 | trustStrongForBound_(true), |
41 | trustStrongForSolution_(true) |
42 | { |
43 | } |
44 | |
45 | OsiChooseVariable::OsiChooseVariable(const OsiSolverInterface * solver) : |
46 | goodObjectiveValue_(COIN_DBL_MAX), |
47 | upChange_(0.0), |
48 | downChange_(0.0), |
49 | goodSolution_(NULL), |
50 | solver_(solver), |
51 | status_(-1), |
52 | bestObjectIndex_(-1), |
53 | bestWhichWay_(-1), |
54 | firstForcedObjectIndex_(-1), |
55 | firstForcedWhichWay_(-1), |
56 | numberUnsatisfied_(0), |
57 | numberStrong_(0), |
58 | numberOnList_(0), |
59 | numberStrongDone_(0), |
60 | numberStrongIterations_(0), |
61 | numberStrongFixed_(0), |
62 | trustStrongForBound_(true), |
63 | trustStrongForSolution_(true) |
64 | { |
65 | // create useful arrays |
66 | int numberObjects = solver_->numberObjects(); |
67 | list_ = new int [numberObjects]; |
68 | useful_ = new double [numberObjects]; |
69 | } |
70 | |
71 | OsiChooseVariable::OsiChooseVariable(const OsiChooseVariable & rhs) |
72 | { |
73 | goodObjectiveValue_ = rhs.goodObjectiveValue_; |
74 | upChange_ = rhs.upChange_; |
75 | downChange_ = rhs.downChange_; |
76 | status_ = rhs.status_; |
77 | bestObjectIndex_ = rhs.bestObjectIndex_; |
78 | bestWhichWay_ = rhs.bestWhichWay_; |
79 | firstForcedObjectIndex_ = rhs.firstForcedObjectIndex_; |
80 | firstForcedWhichWay_ = rhs.firstForcedWhichWay_; |
81 | numberUnsatisfied_ = rhs.numberUnsatisfied_; |
82 | numberStrong_ = rhs.numberStrong_; |
83 | numberOnList_ = rhs.numberOnList_; |
84 | numberStrongDone_ = rhs.numberStrongDone_; |
85 | numberStrongIterations_ = rhs.numberStrongIterations_; |
86 | numberStrongFixed_ = rhs.numberStrongFixed_; |
87 | trustStrongForBound_ = rhs.trustStrongForBound_; |
88 | trustStrongForSolution_ = rhs.trustStrongForSolution_; |
89 | solver_ = rhs.solver_; |
90 | if (solver_) { |
91 | int numberObjects = solver_->numberObjects(); |
92 | int numberColumns = solver_->getNumCols(); |
93 | if (rhs.goodSolution_) { |
94 | goodSolution_ = CoinCopyOfArray(rhs.goodSolution_,numberColumns); |
95 | } else { |
96 | goodSolution_ = NULL; |
97 | } |
98 | list_ = CoinCopyOfArray(rhs.list_,numberObjects); |
99 | useful_ = CoinCopyOfArray(rhs.useful_,numberObjects); |
100 | } else { |
101 | goodSolution_ = NULL; |
102 | list_ = NULL; |
103 | useful_ = NULL; |
104 | } |
105 | } |
106 | |
107 | OsiChooseVariable & |
108 | OsiChooseVariable::operator=(const OsiChooseVariable & rhs) |
109 | { |
110 | if (this != &rhs) { |
111 | delete [] goodSolution_; |
112 | delete [] list_; |
113 | delete [] useful_; |
114 | goodObjectiveValue_ = rhs.goodObjectiveValue_; |
115 | upChange_ = rhs.upChange_; |
116 | downChange_ = rhs.downChange_; |
117 | status_ = rhs.status_; |
118 | bestObjectIndex_ = rhs.bestObjectIndex_; |
119 | bestWhichWay_ = rhs.bestWhichWay_; |
120 | firstForcedObjectIndex_ = rhs.firstForcedObjectIndex_; |
121 | firstForcedWhichWay_ = rhs.firstForcedWhichWay_; |
122 | numberUnsatisfied_ = rhs.numberUnsatisfied_; |
123 | numberStrong_ = rhs.numberStrong_; |
124 | numberOnList_ = rhs.numberOnList_; |
125 | numberStrongDone_ = rhs.numberStrongDone_; |
126 | numberStrongIterations_ = rhs.numberStrongIterations_; |
127 | numberStrongFixed_ = rhs.numberStrongFixed_; |
128 | trustStrongForBound_ = rhs.trustStrongForBound_; |
129 | trustStrongForSolution_ = rhs.trustStrongForSolution_; |
130 | solver_ = rhs.solver_; |
131 | if (solver_) { |
132 | int numberObjects = solver_->numberObjects(); |
133 | int numberColumns = solver_->getNumCols(); |
134 | if (rhs.goodSolution_) { |
135 | goodSolution_ = CoinCopyOfArray(rhs.goodSolution_,numberColumns); |
136 | } else { |
137 | goodSolution_ = NULL; |
138 | } |
139 | list_ = CoinCopyOfArray(rhs.list_,numberObjects); |
140 | useful_ = CoinCopyOfArray(rhs.useful_,numberObjects); |
141 | } else { |
142 | goodSolution_ = NULL; |
143 | list_ = NULL; |
144 | useful_ = NULL; |
145 | } |
146 | } |
147 | return *this; |
148 | } |
149 | |
150 | |
151 | OsiChooseVariable::~OsiChooseVariable () |
152 | { |
153 | delete [] goodSolution_; |
154 | delete [] list_; |
155 | delete [] useful_; |
156 | } |
157 | |
158 | // Clone |
159 | OsiChooseVariable * |
160 | OsiChooseVariable::clone() const |
161 | { |
162 | return new OsiChooseVariable(*this); |
163 | } |
164 | // Set solver and redo arrays |
165 | void |
166 | OsiChooseVariable::setSolver (const OsiSolverInterface * solver) |
167 | { |
168 | solver_ = solver; |
169 | delete [] list_; |
170 | delete [] useful_; |
171 | // create useful arrays |
172 | int numberObjects = solver_->numberObjects(); |
173 | list_ = new int [numberObjects]; |
174 | useful_ = new double [numberObjects]; |
175 | } |
176 | |
177 | |
178 | // Initialize |
179 | int |
180 | OsiChooseVariable::setupList ( OsiBranchingInformation *info, bool initialize) |
181 | { |
182 | if (initialize) { |
183 | status_=-2; |
184 | delete [] goodSolution_; |
185 | bestObjectIndex_=-1; |
186 | numberStrongDone_=0; |
187 | numberStrongIterations_ = 0; |
188 | numberStrongFixed_ = 0; |
189 | goodSolution_ = NULL; |
190 | goodObjectiveValue_ = COIN_DBL_MAX; |
191 | } |
192 | numberOnList_=0; |
193 | numberUnsatisfied_=0; |
194 | int numberObjects = solver_->numberObjects(); |
195 | assert (numberObjects); |
196 | double check = 0.0; |
197 | int checkIndex=0; |
198 | int bestPriority=COIN_INT_MAX; |
199 | // pretend one strong even if none |
200 | int maximumStrong= numberStrong_ ? CoinMin(numberStrong_,numberObjects) : 1; |
201 | int putOther = numberObjects; |
202 | int i; |
203 | for (i=0;i<maximumStrong;i++) { |
204 | list_[i]=-1; |
205 | useful_[i]=0.0; |
206 | } |
207 | OsiObject ** object = info->solver_->objects(); |
208 | // Say feasible |
209 | bool feasible = true; |
210 | for ( i=0;i<numberObjects;i++) { |
211 | int way; |
212 | double value = object[i]->infeasibility(info,way); |
213 | if (value>0.0) { |
214 | numberUnsatisfied_++; |
215 | if (value==COIN_DBL_MAX) { |
216 | // infeasible |
217 | feasible=false; |
218 | break; |
219 | } |
220 | int priorityLevel = object[i]->priority(); |
221 | // Better priority? Flush choices. |
222 | if (priorityLevel<bestPriority) { |
223 | for (int j=0;j<maximumStrong;j++) { |
224 | if (list_[j]>=0) { |
225 | int iObject = list_[j]; |
226 | list_[j]=-1; |
227 | useful_[j]=0.0; |
228 | list_[--putOther]=iObject; |
229 | } |
230 | } |
231 | bestPriority = priorityLevel; |
232 | check=0.0; |
233 | } |
234 | if (priorityLevel==bestPriority) { |
235 | if (value>check) { |
236 | //add to list |
237 | int iObject = list_[checkIndex]; |
238 | if (iObject>=0) |
239 | list_[--putOther]=iObject; // to end |
240 | list_[checkIndex]=i; |
241 | useful_[checkIndex]=value; |
242 | // find worst |
243 | check=COIN_DBL_MAX; |
244 | for (int j=0;j<maximumStrong;j++) { |
245 | if (list_[j]>=0) { |
246 | if (useful_[j]<check) { |
247 | check=useful_[j]; |
248 | checkIndex=j; |
249 | } |
250 | } else { |
251 | check=0.0; |
252 | checkIndex = j; |
253 | break; |
254 | } |
255 | } |
256 | } else { |
257 | // to end |
258 | list_[--putOther]=i; |
259 | } |
260 | } else { |
261 | // to end |
262 | list_[--putOther]=i; |
263 | } |
264 | } |
265 | } |
266 | // Get list |
267 | numberOnList_=0; |
268 | if (feasible) { |
269 | for (i=0;i<maximumStrong;i++) { |
270 | if (list_[i]>=0) { |
271 | list_[numberOnList_]=list_[i]; |
272 | useful_[numberOnList_++]=-useful_[i]; |
273 | } |
274 | } |
275 | if (numberOnList_) { |
276 | // Sort |
277 | CoinSort_2(useful_,useful_+numberOnList_,list_); |
278 | // move others |
279 | i = numberOnList_; |
280 | for (;putOther<numberObjects;putOther++) |
281 | list_[i++]=list_[putOther]; |
282 | assert (i==numberUnsatisfied_); |
283 | if (!numberStrong_) |
284 | numberOnList_=0; |
285 | } |
286 | } else { |
287 | // not feasible |
288 | numberUnsatisfied_=-1; |
289 | } |
290 | return numberUnsatisfied_; |
291 | } |
292 | /* Choose a variable |
293 | Returns - |
294 | -1 Node is infeasible |
295 | 0 Normal termination - we have a candidate |
296 | 1 All looks satisfied - no candidate |
297 | 2 We can change the bound on a variable - but we also have a strong branching candidate |
298 | 3 We can change the bound on a variable - but we have a non-strong branching candidate |
299 | 4 We can change the bound on a variable - no other candidates |
300 | We can pick up branch from whichObject() and whichWay() |
301 | We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay() |
302 | If we have a solution then we can pick up from goodObjectiveValue() and goodSolution() |
303 | */ |
304 | int |
305 | OsiChooseVariable::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *, bool ) |
306 | { |
307 | if (numberUnsatisfied_) { |
308 | bestObjectIndex_=list_[0]; |
309 | bestWhichWay_ = solver->object(bestObjectIndex_)->whichWay(); |
310 | firstForcedObjectIndex_ = -1; |
311 | firstForcedWhichWay_ =-1; |
312 | return 0; |
313 | } else { |
314 | return 1; |
315 | } |
316 | } |
317 | // Returns true if solution looks feasible against given objects |
318 | bool |
319 | OsiChooseVariable::feasibleSolution(const OsiBranchingInformation * info, |
320 | const double * solution, |
321 | int numberObjects, |
322 | const OsiObject ** objects) |
323 | { |
324 | bool satisfied=true; |
325 | const double * saveSolution = info->solution_; |
326 | info->solution_ = solution; |
327 | for (int i=0;i<numberObjects;i++) { |
328 | double value = objects[i]->checkInfeasibility(info); |
329 | if (value>0.0) { |
330 | satisfied=false; |
331 | break; |
332 | } |
333 | } |
334 | info->solution_ = saveSolution; |
335 | return satisfied; |
336 | } |
337 | // Saves a good solution |
338 | void |
339 | OsiChooseVariable::saveSolution(const OsiSolverInterface * solver) |
340 | { |
341 | delete [] goodSolution_; |
342 | int numberColumns = solver->getNumCols(); |
343 | goodSolution_ = CoinCopyOfArray(solver->getColSolution(),numberColumns); |
344 | goodObjectiveValue_ = solver->getObjSense()*solver->getObjValue(); |
345 | } |
346 | // Clears out good solution after use |
347 | void |
348 | OsiChooseVariable::clearGoodSolution() |
349 | { |
350 | delete [] goodSolution_; |
351 | goodSolution_ = NULL; |
352 | goodObjectiveValue_ = COIN_DBL_MAX; |
353 | } |
354 | |
355 | /* This is a utility function which does strong branching on |
356 | a list of objects and stores the results in OsiHotInfo.objects. |
357 | On entry the object sequence is stored in the OsiHotInfo object |
358 | and maybe more. |
359 | It returns - |
360 | -1 - one branch was infeasible both ways |
361 | 0 - all inspected - nothing can be fixed |
362 | 1 - all inspected - some can be fixed (returnCriterion==0) |
363 | 2 - may be returning early - one can be fixed (last one done) (returnCriterion==1) |
364 | 3 - returning because max time |
365 | */ |
366 | int |
367 | OsiChooseStrong::doStrongBranching( OsiSolverInterface * solver, |
368 | OsiBranchingInformation *info, |
369 | int numberToDo, int returnCriterion) |
370 | { |
371 | |
372 | // Might be faster to extend branch() to return bounds changed |
373 | double * saveLower = NULL; |
374 | double * saveUpper = NULL; |
375 | int numberColumns = solver->getNumCols(); |
376 | solver->markHotStart(); |
377 | const double * lower = info->lower_; |
378 | const double * upper = info->upper_; |
379 | saveLower = CoinCopyOfArray(info->lower_,numberColumns); |
380 | saveUpper = CoinCopyOfArray(info->upper_,numberColumns); |
381 | numResults_=0; |
382 | int returnCode=0; |
383 | double timeStart = CoinCpuTime(); |
384 | for (int iDo=0;iDo<numberToDo;iDo++) { |
385 | OsiHotInfo * result = results_ + iDo; |
386 | // For now just 2 way |
387 | OsiBranchingObject * branch = result->branchingObject(); |
388 | assert (branch->numberBranches()==2); |
389 | /* |
390 | Try the first direction. Each subsequent call to branch() performs the |
391 | specified branch and advances the branch object state to the next branch |
392 | alternative.) |
393 | */ |
394 | OsiSolverInterface * thisSolver = solver; |
395 | if (branch->boundBranch()) { |
396 | // ordinary |
397 | branch->branch(solver); |
398 | // maybe we should check bounds for stupidities here? |
399 | solver->solveFromHotStart() ; |
400 | } else { |
401 | // adding cuts or something |
402 | thisSolver = solver->clone(); |
403 | branch->branch(thisSolver); |
404 | // set hot start iterations |
405 | int limit; |
406 | thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit); |
407 | thisSolver->setIntParam(OsiMaxNumIteration,limit); |
408 | thisSolver->resolve(); |
409 | } |
410 | // can check if we got solution |
411 | // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution |
412 | int status0 = result->updateInformation(thisSolver,info,this); |
413 | numberStrongIterations_ += thisSolver->getIterationCount(); |
414 | if (status0==3) { |
415 | // new solution already saved |
416 | if (trustStrongForSolution_) { |
417 | info->cutoff_ = goodObjectiveValue_; |
418 | status0=0; |
419 | } |
420 | } |
421 | if (solver!=thisSolver) |
422 | delete thisSolver; |
423 | // Restore bounds |
424 | for (int j=0;j<numberColumns;j++) { |
425 | if (saveLower[j] != lower[j]) |
426 | solver->setColLower(j,saveLower[j]); |
427 | if (saveUpper[j] != upper[j]) |
428 | solver->setColUpper(j,saveUpper[j]); |
429 | } |
430 | /* |
431 | Try the next direction |
432 | */ |
433 | thisSolver = solver; |
434 | if (branch->boundBranch()) { |
435 | // ordinary |
436 | branch->branch(solver); |
437 | // maybe we should check bounds for stupidities here? |
438 | solver->solveFromHotStart() ; |
439 | } else { |
440 | // adding cuts or something |
441 | thisSolver = solver->clone(); |
442 | branch->branch(thisSolver); |
443 | // set hot start iterations |
444 | int limit; |
445 | thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit); |
446 | thisSolver->setIntParam(OsiMaxNumIteration,limit); |
447 | thisSolver->resolve(); |
448 | } |
449 | // can check if we got solution |
450 | // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution |
451 | int status1 = result->updateInformation(thisSolver,info,this); |
452 | numberStrongDone_++; |
453 | numberStrongIterations_ += thisSolver->getIterationCount(); |
454 | if (status1==3) { |
455 | // new solution already saved |
456 | if (trustStrongForSolution_) { |
457 | info->cutoff_ = goodObjectiveValue_; |
458 | status1=0; |
459 | } |
460 | } |
461 | if (solver!=thisSolver) |
462 | delete thisSolver; |
463 | // Restore bounds |
464 | for (int j=0;j<numberColumns;j++) { |
465 | if (saveLower[j] != lower[j]) |
466 | solver->setColLower(j,saveLower[j]); |
467 | if (saveUpper[j] != upper[j]) |
468 | solver->setColUpper(j,saveUpper[j]); |
469 | } |
470 | /* |
471 | End of evaluation for this candidate variable. Possibilities are: |
472 | * Both sides below cutoff; this variable is a candidate for branching. |
473 | * Both sides infeasible or above the objective cutoff: no further action |
474 | here. Break from the evaluation loop and assume the node will be purged |
475 | by the caller. |
476 | * One side below cutoff: Install the branch (i.e., fix the variable). Possibly break |
477 | from the evaluation loop and assume the node will be reoptimised by the |
478 | caller. |
479 | */ |
480 | numResults_++; |
481 | if (status0==1&&status1==1) { |
482 | // infeasible |
483 | returnCode=-1; |
484 | break; // exit loop |
485 | } else if (status0==1||status1==1) { |
486 | numberStrongFixed_++; |
487 | if (!returnCriterion) { |
488 | returnCode=1; |
489 | } else { |
490 | returnCode=2; |
491 | break; |
492 | } |
493 | } |
494 | bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_); |
495 | if (hitMaxTime) { |
496 | returnCode=3; |
497 | break; |
498 | } |
499 | } |
500 | delete [] saveLower; |
501 | delete [] saveUpper; |
502 | // Delete the snapshot |
503 | solver->unmarkHotStart(); |
504 | return returnCode; |
505 | } |
506 | |
507 | // Given a candidate fill in useful information e.g. estimates |
508 | void |
509 | OsiChooseVariable::updateInformation(const OsiBranchingInformation *info, |
510 | int , OsiHotInfo * hotInfo) |
511 | { |
512 | int index = hotInfo->whichObject(); |
513 | assert (index<solver_->numberObjects()); |
514 | //assert (branch<2); |
515 | OsiObject ** object = info->solver_->objects(); |
516 | upChange_ = object[index]->upEstimate(); |
517 | downChange_ = object[index]->downEstimate(); |
518 | } |
519 | #if 1 |
520 | // Given a branch fill in useful information e.g. estimates |
521 | void |
522 | OsiChooseVariable::updateInformation( int index, int branch, |
523 | double , double , |
524 | int ) |
525 | { |
526 | assert (index<solver_->numberObjects()); |
527 | assert (branch<2); |
528 | OsiObject ** object = solver_->objects(); |
529 | if (branch) |
530 | upChange_ = object[index]->upEstimate(); |
531 | else |
532 | downChange_ = object[index]->downEstimate(); |
533 | } |
534 | #endif |
535 | |
536 | //############################################################################## |
537 | |
538 | void |
539 | OsiPseudoCosts::gutsOfDelete() |
540 | { |
541 | if (numberObjects_ > 0) { |
542 | numberObjects_ = 0; |
543 | numberBeforeTrusted_ = 0; |
544 | delete[] upTotalChange_; upTotalChange_ = NULL; |
545 | delete[] downTotalChange_; downTotalChange_ = NULL; |
546 | delete[] upNumber_; upNumber_ = NULL; |
547 | delete[] downNumber_; downNumber_ = NULL; |
548 | } |
549 | } |
550 | |
551 | void |
552 | OsiPseudoCosts::gutsOfCopy(const OsiPseudoCosts& rhs) |
553 | { |
554 | numberObjects_ = rhs.numberObjects_; |
555 | numberBeforeTrusted_ = rhs.numberBeforeTrusted_; |
556 | if (numberObjects_ > 0) { |
557 | upTotalChange_ = CoinCopyOfArray(rhs.upTotalChange_,numberObjects_); |
558 | downTotalChange_ = CoinCopyOfArray(rhs.downTotalChange_,numberObjects_); |
559 | upNumber_ = CoinCopyOfArray(rhs.upNumber_,numberObjects_); |
560 | downNumber_ = CoinCopyOfArray(rhs.downNumber_,numberObjects_); |
561 | } |
562 | } |
563 | |
564 | OsiPseudoCosts::OsiPseudoCosts() : |
565 | upTotalChange_(NULL), |
566 | downTotalChange_(NULL), |
567 | upNumber_(NULL), |
568 | downNumber_(NULL), |
569 | numberObjects_(0), |
570 | numberBeforeTrusted_(0) |
571 | { |
572 | } |
573 | |
574 | OsiPseudoCosts::~OsiPseudoCosts() |
575 | { |
576 | gutsOfDelete(); |
577 | } |
578 | |
579 | OsiPseudoCosts::OsiPseudoCosts(const OsiPseudoCosts& rhs) : |
580 | upTotalChange_(NULL), |
581 | downTotalChange_(NULL), |
582 | upNumber_(NULL), |
583 | downNumber_(NULL), |
584 | numberObjects_(0), |
585 | numberBeforeTrusted_(0) |
586 | { |
587 | gutsOfCopy(rhs); |
588 | } |
589 | |
590 | OsiPseudoCosts& |
591 | OsiPseudoCosts::operator=(const OsiPseudoCosts& rhs) |
592 | { |
593 | if (this != &rhs) { |
594 | gutsOfDelete(); |
595 | gutsOfCopy(rhs); |
596 | } |
597 | return *this; |
598 | } |
599 | |
600 | void |
601 | OsiPseudoCosts::initialize(int n) |
602 | { |
603 | gutsOfDelete(); |
604 | numberObjects_ = n; |
605 | if (numberObjects_ > 0) { |
606 | upTotalChange_ = new double [numberObjects_]; |
607 | downTotalChange_ = new double [numberObjects_]; |
608 | upNumber_ = new int [numberObjects_]; |
609 | downNumber_ = new int [numberObjects_]; |
610 | CoinZeroN(upTotalChange_,numberObjects_); |
611 | CoinZeroN(downTotalChange_,numberObjects_); |
612 | CoinZeroN(upNumber_,numberObjects_); |
613 | CoinZeroN(downNumber_,numberObjects_); |
614 | } |
615 | } |
616 | |
617 | |
618 | //############################################################################## |
619 | |
620 | OsiChooseStrong::OsiChooseStrong() : |
621 | OsiChooseVariable(), |
622 | shadowPriceMode_(0), |
623 | pseudoCosts_(), |
624 | results_(NULL), |
625 | numResults_(0) |
626 | { |
627 | } |
628 | |
629 | OsiChooseStrong::OsiChooseStrong(const OsiSolverInterface * solver) : |
630 | OsiChooseVariable(solver), |
631 | shadowPriceMode_(0), |
632 | pseudoCosts_(), |
633 | results_(NULL), |
634 | numResults_(0) |
635 | { |
636 | // create useful arrays |
637 | pseudoCosts_.initialize(solver_->numberObjects()); |
638 | } |
639 | |
640 | OsiChooseStrong::OsiChooseStrong(const OsiChooseStrong & rhs) : |
641 | OsiChooseVariable(rhs), |
642 | shadowPriceMode_(rhs.shadowPriceMode_), |
643 | pseudoCosts_(rhs.pseudoCosts_), |
644 | results_(NULL), |
645 | numResults_(0) |
646 | { |
647 | } |
648 | |
649 | OsiChooseStrong & |
650 | OsiChooseStrong::operator=(const OsiChooseStrong & rhs) |
651 | { |
652 | if (this != &rhs) { |
653 | OsiChooseVariable::operator=(rhs); |
654 | shadowPriceMode_ = rhs.shadowPriceMode_; |
655 | pseudoCosts_ = rhs.pseudoCosts_; |
656 | delete[] results_; |
657 | results_ = NULL; |
658 | numResults_ = 0; |
659 | } |
660 | return *this; |
661 | } |
662 | |
663 | |
664 | OsiChooseStrong::~OsiChooseStrong () |
665 | { |
666 | delete[] results_; |
667 | } |
668 | |
669 | // Clone |
670 | OsiChooseVariable * |
671 | OsiChooseStrong::clone() const |
672 | { |
673 | return new OsiChooseStrong(*this); |
674 | } |
675 | #define MAXMIN_CRITERION 0.85 |
676 | // Initialize |
677 | int |
678 | OsiChooseStrong::setupList ( OsiBranchingInformation *info, bool initialize) |
679 | { |
680 | if (initialize) { |
681 | status_=-2; |
682 | delete [] goodSolution_; |
683 | bestObjectIndex_=-1; |
684 | numberStrongDone_=0; |
685 | numberStrongIterations_ = 0; |
686 | numberStrongFixed_ = 0; |
687 | goodSolution_ = NULL; |
688 | goodObjectiveValue_ = COIN_DBL_MAX; |
689 | } |
690 | numberOnList_=0; |
691 | numberUnsatisfied_=0; |
692 | int numberObjects = solver_->numberObjects(); |
693 | if (numberObjects>pseudoCosts_.numberObjects()) { |
694 | // redo useful arrays |
695 | pseudoCosts_.initialize(numberObjects); |
696 | } |
697 | double check = -COIN_DBL_MAX; |
698 | int checkIndex=0; |
699 | int bestPriority=COIN_INT_MAX; |
700 | int maximumStrong= CoinMin(numberStrong_,numberObjects) ; |
701 | int putOther = numberObjects; |
702 | int i; |
703 | for (i=0;i<numberObjects;i++) { |
704 | list_[i]=-1; |
705 | useful_[i]=0.0; |
706 | } |
707 | OsiObject ** object = info->solver_->objects(); |
708 | // Get average pseudo costs and see if pseudo shadow prices possible |
709 | int shadowPossible=shadowPriceMode_; |
710 | if (shadowPossible) { |
711 | for ( i=0;i<numberObjects;i++) { |
712 | if ( !object[i]->canHandleShadowPrices()) { |
713 | shadowPossible=0; |
714 | break; |
715 | } |
716 | } |
717 | if (shadowPossible) { |
718 | int numberRows = solver_->getNumRows(); |
719 | const double * pi = info->pi_; |
720 | double sumPi=0.0; |
721 | for (i=0;i<numberRows;i++) |
722 | sumPi += fabs(pi[i]); |
723 | sumPi /= static_cast<double> (numberRows); |
724 | // and scale back |
725 | sumPi *= 0.01; |
726 | info->defaultDual_ = sumPi; // switch on |
727 | int numberColumns = solver_->getNumCols(); |
728 | int size = CoinMax(numberColumns,2*numberRows); |
729 | info->usefulRegion_ = new double [size]; |
730 | CoinZeroN(info->usefulRegion_,size); |
731 | info->indexRegion_ = new int [size]; |
732 | } |
733 | } |
734 | double sumUp=0.0; |
735 | double numberUp=0.0; |
736 | double sumDown=0.0; |
737 | double numberDown=0.0; |
738 | const double* upTotalChange = pseudoCosts_.upTotalChange(); |
739 | const double* downTotalChange = pseudoCosts_.downTotalChange(); |
740 | const int* upNumber = pseudoCosts_.upNumber(); |
741 | const int* downNumber = pseudoCosts_.downNumber(); |
742 | const int numberBeforeTrusted = pseudoCosts_.numberBeforeTrusted(); |
743 | for ( i=0;i<numberObjects;i++) { |
744 | sumUp += upTotalChange[i]; |
745 | numberUp += upNumber[i]; |
746 | sumDown += downTotalChange[i]; |
747 | numberDown += downNumber[i]; |
748 | } |
749 | double upMultiplier=(1.0+sumUp)/(1.0+numberUp); |
750 | double downMultiplier=(1.0+sumDown)/(1.0+numberDown); |
751 | // Say feasible |
752 | bool feasible = true; |
753 | #if 0 |
754 | int pri[]={10,1000,10000}; |
755 | int priCount[]={0,0,0}; |
756 | #endif |
757 | for ( i=0;i<numberObjects;i++) { |
758 | int way; |
759 | double value = object[i]->infeasibility(info,way); |
760 | if (value>0.0) { |
761 | numberUnsatisfied_++; |
762 | if (value==COIN_DBL_MAX) { |
763 | // infeasible |
764 | feasible=false; |
765 | break; |
766 | } |
767 | int priorityLevel = object[i]->priority(); |
768 | #if 0 |
769 | for (int k=0;k<3;k++) { |
770 | if (priorityLevel==pri[k]) |
771 | priCount[k]++; |
772 | } |
773 | #endif |
774 | // Better priority? Flush choices. |
775 | if (priorityLevel<bestPriority) { |
776 | for (int j=maximumStrong-1;j>=0;j--) { |
777 | if (list_[j]>=0) { |
778 | int iObject = list_[j]; |
779 | list_[j]=-1; |
780 | useful_[j]=0.0; |
781 | list_[--putOther]=iObject; |
782 | } |
783 | } |
784 | maximumStrong = CoinMin(maximumStrong,putOther); |
785 | bestPriority = priorityLevel; |
786 | check=-COIN_DBL_MAX; |
787 | checkIndex=0; |
788 | } |
789 | if (priorityLevel==bestPriority) { |
790 | // Modify value |
791 | sumUp = upTotalChange[i]+1.0e-30; |
792 | numberUp = upNumber[i]; |
793 | sumDown = downTotalChange[i]+1.0e-30; |
794 | numberDown = downNumber[i]; |
795 | double upEstimate = object[i]->upEstimate(); |
796 | double downEstimate = object[i]->downEstimate(); |
797 | if (shadowPossible<2) { |
798 | upEstimate = numberUp ? ((upEstimate*sumUp)/numberUp) : (upEstimate*upMultiplier); |
799 | if (numberUp<numberBeforeTrusted) |
800 | upEstimate *= (numberBeforeTrusted+1.0)/(numberUp+1.0); |
801 | downEstimate = numberDown ? ((downEstimate*sumDown)/numberDown) : (downEstimate*downMultiplier); |
802 | if (numberDown<numberBeforeTrusted) |
803 | downEstimate *= (numberBeforeTrusted+1.0)/(numberDown+1.0); |
804 | } else { |
805 | // use shadow prices always |
806 | } |
807 | value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate); |
808 | if (value>check) { |
809 | //add to list |
810 | int iObject = list_[checkIndex]; |
811 | if (iObject>=0) { |
812 | assert (list_[putOther-1]<0); |
813 | list_[--putOther]=iObject; // to end |
814 | } |
815 | list_[checkIndex]=i; |
816 | assert (checkIndex<putOther); |
817 | useful_[checkIndex]=value; |
818 | // find worst |
819 | check=COIN_DBL_MAX; |
820 | maximumStrong = CoinMin(maximumStrong,putOther); |
821 | for (int j=0;j<maximumStrong;j++) { |
822 | if (list_[j]>=0) { |
823 | if (useful_[j]<check) { |
824 | check=useful_[j]; |
825 | checkIndex=j; |
826 | } |
827 | } else { |
828 | check=0.0; |
829 | checkIndex = j; |
830 | break; |
831 | } |
832 | } |
833 | } else { |
834 | // to end |
835 | assert (list_[putOther-1]<0); |
836 | list_[--putOther]=i; |
837 | maximumStrong = CoinMin(maximumStrong,putOther); |
838 | } |
839 | } else { |
840 | // worse priority |
841 | // to end |
842 | assert (list_[putOther-1]<0); |
843 | list_[--putOther]=i; |
844 | maximumStrong = CoinMin(maximumStrong,putOther); |
845 | } |
846 | } |
847 | } |
848 | #if 0 |
849 | printf("%d at %d, %d at %d and %d at %d\n" ,priCount[0],pri[0], |
850 | priCount[1],pri[1],priCount[2],pri[2]); |
851 | #endif |
852 | // Get list |
853 | numberOnList_=0; |
854 | if (feasible) { |
855 | for (i=0;i<CoinMin(maximumStrong,putOther);i++) { |
856 | if (list_[i]>=0) { |
857 | list_[numberOnList_]=list_[i]; |
858 | useful_[numberOnList_++]=-useful_[i]; |
859 | } |
860 | } |
861 | if (numberOnList_) { |
862 | // Sort |
863 | CoinSort_2(useful_,useful_+numberOnList_,list_); |
864 | // move others |
865 | i = numberOnList_; |
866 | for (;putOther<numberObjects;putOther++) |
867 | list_[i++]=list_[putOther]; |
868 | assert (i==numberUnsatisfied_); |
869 | if (!numberStrong_) |
870 | numberOnList_=0; |
871 | } |
872 | } else { |
873 | // not feasible |
874 | numberUnsatisfied_=-1; |
875 | } |
876 | // Get rid of any shadow prices info |
877 | info->defaultDual_ = -1.0; // switch off |
878 | delete [] info->usefulRegion_; |
879 | delete [] info->indexRegion_; |
880 | return numberUnsatisfied_; |
881 | } |
882 | |
883 | void |
884 | OsiChooseStrong::resetResults(int num) |
885 | { |
886 | delete[] results_; |
887 | numResults_ = 0; |
888 | results_ = new OsiHotInfo[num]; |
889 | } |
890 | |
891 | /* Choose a variable |
892 | Returns - |
893 | -1 Node is infeasible |
894 | 0 Normal termination - we have a candidate |
895 | 1 All looks satisfied - no candidate |
896 | 2 We can change the bound on a variable - but we also have a strong branching candidate |
897 | 3 We can change the bound on a variable - but we have a non-strong branching candidate |
898 | 4 We can change the bound on a variable - no other candidates |
899 | We can pick up branch from whichObject() and whichWay() |
900 | We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay() |
901 | If we have a solution then we can pick up from goodObjectiveValue() and goodSolution() |
902 | */ |
903 | int |
904 | OsiChooseStrong::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables) |
905 | { |
906 | if (numberUnsatisfied_) { |
907 | const double* upTotalChange = pseudoCosts_.upTotalChange(); |
908 | const double* downTotalChange = pseudoCosts_.downTotalChange(); |
909 | const int* upNumber = pseudoCosts_.upNumber(); |
910 | const int* downNumber = pseudoCosts_.downNumber(); |
911 | int numberBeforeTrusted = pseudoCosts_.numberBeforeTrusted(); |
912 | // Somehow we can get here with it 0 ! |
913 | if (!numberBeforeTrusted) { |
914 | numberBeforeTrusted=5; |
915 | pseudoCosts_.setNumberBeforeTrusted(numberBeforeTrusted); |
916 | } |
917 | |
918 | int numberLeft = CoinMin(numberStrong_-numberStrongDone_,numberUnsatisfied_); |
919 | int numberToDo=0; |
920 | resetResults(numberLeft); |
921 | int returnCode=0; |
922 | bestObjectIndex_ = -1; |
923 | bestWhichWay_ = -1; |
924 | firstForcedObjectIndex_ = -1; |
925 | firstForcedWhichWay_ =-1; |
926 | double bestTrusted=-COIN_DBL_MAX; |
927 | for (int i=0;i<numberLeft;i++) { |
928 | int iObject = list_[i]; |
929 | if (upNumber[iObject]<numberBeforeTrusted||downNumber[iObject]<numberBeforeTrusted) { |
930 | results_[numberToDo++] = OsiHotInfo(solver, info, |
931 | solver->objects(), iObject); |
932 | } else { |
933 | const OsiObject * obj = solver->object(iObject); |
934 | double upEstimate = (upTotalChange[iObject]*obj->upEstimate())/upNumber[iObject]; |
935 | double downEstimate = (downTotalChange[iObject]*obj->downEstimate())/downNumber[iObject]; |
936 | double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate); |
937 | if (value > bestTrusted) { |
938 | bestObjectIndex_=iObject; |
939 | bestWhichWay_ = upEstimate>downEstimate ? 0 : 1; |
940 | bestTrusted = value; |
941 | } |
942 | } |
943 | } |
944 | int numberFixed=0; |
945 | if (numberToDo) { |
946 | returnCode = doStrongBranching(solver, info, numberToDo, 1); |
947 | if (returnCode>=0&&returnCode<=2) { |
948 | if (returnCode) { |
949 | returnCode=4; |
950 | if (bestObjectIndex_>=0) |
951 | returnCode=3; |
952 | } |
953 | for (int i=0;i<numResults_;i++) { |
954 | int iObject = results_[i].whichObject(); |
955 | double upEstimate; |
956 | if (results_[i].upStatus()!=1) { |
957 | assert (results_[i].upStatus()>=0); |
958 | upEstimate = results_[i].upChange(); |
959 | } else { |
960 | // infeasible - just say expensive |
961 | if (info->cutoff_<1.0e50) |
962 | upEstimate = 2.0*(info->cutoff_-info->objectiveValue_); |
963 | else |
964 | upEstimate = 2.0*fabs(info->objectiveValue_); |
965 | if (firstForcedObjectIndex_ <0) { |
966 | firstForcedObjectIndex_ = iObject; |
967 | firstForcedWhichWay_ =0; |
968 | } |
969 | numberFixed++; |
970 | if (fixVariables) { |
971 | const OsiObject * obj = solver->object(iObject); |
972 | OsiBranchingObject * branch = obj->createBranch(solver,info,0); |
973 | branch->branch(solver); |
974 | delete branch; |
975 | } |
976 | } |
977 | double downEstimate; |
978 | if (results_[i].downStatus()!=1) { |
979 | assert (results_[i].downStatus()>=0); |
980 | downEstimate = results_[i].downChange(); |
981 | } else { |
982 | // infeasible - just say expensive |
983 | if (info->cutoff_<1.0e50) |
984 | downEstimate = 2.0*(info->cutoff_-info->objectiveValue_); |
985 | else |
986 | downEstimate = 2.0*fabs(info->objectiveValue_); |
987 | if (firstForcedObjectIndex_ <0) { |
988 | firstForcedObjectIndex_ = iObject; |
989 | firstForcedWhichWay_ =1; |
990 | } |
991 | numberFixed++; |
992 | if (fixVariables) { |
993 | const OsiObject * obj = solver->object(iObject); |
994 | OsiBranchingObject * branch = obj->createBranch(solver,info,1); |
995 | branch->branch(solver); |
996 | delete branch; |
997 | } |
998 | } |
999 | double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate); |
1000 | if (value>bestTrusted) { |
1001 | bestTrusted = value; |
1002 | bestObjectIndex_ = iObject; |
1003 | bestWhichWay_ = upEstimate>downEstimate ? 0 : 1; |
1004 | // but override if there is a preferred way |
1005 | const OsiObject * obj = solver->object(iObject); |
1006 | if (obj->preferredWay()>=0&&obj->infeasibility()) |
1007 | bestWhichWay_ = obj->preferredWay(); |
1008 | if (returnCode) |
1009 | returnCode=2; |
1010 | } |
1011 | } |
1012 | } else if (returnCode==3) { |
1013 | // max time - just choose one |
1014 | bestObjectIndex_ = list_[0]; |
1015 | bestWhichWay_ = 0; |
1016 | returnCode=0; |
1017 | } |
1018 | } else { |
1019 | bestObjectIndex_=list_[0]; |
1020 | } |
1021 | if ( bestObjectIndex_ >=0 ) { |
1022 | OsiObject * obj = solver->objects()[bestObjectIndex_]; |
1023 | obj->setWhichWay( bestWhichWay_); |
1024 | } |
1025 | if (numberFixed==numberUnsatisfied_&&numberFixed) |
1026 | returnCode=4; |
1027 | return returnCode; |
1028 | } else { |
1029 | return 1; |
1030 | } |
1031 | } |
1032 | // Given a candidate fill in useful information e.g. estimates |
1033 | void |
1034 | OsiPseudoCosts::updateInformation(const OsiBranchingInformation *info, |
1035 | int branch, OsiHotInfo * hotInfo) |
1036 | { |
1037 | int index = hotInfo->whichObject(); |
1038 | assert (index<info->solver_->numberObjects()); |
1039 | const OsiObject * object = info->solver_->object(index); |
1040 | assert (object->upEstimate()>0.0&&object->downEstimate()>0.0); |
1041 | assert (branch<2); |
1042 | if (branch) { |
1043 | if (hotInfo->upStatus()!=1) { |
1044 | assert (hotInfo->upStatus()>=0); |
1045 | upTotalChange_[index] += hotInfo->upChange()/object->upEstimate(); |
1046 | upNumber_[index]++; |
1047 | } else { |
1048 | #if 0 |
1049 | // infeasible - just say expensive |
1050 | if (info->cutoff_<1.0e50) |
1051 | upTotalChange_[index] += 2.0*(info->cutoff_-info->objectiveValue_)/object->upEstimate(); |
1052 | else |
1053 | upTotalChange_[index] += 2.0*fabs(info->objectiveValue_)/object->upEstimate(); |
1054 | #endif |
1055 | } |
1056 | } else { |
1057 | if (hotInfo->downStatus()!=1) { |
1058 | assert (hotInfo->downStatus()>=0); |
1059 | downTotalChange_[index] += hotInfo->downChange()/object->downEstimate(); |
1060 | downNumber_[index]++; |
1061 | } else { |
1062 | #if 0 |
1063 | // infeasible - just say expensive |
1064 | if (info->cutoff_<1.0e50) |
1065 | downTotalChange_[index] += 2.0*(info->cutoff_-info->objectiveValue_)/object->downEstimate(); |
1066 | else |
1067 | downTotalChange_[index] += 2.0*fabs(info->objectiveValue_)/object->downEstimate(); |
1068 | #endif |
1069 | } |
1070 | } |
1071 | } |
1072 | #if 1 |
1073 | // Given a branch fill in useful information e.g. estimates |
1074 | void |
1075 | OsiPseudoCosts::updateInformation(int index, int branch, |
1076 | double changeInObjective, |
1077 | double changeInValue, |
1078 | int status) |
1079 | { |
1080 | //assert (index<solver_->numberObjects()); |
1081 | assert (branch<2); |
1082 | assert (changeInValue>0.0); |
1083 | assert (branch<2); |
1084 | if (branch) { |
1085 | if (status!=1) { |
1086 | assert (status>=0); |
1087 | upTotalChange_[index] += changeInObjective/changeInValue; |
1088 | upNumber_[index]++; |
1089 | } |
1090 | } else { |
1091 | if (status!=1) { |
1092 | assert (status>=0); |
1093 | downTotalChange_[index] += changeInObjective/changeInValue; |
1094 | downNumber_[index]++; |
1095 | } |
1096 | } |
1097 | } |
1098 | #endif |
1099 | |
1100 | OsiHotInfo::OsiHotInfo() : |
1101 | originalObjectiveValue_(COIN_DBL_MAX), |
1102 | changes_(NULL), |
1103 | iterationCounts_(NULL), |
1104 | statuses_(NULL), |
1105 | branchingObject_(NULL), |
1106 | whichObject_(-1) |
1107 | { |
1108 | } |
1109 | |
1110 | OsiHotInfo::OsiHotInfo(OsiSolverInterface * solver, |
1111 | const OsiBranchingInformation * info, |
1112 | const OsiObject * const * objects, |
1113 | int whichObject) : |
1114 | originalObjectiveValue_(COIN_DBL_MAX), |
1115 | whichObject_(whichObject) |
1116 | { |
1117 | originalObjectiveValue_ = info->objectiveValue_; |
1118 | const OsiObject * object = objects[whichObject_]; |
1119 | // create object - "down" first |
1120 | branchingObject_ = object->createBranch(solver,info,0); |
1121 | // create arrays |
1122 | int numberBranches = branchingObject_->numberBranches(); |
1123 | changes_ = new double [numberBranches]; |
1124 | iterationCounts_ = new int [numberBranches]; |
1125 | statuses_ = new int [numberBranches]; |
1126 | CoinZeroN(changes_,numberBranches); |
1127 | CoinZeroN(iterationCounts_,numberBranches); |
1128 | CoinFillN(statuses_,numberBranches,-1); |
1129 | } |
1130 | |
1131 | OsiHotInfo::OsiHotInfo(const OsiHotInfo & rhs) |
1132 | { |
1133 | originalObjectiveValue_ = rhs.originalObjectiveValue_; |
1134 | whichObject_ = rhs.whichObject_; |
1135 | if (rhs.branchingObject_) { |
1136 | branchingObject_ = rhs.branchingObject_->clone(); |
1137 | int numberBranches = branchingObject_->numberBranches(); |
1138 | changes_ = CoinCopyOfArray(rhs.changes_,numberBranches); |
1139 | iterationCounts_ = CoinCopyOfArray(rhs.iterationCounts_,numberBranches); |
1140 | statuses_ = CoinCopyOfArray(rhs.statuses_,numberBranches); |
1141 | } else { |
1142 | branchingObject_ = NULL; |
1143 | changes_ = NULL; |
1144 | iterationCounts_ = NULL; |
1145 | statuses_ = NULL; |
1146 | } |
1147 | } |
1148 | |
1149 | OsiHotInfo & |
1150 | OsiHotInfo::operator=(const OsiHotInfo & rhs) |
1151 | { |
1152 | if (this != &rhs) { |
1153 | delete branchingObject_; |
1154 | delete [] changes_; |
1155 | delete [] iterationCounts_; |
1156 | delete [] statuses_; |
1157 | originalObjectiveValue_ = rhs.originalObjectiveValue_; |
1158 | whichObject_ = rhs.whichObject_; |
1159 | if (rhs.branchingObject_) { |
1160 | branchingObject_ = rhs.branchingObject_->clone(); |
1161 | int numberBranches = branchingObject_->numberBranches(); |
1162 | changes_ = CoinCopyOfArray(rhs.changes_,numberBranches); |
1163 | iterationCounts_ = CoinCopyOfArray(rhs.iterationCounts_,numberBranches); |
1164 | statuses_ = CoinCopyOfArray(rhs.statuses_,numberBranches); |
1165 | } else { |
1166 | branchingObject_ = NULL; |
1167 | changes_ = NULL; |
1168 | iterationCounts_ = NULL; |
1169 | statuses_ = NULL; |
1170 | } |
1171 | } |
1172 | return *this; |
1173 | } |
1174 | |
1175 | |
1176 | OsiHotInfo::~OsiHotInfo () |
1177 | { |
1178 | delete branchingObject_; |
1179 | delete [] changes_; |
1180 | delete [] iterationCounts_; |
1181 | delete [] statuses_; |
1182 | } |
1183 | |
1184 | // Clone |
1185 | OsiHotInfo * |
1186 | OsiHotInfo::clone() const |
1187 | { |
1188 | return new OsiHotInfo(*this); |
1189 | } |
1190 | /* Fill in useful information after strong branch |
1191 | */ |
1192 | int OsiHotInfo::updateInformation( const OsiSolverInterface * solver, const OsiBranchingInformation * info, |
1193 | OsiChooseVariable * choose) |
1194 | { |
1195 | int iBranch = branchingObject_->branchIndex()-1; |
1196 | assert (iBranch>=0&&iBranch<branchingObject_->numberBranches()); |
1197 | iterationCounts_[iBranch] += solver->getIterationCount(); |
1198 | int status; |
1199 | if (solver->isProvenOptimal()) |
1200 | status=0; // optimal |
1201 | else if (solver->isIterationLimitReached() |
1202 | &&!solver->isDualObjectiveLimitReached()) |
1203 | status=2; // unknown |
1204 | else |
1205 | status=1; // infeasible |
1206 | // Could do something different if we can't trust |
1207 | double newObjectiveValue = solver->getObjSense()*solver->getObjValue(); |
1208 | changes_[iBranch] =CoinMax(0.0,newObjectiveValue-originalObjectiveValue_); |
1209 | // we might have got here by primal |
1210 | if (choose->trustStrongForBound()) { |
1211 | if (!status&&newObjectiveValue>=info->cutoff_) { |
1212 | status=1; // infeasible |
1213 | changes_[iBranch] = 1.0e100; |
1214 | } |
1215 | } |
1216 | statuses_[iBranch] = status; |
1217 | if (!status&&choose->trustStrongForSolution()&&newObjectiveValue<choose->goodObjectiveValue()) { |
1218 | // check if solution |
1219 | const OsiSolverInterface * saveSolver = info->solver_; |
1220 | info->solver_=solver; |
1221 | const double * saveLower = info->lower_; |
1222 | info->lower_ = solver->getColLower(); |
1223 | const double * saveUpper = info->upper_; |
1224 | info->upper_ = solver->getColUpper(); |
1225 | // also need to make sure bounds OK as may not be info solver |
1226 | #if 0 |
1227 | if (saveSolver->getMatrixByCol()) { |
1228 | const CoinBigIndex * columnStart = info->columnStart_; |
1229 | assert (saveSolver->getMatrixByCol()->getVectorStarts()==columnStart); |
1230 | } |
1231 | #endif |
1232 | if (choose->feasibleSolution(info,solver->getColSolution(),solver->numberObjects(), |
1233 | const_cast<const OsiObject **> (solver->objects()))) { |
1234 | // put solution somewhere |
1235 | choose->saveSolution(solver); |
1236 | status=3; |
1237 | } |
1238 | info->solver_=saveSolver; |
1239 | info->lower_ = saveLower; |
1240 | info->upper_ = saveUpper; |
1241 | } |
1242 | // Now update - possible strong branching info |
1243 | choose->updateInformation( info,iBranch,this); |
1244 | return status; |
1245 | } |
1246 | |