reapply google format
This commit is contained in:
@@ -28,13 +28,13 @@ void RunConstraintProgrammingExample() {
|
||||
IntVar *const z = solver.MakeIntVar(0, numVals - 1, "z");
|
||||
|
||||
// Define constraints.
|
||||
std::vector<IntVar *> xyvars = { x, y };
|
||||
std::vector<IntVar *> xyvars = {x, y};
|
||||
solver.AddConstraint(solver.MakeAllDifferent(xyvars));
|
||||
|
||||
LOG(INFO) << "Number of constraints: " << solver.constraints();
|
||||
|
||||
// Create decision builder to search for solutions.
|
||||
std::vector<IntVar *> allvars = { x, y, z };
|
||||
std::vector<IntVar *> allvars = {x, y, z};
|
||||
DecisionBuilder *const db = solver.MakePhase(
|
||||
allvars, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE);
|
||||
|
||||
@@ -51,7 +51,7 @@ void RunConstraintProgrammingExample() {
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << "ms";
|
||||
LOG(INFO) << "Memory usage: " << Solver::MemoryUsage() << " bytes";
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -93,8 +93,8 @@ void CostasHard(const int dim) {
|
||||
std::vector<IntVar> vars;
|
||||
Domain domain(1, dim);
|
||||
for (int i = 0; i < dim; ++i) {
|
||||
vars.push_back(cp_model.NewIntVar(domain)
|
||||
.WithName(absl::StrCat("var_", i)));
|
||||
vars.push_back(
|
||||
cp_model.NewIntVar(domain).WithName(absl::StrCat("var_", i)));
|
||||
}
|
||||
|
||||
cp_model.AddAllDifferent(vars);
|
||||
@@ -106,10 +106,7 @@ void CostasHard(const int dim) {
|
||||
|
||||
for (int j = 0; j < dim - i; ++j) {
|
||||
subset.push_back(cp_model.NewIntVar(diff));
|
||||
cp_model.AddEquality(LinearExpr::Sum({
|
||||
subset[j], vars[j]
|
||||
}),
|
||||
vars[j + i]);
|
||||
cp_model.AddEquality(LinearExpr::Sum({subset[j], vars[j]}), vars[j + i]);
|
||||
}
|
||||
|
||||
cp_model.AddAllDifferent(subset);
|
||||
@@ -171,12 +168,10 @@ void CostasBool(const int dim) {
|
||||
const BoolVar neg = cp_model.NewBoolVar();
|
||||
positive_diffs.push_back(pos);
|
||||
negative_diffs.push_back(neg);
|
||||
cp_model.AddBoolOr({
|
||||
Not(vars[var][value]), Not(vars[var + step][value + diff]), pos
|
||||
});
|
||||
cp_model.AddBoolOr({
|
||||
Not(vars[var][value + diff]), Not(vars[var + step][value]), neg
|
||||
});
|
||||
cp_model.AddBoolOr({Not(vars[var][value]),
|
||||
Not(vars[var + step][value + diff]), pos});
|
||||
cp_model.AddBoolOr({Not(vars[var][value + diff]),
|
||||
Not(vars[var + step][value]), neg});
|
||||
}
|
||||
}
|
||||
cp_model.AddLessOrEqual(LinearExpr::BooleanSum(positive_diffs), 1);
|
||||
@@ -245,12 +240,10 @@ void CostasBoolSoft(const int dim) {
|
||||
const BoolVar neg = cp_model.NewBoolVar();
|
||||
positive_diffs.push_back(pos);
|
||||
negative_diffs.push_back(neg);
|
||||
cp_model.AddBoolOr({
|
||||
Not(vars[var][value]), Not(vars[var + step][value + diff]), pos
|
||||
});
|
||||
cp_model.AddBoolOr({
|
||||
Not(vars[var][value + diff]), Not(vars[var + step][value]), neg
|
||||
});
|
||||
cp_model.AddBoolOr({Not(vars[var][value]),
|
||||
Not(vars[var + step][value + diff]), pos});
|
||||
cp_model.AddBoolOr({Not(vars[var][value + diff]),
|
||||
Not(vars[var + step][value]), neg});
|
||||
}
|
||||
}
|
||||
const IntVar pos_var =
|
||||
@@ -297,8 +290,8 @@ void CostasBoolSoft(const int dim) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -90,12 +90,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -106,26 +106,27 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
const int64 kTimePerDemandUnit = 300;
|
||||
const int64 kHorizon = 24 * 3600;
|
||||
ServiceTimePlusTransition time(
|
||||
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
kTimePerDemandUnit,
|
||||
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
|
||||
|
||||
// Adding disjoint time windows.
|
||||
|
||||
@@ -88,12 +88,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -104,26 +104,27 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
const int64 kTimePerDemandUnit = 300;
|
||||
const int64 kHorizon = 24 * 3600;
|
||||
ServiceTimePlusTransition time(
|
||||
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
kTimePerDemandUnit,
|
||||
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ true, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime);
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
|
||||
|
||||
// Adding time windows.
|
||||
|
||||
@@ -35,7 +35,7 @@ int32 GetSeed(bool deterministic);
|
||||
// Location container, contains positions of orders and can be used to obtain
|
||||
// Manhattan distances/times between locations.
|
||||
class LocationContainer {
|
||||
public:
|
||||
public:
|
||||
LocationContainer(int64 speed, bool use_deterministic_seed);
|
||||
void AddLocation(int64 x, int64 y) { locations_.push_back(Location(x, y)); }
|
||||
void AddRandomLocation(int64 x_max, int64 y_max);
|
||||
@@ -51,15 +51,15 @@ public:
|
||||
RoutingIndexManager::NodeIndex node2) const;
|
||||
int64 SameLocationFromIndex(int64 node1, int64 node2) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
class Location {
|
||||
public:
|
||||
public:
|
||||
Location();
|
||||
Location(int64 x, int64 y);
|
||||
int64 DistanceTo(const Location &location) const;
|
||||
bool IsAtSameLocation(const Location &location) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
static int64 Abs(int64 value);
|
||||
|
||||
int64 x_;
|
||||
@@ -73,14 +73,14 @@ private:
|
||||
|
||||
// Random demand.
|
||||
class RandomDemand {
|
||||
public:
|
||||
public:
|
||||
RandomDemand(int size, RoutingIndexManager::NodeIndex depot,
|
||||
bool use_deterministic_seed);
|
||||
void Initialize();
|
||||
int64 Demand(RoutingIndexManager::NodeIndex from,
|
||||
RoutingIndexManager::NodeIndex to) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<int64[]> demand_;
|
||||
const int size_;
|
||||
const RoutingIndexManager::NodeIndex depot_;
|
||||
@@ -89,14 +89,14 @@ private:
|
||||
|
||||
// Service time (proportional to demand) + transition time callback.
|
||||
class ServiceTimePlusTransition {
|
||||
public:
|
||||
public:
|
||||
ServiceTimePlusTransition(int64 time_per_demand_unit,
|
||||
RoutingNodeEvaluator2 demand,
|
||||
RoutingNodeEvaluator2 transition_time);
|
||||
int64 Compute(RoutingIndexManager::NodeIndex from,
|
||||
RoutingIndexManager::NodeIndex to) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
const int64 time_per_demand_unit_;
|
||||
RoutingNodeEvaluator2 demand_;
|
||||
RoutingNodeEvaluator2 transition_time_;
|
||||
@@ -104,14 +104,14 @@ private:
|
||||
|
||||
// Stop service time + transition time callback.
|
||||
class StopServiceTimePlusTransition {
|
||||
public:
|
||||
public:
|
||||
StopServiceTimePlusTransition(int64 stop_time,
|
||||
const LocationContainer &location_container,
|
||||
RoutingNodeEvaluator2 transition_time);
|
||||
int64 Compute(RoutingIndexManager::NodeIndex from,
|
||||
RoutingIndexManager::NodeIndex to) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
const int64 stop_time_;
|
||||
const LocationContainer &location_container_;
|
||||
RoutingNodeEvaluator2 demand_;
|
||||
@@ -120,14 +120,13 @@ private:
|
||||
|
||||
// Route plan displayer.
|
||||
// TODO(user): Move the display code to the routing library.
|
||||
void
|
||||
DisplayPlan(const operations_research::RoutingIndexManager &manager,
|
||||
const operations_research::RoutingModel &routing,
|
||||
const operations_research::Assignment &plan,
|
||||
bool use_same_vehicle_costs, int64 max_nodes_per_group,
|
||||
int64 same_vehicle_cost,
|
||||
const operations_research::RoutingDimension &capacity_dimension,
|
||||
const operations_research::RoutingDimension &time_dimension);
|
||||
void DisplayPlan(
|
||||
const operations_research::RoutingIndexManager &manager,
|
||||
const operations_research::RoutingModel &routing,
|
||||
const operations_research::Assignment &plan, bool use_same_vehicle_costs,
|
||||
int64 max_nodes_per_group, int64 same_vehicle_cost,
|
||||
const operations_research::RoutingDimension &capacity_dimension,
|
||||
const operations_research::RoutingDimension &time_dimension);
|
||||
|
||||
using NodeIndex = RoutingIndexManager::NodeIndex;
|
||||
|
||||
@@ -191,8 +190,8 @@ int64 LocationContainer::Location::DistanceTo(const Location &location) const {
|
||||
return Abs(x_ - location.x_) + Abs(y_ - location.y_);
|
||||
}
|
||||
|
||||
bool
|
||||
LocationContainer::Location::IsAtSameLocation(const Location &location) const {
|
||||
bool LocationContainer::Location::IsAtSameLocation(
|
||||
const Location &location) const {
|
||||
return x_ == location.x_ && y_ == location.y_;
|
||||
}
|
||||
|
||||
@@ -202,7 +201,8 @@ int64 LocationContainer::Location::Abs(int64 value) {
|
||||
|
||||
RandomDemand::RandomDemand(int size, NodeIndex depot,
|
||||
bool use_deterministic_seed)
|
||||
: size_(size), depot_(depot),
|
||||
: size_(size),
|
||||
depot_(depot),
|
||||
use_deterministic_seed_(use_deterministic_seed) {
|
||||
CHECK_LT(0, size_);
|
||||
}
|
||||
@@ -229,7 +229,8 @@ int64 RandomDemand::Demand(NodeIndex from, NodeIndex /*to*/) const {
|
||||
ServiceTimePlusTransition::ServiceTimePlusTransition(
|
||||
int64 time_per_demand_unit, RoutingNodeEvaluator2 demand,
|
||||
RoutingNodeEvaluator2 transition_time)
|
||||
: time_per_demand_unit_(time_per_demand_unit), demand_(std::move(demand)),
|
||||
: time_per_demand_unit_(time_per_demand_unit),
|
||||
demand_(std::move(demand)),
|
||||
transition_time_(std::move(transition_time)) {}
|
||||
|
||||
int64 ServiceTimePlusTransition::Compute(NodeIndex from, NodeIndex to) const {
|
||||
@@ -239,7 +240,8 @@ int64 ServiceTimePlusTransition::Compute(NodeIndex from, NodeIndex to) const {
|
||||
StopServiceTimePlusTransition::StopServiceTimePlusTransition(
|
||||
int64 stop_time, const LocationContainer &location_container,
|
||||
RoutingNodeEvaluator2 transition_time)
|
||||
: stop_time_(stop_time), location_container_(location_container),
|
||||
: stop_time_(stop_time),
|
||||
location_container_(location_container),
|
||||
transition_time_(std::move(transition_time)) {}
|
||||
|
||||
int64 StopServiceTimePlusTransition::Compute(NodeIndex from,
|
||||
@@ -249,21 +251,19 @@ int64 StopServiceTimePlusTransition::Compute(NodeIndex from,
|
||||
: stop_time_ + transition_time_(from, to);
|
||||
}
|
||||
|
||||
void
|
||||
DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing,
|
||||
const operations_research::Assignment &plan,
|
||||
bool use_same_vehicle_costs, int64 max_nodes_per_group,
|
||||
int64 same_vehicle_cost,
|
||||
const operations_research::RoutingDimension &capacity_dimension,
|
||||
const operations_research::RoutingDimension &time_dimension) {
|
||||
void DisplayPlan(
|
||||
const RoutingIndexManager &manager, const RoutingModel &routing,
|
||||
const operations_research::Assignment &plan, bool use_same_vehicle_costs,
|
||||
int64 max_nodes_per_group, int64 same_vehicle_cost,
|
||||
const operations_research::RoutingDimension &capacity_dimension,
|
||||
const operations_research::RoutingDimension &time_dimension) {
|
||||
// Display plan cost.
|
||||
std::string plan_output = absl::StrFormat("Cost %d\n", plan.ObjectiveValue());
|
||||
|
||||
// Display dropped orders.
|
||||
std::string dropped;
|
||||
for (int64 order = 0; order < routing.Size(); ++order) {
|
||||
if (routing.IsStart(order) || routing.IsEnd(order))
|
||||
continue;
|
||||
if (routing.IsStart(order) || routing.IsEnd(order)) continue;
|
||||
if (plan.Value(routing.NextVar(order)) == order) {
|
||||
if (dropped.empty()) {
|
||||
absl::StrAppendFormat(&dropped, " %d",
|
||||
@@ -283,8 +283,7 @@ DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing,
|
||||
int64 group_same_vehicle_cost = 0;
|
||||
std::set<int> visited;
|
||||
for (int64 order = 0; order < routing.Size(); ++order) {
|
||||
if (routing.IsStart(order) || routing.IsEnd(order))
|
||||
continue;
|
||||
if (routing.IsStart(order) || routing.IsEnd(order)) continue;
|
||||
++group_size;
|
||||
visited.insert(plan.Value(routing.VehicleVar(order)));
|
||||
if (group_size == max_nodes_per_group) {
|
||||
@@ -328,8 +327,7 @@ DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing,
|
||||
plan.Value(load_var), plan.Min(time_var),
|
||||
plan.Max(time_var));
|
||||
}
|
||||
if (routing.IsEnd(order))
|
||||
break;
|
||||
if (routing.IsEnd(order)) break;
|
||||
plan_output += " -> ";
|
||||
order = plan.Value(routing.NextVar(order));
|
||||
}
|
||||
@@ -338,6 +336,6 @@ DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing,
|
||||
}
|
||||
LOG(INFO) << plan_output;
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_
|
||||
#endif // OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_
|
||||
|
||||
@@ -98,12 +98,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -114,26 +114,27 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
const int64 kTimePerDemandUnit = 300;
|
||||
const int64 kHorizon = 24 * 3600;
|
||||
ServiceTimePlusTransition time(
|
||||
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
kTimePerDemandUnit,
|
||||
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
|
||||
RoutingDimension *const time_dimension = routing.GetMutableDimension(kTime);
|
||||
|
||||
// Adding time windows.
|
||||
@@ -172,10 +173,9 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
const std::vector<std::vector<int> > break_data = {
|
||||
{ /*start_min*/ 11, /*start_max*/ 13, /*duration*/ 2400 },
|
||||
{ /*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800 },
|
||||
{ /*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800 }
|
||||
};
|
||||
{/*start_min*/ 11, /*start_max*/ 13, /*duration*/ 2400},
|
||||
{/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800},
|
||||
{/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800}};
|
||||
Solver *const solver = routing.solver();
|
||||
for (int vehicle = 0; vehicle < absl::GetFlag(FLAGS_vrp_vehicles);
|
||||
++vehicle) {
|
||||
|
||||
@@ -89,12 +89,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -105,26 +105,27 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
const int64 kTimePerDemandUnit = 300;
|
||||
const int64 kHorizon = 24 * 3600;
|
||||
ServiceTimePlusTransition time(
|
||||
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
kTimePerDemandUnit,
|
||||
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ true, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime);
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
|
||||
// Adding time windows.
|
||||
ACMRandom randomizer(
|
||||
@@ -143,10 +144,10 @@ int main(int argc, char **argv) {
|
||||
const int64 kFuelCapacity = kXMax + kYMax;
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.NegManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
}),
|
||||
kFuelCapacity, kFuelCapacity, /*fix_start_cumul_to_zero=*/ false, kFuel);
|
||||
return locations.NegManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
}),
|
||||
kFuelCapacity, kFuelCapacity, /*fix_start_cumul_to_zero=*/false, kFuel);
|
||||
const RoutingDimension &fuel_dimension = routing.GetDimensionOrDie(kFuel);
|
||||
for (int order = 0; order < routing.Size(); ++order) {
|
||||
// Only let slack free for refueling nodes.
|
||||
@@ -172,8 +173,8 @@ int main(int argc, char **argv) {
|
||||
absl::GetFlag(FLAGS_routing_search_parameters), ¶meters));
|
||||
const Assignment *solution = routing.SolveWithParameters(parameters);
|
||||
if (solution != nullptr) {
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
|
||||
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
|
||||
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
|
||||
routing.GetDimensionOrDie(kCapacity),
|
||||
routing.GetDimensionOrDie(kTime));
|
||||
} else {
|
||||
|
||||
@@ -87,12 +87,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -103,26 +103,27 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
const int64 kTimePerDemandUnit = 300;
|
||||
const int64 kHorizon = 24 * 3600;
|
||||
ServiceTimePlusTransition time(
|
||||
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
kTimePerDemandUnit,
|
||||
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return demand.Demand(i, j);
|
||||
},
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
|
||||
|
||||
// Adding time windows.
|
||||
@@ -172,8 +173,8 @@ int main(int argc, char **argv) {
|
||||
absl::GetFlag(FLAGS_routing_search_parameters), ¶meters));
|
||||
const Assignment *solution = routing.SolveWithParameters(parameters);
|
||||
if (solution != nullptr) {
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
|
||||
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
|
||||
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
|
||||
routing.GetDimensionOrDie(kCapacity),
|
||||
routing.GetDimensionOrDie(kTime));
|
||||
} else {
|
||||
|
||||
@@ -90,12 +90,12 @@ int main(int argc, char **argv) {
|
||||
locations.AddRandomLocation(kXMax, kYMax, num_orders);
|
||||
}
|
||||
|
||||
// Setting the cost function.
|
||||
// Setting the cost function.
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
return locations.ManhattanDistance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
|
||||
// Adding capacity dimension constraints.
|
||||
@@ -106,9 +106,9 @@ int main(int argc, char **argv) {
|
||||
demand.Initialize();
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
|
||||
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true,
|
||||
kCapacity);
|
||||
|
||||
// Adding time dimension constraints.
|
||||
@@ -117,13 +117,13 @@ int main(int argc, char **argv) {
|
||||
StopServiceTimePlusTransition time(
|
||||
kStopTime, locations,
|
||||
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
return locations.ManhattanTime(i, j);
|
||||
});
|
||||
routing.AddDimension(
|
||||
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
|
||||
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
}),
|
||||
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
|
||||
|
||||
// Adding time windows, for the sake of simplicty same for each stop.
|
||||
@@ -158,14 +158,17 @@ int main(int argc, char **argv) {
|
||||
solver->AddConstraint(
|
||||
solver->MakeIsEqualCt(interval->SafeStartExpr(0), order_start,
|
||||
interval->PerformedExpr()->Var()));
|
||||
// Make interval performed iff corresponding order has service time.
|
||||
// An order has no service time iff it is at the same location as the
|
||||
// next order on the route.
|
||||
// Make interval performed iff corresponding order has service time.
|
||||
// An order has no service time iff it is at the same location as the
|
||||
// next order on the route.
|
||||
IntVar *const is_null_duration =
|
||||
solver->MakeElement([&locations, order](int64 index) {
|
||||
return locations.SameLocationFromIndex(order, index);
|
||||
},
|
||||
routing.NextVar(order))->Var();
|
||||
solver
|
||||
->MakeElement(
|
||||
[&locations, order](int64 index) {
|
||||
return locations.SameLocationFromIndex(order, index);
|
||||
},
|
||||
routing.NextVar(order))
|
||||
->Var();
|
||||
solver->AddConstraint(
|
||||
solver->MakeNonEquality(interval->PerformedExpr(), is_null_duration));
|
||||
routing.AddIntervalToAssignment(interval);
|
||||
@@ -199,8 +202,8 @@ int main(int argc, char **argv) {
|
||||
absl::GetFlag(FLAGS_routing_search_parameters), ¶meters));
|
||||
const Assignment *solution = routing.SolveWithParameters(parameters);
|
||||
if (solution != nullptr) {
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
|
||||
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
|
||||
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
|
||||
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
|
||||
routing.GetDimensionOrDie(kCapacity),
|
||||
routing.GetDimensionOrDie(kTime));
|
||||
LOG(INFO) << "Stop intervals:";
|
||||
|
||||
@@ -170,7 +170,7 @@ int SolveDimacsAssignment(int argc, char *argv[]) {
|
||||
delete graph;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
static const char *const kUsageTemplate = "usage: %s <filename>";
|
||||
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
#include "ortools/util/bitset.h"
|
||||
|
||||
DEFINE_int32(symbols_per_card, 8, "Number of symbols per card.");
|
||||
DEFINE_int32(ls_seed, 1, "Seed for the random number generator (used by "
|
||||
"the Local Neighborhood Search).");
|
||||
DEFINE_int32(ls_seed, 1,
|
||||
"Seed for the random number generator (used by "
|
||||
"the Local Neighborhood Search).");
|
||||
DEFINE_bool(use_filter, true, "Use filter in the local search to prune moves.");
|
||||
DEFINE_int32(num_swaps, 4,
|
||||
"If num_swap > 0, the search for an optimal "
|
||||
@@ -60,13 +61,14 @@ namespace operations_research {
|
||||
// sum_i(card1_symbol_vars[i]*card2_symbol_vars[i]) == count_var.
|
||||
// with all card_symbol_vars[i] being boolean variables.
|
||||
class SymbolsSharedByTwoCardsConstraint : public Constraint {
|
||||
public:
|
||||
public:
|
||||
// This constructor does not take any ownership on its arguments.
|
||||
SymbolsSharedByTwoCardsConstraint(
|
||||
Solver *const solver, const std::vector<IntVar *> &card1_symbol_vars,
|
||||
const std::vector<IntVar *> &card2_symbol_vars,
|
||||
IntVar *const num_symbols_in_common_var)
|
||||
: Constraint(solver), card1_symbol_vars_(card1_symbol_vars),
|
||||
: Constraint(solver),
|
||||
card1_symbol_vars_(card1_symbol_vars),
|
||||
card2_symbol_vars_(card2_symbol_vars),
|
||||
num_symbols_(card1_symbol_vars.size()),
|
||||
num_symbols_in_common_var_(num_symbols_in_common_var) {
|
||||
@@ -175,7 +177,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<IntVar *> card1_symbol_vars_;
|
||||
std::vector<IntVar *> card2_symbol_vars_;
|
||||
const int num_symbols_;
|
||||
@@ -231,11 +233,13 @@ IntVar *CreateViolationVar(Solver *const solver,
|
||||
// parent class below, which contains some shared code to store a
|
||||
// compact representation of which symbols appeal on each cards.
|
||||
class DobbleOperator : public IntVarLocalSearchOperator {
|
||||
public:
|
||||
public:
|
||||
DobbleOperator(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
|
||||
int num_symbols, int num_symbols_per_card)
|
||||
: IntVarLocalSearchOperator(card_symbol_vars), num_cards_(num_cards),
|
||||
num_symbols_(num_symbols), num_symbols_per_card_(num_symbols_per_card),
|
||||
: IntVarLocalSearchOperator(card_symbol_vars),
|
||||
num_cards_(num_cards),
|
||||
num_symbols_(num_symbols),
|
||||
num_symbols_per_card_(num_symbols_per_card),
|
||||
symbols_per_card_(num_cards) {
|
||||
CHECK_GT(num_cards, 0);
|
||||
CHECK_GT(num_symbols, 0);
|
||||
@@ -247,7 +251,7 @@ public:
|
||||
|
||||
~DobbleOperator() override {}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// OnStart() simply stores the current symbols per card in
|
||||
// symbols_per_card_, and defers further initialization to the
|
||||
// subclass's InitNeighborhoodSearch() method.
|
||||
@@ -294,12 +298,14 @@ protected:
|
||||
// symbol to a card that already had it); see the DobbleFilter class
|
||||
// below to see how we filter those out.
|
||||
class SwapSymbols : public DobbleOperator {
|
||||
public:
|
||||
public:
|
||||
SwapSymbols(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
|
||||
int num_symbols, int num_symbols_per_card)
|
||||
: DobbleOperator(card_symbol_vars, num_cards, num_symbols,
|
||||
num_symbols_per_card),
|
||||
current_card1_(-1), current_card2_(-1), current_symbol1_(-1),
|
||||
current_card1_(-1),
|
||||
current_card2_(-1),
|
||||
current_symbol1_(-1),
|
||||
current_symbol2_(-1) {}
|
||||
|
||||
~SwapSymbols() override {}
|
||||
@@ -317,7 +323,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
// Reinit the exploration loop.
|
||||
void InitNeighborhoodSearch() override {
|
||||
current_card1_ = 0;
|
||||
@@ -362,19 +368,20 @@ private:
|
||||
// randomized "infinite" version instead of an iterative, exhaustive
|
||||
// one.
|
||||
class SwapSymbolsOnCardPairs : public DobbleOperator {
|
||||
public:
|
||||
public:
|
||||
SwapSymbolsOnCardPairs(const std::vector<IntVar *> &card_symbol_vars,
|
||||
int num_cards, int num_symbols,
|
||||
int num_symbols_per_card, int max_num_swaps)
|
||||
: DobbleOperator(card_symbol_vars, num_cards, num_symbols,
|
||||
num_symbols_per_card),
|
||||
rand_(absl::GetFlag(FLAGS_ls_seed)), max_num_swaps_(max_num_swaps) {
|
||||
rand_(absl::GetFlag(FLAGS_ls_seed)),
|
||||
max_num_swaps_(max_num_swaps) {
|
||||
CHECK_GE(max_num_swaps, 2);
|
||||
}
|
||||
|
||||
~SwapSymbolsOnCardPairs() override {}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
bool MakeOneNeighbor() override {
|
||||
const int num_swaps =
|
||||
absl::Uniform<int32_t>(rand_, 0, max_num_swaps_ - 1) + 2;
|
||||
@@ -394,7 +401,7 @@ protected:
|
||||
|
||||
void InitNeighborhoodSearch() override {}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::mt19937 rand_;
|
||||
const int max_num_swaps_;
|
||||
};
|
||||
@@ -427,12 +434,15 @@ private:
|
||||
// effectively limits the number of cards to 63, and thus the number
|
||||
// of symbols per card to 8.
|
||||
class DobbleFilter : public IntVarLocalSearchFilter {
|
||||
public:
|
||||
public:
|
||||
DobbleFilter(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
|
||||
int num_symbols, int num_symbols_per_card)
|
||||
: IntVarLocalSearchFilter(card_symbol_vars), num_cards_(num_cards),
|
||||
num_symbols_(num_symbols), num_symbols_per_card_(num_symbols_per_card),
|
||||
temporary_bitset_(0), symbol_bitmask_per_card_(num_cards, 0),
|
||||
: IntVarLocalSearchFilter(card_symbol_vars),
|
||||
num_cards_(num_cards),
|
||||
num_symbols_(num_symbols),
|
||||
num_symbols_per_card_(num_symbols_per_card),
|
||||
temporary_bitset_(0),
|
||||
symbol_bitmask_per_card_(num_cards, 0),
|
||||
violation_costs_(num_cards_, std::vector<int>(num_cards_, 0)) {}
|
||||
|
||||
// We build the current bitmap and the matrix of violation cost
|
||||
@@ -518,7 +528,7 @@ public:
|
||||
return cost_delta < 0;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
// Undo information after an evaluation.
|
||||
struct UndoChange {
|
||||
UndoChange(int c, uint64 b) : card(c), bitset(b) {}
|
||||
@@ -686,8 +696,8 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
|
||||
// strategy "Pick some random, yet unassigned card symbol variable
|
||||
// and set its value to 1".
|
||||
DecisionBuilder *const build_db = solver.MakePhase(
|
||||
all_card_symbol_vars, Solver::CHOOSE_RANDOM, // Solver::IntVarStrategy
|
||||
Solver::ASSIGN_MAX_VALUE); // Solver::IntValueStrategy
|
||||
all_card_symbol_vars, Solver::CHOOSE_RANDOM, // Solver::IntVarStrategy
|
||||
Solver::ASSIGN_MAX_VALUE); // Solver::IntValueStrategy
|
||||
|
||||
// Creates local search operators.
|
||||
std::vector<LocalSearchOperator *> operators;
|
||||
@@ -721,8 +731,8 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
|
||||
all_card_symbol_vars, build_db,
|
||||
solver.MakeLocalSearchPhaseParameters(
|
||||
objective_var, solver.ConcatenateOperators(operators, true),
|
||||
nullptr, // Sub decision builder, not needed here.
|
||||
nullptr, // Limit the search for improving move, we will stop
|
||||
nullptr, // Sub decision builder, not needed here.
|
||||
nullptr, // Limit the search for improving move, we will stop
|
||||
// the exploration of the local search at the first
|
||||
// improving solution (first accept).
|
||||
filter_manager));
|
||||
@@ -744,7 +754,7 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
|
||||
// And solve!
|
||||
solver.Solve(final_db, monitors);
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace operations_research {
|
||||
|
||||
// Prints the instance of the Frequency Assignment Problem.
|
||||
class FapModelPrinter {
|
||||
public:
|
||||
public:
|
||||
FapModelPrinter(const std::map<int, FapVariable> &variables,
|
||||
const std::vector<FapConstraint> &constraints,
|
||||
const std::string &objective, const std::vector<int> &values);
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void PrintFapConstraints();
|
||||
void PrintFapValues();
|
||||
|
||||
private:
|
||||
private:
|
||||
const std::map<int, FapVariable> variables_;
|
||||
const std::vector<FapConstraint> constraints_;
|
||||
const std::string objective_;
|
||||
@@ -53,7 +53,9 @@ FapModelPrinter::FapModelPrinter(const std::map<int, FapVariable> &variables,
|
||||
const std::vector<FapConstraint> &constraints,
|
||||
const std::string &objective,
|
||||
const std::vector<int> &values)
|
||||
: variables_(variables), constraints_(constraints), objective_(objective),
|
||||
: variables_(variables),
|
||||
constraints_(constraints),
|
||||
objective_(objective),
|
||||
values_(values) {}
|
||||
|
||||
FapModelPrinter::~FapModelPrinter() {}
|
||||
@@ -112,5 +114,5 @@ void FapModelPrinter::PrintFapValues() {
|
||||
LOG(INFO) << domain;
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
|
||||
|
||||
@@ -41,8 +41,13 @@ void ParseFileByLines(const std::string &filename,
|
||||
// frequency assignment problem.
|
||||
struct FapVariable {
|
||||
FapVariable()
|
||||
: domain_index(-1), domain_size(0), domain(), degree(0),
|
||||
initial_position(-1), mobility_index(-1), mobility_cost(-1),
|
||||
: domain_index(-1),
|
||||
domain_size(0),
|
||||
domain(),
|
||||
degree(0),
|
||||
initial_position(-1),
|
||||
mobility_index(-1),
|
||||
mobility_cost(-1),
|
||||
hard(false) {}
|
||||
|
||||
~FapVariable() {}
|
||||
@@ -79,8 +84,15 @@ struct FapVariable {
|
||||
// radio links of the frequency assignment problem.
|
||||
struct FapConstraint {
|
||||
FapConstraint()
|
||||
: variable1(-1), variable2(-1), impact(0), type(""), operation(""),
|
||||
value(-1), weight_index(-1), weight_cost(-1), hard(false) {}
|
||||
: variable1(-1),
|
||||
variable2(-1),
|
||||
impact(0),
|
||||
type(""),
|
||||
operation(""),
|
||||
value(-1),
|
||||
weight_index(-1),
|
||||
weight_cost(-1),
|
||||
hard(false) {}
|
||||
~FapConstraint() {}
|
||||
|
||||
// Fields:
|
||||
@@ -135,7 +147,7 @@ struct FapComponent {
|
||||
// This file describes all the variables in the instance.
|
||||
// Each line corresponds to one variable.
|
||||
class VariableParser {
|
||||
public:
|
||||
public:
|
||||
explicit VariableParser(const std::string &data_directory);
|
||||
~VariableParser();
|
||||
|
||||
@@ -143,7 +155,7 @@ public:
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
private:
|
||||
const std::string filename_;
|
||||
// A map is used because in the model, the variables have ids which may not
|
||||
// be consecutive, may be very sparse and don't have a specific upper-bound.
|
||||
@@ -157,7 +169,7 @@ private:
|
||||
// This file describes the domains used by the variables of the problem.
|
||||
// Each line describes one domain.
|
||||
class DomainParser {
|
||||
public:
|
||||
public:
|
||||
explicit DomainParser(const std::string &data_directory);
|
||||
~DomainParser();
|
||||
|
||||
@@ -165,7 +177,7 @@ public:
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
private:
|
||||
const std::string filename_;
|
||||
// A map is used because in the model, the ids of the different available
|
||||
// domains may be random values, since they are used as names. The key of the
|
||||
@@ -179,7 +191,7 @@ private:
|
||||
// This file describes the constraints of the instance.
|
||||
// Each line defines a binary constraint.
|
||||
class ConstraintParser {
|
||||
public:
|
||||
public:
|
||||
explicit ConstraintParser(const std::string &data_directory);
|
||||
~ConstraintParser();
|
||||
|
||||
@@ -187,7 +199,7 @@ public:
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
private:
|
||||
const std::string filename_;
|
||||
std::vector<FapConstraint> constraints_;
|
||||
|
||||
@@ -199,7 +211,7 @@ private:
|
||||
// It may also contain 8 coefficients: 4 for different constraint violation
|
||||
// costs and 4 for different variable mobility costs.
|
||||
class ParametersParser {
|
||||
public:
|
||||
public:
|
||||
explicit ParametersParser(const std::string &data_directory);
|
||||
~ParametersParser();
|
||||
|
||||
@@ -211,7 +223,7 @@ public:
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
private:
|
||||
const std::string filename_;
|
||||
static const int constraint_coefficient_no_ = 4;
|
||||
static const int variable_coefficient_no_ = 4;
|
||||
@@ -227,7 +239,7 @@ int strtoint32(const std::string &word) {
|
||||
CHECK(absl::SimpleAtoi(word, &result));
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
// Function that finds the disjoint sub-graphs of the graph of the instance.
|
||||
void FindComponents(const std::vector<FapConstraint> &constraints,
|
||||
@@ -350,7 +362,8 @@ const int ParametersParser::variable_coefficient_no_;
|
||||
const int ParametersParser::coefficient_no_;
|
||||
|
||||
ParametersParser::ParametersParser(const std::string &data_directory)
|
||||
: filename_(data_directory + "/cst.txt"), objective_(""),
|
||||
: filename_(data_directory + "/cst.txt"),
|
||||
objective_(""),
|
||||
constraint_weights_(constraint_coefficient_no_, 0),
|
||||
variable_weights_(variable_coefficient_no_, 0) {}
|
||||
|
||||
@@ -476,15 +489,17 @@ void FindComponents(const std::vector<FapConstraint> &constraints,
|
||||
}
|
||||
// Insert all the variables of the maximum indexed component to the
|
||||
// variables of the minimum indexed component.
|
||||
((*components)[min_component_index]).variables
|
||||
.insert(((*components)[max_component_index]).variables.begin(),
|
||||
((*components)[max_component_index]).variables.end());
|
||||
((*components)[min_component_index])
|
||||
.variables.insert(
|
||||
((*components)[max_component_index]).variables.begin(),
|
||||
((*components)[max_component_index]).variables.end());
|
||||
// Insert all the constraints of the maximum indexed component to the
|
||||
// constraints of the minimum indexed component.
|
||||
((*components)[min_component_index]).constraints
|
||||
.insert(((*components)[min_component_index]).constraints.end(),
|
||||
((*components)[max_component_index]).constraints.begin(),
|
||||
((*components)[max_component_index]).constraints.end());
|
||||
((*components)[min_component_index])
|
||||
.constraints.insert(
|
||||
((*components)[min_component_index]).constraints.end(),
|
||||
((*components)[max_component_index]).constraints.begin(),
|
||||
((*components)[max_component_index]).constraints.end());
|
||||
(*components)[min_component_index].constraints.push_back(constraint);
|
||||
// Delete the maximum indexed component from the components set.
|
||||
components->erase(max_component_index);
|
||||
@@ -597,5 +612,5 @@ void ParseInstance(const std::string &data_directory, bool find_components,
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_PARSER_H_
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_PARSER_H_
|
||||
|
||||
@@ -69,10 +69,10 @@ void PrintResultsSoft(SolutionCollector *const collector,
|
||||
const std::map<int, int> &index_from_key,
|
||||
const std::vector<int> &key_from_index);
|
||||
|
||||
bool
|
||||
CheckConstraintSatisfaction(const std::vector<FapConstraint> &data_constraints,
|
||||
const std::vector<int> &variables,
|
||||
const std::map<int, int> &index_from_key) {
|
||||
bool CheckConstraintSatisfaction(
|
||||
const std::vector<FapConstraint> &data_constraints,
|
||||
const std::vector<int> &variables,
|
||||
const std::map<int, int> &index_from_key) {
|
||||
bool status = true;
|
||||
for (const FapConstraint &ct : data_constraints) {
|
||||
const int index1 = gtl::FindOrDie(index_from_key, ct.variable1);
|
||||
@@ -164,8 +164,8 @@ void PrintResultsHard(SolutionCollector *const collector,
|
||||
}
|
||||
|
||||
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
|
||||
LOG(INFO) << "Maximum value used: " << *std::max_element(results.begin(),
|
||||
results.end());
|
||||
LOG(INFO) << "Maximum value used: "
|
||||
<< *std::max_element(results.begin(), results.end());
|
||||
LOG(INFO) << " Failures: " << collector->failures(solution_index);
|
||||
}
|
||||
LOG(INFO) << " ============================================================";
|
||||
@@ -216,12 +216,12 @@ void PrintResultsSoft(SolutionCollector *const collector,
|
||||
}
|
||||
|
||||
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
|
||||
LOG(INFO) << "Maximum value used: " << *std::max_element(results.begin(),
|
||||
results.end());
|
||||
LOG(INFO) << "Maximum value used: "
|
||||
<< *std::max_element(results.begin(), results.end());
|
||||
LOG(INFO) << " Failures: " << collector->failures(solution_index);
|
||||
}
|
||||
LOG(INFO) << " ============================================================";
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
|
||||
|
||||
@@ -27,10 +27,10 @@ void MinCostFlowOn4x4Matrix() {
|
||||
LOG(INFO) << "Min Cost Flow on 4x4 Matrix";
|
||||
const int kNumSources = 4;
|
||||
const int kNumTargets = 4;
|
||||
const CostValue kCost[kNumSources][kNumTargets] = { { 90, 75, 75, 80 },
|
||||
{ 35, 85, 55, 65 },
|
||||
{ 125, 95, 90, 105 },
|
||||
{ 45, 110, 95, 115 } };
|
||||
const CostValue kCost[kNumSources][kNumTargets] = {{90, 75, 75, 80},
|
||||
{35, 85, 55, 65},
|
||||
{125, 95, 90, 105},
|
||||
{45, 110, 95, 115}};
|
||||
const CostValue kExpectedCost = 275;
|
||||
StarGraph graph(kNumSources + kNumTargets, kNumSources * kNumTargets);
|
||||
MinCostFlow min_cost_flow(&graph);
|
||||
@@ -59,10 +59,10 @@ void MaxFeasibleFlow() {
|
||||
LOG(INFO) << "Max Feasible Flow";
|
||||
const int kNumNodes = 6;
|
||||
const int kNumArcs = 9;
|
||||
const NodeIndex kTail[kNumArcs] = { 0, 0, 0, 0, 1, 2, 3, 3, 4 };
|
||||
const NodeIndex kHead[kNumArcs] = { 1, 2, 3, 4, 3, 4, 4, 5, 5 };
|
||||
const FlowQuantity kCapacity[kNumArcs] = { 5, 8, 5, 3, 4, 5, 6, 6, 4 };
|
||||
const FlowQuantity kExpectedFlow[kNumArcs] = { 1, 1, 5, 3, 1, 1, 0, 6, 4 };
|
||||
const NodeIndex kTail[kNumArcs] = {0, 0, 0, 0, 1, 2, 3, 3, 4};
|
||||
const NodeIndex kHead[kNumArcs] = {1, 2, 3, 4, 3, 4, 4, 5, 5};
|
||||
const FlowQuantity kCapacity[kNumArcs] = {5, 8, 5, 3, 4, 5, 6, 6, 4};
|
||||
const FlowQuantity kExpectedFlow[kNumArcs] = {1, 1, 5, 3, 1, 1, 0, 6, 4};
|
||||
const FlowQuantity kExpectedTotalFlow = 10;
|
||||
StarGraph graph(kNumNodes, kNumArcs);
|
||||
MaxFlow max_flow(&graph, 0, kNumNodes - 1);
|
||||
@@ -78,7 +78,7 @@ void MaxFeasibleFlow() {
|
||||
CHECK_EQ(kExpectedFlow[i], max_flow.Flow(i)) << " i = " << i;
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -89,10 +89,12 @@ namespace operations_research {
|
||||
// Decision on the relative order that the two variables of a constraint
|
||||
// will have. It takes as parameters the components of the constraint.
|
||||
class OrderingDecision : public Decision {
|
||||
public:
|
||||
public:
|
||||
OrderingDecision(IntVar *const variable1, IntVar *const variable2, int value,
|
||||
std::string operation)
|
||||
: variable1_(variable1), variable2_(variable2), value_(value),
|
||||
: variable1_(variable1),
|
||||
variable2_(variable2),
|
||||
value_(value),
|
||||
operator_(std::move(operation)) {}
|
||||
~OrderingDecision() override {}
|
||||
|
||||
@@ -108,7 +110,7 @@ public:
|
||||
MakeDecision(s, variable2_, variable1_);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
void MakeDecision(Solver *s, IntVar *variable1, IntVar *variable2) {
|
||||
if (operator_ == ">") {
|
||||
IntExpr *difference = (s->MakeDifference(variable2, variable1));
|
||||
@@ -132,7 +134,7 @@ private:
|
||||
// Decision on whether a soft constraint will be added to a model
|
||||
// or if it will be violated.
|
||||
class ConstraintDecision : public Decision {
|
||||
public:
|
||||
public:
|
||||
explicit ConstraintDecision(IntVar *const constraint_violation)
|
||||
: constraint_violation_(constraint_violation) {}
|
||||
|
||||
@@ -150,7 +152,7 @@ public:
|
||||
constraint_violation_->SetValue(1);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
IntVar *const constraint_violation_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ConstraintDecision);
|
||||
@@ -161,22 +163,22 @@ private:
|
||||
// solving becomes much more efficient since we are branching on the
|
||||
// disjunction implied by the absolute value expression.
|
||||
class OrderingBuilder : public DecisionBuilder {
|
||||
public:
|
||||
enum Order {
|
||||
LESS = -1,
|
||||
EQUAL = 0,
|
||||
GREATER = 1
|
||||
};
|
||||
public:
|
||||
enum Order { LESS = -1, EQUAL = 0, GREATER = 1 };
|
||||
|
||||
OrderingBuilder(const std::map<int, FapVariable> &data_variables,
|
||||
const std::vector<FapConstraint> &data_constraints,
|
||||
const std::vector<IntVar *> &variables,
|
||||
const std::vector<IntVar *> &violated_constraints,
|
||||
const std::map<int, int> &index_from_key)
|
||||
: data_variables_(data_variables), data_constraints_(data_constraints),
|
||||
variables_(variables), violated_constraints_(violated_constraints),
|
||||
index_from_key_(index_from_key), size_(data_constraints.size()),
|
||||
iter_(0), checked_iter_(0) {
|
||||
: data_variables_(data_variables),
|
||||
data_constraints_(data_constraints),
|
||||
variables_(variables),
|
||||
violated_constraints_(violated_constraints),
|
||||
index_from_key_(index_from_key),
|
||||
size_(data_constraints.size()),
|
||||
iter_(0),
|
||||
checked_iter_(0) {
|
||||
for (const auto &it : data_variables_) {
|
||||
int first_element = (it.second.domain)[0];
|
||||
minimum_value_available_.push_back(first_element);
|
||||
@@ -237,7 +239,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
Order Variable1LessVariable2(const int variable1, const int variable2,
|
||||
const int value) {
|
||||
minimum_value_available_[variable2] =
|
||||
@@ -439,34 +441,34 @@ void ChooseVariableStrategy(Solver::IntVarStrategy *variable_strategy) {
|
||||
CHECK(variable_strategy != nullptr);
|
||||
|
||||
switch (absl::GetFlag(FLAGS_choose_next_variable_strategy)) {
|
||||
case 1: {
|
||||
*variable_strategy = Solver::CHOOSE_FIRST_UNBOUND;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_LOWEST_MIN "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*variable_strategy = Solver::CHOOSE_RANDOM;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_RANDOM "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(FATAL) << "Should not be here";
|
||||
return;
|
||||
}
|
||||
case 1: {
|
||||
*variable_strategy = Solver::CHOOSE_FIRST_UNBOUND;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_LOWEST_MIN "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*variable_strategy = Solver::CHOOSE_RANDOM;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_RANDOM "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(FATAL) << "Should not be here";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,11 +584,10 @@ void HardFapSolver(const std::map<int, FapVariable> &data_variables,
|
||||
absl::flat_hash_map<int64, std::pair<int64, int64> > history;
|
||||
if (absl::GetFlag(FLAGS_value_evaluator) == "value_evaluator") {
|
||||
LOG(INFO) << "Using ValueEvaluator for value selection strategy.";
|
||||
Solver::IndexEvaluator2 index_evaluator2 =
|
||||
[&history](int64 var, int64 value) {
|
||||
Solver::IndexEvaluator2 index_evaluator2 = [&history](int64 var,
|
||||
int64 value) {
|
||||
return ValueEvaluator(&history, var, value);
|
||||
}
|
||||
;
|
||||
};
|
||||
LOG(INFO) << "Using ValueEvaluator for value selection strategy.";
|
||||
db = solver.MakePhase(variables, variable_strategy, index_evaluator2);
|
||||
} else {
|
||||
@@ -657,11 +658,11 @@ void SplitConstraintHardSoft(const std::vector<FapConstraint> &data_constraints,
|
||||
|
||||
// Penalize the modification of the initial position of soft variable of
|
||||
// the instance.
|
||||
void
|
||||
PenalizeVariablesViolation(const std::map<int, FapVariable> &soft_variables,
|
||||
const std::map<int, int> &index_from_key,
|
||||
const std::vector<IntVar *> &variables,
|
||||
std::vector<IntVar *> *cost, Solver *solver) {
|
||||
void PenalizeVariablesViolation(
|
||||
const std::map<int, FapVariable> &soft_variables,
|
||||
const std::map<int, int> &index_from_key,
|
||||
const std::vector<IntVar *> &variables, std::vector<IntVar *> *cost,
|
||||
Solver *solver) {
|
||||
for (const auto &it : soft_variables) {
|
||||
const int index = gtl::FindOrDie(index_from_key, it.first);
|
||||
CHECK_LT(index, variables.size());
|
||||
@@ -697,8 +698,11 @@ void PenalizeConstraintsViolation(
|
||||
const int index2 = gtl::FindOrDie(index_from_key, ct.variable2);
|
||||
CHECK_LT(index1, variables.size());
|
||||
CHECK_LT(index2, variables.size());
|
||||
IntVar *const absolute_difference = solver->MakeAbs(solver->MakeDifference(
|
||||
variables[index1], variables[index2]))->Var();
|
||||
IntVar *const absolute_difference =
|
||||
solver
|
||||
->MakeAbs(
|
||||
solver->MakeDifference(variables[index1], variables[index2]))
|
||||
->Var();
|
||||
IntVar *violation = nullptr;
|
||||
if (ct.operation == ">") {
|
||||
violation = solver->MakeIsLessCstVar(absolute_difference, ct.value);
|
||||
@@ -778,11 +782,10 @@ int SoftFapSolver(const std::map<int, FapVariable> &data_variables,
|
||||
if (absl::GetFlag(FLAGS_variable_evaluator) == "variable_evaluator") {
|
||||
LOG(INFO) << "Using VariableEvaluator for variable selection strategy and "
|
||||
"Solver::ASSIGN_MIN_VALUE for value selection strategy.";
|
||||
Solver::IndexEvaluator1 var_evaluator =
|
||||
[&key_from_index, &data_variables](int64 index) {
|
||||
Solver::IndexEvaluator1 var_evaluator = [&key_from_index,
|
||||
&data_variables](int64 index) {
|
||||
return VariableEvaluator(key_from_index, data_variables, index);
|
||||
}
|
||||
;
|
||||
};
|
||||
db = solver.MakePhase(variables, var_evaluator, Solver::ASSIGN_MIN_VALUE);
|
||||
} else {
|
||||
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND for variable selection "
|
||||
@@ -850,7 +853,7 @@ void SolveProblem(const std::map<int, FapVariable> &variables,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -39,11 +39,9 @@ DEFINE_int32(
|
||||
"Size of the problem. If equal to 0, will test several increasing sizes.");
|
||||
DEFINE_string(params, "", "Sat parameters.");
|
||||
|
||||
static const int kBestSolutions[] = {
|
||||
0, 1, 3, 6, 11, 17, 25, 34, 44, 55, 72, 85,
|
||||
// just for the optimistics ones, the rest:
|
||||
106, 127, 151, 177, 199, 216, 246
|
||||
};
|
||||
static const int kBestSolutions[] = {0, 1, 3, 6, 11, 17, 25, 34, 44, 55, 72, 85,
|
||||
// just for the optimistics ones, the rest:
|
||||
106, 127, 151, 177, 199, 216, 246};
|
||||
|
||||
static const int kKnownSolutions = 19;
|
||||
|
||||
@@ -65,10 +63,7 @@ void GolombRuler(int size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (int j = i + 1; j < size; ++j) {
|
||||
const IntVar diff = cp_model.NewIntVar(domain);
|
||||
cp_model.AddEquality(LinearExpr::Sum({
|
||||
diff, ticks[i]
|
||||
}),
|
||||
ticks[j]);
|
||||
cp_model.AddEquality(LinearExpr::Sum({diff, ticks[i]}), ticks[j]);
|
||||
diffs.push_back(diff);
|
||||
}
|
||||
}
|
||||
@@ -117,8 +112,8 @@ void GolombRuler(int size) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -83,7 +83,7 @@ void RunAllExamples() {
|
||||
RunIntegerProgrammingExample("GLPK");
|
||||
RunIntegerProgrammingExample("CPLEX");
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -72,8 +72,7 @@ int64 ComputeHorizon(const JsspInputProblem &problem) {
|
||||
const int num_jobs = problem.jobs_size();
|
||||
int64 sum_of_transitions = 0;
|
||||
for (const Machine &machine : problem.machines()) {
|
||||
if (!machine.has_transition_time_matrix())
|
||||
continue;
|
||||
if (!machine.has_transition_time_matrix()) continue;
|
||||
const TransitionTimeMatrix &matrix = machine.transition_time_matrix();
|
||||
for (int i = 0; i < num_jobs; ++i) {
|
||||
int64 max_transition = 0;
|
||||
@@ -238,9 +237,8 @@ void Solve(const JsspInputProblem &problem) {
|
||||
cp_model.AddEquality(shifted_var,
|
||||
LinearExpr(previous_end).AddConstant(-due_date));
|
||||
const IntVar lateness_var = cp_model.NewIntVar(all_horizon);
|
||||
cp_model.AddMaxEquality(lateness_var, {
|
||||
cp_model.NewConstant(0), shifted_var
|
||||
});
|
||||
cp_model.AddMaxEquality(lateness_var,
|
||||
{cp_model.NewConstant(0), shifted_var});
|
||||
objective_vars.push_back(lateness_var);
|
||||
objective_coeffs.push_back(lateness_penalty);
|
||||
}
|
||||
@@ -252,14 +250,11 @@ void Solve(const JsspInputProblem &problem) {
|
||||
if (due_date > 0) {
|
||||
const IntVar shifted_var =
|
||||
cp_model.NewIntVar(Domain(due_date - horizon, due_date));
|
||||
cp_model.AddEquality(LinearExpr::Sum({
|
||||
shifted_var, previous_end
|
||||
}),
|
||||
cp_model.AddEquality(LinearExpr::Sum({shifted_var, previous_end}),
|
||||
due_date);
|
||||
const IntVar earliness_var = cp_model.NewIntVar(all_horizon);
|
||||
cp_model.AddMaxEquality(earliness_var, {
|
||||
cp_model.NewConstant(0), shifted_var
|
||||
});
|
||||
cp_model.AddMaxEquality(earliness_var,
|
||||
{cp_model.NewConstant(0), shifted_var});
|
||||
objective_vars.push_back(earliness_var);
|
||||
objective_coeffs.push_back(earliness_penalty);
|
||||
}
|
||||
@@ -297,8 +292,9 @@ void Solve(const JsspInputProblem &problem) {
|
||||
const IntVar end = machine_to_ends[m][i];
|
||||
circuit.AddArc(i + 1, j + 1, lit);
|
||||
// Push the new start with an extra transition.
|
||||
cp_model.AddLessOrEqual(LinearExpr(end).AddConstant(transition),
|
||||
start).OnlyEnforceIf(lit);
|
||||
cp_model
|
||||
.AddLessOrEqual(LinearExpr(end).AddConstant(transition), start)
|
||||
.OnlyEnforceIf(lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,8 +376,8 @@ void Solve(const JsspInputProblem &problem) {
|
||||
CHECK_LE(response.objective_value(), final_cost + tolerance);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
@@ -25,10 +25,10 @@ void AssignmentOn4x4Matrix() {
|
||||
LOG(INFO) << "Assignment on 4x4 Matrix";
|
||||
const int kNumSources = 4;
|
||||
const int kNumTargets = 4;
|
||||
const CostValue kCost[kNumSources][kNumTargets] = { { 90, 76, 75, 80 },
|
||||
{ 35, 85, 55, 65 },
|
||||
{ 125, 95, 90, 105 },
|
||||
{ 45, 110, 95, 115 } };
|
||||
const CostValue kCost[kNumSources][kNumTargets] = {{90, 76, 75, 80},
|
||||
{35, 85, 55, 65},
|
||||
{125, 95, 90, 105},
|
||||
{45, 110, 95, 115}};
|
||||
const CostValue kExpectedCost =
|
||||
kCost[0][3] + kCost[1][2] + kCost[2][1] + kCost[3][0];
|
||||
ForwardStarGraph graph(kNumSources + kNumTargets, kNumSources * kNumTargets);
|
||||
@@ -46,12 +46,8 @@ void AssignmentOn4x4Matrix() {
|
||||
|
||||
void AnotherAssignment() {
|
||||
LOG(INFO) << "Another assignment on 4x4 matrix";
|
||||
std::vector<std::vector<int> > matrice({
|
||||
{ 8, 7, 9, 9 }
|
||||
, { 5, 2, 7, 8 }
|
||||
, { 6, 1, 4, 9 }
|
||||
, { 2, 3, 2, 6 }
|
||||
});
|
||||
std::vector<std::vector<int> > matrice(
|
||||
{{8, 7, 9, 9}, {5, 2, 7, 8}, {6, 1, 4, 9}, {2, 3, 2, 6}});
|
||||
const int kSize = matrice.size();
|
||||
ForwardStarGraph graph(2 * kSize, kSize * kSize);
|
||||
LinearSumAssignment<ForwardStarGraph> assignement(graph, kSize);
|
||||
@@ -67,7 +63,7 @@ void AnotherAssignment() {
|
||||
LOG(INFO) << "Cost : " << assignement.GetCost();
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -109,7 +109,7 @@ void RunAllExamples() {
|
||||
RunLinearProgrammingExample("GLPK_LP");
|
||||
RunLinearProgrammingExample("XPRESS_LP");
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
|
||||
namespace operations_research {
|
||||
void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
|
||||
const double kObjCoef[] = { 10.0, 6.0, 4.0 };
|
||||
const std::string kVarName[] = { "x1", "x2", "x3" };
|
||||
const double kObjCoef[] = {10.0, 6.0, 4.0};
|
||||
const std::string kVarName[] = {"x1", "x2", "x3"};
|
||||
const int numVars = 3;
|
||||
const int kNumConstraints = 3;
|
||||
const std::string kConstraintName[] = { "c1", "c2", "c3" };
|
||||
const double kConstraintCoef1[] = { 1.0, 1.0, 1.0 };
|
||||
const double kConstraintCoef2[] = { 10.0, 4.0, 5.0 };
|
||||
const double kConstraintCoef3[] = { 2.0, 2.0, 6.0 };
|
||||
const double *kConstraintCoef[] = { kConstraintCoef1, kConstraintCoef2,
|
||||
kConstraintCoef3 };
|
||||
const double kConstraintUb[] = { 100.0, 600.0, 300.0 };
|
||||
const std::string kConstraintName[] = {"c1", "c2", "c3"};
|
||||
const double kConstraintCoef1[] = {1.0, 1.0, 1.0};
|
||||
const double kConstraintCoef2[] = {10.0, 4.0, 5.0};
|
||||
const double kConstraintCoef3[] = {2.0, 2.0, 6.0};
|
||||
const double *kConstraintCoef[] = {kConstraintCoef1, kConstraintCoef2,
|
||||
kConstraintCoef3};
|
||||
const double kConstraintUb[] = {100.0, 600.0, 300.0};
|
||||
|
||||
const double infinity = MPSolver::infinity();
|
||||
MPModelProto model_proto;
|
||||
@@ -39,10 +39,10 @@ void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
|
||||
// Create variables and objective function
|
||||
for (int j = 0; j < numVars; ++j) {
|
||||
MPVariableProto *x = model_proto.add_variable();
|
||||
x->set_name(kVarName[j]); // Could be skipped (optional).
|
||||
x->set_name(kVarName[j]); // Could be skipped (optional).
|
||||
x->set_lower_bound(0.0);
|
||||
x->set_upper_bound(infinity); // Could be skipped (default value).
|
||||
x->set_is_integer(false); // Could be skipped (default value).
|
||||
x->set_upper_bound(infinity); // Could be skipped (default value).
|
||||
x->set_is_integer(false); // Could be skipped (default value).
|
||||
x->set_objective_coefficient(kObjCoef[j]);
|
||||
}
|
||||
model_proto.set_maximize(true);
|
||||
@@ -50,8 +50,8 @@ void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
|
||||
// Create constraints
|
||||
for (int i = 0; i < kNumConstraints; ++i) {
|
||||
MPConstraintProto *constraint_proto = model_proto.add_constraint();
|
||||
constraint_proto->set_name(kConstraintName[i]); // Could be skipped.
|
||||
constraint_proto->set_lower_bound(-infinity); // Could be skipped.
|
||||
constraint_proto->set_name(kConstraintName[i]); // Could be skipped.
|
||||
constraint_proto->set_lower_bound(-infinity); // Could be skipped.
|
||||
constraint_proto->set_upper_bound(kConstraintUb[i]);
|
||||
for (int j = 0; j < numVars; ++j) {
|
||||
// These two lines may be skipped when the coefficient is zero.
|
||||
@@ -66,12 +66,12 @@ void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
|
||||
if (type == MPSolver::GLOP_LINEAR_PROGRAMMING) {
|
||||
model_request.set_solver_type(MPModelRequest::GLOP_LINEAR_PROGRAMMING);
|
||||
}
|
||||
#endif // USE_GLOP
|
||||
#endif // USE_GLOP
|
||||
#if defined(USE_CLP)
|
||||
if (type == MPSolver::CLP_LINEAR_PROGRAMMING) {
|
||||
model_request.set_solver_type(MPModelRequest::CLP_LINEAR_PROGRAMMING);
|
||||
}
|
||||
#endif // USE_CLP
|
||||
#endif // USE_CLP
|
||||
|
||||
MPSolutionResponse solution_response;
|
||||
MPSolver::SolveWithProto(model_request, &solution_response);
|
||||
@@ -90,13 +90,13 @@ void RunAllExamples() {
|
||||
#if defined(USE_GLOP)
|
||||
LOG(INFO) << "----- Running Max Example with GLOP -----";
|
||||
BuildLinearProgrammingMaxExample(MPSolver::GLOP_LINEAR_PROGRAMMING);
|
||||
#endif // USE_GLOP
|
||||
#endif // USE_GLOP
|
||||
#if defined(USE_CLP)
|
||||
LOG(INFO) << "----- Running Max Example with Coin LP -----";
|
||||
BuildLinearProgrammingMaxExample(MPSolver::CLP_LINEAR_PROGRAMMING);
|
||||
#endif // USE_CLP
|
||||
#endif // USE_CLP
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -89,8 +89,8 @@ void MagicSquare(int size) {
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
@@ -23,9 +23,8 @@ void SolveMaxFlow() {
|
||||
// Initialization list is not working on std:tuple cf. N4387
|
||||
// Arc are stored as {{begin_node, end_node}, capacity}
|
||||
std::vector<std::pair<std::pair<NodeIndex, NodeIndex>, FlowQuantity> > arcs =
|
||||
{ { { 0, 1 }, 20 }, { { 0, 2 }, 30 }, { { 0, 3 }, 10 }, { { 1, 2 }, 40 },
|
||||
{ { 1, 4 }, 30 }, { { 2, 3 }, 10 }, { { 2, 4 }, 20 }, { { 3, 2 }, 5 },
|
||||
{ { 3, 4 }, 20 } };
|
||||
{{{0, 1}, 20}, {{0, 2}, 30}, {{0, 3}, 10}, {{1, 2}, 40}, {{1, 4}, 30},
|
||||
{{2, 3}, 10}, {{2, 4}, 20}, {{3, 2}, 5}, {{3, 4}, 20}};
|
||||
StarGraph graph(num_nodes, arcs.size());
|
||||
MaxFlow max_flow(&graph, 0, num_nodes - 1);
|
||||
for (const auto &it : arcs) {
|
||||
@@ -50,7 +49,7 @@ void SolveMaxFlow() {
|
||||
<< max_flow.Flow(i) << " / " << max_flow.Capacity(i);
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -25,18 +25,16 @@ struct Arc {
|
||||
void SolveMinCostFlow() {
|
||||
// Define supply of each node.
|
||||
const std::vector<std::pair<NodeIndex, FlowQuantity> > supplies = {
|
||||
{ 0, 20 }, { 1, 0 }, { 2, 0 }, { 3, -5 }, { 4, -15 }
|
||||
};
|
||||
{0, 20}, {1, 0}, {2, 0}, {3, -5}, {4, -15}};
|
||||
|
||||
// Define each arc
|
||||
// Can't use std::tuple<NodeIndex, NodeIndex, FlowQuantity>
|
||||
// Initialization list is not working on std:tuple cf. N4387
|
||||
// Arc are stored as {{begin_node, end_node}, capacity}
|
||||
const std::vector<Arc> arcs = { { { 0, 1 }, 15, 4 }, { { 0, 2 }, 8, 4 },
|
||||
{ { 1, 2 }, 20, 2 }, { { 1, 3 }, 4, 2 },
|
||||
{ { 1, 4 }, 10, 6 }, { { 2, 3 }, 15, 1 },
|
||||
{ { 2, 4 }, 4, 3 }, { { 3, 4 }, 20, 2 },
|
||||
{ { 4, 2 }, 5, 3 } };
|
||||
const std::vector<Arc> arcs = {
|
||||
{{0, 1}, 15, 4}, {{0, 2}, 8, 4}, {{1, 2}, 20, 2},
|
||||
{{1, 3}, 4, 2}, {{1, 4}, 10, 6}, {{2, 3}, 15, 1},
|
||||
{{2, 4}, 4, 3}, {{3, 4}, 20, 2}, {{4, 2}, 5, 3}};
|
||||
|
||||
StarGraph graph(supplies.size(), arcs.size());
|
||||
MinCostFlow min_cost_flow(&graph);
|
||||
@@ -67,7 +65,7 @@ void SolveMinCostFlow() {
|
||||
<< " / " << min_cost_flow.UnitCost(i);
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -44,9 +44,10 @@ DEFINE_bool(mps_display_full_path, true,
|
||||
"Displays the full path of the input file in the result line.");
|
||||
DEFINE_string(input, "", "File pattern for problems to be optimized.");
|
||||
DEFINE_string(params_file, "", "Path to a GlopParameters file in text format.");
|
||||
DEFINE_string(params, "", "GlopParameters in text format. If --params_file was "
|
||||
"also specified, the --params will be merged onto "
|
||||
"them (i.e. in case of conflicts, --params wins)");
|
||||
DEFINE_string(params, "",
|
||||
"GlopParameters in text format. If --params_file was "
|
||||
"also specified, the --params will be merged onto "
|
||||
"them (i.e. in case of conflicts, --params wins)");
|
||||
|
||||
using google::protobuf::TextFormat;
|
||||
using operations_research::FullProtocolMessageAsString;
|
||||
|
||||
@@ -37,10 +37,10 @@ static const int kVolumeMin = 1156;
|
||||
static const int kVolumeMax = 1600;
|
||||
|
||||
// Data for a single bin problem
|
||||
static const int kItemsWeights[] = { 1008, 2087, 5522, 5250, 5720, 4998, 275,
|
||||
3145, 12580, 382 };
|
||||
static const int kItemsVolumes[] = { 281, 307, 206, 111, 275, 79, 23, 65, 261,
|
||||
40 };
|
||||
static const int kItemsWeights[] = {1008, 2087, 5522, 5250, 5720,
|
||||
4998, 275, 3145, 12580, 382};
|
||||
static const int kItemsVolumes[] = {281, 307, 206, 111, 275,
|
||||
79, 23, 65, 261, 40};
|
||||
static const int kNumItems = 10;
|
||||
|
||||
void MultiKnapsackSat(int scaling, const std::string ¶ms) {
|
||||
@@ -74,16 +74,13 @@ void MultiKnapsackSat(int scaling, const std::string ¶ms) {
|
||||
// Constraints per bins.
|
||||
std::vector<IntVar> bin_weights;
|
||||
for (int b = 0; b < num_bins; ++b) {
|
||||
IntVar bin_weight = builder.NewIntVar({
|
||||
kWeightMin, kWeightMax
|
||||
});
|
||||
IntVar bin_weight = builder.NewIntVar({kWeightMin, kWeightMax});
|
||||
bin_weights.push_back(bin_weight);
|
||||
builder.AddEquality(LinearExpr::BooleanScalProd(items_in_bins[b], weights),
|
||||
bin_weight);
|
||||
builder.AddLinearConstraint(
|
||||
LinearExpr::BooleanScalProd(items_in_bins[b], volumes), {
|
||||
kVolumeMin, kVolumeMax
|
||||
});
|
||||
LinearExpr::BooleanScalProd(items_in_bins[b], volumes),
|
||||
{kVolumeMin, kVolumeMax});
|
||||
}
|
||||
|
||||
// Each item is selected at most one time.
|
||||
@@ -105,8 +102,8 @@ void MultiKnapsackSat(int scaling, const std::string ¶ms) {
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
@@ -45,8 +45,9 @@
|
||||
#include "ortools/util/time_limit.h"
|
||||
|
||||
// ----- Data Generator -----
|
||||
DEFINE_int32(clients, 0, "Number of network clients nodes. If equal to zero, "
|
||||
"then all backbones nodes are also client nodes.");
|
||||
DEFINE_int32(clients, 0,
|
||||
"Number of network clients nodes. If equal to zero, "
|
||||
"then all backbones nodes are also client nodes.");
|
||||
DEFINE_int32(backbones, 0, "Number of backbone nodes");
|
||||
DEFINE_int32(demands, 0, "Number of network demands.");
|
||||
DEFINE_int32(traffic_min, 0, "Min traffic of a demand.");
|
||||
@@ -90,7 +91,7 @@ static const int64 kDisconnectedDistance = -1LL;
|
||||
// (capacity(i->j) == capacity(j->i)).
|
||||
// Demands are not symmetrical.
|
||||
class NetworkRoutingData {
|
||||
public:
|
||||
public:
|
||||
NetworkRoutingData()
|
||||
: name_(""), num_nodes_(-1), max_capacity_(-1), fixed_charge_cost_(-1) {}
|
||||
|
||||
@@ -131,7 +132,7 @@ public:
|
||||
void set_max_capacity(int max_capacity) { max_capacity_ = max_capacity; }
|
||||
void set_fixed_charge_cost(int cost) { fixed_charge_cost_ = cost; }
|
||||
|
||||
private:
|
||||
private:
|
||||
std::string name_;
|
||||
int num_nodes_;
|
||||
int max_capacity_;
|
||||
@@ -154,7 +155,7 @@ private:
|
||||
// Each arc has a capacity of 'max_capacity'. Using an arc incurs a
|
||||
// fixed cost of 'fixed_charge_cost'.
|
||||
class NetworkRoutingDataBuilder {
|
||||
public:
|
||||
public:
|
||||
NetworkRoutingDataBuilder() : random_(0) {}
|
||||
|
||||
void BuildModelFromParameters(int num_clients, int num_backbones,
|
||||
@@ -191,7 +192,7 @@ public:
|
||||
max_backbone_degree, max_capacity, fixed_charge_cost, seed, data);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
void InitData(int size, int seed) {
|
||||
network_.clear();
|
||||
network_.resize(size);
|
||||
@@ -328,17 +329,18 @@ private:
|
||||
|
||||
// Useful data struct to hold demands.
|
||||
struct Demand {
|
||||
public:
|
||||
public:
|
||||
Demand(int the_source, int the_destination, int the_traffic)
|
||||
: source(the_source), destination(the_destination), traffic(the_traffic) {
|
||||
}
|
||||
: source(the_source),
|
||||
destination(the_destination),
|
||||
traffic(the_traffic) {}
|
||||
int source;
|
||||
int destination;
|
||||
int traffic;
|
||||
};
|
||||
|
||||
class NetworkRoutingSolver {
|
||||
public:
|
||||
public:
|
||||
typedef std::unordered_set<int> OnePath;
|
||||
|
||||
NetworkRoutingSolver() : num_nodes_(-1) {}
|
||||
@@ -362,9 +364,8 @@ public:
|
||||
tmp_vars.push_back(node_vars[i]);
|
||||
tmp_vars.push_back(node_vars[i + 1]);
|
||||
tmp_vars.push_back(arc_vars[i]);
|
||||
TableConstraint table = cp_model.AddAllowedAssignments({
|
||||
node_vars[i], node_vars[i + 1], arc_vars[i]
|
||||
});
|
||||
TableConstraint table = cp_model.AddAllowedAssignments(
|
||||
{node_vars[i], node_vars[i + 1], arc_vars[i]});
|
||||
for (const auto &tuple : arcs_data_) {
|
||||
table.AddTuple(tuple);
|
||||
}
|
||||
@@ -381,7 +382,7 @@ public:
|
||||
std::atomic<bool> stopped(false);
|
||||
model.GetOrCreate<TimeLimit>()->RegisterExternalBooleanAsLimit(&stopped);
|
||||
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse &r) {
|
||||
const int path_id = all_paths_[demand_index].size();
|
||||
all_paths_[demand_index].resize(path_id + 1);
|
||||
for (int arc_index = 0; arc_index < max_length - 1; ++arc_index) {
|
||||
@@ -422,9 +423,7 @@ public:
|
||||
}
|
||||
|
||||
void AddArcData(int64 source, int64 destination, int arc_id) {
|
||||
arcs_data_.push_back({
|
||||
source, destination, arc_id
|
||||
});
|
||||
arcs_data_.push_back({source, destination, arc_id});
|
||||
}
|
||||
|
||||
void InitArcInfo(const NetworkRoutingData &data) {
|
||||
@@ -479,11 +478,10 @@ public:
|
||||
for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
|
||||
paths.clear();
|
||||
const Demand &demand = demands_array_[demand_index];
|
||||
CHECK(DijkstraShortestPath(num_nodes_, demand.source, demand.destination,
|
||||
[this](int x, int y) {
|
||||
return HasArc(x, y);
|
||||
},
|
||||
kDisconnectedDistance, &paths));
|
||||
CHECK(DijkstraShortestPath(
|
||||
num_nodes_, demand.source, demand.destination,
|
||||
[this](int x, int y) { return HasArc(x, y); }, kDisconnectedDistance,
|
||||
&paths));
|
||||
all_min_path_lengths_.push_back(paths.size() - 1);
|
||||
}
|
||||
|
||||
@@ -542,7 +540,7 @@ public:
|
||||
if (capacity_[i][j] > 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return kDisconnectedDistance; // disconnected distance.
|
||||
return kDisconnectedDistance; // disconnected distance.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,12 +591,7 @@ public:
|
||||
const int64 capacity = arc_capacity_[arc_index];
|
||||
IntVar scaled_traffic =
|
||||
cp_model.NewIntVar(Domain(0, sum_of_traffic * 1000));
|
||||
cp_model.AddEquality(LinearExpr::ScalProd({
|
||||
traffic_var
|
||||
},
|
||||
{
|
||||
1000
|
||||
}),
|
||||
cp_model.AddEquality(LinearExpr::ScalProd({traffic_var}, {1000}),
|
||||
scaled_traffic);
|
||||
IntVar normalized_traffic =
|
||||
cp_model.NewIntVar(Domain(0, sum_of_traffic * 1000 / capacity));
|
||||
@@ -633,7 +626,7 @@ public:
|
||||
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
|
||||
}
|
||||
int num_solutions = 0;
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse &r) {
|
||||
LOG(INFO) << "Solution " << num_solutions;
|
||||
const double objective_value = r.objective_value();
|
||||
const double percent = SolutionIntegerValue(r, max_usage_cost) / 10.0;
|
||||
@@ -655,7 +648,7 @@ public:
|
||||
return response.objective_value();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
int count_arcs() const { return arcs_data_.size() / 2; }
|
||||
|
||||
std::vector<std::vector<int64> > arcs_data_;
|
||||
@@ -667,8 +660,8 @@ private:
|
||||
std::vector<std::vector<OnePath> > all_paths_;
|
||||
};
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -37,19 +37,19 @@ DEFINE_int32(
|
||||
DEFINE_bool(use_symmetry, false, "Use Symmetry Breaking methods");
|
||||
DECLARE_bool(cp_disable_solve);
|
||||
|
||||
static const int kNumSolutions[] = { 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680,
|
||||
14200, 73712, 365596, 2279184 };
|
||||
static const int kNumSolutions[] = {
|
||||
1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, 2279184};
|
||||
static const int kKnownSolutions = 15;
|
||||
|
||||
static const int kNumUniqueSolutions[] = { 1, 0, 0, 1, 2, 1, 6, 12, 46, 92, 341,
|
||||
1787, 9233, 45752, 285053, 1846955,
|
||||
11977939, 83263591, 621012754 };
|
||||
static const int kNumUniqueSolutions[] = {
|
||||
1, 0, 0, 1, 2, 1, 6, 12, 46, 92,
|
||||
341, 1787, 9233, 45752, 285053, 1846955, 11977939, 83263591, 621012754};
|
||||
static const int kKnownUniqueSolutions = 19;
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
class NQueenSymmetry : public SymmetryBreaker {
|
||||
public:
|
||||
public:
|
||||
NQueenSymmetry(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: solver_(s), vars_(vars), size_(vars.size()) {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
}
|
||||
~NQueenSymmetry() override {}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
int Index(IntVar *const var) const {
|
||||
return gtl::FindWithDefault(indices_, var, -1);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ protected:
|
||||
int symmetric(int index) const { return size_ - 1 - index; }
|
||||
Solver *const solver() const { return solver_; }
|
||||
|
||||
private:
|
||||
private:
|
||||
Solver *const solver_;
|
||||
const std::vector<IntVar *> vars_;
|
||||
std::map<const IntVar *, int> indices_;
|
||||
@@ -80,7 +80,7 @@ private:
|
||||
|
||||
// Symmetry vertical axis.
|
||||
class SX : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
SX(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~SX() override {}
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
|
||||
// Symmetry horizontal axis.
|
||||
class SY : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
SY(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~SY() override {}
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
|
||||
// Symmetry first diagonal axis.
|
||||
class SD1 : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
SD1(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~SD1() override {}
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
|
||||
// Symmetry second diagonal axis.
|
||||
class SD2 : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
SD2(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~SD2() override {}
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
|
||||
// Rotate 1/4 turn.
|
||||
class R90 : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
R90(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~R90() override {}
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
|
||||
// Rotate 1/2 turn.
|
||||
class R180 : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
R180(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~R180() override {}
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
|
||||
// Rotate 3/4 turn.
|
||||
class R270 : public NQueenSymmetry {
|
||||
public:
|
||||
public:
|
||||
R270(Solver *const s, const std::vector<IntVar *> &vars)
|
||||
: NQueenSymmetry(s, vars) {}
|
||||
~R270() override {}
|
||||
@@ -242,25 +242,22 @@ void NQueens(int size) {
|
||||
}
|
||||
|
||||
for (int loop = 0; loop < absl::GetFlag(FLAGS_nb_loops); ++loop) {
|
||||
s.Solve(db, monitors); // go!
|
||||
s.Solve(db, monitors); // go!
|
||||
CheckNumberOfSolutions(size, solution_counter->solution_count());
|
||||
}
|
||||
|
||||
const int num_solutions = solution_counter->solution_count();
|
||||
if (num_solutions > 0 && size < kKnownSolutions) {
|
||||
int print_max = absl::GetFlag(FLAGS_print_all) ? num_solutions
|
||||
: absl::GetFlag(FLAGS_print)
|
||||
? 1
|
||||
: 0;
|
||||
int print_max = absl::GetFlag(FLAGS_print_all)
|
||||
? num_solutions
|
||||
: absl::GetFlag(FLAGS_print) ? 1 : 0;
|
||||
for (int n = 0; n < print_max; ++n) {
|
||||
printf("--- solution #%d\n", n);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const int pos = static_cast<int>(collector->Value(n, queens[i]));
|
||||
for (int k = 0; k < pos; ++k)
|
||||
printf(" . ");
|
||||
for (int k = 0; k < pos; ++k) printf(" . ");
|
||||
printf("%2d ", i);
|
||||
for (int k = pos + 1; k < size; ++k)
|
||||
printf(" . ");
|
||||
for (int k = pos + 1; k < size; ++k) printf(" . ");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
@@ -268,7 +265,7 @@ void NQueens(int size) {
|
||||
printf("========= number of solutions:%d\n", num_solutions);
|
||||
absl::PrintF(" number of failures: %d\n", s.failures());
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace sat {
|
||||
// The format is described here:
|
||||
// http://www.cril.univ-artois.fr/PB12/format.pdf
|
||||
class OpbReader {
|
||||
public:
|
||||
public:
|
||||
OpbReader() {}
|
||||
|
||||
// Loads the given opb filename into the given problem.
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
// Since the problem name is not stored in the cnf format, we infer it from
|
||||
// the file name.
|
||||
static std::string ExtractProblemName(const std::string &filename) {
|
||||
@@ -75,8 +75,7 @@ private:
|
||||
LinearObjective *objective = problem->mutable_objective();
|
||||
for (int i = 1; i < words.size(); ++i) {
|
||||
const std::string &word = words[i];
|
||||
if (word.empty() || word[0] == ';')
|
||||
continue;
|
||||
if (word.empty() || word[0] == ';') continue;
|
||||
if (word[0] == 'x') {
|
||||
int literal;
|
||||
CHECK(absl::SimpleAtoi(word.substr(1), &literal));
|
||||
@@ -133,7 +132,7 @@ private:
|
||||
DISALLOW_COPY_AND_ASSIGN(OpbReader);
|
||||
};
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_SAT_OPB_READER_H_
|
||||
#endif // OR_TOOLS_SAT_OPB_READER_H_
|
||||
|
||||
@@ -38,10 +38,12 @@ DEFINE_bool(assignment_optimize_layout, true,
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
template <typename GraphType> class LinearSumAssignment;
|
||||
template <typename GraphType>
|
||||
class LinearSumAssignment;
|
||||
|
||||
template <typename GraphType> class DimacsAssignmentParser {
|
||||
public:
|
||||
template <typename GraphType>
|
||||
class DimacsAssignmentParser {
|
||||
public:
|
||||
explicit DimacsAssignmentParser(const std::string &filename)
|
||||
: filename_(filename), graph_builder_(nullptr), assignment_(nullptr) {}
|
||||
|
||||
@@ -61,7 +63,7 @@ public:
|
||||
LinearSumAssignment<GraphType> *Parse(std::string *error_message,
|
||||
GraphType **graph);
|
||||
|
||||
private:
|
||||
private:
|
||||
void ParseProblemLine(const std::string &line);
|
||||
|
||||
void ParseNodeLine(const std::string &line);
|
||||
@@ -74,8 +76,11 @@ private:
|
||||
|
||||
struct ErrorTrackingState {
|
||||
ErrorTrackingState()
|
||||
: bad(false), nodes_described(false), reason(nullptr),
|
||||
num_left_nodes(0), num_arcs(0) {}
|
||||
: bad(false),
|
||||
nodes_described(false),
|
||||
reason(nullptr),
|
||||
num_left_nodes(0),
|
||||
num_arcs(0) {}
|
||||
|
||||
bool bad;
|
||||
bool nodes_described;
|
||||
@@ -94,8 +99,8 @@ private:
|
||||
|
||||
// Implementation is below here.
|
||||
template <typename GraphType>
|
||||
void
|
||||
DimacsAssignmentParser<GraphType>::ParseProblemLine(const std::string &line) {
|
||||
void DimacsAssignmentParser<GraphType>::ParseProblemLine(
|
||||
const std::string &line) {
|
||||
static const char *kIncorrectProblemLine =
|
||||
"Incorrect assignment problem line.";
|
||||
static const char *kAssignmentProblemType = "asn";
|
||||
@@ -172,33 +177,33 @@ void DimacsAssignmentParser<GraphType>::ParseOneLine(const std::string &line) {
|
||||
return;
|
||||
}
|
||||
switch (line[0]) {
|
||||
case 'p': {
|
||||
// Problem-specification line
|
||||
ParseProblemLine(line);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
// Comment; do nothing.
|
||||
return;
|
||||
}
|
||||
case 'n': {
|
||||
// Node line defining a node on the left side
|
||||
ParseNodeLine(line);
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
ParseArcLine(line);
|
||||
break;
|
||||
}
|
||||
case '0':
|
||||
case '\n':
|
||||
break;
|
||||
default: {
|
||||
state_.bad = true;
|
||||
state_.reason = "Unknown line type in the input.";
|
||||
state_.bad_line.reset(new std::string(line));
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
// Problem-specification line
|
||||
ParseProblemLine(line);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
// Comment; do nothing.
|
||||
return;
|
||||
}
|
||||
case 'n': {
|
||||
// Node line defining a node on the left side
|
||||
ParseNodeLine(line);
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
ParseArcLine(line);
|
||||
break;
|
||||
}
|
||||
case '0':
|
||||
case '\n':
|
||||
break;
|
||||
default: {
|
||||
state_.bad = true;
|
||||
state_.reason = "Unknown line type in the input.";
|
||||
state_.bad_line.reset(new std::string(line));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,9 +221,8 @@ void DimacsAssignmentParser<GraphType>::ParseOneLine(const std::string &line) {
|
||||
// free the underlying graph (which isn't owned by the
|
||||
// LinearAssignment instance).
|
||||
template <typename GraphType>
|
||||
LinearSumAssignment<GraphType> *
|
||||
DimacsAssignmentParser<GraphType>::Parse(std::string *error_message,
|
||||
GraphType **graph_handle) {
|
||||
LinearSumAssignment<GraphType> *DimacsAssignmentParser<GraphType>::Parse(
|
||||
std::string *error_message, GraphType **graph_handle) {
|
||||
CHECK(error_message != nullptr);
|
||||
CHECK(graph_handle != nullptr);
|
||||
|
||||
@@ -254,6 +258,6 @@ DimacsAssignmentParser<GraphType>::Parse(std::string *error_message,
|
||||
return assignment_;
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_EXAMPLES_PARSE_DIMACS_ASSIGNMENT_H_
|
||||
#endif // OR_TOOLS_EXAMPLES_PARSE_DIMACS_ASSIGNMENT_H_
|
||||
|
||||
@@ -192,11 +192,10 @@ bool SafeParseInt64Array(const std::string &str,
|
||||
std::istringstream input(str);
|
||||
int64 x;
|
||||
parsed_int->clear();
|
||||
while (input >> x)
|
||||
parsed_int->push_back(x);
|
||||
while (input >> x) parsed_int->push_back(x);
|
||||
return input.eof();
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
// Builds and solves a model from a file in the format defined by Li & Lim
|
||||
// (https://www.sintef.no/projectweb/top/pdptw/li-lim-benchmark/documentation/).
|
||||
@@ -208,7 +207,7 @@ bool LoadAndSolve(const std::string &pdp_file,
|
||||
{
|
||||
std::string contents;
|
||||
CHECK_OK(file::GetContents(pdp_file, &contents, file::Defaults()));
|
||||
const int64 kMaxInputFileSize = 1 << 30; // 1GB
|
||||
const int64 kMaxInputFileSize = 1 << 30; // 1GB
|
||||
if (contents.size() >= kMaxInputFileSize) {
|
||||
LOG(WARNING) << "Input file '" << pdp_file << "' is too large (>"
|
||||
<< kMaxInputFileSize << " bytes).";
|
||||
@@ -283,26 +282,24 @@ bool LoadAndSolve(const std::string &pdp_file,
|
||||
RoutingModel routing(manager, model_parameters);
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&coords, &manager](int64 i, int64 j) {
|
||||
return Travel(const_cast<const Coordinates *>(&coords),
|
||||
manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
});
|
||||
return Travel(const_cast<const Coordinates *>(&coords),
|
||||
manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
RoutingTransitCallback2 demand_evaluator =
|
||||
[&](int64 from_index, int64 to_index) {
|
||||
RoutingTransitCallback2 demand_evaluator = [&](int64 from_index,
|
||||
int64 to_index) {
|
||||
return demands[manager.IndexToNode(from_index).value()];
|
||||
}
|
||||
;
|
||||
};
|
||||
routing.AddDimension(routing.RegisterTransitCallback(demand_evaluator), 0,
|
||||
capacity, /*fix_start_cumul_to_zero=*/ true, "demand");
|
||||
RoutingTransitCallback2 time_evaluator =
|
||||
[&](int64 from_index, int64 to_index) {
|
||||
capacity, /*fix_start_cumul_to_zero=*/true, "demand");
|
||||
RoutingTransitCallback2 time_evaluator = [&](int64 from_index,
|
||||
int64 to_index) {
|
||||
return TravelPlusServiceTime(manager, &coords, &service_times, from_index,
|
||||
to_index);
|
||||
}
|
||||
;
|
||||
};
|
||||
routing.AddDimension(routing.RegisterTransitCallback(time_evaluator),
|
||||
kScalingFactor * horizon, kScalingFactor * horizon,
|
||||
/*fix_start_cumul_to_zero=*/ true, "time");
|
||||
/*fix_start_cumul_to_zero=*/true, "time");
|
||||
const RoutingDimension &time_dimension = routing.GetDimensionOrDie("time");
|
||||
Solver *const solver = routing.solver();
|
||||
for (int node = 0; node < num_nodes; ++node) {
|
||||
@@ -344,13 +341,9 @@ bool LoadAndSolve(const std::string &pdp_file,
|
||||
routing.AddVariableMinimizedByFinalizer(total_time);
|
||||
|
||||
RoutingModel::GetTabuVarsCallback tabu_var_callback =
|
||||
[total_time](RoutingModel * model) {
|
||||
return GetTabuVars({
|
||||
total_time
|
||||
},
|
||||
model);
|
||||
}
|
||||
;
|
||||
[total_time](RoutingModel *model) {
|
||||
return GetTabuVars({total_time}, model);
|
||||
};
|
||||
routing.SetTabuVarsCallback(tabu_var_callback);
|
||||
}
|
||||
|
||||
@@ -369,8 +362,8 @@ bool LoadAndSolve(const std::string &pdp_file,
|
||||
timer.Stop();
|
||||
LOG(INFO) << routing.solver()->LocalSearchProfile();
|
||||
if (nullptr != assignment) {
|
||||
LOG(INFO)
|
||||
<< VerboseOutput(routing, manager, *assignment, coords, service_times);
|
||||
LOG(INFO) << VerboseOutput(routing, manager, *assignment, coords,
|
||||
service_times);
|
||||
LOG(INFO) << "Cost: " << assignment->ObjectiveValue();
|
||||
int skipped_nodes = 0;
|
||||
for (int node = 0; node < routing.Size(); node++) {
|
||||
@@ -393,7 +386,7 @@ bool LoadAndSolve(const std::string &pdp_file,
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
template <typename GraphType> class LinearSumAssignment;
|
||||
template <typename GraphType>
|
||||
class LinearSumAssignment;
|
||||
|
||||
// Given a LinearSumAssigment object representing an assignment problem
|
||||
// description, outputs the problem in DIMACS format in the output file.
|
||||
@@ -66,6 +67,6 @@ void PrintDimacsAssignmentProblem(
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_EXAMPLES_PRINT_DIMACS_ASSIGNMENT_H_
|
||||
#endif // OR_TOOLS_EXAMPLES_PRINT_DIMACS_ASSIGNMENT_H_
|
||||
|
||||
@@ -44,10 +44,11 @@ DEFINE_int32(tsp_random_forbidden_connections, 0,
|
||||
"Number of random forbidden connections.");
|
||||
DEFINE_bool(tsp_use_deterministic_random_seed, false,
|
||||
"Use deterministic random seeds.");
|
||||
DEFINE_string(routing_search_parameters, "local_search_operators {"
|
||||
" use_path_lns:BOOL_TRUE"
|
||||
" use_inactive_lns:BOOL_TRUE"
|
||||
"}",
|
||||
DEFINE_string(routing_search_parameters,
|
||||
"local_search_operators {"
|
||||
" use_path_lns:BOOL_TRUE"
|
||||
" use_inactive_lns:BOOL_TRUE"
|
||||
"}",
|
||||
"Text proto RoutingSearchParameters (possibly partial) that will "
|
||||
"override the DefaultRoutingSearchParameters()");
|
||||
|
||||
@@ -68,12 +69,12 @@ int32 GetSeed() {
|
||||
int64 MyDistance(RoutingIndexManager::NodeIndex from,
|
||||
RoutingIndexManager::NodeIndex to) {
|
||||
// Put your distance code here.
|
||||
return (from + to).value(); // for instance
|
||||
return (from + to).value(); // for instance
|
||||
}
|
||||
|
||||
// Random matrix.
|
||||
class RandomMatrix {
|
||||
public:
|
||||
public:
|
||||
explicit RandomMatrix(int size) : size_(size) {}
|
||||
void Initialize() {
|
||||
matrix_ = absl::make_unique<int64[]>(size_ * size_);
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
return matrix_[MatrixIndex(from, to)];
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
int64 MatrixIndex(RoutingIndexManager::NodeIndex from,
|
||||
RoutingIndexManager::NodeIndex to) const {
|
||||
return (from * size_ + to).value();
|
||||
@@ -126,14 +127,15 @@ void Tsp() {
|
||||
matrix.Initialize();
|
||||
const int vehicle_cost = routing.RegisterTransitCallback(
|
||||
[&matrix, &manager](int64 i, int64 j) {
|
||||
return matrix.Distance(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
});
|
||||
return matrix.Distance(manager.IndexToNode(i),
|
||||
manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
} else {
|
||||
const int vehicle_cost =
|
||||
routing.RegisterTransitCallback([&manager](int64 i, int64 j) {
|
||||
return MyDistance(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
});
|
||||
return MyDistance(manager.IndexToNode(i), manager.IndexToNode(j));
|
||||
});
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
|
||||
}
|
||||
// Forbid node connections (randomly).
|
||||
@@ -174,7 +176,7 @@ void Tsp() {
|
||||
LOG(INFO) << "Specify an instance size greater than 0.";
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
@@ -119,7 +119,7 @@ struct CpModelProtoWrapper {
|
||||
//
|
||||
// It also support the wcnf input format for partial weighted max-sat problems.
|
||||
class SatCnfReader {
|
||||
public:
|
||||
public:
|
||||
SatCnfReader() : interpret_cnf_as_max_sat_(false) {}
|
||||
|
||||
// If called with true, then a cnf file will be converted to the max-sat
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
return LoadInternal(filename, &wrapper);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
template <class Problem>
|
||||
bool LoadInternal(const std::string &filename, Problem *problem) {
|
||||
positive_literal_to_weight_.clear();
|
||||
@@ -221,10 +221,8 @@ private:
|
||||
|
||||
template <class Problem>
|
||||
void ProcessNewLine(const std::string &line, Problem *problem) {
|
||||
if (line.empty() || end_marker_seen_)
|
||||
return;
|
||||
if (line[0] == 'c')
|
||||
return;
|
||||
if (line.empty() || end_marker_seen_) return;
|
||||
if (line[0] == 'c') return;
|
||||
if (line[0] == '%') {
|
||||
end_marker_seen_ = true;
|
||||
return;
|
||||
@@ -253,14 +251,13 @@ private:
|
||||
} else {
|
||||
if (signed_value == 0) {
|
||||
end_marker_seen = true;
|
||||
break; // end of clause.
|
||||
break; // end of clause.
|
||||
}
|
||||
tmp_clause_.push_back(signed_value);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (!end_marker_seen)
|
||||
return;
|
||||
if (!end_marker_seen) return;
|
||||
|
||||
if (weight == hard_weight_) {
|
||||
++num_added_clauses_;
|
||||
@@ -301,9 +298,7 @@ private:
|
||||
// Add the binary implications slack_literal true => all the other
|
||||
// clause literals are false.
|
||||
for (int i = 0; i + 1 < tmp_clause_.size(); ++i) {
|
||||
problem->AddConstraint({
|
||||
-slack_literal, -tmp_clause_[i]
|
||||
});
|
||||
problem->AddConstraint({-slack_literal, -tmp_clause_[i]});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,7 +334,7 @@ private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SatCnfReader);
|
||||
};
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_SAT_SAT_CNF_READER_H_
|
||||
#endif // OR_TOOLS_SAT_SAT_CNF_READER_H_
|
||||
|
||||
@@ -133,8 +133,7 @@ double GetScaledTrivialBestBound(const LinearBooleanProblem &problem) {
|
||||
Coefficient best_bound(0);
|
||||
const LinearObjective &objective = problem.objective();
|
||||
for (const int64 value : objective.coefficients()) {
|
||||
if (value < 0)
|
||||
best_bound += Coefficient(value);
|
||||
if (value < 0) best_bound += Coefficient(value);
|
||||
}
|
||||
return AddOffsetAndScaleObjectiveValue(problem, best_bound);
|
||||
}
|
||||
@@ -181,8 +180,7 @@ std::string SolutionString(const LinearBooleanProblem &problem,
|
||||
std::string output;
|
||||
BooleanVariable limit(problem.original_num_variables());
|
||||
for (BooleanVariable index(0); index < limit; ++index) {
|
||||
if (index > 0)
|
||||
output += " ";
|
||||
if (index > 0) output += " ";
|
||||
absl::StrAppend(&output,
|
||||
Literal(index, assignment[index.value()]).SignedValue());
|
||||
}
|
||||
@@ -224,7 +222,7 @@ int Run() {
|
||||
// TODO(user): clean this hack. Ideally LinearBooleanProblem should be
|
||||
// completely replaced by the more general CpModelProto.
|
||||
if (!cp_model.variables().empty()) {
|
||||
problem.Clear(); // We no longer need it, release memory.
|
||||
problem.Clear(); // We no longer need it, release memory.
|
||||
Model model;
|
||||
model.Add(NewSatParameters(parameters));
|
||||
const CpSolverResponse response = SolveCpModel(cp_model, &model);
|
||||
@@ -241,10 +239,8 @@ int Run() {
|
||||
|
||||
// The SAT competition requires a particular exit code and since we don't
|
||||
// really use it for any other purpose, we comply.
|
||||
if (response.status() == CpSolverStatus::FEASIBLE)
|
||||
return 10;
|
||||
if (response.status() == CpSolverStatus::INFEASIBLE)
|
||||
return 20;
|
||||
if (response.status() == CpSolverStatus::FEASIBLE) return 10;
|
||||
if (response.status() == CpSolverStatus::INFEASIBLE) return 20;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -282,13 +278,11 @@ int Run() {
|
||||
LOG(INFO) << "UNSAT when loading the problem.";
|
||||
}
|
||||
}
|
||||
auto strtoint64 = [](const std::string & word) {
|
||||
auto strtoint64 = [](const std::string &word) {
|
||||
int64 value = 0;
|
||||
if (!word.empty())
|
||||
CHECK(absl::SimpleAtoi(word, &value));
|
||||
if (!word.empty()) CHECK(absl::SimpleAtoi(word, &value));
|
||||
return value;
|
||||
}
|
||||
;
|
||||
};
|
||||
if (!AddObjectiveConstraint(
|
||||
problem, !absl::GetFlag(FLAGS_lower_bound).empty(),
|
||||
Coefficient(strtoint64(absl::GetFlag(FLAGS_lower_bound))),
|
||||
@@ -325,9 +319,9 @@ int Run() {
|
||||
if (absl::GetFlag(FLAGS_randomize) > 0 &&
|
||||
(absl::GetFlag(FLAGS_linear_scan) || absl::GetFlag(FLAGS_qmaxsat))) {
|
||||
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
|
||||
result = SolveWithRandomParameters(
|
||||
STDOUT_LOG, problem, absl::GetFlag(FLAGS_randomize), solver.get(),
|
||||
&solution);
|
||||
result = SolveWithRandomParameters(STDOUT_LOG, problem,
|
||||
absl::GetFlag(FLAGS_randomize),
|
||||
solver.get(), &solution);
|
||||
}
|
||||
if (result == SatSolver::LIMIT_REACHED) {
|
||||
if (absl::GetFlag(FLAGS_qmaxsat)) {
|
||||
@@ -434,16 +428,14 @@ int Run() {
|
||||
|
||||
// The SAT competition requires a particular exit code and since we don't
|
||||
// really use it for any other purpose, we comply.
|
||||
if (result == SatSolver::FEASIBLE)
|
||||
return 10;
|
||||
if (result == SatSolver::INFEASIBLE)
|
||||
return 20;
|
||||
if (result == SatSolver::FEASIBLE) return 10;
|
||||
if (result == SatSolver::INFEASIBLE) return 20;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
static const char kUsage[] =
|
||||
"Usage: see flags.\n"
|
||||
|
||||
@@ -45,7 +45,7 @@ DEFINE_string(params, "", "Sat parameters in text proto format.");
|
||||
namespace operations_research {
|
||||
namespace sat {
|
||||
class ShiftMinimizationParser {
|
||||
public:
|
||||
public:
|
||||
struct Job {
|
||||
int start;
|
||||
int end;
|
||||
@@ -57,15 +57,17 @@ public:
|
||||
};
|
||||
|
||||
ShiftMinimizationParser()
|
||||
: load_status_(NOT_STARTED), declared_num_jobs_(0),
|
||||
declared_num_workers_(0), num_workers_read_(0) {}
|
||||
: load_status_(NOT_STARTED),
|
||||
declared_num_jobs_(0),
|
||||
declared_num_workers_(0),
|
||||
num_workers_read_(0) {}
|
||||
|
||||
const std::vector<Job> &jobs() const { return jobs_; }
|
||||
const std::vector<std::vector<int> > &possible_jobs_per_worker() const {
|
||||
return possible_jobs_per_worker_;
|
||||
}
|
||||
const std::vector<std::vector<Assignment> > &
|
||||
possible_assignments_per_job() const {
|
||||
const std::vector<std::vector<Assignment> > &possible_assignments_per_job()
|
||||
const {
|
||||
return possible_assignments_per_job_;
|
||||
}
|
||||
|
||||
@@ -96,13 +98,8 @@ public:
|
||||
declared_num_workers_ == num_workers_read_;
|
||||
}
|
||||
|
||||
private:
|
||||
enum LoadStatus {
|
||||
NOT_STARTED,
|
||||
STARTED,
|
||||
JOBS_SEEN,
|
||||
WORKERS_SEEN
|
||||
};
|
||||
private:
|
||||
enum LoadStatus { NOT_STARTED, STARTED, JOBS_SEEN, WORKERS_SEEN };
|
||||
|
||||
int strtoint32(const std::string &word) {
|
||||
int result;
|
||||
@@ -119,49 +116,46 @@ private:
|
||||
absl::StrSplit(line, absl::ByAnyChar(" :\t"), absl::SkipEmpty());
|
||||
|
||||
switch (load_status_) {
|
||||
case NOT_STARTED: {
|
||||
LOG(FATAL) << "Wrong status: NOT_STARTED";
|
||||
break;
|
||||
}
|
||||
case STARTED: {
|
||||
if (words.size() == 3 && words[0] == "Type") {
|
||||
CHECK_EQ(1, strtoint32(words[2]));
|
||||
} else if (words.size() == 3 && words[0] == "Jobs") {
|
||||
declared_num_jobs_ = strtoint32(words[2]);
|
||||
possible_assignments_per_job_.resize(declared_num_jobs_);
|
||||
load_status_ = JOBS_SEEN;
|
||||
} else {
|
||||
LOG(FATAL) << "Wrong state STARTED with line " << line;
|
||||
case NOT_STARTED: {
|
||||
LOG(FATAL) << "Wrong status: NOT_STARTED";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JOBS_SEEN: {
|
||||
if (words.size() == 2) {
|
||||
jobs_.push_back({
|
||||
strtoint32(words[0]), strtoint32(words[1])
|
||||
});
|
||||
} else if (words.size() == 3 && words[0] == "Qualifications") {
|
||||
declared_num_workers_ = strtoint32(words[2]);
|
||||
possible_jobs_per_worker_.resize(declared_num_workers_);
|
||||
load_status_ = WORKERS_SEEN;
|
||||
} else {
|
||||
LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
|
||||
case STARTED: {
|
||||
if (words.size() == 3 && words[0] == "Type") {
|
||||
CHECK_EQ(1, strtoint32(words[2]));
|
||||
} else if (words.size() == 3 && words[0] == "Jobs") {
|
||||
declared_num_jobs_ = strtoint32(words[2]);
|
||||
possible_assignments_per_job_.resize(declared_num_jobs_);
|
||||
load_status_ = JOBS_SEEN;
|
||||
} else {
|
||||
LOG(FATAL) << "Wrong state STARTED with line " << line;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WORKERS_SEEN: {
|
||||
CHECK_EQ(strtoint32(words[0]), words.size() - 1);
|
||||
for (int i = 1; i < words.size(); ++i) {
|
||||
const int job = strtoint32(words[i]);
|
||||
const int pos = possible_jobs_per_worker_[num_workers_read_].size();
|
||||
possible_jobs_per_worker_[num_workers_read_].push_back(job);
|
||||
possible_assignments_per_job_[job].push_back({
|
||||
num_workers_read_, pos
|
||||
});
|
||||
case JOBS_SEEN: {
|
||||
if (words.size() == 2) {
|
||||
jobs_.push_back({strtoint32(words[0]), strtoint32(words[1])});
|
||||
} else if (words.size() == 3 && words[0] == "Qualifications") {
|
||||
declared_num_workers_ = strtoint32(words[2]);
|
||||
possible_jobs_per_worker_.resize(declared_num_workers_);
|
||||
load_status_ = WORKERS_SEEN;
|
||||
} else {
|
||||
LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WORKERS_SEEN: {
|
||||
CHECK_EQ(strtoint32(words[0]), words.size() - 1);
|
||||
for (int i = 1; i < words.size(); ++i) {
|
||||
const int job = strtoint32(words[i]);
|
||||
const int pos = possible_jobs_per_worker_[num_workers_read_].size();
|
||||
possible_jobs_per_worker_[num_workers_read_].push_back(job);
|
||||
possible_assignments_per_job_[job].push_back(
|
||||
{num_workers_read_, pos});
|
||||
}
|
||||
num_workers_read_++;
|
||||
break;
|
||||
}
|
||||
num_workers_read_++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,9 +210,7 @@ void LoadAndSolve(const std::string &file_name) {
|
||||
if (Overlaps(jobs[job1], jobs[job2])) {
|
||||
const BoolVar v1 = worker_job_vars[w][i];
|
||||
const BoolVar v2 = worker_job_vars[w][j];
|
||||
cp_model.AddBoolOr({
|
||||
Not(v1), Not(v2)
|
||||
});
|
||||
cp_model.AddBoolOr({Not(v1), Not(v2)});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,8 +258,7 @@ void LoadAndSolve(const std::string &file_name) {
|
||||
}
|
||||
|
||||
// Check that we have not already visited this exact set of candidate jobs.
|
||||
if (gtl::ContainsKey(visited_job_lists, intersecting_jobs))
|
||||
continue;
|
||||
if (gtl::ContainsKey(visited_job_lists, intersecting_jobs)) continue;
|
||||
visited_job_lists.insert(intersecting_jobs);
|
||||
|
||||
// Collect the relevant worker job vars.
|
||||
@@ -306,8 +297,8 @@ void LoadAndSolve(const std::string &file_name) {
|
||||
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
}
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
@@ -21,27 +21,28 @@
|
||||
#include "ortools/sat/cp_model.h"
|
||||
#include "ortools/sat/model.h"
|
||||
|
||||
const std::vector<std::vector<int> > tiny = { { 3, 3, 1 } };
|
||||
const std::vector<std::vector<int> > tiny = {{3, 3, 1}};
|
||||
|
||||
const std::vector<std::vector<int> > small = {
|
||||
{ 3, 2, -1, 3 }, { -1, -1, -1, 2 }, { 3, -1, -1, -1 }, { 3, -1, 3, 1 }
|
||||
};
|
||||
{3, 2, -1, 3}, {-1, -1, -1, 2}, {3, -1, -1, -1}, {3, -1, 3, 1}};
|
||||
|
||||
const std::vector<std::vector<int> > medium = {
|
||||
{ -1, 0, -1, 1, -1, -1, 1, -1 }, { -1, 3, -1, -1, 2, 3, -1, 2 },
|
||||
{ -1, -1, 0, -1, -1, -1, -1, 0 }, { -1, 3, -1, -1, 0, -1, -1, -1 },
|
||||
{ -1, -1, -1, 3, -1, -1, 0, -1 }, { 1, -1, -1, -1, -1, 3, -1, -1 },
|
||||
{ 3, -1, 1, 3, -1, -1, 3, -1 }, { -1, 0, -1, -1, 3, -1, 3, -1 }
|
||||
};
|
||||
{-1, 0, -1, 1, -1, -1, 1, -1}, {-1, 3, -1, -1, 2, 3, -1, 2},
|
||||
{-1, -1, 0, -1, -1, -1, -1, 0}, {-1, 3, -1, -1, 0, -1, -1, -1},
|
||||
{-1, -1, -1, 3, -1, -1, 0, -1}, {1, -1, -1, -1, -1, 3, -1, -1},
|
||||
{3, -1, 1, 3, -1, -1, 3, -1}, {-1, 0, -1, -1, 3, -1, 3, -1}};
|
||||
|
||||
const std::vector<std::vector<int> > big = {
|
||||
{ 3, -1, -1, -1, 2, -1, 1, -1, 1, 2 }, { 1, -1, 0, -1, 3, -1, 2, 0, -1, -1 },
|
||||
{ -1, 3, -1, -1, -1, -1, -1, -1, 3, -1 },
|
||||
{ 2, 0, -1, 3, -1, 2, 3, -1, -1, -1 }, { -1, -1, -1, 1, 1, 1, -1, -1, 3, 3 },
|
||||
{ 2, 3, -1, -1, 2, 2, 3, -1, -1, -1 }, { -1, -1, -1, 1, 2, -1, 2, -1, 3, 3 },
|
||||
{ -1, 2, -1, -1, -1, -1, -1, -1, 2, -1 },
|
||||
{ -1, -1, 1, 1, -1, 2, -1, 1, -1, 3 }, { 3, 3, -1, 1, -1, 2, -1, -1, -1, 2 }
|
||||
};
|
||||
{3, -1, -1, -1, 2, -1, 1, -1, 1, 2},
|
||||
{1, -1, 0, -1, 3, -1, 2, 0, -1, -1},
|
||||
{-1, 3, -1, -1, -1, -1, -1, -1, 3, -1},
|
||||
{2, 0, -1, 3, -1, 2, 3, -1, -1, -1},
|
||||
{-1, -1, -1, 1, 1, 1, -1, -1, 3, 3},
|
||||
{2, 3, -1, -1, 2, 2, 3, -1, -1, -1},
|
||||
{-1, -1, -1, 1, 2, -1, 2, -1, 3, 3},
|
||||
{-1, 2, -1, -1, -1, -1, -1, -1, 2, -1},
|
||||
{-1, -1, 1, 1, -1, 2, -1, 1, -1, 3},
|
||||
{3, 3, -1, 1, -1, 2, -1, -1, -1, 2}};
|
||||
|
||||
namespace operations_research {
|
||||
namespace sat {
|
||||
@@ -90,26 +91,23 @@ void SlitherLink(const std::vector<std::vector<int> > &data) {
|
||||
const int num_horizontal_arcs = num_columns * (num_rows + 1);
|
||||
const int num_vertical_arcs = (num_rows) * (num_columns + 1);
|
||||
|
||||
auto undirected_horizontal_arc = [ = ](int x, int y) {
|
||||
auto undirected_horizontal_arc = [=](int x, int y) {
|
||||
CHECK_LT(x, num_columns);
|
||||
CHECK_LT(y, num_rows + 1);
|
||||
return x + (num_columns * y);
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
auto undirected_vertical_arc = [ = ](int x, int y) {
|
||||
auto undirected_vertical_arc = [=](int x, int y) {
|
||||
CHECK_LT(x, num_columns + 1);
|
||||
CHECK_LT(y, num_rows);
|
||||
return x + (num_columns + 1) * y;
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
auto node_index = [ = ](int x, int y) {
|
||||
auto node_index = [=](int x, int y) {
|
||||
CHECK_LT(x, num_columns + 1);
|
||||
CHECK_LT(y, num_rows + 1);
|
||||
return x + y * (num_columns + 1);
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
CpModelBuilder builder;
|
||||
|
||||
@@ -156,8 +154,7 @@ void SlitherLink(const std::vector<std::vector<int> > &data) {
|
||||
|
||||
for (int x = 0; x < num_columns; ++x) {
|
||||
for (int y = 0; y < num_rows; ++y) {
|
||||
if (data[y][x] == -1)
|
||||
continue;
|
||||
if (data[y][x] == -1) continue;
|
||||
std::vector<BoolVar> neighbors;
|
||||
const int top_arc = undirected_horizontal_arc(x, y);
|
||||
neighbors.push_back(horizontal_arcs[2 * top_arc]);
|
||||
@@ -178,43 +175,31 @@ void SlitherLink(const std::vector<std::vector<int> > &data) {
|
||||
// Special rule on corners: value == 3 implies 2 corner arcs used.
|
||||
if (data[0][0] == 3) {
|
||||
const int h_arc = undirected_horizontal_arc(0, 0);
|
||||
builder.AddBoolOr({
|
||||
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
|
||||
const int v_arc = undirected_vertical_arc(0, 0);
|
||||
builder.AddBoolOr({
|
||||
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
|
||||
}
|
||||
if (data[0][num_columns - 1] == 3) {
|
||||
const int h_arc = undirected_horizontal_arc(num_columns - 1, 0);
|
||||
builder.AddBoolOr({
|
||||
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
|
||||
const int v_arc = undirected_vertical_arc(num_columns, 0);
|
||||
builder.AddBoolOr({
|
||||
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
|
||||
}
|
||||
if (data[num_rows - 1][0] == 3) {
|
||||
const int h_arc = undirected_horizontal_arc(0, num_rows);
|
||||
builder.AddBoolOr({
|
||||
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
|
||||
const int v_arc = undirected_vertical_arc(0, num_rows - 1);
|
||||
builder.AddBoolOr({
|
||||
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
|
||||
}
|
||||
if (data[num_rows - 1][num_columns - 1] == 3) {
|
||||
const int h_arc = undirected_horizontal_arc(num_columns - 1, num_rows);
|
||||
builder.AddBoolOr({
|
||||
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
|
||||
const int v_arc = undirected_vertical_arc(num_columns, num_rows - 1);
|
||||
builder.AddBoolOr({
|
||||
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
|
||||
});
|
||||
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
|
||||
}
|
||||
|
||||
// Topology rule: Border arcs are oriented in one direction.
|
||||
@@ -258,8 +243,8 @@ void SlitherLink(const std::vector<std::vector<int> > &data) {
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main() {
|
||||
std::cout << "Tiny problem" << std::endl;
|
||||
|
||||
@@ -63,7 +63,7 @@ DEFINE_string(dump_model, "", "If non-empty, dumps MPModelProto there.");
|
||||
DEFINE_string(dump_request, "", "If non-empty, dumps MPModelRequest there.");
|
||||
DEFINE_string(dump_response, "", "If non-empty, dumps MPModelResponse there.");
|
||||
|
||||
DECLARE_bool(verify_solution); // Defined in ./linear_solver.cc
|
||||
DECLARE_bool(verify_solution); // Defined in ./linear_solver.cc
|
||||
|
||||
static const char kUsageStr[] =
|
||||
"Run MPSolver on the given input file. Many formats are supported: \n"
|
||||
@@ -125,8 +125,8 @@ bool Run() {
|
||||
} else if (absl::GetFlag(FLAGS_dump_format) == "json") {
|
||||
write_format = ProtoWriteFormat::kJson;
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unsupported --dump_format: " << absl::GetFlag(FLAGS_dump_format);
|
||||
LOG(FATAL) << "Unsupported --dump_format: "
|
||||
<< absl::GetFlag(FLAGS_dump_format);
|
||||
}
|
||||
|
||||
// Create the solver, we use the name of the model as the solver name.
|
||||
@@ -148,13 +148,15 @@ bool Run() {
|
||||
<< "Could not read parameters file.";
|
||||
CHECK(solver.SetSolverSpecificParametersAsString(file_contents));
|
||||
} else if (!absl::GetFlag(FLAGS_params).empty()) {
|
||||
CHECK(solver.SetSolverSpecificParametersAsString(
|
||||
absl::GetFlag(FLAGS_params))) << "Wrong --params format.";
|
||||
CHECK(
|
||||
solver.SetSolverSpecificParametersAsString(absl::GetFlag(FLAGS_params)))
|
||||
<< "Wrong --params format.";
|
||||
}
|
||||
absl::PrintF(
|
||||
"%-12s: %s\n", "Solver",
|
||||
MPModelRequest::SolverType_Name(static_cast<MPModelRequest::SolverType>(
|
||||
solver.ProblemType())).c_str());
|
||||
MPModelRequest::SolverType_Name(
|
||||
static_cast<MPModelRequest::SolverType>(solver.ProblemType()))
|
||||
.c_str());
|
||||
|
||||
// Load the proto into the solver.
|
||||
std::string error_message;
|
||||
@@ -229,14 +231,15 @@ bool Run() {
|
||||
// a verification step here.
|
||||
if (has_solution && !absl::GetFlag(FLAGS_verify_solution)) {
|
||||
LOG(INFO) << "Verifying the solution";
|
||||
solver.VerifySolution(/*tolerance=*/ param.GetDoubleParam(
|
||||
solver.VerifySolution(/*tolerance=*/param.GetDoubleParam(
|
||||
MPSolverParameters::PRIMAL_TOLERANCE),
|
||||
/*log_errors=*/ true);
|
||||
/*log_errors=*/true);
|
||||
}
|
||||
|
||||
absl::PrintF("%-12s: %s\n", "Status",
|
||||
MPSolverResponseStatus_Name(
|
||||
static_cast<MPSolverResponseStatus>(solve_status)).c_str());
|
||||
static_cast<MPSolverResponseStatus>(solve_status))
|
||||
.c_str());
|
||||
absl::PrintF("%-12s: %15.15e\n", "Objective",
|
||||
has_solution ? solver.Objective().Value() : 0.0);
|
||||
absl::PrintF("%-12s: %15.15e\n", "BestBound",
|
||||
@@ -250,12 +253,12 @@ bool Run() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace operations_research
|
||||
} // namespace
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/ true);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/true);
|
||||
CHECK(!absl::GetFlag(FLAGS_input).empty()) << "--input is required";
|
||||
operations_research::Run();
|
||||
|
||||
|
||||
@@ -70,11 +70,12 @@ void FirstModel(int num_teams) {
|
||||
Domain opponent_domain(0, num_teams - 1);
|
||||
Domain signed_opponent_domain(0, 2 * num_teams - 1);
|
||||
IntVar opp = builder.NewIntVar(opponent_domain)
|
||||
.WithName(absl::StrCat("opponent_", t, "_", d));
|
||||
.WithName(absl::StrCat("opponent_", t, "_", d));
|
||||
BoolVar home =
|
||||
builder.NewBoolVar().WithName(absl::StrCat("home_aways", t, "_", d));
|
||||
IntVar signed_opp = builder.NewIntVar(signed_opponent_domain)
|
||||
.WithName(absl::StrCat("signed_opponent_", t, "_", d));
|
||||
IntVar signed_opp =
|
||||
builder.NewIntVar(signed_opponent_domain)
|
||||
.WithName(absl::StrCat("signed_opponent_", t, "_", d));
|
||||
|
||||
opponents[t].push_back(opp);
|
||||
home_aways[t].push_back(home);
|
||||
@@ -108,10 +109,7 @@ void FirstModel(int num_teams) {
|
||||
IntVar second_home = builder.NewBoolVar();
|
||||
builder.AddVariableElement(day_opponents[first_team], day_home_aways,
|
||||
second_home);
|
||||
builder.AddEquality(LinearExpr::Sum({
|
||||
first_home, second_home
|
||||
}),
|
||||
1);
|
||||
builder.AddEquality(LinearExpr::Sum({first_home, second_home}), 1);
|
||||
}
|
||||
|
||||
builder.AddEquality(LinearExpr::Sum(day_home_aways), num_teams / 2);
|
||||
@@ -138,13 +136,11 @@ void FirstModel(int num_teams) {
|
||||
|
||||
// Forbid sequence of 3 homes or 3 aways.
|
||||
for (int start = 0; start < num_days - 2; ++start) {
|
||||
builder.AddBoolOr({
|
||||
home_aways[t][start], home_aways[t][start + 1], home_aways[t][start + 2]
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
Not(home_aways[t][start]), Not(home_aways[t][start + 1]),
|
||||
Not(home_aways[t][start + 2])
|
||||
});
|
||||
builder.AddBoolOr({home_aways[t][start], home_aways[t][start + 1],
|
||||
home_aways[t][start + 2]});
|
||||
builder.AddBoolOr({Not(home_aways[t][start]),
|
||||
Not(home_aways[t][start + 1]),
|
||||
Not(home_aways[t][start + 2])});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,12 +150,9 @@ void FirstModel(int num_teams) {
|
||||
for (int d = 0; d < num_days - 1; ++d) {
|
||||
BoolVar break_var =
|
||||
builder.NewBoolVar().WithName(absl::StrCat("break_", t, "_", d));
|
||||
builder.AddBoolOr({
|
||||
Not(home_aways[t][d]), Not(home_aways[t][d + 1]), break_var
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
home_aways[t][d], home_aways[t][d + 1], break_var
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{Not(home_aways[t][d]), Not(home_aways[t][d + 1]), break_var});
|
||||
builder.AddBoolOr({home_aways[t][d], home_aways[t][d + 1], break_var});
|
||||
breaks.push_back(break_var);
|
||||
}
|
||||
}
|
||||
@@ -228,8 +221,7 @@ void SecondModel(int num_teams) {
|
||||
for (int team = 0; team < num_teams; ++team) {
|
||||
std::vector<BoolVar> possible_opponents;
|
||||
for (int other = 0; other < num_teams; ++other) {
|
||||
if (team == other)
|
||||
continue;
|
||||
if (team == other) continue;
|
||||
possible_opponents.push_back(fixtures[d][team][other]);
|
||||
possible_opponents.push_back(fixtures[d][other][team]);
|
||||
}
|
||||
@@ -240,8 +232,7 @@ void SecondModel(int num_teams) {
|
||||
// Each fixture happens once per season.
|
||||
for (int team = 0; team < num_teams; ++team) {
|
||||
for (int other = 0; other < num_teams; ++other) {
|
||||
if (team == other)
|
||||
continue;
|
||||
if (team == other) continue;
|
||||
std::vector<BoolVar> possible_days;
|
||||
for (int d = 0; d < num_days; ++d) {
|
||||
possible_days.push_back(fixtures[d][team][other]);
|
||||
@@ -253,8 +244,7 @@ void SecondModel(int num_teams) {
|
||||
// Meet each opponent once per season.
|
||||
for (int team = 0; team < num_teams; ++team) {
|
||||
for (int other = 0; other < num_teams; ++other) {
|
||||
if (team == other)
|
||||
continue;
|
||||
if (team == other) continue;
|
||||
std::vector<BoolVar> first_half;
|
||||
std::vector<BoolVar> second_half;
|
||||
for (int d = 0; d < matches_per_day; ++d) {
|
||||
@@ -272,8 +262,7 @@ void SecondModel(int num_teams) {
|
||||
for (int d = 0; d < num_days; ++d) {
|
||||
for (int team = 0; team < num_teams; ++team) {
|
||||
for (int other = 0; other < num_teams; ++other) {
|
||||
if (team == other)
|
||||
continue;
|
||||
if (team == other) continue;
|
||||
builder.AddImplication(fixtures[d][team][other], at_home[d][team]);
|
||||
builder.AddImplication(fixtures[d][team][other],
|
||||
Not(at_home[d][other]));
|
||||
@@ -284,13 +273,10 @@ void SecondModel(int num_teams) {
|
||||
// Forbid sequence of 3 homes or 3 aways.
|
||||
for (int team = 0; team < num_teams; ++team) {
|
||||
for (int d = 0; d < num_days - 2; ++d) {
|
||||
builder.AddBoolOr({
|
||||
at_home[d][team], at_home[d + 1][team], at_home[d + 2][team]
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
Not(at_home[d][team]), Not(at_home[d + 1][team]),
|
||||
Not(at_home[d + 2][team])
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{at_home[d][team], at_home[d + 1][team], at_home[d + 2][team]});
|
||||
builder.AddBoolOr({Not(at_home[d][team]), Not(at_home[d + 1][team]),
|
||||
Not(at_home[d + 2][team])});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,18 +285,13 @@ void SecondModel(int num_teams) {
|
||||
for (int t = 0; t < num_teams; ++t) {
|
||||
for (int d = 0; d < num_days - 1; ++d) {
|
||||
BoolVar break_var = builder.NewBoolVar();
|
||||
builder.AddBoolOr({
|
||||
Not(at_home[d][t]), Not(at_home[d + 1][t]), break_var
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
at_home[d][t], at_home[d + 1][t], break_var
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
Not(at_home[d][t]), at_home[d + 1][t], Not(break_var)
|
||||
});
|
||||
builder.AddBoolOr({
|
||||
at_home[d][t], Not(at_home[d + 1][t]), Not(break_var)
|
||||
});
|
||||
builder.AddBoolOr(
|
||||
{Not(at_home[d][t]), Not(at_home[d + 1][t]), break_var});
|
||||
builder.AddBoolOr({at_home[d][t], at_home[d + 1][t], break_var});
|
||||
builder.AddBoolOr(
|
||||
{Not(at_home[d][t]), at_home[d + 1][t], Not(break_var)});
|
||||
builder.AddBoolOr(
|
||||
{at_home[d][t], Not(at_home[d + 1][t]), Not(break_var)});
|
||||
breaks.push_back(break_var);
|
||||
}
|
||||
}
|
||||
@@ -328,8 +309,8 @@ void SecondModel(int num_teams) {
|
||||
LOG(INFO) << CpSolverResponseStats(response);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
static const char kUsage[] =
|
||||
"Usage: see flags.\nThis program runs a sports scheduling problem."
|
||||
|
||||
@@ -18,12 +18,15 @@ namespace operations_research {
|
||||
void RunStiglerDietExample() {
|
||||
// Nutrient minimums.
|
||||
std::vector<std::pair<std::string, double> > nutrients = {
|
||||
{ "Calories (kcal)", 3.0 }, { "Protein (g)", 70.0 }, { "Calcium (g)", 0.8 },
|
||||
{ "Iron (mg)", 12.0 }, { "Vitamin A (kIU)", 5.0 },
|
||||
{ "Thiamine (Vitamin B1) (mg)", 1.8 },
|
||||
{ "Riboflavin (Vitamin B2) (mg)", 2.7 }, { "Niacin (mg)", 18.0 },
|
||||
{ "Ascorbic Acid (Vitamin C) (mg)", 75.0 }
|
||||
};
|
||||
{"Calories (kcal)", 3.0},
|
||||
{"Protein (g)", 70.0},
|
||||
{"Calcium (g)", 0.8},
|
||||
{"Iron (mg)", 12.0},
|
||||
{"Vitamin A (kIU)", 5.0},
|
||||
{"Thiamine (Vitamin B1) (mg)", 1.8},
|
||||
{"Riboflavin (Vitamin B2) (mg)", 2.7},
|
||||
{"Niacin (mg)", 18.0},
|
||||
{"Ascorbic Acid (Vitamin C) (mg)", 75.0}};
|
||||
|
||||
struct Commodity {
|
||||
// Commodity name
|
||||
@@ -45,128 +48,182 @@ void RunStiglerDietExample() {
|
||||
};
|
||||
|
||||
std::vector<Commodity> data = {
|
||||
{ "Wheat Flour (Enriched)", "10 lb.", 36,
|
||||
{ 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 } },
|
||||
{ "Macaroni", "1 lb.", 14.1, { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 } },
|
||||
{ "Wheat Cereal (Enriched)", "28 oz.", 24.2,
|
||||
{ 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 } },
|
||||
{ "Corn Flakes", "8 oz.", 7.1,
|
||||
{ 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 } },
|
||||
{ "Corn Meal", "1 lb.", 4.6,
|
||||
{ 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 } },
|
||||
{ "Hominy Grits", "24 oz.", 8.5,
|
||||
{ 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 } },
|
||||
{ "Rice", "1 lb.", 7.5, { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 } },
|
||||
{ "Rolled Oats", "1 lb.", 7.1,
|
||||
{ 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 } },
|
||||
{ "White Bread (Enriched)", "1 lb.", 7.9,
|
||||
{ 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 } },
|
||||
{ "Whole Wheat Bread", "1 lb.", 9.1,
|
||||
{ 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 } },
|
||||
{ "Rye Bread", "1 lb.", 9.1, { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 } },
|
||||
{ "Pound Cake", "1 lb.", 24.8, { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 } },
|
||||
{ "Soda Crackers", "1 lb.", 15.1, { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 } },
|
||||
{ "Milk", "1 qt.", 11, { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 } },
|
||||
{ "Evaporated Milk (can)", "14.5 oz.", 6.7,
|
||||
{ 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 } },
|
||||
{ "Butter", "1 lb.", 30.8, { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 } },
|
||||
{ "Oleomargarine", "1 lb.", 16.1,
|
||||
{ 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 } },
|
||||
{ "Eggs", "1 doz.", 32.6, { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 } },
|
||||
{ "Cheese (Cheddar)", "1 lb.", 24.2,
|
||||
{ 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 } },
|
||||
{ "Cream", "1/2 pt.", 14.1, { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 } },
|
||||
{ "Peanut Butter", "1 lb.", 17.9,
|
||||
{ 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 } },
|
||||
{ "Mayonnaise", "1/2 pt.", 16.7, { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 } },
|
||||
{ "Crisco", "1 lb.", 20.3, { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||
{ "Lard", "1 lb.", 9.8, { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 } },
|
||||
{ "Sirloin Steak", "1 lb.", 39.6,
|
||||
{ 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 } },
|
||||
{ "Round Steak", "1 lb.", 36.4,
|
||||
{ 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 } },
|
||||
{ "Rib Roast", "1 lb.", 29.2, { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 } },
|
||||
{ "Chuck Roast", "1 lb.", 22.6, { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 } },
|
||||
{ "Plate", "1 lb.", 14.6, { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 } },
|
||||
{ "Liver (Beef)", "1 lb.", 26.8,
|
||||
{ 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 } },
|
||||
{ "Leg of Lamb", "1 lb.", 27.6, { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 } },
|
||||
{ "Lamb Chops (Rib)", "1 lb.", 36.6,
|
||||
{ 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 } },
|
||||
{ "Pork Chops", "1 lb.", 30.7, { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 } },
|
||||
{ "Pork Loin Roast", "1 lb.", 24.2,
|
||||
{ 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 } },
|
||||
{ "Bacon", "1 lb.", 25.6, { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 } },
|
||||
{ "Ham, smoked", "1 lb.", 27.4, { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 } },
|
||||
{ "Salt Pork", "1 lb.", 16, { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 } },
|
||||
{ "Roasting Chicken", "1 lb.", 30.3,
|
||||
{ 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 } },
|
||||
{ "Veal Cutlets", "1 lb.", 42.3,
|
||||
{ 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 } },
|
||||
{ "Salmon, Pink (can)", "16 oz.", 13,
|
||||
{ 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 } },
|
||||
{ "Apples", "1 lb.", 4.4, { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 } },
|
||||
{ "Bananas", "1 lb.", 6.1, { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 } },
|
||||
{ "Lemons", "1 doz.", 26, { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 } },
|
||||
{ "Oranges", "1 doz.", 30.9,
|
||||
{ 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 } },
|
||||
{ "Green Beans", "1 lb.", 7.1,
|
||||
{ 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 } },
|
||||
{ "Cabbage", "1 lb.", 3.7, { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 } },
|
||||
{ "Carrots", "1 bunch", 4.7,
|
||||
{ 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 } },
|
||||
{ "Celery", "1 stalk", 7.3, { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 } },
|
||||
{ "Lettuce", "1 head", 8.2,
|
||||
{ 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 } },
|
||||
{ "Onions", "1 lb.", 3.6, { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 } },
|
||||
{ "Potatoes", "15 lb.", 34,
|
||||
{ 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 } },
|
||||
{ "Spinach", "1 lb.", 8.1,
|
||||
{ 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 } },
|
||||
{ "Sweet Potatoes", "1 lb.", 5.1,
|
||||
{ 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 } },
|
||||
{ "Peaches (can)", "No. 2 1/2", 16.8,
|
||||
{ 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 } },
|
||||
{ "Pears (can)", "No. 2 1/2", 20.4,
|
||||
{ 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 } },
|
||||
{ "Pineapple (can)", "No. 2 1/2", 21.3,
|
||||
{ 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 } },
|
||||
{ "Asparagus (can)", "No. 2", 27.7,
|
||||
{ 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 } },
|
||||
{ "Green Beans (can)", "No. 2", 10,
|
||||
{ 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 } },
|
||||
{ "Pork and Beans (can)", "16 oz.", 7.1,
|
||||
{ 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 } },
|
||||
{ "Corn (can)", "No. 2", 10.4,
|
||||
{ 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 } },
|
||||
{ "Peas (can)", "No. 2", 13.8,
|
||||
{ 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 } },
|
||||
{ "Tomatoes (can)", "No. 2", 8.6,
|
||||
{ 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 } },
|
||||
{ "Tomato Soup (can)", "10 1/2 oz.", 7.6,
|
||||
{ 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 } },
|
||||
{ "Peaches, Dried", "1 lb.", 15.7,
|
||||
{ 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 } },
|
||||
{ "Prunes, Dried", "1 lb.", 9,
|
||||
{ 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 } },
|
||||
{ "Raisins, Dried", "15 oz.", 9.4,
|
||||
{ 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 } },
|
||||
{ "Peas, Dried", "1 lb.", 7.9,
|
||||
{ 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 } },
|
||||
{ "Lima Beans, Dried", "1 lb.", 8.9,
|
||||
{ 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 } },
|
||||
{ "Navy Beans, Dried", "1 lb.", 5.9,
|
||||
{ 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 } },
|
||||
{ "Coffee", "1 lb.", 22.4, { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 } },
|
||||
{ "Tea", "1/4 lb.", 17.4, { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 } },
|
||||
{ "Cocoa", "8 oz.", 8.6, { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 } },
|
||||
{ "Chocolate", "8 oz.", 16.2, { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 } },
|
||||
{ "Sugar", "10 lb.", 51.7, { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||
{ "Corn Syrup", "24 oz.", 13.7, { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 } },
|
||||
{ "Molasses", "18 oz.", 13.6, { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 } },
|
||||
{ "Strawberry Preserves", "1 lb.", 20.5,
|
||||
{ 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 } }
|
||||
};
|
||||
{"Wheat Flour (Enriched)",
|
||||
"10 lb.",
|
||||
36,
|
||||
{44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}},
|
||||
{"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}},
|
||||
{"Wheat Cereal (Enriched)",
|
||||
"28 oz.",
|
||||
24.2,
|
||||
{11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}},
|
||||
{"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}},
|
||||
{"Corn Meal",
|
||||
"1 lb.",
|
||||
4.6,
|
||||
{36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}},
|
||||
{"Hominy Grits",
|
||||
"24 oz.",
|
||||
8.5,
|
||||
{28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}},
|
||||
{"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}},
|
||||
{"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}},
|
||||
{"White Bread (Enriched)",
|
||||
"1 lb.",
|
||||
7.9,
|
||||
{15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}},
|
||||
{"Whole Wheat Bread",
|
||||
"1 lb.",
|
||||
9.1,
|
||||
{12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}},
|
||||
{"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}},
|
||||
{"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}},
|
||||
{"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}},
|
||||
{"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}},
|
||||
{"Evaporated Milk (can)",
|
||||
"14.5 oz.",
|
||||
6.7,
|
||||
{8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}},
|
||||
{"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}},
|
||||
{"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}},
|
||||
{"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}},
|
||||
{"Cheese (Cheddar)",
|
||||
"1 lb.",
|
||||
24.2,
|
||||
{7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}},
|
||||
{"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}},
|
||||
{"Peanut Butter",
|
||||
"1 lb.",
|
||||
17.9,
|
||||
{15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}},
|
||||
{"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}},
|
||||
{"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}},
|
||||
{"Sirloin Steak",
|
||||
"1 lb.",
|
||||
39.6,
|
||||
{2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}},
|
||||
{"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}},
|
||||
{"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}},
|
||||
{"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}},
|
||||
{"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}},
|
||||
{"Liver (Beef)",
|
||||
"1 lb.",
|
||||
26.8,
|
||||
{2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}},
|
||||
{"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}},
|
||||
{"Lamb Chops (Rib)",
|
||||
"1 lb.",
|
||||
36.6,
|
||||
{3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}},
|
||||
{"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}},
|
||||
{"Pork Loin Roast",
|
||||
"1 lb.",
|
||||
24.2,
|
||||
{4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}},
|
||||
{"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}},
|
||||
{"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}},
|
||||
{"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}},
|
||||
{"Roasting Chicken",
|
||||
"1 lb.",
|
||||
30.3,
|
||||
{1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}},
|
||||
{"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}},
|
||||
{"Salmon, Pink (can)",
|
||||
"16 oz.",
|
||||
13,
|
||||
{5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}},
|
||||
{"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}},
|
||||
{"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}},
|
||||
{"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}},
|
||||
{"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}},
|
||||
{"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}},
|
||||
{"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}},
|
||||
{"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}},
|
||||
{"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}},
|
||||
{"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}},
|
||||
{"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}},
|
||||
{"Potatoes",
|
||||
"15 lb.",
|
||||
34,
|
||||
{14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}},
|
||||
{"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}},
|
||||
{"Sweet Potatoes",
|
||||
"1 lb.",
|
||||
5.1,
|
||||
{9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}},
|
||||
{"Peaches (can)",
|
||||
"No. 2 1/2",
|
||||
16.8,
|
||||
{3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}},
|
||||
{"Pears (can)",
|
||||
"No. 2 1/2",
|
||||
20.4,
|
||||
{3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}},
|
||||
{"Pineapple (can)",
|
||||
"No. 2 1/2",
|
||||
21.3,
|
||||
{2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}},
|
||||
{"Asparagus (can)",
|
||||
"No. 2",
|
||||
27.7,
|
||||
{0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}},
|
||||
{"Green Beans (can)",
|
||||
"No. 2",
|
||||
10,
|
||||
{1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}},
|
||||
{"Pork and Beans (can)",
|
||||
"16 oz.",
|
||||
7.1,
|
||||
{7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}},
|
||||
{"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}},
|
||||
{"Peas (can)",
|
||||
"No. 2",
|
||||
13.8,
|
||||
{2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}},
|
||||
{"Tomatoes (can)",
|
||||
"No. 2",
|
||||
8.6,
|
||||
{1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}},
|
||||
{"Tomato Soup (can)",
|
||||
"10 1/2 oz.",
|
||||
7.6,
|
||||
{1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}},
|
||||
{"Peaches, Dried",
|
||||
"1 lb.",
|
||||
15.7,
|
||||
{8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}},
|
||||
{"Prunes, Dried",
|
||||
"1 lb.",
|
||||
9,
|
||||
{12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}},
|
||||
{"Raisins, Dried",
|
||||
"15 oz.",
|
||||
9.4,
|
||||
{13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}},
|
||||
{"Peas, Dried",
|
||||
"1 lb.",
|
||||
7.9,
|
||||
{20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}},
|
||||
{"Lima Beans, Dried",
|
||||
"1 lb.",
|
||||
8.9,
|
||||
{17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}},
|
||||
{"Navy Beans, Dried",
|
||||
"1 lb.",
|
||||
5.9,
|
||||
{26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}},
|
||||
{"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}},
|
||||
{"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}},
|
||||
{"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}},
|
||||
{"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}},
|
||||
{"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}},
|
||||
{"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}},
|
||||
{"Strawberry Preserves",
|
||||
"1 lb.",
|
||||
20.5,
|
||||
{6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};
|
||||
|
||||
// Instantiate the solver
|
||||
MPSolver solver("StiglerDietExample", MPSolver::GLOP_LINEAR_PROGRAMMING);
|
||||
@@ -233,7 +290,7 @@ void RunStiglerDietExample() {
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds";
|
||||
LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations";
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
// No attempt is made to force integrality.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring> // strlen
|
||||
#include <cstring> // strlen
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -80,159 +80,167 @@ struct Instance {
|
||||
const char *grid;
|
||||
};
|
||||
|
||||
Instance kInstances[] = {
|
||||
{ 4, 22, 6, "..@@@@@..............."
|
||||
"..@@@@@@........@@@..."
|
||||
".....@@@@@......@@@..."
|
||||
".......@@@@@@@@@@@@..."
|
||||
".........@@@@@........"
|
||||
".........@@@@@........" },
|
||||
{ 3, 13, 10, "............."
|
||||
"............."
|
||||
"............."
|
||||
"...@@@@......"
|
||||
"...@@@@......"
|
||||
"...@@@@......"
|
||||
".......@@@..."
|
||||
".......@@@..."
|
||||
".......@@@..."
|
||||
"............." },
|
||||
{ 4, 13, 9, "............."
|
||||
"..@.@.@......"
|
||||
"...@.@.@....."
|
||||
"..@.@.@......"
|
||||
"..@.@.@......"
|
||||
"...@.@.@....."
|
||||
"....@.@......"
|
||||
"..........@@@"
|
||||
"..........@@@" },
|
||||
{ 4, 13, 9, ".........@..."
|
||||
".........@..."
|
||||
"@@@@@@@@@@..."
|
||||
"..@......@..."
|
||||
"..@......@..."
|
||||
"..@......@..."
|
||||
"..@@@@@@@@@@@"
|
||||
"..@.........."
|
||||
"..@.........." },
|
||||
{ 7, 25, 14, "........................."
|
||||
"..@@@@@@@@@@@@@@@@@@@@..."
|
||||
"..@@@@@@@@@@@@@@@@@@@@..."
|
||||
"..@@.................@..."
|
||||
"..@@.................@..."
|
||||
"..@@.......@@@.......@.@."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@...@@@@@@@@@@@@@@@..."
|
||||
"..@@...@@@@@@@@@@@@@@@..."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@.................@..."
|
||||
"..@@.................@..."
|
||||
"........................." },
|
||||
{ 6, 25, 16, "........................."
|
||||
"......@@@@@@@@@@@@@......"
|
||||
"........................."
|
||||
".....@..........@........"
|
||||
".....@..........@........"
|
||||
".....@......@............"
|
||||
".....@......@.@@@@@@@...."
|
||||
".....@......@............"
|
||||
".....@......@.@@@@@@@...."
|
||||
".....@......@............"
|
||||
"....@@@@....@............"
|
||||
"....@@@@....@............"
|
||||
"..@@@@@@....@............"
|
||||
"..@@@.......@............"
|
||||
"..@@@...................."
|
||||
"..@@@@@@@@@@@@@@@@@@@@@@@" },
|
||||
{ 5, 40, 18, "........................................"
|
||||
"........................................"
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@.........@@@@@@@@@@............"
|
||||
"...@@@@@@.........@@@@@@@@@@............"
|
||||
"..................@@@@@@@@@@............"
|
||||
"..................@@@@@@@@@@............"
|
||||
".............@@@@@@@@@@@@@@@............"
|
||||
".............@@@@@@@@@@@@@@@............"
|
||||
"........@@@@@@@@@@@@...................."
|
||||
"........@@@@@@@@@@@@...................."
|
||||
"........@@@@@@.........................."
|
||||
"........@@@@@@.........................."
|
||||
"........................................"
|
||||
"........................................"
|
||||
"........................................" },
|
||||
{ 8, 40, 18, "........................................"
|
||||
"..@@.@.@.@.............................."
|
||||
"..@@.@.@.@...............@.............."
|
||||
"..@@.@.@.@............@................."
|
||||
"..@@.@.@.@.............................."
|
||||
"..@@.@.@.@.................@............"
|
||||
"..@@.@..................@..............."
|
||||
"..@@.@.................................."
|
||||
"..@@.@.................................."
|
||||
"..@@.@................@@@@.............."
|
||||
"..@@.@..............@@@@@@@@............"
|
||||
"..@@.@.................................."
|
||||
"..@@.@..............@@@@@@@@............"
|
||||
"..@@.@.................................."
|
||||
"..@@.@................@@@@.............."
|
||||
"..@@.@.................................."
|
||||
"..@@.@.................................."
|
||||
"........................................" },
|
||||
{ 10, 40, 19, "@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@...........@@@@@@@@@@@............."
|
||||
"@@@@@...........@@@@@@@@@@@............."
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"...............@@@@@@@@@@@@@@..........."
|
||||
"...............@@@@@@@@@@@@@@..........."
|
||||
".......@@@@@@@@@@@@@@@@@@@@@@..........."
|
||||
".......@@@@@@@@@........................"
|
||||
"........................................"
|
||||
"........................................"
|
||||
"........................................" },
|
||||
{ 10, 40, 25, "...................@...................."
|
||||
"...............@@@@@@@@@................"
|
||||
"............@@@.........@@@............."
|
||||
"...........@...............@............"
|
||||
"..........@.................@..........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
".........@.....@@......@@....@.........."
|
||||
"........@.....@@@@....@@@@....@........."
|
||||
"........@.....................@........."
|
||||
"........@.....................@........."
|
||||
"........@..........@@.........@........."
|
||||
".......@@..........@@.........@@........"
|
||||
"........@.....................@........."
|
||||
"........@.....................@........."
|
||||
"........@......@@@@@@@@@......@........."
|
||||
"........@......@@@@@@@@@......@........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
"..........@.................@..........."
|
||||
"...........@...............@............"
|
||||
"............@@@.........@@@............."
|
||||
"...............@@@@@@@@@................"
|
||||
"...................@...................." }
|
||||
};
|
||||
Instance kInstances[] = {{4, 22, 6,
|
||||
"..@@@@@..............."
|
||||
"..@@@@@@........@@@..."
|
||||
".....@@@@@......@@@..."
|
||||
".......@@@@@@@@@@@@..."
|
||||
".........@@@@@........"
|
||||
".........@@@@@........"},
|
||||
{3, 13, 10,
|
||||
"............."
|
||||
"............."
|
||||
"............."
|
||||
"...@@@@......"
|
||||
"...@@@@......"
|
||||
"...@@@@......"
|
||||
".......@@@..."
|
||||
".......@@@..."
|
||||
".......@@@..."
|
||||
"............."},
|
||||
{4, 13, 9,
|
||||
"............."
|
||||
"..@.@.@......"
|
||||
"...@.@.@....."
|
||||
"..@.@.@......"
|
||||
"..@.@.@......"
|
||||
"...@.@.@....."
|
||||
"....@.@......"
|
||||
"..........@@@"
|
||||
"..........@@@"},
|
||||
{4, 13, 9,
|
||||
".........@..."
|
||||
".........@..."
|
||||
"@@@@@@@@@@..."
|
||||
"..@......@..."
|
||||
"..@......@..."
|
||||
"..@......@..."
|
||||
"..@@@@@@@@@@@"
|
||||
"..@.........."
|
||||
"..@.........."},
|
||||
{7, 25, 14,
|
||||
"........................."
|
||||
"..@@@@@@@@@@@@@@@@@@@@..."
|
||||
"..@@@@@@@@@@@@@@@@@@@@..."
|
||||
"..@@.................@..."
|
||||
"..@@.................@..."
|
||||
"..@@.......@@@.......@.@."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@...@@@@@@@@@@@@@@@..."
|
||||
"..@@...@@@@@@@@@@@@@@@..."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@.......@@@.......@..."
|
||||
"..@@.................@..."
|
||||
"..@@.................@..."
|
||||
"........................."},
|
||||
{6, 25, 16,
|
||||
"........................."
|
||||
"......@@@@@@@@@@@@@......"
|
||||
"........................."
|
||||
".....@..........@........"
|
||||
".....@..........@........"
|
||||
".....@......@............"
|
||||
".....@......@.@@@@@@@...."
|
||||
".....@......@............"
|
||||
".....@......@.@@@@@@@...."
|
||||
".....@......@............"
|
||||
"....@@@@....@............"
|
||||
"....@@@@....@............"
|
||||
"..@@@@@@....@............"
|
||||
"..@@@.......@............"
|
||||
"..@@@...................."
|
||||
"..@@@@@@@@@@@@@@@@@@@@@@@"},
|
||||
{5, 40, 18,
|
||||
"........................................"
|
||||
"........................................"
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@..............................."
|
||||
"...@@@@@@.........@@@@@@@@@@............"
|
||||
"...@@@@@@.........@@@@@@@@@@............"
|
||||
"..................@@@@@@@@@@............"
|
||||
"..................@@@@@@@@@@............"
|
||||
".............@@@@@@@@@@@@@@@............"
|
||||
".............@@@@@@@@@@@@@@@............"
|
||||
"........@@@@@@@@@@@@...................."
|
||||
"........@@@@@@@@@@@@...................."
|
||||
"........@@@@@@.........................."
|
||||
"........@@@@@@.........................."
|
||||
"........................................"
|
||||
"........................................"
|
||||
"........................................"},
|
||||
{8, 40, 18,
|
||||
"........................................"
|
||||
"..@@.@.@.@.............................."
|
||||
"..@@.@.@.@...............@.............."
|
||||
"..@@.@.@.@............@................."
|
||||
"..@@.@.@.@.............................."
|
||||
"..@@.@.@.@.................@............"
|
||||
"..@@.@..................@..............."
|
||||
"..@@.@.................................."
|
||||
"..@@.@.................................."
|
||||
"..@@.@................@@@@.............."
|
||||
"..@@.@..............@@@@@@@@............"
|
||||
"..@@.@.................................."
|
||||
"..@@.@..............@@@@@@@@............"
|
||||
"..@@.@.................................."
|
||||
"..@@.@................@@@@.............."
|
||||
"..@@.@.................................."
|
||||
"..@@.@.................................."
|
||||
"........................................"},
|
||||
{10, 40, 19,
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@..................................."
|
||||
"@@@@@...........@@@@@@@@@@@............."
|
||||
"@@@@@...........@@@@@@@@@@@............."
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"....................@@@@................"
|
||||
"...............@@@@@@@@@@@@@@..........."
|
||||
"...............@@@@@@@@@@@@@@..........."
|
||||
".......@@@@@@@@@@@@@@@@@@@@@@..........."
|
||||
".......@@@@@@@@@........................"
|
||||
"........................................"
|
||||
"........................................"
|
||||
"........................................"},
|
||||
{10, 40, 25,
|
||||
"...................@...................."
|
||||
"...............@@@@@@@@@................"
|
||||
"............@@@.........@@@............."
|
||||
"...........@...............@............"
|
||||
"..........@.................@..........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
".........@.....@@......@@....@.........."
|
||||
"........@.....@@@@....@@@@....@........."
|
||||
"........@.....................@........."
|
||||
"........@.....................@........."
|
||||
"........@..........@@.........@........."
|
||||
".......@@..........@@.........@@........"
|
||||
"........@.....................@........."
|
||||
"........@.....................@........."
|
||||
"........@......@@@@@@@@@......@........."
|
||||
"........@......@@@@@@@@@......@........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
".........@...................@.........."
|
||||
"..........@.................@..........."
|
||||
"...........@...............@............"
|
||||
"............@@@.........@@@............."
|
||||
"...............@@@@@@@@@................"
|
||||
"...................@...................."}};
|
||||
|
||||
const int kInstanceCount = 10;
|
||||
|
||||
// ---------- Box ---------
|
||||
|
||||
class Box {
|
||||
public:
|
||||
public:
|
||||
static const int kAreaCost = 1;
|
||||
static const int kFixedCost = 10;
|
||||
|
||||
@@ -251,12 +259,9 @@ public:
|
||||
// Lexicographic order
|
||||
int Compare(const Box &box) const {
|
||||
int c;
|
||||
if ((c = (x_min() - box.x_min())) != 0)
|
||||
return c;
|
||||
if ((c = (x_max() - box.x_max())) != 0)
|
||||
return c;
|
||||
if ((c = (y_min() - box.y_min())) != 0)
|
||||
return c;
|
||||
if ((c = (x_min() - box.x_min())) != 0) return c;
|
||||
if ((c = (x_max() - box.x_max())) != 0) return c;
|
||||
if ((c = (y_min() - box.y_min())) != 0) return c;
|
||||
return y_max() - box.y_max();
|
||||
}
|
||||
|
||||
@@ -274,7 +279,7 @@ public:
|
||||
y_max(), Cost());
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
int x_min_;
|
||||
int x_max_;
|
||||
int y_min_;
|
||||
@@ -290,13 +295,16 @@ struct BoxLessThan {
|
||||
// ---------- Covering Problem ---------
|
||||
|
||||
class CoveringProblem {
|
||||
public:
|
||||
public:
|
||||
// Grid is a row-major string of length width*height with '@' for an
|
||||
// occupied cell (strawberry) and '.' for an empty cell. Solver is
|
||||
// not owned.
|
||||
CoveringProblem(MPSolver *const solver, const Instance &instance)
|
||||
: solver_(solver), max_boxes_(instance.max_boxes), width_(instance.width),
|
||||
height_(instance.height), grid_(instance.grid) {}
|
||||
: solver_(solver),
|
||||
max_boxes_(instance.max_boxes),
|
||||
width_(instance.width),
|
||||
height_(instance.height),
|
||||
grid_(instance.grid) {}
|
||||
|
||||
// Constructs initial variables and constraints. Initial column
|
||||
// (box) covers entire grid, ensuring feasibility.
|
||||
@@ -308,14 +316,13 @@ public:
|
||||
}
|
||||
for (int i = 0; i < size; ++i) {
|
||||
char c = grid_[i];
|
||||
if ((c != '@') && (c != '.'))
|
||||
return false;
|
||||
if ((c != '@') && (c != '.')) return false;
|
||||
}
|
||||
|
||||
AddCellConstraints(); // sum for every cell is <=1 or =1
|
||||
AddMaxBoxesConstraint(); // sum of box variables is <= max_boxes()
|
||||
AddCellConstraints(); // sum for every cell is <=1 or =1
|
||||
AddMaxBoxesConstraint(); // sum of box variables is <= max_boxes()
|
||||
if (!absl::GetFlag(FLAGS_colgen_complete)) {
|
||||
AddBox(Box(0, width() - 1, 0, height() - 1)); // grid-covering box
|
||||
AddBox(Box(0, width() - 1, 0, height() - 1)); // grid-covering box
|
||||
} else {
|
||||
// Naive alternative to column generation - generate all boxes;
|
||||
// works fine for smaller problems, too slow for big.
|
||||
@@ -376,7 +383,7 @@ public:
|
||||
for (int x_min = 0; x_min < width(); ++x_min) {
|
||||
for (int x_max = x_min; x_max < width(); ++x_max) {
|
||||
Box box(x_min, x_max, y_min, y_max);
|
||||
const double cell_coverage_dual = // inclusion-exclusion
|
||||
const double cell_coverage_dual = // inclusion-exclusion
|
||||
+zero_access(upper_left_sums, x_max, y_max) -
|
||||
zero_access(upper_left_sums, x_max, y_min - 1) -
|
||||
zero_access(upper_left_sums, x_min - 1, y_max) +
|
||||
@@ -455,7 +462,7 @@ public:
|
||||
std::unique_ptr<char[]> display(new char[(width_ + 1) * height_ + 1]);
|
||||
for (int y = 0; y < height_; ++y) {
|
||||
memcpy(display.get() + y * (width_ + 1), grid_ + width_ * y,
|
||||
width_); // Copy the original line.
|
||||
width_); // Copy the original line.
|
||||
display[y * (width_ + 1) + width_] = '\n';
|
||||
}
|
||||
display[height_ * (width_ + 1)] = '\0';
|
||||
@@ -480,7 +487,7 @@ public:
|
||||
return output;
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
int index(int x, int y) const { return width_ * y + x; }
|
||||
MPConstraint *cell(int x, int y) { return cells_[index(x, y)]; }
|
||||
const MPConstraint *cell(int x, int y) const { return cells_[index(x, y)]; }
|
||||
@@ -524,7 +531,7 @@ protected:
|
||||
}
|
||||
|
||||
typedef std::map<Box, MPVariable *, BoxLessThan> BoxTable;
|
||||
MPSolver *const solver_; // not owned
|
||||
MPSolver *const solver_; // not owned
|
||||
const int max_boxes_;
|
||||
const int width_;
|
||||
const int height_;
|
||||
@@ -587,7 +594,7 @@ void SolveInstance(const Instance &instance,
|
||||
LOG(INFO) << step_number << " columns added";
|
||||
LOG(INFO) << "Final coverage: " << problem.PrintCovering();
|
||||
}
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string usage = "column_generation\n";
|
||||
@@ -604,13 +611,13 @@ int main(int argc, char **argv) {
|
||||
solver_type = operations_research::MPSolver::CLP_LINEAR_PROGRAMMING;
|
||||
found = true;
|
||||
}
|
||||
#endif // USE_CLP
|
||||
#endif // USE_CLP
|
||||
#if defined(USE_GLOP)
|
||||
if (absl::GetFlag(FLAGS_colgen_solver) == "glop") {
|
||||
solver_type = operations_research::MPSolver::GLOP_LINEAR_PROGRAMMING;
|
||||
found = true;
|
||||
}
|
||||
#endif // USE_GLOP
|
||||
#endif // USE_GLOP
|
||||
#if defined(USE_XPRESS)
|
||||
if (absl::GetFlag(FLAGS_colgen_solver) == "xpress") {
|
||||
solver_type = operations_research::MPSolver::XPRESS_LINEAR_PROGRAMMING;
|
||||
|
||||
@@ -39,19 +39,14 @@ DEFINE_double(fix_cost, 5000, "Cost of opening a facility.");
|
||||
namespace operations_research {
|
||||
|
||||
typedef struct {
|
||||
double x { 0 }
|
||||
;
|
||||
double y { 0 }
|
||||
;
|
||||
double x{0};
|
||||
double y{0};
|
||||
} Location;
|
||||
|
||||
typedef struct {
|
||||
int f { -1 }
|
||||
;
|
||||
int c { -1 }
|
||||
;
|
||||
MPVariable *x { nullptr }
|
||||
;
|
||||
int f{-1};
|
||||
int c{-1};
|
||||
MPVariable *x{nullptr};
|
||||
} Edge;
|
||||
|
||||
static double Distance(const Location &src, const Location &dst) {
|
||||
@@ -100,8 +95,7 @@ static void UncapacitatedFacilityLocation(
|
||||
objective->SetMinimization();
|
||||
|
||||
// Add binary facilities variables
|
||||
std::vector<MPVariable *> xf {}
|
||||
;
|
||||
std::vector<MPVariable *> xf{};
|
||||
for (int f = 0; f < facilities; ++f) {
|
||||
snprintf(name_buffer, kStrLen, "x[%d](%g,%g)", f, facility[f].x,
|
||||
facility[f].y);
|
||||
@@ -119,10 +113,8 @@ static void UncapacitatedFacilityLocation(
|
||||
solver.MakeRowConstraint(/* lb */ 1, /* ub */ infinity, name_buffer);
|
||||
for (int f = 0; f < facilities; ++f) {
|
||||
double distance = Distance(facility[f], client[c]);
|
||||
if (distance > kMaxDistance)
|
||||
continue;
|
||||
Edge edge {}
|
||||
;
|
||||
if (distance > kMaxDistance) continue;
|
||||
Edge edge{};
|
||||
snprintf(name_buffer, kStrLen, "x[%d,%d]", f, c);
|
||||
edge.x = solver.MakeNumVar(/* lb */ 0, /*ub */ 1, name_buffer);
|
||||
edge.f = f;
|
||||
@@ -138,13 +130,12 @@ static void UncapacitatedFacilityLocation(
|
||||
edge_constraint->SetCoefficient(edge.x, -1);
|
||||
edge_constraint->SetCoefficient(xf[f], 1);
|
||||
}
|
||||
} // End adding all edge variables
|
||||
} // End adding all edge variables
|
||||
LOG(INFO) << "Number of variables = " << solver.NumVariables();
|
||||
LOG(INFO) << "Number of constraints = " << solver.NumConstraints();
|
||||
// display on screen LP if small enough
|
||||
if (clients <= 10 && facilities <= 10) {
|
||||
std::string lp_string {}
|
||||
;
|
||||
std::string lp_string{};
|
||||
solver.ExportModelAsLpFormat(/* obfuscate */ false, &lp_string);
|
||||
std::cout << "LP-Model:\n" << lp_string << std::endl;
|
||||
}
|
||||
@@ -161,14 +152,12 @@ static void UncapacitatedFacilityLocation(
|
||||
if (absl::GetFlag(FLAGS_verbose)) {
|
||||
std::vector<std::vector<int> > solution(facilities);
|
||||
for (auto &edge : edges) {
|
||||
if (edge.x->solution_value() < 0.5)
|
||||
continue;
|
||||
if (edge.x->solution_value() < 0.5) continue;
|
||||
solution[edge.f].push_back(edge.c);
|
||||
}
|
||||
std::cout << "\tSolution:\n";
|
||||
for (int f = 0; f < facilities; ++f) {
|
||||
if (solution[f].size() < 1)
|
||||
continue;
|
||||
if (solution[f].size() < 1) continue;
|
||||
assert(xf[f]->solution_value() > 0.5);
|
||||
snprintf(name_buffer, kStrLen, "\t Facility[%d](%g,%g):", f,
|
||||
facility[f].x, facility[f].y);
|
||||
@@ -217,18 +206,18 @@ void RunAllExamples(int32 facilities, int32 clients, double fix_cost) {
|
||||
LOG(INFO) << "---- Integer programming example with Gurobi ----";
|
||||
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
|
||||
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING);
|
||||
#endif // USE_GUROBI
|
||||
#endif // USE_GUROBI
|
||||
#if defined(USE_CPLEX)
|
||||
LOG(INFO) << "---- Integer programming example with CPLEX ----";
|
||||
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
|
||||
MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING);
|
||||
#endif // USE_CPLEX
|
||||
#endif // USE_CPLEX
|
||||
LOG(INFO) << "---- Integer programming example with CP-SAT ----";
|
||||
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
|
||||
MPSolver::SAT_INTEGER_PROGRAMMING);
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
@@ -24,15 +24,10 @@ void Solve() {
|
||||
const IntVar end_p2 = cp_model.NewIntVar(Domain(500, 1000));
|
||||
const IntervalVar p2 = cp_model.NewIntervalVar(start_p2, duration_p2, end_p2);
|
||||
|
||||
cp_model.AddEquality(LinearExpr::Sum({
|
||||
duration_p1, duration_p2
|
||||
}),
|
||||
360);
|
||||
cp_model.AddEquality(LinearExpr::Sum({duration_p1, duration_p2}), 360);
|
||||
cp_model.AddLessOrEqual(end_p1, start_p2);
|
||||
|
||||
cp_model.AddNoOverlap({
|
||||
ins, p1, p2
|
||||
});
|
||||
cp_model.AddNoOverlap({ins, p1, p2});
|
||||
|
||||
Model model;
|
||||
|
||||
@@ -47,7 +42,7 @@ void Solve() {
|
||||
|
||||
const int kSolutionLimit = 100;
|
||||
int num_solutions = 0;
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) {
|
||||
LOG(INFO) << "Solution " << num_solutions;
|
||||
LOG(INFO) << " start_p1 = " << SolutionIntegerValue(r, start_p1);
|
||||
LOG(INFO) << " duration_p1 = " << SolutionIntegerValue(r, duration_p1);
|
||||
@@ -65,8 +60,8 @@ void Solve() {
|
||||
LOG(INFO) << "Number of solutions found: " << num_solutions;
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main() {
|
||||
operations_research::sat::Solve();
|
||||
|
||||
@@ -63,8 +63,7 @@ void Solve(const std::vector<int64> &durations,
|
||||
int next_task = -1;
|
||||
int64 next_cost;
|
||||
for (int j = 0; j < num_tasks; ++j) {
|
||||
if (is_taken[j])
|
||||
continue;
|
||||
if (is_taken[j]) continue;
|
||||
const int64 cost = weights[j] * std::max<int64>(0, end - due_dates[j]);
|
||||
if (next_task == -1 || cost < next_cost) {
|
||||
next_task = j;
|
||||
@@ -143,8 +142,7 @@ void Solve(const std::vector<int64> &durations,
|
||||
int num_added_precedences = 0;
|
||||
for (int i = 0; i < num_tasks; ++i) {
|
||||
for (int j = 0; j < num_tasks; ++j) {
|
||||
if (i == j)
|
||||
continue;
|
||||
if (i == j) continue;
|
||||
if (due_dates[i] <= due_dates[j] && durations[i] <= durations[j] &&
|
||||
weights[i] >= weights[j]) {
|
||||
// If two jobs have exactly the same specs, we don't add both
|
||||
@@ -168,7 +166,7 @@ void Solve(const std::vector<int64> &durations,
|
||||
// lower bound for the objective and the tardiness variables.
|
||||
Model model;
|
||||
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse &r) {
|
||||
// Note that we compute the "real" cost here and do not use the tardiness
|
||||
// variables. This is because in the core based approach, the tardiness
|
||||
// variable might be fixed before the end date, and we just have a >=
|
||||
@@ -250,8 +248,8 @@ void ParseAndSolve() {
|
||||
Solve(durations, due_dates, weights);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::SetFlag(&FLAGS_logtostderr, true);
|
||||
|
||||
Reference in New Issue
Block a user