00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "base/hash.h"
00029 #include "base/hash.h"
00030 #include <string>
00031 #include <utility>
00032 #include <vector>
00033
00034 #include "base/callback.h"
00035 #include "base/commandlineflags.h"
00036 #include "base/commandlineflags.h"
00037 #include "base/integral_types.h"
00038 #include "base/logging.h"
00039 #include "base/scoped_ptr.h"
00040 #include "base/stringprintf.h"
00041 #include "base/concise_iterator.h"
00042 #include "base/map-util.h"
00043 #include "base/hash.h"
00044 #include "constraint_solver/constraint_solveri.h"
00045 #include "graph/shortestpaths.h"
00046 #include "util/tuple_set.h"
00047 #include "base/random.h"
00048
00049
00050 DEFINE_int32(clients, 0, "Number of network clients nodes. If equal to zero, "
00051 "then all backbones nodes are also client nodes.");
00052 DEFINE_int32(backbones, 0, "Number of backbone nodes");
00053 DEFINE_int32(demands, 0, "Number of network demands.");
00054 DEFINE_int32(traffic_min, 0, "Min traffic of a demand.");
00055 DEFINE_int32(traffic_max, 0, "Max traffic of a demand.");
00056 DEFINE_int32(min_client_degree, 0,
00057 "Min number of connections from a client to the backbone.");
00058 DEFINE_int32(max_client_degree, 0,
00059 "Max number of connections from a client to the backbone.");
00060 DEFINE_int32(min_backbone_degree, 0,
00061 "Min number of connections from a backbone node to the rest of "
00062 "the backbone nodes.");
00063 DEFINE_int32(max_backbone_degree, 0,
00064 "Max number of connections from a backbone node to the rest of "
00065 "the backbone nodes.");
00066 DEFINE_int32(max_capacity, 0, "Max traffic on any arc.");
00067 DEFINE_int32(fixed_charge_cost, 0, "Fixed charged cost when using an arc.");
00068 DEFINE_int32(seed, 0, "Random seed");
00069
00070
00071 DEFINE_bool(print_model, false, "Print model.");
00072 DEFINE_int32(report, 1, "Report which links and which demands are "
00073 "responsible for the congestion.");
00074 DEFINE_int32(log_period, 100000, "Period for the search log");
00075
00076
00077 DEFINE_int64(comfort_zone, 850,
00078 "Above this limit in 1/1000th, the link is said to be "
00079 "congestioned.");
00080 DEFINE_int32(extra_hops, 6,
00081 "When creating all paths for a demand, we look at paths with "
00082 "maximum length 'shortest path + extra_hops'");
00083 DEFINE_int32(max_paths, 1200, "Max number of possible paths for a demand.");
00084
00085
00086 DEFINE_int32(time_limit, 60000,
00087 "Time limit for search in ms, 0 = no time limit.");
00088 DEFINE_int32(fail_limit, 0, "Failure limit for search, 0 = no limit.");
00089 DEFINE_int32(lns_size, 6, "Number of vars to relax in a lns loop.");
00090 DEFINE_int32(lns_seed, 1, "Seed for the LNS random number generator.");
00091 DEFINE_int32(lns_limit, 30, "Limit the number of failures of the lns loop.");
00092 DEFINE_bool(focus_lns, true, "Focus LNS on highest cost arcs.");
00093
00094 namespace operations_research {
00095
00096 static const int64 kDisconnectedDistance = -1LL;
00097
00098
00099
00100
00101
00102 class NetworkRoutingData {
00103 public:
00104 NetworkRoutingData()
00105 : name_(""),
00106 num_nodes_(-1),
00107 max_capacity_(-1),
00108 fixed_charge_cost_(-1) {}
00109
00110
00111 const string& name() const { return name_; }
00112
00113
00114 int num_nodes() const { return num_nodes_; }
00115
00116 int num_arcs() const { return all_arcs_.size(); }
00117
00118 int num_demands() const { return all_demands_.size(); }
00119
00120
00121 int Capacity(int node1, int node2) const {
00122 return FindWithDefault(all_arcs_,
00123 std::make_pair(std::min(node1, node2),
00124 std::max(node1, node2)),
00125 0);
00126 }
00127
00128
00129
00130 int Demand(int source, int destination) const {
00131 return FindWithDefault(all_demands_,
00132 std::make_pair(source, destination), 0);
00133 }
00134
00135
00136 void set_num_nodes(int num_nodes) { num_nodes_ = num_nodes; }
00137 void AddArc(int node1, int node2, int capacity) {
00138 all_arcs_[std::make_pair(std::min(node1, node2),
00139 std::max(node1, node2))] = capacity;
00140 }
00141 void AddDemand(int source, int destination, int traffic) {
00142 all_demands_[std::make_pair(source, destination)] = traffic;
00143 }
00144 void set_name(const string& name) { name_ = name; }
00145 void set_max_capacity(int max_capacity) { max_capacity_ = max_capacity; }
00146 void set_fixed_charge_cost(int cost) { fixed_charge_cost_ = cost; }
00147
00148 private:
00149 string name_;
00150 int num_nodes_;
00151 int max_capacity_;
00152 int fixed_charge_cost_;
00153 #if defined(_MSC_VER)
00154 hash_map<std::pair<int, int>, int, PairIntHasher> all_arcs_;
00155 hash_map<std::pair<int, int>, int, PairIntHasher> all_demands_;
00156 #else
00157 hash_map<std::pair<int, int>, int> all_arcs_;
00158 hash_map<std::pair<int, int>, int> all_demands_;
00159 #endif
00160 };
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 class NetworkRoutingDataBuilder {
00176 public:
00177 NetworkRoutingDataBuilder() : random_(0) {}
00178
00179 void BuildModelFromParameters(int num_clients,
00180 int num_backbones,
00181 int num_demands,
00182 int traffic_min,
00183 int traffic_max,
00184 int min_client_degree,
00185 int max_client_degree,
00186 int min_backbone_degree,
00187 int max_backbone_degree,
00188 int max_capacity,
00189 int fixed_charge_cost,
00190 int seed,
00191 NetworkRoutingData* const data) {
00192 CHECK_GE(num_backbones, 1);
00193 CHECK_GE(num_clients, 0);
00194 CHECK_GE(num_demands, 1);
00195 CHECK_LE(num_demands, num_clients == 0
00196 ? num_backbones * num_backbones :
00197 num_clients * num_backbones);
00198 CHECK_GE(max_client_degree, min_client_degree);
00199 CHECK_GE(max_backbone_degree, min_backbone_degree);
00200 CHECK_GE(traffic_max, 1);
00201 CHECK_GE(traffic_max, traffic_min);
00202 CHECK_GE(traffic_min, 1);
00203 CHECK_GE(max_backbone_degree, 2);
00204 CHECK_GE(max_client_degree, 2);
00205 CHECK_LE(max_client_degree, num_backbones);
00206 CHECK_LE(max_backbone_degree, num_backbones);
00207 CHECK_GE(max_capacity, 1);
00208
00209 const int size = num_backbones + num_clients;
00210 InitData(size, seed);
00211 BuildGraph(num_clients,
00212 num_backbones,
00213 min_client_degree,
00214 max_client_degree,
00215 min_backbone_degree,
00216 max_backbone_degree);
00217 CreateDemands(num_clients,
00218 num_backbones,
00219 num_demands,
00220 traffic_min,
00221 traffic_max,
00222 data);
00223 FillData(num_clients,
00224 num_backbones,
00225 num_demands,
00226 traffic_min,
00227 traffic_max,
00228 min_client_degree,
00229 max_client_degree,
00230 min_backbone_degree,
00231 max_backbone_degree,
00232 max_capacity,
00233 fixed_charge_cost,
00234 seed,
00235 data);
00236 }
00237
00238 private:
00239 void InitData(int size, int seed) {
00240 network_.clear();
00241 network_.resize(size);
00242 for (int i = 0; i < size; ++i) {
00243 network_[i].resize(size, false);
00244 }
00245 degrees_.clear();
00246 degrees_.resize(size, 0);
00247 random_.Reset(seed);
00248 }
00249
00250 void BuildGraph(int num_clients,
00251 int num_backbones,
00252 int min_client_degree,
00253 int max_client_degree,
00254 int min_backbone_degree,
00255 int max_backbone_degree) {
00256 const int size = num_backbones + num_clients;
00257
00258
00259 for (int i = 1; i < num_backbones; ++i) {
00260 int j = random_.Uniform(i);
00261 CHECK_LT(j, i);
00262 AddEdge(i, j);
00263 }
00264
00265 hash_set<int> to_complete;
00266 hash_set<int> not_full;
00267 for (int i = 0; i < num_backbones; ++i) {
00268 if (degrees_[i] < min_backbone_degree) {
00269 to_complete.insert(i);
00270 }
00271 if (degrees_[i] < max_backbone_degree) {
00272 not_full.insert(i);
00273 }
00274 }
00275 while (!to_complete.empty() && not_full.size() > 1) {
00276 const int node1 = *(to_complete.begin());
00277 int node2 = node1;
00278 while (node2 == node1 || degrees_[node2] >= max_backbone_degree) {
00279 node2 = random_.Uniform(num_backbones);
00280 }
00281 AddEdge(node1, node2);
00282 if (degrees_[node1] >= min_backbone_degree) {
00283 to_complete.erase(node1);
00284 }
00285 if (degrees_[node2] >= min_backbone_degree) {
00286 to_complete.erase(node2);
00287 }
00288 if (degrees_[node1] >= max_backbone_degree) {
00289 not_full.erase(node1);
00290 }
00291 if (degrees_[node2] >= max_backbone_degree) {
00292 not_full.erase(node2);
00293 }
00294 }
00295
00296
00297
00298 for (int i = num_backbones; i < size; ++i) {
00299 const int degree = RandomInInterval(min_client_degree, max_client_degree);
00300 while (degrees_[i] < degree) {
00301 const int j = random_.Uniform(num_backbones);
00302 if (!network_[i][j]) {
00303 AddEdge(i, j);
00304 }
00305 }
00306 }
00307 }
00308
00309 void CreateDemands(int num_clients,
00310 int num_backbones,
00311 int num_demands,
00312 int traffic_min,
00313 int traffic_max,
00314 NetworkRoutingData* const data) {
00315 while (data->num_demands() < num_demands) {
00316 const int source = RandomClient(num_clients, num_backbones);
00317 int dest = source;
00318 while (dest == source) {
00319 dest = RandomClient(num_clients, num_backbones);
00320 }
00321 const int traffic = RandomInInterval(traffic_min, traffic_max);
00322 data->AddDemand(source, dest, traffic);
00323 }
00324 }
00325
00326 void FillData(int num_clients,
00327 int num_backbones,
00328 int num_demands,
00329 int traffic_min,
00330 int traffic_max,
00331 int min_client_degree,
00332 int max_client_degree,
00333 int min_backbone_degree,
00334 int max_backbone_degree,
00335 int max_capacity,
00336 int fixed_charge_cost,
00337 int seed,
00338 NetworkRoutingData* const data) {
00339 const int size = num_backbones + num_clients;
00340
00341 const string name =
00342 StringPrintf("mp_c%i_b%i_d%i.t%i-%i.cd%i-%i.bd%i-%i.mc%i.fc%i.s%i",
00343 num_clients,
00344 num_backbones,
00345 num_demands,
00346 traffic_min,
00347 traffic_max,
00348 min_client_degree,
00349 max_client_degree,
00350 min_backbone_degree,
00351 max_backbone_degree,
00352 max_capacity,
00353 fixed_charge_cost,
00354 seed);
00355 data->set_name(name);
00356
00357 data->set_num_nodes(size);
00358 int num_arcs = 0;
00359 for (int i = 0; i < size - 1; ++i) {
00360 for (int j = i + 1; j < size; ++j) {
00361 if (network_[i][j]) {
00362 data->AddArc(i, j, max_capacity);
00363 num_arcs++;
00364 }
00365 }
00366 }
00367 data->set_max_capacity(max_capacity);
00368 data->set_fixed_charge_cost(fixed_charge_cost);
00369 }
00370
00371 void AddEdge(int i, int j) {
00372 degrees_[i]++;
00373 degrees_[j]++;
00374 network_[i][j] = true;
00375 network_[j][i] = true;
00376 }
00377
00378 int RandomInInterval(int interval_min, int interval_max) {
00379 CHECK_LE(interval_min, interval_max);
00380 return random_.Uniform(interval_max - interval_min + 1) + interval_min;
00381 }
00382
00383 int RandomClient(int num_clients, int num_backbones) {
00384 return (num_clients == 0) ?
00385 random_.Uniform(num_backbones) :
00386 random_.Uniform(num_clients) + num_backbones;
00387 }
00388
00389 std::vector<std::vector<bool> > network_;
00390 std::vector<int> degrees_;
00391 ACMRandom random_;
00392 };
00393
00394
00395
00396
00397 struct Demand {
00398 public:
00399 Demand(int the_source, int the_destination, int the_traffic)
00400 : source(the_source),
00401 destination(the_destination),
00402 traffic(the_traffic) {}
00403 int source;
00404 int destination;
00405 int traffic;
00406 };
00407
00408 class NetworkRoutingSolver {
00409 public:
00410 typedef hash_set<int> OnePath;
00411
00412 NetworkRoutingSolver() : arcs_data_(3), num_nodes_(-1) {}
00413
00414 void ComputeAllPathsForOneDemandAndOnePathLength(int demand_index,
00415 int max_length,
00416 int max_paths) {
00417
00418 Solver solver("Counting");
00419 std::vector<IntVar*> arc_vars;
00420 std::vector<IntVar*> node_vars;
00421 solver.MakeIntVarArray(max_length, 0, num_nodes_ - 1, &node_vars);
00422 solver.MakeIntVarArray(max_length - 1, -1, count_arcs() - 1, &arc_vars);
00423
00424 for (int i = 0; i < max_length - 1; ++i) {
00425 std::vector<IntVar*> tmp_vars;
00426 tmp_vars.push_back(node_vars[i]);
00427 tmp_vars.push_back(node_vars[i + 1]);
00428 tmp_vars.push_back(arc_vars[i]);
00429 solver.AddConstraint(solver.MakeAllowedAssignments(tmp_vars, arcs_data_));
00430 }
00431
00432 const Demand& demand = demands_array_[demand_index];
00433 solver.AddConstraint(solver.MakeEquality(node_vars[0], demand.source));
00434 solver.AddConstraint(solver.MakeEquality(node_vars[max_length - 1],
00435 demand.destination));
00436 solver.AddConstraint(solver.MakeAllDifferent(arc_vars));
00437 solver.AddConstraint(solver.MakeAllDifferent(node_vars));
00438 DecisionBuilder* const db = solver.MakePhase(node_vars,
00439 Solver::CHOOSE_FIRST_UNBOUND,
00440 Solver::ASSIGN_MIN_VALUE);
00441 solver.NewSearch(db);
00442 while (solver.NextSolution()) {
00443 const int path_id = all_paths_[demand_index].size();
00444 all_paths_[demand_index].resize(path_id + 1);
00445 for (int arc_index = 0; arc_index < max_length - 1; ++arc_index) {
00446 const int arc = arc_vars[arc_index]->Value();
00447 all_paths_[demand_index].back().insert(arc);
00448 }
00449 if (all_paths_[demand_index].size() > max_paths) {
00450 break;
00451 }
00452 }
00453 solver.EndSearch();
00454 }
00455
00456
00457
00458
00459 int ComputeAllPaths(int extra_hops, int max_paths) {
00460 int num_paths = 0;
00461 for (int demand_index = 0;
00462 demand_index < demands_array_.size();
00463 ++demand_index) {
00464 const int min_path_length = all_min_path_lengths_[demand_index];
00465 for (int max_length = min_path_length + 1;
00466 max_length <= min_path_length + extra_hops + 1;
00467 ++max_length) {
00468 ComputeAllPathsForOneDemandAndOnePathLength(demand_index,
00469 max_length,
00470 max_paths);
00471 if (all_paths_[demand_index].size() > max_paths) {
00472 break;
00473 }
00474 }
00475 num_paths += all_paths_[demand_index].size();
00476 }
00477 return num_paths;
00478 }
00479
00480 void AddArcData(int index, int source, int destination, int arc_id) {
00481 arcs_data_.Insert3(source, destination, arc_id);
00482 }
00483
00484 void InitArcInfo(const NetworkRoutingData& data) {
00485 const int num_arcs = data.num_arcs();
00486 capacity_.clear();
00487 capacity_.resize(num_nodes_);
00488 for (int node_index = 0; node_index < num_nodes_; ++node_index) {
00489 capacity_[node_index].resize(num_nodes_, 0);
00490 }
00491 int arc_id = 0;
00492 for (int i = 0; i < num_nodes_ - 1; ++i) {
00493 for (int j = i + 1; j < num_nodes_; ++j) {
00494 const int capacity = data.Capacity(i, j);
00495 if (capacity > 0) {
00496 AddArcData(2 * arc_id, i, j, arc_id);
00497 AddArcData(2 * arc_id + 1, j, i, arc_id);
00498 arc_id++;
00499 arc_capacity_.push_back(capacity);
00500 capacity_[i][j] = capacity;
00501 capacity_[j][i] = capacity;
00502 if (FLAGS_print_model) {
00503 LOG(INFO) << "Arc " << i << " <-> " << j
00504 << " with capacity " << capacity;
00505 }
00506 }
00507 }
00508 }
00509 CHECK_EQ(arc_id, num_arcs);
00510 }
00511
00512 int InitDemandInfo(const NetworkRoutingData& data) {
00513 const int num_demands = data.num_demands();
00514 int total_demand = 0;
00515 for (int i = 0; i < num_nodes_; ++i) {
00516 for (int j = 0; j < num_nodes_; ++j) {
00517 const int traffic = data.Demand(i, j);
00518 if (traffic > 0) {
00519 demands_array_.push_back(Demand(i, j, traffic));
00520 total_demand += traffic;
00521 }
00522 }
00523 }
00524 CHECK_EQ(num_demands, demands_array_.size());
00525 return total_demand;
00526 }
00527
00528 int64 InitShortestPaths(const NetworkRoutingData& data) {
00529 const int num_demands = data.num_demands();
00530 int64 total_cumulated_traffic = 0;
00531 all_min_path_lengths_.clear();
00532 std::vector<int> paths;
00533 for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
00534 paths.clear();
00535 const Demand& demand = demands_array_[demand_index];
00536 ResultCallback2<int64, int, int>* const graph_callback =
00537 NewPermanentCallback(this, &NetworkRoutingSolver::HasArc);
00538 CHECK(DijkstraShortestPath(num_nodes_,
00539 demand.source,
00540 demand.destination,
00541 graph_callback,
00542 kDisconnectedDistance,
00543 &paths));
00544 all_min_path_lengths_.push_back(paths.size() - 1);
00545 }
00546
00547 for (int i = 0; i < num_demands; ++i) {
00548 const int min_path_length = all_min_path_lengths_[i];
00549 total_cumulated_traffic += min_path_length * demands_array_[i].traffic;
00550 }
00551 return total_cumulated_traffic;
00552 }
00553
00554 int InitPaths(const NetworkRoutingData& data,
00555 int extra_hops,
00556 int max_paths) {
00557 const int num_demands = data.num_demands();
00558 LOG(INFO) << "Computing all possible paths ";
00559 LOG(INFO) << " - extra hops = " << extra_hops;
00560 LOG(INFO) << " - max paths per demand = " << max_paths;
00561 all_paths_.clear();
00562 all_paths_.resize(num_demands);
00563 const int num_paths = ComputeAllPaths(extra_hops, max_paths);
00564
00565 if (FLAGS_print_model) {
00566 for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
00567 const Demand& demand = demands_array_[demand_index];
00568 LOG(INFO) << "Demand from " << demand.source
00569 << " to " << demand.destination
00570 << " with traffic " << demand.traffic
00571 << ", and " << all_paths_[demand_index].size()
00572 << " possible paths.";
00573 }
00574 }
00575 return num_paths;
00576 }
00577
00578 void Init(const NetworkRoutingData& data, int extra_hops, int max_paths) {
00579 LOG(INFO) << "Model " << data.name();
00580 num_nodes_ = data.num_nodes();
00581 const int num_arcs = data.num_arcs();
00582 const int num_demands = data.num_demands();
00583
00584 InitArcInfo(data);
00585 const int total_demand = InitDemandInfo(data);
00586 const int64 total_cumulated_traffic = InitShortestPaths(data);
00587 const int num_paths = InitPaths(data, extra_hops, max_paths);
00588
00589
00590
00591 LOG(INFO) << "Model created:";
00592 LOG(INFO) << " - " << num_nodes_ << " nodes";
00593 LOG(INFO) << " - " << num_arcs << " arcs";
00594 LOG(INFO) << " - " << num_demands << " demands";
00595 LOG(INFO) << " - a total traffic of " << total_demand;
00596 LOG(INFO) << " - a minimum cumulated traffic of "
00597 << total_cumulated_traffic;
00598 LOG(INFO) << " - " << num_paths << " possible paths for all demands";
00599 }
00600
00601
00602
00603 void BuildNodePathConstraint(Solver* const solver,
00604 const std::vector<IntVar*>& path_vars,
00605 int demand_index,
00606 std::vector<IntVar*>* decision_vars) {
00607
00608 const std::vector<OnePath> paths = all_paths_[demand_index];
00609 IntTupleSet tuple_set(count_arcs() + 1);
00610 for (int path_id = 0; path_id < paths.size(); ++path_id) {
00611 std::vector<int> tuple(count_arcs() + 1);
00612 tuple[0] = path_id;
00613 for (ConstIter<OnePath> it(paths[path_id]); !it.at_end(); ++it) {
00614 const int arc = *it;
00615
00616 tuple[arc + 1] = true;
00617 }
00618 tuple_set.Insert(tuple);
00619 }
00620
00621 const string name = StringPrintf("PathDecision_%i", demand_index);
00622 IntVar* const var = solver->MakeIntVar(0, tuple_set.NumTuples() - 1, name);
00623 std::vector<IntVar*> tmp_vars;
00624 tmp_vars.push_back(var);
00625 for (int i = 0; i < count_arcs(); ++i) {
00626 tmp_vars.push_back(path_vars[i]);
00627 }
00628 solver->AddConstraint(solver->MakeAllowedAssignments(tmp_vars, tuple_set));
00629 decision_vars->push_back(var);
00630 }
00631
00632
00633
00634 void BuildTrafficVariable(Solver* const solver,
00635 int arc_index,
00636 const std::vector<std::vector<IntVar*> >& path_vars,
00637 IntVar** const traffic) {
00638 std::vector<IntVar*> terms;
00639 for (int i = 0; i < path_vars.size(); ++i) {
00640 terms.push_back(solver->MakeProd(path_vars[i][arc_index],
00641 demands_array_[i].traffic)->Var());
00642 }
00643 *traffic = solver->MakeSum(terms)->Var();
00644 }
00645
00646
00647
00648 class PathBasedLns : public BaseLNS {
00649 public:
00650 PathBasedLns(const IntVar* const* vars,
00651 int size,
00652 int fragment_size,
00653 const std::vector<std::vector<OnePath> >& all_paths,
00654 int num_arcs,
00655 const std::vector<int64>& actual_usage_costs)
00656 : BaseLNS(vars, size),
00657 rand_(FLAGS_lns_seed),
00658 fragment_size_(fragment_size),
00659 all_paths_(all_paths),
00660 num_arcs_(num_arcs),
00661 actual_usage_costs_(actual_usage_costs) {
00662 CHECK_GT(fragment_size_, 0);
00663 }
00664
00665 virtual ~PathBasedLns() {}
00666
00667 virtual void InitFragments() {
00668
00669
00670 arc_wrappers_.clear();
00671 for (int i = 0; i < actual_usage_costs_.size(); ++i) {
00672 const int64 cost = actual_usage_costs_[i];
00673 if (cost != 0) {
00674 arc_wrappers_.push_back(ArcWrapper(i, cost));
00675 }
00676 }
00677 if (arc_wrappers_.size() > fragment_size_) {
00678 std::stable_sort(arc_wrappers_.begin(), arc_wrappers_.end());
00679 }
00680 }
00681
00682 virtual bool NextFragment(std::vector<int>* fragment) {
00683
00684 hash_set<int> arcs_to_release;
00685 if (arc_wrappers_.size() <= fragment_size_) {
00686
00687 for (int index = 0; index < arc_wrappers_.size(); ++index) {
00688 arcs_to_release.insert(arc_wrappers_[index].arc_id);
00689 }
00690 } else {
00691 if (FLAGS_focus_lns) {
00692
00693 for (int index = 0; index < fragment_size_ / 2; ++index) {
00694 arcs_to_release.insert(arc_wrappers_[index].arc_id);
00695 }
00696 }
00697
00698
00699
00700 while (arcs_to_release.size() < fragment_size_) {
00701 const int candidate = rand_.Uniform(arc_wrappers_.size());
00702 arcs_to_release.insert(arc_wrappers_[candidate].arc_id);
00703 }
00704 }
00705
00706
00707 const int demands = all_paths_.size();
00708 for (int i = 0; i < demands; ++i) {
00709 const OnePath& path = all_paths_[i][Value(i)];
00710 for (ConstIter<hash_set<int> > it(arcs_to_release);
00711 !it.at_end();
00712 ++it) {
00713 if (ContainsKey(path, *it)) {
00714 fragment->push_back(i);
00715 break;
00716 }
00717 }
00718 }
00719 return true;
00720 }
00721
00722 private:
00723 struct ArcWrapper {
00724 public:
00725 ArcWrapper(int i, int64 c) : arc_id(i), cost(c) {}
00726 int arc_id;
00727 int64 cost;
00728 bool operator<(const ArcWrapper& other_arc_wrapper) const {
00729 return cost > other_arc_wrapper.cost
00730 || (cost == other_arc_wrapper.cost
00731 && arc_id < other_arc_wrapper.arc_id);
00732 }
00733 };
00734
00735 ACMRandom rand_;
00736 const int fragment_size_;
00737 const std::vector<std::vector<OnePath> >& all_paths_;
00738 const int num_arcs_;
00739 const std::vector<int64>& actual_usage_costs_;
00740 std::vector<ArcWrapper> arc_wrappers_;
00741 };
00742
00743
00744
00745 static const int kOneThousand = 1000;
00746
00747 int64 EvaluateMarginalCost(std::vector<IntVar*>* path_costs,
00748 int64 var,
00749 int64 val) {
00750 int64 best_cost = 0;
00751 const int64 traffic = demands_array_[var].traffic;
00752 const OnePath& path = all_paths_[var][val];
00753 for (ConstIter<OnePath> it(path); !it.at_end(); ++it) {
00754 const int64 current_percent = (*path_costs)[*it]->Min();
00755 const int64 current_capacity = arc_capacity_[*it];
00756 const int64 expected_percent =
00757 current_percent + traffic * kOneThousand / current_capacity;
00758 if (expected_percent > best_cost) {
00759 best_cost = expected_percent;
00760 }
00761 }
00762 return best_cost;
00763 }
00764
00765
00766
00767 static Solver::DecisionModification MaxDiscrepancy1(Solver* const solver) {
00768 if (solver->SearchDepth() - solver->SearchLeftDepth() > 1) {
00769 return Solver::KEEP_LEFT;
00770 }
00771 return Solver::NO_CHANGE;
00772 }
00773
00774 class ApplyMaxDiscrepancy : public DecisionBuilder {
00775 public:
00776 virtual ~ApplyMaxDiscrepancy() {}
00777
00778 virtual Decision* Next(Solver* const solver) {
00779 solver->SetBranchSelector(
00780 NewPermanentCallback(&NetworkRoutingSolver::MaxDiscrepancy1));
00781 return NULL;
00782 }
00783
00784 virtual string DebugString() const {
00785 return "ApplyMaxDiscrepancy";
00786 }
00787 };
00788
00789
00790
00791 class StoreUsageCosts : public DecisionBuilder {
00792 public:
00793 StoreUsageCosts(const std::vector<IntVar*>& vars, std::vector<int64>* values)
00794 : vars_(vars), values_(values) {}
00795 virtual ~StoreUsageCosts() {}
00796
00797 virtual Decision* Next(Solver* const s) {
00798 for (int i = 0; i < vars_.size(); ++i) {
00799 (*values_)[i] = vars_[i]->Value();
00800 }
00801 return NULL;
00802 }
00803 private:
00804 const std::vector<IntVar*>& vars_;
00805 std::vector<int64>* const values_;
00806 };
00807
00808
00809
00810 int64 HasArc(int i, int j) {
00811 if (capacity_[i][j] > 0) {
00812 return 1;
00813 } else {
00814 return kDisconnectedDistance;
00815 }
00816 }
00817
00818
00819
00820 int64 LnsSolve(int time_limit, int fail_limit) {
00821 LOG(INFO) << "Solving model";
00822 const int num_demands = demands_array_.size();
00823 const int num_arcs = count_arcs();
00824
00825 Solver solver("MultiPathSolver");
00826 std::vector<std::vector<IntVar*> > path_vars(num_demands);
00827 std::vector<IntVar*> decision_vars;
00828
00829
00830 for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
00831 solver.MakeBoolVarArray(num_arcs,
00832 StringPrintf("path_vars_%i_", demand_index),
00833 &path_vars[demand_index]);
00834 BuildNodePathConstraint(&solver,
00835 path_vars[demand_index],
00836 demand_index,
00837 &decision_vars);
00838 }
00839
00840 std::vector<IntVar*> vtraffic(num_arcs);
00841 for (int arc_index = 0; arc_index < num_arcs; ++arc_index) {
00842 BuildTrafficVariable(&solver,
00843 arc_index,
00844 path_vars,
00845 &vtraffic[arc_index]);
00846 vtraffic[arc_index]->set_name(StringPrintf("traffic_%i", arc_index));
00847 }
00848
00849
00850 std::vector<IntVar*> costs;
00851 std::vector<IntVar*> usage_costs;
00852 std::vector<IntVar*> comfort_costs;
00853 for (int arc_index = 0; arc_index < num_arcs; ++arc_index) {
00854 const int capacity =
00855 capacity_[arcs_data_.Value(2 * arc_index, 0)]
00856 [arcs_data_.Value(2 * arc_index, 1)];
00857 IntVar* const usage_cost =
00858 solver.MakeDiv(solver.MakeProd(vtraffic[arc_index], kOneThousand),
00859 capacity)->Var();
00860 usage_costs.push_back(usage_cost);
00861 IntVar* const comfort_cost =
00862 solver.MakeIsGreaterCstVar(
00863 vtraffic[arc_index],
00864 capacity * FLAGS_comfort_zone / kOneThousand);
00865 comfort_costs.push_back(comfort_cost);
00866 }
00867 IntVar* const max_usage_cost = solver.MakeMax(usage_costs)->Var();
00868 IntVar* const sum_comfort_cost = solver.MakeSum(comfort_costs)->Var();
00869 IntVar* const objective_var =
00870 solver.MakeSum(max_usage_cost, sum_comfort_cost)->Var();
00871 std::vector<SearchMonitor*> monitors;
00872 OptimizeVar* const objective = solver.MakeMinimize(objective_var, 1);
00873 monitors.push_back(objective);
00874
00875
00876 if (FLAGS_report == 0) {
00877 SearchMonitor* const search_log =
00878 solver.MakeSearchLog(FLAGS_log_period, objective);
00879 monitors.push_back(search_log);
00880 }
00881
00882
00883 DecisionBuilder* const db =
00884 solver.MakePhase(decision_vars,
00885 Solver::CHOOSE_RANDOM,
00886 NewPermanentCallback(
00887 this,
00888 &NetworkRoutingSolver::EvaluateMarginalCost,
00889 &usage_costs));
00890
00891
00892 if (time_limit != 0 || fail_limit != 0) {
00893 if (time_limit != 0) {
00894 LOG(INFO) << "adding time limit of " << time_limit
00895 << " ms";
00896 }
00897 if (fail_limit != 0) {
00898 LOG(INFO) << "adding fail limit of " << fail_limit;
00899 }
00900 monitors.push_back(
00901 solver.MakeLimit(time_limit != 0 ?
00902 time_limit : kint64max,
00903 kint64max,
00904 fail_limit != 0 ?
00905 fail_limit : kint64max,
00906 kint64max));
00907 }
00908
00909
00910 LOG(INFO) << "Using Lns with a fragment size of " << FLAGS_lns_size
00911 << ", and fail limit of " << FLAGS_lns_limit;
00912 std::vector<int64> actual_usage_costs(num_arcs);
00913 DecisionBuilder* const store_info =
00914 solver.RevAlloc(new StoreUsageCosts(usage_costs, &actual_usage_costs));
00915
00916 LocalSearchOperator* const local_search_operator =
00917 solver.RevAlloc(new PathBasedLns(decision_vars.data(),
00918 decision_vars.size(),
00919 FLAGS_lns_size,
00920 all_paths_,
00921 num_arcs,
00922 actual_usage_costs));
00923 SearchLimit* const lns_limit =
00924 solver.MakeLimit(kint64max, kint64max, FLAGS_lns_limit, kint64max);
00925 DecisionBuilder* const inner_db =
00926 solver.MakePhase(decision_vars,
00927 Solver::CHOOSE_RANDOM,
00928 NewPermanentCallback(
00929 this,
00930 &NetworkRoutingSolver::EvaluateMarginalCost,
00931 &usage_costs));
00932
00933
00934 DecisionBuilder* const apply = solver.RevAlloc(new ApplyMaxDiscrepancy);
00935 DecisionBuilder* const max_discrepency_db = solver.Compose(apply, inner_db);
00936 DecisionBuilder* const ls_db = solver.MakeSolveOnce(max_discrepency_db,
00937 lns_limit);
00938 LocalSearchPhaseParameters* const parameters =
00939 solver.MakeLocalSearchPhaseParameters(local_search_operator,
00940 solver.Compose(ls_db,
00941 store_info));
00942 DecisionBuilder* const final_db =
00943 solver.Compose(solver.MakeLocalSearchPhase(decision_vars,
00944 db,
00945 parameters),
00946 store_info);
00947
00948
00949 int64 best_cost = kint64max;
00950 solver.NewSearch(final_db, monitors);
00951 while (solver.NextSolution()) {
00952
00953 const double percent = max_usage_cost->Value() / 10.0;
00954 const int64 non_comfort = sum_comfort_cost->Value();
00955 if (non_comfort > 0) {
00956 LOG(INFO) << "*** Found a solution with a max usage of " << percent
00957 << "%, and " << non_comfort
00958 << " links above the comfort zone";
00959 } else {
00960 LOG(INFO) << "*** Found a solution with a max usage of " << percent
00961 << "%";
00962 }
00963 best_cost = objective_var->Value();
00964 if (FLAGS_report > 1) {
00965 DisplaySolution(num_arcs,
00966 max_usage_cost->Value(),
00967 usage_costs,
00968 path_vars,
00969 FLAGS_report > 2,
00970 FLAGS_comfort_zone);
00971 }
00972 }
00973 solver.EndSearch();
00974
00975 return best_cost;
00976 }
00977 void DisplaySolution(int num_arcs,
00978 int64 max_usage_cost,
00979 const std::vector<IntVar*>& usage_costs,
00980 const std::vector<std::vector<IntVar*> >& path_vars,
00981 bool precise,
00982 int64 comfort_zone) {
00983
00984
00985 const int64 kFivePercentInThousandth = 50;
00986 const int64 cutoff =
00987 std::min(max_usage_cost - kFivePercentInThousandth, comfort_zone);
00988 for (int i = 0; i < num_arcs; ++i) {
00989 const int64 arc_usage = usage_costs[i]->Value();
00990 if (arc_usage >= cutoff) {
00991 const int source_index = arcs_data_.Value(2 * i, 0);
00992 const int destination_index = arcs_data_.Value(2 * i, 1);
00993 LOG(INFO) << " + Arc " << source_index
00994 << " <-> " << destination_index
00995 << " has a usage = " << arc_usage / 10.0
00996 << "%, capacity = "
00997 << capacity_[source_index][destination_index];
00998 if (precise) {
00999 const int num_demands = demands_array_.size();
01000 for (int demand_index = 0;
01001 demand_index < num_demands;
01002 ++demand_index) {
01003 if (path_vars[demand_index][i]->Value() == 1) {
01004 const Demand& demand = demands_array_[demand_index];
01005 LOG(INFO) << " - "
01006 << StringPrintf("%i -> %i (%i)",
01007 demand.source,
01008 demand.destination,
01009 demand.traffic);
01010 }
01011 }
01012 }
01013 }
01014 }
01015 }
01016
01017 private:
01018 int count_arcs() const { return arcs_data_.NumTuples() / 2; }
01019
01020 IntTupleSet arcs_data_;
01021 std::vector<int> arc_capacity_;
01022 std::vector<Demand> demands_array_;
01023 int num_nodes_;
01024 std::vector<int64> all_min_path_lengths_;
01025 std::vector<std::vector<int> > capacity_;
01026 std::vector<std::vector<OnePath> > all_paths_;
01027 };
01028
01029 }
01030
01031 int main(int argc, char **argv) {
01032 google::ParseCommandLineFlags(&argc, &argv, true);
01033 operations_research::NetworkRoutingData data;
01034 operations_research::NetworkRoutingDataBuilder builder;
01035 builder.BuildModelFromParameters(FLAGS_clients,
01036 FLAGS_backbones,
01037 FLAGS_demands,
01038 FLAGS_traffic_min,
01039 FLAGS_traffic_max,
01040 FLAGS_min_client_degree,
01041 FLAGS_max_client_degree,
01042 FLAGS_min_backbone_degree,
01043 FLAGS_max_backbone_degree,
01044 FLAGS_max_capacity,
01045 FLAGS_fixed_charge_cost,
01046 FLAGS_seed,
01047 &data);
01048 operations_research::NetworkRoutingSolver solver;
01049 solver.Init(data, FLAGS_extra_hops, FLAGS_max_paths);
01050 LOG(INFO) << "Final cost = "
01051 << solver.LnsSolve(FLAGS_time_limit, FLAGS_fail_limit);
01052 return 0;
01053 }