00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "cuts.h"
00022
00023 #include <cmath>
00024 #include <iostream>
00025 #include <algorithm>
00026 #include <ilcplex/ilocplex.h>
00027
00028 #include "solver_config.h"
00029
00030 using namespace Udine;
00031
00032 IloCplex::Callback Udine::CutManager(IloEnv env, Udine::Model& s, Udine::Config &config) {
00033 return (IloCplex::Callback(new (env) Udine::CutManagerI(env, s, config)));
00034 }
00035
00036 void CutManagerI::main() {
00037 int thisTime = 0;
00038
00039 if (totalCalls >= 2 * (getNnodes() + 1)) return;
00040
00041 std::cout << "Mycuts: Running separation routines ... " << std::endl;
00042
00043 if (config.getParam(UseHeuristicCompactnessAtSurface)
00044 && (totalCalls <= 5 * (getNnodes() + 1)))
00045 thisTime += genCutsFromPatternsWithHeuristicAtSurface();
00046
00047 if (thisTime > 0)
00048 std::cout << "Mycuts: Added " << thisTime << " cuts from patterns (node " << getNnodes() << ", call " << totalCalls << ")" << std::endl;
00049
00050 if (active || totalCalls % config.getFrequency(CutsFromPregeneratedCliques) == 1)
00051 thisTime += genCutsFromCliquePool();
00052
00053 if (config.getParam(UseObjectiveComponents))
00054 thisTime += genCutsFromComponents();
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 if (thisTime > 0)
00066 std::cout << "Mycuts: Added " << thisTime << " cuts in total (node " << getNnodes() << ", call " << totalCalls << ")" << std::endl;
00067
00068 active = (thisTime > 0);
00069 totalCalls += 1;
00070 }
00071
00072
00073 int CutManagerI::genCutsFromCliquePool() {
00074
00075 int cuts = 0;
00076
00077 int p, clique, ci;
00078 std::vector< std::vector<int> > &cs = solver.conflictGraph.cliques;
00079 std::vector<Vertex> &vs = solver.conflictGraph.vs;
00080 std::vector<Edge> &es = solver.conflictGraph.es;
00081
00082 float value = 0;
00083 for(p = 0; p < solver.instance.getPeriodCount(); p++)
00084 for(clique = 0; clique < cs.size(); clique++) {
00085 IloExpr sum(solver.env);
00086 for(ci = 0; ci < cs.at(clique).size(); ci++)
00087 sum += solver.vars.coursePeriods[cs[clique][ci]][p];
00088
00089 if (getValue(sum) <= 1) { sum.end(); continue; }
00090 CliqueCutIdentifier id(p, clique);
00091 if (cliquePool.find(id) != cliquePool.end()) { sum.end(); continue; }
00092 IloConstraint cut(sum <= 1);
00093 addLocal(cut);
00094 cuts += 1;
00095 cliquePool[id] = true;
00096 }
00097
00098 return cuts;
00099 }
00100
00101
00102 int CutManagerI::genCutsFromComponents() {
00103
00104 int cuts = 0;
00105
00106 if (getValue(solver.vars.penaltyRoomStability)
00107 - std::floor(getValue(solver.vars.penaltyRoomStability)) > 0.1) {
00108 addLocal(solver.vars.penaltyRoomStability >= std::ceil(getValue(solver.vars.penaltyRoomStability)));
00109 cuts += 1;
00110 }
00111
00112 if (getValue(solver.vars.penaltyRoomCapacity)
00113 - std::floor(getValue(solver.vars.penaltyRoomCapacity)) > 0.1) {
00114 addLocal(solver.vars.penaltyRoomCapacity >= std::ceil(getValue(solver.vars.penaltyRoomCapacity)));
00115 cuts += 1;
00116 }
00117
00118 if (getValue(solver.vars.penaltyPeriodSingletons)
00119 - std::floor(getValue(solver.vars.penaltyPeriodSingletons)) > 0.1) {
00120 addLocal(solver.vars.penaltyPeriodSingletons >= std::ceil(getValue(solver.vars.penaltyPeriodSingletons)));
00121 cuts += 1;
00122 }
00123
00124 if (getValue(solver.vars.penaltyPeriodSpread)
00125 - std::floor(getValue(solver.vars.penaltyPeriodSpread)) > 0.1) {
00126 addLocal(solver.vars.penaltyPeriodSpread >= std::ceil(getValue(solver.vars.penaltyPeriodSpread)));
00127 cuts += 1;
00128 }
00129
00130 return cuts;
00131 }
00132
00133
00134 int CutManagerI::genCutsFromTriangles() {
00135
00136 int cuts = 0;
00137
00138 std::cout << "Mycuts: Starting cut generation. (Call " << totalCalls << ")" << std::endl;
00139
00140 std::vector< std::vector<int> > &cs = solver.conflictGraph.cliques;
00141 std::vector<Vertex> &vs = solver.conflictGraph.vs;
00142 std::vector<Edge> &es = solver.conflictGraph.es;
00143
00144 for (int u = 0; u < vs.size(); u++)
00145 for (std::set<int>::iterator vi = vs[u].adj.begin(); vi != vs[u].adj.end(); vi++)
00146 if (u < (*vi)) {
00147 for(int p = 0; p < solver.instance.getPeriodCount(); p++)
00148 if (getValue(solver.vars.coursePeriods[u][p] + solver.vars.coursePeriods[*vi][p]) > 1.0) {
00149 std::cout << "Violated for two courses" << std::endl;
00150 }
00151 for (std::set<int>::iterator wi = vs[*vi].adj.begin(); wi != vs[*vi].adj.end(); wi++)
00152 if ((*vi < (*wi)) && (vs[(*wi)].adj.find(u) != vs[(*wi)].adj.end()))
00153 for(int p = 0; p < solver.instance.getPeriodCount(); p++) {
00154 IloExpr sum(solver.env);
00155 sum += solver.vars.coursePeriods[u][p] +
00156 solver.vars.coursePeriods[*vi][p] +
00157 solver.vars.coursePeriods[*wi][p];
00158 if (getValue(sum) > 1.0 && genCutsFromTriangleNeighbourhood(u, *vi, *wi, p)) continue;
00159 if (getValue(sum) <= 1.1) continue;
00160 IloConstraint cut(sum <= 1);
00161 addLocal(cut);
00162 cuts += 1;
00163 sum.end();
00164 }
00165 }
00166
00167 return cuts;
00168 }
00169
00170
00171 int CutManagerI::genCutsFromTriangleNeighbourhood(int u, int v, int w, int p) {
00172 int cuts = 0;
00173
00174 std::vector< std::vector<int> > &cs = solver.conflictGraph.cliques;
00175 std::vector<Vertex> &vs = solver.conflictGraph.vs;
00176
00177 std::vector<int> clique;
00178 clique.push_back(u);
00179 clique.push_back(v);
00180 clique.push_back(w);
00181
00182 std::cout << "Mycuts: Growing from " << u << " " << v << " " << w << std::endl;
00183
00184 std::vector<int> cliqueUpdates;
00185
00186 while (1) {
00187 cliqueUpdates.clear();
00188
00189
00190 std::vector<int>::iterator cliqueElement = clique.begin();
00191 for (; cliqueElement != clique.end(); cliqueElement++) {
00192
00193 std::set<int>::iterator it = vs[*cliqueElement].adj.begin();
00194 for (; it != vs[*cliqueElement].adj.end(); it++) {
00195 if (std::find(clique.begin(), clique.end(), *it) != clique.end()) {
00196 bool add = true;
00197
00198
00199
00200 if (add) cliqueUpdates.push_back(*it);
00201 }
00202 }
00203 }
00204
00205 if (cliqueUpdates.size() == 0) break;
00206 std::copy(cliqueUpdates.begin(), cliqueUpdates.end(), std::back_inserter(clique));
00207 std::sort(clique.begin(), clique.end());
00208 }
00209
00210 if (clique.size() <= 3) return false;
00211 std::sort(clique.begin(), clique.end());
00212 if (std::find(cs.begin(), cs.end(), clique) != cs.end()) return false;
00213 else cs.push_back(clique);
00214
00215 IloExpr sum(solver.env);
00216 for (std::vector<int>::iterator cliqueElement = clique.begin(); cliqueElement != clique.end(); cliqueElement++)
00217 sum += solver.vars.coursePeriods[*cliqueElement][p];
00218 IloConstraint cut(sum <= 1);
00219 addLocal(cut);
00220 totalCutsAdded += 1;
00221 sum.end();
00222
00223 std::cout << "Mycuts: Found a cut dynamically from a triangle and added it to the pool (from call " << totalCalls << ")" << std::endl;
00224 }
00225
00226
00227 int CutManagerI::genCutsFromPatternsWithHeuristicAtSurface() {
00228
00229 int cuts = 0;
00230
00231 int u, ui, d, pd;
00232 int pati;
00233 for(u = 0; u < solver.instance.getProperCurriculumCount(); u++)
00234 for(d = 0; d < solver.instance.getDayCount(); d++) {
00235
00236 try {
00237
00238 float rhs = getValue(solver.vars.singletonChecks[u][d][0]);
00239
00240
00241 for (pati = 0; pati < solver.instance.getPatterns().size(); pati++) {
00242 float lhs = 0;
00243 for (pd = 0; pd < solver.instance.getPeriodsPerDayCount(); pd++) {
00244 IloInt p = d * solver.instance.getPeriodsPerDayCount() + pd;
00245 float factor = 0;
00246 for (ui = 0; ui < solver.instance.getCurriculum(u).courseIds.size(); ui++)
00247 factor += getValue(solver.vars.coursePeriods[solver.instance.getCurriculum(u).courseIds.at(ui)][p]);
00248 lhs += solver.instance.getPatterns()[pati].coefs[pd] * factor;
00249 }
00250 lhs -= solver.instance.getPatterns()[pati].rhs;
00251 lhs *= solver.instance.getPatterns()[pati].penalty;
00252
00253 if (lhs - rhs > 0) {
00254 IloExpr lhsExpr(solver.env);
00255 for (ui = 0; ui < solver.instance.getCurriculum(u).courseIds.size(); ui++) {
00256 IloInt c = solver.instance.getCurriculum(u).courseIds.at(ui);
00257 for (pd = 0; pd < solver.instance.getPeriodsPerDayCount(); pd++) {
00258 lhsExpr += solver.instance.getPatterns()[pati].coefs[pd] *
00259 solver.vars.coursePeriods[c][d * solver.instance.getPeriodsPerDayCount() + pd];
00260 }
00261 }
00262 lhsExpr -= solver.instance.getPatterns()[pati].rhs;
00263 lhsExpr *= solver.instance.getPatterns()[pati].penalty;
00264 IloConstraint cut(lhsExpr - solver.vars.singletonChecks[u][d][0] <= 0);
00265 addLocal(cut);
00266 lhsExpr.end();
00267 cuts += 1;
00268 }
00269 }
00270
00271 } catch (...) {
00272 std::cerr << "Solver: An exception intercepted." << std::endl;
00273 }
00274 }
00275
00276 return cuts;
00277 }
00278
00279
00280 int CutManagerI::genCutsFromPatterns() {
00281
00282 int cuts = 0;
00283
00284 int u, ui, d, pd;
00285 int s, pati;
00286 for(u = 0; u < solver.instance.getProperCurriculumCount(); u++)
00287 for(d = 0; d < solver.instance.getDayCount(); d++) {
00288 IloExpr rhsExpr(solver.env);
00289 try {
00290
00291 for(s = 0; s < solver.instance.getCheckCount(); s++)
00292 rhsExpr += solver.vars.singletonChecks[u][d][s];
00293 float rhs = getValue(rhsExpr);
00294
00295
00296 for (pati = 0; pati < solver.instance.getPatterns().size(); pati++) {
00297 float lhs = 0;
00298 for (pd = 0; pd < solver.instance.getPeriodsPerDayCount(); pd++) {
00299 IloInt p = d * solver.instance.getPeriodsPerDayCount() + pd;
00300 float factor = 0;
00301 for (ui = 0; ui < solver.instance.getCurriculum(u).courseIds.size(); ui++)
00302 factor += getValue(solver.vars.coursePeriods[solver.instance.getCurriculum(u).courseIds.at(ui)][p]);
00303 lhs += solver.instance.getPatterns()[pati].coefs[pd] * factor;
00304 }
00305 lhs -= solver.instance.getPatterns()[pati].rhs;
00306 lhs *= solver.instance.getPatterns()[pati].penalty;
00307
00308 if (lhs - rhs > 0) {
00309 IloExpr lhsExpr(solver.env);
00310 for (ui = 0; ui < solver.instance.getCurriculum(u).courseIds.size(); ui++) {
00311 IloInt c = solver.instance.getCurriculum(u).courseIds.at(ui);
00312 for (pd = 0; pd < solver.instance.getPeriodsPerDayCount(); pd++) {
00313 lhsExpr += solver.instance.getPatterns()[pati].coefs[pd] *
00314 solver.vars.coursePeriods[c][d * solver.instance.getPeriodsPerDayCount() + pd];
00315 }
00316 }
00317 lhsExpr -= solver.instance.getPatterns()[pati].rhs;
00318 lhsExpr *= solver.instance.getPatterns()[pati].penalty;
00319 IloConstraint cut(lhsExpr - rhsExpr <= 0);
00320 addLocal(cut);
00321 lhsExpr.end();
00322 cuts += 1;
00323 }
00324 }
00325
00326 } catch (...) {
00327 std::cerr << "Solver: An exception intercepted." << std::endl;
00328 }
00329 rhsExpr.end();
00330 }
00331
00332 return cuts;
00333 }