00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "strategy.h"
00022
00023 #include "solver_config.h"
00024 #include "neighbourhood.h"
00025 #include "model.h"
00026 #include "cuts.h"
00027
00028 using namespace Udine;
00029
00030 inline int roundProperly(double x) { return int(std::floor(x + 0.5f)); }
00031
00032 int StrategyI::sumMissingCourseDays() {
00033 if (model.definition.type == FixDay || model.definition.type == FixPeriod)
00034 return model.definition.penaltyMinCourseDays;
00035
00036 int i = 0;
00037 for (int c = 0; c < model.instance.getCourseCount(); c++)
00038 try { i += roundProperly(getValue(model.vars.courseMinDayViolations[c])); }
00039 catch (IloAlgorithm::NotExtractedException e) { std::cerr << "Error retrieving " << model.vars.courseMinDayViolations[c].getName() << "." << std::endl; }
00040 catch (...) { std::cerr << "Unknown error retrieving " << model.vars.courseMinDayViolations[c].getName() << "." << std::endl; throw; }
00041 return i;
00042 }
00043
00044 int StrategyI::sumSingletonChecks() {
00045 if (model.definition.type == FixPeriod)
00046 return model.definition.penaltyCompactness;
00047
00048 int i = 0;
00049
00050 int limit = model.instance.getCheckCount();
00051 if ((model.definition.type == Surface && config.getParam(UseHeuristicCompactnessAtSurface))
00052 || (model.definition.type == FixDay && config.getParam(UseHeuristicCompactnessInDayDives)))
00053 limit = 1;
00054
00055 for (int u = 0; u < model.instance.getProperCurriculumCount(); u++)
00056 for (int d = 0; d < model.instance.getDayCount(); d++)
00057 for (int s = 0; s < limit; s++)
00058 try { i += roundProperly(getValue(model.vars.singletonChecks[u][d][s])); }
00059 catch (IloAlgorithm::NotExtractedException e) { std::cerr << "Error retrieving " << model.vars.singletonChecks[u][d][s].getName() << std::endl; }
00060 catch (...) { std::cerr << "Error retrieving " << model.vars.singletonChecks[u][d][s].getName() << std::endl; throw; }
00061 return i;
00062 }
00063
00064 int StrategyI::sumMissingSeats() {
00065 int i = 0;
00066 for (int r = 0; r < model.instance.getRoomCount(model.definition.type); r++)
00067 for (int c = 0; c < model.instance.getCourseCount(); c++)
00068 if (model.instance.getCourse(c).students > model.instance.getRoomPerEventCapacity(model.definition.type, r))
00069 for (int p = 0; p < model.instance.getPeriodCount(); p++)
00070 try {
00071 if (roundProperly(getValue(model.vars.x[p][r][c])) == 1)
00072 i += model.instance.getCourse(c).students - model.instance.getRoomPerEventCapacity(model.definition.type, r);
00073 }
00074 catch (IloAlgorithm::NotExtractedException e) { std::cerr << "Error retrieving " << model.vars.x[p][r][c].getName() << std::endl; }
00075 catch (...) { std::cerr << "Error retrieving " << model.vars.x[p][r][c].getName() << std::endl; throw; }
00076 return i;
00077 }
00078
00079 int StrategyI::sumExtraRoomsUsed() {
00080 int i = 0;
00081 for (int c = 0; c < model.instance.getCourseCount(); c++)
00082 for (int r = 0; r < model.instance.getRoomCount(model.definition.type); r++)
00083
00084 try { i += roundProperly(getValue(model.vars.courseRooms[c][r])); }
00085 catch (IloAlgorithm::NotExtractedException e) { std::cerr << "Error retrieving " << model.vars.courseRooms[c][r].getName() << std::endl; }
00086 catch (...) { std::cerr << "Error retrieving " << model.vars.courseRooms[c][r].getName() << std::endl; throw; }
00087 i -= model.instance.getCourseCount();
00088 return i;
00089 }
00090
00091 void StrategyI::logNeighbrouhood(Neighbourhood def) {
00092 try {
00093 std::stringstream log;
00094 log << "<neighbourhood ";
00095 log << "data='" << config.path << "' ";
00096 log << "discovered='" << config.elapsed() << "' ";
00097 log << "cost='" << def.cost << "' ";
00098 log << "penaltyCompactness='" << def.penaltyCompactness << "' ";
00099 log << "penaltyMinCourseDays='" << def.penaltyMinCourseDays << "' ";
00100 log << "LB='" << def.lowerBound << "' ";
00101 log << "'><definition>" << std::endl;
00102
00103 std::vector<CoursePeriodPair>::iterator itFixPeriod;
00104 for (itFixPeriod = def.fixPeriod.begin();
00105 itFixPeriod != def.fixPeriod.end(); itFixPeriod++) {
00106 log << "<session course='" << itFixPeriod->course << "' ";
00107 log << " period='" << itFixPeriod->period << "'/>";
00108 }
00109
00110 std::vector<CourseDayNumberTriple>::iterator itFixDay;
00111 for (itFixDay = def.fixDay.begin();
00112 itFixDay != def.fixDay.end(); itFixDay++) {
00113 log << "<session course='" << itFixDay->course << "' ";
00114 log << " day='" << itFixDay->day << "' ";
00115 log << " events='" << itFixDay->events << "'/>";
00116 }
00117
00118 log << "</definition></neighbourhood>";
00119
00120 if (model.config.getParam(UseNeighbourhoodLogging)) {
00121 env.out() << "</cplex>\n" << log.str() << "<cplex>" << std::endl;
00122 }
00123
00124 std::stringstream filename;
00125 filename << config.path << ".nei" << (int)def.cost << ".xml";
00126 std::ofstream neiFile(filename.str().c_str(), ios::app);
00127 neiFile << log.str() << std::endl;
00128 neiFile.close();
00129 }
00130 catch (...) { std::cerr << "There was an error saving the neighbourhood." << std::endl; return; }
00131 }
00132
00133
00134 Neighbourhood StrategyI::getFixPeriodNeighbourhood() {
00135 Neighbourhood next;
00136 next.type = FixPeriod;
00137 next.cost = getObjValue();
00138 next.lowerBound = getBestObjValue();
00139 next.penaltyMinCourseDays = sumMissingCourseDays();
00140 next.penaltyCompactness = sumSingletonChecks();
00141
00142 int c, p, r;
00143 for(c = 0; c < model.instance.getCourseCount(); c++)
00144 for (p = 0; p < model.instance.getPeriodCount(); p++) {
00145 CoursePeriodPair pair;
00146 pair.period = p;
00147 pair.course = c;
00148 try {
00149 IloExpr sum(env);
00150 for (r = 0; r < model.instance.getRoomCount(model.definition.type); r++)
00151 sum += model.vars.x[p][r][c];
00152 assert(std::fabs(1 - getValue(sum)) < 0.0001 || std::fabs(getValue(sum)) < 0.0001);
00153 if (roundProperly(getValue(sum)) == 1)
00154 next.fixPeriod.push_back(pair);
00155 else
00156 next.preprocessAway.push_back(pair);
00157 if (model.definition.type == FixDay)
00158 assert(roundProperly(getValue(sum)) == roundProperly(getValue(model.vars.coursePeriods[c][p])));
00159 } catch (IloAlgorithm::NotExtractedException e) {
00160 std::cerr << "Error retrieving " << model.vars.x[p][r][c].getName() << "." << std::endl;
00161 } catch (...) {
00162 std::cerr << "Unknown error retrieving " << model.vars.x[p][r][c].getName() << "." << std::endl;
00163 throw;
00164 }
00165 }
00166 return next;
00167 }
00168
00169
00170 Neighbourhood StrategyI::getFixDayNeighbourhood() {
00171 Neighbourhood next;
00172 next.type = FixDay;
00173 next.cost = getObjValue();
00174 next.lowerBound = getBestObjValue();
00175 next.penaltyMinCourseDays = sumMissingCourseDays();
00176 next.penaltyCompactness = sumSingletonChecks();
00177 int c, d, p, r;
00178
00179 for(c = 0; c < model.instance.getCourseCount(); c++) {
00180 CoursePeriodPair pair;
00181 pair.course = c;
00182 CourseDayNumberTriple triple;
00183 triple.course = c;
00184
00185 for (d = 0; d < model.instance.getDayCount(); d++) {
00186 triple.day = d;
00187 triple.events = 0;
00188 bool ok = true;
00189
00190 for (p = d * model.instance.getPeriodsPerDayCount();
00191 p < (d + 1) * model.instance.getPeriodsPerDayCount(); p++)
00192 try {
00193 IloExpr sum(env);
00194 for (r = 0; r < model.instance.getRoomCount(model.definition.type); r++)
00195 sum += model.vars.x[p][r][c];
00196 triple.events += roundProperly(getValue(sum));
00197 } catch (IloAlgorithm::NotExtractedException e) {
00198 std::cerr << "Error retrieving value of x for c = " << c << " and d = " << d << "." << std::endl;
00199 ok = false;
00200 } catch (...) {
00201 std::cerr << "Unknown error retrieving value of x for c = " << c << " and d = " << d << "." << std::endl;
00202 throw;
00203 }
00204
00205 if (triple.events > 0) {
00206 next.fixDay.push_back(triple);
00207 } else if (ok)
00208 for (p = d * model.instance.getPeriodsPerDayCount();
00209 p < (d + 1) * model.instance.getPeriodsPerDayCount();
00210 p++) {
00211 pair.period = p;
00212 next.preprocessAway.push_back(pair);
00213 }
00214 }
00215 }
00216
00217 return next;
00218 }
00219
00220
00221 void StrategyI::runDiver(Neighbourhood next) {
00222
00223 try {
00224
00225 IloModel subMIPModel(env);
00226 Model subMIP(subMIPModel, model.config, model.instance, model.conflictGraph, next);
00227 IloCplex cplex(subMIPModel);
00228
00229 if (model.config.getParam(UseLpFilesExport)) {
00230 std::stringstream filename;
00231 filename << config.path << "." << next.type << next.cost << ".lp";
00232 cplex.exportModel(filename.str().c_str());
00233 }
00234
00235 env.out() << std::endl << "Diving into the " << next.type << " neighbouhood from ";
00236 env.out() << model.definition.type << " ..." << std::endl;
00237
00238 StrategyI *strategy = NULL;
00239 if (next.type == FixDay)
00240 strategy = new (env) SolutionPolishingStrategyI(env, subMIP, config);
00241 else
00242 strategy = new (env) SolutionSavingStrategyI(env, subMIP, config);
00243 cplex.use(IloCplex::Callback(strategy));
00244
00245 config.apply(cplex, next.type);
00246 cplex.solve();
00247 strategy->finishOff();
00248 }
00249 catch (IloException& e) { std::cerr << "Solver (Strategy): Concert exception caught: " << e << std::endl; }
00250 catch (...) { std::cerr << "Solver (Strategy): Unknown exception caught." << std::endl; }
00251 }
00252
00253
00254
00255
00256 IloCplex::Callback AnytimeStrategy(IloEnv &env, Model& s, Config &configuration) {
00257 return (IloCplex::Callback(new (env) AnytimeStrategyI(env, s, configuration)));
00258 }
00259
00260
00261 void AnytimeStrategyI::main() {
00262 if ( config.anytimeDivingOnset[FixPeriod] >= 0
00263 && config.elapsed() > config.anytimeDivingOnset[FixPeriod]) {
00264 Neighbourhood def = getFixPeriodNeighbourhood();
00265 logNeighbrouhood(def);
00266 runDiver(def);
00267 }
00268 if ( config.anytimeDivingOnset[FixDay] >= 0
00269 && config.elapsed() > config.anytimeDivingOnset[FixDay]) {
00270 Neighbourhood def = getFixDayNeighbourhood();
00271 logNeighbrouhood(def);
00272 runDiver(def);
00273 }
00274 }
00275
00276 void AnytimeStrategyI::finishOff() {
00277 }
00278
00279
00280
00281
00282 IloCplex::Callback ContractStrategy(IloEnv &env, Model& s, Config &configuration) {
00283 return (IloCplex::Callback(new (env) ContractStrategyI(env, s, configuration)));
00284 }
00285
00286
00287 void ContractStrategyI::main() {
00288 fixDayNeighbs.push_back(getFixDayNeighbourhood());
00289 fixPeriodNeighbs.push_back(getFixPeriodNeighbourhood());
00290 logNeighbrouhood(fixDayNeighbs.back());
00291 }
00292
00293 void ContractStrategyI::finishOff() {
00294 int counter = 0;
00295 while (config.elapsed() < config.contractTimelimit
00296 && !fixPeriodNeighbs.empty()
00297 && counter < config.getCount(FixPeriodDiveFromSurface))
00298 try {
00299 runDiver(fixPeriodNeighbs.back());
00300 fixPeriodNeighbs.pop_back();
00301 counter += 1;
00302 } catch (std::exception &e) { std::cerr << "Solver (FixPeriod Dives): " << e.what() << std::endl; }
00303 counter = 0;
00304 while (config.elapsed() < config.contractTimelimit
00305 && !fixDayNeighbs.empty()
00306 && counter < config.getCount(FixDayDiveFromSurface)) {
00307 try {
00308 runDiver(fixDayNeighbs.back());
00309 fixDayNeighbs.pop_back();
00310 counter += 1;
00311 } catch (std::exception &e) { std::cerr << "Solver (FixDay Dives): " << e.what() << std::endl; }
00312 }
00313 }
00314
00315
00316
00317 IloCplex::Callback SolutionSavingStrategy(IloEnv &env, Model& s, Config &configuration) {
00318 return (IloCplex::Callback(new (env) SolutionSavingStrategyI(env, s, configuration)));
00319 }
00320
00321 void SolutionSavingStrategyI::main() {
00322 try {
00323 std::stringstream log;
00324 std::stringstream sol;
00325
00326 int pRoomCapacity = sumMissingSeats();
00327 int pMinDays = sumMissingCourseDays();
00328 int pCompactness = sumSingletonChecks();
00329 int pRoomStability = sumExtraRoomsUsed();
00330 int pTotal =
00331 config.getWeights(model.definition.type).wMinDays * pMinDays +
00332 config.getWeights(model.definition.type).wCompactness * pCompactness +
00333 config.getWeights(model.definition.type).wRoomCapacity * pRoomCapacity +
00334 config.getWeights(model.definition.type).wRoomStability * pRoomStability;
00335
00336 log << "<solution submodelCost='" << getObjValue() << "' ";
00337 log << "cost='" << pTotal << "' ";
00338 log << "data='" << config.path << "' ";
00339 log << "type='" << model.definition.type << "' ";
00340 log << "discovered='" << config.elapsed() << "' ";
00341 log << "neighbourhoodLB='" << getBestObjValue() << "' ";
00342 log << "penaltyRoomCapacity='" << pRoomCapacity << "' ";
00343 log << "penaltyMinCourseDays='" << pMinDays << "' ";
00344 log << "penaltyCompactness='" << pCompactness << "' ";
00345 log << "penaltyRoomStability='" << pRoomStability << "' ";
00346
00347 log << ">\n";
00348
00349 int c, p, r;
00350 for(c = 0; c < model.instance.getCourseCount(); c++)
00351 for(p = 0; p < model.instance.getPeriodCount(); p++) {
00352 int day = (int)std::floor(float(p / model.instance.getPeriodsPerDayCount()));
00353 int periodWithin = p % model.instance.getPeriodsPerDayCount();
00354 for(r = 0; r < model.instance.getRoomCount(model.definition.type); r++)
00355 try {
00356 if (roundProperly(getValue(model.vars.x[p][r][c])) == 1) {
00357 log << "<session course='" << model.instance.getCourse(c).name;
00358 log << "' room='" << model.instance.getRoomName(r);
00359 log << "' period='" << p;
00360 log << "' day='" << day;
00361 log << "' periodWithin='" << periodWithin;
00362 log << "'/> ";
00363 sol << model.instance.getCourse(c).name << " ";
00364 sol << model.instance.getRoomName(r) << " ";
00365 sol << day << " " << periodWithin << "\n";
00366 }
00367 } catch (IloAlgorithm::NotExtractedException e) { std::cerr << "Error retrieving " << model.vars.x[p][r][c].getName() << "." << std::endl; }
00368 catch (...) { std::cerr << "Unknown error retrieving " << model.vars.x[p][r][c].getName() << "." << std::endl; throw; }
00369
00370 }
00371
00372 log << "</solution>\n";
00373
00374 env.out() << "</cplex>\n" << log.str();
00375 env.out() << "\n<cplex>" << std::endl;
00376
00377 std::stringstream xmlname;
00378 xmlname << config.path << ".sol" << pTotal << ".xml";
00379 std::ofstream solFile(xmlname.str().c_str(), ios::out);
00380 solFile << log.str() << std::endl;
00381 solFile.close();
00382
00383 std::stringstream solname;
00384 solname << config.path << ".sol" << pTotal << ".out";
00385 solFile.open(solname.str().c_str(), ios::out);
00386 solFile << sol.str() << std::endl;
00387 solFile.close();
00388
00389 config.addSolutionCost(model.definition.type, pTotal);
00390 }
00391 catch (IloException& e) { env.error() << "Concert error: " << e << std::endl; }
00392 catch (...) { env.error() << "Unknown error: " << std::endl; throw; }
00393 }
00394
00395 void SolutionSavingStrategyI::finishOff() {
00396 }
00397
00398
00399
00400
00401 IloCplex::Callback SolutionPolishingStrategy(IloEnv &env, Model& s, Config &configuration) {
00402 return (IloCplex::Callback(new (env) SolutionPolishingStrategyI(env, s, configuration)));
00403 }
00404
00405 void SolutionPolishingStrategyI::main() {
00406 config.addSolutionCost(model.definition.type, getObjValue());
00407 fixPeriodNeighbs.push_back(getFixPeriodNeighbourhood());
00408 }
00409
00410 void SolutionPolishingStrategyI::finishOff() {
00411 int counter = 0;
00412 while ( !fixPeriodNeighbs.empty()
00413 && counter < config.getCount(FixPeriodDiveFromFixDay)) {
00414 runDiver(fixPeriodNeighbs.back());
00415 fixPeriodNeighbs.pop_back();
00416 counter += 1;
00417 }
00418 }