00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <vector>
00024
00025 #include "base/callback.h"
00026 #include "base/commandlineflags.h"
00027 #include "base/commandlineflags.h"
00028 #include "base/integral_types.h"
00029 #include "base/logging.h"
00030 #include "base/scoped_ptr.h"
00031 #include "base/stringprintf.h"
00032 #include "constraint_solver/routing.h"
00033 #include "base/random.h"
00034
00035 using operations_research::Assignment;
00036 using operations_research::IntVar;
00037 using operations_research::RoutingModel;
00038 using operations_research::Solver;
00039 using operations_research::ACMRandom;
00040 using operations_research::StringAppendF;
00041 using operations_research::StringPrintf;
00042 using operations_research::scoped_array;
00043 using operations_research::scoped_ptr;
00044
00045
00046 DEFINE_int32(vrp_orders, 100, "Nodes in the problem.");
00047 DEFINE_int32(vrp_vehicles, 20, "Size of Traveling Salesman Problem instance.");
00048 DEFINE_bool(vrp_use_deterministic_random_seed, false,
00049 "Use deterministic random seeds.");
00050
00051 const char* kTime = "Time";
00052 const char* kCapacity = "Capacity";
00053
00054
00055 int32 GetSeed() {
00056 if (FLAGS_vrp_use_deterministic_random_seed) {
00057 return ACMRandom::DeterministicSeed();
00058 } else {
00059 return ACMRandom::HostnamePidTimeSeed();
00060 }
00061 }
00062
00063
00064
00065 class LocationContainer {
00066 public:
00067 explicit LocationContainer(int64 speed)
00068 : randomizer_(GetSeed()), speed_(speed) {
00069 CHECK_LT(0, speed_);
00070 }
00071 void AddLocation(int64 x, int64 y) {
00072 locations_.push_back(Location(x, y));
00073 }
00074 void AddRandomLocation(int64 x_max, int64 y_max) {
00075 AddLocation(randomizer_.Uniform(x_max + 1), randomizer_.Uniform(y_max + 1));
00076 }
00077 int64 ManhattanDistance(RoutingModel::NodeIndex from,
00078 RoutingModel::NodeIndex to) const {
00079 return locations_[from].DistanceTo(locations_[to]);
00080 }
00081 int64 ManhattanTime(RoutingModel::NodeIndex from,
00082 RoutingModel::NodeIndex to) const {
00083 return ManhattanDistance(from, to) / speed_;
00084 }
00085
00086 private:
00087 class Location {
00088 public:
00089 Location() : x_(0), y_(0) {}
00090 Location(int64 x, int64 y) : x_(x), y_(y) {}
00091 int64 DistanceTo(const Location& location) const {
00092 return Abs(x_ - location.x_) + Abs(y_ - location.y_);
00093 }
00094 private:
00095 static int64 Abs(int64 value) { return std::max(value, -value); }
00096
00097 int64 x_;
00098 int64 y_;
00099 };
00100
00101 ACMRandom randomizer_;
00102 const int64 speed_;
00103 ITIVector<RoutingModel::NodeIndex, Location> locations_;
00104 };
00105
00106
00107 class RandomDemand {
00108 public:
00109 RandomDemand(int size, RoutingModel::NodeIndex depot)
00110 : size_(size), depot_(depot) {
00111 CHECK_LT(0, size_);
00112 }
00113 void Initialize() {
00114 const int64 kDemandMax = 5;
00115 const int64 kDemandMin = 1;
00116 demand_.reset(new int64[size_]);
00117 ACMRandom randomizer(GetSeed());
00118 for (int order = 0; order < size_; ++order) {
00119 if (order == depot_) {
00120 demand_[order] = 0;
00121 } else {
00122 demand_[order] =
00123 kDemandMin + randomizer.Uniform(kDemandMax - kDemandMin + 1);
00124 }
00125 }
00126 }
00127 int64 Demand(RoutingModel::NodeIndex from,
00128 RoutingModel::NodeIndex to) const {
00129 return demand_[from.value()];
00130 }
00131
00132 private:
00133 scoped_array<int64> demand_;
00134 const int size_;
00135 const RoutingModel::NodeIndex depot_;
00136 };
00137
00138
00139 class ServiceTimePlusTransition {
00140 public:
00141 ServiceTimePlusTransition(int64 time_per_demand_unit,
00142 RoutingModel::NodeEvaluator2* demand,
00143 RoutingModel::NodeEvaluator2* transition_time)
00144 : time_per_demand_unit_(time_per_demand_unit),
00145 demand_(demand),
00146 transition_time_(transition_time) {}
00147 int64 Compute(RoutingModel::NodeIndex from,
00148 RoutingModel::NodeIndex to) const {
00149 return time_per_demand_unit_ * demand_->Run(from, to)
00150 + transition_time_->Run(from, to);
00151 }
00152 private:
00153 const int64 time_per_demand_unit_;
00154 scoped_ptr<RoutingModel::NodeEvaluator2> demand_;
00155 scoped_ptr<RoutingModel::NodeEvaluator2> transition_time_;
00156 };
00157
00158
00159
00160 void DisplayPlan(const RoutingModel& routing, const Assignment& plan) {
00161
00162 string plan_output = StringPrintf("Cost %lld\n", plan.ObjectiveValue());
00163
00164
00165 string dropped;
00166 for (int order = 1; order < routing.nodes(); ++order) {
00167 if (plan.Value(routing.NextVar(order)) == order) {
00168 if (dropped.empty()) {
00169 StringAppendF(&dropped, " %d", order);
00170 } else {
00171 StringAppendF(&dropped, ", %d", order);
00172 }
00173 }
00174 }
00175 if (!dropped.empty()) {
00176 plan_output += "Dropped orders:" + dropped + "\n";
00177 }
00178
00179
00180 for (int route_number = 0;
00181 route_number < routing.vehicles();
00182 ++route_number) {
00183 int64 order = routing.Start(route_number);
00184 StringAppendF(&plan_output, "Route %d: ", route_number);
00185 if (routing.IsEnd(plan.Value(routing.NextVar(order)))) {
00186 plan_output += "Empty\n";
00187 } else {
00188 while (!routing.IsEnd(order)) {
00189 IntVar* load_var = routing.CumulVar(order, kCapacity);
00190 IntVar* time_var = routing.CumulVar(order, kTime);
00191 StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld) -> ",
00192 order,
00193 plan.Value(load_var),
00194 plan.Min(time_var),
00195 plan.Max(time_var));
00196 order = plan.Value(routing.NextVar(order));
00197 }
00198 IntVar* load_var = routing.CumulVar(order, kCapacity);
00199 IntVar* time_var = routing.CumulVar(order, kTime);
00200 StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld)\n",
00201 order,
00202 plan.Value(load_var),
00203 plan.Min(time_var),
00204 plan.Max(time_var));
00205 }
00206 }
00207 LG << plan_output;
00208 }
00209
00210 int main(int argc, char **argv) {
00211 google::ParseCommandLineFlags(&argc, &argv, true);
00212 CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
00213 CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
00214
00215
00216
00217 const RoutingModel::NodeIndex kDepot(0);
00218 RoutingModel routing(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles);
00219 routing.SetDepot(kDepot);
00220
00221 routing.SetCommandLineOption("routing_first_solution", "PathCheapestArc");
00222
00223 routing.SetCommandLineOption("routing_no_lns", "true");
00224
00225
00226 const int64 kXMax = 100000;
00227 const int64 kYMax = 100000;
00228 const int64 kSpeed = 10;
00229 LocationContainer locations(kSpeed);
00230 for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
00231 locations.AddRandomLocation(kXMax, kYMax);
00232 }
00233
00234
00235 routing.SetCost(NewPermanentCallback(&locations,
00236 &LocationContainer::ManhattanDistance));
00237
00238
00239 const int64 kVehicleCapacity = 40;
00240 const int64 kNullCapacitySlack = 0;
00241 RandomDemand demand(routing.nodes(), kDepot);
00242 demand.Initialize();
00243 routing.AddDimension(NewPermanentCallback(&demand, &RandomDemand::Demand),
00244 kNullCapacitySlack, kVehicleCapacity, kCapacity);
00245
00246
00247 const int64 kTimePerDemandUnit = 300;
00248 const int64 kHorizon = 24 * 3600;
00249 ServiceTimePlusTransition time(
00250 kTimePerDemandUnit,
00251 NewPermanentCallback(&demand, &RandomDemand::Demand),
00252 NewPermanentCallback(&locations, &LocationContainer::ManhattanTime));
00253 routing.AddDimension(
00254 NewPermanentCallback(&time,
00255 &ServiceTimePlusTransition::Compute),
00256 kHorizon, kHorizon, kTime);
00257
00258 ACMRandom randomizer(GetSeed());
00259 const int64 kTWDuration = 5 * 3600;
00260 for (int order = 1; order < routing.nodes(); ++order) {
00261 const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
00262 routing.CumulVar(order, kTime)->SetRange(start, start + kTWDuration);
00263 }
00264
00265
00266 const int64 kPenalty = 100000;
00267 const RoutingModel::NodeIndex kFirstNodeAfterDepot(1);
00268 for (RoutingModel::NodeIndex order = kFirstNodeAfterDepot;
00269 order < routing.nodes(); ++order) {
00270 std::vector<RoutingModel::NodeIndex> orders(1, order);
00271 routing.AddDisjunction(orders, kPenalty);
00272 }
00273
00274
00275 const Assignment* solution = routing.Solve();
00276 if (solution != NULL) {
00277 DisplayPlan(routing, *solution);
00278 } else {
00279 LG << "No solution found.";
00280 }
00281 return 0;
00282 }