int CbcBranchUserDecision::bestBranch (CbcBranchingObject ** objects, int numberObjects, int numberUnsatisfied, double * changeUp, int * numberInfeasibilitiesUp, double * changeDown, int * numberInfeasibilitiesDown, double objectiveValue) { int bestWay=0; int whichObject = -1; if (numberObjects) { CbcModel * model = objects[0]->model(); // at continuous //double continuousObjective = model->getContinuousObjective(); //int continuousInfeasibilities = model->getContinuousInfeasibilities(); // average cost to get rid of infeasibility //double averageCostPerInfeasibility = //(objectiveValue-continuousObjective)/ //(double) (abs(continuousInfeasibilities-numberUnsatisfied)+1); /* beforeSolution is : 0 - before any solution n - n heuristic solutions but no branched one -1 - branched solution found */ int numberSolutions = model->getSolutionCount(); double cutoff = model->getCutoff(); int method=0; int i; if (numberSolutions) { int numberHeuristic = model->getNumberHeuristicSolutions(); if (numberHeuristic<numberSolutions) { method = 1; } else { method = 2; // look further for ( i = 0 ; i < numberObjects ; i++) { int numberNext = numberInfeasibilitiesUp[i]; if (numberNext<numberUnsatisfied) { int numberUp = numberUnsatisfied - numberInfeasibilitiesUp[i]; double perUnsatisfied = changeUp[i]/(double) numberUp; double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied; if (estimatedObjective<cutoff) method=3; } numberNext = numberInfeasibilitiesDown[i]; if (numberNext<numberUnsatisfied) { int numberDown = numberUnsatisfied - numberInfeasibilitiesDown[i]; double perUnsatisfied = changeDown[i]/(double) numberDown; double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied; if (estimatedObjective<cutoff) method=3; } } } method=2; } else { method = 0; } // Uncomment next to force method 4 //method=4; /* Methods : 0 - fewest infeasibilities 1 - largest min change in objective 2 - as 1 but use sum of changes if min close 3 - predicted best solution 4 - take cheapest up branch if infeasibilities same */ int bestNumber=COIN_INT_MAX; double bestCriterion=-1.0e50; double alternativeCriterion = -1.0; double bestEstimate = 1.0e100; switch (method) { case 0: // could add in depth as well for ( i = 0 ; i < numberObjects ; i++) { int thisNumber = CoinMin(numberInfeasibilitiesUp[i],numberInfeasibilitiesDown[i]); if (thisNumber<=bestNumber) { int betterWay=0; if (numberInfeasibilitiesUp[i]<numberInfeasibilitiesDown[i]) { if (numberInfeasibilitiesUp[i]<bestNumber) { betterWay = 1; } else { if (changeUp[i]<bestCriterion) betterWay=1; } } else if (numberInfeasibilitiesUp[i]>numberInfeasibilitiesDown[i]) { if (numberInfeasibilitiesDown[i]<bestNumber) { betterWay = -1; } else { if (changeDown[i]<bestCriterion) betterWay=-1; } } else { // up and down have same number bool better=false; if (numberInfeasibilitiesUp[i]<bestNumber) { better=true; } else if (numberInfeasibilitiesUp[i]==bestNumber) { if (CoinMin(changeUp[i],changeDown[i])<bestCriterion) better=true;; } if (better) { // see which way if (changeUp[i]<=changeDown[i]) betterWay=1; else betterWay=-1; } } if (betterWay) { bestCriterion = CoinMin(changeUp[i],changeDown[i]); bestNumber = thisNumber; whichObject = i; bestWay = betterWay; } } } break; case 1: for ( i = 0 ; i < numberObjects ; i++) { int betterWay=0; if (changeUp[i]<=changeDown[i]) { if (changeUp[i]>bestCriterion) betterWay=1; } else { if (changeDown[i]>bestCriterion) betterWay=-1; } if (betterWay) { bestCriterion = CoinMin(changeUp[i],changeDown[i]); whichObject = i; bestWay = betterWay; } } break; case 2: for ( i = 0 ; i < numberObjects ; i++) { double change = CoinMin(changeUp[i],changeDown[i]); double sum = changeUp[i] + changeDown[i]; bool take=false; if (change>1.1*bestCriterion) take=true; else if (change>0.9*bestCriterion&&sum+change>bestCriterion+alternativeCriterion) take=true; if (take) { if (changeUp[i]<=changeDown[i]) { if (changeUp[i]>bestCriterion) bestWay=1; } else { if (changeDown[i]>bestCriterion) bestWay=-1; } bestCriterion = change; alternativeCriterion = sum; whichObject = i; } } break; case 3: for ( i = 0 ; i < numberObjects ; i++) { int numberNext = numberInfeasibilitiesUp[i]; if (numberNext<numberUnsatisfied) { int numberUp = numberUnsatisfied - numberInfeasibilitiesUp[i]; double perUnsatisfied = changeUp[i]/(double) numberUp; double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied; if (estimatedObjective<bestEstimate) { bestEstimate = estimatedObjective; bestWay=1; whichObject=i; } } numberNext = numberInfeasibilitiesDown[i]; if (numberNext<numberUnsatisfied) { int numberDown = numberUnsatisfied - numberInfeasibilitiesDown[i]; double perUnsatisfied = changeDown[i]/(double) numberDown; double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied; if (estimatedObjective<bestEstimate) { bestEstimate = estimatedObjective; bestWay=-1; whichObject=i; } } } break; case 4: // if number infeas same then cheapest up // first get best number or when going down // now choose smallest change up amongst equal number infeas for ( i = 0 ; i < numberObjects ; i++) { int thisNumber = CoinMin(numberInfeasibilitiesUp[i],numberInfeasibilitiesDown[i]); if (thisNumber<=bestNumber) { int betterWay=0; if (numberInfeasibilitiesUp[i]<numberInfeasibilitiesDown[i]) { if (numberInfeasibilitiesUp[i]<bestNumber) { betterWay = 1; } else { if (changeUp[i]<bestCriterion) betterWay=1; } } else if (numberInfeasibilitiesUp[i]>numberInfeasibilitiesDown[i]) { if (numberInfeasibilitiesDown[i]<bestNumber) { betterWay = -1; } else { if (changeDown[i]<bestCriterion) betterWay=-1; } } else { // up and down have same number bool better=false; if (numberInfeasibilitiesUp[i]<bestNumber) { better=true; } else if (numberInfeasibilitiesUp[i]==bestNumber) { if (CoinMin(changeUp[i],changeDown[i])<bestCriterion) better=true;; } if (better) { // see which way if (changeUp[i]<=changeDown[i]) betterWay=1; else betterWay=-1; } } if (betterWay) { bestCriterion = CoinMin(changeUp[i],changeDown[i]); bestNumber = thisNumber; whichObject = i; bestWay = betterWay; } } } bestCriterion=1.0e50; for ( i = 0 ; i < numberObjects ; i++) { int thisNumber = numberInfeasibilitiesUp[i]; if (thisNumber==bestNumber&&changeUp) { if (changeUp[i]<bestCriterion) { bestCriterion = changeUp[i]; whichObject = i; bestWay = 1; } } } break; } // set way in best if (whichObject>=0) objects[whichObject]->way(bestWay); } return whichObject; }