00001 /* 00002 * Copyright 2007 Martin von Gagern 00003 * 00004 * 00005 * This file is part of bande. 00006 * 00007 * bande is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 3 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * bande is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 00022 /** 00023 * @file 00024 * Implementation of class bande::BranchControl. 00025 */ 00026 00027 #include "bande.hh" 00028 00029 namespace bande { 00030 00031 /** 00032 * Run search, return when all solutions have been found. 00033 * 00034 * This is the public interface to start the branching algorithm. 00035 */ 00036 void BranchControl::run() { 00037 statistics.reset(); 00038 branch(0); 00039 } 00040 00041 /** 00042 * Recursive method to search one branch. 00043 * 00044 * This is the central method of the whole program. 00045 * Bit mask 1 in Settings::debug will enable debug output here. 00046 * 00047 * For every invocation, IntegerProgram::solve will be called to 00048 * determine whether the LP relaxation of the current problem is 00049 * feasible, which is a neccessary condition for any feasible 00050 * integral solution. If the LP is infeasible, the branch will 00051 * return immediately. 00052 * 00053 * If the current LP is feasible and all variables are fixed to 00054 * integral values, then we have a new solution, which concludes the 00055 * current branch as well. 00056 * 00057 * If the LP is feasible but not all variables have been fixed, one 00058 * variable is chosen using branchCol() and used for a case 00059 * destinction, leading to two subtrees which are searched by 00060 * recursive invocations. 00061 * 00062 * @param depth number of branching points between the root of the 00063 * search tree and the current subtree. 00064 */ 00065 void BranchControl::branch(int depth) { 00066 00067 #ifndef NDEBUG 00068 if (Settings::debug & 1) 00069 for (int i = 0; i < depth; ++i) std::cerr << '.'; 00070 #endif 00071 00072 // Case 1: current LP infeasible, therefor no solutions here. 00073 if (!ip.solve()) { // see if current problem is feasible at all 00074 DBG(1, " infeasible"); 00075 statistics.infeasible(depth); 00076 return; 00077 } 00078 00079 int bcol = branchCol(); // choose one column to branch upon 00080 00081 // Case 2: no branching column, which means all variables are fixed 00082 if (bcol == -1) { 00083 DBG(1, " SOLUTION"); 00084 ip.mkIntSolution(); // round double solution to int solution 00085 if (!ip.checkIntSolution()) { // this should be a valid solution! 00086 std::cerr << "ERR!" << std::endl; 00087 ip.dumpSolution(); 00088 exit(EXIT_FAILURE); 00089 } 00090 sols.solution(ip); // remember this solution 00091 statistics.solution(depth); // update the statistics 00092 return; 00093 } 00094 00095 // Case 3: we chose a branching column, bcol, and will branch upon this 00096 // Determine a suitable value at which to split, taking care of 00097 // rounding issues by avoiding new bounds that would coincide with 00098 // current bounds. 00099 int bval = (int)floor(ip.getColSolution(bcol)); 00100 if (bval == ip.getColUpper(bcol)) --bval; 00101 if (bval < ip.getColLower(bcol)) bval = ip.getColLower(bcol); 00102 DBG(1, ip.getColName(bcol) << " [" << bcol << "] = " << bval 00103 << " (" << ip.getColSolution(bcol) << ")"); 00104 ++depth; // we are about to descend one level 00105 UndoState state = um.save(); // create checkpoint for undoing things 00106 ip.setColLower(um, bcol, bval + 1); // first subtree: x_bcol >= bval+1 00107 branch(depth); // search first subtree recursively 00108 state.restore(); // undo any changes from that subtree 00109 ip.setColUpper(um, bcol, bval); // second subtree: x_bcol <= bval 00110 branch(depth); // search second subtree recursively 00111 } 00112 00113 /** 00114 * Choose branching column. 00115 * 00116 * When there are free variables left, one of them has to be chosen 00117 * as the one on which the case destinction for branching will be 00118 * made. This method implements a heuristic to make this choice. 00119 * 00120 * The heuristic contains of two parts. First a column that 00121 * currently has a "most fractional" solution is chosen, where most 00122 * fractional means largest distance to nearest integer. If all 00123 * columns are integral or near enough, then the second part will 00124 * chose a column with minimum difference between upper and lower 00125 * bound, in order to increase the number of fixed columns soon. 00126 * 00127 * @return the index of the chosen column, 00128 * or -1 if all columns are already fixed 00129 */ 00130 int BranchControl::branchCol() { 00131 int bcol = -1; 00132 00133 // Part 1: Try to find a column farthest from being integral. 00134 double limit = 1e-5; // due to rounding, treat almost int as int 00135 for (int col = 0; col < ip.getNumCols(); ++col) { 00136 double s = ip.getColSolution(col); 00137 double f = floor(s); 00138 double d = s - f; 00139 d *= 1 - d; 00140 // d now is the product of differences to the nearest integers. 00141 // This value will be maximal for numbers halfway between 00142 // integers, zero for integers, and monotone in between. 00143 if (limit < d) { // we have a now best choice 00144 limit = d; 00145 bcol = col; 00146 } 00147 } 00148 if (bcol >= 0) return bcol; // Part 1 succeeded, search no further 00149 00150 // Part 2: All solutions are (almost) integral, choose one with 00151 // smallest difference between upper and lower bound. This will 00152 // help make that variable completely fixed in the near future. 00153 unsigned minGap = std::numeric_limits<unsigned>::max(); 00154 for (int col = 0; col < ip.getNumCols(); ++col) { 00155 std::pair<int, int> bounds = ip.getColBounds(col); 00156 if (bounds.second == bounds.first) continue; // already fixed 00157 if (minGap > unsigned(bounds.second - bounds.first)) { 00158 minGap = bounds.second - bounds.first; 00159 bcol = col; 00160 } 00161 } 00162 00163 // By now we either have a choice from Part 2, or all columns are 00164 // fixed and we return the initial value of bcol, which was -1. 00165 return bcol; 00166 } 00167 00168 }
1.6.0