diff --git a/examples/cpp/constraint_programming_cp.cc b/examples/cpp/constraint_programming_cp.cc index 324acff1f3..0e178ba1a0 100644 --- a/examples/cpp/constraint_programming_cp.cc +++ b/examples/cpp/constraint_programming_cp.cc @@ -28,13 +28,13 @@ void RunConstraintProgrammingExample() { IntVar *const z = solver.MakeIntVar(0, numVals - 1, "z"); // Define constraints. - std::vector xyvars = { x, y }; + std::vector xyvars = {x, y}; solver.AddConstraint(solver.MakeAllDifferent(xyvars)); LOG(INFO) << "Number of constraints: " << solver.constraints(); // Create decision builder to search for solutions. - std::vector allvars = { x, y, z }; + std::vector 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]); diff --git a/examples/cpp/costas_array_sat.cc b/examples/cpp/costas_array_sat.cc index e2dc85dcd6..8c8d13d48c 100644 --- a/examples/cpp/costas_array_sat.cc +++ b/examples/cpp/costas_array_sat.cc @@ -93,8 +93,8 @@ void CostasHard(const int dim) { std::vector 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); diff --git a/examples/cpp/cvrp_disjoint_tw.cc b/examples/cpp/cvrp_disjoint_tw.cc index e69079f687..a330ef57ec 100644 --- a/examples/cpp/cvrp_disjoint_tw.cc +++ b/examples/cpp/cvrp_disjoint_tw.cc @@ -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. diff --git a/examples/cpp/cvrptw.cc b/examples/cpp/cvrptw.cc index b5fe03435d..a75afb3caf 100644 --- a/examples/cpp/cvrptw.cc +++ b/examples/cpp/cvrptw.cc @@ -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. diff --git a/examples/cpp/cvrptw_lib.h b/examples/cpp/cvrptw_lib.h index 35e039fe06..7ac0e6b6c1 100644 --- a/examples/cpp/cvrptw_lib.h +++ b/examples/cpp/cvrptw_lib.h @@ -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 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 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_ diff --git a/examples/cpp/cvrptw_with_breaks.cc b/examples/cpp/cvrptw_with_breaks.cc index e3c4248335..c041fc9cd8 100644 --- a/examples/cpp/cvrptw_with_breaks.cc +++ b/examples/cpp/cvrptw_with_breaks.cc @@ -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 > 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) { diff --git a/examples/cpp/cvrptw_with_refueling.cc b/examples/cpp/cvrptw_with_refueling.cc index 97021f346a..682d933af4 100644 --- a/examples/cpp/cvrptw_with_refueling.cc +++ b/examples/cpp/cvrptw_with_refueling.cc @@ -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 { diff --git a/examples/cpp/cvrptw_with_resources.cc b/examples/cpp/cvrptw_with_resources.cc index 09b378c9dd..debe54952c 100644 --- a/examples/cpp/cvrptw_with_resources.cc +++ b/examples/cpp/cvrptw_with_resources.cc @@ -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 { diff --git a/examples/cpp/cvrptw_with_stop_times_and_resources.cc b/examples/cpp/cvrptw_with_stop_times_and_resources.cc index af767b4be7..22e249c553 100644 --- a/examples/cpp/cvrptw_with_stop_times_and_resources.cc +++ b/examples/cpp/cvrptw_with_stop_times_and_resources.cc @@ -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:"; diff --git a/examples/cpp/dimacs_assignment.cc b/examples/cpp/dimacs_assignment.cc index e0356205d6..d9d3dbc579 100644 --- a/examples/cpp/dimacs_assignment.cc +++ b/examples/cpp/dimacs_assignment.cc @@ -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 "; diff --git a/examples/cpp/dobble_ls.cc b/examples/cpp/dobble_ls.cc index 6d3d831850..4f06179a14 100644 --- a/examples/cpp/dobble_ls.cc +++ b/examples/cpp/dobble_ls.cc @@ -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 &card1_symbol_vars, const std::vector &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 card1_symbol_vars_; std::vector 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 &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 &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 &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(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 &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(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 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); diff --git a/examples/cpp/fap_model_printer.h b/examples/cpp/fap_model_printer.h index e8b1b40f9e..444ecdc62a 100644 --- a/examples/cpp/fap_model_printer.h +++ b/examples/cpp/fap_model_printer.h @@ -30,7 +30,7 @@ namespace operations_research { // Prints the instance of the Frequency Assignment Problem. class FapModelPrinter { -public: + public: FapModelPrinter(const std::map &variables, const std::vector &constraints, const std::string &objective, const std::vector &values); @@ -41,7 +41,7 @@ public: void PrintFapConstraints(); void PrintFapValues(); -private: + private: const std::map variables_; const std::vector constraints_; const std::string objective_; @@ -53,7 +53,9 @@ FapModelPrinter::FapModelPrinter(const std::map &variables, const std::vector &constraints, const std::string &objective, const std::vector &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_ diff --git a/examples/cpp/fap_parser.h b/examples/cpp/fap_parser.h index fc36776acc..299f66e013 100644 --- a/examples/cpp/fap_parser.h +++ b/examples/cpp/fap_parser.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 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 &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 &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_ diff --git a/examples/cpp/fap_utilities.h b/examples/cpp/fap_utilities.h index 5fc343592d..3b9b50764e 100644 --- a/examples/cpp/fap_utilities.h +++ b/examples/cpp/fap_utilities.h @@ -69,10 +69,10 @@ void PrintResultsSoft(SolutionCollector *const collector, const std::map &index_from_key, const std::vector &key_from_index); -bool -CheckConstraintSatisfaction(const std::vector &data_constraints, - const std::vector &variables, - const std::map &index_from_key) { +bool CheckConstraintSatisfaction( + const std::vector &data_constraints, + const std::vector &variables, + const std::map &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_ diff --git a/examples/cpp/flow_api.cc b/examples/cpp/flow_api.cc index 8b4f097819..c1d3cfe4a0 100644 --- a/examples/cpp/flow_api.cc +++ b/examples/cpp/flow_api.cc @@ -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); diff --git a/examples/cpp/frequency_assignment_problem.cc b/examples/cpp/frequency_assignment_problem.cc index 5c6000a406..7046cd38ac 100644 --- a/examples/cpp/frequency_assignment_problem.cc +++ b/examples/cpp/frequency_assignment_problem.cc @@ -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 &data_variables, const std::vector &data_constraints, const std::vector &variables, const std::vector &violated_constraints, const std::map &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 &data_variables, absl::flat_hash_map > 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 &data_constraints, // Penalize the modification of the initial position of soft variable of // the instance. -void -PenalizeVariablesViolation(const std::map &soft_variables, - const std::map &index_from_key, - const std::vector &variables, - std::vector *cost, Solver *solver) { +void PenalizeVariablesViolation( + const std::map &soft_variables, + const std::map &index_from_key, + const std::vector &variables, std::vector *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 &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 &variables, } } -} // namespace operations_research +} // namespace operations_research int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); diff --git a/examples/cpp/golomb_sat.cc b/examples/cpp/golomb_sat.cc index 43b6ac4fdc..07a558e96d 100644 --- a/examples/cpp/golomb_sat.cc +++ b/examples/cpp/golomb_sat.cc @@ -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); diff --git a/examples/cpp/integer_programming.cc b/examples/cpp/integer_programming.cc index c61acfb6ea..e8edffa81a 100644 --- a/examples/cpp/integer_programming.cc +++ b/examples/cpp/integer_programming.cc @@ -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]); diff --git a/examples/cpp/jobshop_sat.cc b/examples/cpp/jobshop_sat.cc index d4da80b288..6684234b12 100644 --- a/examples/cpp/jobshop_sat.cc +++ b/examples/cpp/jobshop_sat.cc @@ -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); diff --git a/examples/cpp/linear_assignment_api.cc b/examples/cpp/linear_assignment_api.cc index 920d4153ab..6ff5c8aa8d 100644 --- a/examples/cpp/linear_assignment_api.cc +++ b/examples/cpp/linear_assignment_api.cc @@ -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 > matrice({ - { 8, 7, 9, 9 } - , { 5, 2, 7, 8 } - , { 6, 1, 4, 9 } - , { 2, 3, 2, 6 } - }); + std::vector > 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 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); diff --git a/examples/cpp/linear_programming.cc b/examples/cpp/linear_programming.cc index 1275884a61..22968f56a8 100644 --- a/examples/cpp/linear_programming.cc +++ b/examples/cpp/linear_programming.cc @@ -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]); diff --git a/examples/cpp/linear_solver_protocol_buffers.cc b/examples/cpp/linear_solver_protocol_buffers.cc index 364a7b09e5..a176820d8f 100644 --- a/examples/cpp/linear_solver_protocol_buffers.cc +++ b/examples/cpp/linear_solver_protocol_buffers.cc @@ -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); diff --git a/examples/cpp/magic_square_sat.cc b/examples/cpp/magic_square_sat.cc index 6682cc81e5..50c704bbd7 100644 --- a/examples/cpp/magic_square_sat.cc +++ b/examples/cpp/magic_square_sat.cc @@ -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); diff --git a/examples/cpp/max_flow.cc b/examples/cpp/max_flow.cc index 3491d18a73..10601d7066 100644 --- a/examples/cpp/max_flow.cc +++ b/examples/cpp/max_flow.cc @@ -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, 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]); diff --git a/examples/cpp/min_cost_flow.cc b/examples/cpp/min_cost_flow.cc index 294530b547..0aacff1d45 100644 --- a/examples/cpp/min_cost_flow.cc +++ b/examples/cpp/min_cost_flow.cc @@ -25,18 +25,16 @@ struct Arc { void SolveMinCostFlow() { // Define supply of each node. const std::vector > 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 // Initialization list is not working on std:tuple cf. N4387 // Arc are stored as {{begin_node, end_node}, capacity} - const std::vector 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 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]); diff --git a/examples/cpp/mps_driver.cc b/examples/cpp/mps_driver.cc index eecc12a1f4..d99854d8c4 100644 --- a/examples/cpp/mps_driver.cc +++ b/examples/cpp/mps_driver.cc @@ -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; diff --git a/examples/cpp/multi_knapsack_sat.cc b/examples/cpp/multi_knapsack_sat.cc index 3e52ad064f..adc6cb26ef 100644 --- a/examples/cpp/multi_knapsack_sat.cc +++ b/examples/cpp/multi_knapsack_sat.cc @@ -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 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); diff --git a/examples/cpp/network_routing_sat.cc b/examples/cpp/network_routing_sat.cc index b83547b7d2..c776293461 100644 --- a/examples/cpp/network_routing_sat.cc +++ b/examples/cpp/network_routing_sat.cc @@ -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 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 stopped(false); model.GetOrCreate()->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 > arcs_data_; @@ -667,8 +660,8 @@ private: std::vector > all_paths_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); diff --git a/examples/cpp/nqueens.cc b/examples/cpp/nqueens.cc index b7cbc24b37..cf2bb94997 100644 --- a/examples/cpp/nqueens.cc +++ b/examples/cpp/nqueens.cc @@ -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 &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 vars_; std::map indices_; @@ -80,7 +80,7 @@ private: // Symmetry vertical axis. class SX : public NQueenSymmetry { -public: + public: SX(Solver *const s, const std::vector &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 &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 &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 &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 &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 &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 &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(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); diff --git a/examples/cpp/opb_reader.h b/examples/cpp/opb_reader.h index 182b688a86..a267d23d6c 100644 --- a/examples/cpp/opb_reader.h +++ b/examples/cpp/opb_reader.h @@ -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_ diff --git a/examples/cpp/parse_dimacs_assignment.h b/examples/cpp/parse_dimacs_assignment.h index 2c3b024347..06995ab6d7 100644 --- a/examples/cpp/parse_dimacs_assignment.h +++ b/examples/cpp/parse_dimacs_assignment.h @@ -38,10 +38,12 @@ DEFINE_bool(assignment_optimize_layout, true, namespace operations_research { -template class LinearSumAssignment; +template +class LinearSumAssignment; -template class DimacsAssignmentParser { -public: +template +class DimacsAssignmentParser { + public: explicit DimacsAssignmentParser(const std::string &filename) : filename_(filename), graph_builder_(nullptr), assignment_(nullptr) {} @@ -61,7 +63,7 @@ public: LinearSumAssignment *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 -void -DimacsAssignmentParser::ParseProblemLine(const std::string &line) { +void DimacsAssignmentParser::ParseProblemLine( + const std::string &line) { static const char *kIncorrectProblemLine = "Incorrect assignment problem line."; static const char *kAssignmentProblemType = "asn"; @@ -172,33 +177,33 @@ void DimacsAssignmentParser::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::ParseOneLine(const std::string &line) { // free the underlying graph (which isn't owned by the // LinearAssignment instance). template -LinearSumAssignment * -DimacsAssignmentParser::Parse(std::string *error_message, - GraphType **graph_handle) { +LinearSumAssignment *DimacsAssignmentParser::Parse( + std::string *error_message, GraphType **graph_handle) { CHECK(error_message != nullptr); CHECK(graph_handle != nullptr); @@ -254,6 +258,6 @@ DimacsAssignmentParser::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_ diff --git a/examples/cpp/pdptw.cc b/examples/cpp/pdptw.cc index 5ae3483e0f..a4794b488b 100644 --- a/examples/cpp/pdptw.cc +++ b/examples/cpp/pdptw.cc @@ -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(&coords), - manager.IndexToNode(i), manager.IndexToNode(j)); - }); + return Travel(const_cast(&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); diff --git a/examples/cpp/print_dimacs_assignment.h b/examples/cpp/print_dimacs_assignment.h index 047dd2d54f..059be7772c 100644 --- a/examples/cpp/print_dimacs_assignment.h +++ b/examples/cpp/print_dimacs_assignment.h @@ -30,7 +30,8 @@ namespace operations_research { -template class LinearSumAssignment; +template +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_ diff --git a/examples/cpp/random_tsp.cc b/examples/cpp/random_tsp.cc index 79c4770124..d0aed9a172 100644 --- a/examples/cpp/random_tsp.cc +++ b/examples/cpp/random_tsp.cc @@ -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(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); diff --git a/examples/cpp/sat_cnf_reader.h b/examples/cpp/sat_cnf_reader.h index 81f4679cf2..cac40b7420 100644 --- a/examples/cpp/sat_cnf_reader.h +++ b/examples/cpp/sat_cnf_reader.h @@ -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 bool LoadInternal(const std::string &filename, Problem *problem) { positive_literal_to_weight_.clear(); @@ -221,10 +221,8 @@ private: template 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_ diff --git a/examples/cpp/sat_runner.cc b/examples/cpp/sat_runner.cc index 93d118348b..1d8a870537 100644 --- a/examples/cpp/sat_runner.cc +++ b/examples/cpp/sat_runner.cc @@ -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" diff --git a/examples/cpp/shift_minimization_sat.cc b/examples/cpp/shift_minimization_sat.cc index a006720f5b..1ef38b4e7c 100644 --- a/examples/cpp/shift_minimization_sat.cc +++ b/examples/cpp/shift_minimization_sat.cc @@ -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 &jobs() const { return jobs_; } const std::vector > &possible_jobs_per_worker() const { return possible_jobs_per_worker_; } - const std::vector > & - possible_assignments_per_job() const { + const std::vector > &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); diff --git a/examples/cpp/slitherlink_sat.cc b/examples/cpp/slitherlink_sat.cc index a31463371d..52ecfd9e5b 100644 --- a/examples/cpp/slitherlink_sat.cc +++ b/examples/cpp/slitherlink_sat.cc @@ -21,27 +21,28 @@ #include "ortools/sat/cp_model.h" #include "ortools/sat/model.h" -const std::vector > tiny = { { 3, 3, 1 } }; +const std::vector > tiny = {{3, 3, 1}}; const std::vector > 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 > 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 > 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 > &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 > &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 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 > &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 > &data) { LOG(INFO) << CpSolverResponseStats(response); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research int main() { std::cout << "Tiny problem" << std::endl; diff --git a/examples/cpp/solve.cc b/examples/cpp/solve.cc index 8ac78d2105..358ac4110c 100644 --- a/examples/cpp/solve.cc +++ b/examples/cpp/solve.cc @@ -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( - solver.ProblemType())).c_str()); + MPModelRequest::SolverType_Name( + static_cast(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(solve_status)).c_str()); + static_cast(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(); diff --git a/examples/cpp/sports_scheduling_sat.cc b/examples/cpp/sports_scheduling_sat.cc index 7c09364064..6adffeaf18 100644 --- a/examples/cpp/sports_scheduling_sat.cc +++ b/examples/cpp/sports_scheduling_sat.cc @@ -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 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 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 first_half; std::vector 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." diff --git a/examples/cpp/stigler_diet.cc b/examples/cpp/stigler_diet.cc index 88012dd60c..80f5707bd7 100644 --- a/examples/cpp/stigler_diet.cc +++ b/examples/cpp/stigler_diet.cc @@ -18,12 +18,15 @@ namespace operations_research { void RunStiglerDietExample() { // Nutrient minimums. std::vector > 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 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]); diff --git a/examples/cpp/strawberry_fields_with_column_generation.cc b/examples/cpp/strawberry_fields_with_column_generation.cc index aaa1cadc47..9c7f9e8da4 100644 --- a/examples/cpp/strawberry_fields_with_column_generation.cc +++ b/examples/cpp/strawberry_fields_with_column_generation.cc @@ -52,7 +52,7 @@ // No attempt is made to force integrality. #include -#include // strlen +#include // strlen #include #include #include @@ -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 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 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; diff --git a/examples/cpp/uncapacitated_facility_location.cc b/examples/cpp/uncapacitated_facility_location.cc index abcc37c0b3..5b29a35132 100644 --- a/examples/cpp/uncapacitated_facility_location.cc +++ b/examples/cpp/uncapacitated_facility_location.cc @@ -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 xf {} - ; + std::vector 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 > 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]); diff --git a/examples/cpp/variable_intervals_sat.cc b/examples/cpp/variable_intervals_sat.cc index e78153b17b..c58af91376 100644 --- a/examples/cpp/variable_intervals_sat.cc +++ b/examples/cpp/variable_intervals_sat.cc @@ -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(); diff --git a/examples/cpp/weighted_tardiness_sat.cc b/examples/cpp/weighted_tardiness_sat.cc index 1b15d0c62e..aff1c892f6 100644 --- a/examples/cpp/weighted_tardiness_sat.cc +++ b/examples/cpp/weighted_tardiness_sat.cc @@ -63,8 +63,7 @@ void Solve(const std::vector &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(0, end - due_dates[j]); if (next_task == -1 || cost < next_cost) { next_task = j; @@ -143,8 +142,7 @@ void Solve(const std::vector &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 &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); diff --git a/examples/data/roadef_challenge_2011/solution_checker/solution_checker.h b/examples/data/roadef_challenge_2011/solution_checker/solution_checker.h index 7bfa3875de..77cb59d72c 100644 --- a/examples/data/roadef_challenge_2011/solution_checker/solution_checker.h +++ b/examples/data/roadef_challenge_2011/solution_checker/solution_checker.h @@ -11,12 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. - #ifndef SOLUTION_CHECKER_H_ #define SOLUTION_CHECKER_H_ #include #include + #include "assert.h" using namespace std; @@ -58,7 +58,7 @@ void STLDeleteElements(std::vector* elements) { elements->clear(); } -template +template size_t VectorSize(const std::vector& v) { return v.size(); } @@ -127,7 +127,6 @@ class RemainingCapacities { Capacities remaining_capacities_; Capacities transient_remaining_capacities_; const Resources& resources_; - }; class Service; @@ -150,7 +149,6 @@ class Process { const Requirements requirements_; const int move_cost_; const Service& service_; - }; typedef std::vector Processes; typedef std::vector LocalProcesses; @@ -192,7 +190,6 @@ class Service { const NumberOfLocations spread_min_; const Dependencies dependencies_; LocalProcesses processes_; - }; typedef std::vector Services; @@ -249,7 +246,6 @@ class Machine { Capacities safety_remaining_capacities_; RemainingCapacities remaining_capacities_; - }; typedef std::vector Machines; @@ -272,7 +268,6 @@ class SolutionChecker { // document. Note this method assumes all hard constraints are satisfied. int64 GetObjectiveCost() const; - private: // Returns true if process doesn't run on the same machine in the // initial assignment and in the new assignment. @@ -349,7 +344,6 @@ class SolutionChecker { const ProcessAssignments& initial_assignments_; const ProcessAssignments& new_assignments_; - }; // This class parses raw data according to data formats defined in the problem @@ -377,10 +371,8 @@ class DataParser { private: int GetNextModelValue(int max_value); - template - void GetModelVector(size_t size, - int max_value, - std::vector* model_vector); + template + void GetModelVector(size_t size, int max_value, std::vector* model_vector); void Parse(); void ParseModel(); @@ -408,7 +400,6 @@ class DataParser { int process_move_cost_weight_; int service_move_cost_weight_; int machine_move_cost_weight_; - }; } // namespace roadef_challenge diff --git a/examples/tests/remote/tsp.cc b/examples/tests/remote/tsp.cc index 41f9b6cdbc..fbe71d5a73 100644 --- a/examples/tests/remote/tsp.cc +++ b/examples/tests/remote/tsp.cc @@ -103,8 +103,8 @@ int main(int argc, char** argv) { if (absl::GetFlag(FLAGS_tsp_size) > 0) { // TSP of size absl::GetFlag(FLAGS_tsp_size). // Second argument = 1 to build a single tour (it's a TSP). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_tsp_size) - 1, by default the start of - // the route is node 0. + // Nodes are indexed from 0 to absl::GetFlag(FLAGS_tsp_size) - 1, by default + // the start of the route is node 0. RoutingModel routing(absl::GetFlag(FLAGS_tsp_size), 1); // Setting first solution heuristic (cheapest addition). absl::GetFlag(FLAGS_routing_first_solution) = "PathCheapestArc"; @@ -127,9 +127,11 @@ int main(int argc, char** argv) { // Forbid node connections (randomly). ACMRandom randomizer(GetSeed()); int64 forbidden_connections = 0; - while (forbidden_connections < absl::GetFlag(FLAGS_tsp_random_forbidden_connections)) { + while (forbidden_connections < + absl::GetFlag(FLAGS_tsp_random_forbidden_connections)) { const int64 from = randomizer.Uniform(absl::GetFlag(FLAGS_tsp_size) - 1); - const int64 to = randomizer.Uniform(absl::GetFlag(FLAGS_tsp_size) - 1) + 1; + const int64 to = + randomizer.Uniform(absl::GetFlag(FLAGS_tsp_size) - 1) + 1; if (routing.NextVar(from)->Contains(to)) { LOG(INFO) << "Forbidding connection " << from << " -> " << to; routing.NextVar(from)->RemoveValue(to); diff --git a/ortools/algorithms/dense_doubly_linked_list.h b/ortools/algorithms/dense_doubly_linked_list.h index 67debd4a4e..ecc91a2f0b 100644 --- a/ortools/algorithms/dense_doubly_linked_list.h +++ b/ortools/algorithms/dense_doubly_linked_list.h @@ -27,11 +27,12 @@ namespace operations_research { // // It is very fast and compact: it uses exactly 8*n bytes of memory. class DenseDoublyLinkedList { -public: + public: // You can construct a DenseDoublyLinkedList with any range-iterable class // that also has a size() method. The order of the elements is given by the // user and will never change (modulo the removal of elements). - template explicit DenseDoublyLinkedList(const T &sorted_elements); + template + explicit DenseDoublyLinkedList(const T &sorted_elements); int Size() const { return next_.size(); } @@ -43,7 +44,7 @@ public: // You must not call Remove() twice with the same element. void Remove(int i); -private: + private: std::vector next_; std::vector prev_; }; @@ -67,12 +68,9 @@ inline int DenseDoublyLinkedList::Prev(int i) const { inline void DenseDoublyLinkedList::Remove(int i) { const int prev = Prev(i); const int next = Next(i); - if (prev >= 0) - next_[prev] = next; - if (next >= 0) - prev_[next] = prev; - if (DEBUG_MODE) - next_[i] = prev_[i] = -2; // To catch bugs. + if (prev >= 0) next_[prev] = next; + if (next >= 0) prev_[next] = prev; + if (DEBUG_MODE) next_[i] = prev_[i] = -2; // To catch bugs. } template @@ -84,20 +82,16 @@ DenseDoublyLinkedList::DenseDoublyLinkedList(const T &elements) DCHECK_LE(e, Size()); DCHECK_EQ(-2, prev_[e]) << "Duplicate element: " << e; prev_[e] = last; - if (last >= 0) - next_[last] = e; + if (last >= 0) next_[last] = e; last = e; } - if (!elements.empty()) - next_[elements.back()] = -1; + if (!elements.empty()) next_[elements.back()] = -1; if (DEBUG_MODE) { - for (int p : prev_) - DCHECK_NE(-2, p); - for (int n : next_) - DCHECK_NE(-2, n); + for (int p : prev_) DCHECK_NE(-2, p); + for (int n : next_) DCHECK_NE(-2, n); } } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_DENSE_DOUBLY_LINKED_LIST_H_ +#endif // OR_TOOLS_ALGORITHMS_DENSE_DOUBLY_LINKED_LIST_H_ diff --git a/ortools/algorithms/dynamic_partition.cc b/ortools/algorithms/dynamic_partition.cc index 36817579fd..5519862dd6 100644 --- a/ortools/algorithms/dynamic_partition.cc +++ b/ortools/algorithms/dynamic_partition.cc @@ -26,7 +26,7 @@ uint64 FprintOfInt32(int i) { return util_hash::MurmurHash64(reinterpret_cast(&i), sizeof(int)); } -} // namespace +} // namespace DynamicPartition::DynamicPartition(int num_elements) { DCHECK_GE(num_elements, 0); @@ -38,16 +38,14 @@ DynamicPartition::DynamicPartition(int num_elements) { } part_of_.assign(num_elements, 0); uint64 fprint = 0; - for (int i = 0; i < num_elements; ++i) - fprint ^= FprintOfInt32(i); - part_.push_back(Part(/*start_index=*/ 0, /*end_index=*/ num_elements, - /*parent_part=*/ 0, /*fprint=*/ fprint)); + for (int i = 0; i < num_elements; ++i) fprint ^= FprintOfInt32(i); + part_.push_back(Part(/*start_index=*/0, /*end_index=*/num_elements, + /*parent_part=*/0, /*fprint=*/fprint)); } DynamicPartition::DynamicPartition( const std::vector &initial_part_of_element) { - if (initial_part_of_element.empty()) - return; + if (initial_part_of_element.empty()) return; part_of_ = initial_part_of_element; const int n = part_of_.size(); const int num_parts = 1 + *std::max_element(part_of_.begin(), part_of_.end()); @@ -55,29 +53,26 @@ DynamicPartition::DynamicPartition( part_.resize(num_parts); // Compute the part fingerprints. - for (int i = 0; i < n; ++i) - part_[part_of_[i]].fprint ^= FprintOfInt32(i); + for (int i = 0; i < n; ++i) part_[part_of_[i]].fprint ^= FprintOfInt32(i); // Compute the actual start indices of each part, knowing that we'll sort // them as they were given implicitly in "initial_part_of_element". // The code looks a bit weird to do it in-place, with no additional memory. for (int p = 0; p < num_parts; ++p) { - part_[p].end_index = 0; // Temporarily utilized as size_of_part. + part_[p].end_index = 0; // Temporarily utilized as size_of_part. part_[p].parent_part = p; } - for (const int p : part_of_) - ++part_[p].end_index; // size_of_part + for (const int p : part_of_) ++part_[p].end_index; // size_of_part int sum_part_sizes = 0; for (int p = 0; p < num_parts; ++p) { part_[p].start_index = sum_part_sizes; - sum_part_sizes += part_[p].end_index; // size of part. + sum_part_sizes += part_[p].end_index; // size of part. } // Now that we have the correct start indices, we set the end indices to the // start indices, and incrementally add all elements to their part, adjusting // the end indices as we go. - for (Part &part : part_) - part.end_index = part.start_index; + for (Part &part : part_) part.end_index = part.start_index; element_.assign(n, -1); index_of_.assign(n, -1); for (int element = 0; element < n; ++element) { @@ -136,13 +131,12 @@ void DynamicPartition::Refine(const std::vector &distinguished_subset) { const int start_index = part_[part].start_index; const int end_index = part_[part].end_index; const int split_index = end_index - tmp_counter_of_part_[part]; - tmp_counter_of_part_[part] = 0; // Clean up after us. + tmp_counter_of_part_[part] = 0; // Clean up after us. DCHECK_GE(split_index, start_index); DCHECK_LT(split_index, end_index); // Do nothing if all elements were distinguished. - if (split_index == start_index) - continue; + if (split_index == start_index) continue; // Compute the fingerprint of the new part. uint64 new_fprint = 0; @@ -201,8 +195,7 @@ std::string DynamicPartition::DebugString(DebugStringSorting sorting) const { } std::string out; for (const std::vector &part : parts) { - if (!out.empty()) - out += " | "; + if (!out.empty()) out += " | "; out += absl::StrJoin(part, " "); } return out; @@ -212,8 +205,7 @@ void MergingPartition::Reset(int num_nodes) { DCHECK_GE(num_nodes, 0); part_size_.assign(num_nodes, 1); parent_.assign(num_nodes, -1); - for (int i = 0; i < num_nodes; ++i) - parent_[i] = i; + for (int i = 0; i < num_nodes; ++i) parent_[i] = i; tmp_part_bit_.assign(num_nodes, false); } @@ -224,8 +216,7 @@ int MergingPartition::MergePartsOf(int node1, int node2) { DCHECK_LT(node2, NumNodes()); int root1 = GetRoot(node1); int root2 = GetRoot(node2); - if (root1 == root2) - return -1; + if (root1 == root2) return -1; int s1 = part_size_[root1]; int s2 = part_size_[root2]; // Attach the smaller part to the larger one. Break ties by root index. @@ -263,8 +254,7 @@ void MergingPartition::KeepOnlyOneNodePerPart(std::vector *nodes) { // Clean up the tmp_part_bit_ vector. Since we've already compressed the // paths (if backtracking was enabled), no need to do it again. - for (const int node : *nodes) - tmp_part_bit_[GetRoot(node)] = false; + for (const int node : *nodes) tmp_part_bit_[GetRoot(node)] = false; } int MergingPartition::FillEquivalenceClasses( @@ -294,11 +284,10 @@ std::string MergingPartition::DebugString() { // but these won't be visible in the string that we construct below. std::string out; for (const std::vector &part : sorted_parts) { - if (!out.empty()) - out += " | "; + if (!out.empty()) out += " | "; out += absl::StrJoin(part, " "); } return out; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/dynamic_partition.h b/ortools/algorithms/dynamic_partition.h index 2121efd063..ae90b0bdb0 100644 --- a/ortools/algorithms/dynamic_partition.h +++ b/ortools/algorithms/dynamic_partition.h @@ -47,7 +47,7 @@ namespace operations_research { // // TODO(user): rename this to BacktrackableSplittingPartition. class DynamicPartition { -public: + public: // Creates a DynamicPartition on n elements, numbered 0..n-1. Start with // the trivial partition (only one subset containing all elements). explicit DynamicPartition(int num_elements); @@ -137,7 +137,7 @@ public: return element_; } -private: + private: // A DynamicPartition instance maintains a list of all of its elements, // 'sorted' by partitions: elements of the same subset are contiguous // in that list. @@ -152,13 +152,13 @@ private: struct Part { // This part holds elements[start_index .. end_index-1]. // INVARIANT: end_index > start_index. - int start_index; // Inclusive - int end_index; // Exclusive + int start_index; // Inclusive + int end_index; // Exclusive // The Part that this part was split out of. See the comment at Refine(). // INVARIANT: part[i].parent_part <= i, and the equality holds iff part[i] // has no parent. - int parent_part; // Index into the part[] array. + int parent_part; // Index into the part[] array. // The part's fingerprint is the XOR of all fingerprints of its elements. // See FprintOfInt32() in the .cc. @@ -166,10 +166,12 @@ private: Part() : start_index(0), end_index(0), parent_part(0), fprint(0) {} Part(int start_index, int end_index, int parent_part, uint64 fprint) - : start_index(start_index), end_index(end_index), - parent_part(parent_part), fprint(fprint) {} + : start_index(start_index), + end_index(end_index), + parent_part(parent_part), + fprint(fprint) {} }; - std::vector part_; // The disjoint parts. + std::vector part_; // The disjoint parts. // Used temporarily and exclusively by Refine(). This prevents Refine() // from being thread-safe. @@ -199,7 +201,7 @@ struct DynamicPartition::IterablePart { // Partition class that supports incremental merging, using the union-find // algorithm (see http://en.wikipedia.org/wiki/Disjoint-set_data_structure). class MergingPartition { -public: + public: // At first, all nodes are in their own singleton part. MergingPartition() { Reset(0); } explicit MergingPartition(int num_nodes) { Reset(num_nodes); } @@ -216,7 +218,7 @@ public: // // Details: a smaller part will always be merged onto a larger one. // Upons ties, the smaller representative becomes the overall representative. - int MergePartsOf(int node1, int node2); // The 'union' of the union-find. + int MergePartsOf(int node1, int node2); // The 'union' of the union-find. // Get the representative of "node" (a node in the same equivalence class, // which will also be returned for any other "node" in the same class). @@ -257,7 +259,7 @@ public: // version using path compression. int GetRoot(int node) const; -private: + private: // Along the upwards path from 'node' to its root, set the parent of all // nodes (including the root) to 'parent'. void SetParentAlongPathToRoot(int node, int parent); @@ -271,8 +273,8 @@ private: // *** Implementation of inline methods of the above classes. *** -inline DynamicPartition::IterablePart -DynamicPartition::ElementsInPart(int i) const { +inline DynamicPartition::IterablePart DynamicPartition::ElementsInPart( + int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, NumParts()); return IterablePart(element_.begin() + part_[i].start_index, @@ -298,8 +300,8 @@ inline int DynamicPartition::ParentOfPart(int part) const { return part_[part].parent_part; } -inline DynamicPartition::IterablePart -DynamicPartition::ElementsInSamePartAs(int i) const { +inline DynamicPartition::IterablePart DynamicPartition::ElementsInSamePartAs( + int i) const { return ElementsInPart(PartOf(i)); } @@ -315,8 +317,7 @@ inline int MergingPartition::GetRoot(int node) const { int child = node; while (true) { const int parent = parent_[child]; - if (parent == child) - return child; + if (parent == child) return child; child = parent; } } @@ -330,8 +331,7 @@ inline void MergingPartition::SetParentAlongPathToRoot(int node, int parent) { while (true) { const int old_parent = parent_[child]; parent_[child] = parent; - if (old_parent == child) - return; + if (old_parent == child) return; child = old_parent; } } @@ -343,6 +343,6 @@ inline void MergingPartition::ResetNode(int node) { part_size_[node] = 1; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_DYNAMIC_PARTITION_H_ +#endif // OR_TOOLS_ALGORITHMS_DYNAMIC_PARTITION_H_ diff --git a/ortools/algorithms/dynamic_permutation.cc b/ortools/algorithms/dynamic_permutation.cc index 9db20469a2..2022327eab 100644 --- a/ortools/algorithms/dynamic_permutation.cc +++ b/ortools/algorithms/dynamic_permutation.cc @@ -21,8 +21,7 @@ namespace operations_research { DynamicPermutation::DynamicPermutation(int n) : image_(n, -1), ancestor_(n, -1), tmp_mask_(n, false) { - for (int i = 0; i < Size(); ++i) - image_[i] = ancestor_[i] = i; + for (int i = 0; i < Size(); ++i) image_[i] = ancestor_[i] = i; } void DynamicPermutation::AddMappings(const std::vector &src, @@ -33,27 +32,25 @@ void DynamicPermutation::AddMappings(const std::vector &src, for (int i = 0; i < src.size(); ++i) { const int s = src[i]; const int d = dst[i]; - DCHECK_EQ(s, ImageOf(s)); // No prior image of s. - DCHECK_EQ(d, ancestor_[d]); // No prior ancestor of d. + DCHECK_EQ(s, ImageOf(s)); // No prior image of s. + DCHECK_EQ(d, ancestor_[d]); // No prior ancestor of d. ancestor_[d] = RootOf(s); image_[s] = d; - if (image_[d] == d) - loose_ends_.insert(d); - loose_ends_.erase(s); // Also takes care of the corner case s == d. + if (image_[d] == d) loose_ends_.insert(d); + loose_ends_.erase(s); // Also takes care of the corner case s == d. // Remember the sources for the undo stack. mapping_src_stack_.push_back(s); } } -void -DynamicPermutation::UndoLastMappings(std::vector *undone_mapping_src) { +void DynamicPermutation::UndoLastMappings( + std::vector *undone_mapping_src) { DCHECK(undone_mapping_src != nullptr); undone_mapping_src->clear(); - if (mapping_src_size_stack_.empty()) - return; // Nothing to undo. + if (mapping_src_size_stack_.empty()) return; // Nothing to undo. const int num_mappings_before = mapping_src_size_stack_.back(); mapping_src_size_stack_.pop_back(); const int num_mappings_now = mapping_src_stack_.size(); @@ -69,14 +66,13 @@ DynamicPermutation::UndoLastMappings(std::vector *undone_mapping_src) { const int s = mapping_src_stack_[i]; const int d = ImageOf(s); - if (ancestor_[s] != s) - loose_ends_.insert(s); + if (ancestor_[s] != s) loose_ends_.insert(s); loose_ends_.erase(d); ancestor_[d] = d; image_[s] = s; } - mapping_src_stack_.resize(num_mappings_before); // Shrink. + mapping_src_stack_.resize(num_mappings_before); // Shrink. } void DynamicPermutation::Reset() { @@ -90,13 +86,12 @@ void DynamicPermutation::Reset() { loose_ends_.clear(); } -std::unique_ptr -DynamicPermutation::CreateSparsePermutation() const { +std::unique_ptr DynamicPermutation::CreateSparsePermutation() + const { std::unique_ptr sparse_perm(new SparsePermutation(Size())); int num_identity_singletons = 0; for (const int x : mapping_src_stack_) { - if (tmp_mask_[x]) - continue; + if (tmp_mask_[x]) continue; // Deal with the special case of a trivial x->x cycle, which we do *not* // want to add to the sparse permutation. if (ImageOf(x) == x) { @@ -111,13 +106,11 @@ DynamicPermutation::CreateSparsePermutation() const { tmp_mask_[next] = true; DCHECK_NE(next, ImageOf(next)); next = ImageOf(next); - if (next == root) - break; + if (next == root) break; } sparse_perm->CloseCurrentCycle(); } - for (const int x : mapping_src_stack_) - tmp_mask_[x] = false; + for (const int x : mapping_src_stack_) tmp_mask_[x] = false; DCHECK_EQ(mapping_src_stack_.size(), sparse_perm->Support().size() + num_identity_singletons); return sparse_perm; @@ -128,4 +121,4 @@ std::string DynamicPermutation::DebugString() const { return CreateSparsePermutation()->DebugString(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/dynamic_permutation.h b/ortools/algorithms/dynamic_permutation.h index 1c218ac2e8..f1576a9c92 100644 --- a/ortools/algorithms/dynamic_permutation.h +++ b/ortools/algorithms/dynamic_permutation.h @@ -15,7 +15,7 @@ #define OR_TOOLS_ALGORITHMS_DYNAMIC_PERMUTATION_H_ #include -#include // TODO(user): remove when no longer used. +#include // TODO(user): remove when no longer used. #include #include "ortools/base/logging.h" @@ -31,13 +31,11 @@ class SparsePermutation; // RAM usage: as of 2014-04, this class needs less than: // 32.125 * (n + 2 * support_size) bytes. class DynamicPermutation { -public: + public: // Upon construction, every element i in [0..n-1] maps to itself. explicit DynamicPermutation(int n); - int Size() const { - return image_.size(); - } // Return the original "n". + int Size() const { return image_.size(); } // Return the original "n". // Declares a set of mappings for this permutation: src[i] will map to dst[i]. // Requirements that are DCHECKed: @@ -63,7 +61,7 @@ public: // Complexity: O(support size). void Reset(); - int ImageOf(int i) const; // Complexity: one vector lookup. + int ImageOf(int i) const; // Complexity: one vector lookup. // Returns the union of all "src" ever given to AddMappings(). const std::vector &AllMappingsSrc() const { return mapping_src_stack_; } @@ -92,7 +90,7 @@ public: std::string DebugString() const; -private: + private: std::vector image_; // ancestor_[i] isn't exactly RootOf(i): it might itself have an ancestor, and // so on. @@ -125,12 +123,11 @@ inline int DynamicPermutation::RootOf(int i) const { DCHECK_LT(i, Size()); while (true) { const int j = ancestor_[i]; - if (j == i) - return i; + if (j == i) return i; i = j; } } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_DYNAMIC_PERMUTATION_H_ +#endif // OR_TOOLS_ALGORITHMS_DYNAMIC_PERMUTATION_H_ diff --git a/ortools/algorithms/find_graph_symmetries.cc b/ortools/algorithms/find_graph_symmetries.cc index c45b4707f2..c1015c5614 100644 --- a/ortools/algorithms/find_graph_symmetries.cc +++ b/ortools/algorithms/find_graph_symmetries.cc @@ -52,8 +52,7 @@ bool PartitionsAreCompatibleAfterPartIndex(const DynamicPartition &p1, const DynamicPartition &p2, int part_index) { const int num_parts = p1.NumParts(); - if (p2.NumParts() != num_parts) - return false; + if (p2.NumParts() != num_parts) return false; for (int p = part_index; p < num_parts; ++p) { if (p1.SizeOfPart(p) != p2.SizeOfPart(p) || p1.ParentOfPart(p) != p2.ParentOfPart(p)) { @@ -90,20 +89,20 @@ bool ListMapsToList(const List &l1, const List &l2, } (*tmp_node_mask)[mapped_x] = false; } - if (num_elements_delta != 0) - match = false; + if (num_elements_delta != 0) match = false; if (!match) { // We need to clean up tmp_node_mask. - for (const int x : l2) - (*tmp_node_mask)[x] = false; + for (const int x : l2) (*tmp_node_mask)[x] = false; } return match; } -} // namespace +} // namespace GraphSymmetryFinder::GraphSymmetryFinder(const Graph &graph, bool is_undirected) - : graph_(graph), tmp_dynamic_permutation_(NumNodes()), - tmp_node_mask_(NumNodes(), false), tmp_degree_(NumNodes(), 0), + : graph_(graph), + tmp_dynamic_permutation_(NumNodes()), + tmp_node_mask_(NumNodes(), false), + tmp_degree_(NumNodes(), 0), tmp_nodes_with_degree_(NumNodes() + 1) { // Set up an "unlimited" time limit by default. time_limit_ = TimeLimit::Infinite(); @@ -132,16 +131,16 @@ GraphSymmetryFinder::GraphSymmetryFinder(const Graph &graph, bool is_undirected) flattened_reverse_adj_lists_.assign(graph.num_arcs(), -1); for (const int node : graph.AllNodes()) { for (const int arc : graph.OutgoingArcs(node)) { - flattened_reverse_adj_lists_[ - reverse_adj_list_index_[graph.Head(arc) + /*shift*/ 1]++] = node; + flattened_reverse_adj_lists_[reverse_adj_list_index_[graph.Head(arc) + + /*shift*/ 1]++] = + node; } } // The last pass shifted reverse_adj_list_index, so it's now as we want it: // [0, in_degree(node0), in_degree(node0) + in_degree(node1), ...] if (DEBUG_MODE) { DCHECK_EQ(graph.num_arcs(), reverse_adj_list_index_[graph.num_nodes()]); - for (const int i : flattened_reverse_adj_lists_) - DCHECK_NE(i, -1); + for (const int i : flattened_reverse_adj_lists_) DCHECK_NE(i, -1); } } } @@ -150,8 +149,7 @@ bool GraphSymmetryFinder::IsGraphAutomorphism( const DynamicPermutation &permutation) const { for (const int base : permutation.AllMappingsSrc()) { const int image = permutation.ImageOf(base); - if (image == base) - continue; + if (image == base) continue; if (!ListMapsToList(graph_[base], graph_[image], permutation, &tmp_node_mask_)) { return false; @@ -162,8 +160,7 @@ bool GraphSymmetryFinder::IsGraphAutomorphism( // to displaced nodes. for (const int base : permutation.AllMappingsSrc()) { const int image = permutation.ImageOf(base); - if (image == base) - continue; + if (image == base) continue; if (!ListMapsToList(TailsOfIncomingArcsTo(base), TailsOfIncomingArcsTo(image), permutation, &tmp_node_mask_)) { @@ -183,14 +180,12 @@ inline void IncrementCounterForNonSingletons(const T &nodes, std::vector *node_count, std::vector *nodes_seen) { for (const int node : nodes) { - if (partition.ElementsInSamePartAs(node).size() == 1) - continue; + if (partition.ElementsInSamePartAs(node).size() == 1) continue; const int count = ++(*node_count)[node]; - if (count == 1) - nodes_seen->push_back(node); + if (count == 1) nodes_seen->push_back(node); } } -} // namespace +} // namespace void GraphSymmetryFinder::RecursivelyRefinePartitionByAdjacency( int first_unrefined_part_index, DynamicPartition *partition) { @@ -210,10 +205,10 @@ void GraphSymmetryFinder::RecursivelyRefinePartitionByAdjacency( // advertised. std::vector adjacency_directions(1, /*outgoing*/ true); if (!reverse_adj_list_index_.empty()) { - adjacency_directions.push_back(false); // Also look at incoming arcs. + adjacency_directions.push_back(false); // Also look at incoming arcs. } for (int part_index = first_unrefined_part_index; - part_index < partition->NumParts(); // Moving target! + part_index < partition->NumParts(); // Moving target! ++part_index) { for (const bool outgoing_adjacency : adjacency_directions) { // Count the aggregated degree of all nodes, only looking at arcs that @@ -235,16 +230,16 @@ void GraphSymmetryFinder::RecursivelyRefinePartitionByAdjacency( int max_degree = 0; for (const int node : tmp_nodes_with_nonzero_degree) { const int degree = tmp_degree_[node]; - tmp_degree_[node] = 0; // To clean up after us. + tmp_degree_[node] = 0; // To clean up after us. max_degree = std::max(max_degree, degree); tmp_nodes_with_degree_[degree].push_back(node); } - tmp_nodes_with_nonzero_degree.clear(); // To clean up after us. + tmp_nodes_with_nonzero_degree.clear(); // To clean up after us. // For each degree, refine the partition by the set of nodes with that // degree. for (int degree = 1; degree <= max_degree; ++degree) { partition->Refine(tmp_nodes_with_degree_[degree]); - tmp_nodes_with_degree_[degree].clear(); // To clean up after us. + tmp_nodes_with_degree_[degree].clear(); // To clean up after us. } } } @@ -314,7 +309,7 @@ void MergeNodeEquivalenceClassesAccordingToPermutation( void GetAllOtherRepresentativesInSamePartAs( int representative_node, const DynamicPartition &partition, const DenseDoublyLinkedList &representatives_sorted_by_index_in_partition, - MergingPartition *node_equivalence_classes, // Only for debugging. + MergingPartition *node_equivalence_classes, // Only for debugging. std::vector *pruned_other_nodes) { pruned_other_nodes->clear(); const int part_index = partition.PartOf(representative_node); @@ -323,8 +318,7 @@ void GetAllOtherRepresentativesInSamePartAs( while (true) { DCHECK_EQ(repr, node_equivalence_classes->GetRoot(repr)); repr = representatives_sorted_by_index_in_partition.Prev(repr); - if (repr < 0 || partition.PartOf(repr) != part_index) - break; + if (repr < 0 || partition.PartOf(repr) != part_index) break; pruned_other_nodes->push_back(repr); } // ... and then on all contiguous representatives *before* it. @@ -332,8 +326,7 @@ void GetAllOtherRepresentativesInSamePartAs( while (true) { DCHECK_EQ(repr, node_equivalence_classes->GetRoot(repr)); repr = representatives_sorted_by_index_in_partition.Next(repr); - if (repr < 0 || partition.PartOf(repr) != part_index) - break; + if (repr < 0 || partition.PartOf(repr) != part_index) break; pruned_other_nodes->push_back(repr); } @@ -349,8 +342,7 @@ void GetAllOtherRepresentativesInSamePartAs( } } node_equivalence_classes->KeepOnlyOneNodePerPart(&expected_output); - for (int &x : expected_output) - x = node_equivalence_classes->GetRoot(x); + for (int &x : expected_output) x = node_equivalence_classes->GetRoot(x); std::sort(expected_output.begin(), expected_output.end()); std::vector sorted_output = *pruned_other_nodes; std::sort(sorted_output.begin(), sorted_output.end()); @@ -358,7 +350,7 @@ void GetAllOtherRepresentativesInSamePartAs( absl::StrJoin(sorted_output, " ")); } } -} // namespace +} // namespace absl::Status GraphSymmetryFinder::FindSymmetries( double time_limit_seconds, std::vector *node_equivalence_classes_io, @@ -377,15 +369,15 @@ absl::Status GraphSymmetryFinder::FindSymmetries( // Break all inherent asymmetries in the graph. { ScopedTimeDistributionUpdater u(&stats_.initialization_refine_time); - RecursivelyRefinePartitionByAdjacency(/*first_unrefined_part_index=*/ 0, + RecursivelyRefinePartitionByAdjacency(/*first_unrefined_part_index=*/0, &base_partition); } if (time_limit_->LimitReached()) { return absl::Status(absl::StatusCode::kDeadlineExceeded, "During the initial refinement."); } - VLOG(4) << "Base partition: " << base_partition.DebugString( - DynamicPartition::SORT_BY_PART); + VLOG(4) << "Base partition: " + << base_partition.DebugString(DynamicPartition::SORT_BY_PART); MergingPartition node_equivalence_classes(NumNodes()); std::vector > permutations_displacing_node(NumNodes()); @@ -434,8 +426,8 @@ absl::Status GraphSymmetryFinder::FindSymmetries( InvariantDiveState(invariant_node, base_partition.NumParts())); DistinguishNodeInPartition(invariant_node, &base_partition, nullptr); VLOG(4) << "Invariant dive: invariant node = " << invariant_node - << "; partition after: " << base_partition.DebugString( - DynamicPartition::SORT_BY_PART); + << "; partition after: " + << base_partition.DebugString(DynamicPartition::SORT_BY_PART); if (time_limit_->LimitReached()) { return absl::Status(absl::StatusCode::kDeadlineExceeded, "During the invariant dive."); @@ -450,8 +442,7 @@ absl::Status GraphSymmetryFinder::FindSymmetries( IF_STATS_ENABLED(stats_.main_search_time.StartTimer()); while (!invariant_dive_stack.empty()) { - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; // Backtrack the last step of 1) (the invariant dive). IF_STATS_ENABLED(stats_.invariant_unroll_time.StartTimer()); const int root_node = invariant_dive_stack.back().invariant_node; @@ -461,8 +452,8 @@ absl::Status GraphSymmetryFinder::FindSymmetries( base_partition.UndoRefineUntilNumPartsEqual(base_num_parts); image_partition.UndoRefineUntilNumPartsEqual(base_num_parts); VLOG(4) << "Backtracking invariant dive: root node = " << root_node - << "; partition: " << base_partition.DebugString( - DynamicPartition::SORT_BY_PART); + << "; partition: " + << base_partition.DebugString(DynamicPartition::SORT_BY_PART); // Now we'll try to map "root_node" to all image nodes that seem compatible // and that aren't "root_node" itself. @@ -494,8 +485,7 @@ absl::Status GraphSymmetryFinder::FindSymmetries( // Try to map "root_node" to all of its potential images. For each image, // we only care about finding a single compatible permutation, if it exists. while (!potential_root_image_nodes.empty()) { - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; VLOG(4) << "Potential (pruned) images of root node " << root_node << " left: [" << absl::StrJoin(potential_root_image_nodes, " ") << "]."; @@ -598,7 +588,7 @@ inline void GetBestMapping(const DynamicPartition &base_partition, *image_node = *image_partition.ElementsInPart(part_index).begin(); } } -} // namespace +} // namespace // TODO(user): refactor this method and its submethods into a dedicated class // whose members will be ominously accessed by all the class methods; most @@ -607,8 +597,8 @@ std::unique_ptr GraphSymmetryFinder::FindOneSuitablePermutation( int root_node, int root_image_node, DynamicPartition *base_partition, DynamicPartition *image_partition, - const std::vector > & - generators_found_so_far, + const std::vector > + &generators_found_so_far, const std::vector > &permutations_displacing_node) { // DCHECKs() and statistics. ScopedTimeDistributionUpdater search_time_updater(&stats_.search_time); @@ -628,9 +618,9 @@ GraphSymmetryFinder::FindOneSuitablePermutation( // Initialize the search: we can already distinguish "root_node" in the base // partition. See the comment below. search_states_.emplace_back( - /*base_node=*/ root_node, /*first_image_node=*/ -1, - /*num_parts_before_trying_to_map_base_node=*/ base_partition->NumParts(), - /*min_potential_mismatching_part_index=*/ base_partition->NumParts()); + /*base_node=*/root_node, /*first_image_node=*/-1, + /*num_parts_before_trying_to_map_base_node=*/base_partition->NumParts(), + /*min_potential_mismatching_part_index=*/base_partition->NumParts()); // We inject the image node directly as the "remaining_pruned_image_nodes". search_states_.back().remaining_pruned_image_nodes.assign(1, root_image_node); { @@ -638,8 +628,7 @@ GraphSymmetryFinder::FindOneSuitablePermutation( DistinguishNodeInPartition(root_node, base_partition, &base_singletons); } while (!search_states_.empty()) { - if (time_limit_->LimitReached()) - return nullptr; + if (time_limit_->LimitReached()) return nullptr; // When exploring a SearchState "ss", we're supposed to have: // - A base_partition that has already been refined on ss->base_node. // (base_singleton is the list of singletons created on the base @@ -651,9 +640,9 @@ GraphSymmetryFinder::FindOneSuitablePermutation( // Also, one should note that the base partition (before its refinement on // base_node) was deemed compatible with the image partition as it is now. const SearchState &ss = search_states_.back(); - const int image_node = - ss.first_image_node >= 0 ? ss.first_image_node - : ss.remaining_pruned_image_nodes.back(); + const int image_node = ss.first_image_node >= 0 + ? ss.first_image_node + : ss.remaining_pruned_image_nodes.back(); // Statistics, DCHECKs. IF_STATS_ENABLED(stats_.search_depth.Add(search_states_.size())); @@ -801,10 +790,10 @@ GraphSymmetryFinder::FindOneSuitablePermutation( // like incrementally maintaining the list of permutations compatible // with the partition so far. const int part = image_partition->PartOf(last_ss->first_image_node); - last_ss->remaining_pruned_image_nodes - .reserve(image_partition->SizeOfPart(part)); - last_ss->remaining_pruned_image_nodes - .push_back(last_ss->first_image_node); + last_ss->remaining_pruned_image_nodes.reserve( + image_partition->SizeOfPart(part)); + last_ss->remaining_pruned_image_nodes.push_back( + last_ss->first_image_node); for (const int e : image_partition->ElementsInPart(part)) { if (e != last_ss->first_image_node) { last_ss->remaining_pruned_image_nodes.push_back(e); @@ -823,8 +812,7 @@ GraphSymmetryFinder::FindOneSuitablePermutation( last_ss->first_image_node = -1; } last_ss->remaining_pruned_image_nodes.pop_back(); - if (!last_ss->remaining_pruned_image_nodes.empty()) - break; + if (!last_ss->remaining_pruned_image_nodes.empty()) break; VLOG(4) << "Backtracking one level up."; base_partition->UndoRefineUntilNumPartsEqual( @@ -876,14 +864,13 @@ void GraphSymmetryFinder::PruneOrbitsUnderPermutationsCompatibleWithPartition( // the search below the state that we're currently in, times the expected // number of pruned nodes). Sometimes it may be better to skip the // pruning. - if (nodes->size() <= 1) - return; + if (nodes->size() <= 1) return; // Iterate on all targeted permutations. If they are compatible, apply // them to tmp_partition_ which will contain the incrementally merged // equivalence classes. std::vector &tmp_nodes_on_support = - tmp_stack_; // Rename, for readability. + tmp_stack_; // Rename, for readability. DCHECK(tmp_nodes_on_support.empty()); // TODO(user): investigate further optimizations: maybe it's possible // to incrementally maintain the set of permutations that is compatible @@ -901,8 +888,7 @@ void GraphSymmetryFinder::PruneOrbitsUnderPermutationsCompatibleWithPartition( break; } } - if (!compatible) - continue; + if (!compatible) continue; // Now the full compatibility check: each cycle of the permutation must // be fully included in an image part. for (int c = 0; c < permutation.NumCycles(); ++c) { @@ -913,12 +899,11 @@ void GraphSymmetryFinder::PruneOrbitsUnderPermutationsCompatibleWithPartition( compatible = false; break; } - part = partition.PartOf(node); // Initilization of 'part'. + part = partition.PartOf(node); // Initilization of 'part'. } } } - if (!compatible) - continue; + if (!compatible) continue; // The permutation is fully compatible! // TODO(user): ignore cycles that are outside of image_part. MergeNodeEquivalenceClassesAccordingToPermutation(permutation, @@ -973,8 +958,10 @@ bool GraphSymmetryFinder::ConfirmFullMatchOrFindNextMappingDecision( if (*next_base_node != -1) { // We found loose ends, but none that mapped to its own root. Just pick // any valid image. - *next_image_node = *image_partition - .ElementsInPart(base_partition.PartOf(*next_base_node)).begin(); + *next_image_node = + *image_partition + .ElementsInPart(base_partition.PartOf(*next_base_node)) + .begin(); return false; } } @@ -1026,12 +1013,13 @@ bool GraphSymmetryFinder::ConfirmFullMatchOrFindNextMappingDecision( } std::string GraphSymmetryFinder::SearchState::DebugString() const { - return absl::StrFormat("SearchState{ base_node=%d, first_image_node=%d," - " remaining_pruned_image_nodes=[%s]," - " num_parts_before_trying_to_map_base_node=%d }", - base_node, first_image_node, - absl::StrJoin(remaining_pruned_image_nodes, " "), - num_parts_before_trying_to_map_base_node); + return absl::StrFormat( + "SearchState{ base_node=%d, first_image_node=%d," + " remaining_pruned_image_nodes=[%s]," + " num_parts_before_trying_to_map_base_node=%d }", + base_node, first_image_node, + absl::StrJoin(remaining_pruned_image_nodes, " "), + num_parts_before_trying_to_map_base_node); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/find_graph_symmetries.h b/ortools/algorithms/find_graph_symmetries.h index 878fea16c3..9854cc98eb 100644 --- a/ortools/algorithms/find_graph_symmetries.h +++ b/ortools/algorithms/find_graph_symmetries.h @@ -41,7 +41,7 @@ namespace operations_research { class SparsePermutation; class GraphSymmetryFinder { -public: + public: typedef ::util::StaticGraph<> Graph; // If the Graph passed to the GraphSymmetryFinder is undirected, i.e. @@ -128,7 +128,7 @@ public: void DistinguishNodeInPartition(int node, DynamicPartition *partition, std::vector *new_singletons_or_null); -private: + private: const Graph &graph_; inline int NumNodes() const { return graph_.num_nodes(); } @@ -145,8 +145,8 @@ private: // vectors are empty, and TailsOfIncomingArcsTo() crashes. std::vector flattened_reverse_adj_lists_; std::vector reverse_adj_list_index_; - util::BeginEndWrapper::const_iterator> - TailsOfIncomingArcsTo(int node) const; + util::BeginEndWrapper::const_iterator> TailsOfIncomingArcsTo( + int node) const; // Deadline management. Populated upon FindSymmetries(). mutable std::unique_ptr time_limit_; @@ -164,8 +164,8 @@ private: std::unique_ptr FindOneSuitablePermutation( int root_node, int root_image_node, DynamicPartition *base_partition, DynamicPartition *image_partition, - const std::vector > & - generators_found_so_far, + const std::vector > + &generators_found_so_far, const std::vector > &permutations_displacing_node); // Data structure used by FindOneSuitablePermutation(). See the .cc @@ -187,7 +187,8 @@ private: int min_potential_mismatching_part_index; SearchState(int bn, int in, int np, int mi) - : base_node(bn), first_image_node(in), + : base_node(bn), + first_image_node(in), num_parts_before_trying_to_map_base_node(np), min_potential_mismatching_part_index(mi) {} @@ -229,13 +230,14 @@ private: // Temporary objects used by some of the class methods, and owned by the // class to avoid (costly) re-allocation. Their resting states are described // in the side comments; with N = NumNodes(). - DynamicPermutation tmp_dynamic_permutation_; // Identity(N) - mutable std::vector tmp_node_mask_; // [0..N-1] = false - std::vector tmp_degree_; // [0..N-1] = 0. - std::vector tmp_stack_; // Empty. - std::vector > tmp_nodes_with_degree_; // [0..N-1] = []. - MergingPartition tmp_partition_; // Reset(N). - std::vector tmp_compatible_permutations_; // Empty. + DynamicPermutation tmp_dynamic_permutation_; // Identity(N) + mutable std::vector tmp_node_mask_; // [0..N-1] = false + std::vector tmp_degree_; // [0..N-1] = 0. + std::vector tmp_stack_; // Empty. + std::vector > tmp_nodes_with_degree_; // [0..N-1] = []. + MergingPartition tmp_partition_; // Reset(N). + std::vector + tmp_compatible_permutations_; // Empty. // Internal statistics, used for performance tuning and debugging. struct Stats : public StatsGroup { @@ -261,19 +263,16 @@ private: "p ┣╸Mapping election / full match detection", this), map_election_std_mapping_time("q ┃ ┣╸Mapping elected", this), map_election_std_full_match_time("r ┃ ┗╸Full Match", this), - automorphism_test_time( - "s ┣╸[Upon full match] Automorphism check", this), + automorphism_test_time("s ┣╸[Upon full match] Automorphism check", + this), automorphism_test_fail_time("t ┃ ┣╸Fail", this), automorphism_test_success_time("u ┃ ┗╸Success", this), - search_finalize_time("v ┣╸[Upon auto success] Finalization", - this), + search_finalize_time("v ┣╸[Upon auto success] Finalization", this), dynamic_permutation_undo_time( - "w ┣╸[Upon auto fail, full] Dynamic permutation undo", - this), + "w ┣╸[Upon auto fail, full] Dynamic permutation undo", this), map_reelection_time( "x ┣╸[Upon auto fail, partial] Mapping re-election", this), - non_singleton_search_time("y ┃ ┗╸Non-singleton search", - this), + non_singleton_search_time("y ┃ ┗╸Non-singleton search", this), backtracking_time("z ┗╸Backtracking", this), pruning_time("{ ┗╸Pruning", this), search_depth("~ Search Stats: search_depth", this) {} @@ -311,6 +310,6 @@ private: mutable Stats stats_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_FIND_GRAPH_SYMMETRIES_H_ +#endif // OR_TOOLS_ALGORITHMS_FIND_GRAPH_SYMMETRIES_H_ diff --git a/ortools/algorithms/hungarian.cc b/ortools/algorithms/hungarian.cc index e911e67e9c..0374232d89 100644 --- a/ortools/algorithms/hungarian.cc +++ b/ortools/algorithms/hungarian.cc @@ -29,7 +29,7 @@ class HungarianOptimizer { static constexpr int kHungarianOptimizerRowNotFound = -1; static constexpr int kHungarianOptimizerColNotFound = -2; -public: + public: // Setup the initial conditions for the algorithm. // Parameters: costs is a matrix of the cost of assigning each agent to @@ -48,14 +48,10 @@ public: // Like Maximize(), but minimizing the cost instead. void Minimize(std::vector *preimage, std::vector *image); -private: - typedef void(HungarianOptimizer::*Step)(); + private: + typedef void (HungarianOptimizer::*Step)(); - typedef enum { - NONE, - PRIME, - STAR - } Mark; + typedef enum { NONE, PRIME, STAR } Mark; // Convert the final cost matrix into a set of assignments of preimage->image. // Returns the assignment in the two vectors passed as argument, the same as @@ -197,8 +193,8 @@ private: std::vector stars_in_col_; // Representation of a path_ through the matrix - used in step 5. - std::vector preimage_; // i.e. the agents - std::vector image_; // i.e. the tasks + std::vector preimage_; // i.e. the agents + std::vector image_; // i.e. the tasks // The width_ and height_ of the initial (non-expanded) cost matrix. int width_; @@ -210,8 +206,17 @@ private: HungarianOptimizer::HungarianOptimizer( const std::vector > &costs) - : matrix_size_(0), costs_(), max_cost_(0), rows_covered_(), cols_covered_(), - marks_(), stars_in_col_(), preimage_(), image_(), width_(0), height_(0), + : matrix_size_(0), + costs_(), + max_cost_(0), + rows_covered_(), + cols_covered_(), + marks_(), + stars_in_col_(), + preimage_(), + image_(), + width_(0), + height_(0), state_(nullptr) { width_ = costs.size(); @@ -649,10 +654,10 @@ bool InputContainsNan(const std::vector > &input) { return false; } -void -MinimizeLinearAssignment(const std::vector > &cost, - absl::flat_hash_map *direct_assignment, - absl::flat_hash_map *reverse_assignment) { +void MinimizeLinearAssignment( + const std::vector > &cost, + absl::flat_hash_map *direct_assignment, + absl::flat_hash_map *reverse_assignment) { if (InputContainsNan(cost)) { LOG(ERROR) << "Returning before invoking the Hungarian optimizer."; return; @@ -667,10 +672,10 @@ MinimizeLinearAssignment(const std::vector > &cost, } } -void -MaximizeLinearAssignment(const std::vector > &cost, - absl::flat_hash_map *direct_assignment, - absl::flat_hash_map *reverse_assignment) { +void MaximizeLinearAssignment( + const std::vector > &cost, + absl::flat_hash_map *direct_assignment, + absl::flat_hash_map *reverse_assignment) { if (InputContainsNan(cost)) { LOG(ERROR) << "Returning before invoking the Hungarian optimizer."; return; @@ -685,4 +690,4 @@ MaximizeLinearAssignment(const std::vector > &cost, } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/hungarian.h b/ortools/algorithms/hungarian.h index 42846b226b..a5b1385524 100644 --- a/ortools/algorithms/hungarian.h +++ b/ortools/algorithms/hungarian.h @@ -45,17 +45,17 @@ namespace operations_research { // See IMPORTANT NOTE at the top of the file. -void - MinimizeLinearAssignment(const std::vector > &cost, - absl::flat_hash_map *direct_assignment, - absl::flat_hash_map *reverse_assignment); +void MinimizeLinearAssignment( + const std::vector > &cost, + absl::flat_hash_map *direct_assignment, + absl::flat_hash_map *reverse_assignment); // See IMPORTANT NOTE at the top of the file. -void - MaximizeLinearAssignment(const std::vector > &cost, - absl::flat_hash_map *direct_assignment, - absl::flat_hash_map *reverse_assignment); +void MaximizeLinearAssignment( + const std::vector > &cost, + absl::flat_hash_map *direct_assignment, + absl::flat_hash_map *reverse_assignment); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_HUNGARIAN_H_ +#endif // OR_TOOLS_ALGORITHMS_HUNGARIAN_H_ diff --git a/ortools/algorithms/hungarian_test.cc b/ortools/algorithms/hungarian_test.cc index 1b7ec461e8..a328b6d48e 100644 --- a/ortools/algorithms/hungarian_test.cc +++ b/ortools/algorithms/hungarian_test.cc @@ -65,24 +65,24 @@ TEST(LinearAssignmentTest, NullMatrix) { TestMaximization(cost, 0, expected_agents, expected_tasks); } -#define MATRIX_TEST \ - { \ - std::vector > cost(kMatrixHeight); \ - for (int row = 0; row < kMatrixHeight; ++row) { \ - cost[row].resize(kMatrixWidth); \ - for (int col = 0; col < kMatrixWidth; ++col) { \ - cost[row][col] = kCost[row][col]; \ - } \ - } \ - EXPECT_EQ(arraysize(expected_agents_for_min), \ - arraysize(expected_tasks_for_min)); \ - EXPECT_EQ(arraysize(expected_agents_for_max), \ - arraysize(expected_tasks_for_max)); \ - const int assignment_size = arraysize(expected_agents_for_max); \ - TestMinimization(cost, assignment_size, expected_agents_for_min, \ - expected_tasks_for_min); \ - TestMaximization(cost, assignment_size, expected_agents_for_max, \ - expected_tasks_for_max); \ +#define MATRIX_TEST \ + { \ + std::vector > cost(kMatrixHeight); \ + for (int row = 0; row < kMatrixHeight; ++row) { \ + cost[row].resize(kMatrixWidth); \ + for (int col = 0; col < kMatrixWidth; ++col) { \ + cost[row][col] = kCost[row][col]; \ + } \ + } \ + EXPECT_EQ(arraysize(expected_agents_for_min), \ + arraysize(expected_tasks_for_min)); \ + EXPECT_EQ(arraysize(expected_agents_for_max), \ + arraysize(expected_tasks_for_max)); \ + const int assignment_size = arraysize(expected_agents_for_max); \ + TestMinimization(cost, assignment_size, expected_agents_for_min, \ + expected_tasks_for_min); \ + TestMaximization(cost, assignment_size, expected_agents_for_max, \ + expected_tasks_for_max); \ } // Test on a 1x1 matrix @@ -90,11 +90,11 @@ TEST(LinearAssignmentTest, NullMatrix) { TEST(LinearAssignmentTest, SizeOneMatrix) { const int kMatrixHeight = 1; const int kMatrixWidth = 1; - const double kCost[kMatrixHeight][kMatrixWidth] = { { 4 } }; - const int expected_agents_for_min[] = { 0 }; - const int expected_tasks_for_min[] = { 0 }; - const int expected_agents_for_max[] = { 0 }; - const int expected_tasks_for_max[] = { 0 }; + const double kCost[kMatrixHeight][kMatrixWidth] = {{4}}; + const int expected_agents_for_min[] = {0}; + const int expected_tasks_for_min[] = {0}; + const int expected_agents_for_max[] = {0}; + const int expected_tasks_for_max[] = {0}; MATRIX_TEST; } @@ -103,14 +103,14 @@ TEST(LinearAssignmentTest, SizeOneMatrix) { TEST(LinearAssignmentTest, Small4x4Matrix) { const int kMatrixHeight = 4; const int kMatrixWidth = 4; - const double kCost[kMatrixHeight][kMatrixWidth] = { { 90, 75, 75, 80 }, - { 35, 85, 55, 65 }, - { 125, 95, 90, 105 }, - { 45, 110, 95, 115 } }; - const int expected_agents_for_min[] = { 0, 1, 2, 3 }; - const int expected_tasks_for_min[] = { 3, 2, 1, 0 }; - const int expected_agents_for_max[] = { 0, 1, 2, 3 }; - const int expected_tasks_for_max[] = { 2, 1, 0, 3 }; + const double kCost[kMatrixHeight][kMatrixWidth] = {{90, 75, 75, 80}, + {35, 85, 55, 65}, + {125, 95, 90, 105}, + {45, 110, 95, 115}}; + const int expected_agents_for_min[] = {0, 1, 2, 3}; + const int expected_tasks_for_min[] = {3, 2, 1, 0}; + const int expected_agents_for_max[] = {0, 1, 2, 3}; + const int expected_tasks_for_max[] = {2, 1, 0, 3}; MATRIX_TEST; } @@ -118,13 +118,12 @@ TEST(LinearAssignmentTest, Small4x4Matrix) { TEST(LinearAssignmentTest, Small3x4Matrix) { const int kMatrixHeight = 3; const int kMatrixWidth = 4; - const double kCost[kMatrixHeight][kMatrixWidth] = { { 90, 75, 75, 80 }, - { 35, 85, 55, 65 }, - { 125, 95, 90, 105 } }; - const int expected_agents_for_min[] = { 0, 1, 2 }; - const int expected_tasks_for_min[] = { 1, 0, 2 }; - const int expected_agents_for_max[] = { 0, 1, 2 }; - const int expected_tasks_for_max[] = { 3, 1, 0 }; + const double kCost[kMatrixHeight][kMatrixWidth] = { + {90, 75, 75, 80}, {35, 85, 55, 65}, {125, 95, 90, 105}}; + const int expected_agents_for_min[] = {0, 1, 2}; + const int expected_tasks_for_min[] = {1, 0, 2}; + const int expected_agents_for_max[] = {0, 1, 2}; + const int expected_tasks_for_max[] = {3, 1, 0}; MATRIX_TEST; } @@ -133,15 +132,14 @@ TEST(LinearAssignmentTest, Small4x3Matrix) { const int kMatrixHeight = 4; const int kMatrixWidth = 3; const double kCost[kMatrixHeight][kMatrixWidth] = { - { 90, 75, 75 }, { 35, 85, 55 }, { 125, 95, 90 }, { 45, 110, 95 } - }; - const int expected_agents_for_min[] = { 0, 1, 3 }; - const int expected_tasks_for_min[] = { 1, 2, 0 }; - const int expected_agents_for_max[] = { 0, 2, 3 }; - const int expected_tasks_for_max[] = { 2, 0, 1 }; + {90, 75, 75}, {35, 85, 55}, {125, 95, 90}, {45, 110, 95}}; + const int expected_agents_for_min[] = {0, 1, 3}; + const int expected_tasks_for_min[] = {1, 2, 0}; + const int expected_agents_for_max[] = {0, 2, 3}; + const int expected_tasks_for_max[] = {2, 0, 1}; MATRIX_TEST; } #undef MATRIX_TEST -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/knapsack_solver.cc b/ortools/algorithms/knapsack_solver.cc index adbedf3b65..e7695c84a4 100644 --- a/ortools/algorithms/knapsack_solver.cc +++ b/ortools/algorithms/knapsack_solver.cc @@ -63,7 +63,8 @@ struct CompareKnapsackSearchNodePtrInDecreasingUpperBoundOrder { typedef std::priority_queue< KnapsackSearchNode *, std::vector, - CompareKnapsackSearchNodePtrInDecreasingUpperBoundOrder> SearchQueue; + CompareKnapsackSearchNodePtrInDecreasingUpperBoundOrder> + SearchQueue; // Returns true when value_1 * value_2 may overflow int64. inline bool WillProductOverflow(int64 value_1, int64 value_2) { @@ -78,9 +79,7 @@ inline bool WillProductOverflow(int64 value_1, int64 value_2) { // Returns an upper bound of (numerator_1 * numerator_2) / denominator int64 UpperBoundOfRatio(int64 numerator_1, int64 numerator_2, int64 denominator) { - DCHECK_GT(denominator, int64 { - 0 - }); + DCHECK_GT(denominator, int64{0}); if (!WillProductOverflow(numerator_1, numerator_2)) { const int64 numerator = numerator_1 * numerator_2; // Round to zero. @@ -96,14 +95,17 @@ int64 UpperBoundOfRatio(int64 numerator_1, int64 numerator_2, } } -} // namespace +} // namespace // ----- KnapsackSearchNode ----- KnapsackSearchNode::KnapsackSearchNode(const KnapsackSearchNode *const parent, const KnapsackAssignment &assignment) - : depth_((parent == nullptr) ? 0 : parent->depth() + 1), parent_(parent), - assignment_(assignment), current_profit_(0), - profit_upper_bound_(kint64max), next_item_id_(kNoSelection) {} + : depth_((parent == nullptr) ? 0 : parent->depth() + 1), + parent_(parent), + assignment_(assignment), + current_profit_(0), + profit_upper_bound_(kint64max), + next_item_id_(kNoSelection) {} // ----- KnapsackSearchPath ----- KnapsackSearchPath::KnapsackSearchPath(const KnapsackSearchNode &from, @@ -123,9 +125,8 @@ void KnapsackSearchPath::Init() { via_ = node_from; } -const KnapsackSearchNode * -KnapsackSearchPath::MoveUpToDepth(const KnapsackSearchNode &node, - int depth) const { +const KnapsackSearchNode *KnapsackSearchPath::MoveUpToDepth( + const KnapsackSearchNode &node, int depth) const { const KnapsackSearchNode *current_node = &node; while (current_node->depth() > depth) { current_node = current_node->parent(); @@ -159,8 +160,11 @@ bool KnapsackState::UpdateState(bool revert, // ----- KnapsackPropagator ----- KnapsackPropagator::KnapsackPropagator(const KnapsackState &state) - : items_(), current_profit_(0), profit_lower_bound_(0), - profit_upper_bound_(kint64max), state_(state) {} + : items_(), + current_profit_(0), + profit_lower_bound_(0), + profit_upper_bound_(kint64max), + state_(state) {} KnapsackPropagator::~KnapsackPropagator() { gtl::STLDeleteElements(&items_); } @@ -204,8 +208,12 @@ void KnapsackPropagator::CopyCurrentStateToSolution( // ----- KnapsackCapacityPropagator ----- KnapsackCapacityPropagator::KnapsackCapacityPropagator( const KnapsackState &state, int64 capacity) - : KnapsackPropagator(state), capacity_(capacity), consumed_capacity_(0), - break_item_id_(kNoSelection), sorted_items_(), profit_max_(0) {} + : KnapsackPropagator(state), + capacity_(capacity), + consumed_capacity_(0), + break_item_id_(kNoSelection), + sorted_items_(), + profit_max_(0) {} KnapsackCapacityPropagator::~KnapsackCapacityPropagator() {} @@ -326,16 +334,20 @@ int64 KnapsackCapacityPropagator::GetAdditionalProfit(int64 remaining_capacity, // ----- KnapsackGenericSolver ----- KnapsackGenericSolver::KnapsackGenericSolver(const std::string &solver_name) - : BaseKnapsackSolver(solver_name), propagators_(), - master_propagator_id_(kMasterPropagatorId), search_nodes_(), state_(), - best_solution_profit_(0), best_solution_() {} + : BaseKnapsackSolver(solver_name), + propagators_(), + master_propagator_id_(kMasterPropagatorId), + search_nodes_(), + state_(), + best_solution_profit_(0), + best_solution_() {} KnapsackGenericSolver::~KnapsackGenericSolver() { Clear(); } -void -KnapsackGenericSolver::Init(const std::vector &profits, - const std::vector > &weights, - const std::vector &capacities) { +void KnapsackGenericSolver::Init( + const std::vector &profits, + const std::vector > &weights, + const std::vector &capacities) { CHECK_EQ(capacities.size(), weights.size()); Clear(); @@ -366,9 +378,10 @@ void KnapsackGenericSolver::GetLowerAndUpperBoundWhenItem(int item_id, *lower_bound = 0LL; *upper_bound = 0LL; } else { - *lower_bound = (HasOnePropagator()) ? propagators_[master_propagator_id_] - ->profit_lower_bound() - : 0LL; + *lower_bound = + (HasOnePropagator()) + ? propagators_[master_propagator_id_]->profit_lower_bound() + : 0LL; *upper_bound = GetAggregatedProfitUpperBound(); } @@ -500,9 +513,8 @@ bool KnapsackGenericSolver::MakeNewNode(const KnapsackSearchNode &node, return true; } -bool -KnapsackGenericSolver::IncrementalUpdate(bool revert, - const KnapsackAssignment &assignment) { +bool KnapsackGenericSolver::IncrementalUpdate( + bool revert, const KnapsackAssignment &assignment) { // Do not stop on a failure: To be able to be incremental on the update, // partial solution (state) and propagators must all be in the same state. bool no_fail = state_.UpdateState(revert, assignment); @@ -520,8 +532,8 @@ void KnapsackGenericSolver::UpdateBestSolution() { if (best_solution_profit_ < profit_lower_bound) { best_solution_profit_ = profit_lower_bound; - propagators_[master_propagator_id_] - ->CopyCurrentStateToSolution(HasOnePropagator(), &best_solution_); + propagators_[master_propagator_id_]->CopyCurrentStateToSolution( + HasOnePropagator(), &best_solution_); } } @@ -531,7 +543,7 @@ void KnapsackGenericSolver::UpdateBestSolution() { // Experiments show better results than KnapsackGenericSolver when the // number of items is less than 15. class KnapsackBruteForceSolver : public BaseKnapsackSolver { -public: + public: explicit KnapsackBruteForceSolver(const std::string &solver_name); // Initializes the solver and enters the problem to be solved. @@ -547,7 +559,7 @@ public: return (best_solution_ & OneBit32(item_id)) != 0U; } -private: + private: int num_items_; int64 profits_weights_[kMaxNumberOfBruteForceItems * 2]; int64 capacity_; @@ -559,13 +571,16 @@ private: KnapsackBruteForceSolver::KnapsackBruteForceSolver( const std::string &solver_name) - : BaseKnapsackSolver(solver_name), num_items_(0), capacity_(0LL), - best_solution_profit_(0LL), best_solution_(0U) {} + : BaseKnapsackSolver(solver_name), + num_items_(0), + capacity_(0LL), + best_solution_profit_(0LL), + best_solution_(0U) {} -void -KnapsackBruteForceSolver::Init(const std::vector &profits, - const std::vector > &weights, - const std::vector &capacities) { +void KnapsackBruteForceSolver::Init( + const std::vector &profits, + const std::vector > &weights, + const std::vector &capacities) { // TODO(user): Implement multi-dimensional brute force solver. CHECK_EQ(weights.size(), 1) << "Brute force solver only works with one dimension."; @@ -606,12 +621,12 @@ int64 KnapsackBruteForceSolver::Solve(TimeLimit *time_limit, local_state = state; item_id = 0; while (diff_state) { - if (diff_state & 1U) { // There is a diff. - if (local_state & 1U) { // This item is now in the knapsack. + if (diff_state & 1U) { // There is a diff. + if (local_state & 1U) { // This item is now in the knapsack. sum_profit += profits_weights_[item_id]; sum_weight += profits_weights_[item_id + 1]; CHECK_LT(item_id + 1, 2 * num_items_); - } else { // This item has been removed of the knapsack. + } else { // This item has been removed of the knapsack. sum_profit -= profits_weights_[item_id]; sum_weight -= profits_weights_[item_id + 1]; CHECK_LT(item_id + 1, 2 * num_items_); @@ -640,7 +655,9 @@ int64 KnapsackBruteForceSolver::Solve(TimeLimit *time_limit, struct KnapsackItemWithEfficiency { KnapsackItemWithEfficiency(int _id, int64 _profit, int64 _weight, int64 _profit_max) - : id(_id), profit(_profit), weight(_weight), + : id(_id), + profit(_profit), + weight(_weight), efficiency((weight > 0) ? static_cast(_profit) / static_cast(_weight) : static_cast(_profit_max)) {} @@ -656,7 +673,7 @@ struct KnapsackItemWithEfficiency { // items is less or equal to 64. This implementation is about 4 times faster // than KnapsackGenericSolver. class Knapsack64ItemsSolver : public BaseKnapsackSolver { -public: + public: explicit Knapsack64ItemsSolver(const std::string &solver_name); // Initializes the solver and enters the problem to be solved. @@ -672,7 +689,7 @@ public: return (best_solution_ & OneBit64(item_id)) != 0ULL; } -private: + private: int GetBreakItemId(int64 capacity) const; void GetLowerAndUpperBound(int64 *lower_bound, int64 *upper_bound) const; void GoToNextState(bool has_failed); @@ -706,16 +723,24 @@ bool CompareKnapsackItemWithEfficiencyInDecreasingEfficiencyOrder( // ----- Knapsack64ItemsSolver ----- Knapsack64ItemsSolver::Knapsack64ItemsSolver(const std::string &solver_name) - : BaseKnapsackSolver(solver_name), sorted_items_(), sum_profits_(), - sum_weights_(), capacity_(0LL), state_(0ULL), state_depth_(0), - best_solution_profit_(0LL), best_solution_(0ULL), best_solution_depth_(0), - state_weight_(0LL), rejected_items_profit_(0LL), + : BaseKnapsackSolver(solver_name), + sorted_items_(), + sum_profits_(), + sum_weights_(), + capacity_(0LL), + state_(0ULL), + state_depth_(0), + best_solution_profit_(0LL), + best_solution_(0ULL), + best_solution_depth_(0), + state_weight_(0LL), + rejected_items_profit_(0LL), rejected_items_weight_(0LL) {} -void -Knapsack64ItemsSolver::Init(const std::vector &profits, - const std::vector > &weights, - const std::vector &capacities) { +void Knapsack64ItemsSolver::Init( + const std::vector &profits, + const std::vector > &weights, + const std::vector &capacities) { CHECK_EQ(weights.size(), 1) << "Brute force solver only works with one dimension."; CHECK_EQ(capacities.size(), weights.size()); @@ -831,7 +856,7 @@ void Knapsack64ItemsSolver::GetLowerAndUpperBound(int64 *lower_bound, // (10% speed-up). That's the reason why the loop version is implemented. void Knapsack64ItemsSolver::GoToNextState(bool has_failed) { uint64 mask = OneBit64(state_depth_); - if (!has_failed) { // Go to next item. + if (!has_failed) { // Go to next item. ++state_depth_; state_ = state_ | (mask << 1); state_weight_ += sorted_items_[state_depth_].weight; @@ -845,7 +870,7 @@ void Knapsack64ItemsSolver::GoToNextState(bool has_failed) { mask = mask >> 1ULL; } - if (state_ & mask) { // Item was in, remove it. + if (state_ & mask) { // Item was in, remove it. state_ = state_ & ~mask; const KnapsackItemWithEfficiency &item = sorted_items_[state_depth_]; rejected_items_profit_ += item.profit; @@ -905,7 +930,7 @@ void Knapsack64ItemsSolver::BuildBestSolution() { // The implemented algorithm is 'DP-3' in "Knapsack problems", Hans Kellerer, // Ulrich Pferschy and David Pisinger, Springer book (ISBN 978-3540402862). class KnapsackDynamicProgrammingSolver : public BaseKnapsackSolver { -public: + public: explicit KnapsackDynamicProgrammingSolver(const std::string &solver_name); // Initializes the solver and enters the problem to be solved. @@ -921,7 +946,7 @@ public: return best_solution_.at(item_id); } -private: + private: int64 SolveSubProblem(int64 capacity, int num_items); std::vector profits_; @@ -935,8 +960,13 @@ private: // ----- KnapsackDynamicProgrammingSolver ----- KnapsackDynamicProgrammingSolver::KnapsackDynamicProgrammingSolver( const std::string &solver_name) - : BaseKnapsackSolver(solver_name), profits_(), weights_(), capacity_(0), - computed_profits_(), selected_item_ids_(), best_solution_() {} + : BaseKnapsackSolver(solver_name), + profits_(), + weights_(), + capacity_(0), + computed_profits_(), + selected_item_ids_(), + best_solution_() {} void KnapsackDynamicProgrammingSolver::Init( const std::vector &profits, @@ -956,9 +986,7 @@ int64 KnapsackDynamicProgrammingSolver::SolveSubProblem(int64 capacity, int num_items) { const int64 capacity_plus_1 = capacity + 1; std::fill_n(selected_item_ids_.begin(), capacity_plus_1, 0); - std::fill_n(computed_profits_.begin(), capacity_plus_1, int64 { - 0 - }); + std::fill_n(computed_profits_.begin(), capacity_plus_1, int64{0}); for (int item_id = 0; item_id < num_items; ++item_id) { const int64 item_weight = weights_[item_id]; const int64 item_profit = profits_[item_id]; @@ -1001,7 +1029,7 @@ int64 KnapsackDynamicProgrammingSolver::Solve(TimeLimit *time_limit, // ----- KnapsackMIPSolver ----- class KnapsackMIPSolver : public BaseKnapsackSolver { -public: + public: KnapsackMIPSolver(MPSolver::OptimizationProblemType problem_type, const std::string &solver_name); @@ -1018,7 +1046,7 @@ public: return best_solution_.at(item_id); } -private: + private: MPSolver::OptimizationProblemType problem_type_; std::vector profits_; std::vector > weights_; @@ -1029,8 +1057,12 @@ private: KnapsackMIPSolver::KnapsackMIPSolver( MPSolver::OptimizationProblemType problem_type, const std::string &solver_name) - : BaseKnapsackSolver(solver_name), problem_type_(problem_type), profits_(), - weights_(), capacities_(), best_solution_() {} + : BaseKnapsackSolver(solver_name), + problem_type_(problem_type), + profits_(), + weights_(), + capacities_(), + best_solution_() {} void KnapsackMIPSolver::Init(const std::vector &profits, const std::vector > &weights, @@ -1092,48 +1124,54 @@ KnapsackSolver::KnapsackSolver(const std::string &solver_name) KnapsackSolver::KnapsackSolver(SolverType solver_type, const std::string &solver_name) - : solver_(), known_value_(), best_solution_(), mapping_reduced_item_id_(), - is_problem_solved_(false), additional_profit_(0LL), use_reduction_(true), + : solver_(), + known_value_(), + best_solution_(), + mapping_reduced_item_id_(), + is_problem_solved_(false), + additional_profit_(0LL), + use_reduction_(true), time_limit_seconds_(std::numeric_limits::infinity()) { switch (solver_type) { - case KNAPSACK_BRUTE_FORCE_SOLVER: - solver_ = absl::make_unique(solver_name); - break; - case KNAPSACK_64ITEMS_SOLVER: - solver_ = absl::make_unique(solver_name); - break; - case KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER: - solver_ = absl::make_unique(solver_name); - break; - case KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER: - solver_ = absl::make_unique(solver_name); - break; + case KNAPSACK_BRUTE_FORCE_SOLVER: + solver_ = absl::make_unique(solver_name); + break; + case KNAPSACK_64ITEMS_SOLVER: + solver_ = absl::make_unique(solver_name); + break; + case KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER: + solver_ = + absl::make_unique(solver_name); + break; + case KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER: + solver_ = absl::make_unique(solver_name); + break; #if defined(USE_CBC) - case KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER: - solver_ = absl::make_unique( - MPSolver::CBC_MIXED_INTEGER_PROGRAMMING, solver_name); - break; -#endif // USE_CBC + case KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER: + solver_ = absl::make_unique( + MPSolver::CBC_MIXED_INTEGER_PROGRAMMING, solver_name); + break; +#endif // USE_CBC #if defined(USE_SCIP) - case KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER: - solver_ = absl::make_unique( - MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING, solver_name); - break; -#endif // USE_SCIP + case KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER: + solver_ = absl::make_unique( + MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING, solver_name); + break; +#endif // USE_SCIP #if defined(USE_XPRESS) - case KNAPSACK_MULTIDIMENSION_XPRESS_MIP_SOLVER: - solver_ = absl::make_unique( - MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, solver_name); - break; + case KNAPSACK_MULTIDIMENSION_XPRESS_MIP_SOLVER: + solver_ = absl::make_unique( + MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, solver_name); + break; #endif #if defined(USE_CPLEX) - case KNAPSACK_MULTIDIMENSION_CPLEX_MIP_SOLVER: - solver_ = absl::make_unique( - MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, solver_name); - break; + case KNAPSACK_MULTIDIMENSION_CPLEX_MIP_SOLVER: + solver_ = absl::make_unique( + MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, solver_name); + break; #endif - default: - LOG(FATAL) << "Unknown knapsack solver type."; + default: + LOG(FATAL) << "Unknown knapsack solver type."; } } @@ -1270,8 +1308,8 @@ int KnapsackSolver::ReduceProblem(int num_items) { return num_reduced_items; } -void -KnapsackSolver::ComputeAdditionalProfit(const std::vector &profits) { +void KnapsackSolver::ComputeAdditionalProfit( + const std::vector &profits) { const int num_items = profits.size(); additional_profit_ = 0LL; for (int item_id = 0; item_id < num_items; ++item_id) { @@ -1317,8 +1355,9 @@ void KnapsackSolver::InitReducedProblem( int64 KnapsackSolver::Solve() { return additional_profit_ + - ((is_problem_solved_) ? 0 : solver_->Solve(time_limit_.get(), - &is_solution_optimal_)); + ((is_problem_solved_) + ? 0 + : solver_->Solve(time_limit_.get(), &is_solution_optimal_)); } bool KnapsackSolver::BestSolutionContains(int item_id) const { @@ -1342,4 +1381,4 @@ void BaseKnapsackSolver::GetLowerAndUpperBoundWhenItem(int item_id, *upper_bound = kint64max; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/knapsack_solver.h b/ortools/algorithms/knapsack_solver.h index fa8a8827c4..45b4035ffe 100644 --- a/ortools/algorithms/knapsack_solver.h +++ b/ortools/algorithms/knapsack_solver.h @@ -118,7 +118,7 @@ class BaseKnapsackSolver; */ class KnapsackSolver { -public: + public: /** Enum controlling which underlying algorithm is used. * * This enum is passed to the constructor of the KnapsackSolver object. @@ -156,7 +156,7 @@ public: * dimensions. This solver is based on Integer Programming solver CBC. */ KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER = 3, -#endif // USE_CBC +#endif // USE_CBC /** Generic Solver. * @@ -172,7 +172,7 @@ public: * dimensions. This solver is based on Integer Programming solver SCIP. */ KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER = 6, -#endif // USE_SCIP +#endif // USE_SCIP #if defined(USE_XPRESS) /** XPRESS based solver @@ -232,7 +232,7 @@ public: time_limit_ = absl::make_unique(time_limit_seconds_); } -private: + private: // Trivial reduction of capacity constraints when the capacity is higher than // the sum of the weights of the items. Returns the number of reduced items. int ReduceCapacities(int num_items, @@ -332,7 +332,7 @@ typedef KnapsackItem *KnapsackItemPtr; // go through the search tree to incrementally build a partial solution from // a previous search node. class KnapsackSearchNode { -public: + public: KnapsackSearchNode(const KnapsackSearchNode *const parent, const KnapsackAssignment &assignment); int depth() const { return depth_; } @@ -348,7 +348,7 @@ public: int next_item_id() const { return next_item_id_; } void set_next_item_id(int id) { next_item_id_ = id; } -private: + private: // 'depth' field is used to navigate efficiently through the search tree // (see KnapsackSearchPath). int depth_; @@ -386,7 +386,7 @@ private: // So the state can be built by reverting all decisions from 'from' to 'via' // and then applying all decisions from 'via' to 'to'. class KnapsackSearchPath { -public: + public: KnapsackSearchPath(const KnapsackSearchNode &from, const KnapsackSearchNode &to); void Init(); @@ -396,9 +396,9 @@ public: const KnapsackSearchNode *MoveUpToDepth(const KnapsackSearchNode &node, int depth) const; -private: + private: const KnapsackSearchNode &from_; - const KnapsackSearchNode *via_; // Computed in 'Init'. + const KnapsackSearchNode *via_; // Computed in 'Init'. const KnapsackSearchNode &to_; DISALLOW_COPY_AND_ASSIGN(KnapsackSearchPath); @@ -407,7 +407,7 @@ private: // ----- KnapsackState ----- // KnapsackState represents a partial solution to the knapsack problem. class KnapsackState { -public: + public: KnapsackState(); // Initializes vectors with number_of_items set to false (i.e. not bound yet). @@ -421,7 +421,7 @@ public: bool is_bound(int id) const { return is_bound_.at(id); } bool is_in(int id) const { return is_in_.at(id); } -private: + private: // Vectors 'is_bound_' and 'is_in_' contain a boolean value for each item. // 'is_bound_(item_i)' is false when there is no decision for item_i yet. // When item_i is bound, 'is_in_(item_i)' represents the presence (true) or @@ -441,7 +441,7 @@ private: // For instance, 'Init' creates a vector of items, and then calls // 'InitPropagator' to let the derived class perform its own initialization. class KnapsackPropagator { -public: + public: explicit KnapsackPropagator(const KnapsackState &state); virtual ~KnapsackPropagator(); @@ -472,7 +472,7 @@ public: void CopyCurrentStateToSolution(bool has_one_propagator, std::vector *solution) const; -protected: + protected: // Initializes data structure. This method is called after initialization // of KnapsackPropagator data structure. virtual void InitPropagator() = 0; @@ -496,7 +496,7 @@ protected: void set_profit_lower_bound(int64 profit) { profit_lower_bound_ = profit; } void set_profit_upper_bound(int64 profit) { profit_upper_bound_ = profit; } -private: + private: std::vector items_; int64 current_profit_; int64 profit_lower_bound_; @@ -527,24 +527,24 @@ private: // For incrementality reasons, the ith item should be accessible in O(1). That's // the reason why the item vector has to be duplicated 'sorted_items_'. class KnapsackCapacityPropagator : public KnapsackPropagator { -public: + public: KnapsackCapacityPropagator(const KnapsackState &state, int64 capacity); ~KnapsackCapacityPropagator() override; void ComputeProfitBounds() override; int GetNextItemId() const override { return break_item_id_; } -protected: + protected: // Initializes KnapsackCapacityPropagator (e.g., sort items in decreasing // order). void InitPropagator() override; // Updates internal data structure incrementally (i.e., 'consumed_capacity_') // to avoid a O(number_of_items) scan. - bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment) - override; - void CopyCurrentStateToSolutionPropagator(std::vector *solution) const - override; + bool UpdatePropagator(bool revert, + const KnapsackAssignment &assignment) override; + void CopyCurrentStateToSolutionPropagator( + std::vector *solution) const override; -private: + private: // An obvious additional profit upper bound corresponds to the linear // relaxation: remaining_capacity * efficiency of the break item. // It is possible to do better in O(1), using Martello-Toth bound U2. @@ -567,7 +567,7 @@ private: // ----- BaseKnapsackSolver ----- // This is the base class for knapsack solvers. class BaseKnapsackSolver { -public: + public: explicit BaseKnapsackSolver(const std::string &solver_name) : solver_name_(solver_name) {} virtual ~BaseKnapsackSolver() {} @@ -592,7 +592,7 @@ public: virtual std::string GetName() const { return solver_name_; } -private: + private: const std::string solver_name_; }; @@ -606,7 +606,7 @@ private: // an aggregated propagator to combine all dimensions and give a better guide // to select the next item (see, for instance, Dobson's aggregated efficiency). class KnapsackGenericSolver : public BaseKnapsackSolver { -public: + public: explicit KnapsackGenericSolver(const std::string &solver_name); ~KnapsackGenericSolver() override; @@ -616,8 +616,8 @@ public: const std::vector &capacities) override; int GetNumberOfItems() const { return state_.GetNumberOfItems(); } void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, - int64 *lower_bound, int64 *upper_bound) - override; + int64 *lower_bound, + int64 *upper_bound) override; // Sets which propagator should be used to guide the search. // 'master_propagator_id' should be in 0..p-1 with p the number of @@ -633,7 +633,7 @@ public: return best_solution_.at(item_id); } -private: + private: // Clears internal data structure. void Clear(); @@ -671,7 +671,7 @@ private: DISALLOW_COPY_AND_ASSIGN(KnapsackGenericSolver); }; -#endif // SWIG -} // namespace operations_research +#endif // SWIG +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_ +#endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_ diff --git a/ortools/algorithms/knapsack_solver_for_cuts.cc b/ortools/algorithms/knapsack_solver_for_cuts.cc index 2729f54f40..d87c3cd901 100644 --- a/ortools/algorithms/knapsack_solver_for_cuts.cc +++ b/ortools/algorithms/knapsack_solver_for_cuts.cc @@ -59,15 +59,18 @@ using SearchQueue = std::priority_queue< KnapsackSearchNodeForCuts *, std::vector, CompareKnapsackSearchNodePtrInDecreasingUpperBoundOrder>; -} // namespace +} // namespace // ----- KnapsackSearchNodeForCuts ----- KnapsackSearchNodeForCuts::KnapsackSearchNodeForCuts( const KnapsackSearchNodeForCuts *const parent, const KnapsackAssignmentForCuts &assignment) - : depth_(parent == nullptr ? 0 : parent->depth() + 1), parent_(parent), - assignment_(assignment), current_profit_(0), - profit_upper_bound_(kInfinity), next_item_id_(kNoSelection) {} + : depth_(parent == nullptr ? 0 : parent->depth() + 1), + parent_(parent), + assignment_(assignment), + current_profit_(0), + profit_upper_bound_(kInfinity), + next_item_id_(kNoSelection) {} // ----- KnapsackSearchPathForCuts ----- KnapsackSearchPathForCuts::KnapsackSearchPathForCuts( @@ -88,8 +91,8 @@ void KnapsackSearchPathForCuts::Init() { via_ = node_from; } -const KnapsackSearchNodeForCuts * -MoveUpToDepth(const KnapsackSearchNodeForCuts *node, int depth) { +const KnapsackSearchNodeForCuts *MoveUpToDepth( + const KnapsackSearchNodeForCuts *node, int depth) { while (node->depth() > depth) { node = node->parent(); } @@ -105,9 +108,8 @@ void KnapsackStateForCuts::Init(int number_of_items) { } // Returns false when the state is invalid. -bool -KnapsackStateForCuts::UpdateState(bool revert, - const KnapsackAssignmentForCuts &assignment) { +bool KnapsackStateForCuts::UpdateState( + bool revert, const KnapsackAssignmentForCuts &assignment) { if (revert) { is_bound_[assignment.item_id] = false; } else { @@ -124,8 +126,11 @@ KnapsackStateForCuts::UpdateState(bool revert, // ----- KnapsackPropagatorForCuts ----- KnapsackPropagatorForCuts::KnapsackPropagatorForCuts( const KnapsackStateForCuts *state) - : items_(), current_profit_(0), profit_lower_bound_(0), - profit_upper_bound_(kInfinity), state_(state) {} + : items_(), + current_profit_(0), + profit_lower_bound_(0), + profit_upper_bound_(kInfinity), + state_(state) {} KnapsackPropagatorForCuts::~KnapsackPropagatorForCuts() {} @@ -146,9 +151,8 @@ void KnapsackPropagatorForCuts::Init(const std::vector &profits, InitPropagator(); } -bool -KnapsackPropagatorForCuts::Update(bool revert, - const KnapsackAssignmentForCuts &assignment) { +bool KnapsackPropagatorForCuts::Update( + bool revert, const KnapsackAssignmentForCuts &assignment) { if (assignment.is_in) { if (revert) { current_profit_ -= items_[assignment.item_id]->profit; @@ -275,7 +279,8 @@ double KnapsackPropagatorForCuts::GetAdditionalProfitUpperBound( // ----- KnapsackSolverForCuts ----- KnapsackSolverForCuts::KnapsackSolverForCuts(std::string solver_name) - : propagator_(&state_), best_solution_profit_(0), + : propagator_(&state_), + best_solution_profit_(0), solver_name_(std::move(solver_name)) {} void KnapsackSolverForCuts::Init(const std::vector &profits, @@ -328,7 +333,7 @@ double KnapsackSolverForCuts::Solve(TimeLimit *time_limit, root_node->set_next_item_id(GetNextItemId()); search_nodes_.push_back(std::move(root_node)); const KnapsackSearchNodeForCuts *current_node = - search_nodes_.back().get(); // Start with the root node. + search_nodes_.back().get(); // Start with the root node. if (MakeNewNode(*current_node, false)) { search_queue.push(search_nodes_.back().get()); @@ -460,4 +465,4 @@ void KnapsackSolverForCuts::UpdateBestSolution() { } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/knapsack_solver_for_cuts.h b/ortools/algorithms/knapsack_solver_for_cuts.h index c9c5440de9..9a73a576e2 100644 --- a/ortools/algorithms/knapsack_solver_for_cuts.h +++ b/ortools/algorithms/knapsack_solver_for_cuts.h @@ -100,7 +100,7 @@ using KnapsackItemForCutsPtr = std::unique_ptr; // go through the search tree to incrementally build a partial solution from // a previous search node. class KnapsackSearchNodeForCuts { -public: + public: KnapsackSearchNodeForCuts(const KnapsackSearchNodeForCuts *parent, const KnapsackAssignmentForCuts &assignment); @@ -121,7 +121,7 @@ public: int next_item_id() const { return next_item_id_; } void set_next_item_id(int id) { next_item_id_ = id; } -private: + private: // 'depth_' is used to navigate efficiently through the search tree. int depth_; const KnapsackSearchNodeForCuts *const parent_; @@ -156,7 +156,7 @@ private: // So the state can be built by reverting all decisions from 'from' to 'via' // and then applying all decisions from 'via' to 'to'. class KnapsackSearchPathForCuts { -public: + public: KnapsackSearchPathForCuts(const KnapsackSearchNodeForCuts *from, const KnapsackSearchNodeForCuts *to); @@ -169,21 +169,21 @@ public: const KnapsackSearchNodeForCuts &via() const { return *via_; } const KnapsackSearchNodeForCuts &to() const { return *to_; } -private: + private: const KnapsackSearchNodeForCuts *from_; - const KnapsackSearchNodeForCuts *via_; // Computed in 'Init'. + const KnapsackSearchNodeForCuts *via_; // Computed in 'Init'. const KnapsackSearchNodeForCuts *to_; }; // From the given node, this method moves up the tree and returns the node at // given depth. -const KnapsackSearchNodeForCuts * - MoveUpToDepth(const KnapsackSearchNodeForCuts *node, int depth); +const KnapsackSearchNodeForCuts *MoveUpToDepth( + const KnapsackSearchNodeForCuts *node, int depth); // ----- KnapsackStateForCuts ----- // KnapsackStateForCuts represents a partial solution to the knapsack problem. class KnapsackStateForCuts { -public: + public: KnapsackStateForCuts(); KnapsackStateForCuts(const KnapsackStateForCuts &) = delete; @@ -201,7 +201,7 @@ public: bool is_bound(int id) const { return is_bound_.at(id); } bool is_in(int id) const { return is_in_.at(id); } -private: + private: // Vectors 'is_bound_' and 'is_in_' contain a boolean value for each item. // 'is_bound_(item_i)' is false when there is no decision for item_i yet. // When item_i is bound, 'is_in_(item_i)' represents the presence (true) or @@ -229,7 +229,7 @@ private: // the ith item should be accessible in O(1). That's the reason why the item // vector has to be duplicated 'sorted_items_'. class KnapsackPropagatorForCuts { -public: + public: explicit KnapsackPropagatorForCuts(const KnapsackStateForCuts *state); ~KnapsackPropagatorForCuts(); @@ -268,7 +268,7 @@ public: void set_profit_lower_bound(double profit) { profit_lower_bound_ = profit; } void set_profit_upper_bound(double profit) { profit_upper_bound_ = profit; } -private: + private: // An obvious additional profit upper bound corresponds to the linear // relaxation: remaining_capacity * efficiency of the break item. // It is possible to do better in O(1), using Martello-Toth bound U2. @@ -298,7 +298,7 @@ private: // master propagator. Using SetMasterPropagator allows changing the default // (propagator of the first dimension). class KnapsackSolverForCuts { -public: + public: explicit KnapsackSolverForCuts(std::string solver_name); KnapsackSolverForCuts(const KnapsackSolverForCuts &) = delete; @@ -345,7 +345,7 @@ public: const std::string &GetName() const { return solver_name_; } -private: + private: // Updates propagator reverting/applying all decision on the path. Returns // true if the propagation fails. Note that even if it fails, propagator // should be updated to be in a stable state in order to stay incremental. @@ -381,6 +381,6 @@ private: }; // TODO(user) : Add reduction algorithm. -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_FOR_CUTS_H_ +#endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_FOR_CUTS_H_ diff --git a/ortools/algorithms/sparse_permutation.cc b/ortools/algorithms/sparse_permutation.cc index c86d0233e0..9c5f19393f 100644 --- a/ortools/algorithms/sparse_permutation.cc +++ b/ortools/algorithms/sparse_permutation.cc @@ -32,8 +32,8 @@ void SparsePermutation::RemoveCycles(const std::vector &cycle_indices) { << "Duplicate index given to RemoveCycles(): " << i; should_be_deleted[i] = true; } - int new_cycles_size = 0; // new index in cycles_ - int new_cycle_ends_size = 0; // new index in cycle_ends_ + int new_cycles_size = 0; // new index in cycles_ + int new_cycle_ends_size = 0; // new index in cycle_ends_ int start = 0; for (int i = 0; i < NumCycles(); ++i) { const int end = cycle_ends_[i]; @@ -51,30 +51,25 @@ void SparsePermutation::RemoveCycles(const std::vector &cycle_indices) { std::string SparsePermutation::DebugString() const { DCHECK_EQ(cycles_.empty(), cycle_ends_.empty()); - if (!cycles_.empty()) - DCHECK_EQ(cycles_.size(), cycle_ends_.back()); + if (!cycles_.empty()) DCHECK_EQ(cycles_.size(), cycle_ends_.back()); std::vector > cycles; int start = 0; for (const int end : cycle_ends_) { // Find the minimum. int min_pos = start; for (int i = start + 1; i < end; ++i) { - if (cycles_[i] < cycles_[min_pos]) - min_pos = i; + if (cycles_[i] < cycles_[min_pos]) min_pos = i; } std::vector cycle; - for (int i = min_pos; i < end; ++i) - cycle.push_back(cycles_[i]); - for (int i = start; i < min_pos; ++i) - cycle.push_back(cycles_[i]); + for (int i = min_pos; i < end; ++i) cycle.push_back(cycles_[i]); + for (int i = start; i < min_pos; ++i) cycle.push_back(cycles_[i]); cycles.push_back(cycle); start = end; } std::sort(cycles.begin(), cycles.end()); std::string out; for (const std::vector &cycle : cycles) { - if (!out.empty()) - out += " "; + if (!out.empty()) out += " "; out += "("; out += absl::StrJoin(cycle, " "); out += ")"; @@ -82,4 +77,4 @@ std::string SparsePermutation::DebugString() const { return out; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/algorithms/sparse_permutation.h b/ortools/algorithms/sparse_permutation.h index bc42a4c3a6..0a4c6a417c 100644 --- a/ortools/algorithms/sparse_permutation.h +++ b/ortools/algorithms/sparse_permutation.h @@ -25,9 +25,8 @@ namespace operations_research { // elements: it needs only O(K) memory for a permutation that displaces // K elements. class SparsePermutation { -public: - explicit SparsePermutation(int size) : size_(size) { - } // Identity. + public: + explicit SparsePermutation(int size) : size_(size) {} // Identity. // TODO(user,user): complete the reader API. int Size() const { return size_; } @@ -76,7 +75,7 @@ public: // Example: "(1 4 3) (5 9) (6 8 7)". std::string DebugString() const; -private: + private: const int size_; std::vector cycles_; std::vector cycle_ends_; @@ -129,6 +128,6 @@ inline int SparsePermutation::LastElementInCycle(int i) const { return cycles_[cycle_ends_[i] - 1]; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_ALGORITHMS_SPARSE_PERMUTATION_H_ +#endif // OR_TOOLS_ALGORITHMS_SPARSE_PERMUTATION_H_ diff --git a/ortools/base/accurate_sum.h b/ortools/base/accurate_sum.h index c3b365ceff..72faa78564 100644 --- a/ortools/base/accurate_sum.h +++ b/ortools/base/accurate_sum.h @@ -19,8 +19,9 @@ namespace operations_research { // Kahan summation compensation algorithm. // // http://en.wikipedia.org/wiki/Kahan_summation_algorithm -template class AccurateSum { -public: +template +class AccurateSum { + public: // You may copy-construct an AccurateSum. AccurateSum() : sum_(), error_sum_() {} @@ -35,11 +36,11 @@ public: // Gets the value of the sum. FpNumber Value() const { return sum_; } -private: + private: FpNumber sum_; FpNumber error_sum_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_ACCURATE_SUM_H_ +#endif // OR_TOOLS_BASE_ACCURATE_SUM_H_ diff --git a/ortools/base/adjustable_priority_queue-inl.h b/ortools/base/adjustable_priority_queue-inl.h index e3412d3e7c..b6af4d4507 100644 --- a/ortools/base/adjustable_priority_queue-inl.h +++ b/ortools/base/adjustable_priority_queue-inl.h @@ -16,4 +16,4 @@ #include "ortools/base/adjustable_priority_queue.h" -#endif // OR_TOOLS_BASE_ADJUSTABLE_PRIORITY_QUEUE_INL_H_ +#endif // OR_TOOLS_BASE_ADJUSTABLE_PRIORITY_QUEUE_INL_H_ diff --git a/ortools/base/adjustable_priority_queue.h b/ortools/base/adjustable_priority_queue.h index f23e6a8ccf..972a385a38 100644 --- a/ortools/base/adjustable_priority_queue.h +++ b/ortools/base/adjustable_priority_queue.h @@ -24,18 +24,19 @@ #include "ortools/base/logging.h" #include "ortools/base/macros.h" -template class LowerPriorityThan { -public: +template +class LowerPriorityThan { + public: explicit LowerPriorityThan(Comparator *compare) : compare_(compare) {} bool operator()(T *a, T *b) const { return (*compare_)(*a, *b); } -private: + private: Comparator *compare_; }; template > class AdjustablePriorityQueue { -public: + public: // The objects references 'c' and 'm' are not required to be alive for the // lifetime of this object. AdjustablePriorityQueue() {} @@ -89,8 +90,7 @@ public: void AllTop(std::vector *topvec) { topvec->clear(); - if (Size() == 0) - return; + if (Size() == 0) return; std::list need_to_check_children; need_to_check_children.push_back(0); // Implements breadth-first search down tree, stopping whenever @@ -150,7 +150,7 @@ public: // program. const std::vector *Raw() const { return &elems_; } -private: + private: void AdjustUpwards(int i) { T *const t = elems_[i]; while (i > 0) { @@ -193,4 +193,4 @@ private: std::vector elems_; }; -#endif // OR_TOOLS_BASE_ADJUSTABLE_PRIORITY_QUEUE_H_ +#endif // OR_TOOLS_BASE_ADJUSTABLE_PRIORITY_QUEUE_H_ diff --git a/ortools/base/base_export.h b/ortools/base/base_export.h index b834aafa77..aab1828143 100644 --- a/ortools/base/base_export.h +++ b/ortools/base/base_export.h @@ -22,21 +22,21 @@ #else #define BASE_EXPORT __declspec(dllimport) #define BASE_EXPORT_PRIVATE __declspec(dllimport) -#endif // defined(BASE_IMPLEMENTATION) +#endif // defined(BASE_IMPLEMENTATION) -#else // defined(WIN32) +#else // defined(WIN32) #if defined(BASE_IMPLEMENTATION) #define BASE_EXPORT __attribute__((visibility("default"))) #define BASE_EXPORT_PRIVATE __attribute__((visibility("default"))) #else #define BASE_EXPORT #define BASE_EXPORT_PRIVATE -#endif // defined(BASE_IMPLEMENTATION) +#endif // defined(BASE_IMPLEMENTATION) #endif -#else // defined(COMPONENT_BUILD) +#else // defined(COMPONENT_BUILD) #define BASE_EXPORT #define BASE_EXPORT_PRIVATE #endif -#endif // OR_TOOLS_BASE_BASE_EXPORT_H_ +#endif // OR_TOOLS_BASE_BASE_EXPORT_H_ diff --git a/ortools/base/basictypes.h b/ortools/base/basictypes.h index d6705cd993..12980c7901 100644 --- a/ortools/base/basictypes.h +++ b/ortools/base/basictypes.h @@ -19,4 +19,4 @@ #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" -#endif // OR_TOOLS_BASE_BASICTYPES_H_ +#endif // OR_TOOLS_BASE_BASICTYPES_H_ diff --git a/ortools/base/bitmap.cc b/ortools/base/bitmap.cc index 51eda6b641..293e7f6b87 100644 --- a/ortools/base/bitmap.cc +++ b/ortools/base/bitmap.cc @@ -38,4 +38,4 @@ void Bitmap::Resize(uint32 size, bool fill) { Set(index, fill); } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/base/bitmap.h b/ortools/base/bitmap.h index 18ff5c9022..73ccf6961d 100644 --- a/ortools/base/bitmap.h +++ b/ortools/base/bitmap.h @@ -33,14 +33,15 @@ inline void SetBit64(uint64 *const bitset, uint64 pos) { inline void ClearBit64(uint64 *const bitset, uint64 pos) { bitset[BitOffset64(pos)] &= ~OneBit64(BitPos64(pos)); } -} // namespace internal +} // namespace internal class Bitmap { -public: + public: // Constructor : This allocates on a uint32 boundary. // fill: true = initialize with 1's, false = initialize with 0's. explicit Bitmap(uint32 size, bool fill = false) - : max_size_(size), array_size_(internal::BitLength64(size)), + : max_size_(size), + array_size_(internal::BitLength64(size)), map_(new uint64[array_size_]) { // initialize all of the bits SetAll(fill); @@ -75,12 +76,12 @@ public: // Clears all bits in the bitmap void Clear() { SetAll(false); } -private: - uint32 max_size_; // the upper bound of the bitmap + private: + uint32 max_size_; // the upper bound of the bitmap uint32 array_size_; - uint64 *map_; // the bitmap + uint64 *map_; // the bitmap }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_BITMAP_H_ +#endif // OR_TOOLS_BASE_BITMAP_H_ diff --git a/ortools/base/cleanup.h b/ortools/base/cleanup.h index 1d99411e24..c6ebb9b054 100644 --- a/ortools/base/cleanup.h +++ b/ortools/base/cleanup.h @@ -23,12 +23,13 @@ namespace absl { namespace cleanup_internal { -template class Storage { +template +class Storage { using InvokeT = absl::base_internal::invoke_result_t; static_assert(std::is_same::value, ""); static_assert(!std::is_reference::value, ""); -public: + public: Storage() : contains_callback_(false), callback_() {} Storage(Storage &&other_storage) @@ -41,13 +42,12 @@ public: callback_(std::forward(the_callback)) {} template - Storage(Storage &&other_storage) // NOLINT + Storage(Storage &&other_storage) // NOLINT : contains_callback_(other_storage.ContainsCallback()), callback_(other_storage.ReleaseCallback()) {} Storage &operator=(Storage &&other_storage) { - if (ContainsCallback()) - std::move(callback_)(); + if (ContainsCallback()) std::move(callback_)(); contains_callback_ = other_storage.ContainsCallback(); callback_ = other_storage.ReleaseCallback(); return *this; @@ -68,7 +68,7 @@ public: std::move(callback_)(); } -private: + private: bool contains_callback_; Callback callback_; }; @@ -80,13 +80,14 @@ struct AccessStorage { } }; -} // namespace cleanup_internal +} // namespace cleanup_internal -template class ABSL_MUST_USE_RESULT Cleanup { +template +class ABSL_MUST_USE_RESULT Cleanup { using Storage = cleanup_internal::Storage; using AccessStorage = cleanup_internal::AccessStorage; -public: + public: Cleanup() = default; Cleanup(Cleanup &&) = default; @@ -96,12 +97,11 @@ public: : storage_(std::forward(the_callback)) {} template - Cleanup(Cleanup &&other_cleanup) // NOLINT + Cleanup(Cleanup &&other_cleanup) // NOLINT : storage_(std::move(AccessStorage::From(other_cleanup))) {} ~Cleanup() { - if (storage_.ContainsCallback()) - storage_.InvokeCallback(); + if (storage_.ContainsCallback()) storage_.InvokeCallback(); } // Assignment to a cleanup object behaves like destroying it and making a new @@ -110,7 +110,7 @@ public: bool is_released() const { return !storage_.ContainsCallback(); } -private: + private: friend AccessStorage; Storage storage_; @@ -122,6 +122,6 @@ absl::Cleanup > MakeCleanup(Callback &&callback) { std::forward(callback)); } -} // namespace absl +} // namespace absl -#endif // OR_TOOLS_BASE_CLEANUP_H_ +#endif // OR_TOOLS_BASE_CLEANUP_H_ diff --git a/ortools/base/commandlineflags.h b/ortools/base/commandlineflags.h index 58f1e62fd2..ae8468fc7e 100644 --- a/ortools/base/commandlineflags.h +++ b/ortools/base/commandlineflags.h @@ -18,21 +18,29 @@ namespace absl { -template inline void SetFlag(T *flag, const T &value) { +template +inline void SetFlag(T *flag, const T &value) { *flag = value; } -template inline void SetFlag(T *flag, const V &value) { +template +inline void SetFlag(T *flag, const V &value) { *flag = value; } -template inline const T &GetFlag(T *flag) { return *flag; } +template +inline const T &GetFlag(T *flag) { + return *flag; +} -template inline const T &GetFlag(const T &flag) { return flag; } +template +inline const T &GetFlag(const T &flag) { + return flag; +} -} // namespace absl +} // namespace absl #define ABSL_DECLARE_FLAG(t, n) DECLARE_##t(n) #define ABSL_FLAG(t, n, d, h) DEFINE_##t(n, d, h) -#endif // OR_TOOLS_BASE_COMMANDLINEFLAGS_H_ +#endif // OR_TOOLS_BASE_COMMANDLINEFLAGS_H_ diff --git a/ortools/base/container_logging.h b/ortools/base/container_logging.h index 79ec6e3be2..484059c313 100644 --- a/ortools/base/container_logging.h +++ b/ortools/base/container_logging.h @@ -73,60 +73,36 @@ namespace internal { struct LogBase { template - void Log(std::ostream &out, const ElementT &element) const { // NOLINT + void Log(std::ostream &out, const ElementT &element) const { // NOLINT out << element; } - void LogEllipsis(std::ostream &out) const { // NOLINT + void LogEllipsis(std::ostream &out) const { // NOLINT out << "..."; } }; struct LogShortBase : public LogBase { - void LogOpening(std::ostream &out) const { - out << "["; - } // NOLINT - void LogClosing(std::ostream &out) const { - out << "]"; - } // NOLINT - void LogFirstSeparator(std::ostream &out) const { - out << ""; - } // NOLINT - void LogSeparator(std::ostream &out) const { - out << ", "; - } // NOLINT + void LogOpening(std::ostream &out) const { out << "["; } // NOLINT + void LogClosing(std::ostream &out) const { out << "]"; } // NOLINT + void LogFirstSeparator(std::ostream &out) const { out << ""; } // NOLINT + void LogSeparator(std::ostream &out) const { out << ", "; } // NOLINT }; struct LogMultilineBase : public LogBase { - void LogOpening(std::ostream &out) const { - out << "["; - } // NOLINT - void LogClosing(std::ostream &out) const { - out << "\n]"; - } // NOLINT - void LogFirstSeparator(std::ostream &out) const { - out << "\n"; - } // NOLINT - void LogSeparator(std::ostream &out) const { - out << "\n"; - } // NOLINT + void LogOpening(std::ostream &out) const { out << "["; } // NOLINT + void LogClosing(std::ostream &out) const { out << "\n]"; } // NOLINT + void LogFirstSeparator(std::ostream &out) const { out << "\n"; } // NOLINT + void LogSeparator(std::ostream &out) const { out << "\n"; } // NOLINT }; struct LogLegacyBase : public LogBase { - void LogOpening(std::ostream &out) const { - out << ""; - } // NOLINT - void LogClosing(std::ostream &out) const { - out << ""; - } // NOLINT - void LogFirstSeparator(std::ostream &out) const { - out << ""; - } // NOLINT - void LogSeparator(std::ostream &out) const { - out << " "; - } // NOLINT + void LogOpening(std::ostream &out) const { out << ""; } // NOLINT + void LogClosing(std::ostream &out) const { out << ""; } // NOLINT + void LogFirstSeparator(std::ostream &out) const { out << ""; } // NOLINT + void LogSeparator(std::ostream &out) const { out << " "; } // NOLINT }; -} // namespace internal +} // namespace internal // LogShort uses [] braces and separates items with comma-spaces. For // example "[1, 2, 3]". @@ -137,11 +113,11 @@ struct LogShort : public internal::LogShortBase { // LogShortUpToN(max_elements) formats the same as LogShort but prints no more // than the max_elements elements. class LogShortUpToN : public internal::LogShortBase { -public: + public: explicit LogShortUpToN(int64 max_elements) : max_elements_(max_elements) {} int64 MaxElements() const { return max_elements_; } -private: + private: int64 max_elements_; }; @@ -164,12 +140,12 @@ struct LogMultiline : public internal::LogMultilineBase { // LogMultilineUpToN(max_elements) formats the same as LogMultiline but // prints no more than max_elements elements. class LogMultilineUpToN : public internal::LogMultilineBase { -public: + public: explicit LogMultilineUpToN(int64 max_elements) : max_elements_(max_elements) {} int64 MaxElements() const { return max_elements_; } -private: + private: int64 max_elements_; }; @@ -194,7 +170,7 @@ typedef LogShortUpTo100 LogDefault; // LogRangeToStream should be used to define operator<< for // STL and STL-like containers. For example, see stl_logging.h. template -inline void LogRangeToStream(std::ostream &out, // NOLINT +inline void LogRangeToStream(std::ostream &out, // NOLINT IteratorT begin, IteratorT end, const PolicyT &policy) { policy.LogOpening(out); @@ -221,8 +197,9 @@ namespace detail { // LogContainer functions, so its lifetime should be confined to a // single logging statement. Objects of this type should not be // assigned to local variables. -template class RangeLogger { -public: +template +class RangeLogger { + public: RangeLogger(const IteratorT &begin, const IteratorT &end, const PolicyT &policy) : begin_(begin), end_(end), policy_(policy) {} @@ -241,14 +218,15 @@ public: return ss.str(); } -private: + private: IteratorT begin_; IteratorT end_; PolicyT policy_; }; -template class EnumLogger { -public: +template +class EnumLogger { + public: explicit EnumLogger(E e) : e_(e) {} friend std::ostream &operator<<(std::ostream &out, const EnumLogger &v) { @@ -256,11 +234,11 @@ public: return out << static_cast(v.e_); } -private: + private: E e_; }; -} // namespace detail +} // namespace detail // Log a range using "policy". For example: // @@ -295,7 +273,7 @@ detail::RangeLogger LogRange(const IteratorT &begin, // elements, enclosed in [] braces. template auto LogContainer(const ContainerT &container, const PolicyT &policy) - ->decltype(gtl::LogRange(container.begin(), container.end(), policy)) { + -> decltype(gtl::LogRange(container.begin(), container.end(), policy)) { return gtl::LogRange(container.begin(), container.end(), policy); } @@ -307,7 +285,7 @@ auto LogContainer(const ContainerT &container, const PolicyT &policy) // separation, no newlines, and with limit of 100 items. template auto LogContainer(const ContainerT &container) - ->decltype(gtl::LogContainer(container, LogDefault())) { + -> decltype(gtl::LogContainer(container, LogDefault())) { return gtl::LogContainer(container, LogDefault()); } @@ -315,11 +293,12 @@ auto LogContainer(const ContainerT &container) // // enum class Color { kRed, kGreen, kBlue }; // LOG(INFO) << gtl::LogEnum(kRed); -template detail::EnumLogger LogEnum(E e) { +template +detail::EnumLogger LogEnum(E e) { static_assert(std::is_enum::value, "must be an enum"); return detail::EnumLogger(e); } -} // namespace gtl +} // namespace gtl -#endif // OR_TOOLS_BASE_CONTAINER_LOGGING_H_ +#endif // OR_TOOLS_BASE_CONTAINER_LOGGING_H_ diff --git a/ortools/base/dynamic_library.h b/ortools/base/dynamic_library.h index d289c831bc..caf14a7f5a 100644 --- a/ortools/base/dynamic_library.h +++ b/ortools/base/dynamic_library.h @@ -21,7 +21,7 @@ #include "ortools/base/logging.h" #if defined(_MSC_VER) -#define WIN32_LEAN_AND_MEAN // disables several conflicting macros +#define WIN32_LEAN_AND_MEAN // disables several conflicting macros #include #elif defined(__GNUC__) #include @@ -30,7 +30,7 @@ #define NAMEOF(x) #x class DynamicLibrary { -public: + public: DynamicLibrary() : library_handle_(nullptr) {} ~DynamicLibrary() { @@ -64,12 +64,12 @@ public: static_cast(GetProcAddress( static_cast(library_handle_), function_name)); #else - dlsym(library_handle_, function_name); + dlsym(library_handle_, function_name); #endif - CHECK(function_address != nullptr) << "Error: could not find function " - << std::string(function_name) << " in " - << library_name_; + CHECK(function_address != nullptr) + << "Error: could not find function " << std::string(function_name) + << " in " << library_name_; return TypeParser::CreateFunction(function_address); } @@ -90,20 +90,21 @@ public: GetFunction(function, function_name.c_str()); } -private: + private: void *library_handle_ = nullptr; std::string library_name_; - template struct TypeParser { - }; + template + struct TypeParser {}; - template struct TypeParser { - static std::function - CreateFunction(const void *function_address) { - return std::function(reinterpret_cast( + template + struct TypeParser { + static std::function CreateFunction( + const void *function_address) { + return std::function(reinterpret_cast( const_cast(function_address))); } }; }; -#endif // OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_ +#endif // OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_ diff --git a/ortools/base/encodingutils.h b/ortools/base/encodingutils.h index d4b1ba8d5e..cca0e510f4 100644 --- a/ortools/base/encodingutils.h +++ b/ortools/base/encodingutils.h @@ -20,8 +20,7 @@ namespace EncodingUtils { // Returns the number of characters of a UTF8-encoded string. inline int UTF8StrLen(const std::string &utf8_str) { - if (utf8_str.empty()) - return 0; + if (utf8_str.empty()) return 0; const char *c = utf8_str.c_str(); int count = 0; while (*c != '\0') { @@ -33,6 +32,6 @@ inline int UTF8StrLen(const std::string &utf8_str) { return count; } -} // namespace EncodingUtils +} // namespace EncodingUtils -#endif // OR_TOOLS_BASE_ENCODINGUTILS_H_ +#endif // OR_TOOLS_BASE_ENCODINGUTILS_H_ diff --git a/ortools/base/file.cc b/ortools/base/file.cc index fd3fbe2a3e..3ddedfafdd 100644 --- a/ortools/base/file.cc +++ b/ortools/base/file.cc @@ -90,8 +90,7 @@ File *File::OpenOrDie(const char *const name, const char *const flag) { File *File::Open(const char *const name, const char *const flag) { FILE *const f_des = fopen(name, flag); - if (f_des == NULL) - return NULL; + if (f_des == NULL) return NULL; File *const f = new File(f_des, name); return f; } @@ -104,8 +103,7 @@ int64 File::ReadToString(std::string *const output, uint64 max_length) { CHECK(output != nullptr); output->clear(); - if (max_length == 0) - return 0; + if (max_length == 0) return 0; int64 needed = max_length; int bufsize = (needed < (2 << 20) ? needed : (2 << 20)); @@ -130,8 +128,7 @@ size_t File::WriteString(const std::string &line) { } bool File::WriteLine(const std::string &line) { - if (Write(line.c_str(), line.size()) != line.size()) - return false; + if (Write(line.c_str(), line.size()) != line.size()) return false; return Write("\n", 1) == 1; } @@ -169,8 +166,7 @@ absl::Status GetContents(const absl::string_view &filename, std::string *output, File *file = File::Open(filename, "r"); if (file != NULL) { const int64 size = file->Size(); - if (file->ReadToString(output, size) == size) - return absl::OkStatus(); + if (file->ReadToString(output, size) == size) return absl::OkStatus(); } } return absl::Status(absl::StatusCode::kInvalidArgument, @@ -205,10 +201,10 @@ bool WriteStringToFile(const std::string &data, namespace { class NoOpErrorCollector : public google::protobuf::io::ErrorCollector { -public: + public: virtual void AddError(int line, int column, const std::string &message) {} }; -} // namespace +} // namespace bool ReadFileToProto(const absl::string_view &file_name, google::protobuf::Message *proto) { @@ -271,8 +267,7 @@ void WriteProtoToFileOrDie(const google::protobuf::Message &proto, absl::Status GetTextProto(const absl::string_view &filename, google::protobuf::Message *proto, int flags) { if (flags == Defaults()) { - if (ReadFileToProto(filename, proto)) - return absl::OkStatus(); + if (ReadFileToProto(filename, proto)) return absl::OkStatus(); } return absl::Status( absl::StatusCode::kInvalidArgument, @@ -282,8 +277,7 @@ absl::Status GetTextProto(const absl::string_view &filename, absl::Status SetTextProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags) { if (flags == Defaults()) { - if (WriteProtoToASCIIFile(proto, filename)) - return absl::OkStatus(); + if (WriteProtoToASCIIFile(proto, filename)) return absl::OkStatus(); } return absl::Status( absl::StatusCode::kInvalidArgument, @@ -293,8 +287,7 @@ absl::Status SetTextProto(const absl::string_view &filename, absl::Status SetBinaryProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags) { if (flags == Defaults()) { - if (WriteProtoToFile(proto, filename)) - return absl::OkStatus(); + if (WriteProtoToFile(proto, filename)) return absl::OkStatus(); } return absl::Status( absl::StatusCode::kInvalidArgument, @@ -303,8 +296,7 @@ absl::Status SetBinaryProto(const absl::string_view &filename, absl::Status Delete(const absl::string_view &path, int flags) { if (flags == Defaults()) { - if (remove(path.data()) == 0) - return absl::OkStatus(); + if (remove(path.data()) == 0) return absl::OkStatus(); } return absl::Status(absl::StatusCode::kInvalidArgument, absl::StrCat("Could not delete '", path, "'.")); @@ -312,10 +304,9 @@ absl::Status Delete(const absl::string_view &path, int flags) { absl::Status Exists(const absl::string_view &path, int flags) { if (flags == Defaults()) { - if (access(path.data(), F_OK) == 0) - return absl::OkStatus(); + if (access(path.data(), F_OK) == 0) return absl::OkStatus(); } return absl::Status(absl::StatusCode::kInvalidArgument, absl::StrCat("File '", path, "' does not exist.")); } -} // namespace file +} // namespace file diff --git a/ortools/base/file.h b/ortools/base/file.h index b309b3a9e2..1ebd70c8a5 100644 --- a/ortools/base/file.h +++ b/ortools/base/file.h @@ -30,28 +30,28 @@ // This file defines some IO interfaces for compatibility with Google // IO specifications. class File { -public: + public: // Opens file "name" with flags specified by "flag". // Flags are defined by fopen(), that is "r", "r+", "w", "w+". "a", and "a+". static File *Open(const char *const name, const char *const flag); -#ifndef SWIG // no overloading +#ifndef SWIG // no overloading inline static File *Open(const absl::string_view &name, const char *const mode) { return Open(name.data(), mode); } -#endif // SWIG +#endif // SWIG // Opens file "name" with flags specified by "flag". // If open failed, program will exit. static File *OpenOrDie(const char *const name, const char *const flag); -#ifndef SWIG // no overloading +#ifndef SWIG // no overloading inline static File *OpenOrDie(const absl::string_view &name, const char *const flag) { return OpenOrDie(name.data(), flag); } -#endif // SWIG +#endif // SWIG // Reads "size" bytes to buff from file, buff should be pre-allocated. size_t Read(void *const buff, size_t size); @@ -108,7 +108,7 @@ public: bool Open() const; -private: + private: File(FILE *const descriptor, const absl::string_view &name); FILE *f_; @@ -155,6 +155,6 @@ void WriteProtoToFileOrDie(const google::protobuf::Message &proto, absl::Status Delete(const absl::string_view &path, int flags); absl::Status Exists(const absl::string_view &path, int flags); -} // namespace file +} // namespace file -#endif // OR_TOOLS_BASE_FILE_H_ +#endif // OR_TOOLS_BASE_FILE_H_ diff --git a/ortools/base/filelineiter.h b/ortools/base/filelineiter.h index f0abfb0d61..c832005f52 100644 --- a/ortools/base/filelineiter.h +++ b/ortools/base/filelineiter.h @@ -31,17 +31,19 @@ // Implements the minimum interface for a range-based for loop iterator. class FileLineIterator { -public: + public: enum { DEFAULT = 0x0000, REMOVE_LINEFEED = DEFAULT, - KEEP_LINEFEED = 0x0001, // Terminating \n in result. - REMOVE_INLINE_CR = 0x0002, // Remove \r characters. - REMOVE_BLANK_LINES = 0x0004, // Remove empty or \n-only lines. + KEEP_LINEFEED = 0x0001, // Terminating \n in result. + REMOVE_INLINE_CR = 0x0002, // Remove \r characters. + REMOVE_BLANK_LINES = 0x0004, // Remove empty or \n-only lines. }; FileLineIterator(File *file, int options) - : next_position_after_eol_(0), buffer_size_(0), file_(file), + : next_position_after_eol_(0), + buffer_size_(0), + file_(file), options_(options) { ReadNextLine(); } @@ -51,19 +53,17 @@ public: } void operator++() { ReadNextLine(); } -private: + private: bool HasOption(int option) const { return options_ & option; } void ReadNextLine() { line_.clear(); - if (file_ == nullptr) - return; + if (file_ == nullptr) return; do { while (true) { int i = next_position_after_eol_; for (; i < buffer_size_; ++i) { - if (buffer_[i] == '\n') - break; + if (buffer_[i] == '\n') break; } if (i == buffer_size_) { line_.append(&buffer_[next_position_after_eol_], @@ -113,27 +113,25 @@ private: }; class FileLines { -public: + public: FileLines(const std::string &filename, int options) : options_(options) { - if (!file::Open(filename, "r", &file_, file::Defaults()).ok()) - return; + if (!file::Open(filename, "r", &file_, file::Defaults()).ok()) return; } explicit FileLines(const std::string &filename) : FileLines(filename, FileLineIterator::DEFAULT) {} ~FileLines() { - if (file_ != nullptr) - file_->Close(file::Defaults()).IgnoreError(); + if (file_ != nullptr) file_->Close(file::Defaults()).IgnoreError(); } FileLineIterator begin() { return FileLineIterator(file_, options_); } FileLineIterator end() const { return FileLineIterator(nullptr, options_); } -private: + private: File *file_; const int options_; }; -#endif // OR_TOOLS_UTIL_FILELINEITER_H_ +#endif // OR_TOOLS_UTIL_FILELINEITER_H_ diff --git a/ortools/base/hash.h b/ortools/base/hash.h index 85c535abb0..45d121fc05 100644 --- a/ortools/base/hash.h +++ b/ortools/base/hash.h @@ -25,7 +25,7 @@ namespace operations_research { // 32 bit version. -static inline void mix(uint32 &a, uint32 &b, uint32 &c) { // NOLINT +static inline void mix(uint32 &a, uint32 &b, uint32 &c) { // NOLINT a -= b; a -= c; a ^= (c >> 13); @@ -56,7 +56,7 @@ static inline void mix(uint32 &a, uint32 &b, uint32 &c) { // NOLINT } // 64 bit version. -static inline void mix(uint64 &a, uint64 &b, uint64 &c) { // NOLINT +static inline void mix(uint64 &a, uint64 &b, uint64 &c) { // NOLINT a -= b; a -= c; a ^= (c >> 43); @@ -95,34 +95,36 @@ static inline void mix(uint64 &a, uint64 &b, uint64 &c) { // NOLINT c ^= (b >> 22); } inline uint32 Hash32NumWithSeed(uint32 num, uint32 c) { - uint32 b = 0x9e3779b9UL; // The golden ratio; an arbitrary value. + uint32 b = 0x9e3779b9UL; // The golden ratio; an arbitrary value. operations_research::mix(num, b, c); return c; } inline uint64 Hash64NumWithSeed(uint64 num, uint64 c) { - uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // More of the golden ratio. + uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // More of the golden ratio. operations_research::mix(num, b, c); return c; } -} // namespace operations_research +} // namespace operations_research // Support a few hash<> operators, in the hash namespace. namespace std { -template struct hash > { +template +struct hash > { size_t operator()(const std::pair &p) const { size_t h1 = hash()(p.first); size_t h2 = hash()(p.second); // The decision below is at compile time return (sizeof(h1) <= sizeof(uint32)) - ? // NOLINT + ? // NOLINT operations_research::Hash32NumWithSeed(h1, h2) : operations_research::Hash64NumWithSeed(h1, h2); } }; -template struct hash > { -public: +template +struct hash > { + public: size_t operator()(const std::array &t) const { uint64 current = 71; for (int index = 0; index < N; ++index) { @@ -136,17 +138,17 @@ public: bool operator()(const std::array &a, const std::array &b) const { return a < b; } - static const size_t bucket_size = 4; // These are required by MSVC. - static const size_t min_buckets = 8; // 4 and 8 are defaults. + static const size_t bucket_size = 4; // These are required by MSVC. + static const size_t min_buckets = 8; // 4 and 8 are defaults. }; -} // namespace std +} // namespace std -#endif // SWIG +#endif // SWIG namespace util_hash { inline uint64 Hash(uint64 num, uint64 c) { - uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // More of the golden ratio. + uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // More of the golden ratio. operations_research::mix(num, b, c); return c; } @@ -156,6 +158,6 @@ inline uint64 Hash(uint64 a, uint64 b, uint64 c) { return c; } -} // namespace util_hash +} // namespace util_hash -#endif // OR_TOOLS_BASE_HASH_H_ +#endif // OR_TOOLS_BASE_HASH_H_ diff --git a/ortools/base/int_type.h b/ortools/base/int_type.h index 3b18bd482f..87810a5ed4 100644 --- a/ortools/base/int_type.h +++ b/ortools/base/int_type.h @@ -149,7 +149,7 @@ #include #include -#include // NOLINT +#include // NOLINT #include #include "absl/strings/string_view.h" @@ -157,15 +157,16 @@ namespace gtl { -template class IntType; +template +class IntType; // Defines the IntType using value_type and typedefs it to int_type_name. // The struct int_type_name ## _tag_ trickery is needed to ensure that a new // type is created per int_type_name. -#define DEFINE_INT_TYPE(int_type_name, value_type) \ - struct int_type_name##_tag_ { \ - static constexpr absl::string_view TypeName() { return #int_type_name; } \ - }; \ +#define DEFINE_INT_TYPE(int_type_name, value_type) \ + struct int_type_name##_tag_ { \ + static constexpr absl::string_view TypeName() { return #int_type_name; } \ + }; \ typedef ::gtl::IntType int_type_name; // Holds a integral value (of type ValueType) and behaves as a @@ -178,10 +179,11 @@ template class IntType; // the integer type value (see supported list above). // // This class is NOT thread-safe. -template class IntType { -public: - typedef _ValueType ValueType; // for non-member operators - typedef IntType ThisType; // Syntactic sugar. +template +class IntType { + public: + typedef _ValueType ValueType; // for non-member operators + typedef IntType ThisType; // Syntactic sugar. static constexpr absl::string_view TypeName() { return IntTypeName::TypeName(); @@ -194,7 +196,7 @@ public: } }; -public: + public: // Default c'tor initializing value_ to 0. constexpr IntType() : value_(0) {} // C'tor explicitly initializing from a ValueType. @@ -210,25 +212,26 @@ public: // static_cast(var.value()); constexpr ValueType value() const { return value_; } - template constexpr ValType value() const { + template + constexpr ValType value() const { return static_cast(value_); } // -- UNARY OPERATORS -------------------------------------------------------- - ThisType &operator++() { // prefix ++ + ThisType &operator++() { // prefix ++ ++value_; return *this; } - const ThisType operator++(int v) { // postfix ++ + const ThisType operator++(int v) { // postfix ++ ThisType temp(*this); ++value_; return temp; } - ThisType &operator--() { // prefix -- + ThisType &operator--() { // prefix -- --value_; return *this; } - const ThisType operator--(int v) { // postfix -- + const ThisType operator--(int v) { // postfix -- ThisType temp(*this); --value_; return temp; @@ -242,22 +245,22 @@ public: // -- ASSIGNMENT OPERATORS --------------------------------------------------- // We support the following assignment operators: =, +=, -=, *=, /=, <<=, >>= // and %= for both ThisType and ValueType. -#define INT_TYPE_ASSIGNMENT_OP(op) \ - ThisType &operator op(const ThisType & arg_value) { \ - value_ op arg_value.value(); \ - return *this; \ - } \ - ThisType &operator op(ValueType arg_value) { \ - value_ op arg_value; \ - return *this; \ +#define INT_TYPE_ASSIGNMENT_OP(op) \ + ThisType &operator op(const ThisType &arg_value) { \ + value_ op arg_value.value(); \ + return *this; \ + } \ + ThisType &operator op(ValueType arg_value) { \ + value_ op arg_value; \ + return *this; \ } - INT_TYPE_ASSIGNMENT_OP( += ); - INT_TYPE_ASSIGNMENT_OP( -= ); - INT_TYPE_ASSIGNMENT_OP( *= ); - INT_TYPE_ASSIGNMENT_OP( /= ); - INT_TYPE_ASSIGNMENT_OP( <<= ); // NOLINT - INT_TYPE_ASSIGNMENT_OP( >>= ); // NOLINT - INT_TYPE_ASSIGNMENT_OP( %= ); + INT_TYPE_ASSIGNMENT_OP(+=); + INT_TYPE_ASSIGNMENT_OP(-=); + INT_TYPE_ASSIGNMENT_OP(*=); + INT_TYPE_ASSIGNMENT_OP(/=); + INT_TYPE_ASSIGNMENT_OP(<<=); // NOLINT + INT_TYPE_ASSIGNMENT_OP(>>=); // NOLINT + INT_TYPE_ASSIGNMENT_OP(%=); #undef INT_TYPE_ASSIGNMENT_OP ThisType &operator=(ValueType arg_value) { @@ -265,7 +268,7 @@ public: return *this; } -private: + private: // The integer value of type ValueType. ValueType value_; @@ -277,8 +280,8 @@ private: // We provide the << operator, primarily for logging purposes. Currently, there // seems to be no need for an >> operator. template - std::ostream &operator<<(std::ostream &os, // NOLINT - IntType arg) { +std::ostream &operator<<(std::ostream &os, // NOLINT + IntType arg) { return os << arg.value(); } @@ -289,32 +292,32 @@ template // // NB: Although it is possible to do IntType * IntType and IntType / IntType, // it is probably non-sensical from a dimensionality analysis perspective. -#define INT_TYPE_ARITHMETIC_OP(op) \ - template \ - constexpr IntType operator op( \ - IntType id_1, \ - IntType id_2) { \ - return IntType(id_1.value() op id_2.value()); \ - } \ - template \ - constexpr IntType operator op( \ - IntType id, \ - typename IntType::ValueType arg_val) { \ - return IntType(id.value() op arg_val); \ - } \ - template \ - constexpr IntType operator op( \ - typename IntType::ValueType arg_val, \ - IntType id) { \ - return IntType(arg_val op id.value()); \ +#define INT_TYPE_ARITHMETIC_OP(op) \ + template \ + constexpr IntType operator op( \ + IntType id_1, \ + IntType id_2) { \ + return IntType(id_1.value() op id_2.value()); \ + } \ + template \ + constexpr IntType operator op( \ + IntType id, \ + typename IntType::ValueType arg_val) { \ + return IntType(id.value() op arg_val); \ + } \ + template \ + constexpr IntType operator op( \ + typename IntType::ValueType arg_val, \ + IntType id) { \ + return IntType(arg_val op id.value()); \ } INT_TYPE_ARITHMETIC_OP(+); INT_TYPE_ARITHMETIC_OP(-); INT_TYPE_ARITHMETIC_OP(*); -INT_TYPE_ARITHMETIC_OP( / ); -INT_TYPE_ARITHMETIC_OP( << ); // NOLINT -INT_TYPE_ARITHMETIC_OP( >> ); // NOLINT -INT_TYPE_ARITHMETIC_OP( % ); +INT_TYPE_ARITHMETIC_OP(/); +INT_TYPE_ARITHMETIC_OP(<<); // NOLINT +INT_TYPE_ARITHMETIC_OP(>>); // NOLINT +INT_TYPE_ARITHMETIC_OP(%); #undef INT_TYPE_ARITHMETIC_OP // -- NON-MEMBER COMPARISON OPERATORS ------------------------------------------ @@ -323,41 +326,40 @@ INT_TYPE_ARITHMETIC_OP( % ); // IntType OP IntType // IntType OP ValueType // ValueType OP IntType -#define INT_TYPE_COMPARISON_OP(op) \ - template \ - static inline constexpr bool operator op( \ - IntType id_1, \ - IntType id_2) { \ - return id_1.value() op id_2.value(); \ - } \ - template \ - static inline constexpr bool operator op( \ - IntType id, \ - typename IntType::ValueType val) { \ - return id.value() op val; \ - } \ - template \ - static inline constexpr bool operator op( \ - typename IntType::ValueType val, \ - IntType id) { \ - return val op id.value(); \ +#define INT_TYPE_COMPARISON_OP(op) \ + template \ + static inline constexpr bool operator op( \ + IntType id_1, \ + IntType id_2) { \ + return id_1.value() op id_2.value(); \ + } \ + template \ + static inline constexpr bool operator op( \ + IntType id, \ + typename IntType::ValueType val) { \ + return id.value() op val; \ + } \ + template \ + static inline constexpr bool operator op( \ + typename IntType::ValueType val, \ + IntType id) { \ + return val op id.value(); \ } -INT_TYPE_COMPARISON_OP( == ); // NOLINT -INT_TYPE_COMPARISON_OP( != ); // NOLINT -INT_TYPE_COMPARISON_OP( < ); // NOLINT -INT_TYPE_COMPARISON_OP( <= ); // NOLINT -INT_TYPE_COMPARISON_OP( > ); // NOLINT -INT_TYPE_COMPARISON_OP( >= ); // NOLINT +INT_TYPE_COMPARISON_OP(==); // NOLINT +INT_TYPE_COMPARISON_OP(!=); // NOLINT +INT_TYPE_COMPARISON_OP(<); // NOLINT +INT_TYPE_COMPARISON_OP(<=); // NOLINT +INT_TYPE_COMPARISON_OP(>); // NOLINT +INT_TYPE_COMPARISON_OP(>=); // NOLINT #undef INT_TYPE_COMPARISON_OP -} // namespace gtl +} // namespace gtl // Allows it to be used as a key to hashable containers. namespace std { template -struct hash > : gtl::IntType< - IntTypeName, ValueType>::Hasher { -}; -} // namespace std +struct hash > + : gtl::IntType::Hasher {}; +} // namespace std -#endif // OR_TOOLS_BASE_INT_TYPE_H_ +#endif // OR_TOOLS_BASE_INT_TYPE_H_ diff --git a/ortools/base/int_type_indexed_vector.h b/ortools/base/int_type_indexed_vector.h index 15264b0ee0..b329ea2475 100644 --- a/ortools/base/int_type_indexed_vector.h +++ b/ortools/base/int_type_indexed_vector.h @@ -74,7 +74,7 @@ namespace gtl { // STL vector ------------------------------------------------------------------ template > class ITIVector { -public: + public: typedef IntType IndexType; typedef std::vector ParentType; @@ -91,7 +91,7 @@ public: typedef typename ParentType::reverse_iterator reverse_iterator; typedef typename ParentType::const_reverse_iterator const_reverse_iterator; -public: + public: ITIVector() {} explicit ITIVector(const allocator_type &a) : v_(a) {} @@ -101,7 +101,7 @@ public: const allocator_type &a = allocator_type()) : v_(n, v, a) {} - ITIVector(std::initializer_list il) // NOLINT(runtime/explicit) + ITIVector(std::initializer_list il) // NOLINT(runtime/explicit) : v_(il) {} template @@ -128,7 +128,8 @@ public: // -- Pass-through methods to STL vector ------------------------------------- void assign(size_type n, const value_type &val) { v_.assign(n, val); } - template void assign(InputIt f, InputIt l) { + template + void assign(InputIt f, InputIt l) { v_.assign(f, l); } void assign(std::initializer_list ilist) { v_.assign(ilist); } @@ -154,10 +155,9 @@ public: bool empty() const { return v_.empty(); } void reserve(size_type n) { v_.reserve(n); } void push_back(const value_type &x) { v_.push_back(x); } - void push_back(value_type &&x) { - v_.push_back(std::move(x)); - } // NOLINT - template void emplace_back(Args &&... args) { + void push_back(value_type &&x) { v_.push_back(std::move(x)); } // NOLINT + template + void emplace_back(Args &&... args) { v_.emplace_back(std::forward(args)...); } template @@ -182,7 +182,7 @@ public: iterator insert(const_iterator pos, const value_type &x) { return v_.insert(pos, x); } - iterator insert(const_iterator pos, value_type &&x) { // NOLINT + iterator insert(const_iterator pos, value_type &&x) { // NOLINT return v_.insert(pos, std::move(x)); } iterator insert(const_iterator pos, size_type n, const value_type &x) { @@ -216,11 +216,12 @@ public: } friend void swap(ITIVector &x, ITIVector &y) { x.swap(y); } - template friend H AbslHashValue(H h, const ITIVector &v) { + template + friend H AbslHashValue(H h, const ITIVector &v) { return H::combine(std::move(h), v.v_); } -private: + private: static size_type Value(IndexType i) { return i.template value(); } ParentType v_; @@ -229,6 +230,6 @@ private: int_type_indexed_vector_must_have_integral_index); }; -} // namespace gtl +} // namespace gtl -#endif // OR_TOOLS_BASE_INT_TYPE_INDEXED_VECTOR_H_ +#endif // OR_TOOLS_BASE_INT_TYPE_INDEXED_VECTOR_H_ diff --git a/ortools/base/integral_types.h b/ortools/base/integral_types.h index 568f145a94..160f07d5ee 100644 --- a/ortools/base/integral_types.h +++ b/ortools/base/integral_types.h @@ -16,25 +16,25 @@ #include #include -#include // NOLINT +#include // NOLINT // Detect 64 bit. #undef ARCH_K8 #if defined(_MSC_VER) && defined(_WIN64) #define ARCH_K8 #elif defined(__APPLE__) && defined(__GNUC__) -#define ARCH_K8 // We only support 64 bit on Mac OS X. +#define ARCH_K8 // We only support 64 bit on Mac OS X. #elif defined(__GNUC__) && defined(__LP64__) && !defined(__aarch64__) -#define ARCH_K8 // Linux x86_64 +#define ARCH_K8 // Linux x86_64 #endif typedef signed char int8; -typedef short int16; // NOLINT +typedef short int16; // NOLINT typedef int int32; typedef int64_t int64; typedef unsigned char uint8; -typedef unsigned short uint16; // NOLINT +typedef unsigned short uint16; // NOLINT typedef unsigned int uint32; typedef uint64_t uint64; @@ -78,6 +78,6 @@ inline std::ostream &operator<<(std::ostream &os, uint64 i) { os << buffer; return os; } -#endif // STLPORT +#endif // STLPORT -#endif // OR_TOOLS_BASE_INTEGRAL_TYPES_H_ +#endif // OR_TOOLS_BASE_INTEGRAL_TYPES_H_ diff --git a/ortools/base/iterator_adaptors.h b/ortools/base/iterator_adaptors.h index 080669d40c..58d7442b42 100644 --- a/ortools/base/iterator_adaptors.h +++ b/ortools/base/iterator_adaptors.h @@ -16,15 +16,16 @@ namespace gtl { -template class ReverseView { -public: +template +class ReverseView { + public: typedef typename Container::const_reverse_iterator const_it; ReverseView(const Container &c) : c_(c) {} const_it begin() const { return c_.rbegin(); } const_it end() const { return c_.rend(); } -private: + private: const Container &c_; }; @@ -33,6 +34,6 @@ ReverseView reversed_view(const Container &c) { return ReverseView(c); } -} // namespace gtl +} // namespace gtl -#endif // OR_TOOLS_BASE_ITERATOR_ADAPTORS_H_ +#endif // OR_TOOLS_BASE_ITERATOR_ADAPTORS_H_ diff --git a/ortools/base/jniutil.h b/ortools/base/jniutil.h index 47af4c3a89..24cb68cb79 100644 --- a/ortools/base/jniutil.h +++ b/ortools/base/jniutil.h @@ -21,20 +21,18 @@ #include "ortools/base/logging.h" class JNIUtil { -public: + public: // Creates a Java jstring from a null-terminated UTF-8 encoded C String. // The caller must delete the jstring reference. static jstring MakeJString(JNIEnv *env, const char *cstr) { - if (cstr == NULL) - return NULL; + if (cstr == NULL) return NULL; return env->NewStringUTF(cstr); } // Creates a null-terminated UTF-8 encoded C string from a jstring. // The returned string should be "delete[]"-ed when no longer needed. static char *MakeCString(JNIEnv *env, jstring str) { - if (str == NULL) - return NULL; + if (str == NULL) return NULL; jsize length = env->GetStringUTFLength(str); const char *src = env->GetStringUTFChars(str, NULL); char *dst = new char[length + 1]; @@ -68,4 +66,4 @@ public: } }; -#endif // OR_TOOLS_BASE_JNIUTIL_H_ +#endif // OR_TOOLS_BASE_JNIUTIL_H_ diff --git a/ortools/base/logging.cc b/ortools/base/logging.cc index aaffb2380d..7557a3709b 100644 --- a/ortools/base/logging.cc +++ b/ortools/base/logging.cc @@ -13,7 +13,7 @@ #include "ortools/base/logging.h" -#include // NOLINT +#include // NOLINT #include "ortools/base/commandlineflags.h" @@ -22,12 +22,10 @@ DECLARE_bool(logtostderr); namespace { std::once_flag init_done; -} // namespace +} // namespace void FixFlagsAndEnvironmentForSwig() { - std::call_once(init_done, [] { - google::InitGoogleLogging("swig_helper"); - }); + std::call_once(init_done, [] { google::InitGoogleLogging("swig_helper"); }); absl::SetFlag(&FLAGS_logtostderr, true); absl::SetFlag(&FLAGS_log_prefix, false); } diff --git a/ortools/base/logging.h b/ortools/base/logging.h index a5302d284e..26768284e0 100644 --- a/ortools/base/logging.h +++ b/ortools/base/logging.h @@ -31,4 +31,4 @@ // used by or-tools non C++ ports to bridge with the C++ layer. void FixFlagsAndEnvironmentForSwig(); -#endif // OR_TOOLS_BASE_LOGGING_H_ +#endif // OR_TOOLS_BASE_LOGGING_H_ diff --git a/ortools/base/macros.h b/ortools/base/macros.h index 6f1085f3ff..111604b148 100644 --- a/ortools/base/macros.h +++ b/ortools/base/macros.h @@ -14,26 +14,28 @@ #ifndef OR_TOOLS_BASE_MACROS_H_ #define OR_TOOLS_BASE_MACROS_H_ -#include // for size_t. +#include // for size_t. #define COMPILE_ASSERT(x, msg) #ifdef NDEBUG const bool DEBUG_MODE = false; -#else // NDEBUG +#else // NDEBUG const bool DEBUG_MODE = true; -#endif // NDEBUG +#endif // NDEBUG // DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. // It goes in the private: declarations in a class. -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &); \ +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &); \ void operator=(const TypeName &) -template char (&ArraySizeHelper(T (&array)[N]))[N]; +template +char (&ArraySizeHelper(T (&array)[N]))[N]; #ifndef COMPILER_MSVC -template char (&ArraySizeHelper(const T (&array)[N]))[N]; +template +char (&ArraySizeHelper(const T (&array)[N]))[N]; #endif #define arraysize(array) (sizeof(ArraySizeHelper(array))) -#endif // OR_TOOLS_BASE_MACROS_H_ +#endif // OR_TOOLS_BASE_MACROS_H_ diff --git a/ortools/base/map_util.h b/ortools/base/map_util.h index 0472d0aa82..3e06c7c967 100644 --- a/ortools/base/map_util.h +++ b/ortools/base/map_util.h @@ -23,10 +23,10 @@ namespace gtl { // If the key is present in the map then the value associated with that // key is returned, otherwise the value passed as a default is returned. template -const typename Collection::value_type::second_type & -FindWithDefault(const Collection &collection, - const typename Collection::value_type::first_type &key, - const typename Collection::value_type::second_type &value) { +const typename Collection::value_type::second_type &FindWithDefault( + const Collection &collection, + const typename Collection::value_type::first_type &key, + const typename Collection::value_type::second_type &value) { typename Collection::const_iterator it = collection.find(key); if (it == collection.end()) { return value; @@ -38,9 +38,9 @@ FindWithDefault(const Collection &collection, // If the key is present a const pointer to the associated value is returned, // otherwise a NULL pointer is returned. template -const typename Collection::value_type::second_type * -FindOrNull(const Collection &collection, - const typename Collection::value_type::first_type &key) { +const typename Collection::value_type::second_type *FindOrNull( + const Collection &collection, + const typename Collection::value_type::first_type &key) { typename Collection::const_iterator it = collection.find(key); if (it == collection.end()) { return 0; @@ -52,9 +52,9 @@ FindOrNull(const Collection &collection, // Same as above but the returned pointer is not const and can be used to change // the stored value. template -typename Collection::value_type::second_type * -FindOrNull(Collection &collection, // NOLINT - const typename Collection::value_type::first_type &key) { +typename Collection::value_type::second_type *FindOrNull( + Collection &collection, // NOLINT + const typename Collection::value_type::first_type &key) { typename Collection::iterator it = collection.find(key); if (it == collection.end()) { return 0; @@ -67,9 +67,9 @@ FindOrNull(Collection &collection, // NOLINT // returned, otherwise a NULL pointer is returned. This function does not // distinguish between a missing key and a key mapped to a NULL value. template -const typename Collection::value_type::second_type -FindPtrOrNull(const Collection &collection, - const typename Collection::value_type::first_type &key) { +const typename Collection::value_type::second_type FindPtrOrNull( + const Collection &collection, + const typename Collection::value_type::first_type &key) { typename Collection::const_iterator it = collection.find(key); if (it == collection.end()) { return 0; @@ -173,9 +173,9 @@ bool ContainsKey(const Collection &collection, const Key &key) { } template -const typename Collection::value_type::second_type & -FindOrDie(const Collection &collection, - const typename Collection::value_type::first_type &key) { +const typename Collection::value_type::second_type &FindOrDie( + const Collection &collection, + const typename Collection::value_type::first_type &key) { typename Collection::const_iterator it = collection.find(key); CHECK(it != collection.end()) << "Map key not found: " << key; return it->second; @@ -183,9 +183,9 @@ FindOrDie(const Collection &collection, // Same as FindOrDie above, but doesn't log the key on failure. template -const typename Collection::value_type::second_type & -FindOrDieNoPrint(const Collection &collection, - const typename Collection::value_type::first_type &key) { +const typename Collection::value_type::second_type &FindOrDieNoPrint( + const Collection &collection, + const typename Collection::value_type::first_type &key) { typename Collection::const_iterator it = collection.find(key); CHECK(it != collection.end()) << "Map key not found"; return it->second; @@ -193,9 +193,9 @@ FindOrDieNoPrint(const Collection &collection, // Same as above, but returns a non-const reference. template -typename Collection::value_type::second_type & -FindOrDieNoPrint(Collection &collection, // NOLINT - const typename Collection::value_type::first_type &key) { +typename Collection::value_type::second_type &FindOrDieNoPrint( + Collection &collection, // NOLINT + const typename Collection::value_type::first_type &key) { typename Collection::iterator it = collection.find(key); CHECK(it != collection.end()) << "Map key not found"; return it->second; @@ -204,13 +204,13 @@ FindOrDieNoPrint(Collection &collection, // NOLINT // Lookup a key in a std::map or std::unordered_map, insert it if it is not // present. Returns a reference to the value associated with the key. template -typename Collection::value_type::second_type & -LookupOrInsert(Collection *const collection, - const typename Collection::value_type::first_type &key, - const typename Collection::value_type::second_type &value) { +typename Collection::value_type::second_type &LookupOrInsert( + Collection *const collection, + const typename Collection::value_type::first_type &key, + const typename Collection::value_type::second_type &value) { std::pair ret = collection->insert(typename Collection::value_type(key, value)); return ret.first->second; } -} // namespace gtl -#endif // OR_TOOLS_BASE_MAP_UTIL_H_ +} // namespace gtl +#endif // OR_TOOLS_BASE_MAP_UTIL_H_ diff --git a/ortools/base/mathutil.h b/ortools/base/mathutil.h index 148d857c42..71032eee34 100644 --- a/ortools/base/mathutil.h +++ b/ortools/base/mathutil.h @@ -27,7 +27,7 @@ namespace operations_research { class MathUtil { -public: + public: // CeilOfRatio // FloorOfRatio // Returns the ceil (resp. floor) of the ratio of two integers. @@ -91,10 +91,16 @@ public: // for special floating point values. // Note: 0.0 and -0.0 are not differentiated by Abs (Abs(0.0) is -0.0), // which should be OK: see the comment for Max above. - template static T Abs(const T x) { return x > 0 ? x : -x; } + template + static T Abs(const T x) { + return x > 0 ? x : -x; + } // Returns the square of x. - template static T Square(const T x) { return x * x; } + template + static T Square(const T x) { + return x * x; + } // Euclid's Algorithm. // Returns: the greatest common divisor of two unsigned integers x and y. @@ -109,11 +115,13 @@ public: return x; } - template static T IPow(T base, int exp) { + template + static T IPow(T base, int exp) { return pow(base, exp); } - template static IntOut Round(FloatIn x) { + template + static IntOut Round(FloatIn x) { // We don't use sgn(x) below because there is no need to distinguish the // (x == 0) case. Also note that there are specialized faster versions // of this function for Intel, ARM and PPC processors at the bottom @@ -129,6 +137,6 @@ public: static int64 FastInt64Round(double x) { return Round(x); } }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_MATHUTIL_H_ +#endif // OR_TOOLS_BASE_MATHUTIL_H_ diff --git a/ortools/base/murmur.h b/ortools/base/murmur.h index 435c81b295..688f764576 100644 --- a/ortools/base/murmur.h +++ b/ortools/base/murmur.h @@ -23,6 +23,6 @@ namespace util_hash { inline uint64 MurmurHash64(const char *buf, const size_t len) { return ::operations_research::ThoroughHash(buf, len); } -} // namespace util_hash +} // namespace util_hash -#endif // OR_TOOLS_BASE_MURMUR_H_ +#endif // OR_TOOLS_BASE_MURMUR_H_ diff --git a/ortools/base/protobuf_util.h b/ortools/base/protobuf_util.h index eefd0e8f17..0d6a28372b 100644 --- a/ortools/base/protobuf_util.h +++ b/ortools/base/protobuf_util.h @@ -62,8 +62,8 @@ int RemoveAt(RepeatedType *array, const IndexContainer &indices) { Truncate(array, write_index); return num_indices; } -} // namespace util -} // namespace protobuf -} // namespace google +} // namespace util +} // namespace protobuf +} // namespace google -#endif // OR_TOOLS_BASE_PROTOBUF_UTIL_H_ +#endif // OR_TOOLS_BASE_PROTOBUF_UTIL_H_ diff --git a/ortools/base/protoutil.h b/ortools/base/protoutil.h index 3717ed862a..d00d1e2131 100644 --- a/ortools/base/protoutil.h +++ b/ortools/base/protoutil.h @@ -22,8 +22,8 @@ namespace util_time { -inline ::absl::StatusOr -EncodeGoogleApiProto(absl::Duration d) { +inline ::absl::StatusOr EncodeGoogleApiProto( + absl::Duration d) { google::protobuf::Duration proto; const int64 d_in_nano = ToInt64Nanoseconds(d); proto.set_seconds(static_cast(d_in_nano / 1000000000)); @@ -37,11 +37,11 @@ inline ::absl::Status EncodeGoogleApiProto(absl::Duration d, return absl::OkStatus(); } -inline ::absl::StatusOr -DecodeGoogleApiProto(const google::protobuf::Duration &proto) { +inline ::absl::StatusOr DecodeGoogleApiProto( + const google::protobuf::Duration &proto) { return absl::Seconds(proto.seconds() + 1e-9 * proto.nanos()); } -} // namespace util_time +} // namespace util_time -#endif // OR_TOOLS_BASE_PROTOUTIL_H_ +#endif // OR_TOOLS_BASE_PROTOUTIL_H_ diff --git a/ortools/base/ptr_util.h b/ortools/base/ptr_util.h index 62d4ab0702..93b87f78f9 100644 --- a/ortools/base/ptr_util.h +++ b/ortools/base/ptr_util.h @@ -16,4 +16,4 @@ #include -#endif // OR_TOOLS_BASE_PTR_UTIL_H_ +#endif // OR_TOOLS_BASE_PTR_UTIL_H_ diff --git a/ortools/base/python-swig.h b/ortools/base/python-swig.h index e15614e828..ce485e87a6 100644 --- a/ortools/base/python-swig.h +++ b/ortools/base/python-swig.h @@ -25,7 +25,7 @@ #ifndef OR_TOOLS_BASE_PYTHON_SWIG_H_ #define OR_TOOLS_BASE_PYTHON_SWIG_H_ -#if PY_VERSION_HEX >= 0x03030000 // Py3.3+ +#if PY_VERSION_HEX >= 0x03030000 // Py3.3+ // Use Py3 unicode str() type for C++ strings. #ifdef PyString_FromStringAndSize #undef PyString_FromStringAndSize @@ -51,55 +51,57 @@ static inline int PyString_AsStringAndSize(PyObject *obj, char **buf, PyErr_SetString(PyExc_TypeError, "Expecting str or bytes"); return -1; } -#endif // Py3.3+ +#endif // Py3.3+ -template inline bool PyObjAs(PyObject *pystr, T *cstr) { - T::undefined; // You need to define specialization PyObjAs +template +inline bool PyObjAs(PyObject *pystr, T *cstr) { + T::undefined; // You need to define specialization PyObjAs } -template inline PyObject *PyObjFrom(const T &c) { - T::undefined; // You need to define specialization PyObjFrom +template +inline PyObject *PyObjFrom(const T &c) { + T::undefined; // You need to define specialization PyObjFrom } #ifdef HAS_GLOBAL_STRING -template <> inline bool PyObjAs(PyObject *pystr, ::std::string *cstr) { +template <> +inline bool PyObjAs(PyObject *pystr, ::std::string *cstr) { char *buf; Py_ssize_t len; #if PY_VERSION_HEX >= 0x03030000 if (PyUnicode_Check(pystr)) { buf = PyUnicode_AsUTF8AndSize(pystr, &len); - if (!buf) - return false; - } else // NOLINT + if (!buf) return false; + } else // NOLINT #endif if (PyBytes_AsStringAndSize(pystr, &buf, &len) == -1) return false; - if (cstr) - cstr->assign(buf, len); + if (cstr) cstr->assign(buf, len); return true; } #endif -template inline bool PyObjAs(PyObject *pystr, std::string *cstr) { +template +inline bool PyObjAs(PyObject *pystr, std::string *cstr) { char *buf; Py_ssize_t len; #if PY_VERSION_HEX >= 0x03030000 if (PyUnicode_Check(pystr)) { buf = const_cast(PyUnicode_AsUTF8AndSize(pystr, &len)); - if (!buf) - return false; - } else // NOLINT + if (!buf) return false; + } else // NOLINT #endif if (PyBytes_AsStringAndSize(pystr, &buf, &len) == -1) return false; - if (cstr) - cstr->assign(buf, len); + if (cstr) cstr->assign(buf, len); return true; } #ifdef HAS_GLOBAL_STRING -template <> inline PyObject *PyObjFrom(const ::std::string &c) { +template <> +inline PyObject *PyObjFrom(const ::std::string &c) { return PyString_FromStringAndSize(c.data(), c.size()); } #endif -template <> inline PyObject *PyObjFrom(const std::string &c) { +template <> +inline PyObject *PyObjFrom(const std::string &c) { return PyString_FromStringAndSize(c.data(), c.size()); } @@ -107,69 +109,65 @@ template <> inline PyObject *PyObjFrom(const std::string &c) { #include -template <> inline bool PyObjAs(PyObject *py, int *c) { - long i = PyInt_AsLong(py); // NOLINT - if (i == -1 && PyErr_Occurred()) // TypeError or OverflowError. - return false; // Not a Python int. +template <> +inline bool PyObjAs(PyObject *py, int *c) { + long i = PyInt_AsLong(py); // NOLINT + if (i == -1 && PyErr_Occurred()) // TypeError or OverflowError. + return false; // Not a Python int. if (i < std::numeric_limits::min() || i > std::numeric_limits::max()) - return false; // Not C int. - if (c) - *c = static_cast(i); + return false; // Not C int. + if (c) *c = static_cast(i); return true; } -template <> inline bool PyObjAs(PyObject *py, unsigned int *c) { - long i = PyInt_AsLong(py); // NOLINT - if (i == -1 && PyErr_Occurred()) - return false; // Not a Python int. - if (i < 0 || i > std::numeric_limits::max()) - return false; - if (c) - *c = static_cast(i); +template <> +inline bool PyObjAs(PyObject *py, unsigned int *c) { + long i = PyInt_AsLong(py); // NOLINT + if (i == -1 && PyErr_Occurred()) return false; // Not a Python int. + if (i < 0 || i > std::numeric_limits::max()) return false; + if (c) *c = static_cast(i); return true; } -template <> inline bool PyObjAs(PyObject *py, int64 *c) { // NOLINT - int64 i; // NOLINT +template <> +inline bool PyObjAs(PyObject *py, int64 *c) { // NOLINT + int64 i; // NOLINT #if PY_MAJOR_VERSION < 3 if (PyInt_Check(py)) { i = PyInt_AsLong(py); } else { - if (!PyLong_Check(py)) - return false; // Not a Python long. + if (!PyLong_Check(py)) return false; // Not a Python long. #else { #endif i = PyLong_AsLongLong(py); - if (i == -1 && PyErr_Occurred()) - return false; // Not a C long long. + if (i == -1 && PyErr_Occurred()) return false; // Not a C long long. } - if (c) - *c = i; + if (c) *c = i; return true; } -template <> inline bool PyObjAs(PyObject * py, uint64 * c) { // NOLINT - uint64 i; // NOLINT +template <> +inline bool PyObjAs(PyObject *py, uint64 *c) { // NOLINT + uint64 i; // NOLINT #if PY_MAJOR_VERSION < 3 if (PyInt_Check(py)) { i = PyInt_AsUnsignedLongLongMask(py); - } else // NOLINT + } else // NOLINT #endif - { - if (!PyLong_Check(py)) - return false; // Not a Python long. + { + if (!PyLong_Check(py)) return false; // Not a Python long. i = PyLong_AsUnsignedLongLong(py); - if (i == (uint64) - 1 && PyErr_Occurred()) // NOLINT + if (i == (uint64)-1 && PyErr_Occurred()) // NOLINT return false; } - if (c) - *c = i; + if (c) *c = i; return true; } -template <> inline bool PyObjAs(PyObject * py, double * c) { +template <> +inline bool PyObjAs(PyObject *py, double *c) { double d; if (PyFloat_Check(py)) { d = PyFloat_AsDouble(py); @@ -177,80 +175,80 @@ template <> inline bool PyObjAs(PyObject * py, double * c) { } else if (PyInt_Check(py)) { d = PyInt_AsLong(py); } else if (!PyLong_Check(py)) { - return false; // float or int/long expected + return false; // float or int/long expected #endif } else { d = PyLong_AsDouble(py); if (d == -1.0 && PyErr_Occurred()) { - return false; // Overflow (or TypeError for PY3) + return false; // Overflow (or TypeError for PY3) } } - if (c) - *c = d; + if (c) *c = d; return true; } -template <> inline PyObject *PyObjFrom(const double & c) { +template <> +inline PyObject *PyObjFrom(const double &c) { return PyFloat_FromDouble(c); } -template <> inline bool PyObjAs(PyObject * py, float * c) { +template <> +inline bool PyObjAs(PyObject *py, float *c) { double d; - if (!PyObjAs(py, &d)) - return false; - if (c) - *c = static_cast(d); + if (!PyObjAs(py, &d)) return false; + if (c) *c = static_cast(d); return true; } -template <> inline PyObject *PyObjFrom(const float & c) { +template <> +inline PyObject *PyObjFrom(const float &c) { return PyFloat_FromDouble(c); } -template <> inline bool PyObjAs(PyObject * py, bool * c) { - if (!PyBool_Check(py)) - return false; // Not a Python bool. - if (c) - *c = PyObject_Not(py) ? false : true; +template <> +inline bool PyObjAs(PyObject *py, bool *c) { + if (!PyBool_Check(py)) return false; // Not a Python bool. + if (c) *c = PyObject_Not(py) ? false : true; return true; } -inline int SwigPyIntOrLong_Check(PyObject * o) { +inline int SwigPyIntOrLong_Check(PyObject *o) { return (PyLong_Check(o) #if PY_MAJOR_VERSION <= 2 || PyInt_Check(o) #endif - ); // NOLINT + ); // NOLINT } -inline PyObject *SwigString_FromString(const std::string & s) { +inline PyObject *SwigString_FromString(const std::string &s) { return PyString_FromStringAndSize(s.data(), s.size()); } -inline std::string SwigString_AsString(PyObject * o) { +inline std::string SwigString_AsString(PyObject *o) { return std::string(PyString_AsString(o)); } // STL std::vector for common types -namespace { // NOLINT +namespace { // NOLINT -template struct vector_pusher { +template +struct vector_pusher { typedef T *ptr; static void push(std::vector *o, ptr e) { o->push_back(*e); } }; -template struct vector_pusher { +template +struct vector_pusher { typedef T *ptr; static void push(std::vector *o, ptr e) { o->push_back(e); } }; -}; // namespace +}; // namespace template -inline bool vector_input_helper(PyObject * seq, std::vector * out, - bool(*convert)(PyObject *, T * const)) { +inline bool vector_input_helper(PyObject *seq, std::vector *out, + bool (*convert)(PyObject *, T *const)) { PyObject *item, *it = PyObject_GetIter(seq); - if (!it) - return false; + if (!it) return false; T elem; while ((item = PyIter_Next(it))) { bool success = convert(item, &elem); @@ -259,16 +257,15 @@ inline bool vector_input_helper(PyObject * seq, std::vector * out, Py_DECREF(it); return false; } - if (out) - out->push_back(elem); + if (out) out->push_back(elem); } Py_DECREF(it); return static_cast(!PyErr_Occurred()); } template -inline bool vector_input_wrap_helper(PyObject * seq, std::vector * out, - swig_type_info * swig_Tp_type) { +inline bool vector_input_wrap_helper(PyObject *seq, std::vector *out, + swig_type_info *swig_Tp_type) { PyObject *item, *it = PyObject_GetIter(seq); if (!it) { PyErr_SetString(PyExc_TypeError, "sequence expected"); @@ -288,8 +285,7 @@ inline bool vector_input_wrap_helper(PyObject * seq, std::vector * out, return false; } Py_DECREF(item); - if (out) - vector_pusher::push(out, elem); + if (out) vector_pusher::push(out, elem); } Py_DECREF(it); return true; @@ -301,12 +297,10 @@ inline bool vector_input_wrap_helper(PyObject * seq, std::vector * out, // The converter function converts a C++ object of type const T or const T& // into the corresponding Python object. template -inline PyObject *list_output_helper(const T * vec, Converter converter) { - if (vec == NULL) - Py_RETURN_NONE; // Return a nice out-of-band value. +inline PyObject *list_output_helper(const T *vec, Converter converter) { + if (vec == NULL) Py_RETURN_NONE; // Return a nice out-of-band value. PyObject *lst = PyList_New(vec->size()); - if (lst == NULL) - return NULL; + if (lst == NULL) return NULL; int i = 0; for (typename T::const_reference pt : *vec) { PyObject *obj = converter(pt); @@ -319,9 +313,10 @@ inline PyObject *list_output_helper(const T * vec, Converter converter) { return lst; } -template struct OutConverter { +template +struct OutConverter { PyObject *operator()(const T x) const { - return SWIG_NewPointerObj((void *)x, type_, new_); // NOLINT + return SWIG_NewPointerObj((void *)x, type_, new_); // NOLINT } swig_type_info *type_; int new_; @@ -330,29 +325,28 @@ template struct OutConverter { }; template -inline PyObject *vector_output_helper(const std::vector * vec, - PyObject * (*converter)(const TR x)) { +inline PyObject *vector_output_helper(const std::vector *vec, + PyObject *(*converter)(const TR x)) { return list_output_helper(vec, converter); } template -inline PyObject *vector_output_helper(const std::vector * vec, - const OutConverter & converter) { +inline PyObject *vector_output_helper(const std::vector *vec, + const OutConverter &converter) { return list_output_helper(vec, converter); } template -inline PyObject *vector_output_wrap_helper(const std::vector * vec, - swig_type_info * swig_Tp_type, +inline PyObject *vector_output_wrap_helper(const std::vector *vec, + swig_type_info *swig_Tp_type, bool newobj = false) { #if 1 OutConverter converter(swig_Tp_type, newobj); return vector_output_helper(vec, converter); -#else // Lambda version - auto converter = [](const T * x) { - return SWIG_NewPointerObj((void *)x, swig_Tp_type, newobj); // NOLINT - } - return list_output_helper(vec, converter); +#else // Lambda version + auto converter = [](const T *x) { + return SWIG_NewPointerObj((void *)x, swig_Tp_type, newobj); // NOLINT + } return list_output_helper(vec, converter); #endif } @@ -365,4 +359,4 @@ inline PyObject *vector_output_wrap_helper(const std::vector * vec, #define PyInt_FromLong PyLong_FromLong #endif -#endif // OR_TOOLS_BASE_PYTHON_SWIG_H_ +#endif // OR_TOOLS_BASE_PYTHON_SWIG_H_ diff --git a/ortools/base/random.cc b/ortools/base/random.cc index 07149511e9..30c472b5ea 100644 --- a/ortools/base/random.cc +++ b/ortools/base/random.cc @@ -53,18 +53,18 @@ static inline uint32 Word32At(const char *ptr) { (static_cast(ptr[2]) << 16) + (static_cast(ptr[3]) << 24)); } -} // namespace +} // namespace int32 ACMRandom::HostnamePidTimeSeed() { - char name[PATH_MAX + 20]; // need 12 bytes for 3 'empty' uint32's + char name[PATH_MAX + 20]; // need 12 bytes for 3 'empty' uint32's assert(sizeof(name) - PATH_MAX > sizeof(uint32) * 3); if (gethostname(name, PATH_MAX) != 0) { - strcpy(name, "default-hostname"); // NOLINT + strcpy(name, "default-hostname"); // NOLINT } const int namelen = strlen(name); for (size_t i = 0; i < sizeof(uint32) * 3; ++i) { - name[namelen + i] = '\0'; // so we mix 0's once we get to end-of-string + name[namelen + i] = '\0'; // so we mix 0's once we get to end-of-string } #if defined(__GNUC__) uint32 a = getpid(); @@ -74,7 +74,7 @@ int32 ACMRandom::HostnamePidTimeSeed() { #elif defined(_MSC_VER) uint32 a = GetCurrentProcessId(); uint32 b = GetTickCount(); -#else // Do not know what to do, returning 0. +#else // Do not know what to do, returning 0. return 0; #endif uint32 c = 0; @@ -84,11 +84,11 @@ int32 ACMRandom::HostnamePidTimeSeed() { c += Word32At(name + i + sizeof(uint32) + sizeof(uint32)); mix(a, b, c); } - c += namelen; // one final mix + c += namelen; // one final mix mix(a, b, c); - return static_cast(c); // I guess the seed can be negative + return static_cast(c); // I guess the seed can be negative } int32 ACMRandom::DeterministicSeed() { return 0; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/base/random.h b/ortools/base/random.h index 005aa87606..eb16c9fd5c 100644 --- a/ortools/base/random.h +++ b/ortools/base/random.h @@ -24,7 +24,7 @@ namespace operations_research { // A wrapper around std::mt19937. Called ACMRandom for historical reasons. class ACMRandom { -public: + public: explicit ACMRandom(int32 seed) : generator_(seed) {} // Unbounded generators. @@ -48,12 +48,12 @@ public: static constexpr result_type min() { return 0; } static constexpr result_type max() { return kuint32max; } -private: + private: std::mt19937 generator_; }; class MTRandom : public ACMRandom { -public: + public: explicit MTRandom(int32 seed) : ACMRandom(seed) {} // MTRandom also supports a std::string seed. explicit MTRandom(const std::string &str_seed) @@ -61,17 +61,17 @@ public: MTRandom() : ACMRandom(ACMRandom::HostnamePidTimeSeed()) {} -private: + private: int32 GenerateInt32SeedFromString(const std::string &str) { uint32 seed = 1234567; for (size_t i = 0; i < str.size(); ++i) { - seed *= 1000003; // prime + seed *= 1000003; // prime seed += static_cast(str[i]); } - return seed >> 1; // Will fit into an int32. + return seed >> 1; // Will fit into an int32. } }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_RANDOM_H_ +#endif // OR_TOOLS_BASE_RANDOM_H_ diff --git a/ortools/base/recordio.cc b/ortools/base/recordio.cc index a3bc33504f..5f564bd4d1 100644 --- a/ortools/base/recordio.cc +++ b/ortools/base/recordio.cc @@ -33,10 +33,10 @@ void RecordWriter::set_use_compression(bool use_compression) { } std::string RecordWriter::Compress(std::string const &s) const { - const unsigned long source_size = s.size(); // NOLINT + const unsigned long source_size = s.size(); // NOLINT const char *source = s.c_str(); - unsigned long dsize = source_size + (source_size * 0.1f) + 16; // NOLINT + unsigned long dsize = source_size + (source_size * 0.1f) + 16; // NOLINT std::unique_ptr destination(new char[dsize]); // Use compress() from zlib.h. const int result = @@ -56,14 +56,14 @@ bool RecordReader::Close() { return file_->Close(); } void RecordReader::Uncompress(const char *const source, uint64 source_size, char *const output_buffer, uint64 output_size) const { - unsigned long result_size = output_size; // NOLINT - // Use uncompress() from zlib.h + unsigned long result_size = output_size; // NOLINT + // Use uncompress() from zlib.h const int result = uncompress(reinterpret_cast(output_buffer), &result_size, reinterpret_cast(source), source_size); if (result != Z_OK) { LOG(FATAL) << "Uncompress error occurred! Error code: " << result; } - CHECK_LE(result_size, static_cast(output_size)); // NOLINT + CHECK_LE(result_size, static_cast(output_size)); // NOLINT } -} // namespace recordio +} // namespace recordio diff --git a/ortools/base/recordio.h b/ortools/base/recordio.h index 39ef2c36c3..e9b8278b44 100644 --- a/ortools/base/recordio.h +++ b/ortools/base/recordio.h @@ -31,13 +31,14 @@ namespace recordio { // - Payload, possibly compressed. See RecordWriter::Compress() // and RecordReader::Uncompress. class RecordWriter { -public: + public: // Magic number when reading and writing protocol buffers. static const int kMagicNumber; explicit RecordWriter(File *const file); - template bool WriteProtocolMessage(const P &proto) { + template + bool WriteProtocolMessage(const P &proto) { std::string uncompressed_buffer; proto.SerializeToString(&uncompressed_buffer); const uint64 uncompressed_size = uncompressed_buffer.size(); @@ -74,7 +75,7 @@ public: void set_use_compression(bool use_compression); -private: + private: std::string Compress(const std::string &input) const; File *const file_; bool use_compression_; @@ -83,10 +84,11 @@ private: // This class reads a protocol buffer from a file. // The format must be the one described in RecordWriter, above. class RecordReader { -public: + public: explicit RecordReader(File *const file); - template bool ReadProtocolMessage(P *const proto) { + template + bool ReadProtocolMessage(P *const proto) { uint64 usize = 0; uint64 csize = 0; int magic_number = 0; @@ -104,7 +106,7 @@ public: return false; } std::unique_ptr buffer(new char[usize + 1]); - if (csize != 0) { // The data is compressed. + if (csize != 0) { // The data is compressed. std::unique_ptr compressed_buffer(new char[csize + 1]); if (file_->Read(compressed_buffer.get(), csize) != csize) { return false; @@ -123,12 +125,12 @@ public: // Closes the underlying file. bool Close(); -private: + private: void Uncompress(const char *const source, uint64 source_size, char *const output_buffer, uint64 output_size) const; File *const file_; }; -} // namespace recordio +} // namespace recordio -#endif // OR_TOOLS_BASE_RECORDIO_H_ +#endif // OR_TOOLS_BASE_RECORDIO_H_ diff --git a/ortools/base/small_map.h b/ortools/base/small_map.h index 782cd1d8a1..777f7e7440 100644 --- a/ortools/base/small_map.h +++ b/ortools/base/small_map.h @@ -15,8 +15,8 @@ #define OR_TOOLS_BASE_SMALL_MAP_H_ namespace gtl { -template class small_map : public T { -}; -} // namespace gtl +template +class small_map : public T {}; +} // namespace gtl -#endif // OR_TOOLS_BASE_SMALL_MAP_H_ +#endif // OR_TOOLS_BASE_SMALL_MAP_H_ diff --git a/ortools/base/small_ordered_set.h b/ortools/base/small_ordered_set.h index c3c53a58b9..4a9c9567ee 100644 --- a/ortools/base/small_ordered_set.h +++ b/ortools/base/small_ordered_set.h @@ -15,8 +15,8 @@ #define OR_TOOLS_BASE_SMALL_ORDERED_SET_H_ namespace gtl { -template class small_ordered_set : public T { -}; -} // namespace gtl +template +class small_ordered_set : public T {}; +} // namespace gtl -#endif // OR_TOOLS_BASE_SMALL_ORDERED_SET_H_ +#endif // OR_TOOLS_BASE_SMALL_ORDERED_SET_H_ diff --git a/ortools/base/status_builder.h b/ortools/base/status_builder.h index dba958d690..dce52a6a3c 100644 --- a/ortools/base/status_builder.h +++ b/ortools/base/status_builder.h @@ -21,27 +21,28 @@ namespace util { class StatusBuilder { -public: + public: explicit StatusBuilder(const absl::Status &status) : code_(status.code()) { ss_ << std::string(status.message()); } - operator absl::Status() const { // NOLINT + operator absl::Status() const { // NOLINT return absl::Status(code_, ss_.str()); } - template StatusBuilder &operator<<(const T &t) { + template + StatusBuilder &operator<<(const T &t) { ss_ << t; return *this; } StatusBuilder &SetAppend() { return *this; } -private: + private: const absl::StatusCode code_; std::ostringstream ss_; }; -} // namespace util +} // namespace util -#endif // OR_TOOLS_BASE_STATUS_BUILDER_H_ +#endif // OR_TOOLS_BASE_STATUS_BUILDER_H_ diff --git a/ortools/base/status_macros.h b/ortools/base/status_macros.h index 0a4b81313e..1d1f10f272 100644 --- a/ortools/base/status_macros.h +++ b/ortools/base/status_macros.h @@ -24,12 +24,11 @@ namespace absl { // // Example: // RETURN_IF_ERROR(DoThings(4)); -#define RETURN_IF_ERROR(expr) \ - do { \ - /* Using _status below to avoid capture problems if expr is "status". */ \ - const ::absl::Status _status = (expr); \ - if (!_status.ok()) \ - return _status; \ +#define RETURN_IF_ERROR(expr) \ + do { \ + /* Using _status below to avoid capture problems if expr is "status". */ \ + const ::absl::Status _status = (expr); \ + if (!_status.ok()) return _status; \ } while (0) // Internal helper for concatenating macro values. @@ -37,17 +36,16 @@ namespace absl { #define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y) template -::absl::Status DoAssignOrReturn(T &lhs, ::absl::StatusOr result) { // NOLINT +::absl::Status DoAssignOrReturn(T &lhs, ::absl::StatusOr result) { // NOLINT if (result.ok()) { lhs = result.value(); } return result.status(); } -#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \ - ::absl::Status status = DoAssignOrReturn(lhs, (rexpr)); \ - if (!status.ok()) \ - return status; +#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \ + ::absl::Status status = DoAssignOrReturn(lhs, (rexpr)); \ + if (!status.ok()) return status; // Executes an expression that returns an absl::StatusOr, extracting its value // into the variable defined by lhs (or returning on error). @@ -58,10 +56,10 @@ template // // WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used // in a single statement (e.g. as the body of an if statement without {})! -#define ASSIGN_OR_RETURN(lhs, rexpr) \ - ASSIGN_OR_RETURN_IMPL( \ +#define ASSIGN_OR_RETURN(lhs, rexpr) \ + ASSIGN_OR_RETURN_IMPL( \ STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr); -} // namespace absl +} // namespace absl -#endif // OR_TOOLS_BASE_STATUS_MACROS_H_ +#endif // OR_TOOLS_BASE_STATUS_MACROS_H_ diff --git a/ortools/base/stl_util.h b/ortools/base/stl_util.h index 90a0164725..8fbeca0075 100644 --- a/ortools/base/stl_util.h +++ b/ortools/base/stl_util.h @@ -37,17 +37,19 @@ namespace gtl { namespace internal { -template class Equiv { -public: +template +class Equiv { + public: explicit Equiv(const LessFunc &f) : f_(f) {} - template bool operator()(const T &a, const T &b) const { + template + bool operator()(const T &a, const T &b) const { return !f_(b, a) && !f_(a, b); } -private: + private: LessFunc f_; }; -} // namespace internal +} // namespace internal // Sorts and removes duplicates from a sequence container. // If specified, the 'less_func' is used to compose an @@ -59,7 +61,8 @@ inline void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func) { gtl::internal::Equiv(less_func)), v->end()); } -template inline void STLSortAndRemoveDuplicates(T *v) { +template +inline void STLSortAndRemoveDuplicates(T *v) { std::sort(v->begin(), v->end()); v->erase(std::unique(v->begin(), v->end()), v->end()); } @@ -78,7 +81,8 @@ inline void STLStableSortAndRemoveDuplicates(T *v, const LessFunc &less_func) { // Stable sorts and removes duplicates from a sequence container, retaining // the first equivalent element for each equivalence set, using < comparison and // == equivalence testing. -template inline void STLStableSortAndRemoveDuplicates(T *v) { +template +inline void STLStableSortAndRemoveDuplicates(T *v) { std::stable_sort(v->begin(), v->end()); v->erase(std::unique(v->begin(), v->end()), v->end()); } @@ -99,7 +103,8 @@ void STLEraseAllFromSequence(std::forward_list *c, const E &e) { } // Remove each element e in v satisfying pred(e). -template void STLEraseAllFromSequenceIf(T *v, P pred) { +template +void STLEraseAllFromSequenceIf(T *v, P pred) { v->erase(std::remove_if(v->begin(), v->end(), pred), v->end()); } template @@ -114,7 +119,8 @@ void STLEraseAllFromSequenceIf(std::forward_list *c, P pred) { // Clears internal memory of an STL object by swapping the argument with a new, // empty object. STL clear()/reserve(0) does not always free internal memory // allocated. -template void STLClearObject(T *obj) { +template +void STLClearObject(T *obj) { T tmp; tmp.swap(*obj); // This reserve(0) is needed because "T tmp" sometimes allocates memory (arena @@ -122,7 +128,8 @@ template void STLClearObject(T *obj) { obj->reserve(0); } // STLClearObject overload for deque, which is missing reserve(). -template void STLClearObject(std::deque *obj) { +template +void STLClearObject(std::deque *obj) { std::deque tmp; tmp.swap(*obj); } @@ -169,7 +176,8 @@ inline void STLClearIfBig(std::deque *obj, size_t limit = 1 << 20) { // insert a lot of items, the number of buckets is reset to the default to keep // subsequent clear operations cheap. Note that the default number of buckets is // 193 in the Gnu library implementation as of Jan '08. -template inline void STLClearHashIfBig(T *obj, size_t limit) { +template +inline void STLClearHashIfBig(T *obj, size_t limit) { if (obj->bucket_count() >= limit) { T tmp; tmp.swap(*obj); @@ -184,8 +192,7 @@ template inline void STLClearHashIfBig(T *obj, size_t limit) { // The behavior of this function is similar to that of vector::reserve() but for // string. inline void STLStringReserveIfNeeded(std::string *s, size_t min_capacity) { - if (min_capacity > s->capacity()) - s->reserve(min_capacity); + if (min_capacity > s->capacity()) s->reserve(min_capacity); } // Like str->resize(new_size), except any new characters added to "*str" as a @@ -218,8 +225,7 @@ inline bool STLStringSupportsNontrashingResize( // string::assign() may be faster than this.) inline void STLAssignToString(std::string *str, const char *ptr, size_t n) { STLStringResizeUninitialized(str, n); - if (n == 0) - return; + if (n == 0) return; memcpy(&*str->begin(), ptr, n); } @@ -231,8 +237,7 @@ inline void STLAssignToString(std::string *str, const char *ptr, size_t n) { // function makes your code faster. (Even then, a future version of // string::append() may be faster than this.) inline void STLAppendToString(std::string *str, const char *ptr, size_t n) { - if (n == 0) - return; + if (n == 0) return; size_t old_size = str->size(); STLStringResizeUninitialized(str, old_size + n); memcpy(&*str->begin() + old_size, ptr, n); @@ -263,12 +268,10 @@ inline char *string_as_array(std::string *str) { // order of insertions and deletions differed. template inline bool HashSetEquality(const HashSet &set_a, const HashSet &set_b) { - if (set_a.size() != set_b.size()) - return false; + if (set_a.size() != set_b.size()) return false; for (typename HashSet::const_iterator i = set_a.begin(); i != set_a.end(); ++i) - if (set_b.find(*i) == set_b.end()) - return false; + if (set_b.find(*i) == set_b.end()) return false; return true; } @@ -278,15 +281,12 @@ inline bool HashSetEquality(const HashSet &set_a, const HashSet &set_b) { template inline bool HashMapEquality(const HashMap &map_a, const HashMap &map_b, BinaryPredicate mapped_type_equal) { - if (map_a.size() != map_b.size()) - return false; + if (map_a.size() != map_b.size()) return false; for (typename HashMap::const_iterator i = map_a.begin(); i != map_a.end(); ++i) { typename HashMap::const_iterator j = map_b.find(i->first); - if (j == map_b.end()) - return false; - if (!mapped_type_equal(i->second, j->second)) - return false; + if (j == map_b.end()) return false; + if (!mapped_type_equal(i->second, j->second)) return false; } return true; } @@ -368,9 +368,9 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin, // As an alternative to calling STLDeleteElements() directly, consider // ElementDeleter (defined below), which ensures that your container's elements // are deleted when the ElementDeleter goes out of scope. -template void STLDeleteElements(T *container) { - if (!container) - return; +template +void STLDeleteElements(T *container) { + if (!container) return; STLDeleteContainerPointers(container->begin(), container->end()); container->clear(); } @@ -378,9 +378,9 @@ template void STLDeleteElements(T *container) { // Given an STL container consisting of (key, value) pairs, STLDeleteValues // deletes all the "value" components and clears the container. Does nothing in // the case it's given a nullptr. -template void STLDeleteValues(T *v) { - if (!v) - return; +template +void STLDeleteValues(T *v) { + if (!v) return; (STLDeleteContainerPairSecondPointers)(v->begin(), v->end()); v->clear(); } @@ -391,12 +391,12 @@ template void STLDeleteValues(T *v) { // // Clients should NOT use this class directly. class BaseDeleter { -public: + public: virtual ~BaseDeleter() {} BaseDeleter(const BaseDeleter &) = delete; void operator=(const BaseDeleter &) = delete; -protected: + protected: BaseDeleter() {} }; @@ -406,7 +406,7 @@ protected: // Clients should NOT use this class directly. Use ElementDeleter instead. template class TemplatedElementDeleter : public BaseDeleter { -public: + public: explicit TemplatedElementDeleter(STLContainer *ptr) : container_ptr_(ptr) {} virtual ~TemplatedElementDeleter() { STLDeleteElements(container_ptr_); } @@ -414,7 +414,7 @@ public: TemplatedElementDeleter(const TemplatedElementDeleter &) = delete; void operator=(const TemplatedElementDeleter &) = delete; -private: + private: STLContainer *container_ptr_; }; @@ -432,7 +432,7 @@ private: // // Since C++11, consider using containers of std::unique_ptr instead. class ElementDeleter { -public: + public: template explicit ElementDeleter(STLContainer *ptr) : deleter_(new TemplatedElementDeleter(ptr)) {} @@ -442,7 +442,7 @@ public: ElementDeleter(const ElementDeleter &) = delete; void operator=(const ElementDeleter &) = delete; -private: + private: BaseDeleter *deleter_; }; @@ -452,7 +452,7 @@ private: // Clients should NOT use this class directly. Use ValueDeleter instead. template class TemplatedValueDeleter : public BaseDeleter { -public: + public: explicit TemplatedValueDeleter(STLContainer *ptr) : container_ptr_(ptr) {} virtual ~TemplatedValueDeleter() { STLDeleteValues(container_ptr_); } @@ -460,7 +460,7 @@ public: TemplatedValueDeleter(const TemplatedValueDeleter &) = delete; void operator=(const TemplatedValueDeleter &) = delete; -private: + private: STLContainer *container_ptr_; }; @@ -474,7 +474,7 @@ private: // ... // return success; class ValueDeleter { -public: + public: template explicit ValueDeleter(STLContainer *ptr) : deleter_(new TemplatedValueDeleter(ptr)) {} @@ -484,7 +484,7 @@ public: ValueDeleter(const ValueDeleter &) = delete; void operator=(const ValueDeleter &) = delete; -private: + private: BaseDeleter *deleter_; }; @@ -493,12 +493,13 @@ private: // templated and doesn't have a virtual destructor. // // New code should prefer ElementDeleter. -template class STLElementDeleter { -public: +template +class STLElementDeleter { + public: STLElementDeleter(STLContainer *ptr) : container_ptr_(ptr) {} ~STLElementDeleter() { STLDeleteElements(container_ptr_); } -private: + private: STLContainer *container_ptr_; }; @@ -507,12 +508,13 @@ private: // this class is templated and doesn't have a virtual destructor. // // New code should prefer ValueDeleter. -template class STLValueDeleter { -public: +template +class STLValueDeleter { + public: STLValueDeleter(STLContainer *ptr) : container_ptr_(ptr) {} ~STLValueDeleter() { STLDeleteValues(container_ptr_); } -private: + private: STLContainer *container_ptr_; }; @@ -527,7 +529,8 @@ private: // Foo* safe = release_ptr(&v[1]); // // v[1] is now nullptr and the Foo it previously pointed to is now // // stored in "safe" -template ABSL_MUST_USE_RESULT T *release_ptr(T **ptr) { +template +ABSL_MUST_USE_RESULT T *release_ptr(T **ptr) { assert(ptr); T *tmp = *ptr; *ptr = nullptr; @@ -538,7 +541,8 @@ namespace stl_util_internal { // Like std::less, but allows heterogeneous arguments. struct TransparentLess { - template bool operator()(const T &a, const T &b) const { + template + bool operator()(const T &a, const T &b) const { // std::less is better than '<' here, because it can order pointers. return std::less()(a, b); } @@ -553,20 +557,17 @@ struct TransparentLess { // not contain an inner type `reverse_iterator`. // If the container is iterable in reverse, then order might actually matter. template -struct Unordered : std::false_type { -}; +struct Unordered : std::false_type {}; template -struct Unordered > : std::true_type { -}; +struct Unordered > : std::true_type {}; template -struct Unordered< - T, absl::void_t, - absl::void_t > : std::false_type { -}; +struct Unordered, + absl::void_t > + : std::false_type {}; -} // namespace stl_util_internal +} // namespace stl_util_internal // STLSetDifference: // @@ -608,7 +609,7 @@ void STLSetDifference(const In1 &a, const In2 &b, Out *out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename std::enable_if< !std::is_function::value, void>::type +typename std::enable_if::value, void>::type STLSetDifference(const In1 &a, const In2 &b, Out *out) { STLSetDifference(a, b, out, gtl::stl_util_internal::TransparentLess()); } @@ -635,7 +636,8 @@ template In1 STLSetDifference(const In1 &a, const In2 &b) { return STLSetDifference(a, b, gtl::stl_util_internal::TransparentLess()); } -template In1 STLSetDifference(const In1 &a, const In1 &b) { +template +In1 STLSetDifference(const In1 &a, const In1 &b) { return STLSetDifference(a, b, gtl::stl_util_internal::TransparentLess()); } @@ -670,8 +672,8 @@ void STLSetUnion(const In1 &a, const In2 &b, Out *out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename std::enable_if< !std::is_function::value, void>::type -STLSetUnion(const In1 &a, const In2 &b, Out *out) { +typename std::enable_if::value, void>::type STLSetUnion( + const In1 &a, const In2 &b, Out *out) { return STLSetUnion(a, b, out, gtl::stl_util_internal::TransparentLess()); } template @@ -692,7 +694,8 @@ template In1 STLSetUnion(const In1 &a, const In2 &b) { return STLSetUnion(a, b, gtl::stl_util_internal::TransparentLess()); } -template In1 STLSetUnion(const In1 &a, const In1 &b) { +template +In1 STLSetUnion(const In1 &a, const In1 &b) { return STLSetUnion(a, b, gtl::stl_util_internal::TransparentLess()); } @@ -729,7 +732,7 @@ void STLSetSymmetricDifference(const In1 &a, const In2 &b, Out *out, // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename std::enable_if< !std::is_function::value, void>::type +typename std::enable_if::value, void>::type STLSetSymmetricDifference(const In1 &a, const In2 &b, Out *out) { return STLSetSymmetricDifference(a, b, out, gtl::stl_util_internal::TransparentLess()); @@ -791,7 +794,7 @@ void STLSetIntersection(const In1 &a, const In2 &b, Out *out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename std::enable_if< !std::is_function::value, void>::type +typename std::enable_if::value, void>::type STLSetIntersection(const In1 &a, const In2 &b, Out *out) { return STLSetIntersection(a, b, out, gtl::stl_util_internal::TransparentLess()); @@ -815,7 +818,8 @@ template In1 STLSetIntersection(const In1 &a, const In2 &b) { return STLSetIntersection(a, b, gtl::stl_util_internal::TransparentLess()); } -template In1 STLSetIntersection(const In1 &a, const In1 &b) { +template +In1 STLSetIntersection(const In1 &a, const In1 &b) { return STLSetIntersection(a, b, gtl::stl_util_internal::TransparentLess()); } @@ -904,7 +908,7 @@ bool SortedContainersHaveIntersection(const In1 &in1, const In2 &in2) { // template > class STLCountingAllocator : public Alloc { -public: + public: using Base = Alloc; using pointer = typename Alloc::pointer; using size_type = typename Alloc::size_type; @@ -931,21 +935,23 @@ public: } // Rebind allows an std::allocator to be used for a different type - template class rebind { + template + class rebind { using OtherA = typename Alloc::template rebind::other; - public: + public: using other = STLCountingAllocator; }; int64 *bytes_used() const { return bytes_used_; } -private: + private: int64 *bytes_used_; }; -template class STLCountingAllocator : public A { -public: +template +class STLCountingAllocator : public A { + public: STLCountingAllocator() : bytes_used_(nullptr) {} explicit STLCountingAllocator(int64 *b) : bytes_used_(b) {} @@ -954,31 +960,32 @@ public: STLCountingAllocator(const STLCountingAllocator &x) : A(x), bytes_used_(x.bytes_used()) {} - template class rebind { + template + class rebind { using OtherA = typename A::template rebind::other; - public: + public: using other = STLCountingAllocator; }; int64 *bytes_used() const { return bytes_used_; } -private: + private: int64 *bytes_used_; }; template - bool operator==(const STLCountingAllocator &a, - const STLCountingAllocator &b) { +bool operator==(const STLCountingAllocator &a, + const STLCountingAllocator &b) { using Base = typename STLCountingAllocator::Base; return static_cast(a) == static_cast(b) && a.bytes_used() == b.bytes_used(); } template - bool operator!=(const STLCountingAllocator &a, - const STLCountingAllocator &b) { +bool operator!=(const STLCountingAllocator &a, + const STLCountingAllocator &b) { return !(a == b); } -} // namespace gtl -#endif // OR_TOOLS_BASE_STL_UTIL_H_ +} // namespace gtl +#endif // OR_TOOLS_BASE_STL_UTIL_H_ diff --git a/ortools/base/sysinfo.cc b/ortools/base/sysinfo.cc index 98a38a5bcb..4a73bb8988 100644 --- a/ortools/base/sysinfo.cc +++ b/ortools/base/sysinfo.cc @@ -14,17 +14,17 @@ #if defined(__GNUC__) && defined(__linux__) #include #endif -#if defined(__APPLE__) && defined(__GNUC__) // Mac OS X +#if defined(__APPLE__) && defined(__GNUC__) // Mac OS X #include #include -#elif defined(__FreeBSD__) // FreeBSD +#elif defined(__FreeBSD__) // FreeBSD #include #include -#elif defined(_MSC_VER) // WINDOWS - // clang-format off +#elif defined(_MSC_VER) // WINDOWS + // clang-format off #include #include - // clang-format on +// clang-format on #endif #include @@ -34,42 +34,39 @@ namespace operations_research { // GetProcessMemoryUsage -#if defined(__APPLE__) && defined(__GNUC__) // Mac OS X +#if defined(__APPLE__) && defined(__GNUC__) // Mac OS X int64 GetProcessMemoryUsage() { task_t task = MACH_PORT_NULL; struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, - (task_info_t) & t_info, &t_info_count)) { + (task_info_t)&t_info, &t_info_count)) { return -1; } int64 resident_memory = t_info.resident_size; return resident_memory; } -#elif defined(__GNUC__) && !defined(__FreeBSD__) // LINUX +#elif defined(__GNUC__) && !defined(__FreeBSD__) // LINUX int64 GetProcessMemoryUsage() { unsigned size = 0; char buf[30]; - snprintf(buf, sizeof(buf), "/proc/%u/statm", (unsigned) getpid()); + snprintf(buf, sizeof(buf), "/proc/%u/statm", (unsigned)getpid()); FILE *const pf = fopen(buf, "r"); if (pf) { - if (fscanf(pf, "%u", &size) != 1) - return 0; + if (fscanf(pf, "%u", &size) != 1) return 0; } fclose(pf); - return size * int64 { 1024 }; + return size * int64{1024}; } -#elif defined(__FreeBSD__) // FreeBSD +#elif defined(__FreeBSD__) // FreeBSD int64 GetProcessMemoryUsage() { int who = RUSAGE_SELF; struct rusage rusage; getrusage(who, &rusage); - return (int64)(rusage.ru_maxrss * int64 { - 1024 - }); + return (int64)(rusage.ru_maxrss * int64{1024}); } -#elif defined(_MSC_VER) // WINDOWS +#elif defined(_MSC_VER) // WINDOWS int64 GetProcessMemoryUsage() { HANDLE hProcess; PROCESS_MEMORY_COUNTERS pmc; @@ -84,8 +81,8 @@ int64 GetProcessMemoryUsage() { } return memory; } -#else // Unknown, returning 0. +#else // Unknown, returning 0. int64 GetProcessMemoryUsage() { return 0; } #endif -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/base/sysinfo.h b/ortools/base/sysinfo.h index 90c394ad3b..c625d0015e 100644 --- a/ortools/base/sysinfo.h +++ b/ortools/base/sysinfo.h @@ -19,10 +19,10 @@ namespace operations_research { // Returns the memory usage of the process. int64 GetProcessMemoryUsage(); -} // namespace operations_research +} // namespace operations_research inline int64 MemoryUsage(int unused) { return operations_research::GetProcessMemoryUsage(); } -#endif // OR_TOOLS_BASE_SYSINFO_H_ +#endif // OR_TOOLS_BASE_SYSINFO_H_ diff --git a/ortools/base/thorough_hash.h b/ortools/base/thorough_hash.h index bd195a5b51..7aefb225a6 100644 --- a/ortools/base/thorough_hash.h +++ b/ortools/base/thorough_hash.h @@ -48,6 +48,6 @@ inline uint64 ThoroughHash(const char *bytes, size_t len) { } return MixTwoUInt64(fp, last_bytes); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_THOROUGH_HASH_H_ +#endif // OR_TOOLS_BASE_THOROUGH_HASH_H_ diff --git a/ortools/base/threadpool.cc b/ortools/base/threadpool.cc index fc0429acf8..1ad2032c68 100644 --- a/ortools/base/threadpool.cc +++ b/ortools/base/threadpool.cc @@ -87,4 +87,4 @@ void ThreadPool::Schedule(std::function closure) { } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/base/threadpool.h b/ortools/base/threadpool.h index 55e0064888..05aad62e20 100644 --- a/ortools/base/threadpool.h +++ b/ortools/base/threadpool.h @@ -14,17 +14,17 @@ #ifndef OR_TOOLS_BASE_THREADPOOL_H_ #define OR_TOOLS_BASE_THREADPOOL_H_ -#include // NOLINT +#include // NOLINT #include #include -#include // NOLINT +#include // NOLINT #include -#include // NOLINT +#include // NOLINT #include namespace operations_research { class ThreadPool { -public: + public: ThreadPool(const std::string &prefix, int num_threads); ~ThreadPool(); @@ -33,7 +33,7 @@ public: std::function GetNextTask(); void SetQueueCapacity(int capacity); -private: + private: const int num_workers_; std::list > tasks_; std::mutex mutex_; @@ -45,5 +45,5 @@ private: int queue_capacity_ = 2e9; std::vector all_workers_; }; -} // namespace operations_research -#endif // OR_TOOLS_BASE_THREADPOOL_H_ +} // namespace operations_research +#endif // OR_TOOLS_BASE_THREADPOOL_H_ diff --git a/ortools/base/timer.h b/ortools/base/timer.h index 5055692e53..af1cd011de 100644 --- a/ortools/base/timer.h +++ b/ortools/base/timer.h @@ -21,7 +21,7 @@ #include "ortools/base/macros.h" class WallTimer { -public: + public: WallTimer() { Reset(); } void Reset() { running_ = false; @@ -49,12 +49,12 @@ public: return absl::Nanoseconds(GetNanos()); } -protected: + protected: int64 GetNanos() const { return running_ ? absl::GetCurrentTimeNanos() - start_ + sum_ : sum_; } -private: + private: bool running_; int64 start_; int64 sum_; @@ -70,7 +70,7 @@ typedef WallTimer UserTimer; // But this current implementation just uses GetCurrentTimeNanos(). // TODO(user): implement it. class CycleTimer : public WallTimer { -public: + public: // This actually returns a number of nanoseconds instead of the number // of CPU cycles. int64 GetCycles() const { return GetNanos(); } @@ -80,7 +80,7 @@ typedef CycleTimer SimpleCycleTimer; // Conversion routines between CycleTimer::GetCycles and actual times. class CycleTimerBase { -public: + public: static int64 SecondsToCycles(double s) { return static_cast(s * 1e9); } static double CyclesToSeconds(int64 c) { return c * 1e-9; } static int64 CyclesToMs(int64 c) { return c / 1000000; } @@ -93,14 +93,14 @@ typedef CycleTimerBase CycleTimerInstance; typedef WallTimer ClockTimer; class ScopedWallTime { -public: + public: // We do not own the pointer. The pointer must be valid for the duration // of the existence of the ScopedWallTime instance. Not thread safe for // aggregate_time. explicit ScopedWallTime(double *aggregate_time); ~ScopedWallTime(); -private: + private: double *aggregate_time_; // When the instance was created. @@ -108,4 +108,4 @@ private: DISALLOW_COPY_AND_ASSIGN(ScopedWallTime); }; -#endif // OR_TOOLS_BASE_TIMER_H_ +#endif // OR_TOOLS_BASE_TIMER_H_ diff --git a/ortools/base/typeid.h b/ortools/base/typeid.h index 0a2ab3d2e5..b3c8e745bf 100644 --- a/ortools/base/typeid.h +++ b/ortools/base/typeid.h @@ -15,9 +15,10 @@ #define OR_TOOLS_BASE_TYPEID_H_ namespace gtl { -template inline size_t FastTypeId() { +template +inline size_t FastTypeId() { static char d; return reinterpret_cast(&d); } -} // namespace gtl -#endif // OR_TOOLS_BASE_TYPEID_H_ +} // namespace gtl +#endif // OR_TOOLS_BASE_TYPEID_H_ diff --git a/ortools/base/version.cc b/ortools/base/version.cc index 6945419f06..a53135a131 100644 --- a/ortools/base/version.cc +++ b/ortools/base/version.cc @@ -18,4 +18,4 @@ namespace operations_research { int OrToolsMajorVersion() { return OR_TOOLS_MAJOR; } int OrToolsMinorVersion() { return OR_TOOLS_MINOR; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/base/version.h b/ortools/base/version.h index 76e4e8fa13..700c9a41d2 100644 --- a/ortools/base/version.h +++ b/ortools/base/version.h @@ -19,6 +19,6 @@ namespace operations_research { int OrToolsMajorVersion(); int OrToolsMinorVersion(); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_BASE_VERSION_H_ +#endif // OR_TOOLS_BASE_VERSION_H_ diff --git a/ortools/bop/bop_base.cc b/ortools/bop/bop_base.cc index 0b57a3eca3..e7268dfa6e 100644 --- a/ortools/bop/bop_base.cc +++ b/ortools/bop/bop_base.cc @@ -37,20 +37,20 @@ BopOptimizerBase::~BopOptimizerBase() { std::string BopOptimizerBase::GetStatusString(Status status) { switch (status) { - case OPTIMAL_SOLUTION_FOUND: - return "OPTIMAL_SOLUTION_FOUND"; - case SOLUTION_FOUND: - return "SOLUTION_FOUND"; - case INFEASIBLE: - return "INFEASIBLE"; - case LIMIT_REACHED: - return "LIMIT_REACHED"; - case INFORMATION_FOUND: - return "INFORMATION_FOUND"; - case CONTINUE: - return "CONTINUE"; - case ABORT: - return "ABORT"; + case OPTIMAL_SOLUTION_FOUND: + return "OPTIMAL_SOLUTION_FOUND"; + case SOLUTION_FOUND: + return "SOLUTION_FOUND"; + case INFEASIBLE: + return "INFEASIBLE"; + case LIMIT_REACHED: + return "LIMIT_REACHED"; + case INFORMATION_FOUND: + return "INFORMATION_FOUND"; + case CONTINUE: + return "CONTINUE"; + case ABORT: + return "ABORT"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -64,31 +64,32 @@ std::string BopOptimizerBase::GetStatusString(Status status) { const int64 ProblemState::kInitialStampValue(0); ProblemState::ProblemState(const LinearBooleanProblem &problem) - : original_problem_(problem), parameters_(), + : original_problem_(problem), + parameters_(), update_stamp_(kInitialStampValue + 1), is_fixed_(problem.num_variables(), false), - fixed_values_(problem.num_variables(), false), lp_values_(), - solution_(problem, "AllZero"), assignment_preference_(), - lower_bound_(kint64min), upper_bound_(kint64max) { + fixed_values_(problem.num_variables(), false), + lp_values_(), + solution_(problem, "AllZero"), + assignment_preference_(), + lower_bound_(kint64min), + upper_bound_(kint64max) { // TODO(user): Extract to a function used by all solvers. // Compute trivial unscaled lower bound. const LinearObjective &objective = problem.objective(); lower_bound_ = 0; for (int i = 0; i < objective.coefficients_size(); ++i) { - // Fix template version for or-tools. - lower_bound_ += std::min(int64 { - 0 - }, - objective.coefficients(i)); + // Fix template version for or-tools. + lower_bound_ += std::min(int64{0}, objective.coefficients(i)); } upper_bound_ = solution_.IsFeasible() ? solution_.GetCost() : kint64max; } // TODO(user): refactor this to not rely on the optimization status. // All the information can be encoded in the learned_info bounds. -bool -ProblemState::MergeLearnedInfo(const LearnedInfo &learned_info, - BopOptimizerBase::Status optimization_status) { +bool ProblemState::MergeLearnedInfo( + const LearnedInfo &learned_info, + BopOptimizerBase::Status optimization_status) { const std::string kIndent(25, ' '); bool new_lp_values = false; @@ -111,9 +112,8 @@ ProblemState::MergeLearnedInfo(const LearnedInfo &learned_info, } if (binary_clause_manager_.NumClauses() > old_num) { new_binary_clauses = true; - VLOG(1) - << kIndent + - "Num binary clauses: " << binary_clause_manager_.NumClauses(); + VLOG(1) << kIndent + "Num binary clauses: " + << binary_clause_manager_.NumClauses(); } } @@ -203,11 +203,10 @@ ProblemState::MergeLearnedInfo(const LearnedInfo &learned_info, known_status = true; } - const bool updated = - new_lp_values || new_binary_clauses || new_solution || new_lower_bound || - num_newly_fixed_variables > 0 || known_status; - if (updated) - ++update_stamp_; + const bool updated = new_lp_values || new_binary_clauses || new_solution || + new_lower_bound || num_newly_fixed_variables > 0 || + known_status; + if (updated) ++update_stamp_; return updated; } @@ -245,8 +244,8 @@ void ProblemState::MarkAsInfeasible() { ++update_stamp_; } -const std::vector & -ProblemState::NewlyAddedBinaryClauses() const { +const std::vector &ProblemState::NewlyAddedBinaryClauses() + const { return binary_clause_manager_.newly_added(); } @@ -254,5 +253,5 @@ void ProblemState::SynchronizationDone() { binary_clause_manager_.ClearNewlyAdded(); } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_base.h b/ortools/bop/bop_base.h index 7c580d96c7..7396002289 100644 --- a/ortools/bop/bop_base.h +++ b/ortools/bop/bop_base.h @@ -38,7 +38,7 @@ class ProblemState; // Optimizers implementing this class are used in a sort of portfolio and // are run sequentially or concurrently. See for instance BopRandomLNSOptimizer. class BopOptimizerBase { -public: + public: explicit BopOptimizerBase(const std::string &name); virtual ~BopOptimizerBase(); @@ -94,7 +94,7 @@ public: // Returns a string describing the status. static std::string GetStatusString(Status status); -protected: + protected: const std::string name_; mutable StatsGroup stats_; @@ -109,7 +109,7 @@ inline std::ostream &operator<<(std::ostream &os, // This class represents the current state of the problem with all the // information that the solver learned about it at a given time. class ProblemState { -public: + public: explicit ProblemState(const sat::LinearBooleanProblem &problem); // Sets parameters, used for instance to get the tolerance, the gap limit... @@ -219,7 +219,7 @@ public: // once all the optimize have been synchronized. void SynchronizationDone(); -private: + private: const sat::LinearBooleanProblem &original_problem_; BopParameters parameters_; int64 update_stamp_; @@ -244,8 +244,11 @@ private: // by the next called optimizer. struct LearnedInfo { explicit LearnedInfo(const sat::LinearBooleanProblem &problem) - : fixed_literals(), solution(problem, "AllZero"), lower_bound(kint64min), - lp_values(), binary_clauses() {} + : fixed_literals(), + solution(problem, "AllZero"), + lower_bound(kint64min), + lp_values(), + binary_clauses() {} // Clears all just as if the object were a brand new one. This can be used // to reduce the number of creation / deletion of objects. @@ -275,6 +278,6 @@ struct LearnedInfo { std::vector binary_clauses; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_BASE_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_BASE_H_ diff --git a/ortools/bop/bop_fs.cc b/ortools/bop/bop_fs.cc index 4d16d20be8..04c7824330 100644 --- a/ortools/bop/bop_fs.cc +++ b/ortools/bop/bop_fs.cc @@ -68,7 +68,7 @@ void DenseRowToBopSolution(const DenseRow &values, BopSolution *solution) { solution->SetValue(var, round(values[ColIndex(var.value())])); } } -} // anonymous namespace +} // anonymous namespace //------------------------------------------------------------------------------ // GuidedSatFirstSolutionGenerator @@ -76,8 +76,11 @@ void DenseRowToBopSolution(const DenseRow &values, BopSolution *solution) { GuidedSatFirstSolutionGenerator::GuidedSatFirstSolutionGenerator( const std::string &name, Policy policy) - : BopOptimizerBase(name), policy_(policy), abort_(false), - state_update_stamp_(ProblemState::kInitialStampValue), sat_solver_() {} + : BopOptimizerBase(name), + policy_(policy), + abort_(false), + state_update_stamp_(ProblemState::kInitialStampValue), + sat_solver_() {} GuidedSatFirstSolutionGenerator::~GuidedSatFirstSolutionGenerator() {} @@ -110,40 +113,38 @@ BopOptimizerBase::Status GuidedSatFirstSolutionGenerator::SynchronizeIfNeeded( const BopOptimizerBase::Status load_status = LoadStateProblemToSatSolver(problem_state, sat_solver_.get()); - if (load_status != BopOptimizerBase::CONTINUE) - return load_status; + if (load_status != BopOptimizerBase::CONTINUE) return load_status; switch (policy_) { - case Policy::kNotGuided: - break; - case Policy::kLpGuided: - for (ColIndex col(0); col < problem_state.lp_values().size(); ++col) { - const double value = problem_state.lp_values()[col]; - sat_solver_->SetAssignmentPreference( - sat::Literal(sat::BooleanVariable(col.value()), round(value) == 1), - 1 - fabs(value - round(value))); - } - break; - case Policy::kObjectiveGuided: - UseObjectiveForSatAssignmentPreference(problem_state.original_problem(), - sat_solver_.get()); - break; - case Policy::kUserGuided: - for (int i = 0; i < problem_state.assignment_preference().size(); ++i) { - sat_solver_->SetAssignmentPreference( - sat::Literal(sat::BooleanVariable(i), - problem_state.assignment_preference()[i]), - 1.0); - } - break; + case Policy::kNotGuided: + break; + case Policy::kLpGuided: + for (ColIndex col(0); col < problem_state.lp_values().size(); ++col) { + const double value = problem_state.lp_values()[col]; + sat_solver_->SetAssignmentPreference( + sat::Literal(sat::BooleanVariable(col.value()), round(value) == 1), + 1 - fabs(value - round(value))); + } + break; + case Policy::kObjectiveGuided: + UseObjectiveForSatAssignmentPreference(problem_state.original_problem(), + sat_solver_.get()); + break; + case Policy::kUserGuided: + for (int i = 0; i < problem_state.assignment_preference().size(); ++i) { + sat_solver_->SetAssignmentPreference( + sat::Literal(sat::BooleanVariable(i), + problem_state.assignment_preference()[i]), + 1.0); + } + break; } return BopOptimizerBase::CONTINUE; } bool GuidedSatFirstSolutionGenerator::ShouldBeRun( const ProblemState &problem_state) const { - if (abort_) - return false; + if (abort_) return false; if (policy_ == Policy::kLpGuided && problem_state.lp_values().empty()) { return false; } @@ -163,8 +164,7 @@ BopOptimizerBase::Status GuidedSatFirstSolutionGenerator::Optimize( const BopOptimizerBase::Status sync_status = SynchronizeIfNeeded(problem_state); - if (sync_status != BopOptimizerBase::CONTINUE) - return sync_status; + if (sync_status != BopOptimizerBase::CONTINUE) return sync_status; sat::SatParameters sat_params; sat_params.set_max_time_in_seconds(time_limit->GetTimeLeft()); @@ -185,8 +185,7 @@ BopOptimizerBase::Status GuidedSatFirstSolutionGenerator::Optimize( initial_deterministic_time); if (sat_status == sat::SatSolver::INFEASIBLE) { - if (policy_ != Policy::kNotGuided) - abort_ = true; + if (policy_ != Policy::kNotGuided) abort_ = true; if (problem_state.upper_bound() != kint64max) { // As the solution in the state problem is feasible, it is proved optimal. learned_info->lower_bound = problem_state.upper_bound(); @@ -212,8 +211,9 @@ BopOptimizerBase::Status GuidedSatFirstSolutionGenerator::Optimize( BopRandomFirstSolutionGenerator::BopRandomFirstSolutionGenerator( const std::string &name, const BopParameters ¶meters, sat::SatSolver *sat_propagator, MTRandom *random) - : BopOptimizerBase(name), random_(random), sat_propagator_(sat_propagator) { -} + : BopOptimizerBase(name), + random_(random), + sat_propagator_(sat_propagator) {} BopRandomFirstSolutionGenerator::~BopRandomFirstSolutionGenerator() {} @@ -236,9 +236,9 @@ BopOptimizerBase::Status BopRandomFirstSolutionGenerator::Optimize( sat_propagator_->AllPreferences(); const int kMaxNumConflicts = 10; - int64 best_cost = - problem_state.solution().IsFeasible() ? problem_state.solution().GetCost() - : kint64max; + int64 best_cost = problem_state.solution().IsFeasible() + ? problem_state.solution().GetCost() + : kint64max; int64 remaining_num_conflicts = parameters.max_number_of_conflicts_in_random_solution_generation(); int64 old_num_failures = 0; @@ -337,16 +337,23 @@ BopOptimizerBase::Status BopRandomFirstSolutionGenerator::Optimize( //------------------------------------------------------------------------------ LinearRelaxation::LinearRelaxation(const BopParameters ¶meters, const std::string &name) - : BopOptimizerBase(name), parameters_(parameters), + : BopOptimizerBase(name), + parameters_(parameters), state_update_stamp_(ProblemState::kInitialStampValue), - lp_model_loaded_(false), num_full_solves_(0), lp_model_(), lp_solver_(), - scaling_(1), offset_(0), num_fixed_variables_(-1), - problem_already_solved_(false), scaled_solution_cost_(glop::kInfinity) {} + lp_model_loaded_(false), + num_full_solves_(0), + lp_model_(), + lp_solver_(), + scaling_(1), + offset_(0), + num_fixed_variables_(-1), + problem_already_solved_(false), + scaled_solution_cost_(glop::kInfinity) {} LinearRelaxation::~LinearRelaxation() {} -BopOptimizerBase::Status -LinearRelaxation::SynchronizeIfNeeded(const ProblemState &problem_state) { +BopOptimizerBase::Status LinearRelaxation::SynchronizeIfNeeded( + const ProblemState &problem_state) { if (state_update_stamp_ == problem_state.update_stamp()) { return BopOptimizerBase::CONTINUE; } @@ -370,8 +377,7 @@ LinearRelaxation::SynchronizeIfNeeded(const ProblemState &problem_state) { } problem_already_solved_ = problem_already_solved_ && num_fixed_variables_ >= num_fixed_variables; - if (problem_already_solved_) - return BopOptimizerBase::ABORT; + if (problem_already_solved_) return BopOptimizerBase::ABORT; // Create the LP model based on the current problem state. num_fixed_variables_ = num_fixed_variables; @@ -433,10 +439,9 @@ bool LinearRelaxation::ShouldBeRun(const ProblemState &problem_state) const { parameters_.max_lp_solve_for_feasibility_problems() != 0; } -BopOptimizerBase::Status -LinearRelaxation::Optimize(const BopParameters ¶meters, - const ProblemState &problem_state, - LearnedInfo *learned_info, TimeLimit *time_limit) { +BopOptimizerBase::Status LinearRelaxation::Optimize( + const BopParameters ¶meters, const ProblemState &problem_state, + LearnedInfo *learned_info, TimeLimit *time_limit) { CHECK(learned_info != nullptr); CHECK(time_limit != nullptr); learned_info->Clear(); @@ -448,11 +453,9 @@ LinearRelaxation::Optimize(const BopParameters ¶meters, } const glop::ProblemStatus lp_status = Solve(false, time_limit); - VLOG(1) - << " LP: " << absl::StrFormat( - "%.6f", - lp_solver_.GetObjectiveValue()) - << " status: " << GetProblemStatusString(lp_status); + VLOG(1) << " LP: " + << absl::StrFormat("%.6f", lp_solver_.GetObjectiveValue()) + << " status: " << GetProblemStatusString(lp_status); if (lp_status == glop::ProblemStatus::OPTIMAL || lp_status == glop::ProblemStatus::IMPRECISE) { @@ -477,8 +480,8 @@ LinearRelaxation::Optimize(const BopParameters ¶meters, if (parameters_.use_lp_strong_branching()) { lower_bound = ComputeLowerBoundUsingStrongBranching(learned_info, time_limit); - VLOG(1) << " LP: " << absl::StrFormat( - "%.6f", lower_bound) + VLOG(1) << " LP: " + << absl::StrFormat("%.6f", lower_bound) << " using strong branching."; } @@ -487,7 +490,8 @@ LinearRelaxation::Optimize(const BopParameters ¶meters, (lower_bound + tolerance_sign * lp_solver_.GetParameters().solution_feasibility_tolerance()) / - scaling_ - offset_; + scaling_ - + offset_; learned_info->lower_bound = static_cast(ceil(unscaled_cost)); if (AllIntegralValues( @@ -533,8 +537,7 @@ double LinearRelaxation::ComputeLowerBoundUsingStrongBranching( // the cost variation when we snap it to one of its bound) so // we can try the one that seems the most promising first. // That way we can stop the strong branching earlier. - if (time_limit->LimitReached()) - break; + if (time_limit->LimitReached()) break; // Skip fixed variables. if (lp_model_.variable_lower_bounds()[col] == @@ -593,14 +596,14 @@ double LinearRelaxation::ComputeLowerBoundUsingStrongBranching( // Having variable col set to true can't possibly lead to and better // solution than the current one. Set the variable to false. lp_model_.SetVariableBounds(col, 0.0, 0.0); - learned_info->fixed_literals - .push_back(sat::Literal(sat::BooleanVariable(col.value()), false)); + learned_info->fixed_literals.push_back( + sat::Literal(sat::BooleanVariable(col.value()), false)); } else if (CostIsWorseThanSolution(objective_false, tolerance)) { // Having variable col set to false can't possibly lead to and better // solution than the current one. Set the variable to true. lp_model_.SetVariableBounds(col, 1.0, 1.0); - learned_info->fixed_literals - .push_back(sat::Literal(sat::BooleanVariable(col.value()), true)); + learned_info->fixed_literals.push_back( + sat::Literal(sat::BooleanVariable(col.value()), true)); } else { // Unset. This is safe to use 0.0 and 1.0 as the variable is not fixed. lp_model_.SetVariableBounds(col, 0.0, 1.0); @@ -616,5 +619,5 @@ bool LinearRelaxation::CostIsWorseThanSolution(double scaled_cost, : scaled_cost > scaled_solution_cost_ + tolerance; } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_fs.h b/ortools/bop/bop_fs.h index 1b55d3c48b..e86ddc51bd 100644 --- a/ortools/bop/bop_fs.h +++ b/ortools/bop/bop_fs.h @@ -40,13 +40,13 @@ namespace bop { // This optimizer will never run again once it has found a solution except if // the policy is kNotGuided in which case it will be ran again. class GuidedSatFirstSolutionGenerator : public BopOptimizerBase { -public: + public: // The different guiding heuristics enum class Policy { - kNotGuided, // The default SAT solver. - kLpGuided, // Guided by the values of the linear relaxation. - kObjectiveGuided, // Guided by the objective coefficient. - kUserGuided, // Guided by the problem assignment_preference(). + kNotGuided, // The default SAT solver. + kLpGuided, // Guided by the values of the linear relaxation. + kObjectiveGuided, // Guided by the objective coefficient. + kUserGuided, // Guided by the problem assignment_preference(). }; GuidedSatFirstSolutionGenerator(const std::string &name, Policy policy); ~GuidedSatFirstSolutionGenerator() override; @@ -60,9 +60,9 @@ public: const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override; -private: - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state); + private: + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state); const Policy policy_; bool abort_; @@ -81,7 +81,7 @@ private: // TODO(user): Coupled with some Local Search it might be used to diversify // the solutions. To try. class BopRandomFirstSolutionGenerator : public BopOptimizerBase { -public: + public: BopRandomFirstSolutionGenerator(const std::string &name, const BopParameters ¶meters, sat::SatSolver *sat_propagator, @@ -93,9 +93,9 @@ public: const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override; -private: - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state); + private: + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state); int random_seed_; MTRandom *random_; @@ -107,7 +107,7 @@ private: // used by other optimizers as BopSatLpFirstSolutionGenerator for instance, // and the lower bound. class LinearRelaxation : public BopOptimizerBase { -public: + public: LinearRelaxation(const BopParameters ¶meters, const std::string &name); ~LinearRelaxation() override; @@ -116,9 +116,9 @@ public: const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override; -private: - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state); + private: + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state); // Runs Glop to solve the current lp_model_. // Updates the time limit and returns the status of the solve. @@ -151,6 +151,6 @@ private: double scaled_solution_cost_; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_FS_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_FS_H_ diff --git a/ortools/bop/bop_lns.cc b/ortools/bop/bop_lns.cc index 2990c2e561..9b33e12739 100644 --- a/ortools/bop/bop_lns.cc +++ b/ortools/bop/bop_lns.cc @@ -52,7 +52,7 @@ void UseBopSolutionForSatAssignmentPreference(const BopSolution &solution, 1.0); } } -} // namespace +} // namespace BopCompleteLNSOptimizer::BopCompleteLNSOptimizer( const std::string &name, const BopConstraintTerms &objective_terms) @@ -62,9 +62,8 @@ BopCompleteLNSOptimizer::BopCompleteLNSOptimizer( BopCompleteLNSOptimizer::~BopCompleteLNSOptimizer() {} -BopOptimizerBase::Status -BopCompleteLNSOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state, - int num_relaxed_vars) { +BopOptimizerBase::Status BopCompleteLNSOptimizer::SynchronizeIfNeeded( + const ProblemState &problem_state, int num_relaxed_vars) { if (state_update_stamp_ == problem_state.update_stamp()) { return BopOptimizerBase::CONTINUE; } @@ -74,8 +73,7 @@ BopCompleteLNSOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state, sat_solver_ = absl::make_unique(); const BopOptimizerBase::Status status = LoadStateProblemToSatSolver(problem_state, sat_solver_.get()); - if (status != BopOptimizerBase::CONTINUE) - return status; + if (status != BopOptimizerBase::CONTINUE) return status; // Add the constraint that forces the solver to look for a solution // at a distance <= num_relaxed_vars from the current one. Note that not all @@ -95,11 +93,10 @@ BopCompleteLNSOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state, } } sat_solver_->AddLinearConstraint( - /*use_lower_bound=*/ false, sat::Coefficient(0), - /*use_upper_bound=*/ true, sat::Coefficient(num_relaxed_vars), &cst); + /*use_lower_bound=*/false, sat::Coefficient(0), + /*use_upper_bound=*/true, sat::Coefficient(num_relaxed_vars), &cst); - if (sat_solver_->IsModelUnsat()) - return BopOptimizerBase::ABORT; + if (sat_solver_->IsModelUnsat()) return BopOptimizerBase::ABORT; // It sounds like a good idea to force the solver to find a similar solution // from the current one. On another side, this is already somewhat enforced by @@ -109,8 +106,8 @@ BopCompleteLNSOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state, return BopOptimizerBase::CONTINUE; } -bool -BopCompleteLNSOptimizer::ShouldBeRun(const ProblemState &problem_state) const { +bool BopCompleteLNSOptimizer::ShouldBeRun( + const ProblemState &problem_state) const { return problem_state.solution().IsFeasible(); } @@ -207,7 +204,7 @@ bool UseLinearRelaxationForSatAssignmentPreference( } return true; } -} // namespace +} // namespace // Note(user): We prefer to start with a really low difficulty as this works // better for large problem, and for small ones, it will be really quickly @@ -217,16 +214,18 @@ BopAdaptiveLNSOptimizer::BopAdaptiveLNSOptimizer( const std::string &name, bool use_lp_to_guide_sat, NeighborhoodGenerator *neighborhood_generator, sat::SatSolver *sat_propagator) - : BopOptimizerBase(name), use_lp_to_guide_sat_(use_lp_to_guide_sat), + : BopOptimizerBase(name), + use_lp_to_guide_sat_(use_lp_to_guide_sat), neighborhood_generator_(neighborhood_generator), - sat_propagator_(sat_propagator), adaptive_difficulty_(0.001) { + sat_propagator_(sat_propagator), + adaptive_difficulty_(0.001) { CHECK(sat_propagator != nullptr); } BopAdaptiveLNSOptimizer::~BopAdaptiveLNSOptimizer() {} -bool -BopAdaptiveLNSOptimizer::ShouldBeRun(const ProblemState &problem_state) const { +bool BopAdaptiveLNSOptimizer::ShouldBeRun( + const ProblemState &problem_state) const { return problem_state.solution().IsFeasible(); } @@ -242,14 +241,14 @@ BopOptimizerBase::Status BopAdaptiveLNSOptimizer::Optimize( const double initial_dt = sat_propagator_->deterministic_time(); auto sat_propagator_cleanup = ::absl::MakeCleanup([initial_dt, this, &learned_info, &time_limit]() { - if (!sat_propagator_->IsModelUnsat()) { - sat_propagator_->SetAssumptionLevel(0); - sat_propagator_->RestoreSolverToAssumptionLevel(); - ExtractLearnedInfoFromSatSolver(sat_propagator_, learned_info); - } - time_limit->AdvanceDeterministicTime(sat_propagator_->deterministic_time() - - initial_dt); - }); + if (!sat_propagator_->IsModelUnsat()) { + sat_propagator_->SetAssumptionLevel(0); + sat_propagator_->RestoreSolverToAssumptionLevel(); + ExtractLearnedInfoFromSatSolver(sat_propagator_, learned_info); + } + time_limit->AdvanceDeterministicTime( + sat_propagator_->deterministic_time() - initial_dt); + }); // For the SAT conflicts limit of each LNS, we follow a luby sequence times // the base number of conflicts (num_conflicts_). Note that the numbers of the @@ -260,7 +259,7 @@ BopOptimizerBase::Status BopAdaptiveLNSOptimizer::Optimize( // different numbers in the Luby sequence. Note that the initial value is // reused from the last run. const BopParameters &local_parameters = parameters; - int num_tries = 0; // TODO(user): remove? our limit is 1 by default. + int num_tries = 0; // TODO(user): remove? our limit is 1 by default. while (!time_limit->LimitReached() && num_tries < local_parameters.num_random_lns_tries()) { // Compute the target problem difficulty and generate the neighborhood. @@ -426,7 +425,7 @@ std::vector ObjectiveVariablesAssignedToTheirLowCostValue( return result; } -} // namespace +} // namespace void ObjectiveBasedNeighborhood::GenerateNeighborhood( const ProblemState &problem_state, double difficulty, @@ -444,8 +443,7 @@ void ObjectiveBasedNeighborhood::GenerateNeighborhood( sat_propagator->Backtrack(0); for (const sat::Literal literal : candidates) { - if (sat_propagator->LiteralTrail().Index() == target) - break; + if (sat_propagator->LiteralTrail().Index() == target) break; if (sat_propagator->LiteralTrail().Index() > target) { // We prefer to error on the large neighborhood side, so we backtrack the // last enqueued literal. @@ -454,8 +452,7 @@ void ObjectiveBasedNeighborhood::GenerateNeighborhood( break; } sat_propagator->EnqueueDecisionAndBacktrackOnConflict(literal); - if (sat_propagator->IsModelUnsat()) - return; + if (sat_propagator->IsModelUnsat()) return; } } @@ -466,8 +463,7 @@ void ConstraintBasedNeighborhood::GenerateNeighborhood( const LinearBooleanProblem &problem = problem_state.original_problem(); const int num_constraints = problem.constraints_size(); std::vector ct_ids(num_constraints, 0); - for (int ct_id = 0; ct_id < num_constraints; ++ct_id) - ct_ids[ct_id] = ct_id; + for (int ct_id = 0; ct_id < num_constraints; ++ct_id) ct_ids[ct_id] = ct_id; std::shuffle(ct_ids.begin(), ct_ids.end(), *random_); // Mark that we want to relax all the variables of these constraints as long @@ -477,14 +473,12 @@ void ConstraintBasedNeighborhood::GenerateNeighborhood( int num_relaxed = 0; std::vector variable_is_relaxed(problem.num_variables(), false); for (int i = 0; i < ct_ids.size(); ++i) { - if (num_relaxed >= target) - break; + if (num_relaxed >= target) break; const LinearBooleanConstraint &constraint = problem.constraints(ct_ids[i]); // We exclude really large constraints since they are probably note helpful // in picking a nice neighborhood. - if (constraint.literals_size() > 0.7 * num_variables) - continue; + if (constraint.literals_size() > 0.7 * num_variables) continue; for (int j = 0; j < constraint.literals_size(); ++j) { const VariableIndex var_id(constraint.literals(j) - 1); @@ -505,11 +499,9 @@ void ConstraintBasedNeighborhood::GenerateNeighborhood( ObjectiveVariablesAssignedToTheirLowCostValue(problem_state, objective_terms_); for (const sat::Literal literal : to_fix) { - if (variable_is_relaxed[literal.Variable().value()]) - continue; + if (variable_is_relaxed[literal.Variable().value()]) continue; sat_propagator->EnqueueDecisionAndBacktrackOnConflict(literal); - if (sat_propagator->IsModelUnsat()) - return; + if (sat_propagator->IsModelUnsat()) return; } } @@ -529,12 +521,11 @@ RelationGraphBasedNeighborhood::RelationGraphBasedNeighborhood( const double kSizeThreshold = 0.1; for (int i = 0; i < problem.constraints_size(); ++i) { const LinearBooleanConstraint &constraint = problem.constraints(i); - if (constraint.literals_size() > kSizeThreshold * num_variables) - continue; + if (constraint.literals_size() > kSizeThreshold * num_variables) continue; for (int j = 0; j < constraint.literals_size(); ++j) { const sat::Literal literal(constraint.literals(j)); - columns_[VariableIndex(literal.Variable().value())] - .push_back(ConstraintIndex(i)); + columns_[VariableIndex(literal.Variable().value())].push_back( + ConstraintIndex(i)); } } } @@ -579,25 +570,22 @@ void RelationGraphBasedNeighborhood::GenerateNeighborhood( for (sat::BooleanVariable var(0); var < num_variables; ++var) { const sat::Literal literal( var, problem_state.solution().Value(VariableIndex(var.value()))); - if (variable_is_relaxed[literal.Variable().value()]) - continue; + if (variable_is_relaxed[literal.Variable().value()]) continue; const int index = sat_propagator->EnqueueDecisionAndBacktrackOnConflict(literal); if (sat_propagator->CurrentDecisionLevel() > 0) { for (int i = index; i < sat_propagator->LiteralTrail().Index(); ++i) { - if (variable_is_relaxed[sat_propagator->LiteralTrail()[i] - .Variable().value()]) { + if (variable_is_relaxed + [sat_propagator->LiteralTrail()[i].Variable().value()]) { sat_propagator->Backtrack(sat_propagator->CurrentDecisionLevel() - 1); } } } - if (sat_propagator->IsModelUnsat()) - return; + if (sat_propagator->IsModelUnsat()) return; } - VLOG(2) - << "target:" << target << " relaxed:" << num_relaxed - << " actual:" << num_variables - sat_propagator->LiteralTrail().Index(); + VLOG(2) << "target:" << target << " relaxed:" << num_relaxed << " actual:" + << num_variables - sat_propagator->LiteralTrail().Index(); } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_lns.h b/ortools/bop/bop_lns.h index 191c37bd15..c2e5f6899a 100644 --- a/ortools/bop/bop_lns.h +++ b/ortools/bop/bop_lns.h @@ -41,20 +41,19 @@ namespace bop { // Uses SAT to solve the full problem under the constraint that the new solution // should be under a given Hamming distance of the current solution. class BopCompleteLNSOptimizer : public BopOptimizerBase { -public: + public: BopCompleteLNSOptimizer(const std::string &name, const BopConstraintTerms &objective_terms); ~BopCompleteLNSOptimizer() final; -private: + private: bool ShouldBeRun(const ProblemState &problem_state) const final; Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) final; - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state, - int num_relaxed_vars); + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state, int num_relaxed_vars); int64 state_update_stamp_; std::unique_ptr sat_solver_; @@ -69,7 +68,7 @@ private: // code (to investigate). If this happens, we will probably need another // function here and a way to select between which one to call. class NeighborhoodGenerator { -public: + public: NeighborhoodGenerator() {} virtual ~NeighborhoodGenerator() {} @@ -101,7 +100,7 @@ public: // NeighborhoodGenerator and automatically adapt the neighborhood size depending // on how easy it is to solve the associated problem. class BopAdaptiveLNSOptimizer : public BopOptimizerBase { -public: + public: // Takes ownership of the given neighborhood_generator. // The sat_propagator is assumed to contains the current problem. BopAdaptiveLNSOptimizer(const std::string &name, bool use_lp_to_guide_sat, @@ -109,7 +108,7 @@ public: sat::SatSolver *sat_propagator); ~BopAdaptiveLNSOptimizer() final; -private: + private: bool ShouldBeRun(const ProblemState &problem_state) const final; Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, @@ -127,16 +126,16 @@ private: // Generates a neighborhood by randomly fixing a subset of the objective // variables that are currently at their lower cost. class ObjectiveBasedNeighborhood : public NeighborhoodGenerator { -public: + public: ObjectiveBasedNeighborhood(const BopConstraintTerms *objective_terms, MTRandom *random) : objective_terms_(*objective_terms), random_(random) {} ~ObjectiveBasedNeighborhood() final {} -private: + private: void GenerateNeighborhood(const ProblemState &problem_state, - double difficulty, sat::SatSolver *sat_propagator) - final; + double difficulty, + sat::SatSolver *sat_propagator) final; const BopConstraintTerms &objective_terms_; MTRandom *random_; }; @@ -145,16 +144,16 @@ private: // fixing the objective variables that are currently at their lower cost and // not in the given subset of constraints. class ConstraintBasedNeighborhood : public NeighborhoodGenerator { -public: + public: ConstraintBasedNeighborhood(const BopConstraintTerms *objective_terms, MTRandom *random) : objective_terms_(*objective_terms), random_(random) {} ~ConstraintBasedNeighborhood() final {} -private: + private: void GenerateNeighborhood(const ProblemState &problem_state, - double difficulty, sat::SatSolver *sat_propagator) - final; + double difficulty, + sat::SatSolver *sat_propagator) final; const BopConstraintTerms &objective_terms_; MTRandom *random_; }; @@ -163,15 +162,15 @@ private: // undirected graph where the nodes are the variables and two nodes are linked // if they appear in the same constraint. class RelationGraphBasedNeighborhood : public NeighborhoodGenerator { -public: + public: RelationGraphBasedNeighborhood(const sat::LinearBooleanProblem &problem, MTRandom *random); ~RelationGraphBasedNeighborhood() final {} -private: + private: void GenerateNeighborhood(const ProblemState &problem_state, - double difficulty, sat::SatSolver *sat_propagator) - final; + double difficulty, + sat::SatSolver *sat_propagator) final; // TODO(user): reuse by_variable_matrix_ from the LS? Note however than we // don't need the coefficients here. @@ -179,6 +178,6 @@ private: MTRandom *random_; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_LNS_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_LNS_H_ diff --git a/ortools/bop/bop_ls.cc b/ortools/bop/bop_ls.cc index 37792409da..85d5e4c5e8 100644 --- a/ortools/bop/bop_ls.cc +++ b/ortools/bop/bop_ls.cc @@ -34,13 +34,14 @@ LocalSearchOptimizer::LocalSearchOptimizer(const std::string &name, sat::SatSolver *sat_propagator) : BopOptimizerBase(name), state_update_stamp_(ProblemState::kInitialStampValue), - max_num_decisions_(max_num_decisions), sat_wrapper_(sat_propagator), + max_num_decisions_(max_num_decisions), + sat_wrapper_(sat_propagator), assignment_iterator_() {} LocalSearchOptimizer::~LocalSearchOptimizer() {} -bool -LocalSearchOptimizer::ShouldBeRun(const ProblemState &problem_state) const { +bool LocalSearchOptimizer::ShouldBeRun( + const ProblemState &problem_state) const { return problem_state.solution().IsFeasible(); } @@ -177,10 +178,14 @@ template class BacktrackableIntegerSet; AssignmentAndConstraintFeasibilityMaintainer:: AssignmentAndConstraintFeasibilityMaintainer( const LinearBooleanProblem &problem) - : by_variable_matrix_(problem.num_variables()), constraint_lower_bounds_(), - constraint_upper_bounds_(), assignment_(problem, "Assignment"), - reference_(problem, "Assignment"), constraint_values_(), - flipped_var_trail_backtrack_levels_(), flipped_var_trail_() { + : by_variable_matrix_(problem.num_variables()), + constraint_lower_bounds_(), + constraint_upper_bounds_(), + assignment_(problem, "Assignment"), + reference_(problem, "Assignment"), + constraint_values_(), + flipped_var_trail_backtrack_levels_(), + flipped_var_trail_() { // Add the objective constraint as the first constraint. const LinearObjective &objective = problem.objective(); CHECK_EQ(objective.literals_size(), objective.coefficients_size()); @@ -190,8 +195,8 @@ AssignmentAndConstraintFeasibilityMaintainer:: const VariableIndex var(objective.literals(i) - 1); const int64 weight = objective.coefficients(i); - by_variable_matrix_[var] - .push_back(ConstraintEntry(kObjectiveConstraint, weight)); + by_variable_matrix_[var].push_back( + ConstraintEntry(kObjectiveConstraint, weight)); } constraint_lower_bounds_.push_back(kint64min); constraint_values_.push_back(0); @@ -211,8 +216,8 @@ AssignmentAndConstraintFeasibilityMaintainer:: for (int i = 0; i < constraint.literals_size(); ++i) { const VariableIndex var(constraint.literals(i) - 1); const int64 weight = constraint.coefficients(i); - by_variable_matrix_[var] - .push_back(ConstraintEntry(num_constraints_with_objective, weight)); + by_variable_matrix_[var].push_back( + ConstraintEntry(num_constraints_with_objective, weight)); } constraint_lower_bounds_.push_back( constraint.has_lower_bound() ? constraint.lower_bound() : kint64min); @@ -243,7 +248,7 @@ void AssignmentAndConstraintFeasibilityMaintainer::SetReferenceSolution( reference_ = assignment_; flipped_var_trail_backtrack_levels_.clear(); flipped_var_trail_.clear(); - AddBacktrackingLevel(); // To handle initial propagation. + AddBacktrackingLevel(); // To handle initial propagation. // Recompute the value of all constraints. constraint_values_.assign(NumConstraints(), 0); @@ -258,20 +263,19 @@ void AssignmentAndConstraintFeasibilityMaintainer::SetReferenceSolution( MakeObjectiveConstraintInfeasible(1); } -void -AssignmentAndConstraintFeasibilityMaintainer::UseCurrentStateAsReference() { +void AssignmentAndConstraintFeasibilityMaintainer:: + UseCurrentStateAsReference() { for (const VariableIndex var : flipped_var_trail_) { reference_.SetValue(var, assignment_.Value(var)); } flipped_var_trail_.clear(); flipped_var_trail_backtrack_levels_.clear(); - AddBacktrackingLevel(); // To handle initial propagation. + AddBacktrackingLevel(); // To handle initial propagation. MakeObjectiveConstraintInfeasible(1); } -void -AssignmentAndConstraintFeasibilityMaintainer::MakeObjectiveConstraintInfeasible( - int delta) { +void AssignmentAndConstraintFeasibilityMaintainer:: + MakeObjectiveConstraintInfeasible(int delta) { CHECK(IsFeasible()); CHECK(flipped_var_trail_.empty()); constraint_upper_bounds_[kObjectiveConstraint] = @@ -333,12 +337,11 @@ void AssignmentAndConstraintFeasibilityMaintainer::BacktrackOneLevel() { } void AssignmentAndConstraintFeasibilityMaintainer::BacktrackAll() { - while (!flipped_var_trail_backtrack_levels_.empty()) - BacktrackOneLevel(); + while (!flipped_var_trail_backtrack_levels_.empty()) BacktrackOneLevel(); } -const std::vector & -AssignmentAndConstraintFeasibilityMaintainer::PotentialOneFlipRepairs() { +const std::vector + &AssignmentAndConstraintFeasibilityMaintainer::PotentialOneFlipRepairs() { if (!constraint_set_hasher_.IsInitialized()) { InitializeConstraintSetHasher(); } @@ -397,8 +400,8 @@ std::string AssignmentAndConstraintFeasibilityMaintainer::DebugString() const { return str; } -void -AssignmentAndConstraintFeasibilityMaintainer::InitializeConstraintSetHasher() { +void AssignmentAndConstraintFeasibilityMaintainer:: + InitializeConstraintSetHasher() { const int num_constraints_with_objective = constraint_upper_bounds_.size(); // Initialize the potential one flip repair. Note that we ignore the @@ -410,18 +413,16 @@ AssignmentAndConstraintFeasibilityMaintainer::InitializeConstraintSetHasher() { constraint_set_hasher_.IgnoreElement( FromConstraintIndex(kObjectiveConstraint, false)); for (VariableIndex var(0); var < by_variable_matrix_.size(); ++var) { - // We add two entries, one for a positive flip (from false to true) and - // one - // for a negative flip (from true to false). - for (const bool flip_is_positive : { - true, false - }) { + // We add two entries, one for a positive flip (from false to true) and + // one + // for a negative flip (from true to false). + for (const bool flip_is_positive : {true, false}) { uint64 hash = 0; for (const ConstraintEntry &entry : by_variable_matrix_[var]) { const bool coeff_is_positive = entry.weight > 0; hash ^= constraint_set_hasher_.Hash(FromConstraintIndex( entry.constraint, - /*up=*/ flip_is_positive ? coeff_is_positive : !coeff_is_positive)); + /*up=*/flip_is_positive ? coeff_is_positive : !coeff_is_positive)); } hash_to_potential_repairs_[hash].push_back( sat::Literal(sat::BooleanVariable(var.value()), flip_is_positive)); @@ -438,7 +439,8 @@ OneFlipConstraintRepairer::OneFlipConstraintRepairer( const AssignmentAndConstraintFeasibilityMaintainer &maintainer, const sat::VariablesAssignment &sat_assignment) : by_constraint_matrix_(problem.constraints_size() + 1), - maintainer_(maintainer), sat_assignment_(sat_assignment) { + maintainer_(maintainer), + sat_assignment_(sat_assignment) { // Fill the by_constraint_matrix_. // // IMPORTANT: The order of the constraint needs to exactly match the one of @@ -454,8 +456,8 @@ OneFlipConstraintRepairer::OneFlipConstraintRepairer( const VariableIndex var(objective.literals(i) - 1); const int64 weight = objective.coefficients(i); - by_constraint_matrix_[num_constraint] - .push_back(ConstraintTerm(var, weight)); + by_constraint_matrix_[num_constraint].push_back( + ConstraintTerm(var, weight)); } // Add the non-binary problem constraints. @@ -472,8 +474,8 @@ OneFlipConstraintRepairer::OneFlipConstraintRepairer( for (int i = 0; i < constraint.literals_size(); ++i) { const VariableIndex var(constraint.literals(i) - 1); const int64 weight = constraint.coefficients(i); - by_constraint_matrix_[num_constraint] - .push_back(ConstraintTerm(var, weight)); + by_constraint_matrix_[num_constraint].push_back( + ConstraintTerm(var, weight)); } } @@ -496,8 +498,7 @@ ConstraintIndex OneFlipConstraintRepairer::ConstraintToRepair() const { maintainer_.PossiblyInfeasibleConstraints(); for (int index = infeasible_constraints.size() - 1; index >= 0; --index) { const ConstraintIndex &i = infeasible_constraints[index]; - if (maintainer_.ConstraintIsFeasible(i)) - continue; + if (maintainer_.ConstraintIsFeasible(i)) continue; --num_infeasible_constraints_left; // Optimization: We return the only candidate without inspecting it. @@ -523,28 +524,24 @@ ConstraintIndex OneFlipConstraintRepairer::ConstraintToRepair() const { (maintainer_.Assignment(term.var) ? -term.weight : term.weight); if (new_value >= lb && new_value <= ub) { ++num_branches; - if (num_branches >= selected_num_branches) - break; + if (num_branches >= selected_num_branches) break; } } // The constraint can't be repaired in one decision. - if (num_branches == 0) - continue; + if (num_branches == 0) continue; if (num_branches < selected_num_branches) { selected_ct = i; selected_num_branches = num_branches; - if (num_branches == 1) - break; + if (num_branches == 1) break; } } return selected_ct; } -TermIndex -OneFlipConstraintRepairer::NextRepairingTerm(ConstraintIndex ct_index, - TermIndex init_term_index, - TermIndex start_term_index) const { +TermIndex OneFlipConstraintRepairer::NextRepairingTerm( + ConstraintIndex ct_index, TermIndex init_term_index, + TermIndex start_term_index) const { const gtl::ITIVector &terms = by_constraint_matrix_[ct_index]; const int64 constraint_value = maintainer_.ConstraintValue(ct_index); @@ -574,8 +571,7 @@ OneFlipConstraintRepairer::NextRepairingTerm(ConstraintIndex ct_index, bool OneFlipConstraintRepairer::RepairIsValid(ConstraintIndex ct_index, TermIndex term_index) const { - if (maintainer_.ConstraintIsFeasible(ct_index)) - return false; + if (maintainer_.ConstraintIsFeasible(ct_index)) return false; const ConstraintTerm term = by_constraint_matrix_[ct_index][term_index]; if (sat_assignment_.VariableIsAssigned( sat::BooleanVariable(term.var.value()))) { @@ -607,9 +603,9 @@ void OneFlipConstraintRepairer::SortTermsOfEachConstraints(int num_variables) { for (gtl::ITIVector &terms : by_constraint_matrix_) { std::sort(terms.begin(), terms.end(), - [&objective](const ConstraintTerm & a, const ConstraintTerm & b) { - return objective[a.var] > objective[b.var]; - }); + [&objective](const ConstraintTerm &a, const ConstraintTerm &b) { + return objective[a.var] > objective[b.var]; + }); } } @@ -680,15 +676,19 @@ LocalSearchAssignmentIterator::LocalSearchAssignmentIterator( int max_num_broken_constraints, SatWrapper *sat_wrapper) : max_num_decisions_(max_num_decisions), max_num_broken_constraints_(max_num_broken_constraints), - maintainer_(problem_state.original_problem()), sat_wrapper_(sat_wrapper), + maintainer_(problem_state.original_problem()), + sat_wrapper_(sat_wrapper), repairer_(problem_state.original_problem(), maintainer_, sat_wrapper->SatAssignment()), search_nodes_(), - initial_term_index_(problem_state.original_problem().constraints_size() + - 1, - OneFlipConstraintRepairer::kInitTerm), - use_transposition_table_(false), use_potential_one_flip_repairs_(false), - num_nodes_(0), num_skipped_nodes_(0), num_improvements_(0), + initial_term_index_( + problem_state.original_problem().constraints_size() + 1, + OneFlipConstraintRepairer::kInitTerm), + use_transposition_table_(false), + use_potential_one_flip_repairs_(false), + num_nodes_(0), + num_skipped_nodes_(0), + num_improvements_(0), num_improvements_by_one_flip_repairs_(0), num_inspected_one_flip_repairs_(0) {} @@ -701,8 +701,8 @@ LocalSearchAssignmentIterator::~LocalSearchAssignmentIterator() { << num_inspected_one_flip_repairs_; } -void -LocalSearchAssignmentIterator::Synchronize(const ProblemState &problem_state) { +void LocalSearchAssignmentIterator::Synchronize( + const ProblemState &problem_state) { better_solution_has_been_found_ = false; maintainer_.SetReferenceSolution(problem_state.solution()); for (const SearchNode &node : search_nodes_) { @@ -731,8 +731,7 @@ void LocalSearchAssignmentIterator::SynchronizeSatWrapper() { search_nodes_.clear(); for (const SearchNode &node : copy) { - if (!repairer_.RepairIsValid(node.constraint, node.term_index)) - break; + if (!repairer_.RepairIsValid(node.constraint, node.term_index)) break; search_nodes_.push_back(node); ApplyDecision(repairer_.GetFlip(node.constraint, node.term_index)); } @@ -758,8 +757,7 @@ void LocalSearchAssignmentIterator::UseCurrentStateAsReference() { } bool LocalSearchAssignmentIterator::NextAssignment() { - if (sat_wrapper_->IsModelUnsat()) - return false; + if (sat_wrapper_->IsModelUnsat()) return false; if (maintainer_.IsFeasible()) { UseCurrentStateAsReference(); return true; @@ -871,10 +869,9 @@ void LocalSearchAssignmentIterator::InitializeTranspositionTableKey( } } -bool -LocalSearchAssignmentIterator::NewStateIsInTranspositionTable(sat::Literal l) { - if (search_nodes_.size() + 1 > kStoredMaxDecisions) - return false; +bool LocalSearchAssignmentIterator::NewStateIsInTranspositionTable( + sat::Literal l) { + if (search_nodes_.size() + 1 > kStoredMaxDecisions) return false; // Fill the transposition table element, i.e the array 'a' of decisions. std::array a; @@ -892,8 +889,7 @@ LocalSearchAssignmentIterator::NewStateIsInTranspositionTable(sat::Literal l) { void LocalSearchAssignmentIterator::InsertInTranspositionTable() { // If there is more decision that kStoredMaxDecisions, do nothing. - if (search_nodes_.size() > kStoredMaxDecisions) - return; + if (search_nodes_.size() > kStoredMaxDecisions) return; // Fill the transposition table element, i.e the array 'a' of decisions. std::array a; @@ -905,24 +901,21 @@ void LocalSearchAssignmentIterator::InsertInTranspositionTable() { bool LocalSearchAssignmentIterator::EnqueueNextRepairingTermIfAny( ConstraintIndex ct_to_repair, TermIndex term_index) { - if (term_index == initial_term_index_[ct_to_repair]) - return false; + if (term_index == initial_term_index_[ct_to_repair]) return false; if (term_index == OneFlipConstraintRepairer::kInvalidTerm) { term_index = initial_term_index_[ct_to_repair]; } while (true) { term_index = repairer_.NextRepairingTerm( ct_to_repair, initial_term_index_[ct_to_repair], term_index); - if (term_index == OneFlipConstraintRepairer::kInvalidTerm) - return false; + if (term_index == OneFlipConstraintRepairer::kInvalidTerm) return false; if (!use_transposition_table_ || !NewStateIsInTranspositionTable( repairer_.GetFlip(ct_to_repair, term_index))) { search_nodes_.push_back(SearchNode(ct_to_repair, term_index)); return true; } - if (term_index == initial_term_index_[ct_to_repair]) - return false; + if (term_index == initial_term_index_[ct_to_repair]) return false; } } @@ -966,8 +959,7 @@ void LocalSearchAssignmentIterator::Backtrack() { // that the same decisions will not be explored again. Note that the SAT // solver may have learned more the second time the exact same decisions are // seen, but we assume that it is not worth exploring again. - if (use_transposition_table_) - InsertInTranspositionTable(); + if (use_transposition_table_) InsertInTranspositionTable(); const SearchNode last_node = search_nodes_.back(); search_nodes_.pop_back(); @@ -980,5 +972,5 @@ void LocalSearchAssignmentIterator::Backtrack() { } } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_ls.h b/ortools/bop/bop_ls.h index 5c9d699200..a641f4a615 100644 --- a/ortools/bop/bop_ls.h +++ b/ortools/bop/bop_ls.h @@ -48,7 +48,7 @@ namespace bop { // TODO(user): remove? the meat of the logic is used in just one place, so I am // not sure having this extra layer improve the readability. class SatWrapper { -public: + public: explicit SatWrapper(sat::SatSolver *sat_solver); // Returns the current state of the solver propagation trail. @@ -93,7 +93,7 @@ public: // time in seconds. double deterministic_time() const; -private: + private: sat::SatSolver *sat_solver_; DISALLOW_COPY_AND_ASSIGN(SatWrapper); }; @@ -112,12 +112,12 @@ class LocalSearchAssignmentIterator; // Note that due to propagation, the number of variables with a different value // in the new solution can be greater than max_num_decisions. class LocalSearchOptimizer : public BopOptimizerBase { -public: + public: LocalSearchOptimizer(const std::string &name, int max_num_decisions, sat::SatSolver *sat_propagator); ~LocalSearchOptimizer() override; -private: + private: bool ShouldBeRun(const ProblemState &problem_state) const override; Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, @@ -152,8 +152,9 @@ private: // - Maintains the number of elements in the set. // - Maintains a superset of the elements of the set that contains all the // modified elements. -template class BacktrackableIntegerSet { -public: +template +class BacktrackableIntegerSet { + public: BacktrackableIntegerSet() {} // Prepares the class for integers in [0, n) and initializes the set to the @@ -180,7 +181,7 @@ public: void BacktrackOneLevel(); void BacktrackAll(); -private: + private: int size_; // Contains the elements whose status has been changed at least once. @@ -195,8 +196,9 @@ private: // A simple and efficient class to hash a given set of integers in [0, n). // It uses O(n) memory and produces a good hash (random linear function). -template class NonOrderedSetHasher { -public: +template +class NonOrderedSetHasher { + public: NonOrderedSetHasher() : random_("Random seed") {} // Initializes the NonOrderedSetHasher to hash sets of integer in [0, n). @@ -216,8 +218,7 @@ public: // simple random linear function which has really good hashing properties. uint64 Hash(const std::vector &set) const { uint64 hash = 0; - for (const IntType i : set) - hash ^= hashes_[i]; + for (const IntType i : set) hash ^= hashes_[i]; return hash; } @@ -228,7 +229,7 @@ public: // Returns true if Initialize() has been called with a non-zero size. bool IsInitialized() const { return !hashes_.empty(); } -private: + private: MTRandom random_; gtl::ITIVector hashes_; }; @@ -259,7 +260,7 @@ private: // 6- Assign({c}) a b c // 7- BacktrackOneLevel() class AssignmentAndConstraintFeasibilityMaintainer { -public: + public: // Note that the constraint indices used in this class are not the same as // the one used in the given LinearBooleanProblem here. explicit AssignmentAndConstraintFeasibilityMaintainer( @@ -360,7 +361,7 @@ public: std::string DebugString() const; -private: + private: // This is lazily called by PotentialOneFlipRepairs() once. void InitializeConstraintSetHasher(); @@ -426,7 +427,7 @@ private: // in a sparse manner as a vector of terms (w_i, x_i). In the following the // TermIndex term_index refers to the position of the term in the vector. class OneFlipConstraintRepairer { -public: + public: // Note that the constraint indices used in this class follow the same // convention as the one used in the // AssignmentAndConstraintFeasibilityMaintainer. @@ -479,7 +480,7 @@ public: int64 weight; }; -private: + private: // Sorts the terms of each constraints in the by_constraint_matrix_ to iterate // on most promising variables first. void SortTermsOfEachConstraints(int num_variables); @@ -498,7 +499,7 @@ private: // Note that one deliberate variable flip may lead to many other flips due to // constraint propagation, those additional flips are not counted in 'n'. class LocalSearchAssignmentIterator { -public: + public: LocalSearchAssignmentIterator(const ProblemState &problem_state, int max_num_decisions, int max_num_broken_constraints, @@ -542,7 +543,7 @@ public: std::string DebugString() const; -private: + private: // This is called when a better solution has been found to restore the search // to the new "root" node. void UseCurrentStateAsReference(); @@ -635,6 +636,6 @@ private: DISALLOW_COPY_AND_ASSIGN(LocalSearchAssignmentIterator); }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_LS_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_LS_H_ diff --git a/ortools/bop/bop_portfolio.cc b/ortools/bop/bop_portfolio.cc index c181753863..94f0865eaa 100644 --- a/ortools/bop/bop_portfolio.cc +++ b/ortools/bop/bop_portfolio.cc @@ -36,8 +36,7 @@ void BuildObjectiveTerms(const LinearBooleanProblem &problem, BopConstraintTerms *objective_terms) { CHECK(objective_terms != nullptr); - if (!objective_terms->empty()) - return; + if (!objective_terms->empty()) return; const LinearObjective &objective = problem.objective(); const size_t num_objective_terms = objective.literals_size(); @@ -51,7 +50,7 @@ void BuildObjectiveTerms(const LinearBooleanProblem &problem, objective_terms->push_back(BopConstraintTerm(var_id, weight)); } } -} // anonymous namespace +} // anonymous namespace //------------------------------------------------------------------------------ // PortfolioOptimizer @@ -59,10 +58,16 @@ void BuildObjectiveTerms(const LinearBooleanProblem &problem, PortfolioOptimizer::PortfolioOptimizer( const ProblemState &problem_state, const BopParameters ¶meters, const BopSolverOptimizerSet &optimizer_set, const std::string &name) - : BopOptimizerBase(name), random_(), - state_update_stamp_(ProblemState::kInitialStampValue), objective_terms_(), - selector_(), optimizers_(), sat_propagator_(), parameters_(parameters), - lower_bound_(-glop::kInfinity), upper_bound_(glop::kInfinity), + : BopOptimizerBase(name), + random_(), + state_update_stamp_(ProblemState::kInitialStampValue), + objective_terms_(), + selector_(), + optimizers_(), + sat_propagator_(), + parameters_(parameters), + lower_bound_(-glop::kInfinity), + upper_bound_(glop::kInfinity), number_of_consecutive_failing_optimizers_(0) { CreateOptimizers(problem_state.original_problem(), parameters, optimizer_set); } @@ -76,8 +81,8 @@ PortfolioOptimizer::~PortfolioOptimizer() { } } if (!stats_string.empty()) { - LOG(INFO) - << "Stats. #new_solutions/#calls by optimizer:\n" + stats_string; + LOG(INFO) << "Stats. #new_solutions/#calls by optimizer:\n" + + stats_string; } } @@ -86,8 +91,8 @@ PortfolioOptimizer::~PortfolioOptimizer() { gtl::STLDeleteElements(&optimizers_); } -BopOptimizerBase::Status -PortfolioOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { +BopOptimizerBase::Status PortfolioOptimizer::SynchronizeIfNeeded( + const ProblemState &problem_state) { if (state_update_stamp_ == problem_state.update_stamp()) { return BopOptimizerBase::CONTINUE; } @@ -97,8 +102,7 @@ PortfolioOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { const bool first_time = (sat_propagator_.NumVariables() == 0); const BopOptimizerBase::Status status = LoadStateProblemToSatSolver(problem_state, &sat_propagator_); - if (status != BopOptimizerBase::CONTINUE) - return status; + if (status != BopOptimizerBase::CONTINUE) return status; if (first_time) { // We configure the sat_propagator_ to use the objective as an assignment // preference @@ -113,10 +117,9 @@ PortfolioOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { return BopOptimizerBase::CONTINUE; } -BopOptimizerBase::Status -PortfolioOptimizer::Optimize(const BopParameters ¶meters, - const ProblemState &problem_state, - LearnedInfo *learned_info, TimeLimit *time_limit) { +BopOptimizerBase::Status PortfolioOptimizer::Optimize( + const BopParameters ¶meters, const ProblemState &problem_state, + LearnedInfo *learned_info, TimeLimit *time_limit) { CHECK(learned_info != nullptr); CHECK(time_limit != nullptr); learned_info->Clear(); @@ -132,9 +135,9 @@ PortfolioOptimizer::Optimize(const BopParameters ¶meters, i, optimizers_[i]->ShouldBeRun(problem_state)); } - const int64 init_cost = - problem_state.solution().IsFeasible() ? problem_state.solution().GetCost() - : kint64max; + const int64 init_cost = problem_state.solution().IsFeasible() + ? problem_state.solution().GetCost() + : kint64max; const double init_deterministic_time = time_limit->GetElapsedDeterministicTime(); @@ -163,11 +166,11 @@ PortfolioOptimizer::Optimize(const BopParameters ¶meters, // The gain is defined as 1 for the first solution. // TODO(user): Is 1 the right value? It might be better to use a percentage // of the gap, or use the same gain as for the second solution. - const int64 gain = - optimization_status == BopOptimizerBase::SOLUTION_FOUND - ? (init_cost == kint64max ? 1 : init_cost - - learned_info->solution.GetCost()) - : 0; + const int64 gain = optimization_status == BopOptimizerBase::SOLUTION_FOUND + ? (init_cost == kint64max + ? 1 + : init_cost - learned_info->solution.GetCost()) + : 0; const double spent_deterministic_time = time_limit->GetElapsedDeterministicTime() - init_deterministic_time; selector_->UpdateScore(gain, spent_deterministic_time); @@ -197,94 +200,96 @@ PortfolioOptimizer::Optimize(const BopParameters ¶meters, return BopOptimizerBase::CONTINUE; } -void -PortfolioOptimizer::AddOptimizer(const LinearBooleanProblem &problem, - const BopParameters ¶meters, - const BopOptimizerMethod &optimizer_method) { +void PortfolioOptimizer::AddOptimizer( + const LinearBooleanProblem &problem, const BopParameters ¶meters, + const BopOptimizerMethod &optimizer_method) { switch (optimizer_method.type()) { - case BopOptimizerMethod::SAT_CORE_BASED: - optimizers_.push_back(new SatCoreBasedOptimizer("SatCoreBasedOptimizer")); - break; - case BopOptimizerMethod::SAT_LINEAR_SEARCH: - optimizers_.push_back(new GuidedSatFirstSolutionGenerator( - "SatOptimizer", GuidedSatFirstSolutionGenerator::Policy::kNotGuided)); - break; - case BopOptimizerMethod::LINEAR_RELAXATION: - optimizers_.push_back(new LinearRelaxation(parameters, "LinearRelaxation")); - break; - case BopOptimizerMethod::LOCAL_SEARCH: { - for (int i = 1; i <= parameters.max_num_decisions_in_ls(); ++i) { - optimizers_.push_back(new LocalSearchOptimizer( - absl::StrFormat("LS_%d", i), i, &sat_propagator_)); - } - } break; - case BopOptimizerMethod::RANDOM_FIRST_SOLUTION: - optimizers_.push_back(new BopRandomFirstSolutionGenerator( - "SATRandomFirstSolution", parameters, &sat_propagator_, random_.get())); - break; - case BopOptimizerMethod::RANDOM_VARIABLE_LNS: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RandomVariableLns", /*use_lp_to_guide_sat=*/ false, - new ObjectiveBasedNeighborhood(&objective_terms_, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::RANDOM_VARIABLE_LNS_GUIDED_BY_LP: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RandomVariableLnsWithLp", /*use_lp_to_guide_sat=*/ true, - new ObjectiveBasedNeighborhood(&objective_terms_, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::RANDOM_CONSTRAINT_LNS: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RandomConstraintLns", /*use_lp_to_guide_sat=*/ false, - new ConstraintBasedNeighborhood(&objective_terms_, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::RANDOM_CONSTRAINT_LNS_GUIDED_BY_LP: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RandomConstraintLnsWithLp", /*use_lp_to_guide_sat=*/ true, - new ConstraintBasedNeighborhood(&objective_terms_, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::RELATION_GRAPH_LNS: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RelationGraphLns", /*use_lp_to_guide_sat=*/ false, - new RelationGraphBasedNeighborhood(problem, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::RELATION_GRAPH_LNS_GUIDED_BY_LP: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopAdaptiveLNSOptimizer( - "RelationGraphLnsWithLp", /*use_lp_to_guide_sat=*/ true, - new RelationGraphBasedNeighborhood(problem, random_.get()), - &sat_propagator_)); - break; - case BopOptimizerMethod::COMPLETE_LNS: - BuildObjectiveTerms(problem, &objective_terms_); - optimizers_.push_back(new BopCompleteLNSOptimizer("LNS", objective_terms_)); - break; - case BopOptimizerMethod::USER_GUIDED_FIRST_SOLUTION: - optimizers_.push_back(new GuidedSatFirstSolutionGenerator( - "SATUserGuidedFirstSolution", - GuidedSatFirstSolutionGenerator::Policy::kUserGuided)); - break; - case BopOptimizerMethod::LP_FIRST_SOLUTION: - optimizers_.push_back(new GuidedSatFirstSolutionGenerator( - "SATLPFirstSolution", - GuidedSatFirstSolutionGenerator::Policy::kLpGuided)); - break; - case BopOptimizerMethod::OBJECTIVE_FIRST_SOLUTION: - optimizers_.push_back(new GuidedSatFirstSolutionGenerator( - "SATObjectiveFirstSolution", - GuidedSatFirstSolutionGenerator::Policy::kObjectiveGuided)); - break; - default: - LOG(FATAL) << "Unknown optimizer type."; + case BopOptimizerMethod::SAT_CORE_BASED: + optimizers_.push_back(new SatCoreBasedOptimizer("SatCoreBasedOptimizer")); + break; + case BopOptimizerMethod::SAT_LINEAR_SEARCH: + optimizers_.push_back(new GuidedSatFirstSolutionGenerator( + "SatOptimizer", GuidedSatFirstSolutionGenerator::Policy::kNotGuided)); + break; + case BopOptimizerMethod::LINEAR_RELAXATION: + optimizers_.push_back( + new LinearRelaxation(parameters, "LinearRelaxation")); + break; + case BopOptimizerMethod::LOCAL_SEARCH: { + for (int i = 1; i <= parameters.max_num_decisions_in_ls(); ++i) { + optimizers_.push_back(new LocalSearchOptimizer( + absl::StrFormat("LS_%d", i), i, &sat_propagator_)); + } + } break; + case BopOptimizerMethod::RANDOM_FIRST_SOLUTION: + optimizers_.push_back(new BopRandomFirstSolutionGenerator( + "SATRandomFirstSolution", parameters, &sat_propagator_, + random_.get())); + break; + case BopOptimizerMethod::RANDOM_VARIABLE_LNS: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RandomVariableLns", /*use_lp_to_guide_sat=*/false, + new ObjectiveBasedNeighborhood(&objective_terms_, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::RANDOM_VARIABLE_LNS_GUIDED_BY_LP: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RandomVariableLnsWithLp", /*use_lp_to_guide_sat=*/true, + new ObjectiveBasedNeighborhood(&objective_terms_, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::RANDOM_CONSTRAINT_LNS: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RandomConstraintLns", /*use_lp_to_guide_sat=*/false, + new ConstraintBasedNeighborhood(&objective_terms_, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::RANDOM_CONSTRAINT_LNS_GUIDED_BY_LP: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RandomConstraintLnsWithLp", /*use_lp_to_guide_sat=*/true, + new ConstraintBasedNeighborhood(&objective_terms_, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::RELATION_GRAPH_LNS: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RelationGraphLns", /*use_lp_to_guide_sat=*/false, + new RelationGraphBasedNeighborhood(problem, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::RELATION_GRAPH_LNS_GUIDED_BY_LP: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back(new BopAdaptiveLNSOptimizer( + "RelationGraphLnsWithLp", /*use_lp_to_guide_sat=*/true, + new RelationGraphBasedNeighborhood(problem, random_.get()), + &sat_propagator_)); + break; + case BopOptimizerMethod::COMPLETE_LNS: + BuildObjectiveTerms(problem, &objective_terms_); + optimizers_.push_back( + new BopCompleteLNSOptimizer("LNS", objective_terms_)); + break; + case BopOptimizerMethod::USER_GUIDED_FIRST_SOLUTION: + optimizers_.push_back(new GuidedSatFirstSolutionGenerator( + "SATUserGuidedFirstSolution", + GuidedSatFirstSolutionGenerator::Policy::kUserGuided)); + break; + case BopOptimizerMethod::LP_FIRST_SOLUTION: + optimizers_.push_back(new GuidedSatFirstSolutionGenerator( + "SATLPFirstSolution", + GuidedSatFirstSolutionGenerator::Policy::kLpGuided)); + break; + case BopOptimizerMethod::OBJECTIVE_FIRST_SOLUTION: + optimizers_.push_back(new GuidedSatFirstSolutionGenerator( + "SATObjectiveFirstSolution", + GuidedSatFirstSolutionGenerator::Policy::kObjectiveGuided)); + break; + default: + LOG(FATAL) << "Unknown optimizer type."; } } @@ -346,8 +351,7 @@ OptimizerIndex OptimizerSelector::SelectOptimizer() { break; } } - if (selected_index_ == -1) - return kInvalidOptimizerIndex; + if (selected_index_ == -1) return kInvalidOptimizerIndex; } else { // Select the next possible optimizer. If none, select the first one. // Check that the time is smaller than all previous optimizers which are @@ -377,8 +381,7 @@ OptimizerIndex OptimizerSelector::SelectOptimizer() { void OptimizerSelector::UpdateScore(int64 gain, double time_spent) { const bool new_solution_found = gain != 0; - if (new_solution_found) - NewSolutionFound(gain); + if (new_solution_found) NewSolutionFound(gain); UpdateDeterministicTime(time_spent); const double new_score = time_spent == 0.0 ? 0.0 : gain / time_spent; @@ -390,7 +393,7 @@ void OptimizerSelector::UpdateScore(int64 gain, double time_spent) { info.score = std::max(kMinScore, old_score * (1 - kErosion) + kErosion * new_score); - if (new_solution_found) { // Solution found + if (new_solution_found) { // Solution found UpdateOrder(); selected_index_ = run_infos_.size(); } @@ -406,8 +409,8 @@ void OptimizerSelector::SetOptimizerRunnability(OptimizerIndex optimizer_index, run_infos_[info_positions_[optimizer_index]].runnable = runnable; } -std::string -OptimizerSelector::PrintStats(OptimizerIndex optimizer_index) const { +std::string OptimizerSelector::PrintStats( + OptimizerIndex optimizer_index) const { const RunInfo &info = run_infos_[info_positions_[optimizer_index]]; return absl::StrFormat( " %40s : %3d/%-3d (%6.2f%%) Total gain: %6d Total Dtime: %0.3f " @@ -417,8 +420,8 @@ OptimizerSelector::PrintStats(OptimizerIndex optimizer_index) const { info.time_spent, info.score); } -int -OptimizerSelector::NumCallsForOptimizer(OptimizerIndex optimizer_index) const { +int OptimizerSelector::NumCallsForOptimizer( + OptimizerIndex optimizer_index) const { const RunInfo &info = run_infos_[info_positions_[optimizer_index]]; return info.num_calls; } @@ -449,13 +452,13 @@ void OptimizerSelector::UpdateDeterministicTime(double time_spent) { } void OptimizerSelector::UpdateOrder() { - // Re-sort optimizers. + // Re-sort optimizers. std::stable_sort(run_infos_.begin(), run_infos_.end(), - [](const RunInfo & a, const RunInfo & b)->bool { - if (a.total_gain == 0 && b.total_gain == 0) - return a.time_spent < b.time_spent; - return a.score > b.score; - }); + [](const RunInfo &a, const RunInfo &b) -> bool { + if (a.total_gain == 0 && b.total_gain == 0) + return a.time_spent < b.time_spent; + return a.score > b.score; + }); // Update the positions. for (int i = 0; i < run_infos_.size(); ++i) { @@ -463,5 +466,5 @@ void OptimizerSelector::UpdateOrder() { } } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_portfolio.h b/ortools/bop/bop_portfolio.h index a3243e3e78..f26f91da45 100644 --- a/ortools/bop/bop_portfolio.h +++ b/ortools/bop/bop_portfolio.h @@ -58,7 +58,7 @@ class OptimizerSelector; // optimizers that succeeded more in the previous calls to Optimizer() are more // likely to be selected. class PortfolioOptimizer : public BopOptimizerBase { -public: + public: PortfolioOptimizer(const ProblemState &problem_state, const BopParameters ¶meters, const BopSolverOptimizerSet &optimizer_set, @@ -72,9 +72,9 @@ public: const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override; -private: - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state); + private: + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state); void AddOptimizer(const sat::LinearBooleanProblem &problem, const BopParameters ¶meters, const BopOptimizerMethod &optimizer_method); @@ -97,7 +97,7 @@ private: // This class is providing an adaptative selector for optimizers based on // their past successes and deterministic time spent. class OptimizerSelector { -public: + public: // Note that the list of optimizers is only used to get the names for // debug purposes, the ownership of the optimizers is not transferred. explicit OptimizerSelector( @@ -154,7 +154,7 @@ public: // Prints some debug information. Should not be used in production. void DebugPrint() const; -private: + private: // Updates internals when a solution has been found using the selected // optimizer. void NewSolutionFound(int64 gain); @@ -167,9 +167,16 @@ private: struct RunInfo { RunInfo(OptimizerIndex i, const std::string &n) - : optimizer_index(i), name(n), num_successes(0), num_calls(0), - total_gain(0), time_spent(0.0), time_spent_since_last_solution(0), - runnable(true), selectable(true), score(0.0) {} + : optimizer_index(i), + name(n), + num_successes(0), + num_calls(0), + total_gain(0), + time_spent(0.0), + time_spent_since_last_solution(0), + runnable(true), + selectable(true), + score(0.0) {} bool RunnableAndSelectable() const { return runnable && selectable; } @@ -190,6 +197,6 @@ private: int selected_index_; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_PORTFOLIO_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_PORTFOLIO_H_ diff --git a/ortools/bop/bop_solution.cc b/ortools/bop/bop_solution.cc index db81dfa84c..51ec4f3201 100644 --- a/ortools/bop/bop_solution.cc +++ b/ortools/bop/bop_solution.cc @@ -25,8 +25,12 @@ using ::operations_research::sat::LinearObjective; //------------------------------------------------------------------------------ BopSolution::BopSolution(const LinearBooleanProblem &problem, const std::string &name) - : problem_(&problem), name_(name), values_(problem.num_variables(), false), - recompute_cost_(true), recompute_is_feasible_(true), cost_(0), + : problem_(&problem), + name_(name), + values_(problem.num_variables(), false), + recompute_cost_(true), + recompute_is_feasible_(true), + cost_(0), is_feasible_(false) { // Try the lucky assignment, i.e. the optimal one if feasible. const LinearObjective &objective = problem.objective(); @@ -75,5 +79,5 @@ bool BopSolution::ComputeIsFeasible() const { } return true; } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_solution.h b/ortools/bop/bop_solution.h index 99d71e366c..158cc1504f 100644 --- a/ortools/bop/bop_solution.h +++ b/ortools/bop/bop_solution.h @@ -29,7 +29,7 @@ namespace bop { // some constraints of the problem. The IsFeasible() method can be used to test // the feasibility. class BopSolution { -public: + public: BopSolution(const sat::LinearBooleanProblem &problem, const std::string &name); @@ -90,7 +90,7 @@ public: : IsFeasible() > solution.IsFeasible(); } -private: + private: bool ComputeIsFeasible() const; int64 ComputeCost() const; @@ -110,6 +110,6 @@ private: // STL collections / algorithms. }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_SOLUTION_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_SOLUTION_H_ diff --git a/ortools/bop/bop_solver.cc b/ortools/bop/bop_solver.cc index 4902633606..ac8aa69c71 100644 --- a/ortools/bop/bop_solver.cc +++ b/ortools/bop/bop_solver.cc @@ -62,13 +62,15 @@ bool UpdateProblemStateBasedOnStatus(BopOptimizerBase::Status status, return false; } -} // anonymous namespace +} // anonymous namespace //------------------------------------------------------------------------------ // BopSolver //------------------------------------------------------------------------------ BopSolver::BopSolver(const LinearBooleanProblem &problem) - : problem_(problem), problem_state_(problem), parameters_(), + : problem_(problem), + problem_state_(problem), + parameters_(), stats_("BopSolver") { SCOPED_TIME_STAT(&stats_); } @@ -176,8 +178,9 @@ double BopSolver::GetScaledBestBound() const { } double BopSolver::GetScaledGap() const { - return 100.0 * std::abs(problem_state_.solution().GetScaledCost() - - GetScaledBestBound()) / + return 100.0 * + std::abs(problem_state_.solution().GetScaledCost() - + GetScaledBestBound()) / std::abs(problem_state_.solution().GetScaledCost()); } @@ -192,5 +195,5 @@ void BopSolver::UpdateParameters() { problem_state_.SetParameters(parameters_); } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_solver.h b/ortools/bop/bop_solver.h index 5da73782ab..aa52e4fe05 100644 --- a/ortools/bop/bop_solver.h +++ b/ortools/bop/bop_solver.h @@ -59,7 +59,7 @@ namespace operations_research { namespace bop { // Solver of Boolean Optimization Problems based on Local Search. class BopSolver { -public: + public: explicit BopSolver(const sat::LinearBooleanProblem &problem); virtual ~BopSolver(); @@ -88,7 +88,7 @@ public: double GetScaledBestBound() const; double GetScaledGap() const; -private: + private: void UpdateParameters(); BopSolveStatus InternalMonothreadSolver(TimeLimit *time_limit); BopSolveStatus InternalMultithreadSolver(TimeLimit *time_limit); @@ -99,6 +99,6 @@ private: mutable StatsGroup stats_; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_SOLVER_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_SOLVER_H_ diff --git a/ortools/bop/bop_types.h b/ortools/bop/bop_types.h index ebac2fa752..9bb45958ee 100644 --- a/ortools/bop/bop_types.h +++ b/ortools/bop/bop_types.h @@ -32,32 +32,32 @@ enum class BopSolveStatus { // The solver found the proven optimal solution. OPTIMAL_SOLUTION_FOUND, - // The solver found a solution, but it is not proven to be the optimal - // solution. - FEASIBLE_SOLUTION_FOUND, + // The solver found a solution, but it is not proven to be the optimal + // solution. + FEASIBLE_SOLUTION_FOUND, - // The solver didn't find any solution. - NO_SOLUTION_FOUND, + // The solver didn't find any solution. + NO_SOLUTION_FOUND, - // The problem is infeasible. - INFEASIBLE_PROBLEM, + // The problem is infeasible. + INFEASIBLE_PROBLEM, - // The problem is invalid. - INVALID_PROBLEM + // The problem is invalid. + INVALID_PROBLEM }; inline std::string GetSolveStatusString(BopSolveStatus status) { switch (status) { - case BopSolveStatus::OPTIMAL_SOLUTION_FOUND: - return "OPTIMAL_SOLUTION_FOUND"; - case BopSolveStatus::FEASIBLE_SOLUTION_FOUND: - return "FEASIBLE_SOLUTION_FOUND"; - case BopSolveStatus::NO_SOLUTION_FOUND: - return "NO_SOLUTION_FOUND"; - case BopSolveStatus::INFEASIBLE_PROBLEM: - return "INFEASIBLE_PROBLEM"; - case BopSolveStatus::INVALID_PROBLEM: - return "INVALID_PROBLEM"; + case BopSolveStatus::OPTIMAL_SOLUTION_FOUND: + return "OPTIMAL_SOLUTION_FOUND"; + case BopSolveStatus::FEASIBLE_SOLUTION_FOUND: + return "FEASIBLE_SOLUTION_FOUND"; + case BopSolveStatus::NO_SOLUTION_FOUND: + return "NO_SOLUTION_FOUND"; + case BopSolveStatus::INFEASIBLE_PROBLEM: + return "INFEASIBLE_PROBLEM"; + case BopSolveStatus::INVALID_PROBLEM: + return "INVALID_PROBLEM"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -84,6 +84,6 @@ struct BopConstraintTerm { }; typedef gtl::ITIVector BopConstraintTerms; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_TYPES_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_TYPES_H_ diff --git a/ortools/bop/bop_util.cc b/ortools/bop/bop_util.cc index 2a1a656791..938468b85f 100644 --- a/ortools/bop/bop_util.cc +++ b/ortools/bop/bop_util.cc @@ -82,11 +82,10 @@ bool InternalLoadStateProblemToSatSolver(const ProblemState &problem_state, return true; } -} // anonymous namespace +} // anonymous namespace -BopOptimizerBase::Status -LoadStateProblemToSatSolver(const ProblemState &problem_state, - sat::SatSolver *sat_solver) { +BopOptimizerBase::Status LoadStateProblemToSatSolver( + const ProblemState &problem_state, sat::SatSolver *sat_solver) { if (InternalLoadStateProblemToSatSolver(problem_state, sat_solver)) { return BopOptimizerBase::CONTINUE; } @@ -157,7 +156,9 @@ void AdaptiveParameterValue::Decrease() { // LubyAdaptiveParameterValue //------------------------------------------------------------------------------ LubyAdaptiveParameterValue::LubyAdaptiveParameterValue(double initial_value) - : luby_id_(0), luby_boost_(0), luby_value_(0), + : luby_id_(0), + luby_boost_(0), + luby_value_(0), difficulties_(kMaxLubyIndex, AdaptiveParameterValue(initial_value)) { Reset(); } @@ -195,5 +196,5 @@ void LubyAdaptiveParameterValue::UpdateLuby() { ++luby_id_; luby_value_ = sat::SUniv(luby_id_) << luby_boost_; } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/bop_util.h b/ortools/bop/bop_util.h index 1d8ebea305..5fed2a3dfa 100644 --- a/ortools/bop/bop_util.h +++ b/ortools/bop/bop_util.h @@ -35,9 +35,8 @@ namespace bop { // - INFEASIBLE: The problem is proved to be infeasible. // Note that the sat_solver will be backtracked to the root level in order // to add new constraints. -BopOptimizerBase::Status - LoadStateProblemToSatSolver(const ProblemState &problem_state, - sat::SatSolver *sat_solver); +BopOptimizerBase::Status LoadStateProblemToSatSolver( + const ProblemState &problem_state, sat::SatSolver *sat_solver); // Extracts from the sat solver any new information about the problem. Note that // the solver is not const because this function clears what is considered @@ -48,7 +47,7 @@ void SatAssignmentToBopSolution(const sat::VariablesAssignment &assignment, BopSolution *solution); class AdaptiveParameterValue { -public: + public: // Initial value is in [0..1]. explicit AdaptiveParameterValue(double initial_value); @@ -58,13 +57,13 @@ public: double value() const { return value_; } -private: + private: double value_; int num_changes_; }; class LubyAdaptiveParameterValue { -public: + public: // Initial value is in [0..1]. explicit LubyAdaptiveParameterValue(double initial_value); @@ -79,13 +78,13 @@ public: bool BoostLuby(); int luby_value() const { return luby_value_; } -private: + private: int luby_id_; int luby_boost_; int luby_value_; std::vector difficulties_; }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_BOP_UTIL_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_BOP_UTIL_H_ diff --git a/ortools/bop/complete_optimizer.cc b/ortools/bop/complete_optimizer.cc index 03793939ed..0f8d3561a1 100644 --- a/ortools/bop/complete_optimizer.cc +++ b/ortools/bop/complete_optimizer.cc @@ -22,7 +22,8 @@ namespace bop { SatCoreBasedOptimizer::SatCoreBasedOptimizer(const std::string &name) : BopOptimizerBase(name), state_update_stamp_(ProblemState::kInitialStampValue), - initialized_(false), assumptions_already_added_(false) { + initialized_(false), + assumptions_already_added_(false) { // This is in term of number of variables not at their minimal value. lower_bound_ = sat::Coefficient(0); upper_bound_ = sat::kCoefficientMax; @@ -30,8 +31,8 @@ SatCoreBasedOptimizer::SatCoreBasedOptimizer(const std::string &name) SatCoreBasedOptimizer::~SatCoreBasedOptimizer() {} -BopOptimizerBase::Status -SatCoreBasedOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { +BopOptimizerBase::Status SatCoreBasedOptimizer::SynchronizeIfNeeded( + const ProblemState &problem_state) { if (state_update_stamp_ == problem_state.update_stamp()) { return BopOptimizerBase::CONTINUE; } @@ -41,8 +42,7 @@ SatCoreBasedOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { // information. const BopOptimizerBase::Status status = LoadStateProblemToSatSolver(problem_state, &solver_); - if (status != BopOptimizerBase::CONTINUE) - return status; + if (status != BopOptimizerBase::CONTINUE) return status; if (!initialized_) { // Initialize the algorithm. @@ -66,15 +66,15 @@ SatCoreBasedOptimizer::SynchronizeIfNeeded(const ProblemState &problem_state) { sat::SatSolver::Status SatCoreBasedOptimizer::SolveWithAssumptions() { const std::vector assumptions = - sat::ReduceNodesAndExtractAssumptions( - upper_bound_, stratified_lower_bound_, &lower_bound_, &nodes_, - &solver_); + sat::ReduceNodesAndExtractAssumptions(upper_bound_, + stratified_lower_bound_, + &lower_bound_, &nodes_, &solver_); return solver_.ResetAndSolveWithGivenAssumptions(assumptions); } // Only run this if there is an objective. -bool -SatCoreBasedOptimizer::ShouldBeRun(const ProblemState &problem_state) const { +bool SatCoreBasedOptimizer::ShouldBeRun( + const ProblemState &problem_state) const { return problem_state.original_problem().objective().literals_size() > 0; } @@ -150,5 +150,5 @@ BopOptimizerBase::Status SatCoreBasedOptimizer::Optimize( return BopOptimizerBase::CONTINUE; } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/complete_optimizer.h b/ortools/bop/complete_optimizer.h index 005dbe9760..5e360faff0 100644 --- a/ortools/bop/complete_optimizer.h +++ b/ortools/bop/complete_optimizer.h @@ -41,19 +41,19 @@ namespace bop { // TODO(user): Merge this with the code in sat/optimization.cc class SatCoreBasedOptimizer : public BopOptimizerBase { -public: + public: explicit SatCoreBasedOptimizer(const std::string &name); ~SatCoreBasedOptimizer() override; -protected: + protected: bool ShouldBeRun(const ProblemState &problem_state) const override; Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override; -private: - BopOptimizerBase::Status - SynchronizeIfNeeded(const ProblemState &problem_state); + private: + BopOptimizerBase::Status SynchronizeIfNeeded( + const ProblemState &problem_state); sat::SatSolver::Status SolveWithAssumptions(); int64 state_update_stamp_; @@ -68,7 +68,7 @@ private: std::vector nodes_; }; -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research -#endif // OR_TOOLS_BOP_COMPLETE_OPTIMIZER_H_ +#endif // OR_TOOLS_BOP_COMPLETE_OPTIMIZER_H_ diff --git a/ortools/bop/integral_solver.cc b/ortools/bop/integral_solver.cc index c2a56feaa4..6b14939682 100644 --- a/ortools/bop/integral_solver.cc +++ b/ortools/bop/integral_solver.cc @@ -131,8 +131,7 @@ void BuildBooleanProblemWithIntegralConstraints( std::vector coefficients; for (ColIndex col(0); col < linear_problem.num_variables(); ++col) { const Fractional coeff = linear_problem.objective_coefficients()[col]; - if (coeff != 0.0) - coefficients.push_back(coeff); + if (coeff != 0.0) coefficients.push_back(coeff); } double scaling_factor = 0.0; double relative_error = 0.0; @@ -180,7 +179,7 @@ void BuildBooleanProblemWithIntegralConstraints( // In the same way, when only two consecutive values are possible // use only one Boolean variable with an offset. class IntegralVariable { -public: + public: IntegralVariable(); // Creates the minimal number of Boolean variables to represent an integral @@ -213,7 +212,7 @@ public: std::string DebugString() const; -private: + private: // The value of the integral variable is expressed as // sum_i(weights[i] * Value(bits[i])) + offset. // Note that weights can be negative to represent negative values. @@ -272,8 +271,8 @@ int64 IntegralVariable::GetSolutionValue(const BopSolution &solution) const { return value; } -std::vector -IntegralVariable::GetBooleanSolutionValues(int64 integral_value) const { +std::vector IntegralVariable::GetBooleanSolutionValues( + int64 integral_value) const { if (can_be_reversed_) { DCHECK(std::is_sorted(weights_.begin(), weights_.end())); std::vector boolean_values(weights_.size(), false); @@ -319,7 +318,7 @@ std::string IntegralVariable::DebugString() const { // Note that the converter only deals with integral variables, i.e. no // continuous variables. class IntegralProblemConverter { -public: + public: IntegralProblemConverter(); // Converts the LinearProgram into a LinearBooleanProblem. If an initial @@ -336,7 +335,7 @@ public: int64 GetSolutionValue(ColIndex global_col, const BopSolution &solution) const; -private: + private: // Returns true when the linear_problem_ can be converted into a Boolean // problem. Note that floating weights and continuous variables are not // supported. @@ -414,17 +413,16 @@ private: std::vector integral_indices_; int num_boolean_variables_; - enum VariableType { - BOOLEAN, - INTEGRAL, - INTEGRAL_EXPRESSED_AS_BOOLEAN - }; + enum VariableType { BOOLEAN, INTEGRAL, INTEGRAL_EXPRESSED_AS_BOOLEAN }; gtl::ITIVector variable_types_; }; IntegralProblemConverter::IntegralProblemConverter() - : global_to_boolean_(), integral_variables_(), integral_indices_(), - num_boolean_variables_(0), variable_types_() {} + : global_to_boolean_(), + integral_variables_(), + integral_indices_(), + num_boolean_variables_(0), + variable_types_() {} bool IntegralProblemConverter::ConvertToBooleanProblem( const LinearProgram &linear_problem, const DenseRow &initial_solution, @@ -493,9 +491,8 @@ bool IntegralProblemConverter::ConvertToBooleanProblem( return true; } -int64 -IntegralProblemConverter::GetSolutionValue(ColIndex global_col, - const BopSolution &solution) const { +int64 IntegralProblemConverter::GetSolutionValue( + ColIndex global_col, const BopSolution &solution) const { if (problem_is_boolean_and_has_only_integral_constraints_) { return solution.Value(VariableIndex(global_col.value())); } @@ -1028,15 +1025,16 @@ void RunOneBop(const BopParameters ¶meters, int problem_index, const int local_num_variables = std::max(1, problem.num_variables().value()); NestedTimeLimit subproblem_time_limit( - time_limit, std::max(time_per_variable * local_num_variables, - parameters.decomposed_problem_min_time_in_seconds()), + time_limit, + std::max(time_per_variable * local_num_variables, + parameters.decomposed_problem_min_time_in_seconds()), deterministic_time_per_variable * local_num_variables); *status = InternalSolve(problem, parameters, local_initial_solution, subproblem_time_limit.GetTimeLimit(), variable_values, objective_value, best_bound); } -} // anonymous namespace +} // anonymous namespace IntegralSolver::IntegralSolver() : parameters_(), variable_values_(), objective_value_(0.0) {} @@ -1045,15 +1043,14 @@ BopSolveStatus IntegralSolver::Solve(const LinearProgram &linear_problem) { return Solve(linear_problem, DenseRow()); } -BopSolveStatus -IntegralSolver::SolveWithTimeLimit(const LinearProgram &linear_problem, - TimeLimit *time_limit) { +BopSolveStatus IntegralSolver::SolveWithTimeLimit( + const LinearProgram &linear_problem, TimeLimit *time_limit) { return SolveWithTimeLimit(linear_problem, DenseRow(), time_limit); } -BopSolveStatus -IntegralSolver::Solve(const LinearProgram &linear_problem, - const DenseRow &user_provided_initial_solution) { +BopSolveStatus IntegralSolver::Solve( + const LinearProgram &linear_problem, + const DenseRow &user_provided_initial_solution) { std::unique_ptr time_limit = TimeLimit::FromParameters(parameters_); return SolveWithTimeLimit(linear_problem, user_provided_initial_solution, @@ -1130,5 +1127,5 @@ BopSolveStatus IntegralSolver::SolveWithTimeLimit( return status; } -} // namespace bop -} // namespace operations_research +} // namespace bop +} // namespace operations_research diff --git a/ortools/bop/integral_solver.h b/ortools/bop/integral_solver.h index 6cc7c5ed99..987fa25789 100644 --- a/ortools/bop/integral_solver.h +++ b/ortools/bop/integral_solver.h @@ -25,7 +25,7 @@ namespace bop { // problems with both integral and boolean variables, linear constraint and // linear objective function. class IntegralSolver { -public: + public: IntegralSolver(); ~IntegralSolver() {} @@ -38,21 +38,20 @@ public: // Solves the given linear program and returns the solve status. ABSL_MUST_USE_RESULT BopSolveStatus - Solve(const glop::LinearProgram &linear_problem); - ABSL_MUST_USE_RESULT BopSolveStatus - SolveWithTimeLimit(const glop::LinearProgram &linear_problem, - TimeLimit *time_limit); + Solve(const glop::LinearProgram &linear_problem); + ABSL_MUST_USE_RESULT BopSolveStatus SolveWithTimeLimit( + const glop::LinearProgram &linear_problem, TimeLimit *time_limit); // Same as Solve() but starts from the given solution. // TODO(user): Change the API to accept a partial solution instead since the // underlying solver supports it. ABSL_MUST_USE_RESULT BopSolveStatus - Solve(const glop::LinearProgram &linear_problem, - const glop::DenseRow &user_provided_initial_solution); + Solve(const glop::LinearProgram &linear_problem, + const glop::DenseRow &user_provided_initial_solution); ABSL_MUST_USE_RESULT BopSolveStatus - SolveWithTimeLimit(const glop::LinearProgram &linear_problem, - const glop::DenseRow &user_provided_initial_solution, - TimeLimit *time_limit); + SolveWithTimeLimit(const glop::LinearProgram &linear_problem, + const glop::DenseRow &user_provided_initial_solution, + TimeLimit *time_limit); // Returns the objective value of the solution with its offset. glop::Fractional objective_value() const { return objective_value_; } @@ -64,7 +63,7 @@ public: // solution is found. const glop::DenseRow &variable_values() const { return variable_values_; } -private: + private: BopParameters parameters_; glop::DenseRow variable_values_; glop::Fractional objective_value_; @@ -72,6 +71,6 @@ private: DISALLOW_COPY_AND_ASSIGN(IntegralSolver); }; -} // namespace bop -} // namespace operations_research -#endif // OR_TOOLS_BOP_INTEGRAL_SOLVER_H_ +} // namespace bop +} // namespace operations_research +#endif // OR_TOOLS_BOP_INTEGRAL_SOLVER_H_ diff --git a/ortools/constraint_solver/alldiff_cst.cc b/ortools/constraint_solver/alldiff_cst.cc index c2cd1e8685..72cc7c8716 100644 --- a/ortools/constraint_solver/alldiff_cst.cc +++ b/ortools/constraint_solver/alldiff_cst.cc @@ -31,7 +31,7 @@ namespace operations_research { namespace { class BaseAllDifferent : public Constraint { -public: + public: BaseAllDifferent(Solver *const s, const std::vector &vars) : Constraint(s), vars_(vars) {} ~BaseAllDifferent() override {} @@ -39,7 +39,7 @@ public: return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", ")); } -protected: + protected: const std::vector vars_; int64 size() const { return vars_.size(); } }; @@ -48,7 +48,7 @@ protected: // ValueAllDifferent class ValueAllDifferent : public BaseAllDifferent { -public: + public: ValueAllDifferent(Solver *const s, const std::vector &vars) : BaseAllDifferent(s, vars) {} ~ValueAllDifferent() override {} @@ -69,7 +69,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this); } -private: + private: RevSwitch all_instantiated_; }; @@ -121,7 +121,7 @@ bool ValueAllDifferent::AllMoves() { std::sort(values.get(), values.get() + size()); for (int i = 0; i < size() - 1; ++i) { if (values[i] == values[i + 1]) { - values.reset(); // prevent leaks (solver()->Fail() won't return) + values.reset(); // prevent leaks (solver()->Fail() won't return) solver()->Fail(); } } @@ -133,7 +133,7 @@ bool ValueAllDifferent::AllMoves() { // See http://www.cs.uwaterloo.ca/~cquimper/Papers/ijcai03_TR.pdf for details. class RangeBipartiteMatching { -public: + public: struct Interval { int64 min; int64 max; @@ -142,10 +142,15 @@ public: }; RangeBipartiteMatching(Solver *const solver, int size) - : solver_(solver), size_(size), intervals_(new Interval[size + 1]), - min_sorted_(new Interval *[size]), max_sorted_(new Interval *[size]), - bounds_(new int64[2 * size + 2]), tree_(new int[2 * size + 2]), - diff_(new int64[2 * size + 2]), hall_(new int[2 * size + 2]), + : solver_(solver), + size_(size), + intervals_(new Interval[size + 1]), + min_sorted_(new Interval *[size]), + max_sorted_(new Interval *[size]), + bounds_(new int64[2 * size + 2]), + tree_(new int[2 * size + 2]), + diff_(new int64[2 * size + 2]), + hall_(new int[2 * size + 2]), active_size_(0) { for (int i = 0; i < size; ++i) { max_sorted_[i] = &intervals_[i]; @@ -170,7 +175,7 @@ public: int64 Max(int index) const { return intervals_[index].max; } -private: + private: // This method sorts the min_sorted_ and max_sorted_ arrays and fill // the bounds_ array (and set the active_size_ counter). void SortArray() { @@ -187,8 +192,8 @@ private: int i = 0; int j = 0; int nb = 0; - for (;;) { // merge min_sorted_[] and max_sorted_[] into bounds_[]. - if (i < size_ && min <= max) { // make sure min_sorted_ exhausted first. + for (;;) { // merge min_sorted_[] and max_sorted_[] into bounds_[]. + if (i < size_ && min <= max) { // make sure min_sorted_ exhausted first. if (min != last) { last = min; bounds_[++nb] = last; @@ -233,18 +238,18 @@ private: z = PathMax(tree_.get(), z + 1); tree_[z] = j; } - PathSet(x + 1, z, z, tree_.get()); // path compression + PathSet(x + 1, z, z, tree_.get()); // path compression if (diff_[z] < bounds_[z] - bounds_[y]) { solver_->Fail(); } if (hall_[x] > x) { int w = PathMax(hall_.get(), hall_[x]); max_sorted_[i]->min = bounds_[w]; - PathSet(x, w, w, hall_.get()); // path compression + PathSet(x, w, w, hall_.get()); // path compression modified = true; } if (diff_[z] == bounds_[z] - bounds_[y]) { - PathSet(hall_[y], j - 1, y, hall_.get()); // mark hall interval + PathSet(hall_[y], j - 1, y, hall_.get()); // mark hall interval hall_[y] = j - 1; } } @@ -334,19 +339,19 @@ private: Solver *const solver_; const int size_; std::unique_ptr intervals_; - std::unique_ptr min_sorted_; - std::unique_ptr max_sorted_; + std::unique_ptr min_sorted_; + std::unique_ptr max_sorted_; // bounds_[1..active_size_] hold set of min & max in the n intervals_ // while bounds_[0] and bounds_[active_size_ + 1] allow sentinels. std::unique_ptr bounds_; - std::unique_ptr tree_; // tree links. - std::unique_ptr diff_; // diffs between critical capacities. - std::unique_ptr hall_; // hall interval links. + std::unique_ptr tree_; // tree links. + std::unique_ptr diff_; // diffs between critical capacities. + std::unique_ptr hall_; // hall interval links. int active_size_; }; class BoundsAllDifferent : public BaseAllDifferent { -public: + public: BoundsAllDifferent(Solver *const s, const std::vector &vars) : BaseAllDifferent(s, vars), matching_(s, vars.size()) {} @@ -359,9 +364,9 @@ public: for (int i = 0; i < size(); ++i) { vars_[i]->WhenRange(range); - Demon *bound = MakeConstraintDemon1( - solver(), this, &BoundsAllDifferent::PropagateValue, "PropagateValue", - i); + Demon *bound = MakeConstraintDemon1(solver(), this, + &BoundsAllDifferent::PropagateValue, + "PropagateValue", i); vars_[i]->WhenBound(bound); } } @@ -417,17 +422,20 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this); } -private: + private: RangeBipartiteMatching matching_; }; class SortConstraint : public Constraint { -public: + public: SortConstraint(Solver *const solver, const std::vector &original_vars, const std::vector &sorted_vars) - : Constraint(solver), ovars_(original_vars), svars_(sorted_vars), - mins_(original_vars.size(), 0), maxs_(original_vars.size(), 0), + : Constraint(solver), + ovars_(original_vars), + svars_(sorted_vars), + mins_(original_vars.size(), 0), + maxs_(original_vars.size(), 0), matching_(solver, original_vars.size()) {} ~SortConstraint() override {} @@ -491,7 +499,7 @@ public: JoinDebugStringPtr(svars_, ", ")); } -private: + private: int64 size() const { return ovars_.size(); } void FindIntersectionRange(int index, int64 *const range_min, @@ -528,7 +536,7 @@ private: // All variables are pairwise different, unless they are assigned to // the escape value. class AllDifferentExcept : public Constraint { -public: + public: AllDifferentExcept(Solver *const s, std::vector vars, int64 escape_value) : Constraint(s), vars_(std::move(vars)), escape_value_(escape_value) {} @@ -576,7 +584,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this); } -private: + private: std::vector vars_; const int64 escape_value_; }; @@ -587,18 +595,22 @@ private: // the set of values in the first vector minus the escape value does // not intersect the set of values in the second vector. class NullIntersectArrayExcept : public Constraint { -public: + public: NullIntersectArrayExcept(Solver *const s, std::vector first_vars, std::vector second_vars, int64 escape_value) - : Constraint(s), first_vars_(std::move(first_vars)), - second_vars_(std::move(second_vars)), escape_value_(escape_value), + : Constraint(s), + first_vars_(std::move(first_vars)), + second_vars_(std::move(second_vars)), + escape_value_(escape_value), has_escape_value_(true) {} NullIntersectArrayExcept(Solver *const s, std::vector first_vars, std::vector second_vars) - : Constraint(s), first_vars_(std::move(first_vars)), - second_vars_(std::move(second_vars)), escape_value_(0), + : Constraint(s), + first_vars_(std::move(first_vars)), + second_vars_(std::move(second_vars)), + escape_value_(0), has_escape_value_(false) {} ~NullIntersectArrayExcept() override {} @@ -668,13 +680,13 @@ public: visitor->EndVisitConstraint(ModelVisitor::kNullIntersect, this); } -private: + private: std::vector first_vars_; std::vector second_vars_; const int64 escape_value_; const bool has_escape_value_; }; -} // namespace +} // namespace Constraint *Solver::MakeAllDifferent(const std::vector &vars) { return MakeAllDifferent(vars, true); @@ -719,16 +731,15 @@ Constraint *Solver::MakeAllDifferentExcept(const std::vector &vars, } } -Constraint * -Solver::MakeNullIntersect(const std::vector &first_vars, - const std::vector &second_vars) { +Constraint *Solver::MakeNullIntersect( + const std::vector &first_vars, + const std::vector &second_vars) { return RevAlloc(new NullIntersectArrayExcept(this, first_vars, second_vars)); } -Constraint * -Solver::MakeNullIntersectExcept(const std::vector &first_vars, - const std::vector &second_vars, - int64 escape_value) { +Constraint *Solver::MakeNullIntersectExcept( + const std::vector &first_vars, + const std::vector &second_vars, int64 escape_value) { int first_escape_candidates = 0; for (int i = 0; i < first_vars.size(); ++i) { first_escape_candidates += (first_vars[i]->Contains(escape_value)); @@ -745,4 +756,4 @@ Solver::MakeNullIntersectExcept(const std::vector &first_vars, escape_value)); } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/assignment.cc b/ortools/constraint_solver/assignment.cc index 0421fc6252..33ae1e04d9 100644 --- a/ortools/constraint_solver/assignment.cc +++ b/ortools/constraint_solver/assignment.cc @@ -60,8 +60,8 @@ void IntVarElement::Copy(const IntVarElement &element) { } } -void -IntVarElement::LoadFromProto(const IntVarAssignment &int_var_assignment_proto) { +void IntVarElement::LoadFromProto( + const IntVarAssignment &int_var_assignment_proto) { min_ = int_var_assignment_proto.min(); max_ = int_var_assignment_proto.max(); if (int_var_assignment_proto.active()) { @@ -86,8 +86,8 @@ bool IntVarElement::operator==(const IntVarElement &element) const { return min_ == element.min_ && max_ == element.max_; } -void -IntVarElement::WriteToProto(IntVarAssignment *int_var_assignment_proto) const { +void IntVarElement::WriteToProto( + IntVarAssignment *int_var_assignment_proto) const { int_var_assignment_proto->set_var_id(var_->name()); int_var_assignment_proto->set_min(min_); int_var_assignment_proto->set_max(max_); @@ -476,7 +476,7 @@ void LoadElement(const absl::flat_hash_map &id_to_element_map, } } -} // namespace +} // namespace bool Assignment::Load(const std::string &filename) { File *file; @@ -502,7 +502,7 @@ bool Assignment::Load(File *file) { template void RealLoad(const AssignmentProto &assignment_proto, Container *const container, - int(AssignmentProto::*GetSize)() const, + int (AssignmentProto::*GetSize)() const, const Proto &(AssignmentProto::*GetElem)(int) const) { bool fast_load = (container->Size() == (assignment_proto.*GetSize)()); for (int i = 0; fast_load && i < (assignment_proto.*GetSize)(); ++i) { @@ -827,18 +827,18 @@ SequenceVarElement *Assignment::FastAdd(SequenceVar *const var) { return sequence_var_container_.FastAdd(var); } -const std::vector & -Assignment::ForwardSequence(const SequenceVar *const var) const { +const std::vector &Assignment::ForwardSequence( + const SequenceVar *const var) const { return sequence_var_container_.Element(var).ForwardSequence(); } -const std::vector & -Assignment::BackwardSequence(const SequenceVar *const var) const { +const std::vector &Assignment::BackwardSequence( + const SequenceVar *const var) const { return sequence_var_container_.Element(var).BackwardSequence(); } -const std::vector & -Assignment::Unperformed(const SequenceVar *const var) const { +const std::vector &Assignment::Unperformed( + const SequenceVar *const var) const { return sequence_var_container_.Element(var).Unperformed(); } @@ -846,21 +846,20 @@ void Assignment::SetSequence(const SequenceVar *const var, const std::vector &forward_sequence, const std::vector &backward_sequence, const std::vector &unperformed) { - sequence_var_container_.MutableElement(var) - ->SetSequence(forward_sequence, backward_sequence, unperformed); + sequence_var_container_.MutableElement(var)->SetSequence( + forward_sequence, backward_sequence, unperformed); } void Assignment::SetForwardSequence(const SequenceVar *const var, const std::vector &forward_sequence) { - sequence_var_container_.MutableElement(var) - ->SetForwardSequence(forward_sequence); + sequence_var_container_.MutableElement(var)->SetForwardSequence( + forward_sequence); } -void -Assignment::SetBackwardSequence(const SequenceVar *const var, - const std::vector &backward_sequence) { - sequence_var_container_.MutableElement(var) - ->SetBackwardSequence(backward_sequence); +void Assignment::SetBackwardSequence( + const SequenceVar *const var, const std::vector &backward_sequence) { + sequence_var_container_.MutableElement(var)->SetBackwardSequence( + backward_sequence); } void Assignment::SetUnperformed(const SequenceVar *const var, @@ -1044,7 +1043,7 @@ Assignment *Solver::MakeAssignment(const Assignment *const a) { // ----- Storing and Restoring assignments ----- namespace { class RestoreAssignment : public DecisionBuilder { -public: + public: explicit RestoreAssignment(Assignment *assignment) : assignment_(assignment) {} @@ -1057,12 +1056,12 @@ public: std::string DebugString() const override { return "RestoreAssignment"; } -private: + private: Assignment *const assignment_; }; class StoreAssignment : public DecisionBuilder { -public: + public: explicit StoreAssignment(Assignment *assignment) : assignment_(assignment) {} ~StoreAssignment() override {} @@ -1074,10 +1073,10 @@ public: std::string DebugString() const override { return "StoreAssignment"; } -private: + private: Assignment *const assignment_; }; -} // namespace +} // namespace DecisionBuilder *Solver::MakeRestoreAssignment(Assignment *assignment) { return RevAlloc(new RestoreAssignment(assignment)); @@ -1091,4 +1090,4 @@ std::ostream &operator<<(std::ostream &out, const Assignment &assignment) { return out << assignment.DebugString(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/constraint_solver.cc b/ortools/constraint_solver/constraint_solver.cc index f2e7cb2f19..8aeb0e7c82 100644 --- a/ortools/constraint_solver/constraint_solver.cc +++ b/ortools/constraint_solver/constraint_solver.cc @@ -93,7 +93,7 @@ DEFINE_int64(cp_random_seed, 12345, void ConstraintSolverFailsHere() { VLOG(3) << "Fail"; } -#if defined(_MSC_VER) // WINDOWS +#if defined(_MSC_VER) // WINDOWS #pragma warning(disable : 4351 4355) #endif @@ -110,7 +110,7 @@ void ForAll(const std::vector &objects, MethodPointer method, (object->*method)(args...); } } -} // namespace +} // namespace // ----- ConstraintSolverParameters ----- @@ -212,12 +212,17 @@ void Demon::desinhibit(Solver *const s) { extern void CleanVariableOnFail(IntVar *const var); class Queue { -public: + public: static constexpr int64 kTestPeriod = 10000; explicit Queue(Solver *const s) - : solver_(s), stamp_(1), freeze_level_(0), in_process_(false), - clean_action_(nullptr), clean_variable_(nullptr), in_add_(false), + : solver_(s), + stamp_(1), + freeze_level_(0), + in_process_(false), + clean_action_(nullptr), + clean_variable_(nullptr), + in_add_(false), instruments_demons_(s->InstrumentsDemons()) {} ~Queue() {} @@ -388,7 +393,7 @@ public: } } -private: + private: Solver *const solver_; std::deque var_queue_; std::deque delayed_queue_; @@ -406,21 +411,33 @@ private: // ------------------ StateMarker / StateInfo struct ----------- -struct StateInfo { // This is an internal structure to store - // additional information on the choice point. -public: +struct StateInfo { // This is an internal structure to store + // additional information on the choice point. + public: StateInfo() - : ptr_info(nullptr), int_info(0), depth(0), left_depth(0), + : ptr_info(nullptr), + int_info(0), + depth(0), + left_depth(0), reversible_action(nullptr) {} StateInfo(void *pinfo, int iinfo) - : ptr_info(pinfo), int_info(iinfo), depth(0), left_depth(0), + : ptr_info(pinfo), + int_info(iinfo), + depth(0), + left_depth(0), reversible_action(nullptr) {} StateInfo(void *pinfo, int iinfo, int d, int ld) - : ptr_info(pinfo), int_info(iinfo), depth(d), left_depth(ld), + : ptr_info(pinfo), + int_info(iinfo), + depth(d), + left_depth(ld), reversible_action(nullptr) {} StateInfo(Solver::Action a, bool fast) - : ptr_info(nullptr), int_info(static_cast(fast)), depth(0), - left_depth(0), reversible_action(std::move(a)) {} + : ptr_info(nullptr), + int_info(static_cast(fast)), + depth(0), + left_depth(0), + reversible_action(std::move(a)) {} void *ptr_info; int int_info; @@ -430,12 +447,12 @@ public: }; struct StateMarker { -public: + public: StateMarker(Solver::MarkerType t, const StateInfo &info); friend class Solver; friend struct Trail; -private: + private: Solver::MarkerType type_; int rev_int_index_; int rev_int64_index_; @@ -455,11 +472,20 @@ private: }; StateMarker::StateMarker(Solver::MarkerType t, const StateInfo &info) - : type_(t), rev_int_index_(0), rev_int64_index_(0), rev_uint64_index_(0), - rev_double_index_(0), rev_ptr_index_(0), rev_boolvar_list_index_(0), - rev_bools_index_(0), rev_int_memory_index_(0), rev_int64_memory_index_(0), - rev_double_memory_index_(0), rev_object_memory_index_(0), - rev_object_array_memory_index_(0), info_(info) {} + : type_(t), + rev_int_index_(0), + rev_int64_index_(0), + rev_uint64_index_(0), + rev_double_index_(0), + rev_ptr_index_(0), + rev_boolvar_list_index_(0), + rev_bools_index_(0), + rev_int_memory_index_(0), + rev_int64_memory_index_(0), + rev_double_memory_index_(0), + rev_object_memory_index_(0), + rev_object_array_memory_index_(0), + info_(info) {} // ---------- Trail and Reversibility ---------- @@ -468,13 +494,14 @@ namespace { // This template class is used internally to implement reversibility. // It stores an address and the value that was at the address. -template struct addrval { -public: +template +struct addrval { + public: addrval() : address_(nullptr) {} explicit addrval(T *adr) : address_(adr), old_value_(*adr) {} void restore() const { (*address_) = old_value_; } -private: + private: T *address_; T old_value_; }; @@ -484,21 +511,23 @@ private: // ---------- Trail Packer --------- // Abstract class to pack trail blocks. -template class TrailPacker { -public: +template +class TrailPacker { + public: explicit TrailPacker(int block_size) : block_size_(block_size) {} virtual ~TrailPacker() {} int input_size() const { return block_size_ * sizeof(addrval); } virtual void Pack(const addrval *block, std::string *packed_block) = 0; virtual void Unpack(const std::string &packed_block, addrval *block) = 0; -private: + private: const int block_size_; DISALLOW_COPY_AND_ASSIGN(TrailPacker); }; -template class NoCompressionTrailPacker : public TrailPacker { -public: +template +class NoCompressionTrailPacker : public TrailPacker { + public: explicit NoCompressionTrailPacker(int block_size) : TrailPacker(block_size) {} ~NoCompressionTrailPacker() override {} @@ -514,12 +543,13 @@ public: memcpy(block, packed_block.c_str(), packed_block.size()); } -private: + private: DISALLOW_COPY_AND_ASSIGN(NoCompressionTrailPacker); }; -template class ZlibTrailPacker : public TrailPacker { -public: +template +class ZlibTrailPacker : public TrailPacker { + public: explicit ZlibTrailPacker(int block_size) : TrailPacker(block_size), tmp_size_(compressBound(this->input_size())), @@ -550,30 +580,38 @@ public: CHECK_EQ(Z_OK, result); } -private: + private: const uint64 tmp_size_; std::unique_ptr tmp_block_; DISALLOW_COPY_AND_ASSIGN(ZlibTrailPacker); }; -template class CompressedTrail { -public: +template +class CompressedTrail { + public: CompressedTrail( int block_size, ConstraintSolverParameters::TrailCompression compression_level) - : block_size_(block_size), blocks_(nullptr), free_blocks_(nullptr), - data_(new addrval[block_size]), buffer_(new addrval[block_size]), - buffer_used_(false), current_(0), size_(0) { + : block_size_(block_size), + blocks_(nullptr), + free_blocks_(nullptr), + data_(new addrval[block_size]), + buffer_(new addrval[block_size]), + buffer_used_(false), + current_(0), + size_(0) { switch (compression_level) { - case ConstraintSolverParameters::NO_COMPRESSION: { - packer_.reset(new NoCompressionTrailPacker(block_size)); - break; - } - case ConstraintSolverParameters::COMPRESS_WITH_ZLIB: { - packer_.reset(new ZlibTrailPacker(block_size)); - break; - } - default: { LOG(ERROR) << "Should not be here"; } + case ConstraintSolverParameters::NO_COMPRESSION: { + packer_.reset(new NoCompressionTrailPacker(block_size)); + break; + } + case ConstraintSolverParameters::COMPRESS_WITH_ZLIB: { + packer_.reset(new ZlibTrailPacker(block_size)); + break; + } + default: { + LOG(ERROR) << "Should not be here"; + } } // We zero all memory used by addrval arrays. @@ -612,7 +650,7 @@ public: } void PushBack(const addrval &addr_val) { if (current_ >= block_size_) { - if (buffer_used_) { // Buffer is used. + if (buffer_used_) { // Buffer is used. NewTopBlock(); packer_->Pack(buffer_.get(), &blocks_->compressed); // O(1) operation. @@ -629,7 +667,7 @@ public: } int64 size() const { return size_; } -private: + private: struct Block { std::string compressed; Block *next; @@ -665,13 +703,13 @@ private: const int block_size_; Block *blocks_; Block *free_blocks_; - std::unique_ptr []> data_; - std::unique_ptr []> buffer_; + std::unique_ptr[]> data_; + std::unique_ptr[]> buffer_; bool buffer_used_; int current_; int size_; }; -} // namespace +} // namespace // ----- Trail ----- @@ -912,23 +950,41 @@ void InternalSaveBooleanVarValue(Solver *const solver, IntVar *const var) { // ------------------ Search class ----------------- class Search { -public: + public: explicit Search(Solver *const s) - : solver_(s), marker_stack_(), fail_buffer_(), solution_counter_(0), - unchecked_solution_counter_(0), decision_builder_(nullptr), - created_by_solve_(false), search_depth_(0), left_search_depth_(0), - should_restart_(false), should_finish_(false), sentinel_pushed_(0), - jmpbuf_filled_(false), backtrack_at_the_end_of_the_search_(true) {} + : solver_(s), + marker_stack_(), + fail_buffer_(), + solution_counter_(0), + unchecked_solution_counter_(0), + decision_builder_(nullptr), + created_by_solve_(false), + search_depth_(0), + left_search_depth_(0), + should_restart_(false), + should_finish_(false), + sentinel_pushed_(0), + jmpbuf_filled_(false), + backtrack_at_the_end_of_the_search_(true) {} // Constructor for a dummy search. The only difference between a dummy search // and a regular one is that the search depth and left search depth is // initialized to -1 instead of zero. Search(Solver *const s, int /* dummy_argument */) - : solver_(s), marker_stack_(), fail_buffer_(), solution_counter_(0), - unchecked_solution_counter_(0), decision_builder_(nullptr), - created_by_solve_(false), search_depth_(-1), left_search_depth_(-1), - should_restart_(false), should_finish_(false), sentinel_pushed_(0), - jmpbuf_filled_(false), backtrack_at_the_end_of_the_search_(true) {} + : solver_(s), + marker_stack_(), + fail_buffer_(), + solution_counter_(0), + unchecked_solution_counter_(0), + decision_builder_(nullptr), + created_by_solve_(false), + search_depth_(-1), + left_search_depth_(-1), + should_restart_(false), + should_finish_(false), + sentinel_pushed_(0), + jmpbuf_filled_(false), + backtrack_at_the_end_of_the_search_(true) {} ~Search() { gtl::STLDeleteElements(&marker_stack_); } @@ -1001,7 +1057,7 @@ public: std::string search_context() const { return search_context_; } friend class Solver; -private: + private: // Jumps back to the previous choice point, Checks if it was correctly set. void JumpBack(); void ClearBuffer() { @@ -1041,22 +1097,21 @@ private: #ifndef CP_USE_EXCEPTIONS_FOR_BACKTRACK // We cannot use a method/function for this as we would lose the // context in the setjmp implementation. -#define CP_TRY(search) \ - CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \ - search->jmpbuf_filled_ = true; \ +#define CP_TRY(search) \ + CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \ + search->jmpbuf_filled_ = true; \ if (setjmp(search->fail_buffer_) == 0) #define CP_ON_FAIL else #define CP_DO_FAIL(search) longjmp(search->fail_buffer_, 1) -#else // CP_USE_EXCEPTIONS_FOR_BACKTRACK -class FailException { -}; -#define CP_TRY(search) \ - CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \ - search->jmpbuf_filled_ = true; \ +#else // CP_USE_EXCEPTIONS_FOR_BACKTRACK +class FailException {}; +#define CP_TRY(search) \ + CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \ + search->jmpbuf_filled_ = true; \ try #define CP_ON_FAIL catch (FailException &) #define CP_DO_FAIL(search) throw FailException() -#endif // CP_USE_EXCEPTIONS_FOR_BACKTRACK +#endif // CP_USE_EXCEPTIONS_FOR_BACKTRACK void Search::JumpBack() { if (jmpbuf_filled_) { @@ -1072,7 +1127,7 @@ Search *Solver::ActiveSearch() const { return searches_.back(); } namespace { class ApplyBranchSelector : public DecisionBuilder { -public: + public: explicit ApplyBranchSelector(Solver::BranchSelector bs) : selector_(std::move(bs)) {} ~ApplyBranchSelector() override {} @@ -1084,10 +1139,10 @@ public: std::string DebugString() const override { return "Apply(BranchSelector)"; } -private: + private: Solver::BranchSelector const selector_; }; -} // namespace +} // namespace void Search::SetBranchSelector(Solver::BranchSelector bs) { selector_ = std::move(bs); @@ -1098,12 +1153,13 @@ void Solver::SetBranchSelector(BranchSelector bs) { // deleted upon backtrack. Thus we guard the undo action by a // check on the number of nesting of solve(). const int solve_depth = SolveDepth(); - AddBacktrackAction([solve_depth](Solver * s) { - if (s->SolveDepth() == solve_depth) { - s->ActiveSearch()->SetBranchSelector(nullptr); - } - }, - false); + AddBacktrackAction( + [solve_depth](Solver *s) { + if (s->SolveDepth() == solve_depth) { + s->ActiveSearch()->SetBranchSelector(nullptr); + } + }, + false); searches_.back()->SetBranchSelector(std::move(bs)); } @@ -1304,7 +1360,7 @@ namespace { // ---------- Fail Decision ---------- class FailDecision : public Decision { -public: + public: void Apply(Solver *const s) override { s->Fail(); } void Refute(Solver *const s) override { s->Fail(); } }; @@ -1312,12 +1368,12 @@ public: // Balancing decision class BalancingDecision : public Decision { -public: + public: ~BalancingDecision() override {} void Apply(Solver *const s) override {} void Refute(Solver *const s) override {} }; -} // namespace +} // namespace Decision *Solver::MakeFailDecision() { return fail_decision_.get(); } @@ -1331,7 +1387,7 @@ enum SentinelMarker { ROOT_NODE_SENTINEL = 20000000, SOLVER_CTOR_SENTINEL = 40000000 }; -} // namespace +} // namespace extern PropagationMonitor *BuildTrace(Solver *const s); extern LocalSearchMonitor *BuildLocalSearchMonitorMaster(Solver *const s); @@ -1344,19 +1400,24 @@ void CheckSolverParameters(const ConstraintSolverParameters ¶meters) { CHECK_GT(parameters.array_split_size(), 0) << "Were parameters built using Solver::DefaultSolverParameters() ?"; } -} // namespace +} // namespace Solver::Solver(const std::string &name, const ConstraintSolverParameters ¶meters) - : name_(name), parameters_(parameters), random_(CpRandomSeed()), - demon_profiler_(BuildDemonProfiler(this)), use_fast_local_search_(true), + : name_(name), + parameters_(parameters), + random_(CpRandomSeed()), + demon_profiler_(BuildDemonProfiler(this)), + use_fast_local_search_(true), local_search_profiler_(BuildLocalSearchProfiler(this)) { Init(); } Solver::Solver(const std::string &name) - : name_(name), parameters_(DefaultSolverParameters()), - random_(CpRandomSeed()), demon_profiler_(BuildDemonProfiler(this)), + : name_(name), + parameters_(DefaultSolverParameters()), + random_(CpRandomSeed()), + demon_profiler_(BuildDemonProfiler(this)), use_fast_local_search_(true), local_search_profiler_(BuildLocalSearchProfiler(this)) { Init(); @@ -1397,8 +1458,8 @@ void Solver::Init() { } searches_.push_back(new Search(this)); PushSentinel(SOLVER_CTOR_SENTINEL); - InitCachedIntConstants(); // to be called after the SENTINEL is set. - InitCachedConstraint(); // Cache the true constraint. + InitCachedIntConstants(); // to be called after the SENTINEL is set. + InitCachedConstraint(); // Cache the true constraint. timer_->Restart(); model_cache_.reset(BuildModelCache(this)); AddPropagationMonitor( @@ -1426,24 +1487,24 @@ Solver::~Solver() { std::string Solver::DebugString() const { std::string out = "Solver(name = \"" + name_ + "\", state = "; switch (state_) { - case OUTSIDE_SEARCH: - out += "OUTSIDE_SEARCH"; - break; - case IN_ROOT_NODE: - out += "IN_ROOT_NODE"; - break; - case IN_SEARCH: - out += "IN_SEARCH"; - break; - case AT_SOLUTION: - out += "AT_SOLUTION"; - break; - case NO_MORE_SOLUTIONS: - out += "NO_MORE_SOLUTIONS"; - break; - case PROBLEM_INFEASIBLE: - out += "PROBLEM_INFEASIBLE"; - break; + case OUTSIDE_SEARCH: + out += "OUTSIDE_SEARCH"; + break; + case IN_ROOT_NODE: + out += "IN_ROOT_NODE"; + break; + case IN_SEARCH: + out += "IN_SEARCH"; + break; + case AT_SOLUTION: + out += "AT_SOLUTION"; + break; + case NO_MORE_SOLUTIONS: + out += "NO_MORE_SOLUTIONS"; + break; + case PROBLEM_INFEASIBLE: + out += "PROBLEM_INFEASIBLE"; + break; } absl::StrAppendFormat( &out, @@ -1548,16 +1609,16 @@ Solver::MarkerType Solver::PopState(StateInfo *info) { void Solver::check_alloc_state() { switch (state_) { - case OUTSIDE_SEARCH: - case IN_ROOT_NODE: - case IN_SEARCH: - case NO_MORE_SOLUTIONS: - case PROBLEM_INFEASIBLE: - break; - case AT_SOLUTION: - LOG(FATAL) << "allocating at a leaf node"; - default: - LOG(FATAL) << "This switch was supposed to be exhaustive, but it is not!"; + case OUTSIDE_SEARCH: + case IN_ROOT_NODE: + case IN_SEARCH: + case NO_MORE_SOLUTIONS: + case PROBLEM_INFEASIBLE: + break; + case AT_SOLUTION: + LOG(FATAL) << "allocating at a leaf node"; + default: + LOG(FATAL) << "This switch was supposed to be exhaustive, but it is not!"; } } @@ -1730,7 +1791,7 @@ bool Solver::Solve(DecisionBuilder *const db, SearchMonitor *const m1, bool Solver::Solve(DecisionBuilder *const db, const std::vector &monitors) { NewSearch(db, monitors); - searches_.back()->set_created_by_solve(true); // Overwrites default. + searches_.back()->set_created_by_solve(true); // Overwrites default. NextSolution(); const bool solution_found = searches_.back()->solution_counter() > 0; EndSearch(); @@ -1791,7 +1852,7 @@ void Solver::NewSearch(DecisionBuilder *const db, } Search *const search = nested ? new Search(this) : searches_.back(); - search->set_created_by_solve(false); // default behavior. + search->set_created_by_solve(false); // default behavior. // ----- jumps to correct state ----- @@ -1836,11 +1897,11 @@ void Solver::NewSearch(DecisionBuilder *const db, // Install the print trace if needed. // The print_trace needs to be last to detect propagation from the objective. if (nested) { - if (print_trace_ != nullptr) { // Was installed at the top level? - print_trace_->Install(); // Propagates to nested search. + if (print_trace_ != nullptr) { // Was installed at the top level? + print_trace_->Install(); // Propagates to nested search. } - } else { // Top level search - print_trace_ = nullptr; // Clears it first. + } else { // Top level search + print_trace_ = nullptr; // Clears it first. if (parameters_.trace_propagation()) { print_trace_ = BuildPrintTrace(this); print_trace_->Install(); @@ -1872,31 +1933,31 @@ bool Solver::BacktrackOneLevel(Decision **const fail_decision) { StateInfo info; Solver::MarkerType t = PopState(&info); switch (t) { - case SENTINEL: - CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found"; - CHECK((info.int_info == ROOT_NODE_SENTINEL && SolveDepth() == 1) || - (info.int_info == INITIAL_SEARCH_SENTINEL && SolveDepth() > 1)); - searches_.back()->sentinel_pushed_--; - no_more_solutions = true; - end_loop = true; - break; - case SIMPLE_MARKER: - LOG(ERROR) << "Simple markers should not be encountered during search"; - break; - case CHOICE_POINT: - if (info.int_info == 0) { // was left branch - (*fail_decision) = reinterpret_cast(info.ptr_info); + case SENTINEL: + CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found"; + CHECK((info.int_info == ROOT_NODE_SENTINEL && SolveDepth() == 1) || + (info.int_info == INITIAL_SEARCH_SENTINEL && SolveDepth() > 1)); + searches_.back()->sentinel_pushed_--; + no_more_solutions = true; end_loop = true; - searches_.back()->set_search_depth(info.depth); - searches_.back()->set_search_left_depth(info.left_depth); + break; + case SIMPLE_MARKER: + LOG(ERROR) << "Simple markers should not be encountered during search"; + break; + case CHOICE_POINT: + if (info.int_info == 0) { // was left branch + (*fail_decision) = reinterpret_cast(info.ptr_info); + end_loop = true; + searches_.back()->set_search_depth(info.depth); + searches_.back()->set_search_left_depth(info.left_depth); + } + break; + case REVERSIBLE_ACTION: { + if (info.reversible_action != nullptr) { + info.reversible_action(this); + } + break; } - break; - case REVERSIBLE_ACTION: { - if (info.reversible_action != nullptr) { - info.reversible_action(this); - } - break; - } } } Search *const search = searches_.back(); @@ -1924,7 +1985,7 @@ void Solver::PushSentinel(int magic_code) { void Solver::RestartSearch() { Search *const search = searches_.back(); CHECK_NE(0, search->sentinel_pushed_); - if (SolveDepth() == 1) { // top level. + if (SolveDepth() == 1) { // top level. if (search->sentinel_pushed_ > 1) { BacktrackToSentinel(ROOT_NODE_SENTINEL); } @@ -1952,25 +2013,25 @@ void Solver::BacktrackToSentinel(int magic_code) { StateInfo info; Solver::MarkerType t = PopState(&info); switch (t) { - case SENTINEL: { - CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found"; - CHECK_GE(--search->sentinel_pushed_, 0); - search->set_search_depth(0); - search->set_search_left_depth(0); + case SENTINEL: { + CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found"; + CHECK_GE(--search->sentinel_pushed_, 0); + search->set_search_depth(0); + search->set_search_left_depth(0); - if (info.int_info == magic_code) { - end_loop = true; + if (info.int_info == magic_code) { + end_loop = true; + } + break; + } + case SIMPLE_MARKER: + break; + case CHOICE_POINT: + break; + case REVERSIBLE_ACTION: { + info.reversible_action(this); + break; } - break; - } - case SIMPLE_MARKER: - break; - case CHOICE_POINT: - break; - case REVERSIBLE_ACTION: { - info.reversible_action(this); - break; - } } } fail_stamp_++; @@ -2002,7 +2063,7 @@ void Solver::JumpToSentinelWhenNested() { namespace { class ReverseDecision : public Decision { -public: + public: explicit ReverseDecision(Decision *const d) : decision_(d) { CHECK(d != nullptr); } @@ -2023,10 +2084,10 @@ public: return str; } -private: + private: Decision *const decision_; }; -} // namespace +} // namespace // Search for the next solution in the search tree. bool Solver::NextSolution() { @@ -2040,43 +2101,43 @@ bool Solver::NextSolution() { return false; } - if (top_level) { // Manage top level state. + if (top_level) { // Manage top level state. switch (state_) { - case PROBLEM_INFEASIBLE: - return false; - case NO_MORE_SOLUTIONS: - return false; - case AT_SOLUTION: { - if (BacktrackOneLevel(&fd)) { // No more solutions. - state_ = NO_MORE_SOLUTIONS; + case PROBLEM_INFEASIBLE: return false; - } - state_ = IN_SEARCH; - break; - } - case OUTSIDE_SEARCH: { - state_ = IN_ROOT_NODE; - search->BeginInitialPropagation(); - CP_TRY(search) { - ProcessConstraints(); - search->EndInitialPropagation(); - PushSentinel(ROOT_NODE_SENTINEL); + case NO_MORE_SOLUTIONS: + return false; + case AT_SOLUTION: { + if (BacktrackOneLevel(&fd)) { // No more solutions. + state_ = NO_MORE_SOLUTIONS; + return false; + } state_ = IN_SEARCH; - search->ClearBuffer(); + break; } - CP_ON_FAIL { - queue_->AfterFailure(); - BacktrackToSentinel(INITIAL_SEARCH_SENTINEL); - state_ = PROBLEM_INFEASIBLE; - return false; + case OUTSIDE_SEARCH: { + state_ = IN_ROOT_NODE; + search->BeginInitialPropagation(); + CP_TRY(search) { + ProcessConstraints(); + search->EndInitialPropagation(); + PushSentinel(ROOT_NODE_SENTINEL); + state_ = IN_SEARCH; + search->ClearBuffer(); + } + CP_ON_FAIL { + queue_->AfterFailure(); + BacktrackToSentinel(INITIAL_SEARCH_SENTINEL); + state_ = PROBLEM_INFEASIBLE; + return false; + } + break; } - break; - } - case IN_SEARCH: // Usually after a RestartSearch - break; - case IN_ROOT_NODE: - LOG(FATAL) << "Should not happen"; - break; + case IN_SEARCH: // Usually after a RestartSearch + break; + case IN_ROOT_NODE: + LOG(FATAL) << "Should not happen"; + break; } } @@ -2088,7 +2149,7 @@ bool Solver::NextSolution() { CP_TRY(search) { if (fd != nullptr) { StateInfo i1(fd, 1, search->search_depth(), - search->left_search_depth()); // 1 for right branch + search->left_search_depth()); // 1 for right branch PushState(CHOICE_POINT, i1); search->RefuteDecision(fd); branches_++; @@ -2106,44 +2167,46 @@ bool Solver::NextSolution() { d = db->Next(this); search->EndNextDecision(db, d); if (d == fail_decision_.get()) { - Fail(); // fail now instead of after 2 branches. + Fail(); // fail now instead of after 2 branches. } if (d != nullptr) { DecisionModification modification = search->ModifyDecision(); switch (modification) { - case SWITCH_BRANCHES: { - d = RevAlloc(new ReverseDecision(d)); - // We reverse the decision and fall through the normal code. - ABSL_FALLTHROUGH_INTENDED; - } - case NO_CHANGE: { - decisions_++; - StateInfo i2(d, 0, search->search_depth(), - search->left_search_depth()); // 0 for left branch - PushState(CHOICE_POINT, i2); - search->ApplyDecision(d); - branches_++; - d->Apply(this); - CheckFail(); - search->AfterDecision(d, true); - search->LeftMove(); - break; - } - case KEEP_LEFT: { - search->ApplyDecision(d); - d->Apply(this); - CheckFail(); - search->AfterDecision(d, true); - break; - } - case KEEP_RIGHT: { - search->RefuteDecision(d); - d->Refute(this); - CheckFail(); - search->AfterDecision(d, false); - break; - } - case KILL_BOTH: { Fail(); } + case SWITCH_BRANCHES: { + d = RevAlloc(new ReverseDecision(d)); + // We reverse the decision and fall through the normal code. + ABSL_FALLTHROUGH_INTENDED; + } + case NO_CHANGE: { + decisions_++; + StateInfo i2(d, 0, search->search_depth(), + search->left_search_depth()); // 0 for left branch + PushState(CHOICE_POINT, i2); + search->ApplyDecision(d); + branches_++; + d->Apply(this); + CheckFail(); + search->AfterDecision(d, true); + search->LeftMove(); + break; + } + case KEEP_LEFT: { + search->ApplyDecision(d); + d->Apply(this); + CheckFail(); + search->AfterDecision(d, true); + break; + } + case KEEP_RIGHT: { + search->RefuteDecision(d); + d->Refute(this); + CheckFail(); + search->AfterDecision(d, false); + break; + } + case KILL_BOTH: { + Fail(); + } } } else { break; @@ -2181,7 +2244,7 @@ bool Solver::NextSolution() { PushSentinel(top_level ? ROOT_NODE_SENTINEL : INITIAL_SEARCH_SENTINEL); search->RestartSearch(); } else { - if (BacktrackOneLevel(&fd)) { // no more solutions. + if (BacktrackOneLevel(&fd)) { // no more solutions. result = false; finish = true; } @@ -2191,7 +2254,7 @@ bool Solver::NextSolution() { if (result) { search->ClearBuffer(); } - if (top_level) { // Manage state after NextSolution(). + if (top_level) { // Manage state after NextSolution(). state_ = (result ? AT_SOLUTION : NO_MORE_SOLUTIONS); } return result; @@ -2209,8 +2272,8 @@ void Solver::EndSearch() { } search->ExitSearch(); search->Clear(); - if (2 == searches_.size()) { // Ending top level search. - // Restores the state. + if (2 == searches_.size()) { // Ending top level search. + // Restores the state. state_ = OUTSIDE_SEARCH; // Checks if we want to export the profile info. if (!parameters_.profile_file().empty()) { @@ -2221,7 +2284,7 @@ void Solver::EndSearch() { if (parameters_.print_local_search_profile()) { LOG(INFO) << LocalSearchProfile(); } - } else { // We clean the nested Search. + } else { // We clean the nested Search. delete search; searches_.pop_back(); } @@ -2234,7 +2297,7 @@ bool Solver::CheckAssignment(Assignment *const solution) { } // Check state and go to OUTSIDE_SEARCH. Search *const search = searches_.back(); - search->set_created_by_solve(false); // default behavior. + search->set_created_by_solve(false); // default behavior. BacktrackToSentinel(INITIAL_SEARCH_SENTINEL); state_ = OUTSIDE_SEARCH; @@ -2279,7 +2342,7 @@ bool Solver::CheckAssignment(Assignment *const solution) { namespace { class AddConstraintDecisionBuilder : public DecisionBuilder { -public: + public: explicit AddConstraintDecisionBuilder(Constraint *const ct) : constraint_(ct) { CHECK(ct != nullptr); @@ -2297,10 +2360,10 @@ public: constraint_->DebugString()); } -private: + private: Constraint *const constraint_; }; -} // namespace +} // namespace DecisionBuilder *Solver::MakeConstraintAdder(Constraint *const ct) { return RevAlloc(new AddConstraintDecisionBuilder(ct)); @@ -2342,7 +2405,7 @@ bool Solver::SolveAndCommit(DecisionBuilder *const db, SearchMonitor *const m1, bool Solver::SolveAndCommit(DecisionBuilder *const db, const std::vector &monitors) { NewSearch(db, monitors); - searches_.back()->set_created_by_solve(true); // Overwrites default. + searches_.back()->set_created_by_solve(true); // Overwrites default. searches_.back()->set_backtrack_at_the_end_of_the_search(false); NextSolution(); const bool solution_found = searches_.back()->solution_counter() > 0; @@ -2414,7 +2477,7 @@ std::string Solver::GetName(const PropagationBaseObject *object) { void Solver::SetName(const PropagationBaseObject *object, const std::string &name) { if (parameters_.store_names() && - GetName(object) != name) { // in particular if name.empty() + GetName(object) != name) { // in particular if name.empty() propagation_object_names_[object] = name; } } @@ -2463,9 +2526,8 @@ void PropagationBaseObject::EnqueueAll(const SimpleRevFIFO &demons) { std::string DecisionBuilder::DebugString() const { return "DecisionBuilder"; } -void -DecisionBuilder::AppendMonitors(Solver *const solver, - std::vector *const extras) {} +void DecisionBuilder::AppendMonitors( + Solver *const solver, std::vector *const extras) {} void DecisionBuilder::Accept(ModelVisitor *const visitor) const {} @@ -2775,9 +2837,8 @@ void ModelVisitor::VisitInt64ToBoolExtension(Solver::IndexFilter1 filter, } } -void -ModelVisitor::VisitInt64ToInt64Extension(const Solver::IndexEvaluator1 &eval, - int64 index_min, int64 index_max) { +void ModelVisitor::VisitInt64ToInt64Extension( + const Solver::IndexEvaluator1 &eval, int64 index_min, int64 index_max) { CHECK(eval != nullptr); std::vector cached_results; for (int i = index_min; i <= index_max; ++i) { @@ -2860,13 +2921,13 @@ void LocalSearchMonitor::Install() { // ---------- Trace ---------- class Trace : public PropagationMonitor { -public: + public: explicit Trace(Solver *const s) : PropagationMonitor(s) {} ~Trace() override {} - void BeginConstraintInitialPropagation(Constraint *const constraint) - override { + void BeginConstraintInitialPropagation( + Constraint *const constraint) override { ForAll(monitors_, &PropagationMonitor::BeginConstraintInitialPropagation, constraint); } @@ -2876,17 +2937,15 @@ public: constraint); } - void BeginNestedConstraintInitialPropagation(Constraint *const parent, - Constraint *const nested) - override { + void BeginNestedConstraintInitialPropagation( + Constraint *const parent, Constraint *const nested) override { ForAll(monitors_, &PropagationMonitor::BeginNestedConstraintInitialPropagation, parent, nested); } - void EndNestedConstraintInitialPropagation(Constraint *const parent, - Constraint *const nested) - override { + void EndNestedConstraintInitialPropagation( + Constraint *const parent, Constraint *const nested) override { ForAll(monitors_, &PropagationMonitor::EndNestedConstraintInitialPropagation, parent, nested); @@ -2974,8 +3033,8 @@ public: ForAll(monitors_, &PropagationMonitor::SetValues, var, values); } - void RemoveValues(IntVar *const var, const std::vector &values) - override { + void RemoveValues(IntVar *const var, + const std::vector &values) override { ForAll(monitors_, &PropagationMonitor::RemoveValues, var, values); } @@ -2988,8 +3047,8 @@ public: ForAll(monitors_, &PropagationMonitor::SetStartMax, var, new_max); } - void SetStartRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetStartRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { ForAll(monitors_, &PropagationMonitor::SetStartRange, var, new_min, new_max); } @@ -3002,8 +3061,8 @@ public: ForAll(monitors_, &PropagationMonitor::SetEndMax, var, new_max); } - void SetEndRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetEndRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { ForAll(monitors_, &PropagationMonitor::SetEndRange, var, new_min, new_max); } @@ -3015,8 +3074,8 @@ public: ForAll(monitors_, &PropagationMonitor::SetDurationMax, var, new_max); } - void SetDurationRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetDurationRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { ForAll(monitors_, &PropagationMonitor::SetDurationRange, var, new_min, new_max); } @@ -3061,7 +3120,7 @@ public: std::string DebugString() const override { return "Trace"; } -private: + private: std::vector monitors_; }; @@ -3079,7 +3138,7 @@ PropagationMonitor *Solver::GetPropagationMonitor() const { // ---------- Local Search Monitor Master ---------- class LocalSearchMonitorMaster : public LocalSearchMonitor { -public: + public: explicit LocalSearchMonitorMaster(Solver *solver) : LocalSearchMonitor(solver) {} @@ -3101,16 +3160,16 @@ public: void BeginFilterNeighbor(const LocalSearchOperator *op) override { ForAll(monitors_, &LocalSearchMonitor::BeginFilterNeighbor, op); } - void EndFilterNeighbor(const LocalSearchOperator *op, bool neighbor_found) - override { + void EndFilterNeighbor(const LocalSearchOperator *op, + bool neighbor_found) override { ForAll(monitors_, &LocalSearchMonitor::EndFilterNeighbor, op, neighbor_found); } void BeginAcceptNeighbor(const LocalSearchOperator *op) override { ForAll(monitors_, &LocalSearchMonitor::BeginAcceptNeighbor, op); } - void EndAcceptNeighbor(const LocalSearchOperator *op, bool neighbor_found) - override { + void EndAcceptNeighbor(const LocalSearchOperator *op, + bool neighbor_found) override { ForAll(monitors_, &LocalSearchMonitor::EndAcceptNeighbor, op, neighbor_found); } @@ -3136,7 +3195,7 @@ public: return "LocalSearchMonitorMaster"; } -private: + private: std::vector monitors_; }; @@ -3146,7 +3205,8 @@ LocalSearchMonitor *BuildLocalSearchMonitorMaster(Solver *const s) { void Solver::AddLocalSearchMonitor(LocalSearchMonitor *const monitor) { reinterpret_cast( - local_search_monitor_.get())->Add(monitor); + local_search_monitor_.get()) + ->Add(monitor); } LocalSearchMonitor *Solver::GetLocalSearchMonitor() const { @@ -3205,8 +3265,8 @@ void IntExpr::Accept(ModelVisitor *const visitor) const { visitor->EndVisitIntegerExpression("unknown", this); } -#undef CP_TRY // We no longer need those. +#undef CP_TRY // We no longer need those. #undef CP_ON_FAIL #undef CP_DO_FAIL -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/constraint_solver.h b/ortools/constraint_solver/constraint_solver.h index e1d975a50b..1ae1e36353 100644 --- a/ortools/constraint_solver/constraint_solver.h +++ b/ortools/constraint_solver/constraint_solver.h @@ -94,7 +94,7 @@ #if !defined(SWIG) DECLARE_int64(cp_random_seed); -#endif // !defined(SWIG) +#endif // !defined(SWIG) class File; @@ -157,7 +157,8 @@ class ConstraintSolverParameters; class SymmetryBreaker; struct StateInfo; struct Trail; -template class SimpleRevFIFO; +template +class SimpleRevFIFO; inline int64 CpRandomSeed() { return absl::GetFlag(FLAGS_cp_random_seed) == -1 @@ -169,7 +170,7 @@ inline int64 CpRandomSeed() { /// DefaultPhaseParameters is only used by Solver::MakeDefaultPhase methods. /// Note this is for advanced users only. struct DefaultPhaseParameters { -public: + public: enum VariableSelection { CHOOSE_MAX_SUM_IMPACT = 0, CHOOSE_MAX_AVERAGE_IMPACT = 1, @@ -181,11 +182,7 @@ public: SELECT_MAX_IMPACT = 1, }; - enum DisplayLevel { - NONE = 0, - NORMAL = 1, - VERBOSE = 2 - }; + enum DisplayLevel { NONE = 0, NORMAL = 1, VERBOSE = 2 }; /// This parameter describes how the next variable to instantiate /// will be chosen. @@ -249,7 +246,7 @@ public: /// /// For the time being, Solver is neither MT_SAFE nor MT_HOT. class Solver { -public: + public: /// Holds semantic information stating that the 'expression' has been /// cast into 'variable' using the Var() method, and that /// 'maintainer' is responsible for maintaining the equality between @@ -716,12 +713,7 @@ public: /// This enum is used internally in private methods Solver::PushState and /// Solver::PopState to tag states in the search tree. - enum MarkerType { - SENTINEL, - SIMPLE_MARKER, - CHOICE_POINT, - REVERSIBLE_ACTION - }; + enum MarkerType { SENTINEL, SIMPLE_MARKER, CHOICE_POINT, REVERSIBLE_ACTION }; /// This enum represents the state of the solver w.r.t. the search. enum SolverState { @@ -740,11 +732,7 @@ public: }; /// Optimization directions. - enum OptimizationDirection { - NOT_SET, - MAXIMIZATION, - MINIMIZATION - }; + enum OptimizationDirection { NOT_SET, MAXIMIZATION, MINIMIZATION }; /// Callback typedefs typedef std::function IndexEvaluator1; @@ -782,7 +770,10 @@ public: /// SaveValue() saves the value of the corresponding object. It must be /// called before modifying the object. The value will be restored upon /// backtrack. - template void SaveValue(T *o) { InternalSaveValue(o); } + template + void SaveValue(T *o) { + InternalSaveValue(o); + } /// Registers the given object as being reversible. By calling this method, /// the caller gives ownership of the object to the solver, which will @@ -796,7 +787,8 @@ public: /// BaseObject: for all subclasses predefined in the library, the /// corresponding factory methods (e.g., MakeIntVar(...), /// MakeAllDifferent(...) already take care of the registration. - template T *RevAlloc(T *object) { + template + T *RevAlloc(T *object) { return reinterpret_cast(SafeRevAlloc(object)); } @@ -806,7 +798,8 @@ public: /// /// This method is valid for arrays of int, int64, uint64, bool, /// BaseObject*, IntVar*, IntExpr*, and Constraint*. - template T *RevAllocArray(T *object) { + template + T *RevAllocArray(T *object) { return reinterpret_cast(SafeRevAllocArray(object)); } @@ -967,7 +960,7 @@ public: /// indicates whether we need restore all values saved through SaveValue() /// before calling this method. void AddBacktrackAction(Action a, bool fast); -#endif /// !defined(SWIG) +#endif /// !defined(SWIG) /// misc debug string. std::string DebugString() const; @@ -1154,7 +1147,7 @@ public: /// vars(argument) IntExpr *MakeElement(Int64ToIntVar vars, int64 range_start, int64 range_end, IntVar *argument); -#endif // SWIG +#endif // SWIG /// Returns the expression expr such that vars[expr] == value. /// It assumes that vars are all different. @@ -1383,8 +1376,8 @@ public: #if !defined(SWIG) /// Creates a demon from a callback. Demon *MakeActionDemon(Action action); -#endif /// !defined(SWIG) - /// Creates a demon from a closure. +#endif /// !defined(SWIG) + /// Creates a demon from a closure. Demon *MakeClosureDemon(Closure closure); // ----- Between and related constraints ----- @@ -1427,7 +1420,7 @@ public: /// expr should not be in the list of forbidden intervals. Constraint *MakeNotMemberCt(IntExpr *expr, SortedDisjointIntervalList intervals); -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// boolvar == (expr in set) Constraint *MakeIsMemberCt(IntExpr *const expr, @@ -1550,21 +1543,18 @@ public: /// represent permutations of [0..left.size()-1], and that 'right' is /// the inverse permutation of 'left', i.e. for all i in /// [0..left.size()-1], right[left[i]] = i. - Constraint * - MakeInversePermutationConstraint(const std::vector &left, - const std::vector &right); + Constraint *MakeInversePermutationConstraint( + const std::vector &left, const std::vector &right); /// Creates a constraint that binds the index variable to the index of the /// first variable with the maximum value. - Constraint * - MakeIndexOfFirstMaxValueConstraint(IntVar *index, - const std::vector &vars); + Constraint *MakeIndexOfFirstMaxValueConstraint( + IntVar *index, const std::vector &vars); /// Creates a constraint that binds the index variable to the index of the /// first variable with the minimum value. - Constraint * - MakeIndexOfFirstMinValueConstraint(IntVar *index, - const std::vector &vars); + Constraint *MakeIndexOfFirstMinValueConstraint( + IntVar *index, const std::vector &vars); /// Creates a constraint that states that all variables in the first /// vector are different from all variables in the second @@ -1720,9 +1710,9 @@ public: #if defined(SWIGPYTHON) /// Compatibility layer for Python API. - Constraint * - MakeAllowedAssignments(const std::vector &vars, - const std::vector > &raw_tuples) { + Constraint *MakeAllowedAssignments( + const std::vector &vars, + const std::vector > &raw_tuples) { IntTupleSet tuples(vars.size()); tuples.InsertAll(raw_tuples); return MakeAllowedAssignments(vars, tuples); @@ -1966,9 +1956,8 @@ public: /// This constraint forces all interval vars into an non-overlapping /// sequence. Intervals with zero duration can be scheduled anywhere. - DisjunctiveConstraint * - MakeDisjunctiveConstraint(const std::vector &intervals, - const std::string &name); + DisjunctiveConstraint *MakeDisjunctiveConstraint( + const std::vector &intervals, const std::string &name); /// This constraint forces all interval vars into an non-overlapping /// sequence. Intervals with zero durations cannot overlap with over @@ -2068,15 +2057,15 @@ public: Assignment *MakeAssignment(const Assignment *const a); /// Collect the first solution of the search. - SolutionCollector * - MakeFirstSolutionCollector(const Assignment *const assignment); + SolutionCollector *MakeFirstSolutionCollector( + const Assignment *const assignment); /// Collect the first solution of the search. The variables will need to /// be added later. SolutionCollector *MakeFirstSolutionCollector(); /// Collect the last solution of the search. - SolutionCollector * - MakeLastSolutionCollector(const Assignment *const assignment); + SolutionCollector *MakeLastSolutionCollector( + const Assignment *const assignment); /// Collect the last solution of the search. The variables will need to /// be added later. SolutionCollector *MakeLastSolutionCollector(); @@ -2085,9 +2074,8 @@ public: /// of 'assignment'; if 'assignment' does not have an objective no solution is /// collected. This collector only collects one solution corresponding to the /// best objective value (the first one found). - SolutionCollector * - MakeBestValueSolutionCollector(const Assignment *const assignment, - bool maximize); + SolutionCollector *MakeBestValueSolutionCollector( + const Assignment *const assignment, bool maximize); /// Collect the solution corresponding to the optimal value of the /// objective of 'assignment'; if 'assignment' does not have an objective no /// solution is collected. This collector only collects one solution @@ -2098,15 +2086,14 @@ public: /// Same as MakeBestValueSolutionCollector but collects the best /// solution_count solutions. Collected solutions are sorted in increasing /// optimality order (the best solution is the last one). - SolutionCollector * - MakeNBestValueSolutionCollector(const Assignment *const assignment, - int solution_count, bool maximize); + SolutionCollector *MakeNBestValueSolutionCollector( + const Assignment *const assignment, int solution_count, bool maximize); SolutionCollector *MakeNBestValueSolutionCollector(int solution_count, bool maximize); /// Collect all solutions of the search. - SolutionCollector * - MakeAllSolutionCollector(const Assignment *const assignment); + SolutionCollector *MakeAllSolutionCollector( + const Assignment *const assignment); /// Collect all solutions of the search. The variables will need to /// be added later. SolutionCollector *MakeAllSolutionCollector(); @@ -2196,12 +2183,11 @@ public: int64 step, const std::vector &vars, double penalty_factor); - SearchMonitor * - MakeGuidedLocalSearch(bool maximize, IntVar *const objective, - IndexEvaluator3 objective_function, int64 step, - const std::vector &vars, - const std::vector &secondary_vars, - double penalty_factor); + SearchMonitor *MakeGuidedLocalSearch( + bool maximize, IntVar *const objective, + IndexEvaluator3 objective_function, int64 step, + const std::vector &vars, + const std::vector &secondary_vars, double penalty_factor); /// This search monitor will restart the search periodically. /// At the iteration n, it will restart after scale_factor * Luby(n) failures @@ -2344,11 +2330,11 @@ public: /// Compute the number of constraints a variable is attached to. ModelVisitor *MakeVariableDegreeVisitor( absl::flat_hash_map *const map); -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// Symmetry Breaking. - SearchMonitor * - MakeSymmetryManager(const std::vector &visitors); + SearchMonitor *MakeSymmetryManager( + const std::vector &visitors); SearchMonitor *MakeSymmetryManager(SymmetryBreaker *const v1); SearchMonitor *MakeSymmetryManager(SymmetryBreaker *const v1, SymmetryBreaker *const v2); @@ -2516,10 +2502,9 @@ public: /// Returns a decision builder for which the left-most leaf corresponds /// to assignment, the rest of the tree being explored using 'db'. - DecisionBuilder * - MakeDecisionBuilderFromAssignment(Assignment *const assignment, - DecisionBuilder *const db, - const std::vector &vars); + DecisionBuilder *MakeDecisionBuilderFromAssignment( + Assignment *const assignment, DecisionBuilder *const db, + const std::vector &vars); /// Returns a decision builder that will add the given constraint to /// the model. @@ -2576,10 +2561,9 @@ public: SearchMonitor *const monitor2, SearchMonitor *const monitor3, SearchMonitor *const monitor4); - DecisionBuilder * - MakeNestedOptimize(DecisionBuilder *const db, Assignment *const solution, - bool maximize, int64 step, - const std::vector &monitors); + DecisionBuilder *MakeNestedOptimize( + DecisionBuilder *const db, Assignment *const solution, bool maximize, + int64 step, const std::vector &monitors); /// Returns a DecisionBuilder which restores an Assignment /// (calls void Assignment::Restore()) @@ -2631,9 +2615,9 @@ public: /// vectors should be of the same length. This operator generates neighbors in /// which the only difference compared to the current state is that one /// variable that belongs to the given vector is set to its target value. - LocalSearchOperator * - MakeMoveTowardTargetOperator(const std::vector &variables, - const std::vector &target_values); + LocalSearchOperator *MakeMoveTowardTargetOperator( + const std::vector &variables, + const std::vector &target_values); /// Creates a local search operator which concatenates a vector of operators. /// Each operator from the vector is called sequentially. By default, when a @@ -2665,25 +2649,23 @@ public: /// operator order in the vector). This would result in the following order: /// operators[3], operators[0], operators[2], operators[1]. /// - LocalSearchOperator * - ConcatenateOperators(const std::vector &ops); - LocalSearchOperator * - ConcatenateOperators(const std::vector &ops, - bool restart); - LocalSearchOperator * - ConcatenateOperators(const std::vector &ops, - std::function evaluator); + LocalSearchOperator *ConcatenateOperators( + const std::vector &ops); + LocalSearchOperator *ConcatenateOperators( + const std::vector &ops, bool restart); + LocalSearchOperator *ConcatenateOperators( + const std::vector &ops, + std::function evaluator); /// Randomized version of local search concatenator; calls a random operator /// at each call to MakeNextNeighbor(). - LocalSearchOperator * - RandomConcatenateOperators(const std::vector &ops); + LocalSearchOperator *RandomConcatenateOperators( + const std::vector &ops); /// Randomized version of local search concatenator; calls a random operator /// at each call to MakeNextNeighbor(). The provided seed is used to /// initialize the random number generator. - LocalSearchOperator * - RandomConcatenateOperators(const std::vector &ops, - int32 seed); + LocalSearchOperator *RandomConcatenateOperators( + const std::vector &ops, int32 seed); /// Creates a local search operator which concatenates a vector of operators. /// Each operator from the vector is called sequentially. When a neighbor is @@ -2730,22 +2712,21 @@ public: // TODO(user): Make a variant which runs a local search after each // solution found in a DFS. - DecisionBuilder * - MakeLocalSearchPhase(Assignment *const assignment, - LocalSearchPhaseParameters *const parameters); - DecisionBuilder * - MakeLocalSearchPhase(const std::vector &vars, - DecisionBuilder *const first_solution, - LocalSearchPhaseParameters *const parameters); + DecisionBuilder *MakeLocalSearchPhase( + Assignment *const assignment, + LocalSearchPhaseParameters *const parameters); + DecisionBuilder *MakeLocalSearchPhase( + const std::vector &vars, DecisionBuilder *const first_solution, + LocalSearchPhaseParameters *const parameters); /// Variant with a sub_decison_builder specific to the first solution. DecisionBuilder *MakeLocalSearchPhase( const std::vector &vars, DecisionBuilder *const first_solution, DecisionBuilder *const first_solution_sub_decision_builder, LocalSearchPhaseParameters *const parameters); - DecisionBuilder * - MakeLocalSearchPhase(const std::vector &vars, - DecisionBuilder *const first_solution, - LocalSearchPhaseParameters *const parameters); + DecisionBuilder *MakeLocalSearchPhase( + const std::vector &vars, + DecisionBuilder *const first_solution, + LocalSearchPhaseParameters *const parameters); /// Solution Pool. SolutionPool *MakeDefaultSolutionPool(); @@ -2780,15 +2761,13 @@ public: LocalSearchFilter *MakeAcceptFilter(); LocalSearchFilter *MakeRejectFilter(); LocalSearchFilter *MakeVariableDomainFilter(); - IntVarLocalSearchFilter * - MakeSumObjectiveFilter(const std::vector &vars, - IndexEvaluator2 values, - Solver::LocalSearchFilterBound filter_enum); - IntVarLocalSearchFilter * - MakeSumObjectiveFilter(const std::vector &vars, - const std::vector &secondary_vars, - IndexEvaluator3 values, - Solver::LocalSearchFilterBound filter_enum); + IntVarLocalSearchFilter *MakeSumObjectiveFilter( + const std::vector &vars, IndexEvaluator2 values, + Solver::LocalSearchFilterBound filter_enum); + IntVarLocalSearchFilter *MakeSumObjectiveFilter( + const std::vector &vars, + const std::vector &secondary_vars, IndexEvaluator3 values, + Solver::LocalSearchFilterBound filter_enum); /// Performs PeriodicCheck on the top-level search; for instance, can be /// called from a nested solve to check top-level limits. @@ -2823,7 +2802,8 @@ public: DecisionBuilder *MakeApplyBranchSelector(BranchSelector bs); /// All-in-one SaveAndSetValue. - template void SaveAndSetValue(T *adr, T val) { + template + void SaveAndSetValue(T *adr, T val) { if (*adr != val) { InternalSaveValue(adr); *adr = val; @@ -2831,7 +2811,8 @@ public: } /// All-in-one SaveAndAdd_value. - template void SaveAndAdd(T *adr, T val) { + template + void SaveAndAdd(T *adr, T val) { if (val != 0) { InternalSaveValue(adr); (*adr) += val; @@ -2867,7 +2848,7 @@ public: ConstraintSolverStatistics GetConstraintSolverStatistics() const; /// Returns detailed local search statistics. LocalSearchStatistics GetLocalSearchStatistics() const; -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// Returns true whether the current search has been /// created using a Solve() call instead of a NewSearch one. It @@ -2888,7 +2869,7 @@ public: void set_fail_intercept(std::function fail_intercept) { fail_intercept_ = std::move(fail_intercept); } -#endif // !defined(SWIG) +#endif // !defined(SWIG) void clear_fail_intercept() { fail_intercept_ = nullptr; } /// Access to demon profiler. DemonProfiler *demon_profiler() const { return demon_profiler_; } @@ -2967,8 +2948,10 @@ public: #if !defined(SWIG) friend void InternalSaveBooleanVarValue(Solver *const, IntVar *const); - template friend class SimpleRevFIFO; - template friend class RevImmutableMultiMap; + template + friend class SimpleRevFIFO; + template + friend class RevImmutableMultiMap; /// Returns true if expr represents either boolean_var or 1 - /// boolean_var. In that case, it fills inner_var and is_negated to be @@ -2982,7 +2965,7 @@ public: /// these, and returns true. In the other case, it fills inner_expr /// with expr, coefficient with 1, and returns false. bool IsProduct(IntExpr *const expr, IntExpr **inner_expr, int64 *coefficient); -#endif /// !defined(SWIG) +#endif /// !defined(SWIG) /// Internal. If the variables is the result of expr->Var(), this /// method returns expr, nullptr otherwise. @@ -2996,14 +2979,13 @@ public: /// to externally cause the Solver to fail. void ShouldFail() { should_fail_ = true; } void CheckFail() { - if (!should_fail_) - return; + if (!should_fail_) return; should_fail_ = false; Fail(); } -private: - void Init(); /// Initialization. To be called by the constructors only. + private: + void Init(); /// Initialization. To be called by the constructors only. void PushState(MarkerType t, const StateInfo &info); MarkerType PopState(StateInfo *info); void PushSentinel(int magic_code); @@ -3048,12 +3030,14 @@ private: /// UnsafeRevAlloc is used internally for cells in SimpleRevFIFO /// and other structures like this. void *UnsafeRevAllocAux(void *ptr); - template T *UnsafeRevAlloc(T *ptr) { + template + T *UnsafeRevAlloc(T *ptr) { return reinterpret_cast( UnsafeRevAllocAux(reinterpret_cast(ptr))); } void **UnsafeRevAllocArrayAux(void **ptr); - template T **UnsafeRevAllocArray(T **ptr) { + template + T **UnsafeRevAllocArray(T **ptr) { return reinterpret_cast( UnsafeRevAllocArrayAux(reinterpret_cast(ptr))); } @@ -3125,10 +3109,7 @@ private: std::unique_ptr local_search_state_; /// interval of constants cached, inclusive: - enum { - MIN_CACHED_INT_CONST = -8, - MAX_CACHED_INT_CONST = 8 - }; + enum { MIN_CACHED_INT_CONST = -8, MAX_CACHED_INT_CONST = 8 }; IntVar *cached_constants_[MAX_CACHED_INT_CONST + 1 - MIN_CACHED_INT_CONST]; /// Cached constraints. @@ -3150,7 +3131,7 @@ private: DISALLOW_COPY_AND_ASSIGN(Solver); }; -std::ostream &operator<<(std::ostream &out, const Solver *const s); /// NOLINT +std::ostream &operator<<(std::ostream &out, const Solver *const s); /// NOLINT /// This method returns 0. It is useful when 0 can be cast either as /// a pointer or as an integer value and thus lead to an ambiguous @@ -3164,22 +3145,22 @@ inline int64 One() { return 1; } /// A DebugString method and the associated << operator are implemented /// as a convenience. class BaseObject { -public: + public: BaseObject() {} virtual ~BaseObject() {} virtual std::string DebugString() const { return "BaseObject"; } -private: + private: DISALLOW_COPY_AND_ASSIGN(BaseObject); }; -std::ostream &operator<<(std::ostream &out, const BaseObject *o); /// NOLINT +std::ostream &operator<<(std::ostream &out, const BaseObject *o); /// NOLINT /// The PropagationBaseObject is a subclass of BaseObject that is also /// friend to the Solver class. It allows accessing methods useful when /// writing new constraints or new expressions. class PropagationBaseObject : public BaseObject { -public: + public: explicit PropagationBaseObject(Solver *const s) : solver_(s) {} ~PropagationBaseObject() override {} @@ -3214,7 +3195,7 @@ public: void set_action_on_fail(Solver::Action a) { solver_->set_action_on_fail(std::move(a)); } -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// This method clears the failure callback. void reset_action_on_fail() { solver_->reset_action_on_fail(); } @@ -3232,7 +3213,7 @@ public: /// Returns a base name for automatic naming. virtual std::string BaseName() const; -private: + private: Solver *const solver_; DISALLOW_COPY_AND_ASSIGN(PropagationBaseObject); }; @@ -3240,7 +3221,7 @@ private: /// A Decision represents a choice point in the search tree. The two main /// methods are Apply() to go left, or Refute() to go right. class Decision : public BaseObject { -public: + public: Decision() {} ~Decision() override {} @@ -3254,14 +3235,14 @@ public: /// Accepts the given visitor. virtual void Accept(DecisionVisitor *const visitor) const; -private: + private: DISALLOW_COPY_AND_ASSIGN(Decision); }; /// A DecisionVisitor is used to inspect a decision. /// It contains virtual methods for all type of 'declared' decisions. class DecisionVisitor : public BaseObject { -public: + public: DecisionVisitor() {} ~DecisionVisitor() override {} virtual void VisitSetVariableValue(IntVar *const var, int64 value); @@ -3273,14 +3254,14 @@ public: virtual void VisitRankLastInterval(SequenceVar *const sequence, int index); virtual void VisitUnknownDecision(); -private: + private: DISALLOW_COPY_AND_ASSIGN(DecisionVisitor); }; /// A DecisionBuilder is responsible for creating the search tree. The /// important method is Next(), which returns the next decision to execute. class DecisionBuilder : public BaseObject { -public: + public: DecisionBuilder() {} ~DecisionBuilder() override {} /// This is the main method of the decision builder class. It must @@ -3299,7 +3280,7 @@ public: virtual void Accept(ModelVisitor *const visitor) const; #endif -private: + private: DISALLOW_COPY_AND_ASSIGN(DecisionBuilder); }; @@ -3313,7 +3294,7 @@ private: /// - priority() returns its priority. Standard priorities are slow, normal /// or fast. "immediate" is reserved for variables and is treated separately. class Demon : public BaseObject { -public: + public: /// This indicates the priority of a demon. Immediate demons are treated /// separately and corresponds to variables. Demon() : stamp_(GG_ULONGLONG(0)) {} @@ -3336,7 +3317,7 @@ public: /// This method un-inhibits the demon that was previously inhibited. void desinhibit(Solver *const s); -private: + private: friend class Queue; void set_stamp(int64 stamp) { stamp_ = stamp; } uint64 stamp() const { return stamp_; } @@ -3346,7 +3327,7 @@ private: /// Model visitor. class ModelVisitor : public BaseObject { -public: + public: /// Constraint and Expression types. static const char kAbs[]; static const char kAbsEqual[]; @@ -3557,24 +3538,21 @@ public: virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument); - virtual void - VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments); + virtual void VisitIntegerVariableArrayArgument( + const std::string &arg_name, const std::vector &arguments); /// Visit interval argument. virtual void VisitIntervalArgument(const std::string &arg_name, IntervalVar *const argument); - virtual void - VisitIntervalArrayArgument(const std::string &arg_name, - const std::vector &arguments); + virtual void VisitIntervalArrayArgument( + const std::string &arg_name, const std::vector &arguments); /// Visit sequence argument. virtual void VisitSequenceArgument(const std::string &arg_name, SequenceVar *const argument); - virtual void - VisitSequenceArrayArgument(const std::string &arg_name, - const std::vector &arguments); + virtual void VisitSequenceArrayArgument( + const std::string &arg_name, const std::vector &arguments); #if !defined(SWIG) /// Helpers. virtual void VisitIntegerVariableEvaluatorArgument( @@ -3589,7 +3567,7 @@ public: /// Expands function as array when index min is 0. void VisitInt64ToInt64AsArray(const Solver::IndexEvaluator1 &eval, const std::string &arg_name, int64 index_max); -#endif // #if !defined(SWIG) +#endif // #if !defined(SWIG) }; /// A constraint is the main modeling object. It provides two methods: @@ -3599,7 +3577,7 @@ public: /// the initial propagation. The subsequent propagations will be performed /// by the demons Posted during the post() method. class Constraint : public PropagationBaseObject { -public: + public: explicit Constraint(Solver *const solver) : PropagationBaseObject(solver) {} ~Constraint() override {} @@ -3627,7 +3605,7 @@ public: /// returns nullptr if the constraint does not support this API. virtual IntVar *Var(); -private: + private: DISALLOW_COPY_AND_ASSIGN(Constraint); }; @@ -3635,7 +3613,7 @@ private: /// to keep a variable in sync with an expression. They are /// created internally when Var() is called on a subclass of IntExpr. class CastConstraint : public Constraint { -public: + public: CastConstraint(Solver *const solver, IntVar *const target_var) : Constraint(solver), target_var_(target_var) { CHECK(target_var != nullptr); @@ -3644,13 +3622,13 @@ public: IntVar *target_var() const { return target_var_; } -protected: + protected: IntVar *const target_var_; }; /// A search monitor is a simple set of callbacks to monitor all search events class SearchMonitor : public BaseObject { -public: + public: static constexpr int kNoProgress = -1; explicit SearchMonitor(Solver *const s) : solver_(s) {} @@ -3738,7 +3716,7 @@ public: /// and propagation events. virtual void Install(); -private: + private: Solver *const solver_; DISALLOW_COPY_AND_ASSIGN(SearchMonitor); }; @@ -3748,8 +3726,9 @@ private: /// only once per node of the search tree. Please note that actual /// stamps always starts at 1, thus an initial value of 0 will always /// trigger the first SaveValue. -template class Rev { -public: +template +class Rev { + public: explicit Rev(const T &val) : stamp_(0), value_(val) {} const T &Value() const { return value_; } @@ -3764,14 +3743,15 @@ public: } } -private: + private: uint64 stamp_; T value_; }; /// Subclass of Rev which adds numerical operations. -template class NumericalRev : public Rev { -public: +template +class NumericalRev : public Rev { + public: explicit NumericalRev(const T &val) : Rev(val) {} void Add(Solver *const s, const T &to_add) { @@ -3788,8 +3768,9 @@ public: /// once per node of the search tree. /// Please note that actual stamp always starts at 1, thus an initial value of /// 0 always triggers the first SaveValue. -template class RevArray { -public: +template +class RevArray { + public: RevArray(int size, const T &val) : stamps_(new uint64[size]), values_(new T[size]), size_(size) { for (int i = 0; i < size; ++i) { @@ -3819,15 +3800,16 @@ public: } } -private: + private: std::unique_ptr stamps_; std::unique_ptr values_; const int size_; }; /// Subclass of RevArray which adds numerical operations. -template class NumericalRevArray : public RevArray { -public: +template +class NumericalRevArray : public RevArray { + public: NumericalRevArray(int size, const T &val) : RevArray(size, val) {} void Add(Solver *const s, int index, const T &to_add) { @@ -3847,7 +3829,7 @@ public: /// - listening to events modifying its bounds /// - casting it into a variable (instance of IntVar) class IntExpr : public PropagationBaseObject { -public: + public: explicit IntExpr(Solver *const s) : PropagationBaseObject(s) {} ~IntExpr() override {} @@ -3898,12 +3880,12 @@ public: void WhenRange(Solver::Action action) { WhenRange(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// Accepts the given visitor. virtual void Accept(ModelVisitor *const visitor) const; -private: + private: DISALLOW_COPY_AND_ASSIGN(IntExpr); }; @@ -3925,7 +3907,7 @@ private: /// } class IntVarIterator : public BaseObject { -public: + public: ~IntVarIterator() override {} /// This method must be called before each loop. @@ -3952,7 +3934,7 @@ public: /// same iterator instance isn't being iterated on in multiple places /// simultaneously. class InitAndGetValues { -public: + public: explicit InitAndGetValues(IntVarIterator *it) : it_(it), begin_was_called_(false) { it_->Init(); @@ -3970,10 +3952,10 @@ public: struct Iterator { /// These are the only way to construct an Iterator. static Iterator Begin(IntVarIterator *it) { - return Iterator(it, /*is_end=*/ false); + return Iterator(it, /*is_end=*/false); } static Iterator End(IntVarIterator *it) { - return Iterator(it, /*is_end=*/ true); + return Iterator(it, /*is_end=*/true); } int64 operator*() const { @@ -3991,24 +3973,24 @@ public: return it_->Ok(); } - private: + private: Iterator(IntVarIterator *it, bool is_end) : it_(it), is_end_(is_end) {} IntVarIterator *const it_; const bool is_end_; }; -private: + private: IntVarIterator *const it_; bool begin_was_called_; }; -#endif // SWIG +#endif // SWIG /// The class IntVar is a subset of IntExpr. In addition to the /// IntExpr protocol, it offers persistence, removing values from the domains, /// and a finer model for events. class IntVar : public IntExpr { -public: + public: explicit IntVar(Solver *const s); IntVar(Solver *const s, const std::string &name); ~IntVar() override {} @@ -4048,7 +4030,7 @@ public: void WhenBound(Solver::Action action) { WhenBound(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// This method attaches a demon that will watch any domain /// modification of the domain of the variable. @@ -4064,7 +4046,7 @@ public: void WhenDomain(Solver::Action action) { WhenDomain(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// This method returns the number of values in the domain of the variable. virtual uint64 Size() const = 0; @@ -4103,7 +4085,7 @@ public: /// Returns the index of the variable. int index() const { return index_; } -private: + private: const int index_; DISALLOW_COPY_AND_ASSIGN(IntVar); }; @@ -4112,7 +4094,7 @@ private: /// It implements a basic query API to be used independently /// of the collector used. class SolutionCollector : public SearchMonitor { -public: + public: SolutionCollector(Solver *const solver, const Assignment *assignment); explicit SolutionCollector(Solver *const solver); ~SolutionCollector() override; @@ -4176,7 +4158,7 @@ public: /// nth solution. const std::vector &Unperformed(int n, SequenceVar *const var) const; -protected: + protected: struct SolutionData { Assignment *solution; int64 time; @@ -4203,7 +4185,7 @@ protected: std::vector solution_data_; std::vector recycle_solutions_; -private: + private: DISALLOW_COPY_AND_ASSIGN(SolutionCollector); }; @@ -4215,7 +4197,7 @@ private: /// (minimize or maximize), the variable to optimize, and the /// improvement step. class OptimizeVar : public SearchMonitor { -public: + public: OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64 step); ~OptimizeVar() override; @@ -4237,20 +4219,20 @@ public: void ApplyBound(); -protected: + protected: IntVar *const var_; int64 step_; int64 best_; bool maximize_; bool found_initial_solution_; -private: + private: DISALLOW_COPY_AND_ASSIGN(OptimizeVar); }; /// Base class of all search limits. class SearchLimit : public SearchMonitor { -public: + public: explicit SearchLimit(Solver *const s) : SearchMonitor(s), crossed_(false) {} ~SearchLimit() override; @@ -4282,7 +4264,7 @@ public: return absl::StrFormat("SearchLimit(crossed = %i)", crossed_); } -private: + private: void TopPeriodicCheck(); bool crossed_; @@ -4292,7 +4274,7 @@ private: /// Usual limit based on wall_time, number of explored branches and /// number of failures in the search tree class RegularLimit : public SearchLimit { -public: + public: RegularLimit(Solver *const s, absl::Duration time, int64 branches, int64 failures, int64 solutions, bool smart_time_check, bool cumulative); @@ -4324,7 +4306,7 @@ public: void Accept(ModelVisitor *const visitor) const override; -private: + private: bool CheckTime(); absl::Duration TimeElapsed(); static int64 GetPercent(int64 value, int64 offset, int64 total) { @@ -4364,7 +4346,7 @@ private: // limit stops the search when the improvement rate of the objective gets below // this threshold value. class ImprovementSearchLimit : public SearchLimit { -public: + public: ImprovementSearchLimit(Solver *const s, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, @@ -4377,7 +4359,7 @@ public: bool AtSolution() override; void Init() override; -private: + private: IntVar *objective_var_; bool maximize_; double objective_scaling_factor_; @@ -4405,7 +4387,7 @@ private: /// as unperformed when it is not consistent anymore (start greater /// than end, duration < 0...) class IntervalVar : public PropagationBaseObject { -public: + public: /// The smallest acceptable value to be returned by StartMin() static const int64 kMinValidValue; /// The largest acceptable value to be returned by EndMax() @@ -4433,7 +4415,7 @@ public: void WhenStartRange(Solver::Action action) { WhenStartRange(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG virtual void WhenStartBound(Demon *const d) = 0; void WhenStartBound(Solver::Closure closure) { WhenStartBound(solver()->MakeClosureDemon(std::move(closure))); @@ -4442,7 +4424,7 @@ public: void WhenStartBound(Solver::Action action) { WhenStartBound(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// These methods query, set, and watch the duration of the interval var. virtual int64 DurationMin() const = 0; @@ -4460,7 +4442,7 @@ public: void WhenDurationRange(Solver::Action action) { WhenDurationRange(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG virtual void WhenDurationBound(Demon *const d) = 0; void WhenDurationBound(Solver::Closure closure) { WhenDurationBound(solver()->MakeClosureDemon(std::move(closure))); @@ -4469,7 +4451,7 @@ public: void WhenDurationBound(Solver::Action action) { WhenDurationBound(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// These methods query, set, and watch the end position of the interval var. virtual int64 EndMin() const = 0; @@ -4487,7 +4469,7 @@ public: void WhenEndRange(Solver::Action action) { WhenEndRange(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG virtual void WhenEndBound(Demon *const d) = 0; void WhenEndBound(Solver::Closure closure) { WhenEndBound(solver()->MakeClosureDemon(std::move(closure))); @@ -4496,7 +4478,7 @@ public: void WhenEndBound(Solver::Action action) { WhenEndBound(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// These methods query, set, and watch the performed status of the /// interval var. @@ -4516,7 +4498,7 @@ public: void WhenPerformedBound(Solver::Action action) { WhenPerformedBound(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// Attaches a demon awakened when anything about this interval changes. void WhenAnything(Demon *const d); @@ -4529,7 +4511,7 @@ public: void WhenAnything(Solver::Action action) { WhenAnything(solver()->MakeActionDemon(std::move(action))); } -#endif // SWIG +#endif // SWIG /// These methods create expressions encapsulating the start, end /// and duration of the interval var. Please note that these must not @@ -4548,7 +4530,7 @@ public: /// Accepts the given visitor. virtual void Accept(ModelVisitor *const visitor) const = 0; -private: + private: DISALLOW_COPY_AND_ASSIGN(IntervalVar); }; @@ -4559,7 +4541,7 @@ private: /// last; and RankFirst/RankNotFirst/RankLast/RankNotLast, which can be /// used to create the search decision. class SequenceVar : public PropagationBaseObject { -public: + public: SequenceVar(Solver *const s, const std::vector &intervals, const std::vector &nexts, const std::string &name); @@ -4583,7 +4565,7 @@ public: /// Compute statistics on the sequence. void ComputeStatistics(int *const ranked, int *const not_ranked, int *const unperformed) const; -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// Ranks the index_th interval var first of all unranked interval /// vars. After that, it will no longer be considered ranked. @@ -4639,7 +4621,7 @@ public: /// Accepts the given visitor. virtual void Accept(ModelVisitor *const visitor) const; -private: + private: int ComputeForwardFrontier(); int ComputeBackwardFrontier(); void UpdatePrevious() const; @@ -4650,19 +4632,19 @@ private: }; class AssignmentElement { -public: + public: AssignmentElement() : activated_(true) {} void Activate() { activated_ = true; } void Deactivate() { activated_ = false; } bool Activated() const { return activated_; } -private: + private: bool activated_; }; class IntVarElement : public AssignmentElement { -public: + public: IntVarElement(); explicit IntVarElement(IntVar *const var); void Reset(IntVar *const var); @@ -4706,14 +4688,14 @@ public: return !(*this == element); } -private: + private: IntVar *var_; int64 min_; int64 max_; }; class IntervalVarElement : public AssignmentElement { -public: + public: IntervalVarElement(); explicit IntervalVarElement(IntervalVar *const var); void Reset(IntervalVar *const var); @@ -4722,8 +4704,8 @@ public: IntervalVar *Var() const { return var_; } void Store(); void Restore(); - void - LoadFromProto(const IntervalVarAssignment &interval_var_assignment_proto); + void LoadFromProto( + const IntervalVarAssignment &interval_var_assignment_proto); void WriteToProto(IntervalVarAssignment *interval_var_assignment_proto) const; int64 StartMin() const { return start_min_; } @@ -4800,7 +4782,7 @@ public: return !(*this == element); } -private: + private: int64 start_min_; int64 start_max_; int64 duration_min_; @@ -4826,7 +4808,7 @@ private: /// convention, the forward_sequence will contain all such variables /// and the backward_sequence will be empty. class SequenceVarElement : public AssignmentElement { -public: + public: SequenceVarElement(); explicit SequenceVarElement(SequenceVar *const var); void Reset(SequenceVar *const var); @@ -4835,8 +4817,8 @@ public: SequenceVar *Var() const { return var_; } void Store(); void Restore(); - void - LoadFromProto(const SequenceVarAssignment &sequence_var_assignment_proto); + void LoadFromProto( + const SequenceVarAssignment &sequence_var_assignment_proto); void WriteToProto(SequenceVarAssignment *sequence_var_assignment_proto) const; const std::vector &ForwardSequence() const; @@ -4859,7 +4841,7 @@ public: return !(*this == element); } -private: + private: bool CheckClassInvariants(); SequenceVar *var_; @@ -4868,8 +4850,9 @@ private: std::vector unperformed_; }; -template class AssignmentContainer { -public: +template +class AssignmentContainer { + public: AssignmentContainer() {} E *Add(V *var) { CHECK(var != nullptr); @@ -4894,7 +4877,7 @@ public: } void Clear() { elements_.clear(); - if (!elements_map_.empty()) { /// 2x speedup on OR-tools. + if (!elements_map_.empty()) { /// 2x speedup on OR-tools. elements_map_.clear(); } } @@ -4939,8 +4922,8 @@ public: } E *MutableElement(const V *const var) { E *const element = MutableElementOrNull(var); - DCHECK(element != nullptr) << "Unknown variable " << var->DebugString() - << " in solution"; + DCHECK(element != nullptr) + << "Unknown variable " << var->DebugString() << " in solution"; return element; } E *MutableElementOrNull(const V *const var) { @@ -4952,8 +4935,8 @@ public: } const E &Element(const V *const var) const { const E *const element = ElementPtrOrNull(var); - DCHECK(element != nullptr) << "Unknown variable " << var->DebugString() - << " in solution"; + DCHECK(element != nullptr) + << "Unknown variable " << var->DebugString() << " in solution"; return *element; } const E *ElementPtrOrNull(const V *const var) const { @@ -4981,8 +4964,7 @@ public: } bool AreAllElementsBound() const { for (const E &element : elements_) { - if (!element.Bound()) - return false; + if (!element.Bound()) return false; } return true; } @@ -5013,7 +4995,7 @@ public: return !(*this == container); } -private: + private: void EnsureMapIsUpToDate() const { absl::flat_hash_map *map = const_cast *>(&elements_map_); @@ -5049,7 +5031,7 @@ private: /// An Assignment is a variable -> domains mapping, used /// to report solutions to the user. class Assignment : public PropagationBaseObject { -public: + public: typedef AssignmentContainer IntContainer; typedef AssignmentContainer IntervalContainer; @@ -5079,13 +5061,13 @@ public: bool Load(const std::string &filename); #if !defined(SWIG) bool Load(File *file); -#endif /// #if !defined(SWIG) +#endif /// #if !defined(SWIG) void Load(const AssignmentProto &assignment_proto); /// Saves the assignment to a file. bool Save(const std::string &filename) const; #if !defined(SWIG) bool Save(File *file) const; -#endif // #if !defined(SWIG) +#endif // #if !defined(SWIG) void Save(AssignmentProto *const assignment_proto) const; void AddObjective(IntVar *const v); @@ -5223,7 +5205,7 @@ public: return !(*this == assignment); } -private: + private: IntContainer int_var_container_; IntervalContainer interval_var_container_; SequenceContainer sequence_var_container_; @@ -5232,7 +5214,7 @@ private: }; std::ostream &operator<<(std::ostream &out, - const Assignment &assignment); /// NOLINT + const Assignment &assignment); /// NOLINT /// Given a "source_assignment", clears the "target_assignment" and adds /// all IntVars in "target_vars", with the values of the variables set according @@ -5245,7 +5227,7 @@ void SetAssignmentFromAssignment(Assignment *target_assignment, const std::vector &source_vars); class Pack : public Constraint { -public: + public: Pack(Solver *const s, const std::vector &vars, int number_of_bins); ~Pack() override; @@ -5333,7 +5315,7 @@ public: void UnassignAllRemainingItems(); void Accept(ModelVisitor *const visitor) const override; -private: + private: bool IsInProcess() const; const std::vector vars_; const int bins_; @@ -5350,7 +5332,7 @@ private: }; class DisjunctiveConstraint : public Constraint { -public: + public: DisjunctiveConstraint(Solver *const s, const std::vector &intervals, const std::string &name); @@ -5375,20 +5357,20 @@ public: virtual const std::vector &actives() const = 0; virtual const std::vector &time_cumuls() const = 0; virtual const std::vector &time_slacks() const = 0; -#endif // !defined(SWIG) +#endif // !defined(SWIG) -protected: + protected: const std::vector intervals_; Solver::IndexEvaluator2 transition_time_; -private: + private: DISALLOW_COPY_AND_ASSIGN(DisjunctiveConstraint); }; /// This class is used to manage a pool of solutions. It can transform /// a single point local search into a multipoint local search. class SolutionPool : public BaseObject { -public: + public: SolutionPool() {} ~SolutionPool() override {} @@ -5408,6 +5390,6 @@ public: /// an external one. virtual bool SyncNeeded(Assignment *const local_assignment) = 0; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVER_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVER_H_ diff --git a/ortools/constraint_solver/constraint_solveri.h b/ortools/constraint_solver/constraint_solveri.h index ec4f6b2fbc..53f3811bd0 100644 --- a/ortools/constraint_solver/constraint_solveri.h +++ b/ortools/constraint_solver/constraint_solveri.h @@ -107,14 +107,14 @@ class CPIntervalVariableProto; /// This is a consequence of the stateless nature of the expressions that /// makes the code error-prone. class BaseIntExpr : public IntExpr { -public: + public: explicit BaseIntExpr(Solver *const s) : IntExpr(s), var_(nullptr) {} ~BaseIntExpr() override {} IntVar *Var() override; virtual IntVar *CastToVar(); -private: + private: IntVar *var_; }; @@ -141,21 +141,20 @@ enum VarTypes { /// It's main use is to store a list of demons in the various classes of /// variables. #ifndef SWIG -template class SimpleRevFIFO { -private: - enum { - CHUNK_SIZE = 16 - }; // TODO(user): could be an extra template param +template +class SimpleRevFIFO { + private: + enum { CHUNK_SIZE = 16 }; // TODO(user): could be an extra template param struct Chunk { T data_[CHUNK_SIZE]; const Chunk *const next_; explicit Chunk(const Chunk *next) : next_(next) {} }; -public: + public: /// This iterator is not stable with respect to deletion. class Iterator { - public: + public: explicit Iterator(const SimpleRevFIFO *l) : chunk_(l->chunks_), value_(l->Last()) {} bool ok() const { return (value_ != nullptr); } @@ -168,7 +167,7 @@ public: } } - private: + private: const Chunk *chunk_; const T *value_; }; @@ -213,7 +212,7 @@ public: chunks_->data_[pos_.Value()] = v; } -private: + private: Chunk *chunks_; NumericalRev pos_; }; @@ -221,11 +220,11 @@ private: /// Hash functions // TODO(user): use murmurhash. inline uint64 Hash1(uint64 value) { - value = (~value) + (value << 21); /// value = (value << 21) - value - 1; + value = (~value) + (value << 21); /// value = (value << 21) - value - 1; value ^= value >> 24; - value += (value << 3) + (value << 8); /// value * 265 + value += (value << 3) + (value << 8); /// value * 265 value ^= value >> 14; - value += (value << 2) + (value << 4); /// value * 21 + value += (value << 2) + (value << 4); /// value * 21 value ^= value >> 28; value += (value << 31); return value; @@ -247,7 +246,7 @@ inline uint64 Hash1(int64 value) { return Hash1(static_cast(value)); } inline uint64 Hash1(int value) { return Hash1(static_cast(value)); } inline uint64 Hash1(void *const ptr) { -#if defined(__x86_64__) || defined(_M_X64) || defined(__powerpc64__) || \ +#if defined(__x86_64__) || defined(_M_X64) || defined(__powerpc64__) || \ defined(__aarch64__) return Hash1(reinterpret_cast(ptr)); #else @@ -255,7 +254,8 @@ inline uint64 Hash1(void *const ptr) { #endif } -template uint64 Hash1(const std::vector &ptrs) { +template +uint64 Hash1(const std::vector &ptrs) { if (ptrs.empty()) { return 0; } else if (ptrs.size() == 1) { @@ -285,12 +285,14 @@ inline uint64 Hash1(const std::vector &ptrs) { /// Reversible Immutable MultiMap class. /// Represents an immutable multi-map that backtracks with the solver. -template class RevImmutableMultiMap { -public: +template +class RevImmutableMultiMap { + public: RevImmutableMultiMap(Solver *const solver, int initial_size) : solver_(solver), array_(solver->UnsafeRevAllocArray(new Cell *[initial_size])), - size_(initial_size), num_items_(0) { + size_(initial_size), + num_items_(0) { memset(array_, 0, sizeof(*array_) * size_.Value()); } @@ -339,9 +341,9 @@ public: } } -private: + private: class Cell { - public: + public: Cell(const K &key, const V &value, Cell *const next) : key_(key), value_(value), next_(next) {} @@ -356,7 +358,7 @@ private: const V &value() const { return value_; } - private: + private: const K key_; const V value_; Cell *next_; @@ -393,21 +395,21 @@ private: /// A reversible switch that can switch once from false to true. class RevSwitch { -public: + public: RevSwitch() : value_(false) {} bool Switched() const { return value_; } void Switch(Solver *const solver) { solver->SaveAndSetValue(&value_, true); } -private: + private: bool value_; }; /// This class represents a small reversible bitset (size <= 64). /// This class is useful to maintain supports. class SmallRevBitSet { -public: + public: explicit SmallRevBitSet(int64 size); /// Sets the 'pos' bit. void SetToOne(Solver *const solver, int64 pos); @@ -425,14 +427,14 @@ public: /// It returns -1 if the bitset is empty. int64 GetFirstOne() const; -private: + private: Rev bits_; }; /// This class represents a reversible bitset. /// This class is useful to maintain supports. class RevBitSet { -public: + public: explicit RevBitSet(int64 size); ~RevBitSet(); @@ -456,7 +458,7 @@ public: friend class RevBitMatrix; -private: + private: /// Save the offset's part of the bitset. void Save(Solver *const solver, int offset); const int64 size_; @@ -467,7 +469,7 @@ private: /// Matrix version of the RevBitSet class. class RevBitMatrix : private RevBitSet { -public: + public: RevBitMatrix(int64 rows, int64 columns); ~RevBitMatrix(); @@ -495,7 +497,7 @@ public: /// Cleans all bits. void ClearAll(Solver *const solver); -private: + private: const int64 rows_; const int64 columns_; }; @@ -507,9 +509,10 @@ private: /// and demons are just proxies with a priority of NORMAL_PRIORITY. /// Demon proxy to a method on the constraint with no arguments. -template class CallMethod0 : public Demon { -public: - CallMethod0(T *const ct, void(T::*method)(), const std::string &name) +template +class CallMethod0 : public Demon { + public: + CallMethod0(T *const ct, void (T::*method)(), const std::string &name) : constraint_(ct), method_(method), name_(name) {} ~CallMethod0() override {} @@ -520,31 +523,34 @@ public: return "CallMethod_" + name_ + "(" + constraint_->DebugString() + ")"; } -private: + private: T *const constraint_; - void(T::*const method_)(); + void (T::*const method_)(); const std::string name_; }; template -Demon *MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), +Demon *MakeConstraintDemon0(Solver *const s, T *const ct, void (T::*method)(), const std::string &name) { return s->RevAlloc(new CallMethod0(ct, method, name)); } -template std::string ParameterDebugString(P param) { +template +std::string ParameterDebugString(P param) { return absl::StrCat(param); } /// Support limited to pointers to classes which define DebugString(). -template std::string ParameterDebugString(P *param) { +template +std::string ParameterDebugString(P *param) { return param->DebugString(); } /// Demon proxy to a method on the constraint with one argument. -template class CallMethod1 : public Demon { -public: - CallMethod1(T *const ct, void(T::*method)(P), const std::string &name, +template +class CallMethod1 : public Demon { + public: + CallMethod1(T *const ct, void (T::*method)(P), const std::string &name, P param1) : constraint_(ct), method_(method), name_(name), param1_(param1) {} @@ -557,25 +563,29 @@ public: ", ", ParameterDebugString(param1_), ")"); } -private: + private: T *const constraint_; - void(T::*const method_)(P); + void (T::*const method_)(P); const std::string name_; P param1_; }; template -Demon *MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), +Demon *MakeConstraintDemon1(Solver *const s, T *const ct, void (T::*method)(P), const std::string &name, P param1) { return s->RevAlloc(new CallMethod1(ct, method, name, param1)); } /// Demon proxy to a method on the constraint with two arguments. -template class CallMethod2 : public Demon { -public: - CallMethod2(T *const ct, void(T::*method)(P, Q), const std::string &name, +template +class CallMethod2 : public Demon { + public: + CallMethod2(T *const ct, void (T::*method)(P, Q), const std::string &name, P param1, Q param2) - : constraint_(ct), method_(method), name_(name), param1_(param1), + : constraint_(ct), + method_(method), + name_(name), + param1_(param1), param2_(param2) {} ~CallMethod2() override {} @@ -591,9 +601,9 @@ public: absl::StrCat(", ", ParameterDebugString(param2_), ")")); } -private: + private: T *const constraint_; - void(T::*const method_)(P, Q); + void (T::*const method_)(P, Q); const std::string name_; P param1_; Q param2_; @@ -601,18 +611,23 @@ private: template Demon *MakeConstraintDemon2(Solver *const s, T *const ct, - void(T::*method)(P, Q), const std::string &name, + void (T::*method)(P, Q), const std::string &name, P param1, Q param2) { return s->RevAlloc( new CallMethod2(ct, method, name, param1, param2)); } /// Demon proxy to a method on the constraint with three arguments. -template class CallMethod3 : public Demon { -public: - CallMethod3(T *const ct, void(T::*method)(P, Q, R), const std::string &name, +template +class CallMethod3 : public Demon { + public: + CallMethod3(T *const ct, void (T::*method)(P, Q, R), const std::string &name, P param1, Q param2, R param3) - : constraint_(ct), method_(method), name_(name), param1_(param1), - param2_(param2), param3_(param3) {} + : constraint_(ct), + method_(method), + name_(name), + param1_(param1), + param2_(param2), + param3_(param3) {} ~CallMethod3() override {} @@ -628,9 +643,9 @@ public: absl::StrCat(", ", ParameterDebugString(param3_), ")")); } -private: + private: T *const constraint_; - void(T::*const method_)(P, Q, R); + void (T::*const method_)(P, Q, R); const std::string name_; P param1_; Q param2_; @@ -639,7 +654,7 @@ private: template Demon *MakeConstraintDemon3(Solver *const s, T *const ct, - void(T::*method)(P, Q, R), const std::string &name, + void (T::*method)(P, Q, R), const std::string &name, P param1, Q param2, R param3) { return s->RevAlloc( new CallMethod3(ct, method, name, param1, param2, param3)); @@ -652,9 +667,10 @@ Demon *MakeConstraintDemon3(Solver *const s, T *const ct, /// have a priority DELAYED_PRIORITY. /// Low-priority demon proxy to a method on the constraint with no arguments. -template class DelayedCallMethod0 : public Demon { -public: - DelayedCallMethod0(T *const ct, void(T::*method)(), const std::string &name) +template +class DelayedCallMethod0 : public Demon { + public: + DelayedCallMethod0(T *const ct, void (T::*method)(), const std::string &name) : constraint_(ct), method_(method), name_(name) {} ~DelayedCallMethod0() override {} @@ -670,23 +686,24 @@ public: ")"; } -private: + private: T *const constraint_; - void(T::*const method_)(); + void (T::*const method_)(); const std::string name_; }; template Demon *MakeDelayedConstraintDemon0(Solver *const s, T *const ct, - void(T::*method)(), + void (T::*method)(), const std::string &name) { return s->RevAlloc(new DelayedCallMethod0(ct, method, name)); } /// Low-priority demon proxy to a method on the constraint with one argument. -template class DelayedCallMethod1 : public Demon { -public: - DelayedCallMethod1(T *const ct, void(T::*method)(P), const std::string &name, +template +class DelayedCallMethod1 : public Demon { + public: + DelayedCallMethod1(T *const ct, void (T::*method)(P), const std::string &name, P param1) : constraint_(ct), method_(method), name_(name), param1_(param1) {} @@ -704,26 +721,30 @@ public: ParameterDebugString(param1_), ")"); } -private: + private: T *const constraint_; - void(T::*const method_)(P); + void (T::*const method_)(P); const std::string name_; P param1_; }; template Demon *MakeDelayedConstraintDemon1(Solver *const s, T *const ct, - void(T::*method)(P), const std::string &name, - P param1) { + void (T::*method)(P), + const std::string &name, P param1) { return s->RevAlloc(new DelayedCallMethod1(ct, method, name, param1)); } /// Low-priority demon proxy to a method on the constraint with two arguments. -template class DelayedCallMethod2 : public Demon { -public: - DelayedCallMethod2(T *const ct, void(T::*method)(P, Q), +template +class DelayedCallMethod2 : public Demon { + public: + DelayedCallMethod2(T *const ct, void (T::*method)(P, Q), const std::string &name, P param1, Q param2) - : constraint_(ct), method_(method), name_(name), param1_(param1), + : constraint_(ct), + method_(method), + name_(name), + param1_(param1), param2_(param2) {} ~DelayedCallMethod2() override {} @@ -743,9 +764,9 @@ public: absl::StrCat(", ", ParameterDebugString(param2_), ")")); } -private: + private: T *const constraint_; - void(T::*const method_)(P, Q); + void (T::*const method_)(P, Q); const std::string name_; P param1_; Q param2_; @@ -753,7 +774,7 @@ private: template Demon *MakeDelayedConstraintDemon2(Solver *const s, T *const ct, - void(T::*method)(P, Q), + void (T::*method)(P, Q), const std::string &name, P param1, Q param2) { return s->RevAlloc( @@ -761,7 +782,7 @@ Demon *MakeDelayedConstraintDemon2(Solver *const s, T *const ct, } /// @} -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// The base class for all local search operators. /// @@ -783,7 +804,7 @@ Demon *MakeDelayedConstraintDemon2(Solver *const s, T *const ct, // TODO(user): rename Start to Synchronize ? // TODO(user): decouple the iterating from the defining of a neighbor. class LocalSearchOperator : public BaseObject { -public: + public: LocalSearchOperator() {} ~LocalSearchOperator() override {} virtual bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) = 0; @@ -791,7 +812,7 @@ public: virtual void Reset() {} #ifndef SWIG virtual const LocalSearchOperator *Self() const { return this; } -#endif // SWIG +#endif // SWIG virtual bool HasFragments() const { return false; } virtual bool HoldsDelta() const { return false; } }; @@ -799,10 +820,12 @@ public: /// Base operator class for operators manipulating variables. template class VarLocalSearchOperator : public LocalSearchOperator { -public: + public: VarLocalSearchOperator() : activated_(), was_activated_(), cleared_(true) {} explicit VarLocalSearchOperator(Handler var_handler) - : activated_(), was_activated_(), cleared_(true), + : activated_(), + was_activated_(), + cleared_(true), var_handler_(var_handler) {} ~VarLocalSearchOperator() override {} bool HoldsDelta() const override { return true; } @@ -873,8 +896,7 @@ public: void RevertChanges(bool incremental) { cleared_ = false; delta_changes_.SparseClearAll(); - if (incremental && IsIncremental()) - return; + if (incremental && IsIncremental()) return; cleared_ = true; for (const int64 index : changes_.PositionsSetAtLeastOnce()) { values_[index] = old_values_[index]; @@ -907,7 +929,7 @@ public: /// OnStart() should really be protected, but then SWIG doesn't see it. So we /// make it public, but only subclasses should access to it (to override it). -protected: + protected: void MarkChange(int64 index) { delta_changes_.Set(index); changes_.Set(index); @@ -930,7 +952,7 @@ protected: class IntVarLocalSearchOperator; class IntVarLocalSearchHandler { -public: + public: IntVarLocalSearchHandler() : op_(nullptr) {} IntVarLocalSearchHandler(const IntVarLocalSearchHandler &other) : op_(other.op_) {} @@ -963,7 +985,7 @@ public: void OnRevertChanges(int64 index, int64 value); void OnAddVars() {} -private: + private: IntVarLocalSearchOperator *const op_; }; @@ -998,7 +1020,7 @@ private: IntVarLocalSearchHandler>::IsIncremental; % unignore VarLocalSearchOperator::OnStart; -#endif // SWIGPYTHON +#endif // SWIGPYTHON // clang-format off % rename(IntVarLocalSearchOperatorTemplate) @@ -1006,11 +1028,11 @@ private: % template(IntVarLocalSearchOperatorTemplate) VarLocalSearchOperator; // clang-format on -#endif // SWIG +#endif // SWIG class IntVarLocalSearchOperator : public VarLocalSearchOperator { -public: + public: IntVarLocalSearchOperator() : max_inverse_value_(-1) {} // If keep_inverse_values is true, assumes that vars models an injective // function f with domain [0, vars.size()) in which case the operator will @@ -1039,7 +1061,7 @@ public: /// instead. bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override; -protected: + protected: friend class IntVarLocalSearchHandler; /// Creates a new neighbor. It returns false when the neighborhood is @@ -1067,7 +1089,7 @@ protected: old_inverse_values_[index] = value; } -private: + private: const int64 max_inverse_value_; std::vector old_inverse_values_; std::vector inverse_values_; @@ -1101,7 +1123,7 @@ inline void IntVarLocalSearchHandler::OnRevertChanges(int64 index, class SequenceVarLocalSearchOperator; class SequenceVarLocalSearchHandler { -public: + public: SequenceVarLocalSearchHandler() : op_(nullptr) {} SequenceVarLocalSearchHandler(const SequenceVarLocalSearchHandler &other) : op_(other.op_) {} @@ -1115,7 +1137,7 @@ public: void OnRevertChanges(int64 index, const std::vector &value); void OnAddVars(); -private: + private: SequenceVarLocalSearchOperator *const op_; }; @@ -1139,7 +1161,7 @@ typedef VarLocalSearchOperator, class SequenceVarLocalSearchOperator : public SequenceVarLocalSearchOperatorTemplate { -public: + public: SequenceVarLocalSearchOperator() {} explicit SequenceVarLocalSearchOperator( const std::vector &vars) @@ -1162,7 +1184,7 @@ public: MarkChange(index); } -protected: + protected: friend class SequenceVarLocalSearchHandler; std::vector > backward_values_; @@ -1212,9 +1234,8 @@ inline bool SequenceVarLocalSearchHandler::ValueFromAssignment( return element->Activated(); } -inline void -SequenceVarLocalSearchHandler::OnRevertChanges(int64 index, - const std::vector &value) { +inline void SequenceVarLocalSearchHandler::OnRevertChanges( + int64 index, const std::vector &value) { op_->backward_values_[index].clear(); } @@ -1250,7 +1271,7 @@ inline void SequenceVarLocalSearchHandler::OnAddVars() { /// int index_; /// }; class BaseLns : public IntVarLocalSearchOperator { -public: + public: explicit BaseLns(const std::vector &vars); ~BaseLns() override; virtual void InitFragments(); @@ -1259,11 +1280,11 @@ public: int FragmentSize() const; bool HasFragments() const override { return true; } -protected: + protected: /// This method should not be overridden. Override NextFragment() instead. bool MakeOneNeighbor() override; -private: + private: /// This method should not be overridden. Override InitFragments() instead. void OnStart() override; std::vector fragment_; @@ -1274,16 +1295,16 @@ private: /// Sub-classes have to define ModifyValue which determines what the new /// variable value is going to be (given the current value and the variable). class ChangeValue : public IntVarLocalSearchOperator { -public: + public: explicit ChangeValue(const std::vector &vars); ~ChangeValue() override; virtual int64 ModifyValue(int64 index, int64 value) = 0; -protected: + protected: /// This method should not be overridden. Override ModifyValue() instead. bool MakeOneNeighbor() override; -private: + private: void OnStart() override; int index_; @@ -1303,7 +1324,7 @@ private: /// Subclasses only need to override MakeNeighbor to create neighbors using /// the services above (no direct manipulation of assignments). class PathOperator : public IntVarLocalSearchOperator { -public: + public: /// Builds an instance of PathOperator from next and path variables. /// 'number_of_base_nodes' is the number of nodes needed to define a /// neighbor. 'start_empty_path_class' is a callback returning an index such @@ -1350,7 +1371,7 @@ public: /// Number of next variables. int number_of_nexts() const { return number_of_nexts_; } -protected: + protected: /// This method should not be overridden. Override MakeNeighbor() instead. bool MakeOneNeighbor() override; /// Called by OnStart() after initializing node information. Should be @@ -1364,8 +1385,7 @@ protected: int BaseAlternative(int i) const { return base_alternatives_[i]; } /// Returns the alternative node for the ith base node. int64 BaseAlternativeNode(int i) const { - if (!ConsiderAlternatives(i)) - return BaseNode(i); + if (!ConsiderAlternatives(i)) return BaseNode(i); const int alternative_index = alternative_index_[BaseNode(i)]; return alternative_index >= 0 ? alternative_sets_[alternative_index][base_alternatives_[i]] @@ -1377,13 +1397,12 @@ protected: } /// Returns the alternative node for the sibling of the ith base node. int64 BaseSiblingAlternativeNode(int i) const { - if (!ConsiderAlternatives(i)) - return BaseNode(i); + if (!ConsiderAlternatives(i)) return BaseNode(i); const int sibling_alternative_index = GetSiblingAlternativeIndex(BaseNode(i)); return sibling_alternative_index >= 0 - ? alternative_sets_[sibling_alternative_index][ - base_sibling_alternatives_[i]] + ? alternative_sets_[sibling_alternative_index] + [base_sibling_alternatives_[i]] : BaseNode(i); } /// Returns the start node of the ith base node. @@ -1506,16 +1525,16 @@ protected: /// Adds all sets of node alternatives of a vector of alternative pairs. No /// node can be in two altrnatives. void AddPairAlternativeSets( - const std::vector, std::vector > > & - pair_alternative_sets) { + const std::vector, std::vector > > + &pair_alternative_sets) { for (const auto &pair_alternative_set : pair_alternative_sets) { const int alternative = AddAlternativeSet(pair_alternative_set.first); sibling_alternative_.back() = alternative + 1; AddAlternativeSet(pair_alternative_set.second); } } -#endif // SWIG - /// Returns the active node in the given alternative set. +#endif // SWIG + /// Returns the active node in the given alternative set. int64 GetActiveInAlternativeSet(int alternative_index) const { return alternative_index >= 0 ? active_in_alternative_set_[alternative_index] @@ -1527,16 +1546,14 @@ protected: } /// Returns the index of the alternative set of the sibling of node. int GetSiblingAlternativeIndex(int node) const { - if (node >= alternative_index_.size()) - return -1; + if (node >= alternative_index_.size()) return -1; const int alternative = alternative_index_[node]; return alternative >= 0 ? sibling_alternative_[alternative] : -1; } /// Returns the active node in the alternative set of the sibling of the given /// node. int64 GetActiveAlternativeSibling(int node) const { - if (node >= alternative_index_.size()) - return -1; + if (node >= alternative_index_.size()) return -1; const int alternative = alternative_index_[node]; const int sibling_alternative = alternative >= 0 ? sibling_alternative_[alternative] : -1; @@ -1553,7 +1570,7 @@ protected: int num_paths_ = 0; std::vector start_to_path_; -private: + private: void OnStart() override; /// Returns true if two nodes are on the same path in the current assignment. bool OnSamePath(int64 node1, int64 node2) const; @@ -1592,7 +1609,7 @@ private: /// Node alternative data. #ifndef SWIG std::vector > alternative_sets_; -#endif // SWIG +#endif // SWIG std::vector alternative_index_; std::vector active_in_alternative_set_; std::vector sibling_alternative_; @@ -1600,10 +1617,10 @@ private: /// Operator Factories. template -LocalSearchOperator * - MakeLocalSearchOperator(Solver *solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class); +LocalSearchOperator *MakeLocalSearchOperator( + Solver *solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class); /// Classes to which this template function can be applied to as of 04/2014. /// Usage: LocalSearchOperator* op = MakeLocalSearchOperator(...); @@ -1634,13 +1651,13 @@ class RelocateAndMakeInactiveOperator; // invalid state: in particular, an invalid state cannot be saved. class LocalSearchVariable; class LocalSearchState { -public: + public: LocalSearchVariable AddVariable(int64 initial_min, int64 initial_max); void Commit(); void Revert(); bool StateIsValid() const { return state_is_valid_; } -private: + private: friend class LocalSearchVariable; struct Bounds { @@ -1667,7 +1684,7 @@ private: // and the user would have to know the relevant state. The present setup allows // to ensure that variable users will not misuse the state. class LocalSearchVariable { -public: + public: int64 Min() const { return state_->VariableMin(variable_index_); } int64 Max() const { return state_->VariableMax(variable_index_); } bool SetMin(int64 new_min) { @@ -1678,7 +1695,7 @@ public: } void Relax() { state_->RelaxVariableBounds(variable_index_); } -private: + private: // Only LocalSearchState can construct LocalSearchVariables. friend class LocalSearchState; @@ -1688,7 +1705,7 @@ private: LocalSearchState *const state_; const int variable_index_; }; -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// Local Search Filters are used for fast neighbor pruning. /// Filtering a move is done in several phases: @@ -1707,7 +1724,7 @@ private: /// called, to allow late filters to use state done/undone by early filters' /// Accept()/Revert(). class LocalSearchFilter : public BaseObject { -public: + public: /// Lets the filter know what delta and deltadelta will be passed in the next /// Accept(). virtual void Relax(const Assignment *delta, const Assignment *deltadelta) {} @@ -1751,13 +1768,10 @@ public: /// the solution is feasible and compute parts of the new cost. This class /// schedules filter execution and composes costs as a sum. class LocalSearchFilterManager : public BaseObject { -public: + public: // This class is responsible for calling filters methods in a correct order. // For now, an order is specified explicitly by the user. - enum FilterEventType { - kAccept, - kRelax - }; + enum FilterEventType { kAccept, kRelax }; struct FilterEvent { LocalSearchFilter *filter; FilterEventType event_type; @@ -1787,7 +1801,7 @@ public: int64 GetSynchronizedObjectiveValue() const { return synchronized_value_; } int64 GetAcceptedObjectiveValue() const { return accepted_value_; } -private: + private: void InitializeForcedEvents(); std::vector filter_events_; @@ -1802,13 +1816,13 @@ private: }; class IntVarLocalSearchFilter : public LocalSearchFilter { -public: + public: explicit IntVarLocalSearchFilter(const std::vector &vars); ~IntVarLocalSearchFilter() override; /// This method should not be overridden. Override OnSynchronize() instead /// which is called before exiting this method. - void Synchronize(const Assignment *assignment, const Assignment *delta) - override; + void Synchronize(const Assignment *assignment, + const Assignment *delta) override; bool FindIndex(IntVar *const var, int64 *index) const { DCHECK(index != nullptr); @@ -1829,11 +1843,11 @@ public: } bool IsVarSynced(int index) const { return var_synced_[index]; } -protected: + protected: virtual void OnSynchronize(const Assignment *delta) {} void SynchronizeOnAssignment(const Assignment *assignment); -private: + private: std::vector vars_; std::vector values_; std::vector var_synced_; @@ -1842,22 +1856,20 @@ private: }; class PropagationMonitor : public SearchMonitor { -public: + public: explicit PropagationMonitor(Solver *const solver); ~PropagationMonitor() override; std::string DebugString() const override { return "PropagationMonitor"; } /// Propagation events. - virtual void - BeginConstraintInitialPropagation(Constraint *const constraint) = 0; - virtual void - EndConstraintInitialPropagation(Constraint *const constraint) = 0; - virtual void - BeginNestedConstraintInitialPropagation(Constraint *const parent, - Constraint *const nested) = 0; - virtual void - EndNestedConstraintInitialPropagation(Constraint *const parent, - Constraint *const nested) = 0; + virtual void BeginConstraintInitialPropagation( + Constraint *const constraint) = 0; + virtual void EndConstraintInitialPropagation( + Constraint *const constraint) = 0; + virtual void BeginNestedConstraintInitialPropagation( + Constraint *const parent, Constraint *const nested) = 0; + virtual void EndNestedConstraintInitialPropagation( + Constraint *const parent, Constraint *const nested) = 0; virtual void RegisterDemon(Demon *const demon) = 0; virtual void BeginDemonRun(Demon *const demon) = 0; virtual void EndDemonRun(Demon *const demon) = 0; @@ -1909,7 +1921,7 @@ public: class LocalSearchMonitor : public SearchMonitor { // TODO(user): Add monitoring of local search filters. -public: + public: explicit LocalSearchMonitor(Solver *const solver); ~LocalSearchMonitor() override; std::string DebugString() const override { return "LocalSearchMonitor"; } @@ -1935,7 +1947,7 @@ public: }; class BooleanVar : public IntVar { -public: + public: static const int kUnboundBooleanVarValue; explicit BooleanVar(Solver *const s, const std::string &name = "") @@ -1975,7 +1987,7 @@ public: int RawValue() const { return value_; } -protected: + protected: int value_; SimpleRevFIFO bound_demons_; SimpleRevFIFO delayed_bound_demons_; @@ -1987,7 +1999,7 @@ class SymmetryManager; /// create the 'symmetrical' decision in return. /// Each symmetry breaker represents one class of symmetry. class SymmetryBreaker : public DecisionVisitor { -public: + public: SymmetryBreaker() : symmetry_manager_(nullptr), index_in_symmetry_manager_(-1) {} ~SymmetryBreaker() override {} @@ -1997,7 +2009,7 @@ public: int64 value); void AddIntegerVariableLessOrEqualValueClause(IntVar *const var, int64 value); -private: + private: friend class SymmetryManager; void set_symmetry_manager_and_index(SymmetryManager *manager, int index) { CHECK(symmetry_manager_ == nullptr); @@ -2016,7 +2028,7 @@ private: /// The base class of all search logs that periodically outputs information when /// the search is running. class SearchLog : public SearchMonitor { -public: + public: SearchLog(Solver *const s, OptimizeVar *const obj, IntVar *const var, double scaling_factor, double offset, std::function display_callback, @@ -2036,11 +2048,11 @@ public: void EndInitialPropagation() override; std::string DebugString() const override; -protected: + protected: /* Bottleneck function used for all UI related output. */ virtual void OutputLine(const std::string &line); -private: + private: static std::string MemoryUsage(); const int period_; @@ -2066,7 +2078,7 @@ private: /// well as their types. This class is used internally to avoid creating /// duplicate objects. class ModelCache { -public: + public: enum VoidConstraintType { VOID_FALSE_CONSTRAINT = 0, VOID_TRUE_CONSTRAINT, @@ -2175,9 +2187,8 @@ public: VoidConstraintType type) = 0; /// Var Constant Constraints. - virtual Constraint * - FindVarConstantConstraint(IntVar *const var, int64 value, - VarConstantConstraintType type) const = 0; + virtual Constraint *FindVarConstantConstraint( + IntVar *const var, int64 value, VarConstantConstraintType type) const = 0; virtual void InsertVarConstantConstraint(Constraint *const ct, IntVar *const var, int64 value, @@ -2195,9 +2206,9 @@ public: /// Expr Expr Constraints. - virtual Constraint * - FindExprExprConstraint(IntExpr *const expr1, IntExpr *const expr2, - ExprExprConstraintType type) const = 0; + virtual Constraint *FindExprExprConstraint( + IntExpr *const expr1, IntExpr *const expr2, + ExprExprConstraintType type) const = 0; virtual void InsertExprExprConstraint(Constraint *const ct, IntExpr *const expr1, @@ -2215,20 +2226,19 @@ public: /// Expr Constant Expressions. - virtual IntExpr * - FindExprConstantExpression(IntExpr *const expr, int64 value, - ExprConstantExpressionType type) const = 0; + virtual IntExpr *FindExprConstantExpression( + IntExpr *const expr, int64 value, + ExprConstantExpressionType type) const = 0; - virtual void - InsertExprConstantExpression(IntExpr *const expression, - IntExpr *const var, int64 value, - ExprConstantExpressionType type) = 0; + virtual void InsertExprConstantExpression( + IntExpr *const expression, IntExpr *const var, int64 value, + ExprConstantExpressionType type) = 0; /// Expr Expr Expressions. - virtual IntExpr * - FindExprExprExpression(IntExpr *const var1, IntExpr *const var2, - ExprExprExpressionType type) const = 0; + virtual IntExpr *FindExprExprExpression( + IntExpr *const var1, IntExpr *const var2, + ExprExprExpressionType type) const = 0; virtual void InsertExprExprExpression(IntExpr *const expression, IntExpr *const var1, @@ -2261,17 +2271,15 @@ public: IntVar *const var, const std::vector &values, VarConstantArrayExpressionType type) const = 0; - virtual void - InsertVarConstantArrayExpression(IntExpr *const expression, - IntVar *const var, - const std::vector &values, - VarConstantArrayExpressionType type) = 0; + virtual void InsertVarConstantArrayExpression( + IntExpr *const expression, IntVar *const var, + const std::vector &values, + VarConstantArrayExpressionType type) = 0; /// Var Array Expressions. - virtual IntExpr * - FindVarArrayExpression(const std::vector &vars, - VarArrayExpressionType type) const = 0; + virtual IntExpr *FindVarArrayExpression( + const std::vector &vars, VarArrayExpressionType type) const = 0; virtual void InsertVarArrayExpression(IntExpr *const expression, const std::vector &vars, @@ -2300,14 +2308,14 @@ public: Solver *solver() const; -private: + private: Solver *const solver_; }; /// Argument Holder: useful when visiting a model. #if !defined(SWIG) class ArgumentHolder { -public: + public: /// Type of the argument. const std::string &TypeName() const; void SetTypeName(const std::string &type_name); @@ -2337,17 +2345,17 @@ public: int64 FindIntegerArgumentWithDefault(const std::string &arg_name, int64 def) const; int64 FindIntegerArgumentOrDie(const std::string &arg_name) const; - const std::vector & - FindIntegerArrayArgumentOrDie(const std::string &arg_name) const; - const IntTupleSet & - FindIntegerMatrixArgumentOrDie(const std::string &arg_name) const; + const std::vector &FindIntegerArrayArgumentOrDie( + const std::string &arg_name) const; + const IntTupleSet &FindIntegerMatrixArgumentOrDie( + const std::string &arg_name) const; - IntExpr * - FindIntegerExpressionArgumentOrDie(const std::string &arg_name) const; - const std::vector & - FindIntegerVariableArrayArgumentOrDie(const std::string &arg_name) const; + IntExpr *FindIntegerExpressionArgumentOrDie( + const std::string &arg_name) const; + const std::vector &FindIntegerVariableArrayArgumentOrDie( + const std::string &arg_name) const; -private: + private: std::string type_name_; absl::flat_hash_map integer_argument_; absl::flat_hash_map > integer_array_argument_; @@ -2365,7 +2373,7 @@ private: /// Model Parser class ModelParser : public ModelVisitor { -public: + public: ModelParser(); ~ModelParser() override; @@ -2399,35 +2407,37 @@ public: /// Variables. void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument) override; - void VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override; + void VisitIntegerVariableArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override; /// Visit interval argument. void VisitIntervalArgument(const std::string &arg_name, IntervalVar *const argument) override; - void VisitIntervalArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override; + void VisitIntervalArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override; /// Visit sequence argument. void VisitSequenceArgument(const std::string &arg_name, SequenceVar *const argument) override; - void VisitSequenceArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override; + void VisitSequenceArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override; -protected: + protected: void PushArgumentHolder(); void PopArgumentHolder(); ArgumentHolder *Top() const; -private: + private: std::vector holders_; }; -template class ArrayWithOffset : public BaseObject { -public: +template +class ArrayWithOffset : public BaseObject { + public: ArrayWithOffset(int64 index_min, int64 index_max) - : index_min_(index_min), index_max_(index_max), + : index_min_(index_min), + index_max_(index_max), values_(new T[index_max - index_min + 1]) { DCHECK_LE(index_min, index_max); } @@ -2448,19 +2458,20 @@ public: std::string DebugString() const override { return "ArrayWithOffset"; } -private: + private: const int64 index_min_; const int64 index_max_; std::unique_ptr values_; }; -#endif // SWIG +#endif // SWIG /// This class is a reversible growing array. In can grow in both /// directions, and even accept negative indices. The objects stored /// have a type T. As it relies on the solver for reversibility, these /// objects can be up-casted to 'C' when using Solver::SaveValue(). -template class RevGrowingArray { -public: +template +class RevGrowingArray { + public: explicit RevGrowingArray(int64 block_size) : block_size_(block_size), block_offset_(0) { CHECK_GT(block_size, 0); @@ -2490,7 +2501,7 @@ public: reinterpret_cast(value)); } -private: + private: T *NewBlock() const { T *const result = new T[block_size_]; for (int i = 0; i < block_size_; ++i) { @@ -2541,14 +2552,18 @@ private: /// be an integer type. You fill it at first, and then during search, /// you can efficiently remove an element, and query the removed /// elements. -template class RevIntSet { -public: +template +class RevIntSet { + public: static constexpr int kNoInserted = -1; /// Capacity is the fixed size of the set (it cannot grow). explicit RevIntSet(int capacity) - : elements_(new T[capacity]), num_elements_(0), capacity_(capacity), - position_(new int[capacity]), delete_position_(true) { + : elements_(new T[capacity]), + num_elements_(0), + capacity_(capacity), + position_(new int[capacity]), + delete_position_(true) { for (int i = 0; i < capacity; ++i) { position_[i] = kNoInserted; } @@ -2556,8 +2571,11 @@ public: /// Capacity is the fixed size of the set (it cannot grow). RevIntSet(int capacity, int *shared_positions, int shared_positions_size) - : elements_(new T[capacity]), num_elements_(0), capacity_(capacity), - position_(shared_positions), delete_position_(false) { + : elements_(new T[capacity]), + num_elements_(0), + capacity_(capacity), + position_(shared_positions), + delete_position_(false) { for (int i = 0; i < shared_positions_size; ++i) { position_[i] = kNoInserted; } @@ -2587,7 +2605,7 @@ public: void Insert(Solver *const solver, const T &elt) { const int position = num_elements_.Value(); - DCHECK_LT(position, capacity_); /// Valid. + DCHECK_LT(position, capacity_); /// Valid. DCHECK(NotAlreadyInserted(elt)); elements_[position] = elt; position_[elt] = position; @@ -2611,7 +2629,7 @@ public: const_iterator begin() const { return elements_.get(); } const_iterator end() const { return elements_.get() + num_elements_.Value(); } -private: + private: /// Used in DCHECK. bool NotAlreadyInserted(const T &elt) { for (int i = 0; i < num_elements_.Value(); ++i) { @@ -2648,10 +2666,13 @@ private: /// ----- RevPartialSequence ----- class RevPartialSequence { -public: + public: explicit RevPartialSequence(const std::vector &items) - : elements_(items), first_ranked_(0), last_ranked_(items.size() - 1), - size_(items.size()), position_(new int[size_]) { + : elements_(items), + first_ranked_(0), + last_ranked_(items.size() - 1), + size_(items.size()), + position_(new int[size_]) { for (int i = 0; i < size_; ++i) { elements_[i] = items[i]; position_[i] = i; @@ -2659,7 +2680,10 @@ public: } explicit RevPartialSequence(int size) - : elements_(size), first_ranked_(0), last_ranked_(size - 1), size_(size), + : elements_(size), + first_ranked_(0), + last_ranked_(size - 1), + size_(size), position_(new int[size_]) { for (int i = 0; i < size_; ++i) { elements_[i] = i; @@ -2727,7 +2751,7 @@ public: return result; } -private: + private: void SwapTo(int elt, int next_position) { const int current_position = position_[elt]; if (current_position != next_position) { @@ -2756,7 +2780,7 @@ private: /// reversibly subtract another bitset, or check if the current active bitset /// intersects with another bitset. class UnsortedNullableRevBitset { -public: + public: /// Size is the number of bits to store in the bitset. explicit UnsortedNullableRevBitset(int bit_size); @@ -2797,7 +2821,7 @@ public: /// Returns the set of active word indices. const RevIntSet &active_words() const { return active_words_; } -private: + private: void CleanUpActives(Solver *const solver); const int64 bit_size_; @@ -2817,7 +2841,8 @@ bool IsArrayConstant(const std::vector &values, const T &value) { return true; } -template bool IsArrayBoolean(const std::vector &values) { +template +bool IsArrayBoolean(const std::vector &values) { for (int i = 0; i < values.size(); ++i) { if (values[i] != 0 && values[i] != 1) { return false; @@ -2826,11 +2851,13 @@ template bool IsArrayBoolean(const std::vector &values) { return true; } -template bool AreAllOnes(const std::vector &values) { +template +bool AreAllOnes(const std::vector &values) { return IsArrayConstant(values, T(1)); } -template bool AreAllNull(const std::vector &values) { +template +bool AreAllNull(const std::vector &values) { return IsArrayConstant(values, T(0)); } @@ -2854,23 +2881,28 @@ bool AreAllLessOrEqual(const std::vector &values, const T &value) { return true; } -template bool AreAllPositive(const std::vector &values) { +template +bool AreAllPositive(const std::vector &values) { return AreAllGreaterOrEqual(values, T(0)); } -template bool AreAllNegative(const std::vector &values) { +template +bool AreAllNegative(const std::vector &values) { return AreAllLessOrEqual(values, T(0)); } -template bool AreAllStrictlyPositive(const std::vector &values) { +template +bool AreAllStrictlyPositive(const std::vector &values) { return AreAllGreaterOrEqual(values, T(1)); } -template bool AreAllStrictlyNegative(const std::vector &values) { +template +bool AreAllStrictlyNegative(const std::vector &values) { return AreAllLessOrEqual(values, T(-1)); } -template bool IsIncreasingContiguous(const std::vector &values) { +template +bool IsIncreasingContiguous(const std::vector &values) { for (int i = 0; i < values.size() - 1; ++i) { if (values[i + 1] != values[i] + 1) { return false; @@ -2879,7 +2911,8 @@ template bool IsIncreasingContiguous(const std::vector &values) { return true; } -template bool IsIncreasing(const std::vector &values) { +template +bool IsIncreasing(const std::vector &values) { for (int i = 0; i < values.size() - 1; ++i) { if (values[i + 1] < values[i]) { return false; @@ -3029,7 +3062,7 @@ std::vector ToInt64Vector(const std::vector &input); // and the set of changed nodes is empty. Still, the chain-based iterator allows // to browse paths: each path has exactly one chain. class PathState { -public: + public: // A ChainRange allows to iterate on all chains of a path. // ChainRange is a range, its iterator Chain*, its value type Chain. class ChainRange; @@ -3099,7 +3132,7 @@ public: void SetInvalid() { is_invalid_ = true; } bool IsInvalid() const { return is_invalid_; } -private: + private: // Most structs below are named pairs of ints, for typing purposes. // Start and end are stored together to optimize (likely) simultaneous access. @@ -3204,9 +3237,9 @@ private: // A Chain is a range of committed nodes. class PathState::Chain { -public: + public: class Iterator { - public: + public: Iterator &operator++() { ++current_node_; return *this; @@ -3216,7 +3249,7 @@ public: return current_node_ != other.current_node_; } - private: + private: // Only a Chain can construct its iterator. friend class PathState::Chain; explicit Iterator(const CommittedNode *node) : current_node_(node) {} @@ -3234,29 +3267,29 @@ public: Iterator begin() const { return Iterator(begin_); } Iterator end() const { return Iterator(end_); } -private: + private: const CommittedNode *const begin_; const CommittedNode *const end_; }; // A ChainRange is a range of Chains, committed or not. class PathState::ChainRange { -public: + public: class Iterator { - public: + public: Iterator &operator++() { ++current_chain_; return *this; } Chain operator*() const { - return { first_node_ + current_chain_->begin_index, - first_node_ + current_chain_->end_index }; + return {first_node_ + current_chain_->begin_index, + first_node_ + current_chain_->end_index}; } bool operator!=(Iterator other) const { return current_chain_ != other.current_chain_; } - private: + private: // Only a ChainRange can construct its Iterator. friend class ChainRange; Iterator(const ChainBounds *chain, const CommittedNode *const first_node) @@ -3272,14 +3305,10 @@ public: const CommittedNode *const first_node) : begin_(begin_chain), end_(end_chain), first_node_(first_node) {} - Iterator begin() const { - return { begin_, first_node_ }; - } - Iterator end() const { - return { end_, first_node_ }; - } + Iterator begin() const { return {begin_, first_node_}; } + Iterator end() const { return {end_, first_node_}; } -private: + private: const ChainBounds *const begin_; const ChainBounds *const end_; const CommittedNode *const first_node_; @@ -3288,9 +3317,9 @@ private: // A NodeRange allows to iterate on all nodes of a path, // by a two-level iteration on ChainBounds* and CommittedNode* of a PathState. class PathState::NodeRange { -public: + public: class Iterator { - public: + public: Iterator &operator++() { ++current_node_; if (current_node_ == end_node_) { @@ -3308,14 +3337,15 @@ public: return current_chain_ != other.current_chain_; } - private: + private: // Only a NodeRange can construct its Iterator. friend class NodeRange; Iterator(const ChainBounds *current_chain, const CommittedNode *const first_node) : current_node_(first_node + current_chain->begin_index), end_node_(first_node + current_chain->end_index), - current_chain_(current_chain), first_node_(first_node) {} + current_chain_(current_chain), + first_node_(first_node) {} const CommittedNode *current_node_; const CommittedNode *end_node_; const ChainBounds *current_chain_; @@ -3326,18 +3356,15 @@ public: // a NodeRange may be invalidated if on of the underlying vector is modified. NodeRange(const ChainBounds *begin_chain, const ChainBounds *end_chain, const CommittedNode *first_node) - : begin_chain_(begin_chain), end_chain_(end_chain), + : begin_chain_(begin_chain), + end_chain_(end_chain), first_node_(first_node) {} - Iterator begin() const { - return { begin_chain_, first_node_ }; - } + Iterator begin() const { return {begin_chain_, first_node_}; } // Note: there is a sentinel value at the end of PathState::chains_, // so dereferencing chain_range_.end()->begin_ is always valid. - Iterator end() const { - return { end_chain_, first_node_ }; - } + Iterator end() const { return {end_chain_, first_node_}; } -private: + private: const ChainBounds *begin_chain_; const ChainBounds *end_chain_; const CommittedNode *const first_node_; @@ -3358,7 +3385,7 @@ private: // If the path capacity of a path is [kint64min, kint64max], // then the unary dimension requirements are not enforced on this path. class UnaryDimensionChecker { -public: + public: struct Interval { int64 min; int64 max; @@ -3378,7 +3405,7 @@ public: // must be called before PathState::Commit(). void Commit(); -private: + private: // Range min/max query on partial_demand_sums_. // The first_node and last_node MUST form a subpath in the committed state. // Nodes first_node and last_node are passed by their index in precomputed @@ -3456,12 +3483,11 @@ LocalSearchFilter *MakePathStateFilter(Solver *solver, // - Accept() must be called after. // - Synchronize() must be called before. // - Revert() must be called before. -LocalSearchFilter * - MakeUnaryDimensionFilter(Solver *solver, - std::unique_ptr checker); +LocalSearchFilter *MakeUnaryDimensionFilter( + Solver *solver, std::unique_ptr checker); -#endif // !defined(SWIG) +#endif // !defined(SWIG) -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_ diff --git a/ortools/constraint_solver/constraints.cc b/ortools/constraint_solver/constraints.cc index 07adff096a..64fd6787eb 100644 --- a/ortools/constraint_solver/constraints.cc +++ b/ortools/constraint_solver/constraints.cc @@ -35,15 +35,15 @@ Demon *Solver::MakeConstraintInitialPropagateCallback(Constraint *const ct) { "InitialPropagate"); } -Demon * -Solver::MakeDelayedConstraintInitialPropagateCallback(Constraint *const ct) { +Demon *Solver::MakeDelayedConstraintInitialPropagateCallback( + Constraint *const ct) { return MakeDelayedConstraintDemon0(this, ct, &Constraint::InitialPropagate, "InitialPropagate"); } namespace { class ActionDemon : public Demon { -public: + public: explicit ActionDemon(const Solver::Action &action) : action_(action) { CHECK(action != nullptr); } @@ -52,12 +52,12 @@ public: void Run(Solver *const solver) override { action_(solver); } -private: + private: Solver::Action action_; }; class ClosureDemon : public Demon { -public: + public: explicit ClosureDemon(const Solver::Closure &closure) : closure_(closure) { CHECK(closure != nullptr); } @@ -66,14 +66,14 @@ public: void Run(Solver *const solver) override { closure_(); } -private: + private: Solver::Closure closure_; }; // ----- True and False Constraint ----- class TrueConstraint : public Constraint { -public: + public: explicit TrueConstraint(Solver *const s) : Constraint(s) {} ~TrueConstraint() override {} @@ -89,7 +89,7 @@ public: }; class FalseConstraint : public Constraint { -public: + public: explicit FalseConstraint(Solver *const s) : Constraint(s) {} FalseConstraint(Solver *const s, const std::string &explanation) : Constraint(s), explanation_(explanation) {} @@ -107,7 +107,7 @@ public: } IntVar *Var() override { return solver()->MakeIntConst(0); } -private: + private: const std::string explanation_; }; @@ -118,7 +118,7 @@ private: // UpdateActive() is the same as the size at the beginning of VarDomain(). class MapDomain : public Constraint { -public: + public: MapDomain(Solver *const s, IntVar *const var, const std::vector &actives) : Constraint(s), var_(var), actives_(actives) { @@ -135,7 +135,7 @@ public: MakeConstraintDemon0(solver(), this, &MapDomain::VarBound, "VarBound"); var_->WhenBound(vb); std::unique_ptr domain_it( - var_->MakeDomainIterator(/*reversible=*/ false)); + var_->MakeDomainIterator(/*reversible=*/false)); for (const int64 index : InitAndGetValues(domain_it.get())) { if (index >= 0 && index < actives_.size() && !actives_[index]->Bound()) { Demon *d = MakeConstraintDemon1( @@ -147,12 +147,7 @@ public: void InitialPropagate() override { for (int i = 0; i < actives_.size(); ++i) { - actives_[i]->SetRange(int64 { - 0 - }, - int64 { - 1 - }); + actives_[i]->SetRange(int64{0}, int64{1}); if (!var_->Contains(i)) { actives_[i]->SetValue(0); } else if (actives_[i]->Max() == 0LL) { @@ -182,10 +177,7 @@ public: const int64 vmin = var_->Min(); const int64 vmax = var_->Max(); const int64 size = actives_.size(); - for (int64 j = std::max(oldmin, int64 { - 0 - }); - j < std::min(vmin, size); ++j) { + for (int64 j = std::max(oldmin, int64{0}); j < std::min(vmin, size); ++j) { actives_[j]->SetValue(0); } for (const int64 j : InitAndGetValues(holes_)) { @@ -193,19 +185,9 @@ public: actives_[j]->SetValue(0); } } - for (int64 j = std::max(vmax + int64 { - 1 - }, - int64 { - 0 - }); - j <= std::min(oldmax, size - int64 { - 1 - }); - ++j) { - actives_[j]->SetValue(int64 { - 0 - }); + for (int64 j = std::max(vmax + int64{1}, int64{0}); + j <= std::min(oldmax, size - int64{1}); ++j) { + actives_[j]->SetValue(int64{0}); } } @@ -229,7 +211,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMapDomain, this); } -private: + private: IntVar *const var_; std::vector actives_; IntVarIterator *holes_; @@ -238,11 +220,15 @@ private: // ----- Lex constraint ----- class LexicalLess : public Constraint { -public: + public: LexicalLess(Solver *const s, const std::vector &left, const std::vector &right, bool strict) - : Constraint(s), left_(left), right_(right), active_var_(0), - strict_(strict), demon_(nullptr) { + : Constraint(s), + left_(left), + right_(right), + active_var_(0), + strict_(strict), + demon_(nullptr) { CHECK_EQ(left.size(), right.size()); } @@ -301,7 +287,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLexLess, this); } -private: + private: int JumpEqualVariables(int start_position) const { int position = start_position; while (position < left_.size() && left_[position]->Bound() && @@ -322,12 +308,15 @@ private: // ----- Inverse permutation constraint ----- class InversePermutationConstraint : public Constraint { -public: + public: InversePermutationConstraint(Solver *const s, const std::vector &left, const std::vector &right) - : Constraint(s), left_(left), right_(right), - left_hole_iterators_(left.size()), left_domain_iterators_(left_.size()), + : Constraint(s), + left_(left), + right_(right), + left_hole_iterators_(left.size()), + left_domain_iterators_(left_.size()), right_hole_iterators_(right_.size()), right_domain_iterators_(right_.size()) { CHECK_EQ(left_.size(), right_.size()); @@ -355,9 +344,9 @@ public: right_[i]->WhenDomain(right_demon); } solver()->AddConstraint( - solver()->MakeAllDifferent(left_, /*stronger_propagation=*/ false)); + solver()->MakeAllDifferent(left_, /*stronger_propagation=*/false)); solver()->AddConstraint( - solver()->MakeAllDifferent(right_, /*stronger_propagation=*/ false)); + solver()->MakeAllDifferent(right_, /*stronger_propagation=*/false)); } void InitialPropagate() override { @@ -395,13 +384,11 @@ public: visitor->EndVisitConstraint(ModelVisitor::kInversePermutation, this); } -private: + private: // See PropagateHolesOfLeftVarToRight() and PropagateHolesOfRightVarToLeft(). void PropagateHoles(int index, IntVar *const var, IntVarIterator *const holes, const std::vector &inverse) { - const int64 oldmin = std::max(var->OldMin(), int64 { - 0 - }); + const int64 oldmin = std::max(var->OldMin(), int64{0}); const int64 oldmax = std::min(var->OldMax(), static_cast(left_.size() - 1)); const int64 vmin = var->Min(); @@ -450,7 +437,7 @@ private: // Index of first Max Value class IndexOfFirstMaxValue : public Constraint { -public: + public: IndexOfFirstMaxValue(Solver *solver, IntVar *index, const std::vector &vars) : Constraint(solver), index_(index), vars_(vars) {} @@ -468,10 +455,7 @@ public: void InitialPropagate() override { const int64 vsize = vars_.size(); - const int64 imin = std::max(int64 { - 0 - }, - index_->Min()); + const int64 imin = std::max(int64{0}, index_->Min()); const int64 imax = std::min(vsize - 1, index_->Max()); int64 max_max = kint64min; int64 max_min = kint64min; @@ -512,11 +496,11 @@ public: // TODO(user): Implement me. } -private: + private: IntVar *const index_; const std::vector vars_; }; -} // namespace +} // namespace // ----- API ----- @@ -563,25 +547,22 @@ Constraint *Solver::MakeLexicalLessOrEqual(const std::vector &left, return RevAlloc(new LexicalLess(this, left, right, false)); } -Constraint * -Solver::MakeInversePermutationConstraint(const std::vector &left, - const std::vector &right) { +Constraint *Solver::MakeInversePermutationConstraint( + const std::vector &left, const std::vector &right) { return RevAlloc(new InversePermutationConstraint(this, left, right)); } -Constraint * -Solver::MakeIndexOfFirstMaxValueConstraint(IntVar *index, - const std::vector &vars) { +Constraint *Solver::MakeIndexOfFirstMaxValueConstraint( + IntVar *index, const std::vector &vars) { return RevAlloc(new IndexOfFirstMaxValue(this, index, vars)); } -Constraint * -Solver::MakeIndexOfFirstMinValueConstraint(IntVar *index, - const std::vector &vars) { +Constraint *Solver::MakeIndexOfFirstMinValueConstraint( + IntVar *index, const std::vector &vars) { std::vector opp_vars(vars.size()); for (int i = 0; i < vars.size(); ++i) { opp_vars[i] = MakeOpposite(vars[i])->Var(); } return RevAlloc(new IndexOfFirstMaxValue(this, index, opp_vars)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/count_cst.cc b/ortools/constraint_solver/count_cst.cc index 988247ea05..7f8ea8fbaf 100644 --- a/ortools/constraint_solver/count_cst.cc +++ b/ortools/constraint_solver/count_cst.cc @@ -67,11 +67,14 @@ Constraint *Solver::MakeCount(const std::vector &vars, int64 value, namespace { class AtMost : public Constraint { -public: + public: AtMost(Solver *const s, std::vector vars, int64 value, int64 max_count) - : Constraint(s), vars_(std::move(vars)), value_(value), - max_count_(max_count), current_count_(0) {} + : Constraint(s), + vars_(std::move(vars)), + value_(value), + max_count_(max_count), + current_count_(0) {} ~AtMost() override {} @@ -136,7 +139,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAtMost, this); } -private: + private: const std::vector vars_; const int64 value_; const int64 max_count_; @@ -144,12 +147,16 @@ private: }; class Distribute : public Constraint { -public: + public: Distribute(Solver *const s, const std::vector &vars, const std::vector &values, const std::vector &cards) - : Constraint(s), vars_(vars), values_(values), cards_(cards), - undecided_(vars.size(), cards.size()), min_(cards.size(), 0), + : Constraint(s), + vars_(vars), + values_(values), + cards_(cards), + undecided_(vars.size(), cards.size()), + min_(cards.size(), 0), max_(cards.size(), 0) {} ~Distribute() override {} @@ -178,7 +185,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDistribute, this); } -private: + private: int64 var_size() const { return vars_.size(); } int64 card_size() const { return cards_.size(); } @@ -313,7 +320,7 @@ void Distribute::CardMax(int cindex) { // ----- FastDistribute ----- class FastDistribute : public Constraint { -public: + public: FastDistribute(Solver *const s, const std::vector &vars, const std::vector &cards); ~FastDistribute() override {} @@ -354,7 +361,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDistribute, this); } -private: + private: int64 var_size() const { return vars_.size(); } int64 card_size() const { return cards_.size(); } @@ -369,9 +376,13 @@ private: FastDistribute::FastDistribute(Solver *const s, const std::vector &vars, const std::vector &cards) - : Constraint(s), vars_(vars), cards_(cards), - undecided_(vars.size(), cards.size()), min_(cards.size(), 0), - max_(cards.size(), 0), holes_(vars.size()) { + : Constraint(s), + vars_(vars), + cards_(cards), + undecided_(vars.size(), cards.size()), + min_(cards.size(), 0), + max_(cards.size(), 0), + holes_(vars.size()) { for (int var_index = 0; var_index < var_size(); ++var_index) { holes_[var_index] = vars_[var_index]->MakeHoleIterator(true); } @@ -444,9 +455,7 @@ void FastDistribute::OneDomain(int index) { const int64 oldmax = var->OldMax(); const int64 vmin = var->Min(); const int64 vmax = var->Max(); - for (int64 card_index = std::max(oldmin, int64 { - 0 - }); + for (int64 card_index = std::max(oldmin, int64{0}); card_index < std::min(vmin, card_size()); ++card_index) { if (undecided_.IsSet(index, card_index)) { SetRevCannotContribute(index, card_index); @@ -458,9 +467,7 @@ void FastDistribute::OneDomain(int index) { SetRevCannotContribute(index, card_index); } } - for (int64 card_index = std::max(vmax + 1, int64 { - 0 - }); + for (int64 card_index = std::max(vmax + 1, int64{0}); card_index <= std::min(oldmax, card_size() - 1); ++card_index) { if (undecided_.IsSet(index, card_index)) { SetRevCannotContribute(index, card_index); @@ -499,7 +506,7 @@ void FastDistribute::CardMax(int card_index) { // ----- BoundedDistribute ----- class BoundedDistribute : public Constraint { -public: + public: BoundedDistribute(Solver *const s, const std::vector &vars, const std::vector &values, const std::vector &card_min, @@ -547,7 +554,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDistribute, this); } -private: + private: int64 var_size() const { return vars_.size(); } int64 card_size() const { return values_.size(); } @@ -566,9 +573,15 @@ BoundedDistribute::BoundedDistribute(Solver *const s, const std::vector &values, const std::vector &card_min, const std::vector &card_max) - : Constraint(s), vars_(vars), values_(values), card_min_(card_min), - card_max_(card_max), undecided_(vars.size(), values.size()), - min_(values.size(), 0), max_(values.size(), 0), holes_(vars.size()) { + : Constraint(s), + vars_(vars), + values_(values), + card_min_(card_min), + card_max_(card_max), + undecided_(vars.size(), values.size()), + min_(values.size(), 0), + max_(values.size(), 0), + holes_(vars.size()) { for (int var_index = 0; var_index < var_size(); ++var_index) { holes_[var_index] = vars_[var_index]->MakeHoleIterator(true); } @@ -696,7 +709,7 @@ void BoundedDistribute::CardMax(int card_index) { // ----- BoundedFastDistribute ----- class BoundedFastDistribute : public Constraint { -public: + public: BoundedFastDistribute(Solver *const s, const std::vector &vars, const std::vector &card_min, const std::vector &card_max); @@ -742,7 +755,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDistribute, this); } -private: + private: int64 var_size() const { return vars_.size(); } int64 card_size() const { return card_min_.size(); } @@ -759,9 +772,14 @@ BoundedFastDistribute::BoundedFastDistribute(Solver *const s, const std::vector &vars, const std::vector &card_min, const std::vector &card_max) - : Constraint(s), vars_(vars), card_min_(card_min), card_max_(card_max), - undecided_(vars.size(), card_min.size()), min_(card_min.size(), 0), - max_(card_max.size(), 0), holes_(vars.size()) { + : Constraint(s), + vars_(vars), + card_min_(card_min), + card_max_(card_max), + undecided_(vars.size(), card_min.size()), + min_(card_min.size(), 0), + max_(card_max.size(), 0), + holes_(vars.size()) { for (int var_index = 0; var_index < var_size(); ++var_index) { holes_[var_index] = vars_[var_index]->MakeHoleIterator(true); } @@ -850,9 +868,7 @@ void BoundedFastDistribute::OneDomain(int index) { const int64 oldmax = var->OldMax(); const int64 vmin = var->Min(); const int64 vmax = var->Max(); - for (int64 card_index = std::max(oldmin, int64 { - 0 - }); + for (int64 card_index = std::max(oldmin, int64{0}); card_index < std::min(vmin, card_size()); ++card_index) { if (undecided_.IsSet(index, card_index)) { SetRevCannotContribute(index, card_index); @@ -864,9 +880,7 @@ void BoundedFastDistribute::OneDomain(int index) { SetRevCannotContribute(index, card_index); } } - for (int64 card_index = std::max(vmax + 1, int64 { - 0 - }); + for (int64 card_index = std::max(vmax + 1, int64{0}); card_index <= std::min(oldmax, card_size() - 1); ++card_index) { if (undecided_.IsSet(index, card_index)) { SetRevCannotContribute(index, card_index); @@ -908,7 +922,7 @@ void BoundedFastDistribute::CardMax(int card_index) { // ----- SetAllToZero ----- class SetAllToZero : public Constraint { -public: + public: SetAllToZero(Solver *const s, const std::vector &vars) : Constraint(s), vars_(vars) {} @@ -931,10 +945,10 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDistribute, this); } -private: + private: const std::vector vars_; }; -} // namespace +} // namespace // ----- Factory ----- @@ -1065,4 +1079,4 @@ Constraint *Solver::MakeDistribute(const std::vector &vars, return MakeDistribute(vars, ToInt64Vector(values), ToInt64Vector(card_min), ToInt64Vector(card_max)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/default_search.cc b/ortools/constraint_solver/default_search.cc index 04350daf6d..73c2e46b1a 100644 --- a/ortools/constraint_solver/default_search.cc +++ b/ortools/constraint_solver/default_search.cc @@ -41,17 +41,20 @@ const int kDefaultNumberOfSplits = 100; const int kDefaultHeuristicPeriod = 100; const int kDefaultHeuristicNumFailuresLimit = 30; const bool kDefaultUseLastConflict = true; -} // namespace +} // namespace DefaultPhaseParameters::DefaultPhaseParameters() : var_selection_schema(DefaultPhaseParameters::CHOOSE_MAX_SUM_IMPACT), value_selection_schema(DefaultPhaseParameters::SELECT_MIN_IMPACT), - initialization_splits(kDefaultNumberOfSplits), run_all_heuristics(true), + initialization_splits(kDefaultNumberOfSplits), + run_all_heuristics(true), heuristic_period(kDefaultHeuristicPeriod), heuristic_num_failures_limit(kDefaultHeuristicNumFailuresLimit), - persistent_impact(true), random_seed(CpRandomSeed()), + persistent_impact(true), + random_seed(CpRandomSeed()), display_level(DefaultPhaseParameters::NORMAL), - use_last_conflict(kDefaultUseLastConflict), decision_builder(nullptr) {} + use_last_conflict(kDefaultUseLastConflict), + decision_builder(nullptr) {} namespace { // ----- DomainWatcher ----- @@ -59,7 +62,7 @@ namespace { // This class follows the domains of variables and will report the log of the // search space of all integer variables. class DomainWatcher { -public: + public: DomainWatcher(const std::vector &vars, int cache_size) : vars_(vars) { cached_log_.Init(cache_size); @@ -75,7 +78,7 @@ public: double Log2(int64 size) const { return cached_log_.Log2(size); } -private: + private: std::vector vars_; CachedLog cached_log_; DISALLOW_COPY_AND_ASSIGN(DomainWatcher); @@ -84,13 +87,8 @@ private: // ---------- FindVar decision visitor --------- class FindVar : public DecisionVisitor { -public: - enum Operation { - NONE, - ASSIGN, - SPLIT_LOW, - SPLIT_HIGH - }; + public: + enum Operation { NONE, ASSIGN, SPLIT_LOW, SPLIT_HIGH }; FindVar() : var_(nullptr), value_(0), operation_(NONE) {} @@ -141,7 +139,7 @@ public: return "FindVar decision visitor"; } -private: + private: IntVar *var_; int64 value_; Operation operation_; @@ -152,13 +150,15 @@ private: // This class initialize impacts by scanning each value of the domain // of the variable. class InitVarImpacts : public DecisionBuilder { -public: - // ----- main ----- + public: + // ----- main ----- InitVarImpacts() - : var_(nullptr), update_impact_callback_(nullptr), new_start_(false), - var_index_(0), value_index_(-1), update_impact_closure_([this]() { - UpdateImpacts(); - }), + : var_(nullptr), + update_impact_callback_(nullptr), + new_start_(false), + var_index_(0), + value_index_(-1), + update_impact_closure_([this]() { UpdateImpacts(); }), updater_(update_impact_closure_) { CHECK(update_impact_closure_ != nullptr); } @@ -201,12 +201,13 @@ public: update_impact_callback_ = std::move(callback); } -private: + private: // ----- helper decision ----- class AssignCallFail : public Decision { - public: + public: explicit AssignCallFail(const std::function &update_impact_closure) - : var_(nullptr), value_(0), + : var_(nullptr), + value_(0), update_impact_closure_(update_impact_closure) { CHECK(update_impact_closure_ != nullptr); } @@ -223,7 +224,7 @@ private: IntVar *var_; int64 value_; - private: + private: const std::function &update_impact_closure_; DISALLOW_COPY_AND_ASSIGN(AssignCallFail); }; @@ -243,13 +244,15 @@ private: // intervals on the domain of the variable. class InitVarImpactsWithSplits : public DecisionBuilder { -public: + public: // ----- helper decision ----- class AssignIntervalCallFail : public Decision { - public: + public: explicit AssignIntervalCallFail( const std::function &update_impact_closure) - : var_(nullptr), value_min_(0), value_max_(0), + : var_(nullptr), + value_min_(0), + value_max_(0), update_impact_closure_(update_impact_closure) { CHECK(update_impact_closure_ != nullptr); } @@ -268,19 +271,23 @@ public: int64 value_min_; int64 value_max_; - private: + private: const std::function &update_impact_closure_; DISALLOW_COPY_AND_ASSIGN(AssignIntervalCallFail); }; - // ----- main ----- + // ----- main ----- explicit InitVarImpactsWithSplits(int split_size) - : var_(nullptr), update_impact_callback_(nullptr), new_start_(false), - var_index_(0), min_value_(0), max_value_(0), split_size_(split_size), - split_index_(-1), update_impact_closure_([this]() { - UpdateImpacts(); - }), + : var_(nullptr), + update_impact_callback_(nullptr), + new_start_(false), + var_index_(0), + min_value_(0), + max_value_(0), + split_size_(split_size), + split_index_(-1), + update_impact_closure_([this]() { UpdateImpacts(); }), updater_(update_impact_closure_) { CHECK(update_impact_closure_ != nullptr); } @@ -330,7 +337,7 @@ public: update_impact_callback_ = std::move(callback); } -private: + private: IntVar *var_; std::function update_impact_callback_; bool new_start_; @@ -350,7 +357,7 @@ private: // variables. Its main output is to find the optimal pair (variable/value) // based on default phase parameters. class ImpactRecorder : public SearchMonitor { -public: + public: static const int kLogCacheSize; static const double kPerfectImpact; static const double kFailureImpact; @@ -360,12 +367,18 @@ public: ImpactRecorder(Solver *const solver, DomainWatcher *const domain_watcher, const std::vector &vars, DefaultPhaseParameters::DisplayLevel display_level) - : SearchMonitor(solver), domain_watcher_(domain_watcher), vars_(vars), - size_(vars.size()), current_log_space_(0.0), impacts_(size_), + : SearchMonitor(solver), + domain_watcher_(domain_watcher), + vars_(vars), + size_(vars.size()), + current_log_space_(0.0), + impacts_(size_), original_min_(size_, 0LL), domain_iterators_(new IntVarIterator *[size_]), - display_level_(display_level), current_var_(kUninitializedVarIndex), - current_value_(0), init_done_(false) { + display_level_(display_level), + current_var_(kUninitializedVarIndex), + current_value_(0), + init_done_(false) { for (int i = 0; i < size_; ++i) { domain_iterators_[i] = vars_[i]->MakeDomainIterator(true); var_map_[vars_[i]] = i; @@ -417,8 +430,8 @@ public: // By default, we init impacts to 2.0 -> equivalent to failure. // This will be overwritten to real impact values on valid domain // values during the FirstRun() method. - impacts_[i] - .resize(vars_[i]->Max() - vars_[i]->Min() + 1, kInitFailureImpact); + impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1, + kInitFailureImpact); } for (int i = 0; i < size_; ++i) { @@ -433,7 +446,8 @@ public: const double current_impact = impacts_[var_index][value_index]; const double new_impact = (current_impact * (absl::GetFlag(FLAGS_cp_impact_divider) - 1) + - impact) / absl::GetFlag(FLAGS_cp_impact_divider); + impact) / + absl::GetFlag(FLAGS_cp_impact_divider); impacts_[var_index][value_index] = new_impact; } @@ -469,15 +483,15 @@ public: const bool no_split = var->Size() < splits; if (no_split) { // The domain is small enough, we scan it completely. - container->without_split() - ->set_update_impact_callback(container->update_impact_callback()); + container->without_split()->set_update_impact_callback( + container->update_impact_callback()); container->without_split()->Init(var, iterator, var_index); init_decision_builder = container->without_split(); } else { // The domain is too big, we scan it in initialization_splits // intervals. - container->with_splits() - ->set_update_impact_callback(container->update_impact_callback()); + container->with_splits()->set_update_impact_callback( + container->update_impact_callback()); container->with_splits()->Init(var, iterator, var_index); init_decision_builder = container->with_splits(); } @@ -506,10 +520,10 @@ public: } if (display_level_ != DefaultPhaseParameters::NONE) { if (removed_counter) { - LOG(INFO) - << " - init done, time = " << s->wall_time() - init_time << " ms, " - << removed_counter - << " values removed, log2(SearchSpace) = " << current_log_space_; + LOG(INFO) << " - init done, time = " << s->wall_time() - init_time + << " ms, " << removed_counter + << " values removed, log2(SearchSpace) = " + << current_log_space_; } else { LOG(INFO) << " - init done, time = " << s->wall_time() - init_time << " ms"; @@ -549,45 +563,47 @@ public: } switch (var_select) { - case DefaultPhaseParameters::CHOOSE_MAX_AVERAGE_IMPACT: { - *var_impacts = sum_var_impact / vars_[var_index]->Size(); - break; - } - case DefaultPhaseParameters::CHOOSE_MAX_VALUE_IMPACT: { - *var_impacts = max_impact; - break; - } - default: { - *var_impacts = sum_var_impact; - break; - } + case DefaultPhaseParameters::CHOOSE_MAX_AVERAGE_IMPACT: { + *var_impacts = sum_var_impact / vars_[var_index]->Size(); + break; + } + case DefaultPhaseParameters::CHOOSE_MAX_VALUE_IMPACT: { + *var_impacts = max_impact; + break; + } + default: { + *var_impacts = sum_var_impact; + break; + } } switch (value_select) { - case DefaultPhaseParameters::SELECT_MIN_IMPACT: { - *best_impact_value = min_impact_value; - break; - } - case DefaultPhaseParameters::SELECT_MAX_IMPACT: { - *best_impact_value = max_impact_value; - break; - } + case DefaultPhaseParameters::SELECT_MIN_IMPACT: { + *best_impact_value = min_impact_value; + break; + } + case DefaultPhaseParameters::SELECT_MAX_IMPACT: { + *best_impact_value = max_impact_value; + break; + } } } std::string DebugString() const override { return "ImpactRecorder"; } -private: + private: // A container for the variables needed in FirstRun that is reversibly // allocable. class FirstRunVariableContainers : public BaseObject { - public: + public: FirstRunVariableContainers(ImpactRecorder *impact_recorder, int64 splits) - : update_impact_callback_([impact_recorder](int var_index, - int64 value) { - impact_recorder->InitImpact(var_index, value); - }), - removed_values_(), without_splits_(), with_splits_(splits) {} + : update_impact_callback_( + [impact_recorder](int var_index, int64 value) { + impact_recorder->InitImpact(var_index, value); + }), + removed_values_(), + without_splits_(), + with_splits_(splits) {} std::function update_impact_callback() const { return update_impact_callback_; } @@ -603,7 +619,7 @@ private: return "FirstRunVariableContainers"; } - private: + private: const std::function update_impact_callback_; std::vector removed_values_; InitVarImpacts without_splits_; @@ -618,7 +634,7 @@ private: // original_min_[i] + j to variable i. std::vector > impacts_; std::vector original_min_; - std::unique_ptr domain_iterators_; + std::unique_ptr domain_iterators_; int64 init_count_; const DefaultPhaseParameters::DisplayLevel display_level_; int current_var_; @@ -638,7 +654,7 @@ const int ImpactRecorder::kUninitializedVarIndex = -1; // This structure stores 'var[index] (left?==:!=) value'. class ChoiceInfo { -public: + public: ChoiceInfo() : value_(0), var_(nullptr), left_(false) {} ChoiceInfo(IntVar *const var, int64 value, bool left) @@ -657,7 +673,7 @@ public: void set_left(bool left) { left_ = left; } -private: + private: int64 value_; IntVar *var_; bool left_; @@ -666,14 +682,17 @@ private: // ---------- Heuristics ---------- class RunHeuristicsAsDives : public Decision { -public: + public: RunHeuristicsAsDives(Solver *const solver, const std::vector &vars, DefaultPhaseParameters::DisplayLevel level, bool run_all_heuristics, int random_seed, int heuristic_period, int heuristic_num_failures_limit) - : heuristic_limit_(nullptr), display_level_(level), - run_all_heuristics_(run_all_heuristics), random_(random_seed), - heuristic_period_(heuristic_period), heuristic_branch_count_(0), + : heuristic_limit_(nullptr), + display_level_(level), + run_all_heuristics_(run_all_heuristics), + random_(random_seed), + heuristic_period_(heuristic_period), + heuristic_branch_count_(0), heuristic_runs_(0) { Init(solver, vars, heuristic_num_failures_limit); } @@ -771,7 +790,7 @@ public: int heuristic_runs() const { return heuristic_runs_; } -private: + private: // This class wraps one heuristic with extra information: name and // number of runs. struct HeuristicWrapper { @@ -780,7 +799,8 @@ private: Solver::IntValueStrategy value_strategy, const std::string &heuristic_name, int heuristic_runs) : phase(solver->MakePhase(vars, var_strategy, value_strategy)), - name(heuristic_name), runs(heuristic_runs) {} + name(heuristic_name), + runs(heuristic_runs) {} // The decision builder we are going to use in this dive. DecisionBuilder *const phase; @@ -806,12 +826,13 @@ private: // Default phase decision builder. class DefaultIntegerSearch : public DecisionBuilder { -public: + public: static const double kSmallSearchSpaceLimit; DefaultIntegerSearch(Solver *const solver, const std::vector &vars, const DefaultPhaseParameters ¶meters) - : vars_(vars), parameters_(parameters), + : vars_(vars), + parameters_(parameters), domain_watcher_(vars, ImpactRecorder::kLogCacheSize), impact_recorder_(solver, &domain_watcher_, vars, parameters.display_level), @@ -819,8 +840,11 @@ public: parameters_.run_all_heuristics, parameters_.random_seed, parameters_.heuristic_period, parameters_.heuristic_num_failures_limit), - find_var_(), last_int_var_(nullptr), last_int_value_(0), - last_operation_(FindVar::NONE), last_conflict_count_(0), + find_var_(), + last_int_var_(nullptr), + last_int_value_(0), + last_operation_(FindVar::NONE), + last_conflict_count_(0), init_done_(false) {} ~DefaultIntegerSearch() override {} @@ -861,39 +885,41 @@ public: !last_int_var_->Bound() && (decision_var == nullptr || decision_var != last_int_var_)) { switch (last_operation_) { - case FindVar::ASSIGN: { - if (last_int_var_->Contains(last_int_value_)) { - Decision *const assign = - solver->MakeAssignVariableValue(last_int_var_, last_int_value_); - ClearLastDecision(); - last_conflict_count_++; - return assign; + case FindVar::ASSIGN: { + if (last_int_var_->Contains(last_int_value_)) { + Decision *const assign = + solver->MakeAssignVariableValue(last_int_var_, last_int_value_); + ClearLastDecision(); + last_conflict_count_++; + return assign; + } + break; } - break; - } - case FindVar::SPLIT_LOW: { - if (last_int_var_->Max() > last_int_value_ && - last_int_var_->Min() <= last_int_value_) { - Decision *const split = solver->MakeVariableLessOrEqualValue( - last_int_var_, last_int_value_); - ClearLastDecision(); - last_conflict_count_++; - return split; + case FindVar::SPLIT_LOW: { + if (last_int_var_->Max() > last_int_value_ && + last_int_var_->Min() <= last_int_value_) { + Decision *const split = solver->MakeVariableLessOrEqualValue( + last_int_var_, last_int_value_); + ClearLastDecision(); + last_conflict_count_++; + return split; + } + break; } - break; - } - case FindVar::SPLIT_HIGH: { - if (last_int_var_->Min() < last_int_value_ && - last_int_var_->Max() >= last_int_value_) { - Decision *const split = solver->MakeVariableGreaterOrEqualValue( - last_int_var_, last_int_value_); - ClearLastDecision(); - last_conflict_count_++; - return split; + case FindVar::SPLIT_HIGH: { + if (last_int_var_->Min() < last_int_value_ && + last_int_var_->Max() >= last_int_value_) { + Decision *const split = solver->MakeVariableGreaterOrEqualValue( + last_int_var_, last_int_value_); + ClearLastDecision(); + last_conflict_count_++; + return split; + } + break; + } + default: { + break; } - break; - } - default: { break; } } } @@ -973,7 +999,7 @@ public: return result; } -private: + private: void CheckInit(Solver *const solver) { if (init_done_) { return; @@ -1010,12 +1036,12 @@ private: } if (parameters_.display_level != DefaultPhaseParameters::NONE) { - LOG(INFO) - << "Init impact based search phase on " << vars_.size() - << " variables, initialization splits = " - << parameters_.initialization_splits - << ", heuristic_period = " << parameters_.heuristic_period - << ", run_all_heuristics = " << parameters_.run_all_heuristics; + LOG(INFO) << "Init impact based search phase on " << vars_.size() + << " variables, initialization splits = " + << parameters_.initialization_splits + << ", heuristic_period = " << parameters_.heuristic_period + << ", run_all_heuristics = " + << parameters_.run_all_heuristics; } // Init the impacts. impact_recorder_.FirstRun(parameters_.initialization_splits); @@ -1072,7 +1098,7 @@ private: }; const double DefaultIntegerSearch::kSmallSearchSpaceLimit = 10.0; -} // namespace +} // namespace // ---------- API ---------- @@ -1086,9 +1112,9 @@ DecisionBuilder *Solver::MakeDefaultPhase(const std::vector &vars) { return MakeDefaultPhase(vars, parameters); } -DecisionBuilder * -Solver::MakeDefaultPhase(const std::vector &vars, - const DefaultPhaseParameters ¶meters) { +DecisionBuilder *Solver::MakeDefaultPhase( + const std::vector &vars, + const DefaultPhaseParameters ¶meters) { return RevAlloc(new DefaultIntegerSearch(this, vars, parameters)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/demon_profiler.cc b/ortools/constraint_solver/demon_profiler.cc index e82fc42827..f75aafad95 100644 --- a/ortools/constraint_solver/demon_profiler.cc +++ b/ortools/constraint_solver/demon_profiler.cc @@ -42,16 +42,18 @@ struct Container { const Constraint *ct; int64 value; }; -} // namespace +} // namespace // DemonProfiler manages the profiling of demons and allows access to gathered // data. Add this class as a parameter to Solver and access its information // after the end of a search. class DemonProfiler : public PropagationMonitor { -public: + public: explicit DemonProfiler(Solver *const solver) - : PropagationMonitor(solver), active_constraint_(nullptr), - active_demon_(nullptr), start_time_ns_(absl::GetCurrentTimeNanos()) {} + : PropagationMonitor(solver), + active_constraint_(nullptr), + active_demon_(nullptr), + start_time_ns_(absl::GetCurrentTimeNanos()) {} ~DemonProfiler() override { gtl::STLDeleteContainerPairSecondPointers(constraint_map_.begin(), @@ -64,8 +66,8 @@ public: return (absl::GetCurrentTimeNanos() - start_time_ns_) / 1000; } - void BeginConstraintInitialPropagation(Constraint *const constraint) - override { + void BeginConstraintInitialPropagation( + Constraint *const constraint) override { if (solver()->state() == Solver::IN_SEARCH) { return; } @@ -93,9 +95,8 @@ public: active_constraint_ = nullptr; } - void BeginNestedConstraintInitialPropagation(Constraint *const constraint, - Constraint *const delayed) - override { + void BeginNestedConstraintInitialPropagation( + Constraint *const constraint, Constraint *const delayed) override { if (solver()->state() == Solver::IN_SEARCH) { return; } @@ -109,9 +110,8 @@ public: active_constraint_ = constraint; } - void EndNestedConstraintInitialPropagation(Constraint *const constraint, - Constraint *const delayed) - override { + void EndNestedConstraintInitialPropagation( + Constraint *const constraint, Constraint *const delayed) override { CHECK(active_constraint_ != nullptr); CHECK(active_demon_ == nullptr); CHECK(constraint != nullptr); @@ -216,21 +216,21 @@ public: void RemoveInterval(IntVar *const var, int64 imin, int64 imax) override {} void SetValues(IntVar *const var, const std::vector &values) override { } - void RemoveValues(IntVar *const var, const std::vector &values) - override {} + void RemoveValues(IntVar *const var, + const std::vector &values) override {} // IntervalVar modifiers. void SetStartMin(IntervalVar *const var, int64 new_min) override {} void SetStartMax(IntervalVar *const var, int64 new_max) override {} - void SetStartRange(IntervalVar *const var, int64 new_min, int64 new_max) - override {} + void SetStartRange(IntervalVar *const var, int64 new_min, + int64 new_max) override {} void SetEndMin(IntervalVar *const var, int64 new_min) override {} void SetEndMax(IntervalVar *const var, int64 new_max) override {} - void SetEndRange(IntervalVar *const var, int64 new_min, int64 new_max) - override {} + void SetEndRange(IntervalVar *const var, int64 new_min, + int64 new_max) override {} void SetDurationMin(IntervalVar *const var, int64 new_min) override {} void SetDurationMax(IntervalVar *const var, int64 new_max) override {} - void SetDurationRange(IntervalVar *const var, int64 new_min, int64 new_max) - override {} + void SetDurationRange(IntervalVar *const var, int64 new_min, + int64 new_max) override {} void SetPerformed(IntervalVar *const var, bool value) override {} void RankFirst(SequenceVar *const var, int index) override {} void RankNotFirst(SequenceVar *const var, int index) override {} @@ -417,7 +417,7 @@ public: std::string DebugString() const override { return "DemonProfiler"; } -private: + private: Constraint *active_constraint_; Demon *active_demon_; const int64 start_time_ns_; @@ -489,4 +489,4 @@ void DemonProfilerEndInitialPropagation(DemonProfiler *const monitor, monitor->EndConstraintInitialPropagation(constraint); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/deviation.cc b/ortools/constraint_solver/deviation.cc index eb5fcb8b64..ba3aeeac66 100644 --- a/ortools/constraint_solver/deviation.cc +++ b/ortools/constraint_solver/deviation.cc @@ -30,16 +30,24 @@ namespace operations_research { // Constraint, Pierre Schaus et. al., CP07 namespace { class Deviation : public Constraint { -public: + public: Deviation(Solver *const solver, const std::vector &vars, IntVar *const deviation_var, int64 total_sum) - : Constraint(solver), vars_(vars), size_(vars.size()), - deviation_var_(deviation_var), total_sum_(total_sum), + : Constraint(solver), + vars_(vars), + size_(vars.size()), + deviation_var_(deviation_var), + total_sum_(total_sum), scaled_vars_assigned_value_(new int64[size_]), - scaled_vars_min_(new int64[size_]), scaled_vars_max_(new int64[size_]), - scaled_sum_max_(0), scaled_sum_min_(0), maximum_(new int64[size_]), - overlaps_sup_(new int64[size_]), active_sum_(0), - active_sum_rounded_down_(0), active_sum_rounded_up_(0), + scaled_vars_min_(new int64[size_]), + scaled_vars_max_(new int64[size_]), + scaled_sum_max_(0), + scaled_sum_min_(0), + maximum_(new int64[size_]), + overlaps_sup_(new int64[size_]), + active_sum_(0), + active_sum_rounded_down_(0), + active_sum_rounded_up_(0), active_sum_nearest_(0) { CHECK(deviation_var != nullptr); } @@ -78,7 +86,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDeviation, this); } -private: + private: // Builds an assignment with minimal deviation and assign it to // scaled_vars_assigned_value_. It returns the minimal deviation: // sum_i |scaled_vars_assigned_value_[i] - total_sum_|. @@ -98,8 +106,8 @@ private: // - min deviation smaller than max allowed deviation // min_delta is the minimum possible deviation void PropagateBounds(int64 min_delta) { - PropagateBounds(min_delta, true); // Filter upper bounds. - PropagateBounds(min_delta, false); // Filter lower bounds. + PropagateBounds(min_delta, true); // Filter upper bounds. + PropagateBounds(min_delta, false); // Filter lower bounds. } // Prunes the upper/lower-bound of vars. We apply a mirroing of the @@ -267,10 +275,10 @@ private: // Computation of key values for the pruning: // - overlaps_sup_ // - maximum_[i] - if (greedy_sum == scaled_total_sum) { // No repair needed. + if (greedy_sum == scaled_total_sum) { // No repair needed. ComputeMaxWhenNoRepair(); - } else { // Repair and compute maximums. - // Try to repair the sum greedily. + } else { // Repair and compute maximums. + // Try to repair the sum greedily. if (CanPushSumAcrossMean(greedy_sum, scaled_total_sum)) { const int64 delta = greedy_sum > scaled_total_sum ? -size_ : size_; for (int j = 0; j < overlaps_.size() && greedy_sum != scaled_total_sum; @@ -302,7 +310,7 @@ private: maximum_[i] = scaled_vars_assigned_value_[i]; overlaps_sup_[i] = 0; } - } else { // greedy_sum < scaled_total_sum. + } else { // greedy_sum < scaled_total_sum. for (int i = 0; i < size_; ++i) { if (Overlap(i) && num_overlap_sum_rounded_up > 0) { overlaps_sup_[i] = num_overlap_sum_rounded_up - 1; @@ -365,7 +373,7 @@ private: maximum_value += size_ * overlaps_sup_[var_index]; // Slope of 2 x n. const int64 delta = deviation_var_->Max() - current_min_delta; - maximum_value += delta / 2; // n * delta / (2 * n); + maximum_value += delta / 2; // n * delta / (2 * n); return MathUtil::FloorOfRatio(maximum_value, size_); } } @@ -398,11 +406,11 @@ private: int64 active_sum_rounded_up_; int64 active_sum_nearest_; }; -} // namespace +} // namespace Constraint *Solver::MakeDeviation(const std::vector &vars, IntVar *const deviation_var, int64 total_sum) { return RevAlloc(new Deviation(this, vars, deviation_var, total_sum)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/diffn.cc b/ortools/constraint_solver/diffn.cc index a5ddc747a5..beff05d85f 100644 --- a/ortools/constraint_solver/diffn.cc +++ b/ortools/constraint_solver/diffn.cc @@ -30,13 +30,19 @@ namespace operations_research { namespace { DEFINE_INT_TYPE(Box, int); class Diffn : public Constraint { -public: + public: Diffn(Solver *const solver, const std::vector &x_vars, const std::vector &y_vars, const std::vector &x_size, const std::vector &y_size, bool strict) - : Constraint(solver), x_(x_vars), y_(y_vars), dx_(x_size), dy_(y_size), - strict_(strict), size_(x_vars.size()), fail_stamp_(0) { + : Constraint(solver), + x_(x_vars), + y_(y_vars), + dx_(x_size), + dy_(y_size), + strict_(strict), + size_(x_vars.size()), + fail_stamp_(0) { CHECK_EQ(x_vars.size(), y_vars.size()); CHECK_EQ(x_vars.size(), x_size.size()); CHECK_EQ(x_vars.size(), y_size.size()); @@ -130,7 +136,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kDisjunctive, this); } -private: + private: void PropagateAll() { for (const int box : to_propagate_) { FillNeighbors(box); @@ -233,35 +239,37 @@ private: // This is an "hack" to be able to easily test for none or for one // and only one of the conditions below. switch (state) { - case 0: { - solver()->Fail(); - break; - } - case 1: { // We push other left (x increasing). - x_[other]->SetMin(x_[box]->Min() + dx_[box]->Min()); - x_[box]->SetMax(x_[other]->Max() - dx_[box]->Min()); - dx_[box]->SetMax(x_[other]->Max() - x_[box]->Min()); - break; - } - case 2: { // We push other right (x decreasing). - x_[box]->SetMin(x_[other]->Min() + dx_[other]->Min()); - x_[other]->SetMax(x_[box]->Max() - dx_[other]->Min()); - dx_[other]->SetMax(x_[box]->Max() - x_[other]->Min()); - break; - } - case 4: { // We push other up (y increasing). - y_[other]->SetMin(y_[box]->Min() + dy_[box]->Min()); - y_[box]->SetMax(y_[other]->Max() - dy_[box]->Min()); - dy_[box]->SetMax(y_[other]->Max() - y_[box]->Min()); - break; - } - case 8: { // We push other down (y decreasing). - y_[box]->SetMin(y_[other]->Min() + dy_[other]->Min()); - y_[other]->SetMax(y_[box]->Max() - dy_[other]->Min()); - dy_[other]->SetMax(y_[box]->Max() - y_[other]->Min()); - break; - } - default: { break; } + case 0: { + solver()->Fail(); + break; + } + case 1: { // We push other left (x increasing). + x_[other]->SetMin(x_[box]->Min() + dx_[box]->Min()); + x_[box]->SetMax(x_[other]->Max() - dx_[box]->Min()); + dx_[box]->SetMax(x_[other]->Max() - x_[box]->Min()); + break; + } + case 2: { // We push other right (x decreasing). + x_[box]->SetMin(x_[other]->Min() + dx_[other]->Min()); + x_[other]->SetMax(x_[box]->Max() - dx_[other]->Min()); + dx_[other]->SetMax(x_[box]->Max() - x_[other]->Min()); + break; + } + case 4: { // We push other up (y increasing). + y_[other]->SetMin(y_[box]->Min() + dy_[box]->Min()); + y_[box]->SetMax(y_[other]->Max() - dy_[box]->Min()); + dy_[box]->SetMax(y_[other]->Max() - y_[box]->Min()); + break; + } + case 8: { // We push other down (y decreasing). + y_[box]->SetMin(y_[other]->Min() + dy_[other]->Min()); + y_[other]->SetMax(y_[box]->Max() - dy_[other]->Min()); + dy_[other]->SetMax(y_[box]->Max() - y_[other]->Min()); + break; + } + default: { + break; + } } } @@ -286,7 +294,7 @@ private: std::vector neighbors_; uint64 fail_stamp_; }; -} // namespace +} // namespace Constraint *Solver::MakeNonOverlappingBoxesConstraint( const std::vector &x_vars, const std::vector &y_vars, @@ -347,4 +355,4 @@ Constraint *Solver::MakeNonOverlappingNonStrictBoxesConstraint( } return RevAlloc(new Diffn(this, x_vars, y_vars, dx, dy, false)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/element.cc b/ortools/constraint_solver/element.cc index aabdb68c10..38ac25d443 100644 --- a/ortools/constraint_solver/element.cc +++ b/ortools/constraint_solver/element.cc @@ -37,32 +37,34 @@ void LinkVarExpr(Solver *const s, IntExpr *const expr, IntVar *const var); namespace { -template class VectorLess { -public: +template +class VectorLess { + public: explicit VectorLess(const std::vector *values) : values_(values) {} bool operator()(const T &x, const T &y) const { return (*values_)[x] < (*values_)[y]; } -private: + private: const std::vector *values_; }; -template class VectorGreater { -public: +template +class VectorGreater { + public: explicit VectorGreater(const std::vector *values) : values_(values) {} bool operator()(const T &x, const T &y) const { return (*values_)[x] > (*values_)[y]; } -private: + private: const std::vector *values_; }; // ----- BaseIntExprElement ----- class BaseIntExprElement : public BaseIntExpr { -public: + public: BaseIntExprElement(Solver *const s, IntVar *const e); ~BaseIntExprElement() override {} int64 Min() const override; @@ -75,14 +77,14 @@ public: // TODO(user) : improve me, the previous test is not always true void WhenRange(Demon *d) override { expr_->WhenRange(d); } -protected: + protected: virtual int64 ElementValue(int index) const = 0; virtual int64 ExprMin() const = 0; virtual int64 ExprMax() const = 0; IntVar *const expr_; -private: + private: void UpdateSupports() const; mutable int64 min_; @@ -94,8 +96,13 @@ private: }; BaseIntExprElement::BaseIntExprElement(Solver *const s, IntVar *const e) - : BaseIntExpr(s), expr_(e), min_(0), min_support_(-1), max_(0), - max_support_(-1), initial_update_(true), + : BaseIntExpr(s), + expr_(e), + min_(0), + min_support_(-1), + max_(0), + max_support_(-1), + initial_update_(true), expr_iterator_(expr_->MakeDomainIterator(true)) { CHECK(s != nullptr); CHECK(e != nullptr); @@ -117,24 +124,24 @@ void BaseIntExprElement::Range(int64 *mi, int64 *ma) { *ma = max_; } -#define UPDATE_BASE_ELEMENT_INDEX_BOUNDS(test) \ - const int64 emin = ExprMin(); \ - const int64 emax = ExprMax(); \ - int64 nmin = emin; \ - int64 value = ElementValue(nmin); \ - while (nmin < emax && test) { \ - nmin++; \ - value = ElementValue(nmin); \ - } \ - if (nmin == emax && test) { \ - solver()->Fail(); \ - } \ - int64 nmax = emax; \ - value = ElementValue(nmax); \ - while (nmax >= nmin && test) { \ - nmax--; \ - value = ElementValue(nmax); \ - } \ +#define UPDATE_BASE_ELEMENT_INDEX_BOUNDS(test) \ + const int64 emin = ExprMin(); \ + const int64 emax = ExprMax(); \ + int64 nmin = emin; \ + int64 value = ElementValue(nmin); \ + while (nmin < emax && test) { \ + nmin++; \ + value = ElementValue(nmin); \ + } \ + if (nmin == emax && test) { \ + solver()->Fail(); \ + } \ + int64 nmax = emax; \ + value = ElementValue(nmax); \ + while (nmax >= nmin && test) { \ + nmax--; \ + value = ElementValue(nmax); \ + } \ expr_->SetRange(nmin, nmax); void BaseIntExprElement::SetMin(int64 m) { @@ -207,10 +214,12 @@ void BaseIntExprElement::UpdateSupports() const { // It scans the bounds of 'elem' to propagate on the domain of 'index'. // It scans the domain of 'index' to compute the new bounds of 'elem'. class IntElementConstraint : public CastConstraint { -public: + public: IntElementConstraint(Solver *const s, const std::vector &values, IntVar *const index, IntVar *const elem) - : CastConstraint(s, elem), values_(values), index_(index), + : CastConstraint(s, elem), + values_(values), + index_(index), index_iterator_(index_->MakeDomainIterator(true)) { CHECK(index != nullptr); } @@ -264,7 +273,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this); } -private: + private: const std::vector values_; IntVar *const index_; IntVarIterator *const index_iterator_; @@ -276,7 +285,7 @@ private: IntVar *BuildDomainIntVar(Solver *const solver, std::vector *values); class IntExprElement : public BaseIntExprElement { -public: + public: IntExprElement(Solver *const s, const std::vector &vals, IntVar *const expr) : BaseIntExprElement(s, expr), values_(vals) {} @@ -322,7 +331,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this); } -protected: + protected: int64 ElementValue(int index) const override { DCHECK_LT(index, values_.size()); return values_[index]; @@ -333,14 +342,14 @@ protected: : std::min(values_.size() - 1, expr_->Max()); } -private: + private: const std::vector values_; }; // ----- Range Minimum Query-based Element ----- class RangeMinimumQueryExprElement : public BaseIntExpr { -public: + public: RangeMinimumQueryExprElement(Solver *solver, const std::vector &values, IntVar *index); ~RangeMinimumQueryExprElement() override {} @@ -372,7 +381,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this); } -private: + private: int64 IndexMin() const { return std::max(0, index_->Min()); } int64 IndexMax() const { return std::min(min_rmq_.array().size() - 1, index_->Max()); @@ -405,23 +414,23 @@ void RangeMinimumQueryExprElement::Range(int64 *mi, int64 *ma) { *ma = max_rmq_.GetMinimumFromRange(range_min, range_max); } -#define UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS(test) \ - const std::vector &values = min_rmq_.array(); \ - int64 index_min = IndexMin(); \ - int64 index_max = IndexMax(); \ - int64 value = values[index_min]; \ - while (index_min < index_max && (test)) { \ - index_min++; \ - value = values[index_min]; \ - } \ - if (index_min == index_max && (test)) { \ - solver()->Fail(); \ - } \ - value = values[index_max]; \ - while (index_max >= index_min && (test)) { \ - index_max--; \ - value = values[index_max]; \ - } \ +#define UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS(test) \ + const std::vector &values = min_rmq_.array(); \ + int64 index_min = IndexMin(); \ + int64 index_max = IndexMax(); \ + int64 value = values[index_min]; \ + while (index_min < index_max && (test)) { \ + index_min++; \ + value = values[index_min]; \ + } \ + if (index_min == index_max && (test)) { \ + solver()->Fail(); \ + } \ + value = values[index_max]; \ + while (index_max >= index_min && (test)) { \ + index_max--; \ + value = values[index_max]; \ + } \ index_->SetRange(index_min, index_max); void RangeMinimumQueryExprElement::SetMin(int64 m) { @@ -444,7 +453,7 @@ void RangeMinimumQueryExprElement::SetRange(int64 mi, int64 ma) { // ----- Increasing Element ----- class IncreasingIntExprElement : public BaseIntExpr { -public: + public: IncreasingIntExprElement(Solver *const s, const std::vector &values, IntVar *const index); ~IncreasingIntExprElement() override {} @@ -482,7 +491,7 @@ public: return var; } -private: + private: const std::vector values_; IntVar *const index_; }; @@ -577,16 +586,13 @@ IntExpr *BuildElement(Solver *const solver, const std::vector &values, } } if (ones.size() == 1) { - DCHECK_EQ(int64 { - 1 - }, - values[ones.back()]); + DCHECK_EQ(int64{1}, values[ones.back()]); solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1)); return solver->MakeIsEqualCstVar(index, ones.back()); } else if (ones.size() == values.size() - 1) { solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1)); return solver->MakeIsDifferentCstVar(index, first_zero); - } else if (ones.size() == ones.back() - ones.front() + 1) { // contiguous. + } else if (ones.size() == ones.back() - ones.front() + 1) { // contiguous. solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1)); IntVar *const b = solver->MakeBoolVar("ContiguousBooleanElementVar"); solver->AddConstraint( @@ -636,7 +642,7 @@ IntExpr *BuildElement(Solver *const solver, const std::vector &values, return result; } } -} // namespace +} // namespace IntExpr *Solver::MakeElement(const std::vector &values, IntVar *const index) { @@ -662,7 +668,7 @@ IntExpr *Solver::MakeElement(const std::vector &values, namespace { class IntExprFunctionElement : public BaseIntExprElement { -public: + public: IntExprFunctionElement(Solver *const s, Solver::IndexEvaluator1 values, IntVar *const e); ~IntExprFunctionElement() override; @@ -684,12 +690,12 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this); } -protected: + protected: int64 ElementValue(int index) const override { return values_(index); } int64 ExprMin() const override { return expr_->Min(); } int64 ExprMax() const override { return expr_->Max(); } -private: + private: Solver::IndexEvaluator1 values_; }; @@ -705,7 +711,7 @@ IntExprFunctionElement::~IntExprFunctionElement() {} // ----- Increasing Element ----- class IncreasingIntExprFunctionElement : public BaseIntExpr { -public: + public: IncreasingIntExprFunctionElement(Solver *const s, Solver::IndexEvaluator1 values, IntVar *const index) @@ -787,7 +793,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this); } -private: + private: int64 FindNewIndexMin(int64 index_min, int64 index_max, int64 m) { if (m <= values_(index_min)) { return index_min; @@ -841,7 +847,7 @@ private: Solver::IndexEvaluator1 values_; IntVar *const index_; }; -} // namespace +} // namespace IntExpr *Solver::MakeElement(Solver::IndexEvaluator1 values, IntVar *const index) { @@ -861,8 +867,7 @@ IntExpr *Solver::MakeMonotonicElement(Solver::IndexEvaluator1 values, // dandling reference when leaving this scope. Solver::IndexEvaluator1 opposite_values = [values](int64 i) { return -values(i); - } - ; + }; return RegisterIntExpr(MakeOpposite(RevAlloc( new IncreasingIntExprFunctionElement(this, opposite_values, index)))); } @@ -872,7 +877,7 @@ IntExpr *Solver::MakeMonotonicElement(Solver::IndexEvaluator1 values, namespace { class IntIntExprFunctionElement : public BaseIntExpr { -public: + public: IntIntExprFunctionElement(Solver *const s, Solver::IndexEvaluator2 values, IntVar *const expr1, IntVar *const expr2); ~IntIntExprFunctionElement() override; @@ -905,15 +910,14 @@ public: visitor->VisitIntegerArgument(ModelVisitor::kMinArgument, expr1_min); visitor->VisitIntegerArgument(ModelVisitor::kMaxArgument, expr1_max); for (int i = expr1_min; i <= expr1_max; ++i) { - visitor->VisitInt64ToInt64Extension([this, i](int64 j) { - return values_(i, j); - }, - expr2_->Min(), expr2_->Max()); + visitor->VisitInt64ToInt64Extension( + [this, i](int64 j) { return values_(i, j); }, expr2_->Min(), + expr2_->Max()); } visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this); } -private: + private: int64 ElementValue(int index1, int index2) const { return values_(index1, index2); } @@ -936,9 +940,17 @@ private: IntIntExprFunctionElement::IntIntExprFunctionElement( Solver *const s, Solver::IndexEvaluator2 values, IntVar *const expr1, IntVar *const expr2) - : BaseIntExpr(s), expr1_(expr1), expr2_(expr2), min_(0), min_support1_(-1), - min_support2_(-1), max_(0), max_support1_(-1), max_support2_(-1), - initial_update_(true), values_(std::move(values)), + : BaseIntExpr(s), + expr1_(expr1), + expr2_(expr2), + min_(0), + min_support1_(-1), + min_support2_(-1), + max_(0), + max_support1_(-1), + max_support2_(-1), + initial_update_(true), + values_(std::move(values)), expr1_iterator_(expr1_->MakeDomainIterator(true)), expr2_iterator_(expr2_->MakeDomainIterator(true)) { CHECK(values_ != nullptr); @@ -962,74 +974,74 @@ void IntIntExprFunctionElement::Range(int64 *lower_bound, int64 *upper_bound) { *upper_bound = max_; } -#define UPDATE_ELEMENT_INDEX_BOUNDS(test) \ - const int64 emin1 = expr1_->Min(); \ - const int64 emax1 = expr1_->Max(); \ - const int64 emin2 = expr2_->Min(); \ - const int64 emax2 = expr2_->Max(); \ - int64 nmin1 = emin1; \ - bool found = false; \ - while (nmin1 <= emax1 && !found) { \ - for (int i = emin2; i <= emax2; ++i) { \ - int64 value = ElementValue(nmin1, i); \ - if (test) { \ - found = true; \ - break; \ - } \ - } \ - if (!found) { \ - nmin1++; \ - } \ - } \ - if (nmin1 > emax1) { \ - solver()->Fail(); \ - } \ - int64 nmin2 = emin2; \ - found = false; \ - while (nmin2 <= emax2 && !found) { \ - for (int i = emin1; i <= emax1; ++i) { \ - int64 value = ElementValue(i, nmin2); \ - if (test) { \ - found = true; \ - break; \ - } \ - } \ - if (!found) { \ - nmin2++; \ - } \ - } \ - if (nmin2 > emax2) { \ - solver()->Fail(); \ - } \ - int64 nmax1 = emax1; \ - found = false; \ - while (nmax1 >= nmin1 && !found) { \ - for (int i = emin2; i <= emax2; ++i) { \ - int64 value = ElementValue(nmax1, i); \ - if (test) { \ - found = true; \ - break; \ - } \ - } \ - if (!found) { \ - nmax1--; \ - } \ - } \ - int64 nmax2 = emax2; \ - found = false; \ - while (nmax2 >= nmin2 && !found) { \ - for (int i = emin1; i <= emax1; ++i) { \ - int64 value = ElementValue(i, nmax2); \ - if (test) { \ - found = true; \ - break; \ - } \ - } \ - if (!found) { \ - nmax2--; \ - } \ - } \ - expr1_->SetRange(nmin1, nmax1); \ +#define UPDATE_ELEMENT_INDEX_BOUNDS(test) \ + const int64 emin1 = expr1_->Min(); \ + const int64 emax1 = expr1_->Max(); \ + const int64 emin2 = expr2_->Min(); \ + const int64 emax2 = expr2_->Max(); \ + int64 nmin1 = emin1; \ + bool found = false; \ + while (nmin1 <= emax1 && !found) { \ + for (int i = emin2; i <= emax2; ++i) { \ + int64 value = ElementValue(nmin1, i); \ + if (test) { \ + found = true; \ + break; \ + } \ + } \ + if (!found) { \ + nmin1++; \ + } \ + } \ + if (nmin1 > emax1) { \ + solver()->Fail(); \ + } \ + int64 nmin2 = emin2; \ + found = false; \ + while (nmin2 <= emax2 && !found) { \ + for (int i = emin1; i <= emax1; ++i) { \ + int64 value = ElementValue(i, nmin2); \ + if (test) { \ + found = true; \ + break; \ + } \ + } \ + if (!found) { \ + nmin2++; \ + } \ + } \ + if (nmin2 > emax2) { \ + solver()->Fail(); \ + } \ + int64 nmax1 = emax1; \ + found = false; \ + while (nmax1 >= nmin1 && !found) { \ + for (int i = emin2; i <= emax2; ++i) { \ + int64 value = ElementValue(nmax1, i); \ + if (test) { \ + found = true; \ + break; \ + } \ + } \ + if (!found) { \ + nmax1--; \ + } \ + } \ + int64 nmax2 = emax2; \ + found = false; \ + while (nmax2 >= nmin2 && !found) { \ + for (int i = emin1; i <= emax1; ++i) { \ + int64 value = ElementValue(i, nmax2); \ + if (test) { \ + found = true; \ + break; \ + } \ + } \ + if (!found) { \ + nmax2--; \ + } \ + } \ + expr1_->SetRange(nmin1, nmax1); \ expr2_->SetRange(nmin2, nmax2); void IntIntExprFunctionElement::SetMin(int64 lower_bound) { @@ -1085,7 +1097,7 @@ void IntIntExprFunctionElement::UpdateSupports() const { s->SaveAndSetValue(&initial_update_, false); } } -} // namespace +} // namespace IntExpr *Solver::MakeElement(Solver::IndexEvaluator2 values, IntVar *const index1, IntVar *const index2) { @@ -1100,10 +1112,12 @@ IntExpr *Solver::MakeElement(Solver::IndexEvaluator2 values, // ----- IfThenElseCt ----- class IfThenElseCt : public CastConstraint { -public: + public: IfThenElseCt(Solver *const solver, IntVar *const condition, IntExpr *const one, IntExpr *const zero, IntVar *const target) - : CastConstraint(solver, target), condition_(condition), zero_(zero), + : CastConstraint(solver, target), + condition_(condition), + zero_(zero), one_(one) {} ~IfThenElseCt() override {} @@ -1159,7 +1173,7 @@ public: void Accept(ModelVisitor *const visitor) const override {} -private: + private: IntVar *const condition_; IntExpr *const zero_; IntExpr *const one_; @@ -1173,7 +1187,7 @@ private: namespace { class IntExprEvaluatorElementCt : public CastConstraint { -public: + public: IntExprEvaluatorElementCt(Solver *const s, Solver::Int64ToIntVar evaluator, int64 range_start, int64 range_end, IntVar *const index, IntVar *const target_var); @@ -1189,10 +1203,10 @@ public: std::string DebugString() const override; void Accept(ModelVisitor *const visitor) const override; -protected: + protected: IntVar *const index_; -private: + private: const Solver::Int64ToIntVar evaluator_; const int64 range_start_; const int64 range_end_; @@ -1203,9 +1217,13 @@ private: IntExprEvaluatorElementCt::IntExprEvaluatorElementCt( Solver *const s, Solver::Int64ToIntVar evaluator, int64 range_start, int64 range_end, IntVar *const index, IntVar *const target_var) - : CastConstraint(s, target_var), index_(index), - evaluator_(std::move(evaluator)), range_start_(range_start), - range_end_(range_end), min_support_(-1), max_support_(-1) {} + : CastConstraint(s, target_var), + index_(index), + evaluator_(std::move(evaluator)), + range_start_(range_start), + range_end_(range_end), + min_support_(-1), + max_support_(-1) {} void IntExprEvaluatorElementCt::Post() { Demon *const delayed_propagate_demon = MakeDelayedConstraintDemon0( @@ -1235,7 +1253,7 @@ void IntExprEvaluatorElementCt::Propagate() { const int64 vmin = target_var_->Min(); const int64 vmax = target_var_->Max(); if (emin == emax) { - index_->SetValue(emin); // in case it was reduced by the above min/max. + index_->SetValue(emin); // in case it was reduced by the above min/max. evaluator_(emin)->SetRange(vmin, vmax); } else { int64 nmin = emin; @@ -1244,8 +1262,7 @@ void IntExprEvaluatorElementCt::Propagate() { // [evaluator_(nmin)->Min(), evaluator_(nmin)->Max()] and [vmin, vmax] // is non-empty. IntVar *const nmin_var = evaluator_(nmin); - if (nmin_var->Min() <= vmax && nmin_var->Max() >= vmin) - break; + if (nmin_var->Min() <= vmax && nmin_var->Max() >= vmin) break; } int64 nmax = emax; for (; nmin <= nmax; nmax--) { @@ -1253,8 +1270,7 @@ void IntExprEvaluatorElementCt::Propagate() { // [evaluator_(nmin)->Min(), evaluator_(nmin)->Max()] and [vmin, vmax] // is non-empty. IntExpr *const nmax_var = evaluator_(nmax); - if (nmax_var->Min() <= vmax && nmax_var->Max() >= vmin) - break; + if (nmax_var->Min() <= vmax && nmax_var->Max() >= vmin) break; } index_->SetRange(nmin, nmax); if (nmin == nmax) { @@ -1325,7 +1341,7 @@ std::string StringifyInt64ToIntVar(const Solver::Int64ToIntVar &evaluator, } return out; } -} // namespace +} // namespace std::string IntExprEvaluatorElementCt::DebugString() const { return StringifyInt64ToIntVar(evaluator_, range_start_, range_end_); @@ -1347,14 +1363,14 @@ void IntExprEvaluatorElementCt::Accept(ModelVisitor *const visitor) const { // that propagation only occurs when all variables have been touched. class IntExprArrayElementCt : public IntExprEvaluatorElementCt { -public: + public: IntExprArrayElementCt(Solver *const s, std::vector vars, IntVar *const index, IntVar *const target_var); std::string DebugString() const override; void Accept(ModelVisitor *const visitor) const override; -private: + private: const std::vector vars_; }; @@ -1362,10 +1378,9 @@ IntExprArrayElementCt::IntExprArrayElementCt(Solver *const s, std::vector vars, IntVar *const index, IntVar *const target_var) - : IntExprEvaluatorElementCt(s, [this](int64 idx) { - return vars_[idx]; -}, - 0, vars.size(), index, target_var), + : IntExprEvaluatorElementCt( + s, [this](int64 idx) { return vars_[idx]; }, 0, vars.size(), index, + target_var), vars_(std::move(vars)) {} std::string IntExprArrayElementCt::DebugString() const { @@ -1396,10 +1411,13 @@ void IntExprArrayElementCt::Accept(ModelVisitor *const visitor) const { // This constraint implements vars[index] == constant. class IntExprArrayElementCstCt : public Constraint { -public: + public: IntExprArrayElementCstCt(Solver *const s, const std::vector &vars, IntVar *const index, int64 target) - : Constraint(s), vars_(vars), index_(index), target_(target), + : Constraint(s), + vars_(vars), + index_(index), + target_(target), demons_(vars.size()) {} ~IntExprArrayElementCstCt() override {} @@ -1452,7 +1470,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this); } -private: + private: const std::vector vars_; IntVar *const index_; const int64 target_; @@ -1462,11 +1480,15 @@ private: // This constraint implements index == position(constant in vars). class IntExprIndexOfCt : public Constraint { -public: + public: IntExprIndexOfCt(Solver *const s, const std::vector &vars, IntVar *const index, int64 target) - : Constraint(s), vars_(vars), index_(index), target_(target), - demons_(vars_.size()), index_iterator_(index->MakeHoleIterator(true)) {} + : Constraint(s), + vars_(vars), + index_(index), + target_(target), + demons_(vars_.size()), + index_iterator_(index->MakeHoleIterator(true)) {} ~IntExprIndexOfCt() override {} @@ -1541,7 +1563,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIndexOf, this); } -private: + private: const std::vector vars_; IntVar *const index_; const int64 target_; @@ -1570,7 +1592,7 @@ Constraint *MakeElementEqualityFunc(Solver *const solver, } } } -} // namespace +} // namespace Constraint *Solver::MakeIfThenElseCt(IntVar *const condition, IntExpr *const then_expr, @@ -1736,4 +1758,4 @@ IntExpr *Solver::MakeIndexExpression(const std::vector &vars, return index; } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/expr_array.cc b/ortools/constraint_solver/expr_array.cc index c60360d700..ea00173008 100644 --- a/ortools/constraint_solver/expr_array.cc +++ b/ortools/constraint_solver/expr_array.cc @@ -34,10 +34,11 @@ namespace { // ----- Tree Array Constraint ----- class TreeArrayConstraint : public CastConstraint { -public: + public: TreeArrayConstraint(Solver *const solver, const std::vector &vars, IntVar *const sum_var) - : CastConstraint(solver, sum_var), vars_(vars), + : CastConstraint(solver, sum_var), + vars_(vars), block_size_(solver->parameters().array_split_size()) { std::vector lengths; lengths.push_back(vars_.size()); @@ -74,12 +75,12 @@ public: void ReduceRange(int depth, int position, int64 delta_min, int64 delta_max) { NodeInfo *const info = &tree_[depth][position]; if (delta_min > 0) { - info->node_min - .SetValue(solver(), CapAdd(info->node_min.Value(), delta_min)); + info->node_min.SetValue(solver(), + CapAdd(info->node_min.Value(), delta_min)); } if (delta_max > 0) { - info->node_max - .SetValue(solver(), CapSub(info->node_max.Value(), delta_max)); + info->node_max.SetValue(solver(), + CapSub(info->node_max.Value(), delta_max)); } } @@ -130,10 +131,10 @@ public: int Width(int depth) const { return tree_[depth].size(); } -protected: + protected: const std::vector vars_; -private: + private: struct NodeInfo { NodeInfo() : node_min(0), node_max(0) {} Rev node_min; @@ -158,7 +159,7 @@ private: // This constraint implements sum(vars) == sum_var. class SumConstraint : public TreeArrayConstraint { -public: + public: SumConstraint(Solver *const solver, const std::vector &vars, IntVar *const sum_var) : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {} @@ -266,7 +267,7 @@ public: IntVar *const var = vars_[term_index]; PushUp(term_index, CapSub(var->Min(), var->OldMin()), CapSub(var->OldMax(), var->Max())); - EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed? + EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed? } void PushUp(int position, int64 delta_min, int64 delta_max) { @@ -289,17 +290,21 @@ public: AcceptInternal(ModelVisitor::kSumEqual, visitor); } -private: + private: Demon *sum_demon_; }; // This constraint implements sum(vars) == target_var. class SmallSumConstraint : public Constraint { -public: + public: SmallSumConstraint(Solver *const solver, const std::vector &vars, IntVar *const target_var) - : Constraint(solver), vars_(vars), target_var_(target_var), - computed_min_(0), computed_max_(0), sum_demon_(nullptr) {} + : Constraint(solver), + vars_(vars), + target_var_(target_var), + computed_min_(0), + computed_max_(0), + sum_demon_(nullptr) {} ~SmallSumConstraint() override {} @@ -351,7 +356,7 @@ public: vars_[i]->SetValue(vars_[i]->Max()); } } else { - if (new_min > sum_min || new_max < sum_max) { // something to do. + if (new_min > sum_min || new_max < sum_max) { // something to do. // Intersect the new bounds with the computed bounds. new_max = std::min(sum_max, new_max); new_min = std::max(sum_min, new_min); @@ -402,7 +407,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); } -private: + private: const std::vector vars_; IntVar *target_var_; NumericalRev computed_min_; @@ -426,7 +431,7 @@ bool DetectSumOverflow(const std::vector &vars) { // This constraint implements sum(vars) == sum_var. class SafeSumConstraint : public TreeArrayConstraint { -public: + public: SafeSumConstraint(Solver *const solver, const std::vector &vars, IntVar *const sum_var) : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {} @@ -552,7 +557,7 @@ public: IntVar *const var = vars_[term_index]; PushUp(term_index, CapSub(var->Min(), var->OldMin()), CapSub(var->OldMax(), var->Max())); - EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed? + EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed? } void PushUp(int position, int64 delta_min, int64 delta_max) { @@ -567,18 +572,18 @@ public: for (int depth = MaxDepth(); depth >= 0; --depth) { if (Min(depth, position) != kint64min && Max(depth, position) != kint64max && delta_min != kint64max && - delta_max != kint64max && !delta_corrupted) { // No overflow. + delta_max != kint64max && !delta_corrupted) { // No overflow. ReduceRange(depth, position, delta_min, delta_max); - } else if (depth == MaxDepth()) { // Leaf. + } else if (depth == MaxDepth()) { // Leaf. SetRange(depth, position, vars_[position]->Min(), vars_[position]->Max()); delta_corrupted = true; - } else { // Recompute. + } else { // Recompute. int64 sum_min = 0; int64 sum_max = 0; SafeComputeNode(depth, position, &sum_min, &sum_max); if (sum_min == kint64min && sum_max == kint64max) { - return; // Nothing to do upward. + return; // Nothing to do upward. } SetRange(depth, position, sum_min, sum_max); delta_corrupted = true; @@ -597,7 +602,7 @@ public: AcceptInternal(ModelVisitor::kSumEqual, visitor); } -private: + private: bool CheckInternalState() { for (int i = 0; i < vars_.size(); ++i) { CheckLeaf(i, vars_[i]->Min(), vars_[i]->Max()); @@ -630,7 +635,7 @@ private: // This constraint implements min(vars) == min_var. class MinConstraint : public TreeArrayConstraint { -public: + public: MinConstraint(Solver *const solver, const std::vector &vars, IntVar *const min_var) : TreeArrayConstraint(solver, vars, min_var), min_demon_(nullptr) {} @@ -765,7 +770,7 @@ public: depth = parent_depth; position = parent; } - if (depth == 0) { // We have pushed all the way up. + if (depth == 0) { // We have pushed all the way up. target_var_->SetRange(RootMin(), RootMax()); } MinVarChanged(); @@ -779,16 +784,19 @@ public: AcceptInternal(ModelVisitor::kMinEqual, visitor); } -private: + private: Demon *min_demon_; }; class SmallMinConstraint : public Constraint { -public: + public: SmallMinConstraint(Solver *const solver, const std::vector &vars, IntVar *const target_var) - : Constraint(solver), vars_(vars), target_var_(target_var), - computed_min_(0), computed_max_(0) {} + : Constraint(solver), + vars_(vars), + target_var_(target_var), + computed_min_(0), + computed_max_(0) {} ~SmallMinConstraint() override {} @@ -837,7 +845,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMinEqual, this); } -private: + private: void VarChanged(IntVar *var) { const int64 old_min = var->OldMin(); const int64 var_min = var->Min(); @@ -908,7 +916,7 @@ private: // This constraint implements max(vars) == max_var. class MaxConstraint : public TreeArrayConstraint { -public: + public: MaxConstraint(Solver *const solver, const std::vector &vars, IntVar *const max_var) : TreeArrayConstraint(solver, vars, max_var), max_demon_(nullptr) {} @@ -1042,7 +1050,7 @@ public: depth = parent_depth; position = parent; } - if (depth == 0) { // We have pushed all the way up. + if (depth == 0) { // We have pushed all the way up. target_var_->SetRange(RootMin(), RootMax()); } MaxVarChanged(); @@ -1056,16 +1064,19 @@ public: AcceptInternal(ModelVisitor::kMaxEqual, visitor); } -private: + private: Demon *max_demon_; }; class SmallMaxConstraint : public Constraint { -public: + public: SmallMaxConstraint(Solver *const solver, const std::vector &vars, IntVar *const target_var) - : Constraint(solver), vars_(vars), target_var_(target_var), - computed_min_(0), computed_max_(0) {} + : Constraint(solver), + vars_(vars), + target_var_(target_var), + computed_min_(0), + computed_max_(0) {} ~SmallMaxConstraint() override {} @@ -1114,14 +1125,14 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMaxEqual, this); } -private: + private: void VarChanged(IntVar *var) { const int64 old_max = var->OldMax(); const int64 var_min = var->Min(); const int64 var_max = var->Max(); if ((old_max == computed_max_.Value() && old_max != var_max) || - var_min > computed_min_.Value()) { // REWRITE - // Can influence the min var bounds. + var_min > computed_min_.Value()) { // REWRITE + // Can influence the min var bounds. int64 max_min = kint64min; int64 max_max = kint64min; for (IntVar *const var : vars_) { @@ -1184,10 +1195,12 @@ private: // Boolean And and Ors class ArrayBoolAndEq : public CastConstraint { -public: + public: ArrayBoolAndEq(Solver *const s, const std::vector &vars, IntVar *const target) - : CastConstraint(s, target), vars_(vars), demons_(vars.size()), + : CastConstraint(s, target), + vars_(vars), + demons_(vars.size()), unbounded_(0) {} ~ArrayBoolAndEq() override {} @@ -1284,7 +1297,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMinEqual, this); } -private: + private: void InhibitAll() { for (int i = 0; i < demons_.size(); ++i) { if (demons_[i] != nullptr) { @@ -1311,10 +1324,12 @@ private: }; class ArrayBoolOrEq : public CastConstraint { -public: + public: ArrayBoolOrEq(Solver *const s, const std::vector &vars, IntVar *const target) - : CastConstraint(s, target), vars_(vars), demons_(vars.size()), + : CastConstraint(s, target), + vars_(vars), + demons_(vars.size()), unbounded_(0) {} ~ArrayBoolOrEq() override {} @@ -1412,7 +1427,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMaxEqual, this); } -private: + private: void InhibitAll() { for (int i = 0; i < demons_.size(); ++i) { if (demons_[i] != nullptr) { @@ -1441,13 +1456,13 @@ private: // ---------- Specialized cases ---------- class BaseSumBooleanConstraint : public Constraint { -public: + public: BaseSumBooleanConstraint(Solver *const s, const std::vector &vars) : Constraint(s), vars_(vars) {} ~BaseSumBooleanConstraint() override {} -protected: + protected: std::string DebugStringInternal(const std::string &name) const { return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", ")); } @@ -1459,7 +1474,7 @@ protected: // ----- Sum of Boolean <= 1 ----- class SumBooleanLessOrEqualToOne : public BaseSumBooleanConstraint { -public: + public: SumBooleanLessOrEqualToOne(Solver *const s, const std::vector &vars) : BaseSumBooleanConstraint(s, vars) {} @@ -1468,9 +1483,9 @@ public: void Post() override { for (int i = 0; i < vars_.size(); ++i) { if (!vars_[i]->Bound()) { - Demon *u = MakeConstraintDemon1( - solver(), this, &SumBooleanLessOrEqualToOne::Update, "Update", - vars_[i]); + Demon *u = MakeConstraintDemon1(solver(), this, + &SumBooleanLessOrEqualToOne::Update, + "Update", vars_[i]); vars_[i]->WhenBound(u); } } @@ -1522,7 +1537,7 @@ public: // We implement this one as a Max(array) == 1. class SumBooleanGreaterOrEqualToOne : public BaseSumBooleanConstraint { -public: + public: SumBooleanGreaterOrEqualToOne(Solver *const s, const std::vector &vars); ~SumBooleanGreaterOrEqualToOne() override {} @@ -1543,7 +1558,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kSumGreaterOrEqual, this); } -private: + private: RevBitSet bits_; }; @@ -1573,25 +1588,21 @@ void SumBooleanGreaterOrEqualToOne::InitialPropagate() { if (bits_.IsCardinalityZero()) { solver()->Fail(); } else if (bits_.IsCardinalityOne()) { - vars_[bits_.GetFirstBit(0)]->SetValue(int64 { - 1 - }); + vars_[bits_.GetFirstBit(0)]->SetValue(int64{1}); inactive_.Switch(solver()); } } void SumBooleanGreaterOrEqualToOne::Update(int index) { if (!inactive_.Switched()) { - if (vars_[index]->Min() == 1LL) { // Bound to 1. + if (vars_[index]->Min() == 1LL) { // Bound to 1. inactive_.Switch(solver()); } else { bits_.SetToZero(solver(), index); if (bits_.IsCardinalityZero()) { solver()->Fail(); } else if (bits_.IsCardinalityOne()) { - vars_[bits_.GetFirstBit(0)]->SetValue(int64 { - 1 - }); + vars_[bits_.GetFirstBit(0)]->SetValue(int64{1}); inactive_.Switch(solver()); } } @@ -1605,7 +1616,7 @@ std::string SumBooleanGreaterOrEqualToOne::DebugString() const { // ----- Sum of Boolean == 1 ----- class SumBooleanEqualToOne : public BaseSumBooleanConstraint { -public: + public: SumBooleanEqualToOne(Solver *const s, const std::vector &vars) : BaseSumBooleanConstraint(s, vars), active_vars_(0) {} @@ -1652,7 +1663,7 @@ public: void Update(int index) { if (!inactive_.Switched()) { DCHECK(vars_[index]->Bound()); - const int64 value = vars_[index]->Min(); // Faster than Value(). + const int64 value = vars_[index]->Min(); // Faster than Value(). if (value == 0) { active_vars_.Decr(solver()); DCHECK_GE(active_vars_.Value(), 0); @@ -1700,18 +1711,20 @@ public: visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); } -private: + private: NumericalRev active_vars_; }; // ----- Sum of Boolean Equal To Var ----- class SumBooleanEqualToVar : public BaseSumBooleanConstraint { -public: + public: SumBooleanEqualToVar(Solver *const s, const std::vector &bool_vars, IntVar *const sum_var) - : BaseSumBooleanConstraint(s, bool_vars), num_possible_true_vars_(0), - num_always_true_vars_(0), sum_var_(sum_var) {} + : BaseSumBooleanConstraint(s, bool_vars), + num_possible_true_vars_(0), + num_always_true_vars_(0), + sum_var_(sum_var) {} ~SumBooleanEqualToVar() override {} @@ -1768,7 +1781,7 @@ public: void Update(int index) { if (!inactive_.Switched()) { DCHECK(vars_[index]->Bound()); - const int64 value = vars_[index]->Min(); // Faster than Value(). + const int64 value = vars_[index]->Min(); // Faster than Value(). if (value == 0) { num_possible_true_vars_.Decr(solver()); sum_var_->SetRange(num_always_true_vars_.Value(), @@ -1831,7 +1844,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); } -private: + private: NumericalRev num_possible_true_vars_; NumericalRev num_always_true_vars_; IntVar *const sum_var_; @@ -1891,13 +1904,17 @@ int64 SortBothChangeConstant(std::vector *const vars, // This constraint implements sum(vars) == var. It is delayed such // that propagation only occurs when all variables have been touched. class BooleanScalProdLessConstant : public Constraint { -public: + public: BooleanScalProdLessConstant(Solver *const s, const std::vector &vars, const std::vector &coefs, int64 upper_bound) - : Constraint(s), vars_(vars), coefs_(coefs), upper_bound_(upper_bound), - first_unbound_backward_(vars.size() - 1), sum_of_bound_variables_(0LL), + : Constraint(s), + vars_(vars), + coefs_(coefs), + upper_bound_(upper_bound), + first_unbound_backward_(vars.size() - 1), + sum_of_bound_variables_(0LL), max_coefficient_(0) { CHECK(!vars.empty()); for (int i = 0; i < vars_.size(); ++i) { @@ -1984,7 +2001,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kScalProdLessOrEqual, this); } -private: + private: std::vector vars_; std::vector coefs_; int64 upper_bound_; @@ -1996,14 +2013,18 @@ private: // ----- PositiveBooleanScalProdEqVar ----- class PositiveBooleanScalProdEqVar : public CastConstraint { -public: + public: PositiveBooleanScalProdEqVar(Solver *const s, const std::vector &vars, const std::vector &coefs, IntVar *const var) - : CastConstraint(s, var), vars_(vars), coefs_(coefs), - first_unbound_backward_(vars.size() - 1), sum_of_bound_variables_(0LL), - sum_of_all_variables_(0LL), max_coefficient_(0) { + : CastConstraint(s, var), + vars_(vars), + coefs_(coefs), + first_unbound_backward_(vars.size() - 1), + sum_of_bound_variables_(0LL), + sum_of_all_variables_(0LL), + max_coefficient_(0) { SortBothChangeConstant(&vars_, &coefs_, true); max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]); } @@ -2103,7 +2124,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual, this); } -private: + private: std::vector vars_; std::vector coefs_; Rev first_unbound_backward_; @@ -2115,7 +2136,7 @@ private: // ----- PositiveBooleanScalProd ----- class PositiveBooleanScalProd : public BaseIntExpr { -public: + public: // this constructor will copy the array. The caller can safely delete the // exprs array himself PositiveBooleanScalProd(Solver *const s, const std::vector &vars, @@ -2164,7 +2185,7 @@ public: const int64 var_max = CapProd(vars_[i]->Max(), coefficient); current_min = CapAdd(current_min, var_min); current_max = CapAdd(current_max, var_max); - if (var_min != var_max) { // Coefficients are increasing. + if (var_min != var_max) { // Coefficients are increasing. diameter = CapSub(var_max, var_min); } } @@ -2193,13 +2214,9 @@ public: solver()->Fail(); } if (new_min > 0LL) { - var->SetMin(int64 { - 1 - }); + var->SetMin(int64{1}); } else if (new_max < coefficient) { - var->SetMax(int64 { - 0 - }); + var->SetMax(int64{0}); } } } @@ -2238,7 +2255,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kScalProd, this); } -private: + private: std::vector vars_; std::vector coefs_; }; @@ -2246,13 +2263,18 @@ private: // ----- PositiveBooleanScalProdEqCst ----- (all constants >= 0) class PositiveBooleanScalProdEqCst : public Constraint { -public: + public: PositiveBooleanScalProdEqCst(Solver *const s, const std::vector &vars, const std::vector &coefs, int64 constant) - : Constraint(s), vars_(vars), coefs_(coefs), - first_unbound_backward_(vars.size() - 1), sum_of_bound_variables_(0LL), - sum_of_all_variables_(0LL), constant_(constant), max_coefficient_(0) { + : Constraint(s), + vars_(vars), + coefs_(coefs), + first_unbound_backward_(vars.size() - 1), + sum_of_bound_variables_(0LL), + sum_of_all_variables_(0LL), + constant_(constant), + max_coefficient_(0) { CHECK(!vars.empty()); constant_ = CapSub(constant_, SortBothChangeConstant(&vars_, &coefs_, false)); @@ -2345,7 +2367,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual, this); } -private: + private: std::vector vars_; std::vector coefs_; Rev first_unbound_backward_; @@ -2360,7 +2382,7 @@ private: #define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0 class ExprLinearizer : public ModelParser { -public: + public: explicit ExprLinearizer( absl::flat_hash_map *const variables_to_coefficients) : variables_to_coefficients_(variables_to_coefficients), constant_(0) {} @@ -2468,9 +2490,9 @@ public: Top()->SetIntegerExpressionArgument(arg_name, argument); } - void VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntegerVariableArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { Top()->SetIntegerVariableArrayArgument(arg_name, arguments); } @@ -2478,9 +2500,9 @@ public: void VisitIntervalArgument(const std::string &arg_name, IntervalVar *const argument) override {} - void VisitIntervalArrayArgument(const std::string &arg_name, - const std::vector &argument) - override {} + void VisitIntervalArrayArgument( + const std::string &arg_name, + const std::vector &argument) override {} void Visit(const IntExpr *const expr, int64 multiplier) { if (expr->Min() == expr->Max()) { @@ -2496,7 +2518,7 @@ public: std::string DebugString() const override { return "ExprLinearizer"; } -private: + private: void BeginVisit(bool active) { PushArgumentHolder(); } void EndVisit() { PopArgumentHolder(); } @@ -3048,8 +3070,8 @@ IntExpr *MakeSumArrayAux(Solver *const solver, solver->AddConstraint( solver->RevAlloc(new SumConstraint(solver, vars, sum_var))); } - solver->Cache() - ->InsertVarArrayExpression(sum_var, vars, ModelCache::VAR_ARRAY_SUM); + solver->Cache()->InsertVarArrayExpression(sum_var, vars, + ModelCache::VAR_ARRAY_SUM); return solver->MakeSum(sum_var, constant); } } @@ -3101,8 +3123,9 @@ IntExpr *MakeScalProdAux(Solver *solver, const std::vector &vars, if (AreAllPositive(coefs)) { if (vars.size() > 8) { return solver->MakeSum( - solver->RegisterIntExpr(solver->RevAlloc( - new PositiveBooleanScalProd(solver, vars, coefs))) + solver + ->RegisterIntExpr(solver->RevAlloc( + new PositiveBooleanScalProd(solver, vars, coefs))) ->Var(), constant); } else { @@ -3201,16 +3224,14 @@ IntExpr *MakeSumFct(Solver *solver, const std::vector &pre_vars) { } return MakeScalProdAux(solver, vars, coefs, constant); } -} // namespace +} // namespace // ----- API ----- IntExpr *Solver::MakeSum(const std::vector &vars) { const int size = vars.size(); if (size == 0) { - return MakeIntConst(int64 { - 0 - }); + return MakeIntConst(int64{0}); } else if (size == 1) { return vars[0]; } else if (size == 2) { @@ -3489,33 +3510,30 @@ Constraint *Solver::MakeScalProdEquality(const std::vector &vars, target); } -Constraint * -Solver::MakeScalProdGreaterOrEqual(const std::vector &vars, - const std::vector &coeffs, - int64 cst) { +Constraint *Solver::MakeScalProdGreaterOrEqual( + const std::vector &vars, const std::vector &coeffs, + int64 cst) { DCHECK_EQ(vars.size(), coeffs.size()); return MakeScalProdGreaterOrEqualFct(this, vars, coeffs, cst); } -Constraint * -Solver::MakeScalProdGreaterOrEqual(const std::vector &vars, - const std::vector &coeffs, int64 cst) { +Constraint *Solver::MakeScalProdGreaterOrEqual( + const std::vector &vars, const std::vector &coeffs, + int64 cst) { DCHECK_EQ(vars.size(), coeffs.size()); return MakeScalProdGreaterOrEqualFct(this, vars, ToInt64Vector(coeffs), cst); } -Constraint * -Solver::MakeScalProdLessOrEqual(const std::vector &vars, - const std::vector &coefficients, - int64 cst) { +Constraint *Solver::MakeScalProdLessOrEqual( + const std::vector &vars, const std::vector &coefficients, + int64 cst) { DCHECK_EQ(vars.size(), coefficients.size()); return MakeScalProdLessOrEqualFct(this, vars, coefficients, cst); } -Constraint * -Solver::MakeScalProdLessOrEqual(const std::vector &vars, - const std::vector &coefficients, - int64 cst) { +Constraint *Solver::MakeScalProdLessOrEqual( + const std::vector &vars, const std::vector &coefficients, + int64 cst) { DCHECK_EQ(vars.size(), coefficients.size()); return MakeScalProdLessOrEqualFct(this, vars, ToInt64Vector(coefficients), cst); @@ -3532,4 +3550,4 @@ IntExpr *Solver::MakeScalProd(const std::vector &vars, DCHECK_EQ(vars.size(), coefs.size()); return MakeScalProdFct(this, vars, ToInt64Vector(coefs)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/expr_cst.cc b/ortools/constraint_solver/expr_cst.cc index 52854f398f..69468da19a 100644 --- a/ortools/constraint_solver/expr_cst.cc +++ b/ortools/constraint_solver/expr_cst.cc @@ -41,7 +41,7 @@ namespace operations_research { namespace { class EqualityExprCst : public Constraint { -public: + public: EqualityExprCst(Solver *const s, IntExpr *const e, int64 v); ~EqualityExprCst() override {} void Post() override; @@ -59,7 +59,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kEquality, this); } -private: + private: IntExpr *const expr_; int64 value_; }; @@ -79,7 +79,7 @@ void EqualityExprCst::InitialPropagate() { expr_->SetValue(value_); } std::string EqualityExprCst::DebugString() const { return absl::StrFormat("(%s == %d)", expr_->DebugString(), value_); } -} // namespace +} // namespace Constraint *Solver::MakeEquality(IntExpr *const e, int64 v) { CHECK_EQ(this, e->solver()); @@ -116,7 +116,7 @@ Constraint *Solver::MakeEquality(IntExpr *const e, int v) { namespace { class GreaterEqExprCst : public Constraint { -public: + public: GreaterEqExprCst(Solver *const s, IntExpr *const e, int64 v); ~GreaterEqExprCst() override {} void Post() override; @@ -134,7 +134,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kGreaterOrEqual, this); } -private: + private: IntExpr *const expr_; int64 value_; Demon *demon_; @@ -163,7 +163,7 @@ void GreaterEqExprCst::InitialPropagate() { std::string GreaterEqExprCst::DebugString() const { return absl::StrFormat("(%s >= %d)", expr_->DebugString(), value_); } -} // namespace +} // namespace Constraint *Solver::MakeGreaterOrEqual(IntExpr *const e, int64 v) { CHECK_EQ(this, e->solver()); @@ -214,7 +214,7 @@ Constraint *Solver::MakeGreater(IntExpr *const e, int v) { namespace { class LessEqExprCst : public Constraint { -public: + public: LessEqExprCst(Solver *const s, IntExpr *const e, int64 v); ~LessEqExprCst() override {} void Post() override; @@ -231,7 +231,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this); } -private: + private: IntExpr *const expr_; int64 value_; Demon *demon_; @@ -260,7 +260,7 @@ void LessEqExprCst::InitialPropagate() { std::string LessEqExprCst::DebugString() const { return absl::StrFormat("(%s <= %d)", expr_->DebugString(), value_); } -} // namespace +} // namespace Constraint *Solver::MakeLessOrEqual(IntExpr *const e, int64 v) { CHECK_EQ(this, e->solver()); @@ -311,7 +311,7 @@ Constraint *Solver::MakeLess(IntExpr *const e, int v) { namespace { class DiffCst : public Constraint { -public: + public: DiffCst(Solver *const s, IntVar *const var, int64 value); ~DiffCst() override {} void Post() override {} @@ -329,7 +329,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this); } -private: + private: bool HasLargeDomain(IntVar *var); IntVar *const var_; @@ -372,7 +372,7 @@ std::string DiffCst::DebugString() const { bool DiffCst::HasLargeDomain(IntVar *var) { return CapSub(var->Max(), var->Min()) > 0xFFFFFF; } -} // namespace +} // namespace Constraint *Solver::MakeNonEquality(IntExpr *const e, int64 v) { CHECK_EQ(this, e->solver()); @@ -407,7 +407,7 @@ Constraint *Solver::MakeNonEquality(IntExpr *const e, int v) { namespace { class IsEqualCstCt : public CastConstraint { -public: + public: IsEqualCstCt(Solver *const s, IntVar *const v, int64 c, IntVar *const b) : CastConstraint(s, b), var_(v), cst_(c), demon_(nullptr) {} void Post() override { @@ -450,12 +450,12 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this); } -private: + private: IntVar *const var_; int64 cst_; Demon *demon_; }; -} // namespace +} // namespace IntVar *Solver::MakeIsEqualCstVar(IntExpr *const var, int64 value) { IntExpr *left = nullptr; @@ -522,7 +522,7 @@ Constraint *Solver::MakeIsEqualCstCt(IntExpr *const var, int64 value, namespace { class IsDiffCstCt : public CastConstraint { -public: + public: IsDiffCstCt(Solver *const s, IntVar *const v, int64 c, IntVar *const b) : CastConstraint(s, b), var_(v), cst_(c), demon_(nullptr) {} @@ -568,12 +568,12 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this); } -private: + private: IntVar *const var_; int64 cst_; Demon *demon_; }; -} // namespace +} // namespace IntVar *Solver::MakeIsDifferentCstVar(IntExpr *const var, int64 value) { IntExpr *left = nullptr; @@ -595,9 +595,7 @@ Constraint *Solver::MakeIsDifferentCstCt(IntExpr *const var, int64 value, return MakeIsLessOrEqualCstCt(var, value - 1, boolvar); } if (var->IsVar() && !var->Var()->Contains(value)) { - return MakeEquality(boolvar, int64 { - 1 - }); + return MakeEquality(boolvar, int64{1}); } if (var->Bound() && var->Min() == value) { return MakeEquality(boolvar, Zero()); @@ -624,7 +622,7 @@ Constraint *Solver::MakeIsDifferentCstCt(IntExpr *const var, int64 value, namespace { class IsGreaterEqualCstCt : public CastConstraint { -public: + public: IsGreaterEqualCstCt(Solver *const s, IntExpr *const v, int64 c, IntVar *const b) : CastConstraint(s, b), expr_(v), cst_(c), demon_(nullptr) {} @@ -669,23 +667,19 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsGreaterOrEqual, this); } -private: + private: IntExpr *const expr_; int64 cst_; Demon *demon_; }; -} // namespace +} // namespace IntVar *Solver::MakeIsGreaterOrEqualCstVar(IntExpr *const var, int64 value) { if (var->Min() >= value) { - return MakeIntConst(int64 { - 1 - }); + return MakeIntConst(int64{1}); } if (var->Max() < value) { - return MakeIntConst(int64 { - 0 - }); + return MakeIntConst(int64{0}); } if (var->IsVar()) { return var->Var()->IsGreaterOrEqual(value); @@ -726,7 +720,7 @@ Constraint *Solver::MakeIsGreaterCstCt(IntExpr *const v, int64 c, namespace { class IsLessEqualCstCt : public CastConstraint { -public: + public: IsLessEqualCstCt(Solver *const s, IntExpr *const v, int64 c, IntVar *const b) : CastConstraint(s, b), expr_(v), cst_(c), demon_(nullptr) {} @@ -772,23 +766,19 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsLessOrEqual, this); } -private: + private: IntExpr *const expr_; int64 cst_; Demon *demon_; }; -} // namespace +} // namespace IntVar *Solver::MakeIsLessOrEqualCstVar(IntExpr *const var, int64 value) { if (var->Max() <= value) { - return MakeIntConst(int64 { - 1 - }); + return MakeIntConst(int64{1}); } if (var->Min() > value) { - return MakeIntConst(int64 { - 0 - }); + return MakeIntConst(int64{0}); } if (var->IsVar()) { return var->Var()->IsLessOrEqual(value); @@ -829,7 +819,7 @@ Constraint *Solver::MakeIsLessCstCt(IntExpr *const v, int64 c, namespace { class BetweenCt : public Constraint { -public: + public: BetweenCt(Solver *const s, IntExpr *const v, int64 l, int64 u) : Constraint(s), expr_(v), min_(l), max_(u), demon_(nullptr) {} @@ -864,7 +854,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kBetween, this); } -private: + private: IntExpr *const expr_; int64 min_; int64 max_; @@ -874,7 +864,7 @@ private: // ----- NonMember constraint ----- class NotBetweenCt : public Constraint { -public: + public: NotBetweenCt(Solver *const s, IntExpr *const v, int64 l, int64 u) : Constraint(s), expr_(v), min_(l), max_(u), demon_(nullptr) {} @@ -912,7 +902,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kBetween, this); } -private: + private: IntExpr *const expr_; int64 min_; int64 max_; @@ -922,37 +912,31 @@ private: int64 ExtractExprProductCoeff(IntExpr **expr) { int64 prod = 1; int64 coeff = 1; - while ((*expr)->solver()->IsProduct(*expr, expr, &coeff)) - prod *= coeff; + while ((*expr)->solver()->IsProduct(*expr, expr, &coeff)) prod *= coeff; return prod; } -} // namespace +} // namespace Constraint *Solver::MakeBetweenCt(IntExpr *expr, int64 l, int64 u) { DCHECK_EQ(this, expr->solver()); // Catch empty and singleton intervals. if (l >= u) { - if (l > u) - return MakeFalseConstraint(); + if (l > u) return MakeFalseConstraint(); return MakeEquality(expr, l); } int64 emin = 0; int64 emax = 0; expr->Range(&emin, &emax); // Catch the trivial cases first. - if (emax < l || emin > u) - return MakeFalseConstraint(); - if (emin >= l && emax <= u) - return MakeTrueConstraint(); + if (emax < l || emin > u) return MakeFalseConstraint(); + if (emin >= l && emax <= u) return MakeTrueConstraint(); // Catch one-sided constraints. - if (emax <= u) - return MakeGreaterOrEqual(expr, l); - if (emin >= l) - return MakeLessOrEqual(expr, u); + if (emax <= u) return MakeGreaterOrEqual(expr, l); + if (emin >= l) return MakeLessOrEqual(expr, u); // Simplify the common factor, if any. int64 coeff = ExtractExprProductCoeff(&expr); if (coeff != 1) { - CHECK_NE(coeff, 0); // Would have been caught by the trivial cases already. + CHECK_NE(coeff, 0); // Would have been caught by the trivial cases already. if (coeff < 0) { std::swap(u, l); u = -u; @@ -977,15 +961,11 @@ Constraint *Solver::MakeNotBetweenCt(IntExpr *expr, int64 l, int64 u) { int64 emax = 0; expr->Range(&emin, &emax); // Catch the trivial cases first. - if (emax < l || emin > u) - return MakeTrueConstraint(); - if (emin >= l && emax <= u) - return MakeFalseConstraint(); + if (emax < l || emin > u) return MakeTrueConstraint(); + if (emin >= l && emax <= u) return MakeFalseConstraint(); // Catch one-sided constraints. - if (emin >= l) - return MakeGreater(expr, u); - if (emax <= u) - return MakeLess(expr, l); + if (emin >= l) return MakeGreater(expr, u); + if (emax <= u) return MakeLess(expr, l); // TODO(user): Add back simplification code if expr is constant * // other_expr. return RevAlloc(new NotBetweenCt(this, expr, l, u)); @@ -995,10 +975,14 @@ Constraint *Solver::MakeNotBetweenCt(IntExpr *expr, int64 l, int64 u) { namespace { class IsBetweenCt : public Constraint { -public: + public: IsBetweenCt(Solver *const s, IntExpr *const e, int64 l, int64 u, IntVar *const b) - : Constraint(s), expr_(e), min_(l), max_(u), boolvar_(b), + : Constraint(s), + expr_(e), + min_(l), + max_(u), + boolvar_(b), demon_(nullptr) {} void Post() override { @@ -1052,14 +1036,14 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsBetween, this); } -private: + private: IntExpr *const expr_; int64 min_; int64 max_; IntVar *const boolvar_; Demon *demon_; }; -} // namespace +} // namespace Constraint *Solver::MakeIsBetweenCt(IntExpr *expr, int64 l, int64 u, IntVar *const b) { @@ -1067,27 +1051,22 @@ Constraint *Solver::MakeIsBetweenCt(IntExpr *expr, int64 l, int64 u, CHECK_EQ(this, b->solver()); // Catch empty and singleton intervals. if (l >= u) { - if (l > u) - return MakeEquality(b, Zero()); + if (l > u) return MakeEquality(b, Zero()); return MakeIsEqualCstCt(expr, l, b); } int64 emin = 0; int64 emax = 0; expr->Range(&emin, &emax); // Catch the trivial cases first. - if (emax < l || emin > u) - return MakeEquality(b, Zero()); - if (emin >= l && emax <= u) - return MakeEquality(b, 1); + if (emax < l || emin > u) return MakeEquality(b, Zero()); + if (emin >= l && emax <= u) return MakeEquality(b, 1); // Catch one-sided constraints. - if (emax <= u) - return MakeIsGreaterOrEqualCstCt(expr, l, b); - if (emin >= l) - return MakeIsLessOrEqualCstCt(expr, u, b); + if (emax <= u) return MakeIsGreaterOrEqualCstCt(expr, l, b); + if (emin >= l) return MakeIsLessOrEqualCstCt(expr, u, b); // Simplify the common factor, if any. int64 coeff = ExtractExprProductCoeff(&expr); if (coeff != 1) { - CHECK_NE(coeff, 0); // Would have been caught by the trivial cases already. + CHECK_NE(coeff, 0); // Would have been caught by the trivial cases already. if (coeff < 0) { std::swap(u, l); u = -u; @@ -1116,7 +1095,7 @@ IntVar *Solver::MakeIsBetweenVar(IntExpr *const v, int64 l, int64 u) { namespace { // TODO(user): Do not create holes on expressions. class MemberCt : public Constraint { -public: + public: MemberCt(Solver *const s, IntVar *const v, const std::vector &sorted_values) : Constraint(s), var_(v), values_(sorted_values) { @@ -1141,13 +1120,13 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMember, this); } -private: + private: IntVar *const var_; const std::vector values_; }; class NotMemberCt : public Constraint { -public: + public: NotMemberCt(Solver *const s, IntVar *const v, const std::vector &sorted_values) : Constraint(s), var_(v), values_(sorted_values) { @@ -1172,11 +1151,11 @@ public: visitor->EndVisitConstraint(ModelVisitor::kMember, this); } -private: + private: IntVar *const var_; const std::vector values_; }; -} // namespace +} // namespace Constraint *Solver::MakeMemberCt(IntExpr *expr, const std::vector &values) { @@ -1192,8 +1171,7 @@ Constraint *Solver::MakeMemberCt(IntExpr *expr, if (coeff != 1) { int num_kept = 0; for (const int64 v : copied_values) { - if (v % coeff == 0) - copied_values[num_kept++] = v / coeff; + if (v % coeff == 0) copied_values[num_kept++] = v / coeff; } copied_values.resize(num_kept); } @@ -1203,18 +1181,15 @@ Constraint *Solver::MakeMemberCt(IntExpr *expr, int64 emax; expr->Range(&emin, &emax); for (const int64 v : copied_values) { - if (v >= emin && v <= emax) - copied_values[num_kept++] = v; + if (v >= emin && v <= emax) copied_values[num_kept++] = v; } copied_values.resize(num_kept); // Catch empty set. - if (copied_values.empty()) - return MakeFalseConstraint(); + if (copied_values.empty()) return MakeFalseConstraint(); // Sort and remove duplicates. gtl::STLSortAndRemoveDuplicates(&copied_values); // Special case for singleton. - if (copied_values.size() == 1) - return MakeEquality(expr, copied_values[0]); + if (copied_values.size() == 1) return MakeEquality(expr, copied_values[0]); // Catch contiguous intervals. if (copied_values.size() == copied_values.back() - copied_values.front() + 1) { @@ -1227,14 +1202,12 @@ Constraint *Solver::MakeMemberCt(IntExpr *expr, if (emax - emin < 2 * copied_values.size()) { // Convert "copied_values" to list the values *not* allowed. std::vector is_among_input_values(emax - emin + 1, false); - for (const int64 v : copied_values) - is_among_input_values[v - emin] = true; + for (const int64 v : copied_values) is_among_input_values[v - emin] = true; // We use the zero valued indices of is_among_input_values to build the // complement of copied_values. copied_values.clear(); for (int64 v_off = 0; v_off < is_among_input_values.size(); ++v_off) { - if (!is_among_input_values[v_off]) - copied_values.push_back(v_off + emin); + if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin); } // The empty' case (all values in range [expr.Min(), expr.Max()] are in the // "values" input) was caught earlier, by the "contiguous interval" case. @@ -1267,8 +1240,7 @@ Constraint *Solver::MakeNotMemberCt(IntExpr *expr, if (coeff != 1) { int num_kept = 0; for (const int64 v : copied_values) { - if (v % coeff == 0) - copied_values[num_kept++] = v / coeff; + if (v % coeff == 0) copied_values[num_kept++] = v / coeff; } copied_values.resize(num_kept); } @@ -1278,18 +1250,15 @@ Constraint *Solver::MakeNotMemberCt(IntExpr *expr, int64 emax; expr->Range(&emin, &emax); for (const int64 v : copied_values) { - if (v >= emin && v <= emax) - copied_values[num_kept++] = v; + if (v >= emin && v <= emax) copied_values[num_kept++] = v; } copied_values.resize(num_kept); // Catch empty set. - if (copied_values.empty()) - return MakeTrueConstraint(); + if (copied_values.empty()) return MakeTrueConstraint(); // Sort and remove duplicates. gtl::STLSortAndRemoveDuplicates(&copied_values); // Special case for singleton. - if (copied_values.size() == 1) - return MakeNonEquality(expr, copied_values[0]); + if (copied_values.size() == 1) return MakeNonEquality(expr, copied_values[0]); // Catch contiguous intervals. if (copied_values.size() == copied_values.back() - copied_values.front() + 1) { @@ -1301,14 +1270,12 @@ Constraint *Solver::MakeNotMemberCt(IntExpr *expr, if (emax - emin < 2 * copied_values.size()) { // Convert "copied_values" to a dense boolean vector. std::vector is_among_input_values(emax - emin + 1, false); - for (const int64 v : copied_values) - is_among_input_values[v - emin] = true; + for (const int64 v : copied_values) is_among_input_values[v - emin] = true; // Use zero valued indices for is_among_input_values to build the // complement of copied_values. copied_values.clear(); for (int64 v_off = 0; v_off < is_among_input_values.size(); ++v_off) { - if (!is_among_input_values[v_off]) - copied_values.push_back(v_off + emin); + if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin); } // The empty' case (all values in range [expr.Min(), expr.Max()] are in the // "values" input) was caught earlier, by the "contiguous interval" case. @@ -1331,13 +1298,18 @@ Constraint *Solver::MakeNotMemberCt(IntExpr *const expr, namespace { class IsMemberCt : public Constraint { -public: + public: IsMemberCt(Solver *const s, IntVar *const v, const std::vector &sorted_values, IntVar *const b) - : Constraint(s), var_(v), + : Constraint(s), + var_(v), values_as_set_(sorted_values.begin(), sorted_values.end()), - values_(sorted_values), boolvar_(b), support_(0), demon_(nullptr), - domain_(var_->MakeDomainIterator(true)), neg_support_(kint64min) { + values_(sorted_values), + boolvar_(b), + support_(0), + demon_(nullptr), + domain_(var_->MakeDomainIterator(true)), + neg_support_(kint64min) { DCHECK(v != nullptr); DCHECK(s != nullptr); DCHECK(b != nullptr); @@ -1384,7 +1356,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsMember, this); } -private: + private: void VarDomain() { if (boolvar_->Bound()) { TargetBound(); @@ -1501,7 +1473,7 @@ Constraint *BuildIsMemberCt(Solver *const solver, IntExpr *const expr, new IsMemberCt(solver, expr->Var(), filtered_values, boolvar)); } } -} // namespace +} // namespace Constraint *Solver::MakeIsMemberCt(IntExpr *const expr, const std::vector &values, @@ -1531,7 +1503,7 @@ IntVar *Solver::MakeIsMemberVar(IntExpr *const expr, namespace { class SortedDisjointForbiddenIntervalsConstraint : public Constraint { -public: + public: SortedDisjointForbiddenIntervalsConstraint( Solver *const solver, IntVar *const var, SortedDisjointIntervalList intervals) @@ -1590,28 +1562,24 @@ public: visitor->EndVisitConstraint(ModelVisitor::kNotMember, this); } -private: + private: IntVar *const var_; const SortedDisjointIntervalList intervals_; }; -} // namespace +} // namespace Constraint *Solver::MakeNotMemberCt(IntExpr *const expr, std::vector starts, std::vector ends) { - return RevAlloc( - new SortedDisjointForbiddenIntervalsConstraint(this, expr->Var(), { - starts, ends - })); + return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint( + this, expr->Var(), {starts, ends})); } Constraint *Solver::MakeNotMemberCt(IntExpr *const expr, std::vector starts, std::vector ends) { - return RevAlloc( - new SortedDisjointForbiddenIntervalsConstraint(this, expr->Var(), { - starts, ends - })); + return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint( + this, expr->Var(), {starts, ends})); } Constraint *Solver::MakeNotMemberCt(IntExpr *expr, @@ -1619,4 +1587,4 @@ Constraint *Solver::MakeNotMemberCt(IntExpr *expr, return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint( this, expr->Var(), std::move(intervals))); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/expressions.cc b/ortools/constraint_solver/expressions.cc index 1ae6757022..622eb4fcfd 100644 --- a/ortools/constraint_solver/expressions.cc +++ b/ortools/constraint_solver/expressions.cc @@ -65,18 +65,14 @@ IntVar::IntVar(Solver *const s, const std::string &name) const int BooleanVar::kUnboundBooleanVarValue = 2; void BooleanVar::SetMin(int64 m) { - if (m <= 0) - return; - if (m > 1) - solver()->Fail(); + if (m <= 0) return; + if (m > 1) solver()->Fail(); SetValue(1); } void BooleanVar::SetMax(int64 m) { - if (m >= 1) - return; - if (m < 0) - solver()->Fail(); + if (m >= 1) return; + if (m < 0) solver()->Fail(); SetValue(0); } @@ -104,8 +100,7 @@ void BooleanVar::RemoveValue(int64 v) { } void BooleanVar::RemoveInterval(int64 l, int64 u) { - if (u < l) - return; + if (u < l) return; if (l <= 0 && u >= 1) { solver()->Fail(); } else if (l == 1) { @@ -139,7 +134,7 @@ IntVar *BooleanVar::IsEqual(int64 constant) { } if (constant == 1) { return this; - } else { // constant == 0. + } else { // constant == 0. return solver()->MakeDifference(1, this)->Var(); } } @@ -150,7 +145,7 @@ IntVar *BooleanVar::IsDifferent(int64 constant) { } if (constant == 1) { return solver()->MakeDifference(1, this)->Var(); - } else { // constant == 0. + } else { // constant == 0. return this; } } @@ -184,15 +179,15 @@ std::string BooleanVar::DebugString() const { out = "BooleanVar("; } switch (value_) { - case 0: - out += "0"; - break; - case 1: - out += "1"; - break; - case kUnboundBooleanVarValue: - out += "0 .. 1"; - break; + case 0: + out += "0"; + break; + case 1: + out += "1"; + break; + case kUnboundBooleanVarValue: + out += "0 .. 1"; + break; } out += ")"; return out; @@ -204,10 +199,10 @@ namespace { // ----- Domain Int Var: base class for variables ----- // It Contains bounds and a bitset representation of possible values. class DomainIntVar : public IntVar { -public: + public: // Utility classes class BitSetIterator : public BaseObject { - public: + public: BitSetIterator(uint64 *const bitset, int64 omin) : bitset_(bitset), omin_(omin), max_(kint64min), current_(kint64max) {} @@ -225,13 +220,14 @@ public: void Next() { if (++current_ <= max_) { current_ = UnsafeLeastSignificantBitPosition64( - bitset_, current_ - omin_, max_ - omin_) + omin_; + bitset_, current_ - omin_, max_ - omin_) + + omin_; } } std::string DebugString() const override { return "BitSetIterator"; } - private: + private: uint64 *const bitset_; const int64 omin_; int64 max_; @@ -239,7 +235,7 @@ public: }; class BitSet : public BaseObject { - public: + public: explicit BitSet(Solver *const s) : solver_(s), holes_stamp_(0) {} ~BitSet() override {} @@ -273,16 +269,16 @@ public: return holes_stamp_ < solver_->stamp() ? 0 : holes_.size(); } - protected: + protected: Solver *const solver_; - private: + private: std::vector holes_; uint64 holes_stamp_; }; class QueueHandler : public Demon { - public: + public: explicit QueueHandler(DomainIntVar *const var) : var_(var) {} ~QueueHandler() override {} void Run(Solver *const s) override { @@ -297,7 +293,7 @@ public: return absl::StrFormat("Handler(%s)", var_->DebugString()); } - private: + private: DomainIntVar *const var_; }; @@ -306,8 +302,9 @@ public: // This class stores the watchers variables attached to values. It is // reversible and it helps maintaining the set of 'active' watchers // (variables not bound to a single value). - template class RevIntPtrMap { - public: + template + class RevIntPtrMap { + public: RevIntPtrMap(Solver *const solver, int64 rmin, int64 rmax) : solver_(solver), range_min_(rmin), start_(0) {} @@ -323,18 +320,15 @@ public: void UnsafeRevInsert(int64 value, T *elem) { elements_.push_back(std::make_pair(value, elem)); if (solver_->state() != Solver::OUTSIDE_SEARCH) { - solver_->AddBacktrackAction([this, value](Solver * s) { - Uninsert(value); - }, - false); + solver_->AddBacktrackAction( + [this, value](Solver *s) { Uninsert(value); }, false); } } T *FindPtrOrNull(int64 value, int *position) { for (int pos = start_.Value(); pos < elements_.size(); ++pos) { if (elements_[pos].first == value) { - if (position != nullptr) - *position = pos; + if (position != nullptr) *position = pos; return At(pos).second; } } @@ -375,7 +369,7 @@ public: if (elements_[pos].first == value) { DCHECK_GE(pos, start_.Value()); const int last = elements_.size() - 1; - if (pos != last) { // Swap the current with the last. + if (pos != last) { // Swap the current with the last. elements_[pos] = elements_.back(); } elements_.pop_back(); @@ -385,7 +379,7 @@ public: LOG(FATAL) << "The element should have been removed"; } - private: + private: Solver *const solver_; const int64 range_min_; NumericalRev start_; @@ -394,7 +388,7 @@ public: // Base class for value watchers class BaseValueWatcher : public Constraint { - public: + public: explicit BaseValueWatcher(Solver *const solver) : Constraint(solver) {} ~BaseValueWatcher() override {} @@ -407,9 +401,9 @@ public: // This class monitors the domain of the variable and updates the // IsEqual/IsDifferent boolean variables accordingly. class ValueWatcher : public BaseValueWatcher { - public: + public: class WatchDemon : public Demon { - public: + public: WatchDemon(ValueWatcher *const watcher, int64 value, IntVar *var) : value_watcher_(watcher), value_(value), var_(var) {} ~WatchDemon() override {} @@ -418,14 +412,14 @@ public: value_watcher_->ProcessValueWatcher(value_, var_); } - private: + private: ValueWatcher *const value_watcher_; const int64 value_; IntVar *const var_; }; class VarDemon : public Demon { - public: + public: explicit VarDemon(ValueWatcher *const watcher) : value_watcher_(watcher) {} @@ -433,12 +427,13 @@ public: void Run(Solver *const solver) override { value_watcher_->ProcessVar(); } - private: + private: ValueWatcher *const value_watcher_; }; ValueWatcher(Solver *const solver, DomainIntVar *const variable) - : BaseValueWatcher(solver), variable_(variable), + : BaseValueWatcher(solver), + variable_(variable), hole_iterator_(variable_->MakeHoleIterator(true)), var_demon_(nullptr), watchers_(solver, variable->Min(), variable->Max()) {} @@ -447,15 +442,14 @@ public: IntVar *GetOrMakeValueWatcher(int64 value) override { IntVar *const watcher = watchers_.FindPtrOrNull(value, nullptr); - if (watcher != nullptr) - return watcher; + if (watcher != nullptr) return watcher; if (variable_->Contains(value)) { if (variable_->Bound()) { return solver()->MakeIntConst(1); } else { - const std::string vname = - variable_->HasName() ? variable_->name() - : variable_->DebugString(); + const std::string vname = variable_->HasName() + ? variable_->name() + : variable_->DebugString(); const std::string bname = absl::StrFormat("Watch<%s == %d>", vname, value); IntVar *const boolvar = solver()->MakeBoolVar(bname); @@ -624,7 +618,7 @@ public: return absl::StrFormat("ValueWatcher(%s)", variable_->DebugString()); } - private: + private: DomainIntVar *const variable_; IntVarIterator *const hole_iterator_; RevSwitch posted_; @@ -634,9 +628,9 @@ public: // Optimized case for small maps. class DenseValueWatcher : public BaseValueWatcher { - public: + public: class WatchDemon : public Demon { - public: + public: WatchDemon(DenseValueWatcher *const watcher, int64 value, IntVar *var) : value_watcher_(watcher), value_(value), var_(var) {} ~WatchDemon() override {} @@ -645,14 +639,14 @@ public: value_watcher_->ProcessValueWatcher(value_, var_); } - private: + private: DenseValueWatcher *const value_watcher_; const int64 value_; IntVar *const var_; }; class VarDemon : public Demon { - public: + public: explicit VarDemon(DenseValueWatcher *const watcher) : value_watcher_(watcher) {} @@ -660,35 +654,36 @@ public: void Run(Solver *const solver) override { value_watcher_->ProcessVar(); } - private: + private: DenseValueWatcher *const value_watcher_; }; DenseValueWatcher(Solver *const solver, DomainIntVar *const variable) - : BaseValueWatcher(solver), variable_(variable), + : BaseValueWatcher(solver), + variable_(variable), hole_iterator_(variable_->MakeHoleIterator(true)), - var_demon_(nullptr), offset_(variable->Min()), + var_demon_(nullptr), + offset_(variable->Min()), watchers_(variable->Max() - variable->Min() + 1, nullptr), active_watchers_(0) {} ~DenseValueWatcher() override {} IntVar *GetOrMakeValueWatcher(int64 value) override { - const int64 var_max = offset_ + watchers_.size() - 1; // Bad cast. + const int64 var_max = offset_ + watchers_.size() - 1; // Bad cast. if (value < offset_ || value > var_max) { return solver()->MakeIntConst(0); } const int index = value - offset_; IntVar *const watcher = watchers_[index]; - if (watcher != nullptr) - return watcher; + if (watcher != nullptr) return watcher; if (variable_->Contains(value)) { if (variable_->Bound()) { return solver()->MakeIntConst(1); } else { - const std::string vname = - variable_->HasName() ? variable_->name() - : variable_->DebugString(); + const std::string vname = variable_->HasName() + ? variable_->name() + : variable_->DebugString(); const std::string bname = absl::StrFormat("Watch<%s == %d>", vname, value); IntVar *const boolvar = solver()->MakeBoolVar(bname); @@ -739,8 +734,7 @@ public: } else { for (int pos = 0; pos < watchers_.size(); ++pos) { IntVar *const boolvar = watchers_[pos]; - if (boolvar == nullptr) - continue; + if (boolvar == nullptr) continue; const int64 value = pos + offset_; if (!variable_->Contains(value)) { boolvar->SetValue(0); @@ -867,7 +861,7 @@ public: return absl::StrFormat("DenseValueWatcher(%s)", variable_->DebugString()); } - private: + private: DomainIntVar *const variable_; IntVarIterator *const hole_iterator_; RevSwitch posted_; @@ -878,7 +872,7 @@ public: }; class BaseUpperBoundWatcher : public Constraint { - public: + public: explicit BaseUpperBoundWatcher(Solver *const solver) : Constraint(solver) {} ~BaseUpperBoundWatcher() override {} @@ -892,9 +886,9 @@ public: // IsGreater/IsGreaterOrEqual/IsLess/IsLessOrEqual demons // accordingly. class UpperBoundWatcher : public BaseUpperBoundWatcher { - public: + public: class WatchDemon : public Demon { - public: + public: WatchDemon(UpperBoundWatcher *const watcher, int64 index, IntVar *const var) : value_watcher_(watcher), index_(index), var_(var) {} @@ -904,29 +898,32 @@ public: value_watcher_->ProcessUpperBoundWatcher(index_, var_); } - private: + private: UpperBoundWatcher *const value_watcher_; const int64 index_; IntVar *const var_; }; class VarDemon : public Demon { - public: + public: explicit VarDemon(UpperBoundWatcher *const watcher) : value_watcher_(watcher) {} ~VarDemon() override {} void Run(Solver *const solver) override { value_watcher_->ProcessVar(); } - private: + private: UpperBoundWatcher *const value_watcher_; }; UpperBoundWatcher(Solver *const solver, DomainIntVar *const variable) - : BaseUpperBoundWatcher(solver), variable_(variable), + : BaseUpperBoundWatcher(solver), + variable_(variable), var_demon_(nullptr), - watchers_(solver, variable->Min(), variable->Max()), start_(0), - end_(0), sorted_(false) {} + watchers_(solver, variable->Min(), variable->Max()), + start_(0), + end_(0), + sorted_(false) {} ~UpperBoundWatcher() override {} @@ -939,9 +936,9 @@ public: if (variable_->Min() >= value) { return solver()->MakeIntConst(1); } else { - const std::string vname = - variable_->HasName() ? variable_->name() - : variable_->DebugString(); + const std::string vname = variable_->HasName() + ? variable_->name() + : variable_->DebugString(); const std::string bname = absl::StrFormat("Watch<%s >= %d>", vname, value); IntVar *const boolvar = solver()->MakeBoolVar(bname); @@ -1068,7 +1065,7 @@ public: return absl::StrFormat("UpperBoundWatcher(%s)", variable_->DebugString()); } - private: + private: void ProcessUpperBoundWatcher(int64 value, IntVar *const boolvar) { if (boolvar->Min() == 0) { variable_->SetMax(value - 1); @@ -1133,9 +1130,9 @@ public: // Optimized case for small maps. class DenseUpperBoundWatcher : public BaseUpperBoundWatcher { - public: + public: class WatchDemon : public Demon { - public: + public: WatchDemon(DenseUpperBoundWatcher *const watcher, int64 value, IntVar *var) : value_watcher_(watcher), value_(value), var_(var) {} @@ -1145,14 +1142,14 @@ public: value_watcher_->ProcessUpperBoundWatcher(value_, var_); } - private: + private: DenseUpperBoundWatcher *const value_watcher_; const int64 value_; IntVar *const var_; }; class VarDemon : public Demon { - public: + public: explicit VarDemon(DenseUpperBoundWatcher *const watcher) : value_watcher_(watcher) {} @@ -1160,13 +1157,15 @@ public: void Run(Solver *const solver) override { value_watcher_->ProcessVar(); } - private: + private: DenseUpperBoundWatcher *const value_watcher_; }; DenseUpperBoundWatcher(Solver *const solver, DomainIntVar *const variable) - : BaseUpperBoundWatcher(solver), variable_(variable), - var_demon_(nullptr), offset_(variable->Min()), + : BaseUpperBoundWatcher(solver), + variable_(variable), + var_demon_(nullptr), + offset_(variable->Min()), watchers_(variable->Max() - variable->Min() + 1, nullptr), active_watchers_(0) {} @@ -1177,9 +1176,9 @@ public: if (variable_->Min() >= value) { return solver()->MakeIntConst(1); } else { - const std::string vname = - variable_->HasName() ? variable_->name() - : variable_->DebugString(); + const std::string vname = variable_->HasName() + ? variable_->name() + : variable_->DebugString(); const std::string bname = absl::StrFormat("Watch<%s >= %d>", vname, value); IntVar *const boolvar = solver()->MakeBoolVar(bname); @@ -1227,8 +1226,7 @@ public: void InitialPropagate() override { for (int pos = 0; pos < watchers_.size(); ++pos) { IntVar *const boolvar = watchers_[pos]; - if (boolvar == nullptr) - continue; + if (boolvar == nullptr) continue; const int64 value = pos + offset_; if (value <= variable_->Min()) { boolvar->SetValue(1); @@ -1315,7 +1313,7 @@ public: variable_->DebugString()); } - private: + private: DomainIntVar *const variable_; RevSwitch posted_; Demon *var_demon_; @@ -1339,8 +1337,8 @@ public: void SetValue(int64 v) override; bool Bound() const override { return (min_.Value() == max_.Value()); } int64 Value() const override { - CHECK_EQ(min_.Value(), max_.Value()) << " variable " << DebugString() - << " is not bound."; + CHECK_EQ(min_.Value(), max_.Value()) + << " variable " << DebugString() << " is not bound."; return min_.Value(); } void RemoveValue(int64 v) override; @@ -1386,14 +1384,10 @@ public: return s->MakeIsGreaterOrEqualCstVar(this, constant); } if (!Contains(constant)) { - return s->MakeIntConst(int64 { - 0 - }); + return s->MakeIntConst(int64{0}); } if (Bound() && min_.Value() == constant) { - return s->MakeIntConst(int64 { - 1 - }); + return s->MakeIntConst(int64{1}); } IntExpr *const cache = s->Cache()->FindExprConstantExpression( this, constant, ModelCache::EXPR_CONSTANT_IS_EQUAL); @@ -1443,14 +1437,10 @@ public: return s->MakeIsLessOrEqualCstVar(this, constant - 1); } if (!Contains(constant)) { - return s->MakeIntConst(int64 { - 1 - }); + return s->MakeIntConst(int64{1}); } if (Bound() && min_.Value() == constant) { - return s->MakeIntConst(int64 { - 0 - }); + return s->MakeIntConst(int64{0}); } IntExpr *const cache = s->Cache()->FindExprConstantExpression( this, constant, ModelCache::EXPR_CONSTANT_IS_NOT_EQUAL); @@ -1467,14 +1457,10 @@ public: IntVar *IsGreaterOrEqual(int64 constant) override { Solver *const s = solver(); if (max_.Value() < constant) { - return s->MakeIntConst(int64 { - 0 - }); + return s->MakeIntConst(int64{0}); } if (min_.Value() >= constant) { - return s->MakeIntConst(int64 { - 1 - }); + return s->MakeIntConst(int64{1}); } IntExpr *const cache = s->Cache()->FindExprConstantExpression( this, constant, ModelCache::EXPR_CONSTANT_IS_GREATER_OR_EQUAL); @@ -1546,14 +1532,12 @@ public: void Push(); void CleanInProcess(); uint64 Size() const override { - if (bits_ != nullptr) - return bits_->Size(); + if (bits_ != nullptr) return bits_->Size(); return (static_cast(max_.Value()) - static_cast(min_.Value()) + 1); } bool Contains(int64 v) const override { - if (v < min_.Value() || v > max_.Value()) - return false; + if (v < min_.Value() || v > max_.Value()) return false; return (bits_ == nullptr ? true : bits_->Contains(v)); } IntVarIterator *MakeHoleIterator(bool reversible) const override; @@ -1569,7 +1553,7 @@ public: friend class PlusCstDomainIntVar; friend class LinkExprAndDomainIntVar; -private: + private: void CheckOldMin() { if (old_min_ > min_.Value()) { old_min_ = min_.Value(); @@ -1616,10 +1600,15 @@ inline bool ClosedIntervalNoLargerThan(int64 a, int64 b, int64 K) { } class SimpleBitSet : public DomainIntVar::BitSet { -public: + public: SimpleBitSet(Solver *const s, int64 vmin, int64 vmax) - : BitSet(s), bits_(nullptr), stamps_(nullptr), omin_(vmin), omax_(vmax), - size_(vmax - vmin + 1), bsize_(BitLength64(size_.Value())) { + : BitSet(s), + bits_(nullptr), + stamps_(nullptr), + omin_(vmin), + omax_(vmax), + size_(vmax - vmin + 1), + bsize_(BitLength64(size_.Value())) { CHECK(ClosedIntervalNoLargerThan(vmin, vmax, 0xFFFFFFFF)) << "Bitset too large: [" << vmin << ", " << vmax << "]"; bits_ = new uint64[bsize_]; @@ -1634,8 +1623,13 @@ public: SimpleBitSet(Solver *const s, const std::vector &sorted_values, int64 vmin, int64 vmax) - : BitSet(s), bits_(nullptr), stamps_(nullptr), omin_(vmin), omax_(vmax), - size_(sorted_values.size()), bsize_(BitLength64(vmax - vmin + 1)) { + : BitSet(s), + bits_(nullptr), + stamps_(nullptr), + omin_(vmin), + omax_(vmax), + size_(sorted_values.size()), + bsize_(BitLength64(vmax - vmin + 1)) { CHECK(ClosedIntervalNoLargerThan(vmin, vmax, 0xFFFFFFFF)) << "Bitset too large: [" << vmin << ", " << vmax << "]"; bits_ = new uint64[bsize_]; @@ -1666,8 +1660,9 @@ public: DCHECK_LE(cmin, cmax); DCHECK_GE(cmin, omin_); DCHECK_LE(cmax, omax_); - const int64 new_min = UnsafeLeastSignificantBitPosition64( - bits_, nmin - omin_, cmax - omin_) + omin_; + const int64 new_min = + UnsafeLeastSignificantBitPosition64(bits_, nmin - omin_, cmax - omin_) + + omin_; const uint64 removed_bits = BitCountRange64(bits_, cmin - omin_, new_min - omin_ - 1); size_.Add(solver_, -removed_bits); @@ -1680,8 +1675,9 @@ public: DCHECK_LE(cmin, cmax); DCHECK_GE(cmin, omin_); DCHECK_LE(cmax, omax_); - const int64 new_max = UnsafeMostSignificantBitPosition64( - bits_, cmin - omin_, nmax - omin_) + omin_; + const int64 new_max = + UnsafeMostSignificantBitPosition64(bits_, cmin - omin_, nmax - omin_) + + omin_; const uint64 removed_bits = BitCountRange64(bits_, new_max - omin_ + 1, cmax - omin_); size_.Add(solver_, -removed_bits); @@ -1794,7 +1790,7 @@ public: return new DomainIntVar::BitSetIterator(bits_, omin_); } -private: + private: uint64 *bits_; uint64 *stamps_; const int64 omin_; @@ -1808,18 +1804,26 @@ private: // In that case, there are no offset to compute. // Overflows are caught by the robust ClosedIntervalNoLargerThan() method. class SmallBitSet : public DomainIntVar::BitSet { -public: + public: SmallBitSet(Solver *const s, int64 vmin, int64 vmax) - : BitSet(s), bits_(GG_ULONGLONG(0)), stamp_(s->stamp() - 1), omin_(vmin), - omax_(vmax), size_(vmax - vmin + 1) { + : BitSet(s), + bits_(GG_ULONGLONG(0)), + stamp_(s->stamp() - 1), + omin_(vmin), + omax_(vmax), + size_(vmax - vmin + 1) { CHECK(ClosedIntervalNoLargerThan(vmin, vmax, 64)) << vmin << ", " << vmax; bits_ = OneRange64(0, size_.Value() - 1); } SmallBitSet(Solver *const s, const std::vector &sorted_values, int64 vmin, int64 vmax) - : BitSet(s), bits_(GG_ULONGLONG(0)), stamp_(s->stamp() - 1), omin_(vmin), - omax_(vmax), size_(sorted_values.size()) { + : BitSet(s), + bits_(GG_ULONGLONG(0)), + stamp_(s->stamp() - 1), + omin_(vmin), + omax_(vmax), + size_(sorted_values.size()) { CHECK(ClosedIntervalNoLargerThan(vmin, vmax, 64)) << vmin << ", " << vmax; // We know the array is sorted and does not contains duplicate values. for (int i = 0; i < sorted_values.size(); ++i) { @@ -1853,11 +1857,11 @@ public: if (new_bits != GG_ULONGLONG(0)) { // Compute new size and new min size_.SetValue(solver_, BitCount64(new_bits)); - if (bit(nmin)) { // Common case, the new min is inside the bitset + if (bit(nmin)) { // Common case, the new min is inside the bitset return nmin; } return LeastSignificantBitPosition64(new_bits) + omin_; - } else { // == 0 -> Fail() + } else { // == 0 -> Fail() solver_->Fail(); return kint64max; } @@ -1877,11 +1881,11 @@ public: if (new_bits != GG_ULONGLONG(0)) { // Compute new size and new min size_.SetValue(solver_, BitCount64(new_bits)); - if (bit(nmax)) { // Common case, the new max is inside the bitset + if (bit(nmax)) { // Common case, the new max is inside the bitset return nmax; } return MostSignificantBitPosition64(new_bits) + omin_; - } else { // == 0 -> Fail() + } else { // == 0 -> Fail() solver_->Fail(); return kint64min; } @@ -1995,7 +1999,7 @@ public: return new DomainIntVar::BitSetIterator(&bits_, omin_); } -private: + private: uint64 bits_; uint64 stamp_; const int64 omin_; @@ -2005,7 +2009,7 @@ private: }; class EmptyIterator : public IntVarIterator { -public: + public: ~EmptyIterator() override {} void Init() override {} bool Ok() const override { return false; } @@ -2017,7 +2021,7 @@ public: }; class RangeIterator : public IntVarIterator { -public: + public: explicit RangeIterator(const IntVar *const var) : var_(var), min_(kint64max), max_(kint64min), current_(-1) {} @@ -2035,7 +2039,7 @@ public: void Next() override { current_++; } -private: + private: const IntVar *const var_; int64 min_; int64 max_; @@ -2043,7 +2047,7 @@ private: }; class DomainIntVarHoleIterator : public IntVarIterator { -public: + public: explicit DomainIntVarHoleIterator(const DomainIntVar *const v) : var_(v), bits_(nullptr), values_(nullptr), size_(0), index_(0) {} @@ -2072,7 +2076,7 @@ public: void Next() override { index_++; } -private: + private: const DomainIntVar *const var_; DomainIntVar::BitSet *bits_; const int64 *values_; @@ -2081,11 +2085,15 @@ private: }; class DomainIntVarDomainIterator : public IntVarIterator { -public: + public: explicit DomainIntVarDomainIterator(const DomainIntVar *const v, bool reversible) - : var_(v), bitset_iterator_(nullptr), min_(kint64max), max_(kint64min), - current_(-1), reversible_(reversible) {} + : var_(v), + bitset_iterator_(nullptr), + min_(kint64max), + max_(kint64min), + current_(-1), + reversible_(reversible) {} ~DomainIntVarDomainIterator() override { if (!reversible_ && bitset_iterator_) { @@ -2140,7 +2148,7 @@ public: } } -private: + private: const DomainIntVar *const var_; DomainIntVar::BitSetIterator *bitset_iterator_; int64 min_; @@ -2150,7 +2158,7 @@ private: }; class UnaryIterator : public IntVarIterator { -public: + public: UnaryIterator(const IntVar *const v, bool hole, bool reversible) : iterator_(hole ? v->MakeHoleIterator(reversible) : v->MakeDomainIterator(reversible)), @@ -2168,24 +2176,41 @@ public: void Next() override { iterator_->Next(); } -protected: + protected: IntVarIterator *const iterator_; const bool reversible_; }; DomainIntVar::DomainIntVar(Solver *const s, int64 vmin, int64 vmax, const std::string &name) - : IntVar(s, name), min_(vmin), max_(vmax), old_min_(vmin), old_max_(vmax), - new_min_(vmin), new_max_(vmax), handler_(this), in_process_(false), - bits_(nullptr), value_watcher_(nullptr), bound_watcher_(nullptr) {} + : IntVar(s, name), + min_(vmin), + max_(vmax), + old_min_(vmin), + old_max_(vmax), + new_min_(vmin), + new_max_(vmax), + handler_(this), + in_process_(false), + bits_(nullptr), + value_watcher_(nullptr), + bound_watcher_(nullptr) {} DomainIntVar::DomainIntVar(Solver *const s, const std::vector &sorted_values, const std::string &name) - : IntVar(s, name), min_(kint64max), max_(kint64min), old_min_(kint64max), - old_max_(kint64min), new_min_(kint64max), new_max_(kint64min), - handler_(this), in_process_(false), bits_(nullptr), - value_watcher_(nullptr), bound_watcher_(nullptr) { + : IntVar(s, name), + min_(kint64max), + max_(kint64min), + old_min_(kint64max), + old_max_(kint64min), + new_min_(kint64max), + new_max_(kint64min), + handler_(this), + in_process_(false), + bits_(nullptr), + value_watcher_(nullptr), + bound_watcher_(nullptr) { CHECK_GE(sorted_values.size(), 1); // We know that the vector is sorted and does not have duplicate values. const int64 vmin = sorted_values.front(); @@ -2213,10 +2238,8 @@ DomainIntVar::DomainIntVar(Solver *const s, DomainIntVar::~DomainIntVar() {} void DomainIntVar::SetMin(int64 m) { - if (m <= min_.Value()) - return; - if (m > max_.Value()) - solver()->Fail(); + if (m <= min_.Value()) return; + if (m > max_.Value()) solver()->Fail(); if (in_process_) { if (m > new_min_) { new_min_ = m; @@ -2227,8 +2250,9 @@ void DomainIntVar::SetMin(int64 m) { } else { CheckOldMin(); const int64 new_min = - (bits_ == nullptr ? m : bits_->ComputeNewMin(m, min_.Value(), - max_.Value())); + (bits_ == nullptr + ? m + : bits_->ComputeNewMin(m, min_.Value(), max_.Value())); min_.SetValue(solver(), new_min); if (min_.Value() > max_.Value()) { solver()->Fail(); @@ -2238,10 +2262,8 @@ void DomainIntVar::SetMin(int64 m) { } void DomainIntVar::SetMax(int64 m) { - if (m >= max_.Value()) - return; - if (m < min_.Value()) - solver()->Fail(); + if (m >= max_.Value()) return; + if (m < min_.Value()) solver()->Fail(); if (in_process_) { if (m < new_max_) { new_max_ = m; @@ -2252,8 +2274,9 @@ void DomainIntVar::SetMax(int64 m) { } else { CheckOldMax(); const int64 new_max = - (bits_ == nullptr ? m : bits_->ComputeNewMax(m, min_.Value(), - max_.Value())); + (bits_ == nullptr + ? m + : bits_->ComputeNewMax(m, min_.Value(), max_.Value())); max_.SetValue(solver(), new_max); if (min_.Value() > max_.Value()) { solver()->Fail(); @@ -2266,10 +2289,8 @@ void DomainIntVar::SetRange(int64 mi, int64 ma) { if (mi == ma) { SetValue(mi); } else { - if (mi > ma || mi > max_.Value() || ma < min_.Value()) - solver()->Fail(); - if (mi <= min_.Value() && ma >= max_.Value()) - return; + if (mi > ma || mi > max_.Value() || ma < min_.Value()) solver()->Fail(); + if (mi <= min_.Value() && ma >= max_.Value()) return; if (in_process_) { if (ma < new_max_) { new_max_ = ma; @@ -2284,8 +2305,9 @@ void DomainIntVar::SetRange(int64 mi, int64 ma) { if (mi > min_.Value()) { CheckOldMin(); const int64 new_min = - (bits_ == nullptr ? mi : bits_->ComputeNewMin(mi, min_.Value(), - max_.Value())); + (bits_ == nullptr + ? mi + : bits_->ComputeNewMin(mi, min_.Value(), max_.Value())); min_.SetValue(solver(), new_min); } if (min_.Value() > ma) { @@ -2294,8 +2316,9 @@ void DomainIntVar::SetRange(int64 mi, int64 ma) { if (ma < max_.Value()) { CheckOldMax(); const int64 new_max = - (bits_ == nullptr ? ma : bits_->ComputeNewMax(ma, min_.Value(), - max_.Value())); + (bits_ == nullptr + ? ma + : bits_->ComputeNewMax(ma, min_.Value(), max_.Value())); max_.SetValue(solver(), new_max); } if (min_.Value() > max_.Value()) { @@ -2331,8 +2354,7 @@ void DomainIntVar::SetValue(int64 v) { } void DomainIntVar::RemoveValue(int64 v) { - if (v < min_.Value() || v > max_.Value()) - return; + if (v < min_.Value() || v > max_.Value()) return; if (v == min_.Value()) { SetMin(v + 1); } else if (v == max_.Value()) { @@ -2468,10 +2490,10 @@ std::string DomainIntVar::DebugString() const { // ----- Real Boolean Var ----- class ConcreteBooleanVar : public BooleanVar { -public: + public: // Utility classes class Handler : public Demon { - public: + public: explicit Handler(ConcreteBooleanVar *const var) : Demon(), var_(var) {} ~Handler() override {} void Run(Solver *const s) override { @@ -2486,7 +2508,7 @@ public: return absl::StrFormat("Handler(%s)", var_->DebugString()); } - private: + private: ConcreteBooleanVar *const var_; }; @@ -2522,14 +2544,14 @@ public: int64 OldMax() const override { return 1LL; } void RestoreValue() override { value_ = kUnboundBooleanVarValue; } -private: + private: Handler handler_; }; // ----- IntConst ----- class IntConst : public IntVar { -public: + public: IntConst(Solver *const s, int64 value, const std::string &name = "") : IntVar(s, name), value_(value) {} ~IntConst() override {} @@ -2626,14 +2648,14 @@ public: } } -private: + private: int64 value_; }; // ----- x + c variable, optimized case ----- class PlusCstVar : public IntVar { -public: + public: PlusCstVar(Solver *const s, IntVar *v, int64 c) : IntVar(s), var_(v), cst_(c) {} @@ -2684,15 +2706,15 @@ public: int64 Constant() const { return cst_; } -protected: + protected: IntVar *const var_; const int64 cst_; }; class PlusCstIntVar : public PlusCstVar { -public: + public: class PlusCstIntVarIterator : public UnaryIterator { - public: + public: PlusCstIntVarIterator(const IntVar *const v, int64 c, bool hole, bool rev) : UnaryIterator(v, hole, rev), cst_(c) {} @@ -2700,7 +2722,7 @@ public: int64 Value() const override { return iterator_->Value() + cst_; } - private: + private: const int64 cst_; }; @@ -2747,9 +2769,9 @@ public: }; class PlusCstDomainIntVar : public PlusCstVar { -public: + public: class PlusCstDomainIntVarIterator : public UnaryIterator { - public: + public: PlusCstDomainIntVarIterator(const IntVar *const v, int64 c, bool hole, bool reversible) : UnaryIterator(v, hole, reversible), cst_(c) {} @@ -2758,7 +2780,7 @@ public: int64 Value() const override { return iterator_->Value() + cst_; } - private: + private: const int64 cst_; }; @@ -2847,16 +2869,16 @@ bool PlusCstDomainIntVar::Contains(int64 v) const { // c - x variable, optimized case class SubCstIntVar : public IntVar { -public: + public: class SubCstIntVarIterator : public UnaryIterator { - public: + public: SubCstIntVarIterator(const IntVar *const v, int64 c, bool hole, bool rev) : UnaryIterator(v, hole, rev), cst_(c) {} ~SubCstIntVarIterator() override {} int64 Value() const override { return cst_ - iterator_->Value(); } - private: + private: const int64 cst_; }; @@ -2916,7 +2938,7 @@ public: IntVar *SubVar() const { return var_; } int64 Constant() const { return cst_; } -private: + private: IntVar *const var_; const int64 cst_; }; @@ -2981,9 +3003,9 @@ std::string SubCstIntVar::name() const { // -x variable, optimized case class OppIntVar : public IntVar { -public: + public: class OppIntVarIterator : public UnaryIterator { - public: + public: OppIntVarIterator(const IntVar *const v, bool hole, bool reversible) : UnaryIterator(v, hole, reversible) {} ~OppIntVarIterator() override {} @@ -3043,7 +3065,7 @@ public: IntVar *SubVar() const { return var_; } -private: + private: IntVar *const var_; }; @@ -3094,7 +3116,7 @@ std::string OppIntVar::DebugString() const { // x * c variable, optimized case class TimesCstIntVar : public IntVar { -public: + public: TimesCstIntVar(Solver *const s, IntVar *v, int64 c) : IntVar(s), var_(v), cst_(c) {} ~TimesCstIntVar() override {} @@ -3145,15 +3167,15 @@ public: int VarType() const override { return VAR_TIMES_CST; } -protected: + protected: IntVar *const var_; const int64 cst_; }; class TimesPosCstIntVar : public TimesCstIntVar { -public: + public: class TimesPosCstIntVarIterator : public UnaryIterator { - public: + public: TimesPosCstIntVarIterator(const IntVar *const v, int64 c, bool hole, bool reversible) : UnaryIterator(v, hole, reversible), cst_(c) {} @@ -3161,7 +3183,7 @@ public: int64 Value() const override { return iterator_->Value() * cst_; } - private: + private: const int64 cst_; }; @@ -3261,9 +3283,9 @@ bool TimesPosCstIntVar::Contains(int64 v) const { // b * c variable, optimized case class TimesPosCstBoolVar : public TimesCstIntVar { -public: + public: class TimesPosCstBoolVarIterator : public UnaryIterator { - public: + public: // TODO(user) : optimize this. TimesPosCstBoolVarIterator(const IntVar *const v, int64 c, bool hole, bool reversible) @@ -3272,7 +3294,7 @@ public: int64 Value() const override { return iterator_->Value() * cst_; } - private: + private: const int64 cst_; }; @@ -3412,9 +3434,9 @@ bool TimesPosCstBoolVar::Contains(int64 v) const { // TimesNegCstIntVar class TimesNegCstIntVar : public TimesCstIntVar { -public: + public: class TimesNegCstIntVarIterator : public UnaryIterator { - public: + public: TimesNegCstIntVarIterator(const IntVar *const v, int64 c, bool hole, bool reversible) : UnaryIterator(v, hole, reversible), cst_(c) {} @@ -3422,7 +3444,7 @@ public: int64 Value() const override { return iterator_->Value() * cst_; } - private: + private: const int64 cst_; }; @@ -3524,7 +3546,7 @@ bool TimesNegCstIntVar::Contains(int64 v) const { // ----- PlusIntExpr ----- class PlusIntExpr : public BaseIntExpr { -public: + public: PlusIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} @@ -3619,13 +3641,13 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSum, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; class SafePlusIntExpr : public BaseIntExpr { -public: + public: SafePlusIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} @@ -3684,7 +3706,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSum, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -3692,7 +3714,7 @@ private: // ----- PlusIntCstExpr ----- class PlusIntCstExpr : public BaseIntExpr { -public: + public: PlusIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) {} ~PlusIntCstExpr() override {} @@ -3717,7 +3739,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSum, this); } -private: + private: IntExpr *const expr_; const int64 value_; }; @@ -3731,14 +3753,14 @@ IntVar *PlusIntCstExpr::CastToVar() { return BaseIntExpr::CastToVar(); } switch (var->VarType()) { - case DOMAIN_INT_VAR: - cast = s->RegisterIntVar(s->RevAlloc(new PlusCstDomainIntVar( - s, reinterpret_cast(var), value_))); - // FIXME: Break was inserted during fallthrough cleanup. Please check. - break; - default: - cast = s->RegisterIntVar(s->RevAlloc(new PlusCstIntVar(s, var, value_))); - break; + case DOMAIN_INT_VAR: + cast = s->RegisterIntVar(s->RevAlloc(new PlusCstDomainIntVar( + s, reinterpret_cast(var), value_))); + // FIXME: Break was inserted during fallthrough cleanup. Please check. + break; + default: + cast = s->RegisterIntVar(s->RevAlloc(new PlusCstIntVar(s, var, value_))); + break; } return cast; } @@ -3746,7 +3768,7 @@ IntVar *PlusIntCstExpr::CastToVar() { // ----- SubIntExpr ----- class SubIntExpr : public BaseIntExpr { -public: + public: SubIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} @@ -3813,13 +3835,13 @@ public: IntExpr *left() const { return left_; } IntExpr *right() const { return right_; } -protected: + protected: IntExpr *const left_; IntExpr *const right_; }; class SafeSubIntExpr : public SubIntExpr { -public: + public: SafeSubIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : SubIntExpr(s, l, r) {} @@ -3865,7 +3887,7 @@ public: // ----- SubIntCstExpr ----- class SubIntCstExpr : public BaseIntExpr { -public: + public: SubIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) {} ~SubIntCstExpr() override {} @@ -3891,7 +3913,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDifference, this); } -private: + private: IntExpr *const expr_; const int64 value_; }; @@ -3910,7 +3932,7 @@ IntVar *SubIntCstExpr::CastToVar() { // ----- OppIntExpr ----- class OppIntExpr : public BaseIntExpr { -public: + public: OppIntExpr(Solver *const s, IntExpr *const e) : BaseIntExpr(s), expr_(e) {} ~OppIntExpr() override {} int64 Min() const override { return (-expr_->Max()); } @@ -3934,7 +3956,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kOpposite, this); } -private: + private: IntExpr *const expr_; }; @@ -3948,7 +3970,7 @@ IntVar *OppIntExpr::CastToVar() { // ----- TimesIntCstExpr ----- class TimesIntCstExpr : public BaseIntExpr { -public: + public: TimesIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) {} @@ -3978,7 +4000,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -protected: + protected: IntExpr *const expr_; const int64 value_; }; @@ -3986,7 +4008,7 @@ protected: // ----- TimesPosIntCstExpr ----- class TimesPosIntCstExpr : public TimesIntCstExpr { -public: + public: TimesPosIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : TimesIntCstExpr(s, e, v) { CHECK_GT(v, 0); @@ -4020,7 +4042,7 @@ public: // This expressions adds safe arithmetic (w.r.t. overflows) compared // to the previous one. class SafeTimesPosIntCstExpr : public TimesIntCstExpr { -public: + public: SafeTimesPosIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : TimesIntCstExpr(s, e, v) { CHECK_GT(v, 0); @@ -4063,7 +4085,7 @@ public: // ----- TimesIntNegCstExpr ----- class TimesIntNegCstExpr : public TimesIntCstExpr { -public: + public: TimesIntNegCstExpr(Solver *const s, IntExpr *const e, int64 v) : TimesIntCstExpr(s, e, v) { CHECK_LT(v, 0); @@ -4148,11 +4170,11 @@ void SetPosGenMinExpr(IntExpr *const left, IntExpr *const right, int64 m) { if (m > CapProd(lmax, rmax)) { left->solver()->Fail(); } - if (left->Max() == 0) { // left is bound to 0, product is bound to 0. + if (left->Max() == 0) { // left is bound to 0, product is bound to 0. DCHECK_EQ(0, left->Min()); DCHECK_LE(m, 0); } else { - if (m > 0) { // We deduce right > 0. + if (m > 0) { // We deduce right > 0. left->SetMin(PosIntDivUp(m, rmax)); right->SetMin(PosIntDivUp(m, lmax)); } else if (m == 0) { @@ -4160,9 +4182,9 @@ void SetPosGenMinExpr(IntExpr *const left, IntExpr *const right, int64 m) { if (lmin > 0) { right->SetMin(0); } - } else { // m < 0 + } else { // m < 0 const int64 lmin = left->Min(); - if (0 != lmin) { // We cannot deduce anything if 0 is in the domain. + if (0 != lmin) { // We cannot deduce anything if 0 is in the domain. right->SetMin(-PosIntDivDown(-m, lmin)); } } @@ -4182,10 +4204,10 @@ void SetGenGenMinExpr(IntExpr *const left, IntExpr *const right, int64 m) { if (m > std::max(CapProd(lmin, rmin), CapProd(lmax, rmax))) { left->solver()->Fail(); } - if (m > lmin * rmin) { // Must be positive section * positive section. + if (m > lmin * rmin) { // Must be positive section * positive section. left->SetMin(PosIntDivUp(m, rmax)); right->SetMin(PosIntDivUp(m, lmax)); - } else if (m > CapProd(lmax, rmax)) { // Negative section * negative section. + } else if (m > CapProd(lmax, rmax)) { // Negative section * negative section. left->SetMax(-PosIntDivUp(m, -rmin)); right->SetMax(-PosIntDivUp(m, -lmin)); } @@ -4199,7 +4221,7 @@ void TimesSetMin(IntExpr *const left, IntExpr *const right, SetPosPosMinExpr(left, right, m); } else if (right->Max() <= 0) { SetPosPosMaxExpr(left, minus_right, -m); - } else { // right->Min() < 0 && right->Max() > 0 + } else { // right->Min() < 0 && right->Max() > 0 SetPosGenMinExpr(left, right, m); } } else if (left->Max() <= 0) { @@ -4207,23 +4229,25 @@ void TimesSetMin(IntExpr *const left, IntExpr *const right, SetPosPosMaxExpr(right, minus_left, -m); } else if (right->Max() <= 0) { SetPosPosMinExpr(minus_left, minus_right, m); - } else { // right->Min() < 0 && right->Max() > 0 + } else { // right->Min() < 0 && right->Max() > 0 SetPosGenMinExpr(minus_left, minus_right, m); } - } else if (right->Min() >= 0) { // left->Min() < 0 && left->Max() > 0 + } else if (right->Min() >= 0) { // left->Min() < 0 && left->Max() > 0 SetPosGenMinExpr(right, left, m); - } else if (right->Max() <= 0) { // left->Min() < 0 && left->Max() > 0 + } else if (right->Max() <= 0) { // left->Min() < 0 && left->Max() > 0 SetPosGenMinExpr(minus_right, minus_left, m); - } else { // left->Min() < 0 && left->Max() > 0 && - // right->Min() < 0 && right->Max() > 0 + } else { // left->Min() < 0 && left->Max() > 0 && + // right->Min() < 0 && right->Max() > 0 SetGenGenMinExpr(left, right, m); } } class TimesIntExpr : public BaseIntExpr { -public: + public: TimesIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) - : BaseIntExpr(s), left_(l), right_(r), + : BaseIntExpr(s), + left_(l), + right_(r), minus_left_(s->MakeOpposite(left_)), minus_right_(s->MakeOpposite(right_)) {} ~TimesIntExpr() override {} @@ -4266,7 +4290,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; IntExpr *const minus_left_; @@ -4295,7 +4319,7 @@ bool TimesIntExpr::Bound() const { // ----- TimesPosIntExpr ----- class TimesPosIntExpr : public BaseIntExpr { -public: + public: TimesPosIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} ~TimesPosIntExpr() override {} @@ -4324,7 +4348,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -4341,7 +4365,7 @@ bool TimesPosIntExpr::Bound() const { // ----- SafeTimesPosIntExpr ----- class SafeTimesPosIntExpr : public BaseIntExpr { -public: + public: SafeTimesPosIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} ~SafeTimesPosIntExpr() override {} @@ -4381,7 +4405,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -4389,7 +4413,7 @@ private: // ----- TimesBooleanPosIntExpr ----- class TimesBooleanPosIntExpr : public BaseIntExpr { -public: + public: TimesBooleanPosIntExpr(Solver *const s, BooleanVar *const b, IntExpr *const e) : BaseIntExpr(s), boolvar_(b), expr_(e) {} ~TimesBooleanPosIntExpr() override {} @@ -4425,7 +4449,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -private: + private: BooleanVar *const boolvar_; IntExpr *const expr_; }; @@ -4487,35 +4511,37 @@ bool TimesBooleanPosIntExpr::Bound() const { // ----- TimesBooleanIntExpr ----- class TimesBooleanIntExpr : public BaseIntExpr { -public: + public: TimesBooleanIntExpr(Solver *const s, BooleanVar *const b, IntExpr *const e) : BaseIntExpr(s), boolvar_(b), expr_(e) {} ~TimesBooleanIntExpr() override {} int64 Min() const override { switch (boolvar_->RawValue()) { - case 0: { return 0LL; } - case 1: { return expr_->Min(); } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - return std::min(int64 { - 0 - }, - expr_->Min()); - } + case 0: { + return 0LL; + } + case 1: { + return expr_->Min(); + } + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + return std::min(int64{0}, expr_->Min()); + } } } void SetMin(int64 m) override; int64 Max() const override { switch (boolvar_->RawValue()) { - case 0: { return 0LL; } - case 1: { return expr_->Max(); } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - return std::max(int64 { - 0 - }, - expr_->Max()); - } + case 0: { + return 0LL; + } + case 1: { + return expr_->Max(); + } + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + return std::max(int64{0}, expr_->Max()); + } } } void SetMax(int64 m) override; @@ -4543,83 +4569,77 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kProduct, this); } -private: + private: BooleanVar *const boolvar_; IntExpr *const expr_; }; void TimesBooleanIntExpr::SetMin(int64 m) { switch (boolvar_->RawValue()) { - case 0: { - if (m > 0) { - solver()->Fail(); + case 0: { + if (m > 0) { + solver()->Fail(); + } + break; } - break; - } - case 1: { - expr_->SetMin(m); - break; - } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - if (m > 0) { // 0 is no longer possible for boolvar because min > 0. - boolvar_->SetValue(1); + case 1: { expr_->SetMin(m); - } else if (m <= 0 && expr_->Max() < m) { - boolvar_->SetValue(0); + break; + } + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + if (m > 0) { // 0 is no longer possible for boolvar because min > 0. + boolvar_->SetValue(1); + expr_->SetMin(m); + } else if (m <= 0 && expr_->Max() < m) { + boolvar_->SetValue(0); + } } - } } } void TimesBooleanIntExpr::SetMax(int64 m) { switch (boolvar_->RawValue()) { - case 0: { - if (m < 0) { - solver()->Fail(); + case 0: { + if (m < 0) { + solver()->Fail(); + } + break; } - break; - } - case 1: { - expr_->SetMax(m); - break; - } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - if (m < 0) { // 0 is no longer possible for boolvar because max < 0. - boolvar_->SetValue(1); + case 1: { expr_->SetMax(m); - } else if (m >= 0 && expr_->Min() > m) { - boolvar_->SetValue(0); + break; + } + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + if (m < 0) { // 0 is no longer possible for boolvar because max < 0. + boolvar_->SetValue(1); + expr_->SetMax(m); + } else if (m >= 0 && expr_->Min() > m) { + boolvar_->SetValue(0); + } } - } } } void TimesBooleanIntExpr::Range(int64 *mi, int64 *ma) { switch (boolvar_->RawValue()) { - case 0: { - *mi = 0; - *ma = 0; - break; - } - case 1: { - *mi = expr_->Min(); - *ma = expr_->Max(); - break; - } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - *mi = std::min(int64 { - 0 - }, - expr_->Min()); - *ma = std::max(int64 { - 0 - }, - expr_->Max()); - break; - } + case 0: { + *mi = 0; + *ma = 0; + break; + } + case 1: { + *mi = expr_->Min(); + *ma = expr_->Max(); + break; + } + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + *mi = std::min(int64{0}, expr_->Min()); + *ma = std::max(int64{0}, expr_->Max()); + break; + } } } @@ -4628,32 +4648,32 @@ void TimesBooleanIntExpr::SetRange(int64 mi, int64 ma) { solver()->Fail(); } switch (boolvar_->RawValue()) { - case 0: { - if (mi > 0 || ma < 0) { - solver()->Fail(); + case 0: { + if (mi > 0 || ma < 0) { + solver()->Fail(); + } + break; } - break; - } - case 1: { - expr_->SetRange(mi, ma); - break; - } - default: { - DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); - if (mi > 0) { - boolvar_->SetValue(1); - expr_->SetMin(mi); - } else if (mi == 0 && expr_->Max() < 0) { - boolvar_->SetValue(0); + case 1: { + expr_->SetRange(mi, ma); + break; } - if (ma < 0) { - boolvar_->SetValue(1); - expr_->SetMax(ma); - } else if (ma == 0 && expr_->Min() > 0) { - boolvar_->SetValue(0); + default: { + DCHECK_EQ(BooleanVar::kUnboundBooleanVarValue, boolvar_->RawValue()); + if (mi > 0) { + boolvar_->SetValue(1); + expr_->SetMin(mi); + } else if (mi == 0 && expr_->Max() < 0) { + boolvar_->SetValue(0); + } + if (ma < 0) { + boolvar_->SetValue(1); + expr_->SetMax(ma); + } else if (ma == 0 && expr_->Min() > 0) { + boolvar_->SetValue(0); + } + break; } - break; - } } } @@ -4667,7 +4687,7 @@ bool TimesBooleanIntExpr::Bound() const { // ----- DivPosIntCstExpr ----- class DivPosIntCstExpr : public BaseIntExpr { -public: + public: DivPosIntCstExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) { CHECK_GE(v, 0); @@ -4711,7 +4731,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDivide, this); } -private: + private: IntExpr *const expr_; const int64 value_; }; @@ -4719,9 +4739,11 @@ private: // DivPosIntExpr class DivPosIntExpr : public BaseIntExpr { -public: + public: DivPosIntExpr(Solver *const s, IntExpr *const num, IntExpr *const denom) - : BaseIntExpr(s), num_(num), denom_(denom), + : BaseIntExpr(s), + num_(num), + denom_(denom), opp_num_(s->MakeOpposite(num)) {} ~DivPosIntExpr() override {} @@ -4785,14 +4807,14 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDivide, this); } -private: + private: IntExpr *const num_; IntExpr *const denom_; IntExpr *const opp_num_; }; class DivPosPosIntExpr : public BaseIntExpr { -public: + public: DivPosPosIntExpr(Solver *const s, IntExpr *const num, IntExpr *const denom) : BaseIntExpr(s), num_(num), denom_(denom) {} @@ -4851,7 +4873,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDivide, this); } -private: + private: IntExpr *const num_; IntExpr *const denom_; }; @@ -4859,9 +4881,11 @@ private: // DivIntExpr class DivIntExpr : public BaseIntExpr { -public: + public: DivIntExpr(Solver *const s, IntExpr *const num, IntExpr *const denom) - : BaseIntExpr(s), num_(num), denom_(denom), + : BaseIntExpr(s), + num_(num), + denom_(denom), opp_num_(s->MakeOpposite(num)) {} ~DivIntExpr() override {} @@ -4873,18 +4897,18 @@ public: const int64 denom_max = denom_->Max(); if (denom_min == 0 && denom_max == 0) { - return kint64max; // TODO(user): Check this convention. + return kint64max; // TODO(user): Check this convention. } - if (denom_min >= 0) { // Denominator strictly positive. + if (denom_min >= 0) { // Denominator strictly positive. DCHECK_GT(denom_max, 0); const int64 adjusted_denom_min = denom_min == 0 ? 1 : denom_min; return num_min >= 0 ? num_min / denom_max : num_min / adjusted_denom_min; - } else if (denom_max <= 0) { // Denominator strictly negative. + } else if (denom_max <= 0) { // Denominator strictly negative. DCHECK_LT(denom_min, 0); const int64 adjusted_denom_max = denom_max == 0 ? -1 : denom_max; return num_max >= 0 ? num_max / adjusted_denom_max : num_max / denom_min; - } else { // Denominator across 0. + } else { // Denominator across 0. return std::min(num_min, -num_max); } } @@ -4896,19 +4920,19 @@ public: const int64 denom_max = denom_->Max(); if (denom_min == 0 && denom_max == 0) { - return kint64min; // TODO(user): Check this convention. + return kint64min; // TODO(user): Check this convention. } - if (denom_min >= 0) { // Denominator strictly positive. + if (denom_min >= 0) { // Denominator strictly positive. DCHECK_GT(denom_max, 0); const int64 adjusted_denom_min = denom_min == 0 ? 1 : denom_min; return num_max >= 0 ? num_max / adjusted_denom_min : num_max / denom_max; - } else if (denom_max <= 0) { // Denominator strictly negative. + } else if (denom_max <= 0) { // Denominator strictly negative. DCHECK_LT(denom_min, 0); const int64 adjusted_denom_max = denom_max == 0 ? -1 : denom_max; return num_min >= 0 ? num_min / denom_min : -num_min / -adjusted_denom_max; - } else { // Denominator across 0. + } else { // Denominator across 0. return std::max(num_max, -num_min); } } @@ -4930,13 +4954,13 @@ public: const int64 denom_max = denom->Max(); DCHECK_NE(denom_min, 0); DCHECK_NE(denom_max, 0); - if (denom_min > 0) { // Denominator strictly positive. + if (denom_min > 0) { // Denominator strictly positive. num->SetMin(m * denom_min); denom->SetMax(num_max / m); - } else if (denom_max < 0) { // Denominator strictly negative. + } else if (denom_max < 0) { // Denominator strictly negative. num->SetMax(m * denom_max); denom->SetMin(num_min / m); - } else { // Denominator across 0. + } else { // Denominator across 0. if (num_min >= 0) { num->SetMin(m); denom->SetRange(1, num_max / m); @@ -4944,10 +4968,10 @@ public: num->SetMax(-m); denom->SetRange(num_min / m, -1); } else { - if (m > -num_min) { // Denominator is forced positive. + if (m > -num_min) { // Denominator is forced positive. num->SetMin(m); denom->SetRange(1, num_max / m); - } else if (m > num_max) { // Denominator is forced negative. + } else if (m > num_max) { // Denominator is forced negative. num->SetMax(-m); denom->SetRange(num_min / m, -1); } else { @@ -4966,7 +4990,7 @@ public: const int64 denom_max = denom->Max(); DCHECK_NE(denom_min, 0); DCHECK_NE(denom_max, 0); - if (denom_min > 0) { // Denominator strictly positive. + if (denom_min > 0) { // Denominator strictly positive. num->SetMax((m + 1) * denom_max - 1); denom->SetMin((num_min / (m + 1)) + 1); } else if (denom_max < 0) { @@ -5017,7 +5041,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDivide, this); } -private: + private: IntExpr *const num_; IntExpr *const denom_; IntExpr *const opp_num_; @@ -5026,7 +5050,7 @@ private: // ----- IntAbs And IntAbsConstraint ------ class IntAbsConstraint : public CastConstraint { -public: + public: IntAbsConstraint(Solver *const s, IntVar *const sub, IntVar *const target) : CastConstraint(s, target), sub_(sub) {} @@ -5085,12 +5109,12 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAbsEqual, this); } -private: + private: IntVar *const sub_; }; class IntAbs : public BaseIntExpr { -public: + public: IntAbs(Solver *const s, IntExpr *const e) : BaseIntExpr(s), expr_(e) {} ~IntAbs() override {} @@ -5192,7 +5216,7 @@ public: return target; } -private: + private: IntExpr *const expr_; }; @@ -5200,7 +5224,7 @@ private: // TODO(user): shouldn't we compare to kint32max^2 instead of kint64max? class IntSquare : public BaseIntExpr { -public: + public: IntSquare(Solver *const s, IntExpr *const e) : BaseIntExpr(s), expr_(e) {} ~IntSquare() override {} @@ -5267,12 +5291,12 @@ public: IntExpr *expr() const { return expr_; } -protected: + protected: IntExpr *const expr_; }; class PosIntSquare : public IntSquare { -public: + public: PosIntSquare(Solver *const s, IntExpr *const e) : IntSquare(s, e) {} ~PosIntSquare() override {} @@ -5320,7 +5344,7 @@ int64 OverflowLimit(int64 power) { } class BasePower : public BaseIntExpr { -public: + public: BasePower(Solver *const s, IntExpr *const e, int64 n) : BaseIntExpr(s), expr_(e), pow_(n), limit_(OverflowLimit(n)) { CHECK_GT(n, 0); @@ -5352,7 +5376,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kPower, this); } -protected: + protected: int64 Pown(int64 value) const { if (value >= limit_) { return kint64max; @@ -5423,7 +5447,7 @@ protected: }; class IntEvenPower : public BasePower { -public: + public: IntEvenPower(Solver *const s, IntExpr *const e, int64 n) : BasePower(s, e, n) { CHECK_EQ(0, n % 2); @@ -5477,7 +5501,7 @@ public: }; class PosIntEvenPower : public BasePower { -public: + public: PosIntEvenPower(Solver *const s, IntExpr *const e, int64 pow) : BasePower(s, e, pow) { CHECK_EQ(0, pow % 2); @@ -5507,7 +5531,7 @@ public: }; class IntOddPower : public BasePower { -public: + public: IntOddPower(Solver *const s, IntExpr *const e, int64 n) : BasePower(s, e, n) { CHECK_EQ(1, n % 2); } @@ -5526,7 +5550,7 @@ public: // ----- Min(expr, expr) ----- class MinIntExpr : public BaseIntExpr { -public: + public: MinIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} ~MinIntExpr() override {} @@ -5572,7 +5596,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kMin, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -5580,7 +5604,7 @@ private: // ----- Min(expr, constant) ----- class MinCstIntExpr : public BaseIntExpr { -public: + public: MinCstIntExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) {} @@ -5626,7 +5650,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kMin, this); } -private: + private: IntExpr *const expr_; const int64 value_; }; @@ -5634,7 +5658,7 @@ private: // ----- Max(expr, expr) ----- class MaxIntExpr : public BaseIntExpr { -public: + public: MaxIntExpr(Solver *const s, IntExpr *const l, IntExpr *const r) : BaseIntExpr(s), left_(l), right_(r) {} @@ -5681,7 +5705,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kMax, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -5689,7 +5713,7 @@ private: // ----- Max(expr, constant) ----- class MaxCstIntExpr : public BaseIntExpr { -public: + public: MaxCstIntExpr(Solver *const s, IntExpr *const e, int64 v) : BaseIntExpr(s), expr_(e), value_(v) {} @@ -5735,7 +5759,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kMax, this); } -private: + private: IntExpr *const expr_; const int64 value_; }; @@ -5749,18 +5773,17 @@ private: // late_date, the cost is late_cost * (x - late_date). class SimpleConvexPiecewiseExpr : public BaseIntExpr { -public: + public: SimpleConvexPiecewiseExpr(Solver *const s, IntExpr *const e, int64 ec, int64 ed, int64 ld, int64 lc) - : BaseIntExpr(s), expr_(e), early_cost_(ec), + : BaseIntExpr(s), + expr_(e), + early_cost_(ec), early_date_(ec == 0 ? kint64min : ed), - late_date_(lc == 0 ? kint64max : ld), late_cost_(lc) { - DCHECK_GE(ec, int64 { - 0 - }); - DCHECK_GE(lc, int64 { - 0 - }); + late_date_(lc == 0 ? kint64max : ld), + late_cost_(lc) { + DCHECK_GE(ec, int64{0}); + DCHECK_GE(lc, int64{0}); DCHECK_GE(ld, ed); // If the penalty is 0, we can push the "confort zone or zone @@ -5856,7 +5879,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kConvexPiecewise, this); } -private: + private: IntExpr *const expr_; const int64 early_cost_; const int64 early_date_; @@ -5867,16 +5890,12 @@ private: // ----- Semi Continuous ----- class SemiContinuousExpr : public BaseIntExpr { -public: + public: SemiContinuousExpr(Solver *const s, IntExpr *const e, int64 fixed_charge, int64 step) : BaseIntExpr(s), expr_(e), fixed_charge_(fixed_charge), step_(step) { - DCHECK_GE(fixed_charge, int64 { - 0 - }); - DCHECK_GT(step, int64 { - 0 - }); + DCHECK_GE(fixed_charge, int64{0}); + DCHECK_GT(step, int64{0}); } ~SemiContinuousExpr() override {} @@ -5939,20 +5958,18 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSemiContinuous, this); } -private: + private: IntExpr *const expr_; const int64 fixed_charge_; const int64 step_; }; class SemiContinuousStepOneExpr : public BaseIntExpr { -public: + public: SemiContinuousStepOneExpr(Solver *const s, IntExpr *const e, int64 fixed_charge) : BaseIntExpr(s), expr_(e), fixed_charge_(fixed_charge) { - DCHECK_GE(fixed_charge, int64 { - 0 - }); + DCHECK_GE(fixed_charge, int64{0}); } ~SemiContinuousStepOneExpr() override {} @@ -6010,19 +6027,17 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSemiContinuous, this); } -private: + private: IntExpr *const expr_; const int64 fixed_charge_; }; class SemiContinuousStepZeroExpr : public BaseIntExpr { -public: + public: SemiContinuousStepZeroExpr(Solver *const s, IntExpr *const e, int64 fixed_charge) : BaseIntExpr(s), expr_(e), fixed_charge_(fixed_charge) { - DCHECK_GT(fixed_charge, int64 { - 0 - }); + DCHECK_GT(fixed_charge, int64{0}); } ~SemiContinuousStepZeroExpr() override {} @@ -6078,14 +6093,14 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kSemiContinuous, this); } -private: + private: IntExpr *const expr_; const int64 fixed_charge_; }; // This constraints links an expression and the variable it is casted into class LinkExprAndVar : public CastConstraint { -public: + public: LinkExprAndVar(Solver *const s, IntExpr *const expr, IntVar *const var) : CastConstraint(s, var), expr_(expr) {} @@ -6119,17 +6134,19 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLinkExprVar, this); } -private: + private: IntExpr *const expr_; }; // ----- Conditional Expression ----- class ExprWithEscapeValue : public BaseIntExpr { -public: + public: ExprWithEscapeValue(Solver *const s, IntVar *const c, IntExpr *const e, int64 unperformed_value) - : BaseIntExpr(s), condition_(c), expression_(e), + : BaseIntExpr(s), + condition_(c), + expression_(e), unperformed_value_(unperformed_value) {} ~ExprWithEscapeValue() override {} @@ -6224,7 +6241,7 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kConditionalExpr, this); } -private: + private: IntVar *const condition_; IntExpr *const expression_; const int64 unperformed_value_; @@ -6233,11 +6250,14 @@ private: // ----- This is a specialized case when the variable exact type is known ----- class LinkExprAndDomainIntVar : public CastConstraint { -public: + public: LinkExprAndDomainIntVar(Solver *const s, IntExpr *const expr, DomainIntVar *const var) - : CastConstraint(s, var), expr_(expr), cached_min_(kint64min), - cached_max_(kint64max), fail_stamp_(GG_ULONGLONG(0)) {} + : CastConstraint(s, var), + expr_(expr), + cached_min_(kint64min), + cached_max_(kint64max), + fail_stamp_(GG_ULONGLONG(0)) {} ~LinkExprAndDomainIntVar() override {} @@ -6283,13 +6303,13 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLinkExprVar, this); } -private: + private: IntExpr *const expr_; int64 cached_min_; int64 cached_max_; uint64 fail_stamp_; }; -} // namespace +} // namespace // ----- Misc ----- @@ -6363,14 +6383,12 @@ IntVar *Solver::MakeIntVar(const std::vector &values, const std::string &name) { DCHECK(!values.empty()); // Fast-track the case where we have a single value. - if (values.size() == 1) - return MakeIntConst(values[0], name); + if (values.size() == 1) return MakeIntConst(values[0], name); // Sort and remove duplicates. std::vector unique_sorted_values = values; gtl::STLSortAndRemoveDuplicates(&unique_sorted_values); // Case when we have a single value, after clean-up. - if (unique_sorted_values.size() == 1) - return MakeIntConst(values[0], name); + if (unique_sorted_values.size() == 1) return MakeIntConst(values[0], name); // Case when the values are a dense interval of integers. if (unique_sorted_values.size() == unique_sorted_values.back() - unique_sorted_values.front() + 1) { @@ -6384,7 +6402,7 @@ IntVar *Solver::MakeIntVar(const std::vector &values, if (gcd == 0) { gcd = std::abs(v); } else { - gcd = MathUtil::GCD64(gcd, std::abs(v)); // Supports v==0. + gcd = MathUtil::GCD64(gcd, std::abs(v)); // Supports v==0. } if (gcd == 1) { // If it's 1, though, we can't do anything special, so we @@ -6455,7 +6473,7 @@ std::string IndexedName(const std::string &prefix, int index, int max_index) { return absl::StrCat(prefix, index); #endif } -} // namespace +} // namespace void Solver::MakeIntVarArray(int var_count, int64 vmin, int64 vmax, const std::string &name, @@ -6505,7 +6523,7 @@ IntVar **Solver::MakeBoolVarArray(int var_count, const std::string &name) { void Solver::InitCachedIntConstants() { for (int i = MIN_CACHED_INT_CONST; i <= MAX_CACHED_INT_CONST; ++i) { cached_constants_[i - MIN_CACHED_INT_CONST] = - RevAlloc(new IntConst(this, i, "")); // note the empty name + RevAlloc(new IntConst(this, i, "")); // note the empty name } } @@ -6556,51 +6574,52 @@ IntExpr *Solver::MakeSum(IntExpr *const expr, int64 value) { !AddOverflows(value, expr->Min())) { IntVar *const var = expr->Var(); switch (var->VarType()) { - case DOMAIN_INT_VAR: { - result = RegisterIntExpr(RevAlloc(new PlusCstDomainIntVar( - this, reinterpret_cast(var), value))); - break; - } - case CONST_VAR: { - result = RegisterIntExpr(MakeIntConst(var->Min() + value)); - break; - } - case VAR_ADD_CST: { - PlusCstVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - const int64 new_constant = value + add_var->Constant(); - if (new_constant == 0) { - result = sub_var; - } else { - if (sub_var->VarType() == DOMAIN_INT_VAR) { - DomainIntVar *const dvar = - reinterpret_cast(sub_var); - result = RegisterIntExpr( - RevAlloc(new PlusCstDomainIntVar(this, dvar, new_constant))); - } else { - result = RegisterIntExpr( - RevAlloc(new PlusCstIntVar(this, sub_var, new_constant))); - } + case DOMAIN_INT_VAR: { + result = RegisterIntExpr(RevAlloc(new PlusCstDomainIntVar( + this, reinterpret_cast(var), value))); + break; } - break; - } - case CST_SUB_VAR: { - SubCstIntVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - const int64 new_constant = value + add_var->Constant(); - result = RegisterIntExpr( - RevAlloc(new SubCstIntVar(this, sub_var, new_constant))); - break; - } - case OPP_VAR: { - OppIntVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - result = - RegisterIntExpr(RevAlloc(new SubCstIntVar(this, sub_var, value))); - break; - } - default: - result = RegisterIntExpr(RevAlloc(new PlusCstIntVar(this, var, value))); + case CONST_VAR: { + result = RegisterIntExpr(MakeIntConst(var->Min() + value)); + break; + } + case VAR_ADD_CST: { + PlusCstVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + const int64 new_constant = value + add_var->Constant(); + if (new_constant == 0) { + result = sub_var; + } else { + if (sub_var->VarType() == DOMAIN_INT_VAR) { + DomainIntVar *const dvar = + reinterpret_cast(sub_var); + result = RegisterIntExpr( + RevAlloc(new PlusCstDomainIntVar(this, dvar, new_constant))); + } else { + result = RegisterIntExpr( + RevAlloc(new PlusCstIntVar(this, sub_var, new_constant))); + } + } + break; + } + case CST_SUB_VAR: { + SubCstIntVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + const int64 new_constant = value + add_var->Constant(); + result = RegisterIntExpr( + RevAlloc(new SubCstIntVar(this, sub_var, new_constant))); + break; + } + case OPP_VAR: { + OppIntVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + result = + RegisterIntExpr(RevAlloc(new SubCstIntVar(this, sub_var, value))); + break; + } + default: + result = + RegisterIntExpr(RevAlloc(new PlusCstIntVar(this, var, value))); } } else { result = RegisterIntExpr(RevAlloc(new PlusIntCstExpr(this, expr, value))); @@ -6667,33 +6686,34 @@ IntExpr *Solver::MakeDifference(int64 value, IntExpr *const expr) { !SubOverflows(value, expr->Max())) { IntVar *const var = expr->Var(); switch (var->VarType()) { - case VAR_ADD_CST: { - PlusCstVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - const int64 new_constant = value - add_var->Constant(); - if (new_constant == 0) { - result = sub_var; - } else { - result = RegisterIntExpr( - RevAlloc(new SubCstIntVar(this, sub_var, new_constant))); + case VAR_ADD_CST: { + PlusCstVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + const int64 new_constant = value - add_var->Constant(); + if (new_constant == 0) { + result = sub_var; + } else { + result = RegisterIntExpr( + RevAlloc(new SubCstIntVar(this, sub_var, new_constant))); + } + break; } - break; - } - case CST_SUB_VAR: { - SubCstIntVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - const int64 new_constant = value - add_var->Constant(); - result = MakeSum(sub_var, new_constant); - break; - } - case OPP_VAR: { - OppIntVar *const add_var = reinterpret_cast(var); - IntVar *const sub_var = add_var->SubVar(); - result = MakeSum(sub_var, value); - break; - } - default: - result = RegisterIntExpr(RevAlloc(new SubCstIntVar(this, var, value))); + case CST_SUB_VAR: { + SubCstIntVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + const int64 new_constant = value - add_var->Constant(); + result = MakeSum(sub_var, new_constant); + break; + } + case OPP_VAR: { + OppIntVar *const add_var = reinterpret_cast(var); + IntVar *const sub_var = add_var->SubVar(); + result = MakeSum(sub_var, value); + break; + } + default: + result = + RegisterIntExpr(RevAlloc(new SubCstIntVar(this, var, value))); } } else { result = RegisterIntExpr(RevAlloc(new SubIntCstExpr(this, expr, value))); @@ -6754,7 +6774,7 @@ IntExpr *Solver::MakeProd(IntExpr *const expr, int64 value) { } } else if (coefficient == 0) { result = MakeIntConst(0); - } else { // coefficient < 0. + } else { // coefficient < 0. result = RegisterIntExpr( RevAlloc(new TimesIntNegCstExpr(this, m_expr, coefficient))); } @@ -6810,7 +6830,7 @@ void ExtractProduct(IntExpr **const expr, int64 *const coefficient, *modified = true; } } -} // namespace +} // namespace IntExpr *Solver::MakeProd(IntExpr *const left, IntExpr *const right) { if (left->Bound()) { @@ -6879,7 +6899,7 @@ IntExpr *Solver::MakeProd(IntExpr *const left, IntExpr *const right) { } } else if (left->Min() >= 0 && right->Min() >= 0) { if (CapProd(left->Max(), right->Max()) == - kint64max) { // Potential overflow. + kint64max) { // Potential overflow. result = RegisterIntExpr(RevAlloc(new SafeTimesPosIntExpr(this, left, right))); } else { @@ -7004,31 +7024,32 @@ IntExpr *Solver::MakePower(IntExpr *const expr, int64 n) { CHECK_GE(n, 0); if (expr->Bound()) { const int64 v = expr->Min(); - if (v >= OverflowLimit(n)) { // Overflow. + if (v >= OverflowLimit(n)) { // Overflow. return MakeIntConst(kint64max); } return MakeIntConst(IntPower(v, n)); } switch (n) { - case 0: - return MakeIntConst(1); - case 1: - return expr; - case 2: - return MakeSquare(expr); - default: { - IntExpr *result = nullptr; - if (n % 2 == 0) { // even. - if (expr->Min() >= 0) { - result = RegisterIntExpr(RevAlloc(new PosIntEvenPower(this, expr, n))); + case 0: + return MakeIntConst(1); + case 1: + return expr; + case 2: + return MakeSquare(expr); + default: { + IntExpr *result = nullptr; + if (n % 2 == 0) { // even. + if (expr->Min() >= 0) { + result = + RegisterIntExpr(RevAlloc(new PosIntEvenPower(this, expr, n))); + } else { + result = RegisterIntExpr(RevAlloc(new IntEvenPower(this, expr, n))); + } } else { - result = RegisterIntExpr(RevAlloc(new IntEvenPower(this, expr, n))); + result = RegisterIntExpr(RevAlloc(new IntOddPower(this, expr, n))); } - } else { - result = RegisterIntExpr(RevAlloc(new IntOddPower(this, expr, n))); + return result; } - return result; - } } } @@ -7115,9 +7136,7 @@ IntExpr *Solver::MakeSemiContinuousExpr(IntExpr *const expr, int64 fixed_charge, int64 step) { if (step == 0) { if (fixed_charge == 0) { - return MakeIntConst(int64 { - 0 - }); + return MakeIntConst(int64{0}); } else { return RegisterIntExpr( RevAlloc(new SemiContinuousStepZeroExpr(this, expr, fixed_charge))); @@ -7136,7 +7155,7 @@ IntExpr *Solver::MakeSemiContinuousExpr(IntExpr *const expr, int64 fixed_charge, // ----- Piecewise Linear ----- class PiecewiseLinearExpr : public BaseIntExpr { -public: + public: PiecewiseLinearExpr(Solver *solver, IntExpr *expr, const PiecewiseLinearFunction &f) : BaseIntExpr(solver), expr_(expr), f_(f) {} @@ -7181,7 +7200,7 @@ public: // TODO(user): Implement visitor. } -private: + private: IntExpr *const expr_; const PiecewiseLinearFunction f_; }; @@ -7248,48 +7267,50 @@ void IntVar::RemoveValues(const std::vector &values) { const int size = values.size(); DCHECK_GE(size, 0); switch (size) { - case 0: { return; } - case 1: { - RemoveValue(values[0]); - return; - } - case 2: { - RemoveValue(values[0]); - RemoveValue(values[1]); - return; - } - case 3: { - RemoveValue(values[0]); - RemoveValue(values[1]); - RemoveValue(values[2]); - return; - } - default: { - // 4 values, let's start doing some more clever things. - // TODO(user) : Sort values! - int start_index = 0; - int64 new_min = Min(); - if (values[start_index] <= new_min) { - while (start_index < size - 1 && - values[start_index + 1] == values[start_index] + 1) { - new_min = values[start_index + 1] + 1; - start_index++; + case 0: { + return; + } + case 1: { + RemoveValue(values[0]); + return; + } + case 2: { + RemoveValue(values[0]); + RemoveValue(values[1]); + return; + } + case 3: { + RemoveValue(values[0]); + RemoveValue(values[1]); + RemoveValue(values[2]); + return; + } + default: { + // 4 values, let's start doing some more clever things. + // TODO(user) : Sort values! + int start_index = 0; + int64 new_min = Min(); + if (values[start_index] <= new_min) { + while (start_index < size - 1 && + values[start_index + 1] == values[start_index] + 1) { + new_min = values[start_index + 1] + 1; + start_index++; + } + } + int end_index = size - 1; + int64 new_max = Max(); + if (values[end_index] >= new_max) { + while (end_index > start_index + 1 && + values[end_index - 1] == values[end_index] - 1) { + new_max = values[end_index - 1] - 1; + end_index--; + } + } + SetRange(new_min, new_max); + for (int i = start_index; i <= end_index; ++i) { + RemoveValue(values[i]); } } - int end_index = size - 1; - int64 new_max = Max(); - if (values[end_index] >= new_max) { - while (end_index > start_index + 1 && - values[end_index - 1] == values[end_index] - 1) { - new_max = values[end_index - 1] - 1; - end_index--; - } - } - SetRange(new_min, new_max); - for (int i = start_index; i <= end_index; ++i) { - RemoveValue(values[i]); - } - } } } @@ -7300,74 +7321,74 @@ void IntVar::Accept(ModelVisitor *const visitor) const { void IntVar::SetValues(const std::vector &values) { switch (values.size()) { - case 0: { - solver()->Fail(); - break; - } - case 1: { - SetValue(values.back()); - break; - } - case 2: { - if (Contains(values[0])) { - if (Contains(values[1])) { - const int64 l = std::min(values[0], values[1]); - const int64 u = std::max(values[0], values[1]); - SetRange(l, u); - if (u > l + 1) { - RemoveInterval(l + 1, u - 1); + case 0: { + solver()->Fail(); + break; + } + case 1: { + SetValue(values.back()); + break; + } + case 2: { + if (Contains(values[0])) { + if (Contains(values[1])) { + const int64 l = std::min(values[0], values[1]); + const int64 u = std::max(values[0], values[1]); + SetRange(l, u); + if (u > l + 1) { + RemoveInterval(l + 1, u - 1); + } + } else { + SetValue(values[0]); } } else { - SetValue(values[0]); + SetValue(values[1]); } - } else { - SetValue(values[1]); + break; } - break; - } - default: { - // TODO(user): use a clean and safe SortedUniqueCopy() class - // that uses a global, static shared (and locked) storage. - // TODO(user): [optional] consider porting - // STLSortAndRemoveDuplicates from ortools/base/stl_util.h to the - // existing open_source/base/stl_util.h and using it here. - // TODO(user): We could filter out values not in the var. - std::vector &tmp = solver()->tmp_vector_; - tmp.clear(); - tmp.insert(tmp.end(), values.begin(), values.end()); - std::sort(tmp.begin(), tmp.end()); - tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end()); - const int size = tmp.size(); - const int64 vmin = Min(); - const int64 vmax = Max(); - int first = 0; - int last = size - 1; - if (tmp.front() > vmax || tmp.back() < vmin) { - solver()->Fail(); - } - // TODO(user) : We could find the first position >= vmin by dichotomy. - while (tmp[first] < vmin || !Contains(tmp[first])) { - ++first; - if (first > last || tmp[first] > vmax) { + default: { + // TODO(user): use a clean and safe SortedUniqueCopy() class + // that uses a global, static shared (and locked) storage. + // TODO(user): [optional] consider porting + // STLSortAndRemoveDuplicates from ortools/base/stl_util.h to the + // existing open_source/base/stl_util.h and using it here. + // TODO(user): We could filter out values not in the var. + std::vector &tmp = solver()->tmp_vector_; + tmp.clear(); + tmp.insert(tmp.end(), values.begin(), values.end()); + std::sort(tmp.begin(), tmp.end()); + tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end()); + const int size = tmp.size(); + const int64 vmin = Min(); + const int64 vmax = Max(); + int first = 0; + int last = size - 1; + if (tmp.front() > vmax || tmp.back() < vmin) { solver()->Fail(); } - } - while (last > first && (tmp[last] > vmax || !Contains(tmp[last]))) { - // Note that last >= first implies tmp[last] >= vmin. - --last; - } - DCHECK_GE(last, first); - SetRange(tmp[first], tmp[last]); - while (first < last) { - const int64 start = tmp[first] + 1; - const int64 end = tmp[first + 1] - 1; - if (start <= end) { - RemoveInterval(start, end); + // TODO(user) : We could find the first position >= vmin by dichotomy. + while (tmp[first] < vmin || !Contains(tmp[first])) { + ++first; + if (first > last || tmp[first] > vmax) { + solver()->Fail(); + } + } + while (last > first && (tmp[last] > vmax || !Contains(tmp[last]))) { + // Note that last >= first implies tmp[last] >= vmin. + --last; + } + DCHECK_GE(last, first); + SetRange(tmp[first], tmp[last]); + while (first < last) { + const int64 start = tmp[first] + 1; + const int64 end = tmp[first + 1] - 1; + if (start <= end) { + RemoveInterval(start, end); + } + first++; } - first++; } } - } } // ---------- BaseIntExpr --------- @@ -7456,4 +7477,4 @@ bool Solver::IsProduct(IntExpr *const expr, IntExpr **inner_expr, #undef COND_REV_ALLOC -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/graph_constraints.cc b/ortools/constraint_solver/graph_constraints.cc index 2f24758e2a..a48765dd94 100644 --- a/ortools/constraint_solver/graph_constraints.cc +++ b/ortools/constraint_solver/graph_constraints.cc @@ -46,7 +46,7 @@ namespace operations_research { namespace { class NoCycle : public Constraint { -public: + public: NoCycle(Solver *const s, const std::vector &nexts, const std::vector &active, Solver::IndexFilter1 sink_handler, bool assume_paths); @@ -71,7 +71,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kNoCycle, this); } -private: + private: int64 size() const { return nexts_.size(); } const std::vector nexts_; @@ -92,11 +92,17 @@ private: NoCycle::NoCycle(Solver *const s, const std::vector &nexts, const std::vector &active, Solver::IndexFilter1 sink_handler, bool assume_paths) - : Constraint(s), nexts_(nexts), active_(active), - iterators_(nexts.size(), nullptr), starts_(nexts.size(), -1), - ends_(nexts.size(), -1), marked_(nexts.size(), false), - all_nexts_bound_(false), outbound_supports_(nexts.size(), -1), - sink_handler_(std::move(sink_handler)), assume_paths_(assume_paths) { + : Constraint(s), + nexts_(nexts), + active_(active), + iterators_(nexts.size(), nullptr), + starts_(nexts.size(), -1), + ends_(nexts.size(), -1), + marked_(nexts.size(), false), + all_nexts_bound_(false), + outbound_supports_(nexts.size(), -1), + sink_handler_(std::move(sink_handler)), + assume_paths_(assume_paths) { support_leaves_.reserve(size()); unsupported_.reserve(size()); for (int i = 0; i < size(); ++i) { @@ -134,8 +140,7 @@ void NoCycle::InitialPropagate() { } void NoCycle::Post() { - if (size() == 0) - return; + if (size() == 0) return; for (int i = 0; i < size(); ++i) { IntVar *next = nexts_[i]; Demon *support_demon = MakeConstraintDemon1( @@ -191,10 +196,8 @@ void NoCycle::ActiveBound(int index) { } void NoCycle::NextBound(int index) { - if (active_[index]->Min() == 0) - return; - if (marked_[index]) - return; + if (active_[index]->Min() == 0) return; + if (marked_[index]) return; Solver *const s = solver(); // Subtle: marking indices to avoid overwriting chain starts and ends if // propagation for active_[index] or nexts_[index] has already been done. @@ -362,13 +365,22 @@ std::string NoCycle::DebugString() const { // ----- Circuit constraint ----- class Circuit : public Constraint { -public: + public: Circuit(Solver *const s, const std::vector &nexts, bool sub_circuit) - : Constraint(s), nexts_(nexts), size_(nexts_.size()), starts_(size_, -1), - ends_(size_, -1), lengths_(size_, 1), domains_(size_), - outbound_support_(size_, -1), inbound_support_(size_, -1), - temp_support_(size_, -1), inbound_demon_(nullptr), - outbound_demon_(nullptr), root_(-1), num_inactives_(0), + : Constraint(s), + nexts_(nexts), + size_(nexts_.size()), + starts_(size_, -1), + ends_(size_, -1), + lengths_(size_, 1), + domains_(size_), + outbound_support_(size_, -1), + inbound_support_(size_, -1), + temp_support_(size_, -1), + inbound_demon_(nullptr), + outbound_demon_(nullptr), + root_(-1), + num_inactives_(0), sub_circuit_(sub_circuit) { for (int i = 0; i < size_; ++i) { domains_[i] = nexts_[i]->MakeDomainIterator(true); @@ -435,7 +447,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kCircuit, this); } -private: + private: bool Inactive(int index) const { return nexts_[index]->Bound() && nexts_[index]->Min() == index; } @@ -452,8 +464,9 @@ private: const int new_start = starts_.Value(index); starts_.SetValue(s, new_end, new_start); ends_.SetValue(s, new_start, new_end); - lengths_.SetValue(s, new_start, lengths_.Value(new_start) + - lengths_.Value(destination)); + lengths_.SetValue( + s, new_start, + lengths_.Value(new_start) + lengths_.Value(destination)); if (sub_circuit_) { // You are creating the only path. Nexts can no longer loop upon itself. nexts_[destination]->RemoveValue(destination); @@ -496,7 +509,7 @@ private: } void CheckReachabilityFromRoot() { - if (root_.Value() == -1) { // Root is not yet defined. Nothing to deduce. + if (root_.Value() == -1) { // Root is not yet defined. Nothing to deduce. return; } @@ -516,21 +529,21 @@ private: const int candidate = insertion_queue_[processed++]; IntVar *const var = nexts_[candidate]; switch (var->Size()) { - case 1: { - TryInsertReached(candidate, var->Min()); - break; - } - case 2: { - TryInsertReached(candidate, var->Min()); - TryInsertReached(candidate, var->Max()); - break; - } - default: { - IntVarIterator *const domain = domains_[candidate]; - for (const int64 value : InitAndGetValues(domain)) { - TryInsertReached(candidate, value); + case 1: { + TryInsertReached(candidate, var->Min()); + break; + } + case 2: { + TryInsertReached(candidate, var->Min()); + TryInsertReached(candidate, var->Max()); + break; + } + default: { + IntVarIterator *const domain = domains_[candidate]; + for (const int64 value : InitAndGetValues(domain)) { + TryInsertReached(candidate, value); + } } - } } } // All non reachable nodes should point to themselves in the incomplete @@ -601,7 +614,7 @@ private: NumericalRev num_inactives_; const bool sub_circuit_; }; -} // namespace +} // namespace Constraint *Solver::MakeNoCycle(const std::vector &nexts, const std::vector &active, @@ -610,8 +623,7 @@ Constraint *Solver::MakeNoCycle(const std::vector &nexts, CHECK_EQ(nexts.size(), active.size()); if (sink_handler == nullptr) { const int64 size = nexts.size(); - sink_handler = [size](int64 index) { return index >= size; } - ; + sink_handler = [size](int64 index) { return index >= size; }; } return RevAlloc(new NoCycle(this, nexts, active, sink_handler, assume_paths)); } @@ -635,7 +647,7 @@ Constraint *Solver::MakeSubCircuit(const std::vector &nexts) { namespace { class BasePathCumul : public Constraint { -public: + public: BasePathCumul(Solver *const s, const std::vector &nexts, const std::vector &active, const std::vector &cumuls); @@ -649,7 +661,7 @@ public: void CumulRange(int index); std::string DebugString() const override; -protected: + protected: int64 size() const { return nexts_.size(); } int cumul_size() const { return cumuls_.size(); } @@ -664,8 +676,12 @@ BasePathCumul::BasePathCumul(Solver *const s, const std::vector &nexts, const std::vector &active, const std::vector &cumuls) - : Constraint(s), nexts_(nexts), active_(active), cumuls_(cumuls), - prevs_(cumuls.size(), -1), supports_(nexts.size()) { + : Constraint(s), + nexts_(nexts), + active_(active), + cumuls_(cumuls), + prevs_(cumuls.size(), -1), + supports_(nexts.size()) { CHECK_GE(cumul_size(), size()); for (int i = 0; i < size(); ++i) { supports_[i] = -1; @@ -754,7 +770,7 @@ std::string BasePathCumul::DebugString() const { // cumuls[next[i]] = cumuls[i] + transits[i] class PathCumul : public BasePathCumul { -public: + public: PathCumul(Solver *const s, const std::vector &nexts, const std::vector &active, const std::vector &cumuls, @@ -779,7 +795,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this); } -private: + private: const std::vector transits_; }; @@ -793,8 +809,7 @@ void PathCumul::Post() { } void PathCumul::NextBound(int index) { - if (active_[index]->Min() == 0) - return; + if (active_[index]->Min() == 0) return; const int64 next = nexts_[index]->Value(); IntVar *cumul = cumuls_[index]; IntVar *cumul_next = cumuls_[next]; @@ -836,8 +851,9 @@ bool PathCumul::AcceptLink(int i, int j) const { } namespace { -template class StampedVector { -public: +template +class StampedVector { + public: StampedVector() : stamp_(0) {} const std::vector &Values(Solver *solver) { CheckStamp(solver); @@ -852,7 +868,7 @@ public: stamp_ = solver->fail_stamp(); } -private: + private: void CheckStamp(Solver *solver) { if (solver->fail_stamp() > stamp_) { Clear(solver); @@ -862,19 +878,27 @@ private: std::vector values_; uint64 stamp_; }; -} // namespace +} // namespace class DelayedPathCumul : public Constraint { -public: + public: DelayedPathCumul(Solver *const solver, const std::vector &nexts, const std::vector &active, const std::vector &cumuls, const std::vector &transits) - : Constraint(solver), nexts_(nexts), active_(active), cumuls_(cumuls), - transits_(transits), cumul_transit_demons_(cumuls.size(), nullptr), - path_demon_(nullptr), touched_(), chain_starts_(cumuls.size(), -1), - chain_ends_(cumuls.size(), -1), is_chain_start_(cumuls.size(), false), - prevs_(cumuls.size(), -1), supports_(nexts.size()), + : Constraint(solver), + nexts_(nexts), + active_(active), + cumuls_(cumuls), + transits_(transits), + cumul_transit_demons_(cumuls.size(), nullptr), + path_demon_(nullptr), + touched_(), + chain_starts_(cumuls.size(), -1), + chain_ends_(cumuls.size(), -1), + is_chain_start_(cumuls.size(), false), + prevs_(cumuls.size(), -1), + supports_(nexts.size()), was_bound_(nexts.size(), false), has_cumul_demon_(cumuls.size(), false) { for (int64 i = 0; i < cumuls_.size(); ++i) { @@ -948,8 +972,7 @@ public: is_chain_start_[next] = false; } for (const int touched : touched_values) { - if (touched >= nexts_.size()) - continue; + if (touched >= nexts_.size()) continue; IntVar *const next_var = nexts_[touched]; if (!was_bound_[touched] && next_var->Bound() && active_[touched]->Min() > 0) { @@ -1034,7 +1057,7 @@ public: return out; } -private: + private: void CumulRange(int64 index) { if (index < nexts_.size()) { if (nexts_[index]->Bound()) { @@ -1110,7 +1133,7 @@ private: // cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]) class IndexEvaluator2PathCumul : public BasePathCumul { -public: + public: IndexEvaluator2PathCumul(Solver *const s, const std::vector &nexts, const std::vector &active, const std::vector &cumuls, @@ -1134,7 +1157,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this); } -private: + private: Solver::IndexEvaluator2 transits_evaluator_; }; @@ -1146,8 +1169,7 @@ IndexEvaluator2PathCumul::IndexEvaluator2PathCumul( transits_evaluator_(std::move(transit_evaluator)) {} void IndexEvaluator2PathCumul::NextBound(int index) { - if (active_[index]->Min() == 0) - return; + if (active_[index]->Min() == 0) return; const int64 next = nexts_[index]->Value(); IntVar *cumul = cumuls_[index]; IntVar *cumul_next = cumuls_[next]; @@ -1172,7 +1194,7 @@ bool IndexEvaluator2PathCumul::AcceptLink(int i, int j) const { // ----- ResulatCallback2SlackPathCumul ----- class IndexEvaluator2SlackPathCumul : public BasePathCumul { -public: + public: IndexEvaluator2SlackPathCumul(Solver *const s, const std::vector &nexts, const std::vector &active, @@ -1200,7 +1222,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this); } -private: + private: const std::vector slacks_; Solver::IndexEvaluator2 transits_evaluator_; }; @@ -1210,7 +1232,8 @@ IndexEvaluator2SlackPathCumul::IndexEvaluator2SlackPathCumul( const std::vector &active, const std::vector &cumuls, const std::vector &slacks, Solver::IndexEvaluator2 transit_evaluator) - : BasePathCumul(s, nexts, active, cumuls), slacks_(slacks), + : BasePathCumul(s, nexts, active, cumuls), + slacks_(slacks), transits_evaluator_(std::move(transit_evaluator)) {} void IndexEvaluator2SlackPathCumul::Post() { @@ -1241,8 +1264,7 @@ void IndexEvaluator2SlackPathCumul::SlackRange(int index) { } void IndexEvaluator2SlackPathCumul::NextBound(int index) { - if (active_[index]->Min() == 0) - return; + if (active_[index]->Min() == 0) return; const int64 next = nexts_[index]->Value(); IntVar *const cumul = cumuls_[index]; IntVar *const cumul_next = cumuls_[next]; @@ -1271,7 +1293,7 @@ bool IndexEvaluator2SlackPathCumul::AcceptLink(int i, int j) const { CapSub(cumul_j->Min(), cumul_i->Max()) <= CapAdd(slack->Max(), transit); } -} // namespace +} // namespace Constraint *Solver::MakePathCumul(const std::vector &nexts, const std::vector &active, @@ -1301,11 +1323,10 @@ Constraint *Solver::MakePathCumul(const std::vector &nexts, this, nexts, active, cumuls, slacks, std::move(transit_evaluator))); } -Constraint * -Solver::MakeDelayedPathCumul(const std::vector &nexts, - const std::vector &active, - const std::vector &cumuls, - const std::vector &transits) { +Constraint *Solver::MakeDelayedPathCumul( + const std::vector &nexts, const std::vector &active, + const std::vector &cumuls, + const std::vector &transits) { CHECK_EQ(nexts.size(), active.size()); CHECK_EQ(transits.size(), nexts.size()); return RevAlloc(new DelayedPathCumul(this, nexts, active, cumuls, transits)); @@ -1315,14 +1336,17 @@ Solver::MakeDelayedPathCumul(const std::vector &nexts, // next variables from sources[i] to sinks[i]. namespace { class PathConnectedConstraint : public Constraint { -public: + public: PathConnectedConstraint(Solver *solver, std::vector nexts, const std::vector &sources, std::vector sinks, std::vector status) - : Constraint(solver), sources_(sources.size(), -1), - index_to_path_(nexts.size(), -1), sinks_(std::move(sinks)), - nexts_(std::move(nexts)), status_(std::move(status)), + : Constraint(solver), + sources_(sources.size(), -1), + index_to_path_(nexts.size(), -1), + sinks_(std::move(sinks)), + nexts_(std::move(nexts)), + status_(std::move(status)), touched_(nexts_.size()) { CHECK_EQ(status_.size(), sources_.size()); CHECK_EQ(status_.size(), sinks_.size()); @@ -1371,7 +1395,7 @@ public: return output; } -private: + private: void NextBound(int index) { const int path = index_to_path_[index]; if (path >= 0) { @@ -1407,7 +1431,7 @@ private: const std::vector status_; SparseBitset touched_; }; -} // namespace +} // namespace Constraint *Solver::MakePathConnected(std::vector nexts, std::vector sources, @@ -1419,7 +1443,7 @@ Constraint *Solver::MakePathConnected(std::vector nexts, namespace { class PathTransitPrecedenceConstraint : public Constraint { -public: + public: enum PrecedenceType { ANY, LIFO, @@ -1430,11 +1454,14 @@ public: std::vector transits, const std::vector > &precedences, absl::flat_hash_map precedence_types) - : Constraint(solver), nexts_(std::move(nexts)), - transits_(std::move(transits)), predecessors_(nexts_.size()), + : Constraint(solver), + nexts_(std::move(nexts)), + transits_(std::move(transits)), + predecessors_(nexts_.size()), successors_(nexts_.size()), precedence_types_(std::move(precedence_types)), - starts_(nexts_.size(), -1), ends_(nexts_.size(), -1), + starts_(nexts_.size(), -1), + ends_(nexts_.size(), -1), transit_cumuls_(nexts_.size(), 0) { for (int i = 0; i < nexts_.size(); ++i) { starts_.SetValue(solver, i, i); @@ -1471,7 +1498,7 @@ public: } std::string DebugString() const override { std::string output = "PathPrecedence("; - std::vector elements = { JoinDebugStringPtr(nexts_, ",") }; + std::vector elements = {JoinDebugStringPtr(nexts_, ",")}; if (!transits_.empty()) { elements.push_back(JoinDebugStringPtr(transits_, ",")); } @@ -1487,15 +1514,13 @@ public: // TODO(user): Implement. } -private: + private: void NextBound(int index) { - if (!nexts_[index]->Bound()) - return; + if (!nexts_[index]->Bound()) return; const int next = nexts_[index]->Min(); const int start = starts_[index]; const int end = (next < nexts_.size()) ? ends_[next] : next; - if (end < nexts_.size()) - starts_.SetValue(solver(), end, start); + if (end < nexts_.size()) starts_.SetValue(solver(), end, start); ends_.SetValue(solver(), start, end); int current = start; PrecedenceType type = ANY; @@ -1521,8 +1546,7 @@ private: break; } } - if (!found) - solver()->Fail(); + if (!found) solver()->Fail(); pushed_.pop_back(); } if (forbidden_.find(current) != forbidden_.end()) { @@ -1537,14 +1561,14 @@ private: } if (!successors_[current].empty()) { switch (type) { - case LIFO: - pushed_.push_back(current); - break; - case FIFO: - pushed_.push_front(current); - break; - case ANY: - break; + case LIFO: + pushed_.push_back(current); + break; + case FIFO: + pushed_.push_front(current); + break; + case ANY: + break; } } for (const int predecessor : predecessors_[current]) { @@ -1593,14 +1617,12 @@ Constraint *MakePathTransitTypedPrecedenceConstraint( std::move(precedence_types))); } -} // namespace +} // namespace Constraint *Solver::MakePathPrecedenceConstraint( std::vector nexts, const std::vector > &precedences) { - return MakePathTransitPrecedenceConstraint(std::move(nexts), { - }, - precedences); + return MakePathTransitPrecedenceConstraint(std::move(nexts), {}, precedences); } Constraint *Solver::MakePathPrecedenceConstraint( @@ -1616,18 +1638,14 @@ Constraint *Solver::MakePathPrecedenceConstraint( for (int start : fifo_path_starts) { precedence_types[start] = PathTransitPrecedenceConstraint::FIFO; } - return MakePathTransitTypedPrecedenceConstraint(this, std::move(nexts), { - }, - precedences, - std::move(precedence_types)); + return MakePathTransitTypedPrecedenceConstraint( + this, std::move(nexts), {}, precedences, std::move(precedence_types)); } Constraint *Solver::MakePathTransitPrecedenceConstraint( std::vector nexts, std::vector transits, const std::vector > &precedences) { return MakePathTransitTypedPrecedenceConstraint( - this, std::move(nexts), std::move(transits), precedences, { - {} - }); + this, std::move(nexts), std::move(transits), precedences, {{}}); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/interval.cc b/ortools/constraint_solver/interval.cc index 6cea8eca29..802b59bb6f 100644 --- a/ortools/constraint_solver/interval.cc +++ b/ortools/constraint_solver/interval.cc @@ -48,17 +48,13 @@ const int64 IntervalVar::kMaxValidValue = kint64max >> 2; const int64 IntervalVar::kMinValidValue = -kMaxValidValue; namespace { -enum IntervalField { - START, - DURATION, - END -}; +enum IntervalField { START, DURATION, END }; IntervalVar *NullInterval() { return nullptr; } // ----- MirrorIntervalVar ----- class MirrorIntervalVar : public IntervalVar { -public: + public: MirrorIntervalVar(Solver *const s, IntervalVar *const t) : IntervalVar(s, "Mirror<" + t->name() + ">"), t_(t) {} ~MirrorIntervalVar() override {} @@ -138,7 +134,7 @@ public: return solver()->MakeOpposite(t_->SafeStartExpr(-unperformed_value)); } -private: + private: IntervalVar *const t_; DISALLOW_COPY_AND_ASSIGN(MirrorIntervalVar); }; @@ -160,11 +156,13 @@ private: // This class exists so that we can easily implement the // IntervalVarRelaxedMax and IntervalVarRelaxedMin classes below. class AlwaysPerformedIntervalVarWrapper : public IntervalVar { -public: + public: explicit AlwaysPerformedIntervalVarWrapper(IntervalVar *const t) : IntervalVar(t->solver(), absl::StrFormat("AlwaysPerformed<%s>", t->name())), - t_(t), start_expr_(nullptr), duration_expr_(nullptr), + t_(t), + start_expr_(nullptr), + duration_expr_(nullptr), end_expr_(nullptr) {} ~AlwaysPerformedIntervalVarWrapper() override {} @@ -266,13 +264,13 @@ public: } IntExpr *SafeEndExpr(int64 unperformed_value) override { return EndExpr(); } -protected: + protected: IntervalVar *const underlying() const { return t_; } bool MayUnderlyingBePerformed() const { return underlying()->MayBePerformed(); } -private: + private: IntervalVar *const t_; IntExpr *start_expr_; IntExpr *duration_expr_; @@ -294,7 +292,7 @@ private: // This class is very useful to implement propagators that may only modify // the start min or end min. class IntervalVarRelaxedMax : public AlwaysPerformedIntervalVarWrapper { -public: + public: explicit IntervalVarRelaxedMax(IntervalVar *const t) : AlwaysPerformedIntervalVarWrapper(t) {} ~IntervalVarRelaxedMax() override {} @@ -344,7 +342,7 @@ public: // This class is very useful to implement propagators that may only modify // the start max or end max. class IntervalVarRelaxedMin : public AlwaysPerformedIntervalVarWrapper { -public: + public: explicit IntervalVarRelaxedMin(IntervalVar *const t) : AlwaysPerformedIntervalVarWrapper(t) {} ~IntervalVarRelaxedMin() override {} @@ -382,9 +380,9 @@ public: // ----- BaseIntervalVar ----- class BaseIntervalVar : public IntervalVar { -public: + public: class Handler : public Demon { - public: + public: explicit Handler(BaseIntervalVar *const var) : var_(var) {} ~Handler() override {} void Run(Solver *const s) override { var_->Process(); } @@ -395,15 +393,15 @@ public: return absl::StrFormat("Handler(%s)", var_->DebugString()); } - private: + private: BaseIntervalVar *const var_; }; BaseIntervalVar(Solver *const s, const std::string &name) - : IntervalVar(s, name), in_process_(false), handler_(this), - cleaner_([this](Solver * s) { - CleanInProcess(); - }) {} + : IntervalVar(s, name), + in_process_(false), + handler_(this), + cleaner_([this](Solver *s) { CleanInProcess(); }) {} ~BaseIntervalVar() override {} @@ -417,17 +415,23 @@ public: bool InProcess() const { return in_process_; } -protected: + protected: bool in_process_; Handler handler_; Solver::Action cleaner_; }; class RangeVar : public IntExpr { -public: + public: RangeVar(Solver *const s, BaseIntervalVar *var, int64 mi, int64 ma) - : IntExpr(s), min_(mi), max_(ma), var_(var), postponed_min_(mi), - postponed_max_(ma), previous_min_(mi), previous_max_(ma), + : IntExpr(s), + min_(mi), + max_(ma), + var_(var), + postponed_min_(mi), + postponed_max_(ma), + previous_min_(mi), + previous_max_(ma), cast_var_(nullptr) {} ~RangeVar() override {} @@ -573,18 +577,18 @@ public: void ApplyPostponedBounds(IntervalField which) { if (min_.Value() < postponed_min_ || max_.Value() > postponed_max_) { switch (which) { - case START: - var_->SetStartRange(std::max(postponed_min_, min_.Value()), + case START: + var_->SetStartRange(std::max(postponed_min_, min_.Value()), + std::min(postponed_max_, max_.Value())); + break; + case DURATION: + var_->SetDurationRange(std::max(postponed_min_, min_.Value()), + std::min(postponed_max_, max_.Value())); + break; + case END: + var_->SetEndRange(std::max(postponed_min_, min_.Value()), std::min(postponed_max_, max_.Value())); - break; - case DURATION: - var_->SetDurationRange(std::max(postponed_min_, min_.Value()), - std::min(postponed_max_, max_.Value())); - break; - case END: - var_->SetEndRange(std::max(postponed_min_, min_.Value()), - std::min(postponed_max_, max_.Value())); - break; + break; } } } @@ -606,7 +610,7 @@ public: return out; } -private: + private: // The previous bounds are maintained lazily and non reversibly. // When going down in the search tree, the modifications are // monotonic, thus SyncPreviousBounds is a no-op because they are @@ -641,15 +645,16 @@ private: SimpleRevFIFO range_demons_; SimpleRevFIFO delayed_range_demons_; IntVar *cast_var_; -}; // class RangeVar +}; // class RangeVar // ----- PerformedVar ----- class PerformedVar : public BooleanVar { -public: + public: // Optional = true -> var = [0..1], Optional = false -> var = [1]. PerformedVar(Solver *const s, BaseIntervalVar *const var, bool optional) - : BooleanVar(s, ""), var_(var), + : BooleanVar(s, ""), + var_(var), previous_value_(optional ? kUnboundBooleanVarValue : 1), postponed_value_(optional ? kUnboundBooleanVarValue : 1) { if (!optional) { @@ -665,13 +670,13 @@ public: ~PerformedVar() override {} void SetValue(int64 v) override { - if ((v & 0xfffffffffffffffe) != 0 || // Not 0 or 1. + if ((v & 0xfffffffffffffffe) != 0 || // Not 0 or 1. (value_ != kUnboundBooleanVarValue && v != value_)) { solver()->Fail(); } if (var_->InProcess()) { if (postponed_value_ != kUnboundBooleanVarValue && - v != postponed_value_) { // Fail early. + v != postponed_value_) { // Fail early. solver()->Fail(); } else { postponed_value_ = v; @@ -713,16 +718,16 @@ public: std::string DebugString() const override { switch (value_) { - case 0: - return "false"; - case 1: - return "true"; - default: - return "undecided"; + case 0: + return "false"; + case 1: + return "true"; + default: + return "undecided"; } } -private: + private: BaseIntervalVar *const var_; int previous_value_; int postponed_value_; @@ -731,7 +736,7 @@ private: // ----- FixedDurationIntervalVar ----- class FixedDurationIntervalVar : public BaseIntervalVar { -public: + public: FixedDurationIntervalVar(Solver *const s, int64 start_min, int64 start_max, int64 duration, bool optional, const std::string &name); @@ -809,7 +814,7 @@ public: void Push() override; -private: + private: RangeVar start_; int64 duration_; PerformedVar performed_; @@ -818,12 +823,16 @@ private: FixedDurationIntervalVar::FixedDurationIntervalVar( Solver *const s, int64 start_min, int64 start_max, int64 duration, bool optional, const std::string &name) - : BaseIntervalVar(s, name), start_(s, this, start_min, start_max), - duration_(duration), performed_(s, this, optional) {} + : BaseIntervalVar(s, name), + start_(s, this, start_min, start_max), + duration_(duration), + performed_(s, this, optional) {} FixedDurationIntervalVar::FixedDurationIntervalVar(Solver *const s, const std::string &name) - : BaseIntervalVar(s, name), start_(s, this, 0, 0), duration_(0), + : BaseIntervalVar(s, name), + start_(s, this, 0, 0), + duration_(0), performed_(s, this) {} void FixedDurationIntervalVar::Process() { @@ -964,7 +973,7 @@ std::string FixedDurationIntervalVar::DebugString() const { // ----- FixedDurationPerformedIntervalVar ----- class FixedDurationPerformedIntervalVar : public BaseIntervalVar { -public: + public: FixedDurationPerformedIntervalVar(Solver *const s, int64 start_min, int64 start_max, int64 duration, const std::string &name); @@ -1028,7 +1037,7 @@ public: } IntExpr *SafeEndExpr(int64 unperformed_value) override { return EndExpr(); } -private: + private: void CheckOldPerformed() {} void Push() override; @@ -1039,7 +1048,8 @@ private: FixedDurationPerformedIntervalVar::FixedDurationPerformedIntervalVar( Solver *const s, int64 start_min, int64 start_max, int64 duration, const std::string &name) - : BaseIntervalVar(s, name), start_(s, this, start_min, start_max), + : BaseIntervalVar(s, name), + start_(s, this, start_min, start_max), duration_(duration) {} FixedDurationPerformedIntervalVar::FixedDurationPerformedIntervalVar( @@ -1155,7 +1165,7 @@ std::string FixedDurationPerformedIntervalVar::DebugString() const { // ----- StartVarPerformedIntervalVar ----- class StartVarPerformedIntervalVar : public IntervalVar { -public: + public: StartVarPerformedIntervalVar(Solver *const s, IntVar *const var, int64 duration, const std::string &name); ~StartVarPerformedIntervalVar() override {} @@ -1215,7 +1225,7 @@ public: visitor->VisitIntervalVariable(this, "", 0, NullInterval()); } -private: + private: IntVar *const start_var_; int64 duration_; }; @@ -1316,7 +1326,7 @@ std::string StartVarPerformedIntervalVar::DebugString() const { // ----- StartVarIntervalVar ----- class StartVarIntervalVar : public BaseIntervalVar { -public: + public: StartVarIntervalVar(Solver *const s, IntVar *const start, int64 duration, IntVar *const performed, const std::string &name); ~StartVarIntervalVar() override {} @@ -1395,7 +1405,7 @@ public: int64 StoredMin() const { return start_min_.Value(); } int64 StoredMax() const { return start_max_.Value(); } -private: + private: IntVar *const start_; int64 duration_; IntVar *const performed_; @@ -1407,8 +1417,11 @@ StartVarIntervalVar::StartVarIntervalVar(Solver *const s, IntVar *const start, int64 duration, IntVar *const performed, const std::string &name) - : BaseIntervalVar(s, name), start_(start), duration_(duration), - performed_(performed), start_min_(start->Min()), + : BaseIntervalVar(s, name), + start_(start), + duration_(duration), + performed_(performed), + start_min_(start->Min()), start_max_(start->Max()) {} int64 StartVarIntervalVar::StartMin() const { @@ -1545,11 +1558,13 @@ std::string StartVarIntervalVar::DebugString() const { } class LinkStartVarIntervalVar : public Constraint { -public: + public: LinkStartVarIntervalVar(Solver *const solver, StartVarIntervalVar *const interval, IntVar *const start, IntVar *const performed) - : Constraint(solver), interval_(interval), start_(start), + : Constraint(solver), + interval_(interval), + start_(start), performed_(performed) {} ~LinkStartVarIntervalVar() override {} @@ -1573,7 +1588,7 @@ public: } } -private: + private: StartVarIntervalVar *const interval_; IntVar *const start_; IntVar *const performed_; @@ -1582,7 +1597,7 @@ private: // ----- FixedInterval ----- class FixedInterval : public IntervalVar { -public: + public: FixedInterval(Solver *const s, int64 start, int64 duration, const std::string &name); ~FixedInterval() override {} @@ -1642,7 +1657,7 @@ public: } IntExpr *SafeEndExpr(int64 unperformed_value) override { return EndExpr(); } -private: + private: const int64 start_; const int64 duration_; }; @@ -1727,7 +1742,7 @@ std::string FixedInterval::DebugString() const { // ----- VariableDurationIntervalVar ----- class VariableDurationIntervalVar : public BaseIntervalVar { -public: + public: VariableDurationIntervalVar(Solver *const s, int64 start_min, int64 start_max, int64 duration_min, int64 duration_max, int64 end_min, int64 end_max, bool optional, @@ -1954,10 +1969,10 @@ public: out = "IntervalVar(start = "; } - absl::StrAppendFormat( - &out, "%s, duration = %s, end = %s, performed = %s)", - start_.DebugString(), duration_.DebugString(), end_.DebugString(), - performed_.DebugString()); + absl::StrAppendFormat(&out, + "%s, duration = %s, end = %s, performed = %s)", + start_.DebugString(), duration_.DebugString(), + end_.DebugString(), performed_.DebugString()); return out; } } @@ -1980,7 +1995,7 @@ public: return BuildSafeEndExpr(this, unperformed_value); } -private: + private: void Push() override { DCHECK(!in_process_); if (performed_.Max() == 1) { @@ -2007,10 +2022,12 @@ private: // ----- Base synced interval var ----- class FixedDurationSyncedIntervalVar : public IntervalVar { -public: + public: FixedDurationSyncedIntervalVar(IntervalVar *const t, int64 duration, int64 offset, const std::string &name) - : IntervalVar(t->solver(), name), t_(t), duration_(duration), + : IntervalVar(t->solver(), name), + t_(t), + duration_(duration), offset_(offset) {} ~FixedDurationSyncedIntervalVar() override {} int64 DurationMin() const override { return duration_; } @@ -2053,12 +2070,12 @@ public: t_->WhenPerformedBound(d); } -protected: + protected: IntervalVar *const t_; const int64 duration_; const int64 offset_; -private: + private: DISALLOW_COPY_AND_ASSIGN(FixedDurationSyncedIntervalVar); }; @@ -2066,7 +2083,7 @@ private: class FixedDurationIntervalVarStartSyncedOnStart : public FixedDurationSyncedIntervalVar { -public: + public: FixedDurationIntervalVarStartSyncedOnStart(IntervalVar *const t, int64 duration, int64 offset) : FixedDurationSyncedIntervalVar( @@ -2125,7 +2142,7 @@ public: class FixedDurationIntervalVarStartSyncedOnEnd : public FixedDurationSyncedIntervalVar { -public: + public: FixedDurationIntervalVarStartSyncedOnEnd(IntervalVar *const t, int64 duration, int64 offset) : FixedDurationSyncedIntervalVar( @@ -2180,7 +2197,7 @@ public: t_->DebugString(), duration_, offset_); } }; -} // namespace +} // namespace // ----- API ----- @@ -2369,9 +2386,9 @@ void Solver::MakeIntervalVarArray(int count, int64 start_min, int64 start_max, array->clear(); for (int i = 0; i < count; ++i) { const std::string var_name = absl::StrCat(name, i); - array->push_back( - MakeIntervalVar(start_min, start_max, duration_min, duration_max, - end_min, end_max, optional, var_name)); + array->push_back(MakeIntervalVar(start_min, start_max, duration_min, + duration_max, end_min, end_max, optional, + var_name)); } } @@ -2403,4 +2420,4 @@ IntervalVar *Solver::MakeFixedDurationEndSyncedOnEndIntervalVar( RevAlloc(new FixedDurationIntervalVarStartSyncedOnEnd( interval_var, duration, CapSub(offset, duration)))); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/local_search.cc b/ortools/constraint_solver/local_search.cc index 014290650f..bb3e17a571 100644 --- a/ortools/constraint_solver/local_search.cc +++ b/ortools/constraint_solver/local_search.cc @@ -131,7 +131,7 @@ int BaseLns::FragmentSize() const { return fragment_.size(); } namespace { class SimpleLns : public BaseLns { -public: + public: SimpleLns(const std::vector &vars, int number_of_variables) : BaseLns(vars), index_(0), number_of_variables_(number_of_variables) { CHECK_GT(number_of_variables_, 0); @@ -141,7 +141,7 @@ public: bool NextFragment() override; std::string DebugString() const override { return "SimpleLns"; } -private: + private: int index_; const int number_of_variables_; }; @@ -164,7 +164,7 @@ bool SimpleLns::NextFragment() { // Frees up to number_of_variables random variables. class RandomLns : public BaseLns { -public: + public: RandomLns(const std::vector &vars, int number_of_variables, int32 seed) : BaseLns(vars), rand_(seed), number_of_variables_(number_of_variables) { @@ -176,7 +176,7 @@ public: std::string DebugString() const override { return "RandomLns"; } -private: + private: std::mt19937 rand_; const int number_of_variables_; }; @@ -188,17 +188,15 @@ bool RandomLns::NextFragment() { } return true; } -} // namespace +} // namespace -LocalSearchOperator * -Solver::MakeRandomLnsOperator(const std::vector &vars, - int number_of_variables) { +LocalSearchOperator *Solver::MakeRandomLnsOperator( + const std::vector &vars, int number_of_variables) { return MakeRandomLnsOperator(vars, number_of_variables, CpRandomSeed()); } -LocalSearchOperator * -Solver::MakeRandomLnsOperator(const std::vector &vars, - int number_of_variables, int32 seed) { +LocalSearchOperator *Solver::MakeRandomLnsOperator( + const std::vector &vars, int number_of_variables, int32 seed) { return RevAlloc(new RandomLns(vars, number_of_variables, seed)); } @@ -209,10 +207,11 @@ Solver::MakeRandomLnsOperator(const std::vector &vars, // changed from its current value to its target value. namespace { class MoveTowardTargetLS : public IntVarLocalSearchOperator { -public: + public: MoveTowardTargetLS(const std::vector &variables, const std::vector &target_values) - : IntVarLocalSearchOperator(variables), target_(target_values), + : IntVarLocalSearchOperator(variables), + target_(target_values), // Initialize variable_index_ at the number of the of variables minus // one, so that the first to be tried (after one increment) is the one // of index 0. @@ -224,7 +223,7 @@ public: std::string DebugString() const override { return "MoveTowardTargetLS"; } -protected: + protected: // Make a neighbor assigning one variable to its target value. bool MakeOneNeighbor() override { while (num_var_since_last_start_ < Size()) { @@ -240,7 +239,7 @@ protected: return false; } -private: + private: void OnStart() override { // Do not change the value of variable_index_: this way, we keep going from // where we last modified something. This is because we expect that most @@ -267,10 +266,10 @@ private: // Number of variables checked since the last call to OnStart(). int64 num_var_since_last_start_; }; -} // namespace +} // namespace -LocalSearchOperator * -Solver::MakeMoveTowardTargetOperator(const Assignment &target) { +LocalSearchOperator *Solver::MakeMoveTowardTargetOperator( + const Assignment &target) { typedef std::vector Elements; const Elements &elements = target.IntVarContainer().elements(); // Copy target values and construct the vector of variables @@ -285,9 +284,9 @@ Solver::MakeMoveTowardTargetOperator(const Assignment &target) { return MakeMoveTowardTargetOperator(vars, values); } -LocalSearchOperator * -Solver::MakeMoveTowardTargetOperator(const std::vector &variables, - const std::vector &target_values) { +LocalSearchOperator *Solver::MakeMoveTowardTargetOperator( + const std::vector &variables, + const std::vector &target_values) { return RevAlloc(new MoveTowardTargetLS(variables, target_values)); } @@ -315,7 +314,7 @@ void ChangeValue::OnStart() { index_ = 0; } namespace { class IncrementValue : public ChangeValue { -public: + public: explicit IncrementValue(const std::vector &vars) : ChangeValue(vars) {} ~IncrementValue() override {} @@ -327,7 +326,7 @@ public: // Decrements the current value of variables. class DecrementValue : public ChangeValue { -public: + public: explicit DecrementValue(const std::vector &vars) : ChangeValue(vars) {} ~DecrementValue() override {} @@ -335,7 +334,7 @@ public: std::string DebugString() const override { return "DecrementValue"; } }; -} // namespace +} // namespace // ----- Path-based Operators ----- @@ -346,29 +345,34 @@ PathOperator::PathOperator(const std::vector &next_vars, bool accept_path_end_base, std::function start_empty_path_class) : IntVarLocalSearchOperator(next_vars, true), - number_of_nexts_(next_vars.size()), ignore_path_vars_(path_vars.empty()), + number_of_nexts_(next_vars.size()), + ignore_path_vars_(path_vars.empty()), next_base_to_increment_(number_of_base_nodes), base_nodes_(number_of_base_nodes), base_alternatives_(number_of_base_nodes), base_sibling_alternatives_(number_of_base_nodes), - end_nodes_(number_of_base_nodes), base_paths_(number_of_base_nodes), - just_started_(false), first_start_(true), + end_nodes_(number_of_base_nodes), + base_paths_(number_of_base_nodes), + just_started_(false), + first_start_(true), accept_path_end_base_(accept_path_end_base), start_empty_path_class_(std::move(start_empty_path_class)), skip_locally_optimal_paths_(skip_locally_optimal_paths), - optimal_paths_enabled_(false), alternative_index_(next_vars.size(), -1) { + optimal_paths_enabled_(false), + alternative_index_(next_vars.size(), -1) { DCHECK_GT(number_of_base_nodes, 0); if (!ignore_path_vars_) { AddVars(path_vars); } path_basis_.push_back(0); for (int i = 1; i < base_nodes_.size(); ++i) { - if (!OnSamePathAsPreviousBase(i)) - path_basis_.push_back(i); + if (!OnSamePathAsPreviousBase(i)) path_basis_.push_back(i); } if ((path_basis_.size() > 2) || - (!next_vars.empty() && !next_vars.back()->solver()->parameters() - .skip_locally_optimal_paths())) { + (!next_vars.empty() && !next_vars.back() + ->solver() + ->parameters() + .skip_locally_optimal_paths())) { skip_locally_optimal_paths_ = false; } } @@ -409,8 +413,7 @@ bool PathOperator::SkipUnchanged(int index) const { bool PathOperator::MoveChain(int64 before_chain, int64 chain_end, int64 destination) { - if (destination == before_chain || destination == chain_end) - return false; + if (destination == before_chain || destination == chain_end) return false; DCHECK(CheckChainValidity(before_chain, chain_end, destination) && !IsPathEnd(chain_end) && !IsPathEnd(destination)); const int64 destination_path = Path(destination); @@ -483,8 +486,7 @@ bool PathOperator::MakeChainInactive(int64 before_chain, int64 chain_end) { } bool PathOperator::SwapActiveAndInactive(int64 active, int64 inactive) { - if (active == inactive) - return false; + if (active == inactive) return false; const int64 prev = Prev(active); return MakeChainInactive(prev, active) && MakeActive(inactive, prev); } @@ -531,8 +533,7 @@ bool PathOperator::IncrementPosition() { base_alternatives_[i] = 0; base_sibling_alternatives_[i] = 0; base_nodes_[i] = OldNext(base_nodes_[i]); - if (accept_path_end_base_ || !IsPathEnd(base_nodes_[i])) - break; + if (accept_path_end_base_ || !IsPathEnd(base_nodes_[i])) break; } base_alternatives_[i] = 0; base_sibling_alternatives_[i] = 0; @@ -597,15 +598,14 @@ bool PathOperator::IncrementPosition() { base_nodes_[i] = path_starts_[0]; } } - if (!skip_locally_optimal_paths_) - return CheckEnds(); + if (!skip_locally_optimal_paths_) return CheckEnds(); // If the new paths have already been completely explored, we can // skip them from now on. if (path_basis_.size() > 1) { for (int j = 1; j < path_basis_.size(); ++j) { - if (!optimal_paths_[ - num_paths_ * start_to_path_[StartNode(path_basis_[j - 1])] + - start_to_path_[StartNode(path_basis_[j])]]) { + if (!optimal_paths_[num_paths_ * start_to_path_[StartNode( + path_basis_[j - 1])] + + start_to_path_[StartNode(path_basis_[j])]]) { return CheckEnds(); } } @@ -618,8 +618,7 @@ bool PathOperator::IncrementPosition() { } // If we are back to paths we just iterated on or have reached the end // of the neighborhood search space, we can stop. - if (!CheckEnds()) - return false; + if (!CheckEnds()) return false; bool stop = true; for (int i = 0; i < base_node_size; ++i) { if (StartNode(i) != current_starts[i]) { @@ -627,8 +626,7 @@ bool PathOperator::IncrementPosition() { break; } } - if (stop) - return false; + if (stop) return false; } } else { just_started_ = false; @@ -809,8 +807,7 @@ void PathOperator::InitializeAlternatives() { active_in_alternative_set_.resize(alternative_sets_.size(), -1); for (int i = 0; i < alternative_sets_.size(); ++i) { const int64 current_active = active_in_alternative_set_[i]; - if (current_active >= 0 && !IsInactive(current_active)) - continue; + if (current_active >= 0 && !IsInactive(current_active)) continue; for (int64 index : alternative_sets_[i]) { if (!IsInactive(index)) { active_in_alternative_set_[i] = index; @@ -844,8 +841,7 @@ bool PathOperator::OnSamePath(int64 node1, int64 node2) const { // overflow). bool PathOperator::CheckChainValidity(int64 before_chain, int64 chain_end, int64 exclude) const { - if (before_chain == chain_end || before_chain == exclude) - return false; + if (before_chain == chain_end || before_chain == exclude) return false; int64 current = before_chain; int chain_size = 0; while (current != chain_end) { @@ -875,20 +871,21 @@ bool PathOperator::CheckChainValidity(int64 before_chain, int64 chain_end, // 1 -> 4 -> 3 -> 2 -> 5 // 1 -> 2 -> 4 -> 3 -> 5 class TwoOpt : public PathOperator { -public: + public: TwoOpt(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) : PathOperator(vars, secondary_vars, 2, true, true, std::move(start_empty_path_class)), - last_base_(-1), last_(-1) {} + last_base_(-1), + last_(-1) {} ~TwoOpt() override {} bool MakeNeighbor() override; bool IsIncremental() const override { return true; } std::string DebugString() const override { return "TwoOpt"; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override { // Both base nodes have to be on the same path. return true; @@ -897,7 +894,7 @@ protected: return (base_index == 0) ? StartNode(0) : BaseNode(0); } -private: + private: void OnNodeInitialization() override { last_ = -1; } int64 last_base_; @@ -947,14 +944,16 @@ bool TwoOpt::MakeNeighbor() { // 3Opt (breaks 3 arcs on a path). class Relocate : public PathOperator { -public: + public: Relocate(const std::vector &vars, const std::vector &secondary_vars, const std::string &name, std::function start_empty_path_class, int64 chain_length = 1LL, bool single_path = false) : PathOperator(vars, secondary_vars, 2, true, false, std::move(start_empty_path_class)), - chain_length_(chain_length), single_path_(single_path), name_(name) { + chain_length_(chain_length), + single_path_(single_path), + name_(name) { CHECK_GT(chain_length_, 0); } Relocate(const std::vector &vars, @@ -970,14 +969,14 @@ public: std::string DebugString() const override { return name_; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override { // Both base nodes have to be on the same path when it's the single path // version. return single_path_; } -private: + private: const int64 chain_length_; const bool single_path_; const std::string name_; @@ -1010,7 +1009,7 @@ bool Relocate::MakeNeighbor() { // 1 -> 2 -> 4 -> 3 -> 5 class Exchange : public PathOperator { -public: + public: Exchange(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1025,12 +1024,10 @@ public: bool Exchange::MakeNeighbor() { const int64 prev_node0 = BaseNode(0); const int64 node0 = Next(prev_node0); - if (IsPathEnd(node0)) - return false; + if (IsPathEnd(node0)) return false; const int64 prev_node1 = BaseNode(1); const int64 node1 = Next(prev_node1); - if (IsPathEnd(node1)) - return false; + if (IsPathEnd(node1)) return false; const bool ok = MoveChain(prev_node0, node0, prev_node1); return MoveChain(Prev(node1), node1, prev_node0) || ok; } @@ -1048,7 +1045,7 @@ bool Exchange::MakeNeighbor() { // 1 -> 7 -> 5 6 -> 2 -> 3 -> 4 -> 8 class Cross : public PathOperator { -public: + public: Cross(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1063,14 +1060,11 @@ public: bool Cross::MakeNeighbor() { const int64 start0 = StartNode(0); const int64 start1 = StartNode(1); - if (start1 == start0) - return false; + if (start1 == start0) return false; const int64 node0 = BaseNode(0); - if (node0 == start0) - return false; + if (node0 == start0) return false; const int64 node1 = BaseNode(1); - if (node1 == start1) - return false; + if (node1 == start1) return false; if (!IsPathEnd(node0) && !IsPathEnd(node1)) { // If two paths are equivalent don't exchange them. if (PathClass(0) == PathClass(1) && IsPathEnd(Next(node0)) && @@ -1090,7 +1084,7 @@ bool Cross::MakeNeighbor() { // Base class of path operators which make inactive nodes active. class BaseInactiveNodeToPathOperator : public PathOperator { -public: + public: BaseInactiveNodeToPathOperator( const std::vector &vars, const std::vector &secondary_vars, int number_of_base_nodes, @@ -1102,11 +1096,11 @@ public: } ~BaseInactiveNodeToPathOperator() override {} -protected: + protected: bool MakeOneNeighbor() override; int64 GetInactiveNode() const { return inactive_node_; } -private: + private: void OnNodeInitialization() override; int inactive_node_; @@ -1144,7 +1138,7 @@ bool BaseInactiveNodeToPathOperator::MakeOneNeighbor() { // 1 -> 2 -> 3 -> 5 -> 4 class MakeActiveOperator : public BaseInactiveNodeToPathOperator { -public: + public: MakeActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1170,7 +1164,7 @@ bool MakeActiveOperator::MakeNeighbor() { // TODO(user): Naming is close to MakeActiveAndRelocate but this one is // correct; rename MakeActiveAndRelocate if it is actually used. class RelocateAndMakeActiveOperator : public BaseInactiveNodeToPathOperator { -public: + public: RelocateAndMakeActiveOperator( const std::vector &vars, const std::vector &secondary_vars, @@ -1198,7 +1192,7 @@ public: // 0 -> 3 -> 2 -> 4, 1 -> 5. class MakeActiveAndRelocate : public BaseInactiveNodeToPathOperator { -public: + public: MakeActiveAndRelocate(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1230,7 +1224,7 @@ bool MakeActiveAndRelocate::MakeNeighbor() { // 1 -> 2 -> 4 & 3 inactive class MakeInactiveOperator : public PathOperator { -public: + public: MakeInactiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1254,7 +1248,7 @@ public: // 0 -> 4, 1 -> 2 -> 5 & 3 inactive class RelocateAndMakeInactiveOperator : public PathOperator { -public: + public: RelocateAndMakeInactiveOperator( const std::vector &vars, const std::vector &secondary_vars, @@ -1289,7 +1283,7 @@ public: // 1 -> 4 with 2 and 3 inactive class MakeChainInactiveOperator : public PathOperator { -public: + public: MakeChainInactiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1304,7 +1298,7 @@ public: return "MakeChainInactiveOperator"; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override { // Start and end of chain (defined by both base nodes) must be on the same // path. @@ -1330,7 +1324,7 @@ protected: // 1 -> 2 -> 5 -> 4 & 3 inactive class SwapActiveOperator : public BaseInactiveNodeToPathOperator { -public: + public: SwapActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1362,7 +1356,7 @@ bool SwapActiveOperator::MakeNeighbor() { // 1 -> 2 -> 5 -> 4 & 3 inactive class ExtendedSwapActiveOperator : public BaseInactiveNodeToPathOperator { -public: + public: ExtendedSwapActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class) @@ -1396,7 +1390,7 @@ bool ExtendedSwapActiveOperator::MakeNeighbor() { // and cost(i,A) = cost(i,6). class TSPOpt : public PathOperator { -public: + public: TSPOpt(const std::vector &vars, const std::vector &secondary_vars, Solver::IndexEvaluator3 evaluator, int chain_length); @@ -1405,7 +1399,7 @@ public: std::string DebugString() const override { return "TSPOpt"; } -private: + private: std::vector > cost_; HamiltonianPathSolver > > hamiltonian_path_solver_; @@ -1417,7 +1411,8 @@ TSPOpt::TSPOpt(const std::vector &vars, const std::vector &secondary_vars, Solver::IndexEvaluator3 evaluator, int chain_length) : PathOperator(vars, secondary_vars, 1, true, false, nullptr), - hamiltonian_path_solver_(cost_), evaluator_(std::move(evaluator)), + hamiltonian_path_solver_(cost_), + evaluator_(std::move(evaluator)), chain_length_(chain_length) {} bool TSPOpt::MakeNeighbor() { @@ -1463,7 +1458,7 @@ bool TSPOpt::MakeNeighbor() { // as base of a meta-node. class TSPLns : public PathOperator { -public: + public: TSPLns(const std::vector &vars, const std::vector &secondary_vars, Solver::IndexEvaluator3 evaluator, int tsp_size); @@ -1472,10 +1467,10 @@ public: std::string DebugString() const override { return "TSPLns"; } -protected: + protected: bool MakeOneNeighbor() override; -private: + private: void OnNodeInitialization() override { // NOTE: Avoid any computations if there are no vars added. has_long_enough_paths_ = Size() != 0; @@ -1494,8 +1489,11 @@ TSPLns::TSPLns(const std::vector &vars, const std::vector &secondary_vars, Solver::IndexEvaluator3 evaluator, int tsp_size) : PathOperator(vars, secondary_vars, 1, true, false, nullptr), - hamiltonian_path_solver_(cost_), evaluator_(std::move(evaluator)), - tsp_size_(tsp_size), rand_(CpRandomSeed()), has_long_enough_paths_(true) { + hamiltonian_path_solver_(cost_), + evaluator_(std::move(evaluator)), + tsp_size_(tsp_size), + rand_(CpRandomSeed()), + has_long_enough_paths_(true) { CHECK_GE(tsp_size_, 0); cost_.resize(tsp_size_); for (int i = 0; i < tsp_size_; ++i) { @@ -1529,7 +1527,7 @@ bool TSPLns::MakeNeighbor() { absl::flat_hash_set breaks_set; // Always add base node to break nodes (diversification) breaks_set.insert(base_node); - CHECK(!nodes.empty()); // Should have been caught earlier. + CHECK(!nodes.empty()); // Should have been caught earlier. while (breaks_set.size() < tsp_size_) { const int64 one_break = nodes[absl::Uniform(rand_, 0, nodes.size())]; if (!gtl::ContainsKey(breaks_set, one_break)) { @@ -1604,7 +1602,7 @@ bool TSPLns::MakeNeighbor() { // Works in O(size) per variable on average (same approach as qsort) class NearestNeighbors { -public: + public: NearestNeighbors(Solver::IndexEvaluator3 evaluator, const PathOperator &path_operator, int size); virtual ~NearestNeighbors() {} @@ -1613,7 +1611,7 @@ public: virtual std::string DebugString() const { return "NearestNeighbors"; } -private: + private: void ComputeNearest(int row); std::vector > neighbors_; @@ -1627,8 +1625,10 @@ private: NearestNeighbors::NearestNeighbors(Solver::IndexEvaluator3 evaluator, const PathOperator &path_operator, int size) - : evaluator_(std::move(evaluator)), path_operator_(path_operator), - size_(size), initialized_(false) {} + : evaluator_(std::move(evaluator)), + path_operator_(path_operator), + size_(size), + initialized_(false) {} void NearestNeighbors::Initialize() { // TODO(user): recompute if node changes path ? @@ -1670,7 +1670,7 @@ void NearestNeighbors::ComputeNearest(int row) { } class LinKernighan : public PathOperator { -public: + public: LinKernighan(const std::vector &vars, const std::vector &secondary_vars, const Solver::IndexEvaluator3 &evaluator, bool topt); @@ -1679,7 +1679,7 @@ public: std::string DebugString() const override { return "LinKernighan"; } -private: + private: void OnNodeInitialization() override; static const int kNeighbors; @@ -1700,7 +1700,8 @@ LinKernighan::LinKernighan(const std::vector &vars, const std::vector &secondary_vars, const Solver::IndexEvaluator3 &evaluator, bool topt) : PathOperator(vars, secondary_vars, 1, true, false, nullptr), - evaluator_(evaluator), neighbors_(evaluator, *this, kNeighbors), + evaluator_(evaluator), + neighbors_(evaluator, *this, kNeighbors), topt_(topt) {} LinKernighan::~LinKernighan() {} @@ -1713,24 +1714,19 @@ bool LinKernighan::MakeNeighbor() { int64 path = Path(node); int64 base = node; int64 next = Next(node); - if (IsPathEnd(next)) - return false; + if (IsPathEnd(next)) return false; int64 out = -1; int64 gain = 0; marked_.insert(node); - if (topt_) { // Try a 3opt first - if (!InFromOut(node, next, &out, &gain)) - return false; + if (topt_) { // Try a 3opt first + if (!InFromOut(node, next, &out, &gain)) return false; marked_.insert(next); marked_.insert(out); const int64 node1 = out; - if (IsPathEnd(node1)) - return false; + if (IsPathEnd(node1)) return false; const int64 next1 = Next(node1); - if (IsPathEnd(next1)) - return false; - if (!InFromOut(node1, next1, &out, &gain)) - return false; + if (IsPathEnd(next1)) return false; + if (!InFromOut(node1, next1, &out, &gain)) return false; marked_.insert(next1); marked_.insert(out); if (!CheckChainValidity(out, node1, node) || !MoveChain(out, node1, node)) { @@ -1739,14 +1735,11 @@ bool LinKernighan::MakeNeighbor() { const int64 next_out = Next(out); const int64 in_cost = evaluator_(node, next_out, path); const int64 out_cost = evaluator_(out, next_out, path); - if (CapAdd(CapSub(gain, in_cost), out_cost) > 0) - return true; + if (CapAdd(CapSub(gain, in_cost), out_cost) > 0) return true; node = out; - if (IsPathEnd(node)) - return false; + if (IsPathEnd(node)) return false; next = next_out; - if (IsPathEnd(next)) - return false; + if (IsPathEnd(next)) return false; } // Try 2opts while (InFromOut(node, next, &out, &gain)) { @@ -1806,13 +1799,14 @@ bool LinKernighan::InFromOut(int64 in_i, int64 in_j, int64 *out, int64 *gain) { // As a special case, if chunk_size=0, then we break full paths. class PathLns : public PathOperator { -public: + public: PathLns(const std::vector &vars, const std::vector &secondary_vars, int number_of_chunks, int chunk_size, bool unactive_fragments) : PathOperator(vars, secondary_vars, number_of_chunks, true, true, nullptr), - number_of_chunks_(number_of_chunks), chunk_size_(chunk_size), + number_of_chunks_(number_of_chunks), + chunk_size_(chunk_size), unactive_fragments_(unactive_fragments) { CHECK_GE(chunk_size_, 0); } @@ -1822,7 +1816,7 @@ public: std::string DebugString() const override { return "PathLns"; } bool HasFragments() const override { return true; } -private: + private: inline bool ChainsAreFullPaths() const { return chunk_size_ == 0; } void DeactivateChain(int64 node); void DeactivateUnactives(); @@ -1838,8 +1832,7 @@ bool PathLns::MakeNeighbor() { // isn't at the start of a path. // TODO(user): make this more efficient. for (int i = 0; i < number_of_chunks_; ++i) { - if (BaseNode(i) != StartNode(i)) - return false; + if (BaseNode(i) != StartNode(i)) return false; } } for (int i = 0; i < number_of_chunks_; ++i) { @@ -1876,7 +1869,7 @@ void PathLns::DeactivateUnactives() { // ----- Limit the number of neighborhoods explored ----- class NeighborhoodLimit : public LocalSearchOperator { -public: + public: NeighborhoodLimit(LocalSearchOperator *const op, int64 limit) : operator_(op), limit_(limit), next_neighborhood_calls_(0) { CHECK(op != nullptr); @@ -1900,14 +1893,14 @@ public: std::string DebugString() const override { return "NeighborhoodLimit"; } -private: + private: LocalSearchOperator *const operator_; const int64 limit_; int64 next_neighborhood_calls_; }; -LocalSearchOperator * -Solver::MakeNeighborhoodLimit(LocalSearchOperator *const op, int64 limit) { +LocalSearchOperator *Solver::MakeNeighborhoodLimit( + LocalSearchOperator *const op, int64 limit) { return RevAlloc(new NeighborhoodLimit(op, limit)); } @@ -1915,7 +1908,7 @@ Solver::MakeNeighborhoodLimit(LocalSearchOperator *const op, int64 limit) { namespace { class CompoundOperator : public LocalSearchOperator { -public: + public: CompoundOperator(std::vector operators, std::function evaluator); ~CompoundOperator() override {} @@ -1926,17 +1919,18 @@ public: bool HoldsDelta() const override { return true; } std::string DebugString() const override { - return operators_.empty() ? "" : operators_[operator_indices_[index_]] - ->DebugString(); + return operators_.empty() + ? "" + : operators_[operator_indices_[index_]]->DebugString(); } const LocalSearchOperator *Self() const override { return operators_.empty() ? this : operators_[operator_indices_[index_]]->Self(); } -private: + private: class OperatorComparator { - public: + public: OperatorComparator(std::function evaluator, int active_operator) : evaluator_(std::move(evaluator)), active_operator_(active_operator) {} @@ -1946,7 +1940,7 @@ private: return lhs_value < rhs_value || (lhs_value == rhs_value && lhs < rhs); } - private: + private: int64 Evaluate(int operator_index) const { return evaluator_(active_operator_, operator_index); } @@ -1966,9 +1960,12 @@ private: CompoundOperator::CompoundOperator(std::vector operators, std::function evaluator) - : index_(0), operators_(std::move(operators)), - evaluator_(std::move(evaluator)), started_(operators_.size()), - start_assignment_(nullptr), has_fragments_(false) { + : index_(0), + operators_(std::move(operators)), + evaluator_(std::move(evaluator)), + started_(operators_.size()), + start_assignment_(nullptr), + has_fragments_(false) { operators_.erase(std::remove(operators_.begin(), operators_.end(), nullptr), operators_.end()); operator_indices_.resize(operators_.size()); @@ -2036,16 +2033,15 @@ int64 CompoundOperatorNoRestart(int size, int active_index, int64 CompoundOperatorRestart(int active_index, int operator_index) { return 0; } -} // namespace +} // namespace -LocalSearchOperator * -Solver::ConcatenateOperators(const std::vector &ops) { +LocalSearchOperator *Solver::ConcatenateOperators( + const std::vector &ops) { return ConcatenateOperators(ops, false); } -LocalSearchOperator * -Solver::ConcatenateOperators(const std::vector &ops, - bool restart) { +LocalSearchOperator *Solver::ConcatenateOperators( + const std::vector &ops, bool restart) { if (restart) { std::function eval = CompoundOperatorRestart; return ConcatenateOperators(ops, eval); @@ -2057,15 +2053,15 @@ Solver::ConcatenateOperators(const std::vector &ops, } } -LocalSearchOperator * -Solver::ConcatenateOperators(const std::vector &ops, - std::function evaluator) { +LocalSearchOperator *Solver::ConcatenateOperators( + const std::vector &ops, + std::function evaluator) { return RevAlloc(new CompoundOperator(ops, std::move(evaluator))); } namespace { class RandomCompoundOperator : public LocalSearchOperator { -public: + public: explicit RandomCompoundOperator(std::vector operators); RandomCompoundOperator(std::vector operators, int32 seed); @@ -2078,7 +2074,7 @@ public: std::string DebugString() const override { return "RandomCompoundOperator"; } // TODO(user): define Self method. -private: + private: std::mt19937 rand_; const std::vector operators_; bool has_fragments_; @@ -2128,7 +2124,7 @@ bool RandomCompoundOperator::MakeNextNeighbor(Assignment *delta, } return false; } -} // namespace +} // namespace LocalSearchOperator *Solver::RandomConcatenateOperators( const std::vector &ops) { @@ -2142,7 +2138,7 @@ LocalSearchOperator *Solver::RandomConcatenateOperators( namespace { class StagnationLimitingCompoundOperator : public LocalSearchOperator { -public: + public: explicit StagnationLimitingCompoundOperator( std::vector operators); ~StagnationLimitingCompoundOperator() override {} @@ -2158,7 +2154,7 @@ public: return operators_.empty() ? this : operators_[index_]->Self(); } -private: + private: bool StopCurrentOperator() { return false; } void IncrementOperatorIndex(); int64 index_; @@ -2170,8 +2166,11 @@ private: StagnationLimitingCompoundOperator::StagnationLimitingCompoundOperator( std::vector operators) - : index_(0), operators_(std::move(operators)), started_(operators_.size()), - start_assignment_(nullptr), has_fragments_(false) { + : index_(0), + operators_(std::move(operators)), + started_(operators_.size()), + start_assignment_(nullptr), + has_fragments_(false) { operators_.erase(std::remove(operators_.begin(), operators_.end(), nullptr), operators_.end()); for (LocalSearchOperator *const op : operators_) { @@ -2203,11 +2202,9 @@ void StagnationLimitingCompoundOperator::Start(const Assignment *assignment) { } } -bool -StagnationLimitingCompoundOperator::MakeNextNeighbor(Assignment *delta, - Assignment *deltadelta) { - if (operators_.empty()) - return false; +bool StagnationLimitingCompoundOperator::MakeNextNeighbor( + Assignment *delta, Assignment *deltadelta) { + if (operators_.empty()) return false; const int last_index = index_; do { if (!started_[index_]) { @@ -2225,7 +2222,7 @@ StagnationLimitingCompoundOperator::MakeNextNeighbor(Assignment *delta, } while (index_ != last_index); return false; } -} // namespace +} // namespace LocalSearchOperator *Solver::StagnationLimitedConcatenateOperators( const std::vector &ops) { @@ -2235,22 +2232,22 @@ LocalSearchOperator *Solver::StagnationLimitedConcatenateOperators( // ----- Operator factory ----- template -LocalSearchOperator * -MakeLocalSearchOperator(Solver *solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class) { +LocalSearchOperator *MakeLocalSearchOperator( + Solver *solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class) { return solver->RevAlloc( new T(vars, secondary_vars, std::move(start_empty_path_class))); } -#define MAKE_LOCAL_SEARCH_OPERATOR(OperatorClass) \ - template <> \ - LocalSearchOperator *MakeLocalSearchOperator( \ - Solver * solver, const std::vector & vars, \ - const std::vector & secondary_vars, \ - std::function start_empty_path_class) { \ - return solver->RevAlloc(new OperatorClass( \ - vars, secondary_vars, std::move(start_empty_path_class))); \ +#define MAKE_LOCAL_SEARCH_OPERATOR(OperatorClass) \ + template <> \ + LocalSearchOperator *MakeLocalSearchOperator( \ + Solver * solver, const std::vector &vars, \ + const std::vector &secondary_vars, \ + std::function start_empty_path_class) { \ + return solver->RevAlloc(new OperatorClass( \ + vars, secondary_vars, std::move(start_empty_path_class))); \ } MAKE_LOCAL_SEARCH_OPERATOR(TwoOpt) @@ -2273,150 +2270,149 @@ LocalSearchOperator *Solver::MakeOperator(const std::vector &vars, return MakeOperator(vars, std::vector(), op); } -LocalSearchOperator * -Solver::MakeOperator(const std::vector &vars, - const std::vector &secondary_vars, - Solver::LocalSearchOperators op) { +LocalSearchOperator *Solver::MakeOperator( + const std::vector &vars, + const std::vector &secondary_vars, + Solver::LocalSearchOperators op) { LocalSearchOperator *result = nullptr; switch (op) { - case Solver::TWOOPT: { - result = RevAlloc(new TwoOpt(vars, secondary_vars, nullptr)); - break; - } - case Solver::OROPT: { - std::vector operators; - for (int i = 1; i < 4; ++i) { - operators.push_back(RevAlloc( - new Relocate(vars, secondary_vars, absl::StrCat("OrOpt<", i, ">"), - nullptr, i, true))); + case Solver::TWOOPT: { + result = RevAlloc(new TwoOpt(vars, secondary_vars, nullptr)); + break; } - result = ConcatenateOperators(operators); - break; - } - case Solver::RELOCATE: { - result = - MakeLocalSearchOperator(this, vars, secondary_vars, nullptr); - break; - } - case Solver::EXCHANGE: { - result = - MakeLocalSearchOperator(this, vars, secondary_vars, nullptr); - break; - } - case Solver::CROSS: { - result = - MakeLocalSearchOperator(this, vars, secondary_vars, nullptr); - break; - } - case Solver::MAKEACTIVE: { - result = MakeLocalSearchOperator( - this, vars, secondary_vars, nullptr); - break; - } - case Solver::MAKEINACTIVE: { - result = MakeLocalSearchOperator( - this, vars, secondary_vars, nullptr); - break; - } - case Solver::MAKECHAININACTIVE: { - result = MakeLocalSearchOperator( - this, vars, secondary_vars, nullptr); - break; - } - case Solver::SWAPACTIVE: { - result = MakeLocalSearchOperator( - this, vars, secondary_vars, nullptr); - break; - } - case Solver::EXTENDEDSWAPACTIVE: { - result = MakeLocalSearchOperator( - this, vars, secondary_vars, nullptr); - break; - } - case Solver::PATHLNS: { - result = RevAlloc(new PathLns(vars, secondary_vars, 2, 3, false)); - break; - } - case Solver::FULLPATHLNS: { - result = - RevAlloc(new PathLns(vars, secondary_vars, /*number_of_chunks=*/ 1, - /*chunk_size=*/ 0, /*unactive_fragments=*/ true)); - break; - } - case Solver::UNACTIVELNS: { - result = RevAlloc(new PathLns(vars, secondary_vars, 1, 6, true)); - break; - } - case Solver::INCREMENT: { - if (secondary_vars.empty()) { - result = RevAlloc(new IncrementValue(vars)); - } else { - LOG(FATAL) << "Operator " << op - << " does not support secondary variables"; + case Solver::OROPT: { + std::vector operators; + for (int i = 1; i < 4; ++i) { + operators.push_back(RevAlloc( + new Relocate(vars, secondary_vars, absl::StrCat("OrOpt<", i, ">"), + nullptr, i, true))); + } + result = ConcatenateOperators(operators); + break; } - break; - } - case Solver::DECREMENT: { - if (secondary_vars.empty()) { - result = RevAlloc(new DecrementValue(vars)); - } else { - LOG(FATAL) << "Operator " << op - << " does not support secondary variables"; + case Solver::RELOCATE: { + result = MakeLocalSearchOperator(this, vars, secondary_vars, + nullptr); + break; } - break; - } - case Solver::SIMPLELNS: { - if (secondary_vars.empty()) { - result = RevAlloc(new SimpleLns(vars, 1)); - } else { - LOG(FATAL) << "Operator " << op - << " does not support secondary variables"; + case Solver::EXCHANGE: { + result = MakeLocalSearchOperator(this, vars, secondary_vars, + nullptr); + break; } - break; - } - default: - LOG(FATAL) << "Unknown operator " << op; + case Solver::CROSS: { + result = + MakeLocalSearchOperator(this, vars, secondary_vars, nullptr); + break; + } + case Solver::MAKEACTIVE: { + result = MakeLocalSearchOperator( + this, vars, secondary_vars, nullptr); + break; + } + case Solver::MAKEINACTIVE: { + result = MakeLocalSearchOperator( + this, vars, secondary_vars, nullptr); + break; + } + case Solver::MAKECHAININACTIVE: { + result = MakeLocalSearchOperator( + this, vars, secondary_vars, nullptr); + break; + } + case Solver::SWAPACTIVE: { + result = MakeLocalSearchOperator( + this, vars, secondary_vars, nullptr); + break; + } + case Solver::EXTENDEDSWAPACTIVE: { + result = MakeLocalSearchOperator( + this, vars, secondary_vars, nullptr); + break; + } + case Solver::PATHLNS: { + result = RevAlloc(new PathLns(vars, secondary_vars, 2, 3, false)); + break; + } + case Solver::FULLPATHLNS: { + result = + RevAlloc(new PathLns(vars, secondary_vars, /*number_of_chunks=*/1, + /*chunk_size=*/0, /*unactive_fragments=*/true)); + break; + } + case Solver::UNACTIVELNS: { + result = RevAlloc(new PathLns(vars, secondary_vars, 1, 6, true)); + break; + } + case Solver::INCREMENT: { + if (secondary_vars.empty()) { + result = RevAlloc(new IncrementValue(vars)); + } else { + LOG(FATAL) << "Operator " << op + << " does not support secondary variables"; + } + break; + } + case Solver::DECREMENT: { + if (secondary_vars.empty()) { + result = RevAlloc(new DecrementValue(vars)); + } else { + LOG(FATAL) << "Operator " << op + << " does not support secondary variables"; + } + break; + } + case Solver::SIMPLELNS: { + if (secondary_vars.empty()) { + result = RevAlloc(new SimpleLns(vars, 1)); + } else { + LOG(FATAL) << "Operator " << op + << " does not support secondary variables"; + } + break; + } + default: + LOG(FATAL) << "Unknown operator " << op; } return result; } -LocalSearchOperator * -Solver::MakeOperator(const std::vector &vars, - Solver::IndexEvaluator3 evaluator, - Solver::EvaluatorLocalSearchOperators op) { +LocalSearchOperator *Solver::MakeOperator( + const std::vector &vars, Solver::IndexEvaluator3 evaluator, + Solver::EvaluatorLocalSearchOperators op) { return MakeOperator(vars, std::vector(), std::move(evaluator), op); } -LocalSearchOperator * -Solver::MakeOperator(const std::vector &vars, - const std::vector &secondary_vars, - Solver::IndexEvaluator3 evaluator, - Solver::EvaluatorLocalSearchOperators op) { +LocalSearchOperator *Solver::MakeOperator( + const std::vector &vars, + const std::vector &secondary_vars, + Solver::IndexEvaluator3 evaluator, + Solver::EvaluatorLocalSearchOperators op) { LocalSearchOperator *result = nullptr; switch (op) { - case Solver::LK: { - std::vector operators; - operators.push_back(RevAlloc( - new LinKernighan(vars, secondary_vars, evaluator, /*topt=*/ false))); - operators.push_back(RevAlloc( - new LinKernighan(vars, secondary_vars, evaluator, /*topt=*/ true))); - result = ConcatenateOperators(operators); - break; - } - case Solver::TSPOPT: { - result = - RevAlloc(new TSPOpt(vars, secondary_vars, evaluator, - absl::GetFlag(FLAGS_cp_local_search_tsp_opt_size))); - break; - } - case Solver::TSPLNS: { - result = - RevAlloc(new TSPLns(vars, secondary_vars, evaluator, - absl::GetFlag(FLAGS_cp_local_search_tsp_lns_size))); - break; - } - default: - LOG(FATAL) << "Unknown operator " << op; + case Solver::LK: { + std::vector operators; + operators.push_back(RevAlloc( + new LinKernighan(vars, secondary_vars, evaluator, /*topt=*/false))); + operators.push_back(RevAlloc( + new LinKernighan(vars, secondary_vars, evaluator, /*topt=*/true))); + result = ConcatenateOperators(operators); + break; + } + case Solver::TSPOPT: { + result = RevAlloc( + new TSPOpt(vars, secondary_vars, evaluator, + absl::GetFlag(FLAGS_cp_local_search_tsp_opt_size))); + break; + } + case Solver::TSPLNS: { + result = RevAlloc( + new TSPLns(vars, secondary_vars, evaluator, + absl::GetFlag(FLAGS_cp_local_search_tsp_lns_size))); + break; + } + default: + LOG(FATAL) << "Unknown operator " << op; } return result; } @@ -2425,7 +2421,7 @@ namespace { // Classes for Local Search Operation used in Local Search filters. class SumOperation { -public: + public: SumOperation() : value_(0) {} void Init() { value_ = 0; } void Update(int64 update) { value_ = CapAdd(value_, update); } @@ -2433,12 +2429,12 @@ public: int64 value() const { return value_; } void set_value(int64 new_value) { value_ = new_value; } -private: + private: int64 value_; }; class ProductOperation { -public: + public: ProductOperation() : value_(1) {} void Init() { value_ = 1; } void Update(int64 update) { value_ *= update; } @@ -2450,12 +2446,12 @@ public: int64 value() const { return value_; } void set_value(int64 new_value) { value_ = new_value; } -private: + private: int64 value_; }; class MinOperation { -public: + public: void Init() { values_set_.clear(); } void Update(int64 update) { values_set_.insert(update); } void Remove(int64 remove) { values_set_.erase(remove); } @@ -2464,12 +2460,12 @@ public: } void set_value(int64 new_value) {} -private: + private: std::set values_set_; }; class MaxOperation { -public: + public: void Init() { values_set_.clear(); } void Update(int64 update) { values_set_.insert(update); } void Remove(int64 remove) { values_set_.erase(remove); } @@ -2478,22 +2474,22 @@ public: } void set_value(int64 new_value) {} -private: + private: std::set values_set_; }; // Always accepts deltas, cost 0. class AcceptFilter : public LocalSearchFilter { -public: + public: std::string DebugString() const override { return "AcceptFilter"; } bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 obj_min, int64 obj_max) override { return true; } - void Synchronize(const Assignment *assignment, const Assignment *delta) - override {} + void Synchronize(const Assignment *assignment, + const Assignment *delta) override {} }; -} // namespace +} // namespace LocalSearchFilter *Solver::MakeAcceptFilter() { return RevAlloc(new AcceptFilter()); @@ -2502,16 +2498,16 @@ LocalSearchFilter *Solver::MakeAcceptFilter() { namespace { // Never accepts deltas, cost 0. class RejectFilter : public LocalSearchFilter { -public: + public: std::string DebugString() const override { return "RejectFilter"; } bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 obj_min, int64 obj_max) override { return false; } - void Synchronize(const Assignment *assignment, const Assignment *delta) - override {} + void Synchronize(const Assignment *assignment, + const Assignment *delta) override {} }; -} // namespace +} // namespace LocalSearchFilter *Solver::MakeRejectFilter() { return RevAlloc(new RejectFilter()); @@ -2519,48 +2515,38 @@ LocalSearchFilter *Solver::MakeRejectFilter() { PathState::PathState(int num_nodes, std::vector path_start, std::vector path_end) - : num_nodes_(num_nodes), num_paths_(path_start.size()), - num_nodes_threshold_(std::max(16, 4 * num_nodes_)) // Arbitrary value. - { + : num_nodes_(num_nodes), + num_paths_(path_start.size()), + num_nodes_threshold_(std::max(16, 4 * num_nodes_)) // Arbitrary value. +{ DCHECK_EQ(path_start.size(), num_paths_); DCHECK_EQ(path_end.size(), num_paths_); for (int p = 0; p < num_paths_; ++p) { - path_start_end_.push_back({ - path_start[p], path_end[p] - }); + path_start_end_.push_back({path_start[p], path_end[p]}); } // Initial state is all unperformed: paths go from start to end directly. committed_index_.assign(num_nodes_, -1); - committed_nodes_.assign(2 * num_paths_, { - -1, -1 - }); - chains_.assign(num_paths_ + 1, { - -1, -1 - }); // Reserve 1 more for sentinel. - paths_.assign(num_paths_, { - -1, -1 - }); + committed_nodes_.assign(2 * num_paths_, {-1, -1}); + chains_.assign(num_paths_ + 1, {-1, -1}); // Reserve 1 more for sentinel. + paths_.assign(num_paths_, {-1, -1}); for (int path = 0; path < num_paths_; ++path) { const int index = 2 * path; const PathStartEnd start_end = path_start_end_[path]; committed_index_[start_end.start] = index; committed_index_[start_end.end] = index + 1; - committed_nodes_[index] = { start_end.start, path }; - committed_nodes_[index + 1] = { start_end.end, path }; + committed_nodes_[index] = {start_end.start, path}; + committed_nodes_[index + 1] = {start_end.end, path}; - chains_[path] = { index, index + 2 }; - paths_[path] = { path, path + 1 }; + chains_[path] = {index, index + 2}; + paths_[path] = {path, path + 1}; } - chains_[num_paths_] = { 0, 0 }; // Sentinel. + chains_[num_paths_] = {0, 0}; // Sentinel. // Nodes that are not starts or ends are loops. for (int node = 0; node < num_nodes_; ++node) { - if (committed_index_[node] != -1) - continue; // node is start or end. + if (committed_index_[node] != -1) continue; // node is start or end. committed_index_[node] = committed_nodes_.size(); - committed_nodes_.push_back({ - node, -1 - }); + committed_nodes_.push_back({node, -1}); } path_has_changed_.assign(num_paths_, false); } @@ -2580,12 +2566,11 @@ PathState::NodeRange PathState::Nodes(int path) const { } void PathState::CutChains() { - if (is_invalid_) - return; + if (is_invalid_) return; // Filter out unchanged arcs from changed_arcs_, // translate changed arcs to changed arc indices. // Fill changed_paths_ while we hold node_path. - DCHECK_EQ(chains_.size(), num_paths_ + 1); // One per path + sentinel. + DCHECK_EQ(chains_.size(), num_paths_ + 1); // One per path + sentinel. DCHECK(changed_paths_.empty()); tail_head_indices_.clear(); int num_changed_arcs = 0; @@ -2596,17 +2581,15 @@ void PathState::CutChains() { const int next_index = committed_index_[next]; const int node_path = committed_nodes_[node_index].path; if (next != node && - (next_index != node_index + 1 || node_path == -1)) { // New arc. - tail_head_indices_.push_back({ - node_index, next_index - }); - changed_arcs_[num_changed_arcs++] = { node, next }; + (next_index != node_index + 1 || node_path == -1)) { // New arc. + tail_head_indices_.push_back({node_index, next_index}); + changed_arcs_[num_changed_arcs++] = {node, next}; if (node_path != -1 && !path_has_changed_[node_path]) { path_has_changed_[node_path] = true; changed_paths_.push_back(node_path); } - } else if (node == next && node_path != -1) { // New loop. - changed_arcs_[num_changed_arcs++] = { node, node }; + } else if (node == next && node_path != -1) { // New loop. + changed_arcs_[num_changed_arcs++] = {node, node}; } } changed_arcs_.resize(num_changed_arcs); @@ -2628,9 +2611,8 @@ void PathState::CutChains() { // Add a fake end->start arc for each path. for (const int path : changed_paths_) { const PathStartEnd start_end = path_start_end_[path]; - tail_head_indices_.push_back({ - committed_index_[start_end.end], committed_index_[start_end.start] - }); + tail_head_indices_.push_back( + {committed_index_[start_end.end], committed_index_[start_end.start]}); } // Generate pairs (tail_index, arc) and (head_index, arc) for all arcs, @@ -2639,8 +2621,8 @@ void PathState::CutChains() { arcs_by_tail_index_.resize(num_arc_indices); arcs_by_head_index_.resize(num_arc_indices); for (int i = 0; i < num_arc_indices; ++i) { - arcs_by_tail_index_[i] = { tail_head_indices_[i].tail_index, i }; - arcs_by_head_index_[i] = { tail_head_indices_[i].head_index, i }; + arcs_by_tail_index_[i] = {tail_head_indices_[i].tail_index, i}; + arcs_by_head_index_[i] = {tail_head_indices_[i].head_index, i}; } std::sort(arcs_by_tail_index_.begin(), arcs_by_tail_index_.end()); std::sort(arcs_by_head_index_.begin(), arcs_by_head_index_.end()); @@ -2665,9 +2647,9 @@ void PathState::CutChains() { } while (arc != fake_arc); const int path = changed_paths_[fake_arc - first_fake_arc]; const int new_path_end = chains_.size(); - paths_[path] = { new_path_begin, new_path_end }; + paths_[path] = {new_path_begin, new_path_end}; } - chains_.emplace_back(0, 0); // Sentinel. + chains_.emplace_back(0, 0); // Sentinel. } void PathState::Commit() { @@ -2681,9 +2663,9 @@ void PathState::Commit() { void PathState::Revert() { is_invalid_ = false; - chains_.resize(num_paths_ + 1); // One per path + sentinel. + chains_.resize(num_paths_ + 1); // One per path + sentinel. for (const int path : changed_paths_) { - paths_[path] = { path, path + 1 }; + paths_[path] = {path, path + 1}; path_has_changed_[path] = false; } changed_paths_.clear(); @@ -2715,7 +2697,7 @@ void PathState::IncrementalCommit() { const int chain_begin = committed_nodes_.size(); CopyNewPathAtEndOfNodes(path); const int chain_end = committed_nodes_.size(); - chains_[path] = { chain_begin, chain_end }; + chains_[path] = {chain_begin, chain_end}; } // Re-index all copied nodes. const int new_nodes_end = committed_nodes_.size(); @@ -2727,8 +2709,7 @@ void PathState::IncrementalCommit() { for (const auto &arc : ChangedArcs()) { int node, next; std::tie(node, next) = arc; - if (node != next) - continue; + if (node != next) continue; const int index = committed_index_[node]; committed_nodes_[index].path = -1; } @@ -2744,7 +2725,7 @@ void PathState::FullCommit() { const int new_path_begin = committed_nodes_.size() - old_num_nodes; CopyNewPathAtEndOfNodes(path); const int new_path_end = committed_nodes_.size() - old_num_nodes; - chains_[path] = { new_path_begin, new_path_end }; + chains_[path] = {new_path_begin, new_path_end}; } committed_nodes_.erase(committed_nodes_.begin(), committed_nodes_.begin() + old_num_nodes); @@ -2757,12 +2738,9 @@ void PathState::FullCommit() { committed_index_[committed_node.node] = index++; } for (int node = 0; node < num_nodes_; ++node) { - if (committed_index_[node] != kUnindexed) - continue; + if (committed_index_[node] != kUnindexed) continue; committed_index_[node] = index++; - committed_nodes_.push_back({ - node, -1 - }); + committed_nodes_.push_back({node, -1}); } // Committed part of the state is set up, erase incremental changes. Revert(); @@ -2771,7 +2749,7 @@ void PathState::FullCommit() { namespace { class PathStateFilter : public LocalSearchFilter { -public: + public: std::string DebugString() const override { return "PathStateFilter"; } PathStateFilter(std::unique_ptr path_state, const std::vector &nexts); @@ -2780,14 +2758,13 @@ public: int64 objective_min, int64 objective_max) override { return true; } - void Synchronize(const Assignment *delta, const Assignment *deltadelta) - override {} - ; + void Synchronize(const Assignment *delta, + const Assignment *deltadelta) override{}; void Commit(const Assignment *assignment, const Assignment *delta) override; void Revert() override; void Reset() override; -private: + private: const std::unique_ptr path_state_; // Map IntVar* index to node, offset by the min index in nexts. std::vector variable_index_to_node_; @@ -2821,14 +2798,11 @@ void PathStateFilter::Relax(const Assignment *delta, const Assignment *deltadelta) { path_state_->Revert(); for (const IntVarElement &var_value : delta->IntVarContainer().elements()) { - if (var_value.Var() == nullptr) - continue; + if (var_value.Var() == nullptr) continue; const int index = var_value.Var()->index() - index_offset_; - if (index < 0 || variable_index_to_node_.size() <= index) - continue; + if (index < 0 || variable_index_to_node_.size() <= index) continue; const int node = variable_index_to_node_[index]; - if (node == -1) - continue; + if (node == -1) continue; if (var_value.Bound()) { path_state_->ChangeNext(node, var_value.Value()); } else { @@ -2855,8 +2829,7 @@ void PathStateFilter::Reset() { node_is_assigned_[end] = true; } for (int node = 0; node < num_nodes; ++node) { - if (!node_is_assigned_[node]) - path_state_->ChangeNext(node, node); + if (!node_is_assigned_[node]) path_state_->ChangeNext(node, node); } path_state_->CutChains(); path_state_->Commit(); @@ -2878,7 +2851,7 @@ void PathStateFilter::Commit(const Assignment *assignment, void PathStateFilter::Revert() { path_state_->Revert(); } -} // namespace +} // namespace LocalSearchFilter *MakePathStateFilter(Solver *solver, std::unique_ptr path_state, @@ -2891,13 +2864,15 @@ UnaryDimensionChecker::UnaryDimensionChecker( const PathState *path_state, std::vector path_capacity, std::vector path_class, std::vector > demand, std::vector node_capacity) - : path_state_(path_state), path_capacity_(std::move(path_capacity)), - path_class_(std::move(path_class)), demand_(std::move(demand)), + : path_state_(path_state), + path_capacity_(std::move(path_capacity)), + path_class_(std::move(path_class)), + demand_(std::move(demand)), node_capacity_(std::move(node_capacity)), index_(path_state_->NumNodes(), 0), maximum_partial_demand_layer_size_( - std::max(16, 4 * path_state_->NumNodes())) // 16 and 4 are arbitrary. - { + std::max(16, 4 * path_state_->NumNodes())) // 16 and 4 are arbitrary. +{ const int num_nodes = path_state_->NumNodes(); const int num_paths = path_state_->NumPaths(); DCHECK_EQ(num_paths, path_capacity_.size()); @@ -2909,8 +2884,7 @@ UnaryDimensionChecker::UnaryDimensionChecker( } bool UnaryDimensionChecker::Check() const { - if (path_state_->IsInvalid()) - return true; + if (path_state_->IsInvalid()) return true; for (const int path : path_state_->ChangedPaths()) { const Interval path_capacity = path_capacity_[path]; if (path_capacity.min == kint64min && path_capacity.max == kint64max) { @@ -2919,10 +2893,9 @@ bool UnaryDimensionChecker::Check() const { const int path_class = path_class_[path]; // Loop invariant: capacity_used is nonempty and within path_capacity. Interval capacity_used = node_capacity_[path_state_->Start(path)]; - capacity_used = { std::max(capacity_used.min, path_capacity.min), - std::min(capacity_used.max, path_capacity.max) }; - if (capacity_used.min > capacity_used.max) - return false; + capacity_used = {std::max(capacity_used.min, path_capacity.min), + std::min(capacity_used.max, path_capacity.max)}; + if (capacity_used.min > capacity_used.max) return false; for (const auto chain : path_state_->Chains(path)) { const int first_node = chain.First(); @@ -2947,34 +2920,30 @@ bool UnaryDimensionChecker::Check() const { const Interval min_max = GetMinMaxPartialDemandSum(first_index, last_index); const Interval prev_sum = partial_demand_sums_rmq_[0][first_index - 1]; - const Interval min_max_delta = { CapSub(min_max.min, prev_sum.min), - CapSub(min_max.max, prev_sum.max) }; + const Interval min_max_delta = {CapSub(min_max.min, prev_sum.min), + CapSub(min_max.max, prev_sum.max)}; capacity_used = { - std::max(capacity_used.min, - CapSub(path_capacity.min, min_max_delta.min)), - std::min(capacity_used.max, - CapSub(path_capacity.max, min_max_delta.max)) - }; - if (capacity_used.min > capacity_used.max) - return false; + std::max(capacity_used.min, + CapSub(path_capacity.min, min_max_delta.min)), + std::min(capacity_used.max, + CapSub(path_capacity.max, min_max_delta.max))}; + if (capacity_used.min > capacity_used.max) return false; // Move to last node's state, which is valid since we did not return. const Interval last_sum = partial_demand_sums_rmq_[0][last_index]; capacity_used = { - CapSub(CapAdd(capacity_used.min, last_sum.min), prev_sum.min), - CapSub(CapAdd(capacity_used.max, last_sum.max), prev_sum.max) - }; + CapSub(CapAdd(capacity_used.min, last_sum.min), prev_sum.min), + CapSub(CapAdd(capacity_used.max, last_sum.max), prev_sum.max)}; } else { for (const int node : chain) { const Interval node_capacity = node_capacity_[node]; - capacity_used = { std::max(capacity_used.min, node_capacity.min), - std::min(capacity_used.max, node_capacity.max) }; - if (capacity_used.min > capacity_used.max) - return false; + capacity_used = {std::max(capacity_used.min, node_capacity.min), + std::min(capacity_used.max, node_capacity.max)}; + if (capacity_used.min > capacity_used.max) return false; const Interval demand = demand_[path_class][node]; - capacity_used = { CapAdd(capacity_used.min, demand.min), - CapAdd(capacity_used.max, demand.max) }; - capacity_used = { std::max(capacity_used.min, path_capacity.min), - std::min(capacity_used.max, path_capacity.max) }; + capacity_used = {CapAdd(capacity_used.min, demand.min), + CapAdd(capacity_used.max, demand.max)}; + capacity_used = {std::max(capacity_used.min, path_capacity.min), + std::min(capacity_used.max, path_capacity.max)}; } } } @@ -3012,8 +2981,7 @@ void UnaryDimensionChecker::IncrementalCommit() { void UnaryDimensionChecker::FullCommit() { // Clear all structures. previous_nontrivial_index_.clear(); - for (auto &sums : partial_demand_sums_rmq_) - sums.clear(); + for (auto &sums : partial_demand_sums_rmq_) sums.clear(); // Append all paths. const int num_paths = path_state_->NumPaths(); for (int path = 0; path < num_paths; ++path) { @@ -3025,7 +2993,7 @@ void UnaryDimensionChecker::FullCommit() { void UnaryDimensionChecker::AppendPathDemandsToSums(int path) { const int path_class = path_class_[path]; - Interval demand_sum = { 0, 0 }; + Interval demand_sum = {0, 0}; int previous_nontrivial_index = -1; int index = partial_demand_sums_rmq_[0].size(); // Value of partial_demand_sums_rmq_ at node_index-1 must be the sum @@ -3037,8 +3005,8 @@ void UnaryDimensionChecker::AppendPathDemandsToSums(int path) { for (const int node : path_state_->Nodes(path)) { index_[node] = index; const Interval demand = demand_[path_class][node]; - demand_sum = { CapAdd(demand_sum.min, demand.min), - CapAdd(demand_sum.max, demand.max) }; + demand_sum = {CapAdd(demand_sum.min, demand.min), + CapAdd(demand_sum.max, demand.max)}; partial_demand_sums_rmq_[0].push_back(demand_sum); const Interval node_capacity = node_capacity_[node]; @@ -3062,8 +3030,8 @@ void UnaryDimensionChecker::UpdateRMQStructure(int begin_index, int end_index) { for (int i = begin_index; i < end_index - window_size; ++i) { const Interval i1 = partial_demand_sums_rmq_[layer - 1][i]; const Interval i2 = partial_demand_sums_rmq_[layer - 1][i + window_size]; - partial_demand_sums_rmq_[layer][i] = { std::min(i1.min, i2.min), - std::max(i1.max, i2.max) }; + partial_demand_sums_rmq_[layer][i] = {std::min(i1.min, i2.min), + std::max(i1.max, i2.max)}; } std::copy( partial_demand_sums_rmq_[layer - 1].begin() + end_index - window_size, @@ -3093,12 +3061,11 @@ UnaryDimensionChecker::GetMinMaxPartialDemandSum(int first_node_index, const Interval i1 = partial_demand_sums_rmq_[layer][first_node_index]; const Interval i2 = partial_demand_sums_rmq_[layer][last_node_index - window_size + 1]; - return { std::min(i1.min, i2.min), std::max(i1.max, i2.max) }; + return {std::min(i1.min, i2.min), std::max(i1.max, i2.max)}; } -bool -UnaryDimensionChecker::SubpathOnlyHasTrivialNodes(int first_node_index, - int last_node_index) const { +bool UnaryDimensionChecker::SubpathOnlyHasTrivialNodes( + int first_node_index, int last_node_index) const { DCHECK_LE(0, first_node_index); DCHECK_LT(first_node_index, last_node_index); DCHECK_LT(last_node_index, previous_nontrivial_index_.size()); @@ -3108,7 +3075,7 @@ UnaryDimensionChecker::SubpathOnlyHasTrivialNodes(int first_node_index, namespace { class UnaryDimensionFilter : public LocalSearchFilter { -public: + public: std::string DebugString() const override { return "UnaryDimensionFilter"; } explicit UnaryDimensionFilter(std::unique_ptr checker) : checker_(std::move(checker)) {} @@ -3118,20 +3085,19 @@ public: return checker_->Check(); } - void Synchronize(const Assignment *assignment, const Assignment *delta) - override { + void Synchronize(const Assignment *assignment, + const Assignment *delta) override { checker_->Commit(); } -private: + private: std::unique_ptr checker_; }; -} // namespace +} // namespace -LocalSearchFilter * -MakeUnaryDimensionFilter(Solver *solver, - std::unique_ptr checker) { +LocalSearchFilter *MakeUnaryDimensionFilter( + Solver *solver, std::unique_ptr checker) { UnaryDimensionFilter *filter = new UnaryDimensionFilter(std::move(checker)); return solver->RevAlloc(filter); } @@ -3141,13 +3107,13 @@ namespace { // Rejects assignments to values outside the domain of variables class VariableDomainFilter : public LocalSearchFilter { -public: + public: VariableDomainFilter() {} ~VariableDomainFilter() override {} bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, int64 objective_max) override; - void Synchronize(const Assignment *assignment, const Assignment *delta) - override {} + void Synchronize(const Assignment *assignment, + const Assignment *delta) override {} std::string DebugString() const override { return "VariableDomainFilter"; } }; @@ -3165,7 +3131,7 @@ bool VariableDomainFilter::Accept(const Assignment *delta, } return true; } -} // namespace +} // namespace LocalSearchFilter *Solver::MakeVariableDomainFilter() { return RevAlloc(new VariableDomainFilter()); @@ -3208,8 +3174,8 @@ void IntVarLocalSearchFilter::Synchronize(const Assignment *assignment, OnSynchronize(delta); } -void -IntVarLocalSearchFilter::SynchronizeOnAssignment(const Assignment *assignment) { +void IntVarLocalSearchFilter::SynchronizeOnAssignment( + const Assignment *assignment) { const Assignment::IntContainer &container = assignment->IntVarContainer(); const int size = container.Size(); for (int i = 0; i < size; ++i) { @@ -3242,13 +3208,16 @@ IntVarLocalSearchFilter::SynchronizeOnAssignment(const Assignment *assignment) { // - Solver::EQ -> the conjunction of LE and GE. namespace { class SumObjectiveFilter : public IntVarLocalSearchFilter { -public: + public: SumObjectiveFilter(const std::vector &vars, Solver::LocalSearchFilterBound filter_enum) - : IntVarLocalSearchFilter(vars), primary_vars_size_(vars.size()), + : IntVarLocalSearchFilter(vars), + primary_vars_size_(vars.size()), synchronized_costs_(new int64[vars.size()]), - delta_costs_(new int64[vars.size()]), filter_enum_(filter_enum), - synchronized_sum_(kint64min), delta_sum_(kint64min), + delta_costs_(new int64[vars.size()]), + filter_enum_(filter_enum), + synchronized_sum_(kint64min), + delta_sum_(kint64min), incremental_(false) { for (int i = 0; i < vars.size(); ++i) { synchronized_costs_[i] = 0; @@ -3285,15 +3254,19 @@ public: incremental_ = true; } switch (filter_enum_) { - case Solver::LE: { return delta_sum_ <= objective_max; } - case Solver::GE: { return delta_sum_ >= objective_min; } - case Solver::EQ: { - return objective_min <= delta_sum_ && delta_sum_ <= objective_max; - } - default: { - LOG(ERROR) << "Unknown local search filter enum value"; - return false; - } + case Solver::LE: { + return delta_sum_ <= objective_max; + } + case Solver::GE: { + return delta_sum_ >= objective_min; + } + case Solver::EQ: { + return objective_min <= delta_sum_ && delta_sum_ <= objective_max; + } + default: { + LOG(ERROR) << "Unknown local search filter enum value"; + return false; + } } } // If the variable is synchronized, returns its associated cost, otherwise @@ -3302,10 +3275,9 @@ public: // If the variable is bound, fills new_cost with the cost associated to the // variable's valuation in container, and returns true. Otherwise, fills // new_cost with 0, and returns false. - virtual bool - FillCostOfBoundDeltaVariable(const Assignment::IntContainer &container, - int index, int *container_index, - int64 *new_cost) = 0; + virtual bool FillCostOfBoundDeltaVariable( + const Assignment::IntContainer &container, int index, + int *container_index, int64 *new_cost) = 0; bool IsIncremental() const override { return true; } std::string DebugString() const override { return "SumObjectiveFilter"; } @@ -3315,7 +3287,7 @@ public: } int64 GetAcceptedObjectiveValue() const override { return delta_sum_; } -protected: + protected: const int primary_vars_size_; int64 *const synchronized_costs_; int64 *const delta_costs_; @@ -3324,7 +3296,7 @@ protected: int64 delta_sum_; bool incremental_; -private: + private: void OnSynchronize(const Assignment *delta) override { synchronized_sum_ = 0; for (int i = 0; i < primary_vars_size_; ++i) { @@ -3361,7 +3333,7 @@ private: }; class BinaryObjectiveFilter : public SumObjectiveFilter { -public: + public: BinaryObjectiveFilter(const std::vector &vars, Solver::IndexEvaluator2 value_evaluator, Solver::LocalSearchFilterBound filter_enum) @@ -3391,12 +3363,12 @@ public: return false; } -private: + private: Solver::IndexEvaluator2 value_evaluator_; }; class TernaryObjectiveFilter : public SumObjectiveFilter { -public: + public: TernaryObjectiveFilter(const std::vector &vars, const std::vector &secondary_vars, Solver::IndexEvaluator3 value_evaluator, @@ -3448,25 +3420,23 @@ public: return false; } -private: + private: int secondary_vars_offset_; Solver::IndexEvaluator3 value_evaluator_; }; -} // namespace +} // namespace -IntVarLocalSearchFilter * -Solver::MakeSumObjectiveFilter(const std::vector &vars, - Solver::IndexEvaluator2 values, - Solver::LocalSearchFilterBound filter_enum) { +IntVarLocalSearchFilter *Solver::MakeSumObjectiveFilter( + const std::vector &vars, Solver::IndexEvaluator2 values, + Solver::LocalSearchFilterBound filter_enum) { return RevAlloc( new BinaryObjectiveFilter(vars, std::move(values), filter_enum)); } -IntVarLocalSearchFilter * -Solver::MakeSumObjectiveFilter(const std::vector &vars, - const std::vector &secondary_vars, - Solver::IndexEvaluator3 values, - Solver::LocalSearchFilterBound filter_enum) { +IntVarLocalSearchFilter *Solver::MakeSumObjectiveFilter( + const std::vector &vars, + const std::vector &secondary_vars, Solver::IndexEvaluator3 values, + Solver::LocalSearchFilterBound filter_enum) { return RevAlloc(new TernaryObjectiveFilter(vars, secondary_vars, std::move(values), filter_enum)); } @@ -3475,16 +3445,12 @@ LocalSearchVariable LocalSearchState::AddVariable(int64 initial_min, int64 initial_max) { DCHECK(state_is_valid_); DCHECK_LE(initial_min, initial_max); - initial_variable_bounds_.push_back({ - initial_min, initial_max - }); - variable_bounds_.push_back({ - initial_min, initial_max - }); + initial_variable_bounds_.push_back({initial_min, initial_max}); + variable_bounds_.push_back({initial_min, initial_max}); variable_is_relaxed_.push_back(false); const int variable_index = variable_bounds_.size() - 1; - return { this, variable_index }; + return {this, variable_index}; } void LocalSearchState::RelaxVariableBounds(int variable_index) { @@ -3556,7 +3522,7 @@ void LocalSearchState::Revert() { // ----- LocalSearchProfiler ----- class LocalSearchProfiler : public LocalSearchMonitor { -public: + public: explicit LocalSearchProfiler(Solver *solver) : LocalSearchMonitor(solver) {} std::string DebugString() const override { return "LocalSearchProfiler"; } void RestartSearch() override { @@ -3575,16 +3541,16 @@ public: for (const auto &stat : operator_stats_) { operators.push_back(stat.first); } - std::sort(operators.begin(), operators.end(), - [this](const LocalSearchOperator * op1, - const LocalSearchOperator * op2) { - return gtl::FindOrDie(operator_stats_, op1).neighbors > - gtl::FindOrDie(operator_stats_, op2).neighbors; - }); + std::sort( + operators.begin(), operators.end(), + [this](const LocalSearchOperator *op1, const LocalSearchOperator *op2) { + return gtl::FindOrDie(operator_stats_, op1).neighbors > + gtl::FindOrDie(operator_stats_, op2).neighbors; + }); for (const LocalSearchOperator *const op : operators) { const OperatorStats &stats = gtl::FindOrDie(operator_stats_, op); - LocalSearchStatistics:: - LocalSearchOperatorStatistics *const local_search_operator_statistics = + LocalSearchStatistics::LocalSearchOperatorStatistics + *const local_search_operator_statistics = statistics_proto.add_local_search_operator_statistics(); local_search_operator_statistics->set_local_search_operator( op->DebugString()); @@ -3600,15 +3566,15 @@ public: filters.push_back(stat.first); } std::sort(filters.begin(), filters.end(), - [this](const LocalSearchFilter * filter1, - const LocalSearchFilter * filter2) { - return gtl::FindOrDie(filter_stats_, filter1).calls > - gtl::FindOrDie(filter_stats_, filter2).calls; - }); + [this](const LocalSearchFilter *filter1, + const LocalSearchFilter *filter2) { + return gtl::FindOrDie(filter_stats_, filter1).calls > + gtl::FindOrDie(filter_stats_, filter2).calls; + }); for (const LocalSearchFilter *const filter : filters) { const FilterStats &stats = gtl::FindOrDie(filter_stats_, filter); - LocalSearchStatistics:: - LocalSearchFilterStatistics *const local_search_filter_statistics = + LocalSearchStatistics::LocalSearchFilterStatistics + *const local_search_filter_statistics = statistics_proto.add_local_search_filter_statistics(); local_search_filter_statistics->set_local_search_filter( filter->DebugString()); @@ -3631,12 +3597,12 @@ public: max_name_size = std::max(max_name_size, stat.first->DebugString().length()); } - std::sort(operators.begin(), operators.end(), - [this](const LocalSearchOperator * op1, - const LocalSearchOperator * op2) { - return gtl::FindOrDie(operator_stats_, op1).neighbors > - gtl::FindOrDie(operator_stats_, op2).neighbors; - }); + std::sort( + operators.begin(), operators.end(), + [this](const LocalSearchOperator *op1, const LocalSearchOperator *op2) { + return gtl::FindOrDie(operator_stats_, op1).neighbors > + gtl::FindOrDie(operator_stats_, op2).neighbors; + }); std::string overview = "Local search operator statistics:\n"; absl::StrAppendFormat(&overview, "%*s | Neighbors | Filtered | Accepted | Time (s)\n", @@ -3666,11 +3632,11 @@ public: std::max(max_name_size, stat.first->DebugString().length()); } std::sort(filters.begin(), filters.end(), - [this](const LocalSearchFilter * filter1, - const LocalSearchFilter * filter2) { - return gtl::FindOrDie(filter_stats_, filter1).calls > - gtl::FindOrDie(filter_stats_, filter2).calls; - }); + [this](const LocalSearchFilter *filter1, + const LocalSearchFilter *filter2) { + return gtl::FindOrDie(filter_stats_, filter1).calls > + gtl::FindOrDie(filter_stats_, filter2).calls; + }); absl::StrAppendFormat(&overview, "Local search filter statistics:\n%*s | Calls | " " Rejects | Time (s) " @@ -3710,15 +3676,15 @@ public: } } void BeginFilterNeighbor(const LocalSearchOperator *op) override {} - void EndFilterNeighbor(const LocalSearchOperator *op, bool neighbor_found) - override { + void EndFilterNeighbor(const LocalSearchOperator *op, + bool neighbor_found) override { if (neighbor_found) { operator_stats_[op->Self()].filtered_neighbors++; } } void BeginAcceptNeighbor(const LocalSearchOperator *op) override {} - void EndAcceptNeighbor(const LocalSearchOperator *op, bool neighbor_found) - override { + void EndAcceptNeighbor(const LocalSearchOperator *op, + bool neighbor_found) override { if (neighbor_found) { operator_stats_[op->Self()].accepted_neighbors++; } @@ -3737,7 +3703,7 @@ public: } void Install() override { SearchMonitor::Install(); } -private: + private: void UpdateTime() { if (last_operator_ != nullptr) { timer_.Stop(); @@ -3813,21 +3779,18 @@ LocalSearchFilterManager::LocalSearchFilterManager( : synchronized_value_(kint64min), accepted_value_(kint64min) { filter_events_.reserve(2 * filters.size()); for (LocalSearchFilter *filter : filters) { - filter_events_.push_back({ - filter, FilterEventType::kRelax - }); + filter_events_.push_back({filter, FilterEventType::kRelax}); } for (LocalSearchFilter *filter : filters) { - filter_events_.push_back({ - filter, FilterEventType::kAccept - }); + filter_events_.push_back({filter, FilterEventType::kAccept}); } InitializeForcedEvents(); } LocalSearchFilterManager::LocalSearchFilterManager( std::vector filter_events) - : filter_events_(std::move(filter_events)), synchronized_value_(kint64min), + : filter_events_(std::move(filter_events)), + synchronized_value_(kint64min), accepted_value_(kint64min) { InitializeForcedEvents(); } @@ -3836,9 +3799,8 @@ LocalSearchFilterManager::LocalSearchFilterManager( // Relax() was called. void LocalSearchFilterManager::Revert() { for (int i = last_event_called_; i >= 0; --i) { - auto[filter, event_type] = filter_events_[i]; - if (event_type == FilterEventType::kRelax) - filter->Revert(); + auto [filter, event_type] = filter_events_[i]; + if (event_type == FilterEventType::kRelax) filter->Revert(); } last_event_called_ = -1; } @@ -3857,31 +3819,29 @@ bool LocalSearchFilterManager::Accept(LocalSearchMonitor *const monitor, const int num_events = filter_events_.size(); for (int i = 0; i < num_events;) { last_event_called_ = i; - auto[filter, event_type] = filter_events_[last_event_called_]; + auto [filter, event_type] = filter_events_[last_event_called_]; switch (event_type) { - case FilterEventType::kAccept: { - if (monitor != nullptr) - monitor->BeginFiltering(filter); - const bool accept = filter->Accept( - delta, deltadelta, CapSub(objective_min, accepted_value_), - CapSub(objective_max, accepted_value_)); - ok &= accept; - if (monitor != nullptr) - monitor->EndFiltering(filter, !accept); - if (ok) { - accepted_value_ = - CapAdd(accepted_value_, filter->GetAcceptedObjectiveValue()); - // TODO(user): handle objective min. - ok = accepted_value_ <= objective_max; + case FilterEventType::kAccept: { + if (monitor != nullptr) monitor->BeginFiltering(filter); + const bool accept = filter->Accept( + delta, deltadelta, CapSub(objective_min, accepted_value_), + CapSub(objective_max, accepted_value_)); + ok &= accept; + if (monitor != nullptr) monitor->EndFiltering(filter, !accept); + if (ok) { + accepted_value_ = + CapAdd(accepted_value_, filter->GetAcceptedObjectiveValue()); + // TODO(user): handle objective min. + ok = accepted_value_ <= objective_max; + } + break; } - break; - } - case FilterEventType::kRelax: { - filter->Relax(delta, deltadelta); - break; - } - default: - LOG(FATAL) << "Unknown filter event type."; + case FilterEventType::kRelax: { + filter->Relax(delta, deltadelta); + break; + } + default: + LOG(FATAL) << "Unknown filter event type."; } // If the candidate is rejected, forced events must still be called. if (ok) { @@ -3900,39 +3860,41 @@ void LocalSearchFilterManager::Synchronize(const Assignment *assignment, // so they can show the partial solution as a change from the empty solution. const bool reset_to_assignment = delta == nullptr || delta->Empty(); // Relax in the forward direction. - for (auto[filter, event_type] : filter_events_) { + for (auto [filter, event_type] : filter_events_) { switch (event_type) { - case FilterEventType::kAccept: { break; } - case FilterEventType::kRelax: { - if (reset_to_assignment) { - filter->Reset(); - filter->Relax(assignment, nullptr); - } else { - filter->Relax(delta, nullptr); + case FilterEventType::kAccept: { + break; } - break; - } - default: - LOG(FATAL) << "Unknown filter event type."; + case FilterEventType::kRelax: { + if (reset_to_assignment) { + filter->Reset(); + filter->Relax(assignment, nullptr); + } else { + filter->Relax(delta, nullptr); + } + break; + } + default: + LOG(FATAL) << "Unknown filter event type."; } } // Synchronize/Commit backwards, so filters can read changes from their // dependencies before those are synchronized/committed. synchronized_value_ = 0; - for (auto[filter, event_type] : ::gtl::reversed_view(filter_events_)) { + for (auto [filter, event_type] : ::gtl::reversed_view(filter_events_)) { switch (event_type) { - case FilterEventType::kAccept: { - filter->Synchronize(assignment, delta); - synchronized_value_ = - CapAdd(synchronized_value_, filter->GetSynchronizedObjectiveValue()); - break; - } - case FilterEventType::kRelax: { - filter->Commit(assignment, delta); - break; - } - default: - LOG(FATAL) << "Unknown filter event type."; + case FilterEventType::kAccept: { + filter->Synchronize(assignment, delta); + synchronized_value_ = CapAdd(synchronized_value_, + filter->GetSynchronizedObjectiveValue()); + break; + } + case FilterEventType::kRelax: { + filter->Commit(assignment, delta); + break; + } + default: + LOG(FATAL) << "Unknown filter event type."; } } } @@ -3940,7 +3902,7 @@ void LocalSearchFilterManager::Synchronize(const Assignment *assignment, // ----- Finds a neighbor of the assignment passed ----- class FindOneNeighbor : public DecisionBuilder { -public: + public: FindOneNeighbor(Assignment *const assignment, IntVar *objective, SolutionPool *const pool, LocalSearchOperator *const ls_operator, @@ -3951,7 +3913,7 @@ public: Decision *Next(Solver *const solver) override; std::string DebugString() const override { return "FindOneNeighbor"; } -private: + private: bool FilterAccept(Solver *solver, Assignment *delta, Assignment *deltadelta, int64 objective_min, int64 objective_max); void SynchronizeAll(Solver *solver, bool synchronize_filters = true); @@ -3981,11 +3943,17 @@ FindOneNeighbor::FindOneNeighbor(Assignment *const assignment, DecisionBuilder *const sub_decision_builder, const RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : assignment_(assignment), objective_(objective), - reference_assignment_(new Assignment(assignment_)), pool_(pool), - ls_operator_(ls_operator), sub_decision_builder_(sub_decision_builder), - limit_(nullptr), original_limit_(limit), neighbor_found_(false), - filter_manager_(filter_manager), solutions_since_last_check_(0), + : assignment_(assignment), + objective_(objective), + reference_assignment_(new Assignment(assignment_)), + pool_(pool), + ls_operator_(ls_operator), + sub_decision_builder_(sub_decision_builder), + limit_(nullptr), + original_limit_(limit), + neighbor_found_(false), + filter_manager_(filter_manager), + solutions_since_last_check_(0), check_period_( assignment_->solver()->parameters().check_solution_period()), last_checked_assignment_(assignment) { @@ -4092,11 +4060,10 @@ Decision *FindOneNeighbor::Next(Solver *const solver) { } const bool move_filter = FilterAccept(solver, delta, deltadelta, objective_min, objective_max); - solver->GetLocalSearchMonitor() - ->EndFilterNeighbor(ls_operator_, mh_filter && move_filter); + solver->GetLocalSearchMonitor()->EndFilterNeighbor( + ls_operator_, mh_filter && move_filter); if (!mh_filter || !move_filter) { - if (filter_manager_ != nullptr) - filter_manager_->Revert(); + if (filter_manager_ != nullptr) filter_manager_->Revert(); continue; } solver->filtered_neighbors_ += 1; @@ -4116,14 +4083,13 @@ Decision *FindOneNeighbor::Next(Solver *const solver) { !solver->UseFastLocalSearch() || // LNS deltas need to be restored !delta->AreAllElementsBound(); - if (has_checked_assignment_) - solutions_since_last_check_++; + if (has_checked_assignment_) solutions_since_last_check_++; if (solutions_since_last_check_ >= check_period_) { solutions_since_last_check_ = 0; } const bool accept = !check_solution || solver->SolveAndCommit(restore); - solver->GetLocalSearchMonitor() - ->EndAcceptNeighbor(ls_operator_, accept); + solver->GetLocalSearchMonitor()->EndAcceptNeighbor(ls_operator_, + accept); if (accept) { solver->accepted_neighbors_ += 1; if (check_solution) { @@ -4154,8 +4120,7 @@ Decision *FindOneNeighbor::Next(Solver *const solver) { neighbor_found_ = true; } } else { - if (filter_manager_ != nullptr) - filter_manager_->Revert(); + if (filter_manager_ != nullptr) filter_manager_->Revert(); if (check_period_ > 1 && has_checked_assignment_) { // Filtering is not perfect, disabling fast local search and // resynchronizing with the last checked solution. @@ -4182,8 +4147,7 @@ Decision *FindOneNeighbor::Next(Solver *const solver) { // If restoring fails this means filtering is not perfect and the // solver will consider the last checked assignment. assignment_copy->CopyIntersection(assignment_); - if (!solver->SolveAndCommit(restore)) - solver->Fail(); + if (!solver->SolveAndCommit(restore)) solver->Fail(); last_checked_assignment_.CopyIntersection(assignment_); has_checked_assignment_ = true; return nullptr; @@ -4207,8 +4171,7 @@ Decision *FindOneNeighbor::Next(Solver *const solver) { bool FindOneNeighbor::FilterAccept(Solver *solver, Assignment *delta, Assignment *deltadelta, int64 objective_min, int64 objective_max) { - if (filter_manager_ == nullptr) - return true; + if (filter_manager_ == nullptr) return true; LocalSearchMonitor *const monitor = solver->GetLocalSearchMonitor(); return filter_manager_->Accept(monitor, delta, deltadelta, objective_min, objective_max); @@ -4229,14 +4192,17 @@ void FindOneNeighbor::SynchronizeAll(Solver *solver, bool synchronize_filters) { // ---------- Local Search Phase Parameters ---------- class LocalSearchPhaseParameters : public BaseObject { -public: + public: LocalSearchPhaseParameters(IntVar *objective, SolutionPool *const pool, LocalSearchOperator *ls_operator, DecisionBuilder *sub_decision_builder, RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : objective_(objective), solution_pool_(pool), ls_operator_(ls_operator), - sub_decision_builder_(sub_decision_builder), limit_(limit), + : objective_(objective), + solution_pool_(pool), + ls_operator_(ls_operator), + sub_decision_builder_(sub_decision_builder), + limit_(limit), filter_manager_(filter_manager) {} ~LocalSearchPhaseParameters() override {} std::string DebugString() const override { @@ -4254,7 +4220,7 @@ public: return filter_manager_; } -private: + private: IntVar *const objective_; SolutionPool *const solution_pool_; LocalSearchOperator *const ls_operator_; @@ -4325,13 +4291,9 @@ namespace { // DECISION_FOUND - Nested Solve succeeded class NestedSolveDecision : public Decision { -public: + public: // This enum is used internally to tag states in the local search tree. - enum StateType { - DECISION_PENDING, - DECISION_FAILED, - DECISION_FOUND - }; + enum StateType { DECISION_PENDING, DECISION_FAILED, DECISION_FOUND }; NestedSolveDecision(DecisionBuilder *const db, bool restore, const std::vector &monitors); @@ -4342,7 +4304,7 @@ public: std::string DebugString() const override { return "NestedSolveDecision"; } int state() const { return state_; } -private: + private: DecisionBuilder *const db_; bool restore_; std::vector monitors_; @@ -4352,7 +4314,9 @@ private: NestedSolveDecision::NestedSolveDecision( DecisionBuilder *const db, bool restore, const std::vector &monitors) - : db_(db), restore_(restore), monitors_(monitors), + : db_(db), + restore_(restore), + monitors_(monitors), state_(DECISION_PENDING) { CHECK(nullptr != db); } @@ -4392,7 +4356,7 @@ void NestedSolveDecision::Refute(Solver *const solver) {} // or the vector of variables passed. class LocalSearch : public DecisionBuilder { -public: + public: LocalSearch(Assignment *const assignment, IntVar *objective, SolutionPool *const pool, LocalSearchOperator *const ls_operator, DecisionBuilder *const sub_decision_builder, @@ -4424,11 +4388,11 @@ public: std::string DebugString() const override { return "LocalSearch"; } void Accept(ModelVisitor *const visitor) const override; -protected: + protected: void PushFirstSolutionDecision(DecisionBuilder *first_solution); void PushLocalSearchDecision(); -private: + private: Assignment *assignment_; IntVar *const objective_ = nullptr; SolutionPool *const pool_; @@ -4448,11 +4412,16 @@ LocalSearch::LocalSearch(Assignment *const assignment, IntVar *objective, DecisionBuilder *const sub_decision_builder, RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : assignment_(nullptr), objective_(objective), pool_(pool), + : assignment_(nullptr), + objective_(objective), + pool_(pool), ls_operator_(ls_operator), first_solution_sub_decision_builder_(sub_decision_builder), - sub_decision_builder_(sub_decision_builder), nested_decision_index_(0), - limit_(limit), filter_manager_(filter_manager), has_started_(false) { + sub_decision_builder_(sub_decision_builder), + nested_decision_index_(0), + limit_(limit), + filter_manager_(filter_manager), + has_started_(false) { CHECK(nullptr != assignment); CHECK(nullptr != ls_operator); Solver *const solver = assignment->solver(); @@ -4470,11 +4439,16 @@ LocalSearch::LocalSearch(const std::vector &vars, IntVar *objective, DecisionBuilder *const sub_decision_builder, RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : assignment_(nullptr), objective_(objective), pool_(pool), + : assignment_(nullptr), + objective_(objective), + pool_(pool), ls_operator_(ls_operator), first_solution_sub_decision_builder_(sub_decision_builder), - sub_decision_builder_(sub_decision_builder), nested_decision_index_(0), - limit_(limit), filter_manager_(filter_manager), has_started_(false) { + sub_decision_builder_(sub_decision_builder), + nested_decision_index_(0), + limit_(limit), + filter_manager_(filter_manager), + has_started_(false) { CHECK(nullptr != first_solution); CHECK(nullptr != ls_operator); CHECK(!vars.empty()); @@ -4492,11 +4466,16 @@ LocalSearch::LocalSearch( LocalSearchOperator *const ls_operator, DecisionBuilder *const sub_decision_builder, RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : assignment_(nullptr), objective_(objective), pool_(pool), + : assignment_(nullptr), + objective_(objective), + pool_(pool), ls_operator_(ls_operator), first_solution_sub_decision_builder_(first_solution_sub_decision_builder), - sub_decision_builder_(sub_decision_builder), nested_decision_index_(0), - limit_(limit), filter_manager_(filter_manager), has_started_(false) { + sub_decision_builder_(sub_decision_builder), + nested_decision_index_(0), + limit_(limit), + filter_manager_(filter_manager), + has_started_(false) { CHECK(nullptr != first_solution); CHECK(nullptr != ls_operator); CHECK(!vars.empty()); @@ -4514,11 +4493,16 @@ LocalSearch::LocalSearch(const std::vector &vars, DecisionBuilder *const sub_decision_builder, RegularLimit *const limit, LocalSearchFilterManager *filter_manager) - : assignment_(nullptr), objective_(objective), pool_(pool), + : assignment_(nullptr), + objective_(objective), + pool_(pool), ls_operator_(ls_operator), first_solution_sub_decision_builder_(sub_decision_builder), - sub_decision_builder_(sub_decision_builder), nested_decision_index_(0), - limit_(limit), filter_manager_(filter_manager), has_started_(false) { + sub_decision_builder_(sub_decision_builder), + nested_decision_index_(0), + limit_(limit), + filter_manager_(filter_manager), + has_started_(false) { CHECK(nullptr != first_solution); CHECK(nullptr != ls_operator); CHECK(!vars.empty()); @@ -4576,47 +4560,47 @@ Decision *LocalSearch::Next(Solver *const solver) { NestedSolveDecision *decision = nested_decisions_[nested_decision_index_]; const int state = decision->state(); switch (state) { - case NestedSolveDecision::DECISION_FAILED: { - // A local optimum has been reached. The search will continue only if we - // accept up-hill moves (due to metaheuristics). In this case we need to - // reset neighborhood optimal routes. - ls_operator_->Reset(); - if (!LocalOptimumReached(solver->ActiveSearch())) { - nested_decision_index_ = -1; // Stop the search - } - solver->Fail(); - return nullptr; - } - case NestedSolveDecision::DECISION_PENDING: { - // TODO(user): Find a way to make this balancing invisible to the - // user (no increase in branch or fail counts for instance). - const int32 kLocalSearchBalancedTreeDepth = 32; - const int depth = solver->SearchDepth(); - if (depth < kLocalSearchBalancedTreeDepth) { - return solver->balancing_decision(); - } else if (depth > kLocalSearchBalancedTreeDepth) { + case NestedSolveDecision::DECISION_FAILED: { + // A local optimum has been reached. The search will continue only if we + // accept up-hill moves (due to metaheuristics). In this case we need to + // reset neighborhood optimal routes. + ls_operator_->Reset(); + if (!LocalOptimumReached(solver->ActiveSearch())) { + nested_decision_index_ = -1; // Stop the search + } solver->Fail(); + return nullptr; } - return decision; - } - case NestedSolveDecision::DECISION_FOUND: { - // Next time go to next decision - if (nested_decision_index_ + 1 < nested_decisions_.size()) { - ++nested_decision_index_; + case NestedSolveDecision::DECISION_PENDING: { + // TODO(user): Find a way to make this balancing invisible to the + // user (no increase in branch or fail counts for instance). + const int32 kLocalSearchBalancedTreeDepth = 32; + const int depth = solver->SearchDepth(); + if (depth < kLocalSearchBalancedTreeDepth) { + return solver->balancing_decision(); + } else if (depth > kLocalSearchBalancedTreeDepth) { + solver->Fail(); + } + return decision; + } + case NestedSolveDecision::DECISION_FOUND: { + // Next time go to next decision + if (nested_decision_index_ + 1 < nested_decisions_.size()) { + ++nested_decision_index_; + } + return nullptr; + } + default: { + LOG(ERROR) << "Unknown local search state"; + return nullptr; } - return nullptr; - } - default: { - LOG(ERROR) << "Unknown local search state"; - return nullptr; - } } return nullptr; } namespace { class SynchronizeFiltersDecisionBuilder : public DecisionBuilder { -public: + public: SynchronizeFiltersDecisionBuilder(Assignment *assignment, LocalSearchFilterManager *filter_manager) : assignment_(assignment), filter_manager_(filter_manager) {} @@ -4628,11 +4612,11 @@ public: return nullptr; } -private: + private: Assignment *const assignment_; LocalSearchFilterManager *const filter_manager_; }; -} // namespace +} // namespace void LocalSearch::PushFirstSolutionDecision(DecisionBuilder *first_solution) { CHECK(first_solution); @@ -4658,7 +4642,7 @@ void LocalSearch::PushLocalSearchDecision() { } class DefaultSolutionPool : public SolutionPool { -public: + public: DefaultSolutionPool() {} ~DefaultSolutionPool() override {} @@ -4679,28 +4663,26 @@ public: std::string DebugString() const override { return "DefaultSolutionPool"; } -private: + private: std::unique_ptr reference_assignment_; }; -} // namespace +} // namespace SolutionPool *Solver::MakeDefaultSolutionPool() { return RevAlloc(new DefaultSolutionPool()); } -DecisionBuilder * -Solver::MakeLocalSearchPhase(Assignment *assignment, - LocalSearchPhaseParameters *parameters) { +DecisionBuilder *Solver::MakeLocalSearchPhase( + Assignment *assignment, LocalSearchPhaseParameters *parameters) { return RevAlloc(new LocalSearch( assignment, parameters->objective(), parameters->solution_pool(), parameters->ls_operator(), parameters->sub_decision_builder(), parameters->limit(), parameters->filter_manager())); } -DecisionBuilder * -Solver::MakeLocalSearchPhase(const std::vector &vars, - DecisionBuilder *first_solution, - LocalSearchPhaseParameters *parameters) { +DecisionBuilder *Solver::MakeLocalSearchPhase( + const std::vector &vars, DecisionBuilder *first_solution, + LocalSearchPhaseParameters *parameters) { return RevAlloc(new LocalSearch( vars, parameters->objective(), parameters->solution_pool(), first_solution, parameters->ls_operator(), @@ -4719,14 +4701,13 @@ DecisionBuilder *Solver::MakeLocalSearchPhase( parameters->limit(), parameters->filter_manager())); } -DecisionBuilder * -Solver::MakeLocalSearchPhase(const std::vector &vars, - DecisionBuilder *first_solution, - LocalSearchPhaseParameters *parameters) { +DecisionBuilder *Solver::MakeLocalSearchPhase( + const std::vector &vars, DecisionBuilder *first_solution, + LocalSearchPhaseParameters *parameters) { return RevAlloc(new LocalSearch( vars, parameters->objective(), parameters->solution_pool(), first_solution, parameters->ls_operator(), parameters->sub_decision_builder(), parameters->limit(), parameters->filter_manager())); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/model_cache.cc b/ortools/constraint_solver/model_cache.cc index a19803db5b..fa60de89bc 100644 --- a/ortools/constraint_solver/model_cache.cc +++ b/ortools/constraint_solver/model_cache.cc @@ -36,7 +36,10 @@ Solver *ModelCache::solver() const { return solver_; } namespace { // ----- Helpers ----- -template bool IsEqual(const T &a1, const T &a2) { return a1 == a2; } +template +bool IsEqual(const T &a1, const T &a2) { + return a1 == a2; +} template bool IsEqual(const std::vector &a1, const std::vector &a2) { @@ -51,9 +54,10 @@ bool IsEqual(const std::vector &a1, const std::vector &a2) { return true; } -template uint64 Hash2(const A1 &a1, const A2 &a2) { +template +uint64 Hash2(const A1 &a1, const A2 &a2) { uint64 a = Hash1(a1); - uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // more of the golden ratio + uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // more of the golden ratio uint64 c = Hash1(a2); mix(a, b, c); return c; @@ -77,7 +81,8 @@ uint64 Hash4(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) { return c; } -template void Double(C ***array_ptr, int *size_ptr) { +template +void Double(C ***array_ptr, int *size_ptr) { DCHECK(array_ptr != nullptr); DCHECK(size_ptr != nullptr); C **const old_cell_array = *array_ptr; @@ -100,11 +105,13 @@ template void Double(C ***array_ptr, int *size_ptr) { // ----- Cache objects built with 1 object ----- -template class Cache1 { -public: +template +class Cache1 { + public: Cache1() : array_(new Cell *[absl::GetFlag(FLAGS_cache_initial_size)]), - size_(absl::GetFlag(FLAGS_cache_initial_size)), num_items_(0) { + size_(absl::GetFlag(FLAGS_cache_initial_size)), + num_items_(0) { memset(array_, 0, sizeof(*array_) * size_); } @@ -154,9 +161,9 @@ public: } } -private: + private: class Cell { - public: + public: Cell(const A1 &a1, C *const container, Cell *const next) : a1_(a1), container_(container), next_(next) {} @@ -173,7 +180,7 @@ private: Cell *next() const { return next_; } - private: + private: const A1 a1_; C *const container_; Cell *next_; @@ -186,11 +193,13 @@ private: // ----- Cache objects built with 2 objects ----- -template class Cache2 { -public: +template +class Cache2 { + public: Cache2() : array_(new Cell *[absl::GetFlag(FLAGS_cache_initial_size)]), - size_(absl::GetFlag(FLAGS_cache_initial_size)), num_items_(0) { + size_(absl::GetFlag(FLAGS_cache_initial_size)), + num_items_(0) { memset(array_, 0, sizeof(*array_) * size_); } @@ -240,9 +249,9 @@ public: } } -private: + private: class Cell { - public: + public: Cell(const A1 &a1, const A2 &a2, C *const container, Cell *const next) : a1_(a1), a2_(a2), container_(container), next_(next) {} @@ -259,7 +268,7 @@ private: Cell *next() const { return next_; } - private: + private: const A1 a1_; const A2 a2_; C *const container_; @@ -273,11 +282,13 @@ private: // ----- Cache objects built with 2 objects ----- -template class Cache3 { -public: +template +class Cache3 { + public: Cache3() : array_(new Cell *[absl::GetFlag(FLAGS_cache_initial_size)]), - size_(absl::GetFlag(FLAGS_cache_initial_size)), num_items_(0) { + size_(absl::GetFlag(FLAGS_cache_initial_size)), + num_items_(0) { memset(array_, 0, sizeof(*array_) * size_); } @@ -327,9 +338,9 @@ public: } } -private: + private: class Cell { - public: + public: Cell(const A1 &a1, const A2 &a2, const A3 &a3, C *const container, Cell *const next) : a1_(a1), a2_(a2), a3_(a3), container_(container), next_(next) {} @@ -347,7 +358,7 @@ private: Cell *next() const { return next_; } - private: + private: const A1 a1_; const A2 a2_; const A3 a3_; @@ -363,7 +374,7 @@ private: // ----- Model Cache ----- class NonReversibleCache : public ModelCache { -public: + public: typedef Cache1 ExprIntExprCache; typedef Cache1 > VarArrayIntExprCache; @@ -494,8 +505,8 @@ public: return void_constraints_[type]; } - void InsertVoidConstraint(Constraint *const ct, VoidConstraintType type) - override { + void InsertVoidConstraint(Constraint *const ct, + VoidConstraintType type) override { DCHECK_GE(type, 0); DCHECK_LT(type, VOID_CONSTRAINT_MAX); DCHECK(ct != nullptr); @@ -507,9 +518,9 @@ public: // VarConstantConstraint. - Constraint *FindVarConstantConstraint(IntVar *const var, int64 value, - VarConstantConstraintType type) const - override { + Constraint *FindVarConstantConstraint( + IntVar *const var, int64 value, + VarConstantConstraintType type) const override { DCHECK(var != nullptr); DCHECK_GE(type, 0); DCHECK_LT(type, VAR_CONSTANT_CONSTRAINT_MAX); @@ -517,8 +528,8 @@ public: } void InsertVarConstantConstraint(Constraint *const ct, IntVar *const var, - int64 value, VarConstantConstraintType type) - override { + int64 value, + VarConstantConstraintType type) override { DCHECK(ct != nullptr); DCHECK(var != nullptr); DCHECK_GE(type, 0); @@ -552,16 +563,16 @@ public: !absl::GetFlag(FLAGS_cp_disable_cache) && var_constant_constant_constraints_[type]->Find(var, value1, value2) == nullptr) { - var_constant_constant_constraints_[type] - ->UnsafeInsert(var, value1, value2, ct); + var_constant_constant_constraints_[type]->UnsafeInsert(var, value1, + value2, ct); } } // Var Var Constraint. - Constraint *FindExprExprConstraint(IntExpr *const var1, IntExpr *const var2, - ExprExprConstraintType type) const - override { + Constraint *FindExprExprConstraint( + IntExpr *const var1, IntExpr *const var2, + ExprExprConstraintType type) const override { DCHECK(var1 != nullptr); DCHECK(var2 != nullptr); DCHECK_GE(type, 0); @@ -609,9 +620,9 @@ public: // Expr Constant Expressions. - IntExpr *FindExprConstantExpression(IntExpr *const expr, int64 value, - ExprConstantExpressionType type) const - override { + IntExpr *FindExprConstantExpression( + IntExpr *const expr, int64 value, + ExprConstantExpressionType type) const override { DCHECK(expr != nullptr); DCHECK_GE(type, 0); DCHECK_LT(type, EXPR_CONSTANT_EXPRESSION_MAX); @@ -670,11 +681,9 @@ public: return expr_expr_constant_expressions_[type]->Find(var1, var2, constant); } - void InsertExprExprConstantExpression(IntExpr *const expression, - IntExpr *const var1, - IntExpr *const var2, int64 constant, - ExprExprConstantExpressionType type) - override { + void InsertExprExprConstantExpression( + IntExpr *const expression, IntExpr *const var1, IntExpr *const var2, + int64 constant, ExprExprConstantExpressionType type) override { DCHECK(expression != nullptr); DCHECK(var1 != nullptr); DCHECK(var2 != nullptr); @@ -684,8 +693,8 @@ public: !absl::GetFlag(FLAGS_cp_disable_cache) && expr_expr_constant_expressions_[type]->Find(var1, var2, constant) == nullptr) { - expr_expr_constant_expressions_[type] - ->UnsafeInsert(var1, var2, constant, expression); + expr_expr_constant_expressions_[type]->UnsafeInsert(var1, var2, constant, + expression); } } @@ -711,8 +720,8 @@ public: !absl::GetFlag(FLAGS_cp_disable_cache) && var_constant_constant_expressions_[type]->Find(var, value1, value2) == nullptr) { - var_constant_constant_expressions_[type] - ->UnsafeInsert(var, value1, value2, expression); + var_constant_constant_expressions_[type]->UnsafeInsert( + var, value1, value2, expression); } } @@ -727,11 +736,10 @@ public: return var_constant_array_expressions_[type]->Find(var, values); } - void InsertVarConstantArrayExpression(IntExpr *const expression, - IntVar *const var, - const std::vector &values, - VarConstantArrayExpressionType type) - override { + void InsertVarConstantArrayExpression( + IntExpr *const expression, IntVar *const var, + const std::vector &values, + VarConstantArrayExpressionType type) override { DCHECK(expression != nullptr); DCHECK(var != nullptr); DCHECK_GE(type, 0); @@ -739,8 +747,8 @@ public: if (solver()->state() == Solver::OUTSIDE_SEARCH && !absl::GetFlag(FLAGS_cp_disable_cache) && var_constant_array_expressions_[type]->Find(var, values) == nullptr) { - var_constant_array_expressions_[type] - ->UnsafeInsert(var, values, expression); + var_constant_array_expressions_[type]->UnsafeInsert(var, values, + expression); } } @@ -786,38 +794,35 @@ public: if (solver()->state() != Solver::IN_SEARCH && var_array_constant_array_expressions_[type]->Find(vars, values) == nullptr) { - var_array_constant_array_expressions_[type] - ->UnsafeInsert(vars, values, expression); + var_array_constant_array_expressions_[type]->UnsafeInsert(vars, values, + expression); } } // Var Array Constant Expressions. - IntExpr * - FindVarArrayConstantExpression(const std::vector &vars, int64 value, - VarArrayConstantExpressionType type) const - override { + IntExpr *FindVarArrayConstantExpression( + const std::vector &vars, int64 value, + VarArrayConstantExpressionType type) const override { DCHECK_GE(type, 0); DCHECK_LT(type, VAR_ARRAY_CONSTANT_EXPRESSION_MAX); return var_array_constant_expressions_[type]->Find(vars, value); } - void InsertVarArrayConstantExpression(IntExpr *const expression, - const std::vector &vars, - int64 value, - VarArrayConstantExpressionType type) - override { + void InsertVarArrayConstantExpression( + IntExpr *const expression, const std::vector &vars, int64 value, + VarArrayConstantExpressionType type) override { DCHECK(expression != nullptr); DCHECK_GE(type, 0); DCHECK_LT(type, VAR_ARRAY_CONSTANT_EXPRESSION_MAX); if (solver()->state() != Solver::IN_SEARCH && var_array_constant_expressions_[type]->Find(vars, value) == nullptr) { - var_array_constant_expressions_[type] - ->UnsafeInsert(vars, value, expression); + var_array_constant_expressions_[type]->UnsafeInsert(vars, value, + expression); } } -private: + private: std::vector void_constraints_; std::vector var_constant_constraints_; std::vector expr_expr_constraints_; @@ -835,11 +840,11 @@ private: std::vector var_array_constant_expressions_; std::vector expr_expr_constant_expressions_; }; -} // namespace +} // namespace ModelCache *BuildModelCache(Solver *const solver) { return new NonReversibleCache(solver); } ModelCache *Solver::Cache() const { return model_cache_.get(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/pack.cc b/ortools/constraint_solver/pack.cc index 68cf5942c2..6b62c248cd 100644 --- a/ortools/constraint_solver/pack.cc +++ b/ortools/constraint_solver/pack.cc @@ -32,7 +32,7 @@ namespace operations_research { // ---------- Dimension ---------- class Dimension : public BaseObject { -public: + public: explicit Dimension(Solver *const s, Pack *const pack) : solver_(s), pack_(pack) {} ~Dimension() override {} @@ -40,9 +40,8 @@ public: virtual void Post() = 0; virtual void InitialPropagate(int bin_index, const std::vector &forced, const std::vector &undecided) = 0; - virtual void - InitialPropagateUnassigned(const std::vector &assigned, - const std::vector &unassigned) = 0; + virtual void InitialPropagateUnassigned( + const std::vector &assigned, const std::vector &unassigned) = 0; virtual void EndInitialPropagate() = 0; virtual void Propagate(int bin_index, const std::vector &forced, const std::vector &removed) = 0; @@ -98,7 +97,7 @@ public: void UnassignAllRemainingItems() { pack_->UnassignAllRemainingItems(); } -private: + private: Solver *const solver_; Pack *const pack_; }; @@ -107,10 +106,16 @@ private: Pack::Pack(Solver *const s, const std::vector &vars, int number_of_bins) - : Constraint(s), vars_(vars), bins_(number_of_bins), + : Constraint(s), + vars_(vars), + bins_(number_of_bins), unprocessed_(new RevBitMatrix(bins_ + 1, vars_.size())), - forced_(bins_ + 1), removed_(bins_ + 1), holes_(vars_.size()), - stamp_(GG_ULONGLONG(0)), demon_(nullptr), in_process_(false) { + forced_(bins_ + 1), + removed_(bins_ + 1), + holes_(vars_.size()), + stamp_(GG_ULONGLONG(0)), + demon_(nullptr), + in_process_(false) { for (int i = 0; i < vars_.size(); ++i) { holes_[i] = vars_[i]->MakeHoleIterator(true); } @@ -158,7 +163,7 @@ void Pack::PropagateDelayed() { // Pack::InitialPropagate() namespace { class InitialPropagateData : public BaseObject { -public: + public: explicit InitialPropagateData(size_t num_bins) : BaseObject(), undecided_(num_bins) {} void PushAssigned(int index) { assigned_.push_back(index); } @@ -174,12 +179,12 @@ public: std::string DebugString() const override { return "InitialPropagateData"; } -private: + private: std::vector > undecided_; std::vector unassigned_; std::vector assigned_; }; -} // namespace +} // namespace void Pack::InitialPropagate() { const bool need_context = solver()->InstrumentsVariables(); @@ -189,7 +194,7 @@ void Pack::InitialPropagate() { InitialPropagateData *data = s->RevAlloc(new InitialPropagateData(bins_)); for (int var_index = 0; var_index < vars_.size(); ++var_index) { IntVar *const var = vars_[var_index]; - var->SetRange(0, bins_); // bins_ -> item is not assigned to a bin. + var->SetRange(0, bins_); // bins_ -> item is not assigned to a bin. if (var->Bound()) { const int64 value = var->Min(); if (value < bins_) { @@ -251,8 +256,8 @@ void Pack::InitialPropagate() { solver()->GetPropagationMonitor()->PushContext(absl::StrFormat( "InitialProgateDimension(%s)", dims_[dim_index]->DebugString())); } - dims_[dim_index] - ->InitialPropagateUnassigned(data->assigned(), data->unassigned()); + dims_[dim_index]->InitialPropagateUnassigned(data->assigned(), + data->unassigned()); dims_[dim_index]->EndInitialPropagate(); if (need_context) { solver()->GetPropagationMonitor()->PopContext(); @@ -284,8 +289,8 @@ void Pack::Propagate() { solver()->GetPropagationMonitor()->PushContext(absl::StrFormat( "ProgateDimension(%s)", dims_[dim_index]->DebugString())); } - dims_[dim_index] - ->Propagate(bin_index, forced_[bin_index], removed_[bin_index]); + dims_[dim_index]->Propagate(bin_index, forced_[bin_index], + removed_[bin_index]); if (need_context) { solver()->GetPropagationMonitor()->PopContext(); } @@ -297,10 +302,10 @@ void Pack::Propagate() { } if (!removed_[bins_].empty() || !forced_[bins_].empty()) { if (need_context) { - solver()->GetPropagationMonitor() - ->PushContext(absl::StrFormat("Pack(removed = [%s], forced = [%s])", - absl::StrJoin(removed_[bins_], ", "), - absl::StrJoin(forced_[bins_], ", "))); + solver()->GetPropagationMonitor()->PushContext( + absl::StrFormat("Pack(removed = [%s], forced = [%s])", + absl::StrJoin(removed_[bins_], ", "), + absl::StrJoin(forced_[bins_], ", "))); } for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) { @@ -340,13 +345,8 @@ void Pack::OneDomain(int var_index) { const int64 oldmax = var->OldMax(); const int64 vmin = var->Min(); const int64 vmax = var->Max(); - for (int64 value = std::max(oldmin, int64 { - 0 - }); - value < std::min(vmin, bins_ + int64 { - 1 - }); - ++value) { + for (int64 value = std::max(oldmin, int64{0}); + value < std::min(vmin, bins_ + int64{1}); ++value) { if (unprocessed_->IsSet(value, var_index)) { unprocessed_->SetToZero(s, value, var_index); removed_[value].push_back(var_index); @@ -354,10 +354,7 @@ void Pack::OneDomain(int var_index) { } if (!bound) { for (const int64 value : InitAndGetValues(holes_[var_index])) { - if (value >= std::max(int64 { - 0 - }, - vmin) && + if (value >= std::max(int64{0}, vmin) && value <= std::min(static_cast(bins_), vmax)) { DCHECK(unprocessed_->IsSet(value, var_index)); unprocessed_->SetToZero(s, value, var_index); @@ -365,9 +362,7 @@ void Pack::OneDomain(int var_index) { } } } - for (int64 value = std::max(vmax + 1, int64 { - 0 - }); + for (int64 value = std::max(vmax + 1, int64{0}); value <= std::min(oldmax, static_cast(bins_)); ++value) { if (unprocessed_->IsSet(value, var_index)) { unprocessed_->SetToZero(s, value, var_index); @@ -488,8 +483,9 @@ void Pack::AssignAllRemainingItems() { int var_index = unprocessed_->GetFirstBit(bins_, 0); while (var_index != -1 && var_index < vars_.size()) { SetAssigned(var_index); - var_index = var_index == vars_.size() - 1 ? -1 : unprocessed_->GetFirstBit( - bins_, var_index + 1); + var_index = var_index == vars_.size() - 1 + ? -1 + : unprocessed_->GetFirstBit(bins_, var_index + 1); } } @@ -497,8 +493,9 @@ void Pack::UnassignAllRemainingItems() { int var_index = unprocessed_->GetFirstBit(bins_, 0); while (var_index != -1 && var_index < vars_.size()) { SetUnassigned(var_index); - var_index = var_index == vars_.size() - 1 ? -1 : unprocessed_->GetFirstBit( - bins_, var_index + 1); + var_index = var_index == vars_.size() - 1 + ? -1 + : unprocessed_->GetFirstBit(bins_, var_index + 1); } } @@ -559,14 +556,18 @@ void SortIndexByWeight(std::vector *const indices, } class DimensionLessThanConstant : public Dimension { -public: + public: DimensionLessThanConstant(Solver *const s, Pack *const p, const std::vector &weights, const std::vector &upper_bounds) - : Dimension(s, p), vars_count_(weights.size()), weights_(weights), - bins_count_(upper_bounds.size()), upper_bounds_(upper_bounds), + : Dimension(s, p), + vars_count_(weights.size()), + weights_(weights), + bins_count_(upper_bounds.size()), + upper_bounds_(upper_bounds), first_unbound_backward_vector_(bins_count_, 0), - sum_of_bound_variables_vector_(bins_count_, 0LL), ranked_(vars_count_) { + sum_of_bound_variables_vector_(bins_count_, 0LL), + ranked_(vars_count_) { for (int i = 0; i < vars_count_; ++i) { ranked_[i] = i; } @@ -640,7 +641,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension); } -private: + private: const int vars_count_; const std::vector weights_; const int bins_count_; @@ -651,15 +652,19 @@ private: }; class DimensionSumCallbackLessThanConstant : public Dimension { -public: + public: DimensionSumCallbackLessThanConstant(Solver *const s, Pack *const p, const Solver::IndexEvaluator1 &weights, int vars_count, const std::vector &upper_bounds) - : Dimension(s, p), vars_count_(vars_count), weights_(weights), - bins_count_(upper_bounds.size()), upper_bounds_(upper_bounds), + : Dimension(s, p), + vars_count_(vars_count), + weights_(weights), + bins_count_(upper_bounds.size()), + upper_bounds_(upper_bounds), first_unbound_backward_vector_(bins_count_, 0), - sum_of_bound_variables_vector_(bins_count_, 0LL), ranked_(vars_count_) { + sum_of_bound_variables_vector_(bins_count_, 0LL), + ranked_(vars_count_) { DCHECK(weights); DCHECK_GT(vars_count, 0); for (int i = 0; i < vars_count_; ++i) { @@ -736,7 +741,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension); } -private: + private: const int vars_count_; Solver::IndexEvaluator1 weights_; const int bins_count_; @@ -747,15 +752,19 @@ private: }; class DimensionLessThanConstantCallback2 : public Dimension { -public: + public: DimensionLessThanConstantCallback2(Solver *const s, Pack *const p, const Solver::IndexEvaluator2 &weights, int vars_count, const std::vector &upper_bounds) - : Dimension(s, p), vars_count_(vars_count), weights_(weights), - bins_count_(upper_bounds.size()), upper_bounds_(upper_bounds), + : Dimension(s, p), + vars_count_(vars_count), + weights_(weights), + bins_count_(upper_bounds.size()), + upper_bounds_(upper_bounds), first_unbound_backward_vector_(bins_count_, 0), - sum_of_bound_variables_vector_(bins_count_, 0LL), ranked_(bins_count_) { + sum_of_bound_variables_vector_(bins_count_, 0LL), + ranked_(bins_count_) { DCHECK(weights); DCHECK_GT(vars_count, 0); for (int b = 0; b < bins_count_; ++b) { @@ -836,7 +845,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension); } -private: + private: const int vars_count_; Solver::IndexEvaluator2 weights_; const int bins_count_; @@ -847,16 +856,16 @@ private: }; class DimensionWeightedSumEqVar : public Dimension { -public: + public: class VarDemon : public Demon { - public: + public: VarDemon(DimensionWeightedSumEqVar *const dim, int index) : dim_(dim), index_(index) {} ~VarDemon() override {} void Run(Solver *const s) override { dim_->PushFromTop(index_); } - private: + private: DimensionWeightedSumEqVar *const dim_; const int index_; }; @@ -864,11 +873,15 @@ public: DimensionWeightedSumEqVar(Solver *const s, Pack *const p, const std::vector &weights, const std::vector &loads) - : Dimension(s, p), vars_count_(weights.size()), weights_(weights), - bins_count_(loads.size()), loads_(loads), + : Dimension(s, p), + vars_count_(weights.size()), + weights_(weights), + bins_count_(loads.size()), + loads_(loads), first_unbound_backward_vector_(bins_count_, 0), sum_of_bound_variables_vector_(bins_count_, 0LL), - sum_of_all_variables_vector_(bins_count_, 0LL), ranked_(vars_count_) { + sum_of_all_variables_vector_(bins_count_, 0LL), + ranked_(vars_count_) { DCHECK_GT(vars_count_, 0); DCHECK_GT(bins_count_, 0); for (int i = 0; i < vars_count_; ++i) { @@ -966,7 +979,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension); } -private: + private: const int vars_count_; const std::vector weights_; const int bins_count_; @@ -978,16 +991,16 @@ private: }; class DimensionWeightedCallback2SumEqVar : public Dimension { -public: + public: class VarDemon : public Demon { - public: + public: VarDemon(DimensionWeightedCallback2SumEqVar *const dim, int index) : dim_(dim), index_(index) {} ~VarDemon() override {} void Run(Solver *const s) override { dim_->PushFromTop(index_); } - private: + private: DimensionWeightedCallback2SumEqVar *const dim_; const int index_; }; @@ -996,11 +1009,15 @@ public: const Solver::IndexEvaluator2 &weights, int vars_count, const std::vector &loads) - : Dimension(s, p), vars_count_(vars_count), weights_(weights), - bins_count_(loads.size()), loads_(loads), + : Dimension(s, p), + vars_count_(vars_count), + weights_(weights), + bins_count_(loads.size()), + loads_(loads), first_unbound_backward_vector_(bins_count_, 0), sum_of_bound_variables_vector_(bins_count_, 0LL), - sum_of_all_variables_vector_(bins_count_, 0LL), ranked_(bins_count_) { + sum_of_all_variables_vector_(bins_count_, 0LL), + ranked_(bins_count_) { DCHECK(weights); DCHECK_GT(vars_count_, 0); DCHECK_GT(bins_count_, 0); @@ -1104,7 +1121,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension); } -private: + private: const int vars_count_; Solver::IndexEvaluator2 weights_; const int bins_count_; @@ -1116,25 +1133,30 @@ private: }; class AssignedWeightedSumDimension : public Dimension { -public: + public: class VarDemon : public Demon { - public: + public: explicit VarDemon(AssignedWeightedSumDimension *const dim) : dim_(dim) {} ~VarDemon() override {} void Run(Solver *const s) override { dim_->PropagateAll(); } - private: + private: AssignedWeightedSumDimension *const dim_; }; AssignedWeightedSumDimension(Solver *const s, Pack *const p, const std::vector &weights, int bins_count, IntVar *const cost_var) - : Dimension(s, p), vars_count_(weights.size()), weights_(weights), - bins_count_(bins_count), cost_var_(cost_var), - first_unbound_backward_(0), sum_of_assigned_items_(0LL), - sum_of_unassigned_items_(0LL), ranked_(vars_count_), + : Dimension(s, p), + vars_count_(weights.size()), + weights_(weights), + bins_count_(bins_count), + cost_var_(cost_var), + first_unbound_backward_(0), + sum_of_assigned_items_(0LL), + sum_of_unassigned_items_(0LL), + ranked_(vars_count_), sum_all_weights_(0LL) { DCHECK(cost_var); DCHECK_GT(vars_count_, 0); @@ -1225,7 +1247,7 @@ public: ModelVisitor::kWeightedSumOfAssignedEqualVariableExtension); } -private: + private: const int vars_count_; const std::vector weights_; const int bins_count_; @@ -1240,22 +1262,26 @@ private: // ----- Count unassigned jobs dimension ----- class CountAssignedItemsDimension : public Dimension { -public: + public: class VarDemon : public Demon { - public: + public: explicit VarDemon(CountAssignedItemsDimension *const dim) : dim_(dim) {} ~VarDemon() override {} void Run(Solver *const s) override { dim_->PropagateAll(); } - private: + private: CountAssignedItemsDimension *const dim_; }; CountAssignedItemsDimension(Solver *const s, Pack *const p, int vars_count, int bins_count, IntVar *const cost_var) - : Dimension(s, p), vars_count_(vars_count), bins_count_(bins_count), - cost_var_(cost_var), first_unbound_backward_(0), assigned_count_(0), + : Dimension(s, p), + vars_count_(vars_count), + bins_count_(bins_count), + cost_var_(cost_var), + first_unbound_backward_(0), + assigned_count_(0), unassigned_count_(0) { DCHECK(cost_var); DCHECK_GT(vars_count, 0); @@ -1310,7 +1336,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kCountAssignedItemsExtension); } -private: + private: const int vars_count_; const int bins_count_; IntVar *const cost_var_; @@ -1322,23 +1348,30 @@ private: // ----- Count used bin dimension ----- class CountUsedBinDimension : public Dimension { -public: + public: class VarDemon : public Demon { - public: + public: explicit VarDemon(CountUsedBinDimension *const dim) : dim_(dim) {} ~VarDemon() override {} void Run(Solver *const s) override { dim_->PropagateAll(); } - private: + private: CountUsedBinDimension *const dim_; }; CountUsedBinDimension(Solver *const s, Pack *const p, int vars_count, int bins_count, IntVar *const count_var) - : Dimension(s, p), vars_count_(vars_count), bins_count_(bins_count), - count_var_(count_var), used_(bins_count_), candidates_(bins_count_, 0), - card_min_(0), card_max_(bins_count_), initial_min_(0), initial_max_(0) { + : Dimension(s, p), + vars_count_(vars_count), + bins_count_(bins_count), + count_var_(count_var), + used_(bins_count_), + candidates_(bins_count_, 0), + card_min_(0), + card_max_(bins_count_), + initial_min_(0), + initial_max_(0) { DCHECK(count_var); DCHECK_GT(vars_count, 0); DCHECK_GT(bins_count, 0); @@ -1420,7 +1453,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kCountUsedBinsExtension); } -private: + private: const int vars_count_; const int bins_count_; IntVar *const count_var_; @@ -1436,7 +1469,7 @@ private: // This is a very naive, but correct implementation of the constraint. class VariableUsageDimension : public Dimension { -public: + public: VariableUsageDimension(Solver *const solver, Pack *const pack, const std::vector &capacities, const std::vector &weights) @@ -1484,11 +1517,11 @@ public: ModelVisitor::kVariableUsageLessConstantExtension); } -private: + private: const std::vector capacities_; const std::vector weights_; }; -} // namespace +} // namespace // ---------- API ---------- @@ -1578,4 +1611,4 @@ void Pack::AddCountAssignedItemsDimension(IntVar *const count_var) { Pack *Solver::MakePack(const std::vector &vars, int number_of_bins) { return RevAlloc(new Pack(this, vars, number_of_bins)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/python/pywrapcp_util.h b/ortools/constraint_solver/python/pywrapcp_util.h index 783020bcfb..78454a0e8b 100644 --- a/ortools/constraint_solver/python/pywrapcp_util.h +++ b/ortools/constraint_solver/python/pywrapcp_util.h @@ -92,5 +92,4 @@ class CallPyDecisionBuilder : public operations_research::DecisionBuilder { PyObject* str_func_; }; - #endif // OR_TOOLS_CONSTRAINT_SOLVER_PYTHON_PYWRAPCP_UTIL_H_ diff --git a/ortools/constraint_solver/range_cst.cc b/ortools/constraint_solver/range_cst.cc index dd465db593..03970e977f 100644 --- a/ortools/constraint_solver/range_cst.cc +++ b/ortools/constraint_solver/range_cst.cc @@ -30,7 +30,7 @@ namespace operations_research { namespace { class RangeEquality : public Constraint { -public: + public: RangeEquality(Solver *const s, IntExpr *const l, IntExpr *const r) : Constraint(s), left_(l), right_(r) {} @@ -61,7 +61,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kEquality, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; }; @@ -70,7 +70,7 @@ private: // RangeLessOrEqual class RangeLessOrEqual : public Constraint { -public: + public: RangeLessOrEqual(Solver *const s, IntExpr *const l, IntExpr *const r); ~RangeLessOrEqual() override {} void Post() override; @@ -87,7 +87,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *demon_; @@ -119,7 +119,7 @@ std::string RangeLessOrEqual::DebugString() const { // RangeLess class RangeLess : public Constraint { -public: + public: RangeLess(Solver *const s, IntExpr *const l, IntExpr *const r); ~RangeLess() override {} void Post() override; @@ -134,7 +134,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLess, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *demon_; @@ -165,7 +165,7 @@ std::string RangeLess::DebugString() const { // DiffVar class DiffVar : public Constraint { -public: + public: DiffVar(Solver *const s, IntVar *const l, IntVar *const r); ~DiffVar() override {} void Post() override; @@ -183,7 +183,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this); } -private: + private: IntVar *const left_; IntVar *const right_; }; @@ -203,7 +203,7 @@ void DiffVar::Post() { void DiffVar::LeftBound() { if (right_->Size() < 0xFFFFFF) { - right_->RemoveValue(left_->Min()); // we use min instead of value + right_->RemoveValue(left_->Min()); // we use min instead of value } else { solver()->AddConstraint(solver()->MakeNonEquality(right_, left_->Min())); } @@ -211,7 +211,7 @@ void DiffVar::LeftBound() { void DiffVar::RightBound() { if (left_->Size() < 0xFFFFFF) { - left_->RemoveValue(right_->Min()); // see above + left_->RemoveValue(right_->Min()); // see above } else { solver()->AddConstraint(solver()->MakeNonEquality(left_, right_->Min())); } @@ -238,7 +238,7 @@ std::string DiffVar::DebugString() const { // IsEqualCt class IsEqualCt : public CastConstraint { -public: + public: IsEqualCt(Solver *const s, IntExpr *const l, IntExpr *const r, IntVar *const b) : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {} @@ -295,7 +295,7 @@ public: solver()->MakeNonEquality(left_, right_->Min())); } } - } else { // Var is true. + } else { // Var is true. left_->SetRange(right_->Min(), right_->Max()); right_->SetRange(left_->Min(), left_->Max()); } @@ -316,7 +316,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *range_demon_; @@ -325,7 +325,7 @@ private: // IsDifferentCt class IsDifferentCt : public CastConstraint { -public: + public: IsDifferentCt(Solver *const s, IntExpr *const l, IntExpr *const r, IntVar *const b) : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {} @@ -367,7 +367,7 @@ public: if (target_var_->Min() == 0) { left_->SetRange(right_->Min(), right_->Max()); right_->SetRange(left_->Min(), left_->Max()); - } else { // Var is true. + } else { // Var is true. if (left_->Bound()) { range_demon_->inhibit(solver()); solver()->AddConstraint( @@ -395,14 +395,14 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *range_demon_; }; class IsLessOrEqualCt : public CastConstraint { -public: + public: IsLessOrEqualCt(Solver *const s, IntExpr *const l, IntExpr *const r, IntVar *const b) : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {} @@ -421,7 +421,7 @@ public: if (target_var_->Min() == 0) { right_->SetMax(left_->Max() - 1); left_->SetMin(right_->Min() + 1); - } else { // Var is true. + } else { // Var is true. right_->SetMin(left_->Min()); left_->SetMax(right_->Max()); } @@ -449,14 +449,14 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsLessOrEqual, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *demon_; }; class IsLessCt : public CastConstraint { -public: + public: IsLessCt(Solver *const s, IntExpr *const l, IntExpr *const r, IntVar *const b) : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {} @@ -474,7 +474,7 @@ public: if (target_var_->Min() == 0) { right_->SetMax(left_->Max()); left_->SetMin(right_->Min()); - } else { // Var is true. + } else { // Var is true. right_->SetMin(left_->Min() + 1); left_->SetMax(right_->Max() - 1); } @@ -502,12 +502,12 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIsLess, this); } -private: + private: IntExpr *const left_; IntExpr *const right_; Demon *demon_; }; -} // namespace +} // namespace Constraint *Solver::MakeEquality(IntExpr *const l, IntExpr *const r) { CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast"; @@ -802,4 +802,4 @@ Constraint *Solver::MakeIsGreaterCt(IntExpr *const left, IntExpr *const right, return MakeIsLessCt(right, left, b); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/resource.cc b/ortools/constraint_solver/resource.cc index faad6a8ba9..3e714caa80 100644 --- a/ortools/constraint_solver/resource.cc +++ b/ortools/constraint_solver/resource.cc @@ -50,7 +50,8 @@ namespace { // TODO(user): Tie breaking. // Comparison methods, used by the STL sort. -template bool StartMinLessThan(Task *const w1, Task *const w2) { +template +bool StartMinLessThan(Task *const w1, Task *const w2) { return (w1->interval->StartMin() < w2->interval->StartMin()); } @@ -63,15 +64,18 @@ bool ShortestDurationStartMinLessThan(Task *const w1, Task *const w2) { w2->interval->EndMin() - w2->interval->DurationMin(); } -template bool StartMaxLessThan(Task *const w1, Task *const w2) { +template +bool StartMaxLessThan(Task *const w1, Task *const w2) { return (w1->interval->StartMax() < w2->interval->StartMax()); } -template bool EndMinLessThan(Task *const w1, Task *const w2) { +template +bool EndMinLessThan(Task *const w1, Task *const w2) { return (w1->interval->EndMin() < w2->interval->EndMin()); } -template bool EndMaxLessThan(Task *const w1, Task *const w2) { +template +bool EndMaxLessThan(Task *const w1, Task *const w2) { return (w1->interval->EndMax() < w2->interval->EndMax()); } @@ -184,8 +188,8 @@ struct ThetaNode { } std::string DebugString() const { - return absl::StrCat("ThetaNode{ p = ", total_processing, ", e = ", - total_ect < 0LL ? -1LL : total_ect, " }"); + return absl::StrCat("ThetaNode{ p = ", total_processing, + ", e = ", total_ect < 0LL ? -1LL : total_ect, " }"); } int64 total_processing; @@ -200,7 +204,7 @@ struct ThetaNode { // Max_{subset S of the set of contained intervals} ( // Min_{i in S}(i.StartMin) + Sum_{i in S}(i.DurationMin) ) class ThetaTree : public MonoidOperationTree { -public: + public: explicit ThetaTree(int size) : MonoidOperationTree(size) {} int64 Ect() const { return result().total_ect; } @@ -228,21 +232,27 @@ struct LambdaThetaNode { // Identity constructor LambdaThetaNode() - : energy(0LL), energetic_end_min(kint64min), energy_opt(0LL), - argmax_energy_opt(kNone), energetic_end_min_opt(kint64min), + : energy(0LL), + energetic_end_min(kint64min), + energy_opt(0LL), + argmax_energy_opt(kNone), + energetic_end_min_opt(kint64min), argmax_energetic_end_min_opt(kNone) {} // Constructor for a single cumulative task in the Theta set LambdaThetaNode(int64 capacity, const CumulativeTask &task) : energy(task.EnergyMin()), energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)), - energy_opt(energy), argmax_energy_opt(kNone), + energy_opt(energy), + argmax_energy_opt(kNone), energetic_end_min_opt(energetic_end_min), argmax_energetic_end_min_opt(kNone) {} // Constructor for a single cumulative task in the Lambda set LambdaThetaNode(int64 capacity, const CumulativeTask &task, int index) - : energy(0LL), energetic_end_min(kint64min), energy_opt(task.EnergyMin()), + : energy(0LL), + energetic_end_min(kint64min), + energy_opt(task.EnergyMin()), argmax_energy_opt(index), energetic_end_min_opt(capacity * task.interval->StartMin() + energy_opt), @@ -254,13 +264,16 @@ struct LambdaThetaNode { LambdaThetaNode(int64 capacity, const VariableCumulativeTask &task) : energy(task.EnergyMin()), energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)), - energy_opt(energy), argmax_energy_opt(kNone), + energy_opt(energy), + argmax_energy_opt(kNone), energetic_end_min_opt(energetic_end_min), argmax_energetic_end_min_opt(kNone) {} // Constructor for a single cumulative task in the Lambda set LambdaThetaNode(int64 capacity, const VariableCumulativeTask &task, int index) - : energy(0LL), energetic_end_min(kint64min), energy_opt(task.EnergyMin()), + : energy(0LL), + energetic_end_min(kint64min), + energy_opt(task.EnergyMin()), argmax_energy_opt(index), energetic_end_min_opt(capacity * task.interval->StartMin() + energy_opt), @@ -270,16 +283,20 @@ struct LambdaThetaNode { // Constructor for a single interval in the Theta set explicit LambdaThetaNode(const IntervalVar *const interval) - : energy(interval->DurationMin()), energetic_end_min(interval->EndMin()), - energy_opt(interval->DurationMin()), argmax_energy_opt(kNone), + : energy(interval->DurationMin()), + energetic_end_min(interval->EndMin()), + energy_opt(interval->DurationMin()), + argmax_energy_opt(kNone), energetic_end_min_opt(interval->EndMin()), argmax_energetic_end_min_opt(kNone) {} // Constructor for a single interval in the Lambda set // 'index' is the index of the given interval in the est vector LambdaThetaNode(const IntervalVar *const interval, int index) - : energy(0LL), energetic_end_min(kint64min), - energy_opt(interval->DurationMin()), argmax_energy_opt(index), + : energy(0LL), + energetic_end_min(kint64min), + energy_opt(interval->DurationMin()), + argmax_energy_opt(index), energetic_end_min_opt(interval->EndMin()), argmax_energetic_end_min_opt(index) { DCHECK_GE(index, 0); @@ -308,13 +325,13 @@ struct LambdaThetaNode { const int64 ect1 = right.energetic_end_min_opt; const int64 ect2 = CapAdd(left.energetic_end_min, right.energy_opt); const int64 ect3 = CapAdd(left.energetic_end_min_opt, right.energy); - if (ect1 >= ect2 && ect1 >= ect3) { // ect1 max + if (ect1 >= ect2 && ect1 >= ect3) { // ect1 max energetic_end_min_opt = ect1; argmax_energetic_end_min_opt = right.argmax_energetic_end_min_opt; - } else if (ect2 >= ect1 && ect2 >= ect3) { // ect2 max + } else if (ect2 >= ect1 && ect2 >= ect3) { // ect2 max energetic_end_min_opt = ect2; argmax_energetic_end_min_opt = right.argmax_energy_opt; - } else { // ect3 max + } else { // ect3 max energetic_end_min_opt = ect3; argmax_energetic_end_min_opt = left.argmax_energetic_end_min_opt; } @@ -354,7 +371,7 @@ const int LambdaThetaNode::kNone = -1; // Disjunctive Lambda-Theta tree class DisjunctiveLambdaThetaTree : public MonoidOperationTree { -public: + public: explicit DisjunctiveLambdaThetaTree(int size) : MonoidOperationTree(size) {} @@ -374,7 +391,7 @@ public: // A cumulative lambda-theta tree class CumulativeLambdaThetaTree : public MonoidOperationTree { -public: + public: CumulativeLambdaThetaTree(int size, int64 capacity_max) : MonoidOperationTree(size), capacity_max_(capacity_max) {} @@ -414,7 +431,7 @@ public: return result().argmax_energetic_end_min_opt; } -private: + private: int64 capacity_max_; }; @@ -423,7 +440,7 @@ private: // A class that implements the 'Not-Last' propagation algorithm for the unary // resource constraint. class NotLast { -public: + public: NotLast(Solver *const solver, const std::vector &intervals, bool mirror, bool strict); @@ -431,7 +448,7 @@ public: bool Propagate(); -private: + private: ThetaTree theta_tree_; std::vector by_start_min_; std::vector by_end_max_; @@ -443,9 +460,12 @@ private: NotLast::NotLast(Solver *const solver, const std::vector &intervals, bool mirror, bool strict) - : theta_tree_(intervals.size()), by_start_min_(intervals.size()), - by_end_max_(intervals.size()), by_start_max_(intervals.size()), - new_lct_(intervals.size(), -1LL), strict_(strict) { + : theta_tree_(intervals.size()), + by_start_min_(intervals.size()), + by_end_max_(intervals.size()), + by_start_max_(intervals.size()), + new_lct_(intervals.size(), -1LL), + strict_(strict) { // Populate the different vectors. for (int i = 0; i < intervals.size(); ++i) { IntervalVar *const underlying = @@ -520,7 +540,7 @@ bool NotLast::Propagate() { // detectable precedences. These algorithms both push intervals to the right, // which is why they are grouped together. class EdgeFinderAndDetectablePrecedences { -public: + public: EdgeFinderAndDetectablePrecedences( Solver *const solver, const std::vector &intervals, bool mirror, bool strict); @@ -534,7 +554,7 @@ public: bool DetectablePrecedences(); bool EdgeFinder(); -private: + private: Solver *const solver_; // --- All the following member variables are essentially used as local ones: @@ -562,8 +582,10 @@ private: EdgeFinderAndDetectablePrecedences::EdgeFinderAndDetectablePrecedences( Solver *const solver, const std::vector &intervals, bool mirror, bool strict) - : solver_(solver), theta_tree_(intervals.size()), - lt_tree_(intervals.size()), strict_(strict) { + : solver_(solver), + theta_tree_(intervals.size()), + lt_tree_(intervals.size()), + strict_(strict) { // Populate of the array of intervals for (IntervalVar *const interval : intervals) { IntervalVar *const underlying = @@ -619,8 +641,7 @@ bool EdgeFinderAndDetectablePrecedences::DetectablePrecedences() { while (task_i->interval->EndMin() > task_j->interval->StartMax()) { theta_tree_.Insert(task_j); j++; - if (j == size()) - break; + if (j == size()) break; task_j = by_start_max_[j]; } } @@ -699,13 +720,16 @@ bool EdgeFinderAndDetectablePrecedences::EdgeFinder() { // ----- Propagation on ranked activities ----- class RankedPropagator : public Constraint { -public: + public: RankedPropagator(Solver *const solver, const std::vector &nexts, const std::vector &intervals, const std::vector &slacks, DisjunctiveConstraint *const disjunctive) - : Constraint(solver), nexts_(nexts), intervals_(intervals), - slacks_(slacks), disjunctive_(disjunctive), + : Constraint(solver), + nexts_(nexts), + intervals_(intervals), + slacks_(slacks), + disjunctive_(disjunctive), partial_sequence_(intervals.size()), previous_(intervals.size() + 2, 0) {} @@ -798,9 +822,9 @@ public: first_sentinel > 0 ? RankedInterval(first_sentinel - 1) : nullptr; IntVar *const first_slack = first_sentinel > 0 ? RankedSlack(first_sentinel - 1) : nullptr; - IntervalVar *const last_interval = - last_sentinel < last_position ? RankedInterval(last_sentinel + 1) - : nullptr; + IntervalVar *const last_interval = last_sentinel < last_position + ? RankedInterval(last_sentinel + 1) + : nullptr; // Nothing to do afterwards, exiting. if (first_interval == nullptr && last_interval == nullptr) { @@ -901,7 +925,7 @@ public: // TODO(user): IMPLEMENT ME. } -private: + private: std::vector nexts_; std::vector intervals_; std::vector slacks_; @@ -914,15 +938,17 @@ private: // calls them until a fixpoint is reached. class FullDisjunctiveConstraint : public DisjunctiveConstraint { -public: + public: FullDisjunctiveConstraint(Solver *const s, const std::vector &intervals, const std::string &name, bool strict) - : DisjunctiveConstraint(s, intervals, name), sequence_var_(nullptr), + : DisjunctiveConstraint(s, intervals, name), + sequence_var_(nullptr), straight_(s, intervals, false, strict), mirror_(s, intervals, true, strict), straight_not_last_(s, intervals, false, strict), - mirror_not_last_(s, intervals, true, strict), strict_(strict) {} + mirror_not_last_(s, intervals, true, strict), + strict_(strict) {} ~FullDisjunctiveConstraint() override {} @@ -943,7 +969,7 @@ public: break; } } - if (all_optional_or_unperformed) { // Nothing to deduce + if (all_optional_or_unperformed) { // Nothing to deduce return; } @@ -990,8 +1016,7 @@ public: } } // Checks feasibility of performed; - if (performed_.empty()) - return; + if (performed_.empty()) return; std::sort(performed_.begin(), performed_.end(), IntervalStartMinLessThan); for (int i = 0; i < performed_.size() - 1; ++i) { if (performed_[i]->EndMax() > performed_[i + 1]->StartMin()) { @@ -1000,8 +1025,7 @@ public: } // Checks if optional intervals can be inserted. - if (optional_.empty()) - return; + if (optional_.empty()) return; int index = 0; const int num_performed = performed_.size(); std::sort(optional_.begin(), optional_.end(), IntervalStartMinLessThan); @@ -1010,8 +1034,7 @@ public: while (index < num_performed && start >= performed_[index]->EndMax()) { index++; } - if (index == num_performed) - return; + if (index == num_performed) return; if (Intersect(candidate, performed_[index]) || (index < num_performed - 1 && Intersect(candidate, performed_[index + 1]))) { @@ -1058,7 +1081,7 @@ public: return time_slacks_; } -private: + private: int64 Distance(int64 activity_plus_one, int64 next_activity_plus_one) { return (activity_plus_one == 0 || next_activity_plus_one > intervals_.size()) @@ -1128,10 +1151,9 @@ private: } // TODO(user): Find a better UB for the last time cumul. time_cumuls_[num_nodes] = s->MakeIntVar(0, 2 * horizon, ct_name + "_ect"); - s->AddConstraint(s->MakePathCumul(nexts_, actives_, time_cumuls_, - time_slacks_, [this](int64 x, int64 y) { - return Distance(x, y); - })); + s->AddConstraint( + s->MakePathCumul(nexts_, actives_, time_cumuls_, time_slacks_, + [this](int64 x, int64 y) { return Distance(x, y); })); std::vector short_slacks(time_slacks_.begin() + 1, time_slacks_.end()); @@ -1166,7 +1188,8 @@ struct DualCapacityThetaNode { // Identity constructor DualCapacityThetaNode() - : energy(0LL), energetic_end_min(kint64min), + : energy(0LL), + energetic_end_min(kint64min), residual_energetic_end_min(kint64min) {} // Constructor for a single cumulative task in the Theta set. @@ -1174,18 +1197,16 @@ struct DualCapacityThetaNode { const CumulativeTask &task) : energy(task.EnergyMin()), energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)), - residual_energetic_end_min(CapAdd(residual_capacity * - task.interval->StartMin(), - energy)) {} + residual_energetic_end_min( + CapAdd(residual_capacity * task.interval->StartMin(), energy)) {} // Constructor for a single variable cumulative task in the Theta set. DualCapacityThetaNode(int64 capacity, int64 residual_capacity, const VariableCumulativeTask &task) : energy(task.EnergyMin()), energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)), - residual_energetic_end_min(CapAdd(residual_capacity * - task.interval->StartMin(), - energy)) {} + residual_energetic_end_min( + CapAdd(residual_capacity * task.interval->StartMin(), energy)) {} // Sets this DualCapacityThetaNode to the result of the natural binary // operation over the two given operands, corresponding to the following set @@ -1219,11 +1240,12 @@ const int DualCapacityThetaNode::kNone = -1; // A tree for dual capacity theta nodes class DualCapacityThetaTree : public MonoidOperationTree { -public: + public: static const int64 kNotInitialized; explicit DualCapacityThetaTree(int size) - : MonoidOperationTree(size), capacity_max_(-1), + : MonoidOperationTree(size), + capacity_max_(-1), residual_capacity_(-1) {} virtual ~DualCapacityThetaTree() {} @@ -1246,7 +1268,7 @@ public: DualCapacityThetaNode(capacity_max_, residual_capacity_, *task)); } -private: + private: int64 capacity_max_; int64 residual_capacity_; DISALLOW_COPY_AND_ASSIGN(DualCapacityThetaTree); @@ -1265,10 +1287,11 @@ const int64 DualCapacityThetaTree::kNotInitialized = -1LL; // Note: use the version pointed to by this pointer, not the version from the // conference proceedings, which has a few errors. class EnvJCComputeDiver { -public: + public: static const int64 kNotAvailable; explicit EnvJCComputeDiver(int energy_threshold) - : energy_threshold_(energy_threshold), energy_alpha_(kNotAvailable), + : energy_threshold_(energy_threshold), + energy_alpha_(kNotAvailable), energetic_end_min_alpha_(kNotAvailable) {} void OnArgumentReached(int index, const DualCapacityThetaNode &argument) { energy_alpha_ = argument.energy; @@ -1281,7 +1304,7 @@ public: const DualCapacityThetaNode &left_child, const DualCapacityThetaNode &right_child) { if (right_child.residual_energetic_end_min > energy_threshold_) { - return false; // enough energy on right + return false; // enough energy on right } else { energy_threshold_ -= right_child.energy; return true; @@ -1311,7 +1334,7 @@ public: return CapAdd(energetic_end_min_alpha_, energy_beta); } -private: + private: // Energy threshold such that if a set has an energetic_end_min greater than // the threshold, then it can push tasks that must end at or after the // currently considered end max. @@ -1341,7 +1364,7 @@ const int64 EnvJCComputeDiver::kNotAvailable = -1LL; // Collection of all updates (i.e., potential new start mins) for a given value // of the demand. class UpdatesForADemand { -public: + public: explicit UpdatesForADemand(int size) : updates_(size, 0), up_to_date_(false) {} @@ -1355,21 +1378,27 @@ public: bool up_to_date() const { return up_to_date_; } void set_up_to_date() { up_to_date_ = true; } -private: + private: std::vector updates_; bool up_to_date_; DISALLOW_COPY_AND_ASSIGN(UpdatesForADemand); }; // One-sided cumulative edge finder. -template class EdgeFinder : public Constraint { -public: +template +class EdgeFinder : public Constraint { + public: EdgeFinder(Solver *const solver, const std::vector &tasks, IntVar *const capacity) - : Constraint(solver), capacity_(capacity), tasks_(tasks), - by_start_min_(tasks.size()), by_end_max_(tasks.size()), - by_end_min_(tasks.size()), lt_tree_(tasks.size(), capacity_->Max()), - dual_capacity_tree_(tasks.size()), has_zero_demand_tasks_(true) {} + : Constraint(solver), + capacity_(capacity), + tasks_(tasks), + by_start_min_(tasks.size()), + by_end_max_(tasks.size()), + by_end_min_(tasks.size()), + lt_tree_(tasks.size(), capacity_->Max()), + dual_capacity_tree_(tasks.size()), + has_zero_demand_tasks_(true) {} ~EdgeFinder() override { gtl::STLDeleteElements(&tasks_); @@ -1404,7 +1433,7 @@ public: std::string DebugString() const override { return "EdgeFinder"; } -private: + private: UpdatesForADemand *GetOrMakeUpdate(int64 demand_min) { UpdatesForADemand *update = gtl::FindPtrOrNull(update_map_, demand_min); if (update == nullptr) { @@ -1475,8 +1504,7 @@ private: int64 update = IntervalVar::kMinValidValue; for (int i = 0; i < by_end_max_.size(); ++i) { Task *const task = by_end_max_[i]; - if (task->EnergyMin() == 0) - continue; + if (task->EnergyMin() == 0) continue; const int64 current_end_max = task->interval->EndMax(); dual_capacity_tree_.Insert(task); const int64 energy_threshold = residual_capacity * current_end_max; @@ -1672,8 +1700,9 @@ bool TimeLessThan(const ProfileDelta &delta1, const ProfileDelta &delta2) { // // The implementation is quite naive, and could certainly be improved, for // example by maintaining the profile incrementally. -template class CumulativeTimeTable : public Constraint { -public: +template +class CumulativeTimeTable : public Constraint { + public: CumulativeTimeTable(Solver *const solver, const std::vector &tasks, IntVar *const capacity) : Constraint(solver), by_start_min_(tasks), capacity_(capacity) { @@ -1709,7 +1738,7 @@ public: std::string DebugString() const override { return "CumulativeTimeTable"; } -private: + private: // Build the usage profile. Runs in O(n log n). void BuildProfile() { // Build profile with non unique time @@ -1787,7 +1816,7 @@ private: // Init const IntervalVar *const interval = task->interval; const int64 demand_min = task->DemandMin(); - if (demand_min == 0) { // Demand can be null, nothing to propagate. + if (demand_min == 0) { // Demand can be null, nothing to propagate. return; } const int64 residual_capacity = CapSub(capacity_->Max(), demand_min); @@ -1865,8 +1894,9 @@ private: // Worst case: O(n^2 log n) -- really unlikely in practice. // Best case: Omega(1). // Practical: Almost linear in the number of unfixed tasks. -template class TimeTableSync : public Constraint { -public: +template +class TimeTableSync : public Constraint { + public: TimeTableSync(Solver *const solver, const std::vector &tasks, IntVar *const capacity) : Constraint(solver), tasks_(tasks), capacity_(capacity) { @@ -1920,14 +1950,9 @@ public: std::string DebugString() const override { return "TimeTableSync"; } -private: + private: // Task state. - enum State { - NONE, - READY, - CHECK, - CONFLICT - }; + enum State { NONE, READY, CHECK, CONFLICT }; inline int64 NextScpTime() { return !events_scp_.empty() ? events_scp_.top().first : kint64max; @@ -2040,7 +2065,7 @@ private: start_min_[task_id] = pos_; end_min_[task_id] = pos_ + durations_[task_id]; // Filter the domain. - tasks_[task_id]->interval->SetStartMin(pos_); // should not fail. + tasks_[task_id]->interval->SetStartMin(pos_); // should not fail. // The task still have to be checked. if (next_pos_ < end_min_[task_id]) { states_[task_id] = State::CHECK; @@ -2138,12 +2163,14 @@ private: }; class CumulativeConstraint : public Constraint { -public: + public: CumulativeConstraint(Solver *const s, const std::vector &intervals, const std::vector &demands, IntVar *const capacity, const std::string &name) - : Constraint(s), capacity_(capacity), intervals_(intervals), + : Constraint(s), + capacity_(capacity), + intervals_(intervals), demands_(demands) { tasks_.reserve(intervals.size()); for (int i = 0; i < intervals.size(); ++i) { @@ -2199,7 +2226,7 @@ public: capacity_->DebugString()); } -private: + private: // Post temporal disjunctions for tasks that cannot overlap. void PostAllDisjunctions() { for (int i = 0; i < intervals_.size(); ++i) { @@ -2223,7 +2250,7 @@ private: // of the resource void PostHighDemandSequenceConstraint() { Constraint *constraint = nullptr; - { // Need a block to avoid memory leaks in case the AddConstraint fails + { // Need a block to avoid memory leaks in case the AddConstraint fails std::vector high_demand_intervals; high_demand_intervals.reserve(intervals_.size()); for (int i = 0; i < demands_.size(); ++i) { @@ -2254,9 +2281,8 @@ private: // Populate the given vector with useful tasks, meaning the ones on which // some propagation can be done - void - PopulateVectorUsefulTasks(bool mirror, - std::vector *const useful_tasks) { + void PopulateVectorUsefulTasks( + bool mirror, std::vector *const useful_tasks) { DCHECK(useful_tasks->empty()); for (int i = 0; i < tasks_.size(); ++i) { const CumulativeTask &original_task = tasks_[i]; @@ -2330,12 +2356,14 @@ private: }; class VariableDemandCumulativeConstraint : public Constraint { -public: + public: VariableDemandCumulativeConstraint( Solver *const s, const std::vector &intervals, const std::vector &demands, IntVar *const capacity, const std::string &name) - : Constraint(s), capacity_(capacity), intervals_(intervals), + : Constraint(s), + capacity_(capacity), + intervals_(intervals), demands_(demands) { tasks_.reserve(intervals.size()); for (int i = 0; i < intervals.size(); ++i) { @@ -2386,7 +2414,7 @@ public: capacity_->DebugString()); } -private: + private: // Post temporal disjunctions for tasks that cannot overlap. void PostAllDisjunctions() { for (int i = 0; i < intervals_.size(); ++i) { @@ -2411,7 +2439,7 @@ private: // of the resource void PostHighDemandSequenceConstraint() { Constraint *constraint = nullptr; - { // Need a block to avoid memory leaks in case the AddConstraint fails + { // Need a block to avoid memory leaks in case the AddConstraint fails std::vector high_demand_intervals; high_demand_intervals.reserve(intervals_.size()); for (int i = 0; i < demands_.size(); ++i) { @@ -2513,7 +2541,7 @@ private: DISALLOW_COPY_AND_ASSIGN(VariableDemandCumulativeConstraint); }; -} // namespace +} // namespace // Sequence Constraint @@ -2526,8 +2554,7 @@ DisjunctiveConstraint::DisjunctiveConstraint( if (!name.empty()) { set_name(name); } - transition_time_ = [](int64 x, int64 y) { return 0; } - ; + transition_time_ = [](int64 x, int64 y) { return 0; }; } DisjunctiveConstraint::~DisjunctiveConstraint() {} @@ -2537,16 +2564,14 @@ void DisjunctiveConstraint::SetTransitionTime( if (transition_time != nullptr) { transition_time_ = transition_time; } else { - transition_time_ = [](int64 x, int64 y) { return 0; } - ; + transition_time_ = [](int64 x, int64 y) { return 0; }; } } // ---------- Factory methods ---------- -DisjunctiveConstraint * -Solver::MakeDisjunctiveConstraint(const std::vector &intervals, - const std::string &name) { +DisjunctiveConstraint *Solver::MakeDisjunctiveConstraint( + const std::vector &intervals, const std::string &name) { return RevAlloc(new FullDisjunctiveConstraint(this, intervals, name, false)); } @@ -2634,4 +2659,4 @@ Constraint *Solver::MakeCumulative(const std::vector &intervals, return RevAlloc(new VariableDemandCumulativeConstraint( this, intervals, demands, capacity, name)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing.cc b/ortools/constraint_solver/routing.cc index 13d6460a06..b980328d43 100644 --- a/ortools/constraint_solver/routing.cc +++ b/ortools/constraint_solver/routing.cc @@ -61,7 +61,7 @@ namespace operations_research { class LocalSearchPhaseParameters; -} // namespace operations_research +} // namespace operations_research DEFINE_int64(sweep_sectors, 1, "The number of sectors the space is divided before it is sweeped " @@ -79,11 +79,13 @@ namespace { // possible to target values first. // TODO(user): Move to CP solver. class SetValuesFromTargets : public DecisionBuilder { -public: + public: SetValuesFromTargets(std::vector variables, std::vector targets) - : variables_(std::move(variables)), targets_(std::move(targets)), - index_(0), steps_(variables_.size(), 0) { + : variables_(std::move(variables)), + targets_(std::move(targets)), + index_(0), + steps_(variables_.size(), 0) { DCHECK_EQ(variables_.size(), targets_.size()); } Decision *Next(Solver *const solver) override { @@ -92,8 +94,7 @@ public: ++index; } index_.SetValue(solver, index); - if (index >= variables_.size()) - return nullptr; + if (index >= variables_.size()) return nullptr; const int64 variable_min = variables_[index]->Min(); const int64 variable_max = variables_[index]->Max(); // Target can be before, inside, or after the variable range. @@ -126,7 +127,7 @@ public: } } -private: + private: int64 GetNextStep(int64 step) const { return (step > 0) ? -step : CapSub(1, step); } @@ -136,7 +137,7 @@ private: RevArray steps_; }; -} // namespace +} // namespace DecisionBuilder *MakeSetValuesFromTargets(Solver *solver, std::vector variables, @@ -177,15 +178,16 @@ bool DimensionFixedTransitsEqualTransitEvaluators( } class SetCumulsFromLocalDimensionCosts : public DecisionBuilder { -public: + public: SetCumulsFromLocalDimensionCosts( - const std::vector > * - local_optimizers, - const std::vector > * - local_mp_optimizers, + const std::vector > + *local_optimizers, + const std::vector > + *local_mp_optimizers, SearchMonitor *monitor, bool optimize_and_pack = false) : local_optimizers_(*local_optimizers), - local_mp_optimizers_(*local_mp_optimizers), monitor_(monitor), + local_mp_optimizers_(*local_mp_optimizers), + monitor_(monitor), optimize_and_pack_(optimize_and_pack) {} Decision *Next(Solver *const solver) override { // The following boolean variable indicates if the solver should fail, in @@ -196,21 +198,19 @@ public: const auto &local_optimizer = local_optimizers_[i]; const RoutingDimension *const dimension = local_optimizer->dimension(); RoutingModel *const model = dimension->model(); - const auto next = [model](int64 i) { return model->NextVar(i)->Value(); } - ; + const auto next = [model](int64 i) { return model->NextVar(i)->Value(); }; const auto compute_cumul_values = - [this, &next](LocalDimensionCumulOptimizer * optimizer, int vehicle, - std::vector * cumul_values, - std::vector * break_start_end_values) { - if (optimize_and_pack_) { - return optimizer->ComputePackedRouteCumuls( - vehicle, next, cumul_values, break_start_end_values); - } else { - return optimizer->ComputeRouteCumuls(vehicle, next, cumul_values, - break_start_end_values); - } - } - ; + [this, &next](LocalDimensionCumulOptimizer *optimizer, int vehicle, + std::vector *cumul_values, + std::vector *break_start_end_values) { + if (optimize_and_pack_) { + return optimizer->ComputePackedRouteCumuls( + vehicle, next, cumul_values, break_start_end_values); + } else { + return optimizer->ComputeRouteCumuls(vehicle, next, cumul_values, + break_start_end_values); + } + }; for (int vehicle = 0; vehicle < model->vehicles(); ++vehicle) { // TODO(user): Investigate if we should skip unused vehicles. DCHECK(DimensionFixedTransitsEqualTransitEvaluatorForVehicle(*dimension, @@ -297,22 +297,23 @@ public: return nullptr; } -private: - const std::vector > & - local_optimizers_; - const std::vector > & - local_mp_optimizers_; + private: + const std::vector > + &local_optimizers_; + const std::vector > + &local_mp_optimizers_; SearchMonitor *const monitor_; const bool optimize_and_pack_; }; class SetCumulsFromGlobalDimensionCosts : public DecisionBuilder { -public: + public: SetCumulsFromGlobalDimensionCosts( - const std::vector > * - global_optimizers, + const std::vector > + *global_optimizers, SearchMonitor *monitor, bool optimize_and_pack = false) - : global_optimizers_(*global_optimizers), monitor_(monitor), + : global_optimizers_(*global_optimizers), + monitor_(monitor), optimize_and_pack_(optimize_and_pack) {} Decision *Next(Solver *const solver) override { // The following boolean variable indicates if the solver should fail, in @@ -323,8 +324,7 @@ public: const RoutingDimension *dimension = global_optimizer->dimension(); RoutingModel *const model = dimension->model(); - const auto next = [model](int64 i) { return model->NextVar(i)->Value(); } - ; + const auto next = [model](int64 i) { return model->NextVar(i)->Value(); }; DCHECK(DimensionFixedTransitsEqualTransitEvaluators(*dimension)); @@ -377,22 +377,20 @@ public: return nullptr; } -private: - const std::vector > & - global_optimizers_; + private: + const std::vector > + &global_optimizers_; SearchMonitor *const monitor_; const bool optimize_and_pack_; }; -} // namespace +} // namespace const Assignment *RoutingModel::PackCumulsOfOptimizerDimensionsFromAssignment( const Assignment *original_assignment, absl::Duration duration_limit) { CHECK(closed_); - if (original_assignment == nullptr) - return nullptr; - if (duration_limit <= absl::ZeroDuration()) - return original_assignment; + if (original_assignment == nullptr) return nullptr; + if (duration_limit <= absl::ZeroDuration()) return original_assignment; if (global_dimension_optimizers_.empty() && local_dimension_optimizers_.empty()) { DCHECK(local_dimension_mp_optimizers_.empty()); @@ -415,12 +413,12 @@ const Assignment *RoutingModel::PackCumulsOfOptimizerDimensionsFromAssignment( solver_->RevAlloc(new SetCumulsFromLocalDimensionCosts( &local_dimension_optimizers_, &local_dimension_mp_optimizers_, GetOrCreateLargeNeighborhoodSearchLimit(), - /*optimize_and_pack=*/ true))); + /*optimize_and_pack=*/true))); decision_builders.push_back( solver_->RevAlloc(new SetCumulsFromGlobalDimensionCosts( &global_dimension_optimizers_, GetOrCreateLargeNeighborhoodSearchLimit(), - /*optimize_and_pack=*/ true))); + /*optimize_and_pack=*/true))); decision_builders.push_back( CreateFinalizerForMinimizedAndMaximizedVariables()); @@ -445,7 +443,7 @@ const Assignment *RoutingModel::PackCumulsOfOptimizerDimensionsFromAssignment( namespace { // Constraint which ensures that var != values. class DifferentFromValues : public Constraint { -public: + public: DifferentFromValues(Solver *solver, IntVar *var, std::vector values) : Constraint(solver), var_(var), values_(std::move(values)) {} void Post() override {} @@ -453,14 +451,13 @@ public: std::string DebugString() const override { return "DifferentFromValues"; } void Accept(ModelVisitor *const visitor) const override { visitor->BeginVisitConstraint(RoutingModelVisitor::kRemoveValues, this); - visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, { - var_ - }); + visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, + {var_}); visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_); visitor->EndVisitConstraint(RoutingModelVisitor::kRemoveValues, this); } -private: + private: IntVar *const var_; const std::vector values_; }; @@ -476,14 +473,17 @@ private: // variable is bound. // If deep_serialize returns false, the model visitor will not extract all // possible values from the values function. -template class LightFunctionElementConstraint : public Constraint { -public: +template +class LightFunctionElementConstraint : public Constraint { + public: LightFunctionElementConstraint(Solver *const solver, IntVar *const var, IntVar *const index, F values, std::function deep_serialize) - : Constraint(solver), var_(var), index_(index), - values_(std::move(values)), deep_serialize_(std::move(deep_serialize)) { - } + : Constraint(solver), + var_(var), + index_(index), + values_(std::move(values)), + deep_serialize_(std::move(deep_serialize)) {} ~LightFunctionElementConstraint() override {} void Post() override { @@ -517,7 +517,7 @@ public: visitor->EndVisitConstraint(RoutingModelVisitor::kLightElement, this); } -private: + private: void IndexBound() { var_->SetValue(values_(index_->Min())); } IntVar *const var_; @@ -541,14 +541,17 @@ Constraint *MakeLightElement(Solver *const solver, IntVar *const var, // Ownership of the 'values' callback is taken by the constraint. template class LightFunctionElement2Constraint : public Constraint { -public: + public: LightFunctionElement2Constraint(Solver *const solver, IntVar *const var, IntVar *const index1, IntVar *const index2, F values, std::function deep_serialize) - : Constraint(solver), var_(var), index1_(index1), index2_(index2), - values_(std::move(values)), deep_serialize_(std::move(deep_serialize)) { - } + : Constraint(solver), + var_(var), + index1_(index1), + index2_(index2), + values_(std::move(values)), + deep_serialize_(std::move(deep_serialize)) {} ~LightFunctionElement2Constraint() override {} void Post() override { Demon *demon = MakeConstraintDemon0( @@ -578,16 +581,15 @@ public: visitor->VisitIntegerArgument(ModelVisitor::kMaxArgument, index1_max); if (deep_serialize_()) { for (int i = index1_min; i <= index1_max; ++i) { - visitor->VisitInt64ToInt64Extension([this, i](int64 j) { - return values_(i, j); - }, - index2_->Min(), index2_->Max()); + visitor->VisitInt64ToInt64Extension( + [this, i](int64 j) { return values_(i, j); }, index2_->Min(), + index2_->Max()); } } visitor->EndVisitConstraint(RoutingModelVisitor::kLightElement2, this); } -private: + private: void IndexBound() { if (index1_->Bound() && index2_->Bound()) { var_->SetValue(values_(index1_->Min(), index2_->Min())); @@ -614,67 +616,66 @@ Constraint *MakeLightElement2(Solver *const solver, IntVar *const var, // TODO(user): Consider removing all these trivial wrappers and just inlining // the solver->RevAlloc(new ...Operator()) calls in the client code. -LocalSearchOperator * -MakeRelocateNeighbors(Solver *solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - RoutingModel::TransitCallback2 arc_evaluator) { +LocalSearchOperator *MakeRelocateNeighbors( + Solver *solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + RoutingModel::TransitCallback2 arc_evaluator) { return solver->RevAlloc(new MakeRelocateNeighborsOperator( vars, secondary_vars, std::move(start_empty_path_class), std::move(arc_evaluator))); } -LocalSearchOperator * -MakePairActive(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakePairActive( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new MakePairActiveOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakePairInactive(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakePairInactive( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new MakePairInactiveOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakePairRelocate(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakePairRelocate( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new PairRelocateOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakeLightPairRelocate(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakeLightPairRelocate( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new LightPairRelocateOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakePairExchange(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakePairExchange( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new PairExchangeOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakePairExchangeRelocate(Solver *const solver, - const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakePairExchangeRelocate( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new PairExchangeRelocateOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } @@ -687,48 +688,50 @@ LocalSearchOperator *SwapIndexPair(Solver *const solver, new SwapIndexPairOperator(vars, secondary_vars, pairs)); } -LocalSearchOperator * -IndexPairSwapActive(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *IndexPairSwapActive( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new IndexPairSwapActiveOperator( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -PairNodeSwapActive(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { - return solver->ConcatenateOperators({ - solver->RevAlloc(new PairNodeSwapActiveOperator( - vars, secondary_vars, start_empty_path_class, pairs)), - solver->RevAlloc(new PairNodeSwapActiveOperator( - vars, secondary_vars, std::move(start_empty_path_class), pairs)) - }); +LocalSearchOperator *PairNodeSwapActive( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { + return solver->ConcatenateOperators( + {solver->RevAlloc(new PairNodeSwapActiveOperator( + vars, secondary_vars, start_empty_path_class, pairs)), + solver->RevAlloc(new PairNodeSwapActiveOperator( + vars, secondary_vars, std::move(start_empty_path_class), pairs))}); } -LocalSearchOperator * -MakeRelocateSubtrip(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakeRelocateSubtrip( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new RelocateSubtrip( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } -LocalSearchOperator * -MakeExchangeSubtrip(Solver *const solver, const std::vector &vars, - const std::vector &secondary_vars, - std::function start_empty_path_class, - const RoutingModel::IndexPairs &pairs) { +LocalSearchOperator *MakeExchangeSubtrip( + Solver *const solver, const std::vector &vars, + const std::vector &secondary_vars, + std::function start_empty_path_class, + const RoutingModel::IndexPairs &pairs) { return solver->RevAlloc(new ExchangeSubtrip( vars, secondary_vars, std::move(start_empty_path_class), pairs)); } // Evaluators -template static int64 ReturnZero(A a, B b) { return 0; } +template +static int64 ReturnZero(A a, B b) { + return 0; +} bool TransitCallbackPositive(const RoutingTransitCallback2 &callback, int size1, int size2) { @@ -742,7 +745,7 @@ bool TransitCallbackPositive(const RoutingTransitCallback2 &callback, int size1, return true; } -} // namespace +} // namespace // ----- Routing model ----- @@ -759,13 +762,15 @@ RoutingModel::RoutingModel(const RoutingIndexManager &index_manager) RoutingModel::RoutingModel(const RoutingIndexManager &index_manager, const RoutingModelParameters ¶meters) : nodes_(index_manager.num_nodes()), - vehicles_(index_manager.num_vehicles()), max_active_vehicles_(vehicles_), + vehicles_(index_manager.num_vehicles()), + max_active_vehicles_(vehicles_), fixed_cost_of_vehicle_(vehicles_, 0), cost_class_index_of_vehicle_(vehicles_, CostClassIndex(-1)), linear_cost_factor_of_vehicle_(vehicles_, 0), quadratic_cost_factor_of_vehicle_(vehicles_, 0), vehicle_amortized_cost_factors_set_(false), - consider_empty_route_costs_(vehicles_, false), cost_classes_(), + consider_empty_route_costs_(vehicles_, false), + cost_classes_(), costs_are_homogeneous_across_vehicles_( parameters.reduce_vehicle_cost_model()), cache_callbacks_(false), @@ -774,8 +779,11 @@ RoutingModel::RoutingModel(const RoutingIndexManager &index_manager, has_hard_type_incompatibilities_(false), has_temporal_type_incompatibilities_(false), has_same_vehicle_type_requirements_(false), - has_temporal_type_requirements_(false), num_visit_types_(0), - starts_(vehicles_), ends_(vehicles_), manager_(index_manager) { + has_temporal_type_requirements_(false), + num_visit_types_(0), + starts_(vehicles_), + ends_(vehicles_), + manager_(index_manager) { // Initialize vehicle costs to the zero evaluator. vehicle_to_transit_cost_.assign( vehicles_, RegisterTransitCallback(ReturnZero)); @@ -837,9 +845,7 @@ void RoutingModel::Initialize() { &is_bound_to_end_); // Cost cache cost_cache_.clear(); - cost_cache_.resize(size + vehicles_, { - kUnassigned, CostClassIndex(-1), 0 - }); + cost_cache_.resize(size + vehicles_, {kUnassigned, CostClassIndex(-1), 0}); preassignment_ = solver_->MakeAssignment(); } @@ -867,13 +873,11 @@ int RoutingModel::RegisterUnaryTransitCallback(TransitCallback1 callback) { }); } -int -RoutingModel::RegisterPositiveUnaryTransitCallback(TransitCallback1 callback) { +int RoutingModel::RegisterPositiveUnaryTransitCallback( + TransitCallback1 callback) { is_transit_evaluator_positive_.push_back(true); - DCHECK(TransitCallbackPositive([&callback](int i, int) { - return callback(i); - }, - Size() + vehicles(), 1)); + DCHECK(TransitCallbackPositive( + [&callback](int i, int) { return callback(i); }, Size() + vehicles(), 1)); return RegisterUnaryTransitCallback(std::move(callback)); } @@ -886,9 +890,8 @@ int RoutingModel::RegisterTransitCallback(TransitCallback2 callback) { cache[i * size + j] = callback(i, j); } } - transit_evaluators_.push_back([cache, size](int64 i, int64 j) { - return cache[i * size + j]; - }); + transit_evaluators_.push_back( + [cache, size](int64 i, int64 j) { return cache[i * size + j]; }); } else { transit_evaluators_.push_back(std::move(callback)); } @@ -919,15 +922,12 @@ int RoutingModel::RegisterStateDependentTransitCallback( state_dependent_transit_evaluators_cache_.back().get(); state_dependent_transit_evaluators_.push_back( [cache, callback](int64 i, int64 j) { - StateDependentTransit value; - if (gtl::FindCopy(*cache, CacheKey(i, j), &value)) - return value; - value = callback(i, j); - cache->insert({ - CacheKey(i, j), value - }); - return value; - }); + StateDependentTransit value; + if (gtl::FindCopy(*cache, CacheKey(i, j), &value)) return value; + value = callback(i, j); + cache->insert({CacheKey(i, j), value}); + return value; + }); return state_dependent_transit_evaluators_.size() - 1; } @@ -1031,15 +1031,13 @@ int RegisterUnaryCallback(RoutingTransitCallback1 callback, bool is_positive, } return model->RegisterUnaryTransitCallback(std::move(callback)); } -} // namespace +} // namespace bool RoutingModel::AddConstantDimensionWithSlack( int64 value, int64 capacity, int64 slack_max, bool fix_start_cumul_to_zero, const std::string &dimension_name) { - return AddDimension(RegisterUnaryCallback([value](int64) { - return value; - }, - /*is_positive=*/ value >= 0, this), + return AddDimension(RegisterUnaryCallback([value](int64) { return value; }, + /*is_positive=*/value >= 0, this), slack_max, capacity, fix_start_cumul_to_zero, dimension_name); } @@ -1050,11 +1048,10 @@ bool RoutingModel::AddVectorDimension(std::vector values, int64 capacity, return AddDimension( RegisterUnaryCallback( [this, values](int64 i) { - return values[manager_.IndexToNode(i).value()]; - }, /*is_positive=*/ - std::all_of(std::begin(values), std::end(values), [](int64 transit) { - return transit >= 0; - }), + return values[manager_.IndexToNode(i).value()]; + }, /*is_positive=*/ + std::all_of(std::begin(values), std::end(values), + [](int64 transit) { return transit >= 0; }), this), 0, capacity, fix_start_cumul_to_zero, dimension_name); } @@ -1067,18 +1064,17 @@ bool RoutingModel::AddMatrixDimension(std::vector > values, for (const std::vector &transit_values : values) { all_transits_positive = std::all_of(std::begin(transit_values), std::end(transit_values), - [](int64 transit) { - return transit >= 0; - }); + [](int64 transit) { return transit >= 0; }); if (!all_transits_positive) { break; } } - return AddDimension(RegisterCallback([this, values](int64 i, int64 j) { - return values[manager_.IndexToNode(i).value()][manager_.IndexToNode(j) - .value()]; - }, - all_transits_positive, this), + return AddDimension(RegisterCallback( + [this, values](int64 i, int64 j) { + return values[manager_.IndexToNode(i).value()] + [manager_.IndexToNode(j).value()]; + }, + all_transits_positive, this), 0, capacity, fix_start_cumul_to_zero, dimension_name); } @@ -1087,7 +1083,7 @@ namespace { // RangeIntToIntFunction indexed by an IntVar. // Do not create this class dicretly, but rather use MakeRangeMakeElementExpr. class RangeMakeElementExpr : public BaseIntExpr { -public: + public: RangeMakeElementExpr(const RangeIntToIntFunction *callback, IntVar *index, Solver *s) : BaseIntExpr(s), callback_(ABSL_DIE_IF_NULL(callback)), index_(index) { @@ -1147,7 +1143,7 @@ public: } void WhenRange(Demon *d) override { index_->WhenRange(d); } -private: + private: const RangeIntToIntFunction *const callback_; IntVar *const index_; }; @@ -1157,7 +1153,7 @@ IntExpr *MakeRangeMakeElementExpr(const RangeIntToIntFunction *callback, return s->RegisterIntExpr( s->RevAlloc(new RangeMakeElementExpr(callback, index, s))); } -} // namespace +} // namespace bool RoutingModel::AddDimensionDependentDimensionWithVehicleCapacity( const std::vector &dependent_transits, @@ -1212,15 +1208,14 @@ bool RoutingModel::AddDimensionDependentDimensionWithVehicleCapacity( std::move(vehicle_capacities), fix_start_cumul_to_zero, name); } -RoutingModel::StateDependentTransit -RoutingModel::MakeStateDependentTransit(const std::function &f, - int64 domain_start, int64 domain_end) { - const std::function g = [&f](int64 x) { return f(x) + x; } - ; +RoutingModel::StateDependentTransit RoutingModel::MakeStateDependentTransit( + const std::function &f, int64 domain_start, + int64 domain_end) { + const std::function g = [&f](int64 x) { return f(x) + x; }; // The next line is safe, because MakeCachedIntToIntFunction does not count // on keeping the closure of its first argument alive. - return { MakeCachedIntToIntFunction(f, domain_start, domain_end), - MakeCachedRangeMinMaxIndexFunction(g, domain_start, domain_end) }; + return {MakeCachedIntToIntFunction(f, domain_start, domain_end), + MakeCachedRangeMinMaxIndexFunction(g, domain_start, domain_end)}; } std::vector RoutingModel::GetAllDimensionNames() const { @@ -1272,19 +1267,19 @@ bool RoutingModel::HasDimension(const std::string &dimension_name) const { return gtl::ContainsKey(dimension_name_to_index_, dimension_name); } -RoutingModel::DimensionIndex -RoutingModel::GetDimensionIndex(const std::string &dimension_name) const { +RoutingModel::DimensionIndex RoutingModel::GetDimensionIndex( + const std::string &dimension_name) const { return gtl::FindWithDefault(dimension_name_to_index_, dimension_name, kNoDimension); } -const RoutingDimension & -RoutingModel::GetDimensionOrDie(const std::string &dimension_name) const { +const RoutingDimension &RoutingModel::GetDimensionOrDie( + const std::string &dimension_name) const { return *dimensions_[gtl::FindOrDie(dimension_name_to_index_, dimension_name)]; } -RoutingDimension * -RoutingModel::GetMutableDimension(const std::string &dimension_name) const { +RoutingDimension *RoutingModel::GetMutableDimension( + const std::string &dimension_name) const { const DimensionIndex index = GetDimensionIndex(dimension_name); if (index != kNoDimension) { return dimensions_[index]; @@ -1360,14 +1355,14 @@ struct VehicleClassComparator { return RoutingModel::VehicleClass::LessThan(a, b); } }; -} // namespace +} // namespace // static const RoutingModel::CostClassIndex RoutingModel::kCostClassIndexOfZeroCost = CostClassIndex(0); -void -RoutingModel::ComputeCostClasses(const RoutingSearchParameters ¶meters) { +void RoutingModel::ComputeCostClasses( + const RoutingSearchParameters ¶meters) { // Create and reduce the cost classes. cost_classes_.reserve(vehicles_); cost_classes_.clear(); @@ -1390,12 +1385,9 @@ RoutingModel::ComputeCostClasses(const RoutingSearchParameters ¶meters) { // Insert the dimension data in a canonical way. for (const RoutingDimension *const dimension : dimensions_) { const int64 coeff = dimension->vehicle_span_cost_coefficients()[vehicle]; - if (coeff == 0) - continue; + if (coeff == 0) continue; cost_class.dimension_transit_evaluator_class_and_cost_coefficient - .push_back({ - dimension->vehicle_to_class(vehicle), coeff, dimension - }); + .push_back({dimension->vehicle_to_class(vehicle), coeff, dimension}); } std::sort(cost_class.dimension_transit_evaluator_class_and_cost_coefficient .begin(), @@ -1407,7 +1399,7 @@ RoutingModel::ComputeCostClasses(const RoutingSearchParameters ¶meters) { gtl::LookupOrInsert(&cost_class_map, cost_class, num_cost_classes); if (cost_class_index == kCostClassIndexOfZeroCost) { has_vehicle_with_zero_cost_class_ = true; - } else if (cost_class_index == num_cost_classes) { // New cost class. + } else if (cost_class_index == num_cost_classes) { // New cost class. cost_classes_.push_back(cost_class); } cost_class_index_of_vehicle_[vehicle] = cost_class_index; @@ -1424,9 +1416,9 @@ RoutingModel::ComputeCostClasses(const RoutingSearchParameters ¶meters) { // // Fixed costs are simply ignored for computing these cost classes. They are // attached to start nodes directly. - costs_are_homogeneous_across_vehicles_ &= - has_vehicle_with_zero_cost_class_ ? GetCostClassesCount() == 1 - : GetCostClassesCount() <= 2; + costs_are_homogeneous_across_vehicles_ &= has_vehicle_with_zero_cost_class_ + ? GetCostClassesCount() == 1 + : GetCostClassesCount() <= 2; } bool RoutingModel::VehicleClass::LessThan(const VehicleClass &a, @@ -1462,17 +1454,17 @@ void RoutingModel::ComputeVehicleClasses() { index_to_equivalence_class_[End(vehicle)]; for (const RoutingDimension *const dimension : dimensions_) { IntVar *const start_cumul_var = dimension->cumuls()[Start(vehicle)]; - vehicle_class.dimension_start_cumuls_min - .push_back(start_cumul_var->Min()); - vehicle_class.dimension_start_cumuls_max - .push_back(start_cumul_var->Max()); + vehicle_class.dimension_start_cumuls_min.push_back( + start_cumul_var->Min()); + vehicle_class.dimension_start_cumuls_max.push_back( + start_cumul_var->Max()); IntVar *const end_cumul_var = dimension->cumuls()[End(vehicle)]; vehicle_class.dimension_end_cumuls_min.push_back(end_cumul_var->Min()); vehicle_class.dimension_end_cumuls_max.push_back(end_cumul_var->Max()); - vehicle_class.dimension_capacities - .push_back(dimension->vehicle_capacities()[vehicle]); - vehicle_class.dimension_evaluator_classes - .push_back(dimension->vehicle_to_class(vehicle)); + vehicle_class.dimension_capacities.push_back( + dimension->vehicle_capacities()[vehicle]); + vehicle_class.dimension_evaluator_classes.push_back( + dimension->vehicle_to_class(vehicle)); } memset(nodes_unvisitability_bitmask.get(), 0, nodes_unvisitability_num_bytes); @@ -1481,8 +1473,8 @@ void RoutingModel::ComputeVehicleClasses() { if (!IsStart(index) && !IsEnd(index) && (!vehicle_var->Contains(vehicle) || !IsVehicleAllowedForIndex(vehicle, index))) { - nodes_unvisitability_bitmask[index / CHAR_BIT] |= - 1U << (index % CHAR_BIT); + nodes_unvisitability_bitmask[index / CHAR_BIT] |= 1U + << (index % CHAR_BIT); } } vehicle_class.unvisitable_nodes_fprint = ThoroughHash( @@ -1490,7 +1482,7 @@ void RoutingModel::ComputeVehicleClasses() { const VehicleClassIndex num_vehicle_classes(vehicle_classes_.size()); const VehicleClassIndex vehicle_class_index = gtl::LookupOrInsert( &vehicle_class_map, vehicle_class, num_vehicle_classes); - if (vehicle_class_index == num_vehicle_classes) { // New vehicle class + if (vehicle_class_index == num_vehicle_classes) { // New vehicle class vehicle_classes_.push_back(vehicle_class); } vehicle_class_index_of_vehicle_[vehicle] = vehicle_class_index; @@ -1501,8 +1493,8 @@ void RoutingModel::ComputeVehicleTypes() { const int nodes_squared = nodes_ * nodes_; std::vector &type_index_of_vehicle = vehicle_type_container_.type_index_of_vehicle; - std::vector > & - sorted_vehicle_classes_per_type = + std::vector > + &sorted_vehicle_classes_per_type = vehicle_type_container_.sorted_vehicle_classes_per_type; std::vector > &vehicles_per_vehicle_class = vehicle_type_container_.vehicles_per_vehicle_class; @@ -1528,15 +1520,12 @@ void RoutingModel::ComputeVehicleTypes() { const int vehicle_class = GetVehicleClassIndexOfVehicle(v).value(); const VehicleTypeContainer::VehicleClassEntry class_entry = { - vehicle_class, GetFixedCostOfVehicle(v) - }; + vehicle_class, GetFixedCostOfVehicle(v)}; if (vehicle_type_added.second) { // Type was not indexed yet. DCHECK_EQ(sorted_vehicle_classes_per_type.size(), index); - sorted_vehicle_classes_per_type.push_back({ - class_entry - }); + sorted_vehicle_classes_per_type.push_back({class_entry}); } else { // Type already indexed. DCHECK_LT(index, sorted_vehicle_classes_per_type.size()); @@ -1572,9 +1561,8 @@ void RoutingModel::FinalizeVisitTypes() { if (pickup_index_pairs.empty() && delivery_index_pairs.empty()) { single_nodes_of_type_[visit_type].push_back(index); } - for (const std::vector > *index_pairs : { - &pickup_index_pairs, &delivery_index_pairs - }) { + for (const std::vector > *index_pairs : + {&pickup_index_pairs, &delivery_index_pairs}) { for (const std::pair &index_pair : *index_pairs) { const int pair_index = index_pair.first; if (pair_indices_added_for_type[visit_type].insert(pair_index).second) { @@ -1593,9 +1581,7 @@ void RoutingModel::TopologicallySortVisitTypes() { return; } std::vector > type_requirement_tightness( - num_visit_types_, { - 0, 0 - }); + num_visit_types_, {0, 0}); std::vector > type_to_dependent_types( num_visit_types_); SparseBitset<> types_in_requirement_graph(num_visit_types_); @@ -1603,12 +1589,11 @@ void RoutingModel::TopologicallySortVisitTypes() { for (int type = 0; type < num_visit_types_; type++) { int num_alternative_required_types = 0; int num_required_sets = 0; - for (const std::vector > * - required_type_alternatives : { - &required_type_alternatives_when_adding_type_index_[type], + for (const std::vector > + *required_type_alternatives : + {&required_type_alternatives_when_adding_type_index_[type], &required_type_alternatives_when_removing_type_index_[type], - &same_vehicle_required_type_alternatives_per_type_index_[type] - }) { + &same_vehicle_required_type_alternatives_per_type_index_[type]}) { for (const absl::flat_hash_set &alternatives : *required_type_alternatives) { types_in_requirement_graph.Set(type); @@ -1625,9 +1610,9 @@ void RoutingModel::TopologicallySortVisitTypes() { } } if (num_alternative_required_types > 0) { - type_requirement_tightness[type].first += - 1.0 * num_required_sets * num_required_sets / - num_alternative_required_types; + type_requirement_tightness[type].first += 1.0 * num_required_sets * + num_required_sets / + num_alternative_required_types; } } @@ -1646,8 +1631,7 @@ void RoutingModel::TopologicallySortVisitTypes() { while (!current_types_with_zero_indegree.empty()) { // Add all zero-degree nodes to the same topological order group, while // also marking their dependent types that become part of the next group. - topologically_sorted_visit_types_.push_back({ - }); + topologically_sorted_visit_types_.push_back({}); std::vector &topological_group = topologically_sorted_visit_types_.back(); std::vector next_types_with_zero_indegree; @@ -1661,21 +1645,21 @@ void RoutingModel::TopologicallySortVisitTypes() { } } } - // Sort the types in the current topological group based on their - // requirement tightness. - // NOTE: For a deterministic order, types with equal tightness are sorted - // by - // increasing type. - // TODO(user): Put types of the same topological order and same - // requirement tightness in a single group (so that they all get inserted - // simultaneously by the GlobalCheapestInsertion heuristic, for instance). + // Sort the types in the current topological group based on their + // requirement tightness. + // NOTE: For a deterministic order, types with equal tightness are sorted + // by + // increasing type. + // TODO(user): Put types of the same topological order and same + // requirement tightness in a single group (so that they all get inserted + // simultaneously by the GlobalCheapestInsertion heuristic, for instance). std::sort(topological_group.begin(), topological_group.end(), [&type_requirement_tightness](int type1, int type2) { - const auto &tightness1 = type_requirement_tightness[type1]; - const auto &tightness2 = type_requirement_tightness[type2]; - return tightness1 > tightness2 || - (tightness1 == tightness2 && type1 < type2); - }); + const auto &tightness1 = type_requirement_tightness[type1]; + const auto &tightness2 = type_requirement_tightness[type2]; + return tightness1 > tightness2 || + (tightness1 == tightness2 && type1 < type2); + }); // Swap the current types with zero in-degree with the next ones. current_types_with_zero_indegree.swap(next_types_with_zero_indegree); } @@ -1689,18 +1673,15 @@ void RoutingModel::TopologicallySortVisitTypes() { } } -RoutingModel::DisjunctionIndex -RoutingModel::AddDisjunction(const std::vector &indices, int64 penalty, - int64 max_cardinality) { +RoutingModel::DisjunctionIndex RoutingModel::AddDisjunction( + const std::vector &indices, int64 penalty, int64 max_cardinality) { CHECK_GE(max_cardinality, 1); for (int i = 0; i < indices.size(); ++i) { CHECK_NE(kUnassigned, indices[i]); } const DisjunctionIndex disjunction_index(disjunctions_.size()); - disjunctions_.push_back({ - indices, { penalty, max_cardinality } - }); + disjunctions_.push_back({indices, {penalty, max_cardinality}}); for (const int64 index : indices) { index_to_disjunctions_[index].push_back(disjunction_index); } @@ -1712,16 +1693,13 @@ RoutingModel::GetPerfectBinaryDisjunctions() const { std::vector > var_index_pairs; for (const Disjunction &disjunction : disjunctions_) { const std::vector &var_indices = disjunction.indices; - if (var_indices.size() != 2) - continue; + if (var_indices.size() != 2) continue; const int64 v0 = var_indices[0]; const int64 v1 = var_indices[1]; if (index_to_disjunctions_[v0].size() == 1 && index_to_disjunctions_[v1].size() == 1) { - // We output sorted pairs. - var_index_pairs.push_back({ - std::min(v0, v1), std::max(v0, v1) - }); + // We output sorted pairs. + var_index_pairs.push_back({std::min(v0, v1), std::max(v0, v1)}); } } std::sort(var_index_pairs.begin(), var_index_pairs.end()); @@ -1770,9 +1748,8 @@ IntVar *RoutingModel::CreateDisjunction(DisjunctionIndex disjunction) { } } -void -RoutingModel::AddSoftSameVehicleConstraint(const std::vector &indices, - int64 cost) { +void RoutingModel::AddSoftSameVehicleConstraint( + const std::vector &indices, int64 cost) { if (!indices.empty()) { ValuedNodes same_vehicle_cost; for (const int64 index : indices) { @@ -1793,25 +1770,17 @@ void RoutingModel::SetAllowedVehiclesForIndex(const std::vector &vehicles, } void RoutingModel::AddPickupAndDelivery(int64 pickup, int64 delivery) { - AddPickupAndDeliverySetsInternal({ - pickup - }, - { - delivery - }); - pickup_delivery_disjunctions_.push_back({ - kNoDisjunction, kNoDisjunction - }); + AddPickupAndDeliverySetsInternal({pickup}, {delivery}); + pickup_delivery_disjunctions_.push_back({kNoDisjunction, kNoDisjunction}); } -void -RoutingModel::AddPickupAndDeliverySets(DisjunctionIndex pickup_disjunction, - DisjunctionIndex delivery_disjunction) { +void RoutingModel::AddPickupAndDeliverySets( + DisjunctionIndex pickup_disjunction, + DisjunctionIndex delivery_disjunction) { AddPickupAndDeliverySetsInternal(GetDisjunctionIndices(pickup_disjunction), GetDisjunctionIndices(delivery_disjunction)); - pickup_delivery_disjunctions_.push_back({ - pickup_disjunction, delivery_disjunction - }); + pickup_delivery_disjunctions_.push_back( + {pickup_disjunction, delivery_disjunction}); } void RoutingModel::AddPickupAndDeliverySetsInternal( @@ -1830,22 +1799,20 @@ void RoutingModel::AddPickupAndDeliverySetsInternal( delivery_index++) { const int64 delivery = deliveries[delivery_index]; CHECK_LT(delivery, size); - index_to_delivery_index_pairs_[delivery] - .emplace_back(pair_index, delivery_index); + index_to_delivery_index_pairs_[delivery].emplace_back(pair_index, + delivery_index); } - pickup_delivery_pairs_.push_back({ - pickups, deliveries - }); + pickup_delivery_pairs_.push_back({pickups, deliveries}); } -const std::vector > & -RoutingModel::GetPickupIndexPairs(int64 node_index) const { +const std::vector > &RoutingModel::GetPickupIndexPairs( + int64 node_index) const { CHECK_LT(node_index, index_to_pickup_index_pairs_.size()); return index_to_pickup_index_pairs_[node_index]; } -const std::vector > & -RoutingModel::GetDeliveryIndexPairs(int64 node_index) const { +const std::vector > &RoutingModel::GetDeliveryIndexPairs( + int64 node_index) const { CHECK_LT(node_index, index_to_delivery_index_pairs_.size()); return index_to_delivery_index_pairs_[node_index]; } @@ -1906,8 +1873,10 @@ IntVar *RoutingModel::CreateSameVehicleCost(int vehicle_index) { solver_->MakeIsGreaterOrEqualCstVar(vehicle_counts[i], 1)); } vehicle_used.push_back(solver_->MakeIntConst(-1)); - return solver_->MakeProd(solver_->MakeMax(solver_->MakeSum(vehicle_used), 0), - same_vehicle_costs_[vehicle_index].value)->Var(); + return solver_ + ->MakeProd(solver_->MakeMax(solver_->MakeSum(vehicle_used), 0), + same_vehicle_costs_[vehicle_index].value) + ->Var(); } void RoutingModel::AddLocalSearchOperator(LocalSearchOperator *ls_operator) { @@ -1924,18 +1893,15 @@ void RoutingModel::AppendHomogeneousArcCosts( CHECK(cost_elements != nullptr); const auto arc_cost_evaluator = [this, node_index](int64 next_index) { return GetHomogeneousCost(node_index, next_index); - } - ; + }; if (UsesLightPropagation(parameters)) { // Only supporting positive costs. // TODO(user): Detect why changing lower bound to kint64min stalls // the search in GLS in some cases (Solomon instances for instance). IntVar *const base_cost_var = solver_->MakeIntVar(0, kint64max); - solver_->AddConstraint( - MakeLightElement(solver_.get(), base_cost_var, nexts_[node_index], - arc_cost_evaluator, [this]() { - return enable_deep_serialization_; - })); + solver_->AddConstraint(MakeLightElement( + solver_.get(), base_cost_var, nexts_[node_index], arc_cost_evaluator, + [this]() { return enable_deep_serialization_; })); IntVar *const var = solver_->MakeProd(base_cost_var, active_[node_index])->Var(); cost_elements->push_back(var); @@ -1959,25 +1925,27 @@ void RoutingModel::AppendArcCosts(const RoutingSearchParameters ¶meters, IntVar *const base_cost_var = solver_->MakeIntVar(0, kint64max); solver_->AddConstraint(MakeLightElement2( solver_.get(), base_cost_var, nexts_[node_index], - vehicle_vars_[node_index], [this, node_index](int64 to, int64 vehicle) { - return GetArcCostForVehicle(node_index, to, vehicle); - }, - [this]() { - return enable_deep_serialization_; - })); + vehicle_vars_[node_index], + [this, node_index](int64 to, int64 vehicle) { + return GetArcCostForVehicle(node_index, to, vehicle); + }, + [this]() { return enable_deep_serialization_; })); IntVar *const var = solver_->MakeProd(base_cost_var, active_[node_index])->Var(); cost_elements->push_back(var); } else { IntVar *const vehicle_class_var = - solver_->MakeElement([this](int64 index) { - return SafeGetCostClassInt64OfVehicle(index); - }, - vehicle_vars_[node_index])->Var(); + solver_ + ->MakeElement( + [this](int64 index) { + return SafeGetCostClassInt64OfVehicle(index); + }, + vehicle_vars_[node_index]) + ->Var(); IntExpr *const expr = solver_->MakeElement( [this, node_index](int64 next, int64 vehicle_class) { - return GetArcCostForClass(node_index, next, vehicle_class); - }, + return GetArcCostForClass(node_index, next, vehicle_class); + }, nexts_[node_index], vehicle_class_var); IntVar *const var = solver_->MakeProd(expr, active_[node_index])->Var(); cost_elements->push_back(var); @@ -2003,7 +1971,8 @@ std::string RoutingModel::FindErrorInSearchParametersForModel( " (int value: ", first_solution_strategy, ")"); } if (search_parameters.first_solution_strategy() == - FirstSolutionStrategy::SWEEP && sweep_arranger() == nullptr) { + FirstSolutionStrategy::SWEEP && + sweep_arranger() == nullptr) { return "Undefined sweep arranger for ROUTING_SWEEP strategy."; } return ""; @@ -2018,14 +1987,14 @@ void RoutingModel::CloseModel() { } class RoutingModelInspector : public ModelVisitor { -public: + public: explicit RoutingModelInspector(RoutingModel *model) : model_(model) { same_vehicle_components_.SetNumberOfNodes(model->Size()); for (const std::string &name : model->GetAllDimensionNames()) { RoutingDimension *const dimension = model->GetMutableDimension(name); const std::vector &cumuls = dimension->cumuls(); for (int i = 0; i < cumuls.size(); ++i) { - cumul_to_dim_indices_[cumuls[i]] = { dimension, i }; + cumul_to_dim_indices_[cumuls[i]] = {dimension, i}; } } const std::vector &vehicle_vars = model->VehicleVars(); @@ -2049,64 +2018,56 @@ public: } void EndVisitConstraint(const std::string &type_name, const Constraint *const constraint) override { - gtl::FindWithDefault(constraint_inspectors_, type_name, []() { - })(); + gtl::FindWithDefault(constraint_inspectors_, type_name, []() {})(); } void VisitIntegerExpressionArgument(const std::string &type_name, IntExpr *const expr) override { - gtl::FindWithDefault(expr_inspectors_, type_name, [](const IntExpr * expr) { - })(expr); + gtl::FindWithDefault(expr_inspectors_, type_name, + [](const IntExpr *expr) {})(expr); } void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector &values) override { gtl::FindWithDefault(array_inspectors_, arg_name, - [](const std::vector & int_array) { - })(values); + [](const std::vector &int_array) {})(values); } -private: + private: using ExprInspector = std::function; using ArrayInspector = std::function &)>; using ConstraintInspector = std::function; void RegisterInspectors() { - expr_inspectors_[kExpressionArgument] = [this](const IntExpr * expr) { + expr_inspectors_[kExpressionArgument] = [this](const IntExpr *expr) { expr_ = expr; - } - ; - expr_inspectors_[kLeftArgument] = [this](const IntExpr * expr) { + }; + expr_inspectors_[kLeftArgument] = [this](const IntExpr *expr) { left_ = expr; - } - ; - expr_inspectors_[kRightArgument] = [this](const IntExpr * expr) { + }; + expr_inspectors_[kRightArgument] = [this](const IntExpr *expr) { right_ = expr; - } - ; + }; array_inspectors_[kStartsArgument] = - [this](const std::vector & int_array) { - starts_argument_ = int_array; - } - ; + [this](const std::vector &int_array) { + starts_argument_ = int_array; + }; array_inspectors_[kEndsArgument] = - [this](const std::vector & int_array) { - ends_argument_ = int_array; - } - ; + [this](const std::vector &int_array) { + ends_argument_ = int_array; + }; constraint_inspectors_[kNotMember] = [this]() { std::pair dim_index; if (gtl::FindCopy(cumul_to_dim_indices_, expr_, &dim_index)) { RoutingDimension *const dimension = dim_index.first; const int index = dim_index.second; - dimension->forbidden_intervals_[index] - .InsertIntervals(starts_argument_, ends_argument_); + dimension->forbidden_intervals_[index].InsertIntervals(starts_argument_, + ends_argument_); VLOG(2) << dimension->name() << " " << index << ": " << dimension->forbidden_intervals_[index].DebugString(); } expr_ = nullptr; starts_argument_.clear(); ends_argument_.clear(); - } - ; + }; constraint_inspectors_[kEquality] = [this]() { int left_index = 0; int right_index = 0; @@ -2118,8 +2079,7 @@ private: } left_ = nullptr; right_ = nullptr; - } - ; + }; constraint_inspectors_[kLessOrEqual] = [this]() { std::pair left_index; std::pair right_index; @@ -2130,14 +2090,13 @@ private: VLOG(2) << "For dimension " << dimension->name() << ", cumul for " << left_index.second << " is less than " << right_index.second << "."; - dimension->path_precedence_graph_ - .AddArc(left_index.second, right_index.second); + dimension->path_precedence_graph_.AddArc(left_index.second, + right_index.second); } } left_ = nullptr; right_ = nullptr; - } - ; + }; } RoutingModel *const model_; @@ -2178,8 +2137,7 @@ void RoutingModel::CloseModelWithParameters( FinalizeVisitTypes(); vehicle_start_class_callback_ = [this](int64 start) { return GetVehicleStartClass(start); - } - ; + }; AddNoCycleConstraintInternal(); @@ -2313,13 +2271,16 @@ void RoutingModel::CloseModelWithParameters( vehicle_used.push_back( solver_->MakeIsGreaterCstVar(route_lengths[i], 2)); IntVar *const var = - solver_->MakeProd(solver_->MakeOpposite(solver_->MakeSquare( - solver_->MakeSum(route_lengths[i], -2))), - quadratic_cost_factor_of_vehicle_[i])->Var(); + solver_ + ->MakeProd(solver_->MakeOpposite(solver_->MakeSquare( + solver_->MakeSum(route_lengths[i], -2))), + quadratic_cost_factor_of_vehicle_[i]) + ->Var(); cost_elements.push_back(var); } - IntVar *const vehicle_usage_cost = solver_ - ->MakeScalProd(vehicle_used, linear_cost_factor_of_vehicle_)->Var(); + IntVar *const vehicle_usage_cost = + solver_->MakeScalProd(vehicle_used, linear_cost_factor_of_vehicle_) + ->Var(); cost_elements.push_back(vehicle_usage_cost); } } @@ -2331,12 +2292,10 @@ void RoutingModel::CloseModelWithParameters( dimension->vehicle_span_cost_coefficients(); const std::vector &span_ubs = dimension->vehicle_span_upper_bounds(); const bool has_span_constraint = - std::any_of(span_costs.begin(), span_costs.end(), [](int64 coeff) { - return coeff != 0; - }) || - std::any_of(span_ubs.begin(), span_ubs.end(), [](int64 value) { - return value < kint64max; - }) || + std::any_of(span_costs.begin(), span_costs.end(), + [](int64 coeff) { return coeff != 0; }) || + std::any_of(span_ubs.begin(), span_ubs.end(), + [](int64 value) { return value < kint64max; }) || dimension->HasSoftSpanUpperBounds() || dimension->HasQuadraticCostSoftSpanUpperBounds(); if (has_span_constraint) { @@ -2353,23 +2312,19 @@ void RoutingModel::CloseModelWithParameters( } if (dimension->HasSoftSpanUpperBounds()) { for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { - if (spans[vehicle]) - continue; + if (spans[vehicle]) continue; const SimpleBoundCosts::BoundCost bound_cost = dimension->GetSoftSpanUpperBoundForVehicle(vehicle); - if (bound_cost.cost == 0) - continue; + if (bound_cost.cost == 0) continue; spans[vehicle] = solver_->MakeIntVar(0, span_ubs[vehicle]); } } if (dimension->HasQuadraticCostSoftSpanUpperBounds()) { for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { - if (spans[vehicle]) - continue; + if (spans[vehicle]) continue; const SimpleBoundCosts::BoundCost bound_cost = dimension->GetQuadraticCostSoftSpanUpperBoundForVehicle(vehicle); - if (bound_cost.cost == 0) - continue; + if (bound_cost.cost == 0) continue; spans[vehicle] = solver_->MakeIntVar(0, span_ubs[vehicle]); } } @@ -2378,8 +2333,7 @@ void RoutingModel::CloseModelWithParameters( // If a vehicle's span is constrained, its start/end cumuls must be // instantiated. for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { - if (!spans[vehicle] && !total_slacks[vehicle]) - continue; + if (!spans[vehicle] && !total_slacks[vehicle]) continue; if (spans[vehicle]) { AddVariableTargetToFinalizer(spans[vehicle], kint64min); } @@ -2390,12 +2344,13 @@ void RoutingModel::CloseModelWithParameters( } // Add costs of variables. for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { - if (span_costs[vehicle] == 0) - continue; + if (span_costs[vehicle] == 0) continue; DCHECK(total_slacks[vehicle] != nullptr); IntVar *const slack_amount = - solver_->MakeProd(vehicle_costs_considered_[vehicle], - total_slacks[vehicle])->Var(); + solver_ + ->MakeProd(vehicle_costs_considered_[vehicle], + total_slacks[vehicle]) + ->Var(); IntVar *const slack_cost = solver_->MakeProd(slack_amount, span_costs[vehicle])->Var(); cost_elements.push_back(slack_cost); @@ -2406,17 +2361,18 @@ void RoutingModel::CloseModelWithParameters( for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { const auto bound_cost = dimension->GetSoftSpanUpperBoundForVehicle(vehicle); - if (bound_cost.cost == 0 || bound_cost.bound == kint64max) - continue; + if (bound_cost.cost == 0 || bound_cost.bound == kint64max) continue; DCHECK(spans[vehicle] != nullptr); // Additional cost is vehicle_cost_considered_[vehicle] * // max(0, spans[vehicle] - bound_cost.bound) * bound_cost.cost. - IntVar *const span_violation_amount = solver_ - ->MakeProd( - vehicle_costs_considered_[vehicle], - solver_->MakeMax( - solver_->MakeSum(spans[vehicle], -bound_cost.bound), 0)) - ->Var(); + IntVar *const span_violation_amount = + solver_ + ->MakeProd( + vehicle_costs_considered_[vehicle], + solver_->MakeMax( + solver_->MakeSum(spans[vehicle], -bound_cost.bound), + 0)) + ->Var(); IntVar *const span_violation_cost = solver_->MakeProd(span_violation_amount, bound_cost.cost)->Var(); cost_elements.push_back(span_violation_cost); @@ -2428,18 +2384,20 @@ void RoutingModel::CloseModelWithParameters( for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { const auto bound_cost = dimension->GetQuadraticCostSoftSpanUpperBoundForVehicle(vehicle); - if (bound_cost.cost == 0 || bound_cost.bound == kint64max) - continue; + if (bound_cost.cost == 0 || bound_cost.bound == kint64max) continue; DCHECK(spans[vehicle] != nullptr); // Additional cost is vehicle_cost_considered_[vehicle] * // max(0, spans[vehicle] - bound_cost.bound)^2 * bound_cost.cost. IntExpr *max0 = solver_->MakeMax( solver_->MakeSum(spans[vehicle], -bound_cost.bound), 0); IntVar *const squared_span_violation_amount = - solver_->MakeProd(vehicle_costs_considered_[vehicle], - solver_->MakeSquare(max0))->Var(); - IntVar *const span_violation_cost = solver_ - ->MakeProd(squared_span_violation_amount, bound_cost.cost)->Var(); + solver_ + ->MakeProd(vehicle_costs_considered_[vehicle], + solver_->MakeSquare(max0)) + ->Var(); + IntVar *const span_violation_cost = + solver_->MakeProd(squared_span_violation_amount, bound_cost.cost) + ->Var(); cost_elements.push_back(span_violation_cost); AddWeightedVariableMinimizedByFinalizer(squared_span_violation_amount, bound_cost.cost); @@ -2481,14 +2439,14 @@ void RoutingModel::CloseModelWithParameters( std::vector fifo_vehicles; for (int i = 0; i < vehicles_; ++i) { switch (vehicle_pickup_delivery_policy_[i]) { - case PICKUP_AND_DELIVERY_NO_ORDER: - break; - case PICKUP_AND_DELIVERY_LIFO: - lifo_vehicles.push_back(Start(i)); - break; - case PICKUP_AND_DELIVERY_FIFO: - fifo_vehicles.push_back(Start(i)); - break; + case PICKUP_AND_DELIVERY_NO_ORDER: + break; + case PICKUP_AND_DELIVERY_LIFO: + lifo_vehicles.push_back(Start(i)); + break; + case PICKUP_AND_DELIVERY_FIFO: + fifo_vehicles.push_back(Start(i)); + break; } } solver_->AddConstraint(solver_->MakePathPrecedenceConstraint( @@ -2556,8 +2514,11 @@ void RoutingModel::CloseModelWithParameters( struct Link { Link(std::pair link, double value, int vehicle_class, int64 start_depot, int64 end_depot) - : link(link), value(value), vehicle_class(vehicle_class), - start_depot(start_depot), end_depot(end_depot) {} + : link(link), + value(value), + vehicle_class(vehicle_class), + start_depot(start_depot), + end_depot(end_depot) {} ~Link() {} std::pair link; @@ -2579,14 +2540,19 @@ struct LinkSort { // TODO(user): Use the dimension class in this class. // TODO(user): Add support for vehicle-dependent dimension transits. class RouteConstructor { -public: + public: RouteConstructor(Assignment *const assignment, RoutingModel *const model, bool check_assignment, int64 num_indices, const std::vector &links_list) - : assignment_(assignment), model_(model), - check_assignment_(check_assignment), solver_(model_->solver()), - num_indices_(num_indices), links_list_(links_list), - nexts_(model_->Nexts()), in_route_(num_indices_, -1), final_routes_(), + : assignment_(assignment), + model_(model), + check_assignment_(check_assignment), + solver_(model_->solver()), + num_indices_(num_indices), + links_list_(links_list), + nexts_(model_->Nexts()), + in_route_(num_indices_, -1), + final_routes_(), index_to_chain_index_(num_indices, -1), index_to_vehicle_class_index_(num_indices, -1) { { @@ -2630,8 +2596,8 @@ public: for (int dimension_index = 0; dimension_index < dimensions_.size(); ++dimension_index) { cumuls_[dimension_index][index1] = - std::max(dimensions_[dimension_index] - ->GetTransitValue(start_depot, index1, 0), + std::max(dimensions_[dimension_index]->GetTransitValue( + start_depot, index1, 0), dimensions_[dimension_index]->CumulVar(index1)->Min()); } } @@ -2639,8 +2605,8 @@ public: for (int dimension_index = 0; dimension_index < dimensions_.size(); ++dimension_index) { cumuls_[dimension_index][index2] = - std::max(dimensions_[dimension_index] - ->GetTransitValue(start_depot, index2, 0), + std::max(dimensions_[dimension_index]->GetTransitValue( + start_depot, index2, 0), dimensions_[dimension_index]->CumulVar(index2)->Min()); } } @@ -2732,12 +2698,8 @@ public: return final_routes_; } -private: - enum MergeStatus { - FIRST_SECOND, - SECOND_FIRST, - NO_MERGE - }; + private: + enum MergeStatus { FIRST_SECOND, SECOND_FIRST, NO_MERGE }; struct RouteSort { bool operator()(const std::vector &route1, @@ -2895,8 +2857,7 @@ private: int tail1, int head2, int tail2) { // TODO(user): If the chain index is greater than the number of vehicles, // use another vehicle instead. - if (new_chain_index >= model_->vehicles()) - return false; + if (new_chain_index >= model_->vehicles()) return false; const int start = head1; temp_assignment->Add(model_->NextVar(model_->Start(new_chain_index))); temp_assignment->SetValue(model_->NextVar(model_->Start(new_chain_index)), @@ -3028,7 +2989,7 @@ private: const int64 num_indices_; const std::vector links_list_; std::vector nexts_; - std::vector dimensions_; // Not owned. + std::vector dimensions_; // Not owned. std::vector > cumuls_; std::vector > new_possible_cumuls_; std::vector > routes_; @@ -3117,7 +3078,7 @@ void SweepArranger::ArrangeIndices(std::vector *indices) { // Vehicle Routing Problem. // Suitable only when distance is considered as the cost. class SweepBuilder : public DecisionBuilder { -public: + public: SweepBuilder(RoutingModel *const model, bool check_assignment) : model_(model), check_assignment_(check_assignment) {} ~SweepBuilder() override {} @@ -3139,7 +3100,7 @@ public: return nullptr; } -private: + private: void ModelSetup() { const int depot = model_->GetDepot(); num_indices_ = model_->Size() + model_->vehicles(); @@ -3175,7 +3136,7 @@ namespace { // branching and may fail if some nodes cannot be made inactive. class AllUnperformed : public DecisionBuilder { -public: + public: // Does not take ownership of model. explicit AllUnperformed(RoutingModel *const model) : model_(model) {} ~AllUnperformed() override {} @@ -3192,10 +3153,10 @@ public: return nullptr; } -private: + private: RoutingModel *const model_; }; -} // namespace +} // namespace void RoutingModel::AddSearchMonitor(SearchMonitor *const monitor) { monitors_.push_back(monitor); @@ -3203,7 +3164,7 @@ void RoutingModel::AddSearchMonitor(SearchMonitor *const monitor) { namespace { class AtSolutionCallbackMonitor : public SearchMonitor { -public: + public: AtSolutionCallbackMonitor(Solver *solver, std::function callback) : SearchMonitor(solver), callback_(std::move(callback)) {} bool AtSolution() override { @@ -3211,10 +3172,10 @@ public: return false; } -private: + private: std::function callback_; }; -} // namespace +} // namespace void RoutingModel::AddAtSolutionCallback(std::function callback) { AddSearchMonitor(solver_->RevAlloc( @@ -3226,26 +3187,24 @@ const Assignment *RoutingModel::Solve(const Assignment *assignment) { DefaultRoutingSearchParameters()); } -const Assignment * -RoutingModel::SolveWithParameters(const RoutingSearchParameters ¶meters, - std::vector *solutions) { +const Assignment *RoutingModel::SolveWithParameters( + const RoutingSearchParameters ¶meters, + std::vector *solutions) { return SolveFromAssignmentWithParameters(nullptr, parameters, solutions); } namespace { absl::Duration GetTimeLimit(const RoutingSearchParameters ¶meters) { - if (!parameters.has_time_limit()) - return absl::InfiniteDuration(); + if (!parameters.has_time_limit()) return absl::InfiniteDuration(); return util_time::DecodeGoogleApiProto(parameters.time_limit()).value(); } absl::Duration GetLnsTimeLimit(const RoutingSearchParameters ¶meters) { - if (!parameters.has_lns_time_limit()) - return absl::InfiniteDuration(); + if (!parameters.has_lns_time_limit()) return absl::InfiniteDuration(); return util_time::DecodeGoogleApiProto(parameters.lns_time_limit()).value(); } -} // namespace +} // namespace namespace { void MakeAllUnperformed(const RoutingModel *model, Assignment *assignment) { @@ -3260,7 +3219,7 @@ void MakeAllUnperformed(const RoutingModel *model, Assignment *assignment) { ->SetValue(model->End(vehicle)); } } -} // namespace +} // namespace bool RoutingModel::AppendAssignmentIfFeasible( const Assignment &assignment, @@ -3288,10 +3247,9 @@ void RoutingModel::LogSolution(const RoutingSearchParameters ¶meters, : absl::StrFormat( "%d (%.8lf)", solution_cost, cost_scaling_factor * (solution_cost + cost_offset)); - LOG(INFO) - << absl::StrFormat("%s (%s, time = %d ms, memory used = %s)", description, - cost_string, solver_->wall_time() - start_time_ms, - memory_str); + LOG(INFO) << absl::StrFormat( + "%s (%s, time = %d ms, memory used = %s)", description, cost_string, + solver_->wall_time() - start_time_ms, memory_str); } const Assignment *RoutingModel::SolveFromAssignmentWithParameters( @@ -3300,8 +3258,7 @@ const Assignment *RoutingModel::SolveFromAssignmentWithParameters( const int64 start_time_ms = solver_->wall_time(); QuietCloseModelWithParameters(parameters); VLOG(1) << "Search parameters:\n" << parameters.DebugString(); - if (solutions != nullptr) - solutions->clear(); + if (solutions != nullptr) solutions->clear(); if (status_ == ROUTING_INVALID) { return nullptr; } @@ -3474,8 +3431,8 @@ int64 RoutingModel::ComputeLowerBound() { // Left nodes in the bipartite are indexed from 0 to num_nodes - 1; right // nodes are indexed from num_nodes to 2 * num_nodes - 1. for (int tail = 0; tail < Size(); ++tail) { - std::unique_ptr iterator(nexts_[tail] - ->MakeDomainIterator(false)); + std::unique_ptr iterator( + nexts_[tail]->MakeDomainIterator(false)); for (const int64 head : InitAndGetValues(iterator.get())) { // Given there are no disjunction constraints, a node cannot point to // itself. Doing this explicitly given that outside the search, @@ -3519,9 +3476,9 @@ bool RoutingModel::RouteCanBeUsedByVehicle(const Assignment &assignment, return true; } -bool -RoutingModel::ReplaceUnusedVehicle(int unused_vehicle, int active_vehicle, - Assignment *const compact_assignment) const { +bool RoutingModel::ReplaceUnusedVehicle( + int unused_vehicle, int active_vehicle, + Assignment *const compact_assignment) const { CHECK(compact_assignment != nullptr); CHECK(!IsVehicleUsed(*compact_assignment, unused_vehicle)); CHECK(IsVehicleUsed(*compact_assignment, active_vehicle)); @@ -3597,19 +3554,18 @@ RoutingModel::ReplaceUnusedVehicle(int unused_vehicle, int active_vehicle, return true; } -Assignment * -RoutingModel::CompactAssignment(const Assignment &assignment) const { +Assignment *RoutingModel::CompactAssignment( + const Assignment &assignment) const { return CompactAssignmentInternal(assignment, false); } -Assignment * -RoutingModel::CompactAndCheckAssignment(const Assignment &assignment) const { +Assignment *RoutingModel::CompactAndCheckAssignment( + const Assignment &assignment) const { return CompactAssignmentInternal(assignment, true); } -Assignment * -RoutingModel::CompactAssignmentInternal(const Assignment &assignment, - bool check_compact_assignment) const { +Assignment *RoutingModel::CompactAssignmentInternal( + const Assignment &assignment, bool check_compact_assignment) const { CHECK_EQ(assignment.solver(), solver_.get()); if (!CostsAreHomogeneousAcrossVehicles()) { LOG(WARNING) @@ -3772,11 +3728,10 @@ Assignment *RoutingModel::DoRestoreAssignment() { return nullptr; } -bool -RoutingModel::RoutesToAssignment(const std::vector > &routes, - bool ignore_inactive_indices, - bool close_routes, - Assignment *const assignment) const { +bool RoutingModel::RoutesToAssignment( + const std::vector > &routes, + bool ignore_inactive_indices, bool close_routes, + Assignment *const assignment) const { CHECK(assignment != nullptr); if (!closed_) { LOG(ERROR) << "The model is not closed yet"; @@ -3933,8 +3888,8 @@ void RoutingModel::AssignmentToRoutes( } #ifndef SWIG -std::vector > -RoutingModel::GetRoutesFromAssignment(const Assignment &assignment) { +std::vector > RoutingModel::GetRoutesFromAssignment( + const Assignment &assignment) { std::vector > route_indices(vehicles()); for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { if (!assignment.Bound(NextVar(vehicle))) { @@ -3989,7 +3944,7 @@ int64 RoutingModel::GetArcCostForClassInternal( cost = 0; } } - *cache = { static_cast(to_index), cost_class_index, cost }; + *cache = {static_cast(to_index), cost_class_index, cost}; return cost; } @@ -4049,15 +4004,13 @@ int64 RoutingModel::GetArcCostForFirstSolution(int64 from_index, nexts_, active_, is_bound_to_end_, zero_transit)); is_bound_to_end_ct_added_.Switch(solver_.get()); } - if (is_bound_to_end_[to_index]->Min() == 1) - return kint64max; + if (is_bound_to_end_[to_index]->Min() == 1) return kint64max; // TODO(user): Take vehicle into account. return GetHomogeneousCost(from_index, to_index); } -int64 -RoutingModel::GetDimensionTransitCostSum(int64 i, int64 j, - const CostClass &cost_class) const { +int64 RoutingModel::GetDimensionTransitCostSum( + int64 i, int64 j, const CostClass &cost_class) const { int64 cost = 0; for (const auto &evaluator_and_coefficient : cost_class.dimension_transit_evaluator_class_and_cost_coefficient) { @@ -4075,8 +4028,7 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, int64 to2) { // Deal with end nodes: never pick an end node over a non-end node. if (IsEnd(to1) || IsEnd(to2)) { - if (IsEnd(to1) != IsEnd(to2)) - return IsEnd(to2); + if (IsEnd(to1) != IsEnd(to2)) return IsEnd(to2); // If both are end nodes, we don't care; the right end node will be picked // by constraint propagation. Break the tie by index. return to1 < to2; @@ -4086,8 +4038,7 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, const bool mandatory1 = active_[to1]->Min() == 1; const bool mandatory2 = active_[to2]->Min() == 1; // Always pick a mandatory node over a non-mandatory one. - if (mandatory1 != mandatory2) - return mandatory1; + if (mandatory1 != mandatory2) return mandatory1; // Look at the vehicle variables. IntVar *const src_vehicle_var = VehicleVar(from); @@ -4107,9 +4058,8 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, mandatory2 ? to2_vehicle_var->Bound() : (to2_vehicle_var->Size() <= 2); // Prefer a destination bound to a given vehicle, even if it's not // bound to the right one (the propagation will quickly rule it out). - if (bound1 != bound2) - return bound1; - if (bound1) { // same as bound1 && bound2. + if (bound1 != bound2) return bound1; + if (bound1) { // same as bound1 && bound2. // Min() will return kNoVehicle for optional nodes. Thus we use Max(). const int64 vehicle1 = to1_vehicle_var->Max(); const int64 vehicle2 = to2_vehicle_var->Max(); @@ -4121,8 +4071,7 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, // If no destination is bound to the right vehicle, whatever we // return doesn't matter: both are infeasible. To be consistent, we // just break the tie. - if (vehicle1 != src_vehicle) - return to1 < to2; + if (vehicle1 != src_vehicle) return to1 < to2; } } // At this point, either both destinations are bound to the source vehicle, @@ -4139,8 +4088,7 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, IntVar *const dim2 = cumul_vars[to2]; // Prefer the destination that has a lower upper bound for the constrained // dimension. - if (dim1->Max() != dim2->Max()) - return dim1->Max() < dim2->Max(); + if (dim1->Max() != dim2->Max()) return dim1->Max() < dim2->Max(); // TODO(user): evaluate the *actual* Min() of each cumul variable in the // scenario where the corresponding arc from->to is performed, and pick // the destination with the lowest value. @@ -4155,16 +4103,14 @@ bool RoutingModel::ArcIsMoreConstrainedThanArc(int64 from, int64 to1, UnperformedPenalty(to1)); const int64 cost2 = CapSub(GetArcCostForClass(from, to2, cost_class_index), UnperformedPenalty(to2)); - if (cost1 != cost2) - return cost1 < cost2; + if (cost1 != cost2) return cost1 < cost2; } // Further break ties by looking at the size of the VehicleVar. { const int64 num_vehicles1 = VehicleVar(to1)->Size(); const int64 num_vehicles2 = VehicleVar(to2)->Size(); - if (num_vehicles1 != num_vehicles2) - return num_vehicles1 < num_vehicles2; + if (num_vehicles1 != num_vehicles2) return num_vehicles1 < num_vehicles2; } // Break perfect ties by value. @@ -4194,8 +4140,8 @@ const std::vector &RoutingModel::GetPairIndicesOfType(int type) const { return pair_indices_of_type_[type]; } -RoutingModel::VisitTypePolicy -RoutingModel::GetVisitTypePolicy(int64 index) const { +RoutingModel::VisitTypePolicy RoutingModel::GetVisitTypePolicy( + int64 index) const { CHECK_LT(index, index_to_type_policy_.size()); return index_to_type_policy_[index]; } @@ -4227,15 +4173,15 @@ void RoutingModel::AddTemporalTypeIncompatibility(int type1, int type2) { temporal_incompatible_types_per_type_index_[type2].insert(type1); } -const absl::flat_hash_set & -RoutingModel::GetHardTypeIncompatibilitiesOfType(int type) const { +const absl::flat_hash_set + &RoutingModel::GetHardTypeIncompatibilitiesOfType(int type) const { DCHECK_GE(type, 0); DCHECK_LT(type, hard_incompatible_types_per_type_index_.size()); return hard_incompatible_types_per_type_index_[type]; } -const absl::flat_hash_set & -RoutingModel::GetTemporalTypeIncompatibilitiesOfType(int type) const { +const absl::flat_hash_set + &RoutingModel::GetTemporalTypeIncompatibilitiesOfType(int type) const { DCHECK_GE(type, 0); DCHECK_LT(type, temporal_incompatible_types_per_type_index_.size()); return temporal_incompatible_types_per_type_index_[type]; @@ -4282,8 +4228,8 @@ void RoutingModel::AddRequiredTypeAlternativesWhenAddingType( } has_temporal_type_requirements_ = true; - required_type_alternatives_when_adding_type_index_[dependent_type] - .push_back(std::move(required_type_alternatives)); + required_type_alternatives_when_adding_type_index_[dependent_type].push_back( + std::move(required_type_alternatives)); } void RoutingModel::AddRequiredTypeAlternativesWhenRemovingType( @@ -4316,15 +4262,15 @@ RoutingModel::GetSameVehicleRequiredTypeAlternativesOfType(int type) const { return same_vehicle_required_type_alternatives_per_type_index_[type]; } -const std::vector > & -RoutingModel::GetRequiredTypeAlternativesWhenAddingType(int type) const { +const std::vector > + &RoutingModel::GetRequiredTypeAlternativesWhenAddingType(int type) const { DCHECK_GE(type, 0); DCHECK_LT(type, required_type_alternatives_when_adding_type_index_.size()); return required_type_alternatives_when_adding_type_index_[type]; } -const std::vector > & -RoutingModel::GetRequiredTypeAlternativesWhenRemovingType(int type) const { +const std::vector > + &RoutingModel::GetRequiredTypeAlternativesWhenRemovingType(int type) const { DCHECK_GE(type, 0); DCHECK_LT(type, required_type_alternatives_when_removing_type_index_.size()); return required_type_alternatives_when_removing_type_index_[type]; @@ -4336,20 +4282,15 @@ int64 RoutingModel::UnperformedPenalty(int64 var_index) const { int64 RoutingModel::UnperformedPenaltyOrValue(int64 default_value, int64 var_index) const { - if (active_[var_index]->Min() == 1) - return kint64max; // Forced active. + if (active_[var_index]->Min() == 1) return kint64max; // Forced active. const std::vector &disjunction_indices = GetDisjunctionIndices(var_index); - if (disjunction_indices.size() != 1) - return default_value; + if (disjunction_indices.size() != 1) return default_value; const DisjunctionIndex disjunction_index = disjunction_indices[0]; - // The disjunction penalty can be kNoPenalty iff there is more than one node - // in the disjunction; otherwise we would have caught it earlier (the node - // would be forced active). - return std::max(int64 { - 0 - }, - disjunctions_[disjunction_index].value.penalty); + // The disjunction penalty can be kNoPenalty iff there is more than one node + // in the disjunction; otherwise we would have caught it earlier (the node + // would be forced active). + return std::max(int64{0}, disjunctions_[disjunction_index].value.penalty); } std::string RoutingModel::DebugOutputAssignment( @@ -4403,11 +4344,9 @@ std::string RoutingModel::DebugOutputAssignment( solution_assignment.Max(var)); } } - if (IsEnd(index)) - break; + if (IsEnd(index)) break; index = solution_assignment.Value(NextVar(index)); - if (IsEnd(index)) - output.append("Route end "); + if (IsEnd(index)) output.append("Route end "); } output.append("\n"); } @@ -4421,8 +4360,7 @@ std::string RoutingModel::DebugOutputAssignment( has_unperformed = true; } } - if (!has_unperformed) - output.append("None"); + if (!has_unperformed) output.append("None"); output.append("\n"); return output; } @@ -4478,7 +4416,7 @@ Assignment *RoutingModel::GetOrCreateTmpAssignment() { RegularLimit *RoutingModel::GetOrCreateLimit() { if (limit_ == nullptr) { limit_ = solver_->MakeLimit(absl::InfiniteDuration(), kint64max, kint64max, - kint64max, /*smart_time_check=*/ true); + kint64max, /*smart_time_check=*/true); } return limit_; } @@ -4487,7 +4425,7 @@ RegularLimit *RoutingModel::GetOrCreateLocalSearchLimit() { if (ls_limit_ == nullptr) { ls_limit_ = solver_->MakeLimit(absl::InfiniteDuration(), kint64max, kint64max, - /*solutions=*/ 1, /*smart_time_check=*/ true); + /*solutions=*/1, /*smart_time_check=*/true); } return ls_limit_; } @@ -4496,7 +4434,7 @@ RegularLimit *RoutingModel::GetOrCreateLargeNeighborhoodSearchLimit() { if (lns_limit_ == nullptr) { lns_limit_ = solver_->MakeLimit(absl::InfiniteDuration(), kint64max, kint64max, - kint64max, /*smart_time_check=*/ false); + kint64max, /*smart_time_check=*/false); } return lns_limit_; } @@ -4506,7 +4444,7 @@ RoutingModel::GetOrCreateFirstSolutionLargeNeighborhoodSearchLimit() { if (first_solution_lns_limit_ == nullptr) { first_solution_lns_limit_ = solver_->MakeLimit(absl::InfiniteDuration(), kint64max, kint64max, - kint64max, /*smart_time_check=*/ false); + kint64max, /*smart_time_check=*/false); } return first_solution_lns_limit_; } @@ -4519,13 +4457,12 @@ LocalSearchOperator *RoutingModel::CreateInsertionOperator() { CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, vehicle_start_class_callback_); if (!pickup_delivery_pairs_.empty()) { - insertion_operator = solver_->ConcatenateOperators({ - MakePairActive( - solver_.get(), nexts_, - CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - vehicle_start_class_callback_, pickup_delivery_pairs_), - insertion_operator - }); + insertion_operator = solver_->ConcatenateOperators( + {MakePairActive( + solver_.get(), nexts_, + CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, + vehicle_start_class_callback_, pickup_delivery_pairs_), + insertion_operator}); } return insertion_operator; } @@ -4538,47 +4475,48 @@ LocalSearchOperator *RoutingModel::CreateMakeInactiveOperator() { CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, vehicle_start_class_callback_); if (!pickup_delivery_pairs_.empty()) { - make_inactive_operator = solver_->ConcatenateOperators({ - MakePairInactive( - solver_.get(), nexts_, - CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - vehicle_start_class_callback_, pickup_delivery_pairs_), - make_inactive_operator - }); + make_inactive_operator = solver_->ConcatenateOperators( + {MakePairInactive( + solver_.get(), nexts_, + CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, + vehicle_start_class_callback_, pickup_delivery_pairs_), + make_inactive_operator}); } return make_inactive_operator; } -#define CP_ROUTING_ADD_OPERATOR(operator_type, cp_operator_type) \ - if (CostsAreHomogeneousAcrossVehicles()) { \ - local_search_operators_[operator_type] = \ - solver_->MakeOperator(nexts_, Solver::cp_operator_type); \ - } else { \ - local_search_operators_[operator_type] = solver_->MakeOperator( \ - nexts_, vehicle_vars_, Solver::cp_operator_type); \ +#define CP_ROUTING_ADD_OPERATOR(operator_type, cp_operator_type) \ + if (CostsAreHomogeneousAcrossVehicles()) { \ + local_search_operators_[operator_type] = \ + solver_->MakeOperator(nexts_, Solver::cp_operator_type); \ + } else { \ + local_search_operators_[operator_type] = solver_->MakeOperator( \ + nexts_, vehicle_vars_, Solver::cp_operator_type); \ } -#define CP_ROUTING_ADD_OPERATOR2(operator_type, cp_operator_class) \ - local_search_operators_[operator_type] = \ - MakeLocalSearchOperator( \ - solver_.get(), nexts_, \ - CostsAreHomogeneousAcrossVehicles() ? std::vector() \ - : vehicle_vars_, \ +#define CP_ROUTING_ADD_OPERATOR2(operator_type, cp_operator_class) \ + local_search_operators_[operator_type] = \ + MakeLocalSearchOperator( \ + solver_.get(), nexts_, \ + CostsAreHomogeneousAcrossVehicles() ? std::vector() \ + : vehicle_vars_, \ vehicle_start_class_callback_); -#define CP_ROUTING_ADD_CALLBACK_OPERATOR(operator_type, cp_operator_type) \ - if (CostsAreHomogeneousAcrossVehicles()) { \ - local_search_operators_[operator_type] = \ - solver_->MakeOperator(nexts_, [this](int64 i, int64 j, int64 k) { \ - return GetArcCostForVehicle(i, j, k); \ - }, \ - Solver::cp_operator_type); \ - } else { \ - local_search_operators_[operator_type] = solver_->MakeOperator( \ - nexts_, vehicle_vars_, [this](int64 i, int64 j, int64 k) { \ - return GetArcCostForVehicle(i, j, k); \ - }, \ - Solver::cp_operator_type); \ +#define CP_ROUTING_ADD_CALLBACK_OPERATOR(operator_type, cp_operator_type) \ + if (CostsAreHomogeneousAcrossVehicles()) { \ + local_search_operators_[operator_type] = solver_->MakeOperator( \ + nexts_, \ + [this](int64 i, int64 j, int64 k) { \ + return GetArcCostForVehicle(i, j, k); \ + }, \ + Solver::cp_operator_type); \ + } else { \ + local_search_operators_[operator_type] = solver_->MakeOperator( \ + nexts_, vehicle_vars_, \ + [this](int64 i, int64 j, int64 k) { \ + return GetArcCostForVehicle(i, j, k); \ + }, \ + Solver::cp_operator_type); \ } void RoutingModel::CreateNeighborhoodOperators( @@ -4606,49 +4544,44 @@ void RoutingModel::CreateNeighborhoodOperators( local_search_operators_[RELOCATE_NEIGHBORS] = MakeRelocateNeighbors( solver_.get(), nexts_, CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - vehicle_start_class_callback_, [this](int64 from, int64 to) { - return GetHomogeneousCost(from, to); - }); - local_search_operators_[NODE_PAIR_SWAP] = solver_->ConcatenateOperators({ - IndexPairSwapActive( - solver_.get(), nexts_, - CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - vehicle_start_class_callback_, pickup_delivery_pairs_), - SwapIndexPair( - solver_.get(), nexts_, - CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - pickup_delivery_pairs_), - PairNodeSwapActive( - solver_.get(), nexts_, - CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, - vehicle_start_class_callback_, pickup_delivery_pairs_) - }); + vehicle_start_class_callback_, + [this](int64 from, int64 to) { return GetHomogeneousCost(from, to); }); + local_search_operators_[NODE_PAIR_SWAP] = solver_->ConcatenateOperators( + {IndexPairSwapActive( + solver_.get(), nexts_, + CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, + vehicle_start_class_callback_, pickup_delivery_pairs_), + SwapIndexPair( + solver_.get(), nexts_, + CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, + pickup_delivery_pairs_), + PairNodeSwapActive( + solver_.get(), nexts_, + CostsAreHomogeneousAcrossVehicles() ? empty : vehicle_vars_, + vehicle_start_class_callback_, pickup_delivery_pairs_)}); const auto arc_cost_for_path_start = [this](int64 before_node, int64 after_node, int64 start_index) { - const int vehicle = index_to_vehicle_[start_index]; - const int64 arc_cost = - GetArcCostForVehicle(before_node, after_node, vehicle); - return (before_node != start_index || IsEnd(after_node)) - ? arc_cost - : CapSub(arc_cost, GetFixedCostOfVehicle(vehicle)); - } - ; + const int vehicle = index_to_vehicle_[start_index]; + const int64 arc_cost = + GetArcCostForVehicle(before_node, after_node, vehicle); + return (before_node != start_index || IsEnd(after_node)) + ? arc_cost + : CapSub(arc_cost, GetFixedCostOfVehicle(vehicle)); + }; GlobalCheapestInsertionFilteredHeuristic::GlobalCheapestInsertionParameters ls_gci_parameters = { - /* is_sequential */ false, /* farthest_seeds_ratio */ 0.0, - parameters.cheapest_insertion_ls_operator_neighbors_ratio(), - /* use_neighbors_ratio_for_initialization */ true, - parameters.cheapest_insertion_add_unperformed_entries() - }; + /* is_sequential */ false, /* farthest_seeds_ratio */ 0.0, + parameters.cheapest_insertion_ls_operator_neighbors_ratio(), + /* use_neighbors_ratio_for_initialization */ true, + parameters.cheapest_insertion_add_unperformed_entries()}; local_search_operators_[GLOBAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS] = solver_->RevAlloc(new FilteredHeuristicCloseNodesLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { return UnperformedPenaltyOrValue(0, i); }, GetOrCreateFeasibilityFilterManager(parameters), ls_gci_parameters), parameters.heuristic_close_nodes_lns_num_nodes())); @@ -4656,54 +4589,56 @@ void RoutingModel::CreateNeighborhoodOperators( local_search_operators_[LOCAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS] = solver_->RevAlloc(new FilteredHeuristicCloseNodesLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, GetOrCreateFeasibilityFilterManager(parameters)), parameters.heuristic_close_nodes_lns_num_nodes())); local_search_operators_[GLOBAL_CHEAPEST_INSERTION_PATH_LNS] = solver_->RevAlloc(new FilteredHeuristicPathLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { return UnperformedPenaltyOrValue(0, i); }, GetOrCreateFeasibilityFilterManager(parameters), ls_gci_parameters))); local_search_operators_[LOCAL_CHEAPEST_INSERTION_PATH_LNS] = solver_->RevAlloc(new FilteredHeuristicPathLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, GetOrCreateFeasibilityFilterManager(parameters)))); - local_search_operators_[ - RELOCATE_PATH_GLOBAL_CHEAPEST_INSERTION_INSERT_UNPERFORMED] = - solver_->RevAlloc(new RelocatePathAndHeuristicInsertUnperformedOperator( - absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, - GetOrCreateFeasibilityFilterManager(parameters), - ls_gci_parameters))); + local_search_operators_ + [RELOCATE_PATH_GLOBAL_CHEAPEST_INSERTION_INSERT_UNPERFORMED] = + solver_->RevAlloc( + new RelocatePathAndHeuristicInsertUnperformedOperator( + absl::make_unique( + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { + return UnperformedPenaltyOrValue(0, i); + }, + GetOrCreateFeasibilityFilterManager(parameters), + ls_gci_parameters))); local_search_operators_[GLOBAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS] = solver_->RevAlloc(new FilteredHeuristicExpensiveChainLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { return UnperformedPenaltyOrValue(0, i); }, GetOrCreateFeasibilityFilterManager(parameters), ls_gci_parameters), parameters.heuristic_expensive_chain_lns_num_arcs_to_consider(), @@ -4712,9 +4647,10 @@ void RoutingModel::CreateNeighborhoodOperators( local_search_operators_[LOCAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS] = solver_->RevAlloc(new FilteredHeuristicExpensiveChainLNSOperator( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, GetOrCreateFeasibilityFilterManager(parameters)), parameters.heuristic_expensive_chain_lns_num_arcs_to_consider(), arc_cost_for_path_start)); @@ -4757,10 +4693,10 @@ void RoutingModel::CreateNeighborhoodOperators( #undef CP_ROUTING_ADD_OPERATOR2 #undef CP_ROUTING_ADD_OPERATOR -#define CP_ROUTING_PUSH_OPERATOR(operator_type, operator_method, operators) \ - if (search_parameters.local_search_operators().use_##operator_method() == \ - BOOL_TRUE) { \ - operators.push_back(local_search_operators_[operator_type]); \ +#define CP_ROUTING_PUSH_OPERATOR(operator_type, operator_method, operators) \ + if (search_parameters.local_search_operators().use_##operator_method() == \ + BOOL_TRUE) { \ + operators.push_back(local_search_operators_[operator_type]); \ } LocalSearchOperator *RoutingModel::GetNeighborhoodOperators( @@ -4886,8 +4822,7 @@ LocalSearchOperator *RoutingModel::GetNeighborhoodOperators( bool HasUnaryDimension(const std::vector &dimensions) { for (const RoutingDimension *dimension : dimensions) { - if (dimension->GetUnaryTransitEvaluator(0) != nullptr) - return true; + if (dimension->GetUnaryTransitEvaluator(0) != nullptr) return true; } return false; } @@ -4906,7 +4841,7 @@ void ConvertVectorInt64ToVectorInt(const std::vector &input, } } -} // namespace +} // namespace std::vector RoutingModel::GetOrCreateLocalSearchFilters( @@ -4925,68 +4860,50 @@ RoutingModel::GetOrCreateLocalSearchFilters( std::vector filters; // VehicleAmortizedCostFilter can have a negative value, so it must be first. if (filter_cost && vehicle_amortized_cost_factors_set_) { - filters.push_back({ - MakeVehicleAmortizedCostFilter(*this), kAccept - }); + filters.push_back({MakeVehicleAmortizedCostFilter(*this), kAccept}); } // The SumObjectiveFilter has the best reject/second ratio in practice, // so it is the earliest. if (filter_cost) { if (CostsAreHomogeneousAcrossVehicles()) { - LocalSearchFilter *sum = - solver_->MakeSumObjectiveFilter(nexts_, [this](int64 i, int64 j) { - return GetHomogeneousCost(i, j); - }, - Solver::LE); - filters.push_back({ - sum, kAccept - }); + LocalSearchFilter *sum = solver_->MakeSumObjectiveFilter( + nexts_, [this](int64 i, int64 j) { return GetHomogeneousCost(i, j); }, + Solver::LE); + filters.push_back({sum, kAccept}); } else { LocalSearchFilter *sum = solver_->MakeSumObjectiveFilter( - nexts_, vehicle_vars_, [this](int64 i, int64 j, int64 k) { - return GetArcCostForVehicle(i, j, k); - }, + nexts_, vehicle_vars_, + [this](int64 i, int64 j, int64 k) { + return GetArcCostForVehicle(i, j, k); + }, Solver::LE); - filters.push_back({ - sum, kAccept - }); + filters.push_back({sum, kAccept}); } } - filters.push_back({ - solver_->MakeVariableDomainFilter(), kAccept - }); + filters.push_back({solver_->MakeVariableDomainFilter(), kAccept}); if (vehicles_ > max_active_vehicles_) { - filters.push_back({ - MakeMaxActiveVehiclesFilter(*this), kAccept - }); + filters.push_back({MakeMaxActiveVehiclesFilter(*this), kAccept}); } if (!disjunctions_.empty()) { - filters.push_back({ - MakeNodeDisjunctionFilter(*this), kAccept - }); + filters.push_back({MakeNodeDisjunctionFilter(*this), kAccept}); } if (!pickup_delivery_pairs_.empty()) { - filters.push_back({ - MakePickupDeliveryFilter(*this, pickup_delivery_pairs_, - vehicle_pickup_delivery_policy_), - kAccept - }); + filters.push_back( + {MakePickupDeliveryFilter(*this, pickup_delivery_pairs_, + vehicle_pickup_delivery_policy_), + kAccept}); } if (HasTypeRegulations()) { - filters.push_back({ - MakeTypeRegulationsFilter(*this), kAccept - }); + filters.push_back({MakeTypeRegulationsFilter(*this), kAccept}); } - filters.push_back({ - MakeVehicleVarFilter(*this), kAccept - }); + filters.push_back({MakeVehicleVarFilter(*this), kAccept}); const PathState *path_state_reference = nullptr; if (HasUnaryDimension(GetDimensions())) { @@ -4998,9 +4915,9 @@ RoutingModel::GetOrCreateLocalSearchFilters( auto path_state = absl::make_unique( Size() + vehicles(), std::move(path_starts), std::move(path_ends)); path_state_reference = path_state.get(); - filters.push_back({ - MakePathStateFilter(solver_.get(), std::move(path_state), Nexts()), kRelax - }); + filters.push_back( + {MakePathStateFilter(solver_.get(), std::move(path_state), Nexts()), + kRelax}); AppendLightWeightDimensionFilters(path_state_reference, GetDimensions(), &filters); } @@ -5009,11 +4926,8 @@ RoutingModel::GetOrCreateLocalSearchFilters( &filters); for (const RoutingDimension *dimension : dimensions_) { - if (!dimension->HasBreakConstraints()) - continue; - filters.push_back({ - MakeVehicleBreaksFilter(*this, *dimension), kAccept - }); + if (!dimension->HasBreakConstraints()) continue; + filters.push_back({MakeVehicleBreaksFilter(*this, *dimension), kAccept}); } filters.insert(filters.end(), extra_filters_.begin(), extra_filters_.end()); return filters; @@ -5051,10 +4965,8 @@ RoutingModel::GetOrCreateStrongFeasibilityFilterManager( if (!strong_feasibility_filter_manager_) { std::vector filters = GetOrCreateFeasibilityFilters(parameters); - filters.push_back({ - MakeCPFeasibilityFilter(this), - LocalSearchFilterManager::FilterEventType::kAccept - }); + filters.push_back({MakeCPFeasibilityFilter(this), + LocalSearchFilterManager::FilterEventType::kAccept}); strong_feasibility_filter_manager_ = solver_->RevAlloc(new LocalSearchFilterManager(std::move(filters))); } @@ -5070,7 +4982,7 @@ bool AllTransitsPositive(const RoutingDimension &dimension) { } return true; } -} // namespace +} // namespace void RoutingModel::StoreDimensionCumulOptimizers( const RoutingSearchParameters ¶meters) { @@ -5129,18 +5041,12 @@ void RoutingModel::StoreDimensionCumulOptimizers( } } int num_linear_constraints = 0; - if (has_span_cost) - ++num_linear_constraints; - if (has_span_limit) - ++num_linear_constraints; - if (dimension->HasSoftSpanUpperBounds()) - ++num_linear_constraints; - if (has_soft_lower_bound) - ++num_linear_constraints; - if (has_soft_upper_bound) - ++num_linear_constraints; - if (dimension->HasBreakConstraints()) - ++num_linear_constraints; + if (has_span_cost) ++num_linear_constraints; + if (has_span_limit) ++num_linear_constraints; + if (dimension->HasSoftSpanUpperBounds()) ++num_linear_constraints; + if (has_soft_lower_bound) ++num_linear_constraints; + if (has_soft_upper_bound) ++num_linear_constraints; + if (dimension->HasBreakConstraints()) ++num_linear_constraints; if (num_linear_constraints >= 2) { dimension->SetVehicleOffsetsForLocalOptimizer( std::move(vehicle_offsets)); @@ -5186,8 +5092,8 @@ void RoutingModel::StoreDimensionCumulOptimizers( packed_dimensions_collector_assignment); } -std::vector -RoutingModel::GetDimensionsWithSoftOrSpanCosts() const { +std::vector RoutingModel::GetDimensionsWithSoftOrSpanCosts() + const { std::vector dimensions; for (RoutingDimension *dimension : dimensions_) { bool has_soft_or_span_cost = false; @@ -5206,8 +5112,7 @@ RoutingModel::GetDimensionsWithSoftOrSpanCosts() const { } } } - if (has_soft_or_span_cost) - dimensions.push_back(dimension); + if (has_soft_or_span_cost) dimensions.push_back(dimension); } return dimensions; } @@ -5216,10 +5121,10 @@ DecisionBuilder * RoutingModel::CreateFinalizerForMinimizedAndMaximizedVariables() { std::stable_sort(finalizer_variable_cost_pairs_.begin(), finalizer_variable_cost_pairs_.end(), - [](const std::pair & var_cost1, - const std::pair & var_cost2) { - return var_cost1.second > var_cost2.second; - }); + [](const std::pair &var_cost1, + const std::pair &var_cost2) { + return var_cost1.second > var_cost2.second; + }); const int num_variables = finalizer_variable_cost_pairs_.size() + finalizer_variable_target_pairs_.size(); std::vector variables; @@ -5269,73 +5174,70 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( DecisionBuilder *const finalize_solution = CreateSolutionFinalizer(GetOrCreateLargeNeighborhoodSearchLimit()); // Default heuristic - first_solution_decision_builders_[ - FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE] = finalize_solution; - // Global cheapest addition heuristic. - first_solution_decision_builders_[ - FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC] = - solver_->MakePhase(nexts_, [this](int64 i, int64 j) { - return GetArcCostForFirstSolution(i, j); - }, - Solver::CHOOSE_STATIC_GLOBAL_BEST); + first_solution_decision_builders_ + [FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE] = finalize_solution; + // Global cheapest addition heuristic. + first_solution_decision_builders_ + [FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC] = solver_->MakePhase( + nexts_, + [this](int64 i, int64 j) { return GetArcCostForFirstSolution(i, j); }, + Solver::CHOOSE_STATIC_GLOBAL_BEST); // Cheapest addition heuristic. Solver::IndexEvaluator2 eval = [this](int64 i, int64 j) { return GetArcCostForFirstSolution(i, j); - } - ; + }; first_solution_decision_builders_[FirstSolutionStrategy::LOCAL_CHEAPEST_ARC] = solver_->MakePhase(nexts_, Solver::CHOOSE_FIRST_UNBOUND, eval); // Path-based cheapest addition heuristic. first_solution_decision_builders_[FirstSolutionStrategy::PATH_CHEAPEST_ARC] = solver_->MakePhase(nexts_, Solver::CHOOSE_PATH, eval); if (!search_parameters.use_unfiltered_first_solution_strategy()) { - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::PATH_CHEAPEST_ARC] = - solver_->RevAlloc(new IntVarFilteredDecisionBuilder( - absl::make_unique( - this, [this](int64 i, int64 j) { - return GetArcCostForFirstSolution(i, j); - }, - GetOrCreateFeasibilityFilterManager(search_parameters)))); - first_solution_decision_builders_[ - FirstSolutionStrategy::PATH_CHEAPEST_ARC] = - solver_->Try(first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::PATH_CHEAPEST_ARC], - first_solution_decision_builders_[ - FirstSolutionStrategy::PATH_CHEAPEST_ARC]); + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::PATH_CHEAPEST_ARC] = + solver_->RevAlloc(new IntVarFilteredDecisionBuilder( + absl::make_unique( + this, + [this](int64 i, int64 j) { + return GetArcCostForFirstSolution(i, j); + }, + GetOrCreateFeasibilityFilterManager(search_parameters)))); + first_solution_decision_builders_ + [FirstSolutionStrategy::PATH_CHEAPEST_ARC] = + solver_->Try(first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::PATH_CHEAPEST_ARC], + first_solution_decision_builders_ + [FirstSolutionStrategy::PATH_CHEAPEST_ARC]); } // Path-based most constrained arc addition heuristic. Solver::VariableValueComparator comp = [this](int64 i, int64 j, int64 k) { return ArcIsMoreConstrainedThanArc(i, j, k); - } - ; + }; - first_solution_decision_builders_[ - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = - solver_->MakePhase(nexts_, Solver::CHOOSE_PATH, comp); + first_solution_decision_builders_ + [FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = + solver_->MakePhase(nexts_, Solver::CHOOSE_PATH, comp); if (!search_parameters.use_unfiltered_first_solution_strategy()) { - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = - solver_->RevAlloc(new IntVarFilteredDecisionBuilder( - absl::make_unique( - this, comp, - GetOrCreateFeasibilityFilterManager(search_parameters)))); - first_solution_decision_builders_[ - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = - solver_->Try(first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC], - first_solution_decision_builders_[ - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC]); + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = + solver_->RevAlloc(new IntVarFilteredDecisionBuilder( + absl::make_unique( + this, comp, + GetOrCreateFeasibilityFilterManager(search_parameters)))); + first_solution_decision_builders_ + [FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC] = solver_->Try( + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC], + first_solution_decision_builders_ + [FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC]); } // Evaluator-based path heuristic. if (first_solution_evaluator_ != nullptr) { - first_solution_decision_builders_[ - FirstSolutionStrategy::EVALUATOR_STRATEGY] = - solver_->MakePhase(nexts_, Solver::CHOOSE_PATH, - first_solution_evaluator_); + first_solution_decision_builders_ + [FirstSolutionStrategy::EVALUATOR_STRATEGY] = solver_->MakePhase( + nexts_, Solver::CHOOSE_PATH, first_solution_evaluator_); } else { - first_solution_decision_builders_[ - FirstSolutionStrategy::EVALUATOR_STRATEGY] = nullptr; + first_solution_decision_builders_ + [FirstSolutionStrategy::EVALUATOR_STRATEGY] = nullptr; } // All unperformed heuristic. first_solution_decision_builders_[FirstSolutionStrategy::ALL_UNPERFORMED] = @@ -5343,7 +5245,7 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( // Best insertion heuristic. RegularLimit *const ls_limit = solver_->MakeLimit(GetTimeLimit(search_parameters), kint64max, kint64max, - kint64max, /*smart_time_check=*/ true); + kint64max, /*smart_time_check=*/true); DecisionBuilder *const finalize = solver_->MakeSolveOnce( finalize_solution, GetOrCreateLargeNeighborhoodSearchLimit()); LocalSearchPhaseParameters *const insertion_parameters = @@ -5364,22 +5266,19 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( insertion_parameters), GetOrCreateAssignment(), false, optimization_step); first_solution_decision_builders_[FirstSolutionStrategy::BEST_INSERTION] = - solver_->Compose(first_solution_decision_builders_[ - FirstSolutionStrategy::BEST_INSERTION], + solver_->Compose(first_solution_decision_builders_ + [FirstSolutionStrategy::BEST_INSERTION], finalize); // Parallel/Sequential Global cheapest insertion GlobalCheapestInsertionFilteredHeuristic::GlobalCheapestInsertionParameters gci_parameters = { - /* is_sequential */ false, - search_parameters.cheapest_insertion_farthest_seeds_ratio(), - search_parameters.cheapest_insertion_first_solution_neighbors_ratio(), - /* use_neighbors_ratio_for_initialization */ false, - search_parameters.cheapest_insertion_add_unperformed_entries() - }; - for (bool is_sequential : { - false, true - }) { + /* is_sequential */ false, + search_parameters.cheapest_insertion_farthest_seeds_ratio(), + search_parameters.cheapest_insertion_first_solution_neighbors_ratio(), + /* use_neighbors_ratio_for_initialization */ false, + search_parameters.cheapest_insertion_add_unperformed_entries()}; + for (bool is_sequential : {false, true}) { FirstSolutionStrategy::Value first_solution_strategy = is_sequential ? FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION : FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION; @@ -5388,54 +5287,54 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( first_solution_filtered_decision_builders_[first_solution_strategy] = solver_->RevAlloc(new IntVarFilteredDecisionBuilder( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { return UnperformedPenaltyOrValue(0, i); }, GetOrCreateFeasibilityFilterManager(search_parameters), gci_parameters))); IntVarFilteredDecisionBuilder *const strong_gci = solver_->RevAlloc(new IntVarFilteredDecisionBuilder( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - [this](int64 i) { - return UnperformedPenaltyOrValue(0, i); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + [this](int64 i) { return UnperformedPenaltyOrValue(0, i); }, GetOrCreateStrongFeasibilityFilterManager(search_parameters), gci_parameters))); first_solution_decision_builders_[first_solution_strategy] = solver_->Try( first_solution_filtered_decision_builders_[first_solution_strategy], - solver_->Try(strong_gci, first_solution_decision_builders_[ - FirstSolutionStrategy::BEST_INSERTION])); + solver_->Try(strong_gci, first_solution_decision_builders_ + [FirstSolutionStrategy::BEST_INSERTION])); } - // Local cheapest insertion - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION] = - solver_->RevAlloc(new IntVarFilteredDecisionBuilder( - absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, - GetOrCreateFeasibilityFilterManager(search_parameters)))); + // Local cheapest insertion + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION] = + solver_->RevAlloc(new IntVarFilteredDecisionBuilder( + absl::make_unique( + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, + GetOrCreateFeasibilityFilterManager(search_parameters)))); IntVarFilteredDecisionBuilder *const strong_lci = solver_->RevAlloc(new IntVarFilteredDecisionBuilder( absl::make_unique( - this, [this](int64 i, int64 j, int64 vehicle) { - return GetArcCostForVehicle(i, j, vehicle); - }, + this, + [this](int64 i, int64 j, int64 vehicle) { + return GetArcCostForVehicle(i, j, vehicle); + }, GetOrCreateStrongFeasibilityFilterManager(search_parameters)))); - first_solution_decision_builders_[ - FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION] = - solver_->Try( - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION], - solver_->Try(strong_lci, first_solution_decision_builders_[ - FirstSolutionStrategy::BEST_INSERTION])); + first_solution_decision_builders_ + [FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION] = solver_->Try( + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION], + solver_->Try(strong_lci, + first_solution_decision_builders_ + [FirstSolutionStrategy::BEST_INSERTION])); // Savings SavingsFilteredHeuristic::SavingsParameters savings_parameters; savings_parameters.neighbors_ratio = @@ -5457,8 +5356,8 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( absl::make_unique( this, &manager_, savings_parameters, filter_manager))); if (!search_parameters.use_unfiltered_first_solution_strategy()) { - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::SAVINGS] = savings_db; + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::SAVINGS] = savings_db; } first_solution_decision_builders_[FirstSolutionStrategy::SAVINGS] = @@ -5474,8 +5373,8 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( absl::make_unique( this, &manager_, savings_parameters, filter_manager))); if (!search_parameters.use_unfiltered_first_solution_strategy()) { - first_solution_filtered_decision_builders_[ - FirstSolutionStrategy::SAVINGS] = savings_db; + first_solution_filtered_decision_builders_ + [FirstSolutionStrategy::SAVINGS] = savings_db; } first_solution_decision_builders_[FirstSolutionStrategy::SAVINGS] = @@ -5501,12 +5400,11 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders( absl::make_unique( this, GetOrCreateFeasibilityFilterManager(search_parameters), search_parameters.christofides_use_minimum_matching()))); - // Automatic - // TODO(user): make this smarter. + // Automatic + // TODO(user): make this smarter. const bool has_precedences = std::any_of( - dimensions_.begin(), dimensions_.end(), [](RoutingDimension * dim) { - return !dim->GetNodePrecedences().empty(); - }); + dimensions_.begin(), dimensions_.end(), + [](RoutingDimension *dim) { return !dim->GetNodePrecedences().empty(); }); if (pickup_delivery_pairs_.empty() && !has_precedences) { automatic_first_solution_strategy_ = FirstSolutionStrategy::PATH_CHEAPEST_ARC; @@ -5622,45 +5520,45 @@ void RoutingModel::SetupMetaheuristics( const int64 optimization_step = std::max( MathUtil::FastInt64Round(search_parameters.optimization_step()), One()); switch (metaheuristic) { - case LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH: - if (CostsAreHomogeneousAcrossVehicles()) { - optimize = solver_->MakeGuidedLocalSearch( - false, cost_, [this](int64 i, int64 j) { - return GetHomogeneousCost(i, j); - }, - optimization_step, nexts_, - search_parameters.guided_local_search_lambda_coefficient()); - } else { - optimize = solver_->MakeGuidedLocalSearch( - false, cost_, [this](int64 i, int64 j, int64 k) { - return GetArcCostForVehicle(i, j, k); - }, - optimization_step, nexts_, vehicle_vars_, - search_parameters.guided_local_search_lambda_coefficient()); + case LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH: + if (CostsAreHomogeneousAcrossVehicles()) { + optimize = solver_->MakeGuidedLocalSearch( + false, cost_, + [this](int64 i, int64 j) { return GetHomogeneousCost(i, j); }, + optimization_step, nexts_, + search_parameters.guided_local_search_lambda_coefficient()); + } else { + optimize = solver_->MakeGuidedLocalSearch( + false, cost_, + [this](int64 i, int64 j, int64 k) { + return GetArcCostForVehicle(i, j, k); + }, + optimization_step, nexts_, vehicle_vars_, + search_parameters.guided_local_search_lambda_coefficient()); + } + break; + case LocalSearchMetaheuristic::SIMULATED_ANNEALING: + optimize = + solver_->MakeSimulatedAnnealing(false, cost_, optimization_step, 100); + break; + case LocalSearchMetaheuristic::TABU_SEARCH: + optimize = solver_->MakeTabuSearch(false, cost_, optimization_step, + nexts_, 10, 10, .8); + break; + case LocalSearchMetaheuristic::GENERIC_TABU_SEARCH: { + std::vector tabu_vars; + if (tabu_var_callback_) { + tabu_vars = tabu_var_callback_(this); + } else { + tabu_vars.push_back(cost_); + } + optimize = solver_->MakeGenericTabuSearch(false, cost_, optimization_step, + tabu_vars, 100); + break; } - break; - case LocalSearchMetaheuristic::SIMULATED_ANNEALING: - optimize = - solver_->MakeSimulatedAnnealing(false, cost_, optimization_step, 100); - break; - case LocalSearchMetaheuristic::TABU_SEARCH: - optimize = solver_->MakeTabuSearch(false, cost_, optimization_step, nexts_, - 10, 10, .8); - break; - case LocalSearchMetaheuristic::GENERIC_TABU_SEARCH: { - std::vector tabu_vars; - if (tabu_var_callback_) { - tabu_vars = tabu_var_callback_(this); - } else { - tabu_vars.push_back(cost_); - } - optimize = solver_->MakeGenericTabuSearch(false, cost_, optimization_step, - tabu_vars, 100); - break; - } - default: - limit_too_long = false; - optimize = solver_->MakeMinimize(cost_, optimization_step); + default: + limit_too_long = false; + optimize = solver_->MakeMinimize(cost_, optimization_step); } if (limit_too_long) { LOG(WARNING) << LocalSearchMetaheuristic::Value_Name(metaheuristic) @@ -5698,8 +5596,8 @@ void RoutingModel::SetupAssignmentCollector( monitors_.push_back(collect_assignments_); } -void -RoutingModel::SetupTrace(const RoutingSearchParameters &search_parameters) { +void RoutingModel::SetupTrace( + const RoutingSearchParameters &search_parameters) { if (search_parameters.log_search()) { Solver::SearchLogParameters search_log_parameters; search_log_parameters.branch_period = 10000; @@ -5710,8 +5608,7 @@ RoutingModel::SetupTrace(const RoutingSearchParameters &search_parameters) { search_log_parameters.offset = search_parameters.log_cost_offset(); if (!search_parameters.log_tag().empty()) { const std::string &tag = search_parameters.log_tag(); - search_log_parameters.display_callback = [tag]() { return tag; } - ; + search_log_parameters.display_callback = [tag]() { return tag; }; } else { search_log_parameters.display_callback = nullptr; } @@ -5724,7 +5621,7 @@ void RoutingModel::SetupImprovementLimit( const RoutingSearchParameters &search_parameters) { if (search_parameters.has_improvement_limit_parameters()) { monitors_.push_back(solver_->MakeImprovementLimit( - cost_, /*maximize=*/ false, search_parameters.log_cost_scaling_factor(), + cost_, /*maximize=*/false, search_parameters.log_cost_scaling_factor(), search_parameters.log_cost_offset(), search_parameters.improvement_limit_parameters() .improvement_rate_coefficient(), @@ -5765,8 +5662,7 @@ void RoutingModel::AddWeightedVariableMinimizedByFinalizer(IntVar *var, void RoutingModel::AddVariableTargetToFinalizer(IntVar *var, int64 target) { CHECK(var != nullptr); - if (finalizer_variable_target_set_.contains(var)) - return; + if (finalizer_variable_target_set_.contains(var)) return; finalizer_variable_target_set_.insert(var); finalizer_variable_target_pairs_.emplace_back(var, target); } @@ -5779,8 +5675,8 @@ void RoutingModel::AddVariableMinimizedByFinalizer(IntVar *var) { AddVariableTargetToFinalizer(var, kint64min); } -void -RoutingModel::SetupSearch(const RoutingSearchParameters &search_parameters) { +void RoutingModel::SetupSearch( + const RoutingSearchParameters &search_parameters) { SetupDecisionBuilders(search_parameters); SetupSearchMonitors(search_parameters); } @@ -5796,13 +5692,16 @@ void RoutingModel::AddIntervalToAssignment(IntervalVar *const interval) { namespace { class PathSpansAndTotalSlacks : public Constraint { -public: + public: PathSpansAndTotalSlacks(const RoutingModel *model, const RoutingDimension *dimension, std::vector spans, std::vector total_slacks) - : Constraint(model->solver()), model_(model), dimension_(dimension), - spans_(std::move(spans)), total_slacks_(std::move(total_slacks)) { + : Constraint(model->solver()), + model_(model), + dimension_(dimension), + spans_(std::move(spans)), + total_slacks_(std::move(total_slacks)) { CHECK_EQ(spans_.size(), model_->vehicles()); CHECK_EQ(total_slacks_.size(), model_->vehicles()); vehicle_demons_.resize(model_->vehicles()); @@ -5826,16 +5725,13 @@ public: } } for (int vehicle = 0; vehicle < spans_.size(); ++vehicle) { - if (!spans_[vehicle] && !total_slacks_[vehicle]) - continue; + if (!spans_[vehicle] && !total_slacks_[vehicle]) continue; auto *demon = MakeDelayedConstraintDemon1( solver(), this, &PathSpansAndTotalSlacks::PropagateVehicle, "PathSpansAndTotalSlacks::PropagateVehicle", vehicle); vehicle_demons_[vehicle] = demon; - if (spans_[vehicle]) - spans_[vehicle]->WhenRange(demon); - if (total_slacks_[vehicle]) - total_slacks_[vehicle]->WhenRange(demon); + if (spans_[vehicle]) spans_[vehicle]->WhenRange(demon); + if (total_slacks_[vehicle]) total_slacks_[vehicle]->WhenRange(demon); if (dimension_->HasBreakConstraints()) { for (IntervalVar *b : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { b->WhenAnything(demon); @@ -5847,22 +5743,19 @@ public: // Call propagator on all vehicles. void InitialPropagate() override { for (int vehicle = 0; vehicle < spans_.size(); ++vehicle) { - if (!spans_[vehicle] && !total_slacks_[vehicle]) - continue; + if (!spans_[vehicle] && !total_slacks_[vehicle]) continue; PropagateVehicle(vehicle); } } -private: + private: // Called when a path/dimension variables of the node changes, // this delays propagator calls until path variables (Next and VehicleVar) // are instantiated, which saves fruitless and multiple identical calls. void PropagateNode(int node) { - if (!model_->VehicleVar(node)->Bound()) - return; + if (!model_->VehicleVar(node)->Bound()) return; const int vehicle = model_->VehicleVar(node)->Min(); - if (vehicle < 0 || vehicle_demons_[vehicle] == nullptr) - return; + if (vehicle < 0 || vehicle_demons_[vehicle] == nullptr) return; EnqueueDelayedDemon(vehicle_demons_[vehicle]); } @@ -5909,8 +5802,7 @@ private: DCHECK_GE(sum_fixed_transits, 0); IntVar *span = spans_[vehicle]; IntVar *total_slack = total_slacks_[vehicle]; - if (!span || !total_slack) - return; + if (!span || !total_slack) return; span->SetMin(CapAdd(total_slack->Min(), sum_fixed_transits)); span->SetMax(CapAdd(total_slack->Max(), sum_fixed_transits)); total_slack->SetMin(CapSub(span->Min(), sum_fixed_transits)); @@ -5929,8 +5821,7 @@ private: int curr_node = start; while (!model_->IsEnd(curr_node)) { const IntVar *next_var = model_->NextVar(curr_node); - if (!next_var->Bound()) - return; + if (!next_var->Bound()) return; path_.push_back(curr_node); curr_node = next_var->Value(); } @@ -5940,8 +5831,7 @@ private: int64 sum_fixed_transits = 0; for (const int node : path_) { const IntVar *fixed_transit_var = dimension_->FixedTransitVar(node); - if (!fixed_transit_var->Bound()) - return; + if (!fixed_transit_var->Bound()) return; sum_fixed_transits = CapAdd(sum_fixed_transits, fixed_transit_var->Value()); } @@ -5960,8 +5850,7 @@ private: // Compute and propagate lower bound. int64 min_break_duration = 0; for (IntervalVar *br : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { - if (!br->MustBePerformed()) - continue; + if (!br->MustBePerformed()) continue; if (vehicle_start_max < br->EndMin() && br->StartMax() < vehicle_end_min) { min_break_duration = CapAdd(min_break_duration, br->DurationMin()); @@ -5978,8 +5867,7 @@ private: CapSub(SpanMax(vehicle, sum_fixed_transits), sum_fixed_transits); const int64 max_additional_slack = CapSub(slack_max, min_break_duration); for (IntervalVar *br : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { - if (!br->MustBePerformed()) - continue; + if (!br->MustBePerformed()) continue; // Break must be before end, detect whether it must be before start. if (vehicle_start_max >= br->EndMin() && br->StartMax() < vehicle_end_min) { @@ -6115,8 +6003,8 @@ private: SetSpanMin(vehicle, span_lb, sum_fixed_transits); const int64 maximum_deviation = CapSub(SpanMax(vehicle, sum_fixed_transits), span_lb); - dimension_->CumulVar(end) - ->SetMax(CapAdd(arrival_time, maximum_deviation)); + dimension_->CumulVar(end)->SetMax( + CapAdd(arrival_time, maximum_deviation)); } } @@ -6128,12 +6016,11 @@ private: std::vector vehicle_demons_; }; -} // namespace +} // namespace -Constraint * -RoutingModel::MakePathSpansAndTotalSlacks(const RoutingDimension *dimension, - std::vector spans, - std::vector total_slacks) { +Constraint *RoutingModel::MakePathSpansAndTotalSlacks( + const RoutingDimension *dimension, std::vector spans, + std::vector total_slacks) { CHECK_EQ(vehicles_, spans.size()); CHECK_EQ(vehicles_, total_slacks.size()); return solver()->RevAlloc( @@ -6149,8 +6036,11 @@ RoutingDimension::RoutingDimension(RoutingModel *model, const std::string &name, const RoutingDimension *base_dimension) : vehicle_capacities_(std::move(vehicle_capacities)), - base_dimension_(base_dimension), global_span_cost_coefficient_(0), - model_(model), name_(name), global_optimizer_offset_(0) { + base_dimension_(base_dimension), + global_span_cost_coefficient_(0), + model_(model), + name_(name), + global_optimizer_offset_(0) { CHECK(model != nullptr); vehicle_span_upper_bounds_.assign(model->vehicles(), kint64max); vehicle_span_cost_coefficients_.assign(model->vehicles(), 0); @@ -6185,7 +6075,7 @@ namespace { // and is only fit for local search, in particular in the context of vehicle // routing. class LightRangeLessOrEqual : public Constraint { -public: + public: LightRangeLessOrEqual(Solver *const s, IntExpr *const l, IntExpr *const r); ~LightRangeLessOrEqual() override {} void Post() override; @@ -6203,7 +6093,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this); } -private: + private: void CheckRange(); IntExpr *const left_; @@ -6243,7 +6133,7 @@ std::string LightRangeLessOrEqual::DebugString() const { return left_->DebugString() + " < " + right_->DebugString(); } -} // namespace +} // namespace void RoutingDimension::InitializeCumuls() { Solver *const solver = model_->solver(); @@ -6306,7 +6196,7 @@ void ComputeTransitClasses(const std::vector &evaluator_indices, (*vehicle_to_class)[i] = evaluator_class; } } -} // namespace +} // namespace void RoutingDimension::InitializeTransitVariables(int64 slack_max) { CHECK(!class_evaluators_.empty()); @@ -6317,11 +6207,10 @@ void RoutingDimension::InitializeTransitVariables(int64 slack_max) { const int size = model_->Size(); const Solver::IndexEvaluator1 dependent_vehicle_class_function = [this](int index) { - return (0 <= index && index < state_dependent_vehicle_to_class_.size()) - ? state_dependent_vehicle_to_class_[index] - : state_dependent_class_evaluators_.size(); - } - ; + return (0 <= index && index < state_dependent_vehicle_to_class_.size()) + ? state_dependent_vehicle_to_class_[index] + : state_dependent_class_evaluators_.size(); + }; const std::string slack_name = name_ + " slack"; const std::string transit_name = name_ + " fixed transit"; @@ -6333,30 +6222,40 @@ void RoutingDimension::InitializeTransitVariables(int64 slack_max) { if (state_dependent_class_evaluators_.size() == 1) { std::vector transition_variables(cumuls_.size(), nullptr); for (int64 j = 0; j < cumuls_.size(); ++j) { - transition_variables[j] = MakeRangeMakeElementExpr( - model_->StateDependentTransitCallback( - state_dependent_class_evaluators_[0])(i, j) - .transit, - base_dimension_->CumulVar(i), solver)->Var(); + transition_variables[j] = + MakeRangeMakeElementExpr( + model_ + ->StateDependentTransitCallback( + state_dependent_class_evaluators_[0])(i, j) + .transit, + base_dimension_->CumulVar(i), solver) + ->Var(); } - dependent_transits_[i] = solver - ->MakeElement(transition_variables, model_->NextVar(i))->Var(); + dependent_transits_[i] = + solver->MakeElement(transition_variables, model_->NextVar(i)) + ->Var(); } else { IntVar *const vehicle_class_var = - solver->MakeElement(dependent_vehicle_class_function, - model_->VehicleVar(i))->Var(); + solver + ->MakeElement(dependent_vehicle_class_function, + model_->VehicleVar(i)) + ->Var(); std::vector transit_for_vehicle; transit_for_vehicle.reserve(state_dependent_class_evaluators_.size() + 1); for (int evaluator : state_dependent_class_evaluators_) { std::vector transition_variables(cumuls_.size(), nullptr); for (int64 j = 0; j < cumuls_.size(); ++j) { - transition_variables[j] = MakeRangeMakeElementExpr( - model_->StateDependentTransitCallback(evaluator)(i, j).transit, - base_dimension_->CumulVar(i), solver)->Var(); + transition_variables[j] = + MakeRangeMakeElementExpr( + model_->StateDependentTransitCallback(evaluator)(i, j) + .transit, + base_dimension_->CumulVar(i), solver) + ->Var(); } - transit_for_vehicle.push_back(solver->MakeElement( - transition_variables, model_->NextVar(i))->Var()); + transit_for_vehicle.push_back( + solver->MakeElement(transition_variables, model_->NextVar(i)) + ->Var()); } transit_for_vehicle.push_back(solver->MakeIntConst(0)); dependent_transits_[i] = @@ -6610,9 +6509,11 @@ bool TypeRequirementChecker::FinalizeCheck() const { } TypeRegulationsConstraint::TypeRegulationsConstraint(const RoutingModel &model) - : Constraint(model.solver()), model_(model), + : Constraint(model.solver()), + model_(model), incompatibility_checker_(model, /*check_hard_incompatibilities*/ true), - requirement_checker_(model), vehicle_demons_(model.vehicles()) {} + requirement_checker_(model), + vehicle_demons_(model.vehicles()) {} void TypeRegulationsConstraint::PropagateNodeRegulations(int node) { DCHECK_LT(node, model_.Size()); @@ -6621,8 +6522,7 @@ void TypeRegulationsConstraint::PropagateNodeRegulations(int node) { return; } const int vehicle = model_.VehicleVar(node)->Min(); - if (vehicle < 0) - return; + if (vehicle < 0) return; DCHECK(vehicle_demons_[vehicle] != nullptr); EnqueueDelayedDemon(vehicle_demons_[vehicle]); } @@ -6634,8 +6534,7 @@ void TypeRegulationsConstraint::CheckRegulationsOnVehicle(int vehicle) { } // Node not bound, skip to the end of the vehicle. return model_.End(vehicle); - } - ; + }; if (!incompatibility_checker_.CheckVehicle(vehicle, next_accessor) || !requirement_checker_.CheckVehicle(vehicle, next_accessor)) { model_.solver()->Fail(); @@ -6667,16 +6566,14 @@ void RoutingDimension::CloseModel(bool use_light_propagation) { Solver *const solver = model_->solver(); const auto capacity_lambda = [this](int64 vehicle) { return vehicle >= 0 ? vehicle_capacities_[vehicle] : kint64max; - } - ; + }; for (int i = 0; i < capacity_vars_.size(); ++i) { IntVar *const vehicle_var = model_->VehicleVar(i); IntVar *const capacity_var = capacity_vars_[i]; if (use_light_propagation) { - solver->AddConstraint(MakeLightElement(solver, capacity_var, vehicle_var, - capacity_lambda, [this]() { - return model_->enable_deep_serialization_; - })); + solver->AddConstraint(MakeLightElement( + solver, capacity_var, vehicle_var, capacity_lambda, + [this]() { return model_->enable_deep_serialization_; })); } else { solver->AddConstraint(solver->MakeEquality( capacity_var, @@ -6684,39 +6581,35 @@ void RoutingDimension::CloseModel(bool use_light_propagation) { } } const Solver::IndexEvaluator1 vehicle_class_function = [this](int index) { - return IthElementOrValue< -1>(vehicle_to_class_, index); - } - ; + return IthElementOrValue<-1>(vehicle_to_class_, index); + }; for (int i = 0; i < fixed_transits_.size(); ++i) { IntVar *const next_var = model_->NextVar(i); IntVar *const fixed_transit = fixed_transits_[i]; - const auto transit_vehicle_evaluator = - [this, i](int64 to, int64 eval_index) { + const auto transit_vehicle_evaluator = [this, i](int64 to, + int64 eval_index) { return eval_index >= 0 ? transit_evaluator(eval_index)(i, to) : 0; - } - ; + }; if (use_light_propagation) { if (class_evaluators_.size() == 1) { const int class_evaluator_index = class_evaluators_[0]; const auto &unary_callback = model_->UnaryTransitCallbackOrNull(class_evaluator_index); if (unary_callback == nullptr) { - solver->AddConstraint(MakeLightElement(solver, fixed_transit, - next_var, [this, i](int64 to) { - return model_->TransitCallback(class_evaluators_[0])(i, to); - }, - [this]() { - return model_->enable_deep_serialization_; - })); + solver->AddConstraint(MakeLightElement( + solver, fixed_transit, next_var, + [this, i](int64 to) { + return model_->TransitCallback(class_evaluators_[0])(i, to); + }, + [this]() { return model_->enable_deep_serialization_; })); } else { fixed_transit->SetValue(unary_callback(i)); } } else { solver->AddConstraint(MakeLightElement2( solver, fixed_transit, next_var, model_->VehicleVar(i), - transit_vehicle_evaluator, [this]() { - return model_->enable_deep_serialization_; - })); + transit_vehicle_evaluator, + [this]() { return model_->enable_deep_serialization_; })); } } else { if (class_evaluators_.size() == 1) { @@ -6725,20 +6618,26 @@ void RoutingDimension::CloseModel(bool use_light_propagation) { model_->UnaryTransitCallbackOrNull(class_evaluator_index); if (unary_callback == nullptr) { solver->AddConstraint(solver->MakeEquality( - fixed_transit, solver->MakeElement([this, i](int64 to) { - return model_->TransitCallback(class_evaluators_[0])(i, to); - }, - model_->NextVar(i))->Var())); + fixed_transit, solver + ->MakeElement( + [this, i](int64 to) { + return model_->TransitCallback( + class_evaluators_[0])(i, to); + }, + model_->NextVar(i)) + ->Var())); } else { fixed_transit->SetValue(unary_callback(i)); } } else { - IntVar *const vehicle_class_var = solver - ->MakeElement(vehicle_class_function, model_->VehicleVar(i))->Var(); + IntVar *const vehicle_class_var = + solver->MakeElement(vehicle_class_function, model_->VehicleVar(i)) + ->Var(); solver->AddConstraint(solver->MakeEquality( - fixed_transit, - solver->MakeElement(transit_vehicle_evaluator, next_var, - vehicle_class_var)->Var())); + fixed_transit, solver + ->MakeElement(transit_vehicle_evaluator, + next_var, vehicle_class_var) + ->Var())); } } } @@ -6755,9 +6654,8 @@ int64 RoutingDimension::GetTransitValue(int64 from_index, int64 to_index, return transit_evaluator(vehicle)(from_index, to_index); } -SortedDisjointIntervalList -RoutingDimension::GetAllowedIntervalsInRange(int64 index, int64 min_value, - int64 max_value) const { +SortedDisjointIntervalList RoutingDimension::GetAllowedIntervalsInRange( + int64 index, int64 min_value, int64 max_value) const { SortedDisjointIntervalList allowed; const SortedDisjointIntervalList &forbidden = forbidden_intervals_[index]; IntVar *const cumul_var = cumuls_[index]; @@ -6767,8 +6665,7 @@ RoutingDimension::GetAllowedIntervalsInRange(int64 index, int64 min_value, for (SortedDisjointIntervalList::Iterator interval = forbidden.FirstIntervalGreaterOrEqual(min); interval != forbidden.end(); ++interval) { - if (next_start > max) - break; + if (next_start > max) break; if (next_start < interval->start) { allowed.InsertInterval(next_start, CapSub(interval->start, 1)); } @@ -6830,8 +6727,8 @@ bool RoutingDimension::HasCumulVarPiecewiseLinearCost(int64 index) const { cumul_var_piecewise_linear_cost_[index].var != nullptr); } -const PiecewiseLinearFunction * -RoutingDimension::GetCumulVarPiecewiseLinearCost(int64 index) const { +const PiecewiseLinearFunction *RoutingDimension::GetCumulVarPiecewiseLinearCost( + int64 index) const { if (index < cumul_var_piecewise_linear_cost_.size() && cumul_var_piecewise_linear_cost_[index].var != nullptr) { return cumul_var_piecewise_linear_cost_[index].cost.get(); @@ -6851,7 +6748,7 @@ IntVar *BuildVarFromExprAndIndexActiveState(const RoutingModel *model, } return solver->MakeProd(expr, model->ActiveVar(index))->Var(); } -} // namespace +} // namespace void RoutingDimension::SetupCumulVarPiecewiseLinearCosts( std::vector *cost_elements) const { @@ -6875,12 +6772,10 @@ void RoutingDimension::SetupCumulVarPiecewiseLinearCosts( void RoutingDimension::SetCumulVarSoftUpperBound(int64 index, int64 upper_bound, int64 coefficient) { if (index >= cumul_var_soft_upper_bound_.size()) { - cumul_var_soft_upper_bound_.resize(index + 1, { - nullptr, 0, 0 - }); + cumul_var_soft_upper_bound_.resize(index + 1, {nullptr, 0, 0}); } - cumul_var_soft_upper_bound_[index] = { cumuls_[index], upper_bound, - coefficient }; + cumul_var_soft_upper_bound_[index] = {cumuls_[index], upper_bound, + coefficient}; } bool RoutingDimension::HasCumulVarSoftUpperBound(int64 index) const { @@ -6896,8 +6791,8 @@ int64 RoutingDimension::GetCumulVarSoftUpperBound(int64 index) const { return cumuls_[index]->Max(); } -int64 -RoutingDimension::GetCumulVarSoftUpperBoundCoefficient(int64 index) const { +int64 RoutingDimension::GetCumulVarSoftUpperBoundCoefficient( + int64 index) const { if (index < cumul_var_soft_upper_bound_.size() && cumul_var_soft_upper_bound_[index].var != nullptr) { return cumul_var_soft_upper_bound_[index].coefficient; @@ -6928,12 +6823,10 @@ void RoutingDimension::SetupCumulVarSoftUpperBoundCosts( void RoutingDimension::SetCumulVarSoftLowerBound(int64 index, int64 lower_bound, int64 coefficient) { if (index >= cumul_var_soft_lower_bound_.size()) { - cumul_var_soft_lower_bound_.resize(index + 1, { - nullptr, 0, 0 - }); + cumul_var_soft_lower_bound_.resize(index + 1, {nullptr, 0, 0}); } - cumul_var_soft_lower_bound_[index] = { cumuls_[index], lower_bound, - coefficient }; + cumul_var_soft_lower_bound_[index] = {cumuls_[index], lower_bound, + coefficient}; } bool RoutingDimension::HasCumulVarSoftLowerBound(int64 index) const { @@ -6949,8 +6842,8 @@ int64 RoutingDimension::GetCumulVarSoftLowerBound(int64 index) const { return cumuls_[index]->Min(); } -int64 -RoutingDimension::GetCumulVarSoftLowerBoundCoefficient(int64 index) const { +int64 RoutingDimension::GetCumulVarSoftLowerBoundCoefficient( + int64 index) const { if (index < cumul_var_soft_lower_bound_.size() && cumul_var_soft_lower_bound_[index].var != nullptr) { return cumul_var_soft_lower_bound_[index].coefficient; @@ -6985,8 +6878,9 @@ void RoutingDimension::SetupGlobalSpanCost( if (global_span_cost_coefficient_ != 0) { std::vector end_cumuls; for (int i = 0; i < model_->vehicles(); ++i) { - end_cumuls.push_back(solver->MakeProd( - model_->vehicle_costs_considered_[i], cumuls_[model_->End(i)]) + end_cumuls.push_back(solver + ->MakeProd(model_->vehicle_costs_considered_[i], + cumuls_[model_->End(i)]) ->Var()); } IntVar *const max_end_cumul = solver->MakeMax(end_cumuls)->Var(); @@ -7010,14 +6904,17 @@ void RoutingDimension::SetupGlobalSpanCost( for (int var_index = 0; var_index < model_->Size(); ++var_index) { model_->AddWeightedVariableMinimizedByFinalizer( slacks_[var_index], global_span_cost_coefficient_); - cost_elements->push_back(solver->MakeProd( - model_->vehicle_costs_considered_[0], - solver->MakeProd( - solver->MakeProd( - solver->MakeSum(transits_[var_index], - dependent_transits_[var_index]), - global_span_cost_coefficient_), - model_->ActiveVar(var_index)))->Var()); + cost_elements->push_back( + solver + ->MakeProd( + model_->vehicle_costs_considered_[0], + solver->MakeProd( + solver->MakeProd( + solver->MakeSum(transits_[var_index], + dependent_transits_[var_index]), + global_span_cost_coefficient_), + model_->ActiveVar(var_index))) + ->Var()); } } else { IntVar *const end_range = @@ -7032,12 +6929,11 @@ void RoutingDimension::SetupGlobalSpanCost( void RoutingDimension::SetBreakIntervalsOfVehicle( std::vector breaks, int vehicle, std::vector node_visit_transits) { - if (breaks.empty()) - return; + if (breaks.empty()) return; const int visit_evaluator = model()->RegisterTransitCallback( [node_visit_transits](int64 from, int64 to) { - return node_visit_transits[from]; - }); + return node_visit_transits[from]; + }); SetBreakIntervalsOfVehicle(std::move(breaks), vehicle, visit_evaluator, -1); } @@ -7045,12 +6941,11 @@ void RoutingDimension::SetBreakIntervalsOfVehicle( std::vector breaks, int vehicle, std::vector node_visit_transits, std::function group_delays) { - if (breaks.empty()) - return; + if (breaks.empty()) return; const int visit_evaluator = model()->RegisterTransitCallback( [node_visit_transits](int64 from, int64 to) { - return node_visit_transits[from]; - }); + return node_visit_transits[from]; + }); const int delay_evaluator = model()->RegisterTransitCallback(group_delays); SetBreakIntervalsOfVehicle(std::move(breaks), vehicle, visit_evaluator, delay_evaluator); @@ -7061,10 +6956,8 @@ void RoutingDimension::SetBreakIntervalsOfVehicle( int post_travel_evaluator) { DCHECK_LE(0, vehicle); DCHECK_LT(vehicle, model_->vehicles()); - if (breaks.empty()) - return; - if (!break_constraints_are_initialized_) - InitializeBreaks(); + if (breaks.empty()) return; + if (!break_constraints_are_initialized_) InitializeBreaks(); vehicle_break_intervals_[vehicle] = std::move(breaks); vehicle_pre_travel_evaluators_[vehicle] = pre_travel_evaluator; vehicle_post_travel_evaluators_[vehicle] = post_travel_evaluator; @@ -7101,8 +6994,8 @@ bool RoutingDimension::HasBreakConstraints() const { return break_constraints_are_initialized_; } -const std::vector & -RoutingDimension::GetBreakIntervalsOfVehicle(int vehicle) const { +const std::vector &RoutingDimension::GetBreakIntervalsOfVehicle( + int vehicle) const { DCHECK_LE(0, vehicle); DCHECK_LT(vehicle, vehicle_break_intervals_.size()); return vehicle_break_intervals_[vehicle]; @@ -7125,8 +7018,7 @@ void RoutingDimension::SetBreakDistanceDurationOfVehicle(int64 distance, int vehicle) { DCHECK_LE(0, vehicle); DCHECK_LT(vehicle, model_->vehicles()); - if (!break_constraints_are_initialized_) - InitializeBreaks(); + if (!break_constraints_are_initialized_) InitializeBreaks(); vehicle_break_distance_duration_[vehicle].emplace_back(distance, duration); // When a vehicle has breaks, if its start and end are fixed, // then propagation keeps the cumuls min and max on its path feasible. @@ -7136,8 +7028,8 @@ void RoutingDimension::SetBreakDistanceDurationOfVehicle(int64 distance, kint64max); } -const std::vector > & -RoutingDimension::GetBreakDistanceDurationOfVehicle(int vehicle) const { +const std::vector > + &RoutingDimension::GetBreakDistanceDurationOfVehicle(int vehicle) const { DCHECK_LE(0, vehicle); DCHECK_LT(vehicle, vehicle_break_distance_duration_.size()); return vehicle_break_distance_duration_[vehicle]; @@ -7177,8 +7069,7 @@ int64 RoutingDimension::GetPickupToDeliveryLimitForPair(int pair_index, } void RoutingDimension::SetupSlackAndDependentTransitCosts() const { - if (model_->vehicles() == 0) - return; + if (model_->vehicles() == 0) return; // Figure out whether all vehicles have the same span cost coefficient or not. bool all_vehicle_span_costs_are_equal = true; for (int i = 1; i < model_->vehicles(); ++i) { @@ -7188,7 +7079,7 @@ void RoutingDimension::SetupSlackAndDependentTransitCosts() const { if (all_vehicle_span_costs_are_equal && vehicle_span_cost_coefficients_[0] == 0) { - return; // No vehicle span cost. + return; // No vehicle span cost. } // Make sure that the vehicle's start cumul will be maximized in the end; @@ -7200,8 +7091,7 @@ void RoutingDimension::SetupSlackAndDependentTransitCosts() const { // Also, it makes more sense to make decisions from the root of the tree // towards to leaves, and hence the slacks are pushed in reverse order. std::vector dimensions_with_relevant_slacks = { - this - }; + this}; while (true) { const RoutingDimension *next = dimensions_with_relevant_slacks.back()->base_dimension_; @@ -7224,4 +7114,4 @@ void RoutingDimension::SetupSlackAndDependentTransitCosts() const { } } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing.h b/ortools/constraint_solver/routing.h index 7267998ff9..ae6a430823 100644 --- a/ortools/constraint_solver/routing.h +++ b/ortools/constraint_solver/routing.h @@ -209,7 +209,7 @@ class SweepArranger; struct SweepIndex; class RoutingModel { -public: + public: /// Status of the search. enum Status { /// Problem not solved yet (before calling RoutingModel::Solve()). @@ -244,7 +244,7 @@ public: #if !defined(SWIG) typedef RoutingIndexPair IndexPair; typedef RoutingIndexPairs IndexPairs; -#endif // SWIG +#endif // SWIG #if !defined(SWIG) /// What follows is relevant for models with time/state dependent transits. @@ -260,12 +260,12 @@ public: /// routing library, which works out-of-the-box, with very good running time, /// but memory inefficient in some situations. struct StateDependentTransit { - RangeIntToIntFunction *transit; /// f(x) - RangeMinMaxIndexFunction *transit_plus_identity; /// g(x) = f(x) + x + RangeIntToIntFunction *transit; /// f(x) + RangeMinMaxIndexFunction *transit_plus_identity; /// g(x) = f(x) + x }; typedef std::function VariableIndexEvaluator2; -#endif // SWIG +#endif // SWIG #if !defined(SWIG) struct CostClass { @@ -348,7 +348,7 @@ public: /// Comparator for STL containers and algorithms. static bool LessThan(const VehicleClass &a, const VehicleClass &b); }; -#endif // defined(SWIG) +#endif // defined(SWIG) /// Struct used to sort and store vehicles by their type. Two vehicles have /// the same "vehicle type" iff they have the same cost class and start/end @@ -411,8 +411,8 @@ public: CHECK_LT(callback_index, unary_transit_evaluators_.size()); return unary_transit_evaluators_[callback_index]; } - const VariableIndexEvaluator2 & - StateDependentTransitCallback(int callback_index) const { + const VariableIndexEvaluator2 &StateDependentTransitCallback( + int callback_index) const { CHECK_LT(callback_index, state_dependent_transit_evaluators_.size()); return state_dependent_transit_evaluators_[callback_index]; } @@ -522,9 +522,9 @@ public: const std::string &name); /// Creates a cached StateDependentTransit from an std::function. - static RoutingModel::StateDependentTransit - MakeStateDependentTransit(const std::function &f, - int64 domain_start, int64 domain_end); + static RoutingModel::StateDependentTransit MakeStateDependentTransit( + const std::function &f, int64 domain_start, + int64 domain_end); /// For every vehicle of the routing model: /// - if total_slacks[vehicle] is not nullptr, constrains it to be the sum of @@ -567,22 +567,22 @@ public: /// Returns the global/local dimension cumul optimizer for a given dimension, /// or nullptr if there is none. - GlobalDimensionCumulOptimizer * - GetMutableGlobalCumulOptimizer(const RoutingDimension &dimension) const; - LocalDimensionCumulOptimizer * - GetMutableLocalCumulOptimizer(const RoutingDimension &dimension) const; - LocalDimensionCumulOptimizer * - GetMutableLocalCumulMPOptimizer(const RoutingDimension &dimension) const; + GlobalDimensionCumulOptimizer *GetMutableGlobalCumulOptimizer( + const RoutingDimension &dimension) const; + LocalDimensionCumulOptimizer *GetMutableLocalCumulOptimizer( + const RoutingDimension &dimension) const; + LocalDimensionCumulOptimizer *GetMutableLocalCumulMPOptimizer( + const RoutingDimension &dimension) const; /// Returns true if a dimension exists for a given dimension name. bool HasDimension(const std::string &dimension_name) const; /// Returns a dimension from its name. Dies if the dimension does not exist. - const RoutingDimension & - GetDimensionOrDie(const std::string &dimension_name) const; + const RoutingDimension &GetDimensionOrDie( + const std::string &dimension_name) const; /// Returns a dimension from its name. Returns nullptr if the dimension does /// not exist. - RoutingDimension * - GetMutableDimension(const std::string &dimension_name) const; + RoutingDimension *GetMutableDimension( + const std::string &dimension_name) const; /// Set the given dimension as "primary constrained". As of August 2013, this /// is only used by ArcIsMoreConstrainedThanArc(). /// "dimension" must be the name of an existing dimension, or be empty, in @@ -615,8 +615,8 @@ public: int64 penalty = kNoPenalty, int64 max_cardinality = 1); /// Returns the indices of the disjunctions to which an index belongs. - const std::vector & - GetDisjunctionIndices(int64 index) const { + const std::vector &GetDisjunctionIndices( + int64 index) const { return index_to_disjunctions_[index]; } /// Calls f for each variable index of indices in the same disjunctions as the @@ -636,12 +636,12 @@ public: #if !defined(SWIGPYTHON) /// Returns the variable indices of the nodes in the disjunction of index /// 'index'. - const std::vector & - GetDisjunctionIndices(DisjunctionIndex index) const { + const std::vector &GetDisjunctionIndices( + DisjunctionIndex index) const { return disjunctions_[index].indices; } -#endif // !defined(SWIGPYTHON) - /// Returns the penalty of the node disjunction of index 'index'. +#endif // !defined(SWIGPYTHON) + /// Returns the penalty of the node disjunction of index 'index'. int64 GetDisjunctionPenalty(DisjunctionIndex index) const { return disjunctions_[index].value.penalty; } @@ -721,8 +721,8 @@ public: void SetPickupAndDeliveryPolicyOfAllVehicles(PickupAndDeliveryPolicy policy); void SetPickupAndDeliveryPolicyOfVehicle(PickupAndDeliveryPolicy policy, int vehicle); - PickupAndDeliveryPolicy - GetPickupAndDeliveryPolicyOfVehicle(int vehicle) const; + PickupAndDeliveryPolicy GetPickupAndDeliveryPolicyOfVehicle( + int vehicle) const; /// Returns the number of non-start/end nodes which do not appear in a /// pickup/delivery pair. @@ -733,11 +733,11 @@ public: const IndexPairs &GetPickupAndDeliveryPairs() const { return pickup_delivery_pairs_; } - const std::vector > & - GetPickupAndDeliveryDisjunctions() const { + const std::vector > + &GetPickupAndDeliveryDisjunctions() const { return pickup_delivery_disjunctions_; } -#endif // SWIG +#endif // SWIG /// Set the node visit types and incompatibilities/requirements between the /// types (see below). /// @@ -779,23 +779,23 @@ public: void CloseVisitTypes(); int GetNumberOfVisitTypes() const { return num_visit_types_; } #ifndef SWIG - const std::vector > & - GetTopologicallySortedVisitTypes() const { + const std::vector > &GetTopologicallySortedVisitTypes() + const { DCHECK(closed_); return topologically_sorted_visit_types_; } -#endif // SWIG - /// Incompatibilities: +#endif // SWIG + /// Incompatibilities: /// Two nodes with "hard" incompatible types cannot share the same route at /// all, while with a "temporal" incompatibility they can't be on the same /// route at the same time. void AddHardTypeIncompatibility(int type1, int type2); void AddTemporalTypeIncompatibility(int type1, int type2); /// Returns visit types incompatible with a given type. - const absl::flat_hash_set & - GetHardTypeIncompatibilitiesOfType(int type) const; - const absl::flat_hash_set & - GetTemporalTypeIncompatibilitiesOfType(int type) const; + const absl::flat_hash_set &GetHardTypeIncompatibilitiesOfType( + int type) const; + const absl::flat_hash_set &GetTemporalTypeIncompatibilitiesOfType( + int type) const; /// Returns true iff any hard (resp. temporal) type incompatibilities have /// been added to the model. bool HasHardTypeIncompatibilities() const { @@ -995,9 +995,9 @@ public: /// 'search_parameters'. Note that the Assignment returned by the method and /// the ones in solutions are owned by the underlying solver and should not be /// deleted. - const Assignment * - SolveWithParameters(const RoutingSearchParameters &search_parameters, - std::vector *solutions = nullptr); + const Assignment *SolveWithParameters( + const RoutingSearchParameters &search_parameters, + std::vector *solutions = nullptr); const Assignment *SolveFromAssignmentWithParameters( const Assignment *assignment, const RoutingSearchParameters &search_parameters, @@ -1060,9 +1060,9 @@ public: /// that calling this method will run the solver to assign values to the /// dimension variables; this may take considerable amount of time, especially /// when using dimensions with slack. - Assignment * - ReadAssignmentFromRoutes(const std::vector > &routes, - bool ignore_inactive_indices); + Assignment *ReadAssignmentFromRoutes( + const std::vector > &routes, + bool ignore_inactive_indices); /// Fills an assignment from a specification of the routes of the /// vehicles. The routes are specified as lists of variable indices that /// appear on the routes of the vehicles. The indices of the outer vector in @@ -1092,8 +1092,8 @@ public: /// for jth location visited on route i. Note that contrary to /// AssignmentToRoutes, the vectors do include start and end locations. #ifndef SWIG - std::vector > - GetRoutesFromAssignment(const Assignment &assignment); + std::vector > GetRoutesFromAssignment( + const Assignment &assignment); #endif /// Returns a compacted version of the given assignment, in which all vehicles /// with id lower or equal to some N have non-empty routes, and all vehicles @@ -1150,12 +1150,8 @@ public: if (closed_) { LOG(WARNING) << "Model is closed, filter addition will be ignored."; } - extra_filters_.push_back({ - filter, LocalSearchFilterManager::kRelax - }); - extra_filters_.push_back({ - filter, LocalSearchFilterManager::kAccept - }); + extra_filters_.push_back({filter, LocalSearchFilterManager::kRelax}); + extra_filters_.push_back({filter, LocalSearchFilterManager::kAccept}); } /// Model inspection. @@ -1184,7 +1180,7 @@ public: /// Returns all vehicle variables of the model, such that VehicleVars(i) is /// the vehicle variable of the node corresponding to i. const std::vector &VehicleVars() const { return vehicle_vars_; } -#endif /// !defined(SWIGPYTHON) +#endif /// !defined(SWIGPYTHON) /// Returns the next variable of the node corresponding to index. Note that /// NextVar(index) == index is equivalent to ActiveVar(index) == 0. IntVar *NextVar(int64 index) const { return nexts_[index]; } @@ -1217,7 +1213,7 @@ public: /// Returns the cost of the segment between two nodes supposing all vehicle /// costs are the same (returns the cost for the first vehicle otherwise). int64 GetHomogeneousCost(int64 from_index, int64 to_index) const { - return GetArcCostForVehicle(from_index, to_index, /*vehicle=*/ 0); + return GetArcCostForVehicle(from_index, to_index, /*vehicle=*/0); } /// Returns the cost of the arc in the context of the first solution strategy. /// This is typically a simplification of the actual cost; see the .cc. @@ -1293,18 +1289,17 @@ public: /// feasible intervals of the CumulVar for dimension "dimension_to_print" /// at each step of the routes. /// If "dimension_to_print" is omitted, all dimensions will be printed. - std::string - DebugOutputAssignment(const Assignment &solution_assignment, - const std::string &dimension_to_print) const; + std::string DebugOutputAssignment( + const Assignment &solution_assignment, + const std::string &dimension_to_print) const; /// Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair /// containing the minimum and maximum of the CumulVar of the jth node on /// route i. /// - cumul_bounds[i][j].first is the minimum. /// - cumul_bounds[i][j].second is the maximum. #ifndef SWIG - std::vector > > - GetCumulBounds(const Assignment &solution_assignment, - const RoutingDimension &dimension); + std::vector > > GetCumulBounds( + const Assignment &solution_assignment, const RoutingDimension &dimension); #endif /// Returns the underlying constraint solver. Can be used to add extra /// constraints and/or modify search algoithms. @@ -1352,7 +1347,7 @@ public: std::function(RoutingModel *)>; void SetTabuVarsCallback(GetTabuVarsCallback tabu_var_callback); -#endif // SWIG +#endif // SWIG /// The next few members are in the public section only for testing purposes. // TODO(user): Find a way to test and restrict the access at the same time. @@ -1367,18 +1362,18 @@ public: /// builder first calls the callback with argument i, and supposingly the /// returned value is x it creates decisions slack[i] = x, slack[i] = x + /// 1, slack[i] = x - 1, slack[i] = x + 2, etc. - DecisionBuilder * - MakeGuidedSlackFinalizer(const RoutingDimension *dimension, - std::function initializer); + DecisionBuilder *MakeGuidedSlackFinalizer( + const RoutingDimension *dimension, + std::function initializer); #ifndef SWIG // TODO(user): MakeGreedyDescentLSOperator is too general for routing.h. /// Perhaps move it to constraint_solver.h. /// MakeGreedyDescentLSOperator creates a local search operator that tries to /// improve the initial assignment by moving a logarithmically decreasing step /// away in each possible dimension. - static std::unique_ptr - MakeGreedyDescentLSOperator(std::vector variables); -#endif /// __SWIG__ + static std::unique_ptr MakeGreedyDescentLSOperator( + std::vector variables); +#endif /// __SWIG__ /// MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a /// self-dependent dimension. It makes an extensive use of the caches of the /// state dependent transits. @@ -1392,10 +1387,10 @@ public: /// generally works in time O(log(t)*n*m), where t is the latest possible /// departute time, n is the number of nodes in the network and m is the /// number of vehicles. - DecisionBuilder * - MakeSelfDependentDimensionFinalizer(const RoutingDimension *dimension); + DecisionBuilder *MakeSelfDependentDimensionFinalizer( + const RoutingDimension *dimension); -private: + private: /// Local search move operator usable in routing. enum RoutingLocalSearchOperator { RELOCATE = 0, @@ -1439,7 +1434,8 @@ private: /// Structure storing a value for a set of variable indices. Is used to store /// data for index disjunctions (variable indices, max_cardinality and penalty /// when unperformed). - template struct ValuedNodes { + template + struct ValuedNodes { std::vector indices; T value; }; @@ -1544,7 +1540,8 @@ private: int64 SafeGetCostClassInt64OfVehicle(int64 vehicle) const { DCHECK_LT(0, vehicles_); return (vehicle >= 0 ? GetCostClassIndexOfVehicle(vehicle) - : kCostClassIndexOfZeroCost).value(); + : kCostClassIndexOfZeroCost) + .value(); } int64 GetDimensionTransitCostSum(int64 i, int64 j, const CostClass &cost_class) const; @@ -1575,8 +1572,8 @@ private: Assignment *compact_assignment) const; void QuietCloseModel(); - void - QuietCloseModelWithParameters(const RoutingSearchParameters ¶meters) { + void QuietCloseModelWithParameters( + const RoutingSearchParameters ¶meters) { if (!closed_) { CloseModelWithParameters(parameters); } @@ -1621,12 +1618,12 @@ private: LocalSearchOperator *GetNeighborhoodOperators( const RoutingSearchParameters &search_parameters) const; std::vector - GetOrCreateLocalSearchFilters(const RoutingSearchParameters ¶meters, - bool filter_cost = true); + GetOrCreateLocalSearchFilters(const RoutingSearchParameters ¶meters, + bool filter_cost = true); LocalSearchFilterManager *GetOrCreateLocalSearchFilterManager( const RoutingSearchParameters ¶meters); std::vector - GetOrCreateFeasibilityFilters(const RoutingSearchParameters ¶meters); + GetOrCreateFeasibilityFilters(const RoutingSearchParameters ¶meters); LocalSearchFilterManager *GetOrCreateFeasibilityFilterManager( const RoutingSearchParameters ¶meters); LocalSearchFilterManager *GetOrCreateStrongFeasibilityFilterManager( @@ -1658,8 +1655,7 @@ private: void InitSameVehicleGroups(int number_of_groups) { same_vehicle_group_.assign(Size(), 0); - same_vehicle_groups_.assign(number_of_groups, { - }); + same_vehicle_groups_.assign(number_of_groups, {}); } void SetSameVehicleGroup(int index, int group) { same_vehicle_group_[index] = group; @@ -1890,7 +1886,7 @@ private: /// Routing model visitor. class RoutingModelVisitor : public BaseObject { -public: + public: /// Constraint types. static const char kLightElement[]; static const char kLightElement2[]; @@ -1901,7 +1897,7 @@ public: /// This class acts like a CP propagator: it takes a set of tasks given by /// their start/duration/end features, and reduces the range of possible values. class DisjunctivePropagator { -public: + public: /// A structure to hold tasks described by their features. /// The first num_chain_tasks are considered linked by a chain of precedences, /// i.e. if i < j < num_chain_tasks, then end(i) <= start(j). @@ -1964,7 +1960,7 @@ public: /// otherwise the lower bound might be lower than feasible. bool ChainSpanMinDynamic(Tasks *tasks); -private: + private: /// The main algorithm uses Vilim's theta tree data structure. /// See Petr Vilim's PhD thesis "Global Constraints in Scheduling". sat::ThetaLambdaTree theta_lambda_tree_; @@ -1996,7 +1992,7 @@ void FillPathEvaluation(const std::vector &path, void FillTravelBoundsOfVehicle(int vehicle, const std::vector &path, const RoutingDimension &dimension, TravelBounds *travel_bounds); -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// GlobalVehicleBreaksConstraint ensures breaks constraints are enforced on /// all vehicles in the dimension passed to its constructor. @@ -2009,7 +2005,7 @@ void FillTravelBoundsOfVehicle(int vehicle, const std::vector &path, /// i.e. if Next(nodeA) = nodeB, CumulVar(nodeA) = tA and CumulVar(nodeB) = tB, /// then SlackVar(nodeA) >= sum_{breaks \subseteq [tA, tB)} duration(break). class GlobalVehicleBreaksConstraint : public Constraint { -public: + public: explicit GlobalVehicleBreaksConstraint(const RoutingDimension *dimension); std::string DebugString() const override { return "GlobalVehicleBreaksConstraint"; @@ -2018,7 +2014,7 @@ public: void Post() override; void InitialPropagate() override; -private: + private: void PropagateNode(int node); void PropagateVehicle(int vehicle); void PropagateMaxBreakDistance(int vehicle); @@ -2046,9 +2042,10 @@ private: /// structure, a vector's reserved size will adjust to usage and eventually no /// more dynamic allocation will be made. class TaskTranslator { - public: + public: TaskTranslator(IntVar *start, int64 before_start, int64 after_start) - : start_(start), before_start_(before_start), + : start_(start), + before_start_(before_start), after_start_(after_start) {} explicit TaskTranslator(IntervalVar *interval) : interval_(interval) {} TaskTranslator() {} @@ -2087,7 +2084,7 @@ private: } } - private: + private: IntVar *start_ = nullptr; int64 before_start_; int64 after_start_; @@ -2106,17 +2103,17 @@ private: }; class TypeRegulationsChecker { -public: + public: explicit TypeRegulationsChecker(const RoutingModel &model); virtual ~TypeRegulationsChecker() {} bool CheckVehicle(int vehicle, const std::function &next_accessor); -protected: + protected: #ifndef SWIG using VisitTypePolicy = RoutingModel::VisitTypePolicy; -#endif // SWIG +#endif // SWIG struct TypePolicyOccurrence { /// Number of TYPE_ADDED_TO_VEHICLE and @@ -2159,19 +2156,19 @@ protected: const RoutingModel &model_; -private: + private: std::vector occurrences_of_type_; std::vector current_route_visits_; }; /// Checker for type incompatibilities. class TypeIncompatibilityChecker : public TypeRegulationsChecker { -public: + public: TypeIncompatibilityChecker(const RoutingModel &model, bool check_hard_incompatibilities); ~TypeIncompatibilityChecker() override {} -private: + private: bool HasRegulationsToCheck() const override; bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos) override; /// NOTE(user): As temporal incompatibilities are always verified with @@ -2182,12 +2179,12 @@ private: /// Checker for type requirements. class TypeRequirementChecker : public TypeRegulationsChecker { -public: + public: explicit TypeRequirementChecker(const RoutingModel &model) : TypeRegulationsChecker(model) {} ~TypeRequirementChecker() override {} -private: + private: bool HasRegulationsToCheck() const override; void OnInitializeCheck() override { types_with_same_vehicle_requirements_on_route_.clear(); @@ -2246,13 +2243,13 @@ private: /// r1 is visited: /// ... --> A --> ... --> r1 --> ... OR ... --> r1 --> ... --> UV --> ... class TypeRegulationsConstraint : public Constraint { -public: + public: explicit TypeRegulationsConstraint(const RoutingModel &model); void Post() override; void InitialPropagate() override; -private: + private: void PropagateNodeRegulations(int node); void CheckRegulationsOnVehicle(int vehicle); @@ -2275,7 +2272,7 @@ private: /// to type bound_cost reminds the user of the order if they do a copy /// assignment of the element. class SimpleBoundCosts { -public: + public: struct BoundCost { int64 bound; int64 cost; @@ -2288,10 +2285,10 @@ public: SimpleBoundCosts(const SimpleBoundCosts &) = delete; SimpleBoundCosts operator=(const SimpleBoundCosts &) = delete; -private: + private: std::vector bound_costs_; }; -#endif // !defined SWIG +#endif // !defined SWIG /// Dimensions represent quantities accumulated at nodes along the routes. They /// represent quantities such as weights or volumes carried along the route, or @@ -2314,7 +2311,7 @@ private: /// for a given vehicle, it is passed as an external vector, it would be better /// to have this information here. class RoutingDimension { -public: + public: ~RoutingDimension(); /// Returns the model on which the dimension was created. RoutingModel *model() const { return model_; } @@ -2403,20 +2400,20 @@ public: /// Returns the unary callback evaluating the transit value between two node /// indices for a given vehicle. If the corresponding callback is not unary, /// returns a null callback. - const RoutingModel::TransitCallback1 & - GetUnaryTransitEvaluator(int vehicle) const { + const RoutingModel::TransitCallback1 &GetUnaryTransitEvaluator( + int vehicle) const { return model_->UnaryTransitCallbackOrNull( class_evaluators_[vehicle_to_class_[vehicle]]); } /// Returns true iff the transit evaluator of 'vehicle' is positive for all /// arcs. bool AreVehicleTransitsPositive(int vehicle) const { - return model()->is_transit_evaluator_positive_[ - class_evaluators_[vehicle_to_class_[vehicle]]]; + return model()->is_transit_evaluator_positive_ + [class_evaluators_[vehicle_to_class_[vehicle]]]; } int vehicle_to_class(int vehicle) const { return vehicle_to_class_[vehicle]; } -#endif /// !defined(SWIGCSHARP) && !defined(SWIGJAVA) -#endif /// !defined(SWIGPYTHON) +#endif /// !defined(SWIGCSHARP) && !defined(SWIGJAVA) +#endif /// !defined(SWIGPYTHON) /// Sets an upper bound on the dimension span on a given vehicle. This is the /// preferred way to limit the "length" of the route of a vehicle according to /// a dimension. @@ -2449,8 +2446,8 @@ public: bool HasCumulVarPiecewiseLinearCost(int64 index) const; /// Returns the piecewise linear cost of a cumul variable for a given variable /// index. The returned pointer has the same validity as this class. - const PiecewiseLinearFunction * - GetCumulVarPiecewiseLinearCost(int64 index) const; + const PiecewiseLinearFunction *GetCumulVarPiecewiseLinearCost( + int64 index) const; #endif /// Sets a soft upper bound to the cumul variable of a given variable index. @@ -2517,7 +2514,7 @@ public: void SetBreakIntervalsOfVehicle(std::vector breaks, int vehicle, int pre_travel_evaluator, int post_travel_evaluator); -#endif // !defined(SWIGPYTHON) +#endif // !defined(SWIGPYTHON) /// Deprecated, sets pre_travel(i, j) = node_visit_transit[i]. void SetBreakIntervalsOfVehicle(std::vector breaks, @@ -2544,15 +2541,15 @@ public: std::function group_delays); /// Returns the break intervals set by SetBreakIntervalsOfVehicle(). - const std::vector & - GetBreakIntervalsOfVehicle(int vehicle) const; + const std::vector &GetBreakIntervalsOfVehicle( + int vehicle) const; /// Returns the pairs (distance, duration) specified by break distance /// constraints. // clang-format off const std::vector > & GetBreakDistanceDurationOfVehicle(int vehicle) const; // clang-format on -#endif /// !defined(SWIGPYTHON) +#endif /// !defined(SWIGPYTHON) int GetPreTravelEvaluatorOfVehicle(int vehicle) const; int GetPostTravelEvaluatorOfVehicle(int vehicle) const; @@ -2575,7 +2572,7 @@ public: const ReverseArcListGraph &GetPathPrecedenceGraph() const { return path_precedence_graph_; } -#endif // SWIG +#endif // SWIG /// Limits, in terms of maximum difference between the cumul variables, /// between the pickup and delivery alternatives belonging to a single @@ -2608,12 +2605,10 @@ public: const std::vector &GetNodePrecedences() const { return node_precedences_; } -#endif // SWIG +#endif // SWIG void AddNodePrecedence(int64 first_node, int64 second_node, int64 offset) { - AddNodePrecedence({ - first_node, second_node, offset - }); + AddNodePrecedence({first_node, second_node, offset}); } int64 GetSpanUpperBoundForVehicle(int vehicle) const { @@ -2623,7 +2618,7 @@ public: const std::vector &vehicle_span_upper_bounds() const { return vehicle_span_upper_bounds_; } -#endif // SWIG +#endif // SWIG int64 GetSpanCostCoefficientForVehicle(int vehicle) const { return vehicle_span_cost_coefficients_[vehicle]; } @@ -2631,7 +2626,7 @@ public: const std::vector &vehicle_span_cost_coefficients() const { return vehicle_span_cost_coefficients_; } -#endif // SWIG +#endif // SWIG int64 global_span_cost_coefficient() const { return global_span_cost_coefficient_; } @@ -2654,17 +2649,15 @@ public: int vehicle) { if (!HasSoftSpanUpperBounds()) { vehicle_soft_span_upper_bound_ = absl::make_unique( - model_->vehicles(), SimpleBoundCosts::BoundCost { - kint64max, 0 - }); + model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); } vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost; } bool HasSoftSpanUpperBounds() const { return vehicle_soft_span_upper_bound_ != nullptr; } - SimpleBoundCosts::BoundCost - GetSoftSpanUpperBoundForVehicle(int vehicle) const { + SimpleBoundCosts::BoundCost GetSoftSpanUpperBoundForVehicle( + int vehicle) const { DCHECK(HasSoftSpanUpperBounds()); return vehicle_soft_span_upper_bound_->bound_cost(vehicle); } @@ -2674,10 +2667,8 @@ public: SimpleBoundCosts::BoundCost bound_cost, int vehicle) { if (!HasQuadraticCostSoftSpanUpperBounds()) { vehicle_quadratic_cost_soft_span_upper_bound_ = - absl::make_unique(model_->vehicles(), - SimpleBoundCosts::BoundCost { - kint64max, 0 - }); + absl::make_unique( + model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); } vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost; @@ -2685,14 +2676,14 @@ public: bool HasQuadraticCostSoftSpanUpperBounds() const { return vehicle_quadratic_cost_soft_span_upper_bound_ != nullptr; } - SimpleBoundCosts::BoundCost - GetQuadraticCostSoftSpanUpperBoundForVehicle(int vehicle) const { + SimpleBoundCosts::BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle( + int vehicle) const { DCHECK(HasQuadraticCostSoftSpanUpperBounds()); return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle); } -#endif /// !defined SWIG +#endif /// !defined SWIG -private: + private: struct SoftBound { IntVar *var; int64 bound; @@ -2705,8 +2696,7 @@ private: std::unique_ptr cost; }; - class SelfBased { - }; + class SelfBased {}; RoutingDimension(RoutingModel *model, std::vector vehicle_capacities, const std::string &name, const RoutingDimension *base_dimension); @@ -2741,11 +2731,9 @@ private: } /// Moves elements of "offsets" into vehicle_offsets_for_local_optimizer_. void SetVehicleOffsetsForLocalOptimizer(std::vector offsets) { - /// Make sure all offsets are positive. + /// Make sure all offsets are positive. std::transform(offsets.begin(), offsets.end(), offsets.begin(), - [](int64 offset) { - return std::max(Zero(), offset); - }); + [](int64 offset) { return std::max(Zero(), offset); }); local_optimizer_offset_for_vehicle_ = std::move(offsets); } @@ -2828,13 +2816,13 @@ private: /// Class to arrange indices by by their distance and their angles from the /// depot. Used in the Sweep first solution heuristic. class SweepArranger { -public: + public: explicit SweepArranger(const std::vector > &points); virtual ~SweepArranger() {} void ArrangeIndices(std::vector *indices); void SetSectors(int sectors) { sectors_ = sectors; } -private: + private: std::vector coordinates_; int sectors_; @@ -2852,7 +2840,7 @@ DecisionBuilder *MakeSetValuesFromTargets(Solver *solver, // Helper class that stores vehicles by their type. Two vehicles have the same // "vehicle type" iff they have the same cost class and start/end nodes. class VehicleTypeCurator { -public: + public: explicit VehicleTypeCurator( const RoutingModel::VehicleTypeContainer &vehicle_type_container) : vehicle_type_container_(&vehicle_type_container) {} @@ -2894,9 +2882,8 @@ public: // vehicles_per_vehicle_class_[vehicle_class] got empty). std::set &vehicle_classes = sorted_vehicle_classes_per_type_[Type(vehicle)]; - const auto &insertion = vehicle_classes.insert({ - vehicle_class, fixed_cost - }); + const auto &insertion = + vehicle_classes.insert({vehicle_class, fixed_cost}); DCHECK(insertion.second); } vehicles.push_back(vehicle); @@ -2910,7 +2897,7 @@ public: int GetCompatibleVehicleOfType( int type, std::function vehicle_is_compatible); -private: + private: using VehicleClassEntry = RoutingModel::VehicleTypeContainer::VehicleClassEntry; const RoutingModel::VehicleTypeContainer *const vehicle_type_container_; @@ -2937,7 +2924,7 @@ private: // TODO(user): Eventually move this to the core CP solver library /// when the code is mature enough. class IntVarFilteredDecisionBuilder : public DecisionBuilder { -public: + public: explicit IntVarFilteredDecisionBuilder( std::unique_ptr heuristic); @@ -2951,13 +2938,13 @@ public: int64 number_of_decisions() const; int64 number_of_rejects() const; -private: + private: const std::unique_ptr heuristic_; }; /// Generic filter-based heuristic applied to IntVars. class IntVarFilteredHeuristic { -public: + public: IntVarFilteredHeuristic(Solver *solver, const std::vector &vars, LocalSearchFilterManager *filter_manager); @@ -2974,7 +2961,7 @@ public: virtual std::string DebugString() const { return "IntVarFilteredHeuristic"; } -protected: + protected: /// Resets the data members for a new solution. void ResetSolution(); /// Virtual method to initialize the solution. @@ -3017,7 +3004,7 @@ protected: Assignment *const assignment_; -private: + private: /// Checks if filters accept a given modification to the current solution /// (represented by delta). bool FilterAccept(); @@ -3036,13 +3023,13 @@ private: /// Filter-based heuristic dedicated to routing. class RoutingFilteredHeuristic : public IntVarFilteredHeuristic { -public: + public: RoutingFilteredHeuristic(RoutingModel *model, LocalSearchFilterManager *filter_manager); ~RoutingFilteredHeuristic() override {} /// Builds a solution starting from the routes formed by the next accessor. - const Assignment * - BuildSolutionFromRoutes(const std::function &next_accessor); + const Assignment *BuildSolutionFromRoutes( + const std::function &next_accessor); RoutingModel *model() const { return model_; } /// Returns the end of the start chain of vehicle, int GetStartChainEnd(int vehicle) const { return start_chain_ends_[vehicle]; } @@ -3054,12 +3041,12 @@ public: /// Make all unassigned nodes unperformed. void MakeUnassignedNodesUnperformed(); -protected: + protected: bool StopSearch() override { return model_->CheckLimit(); } virtual void SetVehicleIndex(int64 node, int vehicle) {} virtual void ResetVehicleIndices() {} -private: + private: /// Initializes the current solution with empty or partial vehicle routes. bool InitializeSolution() override; @@ -3069,7 +3056,7 @@ private: }; class CheapestInsertionFilteredHeuristic : public RoutingFilteredHeuristic { -public: + public: /// Takes ownership of evaluator. CheapestInsertionFilteredHeuristic( RoutingModel *model, std::function evaluator, @@ -3077,7 +3064,7 @@ public: LocalSearchFilterManager *filter_manager); ~CheapestInsertionFilteredHeuristic() override {} -protected: + protected: typedef std::pair ValuedPosition; struct StartEndValue { int64 distance; @@ -3146,7 +3133,7 @@ protected: /// cost. class GlobalCheapestInsertionFilteredHeuristic : public CheapestInsertionFilteredHeuristic { -public: + public: struct GlobalCheapestInsertionParameters { /// Whether the routes are constructed sequentially or in parallel. bool is_sequential; @@ -3179,7 +3166,7 @@ public: return "GlobalCheapestInsertionFilteredHeuristic"; } -private: + private: class PairEntry; class NodeEntry; typedef absl::flat_hash_set PairEntries; @@ -3336,8 +3323,8 @@ private: int64 neighbor_index) const; /// Returns a reference to the set of pickup neighbors of node_index. - const std::vector & - GetPickupNeighborsOfNodeForCostClass(int cost_class, int64 node_index) const { + const std::vector &GetPickupNeighborsOfNodeForCostClass( + int cost_class, int64 node_index) const { if (gci_params_.neighbors_ratio == 1) { return pickup_nodes_; } @@ -3346,19 +3333,19 @@ private: } /// Same as above for delivery neighbors. - const std::vector & - GetDeliveryNeighborsOfNodeForCostClass(int cost_class, - int64 node_index) const { + const std::vector &GetDeliveryNeighborsOfNodeForCostClass( + int cost_class, int64 node_index) const { if (gci_params_.neighbors_ratio == 1) { return delivery_nodes_; } - return node_index_to_delivery_neighbors_by_cost_class_[node_index][ - cost_class]->PositionsSetAtLeastOnce(); + return node_index_to_delivery_neighbors_by_cost_class_ + [node_index][cost_class] + ->PositionsSetAtLeastOnce(); } /// Same as above for non pickup/delivery neighbors. - const std::vector & - GetSingleNeighborsOfNodeForCostClass(int cost_class, int64 node_index) const { + const std::vector &GetSingleNeighborsOfNodeForCostClass( + int cost_class, int64 node_index) const { if (gci_params_.neighbors_ratio == 1) { return single_nodes_; } @@ -3367,11 +3354,11 @@ private: } /// Returns an iterator to the concatenation of all neighbors. - std::vector *> - GetNeighborsOfNodeForCostClass(int cost_class, int64 node_index) const { - return { &GetSingleNeighborsOfNodeForCostClass(cost_class, node_index), - &GetPickupNeighborsOfNodeForCostClass(cost_class, node_index), - &GetDeliveryNeighborsOfNodeForCostClass(cost_class, node_index) }; + std::vector *> GetNeighborsOfNodeForCostClass( + int cost_class, int64 node_index) const { + return {&GetSingleNeighborsOfNodeForCostClass(cost_class, node_index), + &GetPickupNeighborsOfNodeForCostClass(cost_class, node_index), + &GetDeliveryNeighborsOfNodeForCostClass(cost_class, node_index)}; } void ResetVehicleIndices() override { @@ -3415,7 +3402,7 @@ private: /// nodes are inserted first. class LocalCheapestInsertionFilteredHeuristic : public CheapestInsertionFilteredHeuristic { -public: + public: /// Takes ownership of evaluator. LocalCheapestInsertionFilteredHeuristic( RoutingModel *model, std::function evaluator, @@ -3426,7 +3413,7 @@ public: return "LocalCheapestInsertionFilteredHeuristic"; } -private: + private: /// Computes the possible insertion positions of 'node' and sorts them /// according to the current cost evaluator. /// 'node' is a variable index corresponding to a node, 'sorted_positions' is @@ -3448,21 +3435,21 @@ private: /// Filtered-base decision builder based on the addition heuristic, extending /// a path from its start node with the cheapest arc. class CheapestAdditionFilteredHeuristic : public RoutingFilteredHeuristic { -public: + public: CheapestAdditionFilteredHeuristic(RoutingModel *model, LocalSearchFilterManager *filter_manager); ~CheapestAdditionFilteredHeuristic() override {} bool BuildSolutionInternal() override; -private: + private: class PartialRoutesAndLargeVehicleIndicesFirst { - public: + public: explicit PartialRoutesAndLargeVehicleIndicesFirst( const CheapestAdditionFilteredHeuristic &builder) : builder_(builder) {} bool operator()(int vehicle1, int vehicle2) const; - private: + private: const CheapestAdditionFilteredHeuristic &builder_; }; /// Returns a vector of possible next indices of node from an iterator. @@ -3489,7 +3476,7 @@ private: /// comes from an arc evaluator. class EvaluatorCheapestAdditionFilteredHeuristic : public CheapestAdditionFilteredHeuristic { -public: + public: /// Takes ownership of evaluator. EvaluatorCheapestAdditionFilteredHeuristic( RoutingModel *model, std::function evaluator, @@ -3499,11 +3486,11 @@ public: return "EvaluatorCheapestAdditionFilteredHeuristic"; } -private: + private: /// Next nodes are sorted according to the current evaluator. void SortSuccessors(int64 node, std::vector *successors) override; - int64 FindTopSuccessor(int64 node, const std::vector &successors) - override; + int64 FindTopSuccessor(int64 node, + const std::vector &successors) override; std::function evaluator_; }; @@ -3512,7 +3499,7 @@ private: /// comes from an arc comparator. class ComparatorCheapestAdditionFilteredHeuristic : public CheapestAdditionFilteredHeuristic { -public: + public: /// Takes ownership of evaluator. ComparatorCheapestAdditionFilteredHeuristic( RoutingModel *model, Solver::VariableValueComparator comparator, @@ -3522,11 +3509,11 @@ public: return "ComparatorCheapestAdditionFilteredHeuristic"; } -private: + private: /// Next nodes are sorted according to the current comparator. void SortSuccessors(int64 node, std::vector *successors) override; - int64 FindTopSuccessor(int64 node, const std::vector &successors) - override; + int64 FindTopSuccessor(int64 node, + const std::vector &successors) override; Solver::VariableValueComparator comparator_; }; @@ -3540,7 +3527,7 @@ private: /// partial route. Cost is based on the arc cost function of the routing model /// and cost classes are taken into account. class SavingsFilteredHeuristic : public RoutingFilteredHeuristic { -public: + public: struct SavingsParameters { /// If neighbors_ratio < 1 then for each node only this ratio of its /// neighbors leading to the smallest arc costs are considered. @@ -3563,10 +3550,11 @@ public: ~SavingsFilteredHeuristic() override; bool BuildSolutionInternal() override; -protected: + protected: typedef std::pair Saving; - template class SavingsContainer; + template + class SavingsContainer; virtual double ExtraSavingsMemoryMultiplicativeFactor() const = 0; @@ -3604,7 +3592,7 @@ protected: // clang-format on std::unique_ptr vehicle_type_curator_; -private: + private: /// Used when add_reverse_arcs_ is true. /// Given the vector of adjacency lists of a graph, adds symmetric arcs not /// already in the graph to the adjacencies (i.e. if n1-->n2 is present and @@ -3641,19 +3629,18 @@ private: }; class SequentialSavingsFilteredHeuristic : public SavingsFilteredHeuristic { -public: + public: SequentialSavingsFilteredHeuristic(RoutingModel *model, const RoutingIndexManager *manager, SavingsParameters parameters, LocalSearchFilterManager *filter_manager) : SavingsFilteredHeuristic(model, manager, parameters, filter_manager) {} - ~SequentialSavingsFilteredHeuristic() override {} - ; + ~SequentialSavingsFilteredHeuristic() override{}; std::string DebugString() const override { return "SequentialSavingsFilteredHeuristic"; } -private: + private: /// Builds routes sequentially. /// Once a Saving is used to start a new route, we extend this route as much /// as possible from both ends by gradually inserting the best Saving at @@ -3663,19 +3650,18 @@ private: }; class ParallelSavingsFilteredHeuristic : public SavingsFilteredHeuristic { -public: + public: ParallelSavingsFilteredHeuristic(RoutingModel *model, const RoutingIndexManager *manager, SavingsParameters parameters, LocalSearchFilterManager *filter_manager) : SavingsFilteredHeuristic(model, manager, parameters, filter_manager) {} - ~ParallelSavingsFilteredHeuristic() override {} - ; + ~ParallelSavingsFilteredHeuristic() override{}; std::string DebugString() const override { return "ParallelSavingsFilteredHeuristic"; } -private: + private: /// Goes through the ordered computed Savings to build routes in parallel. /// Given a Saving for a before-->after arc : /// -- If both before and after are uncontained, we start a new route. @@ -3711,7 +3697,7 @@ private: /// path found by the heuristic, before starting a new route. class ChristofidesFilteredHeuristic : public RoutingFilteredHeuristic { -public: + public: ChristofidesFilteredHeuristic(RoutingModel *model, LocalSearchFilterManager *filter_manager, bool use_minimum_matching); @@ -3721,10 +3707,10 @@ public: return "ChristofidesFilteredHeuristic"; } -private: + private: const bool use_minimum_matching_; }; -#endif // SWIG +#endif // SWIG /// Attempts to solve the model using the cp-sat solver. As of 5/2019, will /// solve the TSP corresponding to the model if it has a single vehicle. @@ -3738,14 +3724,14 @@ bool SolveModelWithSat(const RoutingModel &model, /// Generic path-based filter class. class BasePathFilter : public IntVarLocalSearchFilter { -public: + public: BasePathFilter(const std::vector &nexts, int next_domain_size); ~BasePathFilter() override {} bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, int64 objective_max) override; void OnSynchronize(const Assignment *delta) override; -protected: + protected: static const int64 kUnassigned; int64 GetNext(int64 node) const { @@ -3765,12 +3751,8 @@ protected: return new_synchronized_unperformed_nodes_.PositionsSetAtLeastOnce(); } -private: - enum Status { - UNKNOWN, - ENABLED, - DISABLED - }; + private: + enum Status { UNKNOWN, ENABLED, DISABLED }; virtual bool DisableFiltering() const { return false; } virtual void OnBeforeSynchronizePaths() {} @@ -3818,7 +3800,7 @@ private: /// routes, because all Next vars of vehicle starts are already instantiated. // TODO(user): Avoid such false negatives. class CPFeasibilityFilter : public IntVarLocalSearchFilter { -public: + public: explicit CPFeasibilityFilter(RoutingModel *routing_model); ~CPFeasibilityFilter() override {} std::string DebugString() const override { return "CPFeasibilityFilter"; } @@ -3826,7 +3808,7 @@ public: int64 objective_min, int64 objective_max) override; void OnSynchronize(const Assignment *delta) override; -private: + private: void AddDeltaToAssignment(const Assignment *delta, Assignment *assignment); static const int64 kUnassigned; @@ -3839,14 +3821,14 @@ private: }; #if !defined(SWIG) -IntVarLocalSearchFilter * - MakeMaxActiveVehiclesFilter(const RoutingModel &routing_model); -IntVarLocalSearchFilter * - MakeNodeDisjunctionFilter(const RoutingModel &routing_model); -IntVarLocalSearchFilter * - MakeVehicleAmortizedCostFilter(const RoutingModel &routing_model); -IntVarLocalSearchFilter * - MakeTypeRegulationsFilter(const RoutingModel &routing_model); +IntVarLocalSearchFilter *MakeMaxActiveVehiclesFilter( + const RoutingModel &routing_model); +IntVarLocalSearchFilter *MakeNodeDisjunctionFilter( + const RoutingModel &routing_model); +IntVarLocalSearchFilter *MakeVehicleAmortizedCostFilter( + const RoutingModel &routing_model); +IntVarLocalSearchFilter *MakeTypeRegulationsFilter( + const RoutingModel &routing_model); void AppendDimensionCumulFilters( const std::vector &dimensions, const RoutingSearchParameters ¶meters, bool filter_objective_cost, @@ -3855,26 +3837,24 @@ void AppendLightWeightDimensionFilters( const PathState *path_state, const std::vector &dimensions, std::vector *filters); -IntVarLocalSearchFilter * - MakePathCumulFilter(const RoutingDimension &dimension, - const RoutingSearchParameters ¶meters, - bool propagate_own_objective_value, - bool filter_objective_cost, bool can_use_lp = true); -IntVarLocalSearchFilter * - MakeCumulBoundsPropagatorFilter(const RoutingDimension &dimension); -IntVarLocalSearchFilter * - MakeGlobalLPCumulFilter(GlobalDimensionCumulOptimizer *optimizer, - bool filter_objective_cost); +IntVarLocalSearchFilter *MakePathCumulFilter( + const RoutingDimension &dimension, + const RoutingSearchParameters ¶meters, + bool propagate_own_objective_value, bool filter_objective_cost, + bool can_use_lp = true); +IntVarLocalSearchFilter *MakeCumulBoundsPropagatorFilter( + const RoutingDimension &dimension); +IntVarLocalSearchFilter *MakeGlobalLPCumulFilter( + GlobalDimensionCumulOptimizer *optimizer, bool filter_objective_cost); IntVarLocalSearchFilter *MakePickupDeliveryFilter( const RoutingModel &routing_model, const RoutingModel::IndexPairs &pairs, const std::vector &vehicle_policies); -IntVarLocalSearchFilter * - MakeVehicleVarFilter(const RoutingModel &routing_model); -IntVarLocalSearchFilter * - MakeVehicleBreaksFilter(const RoutingModel &routing_model, - const RoutingDimension &dimension); +IntVarLocalSearchFilter *MakeVehicleVarFilter( + const RoutingModel &routing_model); +IntVarLocalSearchFilter *MakeVehicleBreaksFilter( + const RoutingModel &routing_model, const RoutingDimension &dimension); IntVarLocalSearchFilter *MakeCPFeasibilityFilter(RoutingModel *routing_model); #endif -} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_ +} // namespace operations_research +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_ diff --git a/ortools/constraint_solver/routing_breaks.cc b/ortools/constraint_solver/routing_breaks.cc index 2502143e76..5d8551a44f 100644 --- a/ortools/constraint_solver/routing_breaks.cc +++ b/ortools/constraint_solver/routing_breaks.cc @@ -36,12 +36,10 @@ bool DisjunctivePropagator::Propagate(Tasks *tasks) { return false; } if (!tasks->forbidden_intervals.empty()) { - if (!ForbiddenIntervals(tasks) || !Precedences(tasks)) - return false; + if (!ForbiddenIntervals(tasks) || !Precedences(tasks)) return false; } if (!tasks->distance_duration.empty()) { - if (!DistanceDuration(tasks) || !Precedences(tasks)) - return false; + if (!DistanceDuration(tasks) || !Precedences(tasks)) return false; } if (!MirrorTasks(tasks) || !EdgeFinding(tasks) || !Precedences(tasks) || !DetectablePrecedencesWithChain(tasks) || !MirrorTasks(tasks)) { @@ -59,8 +57,7 @@ bool DisjunctivePropagator::Precedences(Tasks *tasks) { time = std::max(tasks->start_min[task], time); tasks->start_min[task] = time; time = CapAdd(time, tasks->duration_min[task]); - if (tasks->end_max[task] < time) - return false; + if (tasks->end_max[task] < time) return false; time = std::max(time, tasks->end_min[task]); tasks->end_min[task] = time; } @@ -70,8 +67,7 @@ bool DisjunctivePropagator::Precedences(Tasks *tasks) { time = std::min(tasks->end_max[task], time); tasks->end_max[task] = time; time = CapSub(time, tasks->duration_min[task]); - if (time < tasks->start_min[task]) - return false; + if (time < tasks->start_min[task]) return false; time = std::min(time, tasks->start_max[task]); tasks->start_max[task] = time; } @@ -100,12 +96,9 @@ bool DisjunctivePropagator::Precedences(Tasks *tasks) { std::max(tasks->duration_min[task], CapSub(tasks->end_min[task], tasks->start_max[task])); } - if (tasks->duration_min[task] > tasks->duration_max[task]) - return false; - if (tasks->end_min[task] > tasks->end_max[task]) - return false; - if (tasks->start_min[task] > tasks->start_max[task]) - return false; + if (tasks->duration_min[task] > tasks->duration_max[task]) return false; + if (tasks->end_min[task] > tasks->end_max[task]) return false; + if (tasks->start_min[task] > tasks->start_max[task]) return false; } return true; } @@ -126,11 +119,10 @@ bool DisjunctivePropagator::MirrorTasks(Tasks *tasks) { } // In the mirror problem, tasks linked by precedences are in reversed order. const int num_chain_tasks = tasks->num_chain_tasks; - for (const auto it : { - tasks->start_min.begin(), tasks->start_max.begin(), + for (const auto it : + {tasks->start_min.begin(), tasks->start_max.begin(), tasks->duration_min.begin(), tasks->duration_max.begin(), - tasks->end_min.begin(), tasks->end_max.begin() - }) { + tasks->end_min.begin(), tasks->end_max.begin()}) { std::reverse(it, it + num_chain_tasks); std::reverse(it + num_chain_tasks, it + num_tasks); } @@ -146,10 +138,9 @@ bool DisjunctivePropagator::EdgeFinding(Tasks *tasks) { // Prepare start_min events for tree. tasks_by_start_min_.resize(num_tasks); std::iota(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), 0); - std::sort(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), - [&](int i, int j) { - return tasks->start_min[i] < tasks->start_min[j]; - }); + std::sort( + tasks_by_start_min_.begin(), tasks_by_start_min_.end(), + [&](int i, int j) { return tasks->start_min[i] < tasks->start_min[j]; }); event_of_task_.resize(num_tasks); for (int event = 0; event < num_tasks; ++event) { event_of_task_[tasks_by_start_min_[event]] = event; @@ -157,10 +148,9 @@ bool DisjunctivePropagator::EdgeFinding(Tasks *tasks) { // Tasks will be browsed according to end_max order. tasks_by_end_max_.resize(num_tasks); std::iota(tasks_by_end_max_.begin(), tasks_by_end_max_.end(), 0); - std::sort(tasks_by_end_max_.begin(), tasks_by_end_max_.end(), - [&](int i, int j) { - return tasks->end_max[i] < tasks->end_max[j]; - }); + std::sort( + tasks_by_end_max_.begin(), tasks_by_end_max_.end(), + [&](int i, int j) { return tasks->end_max[i] < tasks->end_max[j]; }); // Generic overload checking: insert tasks by end_max, // fail if envelope > end_max. @@ -182,9 +172,9 @@ bool DisjunctivePropagator::EdgeFinding(Tasks *tasks) { const int64 envelope = theta_lambda_tree_.GetEnvelope(); // If a nonpreemptible optional would overload end_max, push to envelope. while (theta_lambda_tree_.GetOptionalEnvelope() > tasks->end_max[task]) { - int critical_event; // Dummy value. + int critical_event; // Dummy value. int optional_event; - int64 available_energy; // Dummy value. + int64 available_energy; // Dummy value. theta_lambda_tree_.GetEventsWithOptionalEnvelopeGreaterThan( tasks->end_max[task], &critical_event, &optional_event, &available_energy); @@ -209,10 +199,9 @@ bool DisjunctivePropagator::DetectablePrecedencesWithChain(Tasks *tasks) { // Prepare start_min events for tree. tasks_by_start_min_.resize(num_tasks); std::iota(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), 0); - std::sort(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), - [&](int i, int j) { - return tasks->start_min[i] < tasks->start_min[j]; - }); + std::sort( + tasks_by_start_min_.begin(), tasks_by_start_min_.end(), + [&](int i, int j) { return tasks->start_min[i] < tasks->start_min[j]; }); event_of_task_.resize(num_tasks); for (int event = 0; event < num_tasks; ++event) { event_of_task_[tasks_by_start_min_[event]] = event; @@ -226,9 +215,9 @@ bool DisjunctivePropagator::DetectablePrecedencesWithChain(Tasks *tasks) { nonchain_tasks_by_start_max_.end(), num_chain_tasks); std::sort(nonchain_tasks_by_start_max_.begin(), nonchain_tasks_by_start_max_.end(), [&tasks](int i, int j) { - return tasks->end_max[i] - tasks->duration_min[i] < - tasks->end_max[j] - tasks->duration_min[j]; - }); + return tasks->end_max[i] - tasks->duration_min[i] < + tasks->end_max[j] - tasks->duration_min[j]; + }); // Detectable precedences, specialized for routes: for every task on route, // put all tasks before it in the tree, then push with envelope. @@ -259,20 +248,17 @@ bool DisjunctivePropagator::DetectablePrecedencesWithChain(Tasks *tasks) { } bool DisjunctivePropagator::ForbiddenIntervals(Tasks *tasks) { - if (tasks->forbidden_intervals.empty()) - return true; + if (tasks->forbidden_intervals.empty()) return true; const int num_tasks = tasks->start_min.size(); for (int task = 0; task < num_tasks; ++task) { - if (tasks->duration_min[task] == 0) - continue; - if (tasks->forbidden_intervals[task] == nullptr) - continue; + if (tasks->duration_min[task] == 0) continue; + if (tasks->forbidden_intervals[task] == nullptr) continue; // If start_min forbidden, push to next feasible value. { - const auto &interval = tasks->forbidden_intervals[task] - ->FirstIntervalGreaterOrEqual(tasks->start_min[task]); - if (interval == tasks->forbidden_intervals[task]->end()) - continue; + const auto &interval = + tasks->forbidden_intervals[task]->FirstIntervalGreaterOrEqual( + tasks->start_min[task]); + if (interval == tasks->forbidden_intervals[task]->end()) continue; if (interval->start <= tasks->start_min[task]) { tasks->start_min[task] = CapAdd(interval->end, 1); } @@ -283,8 +269,7 @@ bool DisjunctivePropagator::ForbiddenIntervals(Tasks *tasks) { CapSub(tasks->end_max[task], tasks->duration_min[task]); const auto &interval = tasks->forbidden_intervals[task]->LastIntervalLessOrEqual(start_max); - if (interval == tasks->forbidden_intervals[task]->end()) - continue; + if (interval == tasks->forbidden_intervals[task]->end()) continue; if (interval->end >= start_max) { tasks->end_max[task] = CapAdd(interval->start, tasks->duration_min[task] - 1); @@ -299,10 +284,8 @@ bool DisjunctivePropagator::ForbiddenIntervals(Tasks *tasks) { } bool DisjunctivePropagator::DistanceDuration(Tasks *tasks) { - if (tasks->distance_duration.empty()) - return true; - if (tasks->num_chain_tasks == 0) - return true; + if (tasks->distance_duration.empty()) return true; + if (tasks->num_chain_tasks == 0) return true; const int route_start = 0; const int route_end = tasks->num_chain_tasks - 1; const int num_tasks = tasks->start_min.size(); @@ -424,8 +407,7 @@ bool DisjunctivePropagator::DistanceDuration(Tasks *tasks) { } // If num_active_tasks becomes 1, the unique active task must cover from // current_time. - if (num_active_tasks <= 0) - return false; + if (num_active_tasks <= 0) return false; if (num_active_tasks == 1) { if (xor_active_tasks != route_start) { // xor_active_tasks is the unique task that can cover from @@ -446,8 +428,7 @@ bool DisjunctivePropagator::DistanceDuration(Tasks *tasks) { bool DisjunctivePropagator::ChainSpanMin(Tasks *tasks) { const int num_chain_tasks = tasks->num_chain_tasks; - if (num_chain_tasks < 1) - return true; + if (num_chain_tasks < 1) return true; // TODO(user): add stronger bounds. // The duration of the chain plus that of nonchain tasks that must be // performed during the chain is a lower bound of the chain span. @@ -488,13 +469,10 @@ bool DisjunctivePropagator::ChainSpanMin(Tasks *tasks) { bool DisjunctivePropagator::ChainSpanMinDynamic(Tasks *tasks) { // Do nothing if there are no chain tasks or no nonchain tasks. const int num_chain_tasks = tasks->num_chain_tasks; - if (num_chain_tasks < 1) - return true; - if (num_chain_tasks == tasks->start_min.size()) - return true; + if (num_chain_tasks < 1) return true; + if (num_chain_tasks == tasks->start_min.size()) return true; const int task_index = num_chain_tasks; - if (!Precedences(tasks)) - return false; + if (!Precedences(tasks)) return false; const int64 min_possible_chain_end = tasks->end_min[num_chain_tasks - 1]; const int64 max_possible_chain_start = tasks->start_max[0]; // For each chain task i, compute cumulated duration of chain tasks before it. @@ -532,8 +510,7 @@ bool DisjunctivePropagator::ChainSpanMinDynamic(Tasks *tasks) { int64 span_min = kint64max; bool schedule_is_feasible = false; for (int i = 0; i < num_chain_tasks; ++i) { - if (!tasks->is_preemptible[i]) - continue; + if (!tasks->is_preemptible[i]) continue; // Estimate span min if tasks is performed during i. // For all possible minimal-span schedules, there is a schedule where task i // and nonchain task form a single block. Thus, we only consider those. @@ -543,8 +520,7 @@ bool DisjunctivePropagator::ChainSpanMinDynamic(Tasks *tasks) { const int64 block_start_max = std::min(tasks->start_max[task_index], tasks->start_max[i] - tasks->duration_min[task_index]); - if (block_start_min > block_start_max) - continue; + if (block_start_min > block_start_max) continue; // Compute the block start that yields the minimal span. // Given a feasible block start, a chain of minimum span constrained to @@ -562,9 +538,9 @@ bool DisjunctivePropagator::ChainSpanMinDynamic(Tasks *tasks) { max_possible_chain_start + total_duration_before_[i]; // The map from block start to minimal tail length also has an inflection // point, that additionally depends on the nonchain task's duration. - const int64 tail_inflection = - min_possible_chain_end - (total_duration - total_duration_before_[i]) - - tasks->duration_min[task_index]; + const int64 tail_inflection = min_possible_chain_end - + (total_duration - total_duration_before_[i]) - + tasks->duration_min[task_index]; // All block start values between these two yield the same minimal span. // Indeed, first, mind that the inflection points might be in any order. // - if head_inflection < tail_inflection, then inside the interval @@ -638,8 +614,7 @@ void AppendTasksFromPath(const std::vector &path, tasks->end_max.push_back(CapAdd(cumul_max, after_visit)); tasks->is_preemptible.push_back(false); } - if (i == num_nodes - 1) - break; + if (i == num_nodes - 1) break; // Tasks from travels. // A travel task starts at Cumul(path[i]) + pre_travel, @@ -698,8 +673,7 @@ void FillTravelBoundsOfVehicle(int vehicle, const std::vector &path, void AppendTasksFromIntervals(const std::vector &intervals, DisjunctivePropagator::Tasks *tasks) { for (IntervalVar *interval : intervals) { - if (!interval->MustBePerformed()) - continue; + if (!interval->MustBePerformed()) continue; tasks->start_min.push_back(interval->StartMin()); tasks->start_max.push_back(interval->StartMax()); tasks->duration_min.push_back(interval->DurationMin()); @@ -712,7 +686,8 @@ void AppendTasksFromIntervals(const std::vector &intervals, GlobalVehicleBreaksConstraint::GlobalVehicleBreaksConstraint( const RoutingDimension *dimension) - : Constraint(dimension->model()->solver()), model_(dimension->model()), + : Constraint(dimension->model()->solver()), + model_(dimension->model()), dimension_(dimension) { vehicle_demons_.resize(model_->vehicles()); } @@ -759,11 +734,9 @@ void GlobalVehicleBreaksConstraint::InitialPropagate() { // It also filters out a part of uninteresting events, on which the vehicle // propagator will not find anything new. void GlobalVehicleBreaksConstraint::PropagateNode(int node) { - if (!model_->VehicleVar(node)->Bound()) - return; + if (!model_->VehicleVar(node)->Bound()) return; const int vehicle = model_->VehicleVar(node)->Min(); - if (vehicle < 0 || vehicle_demons_[vehicle] == nullptr) - return; + if (vehicle < 0 || vehicle_demons_[vehicle] == nullptr) return; EnqueueDelayedDemon(vehicle_demons_[vehicle]); } @@ -772,15 +745,15 @@ void GlobalVehicleBreaksConstraint::FillPartialPathOfVehicle(int vehicle) { int current = model_->Start(vehicle); while (!model_->IsEnd(current)) { path_.push_back(current); - current = - model_->NextVar(current)->Bound() ? model_->NextVar(current)->Min() - : model_->End(vehicle); + current = model_->NextVar(current)->Bound() + ? model_->NextVar(current)->Min() + : model_->End(vehicle); } path_.push_back(current); } -void -GlobalVehicleBreaksConstraint::FillPathTravels(const std::vector &path) { +void GlobalVehicleBreaksConstraint::FillPathTravels( + const std::vector &path) { const int num_travels = path.size() - 1; travel_bounds_.min_travels.resize(num_travels); travel_bounds_.max_travels.resize(num_travels); @@ -833,8 +806,7 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { dimension_->GetBreakDistanceDurationOfVehicle(vehicle); // Do the actual reasoning, no need to continue if infeasible. - if (!disjunctive_propagator_.Propagate(&tasks_)) - solver()->Fail(); + if (!disjunctive_propagator_.Propagate(&tasks_)) solver()->Fail(); // Make task translators to help set new bounds of CP variables. task_translators_.clear(); @@ -845,14 +817,12 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { (i == num_nodes - 1) ? 0 : travel_bounds_.pre_travels[i]; task_translators_.emplace_back(dimension_->CumulVar(path_[i]), before_visit, after_visit); - if (i == num_nodes - 1) - break; - task_translators_.emplace_back(); // Dummy translator for travel tasks. + if (i == num_nodes - 1) break; + task_translators_.emplace_back(); // Dummy translator for travel tasks. } for (IntervalVar *interval : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { - if (!interval->MustBePerformed()) - continue; + if (!interval->MustBePerformed()) continue; task_translators_.emplace_back(interval); } @@ -869,8 +839,7 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { // Reasoning on slack variables: when intervals must be inside an arc, // that arc's slack must be large enough to accommodate for those. // TODO(user): Make a version more efficient than O(n^2). - if (dimension_->GetBreakIntervalsOfVehicle(vehicle).empty()) - return; + if (dimension_->GetBreakIntervalsOfVehicle(vehicle).empty()) return; // If the last arc of the path was not bound, do not change slack. const int64 last_bound_arc = num_nodes - 2 - (model_->NextVar(path_[num_nodes - 2])->Bound() ? 0 : 1); @@ -884,8 +853,7 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { int64 total_break_inside_arc = 0; for (IntervalVar *interval : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { - if (!interval->MustBePerformed()) - continue; + if (!interval->MustBePerformed()) continue; const int64 interval_start_max = interval->StartMax(); const int64 interval_end_min = interval->EndMin(); const int64 interval_duration_min = interval->DurationMin(); @@ -910,8 +878,7 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { break; } } - if (!has_optional) - return; + if (!has_optional) return; } const std::vector &break_intervals = dimension_->GetBreakIntervalsOfVehicle(vehicle); @@ -927,8 +894,7 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { CapAdd(dimension_->CumulVar(path_[pos])->Min(), visit_end_offset); for (IntervalVar *interval : break_intervals) { - if (!interval->MayBePerformed()) - continue; + if (!interval->MayBePerformed()) continue; const bool interval_is_performed = interval->MustBePerformed(); const int64 interval_start_max = interval->StartMax(); const int64 interval_end_min = interval->EndMin(); @@ -987,14 +953,14 @@ void GlobalVehicleBreaksConstraint::PropagateVehicle(int vehicle) { namespace { class VehicleBreaksFilter : public BasePathFilter { -public: + public: VehicleBreaksFilter(const RoutingModel &routing_model, const RoutingDimension &dimension); std::string DebugString() const override { return "VehicleBreaksFilter"; } - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; -private: + private: // Fills path_ with the path of vehicle, start to end. void FillPathOfVehicle(int64 vehicle); std::vector path_; @@ -1018,7 +984,8 @@ VehicleBreaksFilter::VehicleBreaksFilter(const RoutingModel &routing_model, const RoutingDimension &dimension) : BasePathFilter(routing_model.Nexts(), routing_model.Size() + routing_model.vehicles()), - model_(routing_model), dimension_(dimension) { + model_(routing_model), + dimension_(dimension) { DCHECK(dimension_.HasBreakConstraints()); start_to_vehicle_.resize(Size(), -1); for (int i = 0; i < routing_model.vehicles(); ++i) { @@ -1055,8 +1022,8 @@ bool VehicleBreaksFilter::AcceptPath(int64 path_start, int64 chain_start, // Add forbidden intervals only if a node has some. tasks_.forbidden_intervals.clear(); if (std::any_of(path_.begin(), path_.end(), [this](int64 node) { - return dimension_.forbidden_intervals()[node].NumIntervals() > 0; - })) { + return dimension_.forbidden_intervals()[node].NumIntervals() > 0; + })) { tasks_.forbidden_intervals.assign(tasks_.start_min.size(), nullptr); for (int i = 0; i < path_.size(); ++i) { tasks_.forbidden_intervals[2 * i] = @@ -1077,8 +1044,7 @@ bool VehicleBreaksFilter::AcceptPath(int64 path_start, int64 chain_start, old_end_min_ = tasks_.end_min; old_end_max_ = tasks_.end_max; is_feasible = disjunctive_propagator_.Propagate(&tasks_); - if (!is_feasible) - break; + if (!is_feasible) break; // If fixed point reached, stop. if ((old_start_min_ == tasks_.start_min) && (old_start_max_ == tasks_.start_max) && @@ -1089,13 +1055,12 @@ bool VehicleBreaksFilter::AcceptPath(int64 path_start, int64 chain_start, return is_feasible; } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeVehicleBreaksFilter(const RoutingModel &routing_model, - const RoutingDimension &dimension) { - return routing_model.solver() - ->RevAlloc(new VehicleBreaksFilter(routing_model, dimension)); +IntVarLocalSearchFilter *MakeVehicleBreaksFilter( + const RoutingModel &routing_model, const RoutingDimension &dimension) { + return routing_model.solver()->RevAlloc( + new VehicleBreaksFilter(routing_model, dimension)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_flags.cc b/ortools/constraint_solver/routing_flags.cc index fd9a216a0f..518b95a8ce 100644 --- a/ortools/constraint_solver/routing_flags.cc +++ b/ortools/constraint_solver/routing_flags.cc @@ -134,26 +134,25 @@ void SetFirstSolutionStrategyFromFlags(RoutingSearchParameters *parameters) { CHECK(parameters != nullptr); const std::map first_solution_string_to_parameters = { - { "PathCheapestArc", FirstSolutionStrategy::PATH_CHEAPEST_ARC }, - { "PathMostConstrainedArc", - FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC }, - { "EvaluatorStrategy", FirstSolutionStrategy::EVALUATOR_STRATEGY }, - { "Savings", FirstSolutionStrategy::SAVINGS }, - { "Sweep", FirstSolutionStrategy::SWEEP }, - { "Christofides", FirstSolutionStrategy::CHRISTOFIDES }, - { "AllUnperformed", FirstSolutionStrategy::ALL_UNPERFORMED }, - { "BestInsertion", FirstSolutionStrategy::BEST_INSERTION }, - { "GlobalCheapestInsertion", - FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION }, - { "SequentialGlobalCheapestInsertion", - FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION }, - { "LocalCheapestInsertion", - FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION }, - { "GlobalCheapestArc", FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC }, - { "LocalCheapestArc", FirstSolutionStrategy::LOCAL_CHEAPEST_ARC }, - { "DefaultStrategy", FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE }, - { "", FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE } - }; + {"PathCheapestArc", FirstSolutionStrategy::PATH_CHEAPEST_ARC}, + {"PathMostConstrainedArc", + FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC}, + {"EvaluatorStrategy", FirstSolutionStrategy::EVALUATOR_STRATEGY}, + {"Savings", FirstSolutionStrategy::SAVINGS}, + {"Sweep", FirstSolutionStrategy::SWEEP}, + {"Christofides", FirstSolutionStrategy::CHRISTOFIDES}, + {"AllUnperformed", FirstSolutionStrategy::ALL_UNPERFORMED}, + {"BestInsertion", FirstSolutionStrategy::BEST_INSERTION}, + {"GlobalCheapestInsertion", + FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION}, + {"SequentialGlobalCheapestInsertion", + FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION}, + {"LocalCheapestInsertion", + FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION}, + {"GlobalCheapestArc", FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC}, + {"LocalCheapestArc", FirstSolutionStrategy::LOCAL_CHEAPEST_ARC}, + {"DefaultStrategy", FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE}, + {"", FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE}}; FirstSolutionStrategy::Value strategy; if (gtl::FindCopy(first_solution_string_to_parameters, absl::GetFlag(FLAGS_routing_first_solution), &strategy)) { @@ -195,15 +194,14 @@ void SetLocalSearchMetaheuristicFromFlags(RoutingSearchParameters *parameters) { namespace { OptionalBoolean ToOptionalBoolean(bool x) { return x ? BOOL_TRUE : BOOL_FALSE; } -} // namespace +} // namespace void AddLocalSearchNeighborhoodOperatorsFromFlags( RoutingSearchParameters *parameters) { CHECK(parameters != nullptr); parameters->set_cheapest_insertion_ls_operator_neighbors_ratio(1.0); - RoutingSearchParameters:: - LocalSearchNeighborhoodOperators *const local_search_operators = - parameters->mutable_local_search_operators(); + RoutingSearchParameters::LocalSearchNeighborhoodOperators *const + local_search_operators = parameters->mutable_local_search_operators(); // TODO(user): Remove these overrides: they should be set by the caller, via // a baseline RoutingSearchParameters obtained from DefaultSearchParameters(). @@ -339,4 +337,4 @@ RoutingModelParameters BuildModelParametersFromFlags() { return parameters; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_flags.h b/ortools/constraint_solver/routing_flags.h index 81d442f9e1..5962359d20 100644 --- a/ortools/constraint_solver/routing_flags.h +++ b/ortools/constraint_solver/routing_flags.h @@ -88,6 +88,6 @@ RoutingModelParameters BuildModelParametersFromFlags(); /// describe a valid set of routing search parameters. RoutingSearchParameters BuildSearchParametersFromFlags(); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_absl::GetFlag(FLAGS_H_) +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_absl::GetFlag(FLAGS_H_) diff --git a/ortools/constraint_solver/routing_flow.cc b/ortools/constraint_solver/routing_flow.cc index 6c5bd02a64..1fff026e99 100644 --- a/ortools/constraint_solver/routing_flow.cc +++ b/ortools/constraint_solver/routing_flow.cc @@ -29,18 +29,16 @@ void AddDisjunctionsFromNodes(const RoutingModel &model, } } } -} // namespace +} // namespace bool RoutingModel::IsMatchingModel() const { // TODO(user): Support overlapping disjunctions and disjunctions with // a cardinality > 1. absl::flat_hash_set disjunction_nodes; for (DisjunctionIndex i(0); i < GetNumberOfDisjunctions(); ++i) { - if (GetDisjunctionMaxCardinality(i) > 1) - return false; + if (GetDisjunctionMaxCardinality(i) > 1) return false; for (int64 node : GetDisjunctionIndices(i)) { - if (!disjunction_nodes.insert(node).second) - return false; + if (!disjunction_nodes.insert(node).second) return false; } } for (const auto &pd_pairs : GetPickupAndDeliveryPairs()) { @@ -48,8 +46,7 @@ bool RoutingModel::IsMatchingModel() const { AddDisjunctionsFromNodes(*this, pd_pairs.first, &disjunctions); AddDisjunctionsFromNodes(*this, pd_pairs.second, &disjunctions); // Pairs involving more than 2 disjunctions are not supported. - if (disjunctions.size() > 2) - return false; + if (disjunctions.size() > 2) return false; } // Detect if a "unary" dimension prevents from having more than a single // non-start/end node (or a single pickup and delivery pair) on a route. @@ -81,8 +78,7 @@ bool RoutingModel::IsMatchingModel() const { for (const auto &pd_pairs : GetPickupAndDeliveryPairs()) { const auto transit_cmp = [&transits](int i, int j) { return transits[i] < transits[j]; - } - ; + }; min_transit = std::min( min_transit, // Min transit from pickup. @@ -101,8 +97,7 @@ bool RoutingModel::IsMatchingModel() const { } // If there cannot be more than one node or pickup and delivery, a matching // problem has been detected. - if (CapProd(min_transit, 2) > max_vehicle_capacity) - return true; + if (CapProd(min_transit, 2) > max_vehicle_capacity) return true; } return false; } @@ -134,11 +129,10 @@ struct FlowArc { int64 capacity; int64 cost; }; -} // namespace +} // namespace -bool -RoutingModel::SolveMatchingModel(Assignment *assignment, - const RoutingSearchParameters ¶meters) { +bool RoutingModel::SolveMatchingModel( + Assignment *assignment, const RoutingSearchParameters ¶meters) { VLOG(2) << "Solving with flow"; assignment->Clear(); @@ -163,8 +157,7 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, // disjunctions. absl::flat_hash_map > flow_to_pd; for (const auto &pd_pairs : GetPickupAndDeliveryPairs()) { - disjunction_to_flow_nodes.push_back({ - }); + disjunction_to_flow_nodes.push_back({}); absl::flat_hash_set disjunctions; AddDisjunctionsFromNodes(*this, pd_pairs.first, &disjunctions); AddDisjunctionsFromNodes(*this, pd_pairs.second, &disjunctions); @@ -172,7 +165,7 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, in_disjunction[pickup] = true; for (int64 delivery : pd_pairs.second) { in_disjunction[delivery] = true; - flow_to_pd[num_flow_nodes] = { pickup, delivery }; + flow_to_pd[num_flow_nodes] = {pickup, delivery}; disjunction_to_flow_nodes.back().push_back(num_flow_nodes); num_flow_nodes++; } @@ -196,13 +189,11 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, // Create non-pickup and delivery flow nodes. absl::flat_hash_map flow_to_non_pd; for (int node = 0; node < Size(); ++node) { - if (IsStart(node) || in_disjunction[node]) - continue; + if (IsStart(node) || in_disjunction[node]) continue; const std::vector &disjunctions = GetDisjunctionIndices(node); DCHECK_LE(disjunctions.size(), 1); - disjunction_to_flow_nodes.push_back({ - }); + disjunction_to_flow_nodes.push_back({}); disjunction_penalties.push_back( disjunctions.empty() ? kNoPenalty : GetDisjunctionPenalty(disjunctions.back())); @@ -234,9 +225,7 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, } else { flow_to_disjunction[num_flow_nodes] = i; for (int64 flow_node : flow_nodes) { - arcs.push_back({ - flow_node, num_flow_nodes, 1, 0 - }); + arcs.push_back({flow_node, num_flow_nodes, 1, 0}); } num_flow_nodes++; } @@ -269,16 +258,14 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, CapAdd(GetArcCostForVehicle(pickup, delivery, vehicle), GetArcCostForVehicle(delivery, end, vehicle))); const absl::flat_hash_map nexts = { - { start, pickup }, { pickup, delivery }, { delivery, end } - }; + {start, pickup}, {pickup, delivery}, {delivery, end}}; for (LocalDimensionCumulOptimizer &optimizer : optimizers) { int64 cumul_cost_value = 0; - // TODO(user): if the result is RELAXED_OPTIMAL_ONLY, do a - // second pass with an MP solver. + // TODO(user): if the result is RELAXED_OPTIMAL_ONLY, do a + // second pass with an MP solver. if (optimizer.ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [&nexts](int64 node) { - return nexts.find(node)->second; - }, + vehicle, + [&nexts](int64 node) { return nexts.find(node)->second; }, &cumul_cost_value) != DimensionSchedulingStatus::INFEASIBLE) { cost = CapAdd(cost, cumul_cost_value); @@ -293,16 +280,15 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, add_arc = true; cost = CapAdd(GetArcCostForVehicle(start, node, vehicle), GetArcCostForVehicle(node, end, vehicle)); - const absl::flat_hash_map nexts = { { start, node }, - { node, end } }; + const absl::flat_hash_map nexts = {{start, node}, + {node, end}}; for (LocalDimensionCumulOptimizer &optimizer : optimizers) { int64 cumul_cost_value = 0; - // TODO(user): if the result is RELAXED_OPTIMAL_ONLY, do a - // second pass with an MP solver. + // TODO(user): if the result is RELAXED_OPTIMAL_ONLY, do a + // second pass with an MP solver. if (optimizer.ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [&nexts](int64 node) { - return nexts.find(node)->second; - }, + vehicle, + [&nexts](int64 node) { return nexts.find(node)->second; }, &cumul_cost_value) != DimensionSchedulingStatus::INFEASIBLE) { cost = CapAdd(cost, cumul_cost_value); @@ -316,9 +302,7 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, DCHECK(false); } if (add_arc) { - arcs.push_back({ - num_flow_nodes, flow_node, 1, cost - }); + arcs.push_back({num_flow_nodes, flow_node, 1, cost}); } } } @@ -331,30 +315,22 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, const int sink = source + 1; // Source connected to vehicle nodes. for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { - arcs.push_back({ - source, vehicle_to_flow[vehicle], 1, 0 - }); + arcs.push_back({source, vehicle_to_flow[vehicle], 1, 0}); } // Handle unperformed nodes. // Create a node to catch unperformed nodes and connect it to source. const int unperformed = num_flow_nodes; const int64 flow_supply = disjunction_to_flow_nodes.size(); - arcs.push_back({ - source, unperformed, flow_supply, 0 - }); + arcs.push_back({source, unperformed, flow_supply, 0}); for (const auto &flow_disjunction_element : flow_to_disjunction) { const int flow_node = flow_disjunction_element.first; const int64 penalty = disjunction_penalties[flow_disjunction_element.second]; if (penalty != kNoPenalty) { - arcs.push_back({ - unperformed, flow_node, 1, penalty - }); + arcs.push_back({unperformed, flow_node, 1, penalty}); } - // Connect non-vehicle flow nodes to sinks. - arcs.push_back({ - flow_node, sink, 1, 0 - }); + // Connect non-vehicle flow nodes to sinks. + arcs.push_back({flow_node, sink, 1, 0}); } // Rescale costs for min-cost flow; assuming max cost resulting from the @@ -363,9 +339,8 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, // accumulate num_nodes+1 such arcs (with capacity being 1 for costed arcs)). int64 scale_factor = 1; const FlowArc &arc_with_max_cost = *std::max_element( - arcs.begin(), arcs.end(), [](const FlowArc & a, const FlowArc & b) { - return a.cost < b.cost; - }); + arcs.begin(), arcs.end(), + [](const FlowArc &a, const FlowArc &b) { return a.cost < b.cost; }); // SimpleMinCostFlow adds a source and a sink node, so actual number of // nodes to consider is num_flow_nodes + 3. const int actual_flow_num_nodes = num_flow_nodes + 3; @@ -450,4 +425,4 @@ RoutingModel::SolveMatchingModel(Assignment *assignment, return true; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_index_manager.cc b/ortools/constraint_solver/routing_index_manager.cc index f18270ff11..4a7ee87637 100644 --- a/ortools/constraint_solver/routing_index_manager.cc +++ b/ortools/constraint_solver/routing_index_manager.cc @@ -25,11 +25,9 @@ const int64 RoutingIndexManager::kUnassigned = -1; RoutingIndexManager::RoutingIndexManager(int num_nodes, int num_vehicles, NodeIndex depot) - : RoutingIndexManager( - num_nodes, num_vehicles, - std::vector >(num_vehicles, { - depot, depot -})) {} + : RoutingIndexManager(num_nodes, num_vehicles, + std::vector >( + num_vehicles, {depot, depot})) {} RoutingIndexManager::RoutingIndexManager(int num_nodes, int num_vehicles, const std::vector &starts, @@ -38,7 +36,7 @@ RoutingIndexManager::RoutingIndexManager(int num_nodes, int num_vehicles, CHECK_EQ(ends.size(), num_vehicles); std::vector > starts_ends(num_vehicles); for (int v = 0; v < num_vehicles; ++v) { - starts_ends[v] = { starts[v], ends[v] }; + starts_ends[v] = {starts[v], ends[v]}; } Initialize(num_nodes, num_vehicles, starts_ends); } @@ -122,8 +120,8 @@ void RoutingIndexManager::Initialize( } } -std::vector -RoutingIndexManager::NodesToIndices(const std::vector &nodes) const { +std::vector RoutingIndexManager::NodesToIndices( + const std::vector &nodes) const { std::vector indices; indices.reserve(nodes.size()); for (const NodeIndex node : nodes) { @@ -134,8 +132,8 @@ RoutingIndexManager::NodesToIndices(const std::vector &nodes) const { return indices; } -std::vector -RoutingIndexManager::IndicesToNodes(const std::vector &indices) const { +std::vector RoutingIndexManager::IndicesToNodes( + const std::vector &indices) const { std::vector nodes; nodes.reserve(indices.size()); for (const int64 index : indices) { @@ -144,4 +142,4 @@ RoutingIndexManager::IndicesToNodes(const std::vector &indices) const { return nodes; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_index_manager.h b/ortools/constraint_solver/routing_index_manager.h index 703cbb57a7..5b1371c24f 100644 --- a/ortools/constraint_solver/routing_index_manager.h +++ b/ortools/constraint_solver/routing_index_manager.h @@ -46,7 +46,7 @@ namespace operations_research { /// and end nodes) + number of non-start or end nodes. /// class RoutingIndexManager { -public: + public: typedef RoutingNodeIndex NodeIndex; static const int64 kUnassigned; @@ -91,8 +91,8 @@ public: return index_to_node_[index]; } // Same as IndexToNode but for a given vector of indices. - std::vector - IndicesToNodes(const std::vector &indices) const; + std::vector IndicesToNodes( + const std::vector &indices) const; // TODO(user) Add unit tests for NodesToIndices and IndicesToNodes. // TODO(user): Remove when removal of NodeIndex from RoutingModel is /// complete. @@ -102,7 +102,7 @@ public: return node_to_index_; } -private: + private: void Initialize( int num_nodes, int num_vehicles, const std::vector > &starts_ends); @@ -116,6 +116,6 @@ private: int num_unique_depots_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_INDEX_MANAGER_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_INDEX_MANAGER_H_ diff --git a/ortools/constraint_solver/routing_lp_scheduling.cc b/ortools/constraint_solver/routing_lp_scheduling.cc index 58fd700e1e..dc9795be65 100644 --- a/ortools/constraint_solver/routing_lp_scheduling.cc +++ b/ortools/constraint_solver/routing_lp_scheduling.cc @@ -99,16 +99,16 @@ void StoreVisitedPickupDeliveryPairsOnRoute( const RoutingDimension &dimension, int vehicle, const std::function &next_accessor, std::vector *visited_pairs, - std::vector > * - visited_pickup_delivery_indices_for_pair) { + std::vector > + *visited_pickup_delivery_indices_for_pair) { // visited_pickup_delivery_indices_for_pair must be all {-1, -1}. DCHECK_EQ(visited_pickup_delivery_indices_for_pair->size(), dimension.model()->GetPickupAndDeliveryPairs().size()); DCHECK(std::all_of(visited_pickup_delivery_indices_for_pair->begin(), visited_pickup_delivery_indices_for_pair->end(), [](std::pair p) { - return p.first == -1 && p.second == -1; - })); + return p.first == -1 && p.second == -1; + })); visited_pairs->clear(); if (!dimension.HasPickupToDeliveryLimits()) { return; @@ -149,41 +149,41 @@ void StoreVisitedPickupDeliveryPairsOnRoute( } } -} // namespace +} // namespace LocalDimensionCumulOptimizer::LocalDimensionCumulOptimizer( const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type) - : optimizer_core_(dimension, /*use_precedence_propagator=*/ false) { + : optimizer_core_(dimension, /*use_precedence_propagator=*/false) { // Using one solver per vehicle in the hope that if routes don't change this // will be faster. const int vehicles = dimension->model()->vehicles(); solver_.resize(vehicles); switch (solver_type) { - case RoutingSearchParameters::GLOP: { - const glop::GlopParameters parameters = GetGlopParametersForLocalLP(); - for (int vehicle = 0; vehicle < vehicles; ++vehicle) { - solver_[vehicle] = absl::make_unique(parameters); + case RoutingSearchParameters::GLOP: { + const glop::GlopParameters parameters = GetGlopParametersForLocalLP(); + for (int vehicle = 0; vehicle < vehicles; ++vehicle) { + solver_[vehicle] = absl::make_unique(parameters); + } + break; } - break; - } - case RoutingSearchParameters::CP_SAT: { - for (int vehicle = 0; vehicle < vehicles; ++vehicle) { - solver_[vehicle] = absl::make_unique(); + case RoutingSearchParameters::CP_SAT: { + for (int vehicle = 0; vehicle < vehicles; ++vehicle) { + solver_[vehicle] = absl::make_unique(); + } + break; } - break; - } - default: - LOG(DFATAL) << "Unrecognized solver type: " << solver_type; + default: + LOG(DFATAL) << "Unrecognized solver type: " << solver_type; } } DimensionSchedulingStatus LocalDimensionCumulOptimizer::ComputeRouteCumulCost( int vehicle, const std::function &next_accessor, int64 *optimal_cost) { - return optimizer_core_.OptimizeSingleRoute( - vehicle, next_accessor, solver_[vehicle].get(), nullptr, nullptr, - optimal_cost, nullptr); + return optimizer_core_.OptimizeSingleRoute(vehicle, next_accessor, + solver_[vehicle].get(), nullptr, + nullptr, optimal_cost, nullptr); } DimensionSchedulingStatus @@ -229,22 +229,18 @@ CumulBoundsPropagator::CumulBoundsPropagator(const RoutingDimension *dimension) tree_parent_node_of_.resize(num_nodes_, kNoParent); propagated_bounds_.resize(num_nodes_); visited_pickup_delivery_indices_for_pair_.resize( - dimension->model()->GetPickupAndDeliveryPairs().size(), { - -1, -1 - }); + dimension->model()->GetPickupAndDeliveryPairs().size(), {-1, -1}); } void CumulBoundsPropagator::AddArcs(int first_index, int second_index, int64 offset) { - // Add arc first_index + offset <= second_index - outgoing_arcs_[PositiveNode(first_index)].push_back({ - PositiveNode(second_index), offset - }); + // Add arc first_index + offset <= second_index + outgoing_arcs_[PositiveNode(first_index)].push_back( + {PositiveNode(second_index), offset}); AddNodeToQueue(PositiveNode(first_index)); - // Add arc -second_index + transit <= -first_index - outgoing_arcs_[NegativeNode(second_index)].push_back({ - NegativeNode(first_index), offset - }); + // Add arc -second_index + transit <= -first_index + outgoing_arcs_[NegativeNode(second_index)].push_back( + {NegativeNode(first_index), offset}); AddNodeToQueue(NegativeNode(second_index)); } @@ -309,7 +305,7 @@ bool CumulBoundsPropagator::InitializeArcsAndBounds( visited_pickup_delivery_indices_for_pair_[pair_index].first; const int64 delivery_index = visited_pickup_delivery_indices_for_pair_[pair_index].second; - visited_pickup_delivery_indices_for_pair_[pair_index] = { -1, -1 }; + visited_pickup_delivery_indices_for_pair_[pair_index] = {-1, -1}; DCHECK_GE(pickup_index, 0); if (delivery_index < 0) { @@ -377,10 +373,8 @@ bool CumulBoundsPropagator::DisassembleSubtree(int source, int target) { tmp_dfs_stack_.pop_back(); for (const ArcInfo &arc : outgoing_arcs_[tail]) { const int child_node = arc.head; - if (tree_parent_node_of_[child_node] != tail) - continue; - if (child_node == target) - return false; + if (tree_parent_node_of_[child_node] != tail) continue; + if (child_node == target) return false; tree_parent_node_of_[child_node] = kParentToBePropagated; tmp_dfs_stack_.push_back(child_node); } @@ -391,9 +385,8 @@ bool CumulBoundsPropagator::DisassembleSubtree(int source, int target) { bool CumulBoundsPropagator::PropagateCumulBounds( const std::function &next_accessor, int64 cumul_offset) { tree_parent_node_of_.assign(num_nodes_, kNoParent); - DCHECK(std::none_of(node_in_queue_.begin(), node_in_queue_.end(), [](bool b) { - return b; - })); + DCHECK(std::none_of(node_in_queue_.begin(), node_in_queue_.end(), + [](bool b) { return b; })); DCHECK(bf_queue_.empty()); if (!InitializeArcsAndBounds(next_accessor, cumul_offset)) { @@ -418,9 +411,9 @@ bool CumulBoundsPropagator::PropagateCumulBounds( for (const ArcInfo &arc : outgoing_arcs_[node]) { // NOTE: kint64min as a lower bound means no lower bound at all, so we // don't use this value to propagate. - const int64 induced_lb = - (lower_bound == kint64min) ? kint64min - : CapAdd(lower_bound, arc.offset); + const int64 induced_lb = (lower_bound == kint64min) + ? kint64min + : CapAdd(lower_bound, arc.offset); const int head_node = arc.head; if (induced_lb <= current_lb[head_node]) { @@ -446,9 +439,7 @@ DimensionCumulOptimizerCore::DimensionCumulOptimizerCore( const RoutingDimension *dimension, bool use_precedence_propagator) : dimension_(dimension), visited_pickup_delivery_indices_for_pair_( - dimension->model()->GetPickupAndDeliveryPairs().size(), { - -1, -1 -}) { + dimension->model()->GetPickupAndDeliveryPairs().size(), {-1, -1}) { if (use_precedence_propagator) { propagator_ = absl::make_unique(dimension); } @@ -462,7 +453,7 @@ DimensionCumulOptimizerCore::DimensionCumulOptimizerCore( for (int vehicle = 0; vehicle < num_vehicles; ++vehicle) { vehicle_to_all_break_variables_offset_.push_back(num_break_vars); const auto &intervals = dimension_->GetBreakIntervalsOfVehicle(vehicle); - num_break_vars += 2 * intervals.size(); // 2 variables per break. + num_break_vars += 2 * intervals.size(); // 2 variables per break. } all_break_variables_.resize(num_break_vars, -1); } @@ -580,9 +571,9 @@ bool DimensionCumulOptimizerCore::OptimizeAndPack( // Note: We pass a non-nullptr cost to the Optimize() method so the costs are // optimized by the LP. int64 cost = 0; - if (!Optimize(next_accessor, solver, /*cumul_values=*/ nullptr, - /*break_values=*/ nullptr, &cost, /*transit_cost=*/ nullptr, - /*clear_lp=*/ false)) { + if (!Optimize(next_accessor, solver, /*cumul_values=*/nullptr, + /*break_values=*/nullptr, &cost, /*transit_cost=*/nullptr, + /*clear_lp=*/false)) { return false; } @@ -609,15 +600,12 @@ DimensionCumulOptimizerCore::OptimizeAndPackSingleRoute( // costs are optimized by the LP. int64 cost = 0; if (OptimizeSingleRoute( - vehicle, next_accessor, solver, /*cumul_values=*/ nullptr, - /*break_values=*/ nullptr, &cost, /*transit_cost=*/ nullptr, - /*clear_lp=*/ false) == DimensionSchedulingStatus::INFEASIBLE) { + vehicle, next_accessor, solver, /*cumul_values=*/nullptr, + /*break_values=*/nullptr, &cost, /*transit_cost=*/nullptr, + /*clear_lp=*/false) == DimensionSchedulingStatus::INFEASIBLE) { return DimensionSchedulingStatus::INFEASIBLE; } - const DimensionSchedulingStatus status = PackRoutes({ - vehicle - }, - solver); + const DimensionSchedulingStatus status = PackRoutes({vehicle}, solver); if (status == DimensionSchedulingStatus::INFEASIBLE) { return DimensionSchedulingStatus::INFEASIBLE; } @@ -631,9 +619,8 @@ DimensionCumulOptimizerCore::OptimizeAndPackSingleRoute( return status; } -DimensionSchedulingStatus -DimensionCumulOptimizerCore::PackRoutes(std::vector vehicles, - RoutingLinearSolverWrapper *solver) { +DimensionSchedulingStatus DimensionCumulOptimizerCore::PackRoutes( + std::vector vehicles, RoutingLinearSolverWrapper *solver) { const RoutingModel *model = dimension_->model(); // NOTE(user): Given our constraint matrix, our problem *should* always @@ -685,8 +672,8 @@ DimensionCumulOptimizerCore::PackRoutes(std::vector vehicles, return solver->Solve(model->RemainingTime()); } -void -DimensionCumulOptimizerCore::InitOptimizer(RoutingLinearSolverWrapper *solver) { +void DimensionCumulOptimizerCore::InitOptimizer( + RoutingLinearSolverWrapper *solver) { solver->Clear(); index_to_cumul_variable_.assign(dimension_->cumuls().size(), -1); max_end_cumul_ = solver->CreateNewPositiveVariable(); @@ -836,17 +823,14 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( solver->SetCoefficient(ct, lp_cumuls[pos], -1); solver->SetCoefficient(ct, lp_slacks[pos], -1); } - if (route_cost_offset != nullptr) - *route_cost_offset = 0; + if (route_cost_offset != nullptr) *route_cost_offset = 0; if (optimize_costs) { // Add soft upper bounds. for (int pos = 0; pos < path_size; ++pos) { - if (!dimension_->HasCumulVarSoftUpperBound(path[pos])) - continue; + if (!dimension_->HasCumulVarSoftUpperBound(path[pos])) continue; const int64 coef = dimension_->GetCumulVarSoftUpperBoundCoefficient(path[pos]); - if (coef == 0) - continue; + if (coef == 0) continue; int64 bound = dimension_->GetCumulVarSoftUpperBound(path[pos]); if (bound < cumul_offset && route_cost_offset != nullptr) { // Add coef * (cumul_offset - bound) to the cost offset. @@ -867,12 +851,10 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( } // Add soft lower bounds. for (int pos = 0; pos < path_size; ++pos) { - if (!dimension_->HasCumulVarSoftLowerBound(path[pos])) - continue; + if (!dimension_->HasCumulVarSoftLowerBound(path[pos])) continue; const int64 coef = dimension_->GetCumulVarSoftLowerBoundCoefficient(path[pos]); - if (coef == 0) - continue; + if (coef == 0) continue; const int64 bound = std::max( 0, CapSub(dimension_->GetCumulVarSoftLowerBound(path[pos]), cumul_offset)); @@ -898,7 +880,7 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( visited_pickup_delivery_indices_for_pair_[pair_index].first; const int64 delivery_index = visited_pickup_delivery_indices_for_pair_[pair_index].second; - visited_pickup_delivery_indices_for_pair_[pair_index] = { -1, -1 }; + visited_pickup_delivery_indices_for_pair_[pair_index] = {-1, -1}; DCHECK_GE(pickup_index, 0); if (delivery_index < 0) { @@ -975,8 +957,7 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( // can miss some cases where the breaks cannot fit. // TODO(user): remove the need for returns in the code below. current_route_break_variables_.clear(); - if (!dimension_->HasBreakConstraints()) - return true; + if (!dimension_->HasBreakConstraints()) return true; const std::vector &breaks = dimension_->GetBreakIntervalsOfVehicle(vehicle); const int num_breaks = breaks.size(); @@ -1040,8 +1021,7 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( vehicle_to_all_break_variables_offset_[vehicle]; for (int br = 0; br < num_breaks; ++br) { const IntervalVar &break_var = *breaks[br]; - if (!break_var.MustBePerformed()) - continue; + if (!break_var.MustBePerformed()) continue; const int64 break_start_min = CapSub(break_var.StartMin(), cumul_offset); const int64 break_start_max = CapSub(break_var.StartMax(), cumul_offset); const int64 break_end_min = CapSub(break_var.EndMin(), cumul_offset); @@ -1064,12 +1044,11 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( lp_break_end[br] = solver->AddVariable(break_end_min, break_end_max); lp_break_duration[br] = solver->AddVariable(break_duration_min, break_duration_max); - // start + duration = end. - solver->AddLinearConstraint(0, 0, { - { lp_break_end[br], 1 } - , { lp_break_start[br], -1 } - , { lp_break_duration[br], -1 } - }); + // start + duration = end. + solver->AddLinearConstraint(0, 0, + {{lp_break_end[br], 1}, + {lp_break_start[br], -1}, + {lp_break_duration[br], -1}}); // Record index of variables all_break_variables_[all_break_variables_offset + 2 * br] = lp_break_start[br]; @@ -1092,20 +1071,16 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( if (solver->IsCPSATSolver()) { // Break can be before route. if (break_end_min <= vehicle_start_max) { - const int ct = solver->AddLinearConstraint(0, kint64max, { - { lp_cumuls.front(), 1 } - , { lp_break_end[br], -1 } - }); + const int ct = solver->AddLinearConstraint( + 0, kint64max, {{lp_cumuls.front(), 1}, {lp_break_end[br], -1}}); const int break_is_before_route = solver->AddVariable(0, 1); solver->SetEnforcementLiteral(ct, break_is_before_route); solver->SetCoefficient(break_in_one_slack_ct, break_is_before_route, 1); } // Break can be after route. if (vehicle_end_min <= break_start_max) { - const int ct = solver->AddLinearConstraint(0, kint64max, { - { lp_break_start[br], 1 } - , { lp_cumuls.back(), -1 } - }); + const int ct = solver->AddLinearConstraint( + 0, kint64max, {{lp_break_start[br], 1}, {lp_cumuls.back(), -1}}); const int break_is_after_route = solver->AddVariable(0, 1); solver->SetEnforcementLiteral(ct, break_is_after_route); solver->SetCoefficient(break_in_one_slack_ct, break_is_after_route, 1); @@ -1118,19 +1093,16 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( // or are not long enough to contain the break. const int64 slack_start_min = CapAdd(current_route_min_cumuls_[pos], pre_travel[pos]); - if (slack_start_min > break_start_max) - break; + if (slack_start_min > break_start_max) break; const int64 slack_end_max = CapSub(current_route_max_cumuls_[pos + 1], post_travel[pos]); - if (break_end_min > slack_end_max) - continue; + if (break_end_min > slack_end_max) continue; const int64 slack_duration_max = std::min(CapSub(CapSub(current_route_max_cumuls_[pos + 1], current_route_min_cumuls_[pos]), fixed_transit[pos]), dimension_->SlackVar(path[pos])->Max()); - if (slack_duration_max < break_duration_min) - continue; + if (slack_duration_max < break_duration_min) continue; // Break can fit into slack: make LP variable, add to break and slack // constraints. @@ -1141,9 +1113,7 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( solver->SetCoefficient(break_in_one_slack_ct, break_in_slack, 1); if (slack_linear_lower_bound_ct[pos] == -1) { slack_linear_lower_bound_ct[pos] = - solver->AddLinearConstraint(kint64min, 0, { - { lp_slacks[pos], -1 } - }); + solver->AddLinearConstraint(kint64min, 0, {{lp_slacks[pos], -1}}); } solver->SetCoefficient(slack_linear_lower_bound_ct[pos], break_in_slack, break_duration_min); @@ -1154,54 +1124,43 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( // lp_slacks(pos). const int break_duration_in_slack = solver->AddVariable(0, slack_duration_max); - solver->AddProductConstraint(break_duration_in_slack, { - break_in_slack, lp_break_duration[br] - }); + solver->AddProductConstraint(break_duration_in_slack, + {break_in_slack, lp_break_duration[br]}); if (slack_exact_lower_bound_ct[pos] == -1) { slack_exact_lower_bound_ct[pos] = - solver->AddLinearConstraint(kint64min, 0, { - { lp_slacks[pos], -1 } - }); + solver->AddLinearConstraint(kint64min, 0, {{lp_slacks[pos], -1}}); } solver->SetCoefficient(slack_exact_lower_bound_ct[pos], break_duration_in_slack, 1); - // If break_in_slack_i == 1, then - // 1) break_start >= cumul[pos] + pre_travel[pos] - const int break_start_after_current_ct = - solver->AddLinearConstraint(pre_travel[pos], kint64max, { - { lp_break_start[br], 1 } - , { lp_cumuls[pos], -1 } - }); + // If break_in_slack_i == 1, then + // 1) break_start >= cumul[pos] + pre_travel[pos] + const int break_start_after_current_ct = solver->AddLinearConstraint( + pre_travel[pos], kint64max, + {{lp_break_start[br], 1}, {lp_cumuls[pos], -1}}); solver->SetEnforcementLiteral(break_start_after_current_ct, break_in_slack); - // 2) break_end <= cumul[pos+1] - post_travel[pos] - const int break_ends_before_next_ct = - solver->AddLinearConstraint(post_travel[pos], kint64max, { - { lp_cumuls[pos + 1], 1 } - , { lp_break_end[br], -1 } - }); + // 2) break_end <= cumul[pos+1] - post_travel[pos] + const int break_ends_before_next_ct = solver->AddLinearConstraint( + post_travel[pos], kint64max, + {{lp_cumuls[pos + 1], 1}, {lp_break_end[br], -1}}); solver->SetEnforcementLiteral(break_ends_before_next_ct, break_in_slack); } } } - if (!solver->IsCPSATSolver()) - return true; + if (!solver->IsCPSATSolver()) return true; if (!dimension_->GetBreakDistanceDurationOfVehicle(vehicle).empty()) { // If there is an optional interval, the following model would be wrong. // TODO(user): support optional intervals. for (const IntervalVar *interval : dimension_->GetBreakIntervalsOfVehicle(vehicle)) { - if (!interval->MustBePerformed()) - return true; + if (!interval->MustBePerformed()) return true; } // When this feature is used, breaks are in sorted order. for (int br = 1; br < num_breaks; ++br) { - solver->AddLinearConstraint(0, kint64max, { - { lp_break_end[br - 1], -1 } - , { lp_break_start[br], 1 } - }); + solver->AddLinearConstraint( + 0, kint64max, {{lp_break_end[br - 1], -1}, {lp_break_start[br], 1}}); } } for (const auto &distance_duration : @@ -1237,13 +1196,10 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( // the whole timeline (-infinity, +infinity). int previous_cover = solver->AddVariable(CapAdd(vehicle_start_min, limit), CapAdd(vehicle_start_max, limit)); - solver->AddLinearConstraint(limit, limit, { - { previous_cover, 1 } - , { lp_cumuls.front(), -1 } - }); + solver->AddLinearConstraint(limit, limit, + {{previous_cover, 1}, {lp_cumuls.front(), -1}}); for (int br = 0; br < num_breaks; ++br) { - if (lp_break_start[br] == -1) - continue; + if (lp_break_start[br] == -1) continue; const int64 break_end_min = CapSub(breaks[br]->EndMin(), cumul_offset); const int64 break_end_max = CapSub(breaks[br]->EndMax(), cumul_offset); // break_is_eligible <=> @@ -1251,21 +1207,15 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( const int break_is_eligible = solver->AddVariable(0, 1); const int break_is_not_eligible = solver->AddVariable(0, 1); { - solver->AddLinearConstraint(1, 1, { - { break_is_eligible, 1 } - , { break_is_not_eligible, 1 } - }); - const int positive_ct = - solver->AddLinearConstraint(min_break_duration, kint64max, { - { lp_break_end[br], 1 } - , { lp_break_start[br], -1 } - }); + solver->AddLinearConstraint( + 1, 1, {{break_is_eligible, 1}, {break_is_not_eligible, 1}}); + const int positive_ct = solver->AddLinearConstraint( + min_break_duration, kint64max, + {{lp_break_end[br], 1}, {lp_break_start[br], -1}}); solver->SetEnforcementLiteral(positive_ct, break_is_eligible); - const int negative_ct = - solver->AddLinearConstraint(kint64min, min_break_duration - 1, { - { lp_break_end[br], 1 } - , { lp_break_start[br], -1 } - }); + const int negative_ct = solver->AddLinearConstraint( + kint64min, min_break_duration - 1, + {{lp_break_end[br], 1}, {lp_break_start[br], -1}}); solver->SetEnforcementLiteral(negative_ct, break_is_not_eligible); } // break_is_eligible => break_cover == break_end + limit. @@ -1276,43 +1226,30 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( const int break_cover = solver->AddVariable( CapAdd(std::min(vehicle_start_min, break_end_min), limit), CapAdd(std::max(vehicle_start_min, break_end_max), limit)); - const int limit_cover_ct = solver->AddLinearConstraint(limit, limit, { - { break_cover, 1 } - , { lp_break_end[br], -1 } - }); + const int limit_cover_ct = solver->AddLinearConstraint( + limit, limit, {{break_cover, 1}, {lp_break_end[br], -1}}); solver->SetEnforcementLiteral(limit_cover_ct, break_is_eligible); const int empty_cover_ct = solver->AddLinearConstraint( - CapAdd(vehicle_start_min, limit), CapAdd(vehicle_start_min, limit), { - { break_cover, 1 } - }); + CapAdd(vehicle_start_min, limit), CapAdd(vehicle_start_min, limit), + {{break_cover, 1}}); solver->SetEnforcementLiteral(empty_cover_ct, break_is_not_eligible); const int cover = solver->AddVariable(CapAdd(vehicle_start_min, limit), kint64max); - solver->AddMaximumConstraint(cover, { - previous_cover, break_cover - }); - // Cover chaining. If route end is not covered, break start must be: - // cover_{i-1} < route_end => s_i <= cover_{i-1} - const int route_end_is_not_covered = - solver->AddReifiedLinearConstraint(1, kint64max, { - { lp_cumuls.back(), 1 } - , { previous_cover, -1 } - }); - const int break_start_cover_ct = - solver->AddLinearConstraint(0, kint64max, { - { previous_cover, 1 } - , { lp_break_start[br], -1 } - }); + solver->AddMaximumConstraint(cover, {previous_cover, break_cover}); + // Cover chaining. If route end is not covered, break start must be: + // cover_{i-1} < route_end => s_i <= cover_{i-1} + const int route_end_is_not_covered = solver->AddReifiedLinearConstraint( + 1, kint64max, {{lp_cumuls.back(), 1}, {previous_cover, -1}}); + const int break_start_cover_ct = solver->AddLinearConstraint( + 0, kint64max, {{previous_cover, 1}, {lp_break_start[br], -1}}); solver->SetEnforcementLiteral(break_start_cover_ct, route_end_is_not_covered); previous_cover = cover; } - solver->AddLinearConstraint(0, kint64max, { - { previous_cover, 1 } - , { lp_cumuls.back(), -1 } - }); + solver->AddLinearConstraint(0, kint64max, + {{previous_cover, 1}, {lp_cumuls.back(), -1}}); } return true; @@ -1353,13 +1290,11 @@ void DimensionCumulOptimizerCore::SetGlobalConstraints( void DimensionCumulOptimizerCore::SetValuesFromLP( const std::vector &lp_variables, int64 offset, RoutingLinearSolverWrapper *solver, std::vector *lp_values) { - if (lp_values == nullptr) - return; + if (lp_values == nullptr) return; lp_values->assign(lp_variables.size(), kint64min); for (int i = 0; i < lp_variables.size(); i++) { const int cumul_var = lp_variables[i]; - if (cumul_var < 0) - continue; // Keep default value, kint64min. + if (cumul_var < 0) continue; // Keep default value, kint64min. const double lp_value_double = solver->GetValue(cumul_var); const int64 lp_value_int64 = (lp_value_double >= kint64max) @@ -1411,4 +1346,4 @@ bool GlobalDimensionCumulOptimizer::ComputePackedCumuls( return optimizer_core_.OptimizeAndPack(next_accessor, solver_.get(), packed_cumuls, packed_breaks); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_lp_scheduling.h b/ortools/constraint_solver/routing_lp_scheduling.h index cebde27f82..34f48ade42 100644 --- a/ortools/constraint_solver/routing_lp_scheduling.h +++ b/ortools/constraint_solver/routing_lp_scheduling.h @@ -32,7 +32,7 @@ namespace operations_research { // Utility class used in the core optimizer to tighten the cumul bounds as much // as possible based on the model precedences. class CumulBoundsPropagator { -public: + public: explicit CumulBoundsPropagator(const RoutingDimension *dimension); // Tightens the cumul bounds starting from the current cumul var min/max, @@ -55,7 +55,7 @@ public: const RoutingDimension &dimension() const { return dimension_; } -private: + private: // An arc "tail --offset--> head" represents the relation // tail + offset <= head. // As arcs are stored by tail, we don't store it in the struct. @@ -126,16 +126,16 @@ private: enum class DimensionSchedulingStatus { // An optimal solution was found respecting all constraints. OPTIMAL, - // An optimal solution was found, however constraints which were relaxed - // were - // violated. - RELAXED_OPTIMAL_ONLY, - // A solution could not be found. - INFEASIBLE + // An optimal solution was found, however constraints which were relaxed + // were + // violated. + RELAXED_OPTIMAL_ONLY, + // A solution could not be found. + INFEASIBLE }; class RoutingLinearSolverWrapper { -public: + public: virtual ~RoutingLinearSolverWrapper() {} virtual void Clear() = 0; virtual int CreateNewPositiveVariable() = 0; @@ -186,8 +186,7 @@ public: int AddReifiedLinearConstraint( int64 lower_bound, int64 upper_bound, const std::vector > &weighted_variables) { - const int reification_ct = AddLinearConstraint(1, 1, { - }); + const int reification_ct = AddLinearConstraint(1, 1, {}); if (kint64min < lower_bound) { const int under_lower_bound = AddVariable(0, 1); SetCoefficient(reification_ct, under_lower_bound, 1); @@ -212,7 +211,7 @@ public: }; class RoutingGlopWrapper : public RoutingLinearSolverWrapper { -public: + public: explicit RoutingGlopWrapper(const glop::GlopParameters ¶meters) { lp_solver_.SetParameters(parameters); linear_program_.SetMaximizationProblem(false); @@ -225,8 +224,8 @@ public: int CreateNewPositiveVariable() override { return linear_program_.CreateNewVariable().value(); } - bool SetVariableBounds(int index, int64 lower_bound, int64 upper_bound) - override { + bool SetVariableBounds(int index, int64 lower_bound, + int64 upper_bound) override { DCHECK_GE(lower_bound, 0); // When variable upper bounds are greater than this threshold, precision // issues arise in GLOP. In this case we are just going to suppose that @@ -281,15 +280,12 @@ public: coefficient); } bool IsCPSATSolver() override { return false; } - void AddMaximumConstraint(int max_var, std::vector vars) override {} - ; - void AddProductConstraint(int product_var, std::vector vars) override {} - ; - void SetEnforcementLiteral(int ct, int condition) override {} - ; + void AddMaximumConstraint(int max_var, std::vector vars) override{}; + void AddProductConstraint(int product_var, std::vector vars) override{}; + void SetEnforcementLiteral(int ct, int condition) override{}; DimensionSchedulingStatus Solve(absl::Duration duration_limit) override { - lp_solver_.GetMutableParameters() - ->set_max_time_in_seconds(absl::ToDoubleSeconds(duration_limit)); + lp_solver_.GetMutableParameters()->set_max_time_in_seconds( + absl::ToDoubleSeconds(duration_limit)); // Because we construct the lp one constraint at a time and we never call // SetCoefficient() on the same variable twice for a constraint, we know @@ -306,9 +302,9 @@ public: } for (const auto &allowed_interval : allowed_intervals_) { const double value_double = GetValue(allowed_interval.first); - const int64 value = - (value_double >= kint64max) ? kint64max - : MathUtil::FastInt64Round(value_double); + const int64 value = (value_double >= kint64max) + ? kint64max + : MathUtil::FastInt64Round(value_double); const SortedDisjointIntervalList *const interval_list = allowed_interval.second.get(); const auto it = interval_list->FirstIntervalGreaterOrEqual(value); @@ -329,7 +325,7 @@ public: /*absolute_tolerance*/ 1e-3); } -private: + private: glop::LinearProgram linear_program_; glop::LPSolver lp_solver_; absl::flat_hash_map > @@ -337,7 +333,7 @@ private: }; class RoutingCPSatWrapper : public RoutingLinearSolverWrapper { -public: + public: RoutingCPSatWrapper() : objective_offset_(0), first_constraint_to_offset_(0) { parameters_.set_num_search_workers(1); // Keeping presolve but with 0 iterations; as of 11/2019 it is @@ -367,8 +363,8 @@ public: variable->add_domain(static_cast(parameters_.mip_max_bound())); return index; } - bool SetVariableBounds(int index, int64 lower_bound, int64 upper_bound) - override { + bool SetVariableBounds(int index, int64 lower_bound, + int64 upper_bound) override { DCHECK_GE(lower_bound, 0); // TODO(user): Find whether there is a way to make the offsetting // system work with other CP-SAT constraints than linear constraints. @@ -379,8 +375,7 @@ public: parameters_.mip_max_bound()); const int64 offset_lower_bound = CapSub(lower_bound, variable_offset_[index]); - if (offset_lower_bound > offset_upper_bound) - return false; + if (offset_lower_bound > offset_upper_bound) return false; sat::IntegerVariableProto *const variable = model_.mutable_variables(index); variable->set_domain(0, offset_lower_bound); variable->set_domain(1, offset_upper_bound); @@ -474,8 +469,7 @@ public: // Set constraint offsets for (int ct_index = first_constraint_to_offset_; ct_index < constraint_offset_.size(); ++ct_index) { - if (!model_.mutable_constraints(ct_index)->has_linear()) - continue; + if (!model_.mutable_constraints(ct_index)->has_linear()) continue; sat::LinearConstraintProto *const ct = model_.mutable_constraints(ct_index)->mutable_linear(); ct->set_domain(0, CapSub(ct->domain(0), constraint_offset_[ct_index])); @@ -512,7 +506,7 @@ public: } bool SolutionIsInteger() const override { return true; } -private: + private: sat::CpModelProto model_; sat::CpSolverResponse response_; sat::SatParameters parameters_; @@ -527,7 +521,7 @@ private: // Utility class used in Local/GlobalDimensionCumulOptimizer to set the linear // solver constraints and solve the problem. class DimensionCumulOptimizerCore { -public: + public: DimensionCumulOptimizerCore(const RoutingDimension *dimension, bool use_precedence_propagator); @@ -559,7 +553,7 @@ public: const RoutingDimension *dimension() const { return dimension_; } -private: + private: // Initializes the containers and given solver. Must be called prior to // setting any contraints and solving. void InitOptimizer(RoutingLinearSolverWrapper *solver); @@ -639,7 +633,7 @@ private: // In its methods, next_accessor is a callback returning the next node of a // given node on a route. class LocalDimensionCumulOptimizer { -public: + public: LocalDimensionCumulOptimizer( const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type); @@ -648,10 +642,9 @@ public: // minimizing cumul soft lower and upper bound costs and vehicle span costs, // and stores it in "optimal_cost" (if not null). // Returns true iff the route respects all constraints. - DimensionSchedulingStatus - ComputeRouteCumulCost(int vehicle, - const std::function &next_accessor, - int64 *optimal_cost); + DimensionSchedulingStatus ComputeRouteCumulCost( + int vehicle, const std::function &next_accessor, + int64 *optimal_cost); // Same as ComputeRouteCumulCost, but the cost computed does not contain // the part of the vehicle span cost due to fixed transits. @@ -679,13 +672,13 @@ public: return optimizer_core_.dimension(); } -private: + private: std::vector > solver_; DimensionCumulOptimizerCore optimizer_core_; }; class GlobalDimensionCumulOptimizer { -public: + public: explicit GlobalDimensionCumulOptimizer(const RoutingDimension *dimension); // If feasible, computes the optimal cost of the entire model with regards to // the optimizer_core_'s dimension costs, minimizing cumul soft lower/upper @@ -719,11 +712,11 @@ public: return optimizer_core_.dimension(); } -private: + private: std::unique_ptr solver_; DimensionCumulOptimizerCore optimizer_core_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_ diff --git a/ortools/constraint_solver/routing_neighborhoods.cc b/ortools/constraint_solver/routing_neighborhoods.cc index 820d633529..23fa118bcd 100644 --- a/ortools/constraint_solver/routing_neighborhoods.cc +++ b/ortools/constraint_solver/routing_neighborhoods.cc @@ -33,16 +33,13 @@ MakeRelocateNeighborsOperator::MakeRelocateNeighborsOperator( bool MakeRelocateNeighborsOperator::MakeNeighbor() { const int64 before_chain = BaseNode(0); int64 chain_end = Next(before_chain); - if (IsPathEnd(chain_end)) - return false; + if (IsPathEnd(chain_end)) return false; const int64 destination = BaseNode(1); - if (chain_end == destination) - return false; + if (chain_end == destination) return false; const int64 max_arc_value = arc_evaluator_(destination, chain_end); int64 next = Next(chain_end); while (!IsPathEnd(next) && arc_evaluator_(chain_end, next) <= max_arc_value) { - if (next == destination) - return false; + if (next == destination) return false; chain_end = next; next = Next(chain_end); } @@ -56,7 +53,7 @@ bool MakeRelocateNeighborsOperator::MoveChainAndRepair(int64 before_chain, if (!IsPathStart(destination)) { int64 current = Prev(destination); int64 last = chain_end; - if (current == last) { // chain was just before destination + if (current == last) { // chain was just before destination current = before_chain; } while (last >= 0 && !IsPathStart(current) && current != last) { @@ -101,13 +98,14 @@ MakePairActiveOperator::MakePairActiveOperator( const RoutingIndexPairs &pairs) : PathOperator(vars, secondary_vars, 2, false, true, std::move(start_empty_path_class)), - inactive_pair_(0), inactive_pair_first_index_(0), - inactive_pair_second_index_(0), pairs_(pairs) {} + inactive_pair_(0), + inactive_pair_first_index_(0), + inactive_pair_second_index_(0), + pairs_(pairs) {} bool MakePairActiveOperator::MakeOneNeighbor() { while (inactive_pair_ < pairs_.size()) { - if (PathOperator::MakeOneNeighbor()) - return true; + if (PathOperator::MakeOneNeighbor()) return true; ResetPosition(); if (inactive_pair_first_index_ < pairs_[inactive_pair_].first.size() - 1) { ++inactive_pair_first_index_; @@ -165,8 +163,7 @@ int MakePairActiveOperator::FindNextInactivePair(int pair_index) const { bool MakePairActiveOperator::ContainsActiveNodes( const std::vector &nodes) const { for (int64 node : nodes) { - if (!IsInactive(node)) - return true; + if (!IsInactive(node)) return true; } return false; } @@ -274,17 +271,13 @@ LightPairRelocateOperator::LightPairRelocateOperator( bool LightPairRelocateOperator::MakeNeighbor() { const int64 prev1 = BaseNode(0); const int64 node1 = Next(prev1); - if (IsPathEnd(node1)) - return false; + if (IsPathEnd(node1)) return false; const int64 sibling1 = GetActiveAlternativeSibling(node1); - if (sibling1 == -1) - return false; + if (sibling1 == -1) return false; const int64 node2 = BaseNode(1); - if (node2 == sibling1) - return false; + if (node2 == sibling1) return false; const int64 sibling2 = GetActiveAlternativeSibling(node2); - if (sibling2 == -1) - return false; + if (sibling2 == -1) return false; // Note: MoveChain will return false if it is a no-op (moving the chain to its // current position). However we want to accept the move if at least node1 or // sibling1 gets moved to a new position. Therefore we want to be sure both @@ -318,16 +311,12 @@ bool PairExchangeOperator::MakeNeighbor() { // Exchanging node1 and node2. if (node1 == prev2) { status = MoveChain(prev2, node2, prev1); - if (sibling_prev1 == node2) - sibling_prev1 = node1; - if (sibling_prev2 == node2) - sibling_prev2 = node1; + if (sibling_prev1 == node2) sibling_prev1 = node1; + if (sibling_prev2 == node2) sibling_prev2 = node1; } else if (node2 == prev1) { status = MoveChain(prev1, node1, prev2); - if (sibling_prev1 == node1) - sibling_prev1 = node2; - if (sibling_prev2 == node1) - sibling_prev2 = node2; + if (sibling_prev1 == node1) sibling_prev1 = node2; + if (sibling_prev2 == node1) sibling_prev2 = node2; } else { status = MoveChain(prev1, node1, node2) && MoveChain(prev2, node2, prev1); if (sibling_prev1 == node1) { @@ -341,8 +330,7 @@ bool PairExchangeOperator::MakeNeighbor() { sibling_prev2 = node1; } } - if (!status) - return false; + if (!status) return false; // Exchanging sibling1 and sibling2. if (sibling1 == sibling_prev2) { status = MoveChain(sibling_prev2, sibling2, sibling_prev1); @@ -360,12 +348,10 @@ bool PairExchangeOperator::MakeNeighbor() { return status; } -bool -PairExchangeOperator::GetPreviousAndSibling(int64 node, int64 *previous, - int64 *sibling, - int64 *sibling_previous) const { - if (IsPathStart(node)) - return false; +bool PairExchangeOperator::GetPreviousAndSibling( + int64 node, int64 *previous, int64 *sibling, + int64 *sibling_previous) const { + if (IsPathStart(node)) return false; *previous = Prev(node); *sibling = GetActiveAlternativeSibling(node); *sibling_previous = *sibling >= 0 ? Prev(*sibling) : -1; @@ -500,8 +486,7 @@ int64 PairExchangeRelocateOperator::GetBaseNodeRestartPosition(int base_index) { bool PairExchangeRelocateOperator::GetPreviousAndSibling( int64 node, int64 *previous, int64 *sibling, int64 *sibling_previous) const { - if (IsPathStart(node)) - return false; + if (IsPathStart(node)) return false; *previous = Prev(node); *sibling = GetActiveAlternativeSibling(node); *sibling_previous = *sibling >= 0 ? Prev(*sibling) : -1; @@ -511,9 +496,13 @@ bool PairExchangeRelocateOperator::GetPreviousAndSibling( SwapIndexPairOperator::SwapIndexPairOperator( const std::vector &vars, const std::vector &path_vars, const RoutingIndexPairs &index_pairs) - : IntVarLocalSearchOperator(vars), index_pairs_(index_pairs), - pair_index_(0), first_index_(0), second_index_(0), - number_of_nexts_(vars.size()), ignore_path_vars_(path_vars.empty()) { + : IntVarLocalSearchOperator(vars), + index_pairs_(index_pairs), + pair_index_(0), + first_index_(0), + second_index_(0), + number_of_nexts_(vars.size()), + ignore_path_vars_(path_vars.empty()) { if (!ignore_path_vars_) { AddVars(path_vars); } @@ -541,11 +530,9 @@ bool SwapIndexPairOperator::MakeNextNeighbor(Assignment *delta, if (prev_second == first_active_) { prev_second = insert_first; } - DCHECK_EQ(path, - ignore_path_vars_ ? int64 { - 0 - } - : Value(second_active_ + number_of_nexts_)); + DCHECK_EQ(path, ignore_path_vars_ + ? int64{0} + : Value(second_active_ + number_of_nexts_)); const int64 next_second = Value(second_active_); // Making current active "delivery" unperformed. SetNext(second_active_, second_active_, kNoPath); @@ -581,8 +568,7 @@ void SwapIndexPairOperator::OnStart() { prevs_.resize(number_of_nexts_, -1); for (int index = 0; index < number_of_nexts_; ++index) { const int64 next = Value(index); - if (next >= prevs_.size()) - prevs_.resize(next + 1, -1); + if (next >= prevs_.size()) prevs_.resize(next + 1, -1); prevs_[next] = index; } pair_index_ = 0; @@ -591,8 +577,7 @@ void SwapIndexPairOperator::OnStart() { first_active_ = -1; second_active_ = -1; while (true) { - if (!UpdateActiveNodes()) - break; + if (!UpdateActiveNodes()) break; if (first_active_ != -1 && second_active_ != -1) { break; } @@ -673,7 +658,8 @@ FilteredHeuristicLocalSearchOperator::FilteredHeuristicLocalSearchOperator( bool keep_inverse_values) : IntVarLocalSearchOperator(heuristic->model()->Nexts(), keep_inverse_values), - model_(*heuristic->model()), removed_nodes_(model_.Size()), + model_(*heuristic->model()), + removed_nodes_(model_.Size()), heuristic_(std::move(heuristic)), consider_vehicle_vars_(!model_.CostsAreHomogeneousAcrossVehicles()) { if (consider_vehicle_vars_) { @@ -757,7 +743,9 @@ bool FilteredHeuristicLocalSearchOperator::MakeChangesAndInsertNodes() { FilteredHeuristicPathLNSOperator::FilteredHeuristicPathLNSOperator( std::unique_ptr heuristic) : FilteredHeuristicLocalSearchOperator(std::move(heuristic)), - current_route_(0), last_route_(0), just_started_(false) {} + current_route_(0), + last_route_(0), + just_started_(false) {} void FilteredHeuristicPathLNSOperator::OnStart() { // NOTE: We set last_route_ to current_route_ here to make sure all routes @@ -804,11 +792,10 @@ FilteredHeuristicPathLNSOperator::SetupNextAccessorForNeighbor() { node = Value(node); } - return[this, start_node, end_node](int64 node) { + return [this, start_node, end_node](int64 node) { if (node == start_node) return end_node; return Value(node); - } - ; + }; } // RelocatePathAndHeuristicInsertUnperformedOperator @@ -817,8 +804,9 @@ RelocatePathAndHeuristicInsertUnperformedOperator:: RelocatePathAndHeuristicInsertUnperformedOperator( std::unique_ptr heuristic) : FilteredHeuristicLocalSearchOperator(std::move(heuristic)), - route_to_relocate_index_(0), empty_route_index_(0), just_started_(false) { -} + route_to_relocate_index_(0), + empty_route_index_(0), + just_started_(false) {} void RelocatePathAndHeuristicInsertUnperformedOperator::OnStart() { has_unperformed_nodes_ = false; @@ -903,17 +891,14 @@ std::function RelocatePathAndHeuristicInsertUnperformedOperator:: const int64 last_relocated_node = last_node_on_route_[relocated_route]; const int64 relocated_route_end = model_.End(relocated_route); - return[this, empty_start_node, empty_end_node, first_relocated_node, - last_relocated_node, relocated_route_start, relocated_route_end]( - int64 node) { + return [this, empty_start_node, empty_end_node, first_relocated_node, + last_relocated_node, relocated_route_start, + relocated_route_end](int64 node) { if (node == relocated_route_start) return relocated_route_end; - if (node == empty_start_node) - return first_relocated_node; - if (node == last_relocated_node) - return empty_end_node; + if (node == empty_start_node) return first_relocated_node; + if (node == last_relocated_node) return empty_end_node; return Value(node); - } - ; + }; } // FilteredHeuristicCloseNodesLNSOperator @@ -923,9 +908,13 @@ FilteredHeuristicCloseNodesLNSOperator::FilteredHeuristicCloseNodesLNSOperator( : FilteredHeuristicLocalSearchOperator(std::move(heuristic), /*keep_inverse_values*/ true), pickup_delivery_pairs_(model_.GetPickupAndDeliveryPairs()), - current_node_(0), last_node_(0), close_nodes_(model_.Size()), - new_nexts_(model_.Size()), changed_nexts_(model_.Size()), - new_prevs_(model_.Size()), changed_prevs_(model_.Size()) { + current_node_(0), + last_node_(0), + close_nodes_(model_.Size()), + new_nexts_(model_.Size()), + changed_nexts_(model_.Size()), + new_prevs_(model_.Size()), + changed_prevs_(model_.Size()) { const int64 size = model_.Size(); const int64 max_num_neighbors = std::max(0, size - 1 - model_.vehicles()); @@ -933,14 +922,12 @@ FilteredHeuristicCloseNodesLNSOperator::FilteredHeuristicCloseNodesLNSOperator( std::min(num_close_nodes, max_num_neighbors); DCHECK_GE(num_closest_neighbors, 0); - if (num_closest_neighbors == 0) - return; + if (num_closest_neighbors == 0) return; const int64 num_cost_classes = model_.GetCostClassesCount(); for (int64 node = 0; node < size; node++) { - if (model_.IsStart(node) || model_.IsEnd(node)) - continue; + if (model_.IsStart(node) || model_.IsEnd(node)) continue; std::vector > costed_after_nodes; costed_after_nodes.reserve(size); @@ -999,10 +986,9 @@ void FilteredHeuristicCloseNodesLNSOperator::RemoveNode(int64 node) { } } -void -FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling(int64 node) { - if (!IsActive(node)) - return; +void FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling( + int64 node) { + if (!IsActive(node)) return; RemoveNode(node); for (int64 sibling_node : GetActiveSiblings(node)) { @@ -1012,8 +998,8 @@ FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling(int64 node) { } } -std::vector -FilteredHeuristicCloseNodesLNSOperator::GetActiveSiblings(int64 node) const { +std::vector FilteredHeuristicCloseNodesLNSOperator::GetActiveSiblings( + int64 node) const { // NOTE: In most use-cases, where each node is a pickup or delivery in a // single index pair, this function is in O(k) where k is the number of // alternative deliveries or pickups for this index pair. @@ -1056,9 +1042,7 @@ FilteredHeuristicCloseNodesLNSOperator::SetupNextAccessorForNeighbor() { RemoveNodeAndActiveSibling(neighbor); } - return[this](int64 node) { return Next(node); -} -; + return [this](int64 node) { return Next(node); }; } // FilteredHeuristicExpensiveChainLNSOperator @@ -1069,11 +1053,10 @@ FilteredHeuristicExpensiveChainLNSOperator:: int num_arcs_to_consider, std::function arc_cost_for_route_start) : FilteredHeuristicLocalSearchOperator(std::move(heuristic)), - current_route_(0), last_route_(0), + current_route_(0), + last_route_(0), num_arcs_to_consider_(num_arcs_to_consider), - current_expensive_arc_indices_({ --1, -1 -}), + current_expensive_arc_indices_({-1, -1}), arc_cost_for_route_start_(std::move(arc_cost_for_route_start)), just_started_(false) { DCHECK_GE(num_arcs_to_consider_, 2); @@ -1090,8 +1073,7 @@ bool FilteredHeuristicExpensiveChainLNSOperator::IncrementPosition() { return FindMostExpensiveChainsOnRemainingRoutes(); } - if (IncrementCurrentArcIndices()) - return true; + if (IncrementCurrentArcIndices()) return true; return IncrementRoute() && FindMostExpensiveChainsOnRemainingRoutes(); } @@ -1123,11 +1105,10 @@ FilteredHeuristicExpensiveChainLNSOperator::SetupNextAccessorForNeighbor() { node = Value(node); } - return[this, before_chain, after_chain](int64 node) { + return [this, before_chain, after_chain](int64 node) { if (node == before_chain) return after_chain; return OldValue(node); - } - ; + }; } bool FilteredHeuristicExpensiveChainLNSOperator::IncrementRoute() { @@ -1162,7 +1143,7 @@ bool FindMostExpensiveArcsOnRoute( std::pair *first_expensive_arc_indices) { if (is_end(next_accessor(start))) { // Empty route. - *first_expensive_arc_indices = { -1, -1 }; + *first_expensive_arc_indices = {-1, -1}; return false; } @@ -1171,7 +1152,8 @@ bool FindMostExpensiveArcsOnRoute( using ArcCostNegativeRankStart = std::tuple; std::priority_queue, - std::greater > arc_info_pq; + std::greater > + arc_info_pq; int64 before_node = start; int rank = 0; @@ -1197,29 +1179,24 @@ bool FindMostExpensiveArcsOnRoute( while (!arc_info_pq.empty()) { const ArcCostNegativeRankStart &arc_info = arc_info_pq.top(); (*most_expensive_arc_starts_and_ranks)[arc_index] = { - std::get<2>(arc_info), -std::get<1>(arc_info) - }; + std::get<2>(arc_info), -std::get<1>(arc_info)}; arc_index--; arc_info_pq.pop(); } - *first_expensive_arc_indices = { 0, 1 }; + *first_expensive_arc_indices = {0, 1}; return true; } -} // namespace +} // namespace bool FilteredHeuristicExpensiveChainLNSOperator:: FindMostExpensiveChainsOnRemainingRoutes() { do { if (FindMostExpensiveArcsOnRoute( num_arcs_to_consider_, model_.Start(current_route_), - [this](int64 i) { - return OldValue(i); - }, - [this](int64 node) { - return model_.IsEnd(node); - }, + [this](int64 i) { return OldValue(i); }, + [this](int64 node) { return model_.IsEnd(node); }, arc_cost_for_route_start_, &most_expensive_arc_starts_and_ranks_, ¤t_expensive_arc_indices_)) { return true; @@ -1236,12 +1213,12 @@ RelocateExpensiveChain::RelocateExpensiveChain( std::function arc_cost_for_path_start) : PathOperator(vars, secondary_vars, 1, false, false, std::move(start_empty_path_class)), - num_arcs_to_consider_(num_arcs_to_consider), current_path_(0), - current_expensive_arc_indices_({ - -1, -1 -}), + num_arcs_to_consider_(num_arcs_to_consider), + current_path_(0), + current_expensive_arc_indices_({-1, -1}), arc_cost_for_path_start_(std::move(arc_cost_for_path_start)), - end_path_(0), has_non_empty_paths_to_explore_(false) { + end_path_(0), + has_non_empty_paths_to_explore_(false) { DCHECK_GE(num_arcs_to_consider_, 2); } @@ -1323,12 +1300,8 @@ bool RelocateExpensiveChain::FindMostExpensiveChainsOnRemainingPaths() { do { if (FindMostExpensiveArcsOnRoute( num_arcs_to_consider_, path_starts()[current_path_], - [this](int64 i) { - return OldNext(i); - }, - [this](int64 node) { - return IsPathEnd(node); - }, + [this](int64 i) { return OldNext(i); }, + [this](int64 node) { return IsPathEnd(node); }, arc_cost_for_path_start_, &most_expensive_arc_starts_and_ranks_, ¤t_expensive_arc_indices_)) { return true; @@ -1363,15 +1336,14 @@ RelocateSubtrip::RelocateSubtrip( bool RelocateSubtrip::RelocateSubTripFromPickup(const int64 chain_first_node, const int64 insertion_node) { - if (IsPathEnd(insertion_node)) - return false; + if (IsPathEnd(insertion_node)) return false; if (Prev(chain_first_node) == insertion_node) - return false; // Skip null move. + return false; // Skip null move. int num_opened_pairs = 0; // Split chain into subtrip and rejected nodes. - rejected_nodes_ = { Prev(chain_first_node) }; - subtrip_nodes_ = { insertion_node }; + rejected_nodes_ = {Prev(chain_first_node)}; + subtrip_nodes_ = {insertion_node}; int current = chain_first_node; do { if (current == insertion_node) { @@ -1412,18 +1384,15 @@ bool RelocateSubtrip::RelocateSubTripFromPickup(const int64 chain_first_node, bool RelocateSubtrip::RelocateSubTripFromDelivery(const int64 chain_last_node, const int64 insertion_node) { - if (IsPathEnd(insertion_node)) - return false; + if (IsPathEnd(insertion_node)) return false; // opened_pairs_bitset_ should be all false. DCHECK(std::none_of(opened_pairs_bitset_.begin(), opened_pairs_bitset_.end(), - [](bool value) { - return value; - })); + [](bool value) { return value; })); int num_opened_pairs = 0; // Split chain into subtrip and rejected nodes. Store nodes in reverse order. - rejected_nodes_ = { Next(chain_last_node) }; - subtrip_nodes_ = { Next(insertion_node) }; + rejected_nodes_ = {Next(chain_last_node)}; + subtrip_nodes_ = {Next(insertion_node)}; int current = chain_last_node; do { if (current == insertion_node) { @@ -1446,8 +1415,7 @@ bool RelocateSubtrip::RelocateSubTripFromDelivery(const int64 chain_last_node, current = Prev(current); } while (num_opened_pairs != 0 && !IsPathStart(current)); DCHECK_EQ(num_opened_pairs, 0); - if (current == insertion_node) - return false; // Skip null move. + if (current == insertion_node) return false; // Skip null move. rejected_nodes_.push_back(current); subtrip_nodes_.push_back(insertion_node); @@ -1511,17 +1479,14 @@ namespace { bool VectorContains(const std::vector &values, int64 target) { return std::find(values.begin(), values.end(), target) != values.end(); } -} // namespace +} // namespace bool ExchangeSubtrip::MakeNeighbor() { - if (pair_of_node_[BaseNode(0)] == -1) - return false; - if (pair_of_node_[BaseNode(1)] == -1) - return false; + if (pair_of_node_[BaseNode(0)] == -1) return false; + if (pair_of_node_[BaseNode(1)] == -1) return false; // Break symmetry: a move generated from (BaseNode(0), BaseNode(1)) is the // same as from (BaseNode(1), BaseNode(1)): no need to do it twice. - if (BaseNode(0) >= BaseNode(1)) - return false; + if (BaseNode(0) >= BaseNode(1)) return false; rejects0_.clear(); subtrip0_.clear(); if (!ExtractChainsAndCheckCanonical(BaseNode(0), &rejects0_, &subtrip0_)) { @@ -1535,32 +1500,26 @@ bool ExchangeSubtrip::MakeNeighbor() { // If paths intersect, skip the move. if (Path(BaseNode(0)) == Path(BaseNode(1))) { - if (VectorContains(rejects0_, subtrip1_.front())) - return false; - if (VectorContains(rejects1_, subtrip0_.front())) - return false; - if (VectorContains(subtrip0_, subtrip1_.front())) - return false; - if (VectorContains(subtrip1_, subtrip0_.front())) - return false; + if (VectorContains(rejects0_, subtrip1_.front())) return false; + if (VectorContains(rejects1_, subtrip0_.front())) return false; + if (VectorContains(subtrip0_, subtrip1_.front())) return false; + if (VectorContains(subtrip1_, subtrip0_.front())) return false; } // Assemble the new paths. - path0_ = { Prev(subtrip0_.front()) }; - path1_ = { Prev(subtrip1_.front()) }; + path0_ = {Prev(subtrip0_.front())}; + path1_ = {Prev(subtrip1_.front())}; const int64 last0 = Next(subtrip0_.back()); const int64 last1 = Next(subtrip1_.back()); const bool concatenated01 = last0 == subtrip1_.front(); const bool concatenated10 = last1 == subtrip0_.front(); - if (is_delivery_node_[BaseNode(0)]) - std::swap(subtrip1_, rejects0_); + if (is_delivery_node_[BaseNode(0)]) std::swap(subtrip1_, rejects0_); path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end()); path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end()); path0_.push_back(last0); - if (is_delivery_node_[BaseNode(1)]) - std::swap(subtrip0_, rejects1_); + if (is_delivery_node_[BaseNode(1)]) std::swap(subtrip0_, rejects1_); path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end()); path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end()); path1_.push_back(last1); @@ -1589,8 +1548,7 @@ bool ExchangeSubtrip::ExtractChainsAndCheckCanonical( is_pickup_node_[base_node] ? ExtractChainsFromPickup(base_node, rejects, subtrip) : ExtractChainsFromDelivery(base_node, rejects, subtrip); - if (!extracted) - return false; + if (!extracted) return false; // Check canonicality. return !is_delivery_node_[base_node] || pair_of_node_[subtrip->front()] != pair_of_node_[subtrip->back()] || @@ -1654,11 +1612,10 @@ bool ExchangeSubtrip::ExtractChainsFromDelivery(int64 base_node, } current = Prev(current); } while (num_opened_pairs != 0 && !IsPathStart(current)); - if (num_opened_pairs != 0) - return false; + if (num_opened_pairs != 0) return false; std::reverse(rejects->begin(), rejects->end()); std::reverse(subtrip->begin(), subtrip->end()); return true; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_neighborhoods.h b/ortools/constraint_solver/routing_neighborhoods.h index eef17e5be5..4e17e5e2f5 100644 --- a/ortools/constraint_solver/routing_neighborhoods.h +++ b/ortools/constraint_solver/routing_neighborhoods.h @@ -45,7 +45,7 @@ namespace operations_research { /// at the same place (for instance nodes part of a same stop). // TODO(user): Consider merging with standard Relocate in local_search.cc. class MakeRelocateNeighborsOperator : public PathOperator { -public: + public: MakeRelocateNeighborsOperator( const std::vector &vars, const std::vector &secondary_vars, @@ -56,7 +56,7 @@ public: bool MakeNeighbor() override; std::string DebugString() const override { return "RelocateNeighbors"; } -private: + private: /// Moves a chain starting after 'before_chain' and ending at 'chain_end' /// after node 'destination'. Tries to repair the resulting solution by /// checking if the new arc created after 'destination' is compatible with @@ -102,7 +102,7 @@ private: /// 1 -> 2 -> [B] -> [A] -> 3 /// which can only be obtained by inserting A after B. class MakePairActiveOperator : public PathOperator { -public: + public: MakePairActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -111,7 +111,7 @@ public: bool MakeNeighbor() override; std::string DebugString() const override { return "MakePairActive"; } -protected: + protected: bool MakeOneNeighbor() override; bool OnSamePathAsPreviousBase(int64 base_index) override { /// Both base nodes have to be on the same path since they represent the @@ -125,7 +125,7 @@ protected: /// compatible with GetBaseNodeRestartPosition. bool RestartAtPathStartOnSynchronize() override { return true; } -private: + private: void OnNodeInitialization() override; int FindNextInactivePair(int pair_index) const; bool ContainsActiveNodes(const std::vector &nodes) const; @@ -138,7 +138,7 @@ private: /// Operator which makes pairs of active nodes inactive. class MakePairInactiveOperator : public PathOperator { -public: + public: MakePairInactiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -157,7 +157,7 @@ public: /// 1 -> 2 -> [A] -> [B] -> 3 /// The pair can be moved to another path. class PairRelocateOperator : public PathOperator { -public: + public: PairRelocateOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -167,7 +167,7 @@ public: bool MakeNeighbor() override; std::string DebugString() const override { return "PairRelocateOperator"; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override { /// Both destination nodes must be on the same path. return base_index == kPairSecondNodeDestination; @@ -178,7 +178,7 @@ protected: return base_index == kPairFirstNode; } -private: + private: bool RestartAtPathStartOnSynchronize() override { return true; } static constexpr int kPairFirstNode = 0; @@ -187,7 +187,7 @@ private: }; class LightPairRelocateOperator : public PathOperator { -public: + public: LightPairRelocateOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -207,7 +207,7 @@ public: /// therefore not be moved, and (A, B) and (C,D) are pairs of nodes): /// 1 -> [C] -> [D] -> 2 -> 3, 4 -> [A] -> [B] -> 5 class PairExchangeOperator : public PathOperator { -public: + public: PairExchangeOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -217,7 +217,7 @@ public: bool MakeNeighbor() override; std::string DebugString() const override { return "PairExchangeOperator"; } -private: + private: bool RestartAtPathStartOnSynchronize() override { return true; } bool ConsiderAlternatives(int64 base_index) const override { return true; } bool GetPreviousAndSibling(int64 node, int64 *previous, int64 *sibling, @@ -238,7 +238,7 @@ private: /// 1 -> C -> 2 -> D -> 3 4 -> A -> 5 -> B -> 6 /// 1 -> 2 -> C -> D -> 3 4 -> 5 -> A -> B -> 6 class PairExchangeRelocateOperator : public PathOperator { -public: + public: PairExchangeRelocateOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -250,11 +250,11 @@ public: return "PairExchangeRelocateOperator"; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override; int64 GetBaseNodeRestartPosition(int base_index) override; -private: + private: bool RestartAtPathStartOnSynchronize() override { return true; } bool GetPreviousAndSibling(int64 node, int64 *previous, int64 *sibling, int64 *sibling_previous) const; @@ -282,7 +282,7 @@ private: /// 1 -> [C] -> a -> 2 /// 1 -> [C] -> [b] -> 2 class SwapIndexPairOperator : public IntVarLocalSearchOperator { -public: + public: SwapIndexPairOperator(const std::vector &vars, const std::vector &path_vars, const RoutingIndexPairs &index_pairs); @@ -292,7 +292,7 @@ public: void OnStart() override; std::string DebugString() const override { return "SwapIndexPairOperator"; } -private: + private: /// Updates first_active_ and second_active_ to make them correspond to the /// active nodes of the node pair of index pair_index_. bool UpdateActiveNodes(); @@ -320,7 +320,7 @@ private: /// Operator which inserts inactive nodes into a path and makes a pair of /// active nodes inactive. class IndexPairSwapActiveOperator : public PathOperator { -public: + public: IndexPairSwapActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -333,7 +333,7 @@ public: return "IndexPairSwapActiveOperator"; } -private: + private: void OnNodeInitialization() override; int inactive_node_; @@ -344,13 +344,13 @@ private: // TODO(user): Put these methods in an object with helper methods instead // of adding a layer to the class hierarchy. class FilteredHeuristicLocalSearchOperator : public IntVarLocalSearchOperator { -public: + public: explicit FilteredHeuristicLocalSearchOperator( std::unique_ptr heuristic, bool keep_inverse_values = false); ~FilteredHeuristicLocalSearchOperator() override {} -protected: + protected: virtual bool IncrementPosition() = 0; /// Virtual method to return the next_accessor to be passed to the heuristic /// to build a new solution. This method should also correctly set the @@ -377,7 +377,7 @@ protected: /// Keeps track of removed nodes when making a neighbor. SparseBitset<> removed_nodes_; -private: + private: bool MakeOneNeighbor() override; bool MakeChangesAndInsertNodes(); @@ -391,7 +391,7 @@ private: /// the solution, after the destruction phase consisting of removing one route. class FilteredHeuristicPathLNSOperator : public FilteredHeuristicLocalSearchOperator { -public: + public: explicit FilteredHeuristicPathLNSOperator( std::unique_ptr heuristic); ~FilteredHeuristicPathLNSOperator() override {} @@ -400,7 +400,7 @@ public: return absl::StrCat("HeuristicPathLNS(", HeuristicName(), ")"); } -private: + private: void OnStart() override; bool IncrementPosition() override; @@ -419,7 +419,7 @@ private: /// unperformed nodes using the heuristic. class RelocatePathAndHeuristicInsertUnperformedOperator : public FilteredHeuristicLocalSearchOperator { -public: + public: explicit RelocatePathAndHeuristicInsertUnperformedOperator( std::unique_ptr heuristic); ~RelocatePathAndHeuristicInsertUnperformedOperator() override {} @@ -429,7 +429,7 @@ public: HeuristicName(), ")"); } -private: + private: void OnStart() override; bool IncrementPosition() override; @@ -453,7 +453,7 @@ private: /// "expensive" chain from a route. class FilteredHeuristicExpensiveChainLNSOperator : public FilteredHeuristicLocalSearchOperator { -public: + public: FilteredHeuristicExpensiveChainLNSOperator( std::unique_ptr heuristic, int num_arcs_to_consider, @@ -464,7 +464,7 @@ public: return absl::StrCat("HeuristicExpensiveChainLNS(", HeuristicName(), ")"); } -private: + private: void OnStart() override; bool IncrementPosition() override; @@ -484,7 +484,8 @@ private: std::pair current_expensive_arc_indices_; std::function arc_cost_for_route_start_; + /*path_start*/ int64)> + arc_cost_for_route_start_; bool just_started_; }; @@ -494,7 +495,7 @@ private: /// each of their corresponding sibling pickup/deliveries that are performed. class FilteredHeuristicCloseNodesLNSOperator : public FilteredHeuristicLocalSearchOperator { -public: + public: FilteredHeuristicCloseNodesLNSOperator( std::unique_ptr heuristic, int num_close_nodes); ~FilteredHeuristicCloseNodesLNSOperator() override {} @@ -503,7 +504,7 @@ public: return absl::StrCat("HeuristicCloseNodesLNS(", HeuristicName(), ")"); } -private: + private: void OnStart() override; bool IncrementPosition() override; @@ -530,8 +531,8 @@ private: std::vector GetActiveSiblings(int64 node) const; - const std::vector, std::vector > > & - pickup_delivery_pairs_; + const std::vector, std::vector > > + &pickup_delivery_pairs_; int current_node_; int last_node_; @@ -553,7 +554,7 @@ private: /// The most expensive chain on a path is the one resulting from cutting the 2 /// most expensive arcs on this path. class RelocateExpensiveChain : public PathOperator { -public: + public: RelocateExpensiveChain( const std::vector &vars, const std::vector &secondary_vars, @@ -566,7 +567,7 @@ public: std::string DebugString() const override { return "RelocateExpensiveChain"; } -private: + private: void OnNodeInitialization() override; void IncrementCurrentPath(); bool IncrementCurrentArcIndices(); @@ -583,7 +584,8 @@ private: std::pair current_expensive_arc_indices_; std::function arc_cost_for_path_start_; + /*path_start*/ int64)> + arc_cost_for_path_start_; int end_path_; /// The following boolean indicates if there are any non-empty paths left to /// explore by the operator. @@ -599,7 +601,7 @@ private: /// pair (with swap_first false). template class PairNodeSwapActiveOperator : public PathOperator { -public: + public: PairNodeSwapActiveOperator(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -612,7 +614,7 @@ public: return "PairNodeSwapActiveOperator"; } -protected: + protected: bool OnSamePathAsPreviousBase(int64 base_index) override { /// Both base nodes have to be on the same path since they represent the /// nodes after which unactive node pairs will be moved. @@ -625,7 +627,7 @@ protected: /// compatible with GetBaseNodeRestartPosition. bool RestartAtPathStartOnSynchronize() override { return true; } -private: + private: void OnNodeInitialization() override; int inactive_pair_; @@ -643,7 +645,8 @@ PairNodeSwapActiveOperator::PairNodeSwapActiveOperator( const RoutingIndexPairs &index_pairs) : PathOperator(vars, secondary_vars, 2, false, false, std::move(start_empty_path_class)), - inactive_pair_(0), pairs_(index_pairs) {} + inactive_pair_(0), + pairs_(index_pairs) {} template int64 PairNodeSwapActiveOperator::GetBaseNodeRestartPosition( @@ -714,7 +717,7 @@ bool PairNodeSwapActiveOperator::MakeNeighbor() { /// is a delivery, it selects the smallest subtrip ending at base_node such that /// rejected nodes are only pickups. class RelocateSubtrip : public PathOperator { -public: + public: RelocateSubtrip(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -723,7 +726,7 @@ public: std::string DebugString() const override { return "RelocateSubtrip"; } bool MakeNeighbor() override; -private: + private: // Relocates the subtrip starting at chain_first_node. It must be a pickup. bool RelocateSubTripFromPickup(int64 chain_first_node, int64 insertion_node); /// Relocates the subtrip ending at chain_first_node. It must be a delivery. @@ -741,7 +744,7 @@ private: }; class ExchangeSubtrip : public PathOperator { -public: + public: ExchangeSubtrip(const std::vector &vars, const std::vector &secondary_vars, std::function start_empty_path_class, @@ -750,7 +753,7 @@ public: std::string DebugString() const override { return "ExchangeSubtrip"; } bool MakeNeighbor() override; -private: + private: // Try to extract a subtrip from base_node (see below) and check that the move // will be canonical. // Given a pickup/delivery pair, this operator could generate the same move @@ -793,6 +796,6 @@ private: std::vector path1_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_NEIGHBORHOODS_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_NEIGHBORHOODS_H_ diff --git a/ortools/constraint_solver/routing_parameters.cc b/ortools/constraint_solver/routing_parameters.cc index baa5f8cb0b..9668aa259a 100644 --- a/ortools/constraint_solver/routing_parameters.cc +++ b/ortools/constraint_solver/routing_parameters.cc @@ -71,7 +71,7 @@ RoutingSearchParameters DefaultRoutingSearchParameters() { " use_lin_kernighan: BOOL_TRUE" " use_tsp_opt: BOOL_FALSE" " use_make_active: BOOL_TRUE" - " use_relocate_and_make_active: BOOL_FALSE" // costly if true by default + " use_relocate_and_make_active: BOOL_FALSE" // costly if true by default " use_make_inactive: BOOL_TRUE" " use_make_chain_inactive: BOOL_FALSE" " use_swap_active: BOOL_TRUE" @@ -102,9 +102,9 @@ RoutingSearchParameters DefaultRoutingSearchParameters() { "mixed_integer_scheduling_solver: CP_SAT " "optimization_step: 0.0 " "number_of_solutions_to_collect: 1 " - // No "time_limit" by default. - "solution_limit: 0x7fffffffffffffff " // kint64max - "lns_time_limit: { seconds:0 nanos:100000000 } " // 0.1s + // No "time_limit" by default. + "solution_limit: 0x7fffffffffffffff " // kint64max + "lns_time_limit: { seconds:0 nanos:100000000 } " // 0.1s "use_full_propagation: false " "log_search: false " "log_cost_scaling_factor: 1.0 " @@ -112,8 +112,8 @@ RoutingSearchParameters DefaultRoutingSearchParameters() { RoutingSearchParameters parameters; if (!google::protobuf::TextFormat::ParseFromString(kSearchParameters, ¶meters)) { - LOG(DFATAL) - << "Unsupported default search parameters: " << kSearchParameters; + LOG(DFATAL) << "Unsupported default search parameters: " + << kSearchParameters; } const std::string error = FindErrorInRoutingSearchParameters(parameters); LOG_IF(DFATAL, !error.empty()) @@ -127,7 +127,7 @@ bool IsValidNonNegativeDuration(const google::protobuf::Duration &d) { return status_or_duration.ok() && status_or_duration.value() >= absl::ZeroDuration(); } -} // namespace +} // namespace std::string FindErrorInRoutingSearchParameters( const RoutingSearchParameters &search_parameters) { @@ -246,13 +246,11 @@ std::string FindErrorInRoutingSearchParameters( } { const int32 num = search_parameters.number_of_solutions_to_collect(); - if (num < 1) - return StrCat("Invalid number_of_solutions_to_collect:", num); + if (num < 1) return StrCat("Invalid number_of_solutions_to_collect:", num); } { const int64 lim = search_parameters.solution_limit(); - if (lim < 1) - return StrCat("Invalid solution_limit:", lim); + if (lim < 1) return StrCat("Invalid solution_limit:", lim); } if (!IsValidNonNegativeDuration(search_parameters.time_limit())) { return "Invalid time_limit: " + @@ -301,8 +299,9 @@ std::string FindErrorInRoutingSearchParameters( } if (search_parameters.has_improvement_limit_parameters()) { - const double improvement_rate_coefficient = search_parameters - .improvement_limit_parameters().improvement_rate_coefficient(); + const double improvement_rate_coefficient = + search_parameters.improvement_limit_parameters() + .improvement_rate_coefficient(); if (std::isnan(improvement_rate_coefficient) || improvement_rate_coefficient <= 0) { return StrCat( @@ -311,8 +310,9 @@ std::string FindErrorInRoutingSearchParameters( improvement_rate_coefficient); } - const int32 improvement_rate_solutions_distance = search_parameters - .improvement_limit_parameters().improvement_rate_solutions_distance(); + const int32 improvement_rate_solutions_distance = + search_parameters.improvement_limit_parameters() + .improvement_rate_solutions_distance(); if (improvement_rate_solutions_distance <= 0) { return StrCat( "Invalid value for " @@ -321,7 +321,7 @@ std::string FindErrorInRoutingSearchParameters( } } - return ""; // = Valid (No error). + return ""; // = Valid (No error). } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_parameters.h b/ortools/constraint_solver/routing_parameters.h index 7629a96a88..443c7faf9c 100644 --- a/ortools/constraint_solver/routing_parameters.h +++ b/ortools/constraint_solver/routing_parameters.h @@ -28,6 +28,6 @@ RoutingSearchParameters DefaultRoutingSearchParameters(); std::string FindErrorInRoutingSearchParameters( const RoutingSearchParameters &search_parameters); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_PARAMETERS_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_PARAMETERS_H_ diff --git a/ortools/constraint_solver/routing_sat.cc b/ortools/constraint_solver/routing_sat.cc index 996309ff8d..efc0a79aca 100644 --- a/ortools/constraint_solver/routing_sat.cc +++ b/ortools/constraint_solver/routing_sat.cc @@ -53,12 +53,13 @@ struct Arc { friend std::ostream &operator<<(std::ostream &strm, const Arc &arc) { return strm << "{" << arc.tail << ", " << arc.head << "}"; } - template friend H AbslHashValue(H h, const Arc &a) { + template + friend H AbslHashValue(H h, const Arc &a) { return H::combine(std::move(h), a.tail, a.head); } }; -using ArcVarMap = std::map; // needs to be stable when iterating +using ArcVarMap = std::map; // needs to be stable when iterating // Adds all dimensions to a CpModelProto. Only adds path cumul constraints and // cumul bounds. @@ -73,8 +74,7 @@ void AddDimensions(const RoutingModel &model, const ArcVarMap &arc_vars, const int64 max_end = std::min(dimension->cumuls()[model.End(0)]->Max(), dimension->vehicle_capacities()[0]); for (int i = 0; i < cumuls.size(); ++i) { - if (model.IsStart(i) || model.IsEnd(i)) - continue; + if (model.IsStart(i) || model.IsEnd(i)) continue; // Reducing bounds supposing the triangular inequality. const int64 cumul_min = std::max(sat::kMinIntegerValue.value(), @@ -89,8 +89,7 @@ void AddDimensions(const RoutingModel &model, const ArcVarMap &arc_vars, for (const auto arc_var : arc_vars) { const int tail = arc_var.first.tail; const int head = arc_var.first.head; - if (tail == head || model.IsStart(tail) || model.IsStart(head)) - continue; + if (tail == head || model.IsStart(tail) || model.IsStart(head)) continue; // arc[tail][head] -> cumuls[head] >= cumuls[tail] + transit. // This is a relaxation of the model as it does not consider slack max. ConstraintProto *ct = cp_model->add_constraints(); @@ -114,16 +113,14 @@ std::vector CreateRanks(const RoutingModel &model, const int rank_size = model.Size() - model.vehicles(); std::vector ranks(size, -1); for (int i = 0; i < size; ++i) { - if (model.IsStart(i) || model.IsEnd(i)) - continue; + if (model.IsStart(i) || model.IsEnd(i)) continue; ranks[i] = AddVariable(cp_model, 0, rank_size); } ranks[depot] = AddVariable(cp_model, 0, 0); for (const auto arc_var : arc_vars) { const int tail = arc_var.first.tail; const int head = arc_var.first.head; - if (tail == head || head == depot) - continue; + if (tail == head || head == depot) continue; // arc[tail][head] -> ranks[head] == ranks[tail] + 1. ConstraintProto *ct = cp_model->add_constraints(); ct->add_enforcement_literal(arc_var.second); @@ -149,15 +146,13 @@ std::vector CreateVehicleVars(const RoutingModel &model, const int size = model.Size() + model.vehicles(); std::vector vehicles(size, -1); for (int i = 0; i < size; ++i) { - if (model.IsStart(i) || model.IsEnd(i)) - continue; + if (model.IsStart(i) || model.IsEnd(i)) continue; vehicles[i] = AddVariable(cp_model, 0, size - 1); } for (const auto arc_var : arc_vars) { const int tail = arc_var.first.tail; const int head = arc_var.first.head; - if (tail == head || head == depot) - continue; + if (tail == head || head == depot) continue; if (tail == depot) { // arc[depot][head] -> vehicles[head] == head. ConstraintProto *ct = cp_model->add_constraints(); @@ -186,8 +181,7 @@ std::vector CreateVehicleVars(const RoutingModel &model, void AddPickupDeliveryConstraints(const RoutingModel &model, const ArcVarMap &arc_vars, CpModelProto *cp_model) { - if (model.GetPickupAndDeliveryPairs().empty()) - return; + if (model.GetPickupAndDeliveryPairs().empty()) return; const std::vector ranks = CreateRanks(model, arc_vars, cp_model); const std::vector vehicles = CreateVehicleVars(model, arc_vars, cp_model); @@ -234,25 +228,21 @@ ArcVarMap PopulateMultiRouteModelFromRoutingModel(const RoutingModel &model, // Create "arc" variables and set their cost. for (int tail = 0; tail < num_nodes; ++tail) { const int tail_index = model.IsStart(tail) ? depot : tail; - std::unique_ptr iter(model.NextVar(tail) - ->MakeDomainIterator(false)); + std::unique_ptr iter( + model.NextVar(tail)->MakeDomainIterator(false)); for (int head : InitAndGetValues(iter.get())) { // Vehicle start and end nodes are represented as a single node in the // CP-SAT model. We choose the start index of the first vehicle to // represent both. We can also skip any head representing a vehicle start // as the CP solver will reject those. - if (model.IsStart(head)) - continue; + if (model.IsStart(head)) continue; const int head_index = model.IsEnd(head) ? depot : head; - if (head_index == tail_index) - continue; + if (head_index == tail_index) continue; const int64 cost = tail != head ? model.GetHomogeneousCost(tail, head) : model.UnperformedPenalty(tail); - if (cost == kint64max) - continue; - const Arc arc = { tail_index, head_index }; - if (gtl::ContainsKey(arc_vars, arc)) - continue; + if (cost == kint64max) continue; + const Arc arc = {tail_index, head_index}; + if (gtl::ContainsKey(arc_vars, arc)) continue; const int index = AddVariable(cp_model, 0, 1); gtl::InsertOrDie(&arc_vars, arc, index); cp_model->mutable_objective()->add_vars(index); @@ -270,15 +260,10 @@ ArcVarMap PopulateMultiRouteModelFromRoutingModel(const RoutingModel &model, ct->add_domain(0); ct->add_domain(0); for (int node = 0; node < num_nodes; ++node) { - if (model.IsStart(node) || model.IsEnd(node)) - continue; - ct->add_vars(gtl::FindOrDie(arc_vars, { - depot, node - })); + if (model.IsStart(node) || model.IsEnd(node)) continue; + ct->add_vars(gtl::FindOrDie(arc_vars, {depot, node})); ct->add_coeffs(1); - ct->add_vars(gtl::FindOrDie(arc_vars, { - node, depot - })); + ct->add_vars(gtl::FindOrDie(arc_vars, {node, depot})); ct->add_coeffs(-1); } } @@ -290,58 +275,43 @@ ArcVarMap PopulateMultiRouteModelFromRoutingModel(const RoutingModel &model, ct->add_domain( std::min(model.vehicles(), model.GetMaximumNumberOfActiveVehicles())); for (int node = 0; node < num_nodes; ++node) { - if (model.IsStart(node) || model.IsEnd(node)) - continue; - ct->add_vars(gtl::FindOrDie(arc_vars, { - depot, node - })); + if (model.IsStart(node) || model.IsEnd(node)) continue; + ct->add_vars(gtl::FindOrDie(arc_vars, {depot, node})); ct->add_coeffs(1); } } for (int tail = 0; tail < num_nodes; ++tail) { - if (model.IsStart(tail) || model.IsEnd(tail)) - continue; + if (model.IsStart(tail) || model.IsEnd(tail)) continue; LinearConstraintProto *ct = cp_model->add_constraints()->mutable_linear(); ct->add_domain(1); ct->add_domain(1); - std::unique_ptr iter(model.NextVar(tail) - ->MakeDomainIterator(false)); + std::unique_ptr iter( + model.NextVar(tail)->MakeDomainIterator(false)); bool depot_added = false; for (int head : InitAndGetValues(iter.get())) { - if (model.IsStart(head)) - continue; - if (tail == head) - continue; + if (model.IsStart(head)) continue; + if (tail == head) continue; if (model.IsEnd(head)) { - if (depot_added) - continue; + if (depot_added) continue; head = depot; depot_added = true; } - ct->add_vars(gtl::FindOrDie(arc_vars, { - tail, head - })); + ct->add_vars(gtl::FindOrDie(arc_vars, {tail, head})); ct->add_coeffs(1); } } for (int head = 0; head < num_nodes; ++head) { - if (model.IsStart(head) || model.IsEnd(head)) - continue; + if (model.IsStart(head) || model.IsEnd(head)) continue; LinearConstraintProto *ct = cp_model->add_constraints()->mutable_linear(); ct->add_domain(1); ct->add_domain(1); for (int tail = 0; tail < num_nodes; ++tail) { - if (model.IsEnd(head)) - continue; - if (tail == head) - continue; - if (model.IsStart(tail) && tail != depot) - continue; - ct->add_vars(gtl::FindOrDie(arc_vars, { - tail, head - })); + if (model.IsEnd(head)) continue; + if (tail == head) continue; + if (model.IsStart(tail) && tail != depot) continue; + ct->add_vars(gtl::FindOrDie(arc_vars, {tail, head})); ct->add_coeffs(1); } } @@ -401,31 +371,25 @@ ArcVarMap PopulateSingleRouteModelFromRoutingModel(const RoutingModel &model, CircuitConstraintProto *circuit = cp_model->add_constraints()->mutable_circuit(); for (int tail = 0; tail < num_nodes; ++tail) { - std::unique_ptr iter(model.NextVar(tail) - ->MakeDomainIterator(false)); + std::unique_ptr iter( + model.NextVar(tail)->MakeDomainIterator(false)); for (int head : InitAndGetValues(iter.get())) { // Vehicle start and end nodes are represented as a single node in the // CP-SAT model. We choose the start index to represent both. We can also // skip any head representing a vehicle start as the CP solver will reject // those. - if (model.IsStart(head)) - continue; - if (model.IsEnd(head)) - head = model.Start(0); + if (model.IsStart(head)) continue; + if (model.IsEnd(head)) head = model.Start(0); const int64 cost = tail != head ? model.GetHomogeneousCost(tail, head) : model.UnperformedPenalty(tail); - if (cost == kint64max) - continue; + if (cost == kint64max) continue; const int index = AddVariable(cp_model, 0, 1); circuit->add_literals(index); circuit->add_tails(tail); circuit->add_heads(head); cp_model->mutable_objective()->add_vars(index); cp_model->mutable_objective()->add_coeffs(cost); - gtl::InsertOrDie(&arc_vars, { - tail, head - }, - index); + gtl::InsertOrDie(&arc_vars, {tail, head}, index); } } AddPickupDeliveryConstraints(model, arc_vars, cp_model); @@ -457,8 +421,7 @@ bool ConvertToSolution(const CpSolverResponse &response, if (response.solution(arc_var.second) != 0) { const int tail = arc_var.first.tail; const int head = arc_var.first.head; - if (head == depot) - continue; + if (head == depot) continue; if (tail != depot) { solution->Add(model.NextVar(tail))->SetValue(head); } else { @@ -482,8 +445,7 @@ void AddSolutionAsHintToModel(const Assignment *solution, const RoutingModel &model, const ArcVarMap &arc_vars, CpModelProto *cp_model) { - if (solution == nullptr) - return; + if (solution == nullptr) return; PartialVariableAssignment *const hint = cp_model->mutable_solution_hint(); hint->Clear(); const int depot = GetDepotFromModel(model); @@ -492,17 +454,14 @@ void AddSolutionAsHintToModel(const Assignment *solution, const int tail_index = model.IsStart(tail) ? depot : tail; const int head = solution->Value(model.NextVar(tail)); const int head_index = model.IsEnd(head) ? depot : head; - if (tail_index == depot && head_index == depot) - continue; - const int *const var_index = gtl::FindOrNull(arc_vars, { - tail_index, head_index - }); + if (tail_index == depot && head_index == depot) continue; + const int *const var_index = + gtl::FindOrNull(arc_vars, {tail_index, head_index}); // Arcs with a cost of kint64max are not added to the model (considered as // infeasible). In some rare cases CP solutions might contain such arcs in // which case they are skipped here and a partial solution is used as a // hint. - if (var_index == nullptr) - continue; + if (var_index == nullptr) continue; hint->add_vars(*var_index); hint->add_values(1); } @@ -528,8 +487,8 @@ CpSolverResponse SolveRoutingModel( return SolveCpModel(cp_model, &model); } -} // namespace -} // namespace sat +} // namespace +} // namespace sat // Solves a RoutingModel using the CP-SAT solver. Returns false if no solution // was found. @@ -537,11 +496,10 @@ bool SolveModelWithSat(const RoutingModel &model, const RoutingSearchParameters &search_parameters, const Assignment *initial_solution, Assignment *solution) { - if (!sat::RoutingModelCanBeSolvedBySat(model)) - return false; + if (!sat::RoutingModelCanBeSolvedBySat(model)) return false; sat::CpModelProto cp_model; - cp_model.mutable_objective() - ->set_scaling_factor(search_parameters.log_cost_scaling_factor()); + cp_model.mutable_objective()->set_scaling_factor( + search_parameters.log_cost_scaling_factor()); cp_model.mutable_objective()->set_offset(search_parameters.log_cost_offset()); const sat::ArcVarMap arc_vars = sat::PopulateModelFromRoutingModel(model, &cp_model); @@ -551,4 +509,4 @@ bool SolveModelWithSat(const RoutingModel &model, arc_vars, solution); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_search.cc b/ortools/constraint_solver/routing_search.cc index 9077ad7400..5722f02a7c 100644 --- a/ortools/constraint_solver/routing_search.cc +++ b/ortools/constraint_solver/routing_search.cc @@ -51,11 +51,12 @@ namespace { // Max active vehicles filter. class MaxActiveVehiclesFilter : public IntVarLocalSearchFilter { -public: + public: explicit MaxActiveVehiclesFilter(const RoutingModel &routing_model) : IntVarLocalSearchFilter(routing_model.Nexts()), routing_model_(routing_model), - is_active_(routing_model.vehicles(), false), active_vehicles_(0) {} + is_active_(routing_model.vehicles(), false), + active_vehicles_(0) {} bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, int64 objective_max) override { const int64 kUnassigned = -1; @@ -85,7 +86,7 @@ public: routing_model_.GetMaximumNumberOfActiveVehicles(); } -private: + private: void OnSynchronize(const Assignment *delta) override { active_vehicles_ = 0; for (int i = 0; i < routing_model_.vehicles(); ++i) { @@ -103,12 +104,12 @@ private: std::vector is_active_; int active_vehicles_; }; -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeMaxActiveVehiclesFilter(const RoutingModel &routing_model) { - return routing_model.solver() - ->RevAlloc(new MaxActiveVehiclesFilter(routing_model)); +IntVarLocalSearchFilter *MakeMaxActiveVehiclesFilter( + const RoutingModel &routing_model) { + return routing_model.solver()->RevAlloc( + new MaxActiveVehiclesFilter(routing_model)); } namespace { @@ -116,7 +117,7 @@ namespace { // Node disjunction filter class. class NodeDisjunctionFilter : public IntVarLocalSearchFilter { -public: + public: explicit NodeDisjunctionFilter(const RoutingModel &routing_model) : IntVarLocalSearchFilter(routing_model.Nexts()), routing_model_(routing_model), @@ -236,7 +237,7 @@ public: return accepted_objective_value_; } -private: + private: void OnSynchronize(const Assignment *delta) override { synchronized_objective_value_ = 0; for (RoutingModel::DisjunctionIndex i(0); @@ -259,7 +260,8 @@ private: const int max_cardinality = routing_model_.GetDisjunctionMaxCardinality(i); if (inactive_per_disjunction_[i] > - disjunction_indices.size() - max_cardinality && penalty > 0) { + disjunction_indices.size() - max_cardinality && + penalty > 0) { synchronized_objective_value_ = CapAdd(synchronized_objective_value_, penalty); } @@ -273,12 +275,12 @@ private: int64 synchronized_objective_value_; int64 accepted_objective_value_; }; -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeNodeDisjunctionFilter(const RoutingModel &routing_model) { - return routing_model.solver() - ->RevAlloc(new NodeDisjunctionFilter(routing_model)); +IntVarLocalSearchFilter *MakeNodeDisjunctionFilter( + const RoutingModel &routing_model) { + return routing_model.solver()->RevAlloc( + new NodeDisjunctionFilter(routing_model)); } const int64 BasePathFilter::kUnassigned = -1; @@ -289,17 +291,16 @@ BasePathFilter::BasePathFilter(const std::vector &nexts, node_path_starts_(next_domain_size, kUnassigned), paths_(nexts.size(), -1), new_synchronized_unperformed_nodes_(nexts.size()), - new_nexts_(nexts.size(), kUnassigned), touched_paths_(nexts.size()), - touched_path_chain_start_ends_(nexts.size(), { - kUnassigned, kUnassigned -}), - ranks_(next_domain_size, -1), status_(BasePathFilter::UNKNOWN) {} + new_nexts_(nexts.size(), kUnassigned), + touched_paths_(nexts.size()), + touched_path_chain_start_ends_(nexts.size(), {kUnassigned, kUnassigned}), + ranks_(next_domain_size, -1), + status_(BasePathFilter::UNKNOWN) {} bool BasePathFilter::Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, int64 objective_max) { - if (IsDisabled()) - return true; + if (IsDisabled()) return true; for (const int touched : delta_touched_) { new_nexts_[touched] = kUnassigned; } @@ -314,14 +315,13 @@ bool BasePathFilter::Accept(const Assignment *delta, // path and will correspond to the min and max ranks of touched nodes in the // current assignment. for (int64 touched_path : touched_paths_.PositionsSetAtLeastOnce()) { - touched_path_chain_start_ends_[touched_path] = { kUnassigned, kUnassigned }; + touched_path_chain_start_ends_[touched_path] = {kUnassigned, kUnassigned}; } touched_paths_.SparseClearAll(); const auto update_touched_path_chain_start_end = [this](int64 index) { const int64 start = node_path_starts_[index]; - if (start == kUnassigned) - return; + if (start == kUnassigned) return; touched_paths_.Set(start); int64 &chain_start = touched_path_chain_start_ends_[start].first; @@ -333,8 +333,7 @@ bool BasePathFilter::Accept(const Assignment *delta, if (chain_end == kUnassigned || ranks_[index] > ranks_[chain_end]) { chain_end = index; } - } - ; + }; for (int i = 0; i < delta_size; ++i) { const IntVarElement &new_element = container.Element(i); @@ -449,8 +448,7 @@ void BasePathFilter::OnSynchronize(const Assignment *delta) { status_ = DisableFiltering() ? BasePathFilter::DISABLED : BasePathFilter::ENABLED; } - if (IsDisabled()) - return; + if (IsDisabled()) return; new_synchronized_unperformed_nodes_.ClearAll(); if (delta == nullptr || delta->Empty() || starts_.empty()) { SynchronizeFullAssignment(); @@ -518,7 +516,7 @@ void BasePathFilter::UpdatePathRanksFromStart(int start) { namespace { class VehicleAmortizedCostFilter : public BasePathFilter { -public: + public: explicit VehicleAmortizedCostFilter(const RoutingModel &routing_model); ~VehicleAmortizedCostFilter() override {} std::string DebugString() const override { @@ -531,12 +529,12 @@ public: return delta_vehicle_cost_; } -private: + private: void OnSynchronizePathFromStart(int64 start) override; void OnAfterSynchronizePaths() override; void InitializeAcceptPath() override; - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; bool FinalizeAcceptPath(const Assignment *delta, int64 objective_min, int64 objective_max) override; @@ -554,7 +552,8 @@ VehicleAmortizedCostFilter::VehicleAmortizedCostFilter( const RoutingModel &routing_model) : BasePathFilter(routing_model.Nexts(), routing_model.Size() + routing_model.vehicles()), - current_vehicle_cost_(0), delta_vehicle_cost_(0), + current_vehicle_cost_(0), + delta_vehicle_cost_(0), current_route_lengths_(Size(), -1), linear_cost_factor_of_vehicle_( routing_model.GetAmortizedLinearCostFactorOfVehicles()), @@ -661,26 +660,26 @@ bool VehicleAmortizedCostFilter::FinalizeAcceptPath(const Assignment *delta, return delta_vehicle_cost_ <= objective_max; } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeVehicleAmortizedCostFilter(const RoutingModel &routing_model) { - return routing_model.solver() - ->RevAlloc(new VehicleAmortizedCostFilter(routing_model)); +IntVarLocalSearchFilter *MakeVehicleAmortizedCostFilter( + const RoutingModel &routing_model) { + return routing_model.solver()->RevAlloc( + new VehicleAmortizedCostFilter(routing_model)); } namespace { class TypeRegulationsFilter : public BasePathFilter { -public: + public: explicit TypeRegulationsFilter(const RoutingModel &model); ~TypeRegulationsFilter() override {} std::string DebugString() const override { return "TypeRegulationsFilter"; } -private: + private: void OnSynchronizePathFromStart(int64 start) override; - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; bool HardIncompatibilitiesRespected(int vehicle, int64 chain_start, int64 chain_end); @@ -697,7 +696,8 @@ private: TypeRegulationsFilter::TypeRegulationsFilter(const RoutingModel &model) : BasePathFilter(model.Nexts(), model.Size() + model.vehicles()), - routing_model_(model), start_to_vehicle_(model.Size(), -1), + routing_model_(model), + start_to_vehicle_(model.Size(), -1), temporal_incompatibility_checker_(model, /*check_hard_incompatibilities*/ false), requirement_checker_(model) { @@ -712,15 +712,14 @@ TypeRegulationsFilter::TypeRegulationsFilter(const RoutingModel &model) const int64 start = model.Start(vehicle); start_to_vehicle_[start] = vehicle; if (has_hard_type_incompatibilities) { - hard_incompatibility_type_counts_per_vehicle_[vehicle] - .resize(num_visit_types, 0); + hard_incompatibility_type_counts_per_vehicle_[vehicle].resize( + num_visit_types, 0); } } } void TypeRegulationsFilter::OnSynchronizePathFromStart(int64 start) { - if (!routing_model_.HasHardTypeIncompatibilities()) - return; + if (!routing_model_.HasHardTypeIncompatibilities()) return; const int vehicle = start_to_vehicle_[start]; CHECK_GE(vehicle, 0); @@ -745,8 +744,7 @@ void TypeRegulationsFilter::OnSynchronizePathFromStart(int64 start) { bool TypeRegulationsFilter::HardIncompatibilitiesRespected(int vehicle, int64 chain_start, int64 chain_end) { - if (!routing_model_.HasHardTypeIncompatibilities()) - return true; + if (!routing_model_.HasHardTypeIncompatibilities()) return true; const std::vector &previous_type_counts = hard_incompatibility_type_counts_per_vehicle_[vehicle]; @@ -804,20 +802,19 @@ bool TypeRegulationsFilter::AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) { const int vehicle = start_to_vehicle_[path_start]; CHECK_GE(vehicle, 0); - const auto next_accessor = [this](int64 node) { return GetNext(node); } - ; + const auto next_accessor = [this](int64 node) { return GetNext(node); }; return HardIncompatibilitiesRespected(vehicle, chain_start, chain_end) && temporal_incompatibility_checker_.CheckVehicle(vehicle, next_accessor) && requirement_checker_.CheckVehicle(vehicle, next_accessor); } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeTypeRegulationsFilter(const RoutingModel &routing_model) { - return routing_model.solver() - ->RevAlloc(new TypeRegulationsFilter(routing_model)); +IntVarLocalSearchFilter *MakeTypeRegulationsFilter( + const RoutingModel &routing_model) { + return routing_model.solver()->RevAlloc( + new TypeRegulationsFilter(routing_model)); } namespace { @@ -828,7 +825,7 @@ namespace { // cumul variables except overall capacity and cumul variables of path ends. class ChainCumulFilter : public BasePathFilter { -public: + public: ChainCumulFilter(const RoutingModel &routing_model, const RoutingDimension &dimension); ~ChainCumulFilter() override {} @@ -836,10 +833,10 @@ public: return "ChainCumulFilter(" + name_ + ")"; } -private: + private: void OnSynchronizePathFromStart(int64 start) override; - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; const std::vector cumuls_; std::vector start_to_vehicle_; @@ -864,7 +861,8 @@ ChainCumulFilter::ChainCumulFilter(const RoutingModel &routing_model, current_max_of_path_end_cumul_mins_(dimension.cumuls().size(), 0), old_nexts_(routing_model.Size(), kUnassigned), old_vehicles_(routing_model.Size(), kUnassigned), - current_transits_(routing_model.Size(), 0), name_(dimension.name()) { + current_transits_(routing_model.Size(), 0), + name_(dimension.name()) { start_to_vehicle_.resize(Size(), -1); start_to_end_.resize(Size(), -1); for (int i = 0; i < routing_model.vehicles(); ++i) { @@ -921,8 +919,7 @@ bool ChainCumulFilter::AcceptPath(int64 path_start, int64 chain_start, cumul = CapAdd(cumul, (*evaluators_[vehicle])(node, next)); } cumul = std::max(cumuls_[next]->Min(), cumul); - if (cumul > capacity) - return false; + if (cumul > capacity) return false; node = next; } const int64 end = start_to_end_[path_start]; @@ -938,7 +935,7 @@ bool ChainCumulFilter::AcceptPath(int64 path_start, int64 chain_start, // PathCumul filter. class PathCumulFilter : public BasePathFilter { -public: + public: PathCumulFilter(const RoutingModel &routing_model, const RoutingDimension &dimension, const RoutingSearchParameters ¶meters, @@ -955,7 +952,7 @@ public: return propagate_own_objective_value_ ? accepted_objective_value_ : 0; } -private: + private: // This structure stores the "best" path cumul value for a solution, the path // supporting this value, and the corresponding path cumul values for all // paths. @@ -975,7 +972,7 @@ private: // This class caches transit values between nodes of paths. Transit and path // nodes are to be added in the order in which they appear on a path. class PathTransits { - public: + public: void Clear() { paths_.clear(); transits_.clear(); @@ -1011,7 +1008,7 @@ private: return transits_[path][position]; } - private: + private: // paths_[r][i] is the ith node on path r. std::vector > paths_; // transits_[r][i] is the transit value between nodes path_[i] and @@ -1029,8 +1026,8 @@ private: lns_detected_ = false; delta_nodes_with_precedences_and_changed_cumul_.ClearAll(); } - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; bool FinalizeAcceptPath(const Assignment *delta, int64 objective_min, int64 objective_max) override; void OnBeforeSynchronizePaths() override; @@ -1063,17 +1060,13 @@ private: int num_linear_constraints = 0; if (dimension_.GetSpanCostCoefficientForVehicle(vehicle) > 0) ++num_linear_constraints; - if (FilterSoftSpanCost(vehicle)) - ++num_linear_constraints; - if (FilterCumulSoftLowerBounds()) - ++num_linear_constraints; - if (FilterCumulSoftBounds()) - ++num_linear_constraints; + if (FilterSoftSpanCost(vehicle)) ++num_linear_constraints; + if (FilterCumulSoftLowerBounds()) ++num_linear_constraints; + if (FilterCumulSoftBounds()) ++num_linear_constraints; if (vehicle_span_upper_bounds_[vehicle] < kint64max) ++num_linear_constraints; const bool has_breaks = FilterBreakCost(vehicle); - if (has_breaks) - ++num_linear_constraints; + if (has_breaks) ++num_linear_constraints; // The DimensionCumulOptimizer is used to compute a more precise value of // the cost related to the cumul values (soft bounds and span costs). @@ -1238,13 +1231,18 @@ PathCumulFilter::PathCumulFilter(const RoutingModel &routing_model, bool propagate_own_objective_value, bool filter_objective_cost, bool can_use_lp) : BasePathFilter(routing_model.Nexts(), dimension.cumuls().size()), - routing_model_(routing_model), dimension_(dimension), - cumuls_(dimension.cumuls()), slacks_(dimension.slacks()), + routing_model_(routing_model), + dimension_(dimension), + cumuls_(dimension.cumuls()), + slacks_(dimension.slacks()), evaluators_(routing_model.vehicles(), nullptr), vehicle_span_upper_bounds_(dimension.vehicle_span_upper_bounds()), - has_vehicle_span_upper_bounds_(false), total_current_cumul_cost_value_(0), - synchronized_objective_value_(0), accepted_objective_value_(0), - current_cumul_cost_values_(), cumul_cost_delta_(0), + has_vehicle_span_upper_bounds_(false), + total_current_cumul_cost_value_(0), + synchronized_objective_value_(0), + accepted_objective_value_(0), + current_cumul_cost_values_(), + cumul_cost_delta_(0), delta_path_cumul_cost_values_(routing_model.vehicles(), kint64min), global_span_cost_coefficient_(dimension.global_span_cost_coefficient()), vehicle_span_cost_coefficients_( @@ -1256,7 +1254,8 @@ PathCumulFilter::PathCumulFilter(const RoutingModel &routing_model, name_(dimension.name()), optimizer_(routing_model.GetMutableLocalCumulOptimizer(dimension)), mp_optimizer_(routing_model.GetMutableLocalCumulMPOptimizer(dimension)), - filter_objective_cost_(filter_objective_cost), can_use_lp_(can_use_lp), + filter_objective_cost_(filter_objective_cost), + can_use_lp_(can_use_lp), propagate_own_objective_value_(propagate_own_objective_value), lns_detected_(false) { for (const int64 upper_bound : vehicle_span_upper_bounds_) { @@ -1334,15 +1333,13 @@ PathCumulFilter::PathCumulFilter(const RoutingModel &routing_model, const std::vector &node_precedences = dimension.GetNodePrecedences(); if (!node_precedences.empty()) { - current_min_max_node_cumuls_.resize(cumuls_.size(), { - -1, -1 - }); + current_min_max_node_cumuls_.resize(cumuls_.size(), {-1, -1}); node_index_to_precedences_.resize(cumuls_.size()); for (const auto &node_precedence : node_precedences) { - node_index_to_precedences_[node_precedence.first_node] - .push_back(node_precedence); - node_index_to_precedences_[node_precedence.second_node] - .push_back(node_precedence); + node_index_to_precedences_[node_precedence.first_node].push_back( + node_precedence); + node_index_to_precedences_[node_precedence.second_node].push_back( + node_precedence); } } // NOTE(user): The model's local optimizer for this dimension could be @@ -1477,8 +1474,8 @@ void PathCumulFilter::OnBeforeSynchronizePaths() { current_cumul_cost_value, GetCumulPiecewiseLinearCost(node, cumul)); } if (FilterPrecedences()) { - StoreMinMaxCumulOfNodesOnPath(/*path=*/ r, min_path_cumuls, - /*is_delta=*/ false); + StoreMinMaxCumulOfNodesOnPath(/*path=*/r, min_path_cumuls, + /*is_delta=*/false); } if (number_of_route_arcs == 1 && !routing_model_.AreEmptyRouteCostsConsideredForVehicle(vehicle)) { @@ -1533,27 +1530,23 @@ void PathCumulFilter::OnBeforeSynchronizePaths() { DCHECK(optimizer != nullptr); const DimensionSchedulingStatus status = optimizer->ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [this](int64 node) { - return Value(node); - }, + vehicle, [this](int64 node) { return Value(node); }, &lp_cumul_cost_value); switch (status) { - case DimensionSchedulingStatus::INFEASIBLE: - lp_cumul_cost_value = 0; - break; - case DimensionSchedulingStatus::RELAXED_OPTIMAL_ONLY: - DCHECK(mp_optimizer_ != nullptr); - if (mp_optimizer_->ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [this](int64 node) { - return Value(node); - }, - &lp_cumul_cost_value) == - DimensionSchedulingStatus::INFEASIBLE) { + case DimensionSchedulingStatus::INFEASIBLE: lp_cumul_cost_value = 0; - } - break; - default: - DCHECK(status == DimensionSchedulingStatus::OPTIMAL); + break; + case DimensionSchedulingStatus::RELAXED_OPTIMAL_ONLY: + DCHECK(mp_optimizer_ != nullptr); + if (mp_optimizer_->ComputeRouteCumulCostWithoutFixedTransits( + vehicle, [this](int64 node) { return Value(node); }, + &lp_cumul_cost_value) == + DimensionSchedulingStatus::INFEASIBLE) { + lp_cumul_cost_value = 0; + } + break; + default: + DCHECK(status == DimensionSchedulingStatus::OPTIMAL); } current_cumul_cost_value = std::max(current_cumul_cost_value, lp_cumul_cost_value); @@ -1570,7 +1563,7 @@ void PathCumulFilter::OnBeforeSynchronizePaths() { if (FilterPrecedences()) { // Update the min/max node cumuls of new unperformed nodes. for (int64 node : GetNewSynchronizedUnperformedNodes()) { - current_min_max_node_cumuls_[node] = { -1, -1 }; + current_min_max_node_cumuls_[node] = {-1, -1}; } } // Use the max of the path end cumul mins to compute the corresponding @@ -1673,22 +1666,19 @@ bool PathCumulFilter::AcceptPath(int64 path_start, int64 chain_start, delta_path_transits_, path, path_start, min_end); const int64 span_lb = CapSub(min_end, max_start_from_min_end); int64 min_total_slack = CapSub(span_lb, total_transit); - if (min_total_slack > slack_max) - return false; + if (min_total_slack > slack_max) return false; if (dimension_.HasBreakConstraints()) { - for (const auto[limit, min_break_duration] : + for (const auto [limit, min_break_duration] : dimension_.GetBreakDistanceDurationOfVehicle(vehicle)) { // Minimal number of breaks depends on total transit: // 0 breaks for 0 <= total transit <= limit, // 1 break for limit + 1 <= total transit <= 2 * limit, // i breaks for i * limit + 1 <= total transit <= (i+1) * limit, ... - if (limit == 0 || total_transit == 0) - continue; + if (limit == 0 || total_transit == 0) continue; const int num_breaks_lb = (total_transit - 1) / limit; const int64 slack_lb = CapProd(num_breaks_lb, min_break_duration); - if (slack_lb > slack_max) - return false; + if (slack_lb > slack_max) return false; min_total_slack = std::max(min_total_slack, slack_lb); } // Compute a lower bound of the amount of break that must be made inside @@ -1701,14 +1691,12 @@ bool PathCumulFilter::AcceptPath(int64 path_start, int64 chain_start, delta_path_transits_, path, path_start, max_path_end); for (const IntervalVar *br : dimension_.GetBreakIntervalsOfVehicle(vehicle)) { - if (!br->MustBePerformed()) - continue; + if (!br->MustBePerformed()) continue; if (max_start < br->EndMin() && br->StartMax() < min_end) { min_total_break = CapAdd(min_total_break, br->DurationMin()); } } - if (min_total_break > slack_max) - return false; + if (min_total_break > slack_max) return false; min_total_slack = std::max(min_total_slack, min_total_break); } if (filter_vehicle_costs) { @@ -1747,7 +1735,7 @@ bool PathCumulFilter::AcceptPath(int64 path_start, int64 chain_start, GetPathCumulSoftLowerBoundCost(delta_path_transits_, path)); } if (FilterPrecedences()) { - StoreMinMaxCumulOfNodesOnPath(path, min_path_cumuls, /*is_delta=*/ true); + StoreMinMaxCumulOfNodesOnPath(path, min_path_cumuls, /*is_delta=*/true); } if (!filter_vehicle_costs) { // If this route's costs should't be taken into account, reset the @@ -1776,17 +1764,16 @@ bool PathCumulFilter::FinalizeAcceptPath(const Assignment *delta, if ((!FilterSpanCost() && !FilterCumulSoftBounds() && !FilterSlackCost() && !FilterCumulSoftLowerBounds() && !FilterCumulPiecewiseLinearCosts() && !FilterPrecedences() && !FilterSoftSpanCost() && - !FilterSoftSpanQuadraticCost()) || lns_detected_) { + !FilterSoftSpanQuadraticCost()) || + lns_detected_) { return true; } if (FilterPrecedences()) { for (int64 node : delta_nodes_with_precedences_and_changed_cumul_ - .PositionsSetAtLeastOnce()) { + .PositionsSetAtLeastOnce()) { const std::pair node_min_max_cumul_in_delta = gtl::FindWithDefault(node_with_precedence_to_delta_min_max_cumuls_, - node, { - -1, -1 - }); + node, {-1, -1}); // NOTE: This node was seen in delta, so its delta min/max cumul should be // stored in the map. DCHECK(node_min_max_cumul_in_delta.first >= 0 && @@ -1809,12 +1796,12 @@ bool PathCumulFilter::FinalizeAcceptPath(const Assignment *delta, other_node, current_min_max_node_cumuls_[other_node]); - const int64 first_min_cumul = - node_is_first ? node_min_max_cumul_in_delta.first - : other_min_max_cumul_in_delta.first; - const int64 second_max_cumul = - node_is_first ? other_min_max_cumul_in_delta.second - : node_min_max_cumul_in_delta.second; + const int64 first_min_cumul = node_is_first + ? node_min_max_cumul_in_delta.first + : other_min_max_cumul_in_delta.first; + const int64 second_max_cumul = node_is_first + ? other_min_max_cumul_in_delta.second + : node_min_max_cumul_in_delta.second; if (second_max_cumul < first_min_cumul + precedence.offset) { return false; @@ -1896,9 +1883,7 @@ bool PathCumulFilter::FinalizeAcceptPath(const Assignment *delta, int64 path_delta_cost_with_lp = 0; const DimensionSchedulingStatus status = optimizer_->ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [this](int64 node) { - return GetNext(node); - }, + vehicle, [this](int64 node) { return GetNext(node); }, &path_delta_cost_with_lp); if (status == DimensionSchedulingStatus::INFEASIBLE) { return false; @@ -1933,9 +1918,7 @@ bool PathCumulFilter::FinalizeAcceptPath(const Assignment *delta, const int vehicle = start_to_vehicle_[start]; int64 path_delta_cost_with_mp = 0; if (mp_optimizer_->ComputeRouteCumulCostWithoutFixedTransits( - vehicle, [this](int64 node) { - return GetNext(node); - }, + vehicle, [this](int64 node) { return GetNext(node); }, &path_delta_cost_with_mp) == DimensionSchedulingStatus::INFEASIBLE) { return false; @@ -1972,9 +1955,7 @@ bool PathCumulFilter::PickupToDeliveryLimitsRespected( const int num_pairs = routing_model_.GetPickupAndDeliveryPairs().size(); DCHECK_GT(num_pairs, 0); std::vector > visited_delivery_and_min_cumul_per_pair( - num_pairs, { - -1, -1 - }); + num_pairs, {-1, -1}); const int path_size = path_transits.PathSize(path); CHECK_EQ(min_path_cumuls.size(), path_size); @@ -2081,13 +2062,13 @@ int64 PathCumulFilter::ComputePathMaxStartFromEndCumul( return std::min(cumul_from_min_end, cumul_from_max_end); } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakePathCumulFilter(const RoutingDimension &dimension, - const RoutingSearchParameters ¶meters, - bool propagate_own_objective_value, - bool filter_objective_cost, bool can_use_lp) { +IntVarLocalSearchFilter *MakePathCumulFilter( + const RoutingDimension &dimension, + const RoutingSearchParameters ¶meters, + bool propagate_own_objective_value, bool filter_objective_cost, + bool can_use_lp) { RoutingModel &model = *dimension.model(); return model.solver()->RevAlloc(new PathCumulFilter( model, dimension, parameters, propagate_own_objective_value, @@ -2097,41 +2078,29 @@ MakePathCumulFilter(const RoutingDimension &dimension, namespace { bool DimensionHasCumulCost(const RoutingDimension &dimension) { - if (dimension.global_span_cost_coefficient() != 0) - return true; - if (dimension.HasSoftSpanUpperBounds()) - return true; - if (dimension.HasQuadraticCostSoftSpanUpperBounds()) - return true; + if (dimension.global_span_cost_coefficient() != 0) return true; + if (dimension.HasSoftSpanUpperBounds()) return true; + if (dimension.HasQuadraticCostSoftSpanUpperBounds()) return true; for (const int64 coefficient : dimension.vehicle_span_cost_coefficients()) { - if (coefficient != 0) - return true; + if (coefficient != 0) return true; } for (int i = 0; i < dimension.cumuls().size(); ++i) { - if (dimension.HasCumulVarSoftUpperBound(i)) - return true; - if (dimension.HasCumulVarSoftLowerBound(i)) - return true; - if (dimension.HasCumulVarPiecewiseLinearCost(i)) - return true; + if (dimension.HasCumulVarSoftUpperBound(i)) return true; + if (dimension.HasCumulVarSoftLowerBound(i)) return true; + if (dimension.HasCumulVarPiecewiseLinearCost(i)) return true; } return false; } bool DimensionHasCumulConstraint(const RoutingDimension &dimension) { - if (dimension.HasBreakConstraints()) - return true; - if (dimension.HasPickupToDeliveryLimits()) - return true; - if (!dimension.GetNodePrecedences().empty()) - return true; + if (dimension.HasBreakConstraints()) return true; + if (dimension.HasPickupToDeliveryLimits()) return true; + if (!dimension.GetNodePrecedences().empty()) return true; for (const int64 upper_bound : dimension.vehicle_span_upper_bounds()) { - if (upper_bound != kint64max) - return true; + if (upper_bound != kint64max) return true; } for (const IntVar *const slack : dimension.slacks()) { - if (slack->Min() > 0) - return true; + if (slack->Min() > 0) return true; } const std::vector &cumuls = dimension.cumuls(); for (int i = 0; i < cumuls.size(); ++i) { @@ -2140,13 +2109,12 @@ bool DimensionHasCumulConstraint(const RoutingDimension &dimension) { !dimension.model()->IsEnd(i)) { return true; } - if (dimension.forbidden_intervals()[i].NumIntervals() > 0) - return true; + if (dimension.forbidden_intervals()[i].NumIntervals() > 0) return true; } return false; } -} // namespace +} // namespace void AppendLightWeightDimensionFilters( const PathState *path_state, @@ -2155,8 +2123,7 @@ void AppendLightWeightDimensionFilters( // For every dimension that fits, add a UnaryDimensionChecker. for (const RoutingDimension *dimension : dimensions) { // Skip dimension if not unary. - if (dimension->GetUnaryTransitEvaluator(0) == nullptr) - continue; + if (dimension->GetUnaryTransitEvaluator(0) == nullptr) continue; using Intervals = std::vector; // Fill path capacities and classes. @@ -2165,7 +2132,7 @@ void AppendLightWeightDimensionFilters( std::vector path_class(num_vehicles); for (int v = 0; v < num_vehicles; ++v) { const auto &vehicle_capacities = dimension->vehicle_capacities(); - path_capacity[v] = { 0, vehicle_capacities[v] }; + path_capacity[v] = {0, vehicle_capacities[v]}; path_class[v] = dimension->vehicle_to_class(v); } // For each class, retrieve the demands of each node. @@ -2180,17 +2147,16 @@ void AppendLightWeightDimensionFilters( const int num_slacks = dimension->slacks().size(); for (int vehicle = 0; vehicle < num_vehicles; ++vehicle) { const int vehicle_class = path_class[vehicle]; - if (!demands[vehicle_class].empty()) - continue; + if (!demands[vehicle_class].empty()) continue; const auto &evaluator = dimension->GetUnaryTransitEvaluator(vehicle); Intervals class_demands(num_cumuls); for (int node = 0; node < num_cumuls; ++node) { if (node < num_slacks) { const int64 demand_min = evaluator(node); const int64 slack_max = dimension->SlackVar(node)->Max(); - class_demands[node] = { demand_min, CapAdd(demand_min, slack_max) }; + class_demands[node] = {demand_min, CapAdd(demand_min, slack_max)}; } else { - class_demands[node] = { 0, 0 }; + class_demands[node] = {0, 0}; } } demands[vehicle_class] = std::move(class_demands); @@ -2199,7 +2165,7 @@ void AppendLightWeightDimensionFilters( Intervals node_capacity(num_cumuls); for (int node = 0; node < num_cumuls; ++node) { const IntVar *cumul = dimension->CumulVar(node); - node_capacity[node] = { cumul->Min(), cumul->Max() }; + node_capacity[node] = {cumul->Min(), cumul->Max()}; } // Make the dimension checker and pass ownership to the filter. auto checker = absl::make_unique( @@ -2208,9 +2174,7 @@ void AppendLightWeightDimensionFilters( const auto kAccept = LocalSearchFilterManager::FilterEventType::kAccept; LocalSearchFilter *filter = MakeUnaryDimensionFilter( dimension->model()->solver(), std::move(checker)); - filters->push_back({ - filter, kAccept - }); + filters->push_back({filter, kAccept}); } } @@ -2249,9 +2213,9 @@ void AppendDimensionCumulFilters( use_cumul_bounds_propagator_filter[d] = has_precedences && !use_global_lp_filter[d]; - filtering_difficulty[d] = - 4 * use_global_lp_filter[d] + - 2 * use_cumul_bounds_propagator_filter[d] + use_path_cumul_filter[d]; + filtering_difficulty[d] = 4 * use_global_lp_filter[d] + + 2 * use_cumul_bounds_propagator_filter[d] + + use_path_cumul_filter[d]; } std::vector sorted_dimension_indices(num_dimensions); @@ -2259,8 +2223,8 @@ void AppendDimensionCumulFilters( 0); std::sort(sorted_dimension_indices.begin(), sorted_dimension_indices.end(), [&filtering_difficulty](int d1, int d2) { - return filtering_difficulty[d1] < filtering_difficulty[d2]; - }); + return filtering_difficulty[d1] < filtering_difficulty[d2]; + }); for (const int d : sorted_dimension_indices) { const RoutingDimension &dimension = *dimensions[d]; @@ -2271,29 +2235,24 @@ void AppendDimensionCumulFilters( // already doing it. const bool use_global_lp = use_global_lp_filter[d]; if (use_path_cumul_filter[d]) { - filters->push_back({ - MakePathCumulFilter(dimension, parameters, !use_global_lp, - filter_objective_cost), - kAccept - }); + filters->push_back( + {MakePathCumulFilter(dimension, parameters, !use_global_lp, + filter_objective_cost), + kAccept}); } else { - filters->push_back({ - model.solver()->RevAlloc(new ChainCumulFilter(model, dimension)), - kAccept - }); + filters->push_back( + {model.solver()->RevAlloc(new ChainCumulFilter(model, dimension)), + kAccept}); } if (use_global_lp) { DCHECK(model.GetMutableGlobalCumulOptimizer(dimension) != nullptr); - filters->push_back({ - MakeGlobalLPCumulFilter(model.GetMutableGlobalCumulOptimizer(dimension), - filter_objective_cost), - kAccept - }); + filters->push_back({MakeGlobalLPCumulFilter( + model.GetMutableGlobalCumulOptimizer(dimension), + filter_objective_cost), + kAccept}); } else if (use_cumul_bounds_propagator_filter[d]) { - filters->push_back({ - MakeCumulBoundsPropagatorFilter(dimension), kAccept - }); + filters->push_back({MakeCumulBoundsPropagatorFilter(dimension), kAccept}); } } } @@ -2302,20 +2261,20 @@ namespace { // Filter for pickup/delivery precedences. class PickupDeliveryFilter : public BasePathFilter { -public: - PickupDeliveryFilter( - const std::vector &nexts, int next_domain_size, - const RoutingModel::IndexPairs &pairs, - const std::vector & - vehicle_policies); + public: + PickupDeliveryFilter(const std::vector &nexts, int next_domain_size, + const RoutingModel::IndexPairs &pairs, + const std::vector + &vehicle_policies); ~PickupDeliveryFilter() override {} - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; std::string DebugString() const override { return "PickupDeliveryFilter"; } -private: + private: bool AcceptPathDefault(int64 path_start); - template bool AcceptPathOrdered(int64 path_start); + template + bool AcceptPathOrdered(int64 path_start); std::vector pair_firsts_; std::vector pair_seconds_; @@ -2331,8 +2290,10 @@ PickupDeliveryFilter::PickupDeliveryFilter( const std::vector &vehicle_policies) : BasePathFilter(nexts, next_domain_size), pair_firsts_(next_domain_size, kUnassigned), - pair_seconds_(next_domain_size, kUnassigned), pairs_(pairs), - visited_(Size()), vehicle_policies_(vehicle_policies) { + pair_seconds_(next_domain_size, kUnassigned), + pairs_(pairs), + visited_(Size()), + vehicle_policies_(vehicle_policies) { for (int i = 0; i < pairs.size(); ++i) { const auto &index_pair = pairs[i]; for (int first : index_pair.first) { @@ -2347,14 +2308,14 @@ PickupDeliveryFilter::PickupDeliveryFilter( bool PickupDeliveryFilter::AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) { switch (vehicle_policies_[GetPath(path_start)]) { - case RoutingModel::PICKUP_AND_DELIVERY_NO_ORDER: - return AcceptPathDefault(path_start); - case RoutingModel::PICKUP_AND_DELIVERY_LIFO: - return AcceptPathOrdered(path_start); - case RoutingModel::PICKUP_AND_DELIVERY_FIFO: - return AcceptPathOrdered(path_start); - default: - return true; + case RoutingModel::PICKUP_AND_DELIVERY_NO_ORDER: + return AcceptPathDefault(path_start); + case RoutingModel::PICKUP_AND_DELIVERY_LIFO: + return AcceptPathOrdered(path_start); + case RoutingModel::PICKUP_AND_DELIVERY_FIFO: + return AcceptPathOrdered(path_start); + default: + return true; } } @@ -2477,12 +2438,12 @@ bool PickupDeliveryFilter::AcceptPathOrdered(int64 path_start) { return true; } -} // namespace +} // namespace IntVarLocalSearchFilter *MakePickupDeliveryFilter( const RoutingModel &routing_model, const RoutingModel::IndexPairs &pairs, - const std::vector & - vehicle_policies) { + const std::vector + &vehicle_policies) { return routing_model.solver()->RevAlloc(new PickupDeliveryFilter( routing_model.Nexts(), routing_model.Size() + routing_model.vehicles(), pairs, vehicle_policies)); @@ -2492,14 +2453,14 @@ namespace { // Vehicle variable filter class VehicleVarFilter : public BasePathFilter { -public: + public: explicit VehicleVarFilter(const RoutingModel &routing_model); ~VehicleVarFilter() override {} - bool AcceptPath(int64 path_start, int64 chain_start, int64 chain_end) - override; + bool AcceptPath(int64 path_start, int64 chain_start, + int64 chain_end) override; std::string DebugString() const override { return "VehicleVariableFilter"; } -private: + private: bool DisableFiltering() const override; bool IsVehicleVariableConstrained(int index) const; @@ -2534,8 +2495,7 @@ bool VehicleVarFilter::AcceptPath(int64 path_start, int64 chain_start, bool VehicleVarFilter::DisableFiltering() const { for (int i = 0; i < vehicle_vars_.size(); ++i) { - if (IsVehicleVariableConstrained(i)) - return false; + if (IsVehicleVariableConstrained(i)) return false; } return true; } @@ -2551,17 +2511,17 @@ bool VehicleVarFilter::IsVehicleVariableConstrained(int index) const { return vehicle_var->Size() != adjusted_unconstrained_vehicle_var_domain_size; } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeVehicleVarFilter(const RoutingModel &routing_model) { +IntVarLocalSearchFilter *MakeVehicleVarFilter( + const RoutingModel &routing_model) { return routing_model.solver()->RevAlloc(new VehicleVarFilter(routing_model)); } namespace { class CumulBoundsPropagatorFilter : public IntVarLocalSearchFilter { -public: + public: explicit CumulBoundsPropagatorFilter(const RoutingDimension &dimension); bool Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, int64 objective_max) override; @@ -2570,7 +2530,7 @@ public: ")"; } -private: + private: CumulBoundsPropagator propagator_; const int64 cumul_offset_; SparseBitset delta_touched_; @@ -2582,7 +2542,8 @@ CumulBoundsPropagatorFilter::CumulBoundsPropagatorFilter( : IntVarLocalSearchFilter(dimension.model()->Nexts()), propagator_(&dimension), cumul_offset_(dimension.GetGlobalOptimizerOffset()), - delta_touched_(Size()), delta_nexts_(Size()) {} + delta_touched_(Size()), + delta_nexts_(Size()) {} bool CumulBoundsPropagatorFilter::Accept(const Assignment *delta, const Assignment *deltadelta, @@ -2603,24 +2564,23 @@ bool CumulBoundsPropagatorFilter::Accept(const Assignment *delta, } const auto &next_accessor = [this](int64 index) { return delta_touched_[index] ? delta_nexts_[index] : Value(index); - } - ; + }; return propagator_.PropagateCumulBounds(next_accessor, cumul_offset_); } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeCumulBoundsPropagatorFilter(const RoutingDimension &dimension) { - return dimension.model()->solver() - ->RevAlloc(new CumulBoundsPropagatorFilter(dimension)); +IntVarLocalSearchFilter *MakeCumulBoundsPropagatorFilter( + const RoutingDimension &dimension) { + return dimension.model()->solver()->RevAlloc( + new CumulBoundsPropagatorFilter(dimension)); } namespace { class LPCumulFilter : public IntVarLocalSearchFilter { -public: + public: LPCumulFilter(const std::vector &nexts, GlobalDimensionCumulOptimizer *optimizer, bool filter_objective_cost); @@ -2633,7 +2593,7 @@ public: return "LPCumulFilter(" + optimizer_.dimension()->name() + ")"; } -private: + private: GlobalDimensionCumulOptimizer &optimizer_; const bool filter_objective_cost_; int64 synchronized_cost_without_transit_; @@ -2645,10 +2605,13 @@ private: LPCumulFilter::LPCumulFilter(const std::vector &nexts, GlobalDimensionCumulOptimizer *optimizer, bool filter_objective_cost) - : IntVarLocalSearchFilter(nexts), optimizer_(*optimizer), + : IntVarLocalSearchFilter(nexts), + optimizer_(*optimizer), filter_objective_cost_(filter_objective_cost), - synchronized_cost_without_transit_(-1), delta_cost_without_transit_(-1), - delta_touched_(Size()), delta_nexts_(Size()) {} + synchronized_cost_without_transit_(-1), + delta_cost_without_transit_(-1), + delta_touched_(Size()), + delta_nexts_(Size()) {} bool LPCumulFilter::Accept(const Assignment *delta, const Assignment *deltadelta, int64 objective_min, @@ -2668,8 +2631,7 @@ bool LPCumulFilter::Accept(const Assignment *delta, } const auto &next_accessor = [this](int64 index) { return delta_touched_[index] ? delta_nexts_[index] : Value(index); - } - ; + }; if (!filter_objective_cost_) { // No need to compute the cost of the LP, only verify its feasibility. @@ -2696,10 +2658,12 @@ void LPCumulFilter::OnSynchronize(const Assignment *delta) { const RoutingModel &model = *optimizer_.dimension()->model(); if (!optimizer_.ComputeCumulCostWithoutFixedTransits( [this, &model](int64 index) { - return IsVarSynced(index) ? Value(index) : model.IsStart(index) - ? model.End(model.VehicleIndex(index)) - : index; - }, + return IsVarSynced(index) + ? Value(index) + : model.IsStart(index) + ? model.End(model.VehicleIndex(index)) + : index; + }, &synchronized_cost_without_transit_)) { // TODO(user): This should only happen if the LP solver times out. // DCHECK the fail wasn't due to an infeasible model. @@ -2711,11 +2675,10 @@ int64 LPCumulFilter::GetSynchronizedObjectiveValue() const { return synchronized_cost_without_transit_; } -} // namespace +} // namespace -IntVarLocalSearchFilter * -MakeGlobalLPCumulFilter(GlobalDimensionCumulOptimizer *optimizer, - bool filter_objective_cost) { +IntVarLocalSearchFilter *MakeGlobalLPCumulFilter( + GlobalDimensionCumulOptimizer *optimizer, bool filter_objective_cost) { const RoutingModel &model = *optimizer->dimension()->model(); return model.solver()->RevAlloc( new LPCumulFilter(model.Nexts(), optimizer, filter_objective_cost)); @@ -2724,13 +2687,14 @@ MakeGlobalLPCumulFilter(GlobalDimensionCumulOptimizer *optimizer, const int64 CPFeasibilityFilter::kUnassigned = -1; CPFeasibilityFilter::CPFeasibilityFilter(RoutingModel *routing_model) - : IntVarLocalSearchFilter(routing_model->Nexts()), model_(routing_model), - solver_(routing_model->solver()), assignment_(solver_->MakeAssignment()), + : IntVarLocalSearchFilter(routing_model->Nexts()), + model_(routing_model), + solver_(routing_model->solver()), + assignment_(solver_->MakeAssignment()), temp_assignment_(solver_->MakeAssignment()), restore_(solver_->MakeRestoreAssignment(temp_assignment_)), - limit_(solver_->MakeCustomLimit([routing_model]() { - return routing_model->CheckLimit(); -})) { + limit_(solver_->MakeCustomLimit( + [routing_model]() { return routing_model->CheckLimit(); })) { assignment_->Add(routing_model->Nexts()); } @@ -2779,8 +2743,8 @@ void CPFeasibilityFilter::AddDeltaToAssignment(const Assignment *delta, } IntVarLocalSearchFilter *MakeCPFeasibilityFilter(RoutingModel *routing_model) { - return routing_model->solver() - ->RevAlloc(new CPFeasibilityFilter(routing_model)); + return routing_model->solver()->RevAlloc( + new CPFeasibilityFilter(routing_model)); } // TODO(user): Implement same-vehicle filter. Could be merged with node @@ -2830,8 +2794,8 @@ Decision *IntVarFilteredDecisionBuilder::Next(Solver *solver) { Assignment *const assignment = heuristic_->BuildSolution(); if (assignment != nullptr) { VLOG(2) << "Number of decisions: " << heuristic_->number_of_decisions(); - VLOG(2) - << "Number of rejected decisions: " << heuristic_->number_of_rejects(); + VLOG(2) << "Number of rejected decisions: " + << heuristic_->number_of_rejects(); assignment->Restore(); } else { solver->Fail(); @@ -2859,10 +2823,15 @@ std::string IntVarFilteredDecisionBuilder::DebugString() const { IntVarFilteredHeuristic::IntVarFilteredHeuristic( Solver *solver, const std::vector &vars, LocalSearchFilterManager *filter_manager) - : assignment_(solver->MakeAssignment()), solver_(solver), vars_(vars), - delta_(solver->MakeAssignment()), is_in_delta_(vars_.size(), false), - empty_(solver->MakeAssignment()), filter_manager_(filter_manager), - number_of_decisions_(0), number_of_rejects_(0) { + : assignment_(solver->MakeAssignment()), + solver_(solver), + vars_(vars), + delta_(solver->MakeAssignment()), + is_in_delta_(vars_.size(), false), + empty_(solver->MakeAssignment()), + filter_manager_(filter_manager), + number_of_decisions_(0), + number_of_rejects_(0) { assignment_->MutableIntVarContainer()->Resize(vars_.size()); delta_indices_.reserve(vars_.size()); } @@ -2951,13 +2920,11 @@ bool IntVarFilteredHeuristic::Commit() { } void IntVarFilteredHeuristic::SynchronizeFilters() { - if (filter_manager_) - filter_manager_->Synchronize(assignment_, delta_); + if (filter_manager_) filter_manager_->Synchronize(assignment_, delta_); } bool IntVarFilteredHeuristic::FilterAccept() { - if (!filter_manager_) - return true; + if (!filter_manager_) return true; LocalSearchMonitor *const monitor = solver_->GetLocalSearchMonitor(); return filter_manager_->Accept(monitor, delta_, empty_, kint64min, kint64max); } @@ -3048,10 +3015,10 @@ bool RoutingFilteredHeuristic::InitializeSolution() { void RoutingFilteredHeuristic::MakeDisjunctionNodesUnperformed(int64 node) { model()->ForEachNodeInDisjunctionWithMaxCardinalityFromIndex( node, 1, [this, node](int alternate) { - if (node != alternate && !Contains(alternate)) { - SetValue(alternate, alternate); - } - }); + if (node != alternate && !Contains(alternate)) { + SetValue(alternate, alternate); + } + }); } void RoutingFilteredHeuristic::MakeUnassignedNodesUnperformed() { @@ -3079,8 +3046,7 @@ CheapestInsertionFilteredHeuristic::ComputeStartEndDistanceForVehicles( model()->Size()); for (int node = 0; node < model()->Size(); node++) { - if (Contains(node)) - continue; + if (Contains(node)) continue; std::vector &start_end_distances = start_end_distances_per_node[node]; @@ -3092,16 +3058,14 @@ CheapestInsertionFilteredHeuristic::ComputeStartEndDistanceForVehicles( const int64 distance = CapAdd(model()->GetArcCostForVehicle(start, node, vehicle), model()->GetArcCostForVehicle(node, end, vehicle)); - start_end_distances.push_back({ - distance, vehicle - }); + start_end_distances.push_back({distance, vehicle}); } - // Sort the distances for the node to all start/ends of available vehicles - // in decreasing order. + // Sort the distances for the node to all start/ends of available vehicles + // in decreasing order. std::sort(start_end_distances.begin(), start_end_distances.end(), - [](const StartEndValue & first, const StartEndValue & second) { - return second < first; - }); + [](const StartEndValue &first, const StartEndValue &second) { + return second < first; + }); } return start_end_distances_per_node; } @@ -3114,8 +3078,7 @@ void CheapestInsertionFilteredHeuristic::InitializePriorityQueue( DCHECK_EQ(start_end_distances_per_node->size(), num_nodes); for (int node = 0; node < num_nodes; node++) { - if (Contains(node)) - continue; + if (Contains(node)) continue; std::vector &start_end_distances = (*start_end_distances_per_node)[node]; if (start_end_distances.empty()) { @@ -3180,19 +3143,22 @@ void SortAndExtractPairSeconds(std::vector > *pairs, sorted_seconds->push_back(p.second); } } -} // namespace +} // namespace // Priority queue entries used by global cheapest insertion heuristic. // Entry in priority queue containing the insertion positions of a node pair. class GlobalCheapestInsertionFilteredHeuristic::PairEntry { -public: + public: PairEntry(int pickup_to_insert, int pickup_insert_after, int delivery_to_insert, int delivery_insert_after, int vehicle) - : heap_index_(-1), value_(kint64max), pickup_to_insert_(pickup_to_insert), + : heap_index_(-1), + value_(kint64max), + pickup_to_insert_(pickup_to_insert), pickup_insert_after_(pickup_insert_after), delivery_to_insert_(delivery_to_insert), - delivery_insert_after_(delivery_insert_after), vehicle_(vehicle) {} + delivery_insert_after_(delivery_insert_after), + vehicle_(vehicle) {} // Note: for compatibility reasons, comparator follows tie-breaking rules used // in the first version of GlobalCheapestInsertion. bool operator<(const PairEntry &other) const { @@ -3220,7 +3186,7 @@ public: int delivery_insert_after() const { return delivery_insert_after_; } int vehicle() const { return vehicle_; } -private: + private: int heap_index_; int64 value_; const int pickup_to_insert_; @@ -3232,10 +3198,13 @@ private: // Entry in priority queue containing the insertion position of a node. class GlobalCheapestInsertionFilteredHeuristic::NodeEntry { -public: + public: NodeEntry(int node_to_insert, int insert_after, int vehicle) - : heap_index_(-1), value_(kint64max), node_to_insert_(node_to_insert), - insert_after_(insert_after), vehicle_(vehicle) {} + : heap_index_(-1), + value_(kint64max), + node_to_insert_(node_to_insert), + insert_after_(insert_after), + vehicle_(vehicle) {} bool operator<(const NodeEntry &other) const { // See PairEntry::operator<(), above. This one is similar. if (value_ != other.value_) { @@ -3255,7 +3224,7 @@ public: int insert_after() const { return insert_after_; } int vehicle() const { return vehicle_; } -private: + private: int heap_index_; int64 value_; const int node_to_insert_; @@ -3275,7 +3244,8 @@ GlobalCheapestInsertionFilteredHeuristic:: : CheapestInsertionFilteredHeuristic(model, std::move(evaluator), std::move(penalty_evaluator), filter_manager), - gci_params_(parameters), node_index_to_vehicle_(model->Size(), -1) { + gci_params_(parameters), + node_index_to_vehicle_(model->Size(), -1) { CHECK_GT(gci_params_.neighbors_ratio, 0); CHECK_LE(gci_params_.neighbors_ratio, 1); @@ -3327,12 +3297,12 @@ void GlobalCheapestInsertionFilteredHeuristic::ComputeNeighborhoods() { node_index_to_delivery_neighbors_by_cost_class_.resize(size); const int num_cost_classes = routing_model.GetCostClassesCount(); for (int64 node_index = 0; node_index < size; node_index++) { - node_index_to_single_neighbors_by_cost_class_[node_index] - .resize(num_cost_classes); - node_index_to_pickup_neighbors_by_cost_class_[node_index] - .resize(num_cost_classes); - node_index_to_delivery_neighbors_by_cost_class_[node_index] - .resize(num_cost_classes); + node_index_to_single_neighbors_by_cost_class_[node_index].resize( + num_cost_classes); + node_index_to_pickup_neighbors_by_cost_class_[node_index].resize( + num_cost_classes); + node_index_to_delivery_neighbors_by_cost_class_[node_index].resize( + num_cost_classes); for (int cc = 0; cc < num_cost_classes; cc++) { node_index_to_single_neighbors_by_cost_class_[node_index][cc] = absl::make_unique >(size); @@ -3393,16 +3363,16 @@ void GlobalCheapestInsertionFilteredHeuristic::AddNeighborForCostClass( int cost_class, int64 node_index, int64 neighbor_index, bool neighbor_is_pickup, bool neighbor_is_delivery) { if (neighbor_is_pickup) { - node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class] - ->Set(neighbor_index); + node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class]->Set( + neighbor_index); } if (neighbor_is_delivery) { node_index_to_delivery_neighbors_by_cost_class_[node_index][cost_class] ->Set(neighbor_index); } if (!neighbor_is_pickup && !neighbor_is_delivery) { - node_index_to_single_neighbors_by_cost_class_[node_index][cost_class] - ->Set(neighbor_index); + node_index_to_single_neighbors_by_cost_class_[node_index][cost_class]->Set( + neighbor_index); } } @@ -3489,9 +3459,7 @@ bool GlobalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() { } } for (const auto &vehicle_and_nodes : vehicle_to_pair_nodes) { - InsertNodesOnRoutes(vehicle_and_nodes.second, { - vehicle_and_nodes.first - }); + InsertNodesOnRoutes(vehicle_and_nodes.second, {vehicle_and_nodes.first}); } InsertPairsAndNodesByRequirementTopologicalOrder(); @@ -3510,8 +3478,7 @@ bool GlobalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() { if (gci_params_.is_sequential) { SequentialInsertNodes(nodes); } else { - InsertNodesOnRoutes(nodes, { - }); + InsertNodesOnRoutes(nodes, {}); } MakeUnassignedNodesUnperformed(); DCHECK(CheckVehicleIndices()); @@ -3524,8 +3491,7 @@ void GlobalCheapestInsertionFilteredHeuristic:: model()->GetTopologicallySortedVisitTypes()) { for (int type : types) { InsertPairs(model()->GetPairIndicesOfType(type)); - InsertNodesOnRoutes(model()->GetSingleNodesOfType(type), { - }); + InsertNodesOnRoutes(model()->GetSingleNodesOfType(type), {}); } } } @@ -3686,9 +3652,7 @@ void GlobalCheapestInsertionFilteredHeuristic::SequentialInsertNodes( &is_vehicle_used); while (vehicle >= 0) { - InsertNodesOnRoutes(nodes, { - vehicle - }); + InsertNodesOnRoutes(nodes, {vehicle}); vehicle = InsertSeedNode(&start_end_distances_per_node, &first_node_queue, &is_vehicle_used); } @@ -3718,8 +3682,7 @@ void GlobalCheapestInsertionFilteredHeuristic::DetectUsedVehicles( } void GlobalCheapestInsertionFilteredHeuristic::InsertFarthestNodesAsSeeds() { - if (gci_params_.farthest_seeds_ratio <= 0) - return; + if (gci_params_.farthest_seeds_ratio <= 0) return; // Insert at least 1 farthest Seed if the parameter is positive. const int num_seeds = static_cast( std::ceil(gci_params_.farthest_seeds_ratio * model()->vehicles())); @@ -3749,8 +3712,7 @@ int GlobalCheapestInsertionFilteredHeuristic::InsertSeedNode( std::vector > *start_end_distances_per_node, Queue *priority_queue, std::vector *is_vehicle_used) { while (!priority_queue->empty()) { - if (StopSearch()) - break; + if (StopSearch()) break; const Seed &seed = priority_queue->top(); const int seed_node = seed.second; @@ -3797,12 +3759,12 @@ int GlobalCheapestInsertionFilteredHeuristic::InsertSeedNode( void GlobalCheapestInsertionFilteredHeuristic::InitializePairPositions( const std::vector &pair_indices, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::PairEntry> *priority_queue, - std::vector * - pickup_to_entries, - std::vector * - delivery_to_entries) { + AdjustablePriorityQueue + *priority_queue, + std::vector + *pickup_to_entries, + std::vector + *delivery_to_entries) { priority_queue->Clear(); pickup_to_entries->clear(); pickup_to_entries->resize(model()->Size()); @@ -3813,11 +3775,9 @@ void GlobalCheapestInsertionFilteredHeuristic::InitializePairPositions( for (int index : pair_indices) { const RoutingModel::IndexPair &index_pair = pickup_delivery_pairs[index]; for (int64 pickup : index_pair.first) { - if (Contains(pickup)) - continue; + if (Contains(pickup)) continue; for (int64 delivery : index_pair.second) { - if (Contains(delivery)) - continue; + if (Contains(delivery)) continue; const int64 pickup_penalty = GetUnperformedValue(pickup); const int64 delivery_penalty = GetUnperformedValue(delivery); const int64 penalty = @@ -3851,12 +3811,12 @@ void GlobalCheapestInsertionFilteredHeuristic:: InitializeInsertionEntriesPerformingPair( int64 pickup, int64 delivery, int64 penalty, AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::PairEntry> * - priority_queue, - std::vector * - pickup_to_entries, - std::vector * - delivery_to_entries) { + GlobalCheapestInsertionFilteredHeuristic::PairEntry> + *priority_queue, + std::vector + *pickup_to_entries, + std::vector + *delivery_to_entries) { if (!gci_params_.use_neighbors_ratio_for_initialization) { std::vector, std::pair > > valued_positions; @@ -3883,8 +3843,8 @@ void GlobalCheapestInsertionFilteredHeuristic:: } } } - for (const std::pair, std::pair > & - valued_position : valued_positions) { + for (const std::pair, std::pair > + &valued_position : valued_positions) { PairEntry *const entry = new PairEntry( pickup, valued_position.second.first, delivery, valued_position.second.second, valued_position.first.second); @@ -3920,8 +3880,7 @@ void GlobalCheapestInsertionFilteredHeuristic:: int64 delivery_insert_after = pickup; while (!model()->IsEnd(delivery_insert_after)) { const std::pair insertion_position = { - pickup_insert_after, delivery_insert_after - }; + pickup_insert_after, delivery_insert_after}; DCHECK(!gtl::ContainsKey(existing_insertion_positions, insertion_position)); existing_insertion_positions.insert(insertion_position); @@ -3988,12 +3947,12 @@ void GlobalCheapestInsertionFilteredHeuristic:: void GlobalCheapestInsertionFilteredHeuristic::UpdatePickupPositions( int vehicle, int64 pickup_insert_after, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::PairEntry> *priority_queue, - std::vector * - pickup_to_entries, - std::vector * - delivery_to_entries) { + AdjustablePriorityQueue + *priority_queue, + std::vector + *pickup_to_entries, + std::vector + *delivery_to_entries) { // First, remove entries which have already been inserted and keep track of // the entries which are being kept and must be updated. using Pair = std::pair; @@ -4008,10 +3967,9 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdatePickupPositions( Contains(pair_entry->delivery_to_insert())) { to_remove.push_back(pair_entry); } else { - existing_insertions.insert({ - { pair_entry->pickup_to_insert(), pair_entry->delivery_to_insert() } - , pair_entry->delivery_insert_after() - }); + existing_insertions.insert( + {{pair_entry->pickup_to_insert(), pair_entry->delivery_to_insert()}, + pair_entry->delivery_insert_after()}); } } for (PairEntry *const pair_entry : to_remove) { @@ -4036,8 +3994,8 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdatePickupPositions( } int64 delivery_insert_after = pickup; while (!model()->IsEnd(delivery_insert_after)) { - const std::pair insertion = { { pickup, delivery }, - delivery_insert_after }; + const std::pair insertion = {{pickup, delivery}, + delivery_insert_after}; if (!gtl::ContainsKey(existing_insertions, insertion)) { PairEntry *const entry = new PairEntry(pickup, pickup_insert_after, delivery, @@ -4065,9 +4023,9 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdatePickupPositions( const int64 pickup_value = GetInsertionCostForNodeAtPosition( pickup, pickup_insert_after, pickup_insert_before, vehicle); const int64 delivery_insert_after = pair_entry->delivery_insert_after(); - const int64 delivery_insert_before = - (delivery_insert_after == pickup) ? pickup_insert_before - : Value(delivery_insert_after); + const int64 delivery_insert_before = (delivery_insert_after == pickup) + ? pickup_insert_before + : Value(delivery_insert_after); const int64 delivery_value = GetInsertionCostForNodeAtPosition( delivery, delivery_insert_after, delivery_insert_before, vehicle); const int64 penalty = @@ -4086,12 +4044,12 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdatePickupPositions( void GlobalCheapestInsertionFilteredHeuristic::UpdateDeliveryPositions( int vehicle, int64 delivery_insert_after, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::PairEntry> *priority_queue, - std::vector * - pickup_to_entries, - std::vector * - delivery_to_entries) { + AdjustablePriorityQueue + *priority_queue, + std::vector + *pickup_to_entries, + std::vector + *delivery_to_entries) { // First, remove entries which have already been inserted and keep track of // the entries which are being kept and must be updated. using Pair = std::pair; @@ -4106,10 +4064,9 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdateDeliveryPositions( Contains(pair_entry->delivery_to_insert())) { to_remove.push_back(pair_entry); } else { - existing_insertions.insert({ - { pair_entry->pickup_to_insert(), pair_entry->delivery_to_insert() } - , pair_entry->pickup_insert_after() - }); + existing_insertions.insert( + {{pair_entry->pickup_to_insert(), pair_entry->delivery_to_insert()}, + pair_entry->pickup_insert_after()}); } } for (PairEntry *const pair_entry : to_remove) { @@ -4135,8 +4092,8 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdateDeliveryPositions( } int64 pickup_insert_after = model()->Start(vehicle); while (pickup_insert_after != delivery_insert_after) { - std::pair insertion = { { pickup, delivery }, - pickup_insert_after }; + std::pair insertion = {{pickup, delivery}, + pickup_insert_after}; if (!gtl::ContainsKey(existing_insertions, insertion)) { PairEntry *const entry = new PairEntry(pickup, pickup_insert_after, delivery, @@ -4178,8 +4135,8 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdateDeliveryPositions( void GlobalCheapestInsertionFilteredHeuristic::DeletePairEntry( GlobalCheapestInsertionFilteredHeuristic::PairEntry *entry, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::PairEntry> *priority_queue, + AdjustablePriorityQueue + *priority_queue, std::vector *pickup_to_entries, std::vector *delivery_to_entries) { priority_queue->Remove(entry); @@ -4194,10 +4151,10 @@ void GlobalCheapestInsertionFilteredHeuristic::DeletePairEntry( void GlobalCheapestInsertionFilteredHeuristic::InitializePositions( const std::vector &nodes, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::NodeEntry> *priority_queue, - std::vector * - position_to_node_entries, + AdjustablePriorityQueue + *priority_queue, + std::vector + *position_to_node_entries, const absl::flat_hash_set &vehicles) { priority_queue->Clear(); position_to_node_entries->clear(); @@ -4233,10 +4190,10 @@ void GlobalCheapestInsertionFilteredHeuristic:: InitializeInsertionEntriesPerformingNode( int64 node, int64 penalty, const absl::flat_hash_set &vehicles, AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::NodeEntry> * - priority_queue, - std::vector * - position_to_node_entries) { + GlobalCheapestInsertionFilteredHeuristic::NodeEntry> + *priority_queue, + std::vector + *position_to_node_entries) { const int num_vehicles = vehicles.empty() ? model()->vehicles() : vehicles.size(); if (!gci_params_.use_neighbors_ratio_for_initialization) { @@ -4263,12 +4220,11 @@ void GlobalCheapestInsertionFilteredHeuristic:: // the node. absl::flat_hash_set vehicles_to_consider; const bool all_vehicles = (num_vehicles == model()->vehicles()); - const auto insert_on_vehicle_for_cost_class = - [this, &vehicles, all_vehicles](int v, int cost_class) { + const auto insert_on_vehicle_for_cost_class = [this, &vehicles, all_vehicles]( + int v, int cost_class) { return (model()->GetCostClassIndexOfVehicle(v).value() == cost_class) && (all_vehicles || vehicles.contains(v)); - } - ; + }; for (int cost_class = 0; cost_class < model()->GetCostClassesCount(); cost_class++) { for (const std::vector *const neighbors : @@ -4297,10 +4253,10 @@ void GlobalCheapestInsertionFilteredHeuristic:: void GlobalCheapestInsertionFilteredHeuristic::UpdatePositions( const std::vector &nodes, int vehicle, int64 insert_after, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::NodeEntry> *priority_queue, - std::vector * - node_entries) { + AdjustablePriorityQueue + *priority_queue, + std::vector + *node_entries) { // Either create new entries if we are inserting after a newly inserted node // or remove entries which have already been inserted. bool update = true; @@ -4353,8 +4309,8 @@ void GlobalCheapestInsertionFilteredHeuristic::UpdatePositions( void GlobalCheapestInsertionFilteredHeuristic::DeleteNodeEntry( GlobalCheapestInsertionFilteredHeuristic::NodeEntry *entry, - AdjustablePriorityQueue< - GlobalCheapestInsertionFilteredHeuristic::NodeEntry> *priority_queue, + AdjustablePriorityQueue + *priority_queue, std::vector *node_entries) { priority_queue->Remove(entry); if (entry->insert_after() != -1) { @@ -4401,8 +4357,7 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() { if (Contains(delivery)) { continue; } - if (StopSearch()) - return false; + if (StopSearch()) return false; visited[pickup] = true; visited[delivery] = true; ComputeEvaluatorSortedPositions(pickup, &insertion_positions); @@ -4418,8 +4373,8 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() { (delivery_insertion == pickup_insertion) ? pickup : (delivery_insertion == pickup) - ? pickup_insertion_next - : Value(delivery_insertion); + ? pickup_insertion_next + : Value(delivery_insertion); InsertBetween(delivery, delivery_insertion, delivery_insertion_next); if (Commit()) { @@ -4441,12 +4396,10 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() { while (!node_queue.empty()) { const int node = node_queue.top().second; node_queue.pop(); - if (Contains(node) || visited[node]) - continue; + if (Contains(node) || visited[node]) continue; ComputeEvaluatorSortedPositions(node, &insertion_positions); for (const int64 insertion : insertion_positions) { - if (StopSearch()) - return false; + if (StopSearch()) return false; InsertBetween(node, insertion, Value(insertion)); if (Commit()) { break; @@ -4541,8 +4494,8 @@ bool CheapestAdditionFilteredHeuristic::BuildSolutionInternal() { found = false; std::vector neighbors; if (index < model()->Nexts().size()) { - std::unique_ptr it(model()->Nexts()[index] - ->MakeDomainIterator(false)); + std::unique_ptr it( + model()->Nexts()[index]->MakeDomainIterator(false)); auto next_values = InitAndGetValues(it.get()); neighbors = GetPossibleNextsFromIterator(index, next_values.begin(), next_values.end()); @@ -4550,14 +4503,14 @@ bool CheapestAdditionFilteredHeuristic::BuildSolutionInternal() { for (int i = 0; !found && i < neighbors.size(); ++i) { int64 next = -1; switch (i) { - case 0: - next = FindTopSuccessor(index, neighbors); - break; - case 1: - SortSuccessors(index, &neighbors); - ABSL_FALLTHROUGH_INTENDED; - default: - next = neighbors[i]; + case 0: + next = FindTopSuccessor(index, neighbors); + break; + case 1: + SortSuccessors(index, &neighbors); + ABSL_FALLTHROUGH_INTENDED; + default: + next = neighbors[i]; } if (model()->IsEnd(next) && next != end) { continue; @@ -4580,21 +4533,19 @@ bool CheapestAdditionFilteredHeuristic::BuildSolutionInternal() { next_deliveries = GetPossibleNextsFromIterator( next, deliveries[next].begin(), deliveries[next].end()); } - if (next_deliveries.empty()) - next_deliveries = { kUnassigned }; + if (next_deliveries.empty()) next_deliveries = {kUnassigned}; for (int j = 0; !found && j < next_deliveries.size(); ++j) { - if (StopSearch()) - return false; + if (StopSearch()) return false; int delivery = -1; switch (j) { - case 0: - delivery = FindTopSuccessor(next, next_deliveries); - break; - case 1: - SortSuccessors(next, &next_deliveries); - ABSL_FALLTHROUGH_INTENDED; - default: - delivery = next_deliveries[j]; + case 0: + delivery = FindTopSuccessor(next, next_deliveries); + break; + case 1: + SortSuccessors(next, &next_deliveries); + ABSL_FALLTHROUGH_INTENDED; + default: + delivery = next_deliveries[j]; } // Insert "next" after "index", and before "end" if it is not the // end already. @@ -4673,11 +4624,9 @@ void EvaluatorCheapestAdditionFilteredHeuristic::SortSuccessors( std::vector > values; values.reserve(successors->size()); for (int64 successor : *successors) { - // Tie-breaking on largest node index to mimic the behavior of - // CheapestValueSelector (search.cc). - values.push_back({ - evaluator_(node, successor), -successor - }); + // Tie-breaking on largest node index to mimic the behavior of + // CheapestValueSelector (search.cc). + values.push_back({evaluator_(node, successor), -successor}); } std::sort(values.begin(), values.end()); successors->clear(); @@ -4699,16 +4648,16 @@ int64 ComparatorCheapestAdditionFilteredHeuristic::FindTopSuccessor( int64 node, const std::vector &successors) { return *std::min_element(successors.begin(), successors.end(), [this, node](int successor1, int successor2) { - return comparator_(node, successor1, successor2); - }); + return comparator_(node, successor1, successor2); + }); } void ComparatorCheapestAdditionFilteredHeuristic::SortSuccessors( int64 node, std::vector *successors) { std::sort(successors->begin(), successors->end(), [this, node](int successor1, int successor2) { - return comparator_(node, successor1, successor2); - }); + return comparator_(node, successor1, successor2); + }); } // Class storing and allowing access to the savings according to the number of @@ -4759,13 +4708,17 @@ void ComparatorCheapestAdditionFilteredHeuristic::SortSuccessors( // ReinjectSkippedSavingsStartingAt() (or ReinjectSkippedSavingsEndingAt()). // Then, when calling GetSaving(), we iterate through the reinjected Savings in // order of insertion in the vectors while there are reinjected savings. -template class SavingsFilteredHeuristic::SavingsContainer { -public: +template +class SavingsFilteredHeuristic::SavingsContainer { + public: explicit SavingsContainer(const SavingsFilteredHeuristic *savings_db, int vehicle_types) - : savings_db_(savings_db), vehicle_types_(vehicle_types), - index_in_sorted_savings_(0), single_vehicle_type_(vehicle_types == 1), - using_incoming_reinjected_saving_(false), sorted_(false), + : savings_db_(savings_db), + vehicle_types_(vehicle_types), + index_in_sorted_savings_(0), + single_vehicle_type_(vehicle_types == 1), + using_incoming_reinjected_saving_(false), + sorted_(false), to_update_(true) {} void InitializeContainer(int64 size, int64 saving_neighbors) { @@ -4801,9 +4754,8 @@ public: CHECK(!sorted_savings_per_vehicle_type_.empty()) << "Container not initialized!"; sorted_savings_per_vehicle_type_[vehicle_type].push_back(saving); - UpdateArcIndicesCostsAndSavings(before_node, after_node, { - total_cost, saving - }); + UpdateArcIndicesCostsAndSavings(before_node, after_node, + {total_cost, saving}); } void Sort() { @@ -4817,11 +4769,9 @@ public: const auto &savings = sorted_savings_per_vehicle_type_[0]; sorted_savings_.resize(savings.size()); std::transform(savings.begin(), savings.end(), sorted_savings_.begin(), - [](const Saving & saving) { - return SavingAndArc({ - saving, /*arc_index*/ -1 - }); - }); + [](const Saving &saving) { + return SavingAndArc({saving, /*arc_index*/ -1}); + }); } else { // For each arc, sort the savings by decreasing total cost // start-->a-->b-->end. @@ -4835,11 +4785,10 @@ public: costs_and_savings_per_arc_[arc_index]; DCHECK(!costs_and_savings.empty()); - std::sort(costs_and_savings.begin(), costs_and_savings.end(), - [](const std::pair & cs1, - const std::pair & cs2) { - return cs1 > cs2; - }); + std::sort( + costs_and_savings.begin(), costs_and_savings.end(), + [](const std::pair &cs1, + const std::pair &cs2) { return cs1 > cs2; }); // Insert all Savings for this arc with the lowest cost into // sorted_savings_. @@ -4847,18 +4796,15 @@ public: const int64 cost = costs_and_savings.back().first; while (!costs_and_savings.empty() && costs_and_savings.back().first == cost) { - sorted_savings_.push_back({ - costs_and_savings.back().second, arc_index - }); + sorted_savings_.push_back( + {costs_and_savings.back().second, arc_index}); costs_and_savings.pop_back(); } } std::sort(sorted_savings_.begin(), sorted_savings_.end()); next_saving_type_and_index_for_arc_.clear(); next_saving_type_and_index_for_arc_.resize( - costs_and_savings_per_arc_.size(), { - -1, -1 - }); + costs_and_savings_per_arc_.size(), {-1, -1}); } sorted_ = true; index_in_sorted_savings_ = 0; @@ -4923,9 +4869,7 @@ public: std::sort(sorted_savings_.begin(), sorted_savings_.end()); next_saving_type_and_index_for_arc_.clear(); next_saving_type_and_index_for_arc_.resize( - costs_and_savings_per_arc_.size(), { - -1, -1 - }); + costs_and_savings_per_arc_.size(), {-1, -1}); } } UpdateReinjectedSavings(); @@ -4953,7 +4897,7 @@ public: incoming_new_reinjected_savings_ = &(skipped_savings_ending_at_[node]); } -private: + private: struct SavingAndArc { Saving saving; int64 arc_index; @@ -5018,13 +4962,11 @@ private: type_and_index.first = savings_db_->GetVehicleTypeFromSaving(next_saving); if (previous_index >= 0) { // Update the previous saving. - next_savings_[previous_index] = { next_saving, arc_index }; + next_savings_[previous_index] = {next_saving, arc_index}; } else { // Insert the new next Saving for this arc. type_and_index.second = next_savings_.size(); - next_savings_.push_back({ - next_saving, arc_index - }); + next_savings_.push_back({next_saving, arc_index}); } next_saving_added = true; } @@ -5037,9 +4979,7 @@ private: // Skip the Saving with the correct type, already added to next_savings_ // if it was found. if (next_saving_added) { - SkipSavingForArc({ - next_saving, arc_index - }); + SkipSavingForArc({next_saving, arc_index}); } } } @@ -5055,10 +4995,10 @@ private: outgoing_new_reinjected_savings_ = nullptr; } - void - UpdateGivenReinjectedSavings(std::deque *new_reinjected_savings, - std::deque **reinjected_savings, - bool using_reinjected_savings) { + void UpdateGivenReinjectedSavings( + std::deque *new_reinjected_savings, + std::deque **reinjected_savings, + bool using_reinjected_savings) { if (new_reinjected_savings == nullptr) { // No new reinjected savings, update the previous ones if needed. if (*reinjected_savings != nullptr && using_reinjected_savings) { @@ -5100,9 +5040,7 @@ private: std::make_pair(after_node, costs_and_savings_per_arc_.size())); const int index = arc_inserted.first->second; if (arc_inserted.second) { - costs_and_savings_per_arc_.push_back({ - cost_and_saving - }); + costs_and_savings_per_arc_.push_back({cost_and_saving}); } else { DCHECK_LT(index, costs_and_savings_per_arc_.size()); costs_and_savings_per_arc_[index].push_back(cost_and_saving); @@ -5157,7 +5095,8 @@ SavingsFilteredHeuristic::SavingsFilteredHeuristic( RoutingModel *model, const RoutingIndexManager *manager, SavingsParameters parameters, LocalSearchFilterManager *filter_manager) : RoutingFilteredHeuristic(model, filter_manager), - vehicle_type_curator_(nullptr), manager_(manager), + vehicle_type_curator_(nullptr), + manager_(manager), savings_params_(parameters) { DCHECK_GT(savings_params_.neighbors_ratio, 0); DCHECK_LE(savings_params_.neighbors_ratio, 1); @@ -5197,8 +5136,7 @@ int SavingsFilteredHeuristic::StartNewRouteWithBestVehicleOfType( SetValue(before_node, after_node); SetValue(after_node, end); return Commit(); - } - ; + }; const int vehicle = vehicle_type_curator_->GetCompatibleVehicleOfType( type, vehicle_is_compatible); @@ -5217,10 +5155,10 @@ void SavingsFilteredHeuristic::AddSymmetricArcsToAdjacencyLists( } std::transform(adjacency_lists->begin(), adjacency_lists->end(), adjacency_lists->begin(), [](std::vector vec) { - std::sort(vec.begin(), vec.end()); - vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); - return vec; - }); + std::sort(vec.begin(), vec.end()); + vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); + return vec; + }); } // Computes the savings related to each pair of non-start and non-end nodes. @@ -5291,8 +5229,8 @@ void SavingsFilteredHeuristic::ComputeSavings() { std::transform(costed_after_nodes.begin(), costed_after_nodes.end(), adjacency_lists[before_node].begin(), [](std::pair cost_and_node) { - return cost_and_node.second; - }); + return cost_and_node.second; + }); } if (savings_params_.add_reverse_arcs) { AddSymmetricArcsToAdjacencyLists(&adjacency_lists); @@ -5341,8 +5279,8 @@ void SavingsFilteredHeuristic::ComputeSavings() { savings_container_->Sort(); } -int64 -SavingsFilteredHeuristic::MaxNumNeighborsPerNode(int num_vehicle_types) const { +int64 SavingsFilteredHeuristic::MaxNumNeighborsPerNode( + int num_vehicle_types) const { const int64 size = model()->Size(); const int64 num_neighbors_with_ratio = @@ -5436,8 +5374,7 @@ void SequentialSavingsFilteredHeuristic::BuildRoutesFromSavings() { while (in_index < in_savings_ptr[saving_offset + after_node].size() || out_index < out_savings_ptr[saving_offset + before_node].size()) { - if (StopSearch()) - return; + if (StopSearch()) return; // First determine how to extend the route. int before_before_node = -1; int after_after_node = -1; @@ -5537,8 +5474,7 @@ void ParallelSavingsFilteredHeuristic::BuildRoutesFromSavings() { } while (savings_container_->HasSaving()) { - if (StopSearch()) - return; + if (StopSearch()) return; const Saving saving = savings_container_->GetSaving(); const int64 before_node = GetBeforeNodeFromSaving(saving); const int64 after_node = GetAfterNodeFromSaving(saving); @@ -5660,8 +5596,7 @@ void ParallelSavingsFilteredHeuristic::MergeRoutes(int first_vehicle, int second_vehicle, int64 before_node, int64 after_node) { - if (StopSearch()) - return; + if (StopSearch()) return; const int64 new_first_node = first_node_on_route_[first_vehicle]; DCHECK_EQ(vehicle_of_first_or_last_node_[new_first_node], first_vehicle); CHECK_EQ(Value(model()->Start(first_vehicle)), new_first_node); @@ -5762,15 +5697,14 @@ bool ChristofidesFilteredHeuristic::BuildSolutionInternal() { // TODO(user): Investigate if ChristofidesPathSolver should not // return a status to bail out fast in case of problem. return std::min(cost, kint64max / 2); - } - ; + }; using Cost = decltype(cost); ChristofidesPathSolver christofides_solver( indices.size(), cost); if (use_minimum_matching_) { - christofides_solver.SetMatchingAlgorithm(ChristofidesPathSolver< - int64, int64, int, - Cost>::MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING); + christofides_solver.SetMatchingAlgorithm( + ChristofidesPathSolver::MatchingAlgorithm:: + MINIMUM_WEIGHT_MATCHING); } path_per_cost_class[cost_class] = christofides_solver.TravelingSalesmanPath(); @@ -5787,8 +5721,7 @@ bool ChristofidesFilteredHeuristic::BuildSolutionInternal() { int prev = GetStartChainEnd(vehicle); const int end = model()->End(vehicle); for (int i = 1; i < path.size() - 1 && prev != end; ++i) { - if (StopSearch()) - return false; + if (StopSearch()) return false; int next = indices[path[i]]; if (!Contains(next)) { SetValue(prev, next); @@ -5806,12 +5739,12 @@ bool ChristofidesFilteredHeuristic::BuildSolutionInternal() { namespace { // The description is in routing.h:MakeGuidedSlackFinalizer class GuidedSlackFinalizer : public DecisionBuilder { -public: + public: GuidedSlackFinalizer(const RoutingDimension *dimension, RoutingModel *model, std::function initializer); Decision *Next(Solver *solver) override; -private: + private: int64 SelectValue(int64 index); int64 ChooseVariable(); @@ -5830,11 +5763,13 @@ private: GuidedSlackFinalizer::GuidedSlackFinalizer( const RoutingDimension *dimension, RoutingModel *model, std::function initializer) - : dimension_(ABSL_DIE_IF_NULL(dimension)), model_(ABSL_DIE_IF_NULL(model)), + : dimension_(ABSL_DIE_IF_NULL(dimension)), + model_(ABSL_DIE_IF_NULL(model)), initializer_(std::move(initializer)), is_initialized_(dimension->slacks().size(), false), initial_values_(dimension->slacks().size(), kint64min), - current_index_(model_->Start(0)), current_route_(0), + current_index_(model_->Start(0)), + current_route_(0), last_delta_used_(dimension->slacks().size(), 0) {} Decision *GuidedSlackFinalizer::Next(Solver *solver) { @@ -5857,8 +5792,9 @@ Decision *GuidedSlackFinalizer::Next(Solver *solver) { int64 GuidedSlackFinalizer::SelectValue(int64 index) { const IntVar *const slack_variable = dimension_->SlackVar(index); const int64 center = initial_values_[index]; - const int64 max_delta = std::max(center - slack_variable->Min(), - slack_variable->Max() - center) + 1; + const int64 max_delta = + std::max(center - slack_variable->Min(), slack_variable->Max() - center) + + 1; int64 delta = last_delta_used_[index]; // The sequence of deltas is 0, 1, -1, 2, -2 ... @@ -5903,7 +5839,7 @@ int64 GuidedSlackFinalizer::ChooseVariable() { return -1; } } -} // namespace +} // namespace DecisionBuilder *RoutingModel::MakeGuidedSlackFinalizer( const RoutingDimension *dimension, @@ -5926,13 +5862,16 @@ int64 RoutingDimension::ShortestTransitionSlack(int64 node) const { const int64 serving_vehicle = model_->VehicleVar(node)->Value(); CHECK_EQ(serving_vehicle, model_->VehicleVar(next)->Value()); const RoutingModel::StateDependentTransit transit_from_next = - model_->StateDependentTransitCallback(state_dependent_class_evaluators_[ - state_dependent_vehicle_to_class_[serving_vehicle]])(next, next_next); + model_->StateDependentTransitCallback( + state_dependent_class_evaluators_ + [state_dependent_vehicle_to_class_[serving_vehicle]])(next, + next_next); // We have that transit[i+1] is a function of cumul[i+1]. const int64 next_cumul_min = CumulVar(next)->Min(); const int64 next_cumul_max = CumulVar(next)->Max(); - const int64 optimal_next_cumul = transit_from_next.transit_plus_identity - ->RangeMinArgument(next_cumul_min, next_cumul_max + 1); + const int64 optimal_next_cumul = + transit_from_next.transit_plus_identity->RangeMinArgument( + next_cumul_min, next_cumul_max + 1); // A few checks to make sure we're on the same page. DCHECK_LE(next_cumul_min, optimal_next_cumul); DCHECK_LE(optimal_next_cumul, next_cumul_max); @@ -5944,12 +5883,15 @@ int64 RoutingDimension::ShortestTransitionSlack(int64 node) const { const int64 current_state_independent_transit = model_->TransitCallback( class_evaluators_[vehicle_to_class_[serving_vehicle]])(node, next); const int64 current_state_dependent_transit = - model_->StateDependentTransitCallback(state_dependent_class_evaluators_[ - state_dependent_vehicle_to_class_[serving_vehicle]])(node, next) + model_ + ->StateDependentTransitCallback( + state_dependent_class_evaluators_ + [state_dependent_vehicle_to_class_[serving_vehicle]])(node, + next) .transit->Query(current_cumul); - const int64 optimal_slack = - optimal_next_cumul - current_cumul - current_state_independent_transit - - current_state_dependent_transit; + const int64 optimal_slack = optimal_next_cumul - current_cumul - + current_state_independent_transit - + current_state_dependent_transit; CHECK_LE(SlackVar(node)->Min(), optimal_slack); CHECK_LE(optimal_slack, SlackVar(node)->Max()); return optimal_slack; @@ -5957,13 +5899,13 @@ int64 RoutingDimension::ShortestTransitionSlack(int64 node) const { namespace { class GreedyDescentLSOperator : public LocalSearchOperator { -public: + public: explicit GreedyDescentLSOperator(std::vector variables); bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override; void Start(const Assignment *assignment) override; -private: + private: int64 FindMaxDistanceToDomain(const Assignment *assignment); const std::vector variables_; @@ -5982,12 +5924,14 @@ private: GreedyDescentLSOperator::GreedyDescentLSOperator( std::vector variables) - : variables_(std::move(variables)), center_(nullptr), current_step_(0), + : variables_(std::move(variables)), + center_(nullptr), + current_step_(0), current_direction_(0) {} bool GreedyDescentLSOperator::MakeNextNeighbor(Assignment *delta, - Assignment */*deltadelta*/) { - static const int64 sings[] = { 1, -1 }; + Assignment * /*deltadelta*/) { + static const int64 sings[] = {1, -1}; for (; 1 <= current_step_; current_step_ /= 2) { for (; current_direction_ < 2 * variables_.size();) { const int64 variable_idx = current_direction_ / 2; @@ -6014,8 +5958,8 @@ void GreedyDescentLSOperator::Start(const Assignment *assignment) { center_ = assignment; } -int64 -GreedyDescentLSOperator::FindMaxDistanceToDomain(const Assignment *assignment) { +int64 GreedyDescentLSOperator::FindMaxDistanceToDomain( + const Assignment *assignment) { int64 result = kint64min; for (const IntVar *const var : variables_) { result = std::max(result, std::abs(var->Max() - assignment->Value(var))); @@ -6023,10 +5967,10 @@ GreedyDescentLSOperator::FindMaxDistanceToDomain(const Assignment *assignment) { } return result; } -} // namespace +} // namespace -std::unique_ptr -RoutingModel::MakeGreedyDescentLSOperator(std::vector variables) { +std::unique_ptr RoutingModel::MakeGreedyDescentLSOperator( + std::vector variables) { return std::unique_ptr( new GreedyDescentLSOperator(std::move(variables))); } @@ -6037,8 +5981,7 @@ DecisionBuilder *RoutingModel::MakeSelfDependentDimensionFinalizer( CHECK(dimension->base_dimension() == dimension); std::function slack_guide = [dimension](int64 index) { return dimension->ShortestTransitionSlack(index); - } - ; + }; DecisionBuilder *const guided_finalizer = MakeGuidedSlackFinalizer(dimension, slack_guide); DecisionBuilder *const slacks_finalizer = @@ -6061,4 +6004,4 @@ DecisionBuilder *RoutingModel::MakeSelfDependentDimensionFinalizer( solver_->MakeLocalSearchPhase(first_solution, parameters); return finalizer; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/routing_types.h b/ortools/constraint_solver/routing_types.h index e66d22343a..a7a96feabe 100644 --- a/ortools/constraint_solver/routing_types.h +++ b/ortools/constraint_solver/routing_types.h @@ -44,6 +44,6 @@ typedef std::function RoutingTransitCallback2; typedef std::pair, std::vector > RoutingIndexPair; typedef std::vector RoutingIndexPairs; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_TYPES_H_ +#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_TYPES_H_ diff --git a/ortools/constraint_solver/samples/tsp_cities_routes.cc b/ortools/constraint_solver/samples/tsp_cities_routes.cc index e77f48ec2c..8faa50db8f 100644 --- a/ortools/constraint_solver/samples/tsp_cities_routes.cc +++ b/ortools/constraint_solver/samples/tsp_cities_routes.cc @@ -114,9 +114,9 @@ void Tsp() { // [START get_routes] // Get the routes and convert indices to nodes. std::vector> routes; - for (const std::vector& - route_indices : routing.GetRoutesFromAssignment(*solution)) { - routes.push_back(manager.IndicesToNodes(route_indices)); + for (const std::vector& route_indices : + routing.GetRoutesFromAssignment(*solution)) { + routes.push_back(manager.IndicesToNodes(route_indices)); } // [END get_routes] diff --git a/ortools/constraint_solver/samples/vrp_routes.cc b/ortools/constraint_solver/samples/vrp_routes.cc index 4d32e4f87b..344e21cf94 100644 --- a/ortools/constraint_solver/samples/vrp_routes.cc +++ b/ortools/constraint_solver/samples/vrp_routes.cc @@ -138,9 +138,9 @@ void Vrp() { // [START get_routes] // Get the routes and convert indices to nodes. std::vector> routes; - for (const std::vector& - route_indices : routing.GetRoutesFromAssignment(*solution)) { - routes.push_back(manager.IndicesToNodes(route_indices)); + for (const std::vector& route_indices : + routing.GetRoutesFromAssignment(*solution)) { + routes.push_back(manager.IndicesToNodes(route_indices)); } // [END get_routes] diff --git a/ortools/constraint_solver/sched_constraints.cc b/ortools/constraint_solver/sched_constraints.cc index b27d287c24..76fa35533c 100644 --- a/ortools/constraint_solver/sched_constraints.cc +++ b/ortools/constraint_solver/sched_constraints.cc @@ -35,17 +35,15 @@ namespace operations_research { namespace { class TreeArrayConstraint : public Constraint { -public: - enum PerformedStatus { - UNPERFORMED, - PERFORMED, - UNDECIDED - }; + public: + enum PerformedStatus { UNPERFORMED, PERFORMED, UNDECIDED }; TreeArrayConstraint(Solver *const solver, const std::vector &vars, IntervalVar *const target_var) - : Constraint(solver), vars_(vars), target_var_(target_var), + : Constraint(solver), + vars_(vars), + target_var_(target_var), block_size_(solver->parameters().array_split_size()) { std::vector lengths; lengths.push_back(vars_.size()); @@ -112,8 +110,8 @@ public: tree_[depth][position].start_max.SetValue(solver(), start_max); tree_[depth][position].end_min.SetValue(solver(), end_min); tree_[depth][position].end_max.SetValue(solver(), end_max); - tree_[depth][position].performed - .SetValue(solver(), static_cast(performed)); + tree_[depth][position].performed.SetValue(solver(), + static_cast(performed)); } int64 StartMin(int depth, int position) const { @@ -227,14 +225,17 @@ public: int Width(int depth) const { return tree_[depth].size(); } -protected: + protected: const std::vector vars_; IntervalVar *const target_var_; -private: + private: struct NodeInfo { NodeInfo() - : start_min(0), start_max(0), end_min(0), end_max(0), + : start_min(0), + start_max(0), + end_min(0), + end_max(0), performed(UNDECIDED) {} Rev start_min; @@ -251,7 +252,7 @@ private: // This constraint implements cover(vars) == cover_var. class CoverConstraint : public TreeArrayConstraint { -public: + public: CoverConstraint(Solver *const solver, const std::vector &vars, IntervalVar *const cover_var) : TreeArrayConstraint(solver, vars, cover_var), cover_demon_(nullptr) {} @@ -302,16 +303,16 @@ public: void PropagateRoot() { // Propagate from the root of the tree to the target var. switch (RootPerformed()) { - case UNPERFORMED: - target_var_->SetPerformed(false); - break; - case PERFORMED: - target_var_->SetPerformed(true); - ABSL_FALLTHROUGH_INTENDED; - case UNDECIDED: - target_var_->SetStartRange(RootStartMin(), RootStartMax()); - target_var_->SetEndRange(RootEndMin(), RootEndMax()); - break; + case UNPERFORMED: + target_var_->SetPerformed(false); + break; + case PERFORMED: + target_var_->SetPerformed(true); + ABSL_FALLTHROUGH_INTENDED; + case UNDECIDED: + target_var_->SetStartRange(RootStartMin(), RootStartMax()); + target_var_->SetEndRange(RootEndMin(), RootEndMax()); + break; } // Check if we need to propagate back. This is useful in case the // target var is performed and only one last interval var may be @@ -340,15 +341,15 @@ public: // Leaf node -> push to leaf var. if (IsLeaf(depth)) { switch (performed) { - case UNPERFORMED: - vars_[position]->SetPerformed(false); - break; - case PERFORMED: - vars_[position]->SetPerformed(true); - ABSL_FALLTHROUGH_INTENDED; - case UNDECIDED: - vars_[position]->SetStartRange(new_start_min, new_start_max); - vars_[position]->SetEndRange(new_end_min, new_end_max); + case UNPERFORMED: + vars_[position]->SetPerformed(false); + break; + case PERFORMED: + vars_[position]->SetPerformed(true); + ABSL_FALLTHROUGH_INTENDED; + case UNDECIDED: + vars_[position]->SetStartRange(new_start_min, new_start_max); + vars_[position]->SetEndRange(new_end_min, new_end_max); } return; } @@ -357,35 +358,47 @@ public: const int block_end = ChildEnd(depth, position); switch (performed) { - case UNPERFORMED: { // Mark all node unperformed. - for (int i = block_start; i <= block_end; ++i) { - PushDown(depth + 1, i, new_start_min, new_start_max, new_end_min, - new_end_max, UNPERFORMED); - } - break; - } - case PERFORMED: { // Count number of undecided or performed; - int candidate = -1; - int may_be_performed_count = 0; - int must_be_performed_count = 0; - for (int i = block_start; i <= block_end; ++i) { - switch (Performed(depth + 1, i)) { - case UNPERFORMED: - break; - case PERFORMED: - must_be_performed_count++; - ABSL_FALLTHROUGH_INTENDED; - case UNDECIDED: - may_be_performed_count++; - candidate = i; + case UNPERFORMED: { // Mark all node unperformed. + for (int i = block_start; i <= block_end; ++i) { + PushDown(depth + 1, i, new_start_min, new_start_max, new_end_min, + new_end_max, UNPERFORMED); } + break; } - if (may_be_performed_count == 0) { - solver()->Fail(); - } else if (may_be_performed_count == 1) { - PushDown(depth + 1, candidate, new_start_min, new_start_max, - new_end_min, new_end_max, PERFORMED); - } else { + case PERFORMED: { // Count number of undecided or performed; + int candidate = -1; + int may_be_performed_count = 0; + int must_be_performed_count = 0; + for (int i = block_start; i <= block_end; ++i) { + switch (Performed(depth + 1, i)) { + case UNPERFORMED: + break; + case PERFORMED: + must_be_performed_count++; + ABSL_FALLTHROUGH_INTENDED; + case UNDECIDED: + may_be_performed_count++; + candidate = i; + } + } + if (may_be_performed_count == 0) { + solver()->Fail(); + } else if (may_be_performed_count == 1) { + PushDown(depth + 1, candidate, new_start_min, new_start_max, + new_end_min, new_end_max, PERFORMED); + } else { + for (int i = block_start; i <= block_end; ++i) { + // Since there are more than 1 active child node, we + // cannot propagate on new_start_max and new_end_min. Thus + // we substitute them with safe bounds e.g. new_end_max + // and new_start_min. + PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min, + new_end_max, UNDECIDED); + } + } + break; + } + case UNDECIDED: { for (int i = block_start; i <= block_end; ++i) { // Since there are more than 1 active child node, we // cannot propagate on new_start_max and new_end_min. Thus @@ -395,18 +408,6 @@ public: new_end_max, UNDECIDED); } } - break; - } - case UNDECIDED: { - for (int i = block_start; i <= block_end; ++i) { - // Since there are more than 1 active child node, we - // cannot propagate on new_start_max and new_end_min. Thus - // we substitute them with safe bounds e.g. new_end_max - // and new_start_min. - PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min, - new_end_max, UNDECIDED); - } - } } } @@ -480,7 +481,7 @@ public: AcceptInternal(ModelVisitor::kCover, visitor); } -private: + private: PerformedStatus ComputePropagationUp(int parent_depth, int parent_position, int64 *const bucket_start_min, int64 *const bucket_start_max, @@ -526,7 +527,7 @@ private: }; class IntervalEquality : public Constraint { -public: + public: IntervalEquality(Solver *const solver, IntervalVar *const var1, IntervalVar *const var2) : Constraint(solver), var1_(var1), var2_(var2) {} @@ -575,11 +576,11 @@ public: visitor->EndVisitConstraint(ModelVisitor::kEquality, this); } -private: + private: IntervalVar *const var1_; IntervalVar *const var2_; }; -} // namespace +} // namespace Constraint *Solver::MakeCover(const std::vector &vars, IntervalVar *const target_var) { @@ -595,4 +596,4 @@ Constraint *Solver::MakeEquality(IntervalVar *const var1, IntervalVar *const var2) { return RevAlloc(new IntervalEquality(this, var1, var2)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/sched_expr.cc b/ortools/constraint_solver/sched_expr.cc index ee2a15791e..7cafa7f1d9 100644 --- a/ortools/constraint_solver/sched_expr.cc +++ b/ortools/constraint_solver/sched_expr.cc @@ -28,7 +28,7 @@ namespace operations_research { namespace { class IntervalVarStartExpr : public BaseIntExpr { -public: + public: explicit IntervalVarStartExpr(IntervalVar *const i) : BaseIntExpr(i->solver()), interval_(i) {} ~IntervalVarStartExpr() override {} @@ -61,13 +61,13 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kStartExpr, this); } -private: + private: IntervalVar *interval_; DISALLOW_COPY_AND_ASSIGN(IntervalVarStartExpr); }; class IntervalVarEndExpr : public BaseIntExpr { -public: + public: explicit IntervalVarEndExpr(IntervalVar *const i) : BaseIntExpr(i->solver()), interval_(i) {} ~IntervalVarEndExpr() override {} @@ -100,13 +100,13 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kEndExpr, this); } -private: + private: IntervalVar *interval_; DISALLOW_COPY_AND_ASSIGN(IntervalVarEndExpr); }; class IntervalVarDurationExpr : public BaseIntExpr { -public: + public: explicit IntervalVarDurationExpr(IntervalVar *const i) : BaseIntExpr(i->solver()), interval_(i) {} ~IntervalVarDurationExpr() override {} @@ -141,11 +141,11 @@ public: visitor->EndVisitIntegerExpression(ModelVisitor::kDurationExpr, this); } -private: + private: IntervalVar *interval_; DISALLOW_COPY_AND_ASSIGN(IntervalVarDurationExpr); }; -} // namespace +} // namespace // ----- API ----- @@ -193,4 +193,4 @@ IntExpr *BuildSafeEndExpr(IntervalVar *var, int64 unperformed_value) { return var->solver()->MakeConditionalExpression( var->PerformedExpr()->Var(), var->EndExpr(), unperformed_value); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/sched_search.cc b/ortools/constraint_solver/sched_search.cc index 2ed40cc6fd..06a86b9305 100644 --- a/ortools/constraint_solver/sched_search.cc +++ b/ortools/constraint_solver/sched_search.cc @@ -27,7 +27,7 @@ namespace { int64 ValueToIndex(int64 value) { return value - 1; } int64 IndexToValue(int64 index) { return index + 1; } -} // namespace +} // namespace // ----- SequenceVar ----- @@ -38,7 +38,9 @@ SequenceVar::SequenceVar(Solver *const s, const std::vector &intervals, const std::vector &nexts, const std::string &name) - : PropagationBaseObject(s), intervals_(intervals), nexts_(nexts), + : PropagationBaseObject(s), + intervals_(intervals), + nexts_(nexts), previous_(nexts.size() + 1, -1) { set_name(name); } @@ -160,7 +162,7 @@ void SequenceVar::ComputeStatistics(int *const ranked, int *const not_ranked, last = previous_[last]; (*ranked)++; } - } else { // We counted the sentinel. + } else { // We counted the sentinel. (*ranked)--; } *not_ranked = intervals_.size() - *ranked - *unperformed; @@ -264,8 +266,8 @@ void SequenceVar::ComputePossibleFirstsAndLasts( void SequenceVar::RankSequence(const std::vector &rank_first, const std::vector &rank_last, const std::vector &unperformed) { - solver()->GetPropagationMonitor() - ->RankSequence(this, rank_first, rank_last, unperformed); + solver()->GetPropagationMonitor()->RankSequence(this, rank_first, rank_last, + unperformed); // Mark unperformed. for (const int value : unperformed) { intervals_[value]->SetPerformed(false); @@ -383,7 +385,7 @@ namespace { // Forward scheduling. // class ScheduleOrPostpone : public Decision { -public: + public: ScheduleOrPostpone(IntervalVar *const var, int64 est, int64 *const marker) : var_(var), est_(est), marker_(marker) {} ~ScheduleOrPostpone() override {} @@ -410,14 +412,14 @@ public: est_.Value()); } -private: + private: IntervalVar *const var_; NumericalRev est_; int64 *const marker_; }; class SetTimesForward : public DecisionBuilder { -public: + public: explicit SetTimesForward(const std::vector &vars) : vars_(vars), markers_(vars.size(), kint64min) {} @@ -443,7 +445,7 @@ public: } // TODO(user) : remove this crude quadratic loop with // reversibles range reduction. - if (support == -1) { // All intervals are either fixed or postponed. + if (support == -1) { // All intervals are either fixed or postponed. UnperformPostponedTaskBefore(kint64max); return nullptr; } @@ -461,7 +463,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension); } -private: + private: bool IsPostponed(int index) { DCHECK(vars_[index]->MayBePerformed()); return vars_[index]->StartMin() <= markers_[index]; @@ -493,7 +495,7 @@ private: // Backward scheduling. // class ScheduleOrExpedite : public Decision { -public: + public: ScheduleOrExpedite(IntervalVar *const var, int64 est, int64 *const marker) : var_(var), est_(est), marker_(marker) {} ~ScheduleOrExpedite() override {} @@ -520,14 +522,14 @@ public: est_.Value()); } -private: + private: IntervalVar *const var_; NumericalRev est_; int64 *const marker_; }; class SetTimesBackward : public DecisionBuilder { -public: + public: explicit SetTimesBackward(const std::vector &vars) : vars_(vars), markers_(vars.size(), kint64max) {} @@ -574,7 +576,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension); } -private: + private: const std::vector vars_; std::vector markers_; }; @@ -582,7 +584,7 @@ private: // ----- Decisions and DecisionBuilders on sequences ----- class RankFirst : public Decision { -public: + public: RankFirst(SequenceVar *const seq, int index) : sequence_(seq), index_(index) {} ~RankFirst() override {} @@ -601,13 +603,13 @@ public: index_); } -private: + private: SequenceVar *const sequence_; const int index_; }; class RankLast : public Decision { -public: + public: RankLast(SequenceVar *const seq, int index) : sequence_(seq), index_(index) {} ~RankLast() override {} @@ -625,13 +627,13 @@ public: index_); } -private: + private: SequenceVar *const sequence_; const int index_; }; class RankFirstIntervalVars : public DecisionBuilder { -public: + public: RankFirstIntervalVars(const std::vector &sequences, Solver::SequenceStrategy str) : sequences_(sequences), strategy_(str) {} @@ -670,7 +672,7 @@ public: visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension); } -private: + private: // Selects the interval var to rank. bool FindIntervalVarOnStartMin(Solver *const s, SequenceVar *const best_sequence, @@ -705,15 +707,15 @@ private: bool FindIntervalVar(Solver *const s, SequenceVar *const best_sequence, int *const best_interval_index) { switch (strategy_) { - case Solver::SEQUENCE_DEFAULT: - case Solver::SEQUENCE_SIMPLE: - case Solver::CHOOSE_MIN_SLACK_RANK_FORWARD: - return FindIntervalVarOnStartMin(s, best_sequence, best_interval_index); - case Solver::CHOOSE_RANDOM_RANK_FORWARD: - return FindIntervalVarRandomly(s, best_sequence, best_interval_index); - default: - LOG(FATAL) << "Unknown strategy " << strategy_; - return false; + case Solver::SEQUENCE_DEFAULT: + case Solver::SEQUENCE_SIMPLE: + case Solver::CHOOSE_MIN_SLACK_RANK_FORWARD: + return FindIntervalVarOnStartMin(s, best_sequence, best_interval_index); + case Solver::CHOOSE_RANDOM_RANK_FORWARD: + return FindIntervalVarRandomly(s, best_sequence, best_interval_index); + default: + LOG(FATAL) << "Unknown strategy " << strategy_; + return false; } } @@ -810,14 +812,14 @@ private: bool FindSequenceVar(Solver *const s, SequenceVar **const best_sequence) { switch (strategy_) { - case Solver::SEQUENCE_DEFAULT: - case Solver::SEQUENCE_SIMPLE: - case Solver::CHOOSE_MIN_SLACK_RANK_FORWARD: - return FindSequenceVarOnSlack(s, best_sequence); - case Solver::CHOOSE_RANDOM_RANK_FORWARD: - return FindSequenceVarRandomly(s, best_sequence); - default: - LOG(FATAL) << "Unknown strategy " << strategy_; + case Solver::SEQUENCE_DEFAULT: + case Solver::SEQUENCE_SIMPLE: + case Solver::CHOOSE_MIN_SLACK_RANK_FORWARD: + return FindSequenceVarOnSlack(s, best_sequence); + case Solver::CHOOSE_RANDOM_RANK_FORWARD: + return FindSequenceVarRandomly(s, best_sequence); + default: + LOG(FATAL) << "Unknown strategy " << strategy_; } } @@ -827,7 +829,7 @@ private: std::vector candidate_possible_firsts_; std::vector candidate_possible_lasts_; }; -} // namespace +} // namespace Decision *Solver::MakeScheduleOrPostpone(IntervalVar *const var, int64 est, int64 *const marker) { @@ -846,14 +848,14 @@ Decision *Solver::MakeScheduleOrExpedite(IntervalVar *const var, int64 est, DecisionBuilder *Solver::MakePhase(const std::vector &intervals, IntervalStrategy str) { switch (str) { - case Solver::INTERVAL_DEFAULT: - case Solver::INTERVAL_SIMPLE: - case Solver::INTERVAL_SET_TIMES_FORWARD: - return RevAlloc(new SetTimesForward(intervals)); - case Solver::INTERVAL_SET_TIMES_BACKWARD: - return RevAlloc(new SetTimesBackward(intervals)); - default: - LOG(FATAL) << "Unknown strategy " << str; + case Solver::INTERVAL_DEFAULT: + case Solver::INTERVAL_SIMPLE: + case Solver::INTERVAL_SET_TIMES_FORWARD: + return RevAlloc(new SetTimesForward(intervals)); + case Solver::INTERVAL_SET_TIMES_BACKWARD: + return RevAlloc(new SetTimesBackward(intervals)); + default: + LOG(FATAL) << "Unknown strategy " << str; } } @@ -873,4 +875,4 @@ DecisionBuilder *Solver::MakePhase(const std::vector &sequences, return RevAlloc(new RankFirstIntervalVars(sequences, str)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/search.cc b/ortools/constraint_solver/search.cc index 3e80d3496d..df2e8e7d4d 100644 --- a/ortools/constraint_solver/search.cc +++ b/ortools/constraint_solver/search.cc @@ -44,8 +44,9 @@ DEFINE_bool(cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties"); -DEFINE_bool(cp_log_to_vlog, false, "Whether search related logging should be " - "vlog or info."); +DEFINE_bool(cp_log_to_vlog, false, + "Whether search related logging should be " + "vlog or info."); DEFINE_int64(cp_large_domain_no_splitting_limit, 0xFFFFF, "Size limit to allow holes in variables from the strategy."); namespace operations_research { @@ -56,12 +57,22 @@ SearchLog::SearchLog(Solver *const s, OptimizeVar *const obj, IntVar *const var, double scaling_factor, double offset, std::function display_callback, bool display_on_new_solutions_only, int period) - : SearchMonitor(s), period_(period), timer_(new WallTimer), var_(var), - obj_(obj), scaling_factor_(scaling_factor), offset_(offset), + : SearchMonitor(s), + period_(period), + timer_(new WallTimer), + var_(var), + obj_(obj), + scaling_factor_(scaling_factor), + offset_(offset), display_callback_(std::move(display_callback)), - display_on_new_solutions_only_(display_on_new_solutions_only), nsol_(0), - tick_(0), objective_min_(kint64max), objective_max_(kint64min), - min_right_depth_(kint32max), max_depth_(0), sliding_min_depth_(0), + display_on_new_solutions_only_(display_on_new_solutions_only), + nsol_(0), + tick_(0), + objective_min_(kint64max), + objective_max_(kint64min), + min_right_depth_(kint32max), + max_depth_(0), + sliding_min_depth_(0), sliding_max_depth_(0) { CHECK(obj == nullptr || var == nullptr) << "Either var or obj need to be nullptr."; @@ -105,8 +116,7 @@ bool SearchLog::AtSolution() { } else { return absl::StrCat(value); } - } - ; + }; if (obj_ != nullptr && obj_->Var()->Bound()) { current = obj_->Var()->Value(); obj_str = obj_->Print(); @@ -122,29 +132,31 @@ bool SearchLog::AtSolution() { } if (objective_updated) { if (current > objective_min_) { - absl::StrAppend(&obj_str, "objective minimum = ", - scaled_str(objective_min_), ", "); + absl::StrAppend(&obj_str, + "objective minimum = ", scaled_str(objective_min_), ", "); } else { objective_min_ = current; } if (current < objective_max_) { - absl::StrAppend(&obj_str, "objective maximum = ", - scaled_str(objective_max_), ", "); + absl::StrAppend(&obj_str, + "objective maximum = ", scaled_str(objective_max_), ", "); } else { objective_max_ = current; } } std::string log; - absl::StrAppendFormat(&log, "Solution #%d (%stime = %d ms, branches = %d," - " failures = %d, depth = %d", + absl::StrAppendFormat(&log, + "Solution #%d (%stime = %d ms, branches = %d," + " failures = %d, depth = %d", nsol_++, obj_str, timer_->GetInMs(), solver()->branches(), solver()->failures(), depth); if (!solver()->SearchContext().empty()) { absl::StrAppendFormat(&log, ", %s", solver()->SearchContext()); } if (solver()->neighbors() != 0) { - absl::StrAppendFormat(&log, ", neighbors = %d, filtered neighbors = %d," - " accepted neighbors = %d", + absl::StrAppendFormat(&log, + ", neighbors = %d, filtered neighbors = %d," + " accepted neighbors = %d", solver()->neighbors(), solver()->filtered_neighbors(), solver()->accepted_neighbors()); } @@ -171,8 +183,9 @@ void SearchLog::NoMoreSolutions() { " failures = %d", timer_->GetInMs(), solver()->branches(), solver()->failures()); if (solver()->neighbors() != 0) { - absl::StrAppendFormat(&buffer, ", neighbors = %d, filtered neighbors = %d," - " accepted neigbors = %d", + absl::StrAppendFormat(&buffer, + ", neighbors = %d, filtered neighbors = %d," + " accepted neigbors = %d", solver()->neighbors(), solver()->filtered_neighbors(), solver()->accepted_neighbors()); } @@ -211,8 +224,9 @@ void SearchLog::OutputDecision() { } if (obj_ != nullptr && objective_min_ != kint64max && objective_max_ != kint64min) { - absl::StrAppendFormat(&buffer, ", objective minimum = %d" - ", objective maximum = %d", + absl::StrAppendFormat(&buffer, + ", objective minimum = %d" + ", objective maximum = %d", objective_min_, objective_max_); } const int progress = solver()->TopProgressPercent(); @@ -275,19 +289,18 @@ SearchMonitor *Solver::MakeSearchLog(int branch_period, IntVar *const var) { return MakeSearchLog(branch_period, var, nullptr); } -SearchMonitor * -Solver::MakeSearchLog(int branch_period, - std::function display_callback) { +SearchMonitor *Solver::MakeSearchLog( + int branch_period, std::function display_callback) { return MakeSearchLog(branch_period, static_cast(nullptr), std::move(display_callback)); } -SearchMonitor * -Solver::MakeSearchLog(int branch_period, IntVar *const var, - std::function display_callback) { - return RevAlloc( - new SearchLog(this, nullptr, var, 1.0, 0.0, std::move(display_callback), - true, branch_period)); +SearchMonitor *Solver::MakeSearchLog( + int branch_period, IntVar *const var, + std::function display_callback) { + return RevAlloc(new SearchLog(this, nullptr, var, 1.0, 0.0, + std::move(display_callback), true, + branch_period)); } SearchMonitor *Solver::MakeSearchLog(int branch_period, @@ -295,12 +308,12 @@ SearchMonitor *Solver::MakeSearchLog(int branch_period, return MakeSearchLog(branch_period, opt_var, nullptr); } -SearchMonitor * -Solver::MakeSearchLog(int branch_period, OptimizeVar *const opt_var, - std::function display_callback) { - return RevAlloc( - new SearchLog(this, opt_var, nullptr, 1.0, 0.0, - std::move(display_callback), true, branch_period)); +SearchMonitor *Solver::MakeSearchLog( + int branch_period, OptimizeVar *const opt_var, + std::function display_callback) { + return RevAlloc(new SearchLog(this, opt_var, nullptr, 1.0, 0.0, + std::move(display_callback), true, + branch_period)); } SearchMonitor *Solver::MakeSearchLog(SearchLogParameters parameters) { @@ -376,7 +389,7 @@ class SearchTrace : public SearchMonitor { private: const std::string prefix_; }; -} // namespace +} // namespace SearchMonitor *Solver::MakeSearchTrace(const std::string &prefix) { return RevAlloc(new SearchTrace(this, prefix)); @@ -400,7 +413,7 @@ bool AtSolutionCallback::AtSolution() { return false; } -} // namespace +} // namespace SearchMonitor *Solver::MakeAtSolutionCallback(std::function callback) { return RevAlloc(new AtSolutionCallback(this, std::move(callback))); @@ -420,7 +433,7 @@ class EnterSearchCallback : public SearchMonitor { void EnterSearchCallback::EnterSearch() { callback_(); } -} // namespace +} // namespace SearchMonitor *Solver::MakeEnterSearchCallback(std::function callback) { return RevAlloc(new EnterSearchCallback(this, std::move(callback))); @@ -440,7 +453,7 @@ class ExitSearchCallback : public SearchMonitor { void ExitSearchCallback::ExitSearch() { callback_(); } -} // namespace +} // namespace SearchMonitor *Solver::MakeExitSearchCallback(std::function callback) { return RevAlloc(new ExitSearchCallback(this, std::move(callback))); @@ -492,7 +505,7 @@ void CompositeDecisionBuilder::Accept(ModelVisitor *const visitor) const { db->Accept(visitor); } } -} // namespace +} // namespace // ---------- Compose Decision Builder ---------- @@ -534,7 +547,7 @@ std::string ComposeDecisionBuilder::DebugString() const { return absl::StrFormat("ComposeDecisionBuilder(%s)", JoinDebugStringPtr(builders_, ", ")); } -} // namespace +} // namespace DecisionBuilder *Solver::Compose(DecisionBuilder *const db1, DecisionBuilder *const db2) { @@ -592,7 +605,7 @@ class ClosureDecision : public Decision { Solver::Action apply_; Solver::Action refute_; }; -} // namespace +} // namespace Decision *Solver::MakeDecision(Action apply, Action refute) { return RevAlloc(new ClosureDecision(std::move(apply), std::move(refute))); @@ -643,12 +656,16 @@ void TryDecision::Refute(Solver *const solver) { } TryDecisionBuilder::TryDecisionBuilder() - : CompositeDecisionBuilder(), try_decision_(this), current_builder_(-1), + : CompositeDecisionBuilder(), + try_decision_(this), + current_builder_(-1), start_new_builder_(true) {} TryDecisionBuilder::TryDecisionBuilder( const std::vector &dbs) - : CompositeDecisionBuilder(dbs), try_decision_(this), current_builder_(-1), + : CompositeDecisionBuilder(dbs), + try_decision_(this), + current_builder_(-1), start_new_builder_(true) {} TryDecisionBuilder::~TryDecisionBuilder() {} @@ -679,7 +696,7 @@ void TryDecisionBuilder::AdvanceToNextBuilder(Solver *const solver) { } } -} // namespace +} // namespace DecisionBuilder *Solver::Try(DecisionBuilder *const db1, DecisionBuilder *const db2) { @@ -724,7 +741,9 @@ class BaseVariableAssignmentSelector : public BaseObject { public: BaseVariableAssignmentSelector(Solver *solver, const std::vector &vars) - : solver_(solver), vars_(vars), first_unbound_(0), + : solver_(solver), + vars_(vars), + first_unbound_(0), last_unbound_(vars.size() - 1) {} ~BaseVariableAssignmentSelector() override {} @@ -1064,7 +1083,7 @@ int64 PathSelector::Choose(Solver *const s, const std::vector &vars, } ++count; if (count >= vars.size() && - !FindPathStart(vars, &index)) { // Cycle detected + !FindPathStart(vars, &index)) { // Cycle detected return -1; } } @@ -1144,7 +1163,7 @@ int64 SelectRandomValue(const IntVar *v, int64 id) { } const uint64 size = v->Size(); Solver *const s = v->solver(); - if (size > span / 4) { // Dense enough, we can try to find the + if (size > span / 4) { // Dense enough, we can try to find the // value randomly. for (;;) { const int64 value = v->Min() + s->Rand64(span); @@ -1152,7 +1171,7 @@ int64 SelectRandomValue(const IntVar *v, int64 id) { return value; } } - } else { // Not dense enough, we will count. + } else { // Not dense enough, we will count. int64 index = s->Rand64(size); if (index <= size / 2) { for (int64 i = v->Min(); i <= v->Max(); ++i) { @@ -1190,7 +1209,7 @@ int64 SelectCenterValue(const IntVar *v, int64 id) { if (v->Contains(mid)) { return mid; } - const int64 diameter = vmax - mid; // always greater than mid - vmix. + const int64 diameter = vmax - mid; // always greater than mid - vmix. for (int64 i = 1; i <= diameter; ++i) { if (v->Contains(mid - i)) { return mid - i; @@ -1277,7 +1296,7 @@ class BestValueByComparisonSelector : public BaseObject { int64 BestValueByComparisonSelector::Select(const IntVar *v, int64 id) { std::unique_ptr it(v->MakeDomainIterator(false)); it->Init(); - DCHECK(it->Ok()); // At least one value. + DCHECK(it->Ok()); // At least one value. int64 best_value = it->Value(); for (it->Next(); it->Ok(); it->Next()) { const int64 candidate_value = it->Value(); @@ -1298,7 +1317,8 @@ class VariableAssignmentSelector : public BaseVariableAssignmentSelector { const std::string &name) : BaseVariableAssignmentSelector(solver, vars), var_selector_(std::move(var_selector)), - value_selector_(std::move(value_selector)), name_(name) {} + value_selector_(std::move(value_selector)), + name_(name) {} ~VariableAssignmentSelector() override {} int64 SelectValue(const IntVar *var, int64 id) override { return value_selector_(var, id); @@ -1370,7 +1390,8 @@ DynamicEvaluatorSelector::DynamicEvaluatorSelector( Solver *solver, const std::vector &vars, std::function evaluator, std::function tie_breaker) - : BaseEvaluatorSelector(solver, vars, std::move(evaluator)), first_(-1), + : BaseEvaluatorSelector(solver, vars, std::move(evaluator)), + first_(-1), tie_breaker_(std::move(tie_breaker)) {} int64 DynamicEvaluatorSelector::SelectValue(const IntVar *var, int64 id) { @@ -1454,7 +1475,8 @@ class StaticEvaluatorSelector : public BaseEvaluatorSelector { StaticEvaluatorSelector::StaticEvaluatorSelector( Solver *solver, const std::vector &vars, const std::function &evaluator) - : BaseEvaluatorSelector(solver, vars, evaluator), comp_(evaluator), + : BaseEvaluatorSelector(solver, vars, evaluator), + comp_(evaluator), first_(-1) {} int64 StaticEvaluatorSelector::SelectValue(const IntVar *var, int64 id) { @@ -1462,7 +1484,7 @@ int64 StaticEvaluatorSelector::SelectValue(const IntVar *var, int64 id) { } int64 StaticEvaluatorSelector::ChooseVariable() { - if (first_ == -1) { // first call to select. update assignment costs + if (first_ == -1) { // first call to select. update assignment costs // Two phases: compute size then filland sort int64 element_size = 0; for (int64 i = 0; i < vars_.size(); ++i) { @@ -1532,7 +1554,7 @@ void AssignOneVariableValue::Apply(Solver *const s) { var_->SetValue(value_); } void AssignOneVariableValue::Refute(Solver *const s) { var_->RemoveValue(value_); } -} // namespace +} // namespace Decision *Solver::MakeAssignVariableValue(IntVar *const var, int64 val) { return RevAlloc(new AssignOneVariableValue(var, val)); @@ -1570,7 +1592,7 @@ void AssignOneVariableValueOrFail::Apply(Solver *const s) { } void AssignOneVariableValueOrFail::Refute(Solver *const s) { s->Fail(); } -} // namespace +} // namespace Decision *Solver::MakeAssignVariableValueOrFail(IntVar *const var, int64 value) { @@ -1599,7 +1621,7 @@ class AssignOneVariableValueDoNothing : public Decision { const int64 value_; }; -} // namespace +} // namespace Decision *Solver::MakeAssignVariableValueOrDoNothing(IntVar *const var, int64 value) { @@ -1653,7 +1675,7 @@ void SplitOneVariable::Refute(Solver *const s) { var_->SetMax(value_); } } -} // namespace +} // namespace Decision *Solver::MakeSplitVariableDomain(IntVar *const var, int64 val, bool start_with_lower_half) { @@ -1726,7 +1748,7 @@ void AssignVariablesValues::Refute(Solver *const s) { } s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1)); } -} // namespace +} // namespace Decision *Solver::MakeAssignVariablesValues(const std::vector &vars, const std::vector &values) { @@ -1751,16 +1773,15 @@ class BaseAssignVariables : public DecisionBuilder { ~BaseAssignVariables() override; Decision *Next(Solver *const s) override; std::string DebugString() const override; - static BaseAssignVariables * - MakePhase(Solver *const s, const std::vector &vars, - Solver::VariableIndexSelector var_selector, - Solver::VariableValueSelector value_selector, - const std::string &value_selector_name, - BaseAssignVariables::Mode mode); + static BaseAssignVariables *MakePhase( + Solver *const s, const std::vector &vars, + Solver::VariableIndexSelector var_selector, + Solver::VariableValueSelector value_selector, + const std::string &value_selector_name, BaseAssignVariables::Mode mode); - static Solver::VariableIndexSelector - MakeVariableSelector(Solver *const s, const std::vector &vars, - Solver::IntVarStrategy str) { + static Solver::VariableIndexSelector MakeVariableSelector( + Solver *const s, const std::vector &vars, + Solver::IntVarStrategy str) { switch (str) { case Solver::INT_VAR_DEFAULT: case Solver::INT_VAR_SIMPLE: @@ -1787,19 +1808,17 @@ class BaseAssignVariables : public DecisionBuilder { case Solver::CHOOSE_MAX_REGRET_ON_MIN: { HighestRegretSelectorOnMin *const selector = s->RevAlloc(new HighestRegretSelectorOnMin(vars)); - return[selector](Solver * solver, const std::vector & vars, - int first_unbound, int last_unbound) { + return [selector](Solver *solver, const std::vector &vars, + int first_unbound, int last_unbound) { return selector->Choose(solver, vars, first_unbound, last_unbound); - } - ; + }; } case Solver::CHOOSE_PATH: { PathSelector *const selector = s->RevAlloc(new PathSelector()); - return[selector](Solver * solver, const std::vector & vars, - int first_unbound, int last_unbound) { + return [selector](Solver *solver, const std::vector &vars, + int first_unbound, int last_unbound) { return selector->Choose(solver, vars, first_unbound, last_unbound); - } - ; + }; } default: LOG(FATAL) << "Unknown int var strategy " << str; @@ -1807,8 +1826,8 @@ class BaseAssignVariables : public DecisionBuilder { } } - static Solver::VariableValueSelector - MakeValueSelector(Solver *const s, Solver::IntValueStrategy val_str) { + static Solver::VariableValueSelector MakeValueSelector( + Solver *const s, Solver::IntValueStrategy val_str) { switch (val_str) { case Solver::INT_VALUE_DEFAULT: case Solver::INT_VALUE_SIMPLE: @@ -1935,7 +1954,7 @@ std::string BuildHeuristicsName(Solver::IntVarStrategy var_str, Solver::IntValueStrategy val_str) { return ChooseVariableName(var_str) + "_" + SelectValueName(val_str); } -} // namespace +} // namespace DecisionBuilder *Solver::MakePhase(IntVar *const v0, Solver::IntVarStrategy var_str, @@ -2006,11 +2025,10 @@ DecisionBuilder *Solver::MakePhase(const std::vector &vars, CheapestVarSelector *const var_selector = RevAlloc(new CheapestVarSelector(std::move(var_evaluator))); Solver::VariableIndexSelector choose_variable = - [var_selector](Solver * solver, const std::vector & vars, + [var_selector](Solver *solver, const std::vector &vars, int first_unbound, int last_unbound) { return var_selector->Choose(solver, vars, first_unbound, last_unbound); - } - ; + }; Solver::VariableValueSelector select_value = BaseAssignVariables::MakeValueSelector(this, val_str); const std::string name = "ChooseCheapestVariable_" + SelectValueName(val_str); @@ -2026,28 +2044,26 @@ DecisionBuilder *Solver::MakePhase(const std::vector &vars, CheapestValueSelector *const value_selector = RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr)); Solver::VariableValueSelector select_value = - [value_selector](const IntVar * var, int64 id) { + [value_selector](const IntVar *var, int64 id) { return value_selector->Select(var, id); - } - ; + }; const std::string name = ChooseVariableName(var_str) + "_SelectCheapestValue"; return BaseAssignVariables::MakePhase(this, vars, choose_variable, select_value, name, BaseAssignVariables::ASSIGN); } -DecisionBuilder * -Solver::MakePhase(const std::vector &vars, IntVarStrategy var_str, - VariableValueComparator var_val1_val2_comparator) { +DecisionBuilder *Solver::MakePhase( + const std::vector &vars, IntVarStrategy var_str, + VariableValueComparator var_val1_val2_comparator) { Solver::VariableIndexSelector choose_variable = BaseAssignVariables::MakeVariableSelector(this, vars, var_str); BestValueByComparisonSelector *const value_selector = RevAlloc( new BestValueByComparisonSelector(std::move(var_val1_val2_comparator))); Solver::VariableValueSelector select_value = - [value_selector](const IntVar * var, int64 id) { + [value_selector](const IntVar *var, int64 id) { return value_selector->Select(var, id); - } - ; + }; return BaseAssignVariables::MakePhase(this, vars, choose_variable, select_value, "CheapestValue", BaseAssignVariables::ASSIGN); @@ -2059,18 +2075,16 @@ DecisionBuilder *Solver::MakePhase(const std::vector &vars, CheapestVarSelector *const var_selector = RevAlloc(new CheapestVarSelector(std::move(var_evaluator))); Solver::VariableIndexSelector choose_variable = - [var_selector](Solver * solver, const std::vector & vars, + [var_selector](Solver *solver, const std::vector &vars, int first_unbound, int last_unbound) { return var_selector->Choose(solver, vars, first_unbound, last_unbound); - } - ; + }; CheapestValueSelector *value_selector = RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr)); Solver::VariableValueSelector select_value = - [value_selector](const IntVar * var, int64 id) { + [value_selector](const IntVar *var, int64 id) { return value_selector->Select(var, id); - } - ; + }; return BaseAssignVariables::MakePhase(this, vars, choose_variable, select_value, "CheapestValue", BaseAssignVariables::ASSIGN); @@ -2085,10 +2099,9 @@ DecisionBuilder *Solver::MakePhase(const std::vector &vars, CheapestValueSelector *value_selector = RevAlloc(new CheapestValueSelector( std::move(value_evaluator), std::move(tie_breaker))); Solver::VariableValueSelector select_value = - [value_selector](const IntVar * var, int64 id) { + [value_selector](const IntVar *var, int64 id) { return value_selector->Select(var, id); - } - ; + }; return BaseAssignVariables::MakePhase(this, vars, choose_variable, select_value, "CheapestValue", BaseAssignVariables::ASSIGN); @@ -2101,18 +2114,16 @@ DecisionBuilder *Solver::MakePhase(const std::vector &vars, CheapestVarSelector *const var_selector = RevAlloc(new CheapestVarSelector(std::move(var_evaluator))); Solver::VariableIndexSelector choose_variable = - [var_selector](Solver * solver, const std::vector & vars, + [var_selector](Solver *solver, const std::vector &vars, int first_unbound, int last_unbound) { return var_selector->Choose(solver, vars, first_unbound, last_unbound); - } - ; + }; CheapestValueSelector *value_selector = RevAlloc(new CheapestValueSelector( std::move(value_evaluator), std::move(tie_breaker))); Solver::VariableValueSelector select_value = - [value_selector](const IntVar * var, int64 id) { + [value_selector](const IntVar *var, int64 id) { return value_selector->Select(var, id); - } - ; + }; return BaseAssignVariables::MakePhase(this, vars, choose_variable, select_value, "CheapestValue", BaseAssignVariables::ASSIGN); @@ -2180,12 +2191,11 @@ class AssignVariablesFromAssignment : public DecisionBuilder { const std::vector vars_; int iter_; }; -} // namespace +} // namespace -DecisionBuilder * -Solver::MakeDecisionBuilderFromAssignment(Assignment *const assignment, - DecisionBuilder *const db, - const std::vector &vars) { +DecisionBuilder *Solver::MakeDecisionBuilderFromAssignment( + Assignment *const assignment, DecisionBuilder *const db, + const std::vector &vars) { return RevAlloc(new AssignVariablesFromAssignment(assignment, db, vars)); } @@ -2355,18 +2365,18 @@ int64 SolutionCollector::PerformedValue(int n, IntervalVar *const var) const { return solution(n)->PerformedValue(var); } -const std::vector & -SolutionCollector::ForwardSequence(int n, SequenceVar *const var) const { +const std::vector &SolutionCollector::ForwardSequence( + int n, SequenceVar *const var) const { return solution(n)->ForwardSequence(var); } -const std::vector & -SolutionCollector::BackwardSequence(int n, SequenceVar *const var) const { +const std::vector &SolutionCollector::BackwardSequence( + int n, SequenceVar *const var) const { return solution(n)->BackwardSequence(var); } -const std::vector & -SolutionCollector::Unperformed(int n, SequenceVar *const var) const { +const std::vector &SolutionCollector::Unperformed( + int n, SequenceVar *const var) const { return solution(n)->Unperformed(var); } @@ -2416,10 +2426,10 @@ std::string FirstSolutionCollector::DebugString() const { return "FirstSolutionCollector(" + prototype_->DebugString() + ")"; } } -} // namespace +} // namespace -SolutionCollector * -Solver::MakeFirstSolutionCollector(const Assignment *const assignment) { +SolutionCollector *Solver::MakeFirstSolutionCollector( + const Assignment *const assignment) { return RevAlloc(new FirstSolutionCollector(this, assignment)); } @@ -2462,10 +2472,10 @@ std::string LastSolutionCollector::DebugString() const { return "LastSolutionCollector(" + prototype_->DebugString() + ")"; } } -} // namespace +} // namespace -SolutionCollector * -Solver::MakeLastSolutionCollector(const Assignment *const assignment) { +SolutionCollector *Solver::MakeLastSolutionCollector( + const Assignment *const assignment) { return RevAlloc(new LastSolutionCollector(this, assignment)); } @@ -2493,12 +2503,14 @@ class BestValueSolutionCollector : public SolutionCollector { BestValueSolutionCollector::BestValueSolutionCollector( Solver *const s, const Assignment *const a, bool maximize) - : SolutionCollector(s, a), maximize_(maximize), + : SolutionCollector(s, a), + maximize_(maximize), best_(maximize ? kint64min : kint64max) {} BestValueSolutionCollector::BestValueSolutionCollector(Solver *const s, bool maximize) - : SolutionCollector(s), maximize_(maximize), + : SolutionCollector(s), + maximize_(maximize), best_(maximize ? kint64min : kint64max) {} void BestValueSolutionCollector::EnterSearch() { @@ -2532,11 +2544,10 @@ std::string BestValueSolutionCollector::DebugString() const { return "BestValueSolutionCollector(" + prototype_->DebugString() + ")"; } } -} // namespace +} // namespace -SolutionCollector * -Solver::MakeBestValueSolutionCollector(const Assignment *const assignment, - bool maximize) { +SolutionCollector *Solver::MakeBestValueSolutionCollector( + const Assignment *const assignment, bool maximize) { return RevAlloc(new BestValueSolutionCollector(this, assignment, maximize)); } @@ -2571,13 +2582,15 @@ class NBestValueSolutionCollector : public SolutionCollector { NBestValueSolutionCollector::NBestValueSolutionCollector( Solver *const solver, const Assignment *const assignment, int solution_count, bool maximize) - : SolutionCollector(solver, assignment), maximize_(maximize), + : SolutionCollector(solver, assignment), + maximize_(maximize), solution_count_(solution_count) {} NBestValueSolutionCollector::NBestValueSolutionCollector(Solver *const solver, int solution_count, bool maximize) - : SolutionCollector(solver), maximize_(maximize), + : SolutionCollector(solver), + maximize_(maximize), solution_count_(solution_count) {} void NBestValueSolutionCollector::EnterSearch() { @@ -2604,17 +2617,15 @@ bool NBestValueSolutionCollector::AtSolution() { const int64 objective_value = maximize_ ? CapSub(0, objective->Max()) : objective->Min(); if (solutions_pq_.size() < solution_count_) { - solutions_pq_.push({ - objective_value, BuildSolutionDataForCurrentState() - }); + solutions_pq_.push( + {objective_value, BuildSolutionDataForCurrentState()}); } else if (!solutions_pq_.empty()) { const auto &top = solutions_pq_.top(); if (top.first > objective_value) { FreeSolution(solutions_pq_.top().second.solution); solutions_pq_.pop(); - solutions_pq_.push({ - objective_value, BuildSolutionDataForCurrentState() - }); + solutions_pq_.push( + {objective_value, BuildSolutionDataForCurrentState()}); } } } @@ -2637,11 +2648,10 @@ void NBestValueSolutionCollector::Clear() { } } -} // namespace +} // namespace -SolutionCollector * -Solver::MakeNBestValueSolutionCollector(const Assignment *const assignment, - int solution_count, bool maximize) { +SolutionCollector *Solver::MakeNBestValueSolutionCollector( + const Assignment *const assignment, int solution_count, bool maximize) { if (solution_count == 1) { return MakeBestValueSolutionCollector(assignment, maximize); } @@ -2692,10 +2702,10 @@ std::string AllSolutionCollector::DebugString() const { return "AllSolutionCollector(" + prototype_->DebugString() + ")"; } } -} // namespace +} // namespace -SolutionCollector * -Solver::MakeAllSolutionCollector(const Assignment *const assignment) { +SolutionCollector *Solver::MakeAllSolutionCollector( + const Assignment *const assignment) { return RevAlloc(new AllSolutionCollector(this, assignment)); } @@ -2707,8 +2717,12 @@ SolutionCollector *Solver::MakeAllSolutionCollector() { OptimizeVar::OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64 step) - : SearchMonitor(s), var_(a), step_(step), best_(kint64max), - maximize_(maximize), found_initial_solution_(false) { + : SearchMonitor(s), + var_(a), + step_(step), + best_(kint64max), + maximize_(maximize), + found_initial_solution_(false) { CHECK_GT(step_, 0); // TODO(user): Store optimization direction in Solver. Besides making the // code simpler it would also having two monitors optimizing in opposite @@ -2732,7 +2746,7 @@ void OptimizeVar::EnterSearch() { } void OptimizeVar::BeginNextDecision(DecisionBuilder *const db) { - if (solver()->SearchDepth() == 0) { // after a restart. + if (solver()->SearchDepth() == 0) { // after a restart. ApplyBound(); } } @@ -2790,9 +2804,8 @@ bool OptimizeVar::AcceptDelta(Assignment *delta, Assignment *deltadelta) { local_search_state->HasObjective() ? CapAdd(local_search_state->ObjectiveMin(), step_) : kint64min; - delta->SetObjectiveMin(std::max({ - var_->Min(), min_objective, delta_min_objective - })); + delta->SetObjectiveMin( + std::max({var_->Min(), min_objective, delta_min_objective})); } else { const int64 delta_max_objective = @@ -2801,9 +2814,8 @@ bool OptimizeVar::AcceptDelta(Assignment *delta, Assignment *deltadelta) { local_search_state->HasObjective() ? CapSub(local_search_state->ObjectiveMax(), step_) : kint64max; - delta->SetObjectiveMax(std::min({ - var_->Max(), max_objective, delta_max_objective - })); + delta->SetObjectiveMax( + std::min({var_->Max(), max_objective, delta_max_objective})); } } } @@ -2855,7 +2867,8 @@ class WeightedOptimizeVar : public OptimizeVar { const std::vector &weights, int64 step) : OptimizeVar(solver, maximize, solver->MakeScalProd(sub_objectives, weights)->Var(), step), - sub_objectives_(sub_objectives), weights_(weights) { + sub_objectives_(sub_objectives), + weights_(weights) { CHECK_EQ(sub_objectives.size(), weights.size()); } @@ -2879,47 +2892,45 @@ std::string WeightedOptimizeVar::Print() const { } return result; } -} // namespace +} // namespace -OptimizeVar * -Solver::MakeWeightedOptimize(bool maximize, - const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedOptimize( + bool maximize, const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return RevAlloc( new WeightedOptimizeVar(this, maximize, sub_objectives, weights, step)); } -OptimizeVar * -Solver::MakeWeightedMinimize(const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedMinimize( + const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return RevAlloc( new WeightedOptimizeVar(this, false, sub_objectives, weights, step)); } -OptimizeVar * -Solver::MakeWeightedMaximize(const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedMaximize( + const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return RevAlloc( new WeightedOptimizeVar(this, true, sub_objectives, weights, step)); } -OptimizeVar * -Solver::MakeWeightedOptimize(bool maximize, - const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedOptimize( + bool maximize, const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return MakeWeightedOptimize(maximize, sub_objectives, ToInt64Vector(weights), step); } -OptimizeVar * -Solver::MakeWeightedMinimize(const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedMinimize( + const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return MakeWeightedMinimize(sub_objectives, ToInt64Vector(weights), step); } -OptimizeVar * -Solver::MakeWeightedMaximize(const std::vector &sub_objectives, - const std::vector &weights, int64 step) { +OptimizeVar *Solver::MakeWeightedMaximize( + const std::vector &sub_objectives, + const std::vector &weights, int64 step) { return MakeWeightedMaximize(sub_objectives, ToInt64Vector(weights), step); } @@ -2947,8 +2958,12 @@ class Metaheuristic : public SearchMonitor { Metaheuristic::Metaheuristic(Solver *const solver, bool maximize, IntVar *objective, int64 step) - : SearchMonitor(solver), objective_(objective), step_(step), - current_(kint64max), best_(kint64max), maximize_(maximize) {} + : SearchMonitor(solver), + objective_(objective), + step_(step), + current_(kint64max), + best_(kint64max), + maximize_(maximize) {} bool Metaheuristic::AtSolution() { current_ = objective_->Value(); @@ -3051,9 +3066,14 @@ TabuSearch::TabuSearch(Solver *const s, bool maximize, IntVar *objective, int64 step, const std::vector &vars, int64 keep_tenure, int64 forbid_tenure, double tabu_factor) - : Metaheuristic(s, maximize, objective, step), vars_(vars), assignment_(s), - last_(kint64max), keep_tenure_(keep_tenure), - forbid_tenure_(forbid_tenure), tabu_factor_(tabu_factor), stamp_(0), + : Metaheuristic(s, maximize, objective, step), + vars_(vars), + assignment_(s), + last_(kint64max), + keep_tenure_(keep_tenure), + forbid_tenure_(forbid_tenure), + tabu_factor_(tabu_factor), + stamp_(0), found_initial_solution_(false) { assignment_.Add(vars_); } @@ -3092,9 +3112,7 @@ void TabuSearch::ApplyDecision(Decision *const d) { if (tabu_var != nullptr) { s->AddConstraint( - s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64 { - 1 - })); + s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64{1})); } // Go downhill to the next local optimum @@ -3218,7 +3236,7 @@ std::vector GenericTabuSearch::CreateTabuVars() { return tabu_vars; } -} // namespace +} // namespace SearchMonitor *Solver::MakeTabuSearch(bool maximize, IntVar *const v, int64 step, @@ -3229,10 +3247,9 @@ SearchMonitor *Solver::MakeTabuSearch(bool maximize, IntVar *const v, forbid_tenure, tabu_factor)); } -SearchMonitor * -Solver::MakeGenericTabuSearch(bool maximize, IntVar *const v, int64 step, - const std::vector &tabu_vars, - int64 forbid_tenure) { +SearchMonitor *Solver::MakeGenericTabuSearch( + bool maximize, IntVar *const v, int64 step, + const std::vector &tabu_vars, int64 forbid_tenure) { return RevAlloc( new GenericTabuSearch(this, maximize, v, step, tabu_vars, forbid_tenure)); } @@ -3267,7 +3284,9 @@ SimulatedAnnealing::SimulatedAnnealing(Solver *const s, bool maximize, IntVar *objective, int64 step, int64 initial_temperature) : Metaheuristic(s, maximize, objective, step), - temperature0_(initial_temperature), iteration_(0), rand_(CpRandomSeed()), + temperature0_(initial_temperature), + iteration_(0), + rand_(CpRandomSeed()), found_initial_solution_(false) {} void SimulatedAnnealing::EnterSearch() { @@ -3324,12 +3343,12 @@ void SimulatedAnnealing::AcceptNeighbor() { double SimulatedAnnealing::Temperature() const { if (iteration_ > 0) { - return (1.0 * temperature0_) / iteration_; // Cauchy annealing + return (1.0 * temperature0_) / iteration_; // Cauchy annealing } else { return 0.; } } -} // namespace +} // namespace SearchMonitor *Solver::MakeSimulatedAnnealing(bool maximize, IntVar *const v, int64 step, @@ -3484,9 +3503,13 @@ GuidedLocalSearch::GuidedLocalSearch(Solver *const s, IntVar *objective, const std::vector &vars, double penalty_factor) : Metaheuristic(s, maximize, objective, step), - penalized_objective_(nullptr), assignment_(s), - assignment_penalized_value_(0), old_penalized_value_(0), vars_(vars), - penalty_factor_(penalty_factor), incremental_(false) { + penalized_objective_(nullptr), + assignment_(s), + assignment_penalized_value_(0), + old_penalized_value_(0), + vars_(vars), + penalty_factor_(penalty_factor), + incremental_(false) { if (!vars.empty()) { // TODO(user): Remove scoped_array. assignment_.Add(vars_); @@ -3563,7 +3586,7 @@ bool GuidedLocalSearch::AtSolution() { if (!Metaheuristic::AtSolution()) { return false; } - if (penalized_objective_ != nullptr) { // In case no move has been found + if (penalized_objective_ != nullptr) { // In case no move has been found current_ += penalized_objective_->Value(); } assignment_.Store(); @@ -3695,13 +3718,13 @@ class BinaryGuidedLocalSearch : public GuidedLocalSearch { double penalty_factor); ~BinaryGuidedLocalSearch() override {} IntExpr *MakeElementPenalty(int index) override; - int64 AssignmentElementPenalty(const Assignment &assignment, int index) - override; - int64 AssignmentPenalty(const Assignment &assignment, int index, int64 next) - override; + int64 AssignmentElementPenalty(const Assignment &assignment, + int index) override; + int64 AssignmentPenalty(const Assignment &assignment, int index, + int64 next) override; bool EvaluateElementValue(const Assignment::IntContainer &container, - int64 index, int *container_index, int64 *penalty) - override; + int64 index, int *container_index, + int64 *penalty) override; private: int64 PenalizedValue(int64 i, int64 j); @@ -3717,15 +3740,13 @@ BinaryGuidedLocalSearch::BinaryGuidedLocalSearch( objective_function_(std::move(objective_function)) {} IntExpr *BinaryGuidedLocalSearch::MakeElementPenalty(int index) { - return solver()->MakeElement([this, index](int64 i) { - return PenalizedValue(index, i); - }, - vars_[index]); + return solver()->MakeElement( + [this, index](int64 i) { return PenalizedValue(index, i); }, + vars_[index]); } -int64 -BinaryGuidedLocalSearch::AssignmentElementPenalty(const Assignment &assignment, - int index) { +int64 BinaryGuidedLocalSearch::AssignmentElementPenalty( + const Assignment &assignment, int index) { return PenalizedValue(index, assignment.Value(vars_[index])); } @@ -3749,7 +3770,7 @@ bool BinaryGuidedLocalSearch::EvaluateElementValue( int64 BinaryGuidedLocalSearch::PenalizedValue(int64 i, int64 j) { const Arc arc(i, j); const int64 penalty = penalties_->Value(arc); - if (penalty != 0) { // objective_function_->Run(i, j) can be costly + if (penalty != 0) { // objective_function_->Run(i, j) can be costly const double penalized_value_fp = penalty_factor_ * penalty * objective_function_(i, j); const int64 penalized_value = (penalized_value_fp <= kint64max) @@ -3774,13 +3795,13 @@ class TernaryGuidedLocalSearch : public GuidedLocalSearch { const std::vector &secondary_vars, double penalty_factor); ~TernaryGuidedLocalSearch() override {} IntExpr *MakeElementPenalty(int index) override; - int64 AssignmentElementPenalty(const Assignment &assignment, int index) - override; - int64 AssignmentPenalty(const Assignment &assignment, int index, int64 next) - override; + int64 AssignmentElementPenalty(const Assignment &assignment, + int index) override; + int64 AssignmentPenalty(const Assignment &assignment, int index, + int64 next) override; bool EvaluateElementValue(const Assignment::IntContainer &container, - int64 index, int *container_index, int64 *penalty) - override; + int64 index, int *container_index, + int64 *penalty) override; private: int64 PenalizedValue(int64 i, int64 j, int64 k); @@ -3806,15 +3827,13 @@ TernaryGuidedLocalSearch::TernaryGuidedLocalSearch( } IntExpr *TernaryGuidedLocalSearch::MakeElementPenalty(int index) { - return solver()->MakeElement([this, index](int64 i, int64 j) { - return PenalizedValue(index, i, j); - }, - vars_[index], secondary_vars_[index]); + return solver()->MakeElement( + [this, index](int64 i, int64 j) { return PenalizedValue(index, i, j); }, + vars_[index], secondary_vars_[index]); } -int64 -TernaryGuidedLocalSearch::AssignmentElementPenalty(const Assignment &assignment, - int index) { +int64 TernaryGuidedLocalSearch::AssignmentElementPenalty( + const Assignment &assignment, int index) { return PenalizedValue(index, assignment.Value(vars_[index]), assignment.Value(secondary_vars_[index])); } @@ -3842,7 +3861,7 @@ bool TernaryGuidedLocalSearch::EvaluateElementValue( int64 TernaryGuidedLocalSearch::PenalizedValue(int64 i, int64 j, int64 k) { const Arc arc(i, j); const int64 penalty = penalties_->Value(arc); - if (penalty != 0) { // objective_function_(i, j, k) can be costly + if (penalty != 0) { // objective_function_(i, j, k) can be costly const double penalized_value_fp = penalty_factor_ * penalty * objective_function_(i, j, k); const int64 penalized_value = (penalized_value_fp <= kint64max) @@ -3871,24 +3890,22 @@ int64 TernaryGuidedLocalSearch::GetAssignmentSecondaryValue( return container.Element(secondary_var).Value(); } } -} // namespace +} // namespace -SearchMonitor * -Solver::MakeGuidedLocalSearch(bool maximize, IntVar *const objective, - Solver::IndexEvaluator2 objective_function, - int64 step, const std::vector &vars, - double penalty_factor) { +SearchMonitor *Solver::MakeGuidedLocalSearch( + bool maximize, IntVar *const objective, + Solver::IndexEvaluator2 objective_function, int64 step, + const std::vector &vars, double penalty_factor) { return RevAlloc(new BinaryGuidedLocalSearch( this, objective, std::move(objective_function), maximize, step, vars, penalty_factor)); } -SearchMonitor * -Solver::MakeGuidedLocalSearch(bool maximize, IntVar *const objective, - Solver::IndexEvaluator3 objective_function, - int64 step, const std::vector &vars, - const std::vector &secondary_vars, - double penalty_factor) { +SearchMonitor *Solver::MakeGuidedLocalSearch( + bool maximize, IntVar *const objective, + Solver::IndexEvaluator3 objective_function, int64 step, + const std::vector &vars, + const std::vector &secondary_vars, double penalty_factor) { return RevAlloc(new TernaryGuidedLocalSearch( this, objective, std::move(objective_function), maximize, step, vars, secondary_vars, penalty_factor)); @@ -3933,12 +3950,20 @@ void SearchLimit::TopPeriodicCheck() { RegularLimit::RegularLimit(Solver *const s, absl::Duration time, int64 branches, int64 failures, int64 solutions, bool smart_time_check, bool cumulative) - : SearchLimit(s), duration_limit_(time), + : SearchLimit(s), + duration_limit_(time), solver_time_at_limit_start_(s->Now()), - last_time_elapsed_(absl::ZeroDuration()), check_count_(0), next_check_(0), - smart_time_check_(smart_time_check), branches_(branches), - branches_offset_(0), failures_(failures), failures_offset_(0), - solutions_(solutions), solutions_offset_(0), cumulative_(cumulative) {} + last_time_elapsed_(absl::ZeroDuration()), + check_count_(0), + next_check_(0), + smart_time_check_(smart_time_check), + branches_(branches), + branches_offset_(0), + failures_(failures), + failures_offset_(0), + solutions_(solutions), + solutions_offset_(0), + cumulative_(cumulative) {} RegularLimit::~RegularLimit() {} @@ -4065,22 +4090,22 @@ absl::Duration RegularLimit::TimeElapsed() { RegularLimit *Solver::MakeTimeLimit(absl::Duration time) { return MakeLimit(time, kint64max, kint64max, kint64max, - /*smart_time_check=*/ false, /*cumulative=*/ false); + /*smart_time_check=*/false, /*cumulative=*/false); } RegularLimit *Solver::MakeBranchesLimit(int64 branches) { return MakeLimit(absl::InfiniteDuration(), branches, kint64max, kint64max, - /*smart_time_check=*/ false, /*cumulative=*/ false); + /*smart_time_check=*/false, /*cumulative=*/false); } RegularLimit *Solver::MakeFailuresLimit(int64 failures) { return MakeLimit(absl::InfiniteDuration(), kint64max, failures, kint64max, - /*smart_time_check=*/ false, /*cumulative=*/ false); + /*smart_time_check=*/false, /*cumulative=*/false); } RegularLimit *Solver::MakeSolutionsLimit(int64 solutions) { return MakeLimit(absl::InfiniteDuration(), kint64max, kint64max, solutions, - /*smart_time_check=*/ false, /*cumulative=*/ false); + /*smart_time_check=*/false, /*cumulative=*/false); } RegularLimit *Solver::MakeLimit(int64 time, int64 branches, int64 failures, @@ -4122,7 +4147,9 @@ ImprovementSearchLimit::ImprovementSearchLimit( double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance) - : SearchLimit(s), objective_var_(objective_var), maximize_(maximize), + : SearchLimit(s), + objective_var_(objective_var), + maximize_(maximize), objective_scaling_factor_(objective_scaling_factor), objective_offset_(objective_offset), improvement_rate_coefficient_(improvement_rate_coefficient), @@ -4200,9 +4227,9 @@ bool ImprovementSearchLimit::AtSolution() { const double scaled_new_objective = objective_scaling_factor_ * (new_objective + objective_offset_); - const bool is_improvement = - maximize_ ? scaled_new_objective > best_objective_ - : scaled_new_objective < best_objective_; + const bool is_improvement = maximize_ + ? scaled_new_objective > best_objective_ + : scaled_new_objective < best_objective_; if (gradient_stage_ && !is_improvement) { gradient_stage_ = false; @@ -4300,7 +4327,7 @@ class ORLimit : public SearchLimit { SearchLimit *const limit_1_; SearchLimit *const limit_2_; }; -} // namespace +} // namespace SearchLimit *Solver::MakeLimit(SearchLimit *const limit_1, SearchLimit *const limit_2) { @@ -4324,8 +4351,7 @@ CustomLimit::CustomLimit(Solver *const s, std::function limiter) : SearchLimit(s), limiter_(std::move(limiter)) {} bool CustomLimit::Check() { - if (limiter_) - return limiter_(); + if (limiter_) return limiter_(); return false; } @@ -4340,7 +4366,7 @@ void CustomLimit::Copy(const SearchLimit *const limit) { SearchLimit *CustomLimit::MakeClone() const { return solver()->RevAlloc(new CustomLimit(solver(), limiter_)); } -} // namespace +} // namespace SearchLimit *Solver::MakeCustomLimit(std::function limiter) { return RevAlloc(new CustomLimit(this, std::move(limiter))); @@ -4383,7 +4409,7 @@ class SolveOnce : public DecisionBuilder { DecisionBuilder *const db_; std::vector monitors_; }; -} // namespace +} // namespace DecisionBuilder *Solver::MakeSolveOnce(DecisionBuilder *const db) { return RevAlloc(new SolveOnce(db)); @@ -4429,9 +4455,8 @@ DecisionBuilder *Solver::MakeSolveOnce(DecisionBuilder *const db, return RevAlloc(new SolveOnce(db, monitors)); } -DecisionBuilder * -Solver::MakeSolveOnce(DecisionBuilder *const db, - const std::vector &monitors) { +DecisionBuilder *Solver::MakeSolveOnce( + DecisionBuilder *const db, const std::vector &monitors) { return RevAlloc(new SolveOnce(db, monitors)); } @@ -4442,7 +4467,10 @@ class NestedOptimize : public DecisionBuilder { public: NestedOptimize(DecisionBuilder *const db, Assignment *const solution, bool maximize, int64 step) - : db_(db), solution_(solution), maximize_(maximize), step_(step), + : db_(db), + solution_(solution), + maximize_(maximize), + step_(step), collector_(nullptr) { CHECK(db != nullptr); CHECK(solution != nullptr); @@ -4453,8 +4481,12 @@ class NestedOptimize : public DecisionBuilder { NestedOptimize(DecisionBuilder *const db, Assignment *const solution, bool maximize, int64 step, const std::vector &monitors) - : db_(db), solution_(solution), maximize_(maximize), step_(step), - monitors_(monitors), collector_(nullptr) { + : db_(db), + solution_(solution), + maximize_(maximize), + step_(step), + monitors_(monitors), + collector_(nullptr) { CHECK(db != nullptr); CHECK(solution != nullptr); CHECK(solution->HasObjective()); @@ -4496,7 +4528,7 @@ class NestedOptimize : public DecisionBuilder { std::vector monitors_; SolutionCollector *collector_; }; -} // namespace +} // namespace DecisionBuilder *Solver::MakeNestedOptimize(DecisionBuilder *const db, Assignment *const solution, @@ -4579,8 +4611,11 @@ int64 NextLuby(int i) { class LubyRestart : public SearchMonitor { public: LubyRestart(Solver *const s, int scale_factor) - : SearchMonitor(s), scale_factor_(scale_factor), iteration_(1), - current_fails_(0), next_step_(scale_factor) { + : SearchMonitor(s), + scale_factor_(scale_factor), + iteration_(1), + current_fails_(0), + next_step_(scale_factor) { CHECK_GE(scale_factor, 1); } @@ -4604,7 +4639,7 @@ class LubyRestart : public SearchMonitor { int64 current_fails_; int64 next_step_; }; -} // namespace +} // namespace SearchMonitor *Solver::MakeLubyRestart(int scale_factor) { return RevAlloc(new LubyRestart(this, scale_factor)); @@ -4637,7 +4672,7 @@ class ConstantRestart : public SearchMonitor { const int frequency_; int64 current_fails_; }; -} // namespace +} // namespace SearchMonitor *Solver::MakeConstantRestart(int frequency) { return RevAlloc(new ConstantRestart(this, frequency)); @@ -4664,9 +4699,11 @@ class SymmetryManager : public SearchMonitor { public: SymmetryManager(Solver *const s, const std::vector &visitors) - : SearchMonitor(s), visitors_(visitors), clauses_(visitors.size()), + : SearchMonitor(s), + visitors_(visitors), + clauses_(visitors.size()), decisions_(visitors.size()), - directions_(visitors.size()) { // false = left. + directions_(visitors.size()) { // false = left. for (int i = 0; i < visitors_.size(); ++i) { visitors_[i]->set_symmetry_manager_and_index(this, i); } @@ -4758,18 +4795,16 @@ void SymmetryBreaker::AddIntegerVariableEqualValueClause(IntVar *const var, symmetry_manager()->AddTermToClause(this, term); } -void -SymmetryBreaker::AddIntegerVariableGreaterOrEqualValueClause(IntVar *const var, - int64 value) { +void SymmetryBreaker::AddIntegerVariableGreaterOrEqualValueClause( + IntVar *const var, int64 value) { CHECK(var != nullptr); Solver *const solver = var->solver(); IntVar *const term = solver->MakeIsGreaterOrEqualCstVar(var, value); symmetry_manager()->AddTermToClause(this, term); } -void -SymmetryBreaker::AddIntegerVariableLessOrEqualValueClause(IntVar *const var, - int64 value) { +void SymmetryBreaker::AddIntegerVariableLessOrEqualValueClause( + IntVar *const var, int64 value) { CHECK(var != nullptr); Solver *const solver = var->solver(); IntVar *const term = solver->MakeIsLessOrEqualCstVar(var, value); @@ -4778,8 +4813,8 @@ SymmetryBreaker::AddIntegerVariableLessOrEqualValueClause(IntVar *const var, // ----- API ----- -SearchMonitor * -Solver::MakeSymmetryManager(const std::vector &visitors) { +SearchMonitor *Solver::MakeSymmetryManager( + const std::vector &visitors) { return RevAlloc(new SymmetryManager(this, visitors)); } @@ -4818,4 +4853,4 @@ SearchMonitor *Solver::MakeSymmetryManager(SymmetryBreaker *const v1, visitors.push_back(v4); return MakeSymmetryManager(visitors); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/table.cc b/ortools/constraint_solver/table.cc index ab005ad273..1a1653d297 100644 --- a/ortools/constraint_solver/table.cc +++ b/ortools/constraint_solver/table.cc @@ -36,7 +36,7 @@ namespace operations_research { namespace { // ----- Presolve helpers ----- // TODO(user): Move this out of this file. -struct AffineTransformation { // y == a*x + b. +struct AffineTransformation { // y == a*x + b. AffineTransformation() : a(1), b(0) {} AffineTransformation(int64 aa, int64 bb) : a(aa), b(bb) { CHECK_NE(a, 0); } int64 a; @@ -69,7 +69,7 @@ struct AffineTransformation { // y == a*x + b. // TODO(user): Move this out too. class VarLinearizer : public ModelParser { -public: + public: VarLinearizer() : target_var_(nullptr), transformation_(nullptr) {} ~VarLinearizer() override {} @@ -113,7 +113,7 @@ public: std::string DebugString() const override { return "VarLinearizer"; } -private: + private: void AddConstant(int64 constant) { transformation_->b += constant * multipliers_.back(); } @@ -150,12 +150,17 @@ static const int kBitsInUint64 = 64; // tuple that supports it. class BasePositiveTableConstraint : public Constraint { -public: + public: BasePositiveTableConstraint(Solver *const s, const std::vector &vars, const IntTupleSet &tuples) - : Constraint(s), tuple_count_(tuples.NumTuples()), arity_(vars.size()), - vars_(arity_), holes_(arity_), iterators_(arity_), tuples_(tuples), + : Constraint(s), + tuple_count_(tuples.NumTuples()), + arity_(vars.size()), + vars_(arity_), + holes_(arity_), + iterators_(arity_), + tuples_(tuples), transformations_(arity_) { // This constraint is intensive on domain and holes iterations on // variables. Thus we can visit all variables to get to the @@ -192,15 +197,15 @@ public: visitor->EndVisitConstraint(ModelVisitor::kAllowedAssignments, this); } -protected: + protected: bool TupleValue(int tuple_index, int var_index, int64 *const value) const { - return transformations_[var_index] - .Reverse(tuples_.Value(tuple_index, var_index), value); + return transformations_[var_index].Reverse( + tuples_.Value(tuple_index, var_index), value); } int64 UnsafeTupleValue(int tuple_index, int var_index) const { - return transformations_[var_index] - .UnsafeReverse(tuples_.Value(tuple_index, var_index)); + return transformations_[var_index].UnsafeReverse( + tuples_.Value(tuple_index, var_index)); } bool IsTupleSupported(int tuple_index) { @@ -221,7 +226,7 @@ protected: std::vector iterators_; std::vector to_remove_; -private: + private: // All allowed tuples. const IntTupleSet tuples_; // The set of affine transformations that describe the @@ -230,7 +235,7 @@ private: }; class PositiveTableConstraint : public BasePositiveTableConstraint { -public: + public: typedef absl::flat_hash_map > ValueBitset; PositiveTableConstraint(Solver *const s, const std::vector &vars, @@ -358,7 +363,7 @@ public: JoinDebugStringPtr(vars_, ", "), tuple_count_); } -protected: + protected: void InitializeMask(int tuple_index) { std::vector cache(arity_); for (int var_index = 0; var_index < arity_; ++var_index) { @@ -385,16 +390,22 @@ protected: // ----- Compact Tables ----- class CompactPositiveTableConstraint : public BasePositiveTableConstraint { -public: + public: CompactPositiveTableConstraint(Solver *const s, const std::vector &vars, const IntTupleSet &tuples) : BasePositiveTableConstraint(s, vars, tuples), word_length_(BitLength64(tuples.NumTuples())), - active_tuples_(tuples.NumTuples()), masks_(arity_), - mask_starts_(arity_), mask_ends_(arity_), original_min_(arity_, 0), - temp_mask_(word_length_, 0), supports_(arity_), demon_(nullptr), - touched_var_(-1), var_sizes_(arity_, 0) {} + active_tuples_(tuples.NumTuples()), + masks_(arity_), + mask_starts_(arity_), + mask_ends_(arity_), + original_min_(arity_, 0), + temp_mask_(word_length_, 0), + supports_(arity_), + demon_(nullptr), + touched_var_(-1), + var_sizes_(arity_, 0) {} ~CompactPositiveTableConstraint() override {} @@ -437,7 +448,7 @@ public: // In that case, if only one var was touched, as propagation is // exact, we do not need to recheck that variable. if (var_index == touched_var_) { - touched_var_ = -1; // Clean now, it is a 1 time flag. + touched_var_ = -1; // Clean now, it is a 1 time flag. continue; } IntVar *const var = vars_[var_index]; @@ -446,84 +457,84 @@ public: // The domain iterator is very slow, let's try to see if we can // work our way around. switch (var_size) { - case 1: { - if (!Supported(var_index, var->Min() - original_min)) { - solver()->Fail(); - } - break; - } - case 2: { - const int64 var_min = var->Min(); - const int64 var_max = var->Max(); - const bool min_support = Supported(var_index, var_min - original_min); - const bool max_support = Supported(var_index, var_max - original_min); - if (!min_support) { - if (!max_support) { + case 1: { + if (!Supported(var_index, var->Min() - original_min)) { solver()->Fail(); - } else { - var->SetValue(var_max); + } + break; + } + case 2: { + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + const bool min_support = Supported(var_index, var_min - original_min); + const bool max_support = Supported(var_index, var_max - original_min); + if (!min_support) { + if (!max_support) { + solver()->Fail(); + } else { + var->SetValue(var_max); + var_sizes_.SetValue(solver(), var_index, 1); + } + } else if (!max_support) { + var->SetValue(var_min); var_sizes_.SetValue(solver(), var_index, 1); } - } else if (!max_support) { - var->SetValue(var_min); - var_sizes_.SetValue(solver(), var_index, 1); + break; } - break; - } - default: { - to_remove_.clear(); - const int64 var_min = var->Min(); - const int64 var_max = var->Max(); - int64 new_min = var_min; - int64 new_max = var_max; - // If the domain of a variable is an interval, it is much - // faster to iterate on that interval instead of using the - // iterator. - if (var_max - var_min + 1 == var_size) { - for (; new_min <= var_max; ++new_min) { - if (Supported(var_index, new_min - original_min)) { - break; - } - } - for (; new_max >= new_min; --new_max) { - if (Supported(var_index, new_max - original_min)) { - break; - } - } - var->SetRange(new_min, new_max); - for (int64 value = new_min + 1; value < new_max; ++value) { - if (!Supported(var_index, value - original_min)) { - to_remove_.push_back(value); - } - } - } else { // Domain is sparse. - // Let's not collect all values below the first supported - // value as this can easily and more rapidly be taken care - // of by a SetRange() call. - new_min = kint64max; // escape value. - for (const int64 value : InitAndGetValues(iterators_[var_index])) { - if (!Supported(var_index, value - original_min)) { - to_remove_.push_back(value); - } else { - if (new_min == kint64max) { - new_min = value; - // This will be covered by the SetRange. - to_remove_.clear(); + default: { + to_remove_.clear(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + int64 new_min = var_min; + int64 new_max = var_max; + // If the domain of a variable is an interval, it is much + // faster to iterate on that interval instead of using the + // iterator. + if (var_max - var_min + 1 == var_size) { + for (; new_min <= var_max; ++new_min) { + if (Supported(var_index, new_min - original_min)) { + break; } - new_max = value; } + for (; new_max >= new_min; --new_max) { + if (Supported(var_index, new_max - original_min)) { + break; + } + } + var->SetRange(new_min, new_max); + for (int64 value = new_min + 1; value < new_max; ++value) { + if (!Supported(var_index, value - original_min)) { + to_remove_.push_back(value); + } + } + } else { // Domain is sparse. + // Let's not collect all values below the first supported + // value as this can easily and more rapidly be taken care + // of by a SetRange() call. + new_min = kint64max; // escape value. + for (const int64 value : InitAndGetValues(iterators_[var_index])) { + if (!Supported(var_index, value - original_min)) { + to_remove_.push_back(value); + } else { + if (new_min == kint64max) { + new_min = value; + // This will be covered by the SetRange. + to_remove_.clear(); + } + new_max = value; + } + } + var->SetRange(new_min, new_max); + // Trim the to_remove vector. + int index = to_remove_.size() - 1; + while (index >= 0 && to_remove_[index] > new_max) { + index--; + } + to_remove_.resize(index + 1); } - var->SetRange(new_min, new_max); - // Trim the to_remove vector. - int index = to_remove_.size() - 1; - while (index >= 0 && to_remove_[index] > new_max) { - index--; - } - to_remove_.resize(index + 1); + var->RemoveValues(to_remove_); + var_sizes_.SetValue(solver(), var_index, var->Size()); } - var->RemoveValues(to_remove_); - var_sizes_.SetValue(solver(), var_index, var->Size()); - } } } } @@ -544,62 +555,63 @@ public: const int64 var_max = var->Max(); switch (var_size) { - case 1: { - changed = AndMaskWithActive(masks_[var_index][var_min - omin]); - break; - } - case 2: { - SetTempMask(var_index, var_min - omin); - OrTempMask(var_index, var_max - omin); - changed = AndMaskWithActive(temp_mask_); - break; - } - default: { - const int64 estimated_hole_size = var_sizes_.Value(var_index) - var_size; - const int64 old_min = var->OldMin(); - const int64 old_max = var->OldMax(); - // Rough estimation of the number of operation if we scan - // deltas in the domain of the variable. - const int64 number_of_operations = - estimated_hole_size + var_min - old_min + old_max - var_max; - if (number_of_operations < var_size) { - // Let's scan the removed values since last run. - for (int64 value = old_min; value < var_min; ++value) { - changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); - } - for (const int64 value : InitAndGetValues(holes_[var_index])) { - changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); - } - for (int64 value = var_max + 1; value <= old_max; ++value) { - changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); - } - } else { - ClearTempMask(); - // Let's build the mask of supported tuples from the current - // domain. - if (var_max - var_min + 1 == var_size) { // Contiguous. - for (int64 value = var_min; value <= var_max; ++value) { - OrTempMask(var_index, value - omin); + case 1: { + changed = AndMaskWithActive(masks_[var_index][var_min - omin]); + break; + } + case 2: { + SetTempMask(var_index, var_min - omin); + OrTempMask(var_index, var_max - omin); + changed = AndMaskWithActive(temp_mask_); + break; + } + default: { + const int64 estimated_hole_size = + var_sizes_.Value(var_index) - var_size; + const int64 old_min = var->OldMin(); + const int64 old_max = var->OldMax(); + // Rough estimation of the number of operation if we scan + // deltas in the domain of the variable. + const int64 number_of_operations = + estimated_hole_size + var_min - old_min + old_max - var_max; + if (number_of_operations < var_size) { + // Let's scan the removed values since last run. + for (int64 value = old_min; value < var_min; ++value) { + changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); + } + for (const int64 value : InitAndGetValues(holes_[var_index])) { + changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); + } + for (int64 value = var_max + 1; value <= old_max; ++value) { + changed |= SubtractMaskFromActive(masks_[var_index][value - omin]); } } else { - for (const int64 value : InitAndGetValues(iterators_[var_index])) { - OrTempMask(var_index, value - omin); + ClearTempMask(); + // Let's build the mask of supported tuples from the current + // domain. + if (var_max - var_min + 1 == var_size) { // Contiguous. + for (int64 value = var_min; value <= var_max; ++value) { + OrTempMask(var_index, value - omin); + } + } else { + for (const int64 value : InitAndGetValues(iterators_[var_index])) { + OrTempMask(var_index, value - omin); + } } + // Then we and this mask with active_tuples_. + changed = AndMaskWithActive(temp_mask_); } - // Then we and this mask with active_tuples_. - changed = AndMaskWithActive(temp_mask_); + // We maintain the size of the variables incrementally (when it + // is > 2). + var_sizes_.SetValue(solver(), var_index, var_size); } - // We maintain the size of the variables incrementally (when it - // is > 2). - var_sizes_.SetValue(solver(), var_index, var_size); - } } // We push the propagate method only if something has changed. if (changed) { if (touched_var_ == -1 || touched_var_ == var_index) { touched_var_ = var_index; } else { - touched_var_ = -2; // more than one var. + touched_var_ = -2; // more than one var. } EnqueueDelayedDemon(demon_); } @@ -610,7 +622,7 @@ public: JoinDebugStringPtr(vars_, ", "), tuple_count_); } -private: + private: // ----- Initialization ----- void BuildMasks() { @@ -791,12 +803,16 @@ private: // TODO(user): regroup code with CompactPositiveTableConstraint. class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { -public: + public: SmallCompactPositiveTableConstraint(Solver *const s, const std::vector &vars, const IntTupleSet &tuples) - : BasePositiveTableConstraint(s, vars, tuples), active_tuples_(0), - stamp_(0), masks_(arity_), original_min_(arity_, 0), demon_(nullptr), + : BasePositiveTableConstraint(s, vars, tuples), + active_tuples_(0), + stamp_(0), + masks_(arity_), + original_min_(arity_, 0), + demon_(nullptr), touched_var_(-1) { CHECK_GE(tuple_count_, 0); CHECK_GE(arity_, 0); @@ -902,7 +918,7 @@ public: // In that case, if only one var was touched, as propagation is // exact, we do not need to recheck that variable. if (var_index == touched_var_) { - touched_var_ = -1; // Clean it, it is a one time flag. + touched_var_ = -1; // Clean it, it is a one time flag. continue; } const std::vector &var_mask = masks_[var_index]; @@ -910,84 +926,84 @@ public: IntVar *const var = vars_[var_index]; const int64 var_size = var->Size(); switch (var_size) { - case 1: { - if ((var_mask[var->Min() - original_min] & actives) == 0) { - // The difference with the non-small version of the table - // is that checking the validity of the resulting active - // tuples is cheap. Therefore we do not delay the check - // code. - solver()->Fail(); - } - break; - } - case 2: { - const int64 var_min = var->Min(); - const int64 var_max = var->Max(); - const bool min_support = - (var_mask[var_min - original_min] & actives) != 0; - const bool max_support = - (var_mask[var_max - original_min] & actives) != 0; - if (!min_support && !max_support) { - solver()->Fail(); - } else if (!min_support) { - var->SetValue(var_max); - } else if (!max_support) { - var->SetValue(var_min); - } - break; - } - default: { - to_remove_.clear(); - const int64 var_min = var->Min(); - const int64 var_max = var->Max(); - int64 new_min = var_min; - int64 new_max = var_max; - if (var_max - var_min + 1 == var_size) { - // Contiguous case. - for (; new_min <= var_max; ++new_min) { - if ((var_mask[new_min - original_min] & actives) != 0) { - break; - } - } - for (; new_max >= new_min; --new_max) { - if ((var_mask[new_max - original_min] & actives) != 0) { - break; - } - } - var->SetRange(new_min, new_max); - for (int64 value = new_min + 1; value < new_max; ++value) { - if ((var_mask[value - original_min] & actives) == 0) { - to_remove_.push_back(value); - } - } - } else { - bool min_set = false; - int last_size = 0; - for (const int64 value : InitAndGetValues(iterators_[var_index])) { - // The iterator is not safe w.r.t. deletion. Thus we - // postpone all value removals. - if ((var_mask[value - original_min] & actives) == 0) { - if (min_set) { - to_remove_.push_back(value); - } - } else { - if (!min_set) { - new_min = value; - min_set = true; - } - new_max = value; - last_size = to_remove_.size(); - } - } - if (min_set) { - var->SetRange(new_min, new_max); - } else { + case 1: { + if ((var_mask[var->Min() - original_min] & actives) == 0) { + // The difference with the non-small version of the table + // is that checking the validity of the resulting active + // tuples is cheap. Therefore we do not delay the check + // code. solver()->Fail(); } - to_remove_.resize(last_size); + break; + } + case 2: { + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + const bool min_support = + (var_mask[var_min - original_min] & actives) != 0; + const bool max_support = + (var_mask[var_max - original_min] & actives) != 0; + if (!min_support && !max_support) { + solver()->Fail(); + } else if (!min_support) { + var->SetValue(var_max); + } else if (!max_support) { + var->SetValue(var_min); + } + break; + } + default: { + to_remove_.clear(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + int64 new_min = var_min; + int64 new_max = var_max; + if (var_max - var_min + 1 == var_size) { + // Contiguous case. + for (; new_min <= var_max; ++new_min) { + if ((var_mask[new_min - original_min] & actives) != 0) { + break; + } + } + for (; new_max >= new_min; --new_max) { + if ((var_mask[new_max - original_min] & actives) != 0) { + break; + } + } + var->SetRange(new_min, new_max); + for (int64 value = new_min + 1; value < new_max; ++value) { + if ((var_mask[value - original_min] & actives) == 0) { + to_remove_.push_back(value); + } + } + } else { + bool min_set = false; + int last_size = 0; + for (const int64 value : InitAndGetValues(iterators_[var_index])) { + // The iterator is not safe w.r.t. deletion. Thus we + // postpone all value removals. + if ((var_mask[value - original_min] & actives) == 0) { + if (min_set) { + to_remove_.push_back(value); + } + } else { + if (!min_set) { + new_min = value; + min_set = true; + } + new_max = value; + last_size = to_remove_.size(); + } + } + if (min_set) { + var->SetRange(new_min, new_max); + } else { + solver()->Fail(); + } + to_remove_.resize(last_size); + } + var->RemoveValues(to_remove_); } - var->RemoveValues(to_remove_); - } } } } @@ -1000,71 +1016,71 @@ public: const int64 original_min = original_min_[var_index]; const int64 var_size = var->Size(); switch (var_size) { - case 1: { - ApplyMask(var_index, masks_[var_index][var->Min() - original_min]); - return; - } - case 2: { - ApplyMask(var_index, masks_[var_index][var->Min() - original_min] | - masks_[var_index][var->Max() - original_min]); - return; - } - default: { - // We first collect the complete set of tuples to blank out in - // temp_mask. - const std::vector &var_mask = masks_[var_index]; - const int64 old_min = var->OldMin(); - const int64 old_max = var->OldMax(); - const int64 var_min = var->Min(); - const int64 var_max = var->Max(); - const bool contiguous = var_size == var_max - var_min + 1; - const bool nearly_contiguous = - var_size > (var_max - var_min + 1) * 7 / 10; - - // Count the number of masks to collect to compare the deduction - // vs the construction of the new active bitset. - // TODO(user): Implement HolesSize() on IntVar* and use it - // to remove this code and the var_sizes in the non_small - // version. - uint64 hole_mask = 0; - if (!contiguous) { - for (const int64 value : InitAndGetValues(holes_[var_index])) { - hole_mask |= var_mask[value - original_min]; - } + case 1: { + ApplyMask(var_index, masks_[var_index][var->Min() - original_min]); + return; } - const int64 hole_operations = var_min - old_min + old_max - var_max; - // We estimate the domain iterator to be 4x slower. - const int64 domain_operations = contiguous ? var_size : 4 * var_size; - if (hole_operations < domain_operations) { - for (int64 value = old_min; value < var_min; ++value) { - hole_mask |= var_mask[value - original_min]; - } - for (int64 value = var_max + 1; value <= old_max; ++value) { - hole_mask |= var_mask[value - original_min]; - } - // We reverse the mask as this was negative information. - ApplyMask(var_index, ~hole_mask); - } else { - uint64 domain_mask = 0; - if (contiguous) { - for (int64 value = var_min; value <= var_max; ++value) { - domain_mask |= var_mask[value - original_min]; + case 2: { + ApplyMask(var_index, masks_[var_index][var->Min() - original_min] | + masks_[var_index][var->Max() - original_min]); + return; + } + default: { + // We first collect the complete set of tuples to blank out in + // temp_mask. + const std::vector &var_mask = masks_[var_index]; + const int64 old_min = var->OldMin(); + const int64 old_max = var->OldMax(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + const bool contiguous = var_size == var_max - var_min + 1; + const bool nearly_contiguous = + var_size > (var_max - var_min + 1) * 7 / 10; + + // Count the number of masks to collect to compare the deduction + // vs the construction of the new active bitset. + // TODO(user): Implement HolesSize() on IntVar* and use it + // to remove this code and the var_sizes in the non_small + // version. + uint64 hole_mask = 0; + if (!contiguous) { + for (const int64 value : InitAndGetValues(holes_[var_index])) { + hole_mask |= var_mask[value - original_min]; } - } else if (nearly_contiguous) { - for (int64 value = var_min; value <= var_max; ++value) { - if (var->Contains(value)) { + } + const int64 hole_operations = var_min - old_min + old_max - var_max; + // We estimate the domain iterator to be 4x slower. + const int64 domain_operations = contiguous ? var_size : 4 * var_size; + if (hole_operations < domain_operations) { + for (int64 value = old_min; value < var_min; ++value) { + hole_mask |= var_mask[value - original_min]; + } + for (int64 value = var_max + 1; value <= old_max; ++value) { + hole_mask |= var_mask[value - original_min]; + } + // We reverse the mask as this was negative information. + ApplyMask(var_index, ~hole_mask); + } else { + uint64 domain_mask = 0; + if (contiguous) { + for (int64 value = var_min; value <= var_max; ++value) { + domain_mask |= var_mask[value - original_min]; + } + } else if (nearly_contiguous) { + for (int64 value = var_min; value <= var_max; ++value) { + if (var->Contains(value)) { + domain_mask |= var_mask[value - original_min]; + } + } + } else { + for (const int64 value : InitAndGetValues(iterators_[var_index])) { domain_mask |= var_mask[value - original_min]; } } - } else { - for (const int64 value : InitAndGetValues(iterators_[var_index])) { - domain_mask |= var_mask[value - original_min]; - } + ApplyMask(var_index, domain_mask); } - ApplyMask(var_index, domain_mask); } } - } } std::string DebugString() const override { @@ -1073,7 +1089,7 @@ public: JoinDebugStringPtr(vars_, ", "), tuple_count_); } -private: + private: void ApplyMask(int var_index, uint64 mask) { if ((~mask & active_tuples_) != 0) { // Check if we need to save the active_tuples in this node. @@ -1088,7 +1104,7 @@ private: if (touched_var_ == -1 || touched_var_ == var_index) { touched_var_ = var_index; } else { - touched_var_ = -2; // more than one var. + touched_var_ = -2; // more than one var. } EnqueueDelayedDemon(demon_); } else { @@ -1112,7 +1128,7 @@ private: }; bool HasCompactDomains(const std::vector &vars) { - return true; // Always assume compact table. + return true; // Always assume compact table. } // ---------- Deterministic Finite Automaton ---------- @@ -1123,21 +1139,27 @@ bool HasCompactDomains(const std::vector &vars) { // (state[i], var[i], state[i+1]) in the transition table. // There is only one possible transition for a state/value pair. class TransitionConstraint : public Constraint { -public: + public: static const int kStatePosition; static const int kNextStatePosition; static const int kTransitionTupleSize; TransitionConstraint(Solver *const s, const std::vector &vars, const IntTupleSet &transition_table, int64 initial_state, const std::vector &final_states) - : Constraint(s), vars_(vars), transition_table_(transition_table), - initial_state_(initial_state), final_states_(final_states) {} + : Constraint(s), + vars_(vars), + transition_table_(transition_table), + initial_state_(initial_state), + final_states_(final_states) {} TransitionConstraint(Solver *const s, const std::vector &vars, const IntTupleSet &transition_table, int64 initial_state, const std::vector &final_states) - : Constraint(s), vars_(vars), transition_table_(transition_table), - initial_state_(initial_state), final_states_(final_states.size()) { + : Constraint(s), + vars_(vars), + transition_table_(transition_table), + initial_state_(initial_state), + final_states_(final_states.size()) { for (int i = 0; i < final_states.size(); ++i) { final_states_[i] = final_states[i]; } @@ -1209,7 +1231,7 @@ public: initial_state_, absl::StrJoin(final_states_, ", ")); } -private: + private: // Variable representing transitions between states. See header file. const std::vector vars_; // The transition as tuples (state, value, next_state). @@ -1223,7 +1245,7 @@ private: const int TransitionConstraint::kStatePosition = 0; const int TransitionConstraint::kNextStatePosition = 2; const int TransitionConstraint::kTransitionTupleSize = 3; -} // namespace +} // namespace // --------- API ---------- @@ -1254,4 +1276,4 @@ Constraint *Solver::MakeTransitionConstraint( initial_state, final_states)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/timetabling.cc b/ortools/constraint_solver/timetabling.cc index 51d4273c4b..984d7c54cb 100644 --- a/ortools/constraint_solver/timetabling.cc +++ b/ortools/constraint_solver/timetabling.cc @@ -25,18 +25,18 @@ namespace operations_research { // ----- interval date ----- namespace { -const char *kUnaryNames[] = { "ENDS_AFTER", "ENDS_AT", "ENDS_BEFORE", - "STARTS_AFTER", "STARTS_AT", "STARTS_BEFORE", - "CROSS_DATE", "AVOID_DATE", }; +const char *kUnaryNames[] = { + "ENDS_AFTER", "ENDS_AT", "ENDS_BEFORE", "STARTS_AFTER", + "STARTS_AT", "STARTS_BEFORE", "CROSS_DATE", "AVOID_DATE", +}; -const char *kBinaryNames[] = { "ENDS_AFTER_END", "ENDS_AFTER_START", - "ENDS_AT_END", "ENDS_AT_START", - "STARTS_AFTER_END", "STARTS_AFTER_START", - "STARTS_AT_END", "STARTS_AT_START", - "STAYS_IN_SYNC" }; +const char *kBinaryNames[] = { + "ENDS_AFTER_END", "ENDS_AFTER_START", "ENDS_AT_END", + "ENDS_AT_START", "STARTS_AFTER_END", "STARTS_AFTER_START", + "STARTS_AT_END", "STARTS_AT_START", "STAYS_IN_SYNC"}; class IntervalUnaryRelation : public Constraint { -public: + public: IntervalUnaryRelation(Solver *const s, IntervalVar *const t, int64 d, Solver::UnaryIntervalRelation rel) : Constraint(s), t_(t), d_(d), rel_(rel) {} @@ -59,7 +59,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIntervalUnaryRelation, this); } -private: + private: IntervalVar *const t_; const int64 d_; const Solver::UnaryIntervalRelation rel_; @@ -75,40 +75,40 @@ void IntervalUnaryRelation::Post() { void IntervalUnaryRelation::InitialPropagate() { if (t_->MayBePerformed()) { switch (rel_) { - case Solver::ENDS_AFTER: - t_->SetEndMin(d_); - break; - case Solver::ENDS_AT: - t_->SetEndRange(d_, d_); - break; - case Solver::ENDS_BEFORE: - t_->SetEndMax(d_); - break; - case Solver::STARTS_AFTER: - t_->SetStartMin(d_); - break; - case Solver::STARTS_AT: - t_->SetStartRange(d_, d_); - break; - - case Solver::STARTS_BEFORE: - t_->SetStartMax(d_); - break; - case Solver::CROSS_DATE: - t_->SetStartMax(d_); - t_->SetEndMin(d_); - break; - case Solver::AVOID_DATE: - if (t_->EndMin() > d_) { - t_->SetStartMin(d_); - } else if (t_->StartMax() < d_) { + case Solver::ENDS_AFTER: + t_->SetEndMin(d_); + break; + case Solver::ENDS_AT: + t_->SetEndRange(d_, d_); + break; + case Solver::ENDS_BEFORE: t_->SetEndMax(d_); - } - break; + break; + case Solver::STARTS_AFTER: + t_->SetStartMin(d_); + break; + case Solver::STARTS_AT: + t_->SetStartRange(d_, d_); + break; + + case Solver::STARTS_BEFORE: + t_->SetStartMax(d_); + break; + case Solver::CROSS_DATE: + t_->SetStartMax(d_); + t_->SetEndMin(d_); + break; + case Solver::AVOID_DATE: + if (t_->EndMin() > d_) { + t_->SetStartMin(d_); + } else if (t_->StartMax() < d_) { + t_->SetEndMax(d_); + } + break; } } } -} // namespace +} // namespace Constraint *Solver::MakeIntervalVarRelation(IntervalVar *const t, Solver::UnaryIntervalRelation r, @@ -120,7 +120,7 @@ Constraint *Solver::MakeIntervalVarRelation(IntervalVar *const t, namespace { class IntervalBinaryRelation : public Constraint { -public: + public: IntervalBinaryRelation(Solver *const s, IntervalVar *const t1, IntervalVar *const t2, Solver::BinaryIntervalRelation rel, int64 delay) @@ -144,7 +144,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIntervalBinaryRelation, this); } -private: + private: IntervalVar *const t1_; IntervalVar *const t2_; const Solver::BinaryIntervalRelation rel_; @@ -163,71 +163,71 @@ void IntervalBinaryRelation::Post() { void IntervalBinaryRelation::InitialPropagate() { if (t2_->MustBePerformed() && t1_->MayBePerformed()) { switch (rel_) { - case Solver::ENDS_AFTER_END: - t1_->SetEndMin(t2_->EndMin() + delay_); - break; - case Solver::ENDS_AFTER_START: - t1_->SetEndMin(t2_->StartMin() + delay_); - break; - case Solver::ENDS_AT_END: - t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); - break; - case Solver::ENDS_AT_START: - t1_->SetEndRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); - break; - case Solver::STARTS_AFTER_END: - t1_->SetStartMin(t2_->EndMin() + delay_); - break; - case Solver::STARTS_AFTER_START: - t1_->SetStartMin(t2_->StartMin() + delay_); - break; - case Solver::STARTS_AT_END: - t1_->SetStartRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); - break; - case Solver::STARTS_AT_START: - t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); - break; - case Solver::STAYS_IN_SYNC: - t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); - t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); - break; + case Solver::ENDS_AFTER_END: + t1_->SetEndMin(t2_->EndMin() + delay_); + break; + case Solver::ENDS_AFTER_START: + t1_->SetEndMin(t2_->StartMin() + delay_); + break; + case Solver::ENDS_AT_END: + t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); + break; + case Solver::ENDS_AT_START: + t1_->SetEndRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); + break; + case Solver::STARTS_AFTER_END: + t1_->SetStartMin(t2_->EndMin() + delay_); + break; + case Solver::STARTS_AFTER_START: + t1_->SetStartMin(t2_->StartMin() + delay_); + break; + case Solver::STARTS_AT_END: + t1_->SetStartRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); + break; + case Solver::STARTS_AT_START: + t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); + break; + case Solver::STAYS_IN_SYNC: + t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_); + t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_); + break; } } if (t1_->MustBePerformed() && t2_->MayBePerformed()) { switch (rel_) { - case Solver::ENDS_AFTER_END: - t2_->SetEndMax(t1_->EndMax() - delay_); - break; - case Solver::ENDS_AFTER_START: - t2_->SetStartMax(t1_->EndMax() - delay_); - break; - case Solver::ENDS_AT_END: - t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); - break; - case Solver::ENDS_AT_START: - t2_->SetStartRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); - break; - case Solver::STARTS_AFTER_END: - t2_->SetEndMax(t1_->StartMax() - delay_); - break; - case Solver::STARTS_AFTER_START: - t2_->SetStartMax(t1_->StartMax() - delay_); - break; - case Solver::STARTS_AT_END: - t2_->SetEndRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); - break; - case Solver::STARTS_AT_START: - t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); - break; - case Solver::STAYS_IN_SYNC: - t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); - t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); - break; + case Solver::ENDS_AFTER_END: + t2_->SetEndMax(t1_->EndMax() - delay_); + break; + case Solver::ENDS_AFTER_START: + t2_->SetStartMax(t1_->EndMax() - delay_); + break; + case Solver::ENDS_AT_END: + t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); + break; + case Solver::ENDS_AT_START: + t2_->SetStartRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); + break; + case Solver::STARTS_AFTER_END: + t2_->SetEndMax(t1_->StartMax() - delay_); + break; + case Solver::STARTS_AFTER_START: + t2_->SetStartMax(t1_->StartMax() - delay_); + break; + case Solver::STARTS_AT_END: + t2_->SetEndRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); + break; + case Solver::STARTS_AT_START: + t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); + break; + case Solver::STAYS_IN_SYNC: + t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_); + t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_); + break; } } } -} // namespace +} // namespace Constraint *Solver::MakeIntervalVarRelation(IntervalVar *const t1, Solver::BinaryIntervalRelation r, @@ -235,10 +235,9 @@ Constraint *Solver::MakeIntervalVarRelation(IntervalVar *const t1, return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, 0)); } -Constraint * -Solver::MakeIntervalVarRelationWithDelay(IntervalVar *const t1, - Solver::BinaryIntervalRelation r, - IntervalVar *const t2, int64 delay) { +Constraint *Solver::MakeIntervalVarRelationWithDelay( + IntervalVar *const t1, Solver::BinaryIntervalRelation r, + IntervalVar *const t2, int64 delay) { return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, delay)); } @@ -246,12 +245,8 @@ Solver::MakeIntervalVarRelationWithDelay(IntervalVar *const t1, namespace { class TemporalDisjunction : public Constraint { -public: - enum State { - ONE_BEFORE_TWO, - TWO_BEFORE_ONE, - UNDECIDED - }; + public: + enum State { ONE_BEFORE_TWO, TWO_BEFORE_ONE, UNDECIDED }; TemporalDisjunction(Solver *const s, IntervalVar *const t1, IntervalVar *const t2, IntVar *const alt) @@ -277,7 +272,7 @@ public: visitor->EndVisitConstraint(ModelVisitor::kIntervalDisjunction, this); } -private: + private: IntervalVar *const t1_; IntervalVar *const t2_; IntVar *const alt_; @@ -336,38 +331,42 @@ void TemporalDisjunction::TryToDecide() { void TemporalDisjunction::RangeDemon1() { switch (state_) { - case ONE_BEFORE_TWO: { - if (t1_->MustBePerformed() && t2_->MayBePerformed()) { - t2_->SetStartMin(t1_->EndMin()); + case ONE_BEFORE_TWO: { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { + t2_->SetStartMin(t1_->EndMin()); + } + break; } - break; - } - case TWO_BEFORE_ONE: { - if (t1_->MustBePerformed() && t2_->MayBePerformed()) { - t2_->SetEndMax(t1_->StartMax()); + case TWO_BEFORE_ONE: { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { + t2_->SetEndMax(t1_->StartMax()); + } + break; + } + case UNDECIDED: { + TryToDecide(); } - break; - } - case UNDECIDED: { TryToDecide(); } } } void TemporalDisjunction::RangeDemon2() { if (t1_->MayBePerformed() || t2_->MayBePerformed()) { switch (state_) { - case ONE_BEFORE_TWO: { - if (t2_->MustBePerformed() && t1_->MayBePerformed()) { - t1_->SetEndMax(t2_->StartMax()); + case ONE_BEFORE_TWO: { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { + t1_->SetEndMax(t2_->StartMax()); + } + break; } - break; - } - case TWO_BEFORE_ONE: { - if (t2_->MustBePerformed() && t1_->MayBePerformed()) { - t1_->SetStartMin(t2_->EndMin()); + case TWO_BEFORE_ONE: { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { + t1_->SetStartMin(t2_->EndMin()); + } + break; + } + case UNDECIDED: { + TryToDecide(); } - break; - } - case UNDECIDED: { TryToDecide(); } } } } @@ -399,7 +398,7 @@ void TemporalDisjunction::Decide(State s) { RangeDemon1(); RangeDemon2(); } -} // namespace +} // namespace Constraint *Solver::MakeTemporalDisjunction(IntervalVar *const t1, IntervalVar *const t2, @@ -412,4 +411,4 @@ Constraint *Solver::MakeTemporalDisjunction(IntervalVar *const t1, return RevAlloc(new TemporalDisjunction(this, t1, t2, nullptr)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/trace.cc b/ortools/constraint_solver/trace.cc index 2447037d3d..3fa1ce362c 100644 --- a/ortools/constraint_solver/trace.cc +++ b/ortools/constraint_solver/trace.cc @@ -35,7 +35,7 @@ namespace operations_research { namespace { // ---------- Code Instrumentation ---------- class TraceIntVar : public IntVar { -public: + public: TraceIntVar(Solver *const solver, IntVar *const inner) : IntVar(solver), inner_(inner) { if (inner->HasName()) { @@ -164,12 +164,12 @@ public: return inner_->IsLessOrEqual(constant); } -private: + private: IntVar *const inner_; }; class TraceIntExpr : public IntExpr { -public: + public: TraceIntExpr(Solver *const solver, IntExpr *const inner) : IntExpr(solver), inner_(inner) { CHECK(!inner->IsVar()); @@ -223,12 +223,12 @@ public: std::string DebugString() const override { return inner_->DebugString(); } -private: + private: IntExpr *const inner_; }; class TraceIntervalVar : public IntervalVar { -public: + public: TraceIntervalVar(Solver *const solver, IntervalVar *const inner) : IntervalVar(solver, ""), inner_(inner) { if (inner->HasName()) { @@ -383,14 +383,14 @@ public: std::string DebugString() const override { return inner_->DebugString(); } -private: + private: IntervalVar *const inner_; }; // ---------- PrintTrace ---------- class PrintTrace : public PropagationMonitor { -public: + public: struct Info { explicit Info(const std::string &m) : message(m), displayed(false) {} std::string message; @@ -399,12 +399,21 @@ public: struct Context { Context() - : initial_indent(0), indent(0), in_demon(false), in_constraint(false), - in_decision_builder(false), in_decision(false), in_objective(false) {} + : initial_indent(0), + indent(0), + in_demon(false), + in_constraint(false), + in_decision_builder(false), + in_decision(false), + in_objective(false) {} explicit Context(int start_indent) - : initial_indent(start_indent), indent(start_indent), in_demon(false), - in_constraint(false), in_decision_builder(false), in_decision(false), + : initial_indent(start_indent), + indent(start_indent), + in_demon(false), + in_constraint(false), + in_decision_builder(false), + in_decision(false), in_objective(false) {} bool TopLevel() const { return initial_indent == indent; } @@ -521,8 +530,8 @@ public: // ----- Propagation events ----- - void BeginConstraintInitialPropagation(Constraint *const constraint) - override { + void BeginConstraintInitialPropagation( + Constraint *const constraint) override { PushDelayedInfo( absl::StrFormat("Constraint(%s)", constraint->DebugString())); contexes_.top().in_constraint = true; @@ -533,9 +542,8 @@ public: contexes_.top().in_constraint = false; } - void BeginNestedConstraintInitialPropagation(Constraint *const parent, - Constraint *const nested) - override { + void BeginNestedConstraintInitialPropagation( + Constraint *const parent, Constraint *const nested) override { PushDelayedInfo(absl::StrFormat("Constraint(%s)", nested->DebugString())); contexes_.top().in_constraint = true; } @@ -629,11 +637,11 @@ public: absl::StrJoin(values, ", "))); } - void RemoveValues(IntVar *const var, const std::vector &values) - override { - DisplayModification( - absl::StrFormat("RemoveValues(%s, %s)", var->DebugString(), - absl::StrJoin(values, ", "))); + void RemoveValues(IntVar *const var, + const std::vector &values) override { + DisplayModification(absl::StrFormat("RemoveValues(%s, %s)", + var->DebugString(), + absl::StrJoin(values, ", "))); } // ----- IntervalVar modifiers ----- @@ -648,8 +656,8 @@ public: absl::StrFormat("SetStartMax(%s, %d)", var->DebugString(), new_max)); } - void SetStartRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetStartRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { DisplayModification(absl::StrFormat("SetStartRange(%s, [%d .. %d])", var->DebugString(), new_min, new_max)); } @@ -664,8 +672,8 @@ public: absl::StrFormat("SetEndMax(%s, %d)", var->DebugString(), new_max)); } - void SetEndRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetEndRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { DisplayModification(absl::StrFormat("SetEndRange(%s, [%d .. %d])", var->DebugString(), new_min, new_max)); } @@ -680,8 +688,8 @@ public: absl::StrFormat("SetDurationMax(%s, %d)", var->DebugString(), new_max)); } - void SetDurationRange(IntervalVar *const var, int64 new_min, int64 new_max) - override { + void SetDurationRange(IntervalVar *const var, int64 new_min, + int64 new_max) override { DisplayModification(absl::StrFormat("SetDurationRange(%s, [%d .. %d])", var->DebugString(), new_min, new_max)); } @@ -729,7 +737,7 @@ public: std::string DebugString() const override { return "PrintTrace"; } -private: + private: void PushDelayedInfo(const std::string &delayed) { if (absl::GetFlag(FLAGS_cp_full_trace)) { LOG(INFO) << Indent() << delayed << " {"; @@ -832,7 +840,7 @@ private: std::stack contexes_; }; -} // namespace +} // namespace IntExpr *Solver::RegisterIntExpr(IntExpr *const expr) { if (InstrumentsVariables()) { @@ -847,8 +855,8 @@ IntExpr *Solver::RegisterIntExpr(IntExpr *const expr) { } IntVar *Solver::RegisterIntVar(IntVar *const var) { - if (InstrumentsVariables() && var->VarType() != TRACE_VAR) { // Not already a - // trace var. + if (InstrumentsVariables() && var->VarType() != TRACE_VAR) { // Not already a + // trace var. return RevAlloc(new TraceIntVar(this, var)); } else { return var; @@ -866,4 +874,4 @@ IntervalVar *Solver::RegisterIntervalVar(IntervalVar *const var) { PropagationMonitor *BuildPrintTrace(Solver *const s) { return s->RevAlloc(new PrintTrace(s)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/utilities.cc b/ortools/constraint_solver/utilities.cc index 792116e661..a33136a6ba 100644 --- a/ortools/constraint_solver/utilities.cc +++ b/ortools/constraint_solver/utilities.cc @@ -56,7 +56,9 @@ int64 SmallRevBitSet::GetFirstOne() const { // ---------- RevBitSet ---------- RevBitSet::RevBitSet(int64 size) - : size_(size), length_(BitLength64(size)), bits_(new uint64[length_]), + : size_(size), + length_(BitLength64(size)), + bits_(new uint64[length_]), stamps_(new uint64[length_]) { DCHECK_GE(size, 1); memset(bits_, 0, sizeof(*bits_) * length_); @@ -217,8 +219,10 @@ void RevBitMatrix::ClearAll(Solver *const solver) { // ----- UnsortedNullableRevBitset ----- UnsortedNullableRevBitset::UnsortedNullableRevBitset(int bit_size) - : bit_size_(bit_size), word_size_(BitLength64(bit_size)), - bits_(word_size_, 0), active_words_(word_size_) {} + : bit_size_(bit_size), + word_size_(BitLength64(bit_size)), + bits_(word_size_, 0), + active_words_(word_size_) {} void UnsortedNullableRevBitset::Init(Solver *const solver, const std::vector &mask) { @@ -303,7 +307,7 @@ bool UnsortedNullableRevBitset::Intersects(const std::vector &mask, namespace { class PrintModelVisitor : public ModelVisitor { -public: + public: PrintModelVisitor() : indent_(0) {} ~PrintModelVisitor() override {} @@ -431,9 +435,9 @@ public: Decrease(); } - void VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntegerVariableArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { LOG(INFO) << Spaces() << arg_name << ": ["; Increase(); for (int i = 0; i < arguments.size(); ++i) { @@ -452,9 +456,9 @@ public: Decrease(); } - virtual void - VisitIntervalArgumentArray(const std::string &arg_name, - const std::vector &arguments) { + virtual void VisitIntervalArgumentArray( + const std::string &arg_name, + const std::vector &arguments) { LOG(INFO) << Spaces() << arg_name << ": ["; Increase(); for (int i = 0; i < arguments.size(); ++i) { @@ -473,9 +477,9 @@ public: Decrease(); } - virtual void - VisitSequenceArgumentArray(const std::string &arg_name, - const std::vector &arguments) { + virtual void VisitSequenceArgumentArray( + const std::string &arg_name, + const std::vector &arguments) { LOG(INFO) << Spaces() << arg_name << ": ["; Increase(); for (int i = 0; i < arguments.size(); ++i) { @@ -487,7 +491,7 @@ public: std::string DebugString() const override { return "PrintModelVisitor"; } -private: + private: void Increase() { indent_ += 2; } void Decrease() { indent_ -= 2; } @@ -513,10 +517,14 @@ private: // ---------- ModelStatisticsVisitor ----------- class ModelStatisticsVisitor : public ModelVisitor { -public: + public: ModelStatisticsVisitor() - : num_constraints_(0), num_variables_(0), num_expressions_(0), - num_casts_(0), num_intervals_(0), num_sequences_(0), + : num_constraints_(0), + num_variables_(0), + num_expressions_(0), + num_casts_(0), + num_intervals_(0), + num_sequences_(0), num_extensions_(0) {} ~ModelStatisticsVisitor() override {} @@ -616,9 +624,9 @@ public: VisitSubArgument(argument); } - void VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntegerVariableArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -630,9 +638,9 @@ public: VisitSubArgument(argument); } - void VisitIntervalArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntervalArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -644,9 +652,9 @@ public: VisitSubArgument(argument); } - void VisitSequenceArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitSequenceArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -654,7 +662,7 @@ public: std::string DebugString() const override { return "ModelStatisticsVisitor"; } -private: + private: void Register(const BaseObject *const object) { already_visited_.insert(object); } @@ -664,7 +672,8 @@ private: } // T should derive from BaseObject - template void VisitSubArgument(T *object) { + template + void VisitSubArgument(T *object) { if (!AlreadyVisited(object)) { Register(object); object->Accept(this); @@ -699,7 +708,7 @@ private: // ---------- Variable Degree Visitor --------- class VariableDegreeVisitor : public ModelVisitor { -public: + public: explicit VariableDegreeVisitor( absl::flat_hash_map *const map) : map_(map) {} @@ -748,9 +757,9 @@ public: VisitSubArgument(argument); } - void VisitIntegerVariableArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntegerVariableArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -762,9 +771,9 @@ public: VisitSubArgument(argument); } - void VisitIntervalArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitIntervalArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -776,9 +785,9 @@ public: VisitSubArgument(argument); } - void VisitSequenceArrayArgument(const std::string &arg_name, - const std::vector &arguments) - override { + void VisitSequenceArrayArgument( + const std::string &arg_name, + const std::vector &arguments) override { for (int i = 0; i < arguments.size(); ++i) { VisitSubArgument(arguments[i]); } @@ -786,15 +795,16 @@ public: std::string DebugString() const override { return "VariableDegreeVisitor"; } -private: + private: // T should derive from BaseObject - template void VisitSubArgument(T *object) { + template + void VisitSubArgument(T *object) { object->Accept(this); } absl::flat_hash_map *const map_; }; -} // namespace +} // namespace ModelVisitor *Solver::MakePrintModelVisitor() { return RevAlloc(new PrintModelVisitor); @@ -818,4 +828,4 @@ std::vector ToInt64Vector(const std::vector &input) { } return result; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/constraint_solver/visitor.cc b/ortools/constraint_solver/visitor.cc index 3e26e4755b..53743c0b3b 100644 --- a/ortools/constraint_solver/visitor.cc +++ b/ortools/constraint_solver/visitor.cc @@ -91,14 +91,13 @@ bool ArgumentHolder::HasIntegerVariableArrayArgument( return gtl::ContainsKey(integer_variable_array_argument_, arg_name); } -int64 -ArgumentHolder::FindIntegerArgumentWithDefault(const std::string &arg_name, - int64 def) const { +int64 ArgumentHolder::FindIntegerArgumentWithDefault( + const std::string &arg_name, int64 def) const { return gtl::FindWithDefault(integer_argument_, arg_name, def); } -int64 -ArgumentHolder::FindIntegerArgumentOrDie(const std::string &arg_name) const { +int64 ArgumentHolder::FindIntegerArgumentOrDie( + const std::string &arg_name) const { return gtl::FindOrDie(integer_argument_, arg_name); } @@ -112,9 +111,9 @@ IntExpr *ArgumentHolder::FindIntegerExpressionArgumentOrDie( return gtl::FindOrDie(integer_expression_argument_, arg_name); } -const std::vector & -ArgumentHolder::FindIntegerVariableArrayArgumentOrDie( - const std::string &arg_name) const { +const std::vector + &ArgumentHolder::FindIntegerVariableArrayArgumentOrDie( + const std::string &arg_name) const { return gtl::FindOrDie(integer_variable_array_argument_, arg_name); } @@ -260,4 +259,4 @@ ArgumentHolder *ModelParser::Top() const { CHECK(!holders_.empty()); return holders_.back(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/data/jobshop_scheduling_parser.cc b/ortools/data/jobshop_scheduling_parser.cc index 26362cfbd7..3597c9a373 100644 --- a/ortools/data/jobshop_scheduling_parser.cc +++ b/ortools/data/jobshop_scheduling_parser.cc @@ -67,38 +67,38 @@ bool JsspParser::ParseFile(const std::string &filename) { continue; } switch (problem_type_) { - case JSSP: { - ProcessJsspLine(line); - break; - } - case TAILLARD: { - ProcessTaillardLine(line); - break; - } - case FLEXIBLE: { - ProcessFlexibleLine(line); - break; - } - case SDST: { - ProcessSdstLine(line); - break; - } - case TARDINESS: { - ProcessTardinessLine(line); - break; - } - case PSS: { - ProcessPssLine(line); - break; - } - case EARLY_TARDY: { - ProcessEarlyTardyLine(line); - break; - } - default: { - LOG(FATAL) << "Should not be here."; - break; - } + case JSSP: { + ProcessJsspLine(line); + break; + } + case TAILLARD: { + ProcessTaillardLine(line); + break; + } + case FLEXIBLE: { + ProcessFlexibleLine(line); + break; + } + case SDST: { + ProcessSdstLine(line); + break; + } + case TARDINESS: { + ProcessTardinessLine(line); + break; + } + case PSS: { + ProcessPssLine(line); + break; + } + case EARLY_TARDY: { + ProcessEarlyTardyLine(line); + break; + } + default: { + LOG(FATAL) << "Should not be here."; + break; + } } } return parser_state_ != PARSING_ERROR; @@ -108,57 +108,61 @@ void JsspParser::ProcessJsspLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - if (words.size() == 2 && words[0] == "instance") { - problem_.set_name(words[1]); - parser_state_ = NAME_READ; - current_job_index_ = 0; - } else if (words.size() == 1 && words[0] == "1") { - problem_type_ = PSS; - } else if (words.size() == 2) { - SetJobs(strtoint32(words[0])); - SetMachines(strtoint32(words[1])); - problem_type_ = EARLY_TARDY; - parser_state_ = JOB_COUNT_READ; + case START: { + if (words.size() == 2 && words[0] == "instance") { + problem_.set_name(words[1]); + parser_state_ = NAME_READ; + current_job_index_ = 0; + } else if (words.size() == 1 && words[0] == "1") { + problem_type_ = PSS; + } else if (words.size() == 2) { + SetJobs(strtoint32(words[0])); + SetMachines(strtoint32(words[1])); + problem_type_ = EARLY_TARDY; + parser_state_ = JOB_COUNT_READ; + } + break; } - break; - } - case NAME_READ: { - if (words.size() == 2) { - SetJobs(strtoint32(words[0])); - SetMachines(strtoint32(words[1])); - problem_.set_makespan_cost_per_time_unit(1L); - parser_state_ = JOB_COUNT_READ; + case NAME_READ: { + if (words.size() == 2) { + SetJobs(strtoint32(words[0])); + SetMachines(strtoint32(words[1])); + problem_.set_makespan_cost_per_time_unit(1L); + parser_state_ = JOB_COUNT_READ; + } + break; } - break; - } - case JOB_COUNT_READ: { - CHECK_GE(words.size(), declared_machine_count_ * 2); - Job *const job = problem_.mutable_jobs(current_job_index_); - for (int i = 0; i < declared_machine_count_; ++i) { - const int machine_id = strtoint32(words[2 * i]); - const int64 duration = strtoint64(words[2 * i + 1]); - Task *const task = job->add_tasks(); - task->add_machine(machine_id); - task->add_duration(duration); + case JOB_COUNT_READ: { + CHECK_GE(words.size(), declared_machine_count_ * 2); + Job *const job = problem_.mutable_jobs(current_job_index_); + for (int i = 0; i < declared_machine_count_; ++i) { + const int machine_id = strtoint32(words[2 * i]); + const int64 duration = strtoint64(words[2 * i + 1]); + Task *const task = job->add_tasks(); + task->add_machine(machine_id); + task->add_duration(duration); + } + if (words.size() == declared_machine_count_ * 2 + 3) { + // Early Tardy problem in JET format. + const int due_date = strtoint32(words[declared_machine_count_ * 2]); + const int early_cost = + strtoint32(words[declared_machine_count_ * 2 + 1]); + const int late_cost = + strtoint32(words[declared_machine_count_ * 2 + 2]); + job->set_early_due_date(due_date); + job->set_late_due_date(due_date); + job->set_earliness_cost_per_time_unit(early_cost); + job->set_lateness_cost_per_time_unit(late_cost); + } + current_job_index_++; + if (current_job_index_ == declared_job_count_) { + parser_state_ = DONE; + } + break; } - if (words.size() == declared_machine_count_ * 2 + 3) { - // Early Tardy problem in JET format. - const int due_date = strtoint32(words[declared_machine_count_ * 2]); - const int early_cost = strtoint32(words[declared_machine_count_ * 2 + 1]); - const int late_cost = strtoint32(words[declared_machine_count_ * 2 + 2]); - job->set_early_due_date(due_date); - job->set_late_due_date(due_date); - job->set_earliness_cost_per_time_unit(early_cost); - job->set_lateness_cost_per_time_unit(late_cost); + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_; } - current_job_index_++; - if (current_job_index_ == declared_job_count_) { - parser_state_ = DONE; - } - break; - } - default: { LOG(FATAL) << "Should not be here with state " << parser_state_; } } } @@ -167,162 +171,168 @@ void JsspParser::ProcessTaillardLine(const std::string &line) { absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - if (words.size() == 2) { // Switch to SDST parser. - problem_type_ = SDST; - ProcessSdstLine(line); - return; - } else if (words.size() == 3) { // Switch to TARDINESS parser. - problem_type_ = TARDINESS; - ProcessTardinessLine(line); - return; + case START: { + if (words.size() == 2) { // Switch to SDST parser. + problem_type_ = SDST; + ProcessSdstLine(line); + return; + } else if (words.size() == 3) { // Switch to TARDINESS parser. + problem_type_ = TARDINESS; + ProcessTardinessLine(line); + return; + } + if (words.size() == 1 && strtoint32(words[0]) > 0) { + parser_state_ = JOB_COUNT_READ; + SetJobs(strtoint32(words[0])); + } + break; } - if (words.size() == 1 && strtoint32(words[0]) > 0) { - parser_state_ = JOB_COUNT_READ; - SetJobs(strtoint32(words[0])); + case JOB_COUNT_READ: { + CHECK_EQ(1, words.size()); + SetMachines(strtoint32(words[0])); + problem_.set_makespan_cost_per_time_unit(1L); + parser_state_ = MACHINE_COUNT_READ; + break; } - break; - } - case JOB_COUNT_READ: { - CHECK_EQ(1, words.size()); - SetMachines(strtoint32(words[0])); - problem_.set_makespan_cost_per_time_unit(1L); - parser_state_ = MACHINE_COUNT_READ; - break; - } - case MACHINE_COUNT_READ: { - CHECK_EQ(1, words.size()); - const int seed = strtoint32(words[0]); - problem_.set_seed(seed); - parser_state_ = SEED_READ; - break; - } - case SEED_READ: - ABSL_FALLTHROUGH_INTENDED; - case JOB_READ: { - CHECK_EQ(1, words.size()); - current_job_index_ = strtoint32(words[0]); - parser_state_ = JOB_ID_READ; - break; - } - case JOB_ID_READ: { - CHECK_EQ(1, words.size()); - parser_state_ = JOB_LENGTH_READ; - break; - } - case JOB_LENGTH_READ: { - CHECK_EQ(declared_machine_count_, words.size()); - Job *const job = problem_.mutable_jobs(current_job_index_); - for (int i = 0; i < declared_machine_count_; ++i) { - const int64 duration = strtoint64(words[i]); - Task *const task = job->add_tasks(); - task->add_machine(i); - task->add_duration(duration); + case MACHINE_COUNT_READ: { + CHECK_EQ(1, words.size()); + const int seed = strtoint32(words[0]); + problem_.set_seed(seed); + parser_state_ = SEED_READ; + break; + } + case SEED_READ: + ABSL_FALLTHROUGH_INTENDED; + case JOB_READ: { + CHECK_EQ(1, words.size()); + current_job_index_ = strtoint32(words[0]); + parser_state_ = JOB_ID_READ; + break; + } + case JOB_ID_READ: { + CHECK_EQ(1, words.size()); + parser_state_ = JOB_LENGTH_READ; + break; + } + case JOB_LENGTH_READ: { + CHECK_EQ(declared_machine_count_, words.size()); + Job *const job = problem_.mutable_jobs(current_job_index_); + for (int i = 0; i < declared_machine_count_; ++i) { + const int64 duration = strtoint64(words[i]); + Task *const task = job->add_tasks(); + task->add_machine(i); + task->add_duration(duration); + } + parser_state_ = + current_job_index_ == declared_job_count_ - 1 ? DONE : JOB_READ; + break; + } + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_; } - parser_state_ = - current_job_index_ == declared_job_count_ - 1 ? DONE : JOB_READ; - break; - } - default: { LOG(FATAL) << "Should not be here with state " << parser_state_; } } } void JsspParser::ProcessFlexibleLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - CHECK_GE(words.size(), 2); - SetJobs(strtoint32(words[0])); - SetMachines(strtoint32(words[1])); - problem_.set_makespan_cost_per_time_unit(1L); - parser_state_ = JOB_COUNT_READ; - break; - } - case JOB_COUNT_READ: { - const int operations_count = strtoint32(words[0]); - int index = 1; - Job *const job = problem_.mutable_jobs(current_job_index_); - for (int operation = 0; operation < operations_count; ++operation) { - const int alternatives_count = strtoint32(words[index++]); - Task *const task = job->add_tasks(); - for (int alt = 0; alt < alternatives_count; alt++) { - // Machine id are 1 based. - const int machine_id = strtoint32(words[index++]) - 1; - const int64 duration = strtoint64(words[index++]); - task->add_machine(machine_id); - task->add_duration(duration); + case START: { + CHECK_GE(words.size(), 2); + SetJobs(strtoint32(words[0])); + SetMachines(strtoint32(words[1])); + problem_.set_makespan_cost_per_time_unit(1L); + parser_state_ = JOB_COUNT_READ; + break; + } + case JOB_COUNT_READ: { + const int operations_count = strtoint32(words[0]); + int index = 1; + Job *const job = problem_.mutable_jobs(current_job_index_); + for (int operation = 0; operation < operations_count; ++operation) { + const int alternatives_count = strtoint32(words[index++]); + Task *const task = job->add_tasks(); + for (int alt = 0; alt < alternatives_count; alt++) { + // Machine id are 1 based. + const int machine_id = strtoint32(words[index++]) - 1; + const int64 duration = strtoint64(words[index++]); + task->add_machine(machine_id); + task->add_duration(duration); + } } + CHECK_LE(index, words.size()); // Ignore CR at the end of the line. + current_job_index_++; + if (current_job_index_ == declared_job_count_) { + parser_state_ = DONE; + } + break; } - CHECK_LE(index, words.size()); // Ignore CR at the end of the line. - current_job_index_++; - if (current_job_index_ == declared_job_count_) { - parser_state_ = DONE; + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_; } - break; - } - default: { LOG(FATAL) << "Should not be here with state " << parser_state_; } } } void JsspParser::ProcessSdstLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - if (words.size() == 2) { - SetJobs(strtoint32(words[0])); - SetMachines(strtoint32(words[1])); - problem_.set_makespan_cost_per_time_unit(1L); - parser_state_ = JOB_COUNT_READ; - current_machine_index_ = 0; + case START: { + if (words.size() == 2) { + SetJobs(strtoint32(words[0])); + SetMachines(strtoint32(words[1])); + problem_.set_makespan_cost_per_time_unit(1L); + parser_state_ = JOB_COUNT_READ; + current_machine_index_ = 0; + } + break; } - break; - } - case JOB_COUNT_READ: { - CHECK_EQ(words.size(), declared_machine_count_ * 2); - Job *const job = problem_.mutable_jobs(current_job_index_); - for (int i = 0; i < declared_machine_count_; ++i) { - const int machine_id = strtoint32(words[2 * i]); - const int64 duration = strtoint64(words[2 * i + 1]); - Task *const task = job->add_tasks(); - task->add_machine(machine_id); - task->add_duration(duration); + case JOB_COUNT_READ: { + CHECK_EQ(words.size(), declared_machine_count_ * 2); + Job *const job = problem_.mutable_jobs(current_job_index_); + for (int i = 0; i < declared_machine_count_; ++i) { + const int machine_id = strtoint32(words[2 * i]); + const int64 duration = strtoint64(words[2 * i + 1]); + Task *const task = job->add_tasks(); + task->add_machine(machine_id); + task->add_duration(duration); + } + current_job_index_++; + if (current_job_index_ == declared_job_count_) { + parser_state_ = JOBS_READ; + } + break; } - current_job_index_++; - if (current_job_index_ == declared_job_count_) { - parser_state_ = JOBS_READ; + case JOBS_READ: { + CHECK_EQ(1, words.size()); + CHECK_EQ("SSD", words[0]); + parser_state_ = SSD_READ; + break; } - break; - } - case JOBS_READ: { - CHECK_EQ(1, words.size()); - CHECK_EQ("SSD", words[0]); - parser_state_ = SSD_READ; - break; - } - case SSD_READ: { - CHECK_EQ(1, words.size()); - CHECK_EQ(words[0], absl::StrCat("M", current_machine_index_)) << line; - current_job_index_ = 0; - parser_state_ = MACHINE_READ; - break; - } - case MACHINE_READ: { - CHECK_EQ(declared_job_count_, words.size()); - Machine *const machine = problem_.mutable_machines(current_machine_index_); - for (const std::string &w : words) { - const int64 t = strtoint64(w); - machine->mutable_transition_time_matrix()->add_transition_time(t); + case SSD_READ: { + CHECK_EQ(1, words.size()); + CHECK_EQ(words[0], absl::StrCat("M", current_machine_index_)) << line; + current_job_index_ = 0; + parser_state_ = MACHINE_READ; + break; } - if (++current_job_index_ == declared_job_count_) { - parser_state_ = - ++current_machine_index_ == declared_machine_count_ ? DONE : SSD_READ; + case MACHINE_READ: { + CHECK_EQ(declared_job_count_, words.size()); + Machine *const machine = + problem_.mutable_machines(current_machine_index_); + for (const std::string &w : words) { + const int64 t = strtoint64(w); + machine->mutable_transition_time_matrix()->add_transition_time(t); + } + if (++current_job_index_ == declared_job_count_) { + parser_state_ = ++current_machine_index_ == declared_machine_count_ + ? DONE + : SSD_READ; + } + break; + } + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_ + << "with line " << line; } - break; - } - default: { - LOG(FATAL) << "Should not be here with state " << parser_state_ - << "with line " << line; - } } } @@ -330,63 +340,64 @@ void JsspParser::ProcessTardinessLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - CHECK_EQ(3, words.size()); - SetJobs(strtoint32(words[0])); - SetMachines(strtoint32(words[1])); - parser_state_ = JOB_COUNT_READ; - current_job_index_ = 0; - break; - } - case JOB_COUNT_READ: { - CHECK_GE(words.size(), 6); - Job *const job = problem_.mutable_jobs(current_job_index_); - const int64 est = strtoint64(words[0]); - if (est != 0L) { - job->mutable_earliest_start()->set_value(est); + case START: { + CHECK_EQ(3, words.size()); + SetJobs(strtoint32(words[0])); + SetMachines(strtoint32(words[1])); + parser_state_ = JOB_COUNT_READ; + current_job_index_ = 0; + break; } - job->set_late_due_date(strtoint64(words[1])); - const double weight = std::stod(words[2]); - const int64 tardiness = static_cast( - round(weight * absl::GetFlag(FLAGS_jssp_scaling_up_factor))); - job->set_lateness_cost_per_time_unit(tardiness); - const int num_operations = strtoint32(words[3]); - for (int i = 0; i < num_operations; ++i) { - const int machine_id = strtoint32(words[4 + 2 * i]) - 1; // 1 based. - const int64 duration = strtoint64(words[5 + 2 * i]); - Task *const task = job->add_tasks(); - task->add_machine(machine_id); - task->add_duration(duration); - } - current_job_index_++; - if (current_job_index_ == declared_job_count_) { - // Fix tardiness weights if all integer from start. - bool all_integral = true; - for (const Job &job : problem_.jobs()) { - if (job.lateness_cost_per_time_unit() % - absl::GetFlag(FLAGS_jssp_scaling_up_factor) != 0) { - all_integral = false; - break; - } + case JOB_COUNT_READ: { + CHECK_GE(words.size(), 6); + Job *const job = problem_.mutable_jobs(current_job_index_); + const int64 est = strtoint64(words[0]); + if (est != 0L) { + job->mutable_earliest_start()->set_value(est); } - if (all_integral) { - for (Job &job : *problem_.mutable_jobs()) { - job.set_lateness_cost_per_time_unit( - job.lateness_cost_per_time_unit() / - absl::GetFlag(FLAGS_jssp_scaling_up_factor)); - } - } else { - problem_.mutable_scaling_factor() - ->set_value(1.0L / absl::GetFlag(FLAGS_jssp_scaling_up_factor)); + job->set_late_due_date(strtoint64(words[1])); + const double weight = std::stod(words[2]); + const int64 tardiness = static_cast( + round(weight * absl::GetFlag(FLAGS_jssp_scaling_up_factor))); + job->set_lateness_cost_per_time_unit(tardiness); + const int num_operations = strtoint32(words[3]); + for (int i = 0; i < num_operations; ++i) { + const int machine_id = strtoint32(words[4 + 2 * i]) - 1; // 1 based. + const int64 duration = strtoint64(words[5 + 2 * i]); + Task *const task = job->add_tasks(); + task->add_machine(machine_id); + task->add_duration(duration); } - parser_state_ = DONE; + current_job_index_++; + if (current_job_index_ == declared_job_count_) { + // Fix tardiness weights if all integer from start. + bool all_integral = true; + for (const Job &job : problem_.jobs()) { + if (job.lateness_cost_per_time_unit() % + absl::GetFlag(FLAGS_jssp_scaling_up_factor) != + 0) { + all_integral = false; + break; + } + } + if (all_integral) { + for (Job &job : *problem_.mutable_jobs()) { + job.set_lateness_cost_per_time_unit( + job.lateness_cost_per_time_unit() / + absl::GetFlag(FLAGS_jssp_scaling_up_factor)); + } + } else { + problem_.mutable_scaling_factor()->set_value( + 1.0L / absl::GetFlag(FLAGS_jssp_scaling_up_factor)); + } + parser_state_ = DONE; + } + break; + } + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_ + << "with line " << line; } - break; - } - default: { - LOG(FATAL) << "Should not be here with state " << parser_state_ - << "with line " << line; - } } } @@ -394,90 +405,91 @@ void JsspParser::ProcessPssLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case START: { - problem_.set_makespan_cost_per_time_unit(1L); - CHECK_EQ(1, words.size()); - SetJobs(strtoint32(words[0])); - parser_state_ = JOB_COUNT_READ; - break; - } - case JOB_COUNT_READ: { - CHECK_EQ(1, words.size()); - SetMachines(strtoint32(words[0])); - parser_state_ = MACHINE_COUNT_READ; - current_job_index_ = 0; - break; - } - case MACHINE_COUNT_READ: { - CHECK_EQ(1, words.size()); - CHECK_EQ(declared_machine_count_, strtoint32(words[0])); - if (++current_job_index_ == declared_job_count_) { - parser_state_ = JOB_LENGTH_READ; - current_job_index_ = 0; - current_machine_index_ = 0; + case START: { + problem_.set_makespan_cost_per_time_unit(1L); + CHECK_EQ(1, words.size()); + SetJobs(strtoint32(words[0])); + parser_state_ = JOB_COUNT_READ; + break; } - break; - } - case JOB_LENGTH_READ: { - CHECK_EQ(4, words.size()); - CHECK_EQ(0, strtoint32(words[2])); - CHECK_EQ(0, strtoint32(words[3])); - const int machine_id = strtoint32(words[0]) - 1; - const int duration = strtoint32(words[1]); - Job *const job = problem_.mutable_jobs(current_job_index_); - Task *const task = job->add_tasks(); - task->add_machine(machine_id); - task->add_duration(duration); - if (++current_machine_index_ == declared_machine_count_) { - current_machine_index_ = 0; + case JOB_COUNT_READ: { + CHECK_EQ(1, words.size()); + SetMachines(strtoint32(words[0])); + parser_state_ = MACHINE_COUNT_READ; + current_job_index_ = 0; + break; + } + case MACHINE_COUNT_READ: { + CHECK_EQ(1, words.size()); + CHECK_EQ(declared_machine_count_, strtoint32(words[0])); if (++current_job_index_ == declared_job_count_) { - current_job_index_ = -1; + parser_state_ = JOB_LENGTH_READ; + current_job_index_ = 0; current_machine_index_ = 0; - parser_state_ = JOBS_READ; - transition_index_ = 0; - for (int m = 0; m < declared_machine_count_; ++m) { - Machine *const machine = problem_.mutable_machines(m); - for (int i = 0; i < declared_job_count_ * declared_job_count_; ++i) { - machine->mutable_transition_time_matrix()->add_transition_time(0); + } + break; + } + case JOB_LENGTH_READ: { + CHECK_EQ(4, words.size()); + CHECK_EQ(0, strtoint32(words[2])); + CHECK_EQ(0, strtoint32(words[3])); + const int machine_id = strtoint32(words[0]) - 1; + const int duration = strtoint32(words[1]); + Job *const job = problem_.mutable_jobs(current_job_index_); + Task *const task = job->add_tasks(); + task->add_machine(machine_id); + task->add_duration(duration); + if (++current_machine_index_ == declared_machine_count_) { + current_machine_index_ = 0; + if (++current_job_index_ == declared_job_count_) { + current_job_index_ = -1; + current_machine_index_ = 0; + parser_state_ = JOBS_READ; + transition_index_ = 0; + for (int m = 0; m < declared_machine_count_; ++m) { + Machine *const machine = problem_.mutable_machines(m); + for (int i = 0; i < declared_job_count_ * declared_job_count_; + ++i) { + machine->mutable_transition_time_matrix()->add_transition_time(0); + } } } } - } - break; - } - case JOBS_READ: { - CHECK_EQ(1, words.size()); - const int index = transition_index_++; - const int size = declared_job_count_ * declared_machine_count_ + 1; - const int t1 = index / size; - const int t2 = index % size; - if (t1 == 0 || t2 == 0) { // Dummy task. break; } - const int item1 = t1 - 1; - const int item2 = t2 - 1; - const int job1 = item1 / declared_machine_count_; - const int task1 = item1 % declared_machine_count_; - const int m1 = problem_.jobs(job1).tasks(task1).machine(0); - const int job2 = item2 / declared_machine_count_; - const int task2 = item2 % declared_machine_count_; - const int m2 = problem_.jobs(job2).tasks(task2).machine(0); - if (m1 != m2) { // We are only interested in same machine transitions. + case JOBS_READ: { + CHECK_EQ(1, words.size()); + const int index = transition_index_++; + const int size = declared_job_count_ * declared_machine_count_ + 1; + const int t1 = index / size; + const int t2 = index % size; + if (t1 == 0 || t2 == 0) { // Dummy task. + break; + } + const int item1 = t1 - 1; + const int item2 = t2 - 1; + const int job1 = item1 / declared_machine_count_; + const int task1 = item1 % declared_machine_count_; + const int m1 = problem_.jobs(job1).tasks(task1).machine(0); + const int job2 = item2 / declared_machine_count_; + const int task2 = item2 % declared_machine_count_; + const int m2 = problem_.jobs(job2).tasks(task2).machine(0); + if (m1 != m2) { // We are only interested in same machine transitions. + break; + } + const int transition = strtoint32(words[0]); + Machine *const machine = problem_.mutable_machines(m1); + machine->mutable_transition_time_matrix()->set_transition_time( + job1 * declared_job_count_ + job2, transition); + if (transition_index_ == size * size) { + parser_state_ = DONE; + } break; } - const int transition = strtoint32(words[0]); - Machine *const machine = problem_.mutable_machines(m1); - machine->mutable_transition_time_matrix() - ->set_transition_time(job1 * declared_job_count_ + job2, transition); - if (transition_index_ == size * size) { - parser_state_ = DONE; + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_ + << "with line " << line; } - break; - } - default: { - LOG(FATAL) << "Should not be here with state " << parser_state_ - << "with line " << line; - } } } @@ -485,31 +497,33 @@ void JsspParser::ProcessEarlyTardyLine(const std::string &line) { const std::vector words = absl::StrSplit(line, ' ', absl::SkipEmpty()); switch (parser_state_) { - case JOB_COUNT_READ: { - CHECK_EQ(words.size(), declared_machine_count_ * 2 + 3); - Job *const job = problem_.mutable_jobs(current_job_index_); - for (int i = 0; i < declared_machine_count_; ++i) { - const int machine_id = strtoint32(words[2 * i]); - const int64 duration = strtoint64(words[2 * i + 1]); - Task *const task = job->add_tasks(); - task->add_machine(machine_id); - task->add_duration(duration); + case JOB_COUNT_READ: { + CHECK_EQ(words.size(), declared_machine_count_ * 2 + 3); + Job *const job = problem_.mutable_jobs(current_job_index_); + for (int i = 0; i < declared_machine_count_; ++i) { + const int machine_id = strtoint32(words[2 * i]); + const int64 duration = strtoint64(words[2 * i + 1]); + Task *const task = job->add_tasks(); + task->add_machine(machine_id); + task->add_duration(duration); + } + // Early Tardy problem in JET format. + const int due_date = strtoint32(words[declared_machine_count_ * 2]); + const int early_cost = strtoint32(words[declared_machine_count_ * 2 + 1]); + const int late_cost = strtoint32(words[declared_machine_count_ * 2 + 2]); + job->set_early_due_date(due_date); + job->set_late_due_date(due_date); + job->set_earliness_cost_per_time_unit(early_cost); + job->set_lateness_cost_per_time_unit(late_cost); + current_job_index_++; + if (current_job_index_ == declared_job_count_) { + parser_state_ = DONE; + } + break; } - // Early Tardy problem in JET format. - const int due_date = strtoint32(words[declared_machine_count_ * 2]); - const int early_cost = strtoint32(words[declared_machine_count_ * 2 + 1]); - const int late_cost = strtoint32(words[declared_machine_count_ * 2 + 2]); - job->set_early_due_date(due_date); - job->set_late_due_date(due_date); - job->set_earliness_cost_per_time_unit(early_cost); - job->set_lateness_cost_per_time_unit(late_cost); - current_job_index_++; - if (current_job_index_ == declared_job_count_) { - parser_state_ = DONE; + default: { + LOG(FATAL) << "Should not be here with state " << parser_state_; } - break; - } - default: { LOG(FATAL) << "Should not be here with state " << parser_state_; } } } @@ -525,6 +539,6 @@ int64 JsspParser::strtoint64(const std::string &word) { return result; } -} // namespace jssp -} // namespace data -} // namespace operations_research +} // namespace jssp +} // namespace data +} // namespace operations_research diff --git a/ortools/data/jobshop_scheduling_parser.h b/ortools/data/jobshop_scheduling_parser.h index e07e7e60c5..c1585c1a96 100644 --- a/ortools/data/jobshop_scheduling_parser.h +++ b/ortools/data/jobshop_scheduling_parser.h @@ -23,7 +23,7 @@ namespace data { namespace jssp { class JsspParser { -public: + public: enum ProblemType { UNDEFINED, JSSP, @@ -60,7 +60,7 @@ public: // Returns the loaded problem. const JsspInputProblem &problem() const { return problem_; } -private: + private: void ProcessJsspLine(const std::string &line); void ProcessTaillardLine(const std::string &line); void ProcessFlexibleLine(const std::string &line); @@ -84,8 +84,8 @@ private: ParserState parser_state_ = START; }; -} // namespace jssp -} // namespace data -} // namespace operations_research +} // namespace jssp +} // namespace data +} // namespace operations_research -#endif // OR_TOOLS_DATA_JOBSHOP_SCHEDULING_PARSER_H_ +#endif // OR_TOOLS_DATA_JOBSHOP_SCHEDULING_PARSER_H_ diff --git a/ortools/data/rcpsp_parser.cc b/ortools/data/rcpsp_parser.cc index af818a4710..4daccc0f5c 100644 --- a/ortools/data/rcpsp_parser.cc +++ b/ortools/data/rcpsp_parser.cc @@ -24,8 +24,11 @@ namespace data { namespace rcpsp { RcpspParser::RcpspParser() - : seed_(-1), load_status_(NOT_STARTED), num_declared_tasks_(-1), - current_task_(-1), unreads_(0) { + : seed_(-1), + load_status_(NOT_STARTED), + num_declared_tasks_(-1), + current_task_(-1), + unreads_(0) { rcpsp_.set_deadline(-1); rcpsp_.set_horizon(-1); } @@ -69,179 +72,182 @@ void RcpspParser::ReportError(const std::string &line) { void RcpspParser::SetNumDeclaredTasks(int t) { num_declared_tasks_ = t; - recipe_sizes_.resize(t + 2, 0); // The data format adds 2 sentinels. + recipe_sizes_.resize(t + 2, 0); // The data format adds 2 sentinels. } void RcpspParser::ProcessRcpspLine(const std::string &line) { - if (absl::StartsWith(line, "***")) - return; - if (absl::StartsWith(line, "---")) - return; + if (absl::StartsWith(line, "***")) return; + if (absl::StartsWith(line, "---")) return; const std::vector words = absl::StrSplit(line, absl::ByAnyChar(" :\t\r"), absl::SkipEmpty()); - if (words.empty()) - return; + if (words.empty()) return; switch (load_status_) { - case NOT_STARTED: { - ReportError(line); - break; - } - case HEADER_SECTION: { - if (words[0] == "file") { - rcpsp_.set_basedata(words[3]); - } else if (words[0] == "initial") { - rcpsp_.set_seed(strtoint64(words[4])); - load_status_ = PROJECT_SECTION; - } else if (words[0] == "jobs") { - // Workaround for the mmlib files which has less headers. - SetNumDeclaredTasks(strtoint32(words[4]) - 2); - load_status_ = PROJECT_SECTION; - } else { + case NOT_STARTED: { ReportError(line); + break; } - break; - } - case PROJECT_SECTION: { - if (words[0] == "projects") { - // Nothing to do. - } else if (words[0] == "jobs") { - // This declaration counts the 2 sentinels. - SetNumDeclaredTasks(strtoint32(words[4]) - 2); - } else if (words[0] == "horizon") { - rcpsp_.set_horizon(strtoint32(words[1])); - } else if (words[0] == "RESOURCES") { - // Nothing to do. - } else if (words.size() > 1 && words[1] == "renewable") { - for (int i = 0; i < strtoint32(words[2]); ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_renewable(true); - res->set_unit_cost(0); - } - } else if (words.size() > 1 && words[1] == "nonrenewable") { - for (int i = 0; i < strtoint32(words[2]); ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_min_capacity(-1); - res->set_renewable(false); - res->set_unit_cost(0); - } - } else if (words.size() > 1 && words[1] == "doubly") { - // Nothing to do. - } else if (words.size() == 2 && words[0] == "PROJECT") { - load_status_ = INFO_SECTION; - } else if (words.size() == 2 && words[0] == "PRECEDENCE") { - // mmlib files have no info section. - load_status_ = PRECEDENCE_SECTION; - } else { - ReportError(line); - } - break; - } - case INFO_SECTION: { - if (words[0] == "pronr.") { - // Nothing to do. - } else if (words.size() == 6) { - SetNumDeclaredTasks(strtoint32(words[1])); - rcpsp_.set_release_date(strtoint32(words[2])); - rcpsp_.set_due_date(strtoint32(words[3])); - rcpsp_.set_tardiness_cost(strtoint32(words[4])); - rcpsp_.set_mpm_time(strtoint32(words[5])); - } else if (words.size() == 2 && words[0] == "PRECEDENCE") { - load_status_ = PRECEDENCE_SECTION; - } else { - ReportError(line); - } - break; - } - case PRECEDENCE_SECTION: { - if (words[0] == "jobnr.") { - // Nothing to do. - } else if (words.size() >= 3) { - const int task_index = strtoint32(words[0]) - 1; - CHECK_EQ(task_index, rcpsp_.tasks_size()); - recipe_sizes_[task_index] = strtoint32(words[1]); - const int num_successors = strtoint32(words[2]); - if (words.size() != 3 + num_successors) { + case HEADER_SECTION: { + if (words[0] == "file") { + rcpsp_.set_basedata(words[3]); + } else if (words[0] == "initial") { + rcpsp_.set_seed(strtoint64(words[4])); + load_status_ = PROJECT_SECTION; + } else if (words[0] == "jobs") { + // Workaround for the mmlib files which has less headers. + SetNumDeclaredTasks(strtoint32(words[4]) - 2); + load_status_ = PROJECT_SECTION; + } else { ReportError(line); - break; } - Task *const task = rcpsp_.add_tasks(); - for (int i = 0; i < num_successors; ++i) { - // The array of tasks is 0-based for us. - task->add_successors(strtoint32(words[3 + i]) - 1); - } - } else if (words[0] == "REQUESTS/DURATIONS") { - load_status_ = REQUEST_SECTION; - } else { - ReportError(line); + break; } - break; - } - case REQUEST_SECTION: { - if (words[0] == "jobnr.") { - // Nothing to do. - } else if (words.size() == 3 + rcpsp_.resources_size()) { - // Start of a new task (index is 0-based for us). - current_task_ = strtoint32(words[0]) - 1; - const int current_recipe = strtoint32(words[1]) - 1; - CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); - if (current_recipe != 0) { + case PROJECT_SECTION: { + if (words[0] == "projects") { + // Nothing to do. + } else if (words[0] == "jobs") { + // This declaration counts the 2 sentinels. + SetNumDeclaredTasks(strtoint32(words[4]) - 2); + } else if (words[0] == "horizon") { + rcpsp_.set_horizon(strtoint32(words[1])); + } else if (words[0] == "RESOURCES") { + // Nothing to do. + } else if (words.size() > 1 && words[1] == "renewable") { + for (int i = 0; i < strtoint32(words[2]); ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_renewable(true); + res->set_unit_cost(0); + } + } else if (words.size() > 1 && words[1] == "nonrenewable") { + for (int i = 0; i < strtoint32(words[2]); ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_min_capacity(-1); + res->set_renewable(false); + res->set_unit_cost(0); + } + } else if (words.size() > 1 && words[1] == "doubly") { + // Nothing to do. + } else if (words.size() == 2 && words[0] == "PROJECT") { + load_status_ = INFO_SECTION; + } else if (words.size() == 2 && words[0] == "PRECEDENCE") { + // mmlib files have no info section. + load_status_ = PRECEDENCE_SECTION; + } else { ReportError(line); - break; } - Recipe *const recipe = rcpsp_.mutable_tasks(current_task_)->add_recipes(); - recipe->set_duration(strtoint32(words[2])); - for (int i = 0; i < rcpsp_.resources_size(); ++i) { - const int demand = strtoint32(words[3 + i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i); - } - } - } else if (words.size() == 2 + rcpsp_.resources_size()) { - // New recipe for a current task. - const int current_recipe = strtoint32(words[0]) - 1; - CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); - Recipe *const recipe = rcpsp_.mutable_tasks(current_task_)->add_recipes(); - recipe->set_duration(strtoint32(words[1])); - for (int i = 0; i < rcpsp_.resources_size(); ++i) { - const int demand = strtoint32(words[2 + i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i); - } - } - } else if (words[0] == "RESOURCEAVAILABILITIES" || - (words[0] == "RESOURCE" && words[1] == "AVAILABILITIES")) { - load_status_ = RESOURCE_SECTION; - } else { - ReportError(line); + break; } - break; - } - case RESOURCE_SECTION: { - if (words.size() == 2 * rcpsp_.resources_size()) { - // Nothing to do. - } else if (words.size() == rcpsp_.resources_size()) { - for (int i = 0; i < words.size(); ++i) { - rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + case INFO_SECTION: { + if (words[0] == "pronr.") { + // Nothing to do. + } else if (words.size() == 6) { + SetNumDeclaredTasks(strtoint32(words[1])); + rcpsp_.set_release_date(strtoint32(words[2])); + rcpsp_.set_due_date(strtoint32(words[3])); + rcpsp_.set_tardiness_cost(strtoint32(words[4])); + rcpsp_.set_mpm_time(strtoint32(words[5])); + } else if (words.size() == 2 && words[0] == "PRECEDENCE") { + load_status_ = PRECEDENCE_SECTION; + } else { + ReportError(line); } - load_status_ = PARSING_FINISHED; - } else { - ReportError(line); + break; + } + case PRECEDENCE_SECTION: { + if (words[0] == "jobnr.") { + // Nothing to do. + } else if (words.size() >= 3) { + const int task_index = strtoint32(words[0]) - 1; + CHECK_EQ(task_index, rcpsp_.tasks_size()); + recipe_sizes_[task_index] = strtoint32(words[1]); + const int num_successors = strtoint32(words[2]); + if (words.size() != 3 + num_successors) { + ReportError(line); + break; + } + Task *const task = rcpsp_.add_tasks(); + for (int i = 0; i < num_successors; ++i) { + // The array of tasks is 0-based for us. + task->add_successors(strtoint32(words[3 + i]) - 1); + } + } else if (words[0] == "REQUESTS/DURATIONS") { + load_status_ = REQUEST_SECTION; + } else { + ReportError(line); + } + break; + } + case REQUEST_SECTION: { + if (words[0] == "jobnr.") { + // Nothing to do. + } else if (words.size() == 3 + rcpsp_.resources_size()) { + // Start of a new task (index is 0-based for us). + current_task_ = strtoint32(words[0]) - 1; + const int current_recipe = strtoint32(words[1]) - 1; + CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); + if (current_recipe != 0) { + ReportError(line); + break; + } + Recipe *const recipe = + rcpsp_.mutable_tasks(current_task_)->add_recipes(); + recipe->set_duration(strtoint32(words[2])); + for (int i = 0; i < rcpsp_.resources_size(); ++i) { + const int demand = strtoint32(words[3 + i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i); + } + } + } else if (words.size() == 2 + rcpsp_.resources_size()) { + // New recipe for a current task. + const int current_recipe = strtoint32(words[0]) - 1; + CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); + Recipe *const recipe = + rcpsp_.mutable_tasks(current_task_)->add_recipes(); + recipe->set_duration(strtoint32(words[1])); + for (int i = 0; i < rcpsp_.resources_size(); ++i) { + const int demand = strtoint32(words[2 + i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i); + } + } + } else if (words[0] == "RESOURCEAVAILABILITIES" || + (words[0] == "RESOURCE" && words[1] == "AVAILABILITIES")) { + load_status_ = RESOURCE_SECTION; + } else { + ReportError(line); + } + break; + } + case RESOURCE_SECTION: { + if (words.size() == 2 * rcpsp_.resources_size()) { + // Nothing to do. + } else if (words.size() == rcpsp_.resources_size()) { + for (int i = 0; i < words.size(); ++i) { + rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + } + load_status_ = PARSING_FINISHED; + } else { + ReportError(line); + } + break; + } + case RESOURCE_MIN_SECTION: { + LOG(FATAL) << "Should not be here"; + break; + } + case PARSING_FINISHED: { + break; + } + case ERROR_FOUND: { + break; } - break; - } - case RESOURCE_MIN_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case PARSING_FINISHED: { break; } - case ERROR_FOUND: { break; } } } @@ -250,220 +256,227 @@ void RcpspParser::ProcessRcpspMaxLine(const std::string &line) { absl::StrSplit(line, absl::ByAnyChar(" :\t[]\r"), absl::SkipEmpty()); switch (load_status_) { - case NOT_STARTED: { - ReportError(line); - break; - } - case HEADER_SECTION: { - rcpsp_.set_is_rcpsp_max(true); - if (words.size() == 2) { - rcpsp_.set_is_consumer_producer(true); - } else if (words.size() < 4 || strtoint32(words[3]) != 0) { + case NOT_STARTED: { ReportError(line); break; } - - if (words.size() == 5) { - rcpsp_.set_deadline(strtoint32(words[4])); - rcpsp_.set_is_resource_investment(true); - } - - SetNumDeclaredTasks(strtoint32(words[0])); - temp_delays_.resize(num_declared_tasks_ + 2); - - // Creates resources. - if (rcpsp_.is_consumer_producer()) { - const int num_nonrenewable_resources = strtoint32(words[1]); - for (int i = 0; i < num_nonrenewable_resources; ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_min_capacity(-1); - res->set_renewable(false); - res->set_unit_cost(0); + case HEADER_SECTION: { + rcpsp_.set_is_rcpsp_max(true); + if (words.size() == 2) { + rcpsp_.set_is_consumer_producer(true); + } else if (words.size() < 4 || strtoint32(words[3]) != 0) { + ReportError(line); + break; } - } else { - const int num_renewable_resources = strtoint32(words[1]); - const int num_nonrenewable_resources = strtoint32(words[2]); - for (int i = 0; i < num_renewable_resources; ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_renewable(true); - res->set_unit_cost(0); - } - for (int i = 0; i < num_nonrenewable_resources; ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_min_capacity(-1); - res->set_renewable(false); - res->set_unit_cost(0); - } - } - // Set up for the next section. - load_status_ = PRECEDENCE_SECTION; - current_task_ = 0; - break; - } - case PROJECT_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case INFO_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case PRECEDENCE_SECTION: { - if (words.size() < 3) { - ReportError(line); + if (words.size() == 5) { + rcpsp_.set_deadline(strtoint32(words[4])); + rcpsp_.set_is_resource_investment(true); + } + + SetNumDeclaredTasks(strtoint32(words[0])); + temp_delays_.resize(num_declared_tasks_ + 2); + + // Creates resources. + if (rcpsp_.is_consumer_producer()) { + const int num_nonrenewable_resources = strtoint32(words[1]); + for (int i = 0; i < num_nonrenewable_resources; ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_min_capacity(-1); + res->set_renewable(false); + res->set_unit_cost(0); + } + } else { + const int num_renewable_resources = strtoint32(words[1]); + const int num_nonrenewable_resources = strtoint32(words[2]); + for (int i = 0; i < num_renewable_resources; ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_renewable(true); + res->set_unit_cost(0); + } + for (int i = 0; i < num_nonrenewable_resources; ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_min_capacity(-1); + res->set_renewable(false); + res->set_unit_cost(0); + } + } + + // Set up for the next section. + load_status_ = PRECEDENCE_SECTION; + current_task_ = 0; break; } - - const int task_id = strtoint32(words[0]); - if (task_id != current_task_) { - ReportError(line); + case PROJECT_SECTION: { + LOG(FATAL) << "Should not be here"; break; - } else { - current_task_++; } - - const int num_recipes = strtoint32(words[1]); - recipe_sizes_[task_id] = num_recipes; - const int num_successors = strtoint32(words[2]); - - Task *const task = rcpsp_.add_tasks(); - - // Read successors. - for (int i = 0; i < num_successors; ++i) { - task->add_successors(strtoint32(words[3 + i])); + case INFO_SECTION: { + LOG(FATAL) << "Should not be here"; + break; } + case PRECEDENCE_SECTION: { + if (words.size() < 3) { + ReportError(line); + break; + } - // Read flattened delays into temp_delays_. - for (int i = 3 + num_successors; i < words.size(); ++i) { - temp_delays_[task_id].push_back(strtoint32(words[i])); - } + const int task_id = strtoint32(words[0]); + if (task_id != current_task_) { + ReportError(line); + break; + } else { + current_task_++; + } - if (task_id == num_declared_tasks_ + 1) { - // Convert the flattened delays into structured delays (1 vector per - // successor) in the task_size. - for (int t = 1; t <= num_declared_tasks_; ++t) { - const int num_recipes = recipe_sizes_[t]; - const int num_successors = rcpsp_.tasks(t).successors_size(); - int count = 0; - for (int s = 0; s < num_successors; ++s) { - PerSuccessorDelays *const succ_delays = - rcpsp_.mutable_tasks(t)->add_successor_delays(); - for (int r1 = 0; r1 < num_recipes; ++r1) { - PerRecipeDelays *const recipe_delays = - succ_delays->add_recipe_delays(); - const int other = rcpsp_.tasks(t).successors(s); - const int num_other_recipes = recipe_sizes_[other]; - for (int r2 = 0; r2 < num_other_recipes; ++r2) { - recipe_delays->add_min_delays(temp_delays_[t][count++]); + const int num_recipes = strtoint32(words[1]); + recipe_sizes_[task_id] = num_recipes; + const int num_successors = strtoint32(words[2]); + + Task *const task = rcpsp_.add_tasks(); + + // Read successors. + for (int i = 0; i < num_successors; ++i) { + task->add_successors(strtoint32(words[3 + i])); + } + + // Read flattened delays into temp_delays_. + for (int i = 3 + num_successors; i < words.size(); ++i) { + temp_delays_[task_id].push_back(strtoint32(words[i])); + } + + if (task_id == num_declared_tasks_ + 1) { + // Convert the flattened delays into structured delays (1 vector per + // successor) in the task_size. + for (int t = 1; t <= num_declared_tasks_; ++t) { + const int num_recipes = recipe_sizes_[t]; + const int num_successors = rcpsp_.tasks(t).successors_size(); + int count = 0; + for (int s = 0; s < num_successors; ++s) { + PerSuccessorDelays *const succ_delays = + rcpsp_.mutable_tasks(t)->add_successor_delays(); + for (int r1 = 0; r1 < num_recipes; ++r1) { + PerRecipeDelays *const recipe_delays = + succ_delays->add_recipe_delays(); + const int other = rcpsp_.tasks(t).successors(s); + const int num_other_recipes = recipe_sizes_[other]; + for (int r2 = 0; r2 < num_other_recipes; ++r2) { + recipe_delays->add_min_delays(temp_delays_[t][count++]); + } } } + CHECK_EQ(count, temp_delays_[t].size()); } - CHECK_EQ(count, temp_delays_[t].size()); - } - // Setup for next section. - current_task_ = 0; - load_status_ = REQUEST_SECTION; + // Setup for next section. + current_task_ = 0; + load_status_ = REQUEST_SECTION; + } + break; } - break; - } - case REQUEST_SECTION: { - if (words.size() == 3 + rcpsp_.resources_size()) { - // Start of a new task. - current_task_ = strtoint32(words[0]); + case REQUEST_SECTION: { + if (words.size() == 3 + rcpsp_.resources_size()) { + // Start of a new task. + current_task_ = strtoint32(words[0]); - // 0 based indices for the recipe. - const int current_recipe = strtoint32(words[1]) - 1; - CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); - if (current_recipe != 0) { - ReportError(line); - break; - } - Recipe *const recipe = rcpsp_.mutable_tasks(current_task_)->add_recipes(); - recipe->set_duration(strtoint32(words[2])); - for (int i = 0; i < rcpsp_.resources_size(); ++i) { - const int demand = strtoint32(words[3 + i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i); + // 0 based indices for the recipe. + const int current_recipe = strtoint32(words[1]) - 1; + CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); + if (current_recipe != 0) { + ReportError(line); + break; } - } - } else if (words.size() == 2 + rcpsp_.resources_size() && - rcpsp_.is_consumer_producer()) { - // Start of a new task. - current_task_ = strtoint32(words[0]); + Recipe *const recipe = + rcpsp_.mutable_tasks(current_task_)->add_recipes(); + recipe->set_duration(strtoint32(words[2])); + for (int i = 0; i < rcpsp_.resources_size(); ++i) { + const int demand = strtoint32(words[3 + i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i); + } + } + } else if (words.size() == 2 + rcpsp_.resources_size() && + rcpsp_.is_consumer_producer()) { + // Start of a new task. + current_task_ = strtoint32(words[0]); - // 0 based indices for the recipe. - const int current_recipe = strtoint32(words[1]) - 1; - CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); - if (current_recipe != 0) { - ReportError(line); - break; - } - Recipe *const recipe = rcpsp_.mutable_tasks(current_task_)->add_recipes(); - recipe->set_duration(0); - for (int i = 0; i < rcpsp_.resources_size(); ++i) { - const int demand = strtoint32(words[2 + i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i); + // 0 based indices for the recipe. + const int current_recipe = strtoint32(words[1]) - 1; + CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); + if (current_recipe != 0) { + ReportError(line); + break; + } + Recipe *const recipe = + rcpsp_.mutable_tasks(current_task_)->add_recipes(); + recipe->set_duration(0); + for (int i = 0; i < rcpsp_.resources_size(); ++i) { + const int demand = strtoint32(words[2 + i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i); + } + } + } else if (words.size() == 2 + rcpsp_.resources_size()) { + // New recipe for a current task. + const int current_recipe = strtoint32(words[0]) - 1; + CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); + Recipe *const recipe = + rcpsp_.mutable_tasks(current_task_)->add_recipes(); + recipe->set_duration(strtoint32(words[1])); + for (int i = 0; i < rcpsp_.resources_size(); ++i) { + const int demand = strtoint32(words[2 + i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i); + } } } - } else if (words.size() == 2 + rcpsp_.resources_size()) { - // New recipe for a current task. - const int current_recipe = strtoint32(words[0]) - 1; - CHECK_EQ(current_recipe, rcpsp_.tasks(current_task_).recipes_size()); - Recipe *const recipe = rcpsp_.mutable_tasks(current_task_)->add_recipes(); - recipe->set_duration(strtoint32(words[1])); - for (int i = 0; i < rcpsp_.resources_size(); ++i) { - const int demand = strtoint32(words[2 + i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i); - } - } - } - if (current_task_ == num_declared_tasks_ + 1) { - if (rcpsp_.is_consumer_producer()) { - load_status_ = RESOURCE_MIN_SECTION; - } else { - load_status_ = RESOURCE_SECTION; - } - } - break; - } - case RESOURCE_SECTION: { - if (words.size() == rcpsp_.resources_size()) { - for (int i = 0; i < words.size(); ++i) { - if (rcpsp_.is_resource_investment()) { - rcpsp_.mutable_resources(i)->set_unit_cost(strtoint32(words[i])); + if (current_task_ == num_declared_tasks_ + 1) { + if (rcpsp_.is_consumer_producer()) { + load_status_ = RESOURCE_MIN_SECTION; } else { - rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + load_status_ = RESOURCE_SECTION; } } - load_status_ = PARSING_FINISHED; - } else { - ReportError(line); + break; } - break; - } - case RESOURCE_MIN_SECTION: { - if (words.size() == rcpsp_.resources_size()) { - for (int i = 0; i < words.size(); ++i) { - rcpsp_.mutable_resources(i)->set_min_capacity(strtoint32(words[i])); + case RESOURCE_SECTION: { + if (words.size() == rcpsp_.resources_size()) { + for (int i = 0; i < words.size(); ++i) { + if (rcpsp_.is_resource_investment()) { + rcpsp_.mutable_resources(i)->set_unit_cost(strtoint32(words[i])); + } else { + rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + } + } + load_status_ = PARSING_FINISHED; + } else { + ReportError(line); } - load_status_ = RESOURCE_SECTION; - } else { - ReportError(line); + break; + } + case RESOURCE_MIN_SECTION: { + if (words.size() == rcpsp_.resources_size()) { + for (int i = 0; i < words.size(); ++i) { + rcpsp_.mutable_resources(i)->set_min_capacity(strtoint32(words[i])); + } + load_status_ = RESOURCE_SECTION; + } else { + ReportError(line); + } + break; + } + case PARSING_FINISHED: { + break; + } + case ERROR_FOUND: { + break; } - break; - } - case PARSING_FINISHED: { break; } - case ERROR_FOUND: { break; } } } @@ -471,106 +484,109 @@ void RcpspParser::ProcessPattersonLine(const std::string &line) { const std::vector words = absl::StrSplit(line, absl::ByAnyChar(" :\t[]\r"), absl::SkipEmpty()); - if (words.empty()) - return; + if (words.empty()) return; switch (load_status_) { - case NOT_STARTED: { - ReportError(line); - break; - } - case HEADER_SECTION: { - if (words.size() != 2) { + case NOT_STARTED: { ReportError(line); break; } - SetNumDeclaredTasks(strtoint32(words[0]) - 2); // Remove the 2 sentinels. - - // Creates resources. - const int num_renewable_resources = strtoint32(words[1]); - for (int i = 0; i < num_renewable_resources; ++i) { - Resource *const res = rcpsp_.add_resources(); - res->set_max_capacity(-1); - res->set_min_capacity(-1); - res->set_renewable(true); - res->set_unit_cost(0); - } - - // Set up for the next section. - load_status_ = RESOURCE_SECTION; - break; - } - case PROJECT_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case INFO_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case PRECEDENCE_SECTION: { - if (unreads_ > 0) { - for (int i = 0; i < words.size(); ++i) { - rcpsp_.mutable_tasks(current_task_) - ->add_successors(strtoint32(words[i]) - 1); - unreads_--; - CHECK_GE(unreads_, 0); - } - } else { - if (words.size() < 2 + rcpsp_.resources_size()) { + case HEADER_SECTION: { + if (words.size() != 2) { ReportError(line); break; } - CHECK_EQ(current_task_, rcpsp_.tasks_size()); - Task *const task = rcpsp_.add_tasks(); - Recipe *const recipe = task->add_recipes(); - recipe->set_duration(strtoint32(words[0])); + SetNumDeclaredTasks(strtoint32(words[0]) - 2); // Remove the 2 sentinels. - const int num_resources = rcpsp_.resources_size(); - for (int i = 1; i <= num_resources; ++i) { - const int demand = strtoint32(words[i]); - if (demand != 0) { - recipe->add_demands(demand); - recipe->add_resources(i - 1); + // Creates resources. + const int num_renewable_resources = strtoint32(words[1]); + for (int i = 0; i < num_renewable_resources; ++i) { + Resource *const res = rcpsp_.add_resources(); + res->set_max_capacity(-1); + res->set_min_capacity(-1); + res->set_renewable(true); + res->set_unit_cost(0); + } + + // Set up for the next section. + load_status_ = RESOURCE_SECTION; + break; + } + case PROJECT_SECTION: { + LOG(FATAL) << "Should not be here"; + break; + } + case INFO_SECTION: { + LOG(FATAL) << "Should not be here"; + break; + } + case PRECEDENCE_SECTION: { + if (unreads_ > 0) { + for (int i = 0; i < words.size(); ++i) { + rcpsp_.mutable_tasks(current_task_) + ->add_successors(strtoint32(words[i]) - 1); + unreads_--; + CHECK_GE(unreads_, 0); + } + } else { + if (words.size() < 2 + rcpsp_.resources_size()) { + ReportError(line); + break; + } + CHECK_EQ(current_task_, rcpsp_.tasks_size()); + Task *const task = rcpsp_.add_tasks(); + Recipe *const recipe = task->add_recipes(); + recipe->set_duration(strtoint32(words[0])); + + const int num_resources = rcpsp_.resources_size(); + for (int i = 1; i <= num_resources; ++i) { + const int demand = strtoint32(words[i]); + if (demand != 0) { + recipe->add_demands(demand); + recipe->add_resources(i - 1); + } + } + + unreads_ = strtoint32(words[1 + num_resources]); + for (int i = 2 + num_resources; i < words.size(); ++i) { + // Successors are 1 based in the data file. + task->add_successors(strtoint32(words[i]) - 1); + unreads_--; + CHECK_GE(unreads_, 0); } } - unreads_ = strtoint32(words[1 + num_resources]); - for (int i = 2 + num_resources; i < words.size(); ++i) { - // Successors are 1 based in the data file. - task->add_successors(strtoint32(words[i]) - 1); - unreads_--; - CHECK_GE(unreads_, 0); + if (unreads_ == 0 && ++current_task_ == num_declared_tasks_ + 2) { + load_status_ = PARSING_FINISHED; } + break; } - - if (unreads_ == 0 && ++current_task_ == num_declared_tasks_ + 2) { - load_status_ = PARSING_FINISHED; + case REQUEST_SECTION: { + LOG(FATAL) << "Should not be here"; + break; } - break; - } - case REQUEST_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case RESOURCE_SECTION: { - if (words.size() == rcpsp_.resources_size()) { - for (int i = 0; i < words.size(); ++i) { - rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + case RESOURCE_SECTION: { + if (words.size() == rcpsp_.resources_size()) { + for (int i = 0; i < words.size(); ++i) { + rcpsp_.mutable_resources(i)->set_max_capacity(strtoint32(words[i])); + } + load_status_ = PRECEDENCE_SECTION; + current_task_ = 0; + } else { + ReportError(line); } - load_status_ = PRECEDENCE_SECTION; - current_task_ = 0; - } else { - ReportError(line); + break; + } + case RESOURCE_MIN_SECTION: { + LOG(FATAL) << "Should not be here"; + break; + } + case PARSING_FINISHED: { + break; + } + case ERROR_FOUND: { + break; } - break; - } - case RESOURCE_MIN_SECTION: { - LOG(FATAL) << "Should not be here"; - break; - } - case PARSING_FINISHED: { break; } - case ERROR_FOUND: { break; } } } @@ -586,6 +602,6 @@ int64 RcpspParser::strtoint64(const std::string &word) { return result; } -} // namespace rcpsp -} // namespace data -} // namespace operations_research +} // namespace rcpsp +} // namespace data +} // namespace operations_research diff --git a/ortools/data/rcpsp_parser.h b/ortools/data/rcpsp_parser.h index ff9a8c884f..bc790d0269 100644 --- a/ortools/data/rcpsp_parser.h +++ b/ortools/data/rcpsp_parser.h @@ -31,7 +31,7 @@ namespace rcpsp { // Parse a RCPSP problem and load it into a RcpspProblem proto. // See description of the problem in ./rcpsp.proto class RcpspParser { -public: + public: RcpspParser(); // We keep the fully qualified name for swig. @@ -42,7 +42,7 @@ public: // Returns false if an error occurred. bool ParseFile(const std::string &file_name); -private: + private: enum LoadStatus { NOT_STARTED, HEADER_SECTION, @@ -77,8 +77,8 @@ private: RcpspProblem rcpsp_; }; -} // namespace rcpsp -} // namespace data -} // namespace operations_research +} // namespace rcpsp +} // namespace data +} // namespace operations_research -#endif // OR_TOOLS_DATA_RCPSP_PARSER_H_ +#endif // OR_TOOLS_DATA_RCPSP_PARSER_H_ diff --git a/ortools/data/set_covering_data.cc b/ortools/data/set_covering_data.cc index 0be69464e6..0dc8c6c956 100644 --- a/ortools/data/set_covering_data.cc +++ b/ortools/data/set_covering_data.cc @@ -33,5 +33,5 @@ void ScpData::AddRowInColumn(int row_id, int column_id) { columns_per_row_[row_id].push_back(column_id); } -} // namespace scp -} // namespace operations_research +} // namespace scp +} // namespace operations_research diff --git a/ortools/data/set_covering_data.h b/ortools/data/set_covering_data.h index eb1843cbd8..0992891975 100644 --- a/ortools/data/set_covering_data.h +++ b/ortools/data/set_covering_data.h @@ -22,7 +22,7 @@ namespace operations_research { namespace scp { class ScpData { -public: + public: ScpData() : is_set_partitioning_(false) {} // Getters. int num_rows() const { return columns_per_row_.size(); } @@ -46,14 +46,14 @@ public: void SetColumnCost(int column_id, int cost); void AddRowInColumn(int row, int column); -private: + private: std::vector > columns_per_row_; std::vector > rows_per_column_; std::vector column_costs_; bool is_set_partitioning_; }; -} // namespace scp -} // namespace operations_research +} // namespace scp +} // namespace operations_research -#endif // OR_TOOLS_DATA_SET_COVERING_DATA_H_ +#endif // OR_TOOLS_DATA_SET_COVERING_DATA_H_ diff --git a/ortools/data/set_covering_parser.cc b/ortools/data/set_covering_parser.cc index 975f92683e..d7f1dbe351 100644 --- a/ortools/data/set_covering_parser.cc +++ b/ortools/data/set_covering_parser.cc @@ -31,8 +31,7 @@ bool ScpParser::LoadProblem(const std::string &filename, Format format, for (const std::string &line : FileLines(filename)) { ProcessLine(line, format, data); - if (section_ == ERROR) - return false; + if (section_ == ERROR) return false; } return section_ == END; } @@ -43,140 +42,144 @@ void ScpParser::ProcessLine(const std::string &line, Format format, const std::vector words = absl::StrSplit(line, absl::ByAnyChar(" :\t\r"), absl::SkipEmpty()); switch (section_) { - case INIT: { - if (words.size() != 2) { - LogError(line, "Problem reading the size of the problem"); - return; - } - const int num_rows = strtoint32(words[0]); - const int num_columns = strtoint32(words[1]); - data->SetProblemSize(num_rows, num_columns); - current_ = 0; - switch (format) { - case SCP_FORMAT: { - section_ = COSTS; - break; - } - case RAILROAD_FORMAT: { - section_ = COLUMN; - break; - } - case TRIPLET_FORMAT: { - section_ = COLUMN; - break; - } - case SPP_FORMAT: { - section_ = COLUMN; - data->set_is_set_partitioning(true); - break; - } - } - break; - } - case COSTS: { - const int num_items = words.size(); - if (current_ + num_items > data->num_columns()) { - LogError(line, "Too many cost items"); - return; - } - for (int i = 0; i < num_items; ++i) { - data->SetColumnCost(current_++, strtoint32(words[i])); - } - if (current_ == data->num_columns()) { - section_ = NUM_COLUMNS_IN_ROW; - current_ = 0; - } - break; - } - case COLUMN: { - switch (format) { - case SCP_FORMAT: { - LogError(line, "Wrong state in the loader"); - return; - } - case RAILROAD_FORMAT: - ABSL_FALLTHROUGH_INTENDED; - case SPP_FORMAT: { - if (words.size() < 2) { - LogError(line, "Column declaration too short"); + case INIT: { + if (words.size() != 2) { + LogError(line, "Problem reading the size of the problem"); return; } - const int cost = strtoint32(words[0]); - data->SetColumnCost(current_, cost); - const int num_items = strtoint32(words[1]); - if (words.size() != 2 + num_items) { - LogError(line, "Mistatch in column declaration"); + const int num_rows = strtoint32(words[0]); + const int num_columns = strtoint32(words[1]); + data->SetProblemSize(num_rows, num_columns); + current_ = 0; + switch (format) { + case SCP_FORMAT: { + section_ = COSTS; + break; + } + case RAILROAD_FORMAT: { + section_ = COLUMN; + break; + } + case TRIPLET_FORMAT: { + section_ = COLUMN; + break; + } + case SPP_FORMAT: { + section_ = COLUMN; + data->set_is_set_partitioning(true); + break; + } + } + break; + } + case COSTS: { + const int num_items = words.size(); + if (current_ + num_items > data->num_columns()) { + LogError(line, "Too many cost items"); return; } for (int i = 0; i < num_items; ++i) { - const int row = strtoint32(words[i + 2]) - 1; // 1 based. - data->AddRowInColumn(row, current_); + data->SetColumnCost(current_++, strtoint32(words[i])); } - current_++; if (current_ == data->num_columns()) { - section_ = format == RAILROAD_FORMAT ? END : NUM_NON_ZEROS; - } - break; - } - case TRIPLET_FORMAT: { - if (words.size() != 3) { - LogError(line, "Column declaration does not contain 3 rows"); - break; - } - data->SetColumnCost(current_, 1); - for (int i = 0; i < 3; ++i) { - const int row = strtoint32(words[i]) - 1; // 1 based. - data->AddRowInColumn(row, current_); - } - current_++; - if (current_ == data->num_columns()) { - section_ = END; - } - break; - } - } - break; - } - case NUM_COLUMNS_IN_ROW: { - if (words.size() != 1) { - LogError(line, "The header of a column should be one number"); - return; - } - remaining_ = strtoint32(words[0]); - section_ = ROW; - break; - } - case ROW: { - const int num_items = words.size(); - if (num_items > remaining_) { - LogError(line, "Too many columns in a row declaration"); - return; - } - for (const std::string &w : words) { - remaining_--; - const int column = strtoint32(w) - 1; // 1 based. - data->AddRowInColumn(current_, column); - } - if (remaining_ == 0) { - current_++; - if (current_ == data->num_rows()) { - section_ = END; - } else { section_ = NUM_COLUMNS_IN_ROW; + current_ = 0; } + break; } - break; - } - case NUM_NON_ZEROS: { - if (words.size() != 1) { - LogError(line, "The header of a column should be one number"); - return; + case COLUMN: { + switch (format) { + case SCP_FORMAT: { + LogError(line, "Wrong state in the loader"); + return; + } + case RAILROAD_FORMAT: + ABSL_FALLTHROUGH_INTENDED; + case SPP_FORMAT: { + if (words.size() < 2) { + LogError(line, "Column declaration too short"); + return; + } + const int cost = strtoint32(words[0]); + data->SetColumnCost(current_, cost); + const int num_items = strtoint32(words[1]); + if (words.size() != 2 + num_items) { + LogError(line, "Mistatch in column declaration"); + return; + } + for (int i = 0; i < num_items; ++i) { + const int row = strtoint32(words[i + 2]) - 1; // 1 based. + data->AddRowInColumn(row, current_); + } + current_++; + if (current_ == data->num_columns()) { + section_ = format == RAILROAD_FORMAT ? END : NUM_NON_ZEROS; + } + break; + } + case TRIPLET_FORMAT: { + if (words.size() != 3) { + LogError(line, "Column declaration does not contain 3 rows"); + break; + } + data->SetColumnCost(current_, 1); + for (int i = 0; i < 3; ++i) { + const int row = strtoint32(words[i]) - 1; // 1 based. + data->AddRowInColumn(row, current_); + } + current_++; + if (current_ == data->num_columns()) { + section_ = END; + } + break; + } + } + break; + } + case NUM_COLUMNS_IN_ROW: { + if (words.size() != 1) { + LogError(line, "The header of a column should be one number"); + return; + } + remaining_ = strtoint32(words[0]); + section_ = ROW; + break; + } + case ROW: { + const int num_items = words.size(); + if (num_items > remaining_) { + LogError(line, "Too many columns in a row declaration"); + return; + } + for (const std::string &w : words) { + remaining_--; + const int column = strtoint32(w) - 1; // 1 based. + data->AddRowInColumn(current_, column); + } + if (remaining_ == 0) { + current_++; + if (current_ == data->num_rows()) { + section_ = END; + } else { + section_ = NUM_COLUMNS_IN_ROW; + } + } + break; + } + case NUM_NON_ZEROS: { + if (words.size() != 1) { + LogError(line, "The header of a column should be one number"); + return; + } + section_ = END; + break; + } + case END: { + break; + } + case ERROR: { + break; } - section_ = END; - break; - } - case END: { break; } - case ERROR: { break; } } } @@ -198,5 +201,5 @@ int64 ScpParser::strtoint64(const std::string &word) { return result; } -} // namespace scp -} // namespace operations_research +} // namespace scp +} // namespace operations_research diff --git a/ortools/data/set_covering_parser.h b/ortools/data/set_covering_parser.h index de8ebe1c95..3f4b3a686d 100644 --- a/ortools/data/set_covering_parser.h +++ b/ortools/data/set_covering_parser.h @@ -34,7 +34,7 @@ namespace scp { // subset is called a column. class ScpParser { -public: + public: enum Section { INIT, COSTS, @@ -94,7 +94,7 @@ public: // This will clear the data before importing the file. bool LoadProblem(const std::string &filename, Format format, ScpData *data); -private: + private: void ProcessLine(const std::string &line, Format format, ScpData *data); void LogError(const std::string &line, const std::string &error_message); int strtoint32(const std::string &word); @@ -106,7 +106,7 @@ private: int current_; }; -} // namespace scp -} // namespace operations_research +} // namespace scp +} // namespace operations_research -#endif // OR_TOOLS_DATA_SET_COVERING_PARSER_H_ +#endif // OR_TOOLS_DATA_SET_COVERING_PARSER_H_ diff --git a/ortools/flatzinc/checker.cc b/ortools/flatzinc/checker.cc index 3469aa728c..f844c49f4e 100644 --- a/ortools/flatzinc/checker.cc +++ b/ortools/flatzinc/checker.cc @@ -30,12 +30,16 @@ namespace { int64 Eval(const Argument &arg, const std::function &evaluator) { switch (arg.type) { - case Argument::INT_VALUE: { return arg.Value(); } - case Argument::INT_VAR_REF: { return evaluator(arg.Var()); } - default: { - LOG(FATAL) << "Cannot evaluate " << arg.DebugString(); - return 0; - } + case Argument::INT_VALUE: { + return arg.Value(); + } + case Argument::INT_VAR_REF: { + return evaluator(arg.Var()); + } + default: { + LOG(FATAL) << "Cannot evaluate " << arg.DebugString(); + return 0; + } } } @@ -46,20 +50,24 @@ int Size(const Argument &arg) { int64 EvalAt(const Argument &arg, int pos, const std::function &evaluator) { switch (arg.type) { - case Argument::INT_LIST: { return arg.ValueAt(pos); } - case Argument::INT_VAR_REF_ARRAY: { return evaluator(arg.VarAt(pos)); } - default: { - LOG(FATAL) << "Cannot evaluate " << arg.DebugString(); - return 0; - } + case Argument::INT_LIST: { + return arg.ValueAt(pos); + } + case Argument::INT_VAR_REF_ARRAY: { + return evaluator(arg.VarAt(pos)); + } + default: { + LOG(FATAL) << "Cannot evaluate " << arg.DebugString(); + return 0; + } } } // Checkers -bool -CheckAllDifferentInt(const Constraint &ct, - const std::function &evaluator) { +bool CheckAllDifferentInt( + const Constraint &ct, + const std::function &evaluator) { absl::flat_hash_set visited; for (int i = 0; i < Size(ct.arguments[0]); ++i) { const int64 value = EvalAt(ct.arguments[0], i, evaluator); @@ -99,9 +107,9 @@ bool CheckAmong(const Constraint &ct, return count == expected; } -bool -CheckArrayBoolAnd(const Constraint &ct, - const std::function &evaluator) { +bool CheckArrayBoolAnd( + const Constraint &ct, + const std::function &evaluator) { int64 result = 1; for (int i = 0; i < Size(ct.arguments[0]); ++i) { @@ -112,9 +120,9 @@ CheckArrayBoolAnd(const Constraint &ct, return result == Eval(ct.arguments[1], evaluator); } -bool -CheckArrayBoolOr(const Constraint &ct, - const std::function &evaluator) { +bool CheckArrayBoolOr( + const Constraint &ct, + const std::function &evaluator) { int64 result = 0; for (int i = 0; i < Size(ct.arguments[0]); ++i) { @@ -125,9 +133,9 @@ CheckArrayBoolOr(const Constraint &ct, return result == Eval(ct.arguments[1], evaluator); } -bool -CheckArrayBoolXor(const Constraint &ct, - const std::function &evaluator) { +bool CheckArrayBoolXor( + const Constraint &ct, + const std::function &evaluator) { int64 result = 0; for (int i = 0; i < Size(ct.arguments[0]); ++i) { @@ -137,9 +145,9 @@ CheckArrayBoolXor(const Constraint &ct, return result % 2 == 1; } -bool -CheckArrayIntElement(const Constraint &ct, - const std::function &evaluator) { +bool CheckArrayIntElement( + const Constraint &ct, + const std::function &evaluator) { if (ct.arguments[0].variables.size() == 2) { // TODO(user): Check 2D element. return true; @@ -244,10 +252,10 @@ bool CheckCircuit(const Constraint &ct, int shift = 0; for (int i = 0; i < size; ++i) { const int64 next = EvalAt(ct.arguments[0], i, evaluator); - if (next == 0) { // 0 based. + if (next == 0) { // 0 based. shift = 0; break; - } else if (next == size) { // 1 based. + } else if (next == size) { // 1 based. shift = -1; break; } @@ -355,21 +363,21 @@ bool CheckDiffnK(const Constraint &ct, return true; } -bool -CheckDiffnNonStrict(const Constraint &ct, - const std::function &evaluator) { +bool CheckDiffnNonStrict( + const Constraint &ct, + const std::function &evaluator) { return true; } -bool -CheckDiffnNonStrictK(const Constraint &ct, - const std::function &evaluator) { +bool CheckDiffnNonStrictK( + const Constraint &ct, + const std::function &evaluator) { return true; } -bool -CheckDisjunctive(const Constraint &ct, - const std::function &evaluator) { +bool CheckDisjunctive( + const Constraint &ct, + const std::function &evaluator) { return true; } @@ -379,9 +387,9 @@ bool CheckDisjunctiveStrict( return true; } -bool -CheckFalseConstraint(const Constraint &ct, - const std::function &evaluator) { +bool CheckFalseConstraint( + const Constraint &ct, + const std::function &evaluator) { return false; } @@ -637,18 +645,18 @@ bool CheckIntLinEq(const Constraint &ct, return left == right; } -bool -CheckIntLinEqImp(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinEqImp( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; return (status && (left == right)) || !status; } -bool -CheckIntLinEqReif(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinEqReif( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; @@ -662,18 +670,18 @@ bool CheckIntLinGe(const Constraint &ct, return left >= right; } -bool -CheckIntLinGeImp(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinGeImp( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; return (status && (left >= right)) || !status; } -bool -CheckIntLinGeReif(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinGeReif( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; @@ -687,18 +695,18 @@ bool CheckIntLinLe(const Constraint &ct, return left <= right; } -bool -CheckIntLinLeImp(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinLeImp( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; return (status && (left <= right)) || !status; } -bool -CheckIntLinLeReif(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinLeReif( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; @@ -712,18 +720,18 @@ bool CheckIntLinNe(const Constraint &ct, return left != right; } -bool -CheckIntLinNeImp(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinNeImp( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; return (status && (left != right)) || !status; } -bool -CheckIntLinNeReif(const Constraint &ct, - const std::function &evaluator) { +bool CheckIntLinNeReif( + const Constraint &ct, + const std::function &evaluator) { const int64 left = ComputeIntLin(ct, evaluator); const int64 right = Eval(ct.arguments[2], evaluator); const bool status = Eval(ct.arguments[3], evaluator) != 0; @@ -849,9 +857,9 @@ bool CheckLexLessInt(const Constraint &ct, return false; } -bool -CheckLexLesseqInt(const Constraint &ct, - const std::function &evaluator) { +bool CheckLexLesseqInt( + const Constraint &ct, + const std::function &evaluator) { CHECK_EQ(Size(ct.arguments[0]), Size(ct.arguments[1])); for (int i = 0; i < Size(ct.arguments[0]); ++i) { const int64 x = EvalAt(ct.arguments[0], i, evaluator); @@ -867,9 +875,9 @@ CheckLexLesseqInt(const Constraint &ct, return true; } -bool -CheckMaximumArgInt(const Constraint &ct, - const std::function &evaluator) { +bool CheckMaximumArgInt( + const Constraint &ct, + const std::function &evaluator) { const int64 max_index = Eval(ct.arguments[1], evaluator) - 1; const int64 max_value = EvalAt(ct.arguments[0], max_index, evaluator); // Checks that all value before max_index are < max_value. @@ -897,9 +905,9 @@ bool CheckMaximumInt(const Constraint &ct, return max_value == Eval(ct.arguments[0], evaluator); } -bool -CheckMinimumArgInt(const Constraint &ct, - const std::function &evaluator) { +bool CheckMinimumArgInt( + const Constraint &ct, + const std::function &evaluator) { const int64 min_index = Eval(ct.arguments[1], evaluator) - 1; const int64 min_value = EvalAt(ct.arguments[0], min_index, evaluator); // Checks that all value before min_index are > min_value. @@ -943,23 +951,22 @@ bool CheckNetworkFlowConservation( } for (const int64 value : balance) { - if (value != 0) - return false; + if (value != 0) return false; } return true; } -bool -CheckNetworkFlow(const Constraint &ct, - const std::function &evaluator) { +bool CheckNetworkFlow( + const Constraint &ct, + const std::function &evaluator) { return CheckNetworkFlowConservation(ct.arguments[0], ct.arguments[1], ct.arguments[2], evaluator); } -bool -CheckNetworkFlowCost(const Constraint &ct, - const std::function &evaluator) { +bool CheckNetworkFlowCost( + const Constraint &ct, + const std::function &evaluator) { if (!CheckNetworkFlowConservation(ct.arguments[0], ct.arguments[1], ct.arguments[3], evaluator)) { return false; @@ -1251,15 +1258,14 @@ CallMap CreateCallMap() { return m; } -} // namespace +} // namespace bool CheckSolution(const Model &model, const std::function &evaluator) { bool ok = true; const CallMap call_map = CreateCallMap(); for (Constraint *ct : model.constraints()) { - if (!ct->active) - continue; + if (!ct->active) continue; const auto &checker = gtl::FindOrDie(call_map, ct->type); if (!checker(*ct, evaluator)) { FZLOG << "Failing constraint " << ct->DebugString() << FZENDL; @@ -1269,5 +1275,5 @@ bool CheckSolution(const Model &model, return ok; } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research diff --git a/ortools/flatzinc/checker.h b/ortools/flatzinc/checker.h index 995873ae4a..59d190da8b 100644 --- a/ortools/flatzinc/checker.h +++ b/ortools/flatzinc/checker.h @@ -27,7 +27,7 @@ namespace fz { bool CheckSolution(const Model &model, const std::function &evaluator); -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_CHECKER_H_ +#endif // OR_TOOLS_FLATZINC_CHECKER_H_ diff --git a/ortools/flatzinc/cp_model_fz_solver.cc b/ortools/flatzinc/cp_model_fz_solver.cc index c68c77e9aa..0e5f6a08cc 100644 --- a/ortools/flatzinc/cp_model_fz_solver.cc +++ b/ortools/flatzinc/cp_model_fz_solver.cc @@ -47,9 +47,7 @@ #include "ortools/sat/table.h" DEFINE_bool(use_flatzinc_format, true, "Output uses the flatzinc format"); -DEFINE_int64(fz_int_max, int64 { - 1 -} << 50, +DEFINE_int64(fz_int_max, int64{1} << 50, "Default max value for unbounded integer variables."); namespace operations_research { @@ -130,17 +128,15 @@ int CpModelProtoWithMapping::LookupConstant(int64 value) { } int CpModelProtoWithMapping::LookupVar(const fz::Argument &argument) { - if (argument.HasOneValue()) - return LookupConstant(argument.Value()); + if (argument.HasOneValue()) return LookupConstant(argument.Value()); CHECK_EQ(argument.type, fz::Argument::INT_VAR_REF); return fz_var_to_index[argument.Var()]; } -std::vector -CpModelProtoWithMapping::LookupVars(const fz::Argument &argument) { +std::vector CpModelProtoWithMapping::LookupVars( + const fz::Argument &argument) { std::vector result; - if (argument.type == fz::Argument::VOID_ARGUMENT) - return result; + if (argument.type == fz::Argument::VOID_ARGUMENT) return result; if (argument.type == fz::Argument::INT_LIST) { for (int64 value : argument.values) { result.push_back(LookupConstant(value)); @@ -191,9 +187,8 @@ int CpModelProtoWithMapping::GetOrCreateOptionalInterval(int start_var, return interval_index; } -std::vector -CpModelProtoWithMapping::CreateIntervals(const std::vector &starts, - const std::vector &durations) { +std::vector CpModelProtoWithMapping::CreateIntervals( + const std::vector &starts, const std::vector &durations) { std::vector intervals; for (int i = 0; i < starts.size(); ++i) { intervals.push_back(GetOrCreateInterval(starts[i], durations[i])); @@ -201,10 +196,9 @@ CpModelProtoWithMapping::CreateIntervals(const std::vector &starts, return intervals; } -void -CpModelProtoWithMapping::FillAMinusBInDomain(const std::vector &domain, - const fz::Constraint &fz_ct, - ConstraintProto *ct) { +void CpModelProtoWithMapping::FillAMinusBInDomain( + const std::vector &domain, const fz::Constraint &fz_ct, + ConstraintProto *ct) { auto *arg = ct->mutable_linear(); if (fz_ct.arguments[1].type == fz::Argument::INT_VALUE) { const int64 value = fz_ct.arguments[1].Value(); @@ -233,8 +227,7 @@ CpModelProtoWithMapping::FillAMinusBInDomain(const std::vector &domain, arg->add_vars(var_b); arg->add_coeffs(1); } else { - for (const int64 domain_bound : domain) - arg->add_domain(domain_bound); + for (const int64 domain_bound : domain) arg->add_domain(domain_bound); arg->add_vars(LookupVar(fz_ct.arguments[0])); arg->add_coeffs(1); arg->add_vars(LookupVar(fz_ct.arguments[1])); @@ -246,8 +239,7 @@ void CpModelProtoWithMapping::FillLinearConstraintWithGivenDomain( const std::vector &domain, const fz::Constraint &fz_ct, ConstraintProto *ct) { auto *arg = ct->mutable_linear(); - for (const int64 domain_bound : domain) - arg->add_domain(domain_bound); + for (const int64 domain_bound : domain) arg->add_domain(domain_bound); std::vector vars = LookupVars(fz_ct.arguments[1]); for (int i = 0; i < vars.size(); ++i) { arg->add_vars(vars[i]); @@ -321,31 +313,16 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, arg->add_literals(TrueLiteral(var)); } } else if (fz_ct.type == "bool_le" || fz_ct.type == "int_le") { - FillAMinusBInDomain({ - kint64min, 0 - }, - fz_ct, ct); + FillAMinusBInDomain({kint64min, 0}, fz_ct, ct); } else if (fz_ct.type == "bool_ge" || fz_ct.type == "int_ge") { - FillAMinusBInDomain({ - 0, kint64max - }, - fz_ct, ct); + FillAMinusBInDomain({0, kint64max}, fz_ct, ct); } else if (fz_ct.type == "bool_lt" || fz_ct.type == "int_lt") { - FillAMinusBInDomain({ - kint64min, -1 - }, - fz_ct, ct); + FillAMinusBInDomain({kint64min, -1}, fz_ct, ct); } else if (fz_ct.type == "bool_gt" || fz_ct.type == "int_gt") { - FillAMinusBInDomain({ - 1, kint64max - }, - fz_ct, ct); + FillAMinusBInDomain({1, kint64max}, fz_ct, ct); } else if (fz_ct.type == "bool_eq" || fz_ct.type == "int_eq" || fz_ct.type == "bool2int") { - FillAMinusBInDomain({ - 0, 0 - }, - fz_ct, ct); + FillAMinusBInDomain({0, 0}, fz_ct, ct); } else if (fz_ct.type == "bool_ne" || fz_ct.type == "bool_not") { auto *arg = ct->mutable_linear(); arg->add_vars(LookupVar(fz_ct.arguments[0])); @@ -355,16 +332,10 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, arg->add_domain(1); arg->add_domain(1); } else if (fz_ct.type == "int_ne") { - FillAMinusBInDomain({ - kint64min, -1, 1, kint64max - }, - fz_ct, ct); + FillAMinusBInDomain({kint64min, -1, 1, kint64max}, fz_ct, ct); } else if (fz_ct.type == "int_lin_eq") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - rhs, rhs - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain({rhs, rhs}, fz_ct, ct); } else if (fz_ct.type == "bool_lin_eq") { auto *arg = ct->mutable_linear(); const std::vector vars = LookupVars(fz_ct.arguments[1]); @@ -384,42 +355,28 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, } } else if (fz_ct.type == "int_lin_le" || fz_ct.type == "bool_lin_le") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - kint64min, rhs - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain({kint64min, rhs}, fz_ct, ct); } else if (fz_ct.type == "int_lin_lt") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - kint64min, rhs - 1 - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain({kint64min, rhs - 1}, fz_ct, ct); } else if (fz_ct.type == "int_lin_ge") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - rhs, kint64max - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain({rhs, kint64max}, fz_ct, ct); } else if (fz_ct.type == "int_lin_gt") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - rhs + 1, kint64max - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain({rhs + 1, kint64max}, fz_ct, ct); } else if (fz_ct.type == "int_lin_ne") { const int64 rhs = fz_ct.arguments[2].values[0]; - FillLinearConstraintWithGivenDomain({ - kint64min, rhs - 1, rhs + 1, kint64max - }, - fz_ct, ct); + FillLinearConstraintWithGivenDomain( + {kint64min, rhs - 1, rhs + 1, kint64max}, fz_ct, ct); } else if (fz_ct.type == "set_in") { auto *arg = ct->mutable_linear(); arg->add_vars(LookupVar(fz_ct.arguments[0])); arg->add_coeffs(1); if (fz_ct.arguments[1].type == fz::Argument::INT_LIST) { - FillDomainInProto(Domain::FromValues(std::vector { - fz_ct.arguments[1].values.begin(), fz_ct.arguments[1].values.end() - }), + FillDomainInProto(Domain::FromValues(std::vector{ + fz_ct.arguments[1].values.begin(), + fz_ct.arguments[1].values.end()}), arg); } else if (fz_ct.arguments[1].type == fz::Argument::INT_INTERVAL) { FillDomainInProto( @@ -433,14 +390,17 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, arg->add_vars(LookupVar(fz_ct.arguments[0])); arg->add_coeffs(1); if (fz_ct.arguments[1].type == fz::Argument::INT_LIST) { - FillDomainInProto(Domain::FromValues(std::vector { - fz_ct.arguments[1].values.begin(), fz_ct.arguments[1].values.end() - }).Complement(), - arg); + FillDomainInProto( + Domain::FromValues( + std::vector{fz_ct.arguments[1].values.begin(), + fz_ct.arguments[1].values.end()}) + .Complement(), + arg); } else if (fz_ct.arguments[1].type == fz::Argument::INT_INTERVAL) { - FillDomainInProto(Domain(fz_ct.arguments[1].values[0], - fz_ct.arguments[1].values[1]).Complement(), - arg); + FillDomainInProto( + Domain(fz_ct.arguments[1].values[0], fz_ct.arguments[1].values[1]) + .Complement(), + arg); } else { LOG(FATAL) << "Wrong format"; } @@ -452,8 +412,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, } else if (fz_ct.type == "array_int_minimum" || fz_ct.type == "minimum_int") { auto *arg = ct->mutable_int_min(); arg->set_target(LookupVar(fz_ct.arguments[0])); - for (const int var : LookupVars(fz_ct.arguments[1])) - arg->add_vars(var); + for (const int var : LookupVars(fz_ct.arguments[1])) arg->add_vars(var); } else if (fz_ct.type == "int_max") { auto *arg = ct->mutable_int_max(); arg->set_target(LookupVar(fz_ct.arguments[2])); @@ -462,8 +421,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, } else if (fz_ct.type == "array_int_maximum" || fz_ct.type == "maximum_int") { auto *arg = ct->mutable_int_max(); arg->set_target(LookupVar(fz_ct.arguments[0])); - for (const int var : LookupVars(fz_ct.arguments[1])) - arg->add_vars(var); + for (const int var : LookupVars(fz_ct.arguments[1])) arg->add_vars(var); } else if (fz_ct.type == "int_times") { auto *arg = ct->mutable_int_prod(); arg->set_target(LookupVar(fz_ct.arguments[2])); @@ -493,8 +451,9 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, arg->set_target(LookupVar(fz_ct.arguments[2])); arg->add_vars(LookupVar(fz_ct.arguments[0])); arg->add_vars(LookupVar(fz_ct.arguments[1])); - } else if (fz_ct.type == "array_int_element" || fz_ct.type == - "array_bool_element" || fz_ct.type == "array_var_int_element" || + } else if (fz_ct.type == "array_int_element" || + fz_ct.type == "array_bool_element" || + fz_ct.type == "array_var_int_element" || fz_ct.type == "array_var_bool_element" || fz_ct.type == "array_int_element_nonshifted") { if (fz_ct.arguments[0].type == fz::Argument::INT_VAR_REF || @@ -509,8 +468,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, // TODO(user): Make sure that zero is not in the index domain... arg->add_vars(arg->target()); } - for (const int var : LookupVars(fz_ct.arguments[1])) - arg->add_vars(var); + for (const int var : LookupVars(fz_ct.arguments[1])) arg->add_vars(var); } else { // Special case added by the presolve or in flatzinc. We encode this // as a table constraint. @@ -519,9 +477,8 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, // the constraint is: // values[coeff1 * vars[0] + coeff2 * vars[1] + offset] == target. - for (const int var : LookupVars(fz_ct.arguments[0])) - arg->add_vars(var); - arg->add_vars(LookupVar(fz_ct.arguments[2])); // the target + for (const int var : LookupVars(fz_ct.arguments[0])) arg->add_vars(var); + arg->add_vars(LookupVar(fz_ct.arguments[2])); // the target const std::vector &values = fz_ct.arguments[1].values; const int64 coeff1 = fz_ct.arguments[3].values[0]; @@ -541,14 +498,11 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, } } else if (fz_ct.type == "ortools_table_int") { auto *arg = ct->mutable_table(); - for (const int var : LookupVars(fz_ct.arguments[0])) - arg->add_vars(var); - for (const int64 value : fz_ct.arguments[1].values) - arg->add_values(value); + for (const int var : LookupVars(fz_ct.arguments[0])) arg->add_vars(var); + for (const int64 value : fz_ct.arguments[1].values) arg->add_values(value); } else if (fz_ct.type == "ortools_regular") { auto *arg = ct->mutable_automaton(); - for (const int var : LookupVars(fz_ct.arguments[0])) - arg->add_vars(var); + for (const int var : LookupVars(fz_ct.arguments[0])) arg->add_vars(var); int count = 0; const int num_states = fz_ct.arguments[1].Value(); @@ -557,8 +511,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, for (int j = 1; j <= num_values; ++j) { CHECK_LT(count, fz_ct.arguments[3].values.size()); const int next = fz_ct.arguments[3].values[count++]; - if (next == 0) - continue; // 0 is a failing state. + if (next == 0) continue; // 0 is a failing state. arg->add_transition_tail(i); arg->add_transition_label(j); arg->add_transition_head(next); @@ -567,39 +520,38 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, arg->set_starting_state(fz_ct.arguments[4].Value()); switch (fz_ct.arguments[5].type) { - case fz::Argument::INT_VALUE: { - arg->add_final_states(fz_ct.arguments[5].values[0]); - break; - } - case fz::Argument::INT_INTERVAL: { - for (int v = fz_ct.arguments[5].values[0]; - v <= fz_ct.arguments[5].values[1]; ++v) { - arg->add_final_states(v); + case fz::Argument::INT_VALUE: { + arg->add_final_states(fz_ct.arguments[5].values[0]); + break; } - break; - } - case fz::Argument::INT_LIST: { - for (const int v : fz_ct.arguments[5].values) { - arg->add_final_states(v); + case fz::Argument::INT_INTERVAL: { + for (int v = fz_ct.arguments[5].values[0]; + v <= fz_ct.arguments[5].values[1]; ++v) { + arg->add_final_states(v); + } + break; + } + case fz::Argument::INT_LIST: { + for (const int v : fz_ct.arguments[5].values) { + arg->add_final_states(v); + } + break; + } + default: { + LOG(FATAL) << "Wrong constraint " << fz_ct.DebugString(); } - break; - } - default: { LOG(FATAL) << "Wrong constraint " << fz_ct.DebugString(); } } } else if (fz_ct.type == "fzn_all_different_int") { auto *arg = ct->mutable_all_diff(); - for (const int var : LookupVars(fz_ct.arguments[0])) - arg->add_vars(var); + for (const int var : LookupVars(fz_ct.arguments[0])) arg->add_vars(var); } else if (fz_ct.type == "fzn_circuit" || fz_ct.type == "fzn_subcircuit") { // Try to auto-detect if it is zero or one based. bool found_zero = false; bool found_size = false; const int size = fz_ct.arguments[0].variables.size(); for (fz::IntegerVariable *const var : fz_ct.arguments[0].variables) { - if (var->domain.Min() == 0) - found_zero = true; - if (var->domain.Max() == size) - found_size = true; + if (var->domain.Min() == 0) found_zero = true; + if (var->domain.Max() == size) found_size = true; } const bool is_one_based = !found_zero || found_size; const int min_index = is_one_based ? 1 : 0; @@ -618,11 +570,9 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, // Restrict the domain of var to [min_index, max_index] domain = domain.IntersectionWith(Domain(min_index, max_index)); if (is_circuit) { - // We simply make sure that the variable cannot take the value index. - domain = domain.IntersectionWith(Domain::FromIntervals({ - { kint64min, index - 1 } - , { index + 1, kint64max } - })); + // We simply make sure that the variable cannot take the value index. + domain = domain.IntersectionWith(Domain::FromIntervals( + {{kint64min, index - 1}, {index + 1, kint64max}})); } FillDomainInProto(domain, proto.mutable_variables(var)); @@ -680,24 +630,19 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, bool found_zero = false; bool found_size = false; for (fz::IntegerVariable *const var : fz_ct.arguments[0].variables) { - if (var->domain.Min() == 0) - found_zero = true; - if (var->domain.Max() == num_variables) - found_size = true; + if (var->domain.Min() == 0) found_zero = true; + if (var->domain.Max() == num_variables) found_size = true; } for (fz::IntegerVariable *const var : fz_ct.arguments[1].variables) { - if (var->domain.Min() == 0) - found_zero = true; - if (var->domain.Max() == num_variables) - found_size = true; + if (var->domain.Min() == 0) found_zero = true; + if (var->domain.Max() == num_variables) found_size = true; } // Add a dummy constant variable at zero if the indexing is one based. const bool is_one_based = !found_zero || found_size; const int offset = is_one_based ? 1 : 0; - if (is_one_based) - arg->add_f_direct(LookupConstant(0)); + if (is_one_based) arg->add_f_direct(LookupConstant(0)); for (const int var : direct_variables) { arg->add_f_direct(var); // Intersect domains with offset + [0, num_variables). @@ -707,8 +652,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, proto.mutable_variables(var)); } - if (is_one_based) - arg->add_f_inverse(LookupConstant(0)); + if (is_one_based) arg->add_f_inverse(LookupConstant(0)); for (const int var : inverse_variables) { arg->add_f_inverse(var); // Intersect domains with offset + [0, num_variables). @@ -769,8 +713,7 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint &fz_ct, for (int arc = 0; arc < num_arcs; arc++) { const int tail = fz_ct.arguments[0].values[2 * arc] - 1; const int head = fz_ct.arguments[0].values[2 * arc + 1] - 1; - if (tail == head) - continue; + if (tail == head) continue; flows_per_node[tail].push_back(flow[arc]); coeffs_per_node[tail].push_back(1); @@ -882,8 +825,7 @@ void CpModelProtoWithMapping::FillReifOrImpliedConstraint( } // One way implication. We can stop here. - if (absl::EndsWith(fz_ct.type, "_imp")) - return; + if (absl::EndsWith(fz_ct.type, "_imp")) return; // Add the other side of the reification because CpModelProto only support // half reification. @@ -958,9 +900,9 @@ void CpModelProtoWithMapping::TranslateSearchAnnotations( } // The format is fixed in the flatzinc specification. -std::string -SolutionString(const fz::SolutionOutputSpecs &output, - const std::function &value_func) { +std::string SolutionString( + const fz::SolutionOutputSpecs &output, + const std::function &value_func) { if (output.variable != nullptr) { const int64 value = value_func(output.variable); if (output.display_as_boolean) { @@ -999,9 +941,9 @@ SolutionString(const fz::SolutionOutputSpecs &output, return ""; } -std::string -SolutionString(const fz::Model &model, - const std::function &value_func) { +std::string SolutionString( + const fz::Model &model, + const std::function &value_func) { std::string solution_string; for (const auto &output_spec : model.output()) { solution_string.append(SolutionString(output_spec, value_func)); @@ -1027,14 +969,14 @@ void OutputFlatzincStats(const CpSolverResponse &response) { << std::endl; std::cout << "%%%mzn-stat: failures=" << response.num_conflicts() << std::endl; - std::cout - << "%%%mzn-stat: propagations=" << response.num_binary_propagations() + - response.num_integer_propagations() - << std::endl; + std::cout << "%%%mzn-stat: propagations=" + << response.num_binary_propagations() + + response.num_integer_propagations() + << std::endl; std::cout << "%%%mzn-stat: solveTime=" << response.wall_time() << std::endl; } -} // namespace +} // namespace void SolveFzWithCpModelProto(const fz::Model &fz_model, const fz::FlatzincSatParameters &p, @@ -1053,8 +995,7 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, // lazily. int num_variables = 0; for (fz::IntegerVariable *fz_var : fz_model.variables()) { - if (!fz_var->active) - continue; + if (!fz_var->active) continue; m.fz_var_to_index[fz_var] = num_variables++; IntegerVariableProto *var = m.proto.add_variables(); var->set_name(fz_var->name); @@ -1065,9 +1006,9 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, // domains (i.e. int in minizinc) to something hopefully large enough. LOG_FIRST_N(WARNING, 1) << "Using flag --fz_int_max for unbounded integer variables."; - LOG_FIRST_N(WARNING, 1) << " actual domain is [" - << -absl::GetFlag(FLAGS_fz_int_max) << ".." - << absl::GetFlag(FLAGS_fz_int_max) << "]"; + LOG_FIRST_N(WARNING, 1) + << " actual domain is [" << -absl::GetFlag(FLAGS_fz_int_max) + << ".." << absl::GetFlag(FLAGS_fz_int_max) << "]"; var->add_domain(-absl::GetFlag(FLAGS_fz_int_max)); var->add_domain(absl::GetFlag(FLAGS_fz_int_max)); } else { @@ -1081,8 +1022,7 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, // Translate the constraints. for (fz::Constraint *fz_ct : fz_model.constraints()) { - if (fz_ct == nullptr || !fz_ct->active) - continue; + if (fz_ct == nullptr || !fz_ct->active) continue; ConstraintProto *ct = m.proto.add_constraints(); ct->set_name(fz_ct->type); if (absl::EndsWith(fz_ct->type, "_reif") || @@ -1144,25 +1084,25 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, // The order is important, we want the flag parameters to overwrite anything // set in m.parameters. sat::SatParameters flag_parameters; - CHECK(google::protobuf::TextFormat::ParseFromString( - sat_params, &flag_parameters)) << sat_params; + CHECK(google::protobuf::TextFormat::ParseFromString(sat_params, + &flag_parameters)) + << sat_params; m.parameters.MergeFrom(flag_parameters); // We only need an observer if 'p.all_solutions' is true. std::function solution_observer = nullptr; if (p.display_all_solutions && absl::GetFlag(FLAGS_use_flatzinc_format)) { - solution_observer = [&fz_model, &m, &p](const CpSolverResponse & r) { + solution_observer = [&fz_model, &m, &p](const CpSolverResponse &r) { const std::string solution_string = - SolutionString(fz_model, [&m, &r](fz::IntegerVariable * v) { - return r.solution(gtl::FindOrDie(m.fz_var_to_index, v)); - }); + SolutionString(fz_model, [&m, &r](fz::IntegerVariable *v) { + return r.solution(gtl::FindOrDie(m.fz_var_to_index, v)); + }); std::cout << solution_string << std::endl; if (p.display_statistics && absl::GetFlag(FLAGS_use_flatzinc_format)) { OutputFlatzincStats(r); } std::cout << "----------" << std::endl; - } - ; + }; } Model sat_model; @@ -1175,7 +1115,7 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, // Check the returned solution with the fz model checker. if (response.status() == CpSolverStatus::FEASIBLE || response.status() == CpSolverStatus::OPTIMAL) { - CHECK(CheckSolution(fz_model, [&response, &m](fz::IntegerVariable * v) { + CHECK(CheckSolution(fz_model, [&response, &m](fz::IntegerVariable *v) { return response.solution(gtl::FindOrDie(m.fz_var_to_index, v)); })); } @@ -1184,11 +1124,11 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, if (absl::GetFlag(FLAGS_use_flatzinc_format)) { if (response.status() == CpSolverStatus::FEASIBLE || response.status() == CpSolverStatus::OPTIMAL) { - if (!p.display_all_solutions) { // Already printed otherwise. + if (!p.display_all_solutions) { // Already printed otherwise. const std::string solution_string = - SolutionString(fz_model, [&response, &m](fz::IntegerVariable * v) { - return response.solution(gtl::FindOrDie(m.fz_var_to_index, v)); - }); + SolutionString(fz_model, [&response, &m](fz::IntegerVariable *v) { + return response.solution(gtl::FindOrDie(m.fz_var_to_index, v)); + }); std::cout << solution_string << std::endl; std::cout << "----------" << std::endl; } @@ -1206,5 +1146,5 @@ void SolveFzWithCpModelProto(const fz::Model &fz_model, } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/flatzinc/cp_model_fz_solver.h b/ortools/flatzinc/cp_model_fz_solver.h index 675418e2e2..cf74c5bd2a 100644 --- a/ortools/flatzinc/cp_model_fz_solver.h +++ b/ortools/flatzinc/cp_model_fz_solver.h @@ -30,7 +30,7 @@ struct FlatzincSatParameters { double max_time_in_seconds = 0.0; }; -} // namespace fz +} // namespace fz namespace sat { @@ -38,7 +38,7 @@ void SolveFzWithCpModelProto(const fz::Model &model, const fz::FlatzincSatParameters &p, const std::string &sat_params); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_CP_MODEL_FZ_SOLVER_H_ +#endif // OR_TOOLS_FLATZINC_CP_MODEL_FZ_SOLVER_H_ diff --git a/ortools/flatzinc/fz.cc b/ortools/flatzinc/fz.cc index 990c390d19..850b61526b 100644 --- a/ortools/flatzinc/fz.cc +++ b/ortools/flatzinc/fz.cc @@ -15,9 +15,9 @@ // of the funcionalities are fixed (name of parameters, format of the // input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf -#if defined(__GNUC__) // Linux or Mac OS X. +#if defined(__GNUC__) // Linux or Mac OS X. #include -#endif // __GNUC__ +#endif // __GNUC__ #include #include @@ -158,8 +158,8 @@ Model ParseFlatzincModel(const std::string &input, bool input_is_filename) { return model; } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research int main(int argc, char **argv) { // Flatzinc specifications require single dash parameters (-a, -f, -p). diff --git a/ortools/flatzinc/logging.h b/ortools/flatzinc/logging.h index d1b1031da8..1c13a4a3d6 100644 --- a/ortools/flatzinc/logging.h +++ b/ortools/flatzinc/logging.h @@ -29,17 +29,14 @@ DECLARE_bool(fz_verbose); DECLARE_bool(fz_debug); #define FZENDL std::endl -#define FZLOG \ - if (absl::GetFlag(FLAGS_fz_logging)) \ - std::cout << "%% " +#define FZLOG \ + if (absl::GetFlag(FLAGS_fz_logging)) std::cout << "%% " -#define FZVLOG \ - if (absl::GetFlag(FLAGS_fz_verbose)) \ - std::cout << "%%%% " +#define FZVLOG \ + if (absl::GetFlag(FLAGS_fz_verbose)) std::cout << "%%%% " -#define FZDLOG \ - if (absl::GetFlag(FLAGS_fz_debug)) \ - std::cout << "%%%%%% " +#define FZDLOG \ + if (absl::GetFlag(FLAGS_fz_debug)) std::cout << "%%%%%% " #define HASVLOG absl::GetFlag(FLAGS_fz_verbose) -#endif // OR_TOOLS_FLATZINC_LOGGING_H_ +#endif // OR_TOOLS_FLATZINC_LOGGING_H_ diff --git a/ortools/flatzinc/model.cc b/ortools/flatzinc/model.cc index de40a754cc..b7b8b8d41e 100644 --- a/ortools/flatzinc/model.cc +++ b/ortools/flatzinc/model.cc @@ -121,7 +121,7 @@ bool Domain::IntersectWithDomain(const Domain &domain) { return false; } if (is_interval) { - is_interval = false; // Other is not an interval. + is_interval = false; // Other is not an interval. if (values.empty()) { values = domain.values; } else { @@ -141,7 +141,7 @@ bool Domain::IntersectWithSingleton(int64 value) { } bool Domain::IntersectWithInterval(int64 interval_min, int64 interval_max) { - if (interval_min > interval_max) { // Empty interval -> empty domain. + if (interval_min > interval_max) { // Empty interval -> empty domain. is_interval = false; values.clear(); return true; @@ -151,8 +151,7 @@ bool Domain::IntersectWithInterval(int64 interval_min, int64 interval_max) { values.push_back(interval_max); return true; } else { - if (values[0] >= interval_min && values[1] <= interval_max) - return false; + if (values[0] >= interval_min && values[1] <= interval_max) return false; values[0] = std::max(values[0], interval_min); values[1] = std::min(values[1], interval_max); if (values[0] > values[1]) { @@ -195,12 +194,12 @@ bool Domain::IntersectWithListOfIntegers(const std::vector &integers) { const int64 dmax = values.empty() ? kint64max : values[1]; values.clear(); for (const int64 v : integers) { - if (v >= dmin && v <= dmax) - values.push_back(v); + if (v >= dmin && v <= dmax) values.push_back(v); } gtl::STLSortAndRemoveDuplicates(&values); - if (!values.empty() && values.back() - values.front() == - values.size() - 1 && values.size() >= 2) { + if (!values.empty() && + values.back() - values.front() == values.size() - 1 && + values.size() >= 2) { if (values.size() > 2) { // Contiguous case. const int64 last = values.back(); @@ -285,7 +284,7 @@ bool IntervalOverlapValues(int64 lb, int64 ub, } return false; } -} // namespace +} // namespace bool Domain::OverlapsIntList(const std::vector &vec) const { if (IsAllInt64()) { @@ -348,7 +347,7 @@ bool Domain::RemoveValue(int64 value) { values[1]--; return true; } else if (values[1] - values[0] < 1024 && value > values[0] && - value < values[1]) { // small + value < values[1]) { // small const int64 vmax = values[1]; values.pop_back(); values.reserve(vmax - values[0]); @@ -447,26 +446,26 @@ Argument Argument::FromDomain(const Domain &domain) { std::string Argument::DebugString() const { switch (type) { - case INT_VALUE: - return absl::StrFormat("% d", values[0]); - case INT_INTERVAL: - return absl::StrFormat("[%d..%d]", values[0], values[1]); - case INT_LIST: - return absl::StrFormat("[%s]", absl::StrJoin(values, ", ")); - case DOMAIN_LIST: - return absl::StrFormat("[%s]", JoinDebugString(domains, ", ")); - case INT_VAR_REF: - return variables[0]->name; - case INT_VAR_REF_ARRAY: { - std::string result = "["; - for (int i = 0; i < variables.size(); ++i) { - result.append(variables[i]->name); - result.append(i != variables.size() - 1 ? ", " : "]"); + case INT_VALUE: + return absl::StrFormat("% d", values[0]); + case INT_INTERVAL: + return absl::StrFormat("[%d..%d]", values[0], values[1]); + case INT_LIST: + return absl::StrFormat("[%s]", absl::StrJoin(values, ", ")); + case DOMAIN_LIST: + return absl::StrFormat("[%s]", JoinDebugString(domains, ", ")); + case INT_VAR_REF: + return variables[0]->name; + case INT_VAR_REF_ARRAY: { + std::string result = "["; + for (int i = 0; i < variables.size(); ++i) { + result.append(variables[i]->name); + result.append(i != variables.size() - 1 ? ", " : "]"); + } + return result; } - return result; - } - case VOID_ARGUMENT: - return "VoidArgument"; + case VOID_ARGUMENT: + return "VoidArgument"; } LOG(FATAL) << "Unhandled case in DebugString " << static_cast(type); return ""; @@ -481,90 +480,94 @@ bool Argument::HasOneValue() const { } int64 Argument::Value() const { - DCHECK(HasOneValue()) - << "Value() called on unbound Argument: " << DebugString(); + DCHECK(HasOneValue()) << "Value() called on unbound Argument: " + << DebugString(); switch (type) { - case INT_VALUE: - case INT_INTERVAL: - case INT_LIST: - return values[0]; - case INT_VAR_REF: { return variables[0]->domain.values[0]; } - default: { - LOG(FATAL) << "Should not be here"; - return 0; - } + case INT_VALUE: + case INT_INTERVAL: + case INT_LIST: + return values[0]; + case INT_VAR_REF: { + return variables[0]->domain.values[0]; + } + default: { + LOG(FATAL) << "Should not be here"; + return 0; + } } } bool Argument::IsArrayOfValues() const { switch (type) { - case INT_VALUE: - return false; - case INT_INTERVAL: - return false; - case INT_LIST: - return true; - case DOMAIN_LIST: { - for (const Domain &domain : domains) { - if (!domain.HasOneValue()) { - return false; + case INT_VALUE: + return false; + case INT_INTERVAL: + return false; + case INT_LIST: + return true; + case DOMAIN_LIST: { + for (const Domain &domain : domains) { + if (!domain.HasOneValue()) { + return false; + } } + return true; } - return true; - } - case INT_VAR_REF: - return false; - case INT_VAR_REF_ARRAY: { - for (IntegerVariable *var : variables) { - if (!var->domain.HasOneValue()) { - return false; + case INT_VAR_REF: + return false; + case INT_VAR_REF_ARRAY: { + for (IntegerVariable *var : variables) { + if (!var->domain.HasOneValue()) { + return false; + } } + return true; } - return true; - } - case VOID_ARGUMENT: - return false; + case VOID_ARGUMENT: + return false; } } bool Argument::Contains(int64 value) const { switch (type) { - case Argument::INT_LIST: { - return std::find(values.begin(), values.end(), value) != values.end(); - } - case Argument::INT_INTERVAL: { - return value >= values.front() && value <= values.back(); - } - case Argument::INT_VALUE: { return value == values.front(); } - default: { - LOG(FATAL) << "Cannot call Contains() on " << DebugString(); - return false; - } + case Argument::INT_LIST: { + return std::find(values.begin(), values.end(), value) != values.end(); + } + case Argument::INT_INTERVAL: { + return value >= values.front() && value <= values.back(); + } + case Argument::INT_VALUE: { + return value == values.front(); + } + default: { + LOG(FATAL) << "Cannot call Contains() on " << DebugString(); + return false; + } } } int64 Argument::ValueAt(int pos) const { switch (type) { - case INT_LIST: - CHECK_GE(pos, 0); - CHECK_LT(pos, values.size()); - return values[pos]; - case DOMAIN_LIST: { - CHECK_GE(pos, 0); - CHECK_LT(pos, domains.size()); - CHECK(domains[pos].HasOneValue()); - return domains[pos].Value(); - } - case INT_VAR_REF_ARRAY: { - CHECK_GE(pos, 0); - CHECK_LT(pos, variables.size()); - CHECK(variables[pos]->domain.HasOneValue()); - return variables[pos]->domain.Value(); - } - default: { - LOG(FATAL) << "Should not be here"; - return 0; - } + case INT_LIST: + CHECK_GE(pos, 0); + CHECK_LT(pos, values.size()); + return values[pos]; + case DOMAIN_LIST: { + CHECK_GE(pos, 0); + CHECK_LT(pos, domains.size()); + CHECK(domains[pos].HasOneValue()); + return domains[pos].Value(); + } + case INT_VAR_REF_ARRAY: { + CHECK_GE(pos, 0); + CHECK_LT(pos, variables.size()); + CHECK(variables[pos]->domain.HasOneValue()); + return variables[pos]->domain.Value(); + } + default: { + LOG(FATAL) << "Should not be here"; + return 0; + } } } @@ -611,8 +614,9 @@ std::string IntegerVariable::DebugString() const { std::string Constraint::DebugString() const { const std::string strong = strong_propagation ? "strong propagation" : ""; const std::string presolve_status_str = - active ? "" : (presolve_propagation_done ? "[propagated during presolve]" - : "[removed during presolve]"); + active ? "" + : (presolve_propagation_done ? "[propagated during presolve]" + : "[removed during presolve]"); return absl::StrFormat("%s(%s)%s %s", type, JoinDebugString(arguments, ", "), strong, presolve_status_str); } @@ -733,27 +737,35 @@ void Annotation::AppendAllIntegerVariables( std::string Annotation::DebugString() const { switch (type) { - case ANNOTATION_LIST: { - return absl::StrFormat("[%s]", JoinDebugString(annotations, ", ")); - } - case IDENTIFIER: { return id; } - case FUNCTION_CALL: { - return absl::StrFormat("%s(%s)", id, JoinDebugString(annotations, ", ")); - } - case INTERVAL: { - return absl::StrFormat("%d..%d", interval_min, interval_max); - } - case INT_VALUE: { return absl::StrCat(interval_min); } - case INT_VAR_REF: { return variables.front()->name; } - case INT_VAR_REF_ARRAY: { - std::string result = "["; - for (int i = 0; i < variables.size(); ++i) { - result.append(variables[i]->DebugString()); - result.append(i != variables.size() - 1 ? ", " : "]"); + case ANNOTATION_LIST: { + return absl::StrFormat("[%s]", JoinDebugString(annotations, ", ")); + } + case IDENTIFIER: { + return id; + } + case FUNCTION_CALL: { + return absl::StrFormat("%s(%s)", id, JoinDebugString(annotations, ", ")); + } + case INTERVAL: { + return absl::StrFormat("%d..%d", interval_min, interval_max); + } + case INT_VALUE: { + return absl::StrCat(interval_min); + } + case INT_VAR_REF: { + return variables.front()->name; + } + case INT_VAR_REF_ARRAY: { + std::string result = "["; + for (int i = 0; i < variables.size(); ++i) { + result.append(variables[i]->DebugString()); + result.append(i != variables.size() - 1 ? ", " : "]"); + } + return result; + } + case STRING_VALUE: { + return absl::StrFormat("\"%s\"", string_value); } - return result; - } - case STRING_VALUE: { return absl::StrFormat("\"%s\"", string_value); } } LOG(FATAL) << "Unhandled case in DebugString " << static_cast(type); return ""; @@ -765,10 +777,9 @@ std::string SolutionOutputSpecs::Bounds::DebugString() const { return absl::StrFormat("%d..%d", min_value, max_value); } -SolutionOutputSpecs -SolutionOutputSpecs::SingleVariable(const std::string &name, - IntegerVariable *variable, - bool display_as_boolean) { +SolutionOutputSpecs SolutionOutputSpecs::SingleVariable( + const std::string &name, IntegerVariable *variable, + bool display_as_boolean) { SolutionOutputSpecs result; result.name = name; result.variable = variable; @@ -950,5 +961,5 @@ void FlattenAnnotations(const Annotation &ann, std::vector *out) { } } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research diff --git a/ortools/flatzinc/model.h b/ortools/flatzinc/model.h index 3c1f616552..d2b39cbd7e 100644 --- a/ortools/flatzinc/model.h +++ b/ortools/flatzinc/model.h @@ -131,7 +131,7 @@ struct IntegerVariable { // there is no need to create it. bool active : 1; -private: + private: friend class Model; IntegerVariable(const std::string &name_, const Domain &domain_, @@ -196,8 +196,11 @@ struct Argument { struct Constraint { Constraint(const std::string &t, std::vector args, bool strong_propag) - : type(t), arguments(std::move(args)), strong_propagation(strong_propag), - active(true), presolve_propagation_done(false) {} + : type(t), + arguments(std::move(args)), + strong_propagation(strong_propag), + active(true), + presolve_propagation_done(false) {} std::string DebugString() const; @@ -292,10 +295,9 @@ struct SolutionOutputSpecs { // Will output (for example): // name = array2d(min1..max1, min2..max2, [list of variable values]) // for a 2d array (bounds.size() == 2). - static SolutionOutputSpecs - MultiDimensionalArray(const std::string &name, std::vector bounds, - std::vector flat_variables, - bool display_as_boolean); + static SolutionOutputSpecs MultiDimensionalArray( + const std::string &name, std::vector bounds, + std::vector flat_variables, bool display_as_boolean); // Empty output. static SolutionOutputSpecs VoidOutput(); @@ -311,7 +313,7 @@ struct SolutionOutputSpecs { }; class Model { -public: + public: explicit Model(const std::string &name) : name_(name), objective_(nullptr), maximize_(true) {} ~Model(); @@ -367,7 +369,7 @@ public: const std::string &name() const { return name_; } -private: + private: const std::string name_; // owned. // TODO(user): use unique_ptr @@ -386,7 +388,7 @@ private: // Stand-alone statistics class on the model. // TODO(user): Clean up API to pass a Model* in argument. class ModelStatistics { -public: + public: explicit ModelStatistics(const Model &model) : model_(model) {} int NumVariableOccurrences(IntegerVariable *var) { return constraints_per_variables_[var].size(); @@ -394,7 +396,7 @@ public: void BuildStatistics(); void PrintStatistics() const; -private: + private: const Model &model_; std::map > constraints_per_type_; absl::flat_hash_map > @@ -404,7 +406,7 @@ private: // Helper method to flatten Search annotations. void FlattenAnnotations(const Annotation &ann, std::vector *out); -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_MODEL_H_ +#endif // OR_TOOLS_FLATZINC_MODEL_H_ diff --git a/ortools/flatzinc/parser.cc b/ortools/flatzinc/parser.cc index 7cadb8b379..67984734fa 100644 --- a/ortools/flatzinc/parser.cc +++ b/ortools/flatzinc/parser.cc @@ -76,5 +76,5 @@ bool ParseFlatzincString(const std::string &input, Model *model) { } return ok; } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research diff --git a/ortools/flatzinc/parser.h b/ortools/flatzinc/parser.h index 03e978709a..d77ad95e58 100644 --- a/ortools/flatzinc/parser.h +++ b/ortools/flatzinc/parser.h @@ -23,6 +23,6 @@ namespace fz { // Public parsing API. bool ParseFlatzincFile(const std::string &filename, Model *model); bool ParseFlatzincString(const std::string &input, Model *model); -} // namespace fz -} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_PARSER_H_ +} // namespace fz +} // namespace operations_research +#endif // OR_TOOLS_FLATZINC_PARSER_H_ diff --git a/ortools/flatzinc/parser.tab.cc b/ortools/flatzinc/parser.tab.cc index 23306d81cd..b53001e54b 100644 --- a/ortools/flatzinc/parser.tab.cc +++ b/ortools/flatzinc/parser.tab.cc @@ -110,46 +110,46 @@ /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, - YYSYMBOL_YYEOF = 0, /* "end of file" */ - YYSYMBOL_YYerror = 1, /* error */ - YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ - YYSYMBOL_ARRAY = 3, /* ARRAY */ - YYSYMBOL_TOKEN_BOOL = 4, /* TOKEN_BOOL */ - YYSYMBOL_CONSTRAINT = 5, /* CONSTRAINT */ - YYSYMBOL_TOKEN_FLOAT = 6, /* TOKEN_FLOAT */ - YYSYMBOL_TOKEN_INT = 7, /* TOKEN_INT */ - YYSYMBOL_MAXIMIZE = 8, /* MAXIMIZE */ - YYSYMBOL_MINIMIZE = 9, /* MINIMIZE */ - YYSYMBOL_OF = 10, /* OF */ - YYSYMBOL_PREDICATE = 11, /* PREDICATE */ - YYSYMBOL_SATISFY = 12, /* SATISFY */ - YYSYMBOL_SET = 13, /* SET */ - YYSYMBOL_SOLVE = 14, /* SOLVE */ - YYSYMBOL_VAR = 15, /* VAR */ - YYSYMBOL_DOTDOT = 16, /* DOTDOT */ - YYSYMBOL_COLONCOLON = 17, /* COLONCOLON */ - YYSYMBOL_IVALUE = 18, /* IVALUE */ - YYSYMBOL_SVALUE = 19, /* SVALUE */ - YYSYMBOL_IDENTIFIER = 20, /* IDENTIFIER */ - YYSYMBOL_DVALUE = 21, /* DVALUE */ - YYSYMBOL_22_ = 22, /* ';' */ - YYSYMBOL_23_ = 23, /* '(' */ - YYSYMBOL_24_ = 24, /* ')' */ - YYSYMBOL_25_ = 25, /* ',' */ - YYSYMBOL_26_ = 26, /* ':' */ - YYSYMBOL_27_ = 27, /* '[' */ - YYSYMBOL_28_ = 28, /* ']' */ - YYSYMBOL_29_ = 29, /* '=' */ - YYSYMBOL_30_ = 30, /* '{' */ - YYSYMBOL_31_ = 31, /* '}' */ - YYSYMBOL_YYACCEPT = 32, /* $accept */ - YYSYMBOL_model = 33, /* model */ - YYSYMBOL_predicates = 34, /* predicates */ - YYSYMBOL_predicate = 35, /* predicate */ - YYSYMBOL_predicate_arguments = 36, /* predicate_arguments */ - YYSYMBOL_predicate_argument = 37, /* predicate_argument */ - YYSYMBOL_predicate_array_argument = 38, /* predicate_array_argument */ - YYSYMBOL_predicate_ints = 39, /* predicate_ints */ + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_ARRAY = 3, /* ARRAY */ + YYSYMBOL_TOKEN_BOOL = 4, /* TOKEN_BOOL */ + YYSYMBOL_CONSTRAINT = 5, /* CONSTRAINT */ + YYSYMBOL_TOKEN_FLOAT = 6, /* TOKEN_FLOAT */ + YYSYMBOL_TOKEN_INT = 7, /* TOKEN_INT */ + YYSYMBOL_MAXIMIZE = 8, /* MAXIMIZE */ + YYSYMBOL_MINIMIZE = 9, /* MINIMIZE */ + YYSYMBOL_OF = 10, /* OF */ + YYSYMBOL_PREDICATE = 11, /* PREDICATE */ + YYSYMBOL_SATISFY = 12, /* SATISFY */ + YYSYMBOL_SET = 13, /* SET */ + YYSYMBOL_SOLVE = 14, /* SOLVE */ + YYSYMBOL_VAR = 15, /* VAR */ + YYSYMBOL_DOTDOT = 16, /* DOTDOT */ + YYSYMBOL_COLONCOLON = 17, /* COLONCOLON */ + YYSYMBOL_IVALUE = 18, /* IVALUE */ + YYSYMBOL_SVALUE = 19, /* SVALUE */ + YYSYMBOL_IDENTIFIER = 20, /* IDENTIFIER */ + YYSYMBOL_DVALUE = 21, /* DVALUE */ + YYSYMBOL_22_ = 22, /* ';' */ + YYSYMBOL_23_ = 23, /* '(' */ + YYSYMBOL_24_ = 24, /* ')' */ + YYSYMBOL_25_ = 25, /* ',' */ + YYSYMBOL_26_ = 26, /* ':' */ + YYSYMBOL_27_ = 27, /* '[' */ + YYSYMBOL_28_ = 28, /* ']' */ + YYSYMBOL_29_ = 29, /* '=' */ + YYSYMBOL_30_ = 30, /* '{' */ + YYSYMBOL_31_ = 31, /* '}' */ + YYSYMBOL_YYACCEPT = 32, /* $accept */ + YYSYMBOL_model = 33, /* model */ + YYSYMBOL_predicates = 34, /* predicates */ + YYSYMBOL_predicate = 35, /* predicate */ + YYSYMBOL_predicate_arguments = 36, /* predicate_arguments */ + YYSYMBOL_predicate_argument = 37, /* predicate_argument */ + YYSYMBOL_predicate_array_argument = 38, /* predicate_array_argument */ + YYSYMBOL_predicate_ints = 39, /* predicate_ints */ YYSYMBOL_variable_or_constant_declarations = 40, /* variable_or_constant_declarations */ YYSYMBOL_variable_or_constant_declaration = 41, @@ -238,30 +238,30 @@ typedef int_least16_t yytype_int16; typedef short yytype_int16; #endif -#if defined __UINT_LEAST8_MAX__ &&__UINT_LEAST8_MAX__ <= __INT_MAX__ +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; -#elif(!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H && \ - UINT_LEAST8_MAX <= INT_MAX) +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H && \ + UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; -#elif !defined __UINT_LEAST8_MAX__ &&UCHAR_MAX <= INT_MAX +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif -#if defined __UINT_LEAST16_MAX__ &&__UINT_LEAST16_MAX__ <= __INT_MAX__ +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; -#elif(!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H && \ - UINT_LEAST16_MAX <= INT_MAX) +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H && \ + UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; -#elif !defined __UINT_LEAST16_MAX__ &&USHRT_MAX <= INT_MAX +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T -#if defined __PTRDIFF_TYPE__ &&defined __PTRDIFF_MAX__ +#if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ #define YYPTRDIFF_T __PTRDIFF_TYPE__ #define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ #elif defined PTRDIFF_MAX @@ -289,9 +289,9 @@ typedef int yytype_uint16; #endif #endif -#define YYSIZE_MAXIMUM \ - YY_CAST(YYPTRDIFF_T, \ - (YYPTRDIFF_MAXIMUM < YY_CAST(YYSIZE_T, -1) ? YYPTRDIFF_MAXIMUM \ +#define YYSIZE_MAXIMUM \ + YY_CAST(YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST(YYSIZE_T, -1) ? YYPTRDIFF_MAXIMUM \ : YY_CAST(YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST(YYPTRDIFF_T, sizeof(X)) @@ -303,7 +303,7 @@ typedef yytype_uint8 yy_state_t; typedef int yy_state_fast_t; #ifndef YY_ -#if defined YYENABLE_NLS &&YYENABLE_NLS +#if defined YYENABLE_NLS && YYENABLE_NLS #if ENABLE_NLS #include /* INFRINGES ON USER NAME SPACE */ #define YY_(Msgid) dgettext("bison-runtime", Msgid) @@ -339,10 +339,10 @@ typedef int yy_state_fast_t; #if defined __GNUC__ && !defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ -#define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \ - _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +#define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") #define YY_IGNORE_MAYBE_UNINITIALIZED_END _Pragma("GCC diagnostic pop") #else #define YY_INITIAL_VALUE(Value) Value @@ -355,9 +355,9 @@ typedef int yy_state_fast_t; #define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif -#if defined __cplusplus &&defined __GNUC__ && !defined __ICC && 6 <= __GNUC__ -#define YY_IGNORE_USELESS_CAST_BEGIN \ - _Pragma("GCC diagnostic push") \ +#if defined __cplusplus && defined __GNUC__ && !defined __ICC && 6 <= __GNUC__ +#define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wuseless-cast\"") #define YY_IGNORE_USELESS_CAST_END _Pragma("GCC diagnostic pop") #endif @@ -387,7 +387,7 @@ typedef int yy_state_fast_t; #define YYSTACK_ALLOC alloca #if !defined _ALLOCA_H && !defined EXIT_SUCCESS #include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +/* Use EXIT_SUCCESS as a witness for stdlib.h. */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif @@ -398,9 +398,9 @@ typedef int yy_state_fast_t; #ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ -#define YYSTACK_FREE(Ptr) \ - do { /* empty */ \ - ; \ +#define YYSTACK_FREE(Ptr) \ + do { /* empty */ \ + ; \ } while (0) #ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, @@ -415,8 +415,8 @@ typedef int yy_state_fast_t; #ifndef YYSTACK_ALLOC_MAXIMUM #define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM #endif -#if (defined __cplusplus && !defined EXIT_SUCCESS && \ - !((defined YYMALLOC || defined malloc) && \ +#if (defined __cplusplus && !defined EXIT_SUCCESS && \ + !((defined YYMALLOC || defined malloc) && \ (defined YYFREE || defined free))) #include /* INFRINGES ON USER NAME SPACE */ #ifndef EXIT_SUCCESS @@ -432,14 +432,14 @@ void *malloc(YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ #ifndef YYFREE #define YYFREE free #if !defined free && !defined EXIT_SUCCESS -void free(void *); /* INFRINGES ON USER NAME SPACE */ +void free(void *); /* INFRINGES ON USER NAME SPACE */ #endif #endif #endif #endif /* 1 */ -#if (!defined yyoverflow && \ - (!defined __cplusplus || \ +#if (!defined yyoverflow && \ + (!defined __cplusplus || \ (defined ORFZ_STYPE_IS_TRIVIAL && ORFZ_STYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ @@ -453,7 +453,7 @@ union yyalloc { /* The size of an array large to enough to hold all stacks, each with N elements. */ -#define YYSTACK_BYTES(N) \ +#define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF(yy_state_t) + YYSIZEOF(YYSTYPE)) + YYSTACK_GAP_MAXIMUM) #define YYCOPY_NEEDED 1 @@ -463,30 +463,29 @@ union yyalloc { elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -#define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do { \ - YYPTRDIFF_T yynewbytes; \ - YYCOPY(&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * YYSIZEOF(*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / YYSIZEOF(*yyptr); \ +#define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY(&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF(*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF(*yyptr); \ } while (0) #endif -#if defined YYCOPY_NEEDED &&YYCOPY_NEEDED +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ #ifndef YYCOPY #if defined __GNUC__ && 1 < __GNUC__ -#define YYCOPY(Dst, Src, Count) \ +#define YYCOPY(Dst, Src, Count) \ __builtin_memcpy(Dst, Src, YY_CAST(YYSIZE_T, (Count)) * sizeof(*(Src))) #else -#define YYCOPY(Dst, Src, Count) \ - do { \ - YYPTRDIFF_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ +#define YYCOPY(Dst, Src, Count) \ + do { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) (Dst)[yyi] = (Src)[yyi]; \ } while (0) #endif #endif @@ -511,38 +510,39 @@ union yyalloc { /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ -#define YYTRANSLATE(YYX) \ - (0 <= (YYX) && (YYX) <= YYMAXUTOK \ - ? YY_CAST(yysymbol_kind_t, yytranslate[YYX]) \ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST(yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 24, 2, 2, 25, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 26, 22, 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 27, 2, 28, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 2, 31, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 -}; + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 23, 24, 2, 2, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 22, + 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 27, 2, 28, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 30, 2, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}; #if ORFZ_DEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 103, 103, 110, 114, 115, 120, 123, 124, 127, 128, 129, 130, 133, 134, 137, - 138, 145, 146, 149, 168, 183, 194, 209, 220, 246, 279, 349, 350, 353, 354, - 355, 358, 362, 368, 369, 382, 400, 401, 402, 403, 410, 411, 412, 413, 420, - 421, 428, 429, 430, 433, 434, 437, 438, 439, 444, 445, 448, 449, 450, 455, - 456, 457, 462, 463, 467, 468, 474, 478, 484, 485, 488, 500, 501, 504, 505, - 506, 507, 508, 513, 544, 561, 586, 595, 599, 602, 603, 606, 607, 608, 609, - 619, 628, 634, 649, 657, 666 -}; + 0, 103, 103, 110, 114, 115, 120, 123, 124, 127, 128, 129, 130, 133, + 134, 137, 138, 145, 146, 149, 168, 183, 194, 209, 220, 246, 279, 349, + 350, 353, 354, 355, 358, 362, 368, 369, 382, 400, 401, 402, 403, 410, + 411, 412, 413, 420, 421, 428, 429, 430, 433, 434, 437, 438, 439, 444, + 445, 448, 449, 450, 455, 456, 457, 462, 463, 467, 468, 474, 478, 484, + 485, 488, 500, 501, 504, 505, 506, 507, 508, 513, 544, 561, 586, 595, + 599, 602, 603, 606, 607, 608, 609, 619, 628, 634, 649, 657, 666}; #endif /** Accessing symbol of state STATE. */ @@ -555,21 +555,71 @@ static const char *yysymbol_name(yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = { - "\"end of file\"", "error", "\"invalid token\"", "ARRAY", "TOKEN_BOOL", - "CONSTRAINT", "TOKEN_FLOAT", "TOKEN_INT", "MAXIMIZE", "MINIMIZE", "OF", - "PREDICATE", "SATISFY", "SET", "SOLVE", "VAR", "DOTDOT", "COLONCOLON", - "IVALUE", "SVALUE", "IDENTIFIER", "DVALUE", "';'", "'('", "')'", "','", "':'", - "'['", "']'", "'='", "'{'", "'}'", "$accept", "model", "predicates", - "predicate", "predicate_arguments", "predicate_argument", - "predicate_array_argument", "predicate_ints", - "variable_or_constant_declarations", "variable_or_constant_declaration", - "optional_var_or_value", "optional_var_or_value_array", "var_or_value_array", - "var_or_value", "int_domain", "set_domain", "float_domain", "domain", - "integers", "integer", "floats", "float", "const_literal", "const_literals", - "constraints", "constraint", "arguments", "argument", "annotations", - "annotation_arguments", "annotation", "solve", YY_NULLPTR -}; +static const char *const yytname[] = {"\"end of file\"", + "error", + "\"invalid token\"", + "ARRAY", + "TOKEN_BOOL", + "CONSTRAINT", + "TOKEN_FLOAT", + "TOKEN_INT", + "MAXIMIZE", + "MINIMIZE", + "OF", + "PREDICATE", + "SATISFY", + "SET", + "SOLVE", + "VAR", + "DOTDOT", + "COLONCOLON", + "IVALUE", + "SVALUE", + "IDENTIFIER", + "DVALUE", + "';'", + "'('", + "')'", + "','", + "':'", + "'['", + "']'", + "'='", + "'{'", + "'}'", + "$accept", + "model", + "predicates", + "predicate", + "predicate_arguments", + "predicate_argument", + "predicate_array_argument", + "predicate_ints", + "variable_or_constant_declarations", + "variable_or_constant_declaration", + "optional_var_or_value", + "optional_var_or_value_array", + "var_or_value_array", + "var_or_value", + "int_domain", + "set_domain", + "float_domain", + "domain", + "integers", + "integer", + "floats", + "float", + "const_literal", + "const_literals", + "constraints", + "constraint", + "arguments", + "argument", + "annotations", + "annotation_arguments", + "annotation", + "solve", + YY_NULLPTR}; static const char *yysymbol_name(yysymbol_kind_t yysymbol) { return yytname[yysymbol]; @@ -579,10 +629,10 @@ static const char *yysymbol_name(yysymbol_kind_t yysymbol) { #ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ -static const yytype_int16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 276, 59, 40, - 41, 44, 58, 91, 93, 61, 123, 125 }; +static const yytype_int16 yytoknum[] = {0, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 59, 40, + 41, 44, 58, 91, 93, 61, 123, 125}; #endif #define YYPACT_NINF (-182) @@ -596,128 +646,131 @@ static const yytype_int16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { - -182, 49, 7, -182, -15, 67, 114, 20, -182, 95, -182, 99, -182, -182, -182, - 136, 76, 122, 141, 11, 154, -182, -182, -182, 143, 130, 40, 157, 12, 151, 160, - 158, -182, 155, 118, -182, -182, 161, 163, -182, 162, 164, 165, 76, 156, 166, - 159, 171, -182, -182, 172, 11, 169, -182, -182, 175, 11, -182, -182, 167, 125, - -182, -182, 27, 168, -182, 40, 176, 177, 179, 120, -182, 170, -182, 22, 80, - 80, 80, -182, 121, 174, 184, 173, -182, 182, -182, -182, 178, -182, -182, 59, - -182, 75, 187, -182, 180, -182, 93, 11, 131, -182, -182, -182, 188, -182, 96, - 121, -182, 198, 190, 199, -182, 200, 150, -182, 195, 185, -182, 34, -182, 196, - 197, -182, 186, -182, 31, -182, 128, -182, 80, 201, 121, 202, 84, -182, -182, - -182, 56, 60, -182, 203, 204, -182, 129, -182, 189, 205, 150, -182, -182, 207, - -182, -182, 147, 206, 121, -182, 76, 192, 76, 209, 210, 211, -182, 212, -182, - -182, 213, -182, -182, -182, -182, 216, 208, 217, 218, 219, 224, -182, -182, - 225, -182, 226, -182, -182, -182, -182, -182, 74, 85, 87, 91, 220, 221, 222, - 223, -182, 97, 75, 64, 104, -182, 133, -182, 137, 227, -182, -182, 138, -182, - -182, 139, -182, 75, -182, 214, 153, -182, -182, -182, 228, -182, -182 -}; + -182, 49, 7, -182, -15, 67, 114, 20, -182, 95, -182, 99, + -182, -182, -182, 136, 76, 122, 141, 11, 154, -182, -182, -182, + 143, 130, 40, 157, 12, 151, 160, 158, -182, 155, 118, -182, + -182, 161, 163, -182, 162, 164, 165, 76, 156, 166, 159, 171, + -182, -182, 172, 11, 169, -182, -182, 175, 11, -182, -182, 167, + 125, -182, -182, 27, 168, -182, 40, 176, 177, 179, 120, -182, + 170, -182, 22, 80, 80, 80, -182, 121, 174, 184, 173, -182, + 182, -182, -182, 178, -182, -182, 59, -182, 75, 187, -182, 180, + -182, 93, 11, 131, -182, -182, -182, 188, -182, 96, 121, -182, + 198, 190, 199, -182, 200, 150, -182, 195, 185, -182, 34, -182, + 196, 197, -182, 186, -182, 31, -182, 128, -182, 80, 201, 121, + 202, 84, -182, -182, -182, 56, 60, -182, 203, 204, -182, 129, + -182, 189, 205, 150, -182, -182, 207, -182, -182, 147, 206, 121, + -182, 76, 192, 76, 209, 210, 211, -182, 212, -182, -182, 213, + -182, -182, -182, -182, 216, 208, 217, 218, 219, 224, -182, -182, + 225, -182, 226, -182, -182, -182, -182, -182, 74, 85, 87, 91, + 220, 221, 222, 223, -182, 97, 75, 64, 104, -182, 133, -182, + 137, 227, -182, -182, 138, -182, -182, 139, -182, 75, -182, 214, + 153, -182, -182, -182, 228, -182, -182}; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { - 5, 0, 0, 1, 0, 0, 0, 70, 4, 0, 3, 0, 37, 45, 38, 0, 0, 0, 0, 0, 0, 47, 48, 49, - 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 51, 17, 0, 0, 84, 0, 0, 0, 0, 0, 8, 0, 0, - 41, 42, 0, 0, 0, 39, 46, 0, 0, 40, 84, 0, 0, 69, 2, 0, 0, 6, 0, 0, 0, 0, 0, - 84, 0, 50, 0, 0, 0, 0, 94, 0, 16, 0, 0, 13, 0, 7, 9, 0, 43, 44, 28, 54, 0, 74, - 76, 79, 75, 0, 0, 0, 73, 96, 95, 88, 89, 90, 0, 83, 0, 0, 0, 10, 0, 0, 25, 60, - 65, 64, 0, 19, 0, 0, 34, 35, 82, 0, 33, 0, 84, 0, 0, 0, 0, 0, 86, 15, 14, 0, - 0, 27, 0, 0, 63, 0, 77, 0, 0, 0, 81, 78, 71, 72, 87, 0, 0, 0, 93, 0, 0, 0, 0, - 0, 0, 61, 0, 62, 80, 0, 32, 91, 92, 85, 0, 0, 0, 0, 0, 0, 66, 36, 0, 11, 0, - 84, 84, 84, 12, 84, 0, 0, 0, 31, 0, 0, 0, 0, 26, 0, 0, 0, 0, 21, 0, 68, 0, 58, - 57, 23, 0, 56, 30, 0, 20, 0, 24, 0, 0, 22, 29, 67, 0, 55, 59 -}; + 5, 0, 0, 1, 0, 0, 0, 70, 4, 0, 3, 0, 37, 45, 38, 0, 0, 0, 0, + 0, 0, 47, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 51, 17, 0, + 0, 84, 0, 0, 0, 0, 0, 8, 0, 0, 41, 42, 0, 0, 0, 39, 46, 0, 0, + 40, 84, 0, 0, 69, 2, 0, 0, 6, 0, 0, 0, 0, 0, 84, 0, 50, 0, 0, + 0, 0, 94, 0, 16, 0, 0, 13, 0, 7, 9, 0, 43, 44, 28, 54, 0, 74, 76, + 79, 75, 0, 0, 0, 73, 96, 95, 88, 89, 90, 0, 83, 0, 0, 0, 10, 0, 0, + 25, 60, 65, 64, 0, 19, 0, 0, 34, 35, 82, 0, 33, 0, 84, 0, 0, 0, 0, + 0, 86, 15, 14, 0, 0, 27, 0, 0, 63, 0, 77, 0, 0, 0, 81, 78, 71, 72, + 87, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 61, 0, 62, 80, 0, 32, 91, 92, + 85, 0, 0, 0, 0, 0, 0, 66, 36, 0, 11, 0, 84, 84, 84, 12, 84, 0, 0, + 0, 31, 0, 0, 0, 0, 26, 0, 0, 0, 0, 21, 0, 68, 0, 58, 57, 23, 0, + 56, 30, 0, 20, 0, 24, 0, 0, 22, 29, 67, 0, 55, 59}; /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = { -182, -182, -182, -182, 191, -182, -182, - 108, -182, -182, -182, -182, 25, -107, - 88, 89, 92, -7, -50, 215, -182, 13, - -181, -182, -182, -182, -182, -72, -56, - 100, -76, -182 }; +static const yytype_int16 yypgoto[] = { + -182, -182, -182, -182, 191, -182, -182, 108, -182, -182, -182, + -182, 25, -107, 88, 89, 92, -7, -50, 215, -182, 13, + -181, -182, -182, -182, -182, -72, -56, 100, -76, -182}; /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = { -1, 1, 2, 6, 44, 45, 82, 83, 7, 20, - 114, 196, 125, 126, 21, 22, 23, 46, - 34, 35, 208, 209, 119, 204, 25, 40, - 99, 100, 60, 133, 134, 41 }; +static const yytype_int16 yydefgoto[] = { + -1, 1, 2, 6, 44, 45, 82, 83, 7, 20, 114, 196, 125, 126, 21, 22, + 23, 46, 34, 35, 208, 209, 119, 204, 25, 40, 99, 100, 60, 133, 134, 41}; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 24, 70, 74, 107, 101, 102, 139, 8, 4, 29, -18, -18, -18, -18, -18, 90, 48, - 203, 5, 49, -18, -18, -18, 11, 12, -18, 13, 14, -18, 32, 50, 33, 219, 15, 80, - 16, 64, -18, 17, 79, 168, 18, 51, 42, 12, 81, 13, 14, 127, 3, 19, 92, 32, 15, - 33, 43, 147, 151, 17, 148, 12, 18, 13, 14, 12, 142, 13, 14, 143, 15, 19, 157, - 150, 15, 17, 159, 79, 18, 17, 171, 12, 18, 13, 14, 205, 206, 19, 9, 113, 15, - 19, 79, 207, 115, 17, 116, 117, 18, 93, 94, 95, 96, 79, 192, 79, 118, 19, 97, - 79, 155, 98, 122, 156, 123, 193, 32, 194, 33, 26, 131, 195, 124, 122, 132, - 123, 201, 27, 188, 189, 190, 158, 191, 210, 76, 77, 38, 10, 78, 30, 103, 104, - 105, 79, 56, 39, 56, 28, 202, 106, 57, 172, 89, 174, 56, 56, 128, 129, 31, 56, - 149, 165, 212, 213, 216, 147, 214, 217, 218, 122, 37, 123, 169, 155, 205, 206, - 47, 36, 52, 53, 54, 65, 58, 55, 59, 61, 67, 62, 68, 69, 71, 75, 66, 63, 72, - 84, 87, 86, 88, 91, 108, 109, 110, 111, 120, 130, 80, 112, 121, 136, 137, 138, - 140, 141, 146, 144, 145, 135, 166, 173, 152, 154, 163, 164, 167, 79, 211, 160, - 161, 181, 221, 162, 153, 220, 0, 170, 175, 176, 177, 183, 184, 178, 179, 180, - 182, 185, 186, 187, 197, 198, 199, 200, 0, 0, 0, 215, 0, 222, 85, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 -}; + 24, 70, 74, 107, 101, 102, 139, 8, 4, 29, -18, -18, -18, -18, -18, + 90, 48, 203, 5, 49, -18, -18, -18, 11, 12, -18, 13, 14, -18, 32, + 50, 33, 219, 15, 80, 16, 64, -18, 17, 79, 168, 18, 51, 42, 12, + 81, 13, 14, 127, 3, 19, 92, 32, 15, 33, 43, 147, 151, 17, 148, + 12, 18, 13, 14, 12, 142, 13, 14, 143, 15, 19, 157, 150, 15, 17, + 159, 79, 18, 17, 171, 12, 18, 13, 14, 205, 206, 19, 9, 113, 15, + 19, 79, 207, 115, 17, 116, 117, 18, 93, 94, 95, 96, 79, 192, 79, + 118, 19, 97, 79, 155, 98, 122, 156, 123, 193, 32, 194, 33, 26, 131, + 195, 124, 122, 132, 123, 201, 27, 188, 189, 190, 158, 191, 210, 76, 77, + 38, 10, 78, 30, 103, 104, 105, 79, 56, 39, 56, 28, 202, 106, 57, + 172, 89, 174, 56, 56, 128, 129, 31, 56, 149, 165, 212, 213, 216, 147, + 214, 217, 218, 122, 37, 123, 169, 155, 205, 206, 47, 36, 52, 53, 54, + 65, 58, 55, 59, 61, 67, 62, 68, 69, 71, 75, 66, 63, 72, 84, + 87, 86, 88, 91, 108, 109, 110, 111, 120, 130, 80, 112, 121, 136, 137, + 138, 140, 141, 146, 144, 145, 135, 166, 173, 152, 154, 163, 164, 167, 79, + 211, 160, 161, 181, 221, 162, 153, 220, 0, 170, 175, 176, 177, 183, 184, + 178, 179, 180, 182, 185, 186, 187, 197, 198, 199, 200, 0, 0, 0, 215, + 0, 222, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 73}; static const yytype_int16 yycheck[] = { - 7, 51, 58, 79, 76, 77, 113, 22, 1, 16, 3, 4, 5, 6, 7, 71, 4, 198, 11, 7, 13, - 14, 15, 3, 4, 18, 6, 7, 21, 18, 18, 20, 213, 13, 7, 15, 43, 30, 18, 17, 147, - 21, 30, 3, 4, 18, 6, 7, 98, 0, 30, 29, 18, 13, 20, 15, 25, 129, 18, 28, 4, 21, - 6, 7, 4, 31, 6, 7, 118, 13, 30, 15, 128, 13, 18, 15, 17, 21, 18, 155, 4, 21, - 6, 7, 20, 21, 30, 20, 29, 13, 30, 17, 28, 18, 18, 20, 21, 21, 18, 19, 20, 21, - 17, 29, 17, 30, 30, 27, 17, 25, 30, 18, 28, 20, 29, 18, 29, 20, 23, 23, 29, - 28, 18, 27, 20, 28, 27, 183, 184, 185, 137, 187, 28, 8, 9, 5, 22, 12, 16, 18, - 19, 20, 17, 25, 14, 25, 10, 197, 27, 31, 157, 31, 159, 25, 25, 24, 25, 16, 25, - 31, 31, 28, 25, 25, 25, 28, 28, 28, 18, 26, 20, 24, 25, 20, 21, 18, 22, 26, - 18, 21, 24, 20, 27, 20, 22, 26, 22, 16, 16, 20, 23, 25, 27, 18, 26, 18, 20, - 18, 28, 25, 16, 28, 20, 16, 16, 7, 28, 27, 18, 10, 10, 16, 27, 27, 18, 18, - 108, 28, 26, 18, 18, 18, 18, 18, 17, 200, 138, 138, 20, 216, 138, 131, 18, -1, - 28, 26, 26, 26, 20, 20, 28, 28, 26, 26, 20, 20, 20, 27, 27, 27, 27, -1, -1, - -1, 27, -1, 28, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56 -}; + 7, 51, 58, 79, 76, 77, 113, 22, 1, 16, 3, 4, 5, 6, 7, 71, + 4, 198, 11, 7, 13, 14, 15, 3, 4, 18, 6, 7, 21, 18, 18, 20, + 213, 13, 7, 15, 43, 30, 18, 17, 147, 21, 30, 3, 4, 18, 6, 7, + 98, 0, 30, 29, 18, 13, 20, 15, 25, 129, 18, 28, 4, 21, 6, 7, + 4, 31, 6, 7, 118, 13, 30, 15, 128, 13, 18, 15, 17, 21, 18, 155, + 4, 21, 6, 7, 20, 21, 30, 20, 29, 13, 30, 17, 28, 18, 18, 20, + 21, 21, 18, 19, 20, 21, 17, 29, 17, 30, 30, 27, 17, 25, 30, 18, + 28, 20, 29, 18, 29, 20, 23, 23, 29, 28, 18, 27, 20, 28, 27, 183, + 184, 185, 137, 187, 28, 8, 9, 5, 22, 12, 16, 18, 19, 20, 17, 25, + 14, 25, 10, 197, 27, 31, 157, 31, 159, 25, 25, 24, 25, 16, 25, 31, + 31, 28, 25, 25, 25, 28, 28, 28, 18, 26, 20, 24, 25, 20, 21, 18, + 22, 26, 18, 21, 24, 20, 27, 20, 22, 26, 22, 16, 16, 20, 23, 25, + 27, 18, 26, 18, 20, 18, 28, 25, 16, 28, 20, 16, 16, 7, 28, 27, + 18, 10, 10, 16, 27, 27, 18, 18, 108, 28, 26, 18, 18, 18, 18, 18, + 17, 200, 138, 138, 20, 216, 138, 131, 18, -1, 28, 26, 26, 26, 20, 20, + 28, 28, 26, 26, 20, 20, 20, 27, 27, 27, 27, -1, -1, -1, 27, -1, + 28, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56}; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { - 0, 33, 34, 0, 1, 11, 35, 40, 22, 20, 22, 3, 4, 6, 7, 13, 15, 18, 21, 30, 41, - 46, 47, 48, 49, 56, 23, 27, 10, 49, 16, 16, 18, 20, 50, 51, 22, 26, 5, 14, 57, - 63, 3, 15, 36, 37, 49, 18, 4, 7, 18, 30, 26, 18, 21, 27, 25, 31, 20, 20, 60, - 22, 22, 27, 49, 24, 25, 26, 16, 16, 50, 20, 18, 51, 60, 23, 8, 9, 12, 17, 7, - 18, 38, 39, 26, 36, 20, 18, 18, 31, 60, 28, 29, 18, 19, 20, 21, 27, 30, 58, - 59, 59, 59, 18, 19, 20, 27, 62, 25, 16, 28, 20, 28, 29, 42, 18, 20, 21, 30, - 54, 16, 27, 18, 20, 28, 44, 45, 50, 24, 25, 16, 23, 27, 61, 62, 39, 18, 10, - 10, 45, 16, 27, 31, 50, 18, 18, 27, 25, 28, 31, 60, 59, 18, 61, 18, 25, 28, - 15, 49, 15, 46, 47, 48, 18, 18, 31, 28, 18, 45, 24, 28, 62, 49, 26, 49, 26, - 26, 26, 28, 28, 26, 20, 26, 20, 20, 20, 20, 20, 60, 60, 60, 60, 29, 29, 29, - 29, 43, 27, 27, 27, 27, 28, 50, 54, 55, 20, 21, 28, 52, 53, 28, 44, 28, 25, - 28, 27, 25, 28, 28, 54, 18, 53, 28 -}; + 0, 33, 34, 0, 1, 11, 35, 40, 22, 20, 22, 3, 4, 6, 7, 13, 15, 18, 21, + 30, 41, 46, 47, 48, 49, 56, 23, 27, 10, 49, 16, 16, 18, 20, 50, 51, 22, 26, + 5, 14, 57, 63, 3, 15, 36, 37, 49, 18, 4, 7, 18, 30, 26, 18, 21, 27, 25, + 31, 20, 20, 60, 22, 22, 27, 49, 24, 25, 26, 16, 16, 50, 20, 18, 51, 60, 23, + 8, 9, 12, 17, 7, 18, 38, 39, 26, 36, 20, 18, 18, 31, 60, 28, 29, 18, 19, + 20, 21, 27, 30, 58, 59, 59, 59, 18, 19, 20, 27, 62, 25, 16, 28, 20, 28, 29, + 42, 18, 20, 21, 30, 54, 16, 27, 18, 20, 28, 44, 45, 50, 24, 25, 16, 23, 27, + 61, 62, 39, 18, 10, 10, 45, 16, 27, 31, 50, 18, 18, 27, 25, 28, 31, 60, 59, + 18, 61, 18, 25, 28, 15, 49, 15, 46, 47, 48, 18, 18, 31, 28, 18, 45, 24, 28, + 62, 49, 26, 49, 26, 26, 26, 28, 28, 26, 20, 26, 20, 20, 20, 20, 20, 60, 60, + 60, 60, 29, 29, 29, 29, 43, 27, 27, 27, 27, 28, 50, 54, 55, 20, 21, 28, 52, + 53, 28, 44, 28, 25, 28, 27, 25, 28, 28, 54, 18, 53, 28}; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_int8 yyr1[] = { - 0, 32, 33, 34, 34, 34, 35, 36, 36, 37, 37, 37, 37, 38, 38, 39, 39, 40, 40, 41, - 41, 41, 41, 41, 41, 41, 41, 42, 42, 43, 43, 43, 44, 44, 45, 45, 45, 46, 46, - 46, 46, 47, 47, 47, 47, 48, 48, 49, 49, 49, 50, 50, 51, 51, 51, 52, 52, 53, - 53, 53, 54, 54, 54, 54, 54, 54, 54, 55, 55, 56, 56, 57, 58, 58, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 60, 60, 61, 61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63 -}; + 0, 32, 33, 34, 34, 34, 35, 36, 36, 37, 37, 37, 37, 38, 38, 39, 39, + 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 43, 43, 43, 44, 44, + 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 49, 49, 49, 50, + 50, 51, 51, 51, 52, 52, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 55, + 55, 56, 56, 57, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, + 61, 61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63}; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_int8 yyr2[] = { - 0, 2, 5, 3, 3, 0, 5, 3, 1, 3, 4, 8, 9, 1, 3, 3, 1, 3, 0, 6, 15, 14, 15, 14, - 15, 6, 13, 2, 0, 4, 3, 0, 3, 1, 1, 1, 4, 1, 1, 3, 3, 3, 3, 5, 5, 1, 3, 1, 1, - 1, 3, 1, 1, 1, 4, 3, 1, 1, 1, 4, 1, 3, 3, 2, 1, 1, 4, 3, 1, 3, 0, 6, 3, 1, 1, - 1, 1, 3, 3, 1, 4, 3, 2, 3, 0, 3, 1, 3, 1, 1, 1, 4, 4, 3, 3, 4, 4 -}; + 0, 2, 5, 3, 3, 0, 5, 3, 1, 3, 4, 8, 9, 1, 3, 3, 1, 3, 0, 6, + 15, 14, 15, 14, 15, 6, 13, 2, 0, 4, 3, 0, 3, 1, 1, 1, 4, 1, 1, 3, + 3, 3, 3, 5, 5, 1, 3, 1, 1, 1, 3, 1, 1, 1, 4, 3, 1, 1, 1, 4, + 1, 3, 3, 2, 1, 1, 4, 3, 1, 3, 0, 6, 3, 1, 1, 1, 1, 3, 3, 1, + 4, 3, 2, 3, 0, 3, 1, 3, 1, 1, 1, 4, 4, 3, 3, 4, 4}; -enum { - YYENOMEM = -2 -}; +enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = ORFZ_EMPTY) @@ -728,19 +781,19 @@ enum { #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ - do \ - if (yychar == ORFZ_EMPTY) { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK(yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } else { \ - yyerror(context, model, ok, scanner, \ - YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == ORFZ_EMPTY) { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK(yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } else { \ + yyerror(context, model, ok, scanner, \ + YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ while (0) /* Backward compatibility with an undocumented macro. @@ -755,24 +808,23 @@ enum { #define YYFPRINTF fprintf #endif -#define YYDPRINTF(Args) \ - do { \ - if (yydebug) \ - YYFPRINTF Args; \ +#define YYDPRINTF(Args) \ + do { \ + if (yydebug) YYFPRINTF Args; \ } while (0) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT -#define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#define YY_LOCATION_PRINT(File, Loc) ((void)0) #endif -#define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ - do { \ - if (yydebug) { \ - YYFPRINTF(stderr, "%s ", Title); \ - yy_symbol_print(stderr, Kind, Value, context, model, ok, scanner); \ - YYFPRINTF(stderr, "\n"); \ - } \ +#define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ + do { \ + if (yydebug) { \ + YYFPRINTF(stderr, "%s ", Title); \ + yy_symbol_print(stderr, Kind, Value, context, model, ok, scanner); \ + YYFPRINTF(stderr, "\n"); \ + } \ } while (0) /*-----------------------------------. @@ -789,11 +841,9 @@ static void yy_symbol_value_print( YYUSE(model); YYUSE(ok); YYUSE(scanner); - if (!yyvaluep) - return; + if (!yyvaluep) return; #ifdef YYPRINT - if (yykind < YYNTOKENS) - YYPRINT(yyo, yytoknum[yykind], *yyvaluep); + if (yykind < YYNTOKENS) YYPRINT(yyo, yytoknum[yykind], *yyvaluep); #endif YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE(yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END @@ -829,10 +879,9 @@ static void yy_stack_print(yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF(stderr, "\n"); } -#define YY_STACK_PRINT(Bottom, Top) \ - do { \ - if (yydebug) \ - yy_stack_print((Bottom), (Top)); \ +#define YY_STACK_PRINT(Bottom, Top) \ + do { \ + if (yydebug) yy_stack_print((Bottom), (Top)); \ } while (0) /*------------------------------------------------. @@ -857,17 +906,17 @@ static void yy_reduce_print(yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule, } } -#define YY_REDUCE_PRINT(Rule) \ - do { \ - if (yydebug) \ - yy_reduce_print(yyssp, yyvsp, Rule, context, model, ok, scanner); \ +#define YY_REDUCE_PRINT(Rule) \ + do { \ + if (yydebug) \ + yy_reduce_print(yyssp, yyvsp, Rule, context, model, ok, scanner); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !ORFZ_DEBUG */ -#define YYDPRINTF(Args) ((void) 0) +#define YYDPRINTF(Args) ((void)0) #define YY_SYMBOL_PRINT(Title, Kind, Value, Location) #define YY_STACK_PRINT(Bottom, Top) #define YY_REDUCE_PRINT(Rule) @@ -926,27 +975,25 @@ static int yypcontext_expected_tokens(const yypcontext_t *yyctx, yyarg[yycount++] = YY_CAST(yysymbol_kind_t, yyx); } } - if (yyarg && yycount == 0 && 0 < yyargn) - yyarg[0] = YYSYMBOL_YYEMPTY; + if (yyarg && yycount == 0 && 0 < yyargn) yyarg[0] = YYSYMBOL_YYEMPTY; return yycount; } #ifndef yystrlen -#if defined __GLIBC__ &&defined _STRING_H +#if defined __GLIBC__ && defined _STRING_H #define yystrlen(S) (YY_CAST(YYPTRDIFF_T, strlen(S))) #else /* Return the length of YYSTR. */ static YYPTRDIFF_T yystrlen(const char *yystr) { YYPTRDIFF_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; + for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } #endif #endif #ifndef yystpcpy -#if defined __GLIBC__ &&defined _STRING_H &&defined _GNU_SOURCE +#if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE #define yystpcpy stpcpy #else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in @@ -955,8 +1002,7 @@ static char *yystpcpy(char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; - while ((*yyd++ = *yys++) != '\0') - continue; + while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } @@ -975,32 +1021,28 @@ static YYPTRDIFF_T yytnamerr(char *yyres, const char *yystr) { if (*yystr == '"') { YYPTRDIFF_T yyn = 0; char const *yyp = yystr; - for (;;) - switch (*++yyp) { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') + for (;;) switch (*++yyp) { + case '\'': + case ',': goto do_not_strip_quotes; - else - goto append; - append: - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; + append: + default: + if (yyres) yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) yyres[yyn] = '\0'; + return yyn; } - do_not_strip_quotes: - ; + do_not_strip_quotes:; } if (yyres) @@ -1039,8 +1081,7 @@ static int yy_syntax_error_arguments(const yypcontext_t *yyctx, */ if (yyctx->yytoken != YYSYMBOL_YYEMPTY) { int yyn; - if (yyarg) - yyarg[yycount] = yyctx->yytoken; + if (yyarg) yyarg[yycount] = yyctx->yytoken; ++yycount; yyn = yypcontext_expected_tokens(yyctx, yyarg ? yyarg + 1 : yyarg, yyargn - 1); @@ -1062,9 +1103,7 @@ static int yy_syntax_error_arguments(const yypcontext_t *yyctx, required number of bytes is too large to store. */ static int yysyntax_error(YYPTRDIFF_T *yymsg_alloc, char **yymsg, const yypcontext_t *yyctx) { - enum { - YYARGS_MAX = 5 - }; + enum { YYARGS_MAX = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat: reported tokens (one for the "unexpected", @@ -1075,22 +1114,22 @@ static int yysyntax_error(YYPTRDIFF_T *yymsg_alloc, char **yymsg, /* Actual size of YYARG. */ int yycount = yy_syntax_error_arguments(yyctx, yyarg, YYARGS_MAX); - if (yycount == YYENOMEM) - return YYENOMEM; + if (yycount == YYENOMEM) return YYENOMEM; switch (yycount) { -#define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - default: /* Avoid compiler warnings. */ - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_( + 5, + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); #undef YYCASE_ } @@ -1147,8 +1186,7 @@ static void yydestruct(const char *yymsg, yysymbol_kind_t yykind, YYUSE(model); YYUSE(ok); YYUSE(scanner); - if (!yymsg) - yymsg = "Deleting"; + if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT(yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE(yykind); @@ -1168,7 +1206,7 @@ int yyparse(operations_research::fz::ParserContext *context, /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE(static YYSTYPE yyval_default;) - YYSTYPE yylval YY_INITIAL_VALUE( = yyval_default); + YYSTYPE yylval YY_INITIAL_VALUE(= yyval_default); /* Number of syntax errors so far. */ int yynerrs = 0; @@ -1261,25 +1299,21 @@ yysetstate: yyvs = yyvs1; } #else /* defined YYSTACK_RELOCATE */ - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; + if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST(union yyalloc *, YYSTACK_ALLOC(YY_CAST(YYSIZE_T, YYSTACK_BYTES(yystacksize)))); - if (!yyptr) - goto yyexhaustedlab; + if (!yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE(yyss_alloc, yyss); YYSTACK_RELOCATE(yyvs_alloc, yyvs); #undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE(yyss1); + if (yyss1 != yyssa) YYSTACK_FREE(yyss1); } #endif @@ -1292,8 +1326,7 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - if (yystate == YYFINAL) - YYACCEPT; + if (yystate == YYFINAL) YYACCEPT; goto yybackup; @@ -1306,8 +1339,7 @@ yybackup: /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default(yyn)) - goto yydefault; + if (yypact_value_is_default(yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ @@ -1337,25 +1369,22 @@ yybackup: /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error(yyn)) - goto yyerrlab; + if (yytable_value_is_error(yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ - if (yyerrstatus) - yyerrstatus--; + if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN * ++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = ORFZ_EMPTY; goto yynewstate; @@ -1365,8 +1394,7 @@ yybackup: `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; + if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. @@ -1388,1001 +1416,1009 @@ yyreduce: YY_REDUCE_PRINT(yyn); switch (yyn) { - case 4: /* predicates: predicates error ';' */ + case 4: /* predicates: predicates error ';' */ #line 114 "./ortools/flatzinc/parser.yy" - { - yyerrok; - } + { + yyerrok; + } #line 1581 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 19: /* variable_or_constant_declaration: domain ':' IDENTIFIER - annotations '=' const_literal */ + case 19: /* variable_or_constant_declaration: domain ':' IDENTIFIER + annotations '=' const_literal */ #line 149 "./ortools/flatzinc/parser.yy" - { - // Declaration of a (named) constant: we simply register it in the - // parser's context, and don't store it in the model. - const Domain &domain = (yyvsp[-5].domain); - const std::string &identifier = (yyvsp[-3].string_value); - const Domain &assignment = (yyvsp[0].domain); - std::vector *const annotations = (yyvsp[-2].annotations); + { + // Declaration of a (named) constant: we simply register it in the + // parser's context, and don't store it in the model. + const Domain &domain = (yyvsp[-5].domain); + const std::string &identifier = (yyvsp[-3].string_value); + const Domain &assignment = (yyvsp[0].domain); + std::vector *const annotations = (yyvsp[-2].annotations); - if (!assignment.HasOneValue()) { - // TODO(lperron): Check that the assignment is included in the domain. - context->domain_map[identifier] = assignment; - } else { - const int64 value = assignment.values.front(); - CHECK(domain.Contains(value)); - context->integer_map[identifier] = value; - } - delete annotations; - } -#line 1605 "./ortools/flatzinc/parser.tab.cc" - break; - - case 20: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF int_domain ':' IDENTIFIER annotations '=' '[' integers - ']' */ -#line 169 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-4].annotations); - // Declaration of a (named) constant array. See rule right above. - CHECK_EQ((yyvsp[-12].integer_value), 1) - << "Only [1..n] array are supported here."; - const int64 num_constants = (yyvsp[-10].integer_value); - const std::string &identifier = (yyvsp[-5].string_value); - const std::vector *const assignments = (yyvsp[-1].integers); - CHECK(assignments != nullptr); - CHECK_EQ(num_constants, assignments->size()); - // TODO(lperron): CHECK all values within domain. - context->integer_array_map[identifier] = *assignments; - delete assignments; - delete annotations; - } -#line 1624 "./ortools/flatzinc/parser.tab.cc" - break; - - case 21: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF int_domain ':' IDENTIFIER annotations '=' '[' ']' */ -#line 184 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-3].annotations); - // Declaration of a (named) constant array. See rule right above. - CHECK_EQ((yyvsp[-11].integer_value), 1) - << "Only [1..n] array are supported here."; - const int64 num_constants = (yyvsp[-9].integer_value); - CHECK_EQ(num_constants, 0) << "Empty arrays should have a size of 0"; - const std::string &identifier = (yyvsp[-4].string_value); - context->integer_array_map[identifier] = std::vector(); - delete annotations; - } -#line 1639 "./ortools/flatzinc/parser.tab.cc" - break; - - case 22: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF float_domain ':' IDENTIFIER annotations '=' '[' floats - ']' */ -#line 195 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-4].annotations); - // Declaration of a (named) constant array. See rule right above. - CHECK_EQ((yyvsp[-12].integer_value), 1) - << "Only [1..n] array are supported here."; - const int64 num_constants = (yyvsp[-10].integer_value); - const std::string &identifier = (yyvsp[-5].string_value); - const std::vector *const assignments = (yyvsp[-1].doubles); - CHECK(assignments != nullptr); - CHECK_EQ(num_constants, assignments->size()); - // TODO(lperron): CHECK all values within domain. - context->float_array_map[identifier] = *assignments; - delete assignments; - delete annotations; - } -#line 1658 "./ortools/flatzinc/parser.tab.cc" - break; - - case 23: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF float_domain ':' IDENTIFIER annotations '=' '[' ']' */ -#line 210 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-3].annotations); - // Declaration of a (named) constant array. See rule right above. - CHECK_EQ((yyvsp[-11].integer_value), 1) - << "Only [1..n] array are supported here."; - const int64 num_constants = (yyvsp[-9].integer_value); - CHECK_EQ(num_constants, 0) << "Empty arrays should have a size of 0"; - const std::string &identifier = (yyvsp[-4].string_value); - context->float_array_map[identifier] = std::vector(); - delete annotations; - } -#line 1673 "./ortools/flatzinc/parser.tab.cc" - break; - - case 24 - : /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF set_domain ':' IDENTIFIER annotations '=' '[' - const_literals ']' */ -#line 221 "./ortools/flatzinc/parser.yy" - { - // Declaration of a (named) constant array: See rule above. - CHECK_EQ((yyvsp[-12].integer_value), 1) - << "Only [1..n] array are supported here."; - const int64 num_constants = (yyvsp[-10].integer_value); - const Domain &domain = (yyvsp[-7].domain); - const std::string &identifier = (yyvsp[-5].string_value); - const std::vector *const assignments = (yyvsp[-1].domains); - const std::vector *const annotations = (yyvsp[-4].annotations); - CHECK(assignments != nullptr); - CHECK_EQ(num_constants, assignments->size()); - - if (!AllDomainsHaveOneValue(*assignments)) { - context->domain_array_map[identifier] = *assignments; - // TODO(lperron): check that all assignments are included in the domain. - } else { - std::vector values(num_constants); - for (int i = 0; i < num_constants; ++i) { - values[i] = (*assignments)[i].values.front(); - CHECK(domain.Contains(values[i])); - } - context->integer_array_map[identifier] = values; - } - delete assignments; - delete annotations; - } -#line 1703 "./ortools/flatzinc/parser.tab.cc" - break; - - case 25: /* variable_or_constant_declaration: VAR domain ':' IDENTIFIER - annotations optional_var_or_value */ -#line 246 "./ortools/flatzinc/parser.yy" - { - // Declaration of a variable. If it's unassigned or assigned to a - // constant, we'll create a new var stored in the model. If it's - // assigned to another variable x then we simply adjust that - // existing variable x according to the current (re-)declaration. - const Domain &domain = (yyvsp[-4].domain); - const std::string &identifier = (yyvsp[-2].string_value); - std::vector *const annotations = (yyvsp[-1].annotations); - const VariableRefOrValue &assignment = (yyvsp[0].var_or_value); - const bool introduced = ContainsId(annotations, "var_is_introduced") || - absl::StartsWith(identifier, "X_INTRODUCED"); - IntegerVariable *var = nullptr; - if (!assignment.defined) { - var = model->AddVariable(identifier, domain, introduced); - } else if (assignment.variable == nullptr) { // just an integer constant. - CHECK(domain.Contains(assignment.value)); - var = model->AddVariable( - identifier, Domain::IntegerValue(assignment.value), introduced); - } else { // a variable. - var = assignment.variable; - var->Merge(identifier, domain, introduced); - } - - // We also register the variable in the parser's context, and add some - // output to the model if needed. - context->variable_map[identifier] = var; - if (ContainsId(annotations, "output_var")) { - model->AddOutput(SolutionOutputSpecs::SingleVariable( - identifier, var, domain.display_as_boolean)); - } - delete annotations; - } -#line 1741 "./ortools/flatzinc/parser.tab.cc" - break; - - case 26: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE - ']' OF VAR domain ':' IDENTIFIER annotations - optional_var_or_value_array */ -#line 280 "./ortools/flatzinc/parser.yy" - { - // Declaration of a "variable array": these is exactly like N simple - // variable declarations, where the identifier for declaration #i is - // IDENTIFIER[i] (1-based index). - CHECK_EQ((yyvsp[-10].integer_value), 1); - const int64 num_vars = (yyvsp[-8].integer_value); - const Domain &domain = (yyvsp[-4].domain); - const std::string &identifier = (yyvsp[-2].string_value); - std::vector *const annotations = (yyvsp[-1].annotations); - VariableRefOrValueArray *const assignments = (yyvsp[0].var_or_value_array); - CHECK(assignments == nullptr || assignments->variables.size() == num_vars); - CHECK(assignments == nullptr || assignments->values.size() == num_vars); - const bool introduced = ContainsId(annotations, "var_is_introduced") || - absl::StartsWith(identifier, "X_INTRODUCED"); - - std::vector vars(num_vars, nullptr); - - for (int i = 0; i < num_vars; ++i) { - const std::string var_name = absl::StrFormat("%s[%d]", identifier, i + 1); - if (assignments == nullptr) { - vars[i] = model->AddVariable(var_name, domain, introduced); - } else if (assignments->variables[i] == nullptr) { - // Assigned to an integer constant. - const int64 value = assignments->values[i]; - CHECK(domain.Contains(value)); - vars[i] = model->AddVariable(var_name, Domain::IntegerValue(value), - introduced); + if (!assignment.HasOneValue()) { + // TODO(lperron): Check that the assignment is included in the domain. + context->domain_map[identifier] = assignment; } else { - IntegerVariable *const var = assignments->variables[i]; - CHECK(var != nullptr); - vars[i] = var; - vars[i]->Merge(var_name, domain, introduced); - } - } - delete assignments; - - // Register the variable array on the context. - context->variable_array_map[identifier] = vars; - - // We parse the annotations to build an output object if - // needed. It's a bit more convoluted than the simple variable - // output. - if (annotations != nullptr) { - for (int i = 0; i < annotations->size(); ++i) { - const Annotation &ann = (*annotations)[i]; - if (ann.IsFunctionCallWithIdentifier("output_array")) { - // We have found an output annotation. - CHECK_EQ(1, ann.annotations.size()); - CHECK_EQ(Annotation::ANNOTATION_LIST, ann.annotations.back().type); - const Annotation &list = ann.annotations.back(); - // Let's build the vector of bounds. - std::vector bounds; - for (int a = 0; a < list.annotations.size(); ++a) { - const Annotation &bound = list.annotations[a]; - CHECK_EQ(Annotation::INTERVAL, bound.type); - bounds.emplace_back(SolutionOutputSpecs::Bounds( - bound.interval_min, bound.interval_max)); - } - // We add the output information. - model->AddOutput(SolutionOutputSpecs::MultiDimensionalArray( - identifier, bounds, vars, domain.display_as_boolean)); - } + const int64 value = assignment.values.front(); + CHECK(domain.Contains(value)); + context->integer_map[identifier] = value; } delete annotations; } - } +#line 1605 "./ortools/flatzinc/parser.tab.cc" + break; + + case 20: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF int_domain ':' IDENTIFIER annotations '=' '[' integers + ']' */ +#line 169 "./ortools/flatzinc/parser.yy" + { + std::vector *const annotations = (yyvsp[-4].annotations); + // Declaration of a (named) constant array. See rule right above. + CHECK_EQ((yyvsp[-12].integer_value), 1) + << "Only [1..n] array are supported here."; + const int64 num_constants = (yyvsp[-10].integer_value); + const std::string &identifier = (yyvsp[-5].string_value); + const std::vector *const assignments = (yyvsp[-1].integers); + CHECK(assignments != nullptr); + CHECK_EQ(num_constants, assignments->size()); + // TODO(lperron): CHECK all values within domain. + context->integer_array_map[identifier] = *assignments; + delete assignments; + delete annotations; + } +#line 1624 "./ortools/flatzinc/parser.tab.cc" + break; + + case 21: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF int_domain ':' IDENTIFIER annotations '=' '[' ']' */ +#line 184 "./ortools/flatzinc/parser.yy" + { + std::vector *const annotations = (yyvsp[-3].annotations); + // Declaration of a (named) constant array. See rule right above. + CHECK_EQ((yyvsp[-11].integer_value), 1) + << "Only [1..n] array are supported here."; + const int64 num_constants = (yyvsp[-9].integer_value); + CHECK_EQ(num_constants, 0) << "Empty arrays should have a size of 0"; + const std::string &identifier = (yyvsp[-4].string_value); + context->integer_array_map[identifier] = std::vector(); + delete annotations; + } +#line 1639 "./ortools/flatzinc/parser.tab.cc" + break; + + case 22: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF float_domain ':' IDENTIFIER annotations '=' '[' floats + ']' */ +#line 195 "./ortools/flatzinc/parser.yy" + { + std::vector *const annotations = (yyvsp[-4].annotations); + // Declaration of a (named) constant array. See rule right above. + CHECK_EQ((yyvsp[-12].integer_value), 1) + << "Only [1..n] array are supported here."; + const int64 num_constants = (yyvsp[-10].integer_value); + const std::string &identifier = (yyvsp[-5].string_value); + const std::vector *const assignments = (yyvsp[-1].doubles); + CHECK(assignments != nullptr); + CHECK_EQ(num_constants, assignments->size()); + // TODO(lperron): CHECK all values within domain. + context->float_array_map[identifier] = *assignments; + delete assignments; + delete annotations; + } +#line 1658 "./ortools/flatzinc/parser.tab.cc" + break; + + case 23: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF float_domain ':' IDENTIFIER annotations '=' '[' ']' */ +#line 210 "./ortools/flatzinc/parser.yy" + { + std::vector *const annotations = (yyvsp[-3].annotations); + // Declaration of a (named) constant array. See rule right above. + CHECK_EQ((yyvsp[-11].integer_value), 1) + << "Only [1..n] array are supported here."; + const int64 num_constants = (yyvsp[-9].integer_value); + CHECK_EQ(num_constants, 0) << "Empty arrays should have a size of 0"; + const std::string &identifier = (yyvsp[-4].string_value); + context->float_array_map[identifier] = std::vector(); + delete annotations; + } +#line 1673 "./ortools/flatzinc/parser.tab.cc" + break; + + case 24: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF set_domain ':' IDENTIFIER annotations '=' '[' + const_literals ']' */ +#line 221 "./ortools/flatzinc/parser.yy" + { + // Declaration of a (named) constant array: See rule above. + CHECK_EQ((yyvsp[-12].integer_value), 1) + << "Only [1..n] array are supported here."; + const int64 num_constants = (yyvsp[-10].integer_value); + const Domain &domain = (yyvsp[-7].domain); + const std::string &identifier = (yyvsp[-5].string_value); + const std::vector *const assignments = (yyvsp[-1].domains); + const std::vector *const annotations = + (yyvsp[-4].annotations); + CHECK(assignments != nullptr); + CHECK_EQ(num_constants, assignments->size()); + + if (!AllDomainsHaveOneValue(*assignments)) { + context->domain_array_map[identifier] = *assignments; + // TODO(lperron): check that all assignments are included in the domain. + } else { + std::vector values(num_constants); + for (int i = 0; i < num_constants; ++i) { + values[i] = (*assignments)[i].values.front(); + CHECK(domain.Contains(values[i])); + } + context->integer_array_map[identifier] = values; + } + delete assignments; + delete annotations; + } +#line 1703 "./ortools/flatzinc/parser.tab.cc" + break; + + case 25: /* variable_or_constant_declaration: VAR domain ':' IDENTIFIER + annotations optional_var_or_value */ +#line 246 "./ortools/flatzinc/parser.yy" + { + // Declaration of a variable. If it's unassigned or assigned to a + // constant, we'll create a new var stored in the model. If it's + // assigned to another variable x then we simply adjust that + // existing variable x according to the current (re-)declaration. + const Domain &domain = (yyvsp[-4].domain); + const std::string &identifier = (yyvsp[-2].string_value); + std::vector *const annotations = (yyvsp[-1].annotations); + const VariableRefOrValue &assignment = (yyvsp[0].var_or_value); + const bool introduced = ContainsId(annotations, "var_is_introduced") || + absl::StartsWith(identifier, "X_INTRODUCED"); + IntegerVariable *var = nullptr; + if (!assignment.defined) { + var = model->AddVariable(identifier, domain, introduced); + } else if (assignment.variable == nullptr) { // just an integer constant. + CHECK(domain.Contains(assignment.value)); + var = model->AddVariable( + identifier, Domain::IntegerValue(assignment.value), introduced); + } else { // a variable. + var = assignment.variable; + var->Merge(identifier, domain, introduced); + } + + // We also register the variable in the parser's context, and add some + // output to the model if needed. + context->variable_map[identifier] = var; + if (ContainsId(annotations, "output_var")) { + model->AddOutput(SolutionOutputSpecs::SingleVariable( + identifier, var, domain.display_as_boolean)); + } + delete annotations; + } +#line 1741 "./ortools/flatzinc/parser.tab.cc" + break; + + case 26: /* variable_or_constant_declaration: ARRAY '[' IVALUE DOTDOT IVALUE + ']' OF VAR domain ':' IDENTIFIER annotations + optional_var_or_value_array */ +#line 280 "./ortools/flatzinc/parser.yy" + { + // Declaration of a "variable array": these is exactly like N simple + // variable declarations, where the identifier for declaration #i is + // IDENTIFIER[i] (1-based index). + CHECK_EQ((yyvsp[-10].integer_value), 1); + const int64 num_vars = (yyvsp[-8].integer_value); + const Domain &domain = (yyvsp[-4].domain); + const std::string &identifier = (yyvsp[-2].string_value); + std::vector *const annotations = (yyvsp[-1].annotations); + VariableRefOrValueArray *const assignments = + (yyvsp[0].var_or_value_array); + CHECK(assignments == nullptr || + assignments->variables.size() == num_vars); + CHECK(assignments == nullptr || assignments->values.size() == num_vars); + const bool introduced = ContainsId(annotations, "var_is_introduced") || + absl::StartsWith(identifier, "X_INTRODUCED"); + + std::vector vars(num_vars, nullptr); + + for (int i = 0; i < num_vars; ++i) { + const std::string var_name = + absl::StrFormat("%s[%d]", identifier, i + 1); + if (assignments == nullptr) { + vars[i] = model->AddVariable(var_name, domain, introduced); + } else if (assignments->variables[i] == nullptr) { + // Assigned to an integer constant. + const int64 value = assignments->values[i]; + CHECK(domain.Contains(value)); + vars[i] = model->AddVariable(var_name, Domain::IntegerValue(value), + introduced); + } else { + IntegerVariable *const var = assignments->variables[i]; + CHECK(var != nullptr); + vars[i] = var; + vars[i]->Merge(var_name, domain, introduced); + } + } + delete assignments; + + // Register the variable array on the context. + context->variable_array_map[identifier] = vars; + + // We parse the annotations to build an output object if + // needed. It's a bit more convoluted than the simple variable + // output. + if (annotations != nullptr) { + for (int i = 0; i < annotations->size(); ++i) { + const Annotation &ann = (*annotations)[i]; + if (ann.IsFunctionCallWithIdentifier("output_array")) { + // We have found an output annotation. + CHECK_EQ(1, ann.annotations.size()); + CHECK_EQ(Annotation::ANNOTATION_LIST, ann.annotations.back().type); + const Annotation &list = ann.annotations.back(); + // Let's build the vector of bounds. + std::vector bounds; + for (int a = 0; a < list.annotations.size(); ++a) { + const Annotation &bound = list.annotations[a]; + CHECK_EQ(Annotation::INTERVAL, bound.type); + bounds.emplace_back(SolutionOutputSpecs::Bounds( + bound.interval_min, bound.interval_max)); + } + // We add the output information. + model->AddOutput(SolutionOutputSpecs::MultiDimensionalArray( + identifier, bounds, vars, domain.display_as_boolean)); + } + } + delete annotations; + } + } #line 1813 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 27: /* optional_var_or_value: '=' var_or_value */ + case 27: /* optional_var_or_value: '=' var_or_value */ #line 349 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value) = (yyvsp[0].var_or_value); - } + { + (yyval.var_or_value) = (yyvsp[0].var_or_value); + } #line 1819 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 28: /* optional_var_or_value: %empty */ + case 28: /* optional_var_or_value: %empty */ #line 350 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value) = VariableRefOrValue::Undefined(); - } + { + (yyval.var_or_value) = VariableRefOrValue::Undefined(); + } #line 1825 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 29: /* optional_var_or_value_array: '=' '[' var_or_value_array ']' */ + case 29: /* optional_var_or_value_array: '=' '[' var_or_value_array ']' */ #line 353 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value_array) = (yyvsp[-1].var_or_value_array); - } + { + (yyval.var_or_value_array) = (yyvsp[-1].var_or_value_array); + } #line 1831 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 30: /* optional_var_or_value_array: '=' '[' ']' */ + case 30: /* optional_var_or_value_array: '=' '[' ']' */ #line 354 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value_array) = nullptr; - } + { + (yyval.var_or_value_array) = nullptr; + } #line 1837 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 31: /* optional_var_or_value_array: %empty */ + case 31: /* optional_var_or_value_array: %empty */ #line 355 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value_array) = nullptr; - } + { + (yyval.var_or_value_array) = nullptr; + } #line 1843 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 32: /* var_or_value_array: var_or_value_array ',' var_or_value */ + case 32: /* var_or_value_array: var_or_value_array ',' var_or_value */ #line 358 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value_array) = (yyvsp[-2].var_or_value_array); - (yyval.var_or_value_array)->PushBack((yyvsp[0].var_or_value)); - } + { + (yyval.var_or_value_array) = (yyvsp[-2].var_or_value_array); + (yyval.var_or_value_array)->PushBack((yyvsp[0].var_or_value)); + } #line 1852 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 33: /* var_or_value_array: var_or_value */ + case 33: /* var_or_value_array: var_or_value */ #line 362 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value_array) = new VariableRefOrValueArray(); - (yyval.var_or_value_array)->PushBack((yyvsp[0].var_or_value)); - } + { + (yyval.var_or_value_array) = new VariableRefOrValueArray(); + (yyval.var_or_value_array)->PushBack((yyvsp[0].var_or_value)); + } #line 1861 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 34: /* var_or_value: IVALUE */ + case 34: /* var_or_value: IVALUE */ #line 368 "./ortools/flatzinc/parser.yy" - { - (yyval.var_or_value) = VariableRefOrValue::Value((yyvsp[0].integer_value)); - } -#line 1867 "./ortools/flatzinc/parser.tab.cc" - break; - - case 35: /* var_or_value: IDENTIFIER */ -#line 369 "./ortools/flatzinc/parser.yy" - { - // A reference to an existing integer constant or variable. - const std::string &id = (yyvsp[0].string_value); - if (gtl::ContainsKey(context->integer_map, id)) { + { (yyval.var_or_value) = - VariableRefOrValue::Value(gtl::FindOrDie(context->integer_map, id)); - } else if (gtl::ContainsKey(context->variable_map, id)) { - (yyval.var_or_value) = VariableRefOrValue::VariableRef( - gtl::FindOrDie(context->variable_map, id)); - } else { - LOG(ERROR) << "Unknown symbol " << id; - (yyval.var_or_value) = VariableRefOrValue::Undefined(); - *ok = false; + VariableRefOrValue::Value((yyvsp[0].integer_value)); + } +#line 1867 "./ortools/flatzinc/parser.tab.cc" + break; + + case 35: /* var_or_value: IDENTIFIER */ +#line 369 "./ortools/flatzinc/parser.yy" + { + // A reference to an existing integer constant or variable. + const std::string &id = (yyvsp[0].string_value); + if (gtl::ContainsKey(context->integer_map, id)) { + (yyval.var_or_value) = + VariableRefOrValue::Value(gtl::FindOrDie(context->integer_map, id)); + } else if (gtl::ContainsKey(context->variable_map, id)) { + (yyval.var_or_value) = VariableRefOrValue::VariableRef( + gtl::FindOrDie(context->variable_map, id)); + } else { + LOG(ERROR) << "Unknown symbol " << id; + (yyval.var_or_value) = VariableRefOrValue::Undefined(); + *ok = false; + } } - } #line 1885 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 36: /* var_or_value: IDENTIFIER '[' IVALUE ']' */ + case 36: /* var_or_value: IDENTIFIER '[' IVALUE ']' */ #line 382 "./ortools/flatzinc/parser.yy" - { - // A given element of an existing constant array or variable array. - const std::string &id = (yyvsp[-3].string_value); - const int64 value = (yyvsp[-1].integer_value); - if (gtl::ContainsKey(context->integer_array_map, id)) { - (yyval.var_or_value) = VariableRefOrValue::Value( - Lookup(gtl::FindOrDie(context->integer_array_map, id), value)); - } else if (gtl::ContainsKey(context->variable_array_map, id)) { - (yyval.var_or_value) = VariableRefOrValue::VariableRef( - Lookup(gtl::FindOrDie(context->variable_array_map, id), value)); - } else { - LOG(ERROR) << "Unknown symbol " << id; - (yyval.var_or_value) = VariableRefOrValue::Undefined(); - *ok = false; + { + // A given element of an existing constant array or variable array. + const std::string &id = (yyvsp[-3].string_value); + const int64 value = (yyvsp[-1].integer_value); + if (gtl::ContainsKey(context->integer_array_map, id)) { + (yyval.var_or_value) = VariableRefOrValue::Value( + Lookup(gtl::FindOrDie(context->integer_array_map, id), value)); + } else if (gtl::ContainsKey(context->variable_array_map, id)) { + (yyval.var_or_value) = VariableRefOrValue::VariableRef( + Lookup(gtl::FindOrDie(context->variable_array_map, id), value)); + } else { + LOG(ERROR) << "Unknown symbol " << id; + (yyval.var_or_value) = VariableRefOrValue::Undefined(); + *ok = false; + } } - } #line 1906 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 37: /* int_domain: TOKEN_BOOL */ + case 37: /* int_domain: TOKEN_BOOL */ #line 400 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::Boolean(); - } + { + (yyval.domain) = Domain::Boolean(); + } #line 1912 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 38: /* int_domain: TOKEN_INT */ + case 38: /* int_domain: TOKEN_INT */ #line 401 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::AllInt64(); - } + { + (yyval.domain) = Domain::AllInt64(); + } #line 1918 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 39: /* int_domain: IVALUE DOTDOT IVALUE */ + case 39: /* int_domain: IVALUE DOTDOT IVALUE */ #line 402 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = - Domain::Interval((yyvsp[-2].integer_value), (yyvsp[0].integer_value)); - } + { + (yyval.domain) = + Domain::Interval((yyvsp[-2].integer_value), (yyvsp[0].integer_value)); + } #line 1924 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 40: /* int_domain: '{' integers '}' */ + case 40: /* int_domain: '{' integers '}' */ #line 403 "./ortools/flatzinc/parser.yy" - { - CHECK((yyvsp[-1].integers) != nullptr); - (yyval.domain) = Domain::IntegerList(std::move(*(yyvsp[-1].integers))); - delete (yyvsp[-1].integers); - } + { + CHECK((yyvsp[-1].integers) != nullptr); + (yyval.domain) = Domain::IntegerList(std::move(*(yyvsp[-1].integers))); + delete (yyvsp[-1].integers); + } #line 1934 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 41: /* set_domain: SET OF TOKEN_BOOL */ + case 41: /* set_domain: SET OF TOKEN_BOOL */ #line 410 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::SetOfBoolean(); - } + { + (yyval.domain) = Domain::SetOfBoolean(); + } #line 1940 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 42: /* set_domain: SET OF TOKEN_INT */ + case 42: /* set_domain: SET OF TOKEN_INT */ #line 411 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::SetOfAllInt64(); - } + { + (yyval.domain) = Domain::SetOfAllInt64(); + } #line 1946 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 43: /* set_domain: SET OF IVALUE DOTDOT IVALUE */ + case 43: /* set_domain: SET OF IVALUE DOTDOT IVALUE */ #line 412 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::SetOfInterval((yyvsp[-2].integer_value), - (yyvsp[0].integer_value)); - } + { + (yyval.domain) = Domain::SetOfInterval((yyvsp[-2].integer_value), + (yyvsp[0].integer_value)); + } #line 1952 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 44: /* set_domain: SET OF '{' integers '}' */ + case 44: /* set_domain: SET OF '{' integers '}' */ #line 413 "./ortools/flatzinc/parser.yy" - { - CHECK((yyvsp[-1].integers) != nullptr); - (yyval.domain) = Domain::SetOfIntegerList(std::move(*(yyvsp[-1].integers))); - delete (yyvsp[-1].integers); - } + { + CHECK((yyvsp[-1].integers) != nullptr); + (yyval.domain) = + Domain::SetOfIntegerList(std::move(*(yyvsp[-1].integers))); + delete (yyvsp[-1].integers); + } #line 1962 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 45: /* float_domain: TOKEN_FLOAT */ + case 45: /* float_domain: TOKEN_FLOAT */ #line 420 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::AllInt64(); - } + { + (yyval.domain) = Domain::AllInt64(); + } #line 1968 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 46: /* float_domain: DVALUE DOTDOT DVALUE */ + case 46: /* float_domain: DVALUE DOTDOT DVALUE */ #line 421 "./ortools/flatzinc/parser.yy" - { - const int64 lb = ConvertAsIntegerOrDie((yyvsp[-2].double_value)); - const int64 ub = ConvertAsIntegerOrDie((yyvsp[0].double_value)); - (yyval.domain) = Domain::Interval(lb, ub); - } + { + const int64 lb = ConvertAsIntegerOrDie((yyvsp[-2].double_value)); + const int64 ub = ConvertAsIntegerOrDie((yyvsp[0].double_value)); + (yyval.domain) = Domain::Interval(lb, ub); + } #line 1978 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 47: /* domain: int_domain */ + case 47: /* domain: int_domain */ #line 428 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = (yyvsp[0].domain); - } + { + (yyval.domain) = (yyvsp[0].domain); + } #line 1984 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 48: /* domain: set_domain */ + case 48: /* domain: set_domain */ #line 429 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = (yyvsp[0].domain); - } + { + (yyval.domain) = (yyvsp[0].domain); + } #line 1990 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 49: /* domain: float_domain */ + case 49: /* domain: float_domain */ #line 430 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = (yyvsp[0].domain); - } + { + (yyval.domain) = (yyvsp[0].domain); + } #line 1996 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 50: /* integers: integers ',' integer */ + case 50: /* integers: integers ',' integer */ #line 433 "./ortools/flatzinc/parser.yy" - { - (yyval.integers) = (yyvsp[-2].integers); - (yyval.integers)->emplace_back((yyvsp[0].integer_value)); - } + { + (yyval.integers) = (yyvsp[-2].integers); + (yyval.integers)->emplace_back((yyvsp[0].integer_value)); + } #line 2002 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 51: /* integers: integer */ + case 51: /* integers: integer */ #line 434 "./ortools/flatzinc/parser.yy" - { - (yyval.integers) = new std::vector(); - (yyval.integers)->emplace_back((yyvsp[0].integer_value)); - } + { + (yyval.integers) = new std::vector(); + (yyval.integers)->emplace_back((yyvsp[0].integer_value)); + } #line 2008 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 52: /* integer: IVALUE */ + case 52: /* integer: IVALUE */ #line 437 "./ortools/flatzinc/parser.yy" - { - (yyval.integer_value) = (yyvsp[0].integer_value); - } + { + (yyval.integer_value) = (yyvsp[0].integer_value); + } #line 2014 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 53: /* integer: IDENTIFIER */ + case 53: /* integer: IDENTIFIER */ #line 438 "./ortools/flatzinc/parser.yy" - { - (yyval.integer_value) = - gtl::FindOrDie(context->integer_map, (yyvsp[0].string_value)); - } + { + (yyval.integer_value) = + gtl::FindOrDie(context->integer_map, (yyvsp[0].string_value)); + } #line 2020 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 54: /* integer: IDENTIFIER '[' IVALUE ']' */ + case 54: /* integer: IDENTIFIER '[' IVALUE ']' */ #line 439 "./ortools/flatzinc/parser.yy" - { - (yyval.integer_value) = Lookup( - gtl::FindOrDie(context->integer_array_map, (yyvsp[-3].string_value)), - (yyvsp[-1].integer_value)); - } + { + (yyval.integer_value) = Lookup( + gtl::FindOrDie(context->integer_array_map, (yyvsp[-3].string_value)), + (yyvsp[-1].integer_value)); + } #line 2028 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 55: /* floats: floats ',' float */ + case 55: /* floats: floats ',' float */ #line 444 "./ortools/flatzinc/parser.yy" - { - (yyval.doubles) = (yyvsp[-2].doubles); - (yyval.doubles)->emplace_back((yyvsp[0].double_value)); - } + { + (yyval.doubles) = (yyvsp[-2].doubles); + (yyval.doubles)->emplace_back((yyvsp[0].double_value)); + } #line 2034 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 56: /* floats: float */ + case 56: /* floats: float */ #line 445 "./ortools/flatzinc/parser.yy" - { - (yyval.doubles) = new std::vector(); - (yyval.doubles)->emplace_back((yyvsp[0].double_value)); - } + { + (yyval.doubles) = new std::vector(); + (yyval.doubles)->emplace_back((yyvsp[0].double_value)); + } #line 2040 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 57: /* float: DVALUE */ + case 57: /* float: DVALUE */ #line 448 "./ortools/flatzinc/parser.yy" - { - (yyval.double_value) = (yyvsp[0].double_value); - } + { + (yyval.double_value) = (yyvsp[0].double_value); + } #line 2046 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 58: /* float: IDENTIFIER */ + case 58: /* float: IDENTIFIER */ #line 449 "./ortools/flatzinc/parser.yy" - { - (yyval.double_value) = - gtl::FindOrDie(context->float_map, (yyvsp[0].string_value)); - } + { + (yyval.double_value) = + gtl::FindOrDie(context->float_map, (yyvsp[0].string_value)); + } #line 2052 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 59: /* float: IDENTIFIER '[' IVALUE ']' */ + case 59: /* float: IDENTIFIER '[' IVALUE ']' */ #line 450 "./ortools/flatzinc/parser.yy" - { - (yyval.double_value) = Lookup( - gtl::FindOrDie(context->float_array_map, (yyvsp[-3].string_value)), - (yyvsp[-1].integer_value)); - } + { + (yyval.double_value) = Lookup( + gtl::FindOrDie(context->float_array_map, (yyvsp[-3].string_value)), + (yyvsp[-1].integer_value)); + } #line 2060 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 60: /* const_literal: IVALUE */ + case 60: /* const_literal: IVALUE */ #line 455 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::IntegerValue((yyvsp[0].integer_value)); - } + { + (yyval.domain) = Domain::IntegerValue((yyvsp[0].integer_value)); + } #line 2066 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 61: /* const_literal: IVALUE DOTDOT IVALUE */ + case 61: /* const_literal: IVALUE DOTDOT IVALUE */ #line 456 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = - Domain::Interval((yyvsp[-2].integer_value), (yyvsp[0].integer_value)); - } + { + (yyval.domain) = + Domain::Interval((yyvsp[-2].integer_value), (yyvsp[0].integer_value)); + } #line 2072 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 62: /* const_literal: '{' integers '}' */ + case 62: /* const_literal: '{' integers '}' */ #line 457 "./ortools/flatzinc/parser.yy" - { - CHECK((yyvsp[-1].integers) != nullptr); - (yyval.domain) = Domain::IntegerList(std::move(*(yyvsp[-1].integers))); - delete (yyvsp[-1].integers); - } + { + CHECK((yyvsp[-1].integers) != nullptr); + (yyval.domain) = Domain::IntegerList(std::move(*(yyvsp[-1].integers))); + delete (yyvsp[-1].integers); + } #line 2082 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 63: /* const_literal: '{' '}' */ + case 63: /* const_literal: '{' '}' */ #line 462 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::EmptyDomain(); - } + { + (yyval.domain) = Domain::EmptyDomain(); + } #line 2088 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 64: /* const_literal: DVALUE */ + case 64: /* const_literal: DVALUE */ #line 463 "./ortools/flatzinc/parser.yy" - { - CHECK_EQ(std::round((yyvsp[0].double_value)), (yyvsp[0].double_value)); - (yyval.domain) = - Domain::IntegerValue(static_cast((yyvsp[0].double_value))); - } + { + CHECK_EQ(std::round((yyvsp[0].double_value)), (yyvsp[0].double_value)); + (yyval.domain) = + Domain::IntegerValue(static_cast((yyvsp[0].double_value))); + } #line 2097 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 65: /* const_literal: IDENTIFIER */ + case 65: /* const_literal: IDENTIFIER */ #line 467 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::IntegerValue( - gtl::FindOrDie(context->integer_map, (yyvsp[0].string_value))); - } + { + (yyval.domain) = Domain::IntegerValue( + gtl::FindOrDie(context->integer_map, (yyvsp[0].string_value))); + } #line 2103 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 66: /* const_literal: IDENTIFIER '[' IVALUE ']' */ + case 66: /* const_literal: IDENTIFIER '[' IVALUE ']' */ #line 468 "./ortools/flatzinc/parser.yy" - { - (yyval.domain) = Domain::IntegerValue(Lookup( - gtl::FindOrDie(context->integer_array_map, (yyvsp[-3].string_value)), - (yyvsp[-1].integer_value))); - } + { + (yyval.domain) = Domain::IntegerValue(Lookup( + gtl::FindOrDie(context->integer_array_map, (yyvsp[-3].string_value)), + (yyvsp[-1].integer_value))); + } #line 2112 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 67: /* const_literals: const_literals ',' const_literal */ + case 67: /* const_literals: const_literals ',' const_literal */ #line 474 "./ortools/flatzinc/parser.yy" - { - (yyval.domains) = (yyvsp[-2].domains); - (yyval.domains)->emplace_back((yyvsp[0].domain)); - } + { + (yyval.domains) = (yyvsp[-2].domains); + (yyval.domains)->emplace_back((yyvsp[0].domain)); + } #line 2121 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 68: /* const_literals: const_literal */ + case 68: /* const_literals: const_literal */ #line 478 "./ortools/flatzinc/parser.yy" - { - (yyval.domains) = new std::vector(); - (yyval.domains)->emplace_back((yyvsp[0].domain)); - } + { + (yyval.domains) = new std::vector(); + (yyval.domains)->emplace_back((yyvsp[0].domain)); + } #line 2127 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 71: /* constraint: CONSTRAINT IDENTIFIER '(' arguments ')' annotations - */ + case 71: /* constraint: CONSTRAINT IDENTIFIER '(' arguments ')' annotations + */ #line 488 "./ortools/flatzinc/parser.yy" - { - const std::string &identifier = (yyvsp[-4].string_value); - CHECK((yyvsp[-2].args) != nullptr) << "Missing argument in constraint"; - const std::vector &arguments = *(yyvsp[-2].args); - std::vector *const annotations = (yyvsp[0].annotations); + { + const std::string &identifier = (yyvsp[-4].string_value); + CHECK((yyvsp[-2].args) != nullptr) << "Missing argument in constraint"; + const std::vector &arguments = *(yyvsp[-2].args); + std::vector *const annotations = (yyvsp[0].annotations); - model->AddConstraint(identifier, arguments, - ContainsId(annotations, "domain")); - delete annotations; - delete (yyvsp[-2].args); - } + model->AddConstraint(identifier, arguments, + ContainsId(annotations, "domain")); + delete annotations; + delete (yyvsp[-2].args); + } #line 2142 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 72: /* arguments: arguments ',' argument */ + case 72: /* arguments: arguments ',' argument */ #line 500 "./ortools/flatzinc/parser.yy" - { - (yyval.args) = (yyvsp[-2].args); - (yyval.args)->emplace_back((yyvsp[0].arg)); - } + { + (yyval.args) = (yyvsp[-2].args); + (yyval.args)->emplace_back((yyvsp[0].arg)); + } #line 2148 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 73: /* arguments: argument */ + case 73: /* arguments: argument */ #line 501 "./ortools/flatzinc/parser.yy" - { - (yyval.args) = new std::vector(); - (yyval.args)->emplace_back((yyvsp[0].arg)); - } + { + (yyval.args) = new std::vector(); + (yyval.args)->emplace_back((yyvsp[0].arg)); + } #line 2154 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 74: /* argument: IVALUE */ + case 74: /* argument: IVALUE */ #line 504 "./ortools/flatzinc/parser.yy" - { - (yyval.arg) = Argument::IntegerValue((yyvsp[0].integer_value)); - } + { + (yyval.arg) = Argument::IntegerValue((yyvsp[0].integer_value)); + } #line 2160 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 75: /* argument: DVALUE */ + case 75: /* argument: DVALUE */ #line 505 "./ortools/flatzinc/parser.yy" - { - (yyval.arg) = - Argument::IntegerValue(ConvertAsIntegerOrDie((yyvsp[0].double_value))); - } -#line 2166 "./ortools/flatzinc/parser.tab.cc" - break; - - case 76: /* argument: SVALUE */ -#line 506 "./ortools/flatzinc/parser.yy" - { - (yyval.arg) = Argument::VoidArgument(); - } -#line 2172 "./ortools/flatzinc/parser.tab.cc" - break; - - case 77: /* argument: IVALUE DOTDOT IVALUE */ -#line 507 "./ortools/flatzinc/parser.yy" - { - (yyval.arg) = - Argument::Interval((yyvsp[-2].integer_value), (yyvsp[0].integer_value)); - } -#line 2178 "./ortools/flatzinc/parser.tab.cc" - break; - - case 78: /* argument: '{' integers '}' */ -#line 508 "./ortools/flatzinc/parser.yy" - { - CHECK((yyvsp[-1].integers) != nullptr); - (yyval.arg) = Argument::IntegerList(std::move(*(yyvsp[-1].integers))); - delete (yyvsp[-1].integers); - } -#line 2188 "./ortools/flatzinc/parser.tab.cc" - break; - - case 79: /* argument: IDENTIFIER */ -#line 513 "./ortools/flatzinc/parser.yy" - { - const std::string &id = (yyvsp[0].string_value); - if (gtl::ContainsKey(context->integer_map, id)) { - (yyval.arg) = - Argument::IntegerValue(gtl::FindOrDie(context->integer_map, id)); - } else if (gtl::ContainsKey(context->integer_array_map, id)) { - (yyval.arg) = - Argument::IntegerList(gtl::FindOrDie(context->integer_array_map, id)); - } else if (gtl::ContainsKey(context->float_map, id)) { - const double d = gtl::FindOrDie(context->float_map, id); - (yyval.arg) = Argument::IntegerValue(ConvertAsIntegerOrDie(d)); - } else if (gtl::ContainsKey(context->float_array_map, id)) { - const auto &double_values = gtl::FindOrDie(context->float_array_map, id); - std::vector integer_values; - for (const double d : double_values) { - const int64 i = ConvertAsIntegerOrDie(d); - integer_values.push_back(i); - } - (yyval.arg) = Argument::IntegerList(std::move(integer_values)); - } else if (gtl::ContainsKey(context->variable_map, id)) { - (yyval.arg) = - Argument::IntVarRef(gtl::FindOrDie(context->variable_map, id)); - } else if (gtl::ContainsKey(context->variable_array_map, id)) { - (yyval.arg) = Argument::IntVarRefArray( - gtl::FindOrDie(context->variable_array_map, id)); - } else if (gtl::ContainsKey(context->domain_map, id)) { - const Domain &d = gtl::FindOrDie(context->domain_map, id); - (yyval.arg) = Argument::FromDomain(d); - } else { - CHECK(gtl::ContainsKey(context->domain_array_map, id)) - << "Unknown identifier: " << id; - const std::vector &d = - gtl::FindOrDie(context->domain_array_map, id); - (yyval.arg) = Argument::DomainList(d); - } - } -#line 2224 "./ortools/flatzinc/parser.tab.cc" - break; - - case 80: /* argument: IDENTIFIER '[' IVALUE ']' */ -#line 544 "./ortools/flatzinc/parser.yy" - { - const std::string &id = (yyvsp[-3].string_value); - const int64 index = (yyvsp[-1].integer_value); - if (gtl::ContainsKey(context->integer_array_map, id)) { + { (yyval.arg) = Argument::IntegerValue( - Lookup(gtl::FindOrDie(context->integer_array_map, id), index)); - } else if (gtl::ContainsKey(context->variable_array_map, id)) { - (yyval.arg) = Argument::IntVarRef( - Lookup(gtl::FindOrDie(context->variable_array_map, id), index)); - } else { - CHECK(gtl::ContainsKey(context->domain_array_map, id)) - << "Unknown identifier: " << id; - const Domain &d = - Lookup(gtl::FindOrDie(context->domain_array_map, id), index); - (yyval.arg) = Argument::FromDomain(d); + ConvertAsIntegerOrDie((yyvsp[0].double_value))); } - } -#line 2246 "./ortools/flatzinc/parser.tab.cc" - break; +#line 2166 "./ortools/flatzinc/parser.tab.cc" + break; - case 81: /* argument: '[' var_or_value_array ']' */ -#line 561 "./ortools/flatzinc/parser.yy" - { - VariableRefOrValueArray *const arguments = (yyvsp[-1].var_or_value_array); - CHECK(arguments != nullptr); - bool has_variables = false; - for (int i = 0; i < arguments->Size(); ++i) { - if (arguments->variables[i] != nullptr) { - has_variables = true; - break; + case 76: /* argument: SVALUE */ +#line 506 "./ortools/flatzinc/parser.yy" + { + (yyval.arg) = Argument::VoidArgument(); + } +#line 2172 "./ortools/flatzinc/parser.tab.cc" + break; + + case 77: /* argument: IVALUE DOTDOT IVALUE */ +#line 507 "./ortools/flatzinc/parser.yy" + { + (yyval.arg) = Argument::Interval((yyvsp[-2].integer_value), + (yyvsp[0].integer_value)); + } +#line 2178 "./ortools/flatzinc/parser.tab.cc" + break; + + case 78: /* argument: '{' integers '}' */ +#line 508 "./ortools/flatzinc/parser.yy" + { + CHECK((yyvsp[-1].integers) != nullptr); + (yyval.arg) = Argument::IntegerList(std::move(*(yyvsp[-1].integers))); + delete (yyvsp[-1].integers); + } +#line 2188 "./ortools/flatzinc/parser.tab.cc" + break; + + case 79: /* argument: IDENTIFIER */ +#line 513 "./ortools/flatzinc/parser.yy" + { + const std::string &id = (yyvsp[0].string_value); + if (gtl::ContainsKey(context->integer_map, id)) { + (yyval.arg) = + Argument::IntegerValue(gtl::FindOrDie(context->integer_map, id)); + } else if (gtl::ContainsKey(context->integer_array_map, id)) { + (yyval.arg) = Argument::IntegerList( + gtl::FindOrDie(context->integer_array_map, id)); + } else if (gtl::ContainsKey(context->float_map, id)) { + const double d = gtl::FindOrDie(context->float_map, id); + (yyval.arg) = Argument::IntegerValue(ConvertAsIntegerOrDie(d)); + } else if (gtl::ContainsKey(context->float_array_map, id)) { + const auto &double_values = + gtl::FindOrDie(context->float_array_map, id); + std::vector integer_values; + for (const double d : double_values) { + const int64 i = ConvertAsIntegerOrDie(d); + integer_values.push_back(i); + } + (yyval.arg) = Argument::IntegerList(std::move(integer_values)); + } else if (gtl::ContainsKey(context->variable_map, id)) { + (yyval.arg) = + Argument::IntVarRef(gtl::FindOrDie(context->variable_map, id)); + } else if (gtl::ContainsKey(context->variable_array_map, id)) { + (yyval.arg) = Argument::IntVarRefArray( + gtl::FindOrDie(context->variable_array_map, id)); + } else if (gtl::ContainsKey(context->domain_map, id)) { + const Domain &d = gtl::FindOrDie(context->domain_map, id); + (yyval.arg) = Argument::FromDomain(d); + } else { + CHECK(gtl::ContainsKey(context->domain_array_map, id)) + << "Unknown identifier: " << id; + const std::vector &d = + gtl::FindOrDie(context->domain_array_map, id); + (yyval.arg) = Argument::DomainList(d); } } - if (has_variables) { - (yyval.arg) = Argument::IntVarRefArray(std::vector()); - (yyval.arg).variables.reserve(arguments->Size()); +#line 2224 "./ortools/flatzinc/parser.tab.cc" + break; + + case 80: /* argument: IDENTIFIER '[' IVALUE ']' */ +#line 544 "./ortools/flatzinc/parser.yy" + { + const std::string &id = (yyvsp[-3].string_value); + const int64 index = (yyvsp[-1].integer_value); + if (gtl::ContainsKey(context->integer_array_map, id)) { + (yyval.arg) = Argument::IntegerValue( + Lookup(gtl::FindOrDie(context->integer_array_map, id), index)); + } else if (gtl::ContainsKey(context->variable_array_map, id)) { + (yyval.arg) = Argument::IntVarRef( + Lookup(gtl::FindOrDie(context->variable_array_map, id), index)); + } else { + CHECK(gtl::ContainsKey(context->domain_array_map, id)) + << "Unknown identifier: " << id; + const Domain &d = + Lookup(gtl::FindOrDie(context->domain_array_map, id), index); + (yyval.arg) = Argument::FromDomain(d); + } + } +#line 2246 "./ortools/flatzinc/parser.tab.cc" + break; + + case 81: /* argument: '[' var_or_value_array ']' */ +#line 561 "./ortools/flatzinc/parser.yy" + { + VariableRefOrValueArray *const arguments = (yyvsp[-1].var_or_value_array); + CHECK(arguments != nullptr); + bool has_variables = false; for (int i = 0; i < arguments->Size(); ++i) { if (arguments->variables[i] != nullptr) { - (yyval.arg).variables.emplace_back(arguments->variables[i]); - } else { - (yyval.arg).variables - .emplace_back(model->AddConstant(arguments->values[i])); + has_variables = true; + break; } } - } else { - (yyval.arg) = Argument::IntegerList(arguments->values); + if (has_variables) { + (yyval.arg) = + Argument::IntVarRefArray(std::vector()); + (yyval.arg).variables.reserve(arguments->Size()); + for (int i = 0; i < arguments->Size(); ++i) { + if (arguments->variables[i] != nullptr) { + (yyval.arg).variables.emplace_back(arguments->variables[i]); + } else { + (yyval.arg).variables.emplace_back( + model->AddConstant(arguments->values[i])); + } + } + } else { + (yyval.arg) = Argument::IntegerList(arguments->values); + } + delete arguments; } - delete arguments; - } #line 2276 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 82: /* argument: '[' ']' */ + case 82: /* argument: '[' ']' */ #line 586 "./ortools/flatzinc/parser.yy" - { - (yyval.arg) = Argument::VoidArgument(); - } + { + (yyval.arg) = Argument::VoidArgument(); + } #line 2284 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 83: /* annotations: annotations COLONCOLON annotation */ + case 83: /* annotations: annotations COLONCOLON annotation */ #line 595 "./ortools/flatzinc/parser.yy" - { - (yyval.annotations) = - (yyvsp[-2].annotations) != nullptr ? (yyvsp[-2].annotations) - : new std::vector(); - (yyval.annotations)->emplace_back((yyvsp[0].annotation)); - } + { + (yyval.annotations) = (yyvsp[-2].annotations) != nullptr + ? (yyvsp[-2].annotations) + : new std::vector(); + (yyval.annotations)->emplace_back((yyvsp[0].annotation)); + } #line 2293 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 84: /* annotations: %empty */ + case 84: /* annotations: %empty */ #line 599 "./ortools/flatzinc/parser.yy" - { - (yyval.annotations) = nullptr; - } + { + (yyval.annotations) = nullptr; + } #line 2299 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 85: /* annotation_arguments: annotation_arguments ',' annotation */ + case 85: /* annotation_arguments: annotation_arguments ',' annotation */ #line 602 "./ortools/flatzinc/parser.yy" - { - (yyval.annotations) = (yyvsp[-2].annotations); - (yyval.annotations)->emplace_back((yyvsp[0].annotation)); - } + { + (yyval.annotations) = (yyvsp[-2].annotations); + (yyval.annotations)->emplace_back((yyvsp[0].annotation)); + } #line 2305 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 86: /* annotation_arguments: annotation */ + case 86: /* annotation_arguments: annotation */ #line 603 "./ortools/flatzinc/parser.yy" - { - (yyval.annotations) = new std::vector(); - (yyval.annotations)->emplace_back((yyvsp[0].annotation)); - } + { + (yyval.annotations) = new std::vector(); + (yyval.annotations)->emplace_back((yyvsp[0].annotation)); + } #line 2311 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 87: /* annotation: IVALUE DOTDOT IVALUE */ + case 87: /* annotation: IVALUE DOTDOT IVALUE */ #line 606 "./ortools/flatzinc/parser.yy" - { - (yyval.annotation) = Annotation::Interval((yyvsp[-2].integer_value), - (yyvsp[0].integer_value)); - } + { + (yyval.annotation) = Annotation::Interval((yyvsp[-2].integer_value), + (yyvsp[0].integer_value)); + } #line 2317 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 88: /* annotation: IVALUE */ + case 88: /* annotation: IVALUE */ #line 607 "./ortools/flatzinc/parser.yy" - { - (yyval.annotation) = Annotation::IntegerValue((yyvsp[0].integer_value)); - } + { + (yyval.annotation) = Annotation::IntegerValue((yyvsp[0].integer_value)); + } #line 2323 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 89: /* annotation: SVALUE */ + case 89: /* annotation: SVALUE */ #line 608 "./ortools/flatzinc/parser.yy" - { - (yyval.annotation) = Annotation::String((yyvsp[0].string_value)); - } + { + (yyval.annotation) = Annotation::String((yyvsp[0].string_value)); + } #line 2329 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 90: /* annotation: IDENTIFIER */ + case 90: /* annotation: IDENTIFIER */ #line 609 "./ortools/flatzinc/parser.yy" - { - const std::string &id = (yyvsp[0].string_value); - if (gtl::ContainsKey(context->variable_map, id)) { - (yyval.annotation) = - Annotation::Variable(gtl::FindOrDie(context->variable_map, id)); - } else if (gtl::ContainsKey(context->variable_array_map, id)) { - (yyval.annotation) = Annotation::VariableList( - gtl::FindOrDie(context->variable_array_map, id)); - } else { - (yyval.annotation) = Annotation::Identifier(id); + { + const std::string &id = (yyvsp[0].string_value); + if (gtl::ContainsKey(context->variable_map, id)) { + (yyval.annotation) = + Annotation::Variable(gtl::FindOrDie(context->variable_map, id)); + } else if (gtl::ContainsKey(context->variable_array_map, id)) { + (yyval.annotation) = Annotation::VariableList( + gtl::FindOrDie(context->variable_array_map, id)); + } else { + (yyval.annotation) = Annotation::Identifier(id); + } } - } #line 2344 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 91: /* annotation: IDENTIFIER '(' annotation_arguments ')' */ + case 91: /* annotation: IDENTIFIER '(' annotation_arguments ')' */ #line 619 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-1].annotations); - if (annotations != nullptr) { - (yyval.annotation) = Annotation::FunctionCallWithArguments( - (yyvsp[-3].string_value), std::move(*annotations)); - delete annotations; - } else { - (yyval.annotation) = Annotation::FunctionCall((yyvsp[-3].string_value)); + { + std::vector *const annotations = (yyvsp[-1].annotations); + if (annotations != nullptr) { + (yyval.annotation) = Annotation::FunctionCallWithArguments( + (yyvsp[-3].string_value), std::move(*annotations)); + delete annotations; + } else { + (yyval.annotation) = Annotation::FunctionCall((yyvsp[-3].string_value)); + } } - } #line 2358 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 92: /* annotation: IDENTIFIER '[' IVALUE ']' */ + case 92: /* annotation: IDENTIFIER '[' IVALUE ']' */ #line 628 "./ortools/flatzinc/parser.yy" - { - CHECK( - gtl::ContainsKey(context->variable_array_map, (yyvsp[-3].string_value))) - << "Unknown identifier: " << (yyvsp[-3].string_value); - (yyval.annotation) = Annotation::Variable(Lookup( - gtl::FindOrDie(context->variable_array_map, (yyvsp[-3].string_value)), - (yyvsp[-1].integer_value))); - } + { + CHECK(gtl::ContainsKey(context->variable_array_map, + (yyvsp[-3].string_value))) + << "Unknown identifier: " << (yyvsp[-3].string_value); + (yyval.annotation) = Annotation::Variable(Lookup( + gtl::FindOrDie(context->variable_array_map, (yyvsp[-3].string_value)), + (yyvsp[-1].integer_value))); + } #line 2369 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 93: /* annotation: '[' annotation_arguments ']' */ + case 93: /* annotation: '[' annotation_arguments ']' */ #line 634 "./ortools/flatzinc/parser.yy" - { - std::vector *const annotations = (yyvsp[-1].annotations); - if (annotations != nullptr) { - (yyval.annotation) = Annotation::AnnotationList(std::move(*annotations)); - delete annotations; - } else { - (yyval.annotation) = Annotation::Empty(); + { + std::vector *const annotations = (yyvsp[-1].annotations); + if (annotations != nullptr) { + (yyval.annotation) = + Annotation::AnnotationList(std::move(*annotations)); + delete annotations; + } else { + (yyval.annotation) = Annotation::Empty(); + } } - } #line 2383 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 94: /* solve: SOLVE annotations SATISFY */ + case 94: /* solve: SOLVE annotations SATISFY */ #line 649 "./ortools/flatzinc/parser.yy" - { - if ((yyvsp[-1].annotations) != nullptr) { - model->Satisfy(std::move(*(yyvsp[-1].annotations))); - delete (yyvsp[-1].annotations); - } else { - model->Satisfy(std::vector()); + { + if ((yyvsp[-1].annotations) != nullptr) { + model->Satisfy(std::move(*(yyvsp[-1].annotations))); + delete (yyvsp[-1].annotations); + } else { + model->Satisfy(std::vector()); + } } - } #line 2396 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 95: /* solve: SOLVE annotations MINIMIZE argument */ + case 95: /* solve: SOLVE annotations MINIMIZE argument */ #line 657 "./ortools/flatzinc/parser.yy" - { - CHECK_EQ(Argument::INT_VAR_REF, (yyvsp[0].arg).type); - if ((yyvsp[-2].annotations) != nullptr) { - model->Minimize((yyvsp[0].arg).Var(), - std::move(*(yyvsp[-2].annotations))); - delete (yyvsp[-2].annotations); - } else { - model->Minimize((yyvsp[0].arg).Var(), std::vector()); + { + CHECK_EQ(Argument::INT_VAR_REF, (yyvsp[0].arg).type); + if ((yyvsp[-2].annotations) != nullptr) { + model->Minimize((yyvsp[0].arg).Var(), + std::move(*(yyvsp[-2].annotations))); + delete (yyvsp[-2].annotations); + } else { + model->Minimize((yyvsp[0].arg).Var(), std::vector()); + } } - } #line 2410 "./ortools/flatzinc/parser.tab.cc" - break; + break; - case 96: /* solve: SOLVE annotations MAXIMIZE argument */ + case 96: /* solve: SOLVE annotations MAXIMIZE argument */ #line 666 "./ortools/flatzinc/parser.yy" - { - CHECK_EQ(Argument::INT_VAR_REF, (yyvsp[0].arg).type); - if ((yyvsp[-2].annotations) != nullptr) { - model->Maximize((yyvsp[0].arg).Var(), - std::move(*(yyvsp[-2].annotations))); - delete (yyvsp[-2].annotations); - } else { - model->Maximize((yyvsp[0].arg).Var(), std::vector()); + { + CHECK_EQ(Argument::INT_VAR_REF, (yyvsp[0].arg).type); + if ((yyvsp[-2].annotations) != nullptr) { + model->Maximize((yyvsp[0].arg).Var(), + std::move(*(yyvsp[-2].annotations))); + delete (yyvsp[-2].annotations); + } else { + model->Maximize((yyvsp[0].arg).Var(), std::vector()); + } } - } #line 2424 "./ortools/flatzinc/parser.tab.cc" - break; + break; #line 2428 "./ortools/flatzinc/parser.tab.cc" - default: - break; + default: + break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the @@ -2427,15 +2463,14 @@ yyerrlab: if (!yyerrstatus) { ++yynerrs; { - yypcontext_t yyctx = { yyssp, yytoken }; + yypcontext_t yyctx = {yyssp, yytoken}; char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = yysyntax_error(&yymsg_alloc, &yymsg, &yyctx); if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == -1) { - if (yymsg != yymsgbuf) - YYSTACK_FREE(yymsg); + if (yymsg != yymsgbuf) YYSTACK_FREE(yymsg); yymsg = YY_CAST(char *, YYSTACK_ALLOC(YY_CAST(YYSIZE_T, yymsg_alloc))); if (yymsg) { yysyntax_error_status = yysyntax_error(&yymsg_alloc, &yymsg, &yyctx); @@ -2447,8 +2482,7 @@ yyerrlab: } } yyerror(context, model, ok, scanner, yymsgp); - if (yysyntax_error_status == YYENOMEM) - goto yyexhaustedlab; + if (yysyntax_error_status == YYENOMEM) goto yyexhaustedlab; } } @@ -2458,8 +2492,7 @@ yyerrlab: if (yychar <= ORFZ_EOF) { /* Return failure if at end of input. */ - if (yychar == ORFZ_EOF) - YYABORT; + if (yychar == ORFZ_EOF) YYABORT; } else { yydestruct("Error: discarding", yytoken, &yylval, context, model, ok, scanner); @@ -2477,8 +2510,7 @@ yyerrlab: yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ - if (0) - YYERROR; + if (0) YYERROR; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ @@ -2501,14 +2533,12 @@ yyerrlab1: yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; - if (0 < yyn) - break; + if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; + if (yyssp == yyss) YYABORT; yydestruct("Error: popping", YY_ACCESSING_SYMBOL(yystate), yyvsp, context, model, ok, scanner); @@ -2517,7 +2547,7 @@ yyerrlab1: YY_STACK_PRINT(yyss, yyssp); } - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN * ++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT("Shifting", YY_ACCESSING_SYMBOL(yyn), yyvsp, yylsp); @@ -2569,11 +2599,9 @@ yyreturn: YYPOPSTACK(1); } #ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE(yyss); + if (yyss != yyssa) YYSTACK_FREE(yyss); #endif - if (yymsg != yymsgbuf) - YYSTACK_FREE(yymsg); + if (yymsg != yymsgbuf) YYSTACK_FREE(yymsg); return yyresult; } diff --git a/ortools/flatzinc/parser.yy.cc b/ortools/flatzinc/parser.yy.cc index c01add8568..c5a59e4b47 100644 --- a/ortools/flatzinc/parser.yy.cc +++ b/ortools/flatzinc/parser.yy.cc @@ -320,7 +320,7 @@ typedef unsigned int flex_uint32_t; #endif #ifndef SIZE_MAX -#define SIZE_MAX (~(size_t) 0) +#define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ @@ -419,31 +419,29 @@ typedef size_t yy_size_t; * performance hit in a non-yylineno scanner, because yy_act is normally * declared as a register variable-- so it is not worth it. */ -#define YY_LESS_LINENO(n) \ - do { \ - int yyl; \ - for (yyl = n; yyl < yyleng; ++yyl) \ - if (yytext[yyl] == '\n') \ - --yylineno; \ +#define YY_LESS_LINENO(n) \ + do { \ + int yyl; \ + for (yyl = n; yyl < yyleng; ++yyl) \ + if (yytext[yyl] == '\n') --yylineno; \ } while (0) -#define YY_LINENO_REWIND_TO(dst) \ - do { \ - const char *p; \ - for (p = yy_cp - 1; p >= (dst); --p) \ - if (*p == '\n') \ - --yylineno; \ +#define YY_LINENO_REWIND_TO(dst) \ + do { \ + const char *p; \ + for (p = yy_cp - 1; p >= (dst); --p) \ + if (*p == '\n') --yylineno; \ } while (0) /* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg); \ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET yyg->yy_c_buf_p = yy_cp = \ - yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ +#define yyless(n) \ + do { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg); \ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET yyg->yy_c_buf_p = yy_cp = \ + yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } while (0) #define unput(c) yyunput(c, yyg->yytext_ptr, yyscanner) @@ -516,7 +514,7 @@ struct yy_buffer_state { * * Returns the top of the stack, or NULL. */ -#define YY_CURRENT_BUFFER \ +#define YY_CURRENT_BUFFER \ (yyg->yy_buffer_stack ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. @@ -545,23 +543,23 @@ void *yyrealloc(void *, yy_size_t, yyscan_t yyscanner); void yyfree(void *, yyscan_t yyscanner); #define yy_new_buffer yy_create_buffer -#define yy_set_interactive(is_interactive) \ - { \ - if (!YY_CURRENT_BUFFER) { \ - yyensure_buffer_stack(yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ +#define yy_set_interactive(is_interactive) \ + { \ + if (!YY_CURRENT_BUFFER) { \ + yyensure_buffer_stack(yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } -#define yy_set_bol(at_bol) \ - { \ - if (!YY_CURRENT_BUFFER) { \ - yyensure_buffer_stack(yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ +#define yy_set_bol(at_bol) \ + { \ + if (!YY_CURRENT_BUFFER) { \ + yyensure_buffer_stack(yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) @@ -584,11 +582,11 @@ static void yynoreturn yy_fatal_error(const char *msg, yyscan_t yyscanner); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyleng = (int)(yy_cp - yy_bp); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int)(yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 31 #define YY_END_OF_BUFFER 32 @@ -599,87 +597,94 @@ struct yy_trans_info { flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[117] = { - 0, 0, 0, 32, 30, 28, 27, 30, 29, 30, 30, 18, 18, 30, 24, 30, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 0, 26, 29, 18, 18, 14, 0, 0, 0, 0, 15, 24, 25, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 8, 24, 24, 24, 24, 24, 24, 21, 0, 23, 20, 19, - 25, 24, 24, 24, 24, 24, 5, 24, 24, 24, 24, 11, 24, 24, 13, 0, 24, 2, 24, 24, - 24, 24, 24, 24, 24, 24, 16, 0, 22, 1, 24, 17, 4, 24, 24, 24, 24, 12, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 10, 24, 6, 7, 24, 24, 9, 3, 0 -}; + 0, 0, 0, 32, 30, 28, 27, 30, 29, 30, 30, 18, 18, 30, 24, 30, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 26, 29, 18, 18, 14, 0, + 0, 0, 0, 15, 24, 25, 0, 24, 24, 24, 24, 24, 24, 24, 24, 8, 24, + 24, 24, 24, 24, 24, 21, 0, 23, 20, 19, 25, 24, 24, 24, 24, 24, 5, + 24, 24, 24, 24, 11, 24, 24, 13, 0, 24, 2, 24, 24, 24, 24, 24, 24, + 24, 24, 16, 0, 22, 1, 24, 17, 4, 24, 24, 24, 24, 12, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 10, 24, 6, 7, 24, 24, 9, 3, 0}; static const YY_CHAR yy_ec[256] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 5, 1, 1, 1, 1, 1, 6, 1, 7, 8, 1, 9, 10, 10, - 10, 10, 10, 10, 10, 11, 11, 12, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 14, 13, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, - 1, 1, 1, 16, 1, 17, 18, 19, 20, 21, 22, 15, 15, 23, 15, 15, 24, 25, 26, 27, - 28, 15, 29, 30, 31, 32, 33, 15, 34, 35, 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 -}; + 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 5, + 1, 1, 1, 1, 1, 6, 1, 7, 8, 1, 9, 10, 10, 10, 10, 10, 10, 10, 11, + 11, 12, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 14, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, 1, + 16, 1, 17, 18, 19, 20, 21, 22, 15, 15, 23, 15, 15, 24, 25, 26, 27, 28, 15, + 29, 30, 31, 32, 33, 15, 34, 35, 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1}; -static const YY_CHAR yy_meta[37] = { 0, 1, 1, 2, 1, 1, 1, 1, 1, 3, 3, 3, 1, 4, - 4, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5 }; +static const YY_CHAR yy_meta[37] = {0, 1, 1, 2, 1, 1, 1, 1, 1, 3, 3, 3, 1, + 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; static const flex_int16_t yy_base[123] = { - 0, 0, 0, 174, 175, 175, 175, 169, 0, 28, 164, 32, 17, 159, 0, 154, 140, 141, - 140, 28, 140, 31, 143, 135, 40, 134, 145, 157, 175, 0, 0, 0, 175, 53, 62, 40, - 0, 175, 0, 0, 144, 130, 131, 131, 132, 128, 123, 119, 126, 0, 130, 119, 118, - 124, 115, 117, 65, 71, 74, 46, 0, 0, 128, 120, 113, 112, 124, 0, 117, 116, - 118, 114, 0, 103, 114, 0, 81, 99, 0, 102, 111, 100, 105, 104, 105, 97, 105, 0, - 84, 87, 0, 96, 0, 0, 101, 100, 103, 99, 0, 103, 83, 69, 83, 54, 55, 56, 49, - 34, 0, 34, 0, 0, 37, 16, 0, 0, 175, 98, 103, 106, 108, 111, 113 -}; + 0, 0, 0, 174, 175, 175, 175, 169, 0, 28, 164, 32, 17, 159, + 0, 154, 140, 141, 140, 28, 140, 31, 143, 135, 40, 134, 145, 157, + 175, 0, 0, 0, 175, 53, 62, 40, 0, 175, 0, 0, 144, 130, + 131, 131, 132, 128, 123, 119, 126, 0, 130, 119, 118, 124, 115, 117, + 65, 71, 74, 46, 0, 0, 128, 120, 113, 112, 124, 0, 117, 116, + 118, 114, 0, 103, 114, 0, 81, 99, 0, 102, 111, 100, 105, 104, + 105, 97, 105, 0, 84, 87, 0, 96, 0, 0, 101, 100, 103, 99, + 0, 103, 83, 69, 83, 54, 55, 56, 49, 34, 0, 34, 0, 0, + 37, 16, 0, 0, 175, 98, 103, 106, 108, 111, 113}; static const flex_int16_t yy_def[123] = { - 0, 116, 1, 116, 116, 116, 116, 117, 118, 116, 116, 116, 11, 116, 119, 120, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 117, 116, 118, 11, 12, - 116, 116, 116, 116, 121, 116, 119, 122, 120, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 116, 116, 116, 116, 121, 122, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 116, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 116, 116, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 0, 116, 116, 116, 116, 116, 116 -}; + 0, 116, 1, 116, 116, 116, 116, 117, 118, 116, 116, 116, 11, 116, + 119, 120, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 117, + 116, 118, 11, 12, 116, 116, 116, 116, 121, 116, 119, 122, 120, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 116, 116, 116, 116, 121, 122, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 116, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 116, 116, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 0, 116, 116, 116, 116, 116, 116}; static const flex_int16_t yy_nxt[212] = { - 0, 4, 5, 6, 7, 8, 4, 9, 10, 11, 12, 12, 13, 14, 14, 14, 15, 16, 17, 18, 14, - 14, 19, 20, 14, 21, 14, 22, 23, 14, 24, 25, 14, 26, 14, 14, 14, 30, 31, 31, - 33, 31, 31, 31, 116, 44, 34, 115, 47, 59, 59, 116, 45, 34, 48, 59, 59, 51, - 114, 35, 113, 52, 56, 56, 56, 112, 36, 53, 57, 57, 111, 58, 58, 58, 56, 56, - 56, 110, 109, 76, 58, 58, 58, 58, 58, 58, 76, 88, 88, 108, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 27, 107, 27, 27, 27, 29, 106, 29, 29, 29, 38, 38, 38, 39, 39, - 60, 60, 61, 61, 61, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, - 92, 91, 90, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 75, 74, 73, 72, 71, - 70, 69, 68, 67, 66, 65, 64, 63, 62, 40, 28, 55, 54, 50, 49, 46, 43, 42, 41, - 40, 37, 32, 28, 116, 3, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116 -}; + 0, 4, 5, 6, 7, 8, 4, 9, 10, 11, 12, 12, 13, 14, 14, + 14, 15, 16, 17, 18, 14, 14, 19, 20, 14, 21, 14, 22, 23, 14, + 24, 25, 14, 26, 14, 14, 14, 30, 31, 31, 33, 31, 31, 31, 116, + 44, 34, 115, 47, 59, 59, 116, 45, 34, 48, 59, 59, 51, 114, 35, + 113, 52, 56, 56, 56, 112, 36, 53, 57, 57, 111, 58, 58, 58, 56, + 56, 56, 110, 109, 76, 58, 58, 58, 58, 58, 58, 76, 88, 88, 108, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 27, 107, 27, 27, 27, 29, + 106, 29, 29, 29, 38, 38, 38, 39, 39, 60, 60, 61, 61, 61, 105, + 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, + 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 75, 74, 73, 72, + 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 40, 28, 55, 54, 50, + 49, 46, 43, 42, 41, 40, 37, 32, 28, 116, 3, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116}; static const flex_int16_t yy_chk[212] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 11, 11, 11, 11, 12, 19, 11, 113, 21, - 35, 35, 12, 19, 11, 21, 59, 59, 24, 112, 11, 109, 24, 33, 33, 33, 107, 11, 24, - 34, 34, 106, 34, 34, 34, 56, 56, 56, 105, 104, 56, 57, 57, 57, 58, 58, 58, 56, - 76, 76, 103, 76, 76, 76, 88, 88, 88, 89, 89, 89, 117, 102, 117, 117, 117, 118, - 101, 118, 118, 118, 119, 119, 119, 120, 120, 121, 121, 122, 122, 122, 100, 99, - 97, 96, 95, 94, 91, 86, 85, 84, 83, 82, 81, 80, 79, 77, 74, 73, 71, 70, 69, - 68, 66, 65, 64, 63, 62, 55, 54, 53, 52, 51, 50, 48, 47, 46, 45, 44, 43, 42, - 41, 40, 27, 26, 25, 23, 22, 20, 18, 17, 16, 15, 13, 10, 7, 3, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116 -}; + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 11, 11, 11, 11, 12, + 19, 11, 113, 21, 35, 35, 12, 19, 11, 21, 59, 59, 24, 112, 11, + 109, 24, 33, 33, 33, 107, 11, 24, 34, 34, 106, 34, 34, 34, 56, + 56, 56, 105, 104, 56, 57, 57, 57, 58, 58, 58, 56, 76, 76, 103, + 76, 76, 76, 88, 88, 88, 89, 89, 89, 117, 102, 117, 117, 117, 118, + 101, 118, 118, 118, 119, 119, 119, 120, 120, 121, 121, 122, 122, 122, 100, + 99, 97, 96, 95, 94, 91, 86, 85, 84, 83, 82, 81, 80, 79, 77, + 74, 73, 71, 70, 69, 68, 66, 65, 64, 63, 62, 55, 54, 53, 52, + 51, 50, 48, 47, 46, 45, 44, 43, 42, 41, 40, 27, 26, 25, 23, + 22, 20, 18, 17, 16, 15, 13, 10, 7, 3, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116}; /* Table of booleans, true if rule could match eol. */ static const flex_int32_t yy_rule_can_match_eol[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, }; /* The intent behind this definition is that it'll catch @@ -856,10 +861,10 @@ static int input(yyscan_t yyscanner); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO \ - do { \ - if (fwrite(yytext, (size_t) yyleng, 1, yyout)) { \ - } \ +#define ECHO \ + do { \ + if (fwrite(yytext, (size_t)yyleng, 1, yyout)) { \ + } \ } while (0) #endif @@ -867,28 +872,27 @@ static int input(yyscan_t yyscanner); * is returned in "result". */ #ifndef YY_INPUT -#define YY_INPUT(buf, result, max_size) \ - if (YY_CURRENT_BUFFER_LVALUE->yy_is_interactive) { \ - int c = '*'; \ - int n; \ - for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n) \ - buf[n] = (char) c; \ - if (c == '\n') \ - buf[n++] = (char) c; \ - if (c == EOF && ferror(yyin)) \ - YY_FATAL_ERROR("input in flex scanner failed"); \ - result = n; \ - } else { \ - errno = 0; \ - while ((result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && \ - ferror(yyin)) { \ - if (errno != EINTR) { \ - YY_FATAL_ERROR("input in flex scanner failed"); \ - break; \ - } \ - errno = 0; \ - clearerr(yyin); \ - } \ +#define YY_INPUT(buf, result, max_size) \ + if (YY_CURRENT_BUFFER_LVALUE->yy_is_interactive) { \ + int c = '*'; \ + int n; \ + for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n) \ + buf[n] = (char)c; \ + if (c == '\n') buf[n++] = (char)c; \ + if (c == EOF && ferror(yyin)) \ + YY_FATAL_ERROR("input in flex scanner failed"); \ + result = n; \ + } else { \ + errno = 0; \ + while ((result = (int)fread(buf, 1, (yy_size_t)max_size, yyin)) == 0 && \ + ferror(yyin)) { \ + if (errno != EINTR) { \ + YY_FATAL_ERROR("input in flex scanner failed"); \ + break; \ + } \ + errno = 0; \ + clearerr(yyin); \ + } \ } #endif @@ -921,7 +925,7 @@ static int input(yyscan_t yyscanner); extern int yylex(YYSTYPE *yylval_param, yyscan_t yyscanner); -#define YY_DECL int yylex(YYSTYPE * yylval_param, yyscan_t yyscanner) +#define YY_DECL int yylex(YYSTYPE *yylval_param, yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng @@ -955,14 +959,11 @@ YY_DECL { YY_USER_INIT; #endif - if (!yyg->yy_start) - yyg->yy_start = 1; /* first start state */ + if (!yyg->yy_start) yyg->yy_start = 1; /* first start state */ - if (!yyin) - yyin = stdin; + if (!yyin) yyin = stdin; - if (!yyout) - yyout = stdout; + if (!yyout) yyout = stdout; if (!YY_CURRENT_BUFFER) { yyensure_buffer_stack(yyscanner); @@ -978,7 +979,7 @@ YY_DECL { #line 1049 "./ortools/flatzinc/parser.yy.cc" while (/*CONSTCOND*/ 1) /* loops until end-of-file is reached */ - { + { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ @@ -998,9 +999,8 @@ YY_DECL { yyg->yy_last_accepting_cpos = yy_cp; } while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) { - yy_current_state = (int) yy_def[yy_current_state]; - if (yy_current_state >= 117) - yy_c = yy_meta[yy_c]; + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 117) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; @@ -1019,8 +1019,7 @@ YY_DECL { if (yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act]) { int yyl; for (yyl = 0; yyl < yyleng; ++yyl) - if (yytext[yyl] == '\n') - do { + if (yytext[yyl] == '\n') do { yylineno++; yycolumn = 0; } while (0); @@ -1029,292 +1028,292 @@ YY_DECL { do_action: /* This label is used only to access EOF actions. */ switch (yy_act) { /* beginning of action switch */ - case 0: /* must back up */ + case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yyg->yy_hold_char; - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - goto yy_find_action; + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; - case 1: - YY_RULE_SETUP + case 1: + YY_RULE_SETUP #line 27 "./ortools/flatzinc/parser.lex" - { - return ARRAY; - } - YY_BREAK case 2 : YY_RULE_SETUP + { + return ARRAY; + } + YY_BREAK case 2 : YY_RULE_SETUP #line 28 "./ortools/flatzinc/parser.lex" - { - return TOKEN_BOOL; - } - YY_BREAK case 3 : YY_RULE_SETUP + { + return TOKEN_BOOL; + } + YY_BREAK case 3 : YY_RULE_SETUP #line 29 "./ortools/flatzinc/parser.lex" - { - return CONSTRAINT; - } - YY_BREAK case 4 : YY_RULE_SETUP + { + return CONSTRAINT; + } + YY_BREAK case 4 : YY_RULE_SETUP #line 30 "./ortools/flatzinc/parser.lex" - { - return TOKEN_FLOAT; - } - YY_BREAK case 5 : YY_RULE_SETUP + { + return TOKEN_FLOAT; + } + YY_BREAK case 5 : YY_RULE_SETUP #line 31 "./ortools/flatzinc/parser.lex" - { - return TOKEN_INT; - } - YY_BREAK case 6 : YY_RULE_SETUP + { + return TOKEN_INT; + } + YY_BREAK case 6 : YY_RULE_SETUP #line 32 "./ortools/flatzinc/parser.lex" - { - return MAXIMIZE; - } - YY_BREAK case 7 : YY_RULE_SETUP + { + return MAXIMIZE; + } + YY_BREAK case 7 : YY_RULE_SETUP #line 33 "./ortools/flatzinc/parser.lex" - { - return MINIMIZE; - } - YY_BREAK case 8 : YY_RULE_SETUP + { + return MINIMIZE; + } + YY_BREAK case 8 : YY_RULE_SETUP #line 34 "./ortools/flatzinc/parser.lex" - { - return OF; - } - YY_BREAK case 9 : YY_RULE_SETUP + { + return OF; + } + YY_BREAK case 9 : YY_RULE_SETUP #line 35 "./ortools/flatzinc/parser.lex" - { - return PREDICATE; - } - YY_BREAK case 10 : YY_RULE_SETUP + { + return PREDICATE; + } + YY_BREAK case 10 : YY_RULE_SETUP #line 36 "./ortools/flatzinc/parser.lex" - { - return SATISFY; - } - YY_BREAK case 11 : YY_RULE_SETUP + { + return SATISFY; + } + YY_BREAK case 11 : YY_RULE_SETUP #line 37 "./ortools/flatzinc/parser.lex" - { - return SET; - } - YY_BREAK case 12 : YY_RULE_SETUP + { + return SET; + } + YY_BREAK case 12 : YY_RULE_SETUP #line 38 "./ortools/flatzinc/parser.lex" - { - return SOLVE; - } - YY_BREAK case 13 : YY_RULE_SETUP + { + return SOLVE; + } + YY_BREAK case 13 : YY_RULE_SETUP #line 39 "./ortools/flatzinc/parser.lex" - { - return VAR; - } - YY_BREAK case 14 : YY_RULE_SETUP + { + return VAR; + } + YY_BREAK case 14 : YY_RULE_SETUP #line 40 "./ortools/flatzinc/parser.lex" - { - return DOTDOT; - } - YY_BREAK case 15 : YY_RULE_SETUP + { + return DOTDOT; + } + YY_BREAK case 15 : YY_RULE_SETUP #line 41 "./ortools/flatzinc/parser.lex" - { - return COLONCOLON; - } - YY_BREAK case 16 : YY_RULE_SETUP + { + return COLONCOLON; + } + YY_BREAK case 16 : YY_RULE_SETUP #line 43 "./ortools/flatzinc/parser.lex" - { - yylval->integer_value = 1; - return IVALUE; - } - YY_BREAK case 17 : YY_RULE_SETUP + { + yylval->integer_value = 1; + return IVALUE; + } + YY_BREAK case 17 : YY_RULE_SETUP #line 47 "./ortools/flatzinc/parser.lex" - { - yylval->integer_value = 0; - return IVALUE; - } - YY_BREAK case 18 : YY_RULE_SETUP + { + yylval->integer_value = 0; + return IVALUE; + } + YY_BREAK case 18 : YY_RULE_SETUP #line 51 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); - return IVALUE; - } - YY_BREAK case 19 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); + return IVALUE; + } + YY_BREAK case 19 : YY_RULE_SETUP #line 55 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); - return IVALUE; - } - YY_BREAK case 20 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); + return IVALUE; + } + YY_BREAK case 20 : YY_RULE_SETUP #line 59 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); - return IVALUE; - } - YY_BREAK case 21 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtoi(yytext, &yylval->integer_value)); + return IVALUE; + } + YY_BREAK case 21 : YY_RULE_SETUP #line 63 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); - return DVALUE; - } - YY_BREAK case 22 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); + return DVALUE; + } + YY_BREAK case 22 : YY_RULE_SETUP #line 67 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); - return DVALUE; - } - YY_BREAK case 23 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); + return DVALUE; + } + YY_BREAK case 23 : YY_RULE_SETUP #line 71 "./ortools/flatzinc/parser.lex" - { - CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); - return DVALUE; - } - YY_BREAK case 24 : YY_RULE_SETUP + { + CHECK(absl::SimpleAtod(yytext, &yylval->double_value)); + return DVALUE; + } + YY_BREAK case 24 : YY_RULE_SETUP #line 76 "./ortools/flatzinc/parser.lex" - { - yylval->string_value = yytext; - return IDENTIFIER; - } - YY_BREAK case 25 : YY_RULE_SETUP + { + yylval->string_value = yytext; + return IDENTIFIER; + } + YY_BREAK case 25 : YY_RULE_SETUP #line 80 "./ortools/flatzinc/parser.lex" - { - yylval->string_value = yytext; - return IDENTIFIER; - } - YY_BREAK case 26 : YY_RULE_SETUP + { + yylval->string_value = yytext; + return IDENTIFIER; + } + YY_BREAK case 26 : YY_RULE_SETUP #line 84 "./ortools/flatzinc/parser.lex" - { - yylval->string_value = yytext; - return SVALUE; - } - YY_BREAK case 27 : /* rule 27 can match eol */ - YY_RULE_SETUP + { + yylval->string_value = yytext; + return SVALUE; + } + YY_BREAK case 27 : /* rule 27 can match eol */ + YY_RULE_SETUP #line 85 "./ortools/flatzinc/parser.lex" - ; - YY_BREAK case 28 : YY_RULE_SETUP + ; + YY_BREAK case 28 : YY_RULE_SETUP #line 86 "./ortools/flatzinc/parser.lex" - ; - YY_BREAK case 29 : YY_RULE_SETUP + ; + YY_BREAK case 29 : YY_RULE_SETUP #line 87 "./ortools/flatzinc/parser.lex" - ; - YY_BREAK case 30 : YY_RULE_SETUP + ; + YY_BREAK case 30 : YY_RULE_SETUP #line 88 "./ortools/flatzinc/parser.lex" - { - return yytext[0]; - } - YY_BREAK case 31 : YY_RULE_SETUP + { + return yytext[0]; + } + YY_BREAK case 31 : YY_RULE_SETUP #line 89 "./ortools/flatzinc/parser.lex" - ECHO; - YY_BREAK + ECHO; + YY_BREAK #line 1305 "./ortools/flatzinc/parser.yy.cc" - case YY_STATE_EOF(INITIAL) - : yyterminate(); + case YY_STATE_EOF(INITIAL): + yyterminate(); - case YY_END_OF_BUFFER: { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int)(yy_cp - yyg->yytext_ptr) - 1; + case YY_END_OF_BUFFER: { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int)(yy_cp - yyg->yytext_ptr) - 1; - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET if (YY_CURRENT_BUFFER_LVALUE - ->yy_buffer_status == YY_BUFFER_NEW) { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if (yyg->yy_c_buf_p <= - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]) { - /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(yyscanner); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans(yy_current_state, yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if (yy_next_state) { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } else { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } - } else - switch (yy_get_next_buffer(yyscanner)) { - case EOB_ACT_END_OF_FILE: { - yyg->yy_did_buffer_switch_on_eof = 0; - - if (yywrap(yyscanner)) { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } else { - if (!yyg->yy_did_buffer_switch_on_eof) - YY_NEW_FILE; - } - break; + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET if (YY_CURRENT_BUFFER_LVALUE + ->yy_buffer_status == + YY_BUFFER_NEW) { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } - case EOB_ACT_CONTINUE_SCAN: + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if (yyg->yy_c_buf_p <= + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]) { + /* This was really a NUL. */ + yy_state_type yy_next_state; + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(yyscanner); - yy_cp = yyg->yy_c_buf_p; + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans(yy_current_state, yyscanner); + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + if (yy_next_state) { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } else { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } else + switch (yy_get_next_buffer(yyscanner)) { + case EOB_ACT_END_OF_FILE: { + yyg->yy_did_buffer_switch_on_eof = 0; - yy_current_state = yy_get_previous_state(yyscanner); + if (yywrap(yyscanner)) { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } else { + if (!yyg->yy_did_buffer_switch_on_eof) YY_NEW_FILE; + } + break; + } - default: - YY_FATAL_ERROR("fatal flex scanner internal error--no action found"); + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(yyscanner); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state(yyscanner); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR("fatal flex scanner internal error--no action found"); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ -} /* end of yylex */ +} /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * @@ -1354,8 +1353,7 @@ static int yy_get_next_buffer(yyscan_t yyscanner) { /* First move last chars to start of buffer. */ number_to_move = (int)(yyg->yy_c_buf_p - yyg->yytext_ptr - 1); - for (i = 0; i < number_to_move; ++i) - *(dest++) = *(source++); + for (i = 0; i < number_to_move; ++i) *(dest++) = *(source++); if (YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING) /* don't do the read, it's not guaranteed to return an EOF, @@ -1397,8 +1395,7 @@ static int yy_get_next_buffer(yyscan_t yyscanner) { num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } - if (num_to_read > YY_READ_BUF_SIZE) - num_to_read = YY_READ_BUF_SIZE; + if (num_to_read > YY_READ_BUF_SIZE) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT((&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), @@ -1424,7 +1421,7 @@ static int yy_get_next_buffer(yyscan_t yyscanner) { int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *)yyrealloc((void *)YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, - (yy_size_t) new_size, yyscanner); + (yy_size_t)new_size, yyscanner); if (!YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) YY_FATAL_ERROR("out of dynamic memory in yy_get_next_buffer()"); /* "- 2" to take care of EOB's */ @@ -1458,9 +1455,8 @@ static yy_state_type yy_get_previous_state(yyscan_t yyscanner) { yyg->yy_last_accepting_cpos = yy_cp; } while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) { - yy_current_state = (int) yy_def[yy_current_state]; - if (yy_current_state >= 117) - yy_c = yy_meta[yy_c]; + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 117) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } @@ -1477,7 +1473,7 @@ static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state, yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - /* This var may be unused depending upon options. */ + /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; @@ -1486,14 +1482,13 @@ static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state, yyg->yy_last_accepting_cpos = yy_cp; } while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) { - yy_current_state = (int) yy_def[yy_current_state]; - if (yy_current_state >= 117) - yy_c = yy_meta[yy_c]; + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 117) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 116); - (void) yyg; + (void)yyg; return yy_is_jam ? 0 : yy_current_state; } @@ -1513,22 +1508,21 @@ static void yyunput(int c, char *yy_bp, yyscan_t yyscanner) { /* +2 for EOB chars. */ int number_to_move = yyg->yy_n_chars + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE - ->yy_ch_buf[YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + ->yy_ch_buf[YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - while (source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) - *--dest = *--source; + while (source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) *--dest = *--source; yy_cp += (int)(dest - source); yy_bp += (int)(dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = - (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + (int)YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if (yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2) YY_FATAL_ERROR("flex scanner push-back overflow"); } - *--yy_cp = (char) c; + *--yy_cp = (char)c; if (c == '\n') { --yylineno; @@ -1545,9 +1539,9 @@ static void yyunput(int c, char *yy_bp, yyscan_t yyscanner) { #ifdef __cplusplus static int yyinput(yyscan_t yyscanner) #else - static int input(yyscan_t yyscanner) +static int input(yyscan_t yyscanner) #endif - { +{ int c; struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; @@ -1567,38 +1561,36 @@ static int yyinput(yyscan_t yyscanner) ++yyg->yy_c_buf_p; switch (yy_get_next_buffer(yyscanner)) { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ - /* Reset buffer status. */ - yyrestart(yyin, yyscanner); + /* Reset buffer status. */ + yyrestart(yyin, yyscanner); - /*FALLTHROUGH*/ + /*FALLTHROUGH*/ - case EOB_ACT_END_OF_FILE: { - if (yywrap(yyscanner)) - return 0; + case EOB_ACT_END_OF_FILE: { + if (yywrap(yyscanner)) return 0; - if (!yyg->yy_did_buffer_switch_on_eof) - YY_NEW_FILE; + if (!yyg->yy_did_buffer_switch_on_eof) YY_NEW_FILE; #ifdef __cplusplus - return yyinput(yyscanner); + return yyinput(yyscanner); #else - return input(yyscanner); + return input(yyscanner); #endif - } + } - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; } } } @@ -1607,8 +1599,7 @@ static int yyinput(yyscan_t yyscanner) *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; - if (c == '\n') - do { + if (c == '\n') do { yylineno++; yycolumn = 0; } while (0); @@ -1647,8 +1638,7 @@ void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) { * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack(yyscanner); - if (YY_CURRENT_BUFFER == new_buffer) - return; + if (YY_CURRENT_BUFFER == new_buffer) return; if (YY_CURRENT_BUFFER) { /* Flush out information for old buffer. */ @@ -1686,9 +1676,8 @@ static void yy_load_buffer_state(yyscan_t yyscanner) { YY_BUFFER_STATE yy_create_buffer(FILE *file, int size, yyscan_t yyscanner) { YY_BUFFER_STATE b; - b = (YY_BUFFER_STATE) yyalloc(sizeof(struct yy_buffer_state), yyscanner); - if (!b) - YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()"); + b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state), yyscanner); + if (!b) YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()"); b->yy_buf_size = size; @@ -1713,14 +1702,12 @@ YY_BUFFER_STATE yy_create_buffer(FILE *file, int size, yyscan_t yyscanner) { void yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (!b) - return; + if (!b) return; if (b == YY_CURRENT_BUFFER) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE)0; - if (b->yy_is_our_buffer) - yyfree((void *)b->yy_ch_buf, yyscanner); + if (b->yy_is_our_buffer) yyfree((void *)b->yy_ch_buf, yyscanner); yyfree((void *)b, yyscanner); } @@ -1758,8 +1745,7 @@ static void yy_init_buffer(YY_BUFFER_STATE b, FILE *file, yyscan_t yyscanner) { */ void yy_flush_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (!b) - return; + if (!b) return; b->yy_n_chars = 0; @@ -1775,8 +1761,7 @@ void yy_flush_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) { b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; - if (b == YY_CURRENT_BUFFER) - yy_load_buffer_state(yyscanner); + if (b == YY_CURRENT_BUFFER) yy_load_buffer_state(yyscanner); } /** Pushes the new state onto the stack. The new state becomes @@ -1787,8 +1772,7 @@ void yy_flush_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) { */ void yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (new_buffer == NULL) - return; + if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); @@ -1801,8 +1785,7 @@ void yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) { } /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; + if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ @@ -1816,13 +1799,11 @@ void yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) { */ void yypop_buffer_state(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (!YY_CURRENT_BUFFER) - return; + if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; + if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state(yyscanner); @@ -1889,9 +1870,8 @@ YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner) { /* They forgot to leave room for the EOB's. */ return NULL; - b = (YY_BUFFER_STATE) yyalloc(sizeof(struct yy_buffer_state), yyscanner); - if (!b) - YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()"); + b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state), yyscanner); + if (!b) YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()"); b->yy_buf_size = (int)(size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; @@ -1917,7 +1897,7 @@ YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner) { * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string(const char *yystr, yyscan_t yyscanner) { - return yy_scan_bytes(yystr, (int) strlen(yystr), yyscanner); + return yy_scan_bytes(yystr, (int)strlen(yystr), yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to @@ -1937,17 +1917,14 @@ YY_BUFFER_STATE yy_scan_bytes(const char *yybytes, int _yybytes_len, /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t)(_yybytes_len + 2); buf = (char *)yyalloc(n, yyscanner); - if (!buf) - YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()"); + if (!buf) YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()"); - for (i = 0; i < _yybytes_len; ++i) - buf[i] = yybytes[i]; + for (i = 0; i < _yybytes_len; ++i) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len + 1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf, n, yyscanner); - if (!b) - YY_FATAL_ERROR("bad buffer in yy_scan_bytes()"); + if (!b) YY_FATAL_ERROR("bad buffer in yy_scan_bytes()"); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. @@ -1963,7 +1940,7 @@ YY_BUFFER_STATE yy_scan_bytes(const char *yybytes, int _yybytes_len, static void yynoreturn yy_fatal_error(const char *msg, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - (void) yyg; + (void)yyg; fprintf(stderr, "%s\n", msg); exit(YY_EXIT_FAILURE); } @@ -1971,16 +1948,16 @@ static void yynoreturn yy_fatal_error(const char *msg, yyscan_t yyscanner) { /* Redefine yyless() so it works in section 3 code. */ #undef yyless -#define yyless(n) \ - do { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg); \ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ +#define yyless(n) \ + do { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg); \ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ } while (0) /* Accessor methods (get/set functions) to struct members. */ @@ -1999,8 +1976,7 @@ YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner) { int yyget_lineno(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (!YY_CURRENT_BUFFER) - return 0; + if (!YY_CURRENT_BUFFER) return 0; return yylineno; } @@ -2011,8 +1987,7 @@ int yyget_lineno(yyscan_t yyscanner) { int yyget_column(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - if (!YY_CURRENT_BUFFER) - return 0; + if (!YY_CURRENT_BUFFER) return 0; return yycolumn; } @@ -2067,8 +2042,7 @@ void yyset_lineno(int _line_number, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; /* lineno is only valid if an input buffer exists. */ - if (!YY_CURRENT_BUFFER) - YY_FATAL_ERROR("yyset_lineno called with no buffer"); + if (!YY_CURRENT_BUFFER) YY_FATAL_ERROR("yyset_lineno called with no buffer"); yylineno = _line_number; } @@ -2081,8 +2055,7 @@ void yyset_column(int _column_no, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; /* column is only valid if an input buffer exists. */ - if (!YY_CURRENT_BUFFER) - YY_FATAL_ERROR("yyset_column called with no buffer"); + if (!YY_CURRENT_BUFFER) YY_FATAL_ERROR("yyset_column called with no buffer"); yycolumn = _column_no; } @@ -2138,7 +2111,7 @@ int yylex_init(yyscan_t *ptr_yy_globals) { return 1; } - *ptr_yy_globals = (yyscan_t) yyalloc(sizeof(struct yyguts_t), NULL); + *ptr_yy_globals = (yyscan_t)yyalloc(sizeof(struct yyguts_t), NULL); if (*ptr_yy_globals == NULL) { errno = ENOMEM; @@ -2169,7 +2142,7 @@ int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined, yyscan_t *ptr_yy_globals) { return 1; } - *ptr_yy_globals = (yyscan_t) yyalloc(sizeof(struct yyguts_t), &dummy_yyguts); + *ptr_yy_globals = (yyscan_t)yyalloc(sizeof(struct yyguts_t), &dummy_yyguts); if (*ptr_yy_globals == NULL) { errno = ENOMEM; @@ -2254,11 +2227,10 @@ int yylex_destroy(yyscan_t yyscanner) { static void yy_flex_strncpy(char *s1, const char *s2, int n, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - (void) yyg; + (void)yyg; int i; - for (i = 0; i < n; ++i) - s1[i] = s2[i]; + for (i = 0; i < n; ++i) s1[i] = s2[i]; } #endif @@ -2274,13 +2246,13 @@ static int yy_flex_strlen(const char *s, yyscan_t yyscanner) { void *yyalloc(yy_size_t size, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - (void) yyg; + (void)yyg; return malloc(size); } void *yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - (void) yyg; + (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those @@ -2294,7 +2266,7 @@ void *yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) { void yyfree(void *ptr, yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; - (void) yyg; + (void)yyg; free((char *)ptr); /* see yyrealloc() for (char *) cast */ } diff --git a/ortools/flatzinc/parser_main.cc b/ortools/flatzinc/parser_main.cc index 954b5a1c73..2744a407f7 100644 --- a/ortools/flatzinc/parser_main.cc +++ b/ortools/flatzinc/parser_main.cc @@ -67,8 +67,8 @@ void ParseFile(const std::string &filename, bool presolve) { FZLOG << model.DebugString() << FZENDL; } } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research int main(int argc, char **argv) { const char kUsage[] = diff --git a/ortools/flatzinc/parser_util.cc b/ortools/flatzinc/parser_util.cc index b12cda74c7..37fa67d02c 100644 --- a/ortools/flatzinc/parser_util.cc +++ b/ortools/flatzinc/parser_util.cc @@ -71,11 +71,12 @@ int64 ConvertAsIntegerOrDie(double d) { // Array in flatzinc are 1 based. We use this trivial wrapper for all flatzinc // arrays. -template const T &Lookup(const std::vector &v, int index) { +template +const T &Lookup(const std::vector &v, int index) { // TODO(user): replace this by a macro for better logging. CHECK_GE(index, 1); CHECK_LE(index, v.size()); return v[index - 1]; } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research diff --git a/ortools/flatzinc/parser_util.h b/ortools/flatzinc/parser_util.h index f9a5a06e14..399c726ecc 100644 --- a/ortools/flatzinc/parser_util.h +++ b/ortools/flatzinc/parser_util.h @@ -102,6 +102,6 @@ struct LexerInfo { // If the argument is an integer, return it as int64. Otherwise, die. int64 ConvertAsIntegerOrDie(double d); -} // namespace fz -} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_PARSER_UTIL_H_ +} // namespace fz +} // namespace operations_research +#endif // OR_TOOLS_FLATZINC_PARSER_UTIL_H_ diff --git a/ortools/flatzinc/presolve.cc b/ortools/flatzinc/presolve.cc index 3273996059..a2b7364b38 100644 --- a/ortools/flatzinc/presolve.cc +++ b/ortools/flatzinc/presolve.cc @@ -33,11 +33,7 @@ DEFINE_bool(fz_floats_are_ints, true, namespace operations_research { namespace fz { namespace { -enum PresolveState { - ALWAYS_FALSE, - ALWAYS_TRUE, - UNDECIDED -}; +enum PresolveState { ALWAYS_FALSE, ALWAYS_TRUE, UNDECIDED }; // TODO(user): accept variables fixed to 0 or 1. bool Has01Values(IntegerVariable *var) { @@ -46,7 +42,8 @@ bool Has01Values(IntegerVariable *var) { bool Is0Or1(int64 value) { return !(value & ~1LL); } -template bool IsArrayBoolean(const std::vector &values) { +template +bool IsArrayBoolean(const std::vector &values) { for (int i = 0; i < values.size(); ++i) { if (values[i] != 0 && values[i] != 1) { return false; @@ -55,7 +52,8 @@ template bool IsArrayBoolean(const std::vector &values) { return true; } -template bool AtMostOne0OrAtMostOne1(const std::vector &values) { +template +bool AtMostOne0OrAtMostOne1(const std::vector &values) { CHECK(IsArrayBoolean(values)); int num_zero = 0; int num_one = 0; @@ -104,37 +102,43 @@ bool OverlapsAt(const Argument &array, int pos, const Argument &other) { return true; } switch (other.type) { - case Argument::INT_VALUE: { return domain.Contains(other.Value()); } - case Argument::INT_INTERVAL: { - return domain.OverlapsIntInterval(other.values[0], other.values[1]); - } - case Argument::INT_LIST: { return domain.OverlapsIntList(other.values); } - case Argument::INT_VAR_REF: { - return domain.OverlapsDomain(other.variables[0]->domain); - } - default: { - LOG(FATAL) << "Case not supported in OverlapsAt"; - return false; - } + case Argument::INT_VALUE: { + return domain.Contains(other.Value()); + } + case Argument::INT_INTERVAL: { + return domain.OverlapsIntInterval(other.values[0], other.values[1]); + } + case Argument::INT_LIST: { + return domain.OverlapsIntList(other.values); + } + case Argument::INT_VAR_REF: { + return domain.OverlapsDomain(other.variables[0]->domain); + } + default: { + LOG(FATAL) << "Case not supported in OverlapsAt"; + return false; + } } } else if (array.type == Argument::INT_LIST) { const int64 value = array.values[pos]; switch (other.type) { - case Argument::INT_VALUE: { return value == other.values[0]; } - case Argument::INT_INTERVAL: { - return other.values[0] <= value && value <= other.values[1]; - } - case Argument::INT_LIST: { - return std::find(other.values.begin(), other.values.end(), value) != - other.values.end(); - } - case Argument::INT_VAR_REF: { - return other.variables[0]->domain.Contains(value); - } - default: { - LOG(FATAL) << "Case not supported in OverlapsAt"; - return false; - } + case Argument::INT_VALUE: { + return value == other.values[0]; + } + case Argument::INT_INTERVAL: { + return other.values[0] <= value && value <= other.values[1]; + } + case Argument::INT_LIST: { + return std::find(other.values.begin(), other.values.end(), value) != + other.values.end(); + } + case Argument::INT_VAR_REF: { + return other.variables[0]->domain.Contains(value); + } + default: { + LOG(FATAL) << "Case not supported in OverlapsAt"; + return false; + } } } else { LOG(FATAL) << "First argument not supported in OverlapsAt"; @@ -151,7 +155,7 @@ void AppendIfNotInSet(T *value, absl::flat_hash_set *s, DCHECK_EQ(s->size(), vec->size()); } -} // namespace +} // namespace // Note on documentation // @@ -272,7 +276,7 @@ bool IsStrictPrefix(const std::vector &v1, const std::vector &v2) { } return true; } -} // namespace +} // namespace // Rewrite array element: array_int_element: // @@ -293,8 +297,7 @@ bool IsStrictPrefix(const std::vector &v1, const std::vector &v2) { // Input : array_int_element(x, [c1, .., cn], y) with x0 ci = c0 + i // Output: int_lin_eq([-1, 1], [y, x], 1 - c) (e.g. y = x + c - 1) void Presolver::PresolveSimplifyElement(Constraint *ct) { - if (ct->arguments[0].variables.size() != 1) - return; + if (ct->arguments[0].variables.size() != 1) return; IntegerVariable *const index_var = ct->arguments[0].Var(); // Rule 1. @@ -337,8 +340,8 @@ void Presolver::PresolveSimplifyElement(Constraint *ct) { // Rewrite constraint. UpdateRuleStats("array_int_element: simplify using affine mapping."); ct->arguments[0].variables[0] = mapping.variable; - ct->arguments[0].variables[0]->domain - .IntersectWithInterval(1, new_values.size()); + ct->arguments[0].variables[0]->domain.IntersectWithInterval( + 1, new_values.size()); // TODO(user): Encapsulate argument setters. ct->arguments[1].values.swap(new_values); if (ct->arguments[1].values.size() == 1) { @@ -357,10 +360,9 @@ void Presolver::PresolveSimplifyElement(Constraint *ct) { if (gtl::ContainsKey(array2d_index_map_, index_var)) { UpdateRuleStats("array_int_element: rewrite as a 2d element"); const Array2DIndexMapping &mapping = array2d_index_map_[index_var]; - // Rewrite constraint. - ct->arguments[0] = Argument::IntVarRefArray({ - mapping.variable1, mapping.variable2 - }); + // Rewrite constraint. + ct->arguments[0] = + Argument::IntVarRefArray({mapping.variable1, mapping.variable2}); std::vector coefs; coefs.push_back(mapping.coefficient); coefs.push_back(1); @@ -393,12 +395,8 @@ void Presolver::PresolveSimplifyElement(Constraint *ct) { } else { // Rewrite constraint into a int_lin_eq ct->type = "int_lin_eq"; - ct->arguments[0] = Argument::IntegerList({ - -1, 1 - }); - ct->arguments[1] = Argument::IntVarRefArray({ - target, index - }); + ct->arguments[0] = Argument::IntegerList({-1, 1}); + ct->arguments[1] = Argument::IntVarRefArray({target, index}); ct->arguments[2] = Argument::IntegerValue(1 - start); } } @@ -409,8 +407,7 @@ void Presolver::PresolveSimplifyElement(Constraint *ct) { // Input : array_var_int_element(x0, [x1, .., xn], y) with x0 = a * x + b // Output: array_var_int_element(x, [x_a1, .., x_an], b) with a * i = b = ai void Presolver::PresolveSimplifyExprElement(Constraint *ct) { - if (ct->arguments[0].variables.size() != 1) - return; + if (ct->arguments[0].variables.size() != 1) return; IntegerVariable *const index_var = ct->arguments[0].Var(); if (gtl::ContainsKey(affine_map_, index_var)) { @@ -441,8 +438,9 @@ void Presolver::PresolveSimplifyExprElement(Constraint *ct) { // Mark old index var and affine constraint as presolved out. mapping.constraint->MarkAsInactive(); index_var->active = false; - } else if (index_var->domain.is_interval && index_var->domain.values.size() == - 2 && index_var->domain.Max() < ct->arguments[1].variables.size()) { + } else if (index_var->domain.is_interval && + index_var->domain.values.size() == 2 && + index_var->domain.Max() < ct->arguments[1].variables.size()) { // Reduce array of variables. ct->arguments[1].variables.resize(index_var->domain.Max()); UpdateRuleStats("array_var_int_element: reduce array"); @@ -580,15 +578,13 @@ void Presolver::AddVariableSubstitution(IntegerVariable *from, } IntegerVariable *Presolver::FindRepresentativeOfVar(IntegerVariable *var) { - if (var == nullptr) - return nullptr; + if (var == nullptr) return nullptr; IntegerVariable *start_var = var; // First loop: find the top parent. for (;;) { IntegerVariable *parent = gtl::FindWithDefault(var_representative_map_, var, var); - if (parent == var) - break; + if (parent == var) break; var = parent; } // Second loop: attach all the path to the top parent. @@ -607,18 +603,19 @@ void Presolver::SubstituteEverywhere(Model *model) { for (int i = 0; i < ct->arguments.size(); ++i) { Argument &argument = ct->arguments[i]; switch (argument.type) { - case Argument::INT_VAR_REF: - case Argument::INT_VAR_REF_ARRAY: { - for (int i = 0; i < argument.variables.size(); ++i) { - IntegerVariable *const old_var = argument.variables[i]; - IntegerVariable *const new_var = FindRepresentativeOfVar(old_var); - if (new_var != old_var) { - argument.variables[i] = new_var; + case Argument::INT_VAR_REF: + case Argument::INT_VAR_REF_ARRAY: { + for (int i = 0; i < argument.variables.size(); ++i) { + IntegerVariable *const old_var = argument.variables[i]; + IntegerVariable *const new_var = FindRepresentativeOfVar(old_var); + if (new_var != old_var) { + argument.variables[i] = new_var; + } } + break; + } + default: { } - break; - } - default: {} } } } @@ -643,8 +640,7 @@ void Presolver::SubstituteEverywhere(Model *model) { // Change the objective variable. IntegerVariable *const current_objective = model->objective(); - if (current_objective == nullptr) - return; + if (current_objective == nullptr) return; IntegerVariable *const new_objective = FindRepresentativeOfVar(current_objective); if (new_objective != current_objective) { @@ -655,23 +651,24 @@ void Presolver::SubstituteEverywhere(Model *model) { void Presolver::SubstituteAnnotation(Annotation *ann) { // TODO(user): Remove recursion. switch (ann->type) { - case Annotation::ANNOTATION_LIST: - case Annotation::FUNCTION_CALL: { - for (int i = 0; i < ann->annotations.size(); ++i) { - SubstituteAnnotation(&ann->annotations[i]); + case Annotation::ANNOTATION_LIST: + case Annotation::FUNCTION_CALL: { + for (int i = 0; i < ann->annotations.size(); ++i) { + SubstituteAnnotation(&ann->annotations[i]); + } + break; } - break; - } - case Annotation::INT_VAR_REF: - case Annotation::INT_VAR_REF_ARRAY: { - for (int i = 0; i < ann->variables.size(); ++i) { - ann->variables[i] = FindRepresentativeOfVar(ann->variables[i]); + case Annotation::INT_VAR_REF: + case Annotation::INT_VAR_REF_ARRAY: { + for (int i = 0; i < ann->variables.size(); ++i) { + ann->variables[i] = FindRepresentativeOfVar(ann->variables[i]); + } + break; + } + default: { } - break; - } - default: {} } } -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research diff --git a/ortools/flatzinc/presolve.h b/ortools/flatzinc/presolve.h index 015b501ef7..ed30bfcd07 100644 --- a/ortools/flatzinc/presolve.h +++ b/ortools/flatzinc/presolve.h @@ -32,7 +32,7 @@ namespace fz { // // TODO(user): Error reporting of unfeasible models. class Presolver { -public: + public: // Recursively apply all the pre-solve rules to the model, until exhaustion. // The reduced model will: // - Have some unused variables. @@ -41,7 +41,7 @@ public: // refer to unused variables). void Run(Model *model); -private: + private: // This struct stores the affine mapping of one variable: // it represents new_var = var * coefficient + offset. It also stores the // constraint that defines this mapping. @@ -70,11 +70,17 @@ private: Constraint *constraint; Array2DIndexMapping() - : variable1(nullptr), coefficient(0), variable2(nullptr), offset(0), + : variable1(nullptr), + coefficient(0), + variable2(nullptr), + offset(0), constraint(nullptr) {} Array2DIndexMapping(IntegerVariable *v1, int64 c, IntegerVariable *v2, int64 o, Constraint *ct) - : variable1(v1), coefficient(c), variable2(v2), offset(o), + : variable1(v1), + coefficient(c), + variable2(v2), + offset(o), constraint(ct) {} }; @@ -117,7 +123,7 @@ private: // purposes. std::map successful_rules_; }; -} // namespace fz -} // namespace operations_research +} // namespace fz +} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_PRESOLVE_H_ +#endif // OR_TOOLS_FLATZINC_PRESOLVE_H_ diff --git a/ortools/glop/basis_representation.cc b/ortools/glop/basis_representation.cc index 02dd08d553..46f6cfff27 100644 --- a/ortools/glop/basis_representation.cc +++ b/ortools/glop/basis_representation.cc @@ -28,7 +28,8 @@ const Fractional EtaMatrix::kSparseThreshold = 0.5; EtaMatrix::EtaMatrix(ColIndex eta_col, const ScatteredColumn &direction) : eta_col_(eta_col), - eta_col_coefficient_(direction[ColToRowIndex(eta_col)]), eta_coeff_(), + eta_col_coefficient_(direction[ColToRowIndex(eta_col)]), + eta_coeff_(), sparse_eta_coeff_() { DCHECK_NE(0.0, eta_col_coefficient_); eta_coeff_ = direction.values; @@ -38,8 +39,7 @@ EtaMatrix::EtaMatrix(ColIndex eta_col, const ScatteredColumn &direction) if (direction.non_zeros.size() < kSparseThreshold * eta_coeff_.size().value()) { for (const RowIndex row : direction.non_zeros) { - if (row == ColToRowIndex(eta_col)) - continue; + if (row == ColToRowIndex(eta_col)) continue; sparse_eta_coeff_.SetCoefficient(row, eta_coeff_[row]); } DCHECK(sparse_eta_coeff_.CheckNoDuplicates()); @@ -64,8 +64,7 @@ void EtaMatrix::RightSolve(DenseColumn *d) const { // Nothing to do if 'a' is zero at position eta_row. // This exploits the possible sparsity of the column 'a'. - if ((*d)[ColToRowIndex(eta_col_)] == 0.0) - return; + if ((*d)[ColToRowIndex(eta_col_)] == 0.0) return; if (!sparse_eta_coeff_.IsEmpty()) { RightSolveWithSparseEta(d); } else { @@ -93,8 +92,7 @@ void EtaMatrix::SparseLeftSolve(DenseRow *y, ColIndexVector *pos) const { (*y)[eta_col_] = y_value / eta_col_coefficient_; // We add the new non-zero position if it wasn't already there. - if (!is_eta_col_in_pos) - pos->push_back(eta_col_); + if (!is_eta_col_in_pos) pos->push_back(eta_col_); } void EtaMatrix::LeftSolveWithDenseEta(DenseRow *y) const { @@ -178,9 +176,15 @@ void EtaFactorization::RightSolve(DenseColumn *d) const { // -------------------------------------------------------- BasisFactorization::BasisFactorization( const CompactSparseMatrix *compact_matrix, const RowToColMapping *basis) - : stats_(), compact_matrix_(*compact_matrix), basis_(*basis), - tau_is_computed_(false), max_num_updates_(0), num_updates_(0), - eta_factorization_(), lu_factorization_(), deterministic_time_(0.0) { + : stats_(), + compact_matrix_(*compact_matrix), + basis_(*basis), + tau_is_computed_(false), + max_num_updates_(0), + num_updates_(0), + eta_factorization_(), + lu_factorization_(), + deterministic_time_(0.0) { SetParameters(parameters_); } @@ -202,8 +206,7 @@ void BasisFactorization::Clear() { Status BasisFactorization::Initialize() { SCOPED_TIME_STAT(&stats_); Clear(); - if (IsIdentityBasis()) - return Status::OK(); + if (IsIdentityBasis()) return Status::OK(); CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_); return lu_factorization_.ComputeFactorization(basis_matrix); } @@ -211,8 +214,7 @@ Status BasisFactorization::Initialize() { bool BasisFactorization::IsRefactorized() const { return num_updates_ == 0; } Status BasisFactorization::Refactorize() { - if (IsRefactorized()) - return Status::OK(); + if (IsRefactorized()) return Status::OK(); return ForceRefactorization(); } @@ -238,9 +240,8 @@ Status BasisFactorization::ForceRefactorization() { // (right_update_vector - U.column(leaving_column)).left_update_vector).U // new B = L.RankOneUpdateElementatyMatrix( // right_update_vector - U.column(leaving_column), left_update_vector) -Status -BasisFactorization::MiddleProductFormUpdate(ColIndex entering_col, - RowIndex leaving_variable_row) { +Status BasisFactorization::MiddleProductFormUpdate( + ColIndex entering_col, RowIndex leaving_variable_row) { const ColIndex right_index = right_pool_mapping_[entering_col]; const ColIndex left_index = left_pool_mapping_[RowToColIndex(leaving_variable_row)]; @@ -334,8 +335,8 @@ void BasisFactorization::RightSolve(ScatteredColumn *d) const { } } -const DenseColumn & -BasisFactorization::RightSolveForTau(const ScatteredColumn &a) const { +const DenseColumn &BasisFactorization::RightSolveForTau( + const ScatteredColumn &a) const { SCOPED_TIME_STAT(&stats_); BumpDeterministicTimeForSolve(compact_matrix_.num_rows().value()); if (use_middle_product_form_update_) { @@ -429,8 +430,8 @@ void BasisFactorization::RightSolveForProblemColumn(ColIndex col, ScatteredColumn *d) const { SCOPED_TIME_STAT(&stats_); RETURN_IF_NULL(d); - BumpDeterministicTimeForSolve(compact_matrix_.column(col) - .num_entries().value()); + BumpDeterministicTimeForSolve( + compact_matrix_.column(col).num_entries().value()); ClearAndResizeVectorWithNonZeros(compact_matrix_.num_rows(), d); if (!use_middle_product_form_update_) { @@ -463,8 +464,8 @@ void BasisFactorization::RightSolveForProblemColumn(ColIndex col, d->SortNonZerosIfNeeded(); } -Fractional -BasisFactorization::RightSolveSquaredNorm(const ColumnView &a) const { +Fractional BasisFactorization::RightSolveSquaredNorm( + const ColumnView &a) const { SCOPED_TIME_STAT(&stats_); DCHECK(IsRefactorized()); BumpDeterministicTimeForSolve(a.num_entries().value()); @@ -482,26 +483,22 @@ bool BasisFactorization::IsIdentityBasis() const { const RowIndex num_rows = compact_matrix_.num_rows(); for (RowIndex row(0); row < num_rows; ++row) { const ColIndex col = basis_[row]; - if (compact_matrix_.column(col).num_entries().value() != 1) - return false; + if (compact_matrix_.column(col).num_entries().value() != 1) return false; const Fractional coeff = compact_matrix_.column(col).GetFirstCoefficient(); const RowIndex entry_row = compact_matrix_.column(col).GetFirstRow(); - if (entry_row != row || coeff != 1.0) - return false; + if (entry_row != row || coeff != 1.0) return false; } return true; } Fractional BasisFactorization::ComputeOneNorm() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_); return basis_matrix.ComputeOneNorm(); } Fractional BasisFactorization::ComputeInfinityNorm() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_); return basis_matrix.ComputeInfinityNorm(); } @@ -510,8 +507,7 @@ Fractional BasisFactorization::ComputeInfinityNorm() const { // with that of MatrixView. Maybe use a wrapper class for InverseMatrix. Fractional BasisFactorization::ComputeInverseOneNorm() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; const RowIndex num_rows = compact_matrix_.num_rows(); const ColIndex num_cols = RowToColIndex(num_rows); Fractional norm = 0.0; @@ -533,8 +529,7 @@ Fractional BasisFactorization::ComputeInverseOneNorm() const { } Fractional BasisFactorization::ComputeInverseInfinityNorm() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; const RowIndex num_rows = compact_matrix_.num_rows(); const ColIndex num_cols = RowToColIndex(num_rows); DenseColumn row_sum(num_rows, 0.0); @@ -558,21 +553,18 @@ Fractional BasisFactorization::ComputeInverseInfinityNorm() const { } Fractional BasisFactorization::ComputeOneNormConditionNumber() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; return ComputeOneNorm() * ComputeInverseOneNorm(); } Fractional BasisFactorization::ComputeInfinityNormConditionNumber() const { - if (IsIdentityBasis()) - return 1.0; + if (IsIdentityBasis()) return 1.0; return ComputeInfinityNorm() * ComputeInverseInfinityNorm(); } -Fractional -BasisFactorization::ComputeInfinityNormConditionNumberUpperBound() const { - if (IsIdentityBasis()) - return 1.0; +Fractional BasisFactorization::ComputeInfinityNormConditionNumberUpperBound() + const { + if (IsIdentityBasis()) return 1.0; BumpDeterministicTimeForSolve(compact_matrix_.num_rows().value()); return ComputeInfinityNorm() * lu_factorization_.ComputeInverseInfinityNormUpperBound(); @@ -584,8 +576,7 @@ double BasisFactorization::DeterministicTime() const { void BasisFactorization::BumpDeterministicTimeForSolve(int num_entries) const { // TODO(user): Spend more time finding a good approximation here. - if (compact_matrix_.num_rows().value() == 0) - return; + if (compact_matrix_.num_rows().value() == 0) return; const double density = static_cast(num_entries) / static_cast(compact_matrix_.num_rows().value()); @@ -596,5 +587,5 @@ void BasisFactorization::BumpDeterministicTimeForSolve(int num_entries) const { rank_one_factorization_.num_entries().value()); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/basis_representation.h b/ortools/glop/basis_representation.h index 69a023bc78..8464327a5b 100644 --- a/ortools/glop/basis_representation.h +++ b/ortools/glop/basis_representation.h @@ -50,7 +50,7 @@ namespace glop { // ... ... ... ... ... ... ... // 0 ... 0 -e_{n-1}/e_j 0 ... 1 ] class EtaMatrix { -public: + public: EtaMatrix(ColIndex eta_col, const ScatteredColumn &direction); virtual ~EtaMatrix(); @@ -75,7 +75,7 @@ public: // a_{n-1} - e_{n-1} * a_j / e_j ] void RightSolve(DenseColumn *d) const; -private: + private: // Internal RightSolve() and LeftSolve() implementations using either the // dense or the sparse representation of the eta vector. void LeftSolveWithDenseEta(DenseRow *y) const; @@ -107,7 +107,7 @@ private: // - E.d = a (where a is usually the entering column). // - y.E = c (where c is usually the objective row). class EtaFactorization { -public: + public: EtaFactorization(); virtual ~EtaFactorization(); @@ -131,7 +131,7 @@ public: // Right solves all systems from left to right, i.e. E_i.d_{i+1} = d_i void RightSolve(DenseColumn *d) const; -private: + private: std::vector eta_matrix_; DISALLOW_COPY_AND_ASSIGN(EtaFactorization); @@ -149,7 +149,7 @@ private: // This class does not take ownership of the underlying matrix and basis, and // thus they must outlive this class (and keep the same address in memory). class BasisFactorization { -public: + public: BasisFactorization(const CompactSparseMatrix *compact_matrix, const RowToColMapping *basis); virtual ~BasisFactorization(); @@ -281,7 +281,7 @@ public: // solve and each factorization. double DeterministicTime() const; -private: + private: // Return true if the submatrix of matrix_ given by basis_ is exactly the // identity (without permutation). bool IsIdentityBasis() const; @@ -290,8 +290,7 @@ private: // Qi Huangfu, J. A. Julian Hall, "Novel update techniques for the revised // simplex method", 28 january 2013, Technical Report ERGO-13-0001 ABSL_MUST_USE_RESULT Status - MiddleProductFormUpdate(ColIndex entering_col, - RowIndex leaving_variable_row); + MiddleProductFormUpdate(ColIndex entering_col, RowIndex leaving_variable_row); // Increases the deterministic time for a solve operation with a vector having // this number of non-zero entries (it can be an approximation). @@ -365,7 +364,7 @@ private: DISALLOW_COPY_AND_ASSIGN(BasisFactorization); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_BASIS_REPRESENTATION_H_ +#endif // OR_TOOLS_GLOP_BASIS_REPRESENTATION_H_ diff --git a/ortools/glop/dual_edge_norms.cc b/ortools/glop/dual_edge_norms.cc index e888b4efc3..0d55513231 100644 --- a/ortools/glop/dual_edge_norms.cc +++ b/ortools/glop/dual_edge_norms.cc @@ -33,15 +33,13 @@ void DualEdgeNorms::ResizeOnNewRows(RowIndex new_size) { } const DenseColumn &DualEdgeNorms::GetEdgeSquaredNorms() { - if (recompute_edge_squared_norms_) - ComputeEdgeSquaredNorms(); + if (recompute_edge_squared_norms_) ComputeEdgeSquaredNorms(); return edge_squared_norms_; } -void -DualEdgeNorms::UpdateDataOnBasisPermutation(const ColumnPermutation &col_perm) { - if (recompute_edge_squared_norms_) - return; +void DualEdgeNorms::UpdateDataOnBasisPermutation( + const ColumnPermutation &col_perm) { + if (recompute_edge_squared_norms_) return; ApplyColumnPermutationToRowIndexedVector(col_perm, &edge_squared_norms_); } @@ -50,8 +48,7 @@ void DualEdgeNorms::UpdateBeforeBasisPivot( const ScatteredColumn &direction, const ScatteredRow &unit_row_left_inverse) { // No need to update if we will recompute it from scratch later. - if (recompute_edge_squared_norms_) - return; + if (recompute_edge_squared_norms_) return; const DenseColumn &tau = ComputeTau(TransposedView(unit_row_left_inverse)); SCOPED_TIME_STAT(&stats_); @@ -95,8 +92,7 @@ void DualEdgeNorms::UpdateBeforeBasisPivot( // (edge . leaving_column)^2 = 1.0 < ||edge||^2 * ||leaving_column||^2 const Fractional kLowerBound = 1e-4; if (edge_squared_norms_[e.row()] < kLowerBound) { - if (e.row() == leaving_row) - continue; + if (e.row() == leaving_row) continue; edge_squared_norms_[e.row()] = kLowerBound; ++stat_lower_bounded_norms; } @@ -119,8 +115,8 @@ void DualEdgeNorms::ComputeEdgeSquaredNorms() { recompute_edge_squared_norms_ = false; } -const DenseColumn & -DualEdgeNorms::ComputeTau(const ScatteredColumn &unit_row_left_inverse) { +const DenseColumn &DualEdgeNorms::ComputeTau( + const ScatteredColumn &unit_row_left_inverse) { SCOPED_TIME_STAT(&stats_); const DenseColumn &result = basis_factorization_.RightSolveForTau(unit_row_left_inverse); @@ -128,5 +124,5 @@ DualEdgeNorms::ComputeTau(const ScatteredColumn &unit_row_left_inverse) { return result; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/dual_edge_norms.h b/ortools/glop/dual_edge_norms.h index e21271ee68..b96d68cf01 100644 --- a/ortools/glop/dual_edge_norms.h +++ b/ortools/glop/dual_edge_norms.h @@ -45,7 +45,7 @@ namespace glop { // implementation", PhD, Paderborn, Univ., 2005. // http://digital.ub.uni-paderborn.de/hs/download/pdf/3885?originalFilename=true class DualEdgeNorms { -public: + public: // Takes references to the linear program data we need. explicit DualEdgeNorms(const BasisFactorization &basis_factorization); @@ -91,7 +91,7 @@ public: // Stats related functions. std::string StatString() const { return stats_.StatString(); } -private: + private: // Recomputes the dual edge squared norms from scratch with maximum precision. // The matrix must have been refactorized before because we will do a lot of // inversions. See NeedsBasisRefactorization(). This is checked in debug mode. @@ -104,7 +104,8 @@ private: // Statistics. struct Stats : public StatsGroup { Stats() - : StatsGroup("DualEdgeNorms"), tau_density("tau_density", this), + : StatsGroup("DualEdgeNorms"), + tau_density("tau_density", this), edge_norms_accuracy("edge_norms_accuracy", this), lower_bounded_norms("lower_bounded_norms", this) {} RatioDistribution tau_density; @@ -128,7 +129,7 @@ private: DISALLOW_COPY_AND_ASSIGN(DualEdgeNorms); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_DUAL_EDGE_NORMS_H_ +#endif // OR_TOOLS_GLOP_DUAL_EDGE_NORMS_H_ diff --git a/ortools/glop/entering_variable.cc b/ortools/glop/entering_variable.cc index 68fb79fb40..ca5801a36d 100644 --- a/ortools/glop/entering_variable.cc +++ b/ortools/glop/entering_variable.cc @@ -26,9 +26,13 @@ EnteringVariable::EnteringVariable(const VariablesInfo &variables_info, random_engine_t *random, ReducedCosts *reduced_costs, PrimalEdgeNorms *primal_edge_norms) - : variables_info_(variables_info), random_(random), - reduced_costs_(reduced_costs), primal_edge_norms_(primal_edge_norms), - parameters_(), rule_(GlopParameters::DANTZIG), unused_columns_() {} + : variables_info_(variables_info), + random_(random), + reduced_costs_(reduced_costs), + primal_edge_norms_(primal_edge_norms), + parameters_(), + rule_(GlopParameters::DANTZIG), + unused_columns_() {} Status EnteringVariable::PrimalChooseEnteringColumn(ColIndex *entering_col) { SCOPED_TIME_STAT(&stats_); @@ -40,40 +44,40 @@ Status EnteringVariable::PrimalChooseEnteringColumn(ColIndex *entering_col) { const bool kSteepest = true; switch (rule_) { - case GlopParameters::DANTZIG: - if (parameters_.use_nested_pricing()) { - if (unused_columns_.size() != variables_info_.GetNumberOfColumns()) { + case GlopParameters::DANTZIG: + if (parameters_.use_nested_pricing()) { + if (unused_columns_.size() != variables_info_.GetNumberOfColumns()) { + ResetUnusedColumns(); + } + if (parameters_.normalize_using_column_norm()) { + DantzigChooseEnteringColumn(entering_col); + } else { + DantzigChooseEnteringColumn(entering_col); + } + if (*entering_col != kInvalidCol) { + unused_columns_.Clear(*entering_col); + return Status::OK(); + } ResetUnusedColumns(); - } - if (parameters_.normalize_using_column_norm()) { - DantzigChooseEnteringColumn(entering_col); + if (parameters_.normalize_using_column_norm()) { + DantzigChooseEnteringColumn(entering_col); + } else { + DantzigChooseEnteringColumn(entering_col); + } } else { - DantzigChooseEnteringColumn< !kNormalize, kNested>(entering_col); + if (parameters_.normalize_using_column_norm()) { + DantzigChooseEnteringColumn(entering_col); + } else { + DantzigChooseEnteringColumn(entering_col); + } } - if (*entering_col != kInvalidCol) { - unused_columns_.Clear(*entering_col); - return Status::OK(); - } - ResetUnusedColumns(); - if (parameters_.normalize_using_column_norm()) { - DantzigChooseEnteringColumn(entering_col); - } else { - DantzigChooseEnteringColumn< !kNormalize, kNested>(entering_col); - } - } else { - if (parameters_.normalize_using_column_norm()) { - DantzigChooseEnteringColumn(entering_col); - } else { - DantzigChooseEnteringColumn< !kNormalize, !kNested>(entering_col); - } - } - return Status::OK(); - case GlopParameters::STEEPEST_EDGE: - NormalizedChooseEnteringColumn(entering_col); - return Status::OK(); - case GlopParameters::DEVEX: - NormalizedChooseEnteringColumn< !kSteepest>(entering_col); - return Status::OK(); + return Status::OK(); + case GlopParameters::STEEPEST_EDGE: + NormalizedChooseEnteringColumn(entering_col); + return Status::OK(); + case GlopParameters::DEVEX: + NormalizedChooseEnteringColumn(entering_col); + return Status::OK(); } LOG(DFATAL) << "Unknown pricing rule: " << ProtoEnumToString(rule_) @@ -118,8 +122,7 @@ Status EnteringVariable::DualChooseEnteringColumn( // already, and the column will be dual-infeasible. if (can_decrease.IsSet(col) && coeff > threshold) { if (!is_boxed[col]) { - if (-reduced_costs[col] > harris_ratio * coeff) - continue; + if (-reduced_costs[col] > harris_ratio * coeff) continue; harris_ratio = std::min( harris_ratio, (-reduced_costs[col] + harris_tolerance) / coeff); harris_ratio = std::max(0.0, harris_ratio); @@ -132,8 +135,7 @@ Status EnteringVariable::DualChooseEnteringColumn( // already, and the column will be dual-infeasible. if (can_increase.IsSet(col) && coeff < -threshold) { if (!is_boxed[col]) { - if (reduced_costs[col] > harris_ratio * -coeff) - continue; + if (reduced_costs[col] > harris_ratio * -coeff) continue; harris_ratio = std::min( harris_ratio, (reduced_costs[col] + harris_tolerance) / -coeff); harris_ratio = std::max(0.0, harris_ratio); @@ -168,8 +170,7 @@ Status EnteringVariable::DualChooseEnteringColumn( equivalent_entering_choices_.clear(); while (!breakpoints_.empty()) { const ColWithRatio top = breakpoints_.front(); - if (top.ratio > harris_ratio) - break; + if (top.ratio > harris_ratio) break; // If the column is boxed, we can just switch its bounds and // ignore the breakpoint! But we need to see if the entering row still @@ -241,8 +242,7 @@ Status EnteringVariable::DualChooseEnteringColumn( stats_.num_perfect_ties.Add(equivalent_entering_choices_.size())); } - if (*entering_col == kInvalidCol) - return Status::OK(); + if (*entering_col == kInvalidCol) return Status::OK(); // If the step is 0.0, we make sure the reduced cost is 0.0 so // UpdateReducedCosts() will not take a step that goes in the wrong way (a few @@ -295,8 +295,7 @@ Status EnteringVariable::DualPhaseIChooseEnteringColumn( DCHECK_NE(variable_type[col], VariableType::FIXED_VARIABLE); // Skip if the coeff is too small to be a numerically stable pivot. - if (std::abs(update_coefficient[col]) < threshold) - continue; + if (std::abs(update_coefficient[col]) < threshold) continue; // We will add ratio * coeff to this column. cost_variation makes sure // the leaving variable will be dual-feasible (its update coeff is @@ -311,10 +310,8 @@ Status EnteringVariable::DualPhaseIChooseEnteringColumn( // is close to zero, then the variable is supposed to be dual-feasible. if (std::abs(reduced_costs[col]) <= dual_feasibility_tolerance) { // Continue if the variation goes in the dual-feasible direction. - if (coeff > 0 && !can_decrease.IsSet(col)) - continue; - if (coeff < 0 && !can_increase.IsSet(col)) - continue; + if (coeff > 0 && !can_decrease.IsSet(col)) continue; + if (coeff < 0 && !can_increase.IsSet(col)) continue; // Note that here, a variable which is already dual-infeasible will still // have a positive ratio. This may sounds weird, but the idea is to put @@ -323,8 +320,7 @@ Status EnteringVariable::DualPhaseIChooseEnteringColumn( // wrong direction. } else { // If the two are of the same sign, there is no transition, skip. - if (coeff * reduced_costs[col] > 0) - continue; + if (coeff * reduced_costs[col] > 0) continue; } // We are sure there is a transition, add it to the set of breakpoints. @@ -366,8 +362,7 @@ Status EnteringVariable::DualPhaseIChooseEnteringColumn( improvement -= top.coeff_magnitude; } - if (improvement <= 0.0) - break; + if (improvement <= 0.0) break; std::pop_heap(breakpoints_.begin(), breakpoints_.end()); breakpoints_.pop_back(); } @@ -414,8 +409,7 @@ void EnteringVariable::DantzigChooseEnteringColumn(ColIndex *entering_col) { Fractional best_price(0.0); *entering_col = kInvalidCol; for (const ColIndex col : reduced_costs_->GetDualInfeasiblePositions()) { - if (nested_pricing && !unused_columns_.IsSet(col)) - continue; + if (nested_pricing && !unused_columns_.IsSet(col)) continue; const Fractional unormalized_price = std::abs(reduced_costs[col]); if (normalize) { if (unormalized_price > best_price * matrix_column_norms[col]) { @@ -438,9 +432,9 @@ void EnteringVariable::DantzigChooseEnteringColumn(ColIndex *entering_col) { // the other parts of the simplex algorithm. template void EnteringVariable::NormalizedChooseEnteringColumn(ColIndex *entering_col) { - const DenseRow &weights = - use_steepest_edge ? primal_edge_norms_->GetEdgeSquaredNorms() - : primal_edge_norms_->GetDevexWeights(); + const DenseRow &weights = use_steepest_edge + ? primal_edge_norms_->GetEdgeSquaredNorms() + : primal_edge_norms_->GetDevexWeights(); const DenseRow &reduced_costs = reduced_costs_->GetReducedCosts(); SCOPED_TIME_STAT(&stats_); @@ -484,5 +478,5 @@ void EnteringVariable::NormalizedChooseEnteringColumn(ColIndex *entering_col) { } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/entering_variable.h b/ortools/glop/entering_variable.h index 1e1b793535..c65ded384e 100644 --- a/ortools/glop/entering_variable.h +++ b/ortools/glop/entering_variable.h @@ -51,7 +51,7 @@ namespace glop { // - Ping-Qi Pan, "Efficient nested pricing in the simplex algorithm", // http://www.optimization-online.org/DB_FILE/2007/10/1810.pdf class EnteringVariable { -public: + public: // Takes references to the linear program data we need. EnteringVariable(const VariablesInfo &variables_info, random_engine_t *random, ReducedCosts *reduced_costs, @@ -62,27 +62,25 @@ public: // such column exists. This latter case means that the primal algorithm has // terminated: the optimal has been reached. ABSL_MUST_USE_RESULT Status - PrimalChooseEnteringColumn(ColIndex *entering_col); + PrimalChooseEnteringColumn(ColIndex *entering_col); // Dual optimization phase (i.e. phase II) ratio test. // Returns the index of the entering column given that we want to move along // the "update" row vector in the direction given by the sign of // cost_variation. Computes the smallest step that keeps the dual feasibility // for all the columns. - ABSL_MUST_USE_RESULT Status - DualChooseEnteringColumn(const UpdateRow &update_row, - Fractional cost_variation, - std::vector *bound_flip_candidates, - ColIndex *entering_col, Fractional *step); + ABSL_MUST_USE_RESULT Status DualChooseEnteringColumn( + const UpdateRow &update_row, Fractional cost_variation, + std::vector *bound_flip_candidates, ColIndex *entering_col, + Fractional *step); // Dual feasibility phase (i.e. phase I) ratio test. // Similar to the optimization phase test, but allows a step that increases // the infeasibility of an already infeasible column. The step magnitude is // the one that minimize the sum of infeasibilities when applied. - ABSL_MUST_USE_RESULT Status - DualPhaseIChooseEnteringColumn(const UpdateRow &update_row, - Fractional cost_variation, - ColIndex *entering_col, Fractional *step); + ABSL_MUST_USE_RESULT Status DualPhaseIChooseEnteringColumn( + const UpdateRow &update_row, Fractional cost_variation, + ColIndex *entering_col, Fractional *step); // Sets the pricing parameters. This does not change the pricing rule. void SetParameters(const GlopParameters ¶meters); @@ -97,7 +95,7 @@ public: // Visible for testing (the returns value is also there for testing). DenseBitRow *ResetUnusedColumns(); -private: + private: // Dantzig selection rule: choose the variable with the best reduced cost. // If normalize is true, we normalize the costs by the column norms. // If nested_pricing is true, we use nested pricing (see parameters.proto). @@ -169,8 +167,8 @@ private: DISALLOW_COPY_AND_ASSIGN(EnteringVariable); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // SWIG -#endif // OR_TOOLS_GLOP_ENTERING_VARIABLE_H_ +#endif // SWIG +#endif // OR_TOOLS_GLOP_ENTERING_VARIABLE_H_ diff --git a/ortools/glop/initial_basis.cc b/ortools/glop/initial_basis.cc index ad9cf494b8..981973e68b 100644 --- a/ortools/glop/initial_basis.cc +++ b/ortools/glop/initial_basis.cc @@ -26,10 +26,14 @@ InitialBasis::InitialBasis(const CompactSparseMatrix &compact_matrix, const DenseRow &lower_bound, const DenseRow &upper_bound, const VariableTypeRow &variable_type) - : max_scaled_abs_cost_(0.0), bixby_column_comparator_(*this), - triangular_column_comparator_(*this), compact_matrix_(compact_matrix), - objective_(objective), lower_bound_(lower_bound), - upper_bound_(upper_bound), variable_type_(variable_type) {} + : max_scaled_abs_cost_(0.0), + bixby_column_comparator_(*this), + triangular_column_comparator_(*this), + compact_matrix_(compact_matrix), + objective_(objective), + lower_bound_(lower_bound), + upper_bound_(upper_bound), + variable_type_(variable_type) {} void InitialBasis::CompleteBixbyBasis(ColIndex num_cols, RowToColMapping *basis) { @@ -66,8 +70,7 @@ void InitialBasis::CompleteBixbyBasis(ColIndex num_cols, // case by default since we only use this when the matrix is scaled, but // it is not the case for our tests... The overhead for computing the // infinity norm for each column should be minimal. - if (InfinityNorm(candidate_col) != 1.0) - continue; + if (InfinityNorm(candidate_col) != 1.0) continue; RowIndex candidate_row; Fractional candidate_coeff = RestrictedInfinityNorm( @@ -132,8 +135,7 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols, MatrixNonZeroPattern residual_pattern; residual_pattern.Reset(num_rows, num_cols); for (ColIndex col(0); col < num_cols; ++col) { - if (only_allow_zero_cost_column && objective_[col] != 0.0) - continue; + if (only_allow_zero_cost_column && objective_[col] != 0.0) continue; for (const SparseColumn::Entry e : compact_matrix_.column(col)) { if (can_be_replaced[e.row()]) { residual_pattern.AddEntry(e.row(), col); @@ -156,17 +158,16 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols, max_scaled_abs_cost_ = (max_scaled_abs_cost_ == 0.0) ? 1.0 : kBixbyWeight * max_scaled_abs_cost_; std::priority_queue, - InitialBasis::TriangularColumnComparator> queue( - residual_singleton_column.begin(), residual_singleton_column.end(), - triangular_column_comparator_); + InitialBasis::TriangularColumnComparator> + queue(residual_singleton_column.begin(), residual_singleton_column.end(), + triangular_column_comparator_); // Process the residual singleton columns by priority and add them to the // basis if their "diagonal" coefficient is not too small. while (!queue.empty()) { const ColIndex candidate = queue.top(); queue.pop(); - if (residual_pattern.ColDegree(candidate) != 1) - continue; + if (residual_pattern.ColDegree(candidate) != 1) continue; // Find the position of the singleton and compute the infinity norm of // the column (note that this is always 1.0 if the problem was scaled). @@ -182,8 +183,7 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols, } } const Fractional kStabilityThreshold = 0.01; - if (std::abs(coeff) < kStabilityThreshold * max_magnitude) - continue; + if (std::abs(coeff) < kStabilityThreshold * max_magnitude) continue; DCHECK_NE(kInvalidRow, row); // Use this candidate column in the basis. @@ -191,8 +191,7 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols, can_be_replaced[row] = false; residual_pattern.DeleteRowAndColumn(row, candidate); for (const ColIndex col : residual_pattern.RowNonZero(row)) { - if (col == candidate) - continue; + if (col == candidate) continue; residual_pattern.DecreaseColDegree(col); if (residual_pattern.ColDegree(col) == 1) { queue.push(col); @@ -204,16 +203,16 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols, int InitialBasis::GetMarosPriority(ColIndex col) const { // Priority values for columns as defined in Maros's book. switch (variable_type_[col]) { - case VariableType::UNCONSTRAINED: - return 3; - case VariableType::LOWER_BOUNDED: - return 2; - case VariableType::UPPER_BOUNDED: - return 2; - case VariableType::UPPER_AND_LOWER_BOUNDED: - return 1; - case VariableType::FIXED_VARIABLE: - return 0; + case VariableType::UNCONSTRAINED: + return 3; + case VariableType::LOWER_BOUNDED: + return 2; + case VariableType::UPPER_BOUNDED: + return 2; + case VariableType::UPPER_AND_LOWER_BOUNDED: + return 1; + case VariableType::FIXED_VARIABLE: + return 0; } } @@ -286,8 +285,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping *basis) { } } } - if (max_rpf_row == kInvalidRow) - break; + if (max_rpf_row == kInvalidRow) break; // Trace row for nonzero entries and pick one with best Column Priority // Function (cpf). @@ -296,8 +294,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping *basis) { int max_col_priority_function(std::numeric_limits::min()); Fractional pivot_absolute_value = 0.0; for (const ColIndex col : residual_pattern.RowNonZero(max_rpf_row)) { - if (!available[col]) - continue; + if (!available[col]) continue; const int cpf = 10 * GetMarosPriority(col) - residual_pattern.ColDegree(col); if (cpf > max_col_priority_function) { @@ -307,8 +304,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping *basis) { const auto &column_values = compact_matrix_.column(col); for (const SparseColumn::Entry e : column_values) { const Fractional absolute_value = std::fabs(e.coefficient()); - if (e.row() == max_rpf_row) - pivot_absolute_value = absolute_value; + if (e.row() == max_rpf_row) pivot_absolute_value = absolute_value; max_magnitude = std::max(max_magnitude, absolute_value); } if (pivot_absolute_value >= kStabilityThreshold * max_magnitude) { @@ -376,16 +372,16 @@ int InitialBasis::GetColumnCategory(ColIndex col) const { // Only the relative position of the returned number is important, so we use // 2 for the category C2 in Bixby's paper and so on. switch (variable_type_[col]) { - case VariableType::UNCONSTRAINED: - return 2; - case VariableType::LOWER_BOUNDED: - return 3; - case VariableType::UPPER_BOUNDED: - return 3; - case VariableType::UPPER_AND_LOWER_BOUNDED: - return 4; - case VariableType::FIXED_VARIABLE: - return 5; + case VariableType::UNCONSTRAINED: + return 2; + case VariableType::LOWER_BOUNDED: + return 3; + case VariableType::UPPER_BOUNDED: + return 3; + case VariableType::UPPER_AND_LOWER_BOUNDED: + return 4; + case VariableType::FIXED_VARIABLE: + return 5; } } @@ -406,8 +402,7 @@ Fractional InitialBasis::GetColumnPenalty(ColIndex col) const { bool InitialBasis::BixbyColumnComparator::operator()(ColIndex col_a, ColIndex col_b) const { - if (col_a == col_b) - return false; + if (col_a == col_b) return false; const int category_a = initial_basis_.GetColumnCategory(col_a); const int category_b = initial_basis_.GetColumnCategory(col_b); if (category_a != category_b) { @@ -418,11 +413,9 @@ bool InitialBasis::BixbyColumnComparator::operator()(ColIndex col_a, } } -bool -InitialBasis::TriangularColumnComparator::operator()(ColIndex col_a, - ColIndex col_b) const { - if (col_a == col_b) - return false; +bool InitialBasis::TriangularColumnComparator::operator()( + ColIndex col_a, ColIndex col_b) const { + if (col_a == col_b) return false; const int category_a = initial_basis_.GetColumnCategory(col_a); const int category_b = initial_basis_.GetColumnCategory(col_b); if (category_a != category_b) { @@ -444,5 +437,5 @@ InitialBasis::TriangularColumnComparator::operator()(ColIndex col_a, initial_basis_.GetColumnPenalty(col_b); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/initial_basis.h b/ortools/glop/initial_basis.h index 4abdd42f03..8963a456cc 100644 --- a/ortools/glop/initial_basis.h +++ b/ortools/glop/initial_basis.h @@ -42,7 +42,7 @@ namespace glop { // column to add is chosen amongst the set of possible candidates using a // heuristic similar to the one used by Bixby. class InitialBasis { -public: + public: // Takes references to the linear program data we need. InitialBasis(const CompactSparseMatrix &compact_matrix, const DenseRow &objective, const DenseRow &lower_bound, @@ -77,7 +77,7 @@ public: // bixby_column_comparator_. This also fills max_scaled_abs_cost_. void ComputeCandidates(ColIndex num_cols, std::vector *candidates); -private: + private: // Internal implementation of the Primal/Dual CompleteTriangularBasis(). template void CompleteTriangularBasis(ColIndex num_cols, RowToColMapping *basis); @@ -129,7 +129,7 @@ private: DISALLOW_COPY_AND_ASSIGN(InitialBasis); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_INITIAL_BASIS_H_ +#endif // OR_TOOLS_GLOP_INITIAL_BASIS_H_ diff --git a/ortools/glop/lp_solver.cc b/ortools/glop/lp_solver.cc index 8f803896e6..1b4fb816ef 100644 --- a/ortools/glop/lp_solver.cc +++ b/ortools/glop/lp_solver.cc @@ -70,8 +70,7 @@ namespace { // Warning: is a no-op on portable platforms (android, ios, etc). void DumpLinearProgramIfRequiredByFlags(const LinearProgram &linear_program, int num) { - if (!absl::GetFlag(FLAGS_lp_dump_to_proto_file)) - return; + if (!absl::GetFlag(FLAGS_lp_dump_to_proto_file)) return; #ifdef __PORTABLE_PLATFORM__ LOG(WARNING) << "DumpLinearProgramIfRequiredByFlags(linear_program, num) " "requested for linear_program.name()='" @@ -94,9 +93,9 @@ void DumpLinearProgramIfRequiredByFlags(const LinearProgram &linear_program, absl::StrCat(absl::GetFlag(FLAGS_lp_dump_dir), "/", filename); MPModelProto proto; LinearProgramToMPModelProto(linear_program, &proto); - const ProtoWriteFormat write_format = - absl::GetFlag(FLAGS_lp_dump_binary_file) ? ProtoWriteFormat::kProtoBinary - : ProtoWriteFormat::kProtoText; + const ProtoWriteFormat write_format = absl::GetFlag(FLAGS_lp_dump_binary_file) + ? ProtoWriteFormat::kProtoBinary + : ProtoWriteFormat::kProtoText; if (!WriteProtoToFile(filespec, proto, write_format, absl::GetFlag(FLAGS_lp_dump_compressed_file))) { LOG(DFATAL) << "Could not write " << filespec; @@ -104,7 +103,7 @@ void DumpLinearProgramIfRequiredByFlags(const LinearProgram &linear_program, #endif } -} // anonymous namespace +} // anonymous namespace // -------------------------------------------------------- // LPSolver @@ -182,8 +181,8 @@ ProblemStatus LPSolver::SolveWithTimeLimit(const LinearProgram &lp, const bool postsolve_is_needed = preprocessor.Run(¤t_linear_program_); - VLOG(1) - << "Presolved problem: " << current_linear_program_.GetDimensionString(); + VLOG(1) << "Presolved problem: " + << current_linear_program_.GetDimensionString(); // At this point, we need to initialize a ProblemSolution with the correct // size and status. @@ -198,8 +197,7 @@ ProblemStatus LPSolver::SolveWithTimeLimit(const LinearProgram &lp, RunRevisedSimplexIfNeeded(&solution, time_limit); } - if (postsolve_is_needed) - preprocessor.RecoverSolution(&solution); + if (postsolve_is_needed) preprocessor.RecoverSolution(&solution); const ProblemStatus status = LoadAndVerifySolution(lp, solution); // LOG some statistics that can be parsed by our benchmark script. @@ -207,8 +205,8 @@ ProblemStatus LPSolver::SolveWithTimeLimit(const LinearProgram &lp, VLOG(1) << "objective: " << GetObjectiveValue(); VLOG(1) << "iterations: " << GetNumberOfSimplexIterations(); VLOG(1) << "time: " << time_limit->GetElapsedTime(); - VLOG(1) - << "deterministic_time: " << time_limit->GetElapsedDeterministicTime(); + VLOG(1) << "deterministic_time: " + << time_limit->GetElapsedDeterministicTime(); return status; } @@ -218,9 +216,9 @@ void LPSolver::Clear() { revised_simplex_.reset(nullptr); } -void -LPSolver::SetInitialBasis(const VariableStatusRow &variable_statuses, - const ConstraintStatusColumn &constraint_statuses) { +void LPSolver::SetInitialBasis( + const VariableStatusRow &variable_statuses, + const ConstraintStatusColumn &constraint_statuses) { // Create the associated basis state. BasisState state; state.statuses = variable_statuses; @@ -228,21 +226,21 @@ LPSolver::SetInitialBasis(const VariableStatusRow &variable_statuses, // Note the change of upper/lower bound between the status of a constraint // and the status of its associated slack variable. switch (status) { - case ConstraintStatus::FREE: - state.statuses.push_back(VariableStatus::FREE); - break; - case ConstraintStatus::AT_LOWER_BOUND: - state.statuses.push_back(VariableStatus::AT_UPPER_BOUND); - break; - case ConstraintStatus::AT_UPPER_BOUND: - state.statuses.push_back(VariableStatus::AT_LOWER_BOUND); - break; - case ConstraintStatus::FIXED_VALUE: - state.statuses.push_back(VariableStatus::FIXED_VALUE); - break; - case ConstraintStatus::BASIC: - state.statuses.push_back(VariableStatus::BASIC); - break; + case ConstraintStatus::FREE: + state.statuses.push_back(VariableStatus::FREE); + break; + case ConstraintStatus::AT_LOWER_BOUND: + state.statuses.push_back(VariableStatus::AT_UPPER_BOUND); + break; + case ConstraintStatus::AT_UPPER_BOUND: + state.statuses.push_back(VariableStatus::AT_LOWER_BOUND); + break; + case ConstraintStatus::FIXED_VALUE: + state.statuses.push_back(VariableStatus::FIXED_VALUE); + break; + case ConstraintStatus::BASIC: + state.statuses.push_back(VariableStatus::BASIC); + break; } } if (revised_simplex_ == nullptr) { @@ -268,7 +266,7 @@ Fractional ProblemObjectiveValue(const LinearProgram &lp, Fractional value) { Fractional AllowedError(Fractional tolerance, Fractional value) { return tolerance * std::max(1.0, std::abs(value)); } -} // namespace +} // namespace // TODO(user): Try to also check the precision of an INFEASIBLE or UNBOUNDED // return status. @@ -350,8 +348,8 @@ ProblemStatus LPSolver::LoadAndVerifySolution(const LinearProgram &lp, std::max(primal_infeasibility, primal_residual); max_absolute_dual_infeasibility_ = std::max(dual_infeasibility, dual_residual); - VLOG(1) - << "Max. primal infeasibility = " << max_absolute_primal_infeasibility_; + VLOG(1) << "Max. primal infeasibility = " + << max_absolute_primal_infeasibility_; VLOG(1) << "Max. dual infeasibility = " << max_absolute_dual_infeasibility_; // Now that all the relevant quantities are computed, we check the precision @@ -419,8 +417,7 @@ bool LPSolver::IsOptimalSolutionOnFacet(const LinearProgram &lp) { const double kBoundTolerance = 1e-7; const ColIndex num_cols = lp.num_variables(); for (ColIndex col(0); col < num_cols; ++col) { - if (variable_statuses_[col] == VariableStatus::FIXED_VALUE) - continue; + if (variable_statuses_[col] == VariableStatus::FIXED_VALUE) continue; const Fractional lower_bound = lp.variable_lower_bounds()[col]; const Fractional upper_bound = lp.variable_upper_bounds()[col]; const Fractional value = primal_values_[col]; @@ -433,8 +430,7 @@ bool LPSolver::IsOptimalSolutionOnFacet(const LinearProgram &lp) { } const RowIndex num_rows = lp.num_constraints(); for (RowIndex row(0); row < num_rows; ++row) { - if (constraint_statuses_[row] == ConstraintStatus::FIXED_VALUE) - continue; + if (constraint_statuses_[row] == ConstraintStatus::FIXED_VALUE) continue; const Fractional lower_bound = lp.constraint_lower_bounds()[row]; const Fractional upper_bound = lp.constraint_upper_bounds()[row]; const Fractional activity = constraint_activities_[row]; @@ -529,8 +525,7 @@ void LPSolver::RunRevisedSimplexIfNeeded(ProblemSolution *solution, // Note that the transpose matrix is no longer needed at this point. // This helps reduce the peak memory usage of the solver. current_linear_program_.ClearTransposeMatrix(); - if (solution->status != ProblemStatus::INIT) - return; + if (solution->status != ProblemStatus::INIT) return; if (revised_simplex_ == nullptr) { revised_simplex_ = absl::make_unique(); } @@ -577,21 +572,16 @@ void LogConstraintStatusError(RowIndex row, ConstraintStatus status, << ", " << ub << "]."; } -} // namespace +} // namespace -bool -LPSolver::IsProblemSolutionConsistent(const LinearProgram &lp, - const ProblemSolution &solution) const { +bool LPSolver::IsProblemSolutionConsistent( + const LinearProgram &lp, const ProblemSolution &solution) const { const RowIndex num_rows = lp.num_constraints(); const ColIndex num_cols = lp.num_variables(); - if (solution.variable_statuses.size() != num_cols) - return false; - if (solution.constraint_statuses.size() != num_rows) - return false; - if (solution.primal_values.size() != num_cols) - return false; - if (solution.dual_values.size() != num_rows) - return false; + if (solution.variable_statuses.size() != num_cols) return false; + if (solution.constraint_statuses.size() != num_rows) return false; + if (solution.primal_values.size() != num_cols) return false; + if (solution.dual_values.size() != num_rows) return false; if (solution.status != ProblemStatus::OPTIMAL && solution.status != ProblemStatus::PRIMAL_FEASIBLE && solution.status != ProblemStatus::DUAL_FEASIBLE) { @@ -607,46 +597,46 @@ LPSolver::IsProblemSolutionConsistent(const LinearProgram &lp, const Fractional ub = lp.variable_upper_bounds()[col]; const VariableStatus status = solution.variable_statuses[col]; switch (solution.variable_statuses[col]) { - case VariableStatus::BASIC: - // TODO(user): Check that the reduced cost of this column is epsilon - // close to zero. - ++num_basic_variables; - break; - case VariableStatus::FIXED_VALUE: - // TODO(user): Because of scaling, it is possible that a FIXED_VALUE - // status (only reserved for the exact lb == ub case) is now set for a - // variable where (ub == lb + epsilon). So we do not check here that the - // two bounds are exactly equal. The best is probably to remove the - // FIXED status from the API completely and report one of AT_LOWER_BOUND - // or AT_UPPER_BOUND instead. This also allows to indicate if at - // optimality, the objective is limited because of this variable lower - // bound or its upper bound. Note that there are other TODOs in the - // codebase about removing this FIXED_VALUE status. - if (value != ub && value != lb) { - LogVariableStatusError(col, value, status, lb, ub); - return false; - } - break; - case VariableStatus::AT_LOWER_BOUND: - if (value != lb || lb == ub) { - LogVariableStatusError(col, value, status, lb, ub); - return false; - } - break; - case VariableStatus::AT_UPPER_BOUND: - // TODO(user): revert to an exact comparison once the bug causing this - // to fail has been fixed. - if (!AreWithinAbsoluteTolerance(value, ub, 1e-7) || lb == ub) { - LogVariableStatusError(col, value, status, lb, ub); - return false; - } - break; - case VariableStatus::FREE: - if (lb != -kInfinity || ub != kInfinity || value != 0.0) { - LogVariableStatusError(col, value, status, lb, ub); - return false; - } - break; + case VariableStatus::BASIC: + // TODO(user): Check that the reduced cost of this column is epsilon + // close to zero. + ++num_basic_variables; + break; + case VariableStatus::FIXED_VALUE: + // TODO(user): Because of scaling, it is possible that a FIXED_VALUE + // status (only reserved for the exact lb == ub case) is now set for a + // variable where (ub == lb + epsilon). So we do not check here that the + // two bounds are exactly equal. The best is probably to remove the + // FIXED status from the API completely and report one of AT_LOWER_BOUND + // or AT_UPPER_BOUND instead. This also allows to indicate if at + // optimality, the objective is limited because of this variable lower + // bound or its upper bound. Note that there are other TODOs in the + // codebase about removing this FIXED_VALUE status. + if (value != ub && value != lb) { + LogVariableStatusError(col, value, status, lb, ub); + return false; + } + break; + case VariableStatus::AT_LOWER_BOUND: + if (value != lb || lb == ub) { + LogVariableStatusError(col, value, status, lb, ub); + return false; + } + break; + case VariableStatus::AT_UPPER_BOUND: + // TODO(user): revert to an exact comparison once the bug causing this + // to fail has been fixed. + if (!AreWithinAbsoluteTolerance(value, ub, 1e-7) || lb == ub) { + LogVariableStatusError(col, value, status, lb, ub); + return false; + } + break; + case VariableStatus::FREE: + if (lb != -kInfinity || ub != kInfinity || value != 0.0) { + LogVariableStatusError(col, value, status, lb, ub); + return false; + } + break; } } for (RowIndex row(0); row < num_rows; ++row) { @@ -659,46 +649,46 @@ LPSolver::IsProblemSolutionConsistent(const LinearProgram &lp, // TODO(user): Check that the activity is epsilon close to the expected // value. switch (status) { - case ConstraintStatus::BASIC: - if (dual_value != 0.0) { - VLOG(1) << "Constraint " << row << " is BASIC, but its dual value is " - << dual_value << " instead of 0."; - return false; - } - ++num_basic_variables; - break; - case ConstraintStatus::FIXED_VALUE: - // Exactly the same remark as for the VariableStatus::FIXED_VALUE case - // above. Because of precision error, this can happen when the - // difference between the two bounds is small and not just exactly zero. - if (ub - lb > 1e-12) { - LogConstraintStatusError(row, status, lb, ub); - return false; - } - break; - case ConstraintStatus::AT_LOWER_BOUND: - if (lb == -kInfinity) { - LogConstraintStatusError(row, status, lb, ub); - return false; - } - break; - case ConstraintStatus::AT_UPPER_BOUND: - if (ub == kInfinity) { - LogConstraintStatusError(row, status, lb, ub); - return false; - } - break; - case ConstraintStatus::FREE: - if (dual_value != 0.0) { - VLOG(1) << "Constraint " << row << " is FREE, but its dual value is " - << dual_value << " instead of 0."; - return false; - } - if (lb != -kInfinity || ub != kInfinity) { - LogConstraintStatusError(row, status, lb, ub); - return false; - } - break; + case ConstraintStatus::BASIC: + if (dual_value != 0.0) { + VLOG(1) << "Constraint " << row << " is BASIC, but its dual value is " + << dual_value << " instead of 0."; + return false; + } + ++num_basic_variables; + break; + case ConstraintStatus::FIXED_VALUE: + // Exactly the same remark as for the VariableStatus::FIXED_VALUE case + // above. Because of precision error, this can happen when the + // difference between the two bounds is small and not just exactly zero. + if (ub - lb > 1e-12) { + LogConstraintStatusError(row, status, lb, ub); + return false; + } + break; + case ConstraintStatus::AT_LOWER_BOUND: + if (lb == -kInfinity) { + LogConstraintStatusError(row, status, lb, ub); + return false; + } + break; + case ConstraintStatus::AT_UPPER_BOUND: + if (ub == kInfinity) { + LogConstraintStatusError(row, status, lb, ub); + return false; + } + break; + case ConstraintStatus::FREE: + if (dual_value != 0.0) { + VLOG(1) << "Constraint " << row << " is FREE, but its dual value is " + << dual_value << " instead of 0."; + return false; + } + if (lb != -kInfinity || ub != kInfinity) { + LogConstraintStatusError(row, status, lb, ub); + return false; + } + break; } } @@ -715,9 +705,8 @@ LPSolver::IsProblemSolutionConsistent(const LinearProgram &lp, // following complementary slackness conditions: // - Reduced cost is exactly zero for FREE and BASIC variables. // - Reduced cost is of the correct sign for variables at their bounds. -Fractional -LPSolver::ComputeMaxCostPerturbationToEnforceOptimality(const LinearProgram &lp, - bool *is_too_large) { +Fractional LPSolver::ComputeMaxCostPerturbationToEnforceOptimality( + const LinearProgram &lp, bool *is_too_large) { Fractional max_cost_correction = 0.0; const ColIndex num_cols = lp.num_variables(); const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0; @@ -744,9 +733,8 @@ LPSolver::ComputeMaxCostPerturbationToEnforceOptimality(const LinearProgram &lp, // This computes by how much the rhs must be perturbed to enforce the fact that // the constraint activities exactly reflect their status. -Fractional -LPSolver::ComputeMaxRhsPerturbationToEnforceOptimality(const LinearProgram &lp, - bool *is_too_large) { +Fractional LPSolver::ComputeMaxRhsPerturbationToEnforceOptimality( + const LinearProgram &lp, bool *is_too_large) { Fractional max_rhs_correction = 0.0; const RowIndex num_rows = lp.num_constraints(); const Fractional tolerance = parameters_.solution_feasibility_tolerance(); @@ -779,8 +767,8 @@ void LPSolver::ComputeConstraintActivities(const LinearProgram &lp) { DCHECK_EQ(num_cols, primal_values_.size()); constraint_activities_.assign(num_rows, 0.0); for (ColIndex col(0); col < num_cols; ++col) { - lp.GetSparseColumn(col) - .AddMultipleToDenseVector(primal_values_[col], &constraint_activities_); + lp.GetSparseColumn(col).AddMultipleToDenseVector(primal_values_[col], + &constraint_activities_); } } @@ -1031,5 +1019,5 @@ double LPSolver::ComputeReducedCostInfeasibility(const LinearProgram &lp, return infeasibility; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/lp_solver.h b/ortools/glop/lp_solver.h index be479d0f81..c7644c1705 100644 --- a/ortools/glop/lp_solver.h +++ b/ortools/glop/lp_solver.h @@ -27,7 +27,7 @@ namespace glop { // A full-fledged linear programming solver. class LPSolver { -public: + public: LPSolver(); // Sets and gets the solver parameters. @@ -149,7 +149,7 @@ public: // TODO(user): Improve the correlation with the running time. double DeterministicTime() const; -private: + private: // Resizes all the solution vectors to the given sizes. // This is used in case of error to make sure all the getter functions will // not crash when given row/col inside the initial linear program dimension. @@ -211,12 +211,10 @@ private: // Note(user): We could get EXACT bounds on these perturbations by changing // the rounding mode appropriately during these computations. But this is // probably not needed. - Fractional - ComputeMaxCostPerturbationToEnforceOptimality(const LinearProgram &lp, - bool *is_too_large); - Fractional - ComputeMaxRhsPerturbationToEnforceOptimality(const LinearProgram &lp, - bool *is_too_large); + Fractional ComputeMaxCostPerturbationToEnforceOptimality( + const LinearProgram &lp, bool *is_too_large); + Fractional ComputeMaxRhsPerturbationToEnforceOptimality( + const LinearProgram &lp, bool *is_too_large); // Computes the maximum of the infeasibilities associated with each values. // The returned infeasibilities are the maximum of the "absolute" errors of @@ -273,7 +271,7 @@ private: DISALLOW_COPY_AND_ASSIGN(LPSolver); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_LP_SOLVER_H_ +#endif // OR_TOOLS_GLOP_LP_SOLVER_H_ diff --git a/ortools/glop/lu_factorization.cc b/ortools/glop/lu_factorization.cc index c51aa25489..6b0dd42614 100644 --- a/ortools/glop/lu_factorization.cc +++ b/ortools/glop/lu_factorization.cc @@ -22,8 +22,11 @@ namespace operations_research { namespace glop { LuFactorization::LuFactorization() - : is_identity_factorization_(true), col_perm_(), inverse_col_perm_(), - row_perm_(), inverse_row_perm_() {} + : is_identity_factorization_(true), + col_perm_(), + inverse_col_perm_(), + row_perm_(), + inverse_row_perm_() {} void LuFactorization::Clear() { SCOPED_TIME_STAT(&stats_); @@ -64,8 +67,7 @@ Status LuFactorization::ComputeFactorization( void LuFactorization::RightSolve(DenseColumn *x) const { SCOPED_TIME_STAT(&stats_); - if (is_identity_factorization_) - return; + if (is_identity_factorization_) return; ApplyPermutation(row_perm_, *x, &dense_column_scratchpad_); lower_.LowerSolve(&dense_column_scratchpad_); @@ -75,8 +77,7 @@ void LuFactorization::RightSolve(DenseColumn *x) const { void LuFactorization::LeftSolve(DenseRow *y) const { SCOPED_TIME_STAT(&stats_); - if (is_identity_factorization_) - return; + if (is_identity_factorization_) return; // We need to interpret y as a column for the permutation functions. DenseColumn *const x = reinterpret_cast(y); @@ -90,9 +91,8 @@ namespace { // If non_zeros is empty, uses a dense algorithm to compute the squared L2 // norm of the given column, otherwise do the same with a sparse version. In // both cases column is cleared. -Fractional -ComputeSquaredNormAndResetToZero(const std::vector &non_zeros, - DenseColumn *column) { +Fractional ComputeSquaredNormAndResetToZero( + const std::vector &non_zeros, DenseColumn *column) { Fractional sum = 0.0; if (non_zeros.empty()) { sum = SquaredNorm(*column); @@ -105,12 +105,11 @@ ComputeSquaredNormAndResetToZero(const std::vector &non_zeros, } return sum; } -} // namespace +} // namespace Fractional LuFactorization::RightSolveSquaredNorm(const ColumnView &a) const { SCOPED_TIME_STAT(&stats_); - if (is_identity_factorization_) - return SquaredNorm(a); + if (is_identity_factorization_) return SquaredNorm(a); non_zero_rows_.clear(); dense_zero_scratchpad_.resize(lower_.num_rows(), 0.0); @@ -140,8 +139,7 @@ Fractional LuFactorization::RightSolveSquaredNorm(const ColumnView &a) const { } Fractional LuFactorization::DualEdgeSquaredNorm(RowIndex row) const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; SCOPED_TIME_STAT(&stats_); const RowIndex permuted_row = col_perm_.empty() ? row : ColToRowIndex(col_perm_[RowToColIndex(row)]); @@ -177,12 +175,11 @@ bool AreEqualWithPermutation(const DenseColumn &a, const DenseColumn &b, const RowPermutation &perm) { const RowIndex num_rows = perm.size(); for (RowIndex row(0); row < num_rows; ++row) { - if (a[row] != b[perm[row]]) - return false; + if (a[row] != b[perm[row]]) return false; } return true; } -} // namespace +} // namespace void LuFactorization::RightSolveLWithPermutedInput(const DenseColumn &a, ScatteredColumn *x) const { @@ -249,8 +246,7 @@ void LuFactorization::RightSolveLForColumnView(const ColumnView &b, } void LuFactorization::RightSolveLWithNonZeros(ScatteredColumn *x) const { - if (is_identity_factorization_) - return; + if (is_identity_factorization_) return; if (x->non_zeros.empty()) { PermuteWithScratchpad(row_perm_, &dense_zero_scratchpad_, &x->values); lower_.LowerSolve(&x->values); @@ -290,8 +286,7 @@ void LuFactorization::RightSolveLForScatteredColumn(const ScatteredColumn &b, void LuFactorization::LeftSolveUWithNonZeros(ScatteredRow *y) const { SCOPED_TIME_STAT(&stats_); CHECK(col_perm_.empty()); - if (is_identity_factorization_) - return; + if (is_identity_factorization_) return; DenseColumn *const x = reinterpret_cast(&y->values); RowIndexVector *const nz = reinterpret_cast(&y->non_zeros); @@ -307,8 +302,7 @@ void LuFactorization::LeftSolveUWithNonZeros(ScatteredRow *y) const { void LuFactorization::RightSolveUWithNonZeros(ScatteredColumn *x) const { SCOPED_TIME_STAT(&stats_); CHECK(col_perm_.empty()); - if (is_identity_factorization_) - return; + if (is_identity_factorization_) return; // If non-zeros is non-empty, we use an hypersparse solve. Note that if // non_zeros starts to be too big, we clear it and thus switch back to a @@ -442,20 +436,19 @@ double LuFactorization::GetFillInPercentage( const int initial_num_entries = matrix.num_entries().value(); const int lu_num_entries = (lower_.num_entries() + upper_.num_entries()).value(); - if (is_identity_factorization_ || initial_num_entries == 0) - return 1.0; + if (is_identity_factorization_ || initial_num_entries == 0) return 1.0; return static_cast(lu_num_entries) / static_cast(initial_num_entries); } EntryIndex LuFactorization::NumberOfEntries() const { - return is_identity_factorization_ ? EntryIndex(0) : lower_.num_entries() + - upper_.num_entries(); + return is_identity_factorization_ + ? EntryIndex(0) + : lower_.num_entries() + upper_.num_entries(); } Fractional LuFactorization::ComputeDeterminant() const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; DCHECK_EQ(upper_.num_rows().value(), upper_.num_cols().value()); Fractional product(1.0); for (ColIndex col(0); col < upper_.num_cols(); ++col) { @@ -466,8 +459,7 @@ Fractional LuFactorization::ComputeDeterminant() const { } Fractional LuFactorization::ComputeInverseOneNorm() const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; const RowIndex num_rows = lower_.num_rows(); const ColIndex num_cols = lower_.num_cols(); Fractional norm = 0.0; @@ -488,8 +480,7 @@ Fractional LuFactorization::ComputeInverseOneNorm() const { } Fractional LuFactorization::ComputeInverseInfinityNorm() const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; const RowIndex num_rows = lower_.num_rows(); const ColIndex num_cols = lower_.num_cols(); DenseColumn row_sum(num_rows, 0.0); @@ -513,15 +504,13 @@ Fractional LuFactorization::ComputeInverseInfinityNorm() const { Fractional LuFactorization::ComputeOneNormConditionNumber( const CompactSparseMatrixView &matrix) const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; return matrix.ComputeOneNorm() * ComputeInverseOneNorm(); } Fractional LuFactorization::ComputeInfinityNormConditionNumber( const CompactSparseMatrixView &matrix) const { - if (is_identity_factorization_) - return 1.0; + if (is_identity_factorization_) return 1.0; return matrix.ComputeInfinityNorm() * ComputeInverseInfinityNorm(); } @@ -542,7 +531,7 @@ double ComputeDensity(const SparseColumn &b, const RowPermutation &row_perm) { const RowIndex num_rows = row_perm.size(); return density / num_rows.value(); } -} // anonymous namespace +} // anonymous namespace void LuFactorization::ComputeTransposeUpper() { SCOPED_TIME_STAT(&stats_); @@ -556,8 +545,7 @@ void LuFactorization::ComputeTransposeLower() const { bool LuFactorization::CheckFactorization(const CompactSparseMatrixView &matrix, Fractional tolerance) const { - if (is_identity_factorization_) - return true; + if (is_identity_factorization_) return true; SparseMatrix lu; ComputeLowerTimesUpper(&lu); SparseMatrix paq; @@ -585,5 +573,5 @@ bool LuFactorization::CheckFactorization(const CompactSparseMatrixView &matrix, return true; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/lu_factorization.h b/ortools/glop/lu_factorization.h index aaeea04a0c..04b8e6f947 100644 --- a/ortools/glop/lu_factorization.h +++ b/ortools/glop/lu_factorization.h @@ -32,7 +32,7 @@ namespace glop { // all the Solve() functions that deal with the permutations and the L and U // factors once they are computed. class LuFactorization { -public: + public: LuFactorization(); // Returns true if the LuFactorization is a factorization of the identity @@ -53,7 +53,7 @@ public: // reason behind it is that this way, calling any public function of this // class will never cause a crash of the program. ABSL_MUST_USE_RESULT Status - ComputeFactorization(const CompactSparseMatrixView &compact_matrix); + ComputeFactorization(const CompactSparseMatrixView &compact_matrix); // Returns the column permutation used by the LU factorization. const ColumnPermutation &GetColumnPermutation() const { return col_perm_; } @@ -212,7 +212,7 @@ public: return inverse_col_perm_; } -private: + private: // Statistics about this class. struct Stats : public StatsGroup { Stats() @@ -289,6 +289,6 @@ private: DISALLOW_COPY_AND_ASSIGN(LuFactorization); }; -} // namespace glop -} // namespace operations_research -#endif // OR_TOOLS_GLOP_LU_FACTORIZATION_H_ +} // namespace glop +} // namespace operations_research +#endif // OR_TOOLS_GLOP_LU_FACTORIZATION_H_ diff --git a/ortools/glop/markowitz.cc b/ortools/glop/markowitz.cc index 95b9b2815e..e46f10dd92 100644 --- a/ortools/glop/markowitz.cc +++ b/ortools/glop/markowitz.cc @@ -34,8 +34,7 @@ Status Markowitz::ComputeRowAndColumnPermutation( row_perm->assign(num_rows, kInvalidRow); // Get the empty matrix corner case out of the way. - if (basis_matrix.IsEmpty()) - return Status::OK(); + if (basis_matrix.IsEmpty()) return Status::OK(); basis_matrix_ = &basis_matrix; // Initialize all the matrices. @@ -106,12 +105,11 @@ Status Markowitz::ComputeRowAndColumnPermutation( RemoveColumnFromResidualMatrix(pivot_row, pivot_col); } } else { - // TODO(user): Note that in some rare cases, because of numerical - // cancellation, the column degree may actually be smaller than - // pivot_col_degree. Exploit that better? - IF_STATS_ENABLED(if (pivot_col_degree == 2) { - ++stats_degree_two_pivot_columns; - }); + // TODO(user): Note that in some rare cases, because of numerical + // cancellation, the column degree may actually be smaller than + // pivot_col_degree. Exploit that better? + IF_STATS_ENABLED( + if (pivot_col_degree == 2) { ++stats_degree_two_pivot_columns; }); UpdateResidualMatrix(pivot_row, pivot_col); } @@ -135,10 +133,10 @@ Status Markowitz::ComputeRowAndColumnPermutation( ++index; } - stats_.pivots_without_fill_in_ratio - .Add(1.0 * stats_num_pivots_without_fill_in / end_index); - stats_.degree_two_pivot_columns - .Add(1.0 * stats_degree_two_pivot_columns / end_index); + stats_.pivots_without_fill_in_ratio.Add( + 1.0 * stats_num_pivots_without_fill_in / end_index); + stats_.degree_two_pivot_columns.Add(1.0 * stats_degree_two_pivot_columns / + end_index); return Status::OK(); } @@ -184,12 +182,11 @@ struct MatrixEntry { } }; -} // namespace +} // namespace -void -Markowitz::ExtractSingletonColumns(const CompactSparseMatrixView &basis_matrix, - RowPermutation *row_perm, - ColumnPermutation *col_perm, int *index) { +void Markowitz::ExtractSingletonColumns( + const CompactSparseMatrixView &basis_matrix, RowPermutation *row_perm, + ColumnPermutation *col_perm, int *index) { SCOPED_TIME_STAT(&stats_); std::vector singleton_entries; const ColIndex num_cols = basis_matrix.num_cols(); @@ -213,8 +210,8 @@ Markowitz::ExtractSingletonColumns(const CompactSparseMatrixView &basis_matrix, ++(*index); } } - stats_.basis_singleton_column_ratio - .Add(static_cast(*index) / num_cols.value()); + stats_.basis_singleton_column_ratio.Add(static_cast(*index) / + num_cols.value()); } bool Markowitz::IsResidualSingletonColumn(const ColumnView &column, @@ -222,11 +219,9 @@ bool Markowitz::IsResidualSingletonColumn(const ColumnView &column, RowIndex *row) { int residual_degree = 0; for (const auto e : column) { - if (row_perm[e.row()] != kInvalidRow) - continue; + if (row_perm[e.row()] != kInvalidRow) continue; ++residual_degree; - if (residual_degree > 1) - return false; + if (residual_degree > 1) return false; *row = e.row(); } return residual_degree == 1; @@ -239,19 +234,17 @@ void Markowitz::ExtractResidualSingletonColumns( const ColIndex num_cols = basis_matrix.num_cols(); RowIndex row = kInvalidRow; for (ColIndex col(0); col < num_cols; ++col) { - if ((*col_perm)[col] != kInvalidCol) - continue; + if ((*col_perm)[col] != kInvalidCol) continue; const ColumnView &column = basis_matrix.column(col); - if (!IsResidualSingletonColumn(column, *row_perm, &row)) - continue; + if (!IsResidualSingletonColumn(column, *row_perm, &row)) continue; (*col_perm)[col] = ColIndex(*index); (*row_perm)[row] = RowIndex(*index); lower_.AddDiagonalOnlyColumn(1.0); upper_.AddTriangularColumn(column, row); ++(*index); } - stats_.basis_residual_singleton_column_ratio - .Add(static_cast(*index) / num_cols.value()); + stats_.basis_residual_singleton_column_ratio.Add(static_cast(*index) / + num_cols.value()); } const SparseColumn &Markowitz::ComputeColumn(const RowPermutation &row_perm, @@ -320,8 +313,7 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, // // TODO(user): We could detect the singularity at this point, but that // may make the code more complex. - if (residual_matrix_non_zero_.ColDegree(col) != 1) - continue; + if (residual_matrix_non_zero_.ColDegree(col) != 1) continue; // ComputeColumn() is not used as long as only singleton columns of the // residual matrix are used. See the other condition in @@ -338,8 +330,7 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, return 0; } const SparseColumn &column = ComputeColumn(row_perm, col); - if (column.IsEmpty()) - continue; + if (column.IsEmpty()) continue; *pivot_col = col; *pivot_row = column.GetFirstRow(); *pivot_coefficient = column.GetFirstCoefficient(); @@ -356,20 +347,16 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, // A singleton row could have been processed when processing a singleton // column. Skip if this is the case. - if (row_perm[row] != kInvalidRow) - continue; + if (row_perm[row] != kInvalidRow) continue; // This shows that the matrix is singular, see comment above for the same // case when processing singleton columns. - if (residual_matrix_non_zero_.RowDegree(row) != 1) - continue; + if (residual_matrix_non_zero_.RowDegree(row) != 1) continue; const ColIndex col = residual_matrix_non_zero_.GetFirstNonDeletedColumnFromRow(row); - if (col == kInvalidCol) - continue; + if (col == kInvalidCol) continue; const SparseColumn &column = ComputeColumn(row_perm, col); - if (column.IsEmpty()) - continue; + if (column.IsEmpty()) continue; *pivot_col = col; *pivot_row = row; @@ -384,8 +371,7 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, const ColIndex num_cols = col_perm.size(); col_by_degree_.Reset(row_perm.size().value(), num_cols); for (ColIndex col(0); col < num_cols; ++col) { - if (col_perm[col] != kInvalidCol) - continue; + if (col_perm[col] != kInvalidCol) continue; const int degree = residual_matrix_non_zero_.ColDegree(col); DCHECK_NE(degree, 1); UpdateDegree(col, degree); @@ -400,10 +386,8 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, const Fractional threshold = parameters_.lu_factorization_pivot_threshold(); while (examined_col_.size() < num_columns_to_examine) { const ColIndex col = col_by_degree_.Pop(); - if (col == kInvalidCol) - break; - if (col_perm[col] != kInvalidCol) - continue; + if (col == kInvalidCol) break; + if (col_perm[col] != kInvalidCol) continue; const int col_degree = residual_matrix_non_zero_.ColDegree(col); examined_col_.push_back(col); @@ -417,8 +401,7 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, // // Todo(user): keep the minimum row degree to have a better bound? const int64 markowitz_lower_bound = col_degree - 1; - if (min_markowitz_number < markowitz_lower_bound) - break; + if (min_markowitz_number < markowitz_lower_bound) break; // TODO(user): col_degree (which is the same as column.num_entries()) is // actually an upper bound on the number of non-zeros since there may be @@ -441,8 +424,7 @@ int64 Markowitz::FindPivot(const RowPermutation &row_perm, const Fractional skip_threshold = threshold * max_magnitude; for (const SparseColumn::Entry e : column) { const Fractional magnitude = std::abs(e.coefficient()); - if (magnitude < skip_threshold) - continue; + if (magnitude < skip_threshold) continue; const int row_degree = residual_matrix_non_zero_.RowDegree(e.row()); const int64 markowitz_number = (col_degree - 1) * (row_degree - 1); @@ -513,14 +495,12 @@ void Markowitz::RemoveRowFromResidualMatrix(RowIndex pivot_row, // will not need the pivot row anymore. if (is_col_by_degree_initialized_) { for (const ColIndex col : residual_matrix_non_zero_.RowNonZero(pivot_row)) { - if (residual_matrix_non_zero_.IsColumnDeleted(col)) - continue; + if (residual_matrix_non_zero_.IsColumnDeleted(col)) continue; UpdateDegree(col, residual_matrix_non_zero_.DecreaseColDegree(col)); } } else { for (const ColIndex col : residual_matrix_non_zero_.RowNonZero(pivot_row)) { - if (residual_matrix_non_zero_.IsColumnDeleted(col)) - continue; + if (residual_matrix_non_zero_.IsColumnDeleted(col)) continue; if (residual_matrix_non_zero_.DecreaseColDegree(col) == 1) { singleton_column_.push_back(col); } @@ -605,8 +585,7 @@ void MatrixNonZeroPattern::InitializeFromMatrixSubset( for (RowIndex row(0); row < num_rows; ++row) { if (row_perm[row] == kInvalidRow) { row_non_zero_[row].reserve(row_degree_[row]); - if (row_degree_[row] == 1) - singleton_rows->push_back(row); + if (row_degree_[row] == 1) singleton_rows->push_back(row); } else { // This is needed because in the row degree computation above, we do not // test for row_perm[row] == kInvalidRow because it is a bit faster. @@ -616,8 +595,7 @@ void MatrixNonZeroPattern::InitializeFromMatrixSubset( // Initialize row_non_zero_. for (ColIndex col(0); col < num_cols; ++col) { - if (col_perm[col] != kInvalidCol) - continue; + if (col_perm[col] != kInvalidCol) continue; int32 col_degree = 0; for (const SparseColumn::Entry e : basis_matrix.column(col)) { const RowIndex row = e.row(); @@ -627,8 +605,7 @@ void MatrixNonZeroPattern::InitializeFromMatrixSubset( } } col_degree_[col] = col_degree; - if (col_degree == 1) - singleton_columns->push_back(col); + if (col_degree == 1) singleton_columns->push_back(col); } } @@ -674,11 +651,10 @@ void MatrixNonZeroPattern::RemoveDeletedColumnsFromRow(RowIndex row) { ref.resize(new_index); } -ColIndex -MatrixNonZeroPattern::GetFirstNonDeletedColumnFromRow(RowIndex row) const { +ColIndex MatrixNonZeroPattern::GetFirstNonDeletedColumnFromRow( + RowIndex row) const { for (const ColIndex col : RowNonZero(row)) { - if (!IsColumnDeleted(col)) - return col; + if (!IsColumnDeleted(col)) return col; } return kInvalidCol; } @@ -703,14 +679,12 @@ void MatrixNonZeroPattern::Update(RowIndex pivot_row, ColIndex pivot_col, // degrees due to the deletion of pivot_col will happen outside this function. for (const SparseColumn::Entry e : column) { const RowIndex row = e.row(); - if (row == pivot_row) - continue; + if (row == pivot_row) continue; // If the row is fully dense, there is nothing to do (the merge below will // not change anything). This is a small price to pay for a huge gain when // the matrix becomes dense. - if (e.coefficient() == 0.0 || row_degree_[row] == max_row_degree) - continue; + if (e.coefficient() == 0.0 || row_degree_[row] == max_row_degree) continue; DCHECK_LT(row_degree_[row], max_row_degree); // We only clean row_non_zero_[row] if there are more than 4 entries to @@ -724,7 +698,7 @@ void MatrixNonZeroPattern::Update(RowIndex pivot_row, ColIndex pivot_col, RemoveDeletedColumnsFromRow(row); } // TODO(user): Special case if row_non_zero_[pivot_row].size() == 1? - if (/* DISABLES CODE */(true)) { + if (/* DISABLES CODE */ (true)) { MergeInto(pivot_row, row); } else { // This is currently not used, but kept as an alternative algorithm to @@ -765,8 +739,7 @@ namespace { // of input_a will appear before the identical elements of the second input. template void MergeSortedVectors(const V &input_a, W *out) { - if (input_a.empty()) - return; + if (input_a.empty()) return; const auto &input_b = *out; int index_a = input_a.size() - 1; int index_b = input_b.size() - 1; @@ -792,7 +765,7 @@ void MergeSortedVectors(const V &input_a, W *out) { } } -} // namespace +} // namespace // The algorithm first computes into col_scratchpad_ the entries in pivot_row // that are not in the row (i.e. the fill-in). It then updates the non-zero @@ -804,9 +777,10 @@ void MatrixNonZeroPattern::MergeIntoSorted(RowIndex pivot_row, RowIndex row) { // These two resizes are because of the set_difference() output iterator api. col_scratchpad_.resize(input.size()); - col_scratchpad_.resize(std::set_difference( - input.begin(), input.end(), output.begin(), output.end(), - col_scratchpad_.begin()) - col_scratchpad_.begin()); + col_scratchpad_.resize(std::set_difference(input.begin(), input.end(), + output.begin(), output.end(), + col_scratchpad_.begin()) - + col_scratchpad_.begin()); // Add the fill-in to the pattern. for (const ColIndex col : col_scratchpad_) { @@ -856,8 +830,7 @@ void ColumnPriorityQueue::PushOrAdjust(ColIndex col, int32 degree) { ColIndex ColumnPriorityQueue::Pop() { while (col_by_degree_[min_degree_].empty()) { min_degree_++; - if (min_degree_ == col_by_degree_.size()) - return kInvalidCol; + if (min_degree_ == col_by_degree_.size()) return kInvalidCol; } const ColIndex col = col_by_degree_[min_degree_].back(); col_by_degree_[min_degree_].pop_back(); @@ -872,17 +845,15 @@ void SparseMatrixWithReusableColumnMemory::Reset(ColIndex num_cols) { columns_.clear(); } -const SparseColumn & -SparseMatrixWithReusableColumnMemory::column(ColIndex col) const { - if (mapping_[col] == -1) - return empty_column_; +const SparseColumn &SparseMatrixWithReusableColumnMemory::column( + ColIndex col) const { + if (mapping_[col] == -1) return empty_column_; return columns_[mapping_[col]]; } -SparseColumn * -SparseMatrixWithReusableColumnMemory::mutable_column(ColIndex col) { - if (mapping_[col] != -1) - return &columns_[mapping_[col]]; +SparseColumn *SparseMatrixWithReusableColumnMemory::mutable_column( + ColIndex col) { + if (mapping_[col] != -1) return &columns_[mapping_[col]]; int new_col_index; if (free_columns_.empty()) { new_col_index = columns_.size(); @@ -908,5 +879,5 @@ void SparseMatrixWithReusableColumnMemory::Clear() { columns_.clear(); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/markowitz.h b/ortools/glop/markowitz.h index 08022d72a3..0e38e3383a 100644 --- a/ortools/glop/markowitz.h +++ b/ortools/glop/markowitz.h @@ -96,7 +96,7 @@ namespace glop { // indices of the non-removed part do not change, so the residual matrix at a // given step will only correspond to a subset of the initial indices. class MatrixNonZeroPattern { -public: + public: MatrixNonZeroPattern() {} // Releases the memory used by this class. @@ -167,7 +167,7 @@ public: return row_non_zero_[row]; } -private: + private: // Augments the non-zero pattern of the given row by taking its union with the // non-zero pattern of the given pivot_row. void MergeInto(RowIndex pivot_row, RowIndex row); @@ -201,7 +201,7 @@ private: // smallest degree first (degree = number of entries in the column). // Empty columns (i.e. with degree 0) are not stored in the queue. class ColumnPriorityQueue { -public: + public: ColumnPriorityQueue() {} // Releases the memory used by this class. @@ -220,7 +220,7 @@ public: // it. Returns kInvalidCol if the queue is empty. ColIndex Pop(); -private: + private: StrictITIVector col_index_; StrictITIVector col_degree_; std::vector > col_by_degree_; @@ -233,7 +233,7 @@ private: // is needed at the same time (like it is the case in our LU algorithm). It // reuses the memory of the columns that are no longer needed. class SparseMatrixWithReusableColumnMemory { -public: + public: SparseMatrixWithReusableColumnMemory() {} // Resets the repository to num_cols empty columns. @@ -255,7 +255,7 @@ public: // be fine). void Clear(); -private: + private: // mutable_column(col) is stored in columns_[mapping_[col]]. // The columns_ that can be reused have their index stored in free_columns_. const SparseColumn empty_column_; @@ -269,7 +269,7 @@ private: // permutation P and Q such that P.B.Q^{-1} will have a sparse L.U // decomposition. class Markowitz { -public: + public: Markowitz() {} // Computes the full factorization with P, Q, L and U. @@ -280,9 +280,9 @@ public: // such that 'row_perm[row] == kInvalidRow', then the matrix will be // non-singular. ABSL_MUST_USE_RESULT Status - ComputeLU(const CompactSparseMatrixView &basis_matrix, - RowPermutation *row_perm, ColumnPermutation *col_perm, - TriangularMatrix *lower, TriangularMatrix *upper); + ComputeLU(const CompactSparseMatrixView &basis_matrix, + RowPermutation *row_perm, ColumnPermutation *col_perm, + TriangularMatrix *lower, TriangularMatrix *upper); // Only computes P and Q^{-1}, L and U can be computed later from these // permutations using another algorithm (for instance left-looking L.U). This @@ -309,7 +309,7 @@ public: parameters_ = parameters; } -private: + private: // Statistics about this class. struct Stats : public StatsGroup { Stats() @@ -442,7 +442,7 @@ private: DISALLOW_COPY_AND_ASSIGN(Markowitz); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_MARKOWITZ_H_ +#endif // OR_TOOLS_GLOP_MARKOWITZ_H_ diff --git a/ortools/glop/preprocessor.cc b/ortools/glop/preprocessor.cc index b9ebc342a6..cc23cb4bb9 100644 --- a/ortools/glop/preprocessor.cc +++ b/ortools/glop/preprocessor.cc @@ -37,14 +37,16 @@ std::string IntervalString(Fractional lb, Fractional ub) { #if defined(_MSC_VER) double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #endif -} // namespace +} // namespace // -------------------------------------------------------- // Preprocessor // -------------------------------------------------------- Preprocessor::Preprocessor(const GlopParameters *parameters) - : status_(ProblemStatus::INIT), parameters_(*parameters), - in_mip_context_(false), infinite_time_limit_(TimeLimit::Infinite()), + : status_(ProblemStatus::INIT), + parameters_(*parameters), + in_mip_context_(false), + infinite_time_limit_(TimeLimit::Infinite()), time_limit_(infinite_time_limit_.get()) {} Preprocessor::~Preprocessor() {} @@ -52,8 +54,8 @@ Preprocessor::~Preprocessor() {} // MainLpPreprocessor // -------------------------------------------------------- -#define RUN_PREPROCESSOR(name) \ - RunAndPushIfRelevant(std::unique_ptr(new name(¶meters_)), \ +#define RUN_PREPROCESSOR(name) \ + RunAndPushIfRelevant(std::unique_ptr(new name(¶meters_)), \ #name, time_limit_, lp) bool MainLpPreprocessor::Run(LinearProgram *lp) { @@ -129,8 +131,7 @@ void MainLpPreprocessor::RunAndPushIfRelevant( TimeLimit *time_limit, LinearProgram *lp) { RETURN_IF_NULL(preprocessor); RETURN_IF_NULL(time_limit); - if (status_ != ProblemStatus::INIT || time_limit->LimitReached()) - return; + if (status_ != ProblemStatus::INIT || time_limit->LimitReached()) return; const double start_time = time_limit->GetElapsedTime(); preprocessor->SetTimeLimit(time_limit); @@ -146,16 +147,16 @@ void MainLpPreprocessor::RunAndPushIfRelevant( const EntryIndex new_num_entries = lp->num_entries(); const double preprocess_time = time_limit->GetElapsedTime() - start_time; VLOG(1) << absl::StrFormat( - "%s(%fs): %d(%d) rows, %d(%d) columns, %d(%d) entries.", - name, preprocess_time, lp->num_constraints().value(), - (lp->num_constraints() - initial_num_rows_).value(), - lp->num_variables().value(), - (lp->num_variables() - initial_num_cols_).value(), - // static_cast is needed because the Android port uses - // int32. - static_cast(new_num_entries.value()), - static_cast(new_num_entries.value() - - initial_num_entries_.value())); + "%s(%fs): %d(%d) rows, %d(%d) columns, %d(%d) entries.", name, + preprocess_time, lp->num_constraints().value(), + (lp->num_constraints() - initial_num_rows_).value(), + lp->num_variables().value(), + (lp->num_variables() - initial_num_cols_).value(), + // static_cast is needed because the Android port uses + // int32. + static_cast(new_num_entries.value()), + static_cast(new_num_entries.value() - + initial_num_entries_.value())); status_ = preprocessor->status(); preprocessors_.push_back(std::move(preprocessor)); return; @@ -204,8 +205,8 @@ void ColumnDeletionHelper::MarkColumnForDeletionWithState( stored_status_[col] = status; } -void -ColumnDeletionHelper::RestoreDeletedColumns(ProblemSolution *solution) const { +void ColumnDeletionHelper::RestoreDeletedColumns( + ProblemSolution *solution) const { DenseRow new_primal_values; VariableStatusRow new_variable_statuses; ColIndex old_index(0); @@ -246,8 +247,7 @@ void RowDeletionHelper::MarkRowForDeletion(RowIndex row) { } void RowDeletionHelper::UnmarkRow(RowIndex row) { - if (row >= is_row_deleted_.size()) - return; + if (row >= is_row_deleted_.size()) return; is_row_deleted_[row] = false; } @@ -338,7 +338,7 @@ Fractional ComputeMaxVariableBoundsMagnitude(const LinearProgram &lp) { return max_bounds_magnitude; } -} // namespace +} // namespace bool EmptyColumnPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); @@ -436,7 +436,7 @@ struct ColumnWithRepresentativeAndScaledCost { } }; -} // namespace +} // namespace bool ProportionalColumnPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); @@ -462,8 +462,7 @@ bool ProportionalColumnPreprocessor::Run(LinearProgram *lp) { proportional_columns.push_back(col); } } - if (proportional_columns.empty()) - return false; + if (proportional_columns.empty()) return false; VLOG(1) << "The problem contains " << proportional_columns.size() << " columns which belong to " << num_proportionality_classes << " proportionality classes."; @@ -606,8 +605,7 @@ bool ProportionalColumnPreprocessor::Run(LinearProgram *lp) { int num_merged = 0; for (++i; i < sorted_columns.size(); ++i) { - if (sorted_columns[i].representative != target_representative) - break; + if (sorted_columns[i].representative != target_representative) break; if (std::abs(sorted_columns[i].scaled_cost - target_scaled_cost) >= parameters_.preprocessor_zero_tolerance()) { break; @@ -862,8 +860,7 @@ bool ProportionalRowPreprocessor::Run(LinearProgram *lp) { // a representative for each class of proportional columns that has at least // one of the two tightest bounds. for (RowIndex row(0); row < num_rows; ++row) { - if (!is_a_representative[row]) - continue; + if (!is_a_representative[row]) continue; const RowIndex lower_source = lower_bound_sources_[row]; const RowIndex upper_source = upper_bound_sources_[row]; lower_bound_sources_[row] = kInvalidRow; @@ -960,8 +957,8 @@ bool ProportionalRowPreprocessor::Run(LinearProgram *lp) { return !row_deletion_helper_.IsEmpty(); } -void -ProportionalRowPreprocessor::RecoverSolution(ProblemSolution *solution) const { +void ProportionalRowPreprocessor::RecoverSolution( + ProblemSolution *solution) const { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_IF_NULL(solution); row_deletion_helper_.RestoreDeletedRows(solution); @@ -973,25 +970,23 @@ ProportionalRowPreprocessor::RecoverSolution(ProblemSolution *solution) const { for (RowIndex row(0); row < num_rows; ++row) { const RowIndex lower_source = lower_bound_sources_[row]; const RowIndex upper_source = upper_bound_sources_[row]; - if (lower_source == kInvalidRow && upper_source == kInvalidRow) - continue; + if (lower_source == kInvalidRow && upper_source == kInvalidRow) continue; DCHECK_NE(lower_source, upper_source); DCHECK(lower_source == row || upper_source == row); // If the representative is ConstraintStatus::BASIC, then all rows in this // class will be ConstraintStatus::BASIC and there is nothing to do. ConstraintStatus status = solution->constraint_statuses[row]; - if (status == ConstraintStatus::BASIC) - continue; + if (status == ConstraintStatus::BASIC) continue; // If the row is FIXED it will behave as a row // ConstraintStatus::AT_UPPER_BOUND or // ConstraintStatus::AT_LOWER_BOUND depending on the corresponding dual // variable sign. if (status == ConstraintStatus::FIXED_VALUE) { - const Fractional corrected_dual_value = - lp_is_maximization_problem_ ? -solution->dual_values[row] - : solution->dual_values[row]; + const Fractional corrected_dual_value = lp_is_maximization_problem_ + ? -solution->dual_values[row] + : solution->dual_values[row]; if (corrected_dual_value != 0.0) { status = corrected_dual_value > 0.0 ? ConstraintStatus::AT_LOWER_BOUND : ConstraintStatus::AT_UPPER_BOUND; @@ -1058,8 +1053,8 @@ bool FixedVariablePreprocessor::Run(LinearProgram *lp) { return !column_deletion_helper_.IsEmpty(); } -void -FixedVariablePreprocessor::RecoverSolution(ProblemSolution *solution) const { +void FixedVariablePreprocessor::RecoverSolution( + ProblemSolution *solution) const { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_IF_NULL(solution); column_deletion_helper_.RestoreDeletedColumns(solution); @@ -1103,8 +1098,7 @@ bool ForcingAndImpliedFreeConstraintPreprocessor::Run(LinearProgram *lp) { is_forcing_up_.assign(num_rows, false); DenseBooleanColumn is_forcing_down(num_rows, false); for (RowIndex row(0); row < num_rows; ++row) { - if (row_degree[row] == 0) - continue; + if (row_degree[row] == 0) continue; Fractional lower = lp->constraint_lower_bounds()[row]; Fractional upper = lp->constraint_upper_bounds()[row]; @@ -1247,8 +1241,7 @@ void ForcingAndImpliedFreeConstraintPreprocessor::RecoverSolution( const ColIndex num_cols = deleted_columns_.num_cols(); ColToRowMapping last_deleted_row(num_cols, kInvalidRow); for (ColIndex col(0); col < num_cols; ++col) { - if (!column_deletion_helper_.IsColumnMarked(col)) - continue; + if (!column_deletion_helper_.IsColumnMarked(col)) continue; for (const SparseColumn::Entry e : deleted_columns_.column(col)) { const RowIndex row = e.row(); if (row_deletion_helper_.IsRowMarked(row)) { @@ -1276,8 +1269,7 @@ void ForcingAndImpliedFreeConstraintPreprocessor::RecoverSolution( ColIndex new_basic_column = kInvalidCol; for (const SparseColumn::Entry e : transpose.column(RowToColIndex(row))) { const ColIndex col = RowToColIndex(e.row()); - if (last_deleted_row[col] != row) - continue; + if (last_deleted_row[col] != row) continue; const Fractional scalar_product = ScalarProduct(solution->dual_values, deleted_columns_.column(col)); const Fractional reduced_cost = costs_[col] - scalar_product; @@ -1321,7 +1313,7 @@ struct ColWithDegree { return num_entries < other.num_entries; } }; -} // namespace +} // namespace bool ImpliedFreePreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); @@ -1346,8 +1338,7 @@ bool ImpliedFreePreprocessor::Run(LinearProgram *lp) { for (const SparseColumn::Entry e : lp->GetSparseColumn(col)) { Fractional entry_lb = e.coefficient() * lower_bound; Fractional entry_ub = e.coefficient() * upper_bound; - if (e.coefficient() < 0.0) - std::swap(entry_lb, entry_ub); + if (e.coefficient() < 0.0) std::swap(entry_lb, entry_ub); lb_sums[e.row()].Add(entry_lb); ub_sums[e.row()].Add(entry_ub); } @@ -1406,8 +1397,7 @@ bool ImpliedFreePreprocessor::Run(LinearProgram *lp) { ++num_already_free_variables; continue; } - if (lower_bound == upper_bound) - continue; + if (lower_bound == upper_bound) continue; // Detect if the variable is implied free. Fractional overall_implied_lb = -kInfinity; @@ -1415,15 +1405,13 @@ bool ImpliedFreePreprocessor::Run(LinearProgram *lp) { for (const SparseColumn::Entry e : lp->GetSparseColumn(col)) { // If the row contains another implied free variable, then the bounds // implied by it will just be [-kInfinity, kInfinity] so we can skip it. - if (used_rows[e.row()]) - continue; + if (used_rows[e.row()]) continue; // This is the contribution of this column to the sum above. const Fractional coeff = e.coefficient(); Fractional entry_lb = coeff * lower_bound; Fractional entry_ub = coeff * upper_bound; - if (coeff < 0.0) - std::swap(entry_lb, entry_ub); + if (coeff < 0.0) std::swap(entry_lb, entry_ub); // If X is the variable with index col and Y the sum of all the other // variables and of (-activity), then coeff * X + Y = 0. Since Y's bounds @@ -1431,8 +1419,7 @@ bool ImpliedFreePreprocessor::Run(LinearProgram *lp) { // implied bounds on X. Fractional implied_lb = -ub_sums[e.row()].SumWithout(entry_ub) / coeff; Fractional implied_ub = -lb_sums[e.row()].SumWithout(entry_lb) / coeff; - if (coeff < 0.0) - std::swap(implied_lb, implied_ub); + if (coeff < 0.0) std::swap(implied_lb, implied_ub); overall_implied_lb = std::max(overall_implied_lb, implied_lb); overall_implied_ub = std::min(overall_implied_ub, implied_ub); } @@ -1551,12 +1538,9 @@ bool DoubletonFreeColumnPreprocessor::Run(LinearProgram *lp) { const ColIndex num_cols(lp->num_variables()); for (ColIndex doubleton_col(0); doubleton_col < num_cols; ++doubleton_col) { // Only consider doubleton free columns. - if (original_matrix.column(doubleton_col).num_entries() != 2) - continue; - if (lp->variable_lower_bounds()[doubleton_col] != -kInfinity) - continue; - if (lp->variable_upper_bounds()[doubleton_col] != kInfinity) - continue; + if (original_matrix.column(doubleton_col).num_entries() != 2) continue; + if (lp->variable_lower_bounds()[doubleton_col] != -kInfinity) continue; + if (lp->variable_upper_bounds()[doubleton_col] != kInfinity) continue; // Collect the two column items. Note that we skip a column involving a // deleted row since it is no longer a doubleton then. @@ -1565,15 +1549,13 @@ bool DoubletonFreeColumnPreprocessor::Run(LinearProgram *lp) { r.objective_coefficient = lp->objective_coefficients()[r.col]; int index = 0; for (const SparseColumn::Entry e : original_matrix.column(r.col)) { - if (row_deletion_helper_.IsRowMarked(e.row())) - break; + if (row_deletion_helper_.IsRowMarked(e.row())) break; r.row[index] = e.row(); r.coeff[index] = e.coefficient(); DCHECK_NE(0.0, e.coefficient()); ++index; } - if (index != NUM_ROWS) - continue; + if (index != NUM_ROWS) continue; // Since the column didn't touch any previously deleted row, we are sure // that the coefficients were left untouched. @@ -1594,8 +1576,8 @@ bool DoubletonFreeColumnPreprocessor::Run(LinearProgram *lp) { // transpose at the same time. This last operation is not strictly needed, // but it is faster to do it this way (both here and later when we will take // the transpose of the final transpose matrix). - r.deleted_row_as_column - .Swap(transpose->mutable_column(RowToColIndex(r.row[DELETED]))); + r.deleted_row_as_column.Swap( + transpose->mutable_column(RowToColIndex(r.row[DELETED]))); // Move the bound of the deleted constraint to the initially free variable. { @@ -1605,8 +1587,7 @@ bool DoubletonFreeColumnPreprocessor::Run(LinearProgram *lp) { lp->constraint_upper_bounds()[r.row[DELETED]]; new_variable_lb /= r.coeff[DELETED]; new_variable_ub /= r.coeff[DELETED]; - if (r.coeff[DELETED] < 0.0) - std::swap(new_variable_lb, new_variable_ub); + if (r.coeff[DELETED] < 0.0) std::swap(new_variable_lb, new_variable_ub); lp->SetVariableBounds(r.col, new_variable_lb, new_variable_ub); } @@ -1622,8 +1603,7 @@ bool DoubletonFreeColumnPreprocessor::Run(LinearProgram *lp) { if (r.objective_coefficient != 0.0) { for (const SparseColumn::Entry e : r.deleted_row_as_column) { const ColIndex col = RowToColIndex(e.row()); - if (col == r.col) - continue; + if (col == r.col) continue; const Fractional new_objective = lp->objective_coefficients()[col] - e.coefficient() * r.objective_coefficient / r.coeff[DELETED]; @@ -1659,28 +1639,28 @@ void DoubletonFreeColumnPreprocessor::RecoverSolution( for (const RestoreInfo &r : Reverse(restore_stack_)) { // Correct the constraint status. switch (solution->variable_statuses[r.col]) { - case VariableStatus::FIXED_VALUE: - solution->constraint_statuses[r.row[DELETED]] = - ConstraintStatus::FIXED_VALUE; - break; - case VariableStatus::AT_UPPER_BOUND: - solution->constraint_statuses[r.row[DELETED]] = - r.coeff[DELETED] > 0.0 ? ConstraintStatus::AT_UPPER_BOUND - : ConstraintStatus::AT_LOWER_BOUND; - break; - case VariableStatus::AT_LOWER_BOUND: - solution->constraint_statuses[r.row[DELETED]] = - r.coeff[DELETED] > 0.0 ? ConstraintStatus::AT_LOWER_BOUND - : ConstraintStatus::AT_UPPER_BOUND; - break; - case VariableStatus::FREE: - solution->constraint_statuses[r.row[DELETED]] = ConstraintStatus::FREE; - break; - case VariableStatus::BASIC: - // The default is good here: - DCHECK_EQ(solution->constraint_statuses[r.row[DELETED]], - ConstraintStatus::BASIC); - break; + case VariableStatus::FIXED_VALUE: + solution->constraint_statuses[r.row[DELETED]] = + ConstraintStatus::FIXED_VALUE; + break; + case VariableStatus::AT_UPPER_BOUND: + solution->constraint_statuses[r.row[DELETED]] = + r.coeff[DELETED] > 0.0 ? ConstraintStatus::AT_UPPER_BOUND + : ConstraintStatus::AT_LOWER_BOUND; + break; + case VariableStatus::AT_LOWER_BOUND: + solution->constraint_statuses[r.row[DELETED]] = + r.coeff[DELETED] > 0.0 ? ConstraintStatus::AT_LOWER_BOUND + : ConstraintStatus::AT_UPPER_BOUND; + break; + case VariableStatus::FREE: + solution->constraint_statuses[r.row[DELETED]] = ConstraintStatus::FREE; + break; + case VariableStatus::BASIC: + // The default is good here: + DCHECK_EQ(solution->constraint_statuses[r.row[DELETED]], + ConstraintStatus::BASIC); + break; } // Correct the primal variable value. @@ -1688,8 +1668,7 @@ void DoubletonFreeColumnPreprocessor::RecoverSolution( Fractional new_variable_value = solution->primal_values[r.col]; for (const SparseColumn::Entry e : r.deleted_row_as_column) { const ColIndex col = RowToColIndex(e.row()); - if (col == r.col) - continue; + if (col == r.col) continue; new_variable_value -= (e.coefficient() / r.coeff[DELETED]) * solution->primal_values[RowToColIndex(e.row())]; } @@ -1729,7 +1708,7 @@ bool IsConstraintBlockingVariable(const LinearProgram &lp, Fractional direction, : lp.constraint_lower_bounds()[row] != -kInfinity; } -} // namespace +} // namespace void UnconstrainedVariablePreprocessor::RemoveZeroCostUnconstrainedVariable( ColIndex col, Fractional target_bound, LinearProgram *lp) { @@ -1752,16 +1731,16 @@ void UnconstrainedVariablePreprocessor::RemoveZeroCostUnconstrainedVariable( row_deletion_helper_.MarkRowForDeletion(row); const ColIndex row_as_col = RowToColIndex(row); deleted_rows_as_column_.mutable_column(row_as_col) - ->PopulateFromSparseVector(lp->GetTransposeSparseMatrix() - .column(row_as_col)); + ->PopulateFromSparseVector( + lp->GetTransposeSparseMatrix().column(row_as_col)); } const bool is_constraint_upper_bound_relevant = e.coefficient() > 0.0 ? !is_unbounded_up : is_unbounded_up; activity_sign_correction_[row] = is_constraint_upper_bound_relevant ? 1.0 : -1.0; - rhs_[row] = - is_constraint_upper_bound_relevant ? lp->constraint_upper_bounds()[row] - : lp->constraint_lower_bounds()[row]; + rhs_[row] = is_constraint_upper_bound_relevant + ? lp->constraint_upper_bounds()[row] + : lp->constraint_lower_bounds()[row]; // TODO(user): Here, we may render the row free, so subsequent columns // processed by the columns loop in Run() have more chance to be removed. @@ -1825,8 +1804,7 @@ bool UnconstrainedVariablePreprocessor::Run(LinearProgram *lp) { const ColIndex col = columns_to_process.front(); columns_to_process.pop_front(); in_columns_to_process[col] = false; - if (column_deletion_helper_.IsColumnMarked(col)) - continue; + if (column_deletion_helper_.IsColumnMarked(col)) continue; const SparseColumn &column = lp->GetSparseColumn(col); const Fractional col_cost = @@ -1840,8 +1818,7 @@ bool UnconstrainedVariablePreprocessor::Run(LinearProgram *lp) { rc_lb.Add(col_cost); rc_ub.Add(col_cost); for (const SparseColumn::Entry e : column) { - if (row_deletion_helper_.IsRowMarked(e.row())) - continue; + if (row_deletion_helper_.IsRowMarked(e.row())) continue; const Fractional coeff = e.coefficient(); if (coeff > 0.0) { rc_lb.Add(-coeff * dual_ub_[e.row()]); @@ -1904,8 +1881,7 @@ bool UnconstrainedVariablePreprocessor::Run(LinearProgram *lp) { // not block it in one direction. // // TODO(user): deal with the more generic case. - if (col_cost != 0.0) - continue; + if (col_cost != 0.0) continue; bool skip = false; for (const SparseColumn::Entry e : column) { // Note that it is important to check the rows that are already @@ -1915,13 +1891,11 @@ bool UnconstrainedVariablePreprocessor::Run(LinearProgram *lp) { break; } } - if (skip) - continue; + if (skip) continue; // TODO(user): this also works if the variable is integer, but we must // choose an integer value during the post-solve. Implement this. - if (in_mip_context_) - continue; + if (in_mip_context_) continue; RemoveZeroCostUnconstrainedVariable(col, target_bound, lp); continue; } @@ -1931,18 +1905,15 @@ bool UnconstrainedVariablePreprocessor::Run(LinearProgram *lp) { // it if the column was removed or if it is not unconstrained in some // direction. DCHECK(!can_be_removed); - if (col_lb != -kInfinity && col_ub != kInfinity) - continue; + if (col_lb != -kInfinity && col_ub != kInfinity) continue; // For MIP, we only exploit the constraints. TODO(user): It should probably // work with only small modification, investigate. - if (in_mip_context_) - continue; + if (in_mip_context_) continue; changed_rows.clear(); for (const SparseColumn::Entry e : column) { - if (row_deletion_helper_.IsRowMarked(e.row())) - continue; + if (row_deletion_helper_.IsRowMarked(e.row())) continue; const Fractional c = e.coefficient(); const RowIndex row = e.row(); if (col_ub == kInfinity) { @@ -2039,8 +2010,7 @@ void UnconstrainedVariablePreprocessor::RecoverSolution( // Note that this will be empty if there were no deleted rows. const ColIndex num_cols = is_unbounded_.size(); for (ColIndex col(0); col < num_cols; ++col) { - if (!is_unbounded_[col]) - continue; + if (!is_unbounded_[col]) continue; Fractional primal_value_shift = 0.0; RowIndex row_at_bound = kInvalidRow; for (const SparseColumn::Entry e : deleted_columns_.column(col)) { @@ -2050,8 +2020,7 @@ void UnconstrainedVariablePreprocessor::RecoverSolution( // Note that currently VariableStatus::FREE rows should be removed before // this is called. DCHECK(IsFinite(rhs_[row])); - if (last_deleted_column[row] != col || !IsFinite(rhs_[row])) - continue; + if (last_deleted_column[row] != col || !IsFinite(rhs_[row])) continue; const SparseColumn &row_as_column = deleted_rows_as_column_.column(RowToColIndex(row)); const Fractional activity = @@ -2099,8 +2068,8 @@ bool FreeConstraintPreprocessor::Run(LinearProgram *lp) { return !row_deletion_helper_.IsEmpty(); } -void -FreeConstraintPreprocessor::RecoverSolution(ProblemSolution *solution) const { +void FreeConstraintPreprocessor::RecoverSolution( + ProblemSolution *solution) const { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_IF_NULL(solution); row_deletion_helper_.RestoreDeletedRows(solution); @@ -2147,8 +2116,8 @@ bool EmptyConstraintPreprocessor::Run(LinearProgram *lp) { return !row_deletion_helper_.IsEmpty(); } -void -EmptyConstraintPreprocessor::RecoverSolution(ProblemSolution *solution) const { +void EmptyConstraintPreprocessor::RecoverSolution( + ProblemSolution *solution) const { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_IF_NULL(solution); row_deletion_helper_.RestoreDeletedRows(solution); @@ -2160,7 +2129,9 @@ EmptyConstraintPreprocessor::RecoverSolution(ProblemSolution *solution) const { SingletonUndo::SingletonUndo(OperationType type, const LinearProgram &lp, MatrixEntry e, ConstraintStatus status) - : type_(type), is_maximization_(lp.IsMaximizationProblem()), e_(e), + : type_(type), + is_maximization_(lp.IsMaximizationProblem()), + e_(e), cost_(lp.objective_coefficients()[e.col]), variable_lower_bound_(lp.variable_lower_bounds()[e.col]), variable_upper_bound_(lp.variable_upper_bounds()[e.col]), @@ -2173,18 +2144,18 @@ void SingletonUndo::Undo(const GlopParameters ¶meters, const SparseMatrix &deleted_rows, ProblemSolution *solution) const { switch (type_) { - case SINGLETON_ROW: - SingletonRowUndo(deleted_columns, solution); - break; - case ZERO_COST_SINGLETON_COLUMN: - ZeroCostSingletonColumnUndo(parameters, deleted_rows, solution); - break; - case SINGLETON_COLUMN_IN_EQUALITY: - SingletonColumnInEqualityUndo(parameters, deleted_rows, solution); - break; - case MAKE_CONSTRAINT_AN_EQUALITY: - MakeConstraintAnEqualityUndo(solution); - break; + case SINGLETON_ROW: + SingletonRowUndo(deleted_columns, solution); + break; + case ZERO_COST_SINGLETON_COLUMN: + ZeroCostSingletonColumnUndo(parameters, deleted_rows, solution); + break; + case SINGLETON_COLUMN_IN_EQUALITY: + SingletonColumnInEqualityUndo(parameters, deleted_rows, solution); + break; + case MAKE_CONSTRAINT_AN_EQUALITY: + MakeConstraintAnEqualityUndo(solution); + break; } } @@ -2216,8 +2187,9 @@ void SingletonPreprocessor::DeleteSingletonRow(MatrixEntry e, if (!IsSmallerWithinFeasibilityTolerance(new_lower_bound, new_upper_bound)) { VLOG(1) << "Problem ProblemStatus::INFEASIBLE_OR_UNBOUNDED, singleton " - "row causes the bound of the variable " << e.col - << " to be infeasible by " << new_lower_bound - new_upper_bound; + "row causes the bound of the variable " + << e.col << " to be infeasible by " + << new_lower_bound - new_upper_bound; status_ = ProblemStatus::PRIMAL_INFEASIBLE; return; } @@ -2234,8 +2206,8 @@ void SingletonPreprocessor::DeleteSingletonRow(MatrixEntry e, undo_stack_.push_back(SingletonUndo(SingletonUndo::SINGLETON_ROW, *lp, e, ConstraintStatus::FREE)); if (deleted_columns_.column(e.col).IsEmpty()) { - deleted_columns_.mutable_column(e.col) - ->PopulateFromSparseVector(lp->GetSparseColumn(e.col)); + deleted_columns_.mutable_column(e.col)->PopulateFromSparseVector( + lp->GetSparseColumn(e.col)); } lp->SetVariableBounds(e.col, new_lower_bound, new_upper_bound); @@ -2250,8 +2222,7 @@ void SingletonUndo::SingletonRowUndo(const SparseMatrix &deleted_columns, // VariableStatus::BASIC and // 0.0 as the dual value. const VariableStatus status = solution->variable_statuses[e_.col]; - if (status == VariableStatus::BASIC || status == VariableStatus::FREE) - return; + if (status == VariableStatus::BASIC || status == VariableStatus::FREE) return; // Compute whether or not the variable bounds changed. Fractional implied_lower_bound = constraint_lower_bound_ / e_.coeff; @@ -2262,12 +2233,9 @@ void SingletonUndo::SingletonRowUndo(const SparseMatrix &deleted_columns, const bool lower_bound_changed = implied_lower_bound > variable_lower_bound_; const bool upper_bound_changed = implied_upper_bound < variable_upper_bound_; - if (!lower_bound_changed && !upper_bound_changed) - return; - if (status == VariableStatus::AT_LOWER_BOUND && !lower_bound_changed) - return; - if (status == VariableStatus::AT_UPPER_BOUND && !upper_bound_changed) - return; + if (!lower_bound_changed && !upper_bound_changed) return; + if (status == VariableStatus::AT_LOWER_BOUND && !lower_bound_changed) return; + if (status == VariableStatus::AT_UPPER_BOUND && !upper_bound_changed) return; // This is the reduced cost of the variable before the singleton constraint is // added back. @@ -2298,9 +2266,9 @@ void SingletonUndo::SingletonRowUndo(const SparseMatrix &deleted_columns, ConstraintStatus new_constraint_status = VariableToConstraintStatus(status); if (status == VariableStatus::FIXED_VALUE && (!lower_bound_changed || !upper_bound_changed)) { - new_constraint_status = - lower_bound_changed ? ConstraintStatus::AT_LOWER_BOUND - : ConstraintStatus::AT_UPPER_BOUND; + new_constraint_status = lower_bound_changed + ? ConstraintStatus::AT_LOWER_BOUND + : ConstraintStatus::AT_UPPER_BOUND; } if (e_.coeff < 0.0) { if (new_constraint_status == ConstraintStatus::AT_LOWER_BOUND) { @@ -2381,10 +2349,9 @@ void SingletonPreprocessor::DeleteZeroCostSingletonColumn( } // We need to restore the variable value in order to satisfy the constraint. -void -SingletonUndo::ZeroCostSingletonColumnUndo(const GlopParameters ¶meters, - const SparseMatrix &deleted_rows, - ProblemSolution *solution) const { +void SingletonUndo::ZeroCostSingletonColumnUndo( + const GlopParameters ¶meters, const SparseMatrix &deleted_rows, + ProblemSolution *solution) const { // If the variable was fixed, this is easy. Note that this is the only // possible case if the current constraint status is FIXED. if (variable_upper_bound_ == variable_lower_bound_) { @@ -2424,11 +2391,10 @@ SingletonUndo::ZeroCostSingletonColumnUndo(const GlopParameters ¶meters, // Preprocessor::IsSmallerWithinPreprocessorZeroTolerance() which we can't use // here because we are not deriving from the Preprocessor class. const Fractional tolerance = parameters.preprocessor_zero_tolerance(); - const auto is_smaller_with_tolerance = - [tolerance](Fractional a, Fractional b) { + const auto is_smaller_with_tolerance = [tolerance](Fractional a, + Fractional b) { return ::operations_research::IsSmallerWithinTolerance(a, b, tolerance); - } - ; + }; if (variable_lower_bound_ != -kInfinity) { const Fractional activity_at_lb = activity + e_.coeff * variable_lower_bound_; @@ -2539,10 +2505,9 @@ void SingletonPreprocessor::DeleteSingletonColumnInEquality( column_deletion_helper_.MarkColumnForDeletion(e.col); } -void -SingletonUndo::SingletonColumnInEqualityUndo(const GlopParameters ¶meters, - const SparseMatrix &deleted_rows, - ProblemSolution *solution) const { +void SingletonUndo::SingletonColumnInEqualityUndo( + const GlopParameters ¶meters, const SparseMatrix &deleted_rows, + ProblemSolution *solution) const { // First do the same as a zero-cost singleton column. ZeroCostSingletonColumnUndo(parameters, deleted_rows, solution); @@ -2555,8 +2520,8 @@ SingletonUndo::SingletonColumnInEqualityUndo(const GlopParameters ¶meters, } } -void -SingletonUndo::MakeConstraintAnEqualityUndo(ProblemSolution *solution) const { +void SingletonUndo::MakeConstraintAnEqualityUndo( + ProblemSolution *solution) const { if (solution->constraint_statuses[e_.row] == ConstraintStatus::FIXED_VALUE) { solution->constraint_statuses[e_.row] = constraint_status_; } @@ -2568,8 +2533,7 @@ bool SingletonPreprocessor::MakeConstraintAnEqualityIfPossible( // infinity. const Fractional cst_lower_bound = lp->constraint_lower_bounds()[e.row]; const Fractional cst_upper_bound = lp->constraint_upper_bounds()[e.row]; - if (cst_lower_bound == cst_upper_bound) - return true; + if (cst_lower_bound == cst_upper_bound) return true; // To be efficient, we only process a row once and cache the domain that an // "artificial" extra variable x with coefficient 1.0 could take while still @@ -2597,8 +2561,7 @@ bool SingletonPreprocessor::MakeConstraintAnEqualityIfPossible( // // TODO(user): Find a more robust way? it seems easy to add new deletion // rules that may break this assumption. - if (column_deletion_helper_.IsColumnMarked(row_as_col)) - continue; + if (column_deletion_helper_.IsColumnMarked(row_as_col)) continue; if (entry.coefficient() > 0.0) { row_lb_sum_[e.row].Add(-entry.coefficient() * variable_ubs[row_as_col]); row_ub_sum_[e.row].Add(-entry.coefficient() * variable_lbs[row_as_col]); @@ -2653,8 +2616,9 @@ bool SingletonPreprocessor::MakeConstraintAnEqualityIfPossible( if (status_ == ProblemStatus::INFEASIBLE_OR_UNBOUNDED) { DCHECK_EQ(ub, kInfinity); VLOG(1) << "Problem ProblemStatus::INFEASIBLE_OR_UNBOUNDED, singleton " - "variable " << e.col << " has a cost (for minimization) of " - << cost << " and is unbounded towards kInfinity."; + "variable " + << e.col << " has a cost (for minimization) of " << cost + << " and is unbounded towards kInfinity."; return false; } @@ -2694,8 +2658,9 @@ bool SingletonPreprocessor::MakeConstraintAnEqualityIfPossible( if (status_ == ProblemStatus::INFEASIBLE_OR_UNBOUNDED) { DCHECK_EQ(lb, -kInfinity); VLOG(1) << "Problem ProblemStatus::INFEASIBLE_OR_UNBOUNDED, singleton " - "variable " << e.col << " has a cost (for minimization) of " - << cost << " and is unbounded towards -kInfinity."; + "variable " + << e.col << " has a cost (for minimization) of " << cost + << " and is unbounded towards -kInfinity."; return false; } @@ -2750,8 +2715,7 @@ bool SingletonPreprocessor::Run(LinearProgram *lp) { while (status_ == ProblemStatus::INIT && !column_to_process.empty()) { const ColIndex col = column_to_process.back(); column_to_process.pop_back(); - if (column_degree[col] <= 0) - continue; + if (column_degree[col] <= 0) continue; const MatrixEntry e = GetSingletonColumnMatrixEntry(col, matrix); if (in_mip_context_ && lp->IsVariableInteger(e.col) && !IntegerSingletonColumnIsRemovable(e, *lp)) { @@ -2775,8 +2739,7 @@ bool SingletonPreprocessor::Run(LinearProgram *lp) { while (status_ == ProblemStatus::INIT && !row_to_process.empty()) { const RowIndex row = row_to_process.back(); row_to_process.pop_back(); - if (row_degree[row] <= 0) - continue; + if (row_degree[row] <= 0) continue; const MatrixEntry e = GetSingletonRowMatrixEntry(row, transpose); DeleteSingletonRow(e, lp); @@ -2787,8 +2750,7 @@ bool SingletonPreprocessor::Run(LinearProgram *lp) { } } - if (status_ != ProblemStatus::INIT) - return false; + if (status_ != ProblemStatus::INIT) return false; lp->DeleteColumns(column_deletion_helper_.GetMarkedColumns()); lp->DeleteRows(row_deletion_helper_.GetMarkedRows()); return !column_deletion_helper_.IsEmpty() || !row_deletion_helper_.IsEmpty(); @@ -2851,8 +2813,7 @@ bool RemoveNearZeroEntriesPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_VALUE_IF_NULL(lp, false); const ColIndex num_cols = lp->num_variables(); - if (num_cols == 0) - return false; + if (num_cols == 0) return false; // We will use a different threshold for each row depending on its degree. // We use Fractionals for convenience since they will be used as such below. @@ -2887,15 +2848,15 @@ bool RemoveNearZeroEntriesPreprocessor::Run(LinearProgram *lp) { // can use this better estimate here and remove more near-zero entries. const Fractional max_magnitude = std::max(std::abs(lower_bound), std::abs(upper_bound)); - if (max_magnitude == kInfinity || max_magnitude == 0) - continue; + if (max_magnitude == kInfinity || max_magnitude == 0) continue; const Fractional threshold = allowed_impact / max_magnitude; - lp->GetMutableSparseColumn(col) - ->RemoveNearZeroEntriesWithWeights(threshold, row_degree); + lp->GetMutableSparseColumn(col)->RemoveNearZeroEntriesWithWeights( + threshold, row_degree); if (lp->objective_coefficients()[col] != 0.0 && num_non_zero_objective_coefficients * - std::abs(lp->objective_coefficients()[col]) < threshold) { + std::abs(lp->objective_coefficients()[col]) < + threshold) { lp->SetObjectiveCoefficient(col, 0.0); ++num_zeroed_objective_coefficients; } @@ -2926,8 +2887,7 @@ bool SingletonColumnSignPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_VALUE_IF_NULL(lp, false); const ColIndex num_cols = lp->num_variables(); - if (num_cols == 0) - return false; + if (num_cols == 0) return false; changed_columns_.clear(); int num_singletons = 0; @@ -3004,12 +2964,11 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { // always pick the first column as the to-be-deleted one. // TODO(user): make a smarter choice of which column to delete, and // swap col[] and coeff[] accordingly. - RestoreInfo r; // Use a short name since we're using it everywhere. + RestoreInfo r; // Use a short name since we're using it everywhere. int entry_index = 0; for (const SparseColumn::Entry e : original_row) { const ColIndex col = RowToColIndex(e.row()); - if (column_deletion_helper_.IsColumnMarked(col)) - continue; + if (column_deletion_helper_.IsColumnMarked(col)) continue; r.col[entry_index] = col; r.coeff[entry_index] = e.coefficient(); DCHECK_NE(0.0, r.coeff[entry_index]); @@ -3019,8 +2978,7 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { // Discard some cases that will be treated by other preprocessors, or by // another run of this one. // 1) One or two of the items were in a deleted column. - if (entry_index < 2) - continue; + if (entry_index < 2) continue; // Fill the RestoreInfo, even if we end up not using it (because we // give up on preprocessing this row): it has a bunch of handy shortcuts. @@ -3078,8 +3036,9 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { } else { lb = carried_over_lb; r.bound_backtracking_at_lower_bound = RestoreInfo::ColChoiceAndStatus( - DELETED, carry_over_factor > 0 ? VariableStatus::AT_LOWER_BOUND - : VariableStatus::AT_UPPER_BOUND, + DELETED, + carry_over_factor > 0 ? VariableStatus::AT_LOWER_BOUND + : VariableStatus::AT_UPPER_BOUND, carry_over_factor > 0 ? r.lb[DELETED] : r.ub[DELETED]); } if (carried_over_ub >= ub) { @@ -3089,15 +3048,15 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { } else { ub = carried_over_ub; r.bound_backtracking_at_upper_bound = RestoreInfo::ColChoiceAndStatus( - DELETED, carry_over_factor > 0 ? VariableStatus::AT_UPPER_BOUND - : VariableStatus::AT_LOWER_BOUND, + DELETED, + carry_over_factor > 0 ? VariableStatus::AT_UPPER_BOUND + : VariableStatus::AT_LOWER_BOUND, carry_over_factor > 0 ? r.ub[DELETED] : r.lb[DELETED]); } // 3) If the new bounds are fixed (the domain is a singleton) or // infeasible, then we let the // ForcingAndImpliedFreeConstraintPreprocessor do the work. - if (IsSmallerWithinPreprocessorZeroTolerance(ub, lb)) - continue; + if (IsSmallerWithinPreprocessorZeroTolerance(ub, lb)) continue; lp->SetVariableBounds(r.col[MODIFIED], lb, ub); } @@ -3110,8 +3069,8 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { // Looking at the matrix, this translates into colY += (-b/a) colX. DCHECK_NE(r.coeff[DELETED], 0.0); const Fractional substitution_factor = - -r.coeff[MODIFIED] / r.coeff[DELETED]; // -b/a - const Fractional constant_offset_factor = r.rhs / r.coeff[DELETED]; // c/a + -r.coeff[MODIFIED] / r.coeff[DELETED]; // -b/a + const Fractional constant_offset_factor = r.rhs / r.coeff[DELETED]; // c/a // Again we don't bother too much with over/underflows. if (!IsFinite(substitution_factor) || substitution_factor == 0.0 || !IsFinite(constant_offset_factor)) { @@ -3146,8 +3105,7 @@ bool DoubletonEqualityRowPreprocessor::Run(LinearProgram *lp) { column_deletion_helper_.MarkColumnForDeletion(r.col[DELETED]); row_deletion_helper_.MarkRowForDeletion(row); } - if (status_ != ProblemStatus::INIT) - return false; + if (status_ != ProblemStatus::INIT) return false; lp->DeleteColumns(column_deletion_helper_.GetMarkedColumns()); lp->DeleteRows(row_deletion_helper_.GetMarkedRows()); return !column_deletion_helper_.IsEmpty(); @@ -3161,49 +3119,50 @@ void DoubletonEqualityRowPreprocessor::RecoverSolution( row_deletion_helper_.RestoreDeletedRows(solution); for (const RestoreInfo &r : Reverse(restore_stack_)) { switch (solution->variable_statuses[r.col[MODIFIED]]) { - case VariableStatus::FIXED_VALUE: - LOG(DFATAL) << "FIXED variable produced by DoubletonPreprocessor!"; - // In non-fastbuild mode, we rely on the rest of the code producing an - // ProblemStatus::ABNORMAL status here. - break; - // When the modified variable is either basic or free, we keep it as is, - // and simply make the deleted one basic. - case VariableStatus::FREE: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::BASIC: - // Several code paths set the deleted column as basic. The code that - // sets its value in that case is below, after the switch() block. - solution->variable_statuses[r.col[DELETED]] = VariableStatus::BASIC; - break; - case VariableStatus::AT_LOWER_BOUND: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::AT_UPPER_BOUND: { - // The bound was induced by a bound of one of the two original - // variables. Put that original variable at its bound, and make - // the other one basic. - const RestoreInfo::ColChoiceAndStatus &bound_backtracking = - solution->variable_statuses[r.col[MODIFIED]] == - VariableStatus::AT_LOWER_BOUND - ? r.bound_backtracking_at_lower_bound - : r.bound_backtracking_at_upper_bound; - const ColIndex bounded_var = r.col[bound_backtracking.col_choice]; - const ColIndex basic_var = - r.col[OtherColChoice(bound_backtracking.col_choice)]; - solution->variable_statuses[bounded_var] = bound_backtracking.status; - solution->primal_values[bounded_var] = bound_backtracking.value; - solution->variable_statuses[basic_var] = VariableStatus::BASIC; - // If the modified column is VariableStatus::BASIC, then its value is - // already set - // correctly. If it's the deleted column that is basic, its value is - // set below the switch() block. - } + case VariableStatus::FIXED_VALUE: + LOG(DFATAL) << "FIXED variable produced by DoubletonPreprocessor!"; + // In non-fastbuild mode, we rely on the rest of the code producing an + // ProblemStatus::ABNORMAL status here. + break; + // When the modified variable is either basic or free, we keep it as is, + // and simply make the deleted one basic. + case VariableStatus::FREE: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::BASIC: + // Several code paths set the deleted column as basic. The code that + // sets its value in that case is below, after the switch() block. + solution->variable_statuses[r.col[DELETED]] = VariableStatus::BASIC; + break; + case VariableStatus::AT_LOWER_BOUND: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::AT_UPPER_BOUND: { + // The bound was induced by a bound of one of the two original + // variables. Put that original variable at its bound, and make + // the other one basic. + const RestoreInfo::ColChoiceAndStatus &bound_backtracking = + solution->variable_statuses[r.col[MODIFIED]] == + VariableStatus::AT_LOWER_BOUND + ? r.bound_backtracking_at_lower_bound + : r.bound_backtracking_at_upper_bound; + const ColIndex bounded_var = r.col[bound_backtracking.col_choice]; + const ColIndex basic_var = + r.col[OtherColChoice(bound_backtracking.col_choice)]; + solution->variable_statuses[bounded_var] = bound_backtracking.status; + solution->primal_values[bounded_var] = bound_backtracking.value; + solution->variable_statuses[basic_var] = VariableStatus::BASIC; + // If the modified column is VariableStatus::BASIC, then its value is + // already set + // correctly. If it's the deleted column that is basic, its value is + // set below the switch() block. + } } // Restore the value of the deleted column if it is VariableStatus::BASIC. if (solution->variable_statuses[r.col[DELETED]] == VariableStatus::BASIC) { solution->primal_values[r.col[DELETED]] = - (r.rhs - solution->primal_values[r.col[MODIFIED]] * - r.coeff[MODIFIED]) / r.coeff[DELETED]; + (r.rhs - + solution->primal_values[r.col[MODIFIED]] * r.coeff[MODIFIED]) / + r.coeff[DELETED]; } // Make the deleted constraint status FIXED. @@ -3242,8 +3201,7 @@ void FixConstraintWithFixedStatuses(const DenseColumn &row_lower_bounds, if (solution->constraint_statuses[row] != ConstraintStatus::FIXED_VALUE) { continue; } - if (row_lower_bounds[row] == row_upper_bounds[row]) - continue; + if (row_lower_bounds[row] == row_upper_bounds[row]) continue; // We need to fix the status and we just need to make sure that the bound we // choose satisfies the LP optimality conditions. @@ -3255,9 +3213,8 @@ void FixConstraintWithFixedStatuses(const DenseColumn &row_lower_bounds, } } -void -DoubletonEqualityRowPreprocessor::SwapDeletedAndModifiedVariableRestoreInfo( - RestoreInfo *r) { +void DoubletonEqualityRowPreprocessor:: + SwapDeletedAndModifiedVariableRestoreInfo(RestoreInfo *r) { using std::swap; swap(r->col[DELETED], r->col[MODIFIED]); swap(r->coeff[DELETED], r->coeff[MODIFIED]); @@ -3496,23 +3453,23 @@ void DualizerPreprocessor::RecoverSolution(ProblemSolution *solution) const { new_constraint_statuses.swap(solution->constraint_statuses); } -ProblemStatus -DualizerPreprocessor::ChangeStatusToDualStatus(ProblemStatus status) const { +ProblemStatus DualizerPreprocessor::ChangeStatusToDualStatus( + ProblemStatus status) const { switch (status) { - case ProblemStatus::PRIMAL_INFEASIBLE: - return ProblemStatus::DUAL_INFEASIBLE; - case ProblemStatus::DUAL_INFEASIBLE: - return ProblemStatus::PRIMAL_INFEASIBLE; - case ProblemStatus::PRIMAL_UNBOUNDED: - return ProblemStatus::DUAL_UNBOUNDED; - case ProblemStatus::DUAL_UNBOUNDED: - return ProblemStatus::PRIMAL_UNBOUNDED; - case ProblemStatus::PRIMAL_FEASIBLE: - return ProblemStatus::DUAL_FEASIBLE; - case ProblemStatus::DUAL_FEASIBLE: - return ProblemStatus::PRIMAL_FEASIBLE; - default: - return status; + case ProblemStatus::PRIMAL_INFEASIBLE: + return ProblemStatus::DUAL_INFEASIBLE; + case ProblemStatus::DUAL_INFEASIBLE: + return ProblemStatus::PRIMAL_INFEASIBLE; + case ProblemStatus::PRIMAL_UNBOUNDED: + return ProblemStatus::DUAL_UNBOUNDED; + case ProblemStatus::DUAL_UNBOUNDED: + return ProblemStatus::PRIMAL_UNBOUNDED; + case ProblemStatus::PRIMAL_FEASIBLE: + return ProblemStatus::DUAL_FEASIBLE; + case ProblemStatus::DUAL_FEASIBLE: + return ProblemStatus::PRIMAL_FEASIBLE; + default: + return status; } } @@ -3540,8 +3497,7 @@ bool ShiftVariableBoundsPreprocessor::Run(LinearProgram *lp) { << ComputeMaxVariableBoundsMagnitude(*lp); // Abort early if there is nothing to do. - if (all_variable_domains_contain_zero) - return false; + if (all_variable_domains_contain_zero) return false; // Shift the variable bounds and compute the changes to the constraint bounds // and objective offset in a precise way. @@ -3599,19 +3555,19 @@ void ShiftVariableBoundsPreprocessor::RecoverSolution( solution->primal_values[col] += offsets_[col]; } else { switch (solution->variable_statuses[col]) { - case VariableStatus::FIXED_VALUE: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::AT_LOWER_BOUND: - solution->primal_values[col] = variable_initial_lbs_[col]; - break; - case VariableStatus::AT_UPPER_BOUND: - solution->primal_values[col] = variable_initial_ubs_[col]; - break; - case VariableStatus::BASIC: - solution->primal_values[col] += offsets_[col]; - break; - case VariableStatus::FREE: - break; + case VariableStatus::FIXED_VALUE: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::AT_LOWER_BOUND: + solution->primal_values[col] = variable_initial_lbs_[col]; + break; + case VariableStatus::AT_UPPER_BOUND: + solution->primal_values[col] = variable_initial_ubs_[col]; + break; + case VariableStatus::BASIC: + solution->primal_values[col] += offsets_[col]; + break; + case VariableStatus::FREE: + break; } } } @@ -3624,8 +3580,7 @@ void ShiftVariableBoundsPreprocessor::RecoverSolution( bool ScalingPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_VALUE_IF_NULL(lp, false); - if (!parameters_.use_scaling()) - return false; + if (!parameters_.use_scaling()) return false; // Save the linear program bounds before scaling them. const ColIndex num_cols = lp->num_variables(); @@ -3665,18 +3620,18 @@ void ScalingPreprocessor::RecoverSolution(ProblemSolution *solution) const { const ColIndex num_cols = solution->primal_values.size(); for (ColIndex col(0); col < num_cols; ++col) { switch (solution->variable_statuses[col]) { - case VariableStatus::AT_UPPER_BOUND: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::FIXED_VALUE: - solution->primal_values[col] = variable_upper_bounds_[col]; - break; - case VariableStatus::AT_LOWER_BOUND: - solution->primal_values[col] = variable_lower_bounds_[col]; - break; - case VariableStatus::FREE: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::BASIC: - break; + case VariableStatus::AT_UPPER_BOUND: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::FIXED_VALUE: + solution->primal_values[col] = variable_upper_bounds_[col]; + break; + case VariableStatus::AT_LOWER_BOUND: + solution->primal_values[col] = variable_lower_bounds_[col]; + break; + case VariableStatus::FREE: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::BASIC: + break; } } } @@ -3702,8 +3657,8 @@ bool ToMinimizationPreprocessor::Run(LinearProgram *lp) { return false; } -void -ToMinimizationPreprocessor::RecoverSolution(ProblemSolution *solution) const {} +void ToMinimizationPreprocessor::RecoverSolution( + ProblemSolution *solution) const {} // -------------------------------------------------------- // AddSlackVariablesPreprocessor @@ -3712,7 +3667,7 @@ ToMinimizationPreprocessor::RecoverSolution(ProblemSolution *solution) const {} bool AddSlackVariablesPreprocessor::Run(LinearProgram *lp) { SCOPED_INSTRUCTION_COUNT(time_limit_); RETURN_VALUE_IF_NULL(lp, false); - lp->AddSlackVariablesWhereNecessary(/*detect_integer_constraints=*/ true); + lp->AddSlackVariablesWhereNecessary(/*detect_integer_constraints=*/true); first_slack_col_ = lp->GetFirstSlackVariable(); return true; } @@ -3732,15 +3687,15 @@ void AddSlackVariablesPreprocessor::RecoverSolution( // The slack variables have reversed bounds - if the value of the variable // is at one bound, the value of the constraint is at the opposite bound. switch (variable_status) { - case VariableStatus::AT_LOWER_BOUND: - constraint_status = ConstraintStatus::AT_UPPER_BOUND; - break; - case VariableStatus::AT_UPPER_BOUND: - constraint_status = ConstraintStatus::AT_LOWER_BOUND; - break; - default: - constraint_status = VariableToConstraintStatus(variable_status); - break; + case VariableStatus::AT_LOWER_BOUND: + constraint_status = ConstraintStatus::AT_UPPER_BOUND; + break; + case VariableStatus::AT_UPPER_BOUND: + constraint_status = ConstraintStatus::AT_LOWER_BOUND; + break; + default: + constraint_status = VariableToConstraintStatus(variable_status); + break; } solution->constraint_statuses[row] = constraint_status; } @@ -3750,5 +3705,5 @@ void AddSlackVariablesPreprocessor::RecoverSolution( solution->variable_statuses.resize(first_slack_col_, VariableStatus::FREE); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/preprocessor.h b/ortools/glop/preprocessor.h index 77bcb29210..6d79d00a76 100644 --- a/ortools/glop/preprocessor.h +++ b/ortools/glop/preprocessor.h @@ -40,7 +40,7 @@ namespace glop { // TODO(user): On most preprocessors, calling Run() more than once will not work // as expected. Fix? or document and crash in debug if this happens. class Preprocessor { -public: + public: explicit Preprocessor(const GlopParameters *parameters); Preprocessor(const Preprocessor &) = delete; Preprocessor &operator=(const Preprocessor &) = delete; @@ -73,7 +73,7 @@ public: void SetTimeLimit(TimeLimit *time_limit) { time_limit_ = time_limit; } -protected: + protected: // Returns true if a is less than b (or slighlty greater than b with a given // tolerance). bool IsSmallerWithinFeasibilityTolerance(Fractional a, Fractional b) const { @@ -100,7 +100,7 @@ protected: // This is the main LP preprocessor responsible for calling all the other // preprocessors in this file, possibly more than once. class MainLpPreprocessor : public Preprocessor { -public: + public: explicit MainLpPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} MainLpPreprocessor(const MainLpPreprocessor &) = delete; @@ -110,7 +110,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const override; -private: + private: // Runs the given preprocessor and push it on preprocessors_ for the postsolve // step when needed. void RunAndPushIfRelevant(std::unique_ptr preprocessor, @@ -135,7 +135,7 @@ private: // -------------------------------------------------------- // Help preprocessors deal with column deletion. class ColumnDeletionHelper { -public: + public: ColumnDeletionHelper() {} ColumnDeletionHelper(const ColumnDeletionHelper &) = delete; ColumnDeletionHelper &operator=(const ColumnDeletionHelper &) = delete; @@ -175,7 +175,7 @@ public: // make sense. const DenseRow &GetStoredValue() const { return stored_value_; } -private: + private: DenseBooleanRow is_column_deleted_; // Note that this vector has the same size as is_column_deleted_ and that @@ -191,7 +191,7 @@ private: // -------------------------------------------------------- // Help preprocessors deal with row deletion. class RowDeletionHelper { -public: + public: RowDeletionHelper() {} RowDeletionHelper(const RowDeletionHelper &) = delete; RowDeletionHelper &operator=(const RowDeletionHelper &) = delete; @@ -221,7 +221,7 @@ public: // This latter value is important, many preprocessors rely on it. void RestoreDeletedRows(ProblemSolution *solution) const; -private: + private: DenseBooleanColumn is_row_deleted_; }; @@ -230,7 +230,7 @@ private: // -------------------------------------------------------- // Removes the empty columns from the problem. class EmptyColumnPreprocessor : public Preprocessor { -public: + public: explicit EmptyColumnPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} EmptyColumnPreprocessor(const EmptyColumnPreprocessor &) = delete; @@ -239,7 +239,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: ColumnDeletionHelper column_deletion_helper_; }; @@ -254,7 +254,7 @@ private: // scaled. However, during presolve the columns can't be assumed to be scaled, // so it makes sense to use the more general notion of proportional columns. class ProportionalColumnPreprocessor : public Preprocessor { -public: + public: explicit ProportionalColumnPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ProportionalColumnPreprocessor(const ProportionalColumnPreprocessor &) = @@ -266,7 +266,7 @@ public: void RecoverSolution(ProblemSolution *solution) const final; void UseInMipContext() final { LOG(FATAL) << "Not implemented."; } -private: + private: // Postsolve information about proportional columns with the same scaled cost // that were merged during presolve. @@ -295,7 +295,7 @@ private: // The linear programming literature also calls such rows duplicates, see the // same remark above for columns in ProportionalColumnPreprocessor. class ProportionalRowPreprocessor : public Preprocessor { -public: + public: explicit ProportionalRowPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ProportionalRowPreprocessor(const ProportionalRowPreprocessor &) = delete; @@ -305,7 +305,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: // Informations about proportional rows, only filled for such rows. DenseColumn row_factors_; RowMapping upper_bound_sources_; @@ -337,7 +337,7 @@ struct MatrixEntry { // Stores the information needed to undo a singleton row/column deletion. class SingletonUndo { -public: + public: // The type of a given operation. typedef enum { ZERO_COST_SINGLETON_COLUMN, @@ -361,7 +361,7 @@ public: const SparseMatrix &deleted_columns, const SparseMatrix &deleted_rows, ProblemSolution *solution) const; -private: + private: // Actual undo functions for each OperationType. // Undo() just calls the correct one. void SingletonRowUndo(const SparseMatrix &deleted_columns, @@ -394,7 +394,7 @@ private: // Deletes as many singleton rows or singleton columns as possible. Note that // each time we delete a row or a column, new singletons may be created. class SingletonPreprocessor : public Preprocessor { -public: + public: explicit SingletonPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} SingletonPreprocessor(const SingletonPreprocessor &) = delete; @@ -403,7 +403,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: // Returns the MatrixEntry of the given singleton row or column, taking into // account the rows and columns that were already deleted. MatrixEntry GetSingletonColumnMatrixEntry(ColIndex col, @@ -480,7 +480,7 @@ private: // -------------------------------------------------------- // Removes the fixed variables from the problem. class FixedVariablePreprocessor : public Preprocessor { -public: + public: explicit FixedVariablePreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} FixedVariablePreprocessor(const FixedVariablePreprocessor &) = delete; @@ -490,7 +490,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: ColumnDeletionHelper column_deletion_helper_; }; @@ -515,7 +515,7 @@ private: // // * Otherwise, wo do nothing. class ForcingAndImpliedFreeConstraintPreprocessor : public Preprocessor { -public: + public: explicit ForcingAndImpliedFreeConstraintPreprocessor( const GlopParameters *parameters) : Preprocessor(parameters) {} @@ -527,7 +527,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: bool lp_is_maximization_problem_; SparseMatrix deleted_columns_; DenseRow costs_; @@ -561,7 +561,7 @@ private: // later passes to create more doubleton columns? Such columns lead to a smaller // problem thanks to the DoubletonFreeColumnPreprocessor. class ImpliedFreePreprocessor : public Preprocessor { -public: + public: explicit ImpliedFreePreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ImpliedFreePreprocessor(const ImpliedFreePreprocessor &) = delete; @@ -570,7 +570,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: // This preprocessor adds fixed offsets to some variables. We remember those // here to un-offset them in RecoverSolution(). DenseRow variable_offsets_; @@ -607,7 +607,7 @@ private: // columns if one of the two rows is also an equality which is not actually // required. Most probably, commercial solvers do use it though. class DoubletonFreeColumnPreprocessor : public Preprocessor { -public: + public: explicit DoubletonFreeColumnPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} DoubletonFreeColumnPreprocessor(const DoubletonFreeColumnPreprocessor &) = @@ -618,7 +618,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: enum RowChoice { DELETED = 0, MODIFIED = 1, @@ -658,7 +658,7 @@ private: // variables to their bounds. This is called forcing and dominated columns in // the Andersen & Andersen paper. class UnconstrainedVariablePreprocessor : public Preprocessor { -public: + public: explicit UnconstrainedVariablePreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} UnconstrainedVariablePreprocessor(const UnconstrainedVariablePreprocessor &) = @@ -683,7 +683,7 @@ public: Fractional target_bound, LinearProgram *lp); -private: + private: // Lower/upper bounds on the feasible dual value. We use constraints and // variables unbounded in one direction to derive these bounds. We use these // bounds to compute bounds on the reduced costs of the problem variables. @@ -712,7 +712,7 @@ private: // -------------------------------------------------------- // Removes the constraints with no bounds from the problem. class FreeConstraintPreprocessor : public Preprocessor { -public: + public: explicit FreeConstraintPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} FreeConstraintPreprocessor(const FreeConstraintPreprocessor &) = delete; @@ -722,7 +722,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: RowDeletionHelper row_deletion_helper_; }; @@ -731,7 +731,7 @@ private: // -------------------------------------------------------- // Removes the constraints with no coefficients from the problem. class EmptyConstraintPreprocessor : public Preprocessor { -public: + public: explicit EmptyConstraintPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} EmptyConstraintPreprocessor(const EmptyConstraintPreprocessor &) = delete; @@ -741,7 +741,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: RowDeletionHelper row_deletion_helper_; }; @@ -756,7 +756,7 @@ private: // particular, it will set the objective to zero if all the objective // coefficients are small! Run it after ScalingPreprocessor or fix the code. class RemoveNearZeroEntriesPreprocessor : public Preprocessor { -public: + public: explicit RemoveNearZeroEntriesPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} RemoveNearZeroEntriesPreprocessor(const RemoveNearZeroEntriesPreprocessor &) = @@ -767,7 +767,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: }; // -------------------------------------------------------- @@ -778,7 +778,7 @@ private: // be transformed in an identity column by the scaling. This will lead to more // efficient solve when this column is involved. class SingletonColumnSignPreprocessor : public Preprocessor { -public: + public: explicit SingletonColumnSignPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} SingletonColumnSignPreprocessor(const SingletonColumnSignPreprocessor &) = @@ -789,7 +789,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: std::vector changed_columns_; }; @@ -800,7 +800,7 @@ private: // by substitution (and thus removal) of one of the variables by the other // in all the constraints that it is involved in. class DoubletonEqualityRowPreprocessor : public Preprocessor { -public: + public: explicit DoubletonEqualityRowPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} DoubletonEqualityRowPreprocessor(const DoubletonEqualityRowPreprocessor &) = @@ -811,7 +811,7 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: enum ColChoice { DELETED = 0, MODIFIED = 1, @@ -828,7 +828,7 @@ private: struct RestoreInfo { // The row index of the doubleton equality constraint, and its constant. RowIndex row; - Fractional rhs; // The constant c in the equality aX + bY = c. + Fractional rhs; // The constant c in the equality aX + bY = c. // The indices and the data of the two columns that we touched, exactly // as they were beforehand. @@ -887,7 +887,7 @@ void FixConstraintWithFixedStatuses(const DenseColumn &row_lower_bounds, // IMPORTANT: FreeConstraintPreprocessor() must be called first since this // preprocessor does not deal correctly with free constraints. class DualizerPreprocessor : public Preprocessor { -public: + public: explicit DualizerPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} DualizerPreprocessor(const DualizerPreprocessor &) = delete; @@ -903,7 +903,7 @@ public: // Convert the given problem status to the one of its dual. ProblemStatus ChangeStatusToDualStatus(ProblemStatus status) const; -private: + private: DenseRow variable_lower_bounds_; DenseRow variable_upper_bounds_; @@ -945,7 +945,7 @@ private: // [-1e10, 1e10] may introduce numerical issues. Relax the definition of // a free variable so that only having a domain containing 0.0 is enough? class ShiftVariableBoundsPreprocessor : public Preprocessor { -public: + public: explicit ShiftVariableBoundsPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ShiftVariableBoundsPreprocessor(const ShiftVariableBoundsPreprocessor &) = @@ -958,7 +958,7 @@ public: const DenseRow &offsets() const { return offsets_; } -private: + private: // Contains for each variable by how much its bounds where shifted during // presolve. Note that the shift was negative (new bound = initial bound - // offset). @@ -975,7 +975,7 @@ private: // Scales the SparseMatrix of the linear program using a SparseMatrixScaler. // This is only applied if the parameter use_scaling is true. class ScalingPreprocessor : public Preprocessor { -public: + public: explicit ScalingPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ScalingPreprocessor(const ScalingPreprocessor &) = delete; @@ -985,7 +985,7 @@ public: void RecoverSolution(ProblemSolution *solution) const final; void UseInMipContext() final { LOG(FATAL) << "Not implemented."; } -private: + private: DenseRow variable_lower_bounds_; DenseRow variable_upper_bounds_; Fractional cost_scaling_factor_; @@ -998,7 +998,7 @@ private: // -------------------------------------------------------- // Changes the problem from maximization to minimization (if applicable). class ToMinimizationPreprocessor : public Preprocessor { -public: + public: explicit ToMinimizationPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} ToMinimizationPreprocessor(const ToMinimizationPreprocessor &) = delete; @@ -1023,7 +1023,7 @@ public: // after this preprocessor. Note that the slack variables are always added last, // so that the rightmost square sub-matrix is always the identity matrix. class AddSlackVariablesPreprocessor : public Preprocessor { -public: + public: explicit AddSlackVariablesPreprocessor(const GlopParameters *parameters) : Preprocessor(parameters) {} AddSlackVariablesPreprocessor(const AddSlackVariablesPreprocessor &) = delete; @@ -1033,11 +1033,11 @@ public: bool Run(LinearProgram *lp) final; void RecoverSolution(ProblemSolution *solution) const final; -private: + private: ColIndex first_slack_col_; }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_PREPROCESSOR_H_ +#endif // OR_TOOLS_GLOP_PREPROCESSOR_H_ diff --git a/ortools/glop/primal_edge_norms.cc b/ortools/glop/primal_edge_norms.cc index 2a6a287ed6..d4f6fe18e0 100644 --- a/ortools/glop/primal_edge_norms.cc +++ b/ortools/glop/primal_edge_norms.cc @@ -22,11 +22,17 @@ namespace glop { PrimalEdgeNorms::PrimalEdgeNorms(const CompactSparseMatrix &compact_matrix, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization) - : compact_matrix_(compact_matrix), variables_info_(variables_info), - basis_factorization_(basis_factorization), stats_(), - recompute_edge_squared_norms_(true), reset_devex_weights_(true), - edge_squared_norms_(), matrix_column_norms_(), devex_weights_(), - direction_left_inverse_(), num_operations_(0) {} + : compact_matrix_(compact_matrix), + variables_info_(variables_info), + basis_factorization_(basis_factorization), + stats_(), + recompute_edge_squared_norms_(true), + reset_devex_weights_(true), + edge_squared_norms_(), + matrix_column_norms_(), + devex_weights_(), + direction_left_inverse_(), + num_operations_(0) {} void PrimalEdgeNorms::Clear() { SCOPED_TIME_STAT(&stats_); @@ -39,20 +45,17 @@ bool PrimalEdgeNorms::NeedsBasisRefactorization() const { } const DenseRow &PrimalEdgeNorms::GetEdgeSquaredNorms() { - if (recompute_edge_squared_norms_) - ComputeEdgeSquaredNorms(); + if (recompute_edge_squared_norms_) ComputeEdgeSquaredNorms(); return edge_squared_norms_; } const DenseRow &PrimalEdgeNorms::GetDevexWeights() { - if (reset_devex_weights_) - ResetDevexWeights(); + if (reset_devex_weights_) ResetDevexWeights(); return devex_weights_; } const DenseRow &PrimalEdgeNorms::GetMatrixColumnNorms() { - if (matrix_column_norms_.empty()) - ComputeMatrixColumnNorms(); + if (matrix_column_norms_.empty()) ComputeMatrixColumnNorms(); return matrix_column_norms_; } @@ -127,9 +130,8 @@ void PrimalEdgeNorms::ComputeEdgeSquaredNorms() { for (const ColIndex col : variables_info_.GetIsRelevantBitRow()) { // Note the +1.0 in the squared norm for the component of the edge on the // 'entering_col'. - edge_squared_norms_[col] = - 1.0 + - basis_factorization_.RightSolveSquaredNorm(compact_matrix_.column(col)); + edge_squared_norms_[col] = 1.0 + basis_factorization_.RightSolveSquaredNorm( + compact_matrix_.column(col)); } recompute_edge_squared_norms_ = false; } @@ -137,9 +139,8 @@ void PrimalEdgeNorms::ComputeEdgeSquaredNorms() { // TODO(user): It should be possible to reorganize the code and call this when // the value of direction is no longer needed. This will simplify the code and // avoid a copy here. -void -PrimalEdgeNorms::ComputeDirectionLeftInverse(ColIndex entering_col, - const ScatteredColumn &direction) { +void PrimalEdgeNorms::ComputeDirectionLeftInverse( + ColIndex entering_col, const ScatteredColumn &direction) { SCOPED_TIME_STAT(&stats_); // Initialize direction_left_inverse_ to direction. Note the special case when @@ -165,9 +166,10 @@ PrimalEdgeNorms::ComputeDirectionLeftInverse(ColIndex entering_col, basis_factorization_.LeftSolve(&direction_left_inverse_); // TODO(user): Refactorize if estimated accuracy above a threshold. - IF_STATS_ENABLED(stats_.direction_left_inverse_accuracy.Add(ScalarProduct( - direction_left_inverse_.values, - matrix_.column(entering_col)) - SquaredNorm(direction.values))); + IF_STATS_ENABLED(stats_.direction_left_inverse_accuracy.Add( + ScalarProduct(direction_left_inverse_.values, + matrix_.column(entering_col)) - + SquaredNorm(direction.values))); IF_STATS_ENABLED(stats_.direction_left_inverse_density.Add( Density(direction_left_inverse_.values))); } @@ -258,5 +260,5 @@ void PrimalEdgeNorms::ResetDevexWeights() { reset_devex_weights_ = false; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/primal_edge_norms.h b/ortools/glop/primal_edge_norms.h index e92de8647c..1fcf41ec06 100644 --- a/ortools/glop/primal_edge_norms.h +++ b/ortools/glop/primal_edge_norms.h @@ -52,7 +52,7 @@ namespace glop { // - Ping-Qi Pan, "Efficient nested pricing in the simplex algorithm", // http://www.optimization-online.org/DB_FILE/2007/10/1810.pdf class PrimalEdgeNorms { -public: + public: // Takes references to the linear program data we need. Note that we assume // that the matrix will never change in our back, but the other references are // supposed to reflect the correct state. @@ -119,7 +119,7 @@ public: return DeterministicTimeForFpOperations(num_operations_); } -private: + private: // Statistics about this class. struct Stats : public StatsGroup { Stats() @@ -202,7 +202,7 @@ private: DISALLOW_COPY_AND_ASSIGN(PrimalEdgeNorms); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_PRIMAL_EDGE_NORMS_H_ +#endif // OR_TOOLS_GLOP_PRIMAL_EDGE_NORMS_H_ diff --git a/ortools/glop/rank_one_update.h b/ortools/glop/rank_one_update.h index e39f897707..c5aa75dcb4 100644 --- a/ortools/glop/rank_one_update.h +++ b/ortools/glop/rank_one_update.h @@ -36,7 +36,7 @@ namespace glop { // Qi Huangfu, J. A. Julian Hall, "Novel update techniques for the revised // simplex method", 28 january 2013, Technical Report ERGO-13-0001 class RankOneUpdateElementaryMatrix { -public: + public: // Rather than copying the vectors u and v, RankOneUpdateElementaryMatrix // takes two columns of a provided CompactSparseMatrix which is used for // storage. This has a couple of advantages, especially in the context of the @@ -46,7 +46,9 @@ public: RankOneUpdateElementaryMatrix(const CompactSparseMatrix *storage, ColIndex u_index, ColIndex v_index, Fractional u_dot_v) - : storage_(storage), u_index_(u_index), v_index_(v_index), + : storage_(storage), + u_index_(u_index), + v_index_(v_index), mu_(1.0 + u_dot_v) {} // Returns whether or not this matrix is singular. @@ -110,7 +112,7 @@ public: storage_->column(v_index_).num_entries(); } -private: + private: // This is only used in debug mode. Fractional ComputeUScalarV() const { DenseColumn dense_u; @@ -129,7 +131,7 @@ private: // A rank one update factorization corresponds to the product of k rank one // update elementary matrices, i.e. T = T_0.T_1. ... .T_{k-1} class RankOneUpdateFactorization { -public: + public: // TODO(user): make the 5% a parameter and share it between all the places // that switch between a sparse/dense version. RankOneUpdateFactorization() : hypersparse_ratio_(0.05) {} @@ -219,14 +221,14 @@ public: EntryIndex num_entries() const { return num_entries_; } -private: + private: double hypersparse_ratio_; EntryIndex num_entries_; std::vector elementary_matrices_; DISALLOW_COPY_AND_ASSIGN(RankOneUpdateFactorization); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_RANK_ONE_UPDATE_H_ +#endif // OR_TOOLS_GLOP_RANK_ONE_UPDATE_H_ diff --git a/ortools/glop/reduced_costs.cc b/ortools/glop/reduced_costs.cc index dd667529fd..358e2199c7 100644 --- a/ortools/glop/reduced_costs.cc +++ b/ortools/glop/reduced_costs.cc @@ -30,25 +30,34 @@ ReducedCosts::ReducedCosts(const CompactSparseMatrix &matrix, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization, random_engine_t *random) - : matrix_(matrix), objective_(objective), basis_(basis), + : matrix_(matrix), + objective_(objective), + basis_(basis), variables_info_(variables_info), - basis_factorization_(basis_factorization), random_(random), parameters_(), - stats_(), must_refactorize_basis_(false), + basis_factorization_(basis_factorization), + random_(random), + parameters_(), + stats_(), + must_refactorize_basis_(false), recompute_basic_objective_left_inverse_(true), - recompute_basic_objective_(true), recompute_reduced_costs_(true), - are_reduced_costs_precise_(false), are_reduced_costs_recomputed_(false), - basic_objective_(), reduced_costs_(), basic_objective_left_inverse_(), - dual_feasibility_tolerance_(), is_dual_infeasible_(), + recompute_basic_objective_(true), + recompute_reduced_costs_(true), + are_reduced_costs_precise_(false), + are_reduced_costs_recomputed_(false), + basic_objective_(), + reduced_costs_(), + basic_objective_left_inverse_(), + dual_feasibility_tolerance_(), + is_dual_infeasible_(), are_dual_infeasible_positions_maintained_(false) {} bool ReducedCosts::NeedsBasisRefactorization() const { return must_refactorize_basis_; } -bool -ReducedCosts::TestEnteringReducedCostPrecision(ColIndex entering_col, - const ScatteredColumn &direction, - Fractional *reduced_cost) { +bool ReducedCosts::TestEnteringReducedCostPrecision( + ColIndex entering_col, const ScatteredColumn &direction, + Fractional *reduced_cost) { SCOPED_TIME_STAT(&stats_); if (recompute_basic_objective_) { ComputeBasicObjective(); @@ -92,9 +101,9 @@ ReducedCosts::TestEnteringReducedCostPrecision(ColIndex entering_col, stats_.reduced_costs_accuracy.Add(estimated_reduced_costs_accuracy / scale); if (std::abs(estimated_reduced_costs_accuracy) / scale > parameters_.recompute_reduced_costs_threshold()) { - VLOG(1) - << "Recomputing reduced costs, value = " << precise_reduced_cost - << " error = " << std::abs(precise_reduced_cost - old_reduced_cost); + VLOG(1) << "Recomputing reduced costs, value = " << precise_reduced_cost + << " error = " + << std::abs(precise_reduced_cost - old_reduced_cost); MakeReducedCostsPrecise(); } } @@ -104,8 +113,7 @@ ReducedCosts::TestEnteringReducedCostPrecision(ColIndex entering_col, Fractional ReducedCosts::ComputeMaximumDualResidual() const { SCOPED_TIME_STAT(&stats_); DCHECK(!recompute_reduced_costs_); - if (recompute_reduced_costs_) - return 0.0; + if (recompute_reduced_costs_) return 0.0; // The current reduced costs of the slack columns are the opposite of the dual // values. Note that they are updated by UpdateBeforeBasisPivot(). @@ -115,9 +123,9 @@ Fractional ReducedCosts::ComputeMaximumDualResidual() const { for (RowIndex row(0); row < num_rows; ++row) { const ColIndex row_as_col = RowToColIndex(row); const ColIndex slack_col = first_slack_col + row_as_col; - dual_values[row_as_col] = - objective_[slack_col] + cost_perturbations_[slack_col] - - reduced_costs_[slack_col]; + dual_values[row_as_col] = objective_[slack_col] + + cost_perturbations_[slack_col] - + reduced_costs_[slack_col]; } Fractional dual_residual_error(0.0); for (RowIndex row(0); row < num_rows; ++row) { @@ -133,8 +141,7 @@ Fractional ReducedCosts::ComputeMaximumDualResidual() const { Fractional ReducedCosts::ComputeMaximumDualInfeasibility() const { SCOPED_TIME_STAT(&stats_); DCHECK(!recompute_reduced_costs_); - if (recompute_reduced_costs_) - return 0.0; + if (recompute_reduced_costs_) return 0.0; Fractional maximum_dual_infeasibility = 0.0; const DenseBitRow &can_decrease = variables_info_.GetCanDecreaseBitRow(); const DenseBitRow &can_increase = variables_info_.GetCanIncreaseBitRow(); @@ -152,8 +159,7 @@ Fractional ReducedCosts::ComputeMaximumDualInfeasibility() const { Fractional ReducedCosts::ComputeSumOfDualInfeasibilities() const { SCOPED_TIME_STAT(&stats_); DCHECK(!recompute_reduced_costs_); - if (recompute_reduced_costs_) - return 0.0; + if (recompute_reduced_costs_) return 0.0; Fractional dual_infeasibility_sum = 0.0; const DenseBitRow &can_decrease = variables_info_.GetCanDecreaseBitRow(); const DenseBitRow &can_increase = variables_info_.GetCanIncreaseBitRow(); @@ -225,8 +231,7 @@ void ReducedCosts::UpdateDataOnBasisPermutation() { void ReducedCosts::MakeReducedCostsPrecise() { SCOPED_TIME_STAT(&stats_); - if (are_reduced_costs_precise_) - return; + if (are_reduced_costs_precise_) return; must_refactorize_basis_ = true; recompute_basic_objective_left_inverse_ = true; recompute_reduced_costs_ = true; @@ -257,28 +262,28 @@ void ReducedCosts::PerturbCosts() { // feasible. This is important. const VariableType type = variables_info_.GetTypeRow()[col]; switch (type) { - case VariableType::UNCONSTRAINED: - break; - case VariableType::FIXED_VARIABLE: - break; - case VariableType::LOWER_BOUNDED: - cost_perturbations_[col] = magnitude; - break; - case VariableType::UPPER_BOUNDED: - cost_perturbations_[col] = -magnitude; - break; - case VariableType::UPPER_AND_LOWER_BOUNDED: - // Here we don't necessarily maintain the dual-feasibility of a dual - // feasible solution, however we can always shift the variable to its - // other bound (because it is boxed) to restore dual-feasiblity. This is - // done by MakeBoxedVariableDualFeasible() at the end of the dual - // phase-I algorithm. - if (objective > 0.0) { + case VariableType::UNCONSTRAINED: + break; + case VariableType::FIXED_VARIABLE: + break; + case VariableType::LOWER_BOUNDED: cost_perturbations_[col] = magnitude; - } else if (objective < 0.0) { + break; + case VariableType::UPPER_BOUNDED: cost_perturbations_[col] = -magnitude; - } - break; + break; + case VariableType::UPPER_AND_LOWER_BOUNDED: + // Here we don't necessarily maintain the dual-feasibility of a dual + // feasible solution, however we can always shift the variable to its + // other bound (because it is boxed) to restore dual-feasiblity. This is + // done by MakeBoxedVariableDualFeasible() at the end of the dual + // phase-I algorithm. + if (objective > 0.0) { + cost_perturbations_[col] = magnitude; + } else if (objective < 0.0) { + cost_perturbations_[col] = -magnitude; + } + break; } } } @@ -400,7 +405,7 @@ void ReducedCosts::ComputeReducedCosts() { dual_residual_error = std::max(dual_residual_error, thread_local_dual_residual_error[i]); } -#endif // OMP +#endif // OMP } recompute_reduced_costs_ = false; @@ -444,8 +449,7 @@ void ReducedCosts::UpdateReducedCosts(ColIndex entering_col, UpdateRow *update_row) { DCHECK_NE(entering_col, leaving_col); DCHECK_NE(pivot, 0.0); - if (recompute_reduced_costs_) - return; + if (recompute_reduced_costs_) return; // Note that this is precise because of the CheckPrecision(). const Fractional entering_reduced_cost = reduced_costs_[entering_col]; @@ -477,8 +481,7 @@ void ReducedCosts::UpdateReducedCosts(ColIndex entering_col, const Fractional new_leaving_reduced_cost = entering_reduced_cost / -pivot; for (const ColIndex col : update_row->GetNonZeroPositions()) { // Because the columns are in order, it is safe to break here. - if (col >= first_slack_col) - break; + if (col >= first_slack_col) break; const Fractional coeff = update_row->GetCoefficient(col); reduced_costs_[col] += new_leaving_reduced_cost * coeff; } @@ -561,5 +564,5 @@ void ReducedCosts::UpdateBasicObjective(ColIndex entering_col, recompute_basic_objective_left_inverse_ = true; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/reduced_costs.h b/ortools/glop/reduced_costs.h index a7b8b2a9d8..601d17b522 100644 --- a/ortools/glop/reduced_costs.h +++ b/ortools/glop/reduced_costs.h @@ -46,7 +46,7 @@ namespace glop { // - The reduced cost of a column is also equal to the scalar product of this // column with the vector of the dual values. class ReducedCosts { -public: + public: // Takes references to the linear program data we need. ReducedCosts(const CompactSparseMatrix &matrix_, const DenseRow &objective, const RowToColMapping &basis, @@ -183,7 +183,7 @@ public: // Visible for testing. const DenseRow &GetCostPerturbations() const { return cost_perturbations_; } -private: + private: // Statistics about this class. struct Stats : public StatsGroup { Stats() @@ -287,7 +287,7 @@ private: DISALLOW_COPY_AND_ASSIGN(ReducedCosts); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_REDUCED_COSTS_H_ +#endif // OR_TOOLS_GLOP_REDUCED_COSTS_H_ diff --git a/ortools/glop/revised_simplex.cc b/ortools/glop/revised_simplex.cc index 8b24483894..b9cadbeb03 100644 --- a/ortools/glop/revised_simplex.cc +++ b/ortools/glop/revised_simplex.cc @@ -50,34 +50,42 @@ namespace { // Calls the given closure upon destruction. It can be used to ensure that a // closure is executed whenever a function returns. class Cleanup { -public: + public: explicit Cleanup(std::function closure) : closure_(std::move(closure)) {} ~Cleanup() { closure_(); } -private: + private: std::function closure_; }; -} // namespace +} // namespace -#define DCHECK_COL_BOUNDS(col) \ - { \ - DCHECK_LE(0, col); \ - DCHECK_GT(num_cols_, col); \ +#define DCHECK_COL_BOUNDS(col) \ + { \ + DCHECK_LE(0, col); \ + DCHECK_GT(num_cols_, col); \ } -#define DCHECK_ROW_BOUNDS(row) \ - { \ - DCHECK_LE(0, row); \ - DCHECK_GT(num_rows_, row); \ +#define DCHECK_ROW_BOUNDS(row) \ + { \ + DCHECK_LE(0, row); \ + DCHECK_GT(num_rows_, row); \ } constexpr const uint64 kDeterministicSeed = 42; RevisedSimplex::RevisedSimplex() - : problem_status_(ProblemStatus::INIT), num_rows_(0), num_cols_(0), - first_slack_col_(0), objective_(), lower_bound_(), upper_bound_(), - basis_(), variable_name_(), direction_(), error_(), + : problem_status_(ProblemStatus::INIT), + num_rows_(0), + num_cols_(0), + first_slack_col_(0), + objective_(), + lower_bound_(), + upper_bound_(), + basis_(), + variable_name_(), + direction_(), + error_(), basis_factorization_(&compact_matrix_, &basis_), variables_info_(compact_matrix_, lower_bound_, upper_bound_), variable_values_(parameters_, compact_matrix_, basis_, variables_info_, @@ -91,12 +99,20 @@ RevisedSimplex::RevisedSimplex() basis_factorization_, &random_), entering_variable_(variables_info_, &random_, &reduced_costs_, &primal_edge_norms_), - num_iterations_(0), num_feasibility_iterations_(0), - num_optimization_iterations_(0), total_time_(0.0), feasibility_time_(0.0), - optimization_time_(0.0), last_deterministic_time_update_(0.0), - iteration_stats_(), ratio_test_stats_(), - function_stats_("SimplexFunctionStats"), parameters_(), test_lu_(), - feasibility_phase_(true), random_(kDeterministicSeed) { + num_iterations_(0), + num_feasibility_iterations_(0), + num_optimization_iterations_(0), + total_time_(0.0), + feasibility_time_(0.0), + optimization_time_(0.0), + last_deterministic_time_update_(0.0), + iteration_stats_(), + ratio_test_stats_(), + function_stats_("SimplexFunctionStats"), + parameters_(), + test_lu_(), + feasibility_phase_(true), + random_(kDeterministicSeed) { SetParameters(parameters_); } @@ -123,9 +139,8 @@ Status RevisedSimplex::Solve(const LinearProgram &lp, TimeLimit *time_limit) { return Status(Status::ERROR_INVALID_PROBLEM, "The problem is not in the equations form."); } - Cleanup update_deterministic_time_on_return([this, time_limit]() { - AdvanceDeterministicTime(time_limit); - }); + Cleanup update_deterministic_time_on_return( + [this, time_limit]() { AdvanceDeterministicTime(time_limit); }); // Initialization. Note That Initialize() must be called first since it // analyzes the current solver state. @@ -196,7 +211,7 @@ Status RevisedSimplex::Solve(const LinearProgram &lp, TimeLimit *time_limit) { // This is needed to display errors properly. MakeBoxedVariableDualFeasible(variables_info_.GetNonBasicBoxedVariables(), - /*update_basic_values=*/ false); + /*update_basic_values=*/false); variable_values_.RecomputeBasicVariableValues(); variable_values_.ResetPrimalInfeasibilityInformation(); } @@ -242,13 +257,13 @@ Status RevisedSimplex::Solve(const LinearProgram &lp, TimeLimit *time_limit) { // *equal* to the corresponding limits (to return a meaningful status // when the limits are set to 0). num_optims <= parameters_.max_number_of_reoptimizations() && - !objective_limit_reached_ && - (num_iterations_ == 0 || - num_iterations_ < parameters_.max_number_of_iterations()) && - !time_limit->LimitReached() && - !absl::GetFlag(FLAGS_simplex_stop_after_feasibility) && - (problem_status_ == ProblemStatus::PRIMAL_FEASIBLE || - problem_status_ == ProblemStatus::DUAL_FEASIBLE); + !objective_limit_reached_ && + (num_iterations_ == 0 || + num_iterations_ < parameters_.max_number_of_iterations()) && + !time_limit->LimitReached() && + !absl::GetFlag(FLAGS_simplex_stop_after_feasibility) && + (problem_status_ == ProblemStatus::PRIMAL_FEASIBLE || + problem_status_ == ProblemStatus::DUAL_FEASIBLE); ++num_optims) { if (problem_status_ == ProblemStatus::PRIMAL_FEASIBLE) { // Run the primal simplex. @@ -510,8 +525,8 @@ void RevisedSimplex::SetVariableNames() { } } -VariableStatus -RevisedSimplex::ComputeDefaultVariableStatus(ColIndex col) const { +VariableStatus RevisedSimplex::ComputeDefaultVariableStatus( + ColIndex col) const { DCHECK_COL_BOUNDS(col); if (lower_bound_[col] == upper_bound_[col]) { return VariableStatus::FIXED_VALUE; @@ -528,9 +543,8 @@ RevisedSimplex::ComputeDefaultVariableStatus(ColIndex col) const { : VariableStatus::AT_UPPER_BOUND; } -void -RevisedSimplex::SetNonBasicVariableStatusAndDeriveValue(ColIndex col, - VariableStatus status) { +void RevisedSimplex::SetNonBasicVariableStatusAndDeriveValue( + ColIndex col, VariableStatus status) { variables_info_.UpdateToNonBasicStatus(col, status); variable_values_.SetNonBasicVariableValueFromStatus(col); } @@ -540,10 +554,8 @@ bool RevisedSimplex::BasisIsConsistent() const { const VariableStatusRow &variable_statuses = variables_info_.GetStatusRow(); for (RowIndex row(0); row < num_rows_; ++row) { const ColIndex col = basis_[row]; - if (!is_basic.IsSet(col)) - return false; - if (variable_statuses[col] != VariableStatus::BASIC) - return false; + if (!is_basic.IsSet(col)) return false; + if (variable_statuses[col] != VariableStatus::BASIC) return false; } ColIndex cols_in_basis(0); ColIndex cols_not_in_basis(0); @@ -555,10 +567,8 @@ bool RevisedSimplex::BasisIsConsistent() const { return false; } } - if (cols_in_basis != RowToColIndex(num_rows_)) - return false; - if (cols_not_in_basis != num_cols_ - RowToColIndex(num_rows_)) - return false; + if (cols_in_basis != RowToColIndex(num_rows_)) return false; + if (cols_not_in_basis != num_cols_ - RowToColIndex(num_rows_)) return false; return true; } @@ -596,17 +606,17 @@ namespace { // Comparator used to sort column indices according to a given value vector. class ColumnComparator { -public: + public: explicit ColumnComparator(const DenseRow &value) : value_(value) {} bool operator()(ColIndex col_a, ColIndex col_b) const { return value_[col_a] < value_[col_b]; } -private: + private: const DenseRow &value_; }; -} // namespace +} // namespace // To understand better what is going on in this function, let us say that this // algorithm will produce the optimal solution to a problem containing only @@ -626,10 +636,8 @@ void RevisedSimplex::UseSingletonColumnInInitialBasis(RowToColMapping *basis) { std::vector singleton_column; DenseRow cost_variation(num_cols_, 0.0); for (ColIndex col(0); col < num_cols_; ++col) { - if (compact_matrix_.column(col).num_entries() != 1) - continue; - if (lower_bound_[col] == upper_bound_[col]) - continue; + if (compact_matrix_.column(col).num_entries() != 1) continue; + if (lower_bound_[col] == upper_bound_[col]) continue; const Fractional slope = compact_matrix_.column(col).GetFirstCoefficient(); if (variable_values_.Get(col) == lower_bound_[col]) { cost_variation[col] = objective_[col] / std::abs(slope); @@ -638,8 +646,7 @@ void RevisedSimplex::UseSingletonColumnInInitialBasis(RowToColMapping *basis) { } singleton_column.push_back(col); } - if (singleton_column.empty()) - return; + if (singleton_column.empty()) return; // Sort the singleton columns for the case where many of them correspond to // the same row (equivalent to a piecewise-linear objective on this variable). @@ -669,8 +676,7 @@ void RevisedSimplex::UseSingletonColumnInInitialBasis(RowToColMapping *basis) { // If there is already no error in this row (i.e. it is primal-feasible), // there is nothing to do. - if (error_[row] == 0.0) - continue; + if (error_[row] == 0.0) continue; // In this case, all the infeasibility can be "absorbed" and this variable // may not be at one of its bound anymore, so we have to use it in the @@ -738,15 +744,15 @@ bool RevisedSimplex::InitializeMatrixAndTestIfUnchanged( // Check if the new matrix can be derived from the old one just by adding // new rows (i.e new constraints). - *only_change_is_new_rows = - old_part_of_matrix_is_unchanged && lp.num_constraints() > num_rows_ && - lp.GetFirstSlackVariable() == first_slack_col_; + *only_change_is_new_rows = old_part_of_matrix_is_unchanged && + lp.num_constraints() > num_rows_ && + lp.GetFirstSlackVariable() == first_slack_col_; // Check if the new matrix can be derived from the old one just by adding // new columns (i.e new variables). - *only_change_is_new_cols = - old_part_of_matrix_is_unchanged && lp.num_constraints() == num_rows_ && - lp.GetFirstSlackVariable() > first_slack_col_; + *only_change_is_new_cols = old_part_of_matrix_is_unchanged && + lp.num_constraints() == num_rows_ && + lp.GetFirstSlackVariable() > first_slack_col_; *num_new_cols = *only_change_is_new_cols ? lp.num_variables() - num_cols_ : ColIndex(0); @@ -799,8 +805,8 @@ bool RevisedSimplex::OldBoundsAreUnchangedAndNewVariablesHaveOneBoundAtZero( return true; } -bool -RevisedSimplex::InitializeBoundsAndTestIfUnchanged(const LinearProgram &lp) { +bool RevisedSimplex::InitializeBoundsAndTestIfUnchanged( + const LinearProgram &lp) { SCOPED_TIME_STAT(&function_stats_); lower_bound_.resize(num_cols_, 0.0); upper_bound_.resize(num_cols_, 0.0); @@ -823,8 +829,8 @@ RevisedSimplex::InitializeBoundsAndTestIfUnchanged(const LinearProgram &lp) { return bounds_are_unchanged; } -bool -RevisedSimplex::InitializeObjectiveAndTestIfUnchanged(const LinearProgram &lp) { +bool RevisedSimplex::InitializeObjectiveAndTestIfUnchanged( + const LinearProgram &lp) { SCOPED_TIME_STAT(&function_stats_); bool objective_is_unchanged = true; @@ -865,9 +871,7 @@ void RevisedSimplex::InitializeObjectiveLimit(const LinearProgram &lp) { // This sets dual_objective_limit_ and then primal_objective_limit_. const Fractional tolerance = parameters_.solution_feasibility_tolerance(); - for (const bool set_dual : { - true, false - }) { + for (const bool set_dual : {true, false}) { // NOTE(user): If objective_scaling_factor_ is negative, the optimization // direction was reversed (during preprocessing or inside revised simplex), // i.e., the original problem is maximization. In such case the _meaning_ of @@ -888,20 +892,19 @@ void RevisedSimplex::InitializeObjectiveLimit(const LinearProgram &lp) { // The isfinite() test is there to avoid generating NaNs with clang in // fast-math mode on iOS 9.3.i. if (set_dual) { - dual_objective_limit_ = - std::isfinite(shifted_limit) ? shifted_limit * (1.0 + tolerance) - : shifted_limit; + dual_objective_limit_ = std::isfinite(shifted_limit) + ? shifted_limit * (1.0 + tolerance) + : shifted_limit; } else { - primal_objective_limit_ = - std::isfinite(shifted_limit) ? shifted_limit * (1.0 - tolerance) - : shifted_limit; + primal_objective_limit_ = std::isfinite(shifted_limit) + ? shifted_limit * (1.0 - tolerance) + : shifted_limit; } } } -void -RevisedSimplex::InitializeVariableStatusesForWarmStart(const BasisState &state, - ColIndex num_new_cols) { +void RevisedSimplex::InitializeVariableStatusesForWarmStart( + const BasisState &state, ColIndex num_new_cols) { variables_info_.InitializeAndComputeType(); RowIndex num_basic_variables(0); DCHECK_LE(num_new_cols, first_slack_col_); @@ -969,8 +972,7 @@ Status RevisedSimplex::CreateInitialBasis() { for (ColIndex col(0); col < num_cols_; ++col) { const VariableStatus status = ComputeDefaultVariableStatus(col); SetNonBasicVariableStatusAndDeriveValue(col, status); - if (status == VariableStatus::FREE) - ++num_free_variables; + if (status == VariableStatus::FREE) ++num_free_variables; } VLOG(1) << "Number of free variables in the problem: " << num_free_variables; @@ -989,8 +991,7 @@ Status RevisedSimplex::CreateInitialBasis() { // the value of the boxed singleton column with a non-zero cost to the best // of their two bounds. for (ColIndex col(0); col < num_cols_; ++col) { - if (compact_matrix_.column(col).num_entries() != 1) - continue; + if (compact_matrix_.column(col).num_entries() != 1) continue; const VariableStatus status = variables_info_.GetStatusRow()[col]; const Fractional objective = objective_[col]; if (objective > 0 && IsFinite(lower_bound_[col]) && @@ -1150,10 +1151,10 @@ Status RevisedSimplex::InitializeFirstBasis(const RowToColMapping &basis) { if (VLOG_IS_ON(1)) { const Fractional tolerance = parameters_.primal_feasibility_tolerance(); if (variable_values_.ComputeMaximumPrimalResidual() > tolerance) { - VLOG(1) << absl::StrCat("The primal residual of the initial basis is " - "above the tolerance, ", - variable_values_.ComputeMaximumPrimalResidual(), - " vs. ", tolerance); + VLOG(1) << absl::StrCat( + "The primal residual of the initial basis is " + "above the tolerance, ", + variable_values_.ComputeMaximumPrimalResidual(), " vs. ", tolerance); } } return Status::OK(); @@ -1362,8 +1363,8 @@ void RevisedSimplex::DisplayBasicVariableStatistics() { } VLOG(1) << "Basis size: " << num_rows_; - VLOG(1) - << "Number of basic infeasible variables: " << num_infeasible_variables; + VLOG(1) << "Number of basic infeasible variables: " + << num_infeasible_variables; VLOG(1) << "Number of basic slack variables: " << num_slack_variables; VLOG(1) << "Number of basic variables at bound: " << num_variables_at_bound; VLOG(1) << "Number of basic fixed variables: " << num_fixed_variables; @@ -1477,8 +1478,9 @@ void RevisedSimplex::ComputeDirection(ColIndex col) { } } IF_STATS_ENABLED(ratio_test_stats_.direction_density.Add( - num_rows_ == 0 ? 0.0 : static_cast(direction_.non_zeros.size()) / - static_cast(num_rows_.value()))); + num_rows_ == 0 ? 0.0 + : static_cast(direction_.non_zeros.size()) / + static_cast(num_rows_.value()))); } Fractional RevisedSimplex::ComputeDirectionError(ColIndex col) { @@ -1539,8 +1541,7 @@ Fractional RevisedSimplex::ComputeHarrisRatioAndLeavingCandidates( for (const auto e : direction_) { const Fractional magnitude = std::abs(e.coefficient()); - if (magnitude <= threshold) - continue; + if (magnitude <= threshold) continue; Fractional ratio = GetRatio(e.row()); // TODO(user): The perturbation is currently disabled, so no need to test // anything here. @@ -1587,7 +1588,7 @@ bool IsRatioMoreOrEquallyStable(Fractional candidate, Fractional current) { } } -} // namespace +} // namespace // Ratio-test or Quotient-test. Choose the row of the leaving variable. // Known as CHUZR or CHUZRO in FORTRAN codes. @@ -1644,8 +1645,7 @@ Status RevisedSimplex::ChooseLeavingVariableRow( equivalent_leaving_choices_.clear(); for (const SparseColumn::Entry e : leaving_candidates_) { const Fractional ratio = e.coefficient(); - if (ratio > harris_ratio) - continue; + if (ratio > harris_ratio) continue; ++stats_num_leaving_choices; const RowIndex row = e.row(); @@ -1653,11 +1653,9 @@ Status RevisedSimplex::ChooseLeavingVariableRow( // what is probably the more stable ratio, see // IsRatioMoreOrEquallyStable(). const Fractional candidate_magnitude = std::abs(direction_[row]); - if (candidate_magnitude < pivot_magnitude) - continue; + if (candidate_magnitude < pivot_magnitude) continue; if (candidate_magnitude == pivot_magnitude) { - if (!IsRatioMoreOrEquallyStable(ratio, current_ratio)) - continue; + if (!IsRatioMoreOrEquallyStable(ratio, current_ratio)) continue; if (ratio == current_ratio) { DCHECK_NE(kInvalidRow, *leaving_row); equivalent_leaving_choices_.push_back(row); @@ -1701,7 +1699,7 @@ Status RevisedSimplex::ChooseLeavingVariableRow( // Note(user): Testing the pivot at each iteration is useful for debugging // an LU factorization problem. Remove the false if you need to investigate // this, it makes sure that this will be compiled away. - if (/* DISABLES CODE */(false)) { + if (/* DISABLES CODE */ (false)) { TestPivot(entering_col, *leaving_row); } @@ -1754,12 +1752,12 @@ Status RevisedSimplex::ChooseLeavingVariableRow( : lower_bound_[basis_[*leaving_row]]; } - // Stats. + // Stats. IF_STATS_ENABLED({ ratio_test_stats_.leaving_choices.Add(stats_num_leaving_choices); if (!equivalent_leaving_choices_.empty()) { - ratio_test_stats_.num_perfect_ties - .Add(equivalent_leaving_choices_.size()); + ratio_test_stats_.num_perfect_ties.Add( + equivalent_leaving_choices_.size()); } if (*leaving_row != kInvalidRow) { ratio_test_stats_.abs_used_pivot.Add(std::abs(direction_[*leaving_row])); @@ -1776,7 +1774,9 @@ namespace { struct BreakPoint { BreakPoint(RowIndex _row, Fractional _ratio, Fractional _coeff_magnitude, Fractional _target_bound) - : row(_row), ratio(_ratio), coeff_magnitude(_coeff_magnitude), + : row(_row), + ratio(_ratio), + coeff_magnitude(_coeff_magnitude), target_bound(_target_bound) {} // We want to process the breakpoints by increasing ratio and decreasing @@ -1798,7 +1798,7 @@ struct BreakPoint { Fractional target_bound; }; -} // namespace +} // namespace void RevisedSimplex::PrimalPhaseIChooseLeavingVariableRow( ColIndex entering_col, Fractional reduced_cost, bool *refactorize, @@ -1814,9 +1814,9 @@ void RevisedSimplex::PrimalPhaseIChooseLeavingVariableRow( // We initialize current_ratio with the maximum step the entering variable // can take (bound-flip). Note that we do not use tolerance here. const Fractional entering_value = variable_values_.Get(entering_col); - Fractional current_ratio = - (reduced_cost > 0.0) ? entering_value - lower_bound_[entering_col] - : upper_bound_[entering_col] - entering_value; + Fractional current_ratio = (reduced_cost > 0.0) + ? entering_value - lower_bound_[entering_col] + : upper_bound_[entering_col] - entering_value; DCHECK_GT(current_ratio, 0.0); std::vector breakpoints; @@ -1825,8 +1825,7 @@ void RevisedSimplex::PrimalPhaseIChooseLeavingVariableRow( const Fractional direction = reduced_cost > 0.0 ? e.coefficient() : -e.coefficient(); const Fractional magnitude = std::abs(direction); - if (magnitude < tolerance) - continue; + if (magnitude < tolerance) continue; // Computes by how much we can add 'direction' to the basic variable value // with index 'row' until it changes of primal feasibility status. That is @@ -1890,8 +1889,7 @@ void RevisedSimplex::PrimalPhaseIChooseLeavingVariableRow( // As long as the sum of primal infeasibilities is decreasing, we look for // pivots that are numerically more stable. improvement -= top.coeff_magnitude; - if (improvement <= 0.0) - break; + if (improvement <= 0.0) break; std::pop_heap(breakpoints.begin(), breakpoints.end()); breakpoints.pop_back(); } @@ -1949,8 +1947,7 @@ Status RevisedSimplex::DualChooseLeavingVariableRow(RowIndex *leaving_row, // Return right away if there is no leaving variable. // Fill cost_variation and target_bound otherwise. - if (*leaving_row == kInvalidRow) - return Status::OK(); + if (*leaving_row == kInvalidRow) return Status::OK(); const ColIndex leaving_col = basis_[*leaving_row]; const Fractional value = variable_values_.Get(leaving_col); if (value < lower_bound_[leaving_col]) { @@ -1972,15 +1969,14 @@ namespace { // to keep is_dual_entering_candidate_ up to date. bool IsDualPhaseILeavingCandidate(Fractional cost, VariableType type, Fractional threshold) { - if (cost == 0.0) - return false; + if (cost == 0.0) return false; return type == VariableType::UPPER_AND_LOWER_BOUNDED || type == VariableType::FIXED_VARIABLE || (type == VariableType::UPPER_BOUNDED && cost < -threshold) || (type == VariableType::LOWER_BOUNDED && cost > threshold); } -} // namespace +} // namespace void RevisedSimplex::DualPhaseIUpdatePrice(RowIndex leaving_row, ColIndex entering_col) { @@ -2022,8 +2018,8 @@ void RevisedSimplex::DualPhaseIUpdatePrice(RowIndex leaving_row, } template -void -RevisedSimplex::DualPhaseIUpdatePriceOnReducedCostChange(const Cols &cols) { +void RevisedSimplex::DualPhaseIUpdatePriceOnReducedCostChange( + const Cols &cols) { SCOPED_TIME_STAT(&function_stats_); bool something_to_do = false; const DenseBitRow &can_decrease = variables_info_.GetCanDecreaseBitRow(); @@ -2035,9 +2031,8 @@ RevisedSimplex::DualPhaseIUpdatePriceOnReducedCostChange(const Cols &cols) { const Fractional sign = (can_increase.IsSet(col) && reduced_cost < -tolerance) ? 1.0 - : (can_decrease.IsSet(col) && reduced_cost > tolerance) - ? -1.0 - : 0.0; + : (can_decrease.IsSet(col) && reduced_cost > tolerance) ? -1.0 + : 0.0; if (sign != dual_infeasibility_improvement_direction_[col]) { if (sign == 0.0) { --num_dual_infeasible_positions_; @@ -2065,8 +2060,7 @@ RevisedSimplex::DualPhaseIUpdatePriceOnReducedCostChange(const Cols &cols) { basis_factorization_.RightSolve(&initially_all_zero_scratchpad_); if (initially_all_zero_scratchpad_.non_zeros.empty()) { for (RowIndex row(0); row < num_rows_; ++row) { - if (initially_all_zero_scratchpad_[row] == 0.0) - continue; + if (initially_all_zero_scratchpad_[row] == 0.0) continue; dual_pricing_vector_[row] += initially_all_zero_scratchpad_[row]; is_dual_entering_candidate_.Set( row, IsDualPhaseILeavingCandidate(dual_pricing_vector_[row], @@ -2088,10 +2082,9 @@ RevisedSimplex::DualPhaseIUpdatePriceOnReducedCostChange(const Cols &cols) { } } -Status -RevisedSimplex::DualPhaseIChooseLeavingVariableRow(RowIndex *leaving_row, - Fractional *cost_variation, - Fractional *target_bound) { +Status RevisedSimplex::DualPhaseIChooseLeavingVariableRow( + RowIndex *leaving_row, Fractional *cost_variation, + Fractional *target_bound) { SCOPED_TIME_STAT(&function_stats_); GLOP_RETURN_ERROR_IF_NULL(leaving_row); GLOP_RETURN_ERROR_IF_NULL(cost_variation); @@ -2123,8 +2116,7 @@ RevisedSimplex::DualPhaseIChooseLeavingVariableRow(RowIndex *leaving_row, // If there is no dual-infeasible position, we are done. *leaving_row = kInvalidRow; - if (num_dual_infeasible_positions_ == 0) - return Status::OK(); + if (num_dual_infeasible_positions_ == 0) return Status::OK(); // TODO(user): Reuse parameters_.optimization_rule() to decide if we use // steepest edge or the normal Dantzig pricing. @@ -2159,8 +2151,7 @@ RevisedSimplex::DualPhaseIChooseLeavingVariableRow(RowIndex *leaving_row, // Returns right away if there is no leaving variable or fill the other // return values otherwise. - if (*leaving_row == kInvalidRow) - return Status::OK(); + if (*leaving_row == kInvalidRow) return Status::OK(); *cost_variation = dual_pricing_vector_[*leaving_row]; const ColIndex leaving_col = basis_[*leaving_row]; if (*cost_variation < 0.0) { @@ -2173,9 +2164,8 @@ RevisedSimplex::DualPhaseIChooseLeavingVariableRow(RowIndex *leaving_row, } template -void -RevisedSimplex::MakeBoxedVariableDualFeasible(const BoxedVariableCols &cols, - bool update_basic_values) { +void RevisedSimplex::MakeBoxedVariableDualFeasible( + const BoxedVariableCols &cols, bool update_basic_values) { SCOPED_TIME_STAT(&function_stats_); std::vector changed_cols; @@ -2214,9 +2204,8 @@ RevisedSimplex::MakeBoxedVariableDualFeasible(const BoxedVariableCols &cols, } } -Fractional -RevisedSimplex::ComputeStepToMoveBasicVariableToBound(RowIndex leaving_row, - Fractional target_bound) { +Fractional RevisedSimplex::ComputeStepToMoveBasicVariableToBound( + RowIndex leaving_row, Fractional target_bound) { SCOPED_TIME_STAT(&function_stats_); // We just want the leaving variable to go to its target_bound. @@ -2258,8 +2247,7 @@ void RevisedSimplex::PermuteBasis() { // means the permutation is the identity. const ColumnPermutation &col_perm = basis_factorization_.GetColumnPermutation(); - if (col_perm.empty()) - return; + if (col_perm.empty()) return; // Permute basis_. ApplyColumnPermutationToRowIndexedVector(col_perm, &basis_); @@ -2291,11 +2279,11 @@ Status RevisedSimplex::UpdateAndPivot(ColIndex entering_col, lower_bound_[leaving_col] == upper_bound_[leaving_col] ? VariableStatus::FIXED_VALUE : target_bound == lower_bound_[leaving_col] - ? VariableStatus::AT_LOWER_BOUND - : VariableStatus::AT_UPPER_BOUND; + ? VariableStatus::AT_LOWER_BOUND + : VariableStatus::AT_UPPER_BOUND; if (variable_values_.Get(leaving_col) != target_bound) { - ratio_test_stats_.bound_shift - .Add(variable_values_.Get(leaving_col) - target_bound); + ratio_test_stats_.bound_shift.Add(variable_values_.Get(leaving_col) - + target_bound); } UpdateBasis(entering_col, leaving_row, leaving_variable_status); @@ -2320,18 +2308,15 @@ Status RevisedSimplex::UpdateAndPivot(ColIndex entering_col, } bool RevisedSimplex::NeedsBasisRefactorization(bool refactorize) { - if (basis_factorization_.IsRefactorized()) - return false; - if (reduced_costs_.NeedsBasisRefactorization()) - return true; + if (basis_factorization_.IsRefactorized()) return false; + if (reduced_costs_.NeedsBasisRefactorization()) return true; const GlopParameters::PricingRule pricing_rule = feasibility_phase_ ? parameters_.feasibility_rule() : parameters_.optimization_rule(); if (parameters_.use_dual_simplex()) { // TODO(user): Currently the dual is always using STEEPEST_EDGE. DCHECK_EQ(pricing_rule, GlopParameters::STEEPEST_EDGE); - if (dual_edge_norms_.NeedsBasisRefactorization()) - return true; + if (dual_edge_norms_.NeedsBasisRefactorization()) return true; } else { if (pricing_rule == GlopParameters::STEEPEST_EDGE && primal_edge_norms_.NeedsBasisRefactorization()) { @@ -2369,9 +2354,8 @@ Status RevisedSimplex::RefactorizeBasisIfNeeded(bool *refactorize) { // y.B = c_B and B.d = a (a being the entering column). Status RevisedSimplex::Minimize(TimeLimit *time_limit) { GLOP_RETURN_ERROR_IF_NULL(time_limit); - Cleanup update_deterministic_time_on_return([this, time_limit]() { - AdvanceDeterministicTime(time_limit); - }); + Cleanup update_deterministic_time_on_return( + [this, time_limit]() { AdvanceDeterministicTime(time_limit); }); num_consecutive_degenerate_iterations_ = 0; DisplayIterationInfo(); bool refactorize = false; @@ -2483,16 +2467,15 @@ Status RevisedSimplex::Minimize(TimeLimit *time_limit) { RowIndex leaving_row; Fractional target_bound; if (feasibility_phase_) { - PrimalPhaseIChooseLeavingVariableRow( - entering_col, reduced_cost, &refactorize, &leaving_row, &step_length, - &target_bound); + PrimalPhaseIChooseLeavingVariableRow(entering_col, reduced_cost, + &refactorize, &leaving_row, + &step_length, &target_bound); } else { GLOP_RETURN_IF_ERROR( ChooseLeavingVariableRow(entering_col, reduced_cost, &refactorize, &leaving_row, &step_length, &target_bound)); } - if (refactorize) - continue; + if (refactorize) continue; if (step_length == kInfinity || step_length == -kInfinity) { if (!basis_factorization_.IsRefactorized() || @@ -2610,16 +2593,16 @@ Status RevisedSimplex::Minimize(TimeLimit *time_limit) { num_consecutive_degenerate_iterations_++; } else { if (num_consecutive_degenerate_iterations_ > 0) { - iteration_stats_.degenerate_run_size - .Add(num_consecutive_degenerate_iterations_); + iteration_stats_.degenerate_run_size.Add( + num_consecutive_degenerate_iterations_); num_consecutive_degenerate_iterations_ = 0; } } ++num_iterations_; } if (num_consecutive_degenerate_iterations_ > 0) { - iteration_stats_.degenerate_run_size - .Add(num_consecutive_degenerate_iterations_); + iteration_stats_.degenerate_run_size.Add( + num_consecutive_degenerate_iterations_); } return Status::OK(); } @@ -2635,9 +2618,8 @@ Status RevisedSimplex::Minimize(TimeLimit *time_limit) { // // Note that the returned status applies to the primal problem! Status RevisedSimplex::DualMinimize(TimeLimit *time_limit) { - Cleanup update_deterministic_time_on_return([this, time_limit]() { - AdvanceDeterministicTime(time_limit); - }); + Cleanup update_deterministic_time_on_return( + [this, time_limit]() { AdvanceDeterministicTime(time_limit); }); num_consecutive_degenerate_iterations_ = 0; bool refactorize = false; @@ -2700,7 +2682,7 @@ Status RevisedSimplex::DualMinimize(TimeLimit *time_limit) { if (!feasibility_phase_) { MakeBoxedVariableDualFeasible( variables_info_.GetNonBasicBoxedVariables(), - /*update_basic_values=*/ false); + /*update_basic_values=*/false); variable_values_.RecomputeBasicVariableValues(); variable_values_.ResetPrimalInfeasibilityInformation(); @@ -2725,7 +2707,7 @@ Status RevisedSimplex::DualMinimize(TimeLimit *time_limit) { // Make sure the boxed variables are dual-feasible before choosing the // leaving variable row. MakeBoxedVariableDualFeasible(bound_flip_candidates_, - /*update_basic_values=*/ true); + /*update_basic_values=*/true); bound_flip_candidates_.clear(); // The direction_.non_zeros contains the positions for which the basic @@ -2828,9 +2810,7 @@ Status RevisedSimplex::DualMinimize(TimeLimit *time_limit) { VLOG(1) << "Do not pivot by " << entering_coeff << " because the direction is " << direction_[leaving_row]; refactorize = true; - pair_to_ignore_.push_back({ - leaving_row, entering_col - }); + pair_to_ignore_.push_back({leaving_row, entering_col}); continue; } pair_to_ignore_.clear(); @@ -2958,9 +2938,9 @@ void RevisedSimplex::PropagateParameters() { void RevisedSimplex::DisplayIterationInfo() const { if (VLOG_IS_ON(1)) { - const int iter = - feasibility_phase_ ? num_iterations_ - : num_iterations_ - num_feasibility_iterations_; + const int iter = feasibility_phase_ + ? num_iterations_ + : num_iterations_ - num_feasibility_iterations_; // Note that in the dual phase II, ComputeObjectiveValue() is also computing // the dual objective even if it uses the variable values. This is because // if we modify the bounds to make the problem primal-feasible, we are at @@ -3006,7 +2986,7 @@ std::string StringifyWithFlags(const Fractional x) { absl::GetFlag(FLAGS_simplex_display_numbers_as_fractions)); } -} // namespace +} // namespace std::string RevisedSimplex::SimpleVariableInfo(ColIndex col) const { std::string output; @@ -3043,35 +3023,35 @@ void RevisedSimplex::DisplayVariableBounds() { const VariableTypeRow &variable_type = variables_info_.GetTypeRow(); for (ColIndex col(0); col < num_cols_; ++col) { switch (variable_type[col]) { - case VariableType::UNCONSTRAINED: - break; - case VariableType::LOWER_BOUNDED: - VLOG(3) << variable_name_[col] - << " >= " << StringifyWithFlags(lower_bound_[col]) << ";"; - break; - case VariableType::UPPER_BOUNDED: - VLOG(3) << variable_name_[col] - << " <= " << StringifyWithFlags(upper_bound_[col]) << ";"; - break; - case VariableType::UPPER_AND_LOWER_BOUNDED: - VLOG(3) << StringifyWithFlags(lower_bound_[col]) - << " <= " << variable_name_[col] - << " <= " << StringifyWithFlags(upper_bound_[col]) << ";"; - break; - case VariableType::FIXED_VARIABLE: - VLOG(3) << variable_name_[col] << " = " - << StringifyWithFlags(lower_bound_[col]) << ";"; - break; - default: // This should never happen. - LOG(DFATAL) << "Column " << col << " has no meaningful status."; - break; + case VariableType::UNCONSTRAINED: + break; + case VariableType::LOWER_BOUNDED: + VLOG(3) << variable_name_[col] + << " >= " << StringifyWithFlags(lower_bound_[col]) << ";"; + break; + case VariableType::UPPER_BOUNDED: + VLOG(3) << variable_name_[col] + << " <= " << StringifyWithFlags(upper_bound_[col]) << ";"; + break; + case VariableType::UPPER_AND_LOWER_BOUNDED: + VLOG(3) << StringifyWithFlags(lower_bound_[col]) + << " <= " << variable_name_[col] + << " <= " << StringifyWithFlags(upper_bound_[col]) << ";"; + break; + case VariableType::FIXED_VARIABLE: + VLOG(3) << variable_name_[col] << " = " + << StringifyWithFlags(lower_bound_[col]) << ";"; + break; + default: // This should never happen. + LOG(DFATAL) << "Column " << col << " has no meaningful status."; + break; } } } } -gtl::ITIVector -RevisedSimplex::ComputeDictionary(const DenseRow *column_scales) { +gtl::ITIVector RevisedSimplex::ComputeDictionary( + const DenseRow *column_scales) { gtl::ITIVector dictionary(num_rows_.value()); for (ColIndex col(0); col < num_cols_; ++col) { ComputeDirection(col); @@ -3085,8 +3065,8 @@ RevisedSimplex::ComputeDictionary(const DenseRow *column_scales) { const Fractional denominator = GetBasis(e.row()) < column_scales->size() ? (*column_scales)[GetBasis(e.row())] : 1.0; - dictionary[e.row()] - .SetCoefficient(col, direction_[e.row()] * (numerator / denominator)); + dictionary[e.row()].SetCoefficient( + col, direction_[e.row()] * (numerator / denominator)); } } return dictionary; @@ -3181,5 +3161,5 @@ void RevisedSimplex::AdvanceDeterministicTime(TimeLimit *time_limit) { #undef DCHECK_COL_BOUNDS #undef DCHECK_ROW_BOUNDS -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/revised_simplex.h b/ortools/glop/revised_simplex.h index 3167c05ef4..905e427d43 100644 --- a/ortools/glop/revised_simplex.h +++ b/ortools/glop/revised_simplex.h @@ -146,7 +146,7 @@ struct BasisState { // Entry point of the revised simplex algorithm implementation. class RevisedSimplex { -public: + public: RevisedSimplex(); // Sets or gets the algorithm parameters to be used on the next Solve(). @@ -245,7 +245,7 @@ public: void ComputeBasicVariablesForState(const LinearProgram &linear_program, const BasisState &state); -private: + private: // Propagates parameters_ to all the other classes that need it. // // TODO(user): Maybe a better design is for them to have a reference to a @@ -374,7 +374,7 @@ private: // Sets the initial basis to the given columns, try to factorize it and // recompute the basic variable values. ABSL_MUST_USE_RESULT Status - InitializeFirstBasis(const RowToColMapping &initial_basis); + InitializeFirstBasis(const RowToColMapping &initial_basis); // Entry point for the solver initialization. ABSL_MUST_USE_RESULT Status Initialize(const LinearProgram &lp); @@ -468,10 +468,9 @@ private: // along this dual edge. // - target_bound: the bound at which the leaving variable should go when // leaving the basis. - ABSL_MUST_USE_RESULT Status - DualChooseLeavingVariableRow(RowIndex *leaving_row, - Fractional *cost_variation, - Fractional *target_bound); + ABSL_MUST_USE_RESULT Status DualChooseLeavingVariableRow( + RowIndex *leaving_row, Fractional *cost_variation, + Fractional *target_bound); // Updates the prices used by DualChooseLeavingVariableRow() after a simplex // iteration by using direction_. The prices are stored in @@ -492,10 +491,9 @@ private: // Dual Phase-1 Algorithm for the Simplex Method", Computational Optimization // and Applications, October 2003, Volume 26, Issue 1, pp 63-81. // http://rd.springer.com/article/10.1023%2FA%3A1025102305440 - ABSL_MUST_USE_RESULT Status - DualPhaseIChooseLeavingVariableRow(RowIndex *leaving_row, - Fractional *cost_variation, - Fractional *target_bound); + ABSL_MUST_USE_RESULT Status DualPhaseIChooseLeavingVariableRow( + RowIndex *leaving_row, Fractional *cost_variation, + Fractional *target_bound); // Makes sure the boxed variable are dual-feasible by setting them to the // correct bound according to their reduced costs. This is called @@ -708,8 +706,10 @@ private: // Statistics about the iterations done by Minimize(). struct IterationStats : public StatsGroup { IterationStats() - : StatsGroup("IterationStats"), total("total", this), - normal("normal", this), bound_flip("bound_flip", this), + : StatsGroup("IterationStats"), + total("total", this), + normal("normal", this), + bound_flip("bound_flip", this), degenerate("degenerate", this), degenerate_run_size("degenerate_run_size", this) {} TimeDistribution total; @@ -722,7 +722,8 @@ private: struct RatioTestStats : public StatsGroup { RatioTestStats() - : StatsGroup("RatioTestStats"), bound_shift("bound_shift", this), + : StatsGroup("RatioTestStats"), + bound_shift("bound_shift", this), abs_used_pivot("abs_used_pivot", this), abs_tested_pivot("abs_tested_pivot", this), abs_skipped_pivot("abs_skipped_pivot", this), @@ -788,7 +789,7 @@ private: // GLOP will support generating the dictionary one row at a time without having // to store the whole matrix in memory. class RevisedSimplexDictionary { -public: + public: typedef RowMajorSparseMatrix::const_iterator ConstIterator; // RevisedSimplex cannot be passed const because we have to call a non-const @@ -798,8 +799,8 @@ public: // ComputeDictionary can take a const& argument. RevisedSimplexDictionary(const DenseRow *col_scales, RevisedSimplex *revised_simplex) - : dictionary_(ABSL_DIE_IF_NULL(revised_simplex) - ->ComputeDictionary(col_scales)), + : dictionary_( + ABSL_DIE_IF_NULL(revised_simplex)->ComputeDictionary(col_scales)), basis_vars_(ABSL_DIE_IF_NULL(revised_simplex)->GetBasisVector()) {} ConstIterator begin() const { return dictionary_.begin(); } @@ -811,7 +812,7 @@ public: ColIndex GetBasicColumnForRow(RowIndex r) const { return basis_vars_[r]; } SparseRow GetRow(RowIndex r) const { return dictionary_[r]; } -private: + private: const RowMajorSparseMatrix dictionary_; const RowToColMapping basis_vars_; DISALLOW_COPY_AND_ASSIGN(RevisedSimplexDictionary); @@ -820,7 +821,7 @@ private: // TODO(user): When a row-by-row generation of the dictionary is supported, // implement DictionaryIterator class that would call it inside operator*(). -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_REVISED_SIMPLEX_H_ +#endif // OR_TOOLS_GLOP_REVISED_SIMPLEX_H_ diff --git a/ortools/glop/status.cc b/ortools/glop/status.cc index 7b85f56835..b1fb35c982 100644 --- a/ortools/glop/status.cc +++ b/ortools/glop/status.cc @@ -28,16 +28,16 @@ Status::Status(ErrorCode error_code, std::string error_message) std::string GetErrorCodeString(Status::ErrorCode error_code) { switch (error_code) { - case Status::GLOP_OK: - return "GLOP_OK"; - case Status::ERROR_LU: - return "ERROR_LU"; - case Status::ERROR_BOUND: - return "ERROR_BOUND"; - case Status::ERROR_NULL: - return "ERROR_NULL"; - case Status::ERROR_INVALID_PROBLEM: - return "INVALID_PROBLEM"; + case Status::GLOP_OK: + return "GLOP_OK"; + case Status::ERROR_LU: + return "ERROR_LU"; + case Status::ERROR_BOUND: + return "ERROR_BOUND"; + case Status::ERROR_NULL: + return "ERROR_NULL"; + case Status::ERROR_INVALID_PROBLEM: + return "INVALID_PROBLEM"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -45,5 +45,5 @@ std::string GetErrorCodeString(Status::ErrorCode error_code) { return "UNKNOWN Status::ErrorCode"; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/status.h b/ortools/glop/status.h index 56fe25ade0..0aa19f5215 100644 --- a/ortools/glop/status.h +++ b/ortools/glop/status.h @@ -22,7 +22,7 @@ namespace glop { // Return type for the solver functions that return "Did that work?". // It should only be used for unrecoverable errors. class Status { -public: + public: // Possible kinds of errors. enum ErrorCode { // Not an error. Returned on success. @@ -58,7 +58,7 @@ public: const std::string &error_message() const { return error_message_; } bool ok() const { return error_code_ == GLOP_OK; } -private: + private: ErrorCode error_code_; std::string error_message_; }; @@ -67,31 +67,30 @@ private: std::string GetErrorCodeString(Status::ErrorCode error_code); // Macro to simplify error propagation between function returning Status. -#define GLOP_RETURN_IF_ERROR(function_call) \ - do { \ - Status return_status = function_call; \ - if (!return_status.ok()) \ - return return_status; \ +#define GLOP_RETURN_IF_ERROR(function_call) \ + do { \ + Status return_status = function_call; \ + if (!return_status.ok()) return return_status; \ } while (false) // Macro to simplify the creation of an error. -#define GLOP_RETURN_AND_LOG_ERROR(error_code, message) \ - do { \ - std::string error_message = message; \ - LOG(ERROR) << GetErrorCodeString(error_code) << ": " << error_message; \ - return Status(error_code, error_message); \ +#define GLOP_RETURN_AND_LOG_ERROR(error_code, message) \ + do { \ + std::string error_message = message; \ + LOG(ERROR) << GetErrorCodeString(error_code) << ": " << error_message; \ + return Status(error_code, error_message); \ } while (false) // Macro to check that a pointer argument is not null. -#define GLOP_RETURN_ERROR_IF_NULL(arg) \ - if (arg == nullptr) { \ - const std::string variable_name = #arg; \ - std::string error_message = variable_name + " must not be null."; \ - LOG(DFATAL) << error_message; \ - return Status(Status::ERROR_NULL, error_message); \ +#define GLOP_RETURN_ERROR_IF_NULL(arg) \ + if (arg == nullptr) { \ + const std::string variable_name = #arg; \ + std::string error_message = variable_name + " must not be null."; \ + LOG(DFATAL) << error_message; \ + return Status(Status::ERROR_NULL, error_message); \ } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_STATUS_H_ +#endif // OR_TOOLS_GLOP_STATUS_H_ diff --git a/ortools/glop/update_row.cc b/ortools/glop/update_row.cc index 2d8d6100cd..10a86da1bb 100644 --- a/ortools/glop/update_row.cc +++ b/ortools/glop/update_row.cc @@ -23,11 +23,19 @@ UpdateRow::UpdateRow(const CompactSparseMatrix &matrix, const VariablesInfo &variables_info, const RowToColMapping &basis, const BasisFactorization &basis_factorization) - : matrix_(matrix), transposed_matrix_(transposed_matrix), - variables_info_(variables_info), basis_(basis), - basis_factorization_(basis_factorization), unit_row_left_inverse_(), - non_zero_position_list_(), non_zero_position_set_(), coefficient_(), - compute_update_row_(true), num_operations_(0), parameters_(), stats_() {} + : matrix_(matrix), + transposed_matrix_(transposed_matrix), + variables_info_(variables_info), + basis_(basis), + basis_factorization_(basis_factorization), + unit_row_left_inverse_(), + non_zero_position_list_(), + non_zero_position_set_(), + coefficient_(), + compute_update_row_(true), + num_operations_(0), + parameters_(), + stats_() {} void UpdateRow::Invalidate() { SCOPED_TIME_STAT(&stats_); @@ -36,8 +44,7 @@ void UpdateRow::Invalidate() { void UpdateRow::IgnoreUpdatePosition(ColIndex col) { SCOPED_TIME_STAT(&stats_); - if (col >= coefficient_.size()) - return; + if (col >= coefficient_.size()) return; coefficient_[col] = 0.0; } @@ -46,8 +53,8 @@ const ScatteredRow &UpdateRow::GetUnitRowLeftInverse() const { return unit_row_left_inverse_; } -const ScatteredRow & -UpdateRow::ComputeAndGetUnitRowLeftInverse(RowIndex leaving_row) { +const ScatteredRow &UpdateRow::ComputeAndGetUnitRowLeftInverse( + RowIndex leaving_row) { Invalidate(); basis_factorization_.TemporaryLeftSolveForUnitRow(RowToColIndex(leaving_row), &unit_row_left_inverse_); @@ -60,16 +67,16 @@ void UpdateRow::ComputeUnitRowLeftInverse(RowIndex leaving_row) { &unit_row_left_inverse_); // TODO(user): Refactorize if the estimated accuracy is above a threshold. - IF_STATS_ENABLED( - stats_.unit_row_left_inverse_accuracy.Add(matrix_.ColumnScalarProduct( - basis_[leaving_row], unit_row_left_inverse_.values) - 1.0)); + IF_STATS_ENABLED(stats_.unit_row_left_inverse_accuracy.Add( + matrix_.ColumnScalarProduct(basis_[leaving_row], + unit_row_left_inverse_.values) - + 1.0)); IF_STATS_ENABLED(stats_.unit_row_left_inverse_density.Add( Density(unit_row_left_inverse_.values()))); } void UpdateRow::ComputeUpdateRow(RowIndex leaving_row) { - if (!compute_update_row_ && update_row_computed_for_ == leaving_row) - return; + if (!compute_update_row_ && update_row_computed_for_ == leaving_row) return; compute_update_row_ = false; update_row_computed_for_ = leaving_row; ComputeUnitRowLeftInverse(leaving_row); @@ -278,5 +285,5 @@ void UpdateRow::ComputeUpdatesColumnWise() { } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/update_row.h b/ortools/glop/update_row.h index 825cf9f258..50effa36d2 100644 --- a/ortools/glop/update_row.h +++ b/ortools/glop/update_row.h @@ -36,7 +36,7 @@ namespace glop { // scalar product of this left inverse with all the columns of A: // update_row[col] = (unit_{leaving_row} . B^{-1}) . A_col class UpdateRow { -public: + public: // Takes references to the linear program data we need. UpdateRow(const CompactSparseMatrix &matrix, const CompactSparseMatrix &transposed_matrix, @@ -97,7 +97,7 @@ public: // the class state by calling Invalidate(). const ScatteredRow &ComputeAndGetUnitRowLeftInverse(RowIndex leaving_row); -private: + private: // Computes the left inverse of the given unit row, and stores it in // unit_row_left_inverse_. void ComputeUnitRowLeftInverse(RowIndex leaving_row); @@ -156,7 +156,7 @@ private: DISALLOW_COPY_AND_ASSIGN(UpdateRow); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_UPDATE_ROW_H_ +#endif // OR_TOOLS_GLOP_UPDATE_ROW_H_ diff --git a/ortools/glop/variable_values.cc b/ortools/glop/variable_values.cc index 454aa9b30b..df21f6208a 100644 --- a/ortools/glop/variable_values.cc +++ b/ortools/glop/variable_values.cc @@ -24,9 +24,12 @@ VariableValues::VariableValues(const GlopParameters ¶meters, const RowToColMapping &basis, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization) - : parameters_(parameters), matrix_(matrix), basis_(basis), + : parameters_(parameters), + matrix_(matrix), + basis_(basis), variables_info_(variables_info), - basis_factorization_(basis_factorization), stats_("VariableValues") {} + basis_factorization_(basis_factorization), + stats_("VariableValues") {} void VariableValues::SetNonBasicVariableValueFromStatus(ColIndex col) { SCOPED_TIME_STAT(&stats_); @@ -34,28 +37,28 @@ void VariableValues::SetNonBasicVariableValueFromStatus(ColIndex col) { const DenseRow &upper_bounds = variables_info_.GetVariableUpperBounds(); variable_values_.resize(matrix_.num_cols(), 0.0); switch (variables_info_.GetStatusRow()[col]) { - case VariableStatus::FIXED_VALUE: - DCHECK_NE(-kInfinity, lower_bounds[col]); - DCHECK_EQ(lower_bounds[col], upper_bounds[col]); - variable_values_[col] = lower_bounds[col]; - break; - case VariableStatus::AT_LOWER_BOUND: - DCHECK_NE(-kInfinity, lower_bounds[col]); - variable_values_[col] = lower_bounds[col]; - break; - case VariableStatus::AT_UPPER_BOUND: - DCHECK_NE(kInfinity, upper_bounds[col]); - variable_values_[col] = upper_bounds[col]; - break; - case VariableStatus::FREE: - DCHECK_EQ(-kInfinity, lower_bounds[col]); - DCHECK_EQ(kInfinity, upper_bounds[col]); - variable_values_[col] = 0.0; - break; - case VariableStatus::BASIC: - LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't " - << "be called on a BASIC variable."; - break; + case VariableStatus::FIXED_VALUE: + DCHECK_NE(-kInfinity, lower_bounds[col]); + DCHECK_EQ(lower_bounds[col], upper_bounds[col]); + variable_values_[col] = lower_bounds[col]; + break; + case VariableStatus::AT_LOWER_BOUND: + DCHECK_NE(-kInfinity, lower_bounds[col]); + variable_values_[col] = lower_bounds[col]; + break; + case VariableStatus::AT_UPPER_BOUND: + DCHECK_NE(kInfinity, upper_bounds[col]); + variable_values_[col] = upper_bounds[col]; + break; + case VariableStatus::FREE: + DCHECK_EQ(-kInfinity, lower_bounds[col]); + DCHECK_EQ(kInfinity, upper_bounds[col]); + variable_values_[col] = 0.0; + break; + case VariableStatus::BASIC: + LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't " + << "be called on a BASIC variable."; + break; } // Note that there is no default value in the switch() statement above to // get a compile-time error if a value is missing. @@ -69,19 +72,19 @@ void VariableValues::ResetAllNonBasicVariableValues() { variable_values_.resize(num_cols, 0.0); for (ColIndex col(0); col < num_cols; ++col) { switch (statuses[col]) { - case VariableStatus::FIXED_VALUE: - ABSL_FALLTHROUGH_INTENDED; - case VariableStatus::AT_LOWER_BOUND: - variable_values_[col] = lower_bounds[col]; - break; - case VariableStatus::AT_UPPER_BOUND: - variable_values_[col] = upper_bounds[col]; - break; - case VariableStatus::FREE: - variable_values_[col] = 0.0; - break; - case VariableStatus::BASIC: - break; + case VariableStatus::FIXED_VALUE: + ABSL_FALLTHROUGH_INTENDED; + case VariableStatus::AT_LOWER_BOUND: + variable_values_[col] = lower_bounds[col]; + break; + case VariableStatus::AT_UPPER_BOUND: + variable_values_[col] = upper_bounds[col]; + break; + case VariableStatus::FREE: + variable_values_[col] = 0.0; + break; + case VariableStatus::BASIC: + break; } } } @@ -262,5 +265,5 @@ void VariableValues::UpdatePrimalInfeasibilityInformation( } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/variable_values.h b/ortools/glop/variable_values.h index af5c9102a1..73520ce512 100644 --- a/ortools/glop/variable_values.h +++ b/ortools/glop/variable_values.h @@ -38,7 +38,7 @@ namespace glop { // pivoting which is implemented by not setting the variable values exactly at // their bounds to have a lower primal residual error. class VariableValues { -public: + public: VariableValues(const GlopParameters ¶meters, const CompactSparseMatrix &matrix, const RowToColMapping &basis, @@ -117,7 +117,7 @@ public: // Parameters and stats functions. std::string StatString() const { return stats_.StatString(); } -private: + private: // It is important that the infeasibility is always computed in the same // way. So the code should always use these functions that returns a positive // value when the variable is out of bounds. @@ -175,7 +175,7 @@ bool VariableValues::UpdatePrimalPhaseICosts(const Rows &rows, return changed; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_VARIABLE_VALUES_H_ +#endif // OR_TOOLS_GLOP_VARIABLE_VALUES_H_ diff --git a/ortools/glop/variables_info.cc b/ortools/glop/variables_info.cc index d00d6c7de0..d62ae4c6b4 100644 --- a/ortools/glop/variables_info.cc +++ b/ortools/glop/variables_info.cc @@ -19,7 +19,9 @@ namespace glop { VariablesInfo::VariablesInfo(const CompactSparseMatrix &matrix, const DenseRow &lower_bound, const DenseRow &upper_bound) - : matrix_(matrix), lower_bound_(lower_bound), upper_bound_(upper_bound), + : matrix_(matrix), + lower_bound_(lower_bound), + upper_bound_(upper_bound), boxed_variables_are_relevant_(true) {} void VariablesInfo::InitializeAndComputeType() { @@ -42,8 +44,7 @@ void VariablesInfo::InitializeAndComputeType() { } void VariablesInfo::MakeBoxedVariableRelevant(bool value) { - if (value == boxed_variables_are_relevant_) - return; + if (value == boxed_variables_are_relevant_) return; boxed_variables_are_relevant_ = value; if (value) { for (const ColIndex col : non_basic_boxed_variables_) { @@ -144,8 +145,7 @@ VariableType VariablesInfo::ComputeVariableType(ColIndex col) const { } void VariablesInfo::SetRelevance(ColIndex col, bool relevance) { - if (relevance_.IsSet(col) == relevance) - return; + if (relevance_.IsSet(col) == relevance) return; if (relevance) { relevance_.Set(col); num_entries_in_relevant_columns_ += matrix_.ColumnNumEntries(col); @@ -155,5 +155,5 @@ void VariablesInfo::SetRelevance(ColIndex col, bool relevance) { } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/glop/variables_info.h b/ortools/glop/variables_info.h index 0d094b169e..01a66af6e2 100644 --- a/ortools/glop/variables_info.h +++ b/ortools/glop/variables_info.h @@ -27,7 +27,7 @@ namespace glop { // maintain it since it only requires a few calls to Update() per simplex // iteration. class VariablesInfo { -public: + public: // Takes references to the linear program data we need. VariablesInfo(const CompactSparseMatrix &matrix, const DenseRow &lower_bound, const DenseRow &upper_bound); @@ -77,7 +77,7 @@ public: return upper_bound_[col] - lower_bound_[col]; } -private: + private: // Computes the variable type from its lower and upper bound. VariableType ComputeVariableType(ColIndex col) const; @@ -125,7 +125,7 @@ private: DISALLOW_COPY_AND_ASSIGN(VariablesInfo); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_GLOP_VARIABLES_INFO_H_ +#endif // OR_TOOLS_GLOP_VARIABLES_INFO_H_ diff --git a/ortools/graph/assignment.cc b/ortools/graph/assignment.cc index 7cc0626ab4..e70722e51d 100644 --- a/ortools/graph/assignment.cc +++ b/ortools/graph/assignment.cc @@ -52,16 +52,14 @@ CostValue SimpleLinearSumAssignment::Cost(ArcIndex arc) const { SimpleLinearSumAssignment::Status SimpleLinearSumAssignment::Solve() { optimal_cost_ = 0; assignment_arcs_.clear(); - if (NumNodes() == 0) - return OPTIMAL; + if (NumNodes() == 0) return OPTIMAL; // HACK(user): Detect overflows early. In ./linear_assignment.h, the cost of // each arc is internally multiplied by cost_scaling_factor_ (which is equal // to (num_nodes + 1)) without overflow checking. const CostValue max_supported_arc_cost = std::numeric_limits::max() / (NumNodes() + 1); for (const CostValue unscaled_arc_cost : arc_cost_) { - if (unscaled_arc_cost > max_supported_arc_cost) - return POSSIBLE_OVERFLOW; + if (unscaled_arc_cost > max_supported_arc_cost) return POSSIBLE_OVERFLOW; } const ArcIndex num_arcs = arc_cost_.size(); @@ -73,10 +71,8 @@ SimpleLinearSumAssignment::Status SimpleLinearSumAssignment::Solve() { } // TODO(user): Improve the LinearSumAssignment api to clearly define // the error cases. - if (!assignment.FinalizeSetup()) - return POSSIBLE_OVERFLOW; - if (!assignment.ComputeAssignment()) - return INFEASIBLE; + if (!assignment.FinalizeSetup()) return POSSIBLE_OVERFLOW; + if (!assignment.ComputeAssignment()) return INFEASIBLE; optimal_cost_ = assignment.GetCost(); for (NodeIndex node = 0; node < num_nodes_; ++node) { assignment_arcs_.push_back(assignment.GetAssignmentArc(node)); @@ -84,4 +80,4 @@ SimpleLinearSumAssignment::Status SimpleLinearSumAssignment::Solve() { return OPTIMAL; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/assignment.h b/ortools/graph/assignment.h index ea6da33c2c..b64f1c7d23 100644 --- a/ortools/graph/assignment.h +++ b/ortools/graph/assignment.h @@ -55,7 +55,7 @@ namespace operations_research { class SimpleLinearSumAssignment { -public: + public: // The constructor takes no size. // New node indices will be created lazily by AddArcWithCost(). SimpleLinearSumAssignment(); @@ -86,9 +86,9 @@ public: // Solves the problem (finds the perfect matching that minimizes the // cost) and returns the solver status. enum Status { - OPTIMAL, // The algorithm found a minimum-cost perfect matching. - INFEASIBLE, // The given problem admits no perfect matching. - POSSIBLE_OVERFLOW, // Some cost magnitude is too large. + OPTIMAL, // The algorithm found a minimum-cost perfect matching. + INFEASIBLE, // The given problem admits no perfect matching. + POSSIBLE_OVERFLOW, // Some cost magnitude is too large. }; Status Solve(); @@ -115,7 +115,7 @@ public: return arc_cost_[assignment_arcs_[left_node]]; } -private: + private: NodeIndex num_nodes_; std::vector arc_tail_; std::vector arc_head_; @@ -125,6 +125,6 @@ private: DISALLOW_COPY_AND_ASSIGN(SimpleLinearSumAssignment); }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_ASSIGNMENT_H_ +#endif // OR_TOOLS_GRAPH_ASSIGNMENT_H_ diff --git a/ortools/graph/astar.cc b/ortools/graph/astar.cc index 5e21579ee4..9887b6b5ec 100644 --- a/ortools/graph/astar.cc +++ b/ortools/graph/astar.cc @@ -25,7 +25,7 @@ namespace { // Priority queue element class Element { -public: + public: Element() : heap_index_(-1), distance_(0), node_(-1), distance_with_heuristic_(0) {} @@ -46,27 +46,30 @@ public: void set_node(int node) { node_ = node; } int node() const { return node_; } -private: + private: int heap_index_; int64 distance_; int64 distance_with_heuristic_; int node_; }; -} // namespace +} // namespace class AStarSP { -public: + public: static const int64 kInfinity = kint64max / 2; AStarSP(int node_count, int start_node, std::function graph, std::function heuristic, int64 disconnected_distance) - : node_count_(node_count), start_node_(start_node), - graph_(std::move(graph)), disconnected_distance_(disconnected_distance), - predecessor_(new int[node_count]), elements_(node_count), + : node_count_(node_count), + start_node_(start_node), + graph_(std::move(graph)), + disconnected_distance_(disconnected_distance), + predecessor_(new int[node_count]), + elements_(node_count), heuristic_(std::move(heuristic)) {} bool ShortestPath(int end_node, std::vector *nodes); -private: + private: void Initialize(); int SelectClosestNode(int64 *distance); void Update(int label); @@ -172,4 +175,4 @@ bool AStarShortestPath(int node_count, int start_node, int end_node, disconnected_distance); return bf.ShortestPath(end_node, nodes); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/bellman_ford.cc b/ortools/graph/bellman_ford.cc index 125f443626..dc6cadf540 100644 --- a/ortools/graph/bellman_ford.cc +++ b/ortools/graph/bellman_ford.cc @@ -21,17 +21,20 @@ namespace operations_research { class BellmanFord { -public: + public: static constexpr int64 kInfinity = kint64max / 2; BellmanFord(int node_count, int start_node, std::function graph, int64 disconnected_distance) - : node_count_(node_count), start_node_(start_node), - graph_(std::move(graph)), disconnected_distance_(disconnected_distance), - distance_(new int64[node_count_]), predecessor_(new int[node_count_]) {} + : node_count_(node_count), + start_node_(start_node), + graph_(std::move(graph)), + disconnected_distance_(disconnected_distance), + distance_(new int64[node_count_]), + predecessor_(new int[node_count_]) {} bool ShortestPath(int end_node, std::vector *nodes); -private: + private: void Initialize(); void Update(); bool Check() const; @@ -114,4 +117,4 @@ bool BellmanFordShortestPath(int node_count, int start_node, int end_node, disconnected_distance); return bf.ShortestPath(end_node, nodes); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/christofides.h b/ortools/graph/christofides.h index 20c7c1f440..a8d022698f 100644 --- a/ortools/graph/christofides.h +++ b/ortools/graph/christofides.h @@ -38,13 +38,13 @@ template < typename CostType, typename ArcIndex = int64, typename NodeIndex = int32, typename CostFunction = std::function > class ChristofidesPathSolver { -public: + public: enum class MatchingAlgorithm { MINIMUM_WEIGHT_MATCHING, #if defined(USE_CBC) || defined(USE_SCIP) - MINIMUM_WEIGHT_MATCHING_WITH_MIP, -#endif // defined(USE_CBC) || defined(USE_SCIP) - MINIMAL_WEIGHT_MATCHING, + MINIMUM_WEIGHT_MATCHING_WITH_MIP, +#endif // defined(USE_CBC) || defined(USE_SCIP) + MINIMAL_WEIGHT_MATCHING, }; ChristofidesPathSolver(NodeIndex num_nodes, CostFunction costs); @@ -66,7 +66,7 @@ public: // Returns the approximate TSP tour. std::vector TravelingSalesmanPath(); -private: + private: // Runs the Christofides algorithm. void Solve(); @@ -120,7 +120,7 @@ ComputeMinimumWeightMatching(const GraphType &graph, std::vector > match; for (NodeIndex tail : graph.AllNodes()) { const NodeIndex head = matching.Match(tail); - if (tail < head) { // Both arcs are matched for a given edge, we keep one. + if (tail < head) { // Both arcs are matched for a given edge, we keep one. match.emplace_back(tail, head); } } @@ -203,15 +203,17 @@ ComputeMinimumWeightMatchingWithMIP(const GraphType &graph, } return matching; } -#endif // defined(USE_CBC) || defined(USE_SCIP) +#endif // defined(USE_CBC) || defined(USE_SCIP) template -ChristofidesPathSolver::ChristofidesPathSolver( - NodeIndex num_nodes, CostFunction costs) - : matching_(MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING), graph_(num_nodes), - costs_(std::move(costs)), tsp_cost_(0), solved_(false) {} +ChristofidesPathSolver:: + ChristofidesPathSolver(NodeIndex num_nodes, CostFunction costs) + : matching_(MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING), + graph_(num_nodes), + costs_(std::move(costs)), + tsp_cost_(0), + solved_(false) {} template @@ -235,22 +237,22 @@ std::vector ChristofidesPathSolver< template -void -ChristofidesPathSolver::Solve() { +void ChristofidesPathSolver::Solve() { const NodeIndex num_nodes = graph_.num_nodes(); tsp_path_.clear(); tsp_cost_ = 0; if (num_nodes == 1) { - tsp_path_ = { 0, 0 }; + tsp_path_ = {0, 0}; } if (num_nodes <= 1) { return; } - // Compute Minimum Spanning Tree. + // Compute Minimum Spanning Tree. const std::vector mst = BuildPrimMinimumSpanningTree(graph_, [this](ArcIndex arc) { - return costs_(graph_.Tail(arc), graph_.Head(arc)); - }); + return costs_(graph_.Tail(arc), graph_.Head(arc)); + }); // Detect odd degree nodes. std::vector degrees(num_nodes, 0); for (ArcIndex arc : mst) { @@ -270,55 +272,55 @@ ChristofidesPathSolver::Solve() { CompleteGraph reduced_graph(reduced_size); std::vector > closure_arcs; switch (matching_) { - case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING: { - closure_arcs = ComputeMinimumWeightMatching( - reduced_graph, [this, &reduced_graph, &odd_degree_nodes]( - CompleteGraph<>::ArcIndex arc) { - return costs_(odd_degree_nodes[reduced_graph.Tail(arc)], - odd_degree_nodes[reduced_graph.Head(arc)]); - }); - break; - } + case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING: { + closure_arcs = ComputeMinimumWeightMatching( + reduced_graph, [this, &reduced_graph, + &odd_degree_nodes](CompleteGraph<>::ArcIndex arc) { + return costs_(odd_degree_nodes[reduced_graph.Tail(arc)], + odd_degree_nodes[reduced_graph.Head(arc)]); + }); + break; + } #if defined(USE_CBC) || defined(USE_SCIP) - case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING_WITH_MIP: { - closure_arcs = ComputeMinimumWeightMatchingWithMIP( - reduced_graph, [this, &reduced_graph, &odd_degree_nodes]( - CompleteGraph<>::ArcIndex arc) { - return costs_(odd_degree_nodes[reduced_graph.Tail(arc)], - odd_degree_nodes[reduced_graph.Head(arc)]); - }); - break; - } -#endif // defined(USE_CBC) || defined(USE_SCIP) - case MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING: { - // TODO(user): Cost caching was added and can gain up to 20% but - // increases memory usage; see if we can avoid caching. - std::vector ordered_arcs(reduced_graph.num_arcs()); - std::vector ordered_arc_costs(reduced_graph.num_arcs(), 0); - for (const ArcIndex arc : reduced_graph.AllForwardArcs()) { - ordered_arcs[arc] = arc; - ordered_arc_costs[arc] = - costs_(odd_degree_nodes[reduced_graph.Tail(arc)], - odd_degree_nodes[reduced_graph.Head(arc)]); + case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING_WITH_MIP: { + closure_arcs = ComputeMinimumWeightMatchingWithMIP( + reduced_graph, [this, &reduced_graph, + &odd_degree_nodes](CompleteGraph<>::ArcIndex arc) { + return costs_(odd_degree_nodes[reduced_graph.Tail(arc)], + odd_degree_nodes[reduced_graph.Head(arc)]); + }); + break; } - std::sort(ordered_arcs.begin(), ordered_arcs.end(), - [&ordered_arc_costs](ArcIndex arc_a, ArcIndex arc_b) { - return ordered_arc_costs[arc_a] < ordered_arc_costs[arc_b]; - }); - std::vector touched_nodes(reduced_size, false); - for (ArcIndex arc_index = 0; closure_arcs.size() * 2 < reduced_size; - ++arc_index) { - const ArcIndex arc = ordered_arcs[arc_index]; - const NodeIndex tail = reduced_graph.Tail(arc); - const NodeIndex head = reduced_graph.Head(arc); - if (head != tail && !touched_nodes[tail] && !touched_nodes[head]) { - touched_nodes[tail] = true; - touched_nodes[head] = true; - closure_arcs.emplace_back(tail, head); +#endif // defined(USE_CBC) || defined(USE_SCIP) + case MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING: { + // TODO(user): Cost caching was added and can gain up to 20% but + // increases memory usage; see if we can avoid caching. + std::vector ordered_arcs(reduced_graph.num_arcs()); + std::vector ordered_arc_costs(reduced_graph.num_arcs(), 0); + for (const ArcIndex arc : reduced_graph.AllForwardArcs()) { + ordered_arcs[arc] = arc; + ordered_arc_costs[arc] = + costs_(odd_degree_nodes[reduced_graph.Tail(arc)], + odd_degree_nodes[reduced_graph.Head(arc)]); } + std::sort(ordered_arcs.begin(), ordered_arcs.end(), + [&ordered_arc_costs](ArcIndex arc_a, ArcIndex arc_b) { + return ordered_arc_costs[arc_a] < ordered_arc_costs[arc_b]; + }); + std::vector touched_nodes(reduced_size, false); + for (ArcIndex arc_index = 0; closure_arcs.size() * 2 < reduced_size; + ++arc_index) { + const ArcIndex arc = ordered_arcs[arc_index]; + const NodeIndex tail = reduced_graph.Tail(arc); + const NodeIndex head = reduced_graph.Head(arc); + if (head != tail && !touched_nodes[tail] && !touched_nodes[head]) { + touched_nodes[tail] = true; + touched_nodes[head] = true; + closure_arcs.emplace_back(tail, head); + } + } + break; } - break; - } } // Build Eulerian path on minimum spanning tree + closing edges from matching // and extract a solution to the Traveling Salesman from the path by skipping @@ -334,8 +336,7 @@ ChristofidesPathSolver::Solve() { std::vector touched(num_nodes, false); DCHECK(IsEulerianGraph(egraph)); for (const NodeIndex node : BuildEulerianTourFromNode(egraph, 0)) { - if (touched[node]) - continue; + if (touched[node]) continue; touched[node] = true; tsp_cost_ = SafeAdd(tsp_cost_, tsp_path_.empty() ? 0 : costs_(tsp_path_.back(), node)); @@ -346,6 +347,6 @@ ChristofidesPathSolver::Solve() { tsp_path_.push_back(0); solved_ = true; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_CHRISTOFIDES_H_ +#endif // OR_TOOLS_GRAPH_CHRISTOFIDES_H_ diff --git a/ortools/graph/cliques.cc b/ortools/graph/cliques.cc index b787ea1f9d..c11822d34b 100644 --- a/ortools/graph/cliques.cc +++ b/ortools/graph/cliques.cc @@ -185,7 +185,7 @@ void Search(std::function graph, } class FindAndEliminate { -public: + public: FindAndEliminate(std::function graph, int node_count, std::function &)> callback) : graph_(graph), node_count_(node_count), callback_(callback) {} @@ -213,13 +213,13 @@ public: return false; } -private: + private: std::function graph_; int node_count_; std::function &)> callback_; absl::flat_hash_set > visited_; }; -} // namespace +} // namespace // This method implements the 'version2' of the Bron-Kerbosch // algorithm to find all maximal cliques in a undirected graph. @@ -237,22 +237,20 @@ void FindCliques(std::function graph, int node_count, &stop); } -void -CoverArcsByCliques(std::function graph, int node_count, - std::function &)> callback) { +void CoverArcsByCliques( + std::function graph, int node_count, + std::function &)> callback) { FindAndEliminate cache(graph, node_count, callback); std::unique_ptr initial_candidates(new int[node_count]); std::vector actual; std::function cached_graph = [&cache](int i, int j) { return cache.GraphCallback(i, j); - } - ; + }; std::function &)> cached_callback = - [&cache](const std::vector & res) { - return cache.SolutionCallback(res); - } - ; + [&cache](const std::vector &res) { + return cache.SolutionCallback(res); + }; for (int c = 0; c < node_count; ++c) { initial_candidates[c] = c; @@ -263,4 +261,4 @@ CoverArcsByCliques(std::function graph, int node_count, &actual, &stop); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/cliques.h b/ortools/graph/cliques.h index 574d53e991..b3af6af911 100644 --- a/ortools/graph/cliques.h +++ b/ortools/graph/cliques.h @@ -58,10 +58,10 @@ void CoverArcsByCliques(std::function graph, int node_count, enum class CliqueResponse { // The algorithm will continue searching for other maximal cliques. CONTINUE, - // The algorithm will stop the search immediately. The search can be - // resumed - // by calling BronKerboschAlgorithm::Run (resp. RunIterations) again. - STOP + // The algorithm will stop the search immediately. The search can be + // resumed + // by calling BronKerboschAlgorithm::Run (resp. RunIterations) again. + STOP }; // The status value returned by BronKerboschAlgorithm::Run and @@ -69,10 +69,10 @@ enum class CliqueResponse { enum class BronKerboschAlgorithmStatus { // The algorithm has enumerated all maximal cliques. COMPLETED, - // The search algorithm was interrupted either because it reached the - // iteration limit or because the clique callback returned - // CliqueResponse::STOP. - INTERRUPTED + // The search algorithm was interrupted either because it reached the + // iteration limit or because the clique callback returned + // CliqueResponse::STOP. + INTERRUPTED }; // Implements the Bron-Kerbosch algorithm for finding maximal cliques. @@ -141,8 +141,9 @@ enum class BronKerboschAlgorithmStatus { // // The worst-case time complexity of the algorithm is O(3^(N/3)), and the memory // complexity is O(N^2), where N is the number of nodes in the graph. -template class BronKerboschAlgorithm { -public: +template +class BronKerboschAlgorithm { + public: // A callback called by the algorithm to test if there is an arc between a // pair of nodes. The callback must return true if and only if there is an // arc. Note that to function properly, the function must be symmetrical @@ -164,7 +165,8 @@ public: BronKerboschAlgorithm(IsArcCallback is_arc, NodeIndex num_nodes, CliqueCallback clique_callback) : is_arc_(std::move(is_arc)), - clique_callback_(std::move(clique_callback)), num_nodes_(num_nodes) {} + clique_callback_(std::move(clique_callback)), + num_nodes_(num_nodes) {} // Runs the Bron-Kerbosch algorithm for kint64max iterations. In practice, // this is equivalent to running until completion or until the clique callback @@ -204,7 +206,7 @@ public: return RunWithTimeLimit(kint64max, time_limit); } -private: + private: DEFINE_INT_TYPE(CandidateIndex, ptrdiff_t); // A data structure that maintains the variables of one "iteration" of the @@ -248,8 +250,7 @@ private: "\nnum_remaining_candidates = ", num_remaining_candidates, "\ncandidates = ["); for (CandidateIndex i(0); i < candidates.size(); ++i) { - if (i > 0) - buffer += ", "; + if (i > 0) buffer += ", "; absl::StrAppend(&buffer, candidates[i]); } absl::StrAppend( @@ -363,7 +364,7 @@ void BronKerboschAlgorithm::InitializeState(State *state) { CandidateIndex pivot_index(-1); for (CandidateIndex pivot_candidate_index(0); pivot_candidate_index < num_candidates && - num_disconnected_candidates > 0; + num_disconnected_candidates > 0; ++pivot_candidate_index) { const NodeIndex pivot_candidate = state->candidates[pivot_candidate_index]; int count = 0; @@ -506,9 +507,8 @@ void BronKerboschAlgorithm::PushState(NodeIndex selected) { } template -BronKerboschAlgorithmStatus -BronKerboschAlgorithm::RunWithTimeLimit(int64 max_num_iterations, - TimeLimit *time_limit) { +BronKerboschAlgorithmStatus BronKerboschAlgorithm::RunWithTimeLimit( + int64 max_num_iterations, TimeLimit *time_limit) { CHECK(time_limit != nullptr); time_limit_ = time_limit; if (states_.empty()) { @@ -516,7 +516,7 @@ BronKerboschAlgorithm::RunWithTimeLimit(int64 max_num_iterations, } for (num_remaining_iterations_ = max_num_iterations; !states_.empty() && num_remaining_iterations_ > 0 && - !time_limit->LimitReached(); + !time_limit->LimitReached(); --num_remaining_iterations_) { State *const state = &states_.back(); DVLOG(2) << "Loop: " << states_.size() << " states, " @@ -545,8 +545,8 @@ BronKerboschAlgorithm::RunWithTimeLimit(int64 max_num_iterations, } template -BronKerboschAlgorithmStatus -BronKerboschAlgorithm::RunIterations(int64 max_num_iterations) { +BronKerboschAlgorithmStatus BronKerboschAlgorithm::RunIterations( + int64 max_num_iterations) { TimeLimit time_limit(std::numeric_limits::infinity()); return RunWithTimeLimit(max_num_iterations, &time_limit); } @@ -559,6 +559,6 @@ BronKerboschAlgorithmStatus BronKerboschAlgorithm::Run() { template const double BronKerboschAlgorithm< NodeIndex>::kPushStateDeterministicTimeSecondsPerCandidate = 0.54663e-7; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_CLIQUES_H_ +#endif // OR_TOOLS_GRAPH_CLIQUES_H_ diff --git a/ortools/graph/connected_components.cc b/ortools/graph/connected_components.cc index 8458e6186a..f663d9c09b 100644 --- a/ortools/graph/connected_components.cc +++ b/ortools/graph/connected_components.cc @@ -83,13 +83,12 @@ const std::vector &DenseConnectedComponentsFinder::GetComponentRoots() { num_nodes_at_last_get_roots_call_); } - // Remove the roots that have been merged with other components. Each node - // only gets removed once from the roots vector, so the cost of FindRoot() - // is - // amortized against adding the edge. - gtl::STLEraseAllFromSequenceIf(&roots_, [&](const int node) { - return node != FindRoot(node); - }); + // Remove the roots that have been merged with other components. Each node + // only gets removed once from the roots vector, so the cost of FindRoot() + // is + // amortized against adding the edge. + gtl::STLEraseAllFromSequenceIf( + &roots_, [&](const int node) { return node != FindRoot(node); }); num_nodes_at_last_get_roots_call_ = num_nodes; return roots_; diff --git a/ortools/graph/connected_components.h b/ortools/graph/connected_components.h index 2ca7926b40..d75808248e 100644 --- a/ortools/graph/connected_components.h +++ b/ortools/graph/connected_components.h @@ -72,14 +72,14 @@ namespace util { template std::vector GetConnectedComponents(int num_nodes, const UndirectedGraph &graph); -} // namespace util +} // namespace util // NOTE(user): The rest of the functions below should also be in namespace // util, but for historical reasons it hasn't been done yet. // A connected components finder that only works on dense ints. class DenseConnectedComponentsFinder { -public: + public: DenseConnectedComponentsFinder() {} DenseConnectedComponentsFinder(const DenseConnectedComponentsFinder &) = @@ -113,7 +113,7 @@ public: // Returns the same as GetConnectedComponents(). std::vector GetComponentIds(); -private: + private: // parent[i] is the id of an ancestor for node i. A node is a root iff // parent[i] == i. std::vector parent_; @@ -138,7 +138,8 @@ template struct ConnectedComponentsTypeHelper { // SFINAE trait to detect hash functors and select unordered containers if so, // and ordered containers otherwise (= by default). - template struct SelectContainer { + template + struct SelectContainer { using Set = std::set; using Map = std::map; }; @@ -159,7 +160,7 @@ struct ConnectedComponentsTypeHelper { using Map = typename SelectContainer::Map; }; -} // namespace internal +} // namespace internal // Usage: // ConnectedComponentsFinder cc; @@ -195,7 +196,7 @@ struct ConnectedComponentsTypeHelper { // these pointers through its lifetime (though it doesn't dereference them). template > class ConnectedComponentsFinder { -public: + public: // Constructs a connected components finder. ConnectedComponentsFinder() {} @@ -268,10 +269,11 @@ public: // Nodes that were added several times only count once. int GetNumberOfNodes() const { return delegate_.GetNumberOfNodes(); } -private: + private: // Returns the index for the given node. If the node does not exist and // update_delegate is true, explicitly add the node to the delegate. - template int LookupOrInsertNode(T node) { + template + int LookupOrInsertNode(T node) { const auto result = index_.emplace(node, index_.size()); const int node_id = result.first->second; if (update_delegate && result.second) { @@ -297,15 +299,13 @@ std::vector GetConnectedComponents(int num_nodes, std::vector bfs_queue; int num_components = 0; for (int src = 0; src < num_nodes; ++src) { - if (component_of_node[src] >= 0) - continue; + if (component_of_node[src] >= 0) continue; bfs_queue.push_back(src); component_of_node[src] = num_components; for (int num_visited = 0; num_visited < bfs_queue.size(); ++num_visited) { const int node = bfs_queue[num_visited]; for (const int neighbor : graph[node]) { - if (component_of_node[neighbor] >= 0) - continue; + if (component_of_node[neighbor] >= 0) continue; component_of_node[neighbor] = num_components; bfs_queue.push_back(neighbor); } @@ -315,6 +315,6 @@ std::vector GetConnectedComponents(int num_nodes, } return component_of_node; } -} // namespace util +} // namespace util -#endif // UTIL_GRAPH_CONNECTED_COMPONENTS_H_ +#endif // UTIL_GRAPH_CONNECTED_COMPONENTS_H_ diff --git a/ortools/graph/dijkstra.cc b/ortools/graph/dijkstra.cc index 4207c0ffe2..b26204d9a6 100644 --- a/ortools/graph/dijkstra.cc +++ b/ortools/graph/dijkstra.cc @@ -26,7 +26,7 @@ namespace { // Priority queue element class Element { -public: + public: bool operator<(const Element &other) const { return distance_ != other.distance_ ? distance_ > other.distance_ : node_ > other.node_; @@ -38,22 +38,26 @@ public: void set_node(int node) { node_ = node; } int node() const { return node_; } -private: + private: int64 distance_ = 0; int heap_index_ = -1; int node_ = -1; }; -} // namespace +} // namespace -template class DijkstraSP { -public: +template +class DijkstraSP { + public: static constexpr int64 kInfinity = kint64max / 2; DijkstraSP(int node_count, int start_node, std::function graph, int64 disconnected_distance) - : node_count_(node_count), start_node_(start_node), - graph_(std::move(graph)), disconnected_distance_(disconnected_distance), - predecessor_(new int[node_count]), elements_(node_count) {} + : node_count_(node_count), + start_node_(start_node), + graph_(std::move(graph)), + disconnected_distance_(disconnected_distance), + predecessor_(new int[node_count]), + elements_(node_count) {} bool ShortestPath(int end_node, std::vector *nodes) { Initialize(); @@ -76,7 +80,7 @@ public: return found; } -private: + private: void Initialize() { for (int i = 0; i < node_count_; i++) { elements_[i].set_node(i); @@ -157,4 +161,4 @@ bool StableDijkstraShortestPath(int node_count, int start_node, int end_node, disconnected_distance); return bf.ShortestPath(end_node, nodes); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/ebert_graph.h b/ortools/graph/ebert_graph.h index 3c37210621..a8ddffca31 100644 --- a/ortools/graph/ebert_graph.h +++ b/ortools/graph/ebert_graph.h @@ -184,7 +184,8 @@ namespace operations_research { // Forward declarations. -template class EbertGraph; +template +class EbertGraph; template class ForwardEbertGraph; template @@ -210,7 +211,7 @@ typedef ZVector CostArray; template class StarGraphBase { -public: + public: // The index of the 'nil' node in the graph. static const NodeIndexType kNilNode; @@ -317,7 +318,7 @@ public: #if !defined(SWIG) // Iterator class for traversing all the nodes in the graph. class NodeIterator { - public: + public: explicit NodeIterator(const DerivedGraph &graph) : graph_(graph), head_(graph_.StartNode(kFirstNode)) {} @@ -330,7 +331,7 @@ public: // Returns the index of the node currently pointed to by the iterator. NodeIndexType Index() const { return head_; } - private: + private: // A reference to the current DerivedGraph considered. const DerivedGraph &graph_; @@ -340,7 +341,7 @@ public: // Iterator class for traversing the arcs in the graph. class ArcIterator { - public: + public: explicit ArcIterator(const DerivedGraph &graph) : graph_(graph), arc_(graph_.StartArc(kFirstArc)) {} @@ -353,7 +354,7 @@ public: // Returns the index of the arc currently pointed to by the iterator. ArcIndexType Index() const { return arc_; } - private: + private: // A reference to the current DerivedGraph considered. const DerivedGraph &graph_; @@ -363,9 +364,10 @@ public: // Iterator class for traversing the outgoing arcs associated to a given node. class OutgoingArcIterator { - public: + public: OutgoingArcIterator(const DerivedGraph &graph, NodeIndexType node) - : graph_(graph), node_(graph_.StartNode(node)), + : graph_(graph), + node_(graph_.StartNode(node)), arc_(graph_.StartArc(graph_.FirstOutgoingArc(node))) { DCHECK(CheckInvariant()); } @@ -374,7 +376,8 @@ public: // start at arc. OutgoingArcIterator(const DerivedGraph &graph, NodeIndexType node, ArcIndexType arc) - : graph_(graph), node_(graph_.StartNode(node)), + : graph_(graph), + node_(graph_.StartNode(node)), arc_(graph_.StartArc(arc)) { DCHECK(CheckInvariant()); } @@ -398,12 +401,12 @@ public: // Returns the index of the arc currently pointed to by the iterator. ArcIndexType Index() const { return arc_; } - private: + private: // Returns true if the invariant for the iterator is verified. // To be used in a DCHECK. bool CheckInvariant() const { if (arc_ == kNilArc) { - return true; // This occurs when the iterator has reached the end. + return true; // This occurs when the iterator has reached the end. } DCHECK(graph_.IsOutgoing(arc_, node_)); return true; @@ -418,11 +421,14 @@ public: // The index of the current arc considered. ArcIndexType arc_; }; -#endif // SWIG +#endif // SWIG -protected: + protected: StarGraphBase() - : max_num_nodes_(0), max_num_arcs_(0), num_nodes_(0), num_arcs_(0), + : max_num_nodes_(0), + max_num_arcs_(0), + num_nodes_(0), + num_arcs_(0), first_incident_arc_() {} ~StarGraphBase() {} @@ -495,7 +501,7 @@ protected: // incident to node i. ZVector first_incident_arc_; -private: + private: // Shorthand: returns a const DerivedGraph*-typed version of our // "this" pointer. inline const DerivedGraph *ThisAsDerived() const { @@ -511,7 +517,7 @@ private: template class PermutationIndexComparisonByArcHead { -public: + public: explicit PermutationIndexComparisonByArcHead( const ZVector &head) : head_(head) {} @@ -520,7 +526,7 @@ public: return head_[a] < head_[b]; } -private: + private: const ZVector &head_; }; @@ -529,7 +535,8 @@ class ForwardStaticGraph : public StarGraphBase > { typedef StarGraphBase > Base; + ForwardStaticGraph > + Base; friend class StarGraphBase >; @@ -543,7 +550,7 @@ class ForwardStaticGraph using Base::num_arcs_; using Base::num_nodes_; -public: + public: #if !defined(SWIG) using Base::end_arc_index; using Base::Head; @@ -552,7 +559,7 @@ public: using Base::kFirstArc; using Base::kFirstNode; using Base::kNilArc; -#endif // SWIG +#endif // SWIG typedef NodeIndexType NodeIndex; typedef ArcIndexType ArcIndex; @@ -564,7 +571,7 @@ public: : public ArrayIndexCycleHandler { typedef ArrayIndexCycleHandler Base; - public: + public: CycleHandlerForAnnotatedArcs( PermutationCycleHandler *annotation_handler, NodeIndexType *data) @@ -576,8 +583,8 @@ public: annotation_handler_->SetTempFromIndex(source); } - void SetIndexFromIndex(ArcIndexType source, ArcIndexType destination) const - override { + void SetIndexFromIndex(ArcIndexType source, + ArcIndexType destination) const override { Base::SetIndexFromIndex(source, destination); annotation_handler_->SetIndexFromIndex(source, destination); } @@ -587,12 +594,12 @@ public: annotation_handler_->SetIndexFromTemp(destination); } - private: + private: PermutationCycleHandler *annotation_handler_; DISALLOW_COPY_AND_ASSIGN(CycleHandlerForAnnotatedArcs); }; -#endif // SWIG +#endif // SWIG // Constructor for use by GraphBuilderFromArcs instances and direct // clients that want to materialize a graph in one step. @@ -618,8 +625,8 @@ public: // TODO(user): For some reason, SWIG breaks if the // operations_research namespace is not explicit in the // following argument declaration. - operations_research::PermutationCycleHandler< - ArcIndexType> *const client_cycle_handler) { + operations_research::PermutationCycleHandler + *const client_cycle_handler) { max_num_arcs_ = num_arcs; num_arcs_ = num_arcs; max_num_nodes_ = num_nodes; @@ -846,7 +853,7 @@ public: return true; } -private: + private: bool IsDirect() const { return true; } bool RepresentationClean() const { return true; } bool IsOutgoing(const NodeIndexType node, @@ -943,7 +950,7 @@ class EbertGraphBase typedef StarGraphBase Base; friend class StarGraphBase; -protected: + protected: using Base::first_incident_arc_; using Base::head_; using Base::max_num_arcs_; @@ -951,7 +958,7 @@ protected: using Base::num_arcs_; using Base::num_nodes_; -public: + public: #if !SWIG using Base::end_arc_index; using Base::IsNodeValid; @@ -962,7 +969,7 @@ public: using Base::kMaxNumNodes; using Base::kNilArc; using Base::kNilNode; -#endif // SWIG +#endif // SWIG // Reserves memory needed for max_num_nodes nodes and max_num_arcs arcs. // Returns false if the parameters passed are not OK. @@ -997,7 +1004,7 @@ public: return kNilArc; } if (tail + 1 > num_nodes_) { - num_nodes_ = tail + 1; // max does not work on int16. + num_nodes_ = tail + 1; // max does not work on int16. } if (head + 1 > num_nodes_) { num_nodes_ = head + 1; @@ -1039,12 +1046,14 @@ public: class CycleHandlerForAnnotatedArcs : public PermutationCycleHandler { - public: + public: CycleHandlerForAnnotatedArcs( PermutationCycleHandler *annotation_handler, DerivedGraph *graph) - : annotation_handler_(annotation_handler), graph_(graph), - head_temp_(kNilNode), tail_temp_(kNilNode) {} + : annotation_handler_(annotation_handler), + graph_(graph), + head_temp_(kNilNode), + tail_temp_(kNilNode) {} void SetTempFromIndex(ArcIndexType source) override { if (annotation_handler_ != nullptr) { @@ -1054,8 +1063,8 @@ public: tail_temp_ = graph_->Tail(source); } - void SetIndexFromIndex(ArcIndexType source, ArcIndexType destination) const - override { + void SetIndexFromIndex(ArcIndexType source, + ArcIndexType destination) const override { if (annotation_handler_ != nullptr) { annotation_handler_->SetIndexFromIndex(source, destination); } @@ -1085,7 +1094,7 @@ public: ~CycleHandlerForAnnotatedArcs() override {} - private: + private: PermutationCycleHandler *annotation_handler_; DerivedGraph *graph_; NodeIndexType head_temp_; @@ -1093,9 +1102,9 @@ public: DISALLOW_COPY_AND_ASSIGN(CycleHandlerForAnnotatedArcs); }; -#endif // SWIG +#endif // SWIG -protected: + protected: EbertGraphBase() : next_adjacent_arc_(), representation_clean_(true) {} ~EbertGraphBase() {} @@ -1111,8 +1120,8 @@ protected: } // Returns the first arc in node's incidence list. - ArcIndexType - FirstOutgoingOrOppositeIncomingArc(const NodeIndexType node) const { + ArcIndexType FirstOutgoingOrOppositeIncomingArc( + const NodeIndexType node) const { DCHECK(representation_clean_); DCHECK(IsNodeValid(node)); return first_incident_arc_[node]; @@ -1142,7 +1151,7 @@ protected: // builds. bool representation_clean_; -private: + private: // Shorthand: returns a const DerivedGraph*-typed version of our // "this" pointer. inline const DerivedGraph *ThisAsDerived() const { @@ -1174,10 +1183,12 @@ private: // Most users should only use StarGraph, which is EbertGraph, and // other type shortcuts; see the bottom of this file. template -class EbertGraph : public EbertGraphBase< - NodeIndexType, ArcIndexType, EbertGraph > { +class EbertGraph + : public EbertGraphBase > { typedef EbertGraphBase > Base; + EbertGraph > + Base; friend class EbertGraphBase >; friend class StarGraphBase > { typedef EbertGraphBase > Base; + ForwardEbertGraph > + Base; friend class EbertGraphBase >; friend class StarGraphBase struct graph_traits { +template +struct graph_traits { static constexpr bool has_reverse_arcs = true; static constexpr bool is_dynamic = true; }; @@ -1851,7 +1868,8 @@ namespace or_internal { // clients. It is a helper for the TailArrayManager template. // // The TailArrayBuilder for graphs with reverse arcs does nothing. -template struct TailArrayBuilder { +template +struct TailArrayBuilder { explicit TailArrayBuilder(GraphType *unused_graph) {} bool BuildTailArray() const { return true; } @@ -1860,7 +1878,8 @@ template struct TailArrayBuilder { // The TailArrayBuilder for graphs without reverse arcs calls the // appropriate method on the graph from the TailArrayBuilder // constructor. -template struct TailArrayBuilder { +template +struct TailArrayBuilder { explicit TailArrayBuilder(GraphType *graph) : graph_(graph) {} bool BuildTailArray() const { return graph_->BuildTailArray(); } @@ -1872,7 +1891,8 @@ template struct TailArrayBuilder { // clients. It is a helper for the TailArrayManager template. // // The TailArrayReleaser for graphs with reverse arcs does nothing. -template struct TailArrayReleaser { +template +struct TailArrayReleaser { explicit TailArrayReleaser(GraphType *unused_graph) {} void ReleaseTailArray() const {} @@ -1881,7 +1901,8 @@ template struct TailArrayReleaser { // The TailArrayReleaser for graphs without reverse arcs calls the // appropriate method on the graph from the TailArrayReleaser // constructor. -template struct TailArrayReleaser { +template +struct TailArrayReleaser { explicit TailArrayReleaser(GraphType *graph) : graph_(graph) {} void ReleaseTailArray() const { graph_->ReleaseTailArray(); } @@ -1889,10 +1910,11 @@ template struct TailArrayReleaser { GraphType *const graph_; }; -} // namespace or_internal +} // namespace or_internal -template class TailArrayManager { -public: +template +class TailArrayManager { + public: explicit TailArrayManager(GraphType *g) : graph_(g) {} bool BuildTailArrayFromAdjacencyListsIfForwardGraph() const { @@ -1909,12 +1931,13 @@ public: tail_array_releaser.ReleaseTailArray(); } -private: + private: GraphType *graph_; }; -template class ArcFunctorOrderingByTailAndHead { -public: +template +class ArcFunctorOrderingByTailAndHead { + public: explicit ArcFunctorOrderingByTailAndHead(const GraphType &graph) : graph_(graph) {} @@ -1925,7 +1948,7 @@ public: (graph_.Head(a) < graph_.Head(b)))); } -private: + private: const GraphType &graph_; }; @@ -1936,8 +1959,9 @@ namespace or_internal { // template. // // Deletes itself upon returning the graph! -template class GraphBuilderFromArcs { -public: +template +class GraphBuilderFromArcs { + public: GraphBuilderFromArcs(typename GraphType::NodeIndex max_num_nodes, typename GraphType::ArcIndex max_num_arcs, bool sort_arcs) @@ -1964,15 +1988,15 @@ public: } // Builds the graph from the given arcs. - GraphType *Graph(PermutationCycleHandler * - client_cycle_handler) { + GraphType *Graph(PermutationCycleHandler + *client_cycle_handler) { GraphType *graph = new GraphType(max_num_nodes_, num_arcs_, sort_arcs_, &arcs_, client_cycle_handler); delete this; return graph; } -private: + private: bool Reserve(typename GraphType::NodeIndex new_max_num_nodes, typename GraphType::ArcIndex new_max_num_arcs) { max_num_nodes_ = new_max_num_nodes; @@ -1985,8 +2009,9 @@ private: typename GraphType::ArcIndex max_num_arcs_; typename GraphType::ArcIndex num_arcs_; - std::vector > arcs_; + std::vector< + std::pair > + arcs_; const bool sort_arcs_; }; @@ -1994,8 +2019,9 @@ private: // Trivial delegating specialization for dynamic graphs. // // Deletes itself upon returning the graph! -template class GraphBuilderFromArcs { -public: +template +class GraphBuilderFromArcs { + public: GraphBuilderFromArcs(typename GraphType::NodeIndex max_num_nodes, typename GraphType::ArcIndex max_num_arcs, bool sort_arcs) @@ -2007,14 +2033,14 @@ public: return graph_->Reserve(new_max_num_nodes, new_max_num_arcs); } - typename GraphType::ArcIndex - AddArc(const typename GraphType::NodeIndex tail, - const typename GraphType::NodeIndex head) { + typename GraphType::ArcIndex AddArc( + const typename GraphType::NodeIndex tail, + const typename GraphType::NodeIndex head) { return graph_->AddArc(tail, head); } - GraphType *Graph(PermutationCycleHandler * - client_cycle_handler) { + GraphType *Graph(PermutationCycleHandler + *client_cycle_handler) { if (sort_arcs_) { TailArrayManager tail_array_manager(graph_); tail_array_manager.BuildTailArrayFromAdjacencyListsIfForwardGraph(); @@ -2027,23 +2053,24 @@ public: return result; } -private: + private: GraphType *const graph_; const bool sort_arcs_; }; -} // namespace or_internal +} // namespace or_internal template -class AnnotatedGraphBuildManager : public or_internal::GraphBuilderFromArcs< - GraphType, graph_traits::is_dynamic> { -public: +class AnnotatedGraphBuildManager + : public or_internal::GraphBuilderFromArcs< + GraphType, graph_traits::is_dynamic> { + public: AnnotatedGraphBuildManager(typename GraphType::NodeIndex num_nodes, typename GraphType::ArcIndex num_arcs, bool sort_arcs) - : or_internal::GraphBuilderFromArcs< - GraphType, graph_traits::is_dynamic>(num_nodes, num_arcs, - sort_arcs) {} + : or_internal::GraphBuilderFromArcs::is_dynamic>( + num_nodes, num_arcs, sort_arcs) {} }; // Builds a directed line graph for 'graph' (see "directed line graph" in @@ -2093,5 +2120,5 @@ bool BuildLineGraph(const GraphType &graph, GraphType *const line_graph) { return true; } -} // namespace operations_research -#endif // OR_TOOLS_GRAPH_EBERT_GRAPH_H_ +} // namespace operations_research +#endif // OR_TOOLS_GRAPH_EBERT_GRAPH_H_ diff --git a/ortools/graph/eulerian_path.h b/ortools/graph/eulerian_path.h index 3acbc84757..b917ae2ab0 100644 --- a/ortools/graph/eulerian_path.h +++ b/ortools/graph/eulerian_path.h @@ -36,7 +36,8 @@ namespace operations_research { // Returns true if a graph is Eulerian, aka all its nodes are of even degree. -template bool IsEulerianGraph(const Graph &graph) { +template +bool IsEulerianGraph(const Graph &graph) { typedef typename Graph::NodeIndex NodeIndex; for (const NodeIndex node : graph.AllNodes()) { if ((graph.OutDegree(node) + graph.InDegree(node)) % 2 != 0) { @@ -76,7 +77,7 @@ std::vector BuildEulerianPathFromNode(const Graph &graph, std::vector unvisited_edges(graph.num_arcs(), true); std::vector tour; if (graph.IsNodeValid(root)) { - std::vector tour_stack = { root }; + std::vector tour_stack = {root}; std::vector active_arcs(graph.num_nodes()); for (const NodeIndex node : graph.AllNodes()) { active_arcs[node] = *(graph.OutgoingOrOppositeIncomingArcs(node)).begin(); @@ -144,6 +145,6 @@ std::vector BuildEulerianPath(const Graph &graph) { } return path; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_EULERIAN_PATH_H_ +#endif // OR_TOOLS_GRAPH_EULERIAN_PATH_H_ diff --git a/ortools/graph/graph.h b/ortools/graph/graph.h index 24b56a8986..67b9b7be41 100644 --- a/ortools/graph/graph.h +++ b/ortools/graph/graph.h @@ -170,7 +170,8 @@ namespace util { // Forward declaration. -template class SVector; +template +class SVector; // Base class of all Graphs implemented here. The default value for the graph // index types is int32 since allmost all graphs that fit into memory do not @@ -181,7 +182,7 @@ template class SVector; template class BaseGraph { -public: + public: // Typedef so you can use Graph::NodeIndex and Graph::ArcIndex to be generic // but also to improve the readability of your code. We also recommend // that you define a typedef ... Graph; for readability. @@ -189,7 +190,10 @@ public: typedef ArcIndexType ArcIndex; BaseGraph() - : num_nodes_(0), node_capacity_(0), num_arcs_(0), arc_capacity_(0), + : num_nodes_(0), + node_capacity_(0), + num_arcs_(0), + arc_capacity_(0), const_capacities_(false) {} virtual ~BaseGraph() {} @@ -231,15 +235,13 @@ public: virtual void ReserveNodes(NodeIndexType bound) { DCHECK(!const_capacities_); DCHECK_GE(bound, num_nodes_); - if (bound <= num_nodes_) - return; + if (bound <= num_nodes_) return; node_capacity_ = bound; } virtual void ReserveArcs(ArcIndexType bound) { DCHECK(!const_capacities_); DCHECK_GE(bound, num_arcs_); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; arc_capacity_ = bound; } void Reserve(NodeIndexType node_capacity, ArcIndexType arc_capacity) { @@ -264,7 +266,7 @@ public: } ArcIndexType max_end_arc_index() const { return arc_capacity_; } -protected: + protected: // Functions commented when defined because they are implementation details. void ComputeCumulativeSum(std::vector *v); void BuildStartAndForwardHead(SVector *head, @@ -300,7 +302,7 @@ class ListGraph : public BaseGraph { using Base::num_arcs_; using Base::num_nodes_; -public: + public: using Base::IsArcValid; ListGraph() {} @@ -355,8 +357,8 @@ public: // Advanced usage. Same as OutgoingArcs(), but allows to restart the iteration // from an already known outgoing arc of the given node. - BeginEndWrapper - OutgoingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; + BeginEndWrapper OutgoingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; // This loops over the heads of the OutgoingArcs(node). It is just a more // convenient way to achieve this. Moreover this interface is used by some @@ -370,7 +372,7 @@ public: void ReserveNodes(NodeIndexType bound) override; void ReserveArcs(ArcIndexType bound) override; -private: + private: std::vector start_; std::vector next_; std::vector head_; @@ -399,7 +401,7 @@ class StaticGraph : public BaseGraph { using Base::num_arcs_; using Base::num_nodes_; -public: + public: using Base::IsArcValid; StaticGraph() : is_built_(false), arc_in_order_(true), last_tail_seen_(0) {} StaticGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) @@ -414,10 +416,10 @@ public: NodeIndexType Head(ArcIndexType arc) const; NodeIndexType Tail(ArcIndexType arc) const; - ArcIndexType OutDegree(NodeIndexType node) const; // Work in O(1). + ArcIndexType OutDegree(NodeIndexType node) const; // Work in O(1). BeginEndWrapper OutgoingArcs(NodeIndexType node) const; - BeginEndWrapper - OutgoingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; + BeginEndWrapper OutgoingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; // This loops over the heads of the OutgoingArcs(node). It is just a more // convenient way to achieve this. Moreover this interface is used by some @@ -432,7 +434,7 @@ public: void Build() { Build(nullptr); } void Build(std::vector *permutation); -private: + private: ArcIndexType DirectArcLimit(NodeIndexType node) const { DCHECK(is_built_); DCHECK(Base::IsNodeValid(node)); @@ -463,7 +465,7 @@ class ReverseArcListGraph using Base::num_arcs_; using Base::num_nodes_; -public: + public: using Base::IsArcValid; ReverseArcListGraph() {} ReverseArcListGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) { @@ -496,19 +498,18 @@ public: BeginEndWrapper OutgoingArcs(NodeIndexType node) const; BeginEndWrapper IncomingArcs(NodeIndexType node) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OutgoingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; - BeginEndWrapper - IncomingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; + OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; + BeginEndWrapper OppositeIncomingArcs( + NodeIndexType node) const; + BeginEndWrapper OutgoingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; + BeginEndWrapper IncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; - BeginEndWrapper - OppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; + OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, + ArcIndexType from) const; + BeginEndWrapper OppositeIncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; // This loops over the heads of the OutgoingArcs(node). It is just a more // convenient way to achieve this. Moreover this interface is used by some @@ -526,7 +527,7 @@ public: void Build() { Build(nullptr); } void Build(std::vector *permutation); -private: + private: std::vector start_; std::vector reverse_start_; SVector next_; @@ -552,7 +553,7 @@ class ReverseArcStaticGraph using Base::num_arcs_; using Base::num_nodes_; -public: + public: using Base::IsArcValid; ReverseArcStaticGraph() : is_built_(false) {} ReverseArcStaticGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) @@ -575,19 +576,18 @@ public: BeginEndWrapper OutgoingArcs(NodeIndexType node) const; BeginEndWrapper IncomingArcs(NodeIndexType node) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OutgoingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; - BeginEndWrapper - IncomingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; + OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; + BeginEndWrapper OppositeIncomingArcs( + NodeIndexType node) const; + BeginEndWrapper OutgoingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; + BeginEndWrapper IncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; - BeginEndWrapper - OppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; + OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, + ArcIndexType from) const; + BeginEndWrapper OppositeIncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; // This loops over the heads of the OutgoingArcs(node). It is just a more // convenient way to achieve this. Moreover this interface is used by some @@ -606,7 +606,7 @@ public: void Build() { Build(nullptr); } void Build(std::vector *permutation); -private: + private: ArcIndexType DirectArcLimit(NodeIndexType node) const { DCHECK(is_built_); DCHECK(Base::IsNodeValid(node)); @@ -641,7 +641,7 @@ class ReverseArcMixedGraph using Base::num_arcs_; using Base::num_nodes_; -public: + public: using Base::IsArcValid; ReverseArcMixedGraph() : is_built_(false) {} ReverseArcMixedGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) @@ -657,25 +657,24 @@ public: class IncomingArcIterator; class OutgoingArcIterator; - ArcIndexType OutDegree(NodeIndexType node) const; // O(1) - ArcIndexType InDegree(NodeIndexType node) const; // O(in-degree) + ArcIndexType OutDegree(NodeIndexType node) const; // O(1) + ArcIndexType InDegree(NodeIndexType node) const; // O(in-degree) BeginEndWrapper OutgoingArcs(NodeIndexType node) const; BeginEndWrapper IncomingArcs(NodeIndexType node) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OppositeIncomingArcs(NodeIndexType node) const; - BeginEndWrapper - OutgoingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; - BeginEndWrapper - IncomingArcsStartingFrom(NodeIndexType node, ArcIndexType from) const; + OutgoingOrOppositeIncomingArcs(NodeIndexType node) const; + BeginEndWrapper OppositeIncomingArcs( + NodeIndexType node) const; + BeginEndWrapper OutgoingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; + BeginEndWrapper IncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; BeginEndWrapper - OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; - BeginEndWrapper - OppositeIncomingArcsStartingFrom(NodeIndexType node, - ArcIndexType from) const; + OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node, + ArcIndexType from) const; + BeginEndWrapper OppositeIncomingArcsStartingFrom( + NodeIndexType node, ArcIndexType from) const; // This loops over the heads of the OutgoingArcs(node). It is just a more // convenient way to achieve this. Moreover this interface is used by some @@ -694,7 +693,7 @@ public: void Build() { Build(nullptr); } void Build(std::vector *permutation); -private: + private: ArcIndexType DirectArcLimit(NodeIndexType node) const { DCHECK(is_built_); DCHECK(Base::IsNodeValid(node)); @@ -769,8 +768,9 @@ void Permute(const IntVector &permutation, // v.clear(); // v.swap(new_v); // std:swap(v[i], v[~i]); -template class SVector { -public: +template +class SVector { + public: SVector() : base_(nullptr), size_(0), capacity_(0) {} ~SVector() { clear_and_dealloc(); } @@ -786,7 +786,7 @@ public: base_ = static_cast(malloc(2LL * capacity_ * sizeof(T))); CHECK(base_ != nullptr); base_ += capacity_; - } else { // capacity_ >= other.size + } else { // capacity_ >= other.size clear(); } // Perform the actual copy of the payload. @@ -874,8 +874,8 @@ public: if (size_ == capacity_) { // We have to copy the elements because they are allowed to be element of // *this. - T left_copy(left); // NOLINT - T right_copy(right); // NOLINT + T left_copy(left); // NOLINT + T right_copy(right); // NOLINT reserve(NewCapacity(1)); new (base_ + size_) T(right_copy); new (base_ - size_ - 1) T(left_copy); @@ -894,8 +894,7 @@ public: int max_size() const { return std::numeric_limits::max(); } void clear_and_dealloc() { - if (base_ == nullptr) - return; + if (base_ == nullptr) return; clear(); if (capacity_ > 0) { free(base_ - capacity_); @@ -904,7 +903,7 @@ public: base_ = nullptr; } -private: + private: int NewCapacity(int delta) { // TODO(user): check validity. double candidate = 1.3 * static_cast(capacity_); @@ -918,9 +917,9 @@ private: return capacity_ + delta; } - T *base_; // Pointer to the element of index 0. - int size_; // Valid index are [- size_, size_). - int capacity_; // Reserved index are [- capacity_, capacity_). + T *base_; // Pointer to the element of index 0. + int size_; // Valid index are [- size_, size_). + int capacity_; // Reserved index are [- capacity_, capacity_). }; // BaseGraph implementation ---------------------------------------------------- @@ -963,8 +962,8 @@ BaseGraph::arc_capacity() const { } template -void -BaseGraph::FreezeCapacities() { +void BaseGraph::FreezeCapacities() { // TODO(user): Only define this in debug mode at the cost of having a lot // of ifndef NDEBUG all over the place? remove the function completely ? const_capacities_ = true; @@ -975,9 +974,8 @@ BaseGraph::FreezeCapacities() { // Computes the cummulative sum of the entry in v. We only use it with // in/out degree distribution, hence the Check() at the end. template -void -BaseGraph::ComputeCumulativeSum( - std::vector *v) { +void BaseGraph:: + ComputeCumulativeSum(std::vector *v) { ArcIndexType sum = 0; for (int i = 0; i < num_nodes_; ++i) { ArcIndexType temp = (*v)[i]; @@ -993,10 +991,10 @@ BaseGraph::ComputeCumulativeSum( // - Put in start[i] the index of the first arc with tail >= i. // - Update "permutation" to reflect the change, unless it is NULL. template -void BaseGraph::BuildStartAndForwardHead( - SVector *head, std::vector *start, - std::vector *permutation) { +void BaseGraph:: + BuildStartAndForwardHead(SVector *head, + std::vector *start, + std::vector *permutation) { // Computes the outgoing degree of each nodes and check if we need to permute // something or not. Note that the tails are currently stored in the positive // range of the SVector head. @@ -1057,36 +1055,36 @@ void BaseGraph \ - BeginEndWrapper::t##ArcIterator> \ - c::t##Arcs(NodeIndexType node) const { \ - return BeginEndWrapper(t##ArcIterator(*this, node), \ - t##ArcIterator(*this, node, e)); \ - } \ - template \ - BeginEndWrapper::t##ArcIterator> \ - c::t##ArcsStartingFrom( \ - NodeIndexType node, ArcIndexType from) const { \ - return BeginEndWrapper(t##ArcIterator(*this, node, from), \ - t##ArcIterator(*this, node, e)); \ +#define DEFINE_RANGE_BASED_ARC_ITERATION(c, t, e) \ + template \ + BeginEndWrapper::t##ArcIterator> \ + c::t##Arcs(NodeIndexType node) const { \ + return BeginEndWrapper(t##ArcIterator(*this, node), \ + t##ArcIterator(*this, node, e)); \ + } \ + template \ + BeginEndWrapper::t##ArcIterator> \ + c::t##ArcsStartingFrom( \ + NodeIndexType node, ArcIndexType from) const { \ + return BeginEndWrapper(t##ArcIterator(*this, node, from), \ + t##ArcIterator(*this, node, e)); \ } // Adapt our old iteration style to support range-based for loops. Add typedefs // required by std::iterator_traits. -#define DEFINE_STL_ITERATOR_FUNCTIONS(iterator_class_name) \ - using iterator_category = std::input_iterator_tag; \ - using difference_type = ptrdiff_t; \ - using pointer = const ArcIndexType * ; \ - using reference = const ArcIndexType & ; \ - using value_type = ArcIndexType; \ - bool operator!=(const iterator_class_name & other) const { \ - return this->index_ != other.index_; \ - } \ - bool operator==(const iterator_class_name & other) const { \ - return this->index_ == other.index_; \ - } \ - ArcIndexType operator*() const { return this->Index(); } \ +#define DEFINE_STL_ITERATOR_FUNCTIONS(iterator_class_name) \ + using iterator_category = std::input_iterator_tag; \ + using difference_type = ptrdiff_t; \ + using pointer = const ArcIndexType *; \ + using reference = const ArcIndexType &; \ + using value_type = ArcIndexType; \ + bool operator!=(const iterator_class_name &other) const { \ + return this->index_ != other.index_; \ + } \ + bool operator==(const iterator_class_name &other) const { \ + return this->index_ == other.index_; \ + } \ + ArcIndexType operator*() const { return this->Index(); } \ void operator++() { this->Next(); } // ListGraph implementation ---------------------------------------------------- @@ -1103,41 +1101,38 @@ ListGraph::operator[](NodeIndexType node) const { } template -NodeIndexType -ListGraph::Tail(ArcIndexType arc) const { +NodeIndexType ListGraph::Tail( + ArcIndexType arc) const { DCHECK(IsArcValid(arc)); return tail_[arc]; } template -NodeIndexType -ListGraph::Head(ArcIndexType arc) const { +NodeIndexType ListGraph::Head( + ArcIndexType arc) const { DCHECK(IsArcValid(arc)); return head_[arc]; } template -ArcIndexType -ListGraph::OutDegree(NodeIndexType node) const { +ArcIndexType ListGraph::OutDegree( + NodeIndexType node) const { ArcIndexType degree(0); - for (auto arc ABSL_ATTRIBUTE_UNUSED : OutgoingArcs(node)) - ++degree; + for (auto arc ABSL_ATTRIBUTE_UNUSED : OutgoingArcs(node)) ++degree; return degree; } template void ListGraph::AddNode(NodeIndexType node) { - if (node < num_nodes_) - return; + if (node < num_nodes_) return; DCHECK(!const_capacities_ || node < node_capacity_); num_nodes_ = node + 1; start_.resize(num_nodes_, Base::kNilArc); } template -ArcIndexType -ListGraph::AddArc(NodeIndexType tail, - NodeIndexType head) { +ArcIndexType ListGraph::AddArc( + NodeIndexType tail, NodeIndexType head) { DCHECK_GE(tail, 0); DCHECK_GE(head, 0); AddNode(tail > head ? tail : head); @@ -1152,16 +1147,14 @@ ListGraph::AddArc(NodeIndexType tail, template void ListGraph::ReserveNodes(NodeIndexType bound) { Base::ReserveNodes(bound); - if (bound <= num_nodes_) - return; + if (bound <= num_nodes_) return; start_.reserve(bound); } template void ListGraph::ReserveArcs(ArcIndexType bound) { Base::ReserveArcs(bound); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; head_.reserve(bound); tail_.reserve(bound); next_.reserve(bound); @@ -1177,7 +1170,7 @@ void ListGraph::Build( template class ListGraph::OutgoingArcIterator { -public: + public: OutgoingArcIterator(const ListGraph &graph, NodeIndexType node) : graph_(graph), index_(graph.start_[node]) { DCHECK(graph.IsNodeValid(node)); @@ -1197,18 +1190,18 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator); -private: + private: const ListGraph &graph_; ArcIndexType index_; }; template class ListGraph::OutgoingHeadIterator { -public: + public: using iterator_category = std::input_iterator_tag; using difference_type = ptrdiff_t; - using pointer = const NodeIndexType * ; - using reference = const NodeIndexType & ; + using pointer = const NodeIndexType *; + using reference = const NodeIndexType &; using value_type = NodeIndexType; OutgoingHeadIterator(const ListGraph &graph, NodeIndexType node) @@ -1229,14 +1222,14 @@ public: } bool operator!=(const typename ListGraph::OutgoingHeadIterator & - other) const { + ArcIndexType>::OutgoingHeadIterator + &other) const { return index_ != other.index_; } NodeIndexType operator*() const { return Index(); } void operator++() { Next(); } -private: + private: const ListGraph &graph_; ArcIndexType index_; }; @@ -1253,42 +1246,38 @@ StaticGraph::operator[](NodeIndexType node) const { } template -ArcIndexType -StaticGraph::OutDegree(NodeIndexType node) const { +ArcIndexType StaticGraph::OutDegree( + NodeIndexType node) const { return DirectArcLimit(node) - start_[node]; } template -void -StaticGraph::ReserveNodes(NodeIndexType bound) { +void StaticGraph::ReserveNodes( + NodeIndexType bound) { Base::ReserveNodes(bound); - if (bound <= num_nodes_) - return; + if (bound <= num_nodes_) return; start_.reserve(bound); } template void StaticGraph::ReserveArcs(ArcIndexType bound) { Base::ReserveArcs(bound); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; head_.reserve(bound); tail_.reserve(bound); } template void StaticGraph::AddNode(NodeIndexType node) { - if (node < num_nodes_) - return; + if (node < num_nodes_) return; DCHECK(!const_capacities_ || node < node_capacity_) << node; num_nodes_ = node + 1; start_.resize(num_nodes_, 0); } template -ArcIndexType -StaticGraph::AddArc(NodeIndexType tail, - NodeIndexType head) { +ArcIndexType StaticGraph::AddArc( + NodeIndexType tail, NodeIndexType head) { DCHECK_GE(tail, 0); DCHECK_GE(head, 0); DCHECK(!is_built_); @@ -1308,15 +1297,15 @@ StaticGraph::AddArc(NodeIndexType tail, } template -NodeIndexType -StaticGraph::Tail(ArcIndexType arc) const { +NodeIndexType StaticGraph::Tail( + ArcIndexType arc) const { DCHECK(IsArcValid(arc)); return tail_[arc]; } template -NodeIndexType -StaticGraph::Head(ArcIndexType arc) const { +NodeIndexType StaticGraph::Head( + ArcIndexType arc) const { DCHECK(IsArcValid(arc)); return head_[arc]; } @@ -1337,8 +1326,7 @@ template void StaticGraph::Build( std::vector *permutation) { DCHECK(!is_built_); - if (is_built_) - return; + if (is_built_) return; is_built_ = true; node_capacity_ = num_nodes_; arc_capacity_ = num_arcs_; @@ -1395,7 +1383,7 @@ void StaticGraph::Build( template class StaticGraph::OutgoingArcIterator { -public: + public: OutgoingArcIterator(const StaticGraph &graph, NodeIndexType node) : index_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) {} OutgoingArcIterator(const StaticGraph &graph, NodeIndexType node, @@ -1420,7 +1408,7 @@ public: // arcs. DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator); -private: + private: ArcIndexType index_; const ArcIndexType limit_; }; @@ -1436,8 +1424,9 @@ DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcListGraph, OppositeIncoming, template BeginEndWrapper::OutgoingHeadIterator> ReverseArcListGraph< - NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const { + NodeIndexType, ArcIndexType>::OutgoingHeadIterator> +ReverseArcListGraph::operator[]( + NodeIndexType node) const { return BeginEndWrapper( OutgoingHeadIterator(*this, node), OutgoingHeadIterator(*this, node, Base::kNilArc)); @@ -1447,8 +1436,7 @@ template ArcIndexType ReverseArcListGraph::OutDegree( NodeIndexType node) const { ArcIndexType degree(0); - for (auto arc ABSL_ATTRIBUTE_UNUSED : OutgoingArcs(node)) - ++degree; + for (auto arc ABSL_ATTRIBUTE_UNUSED : OutgoingArcs(node)) ++degree; return degree; } @@ -1456,8 +1444,7 @@ template ArcIndexType ReverseArcListGraph::InDegree( NodeIndexType node) const { ArcIndexType degree(0); - for (auto arc ABSL_ATTRIBUTE_UNUSED : OppositeIncomingArcs(node)) - ++degree; + for (auto arc ABSL_ATTRIBUTE_UNUSED : OppositeIncomingArcs(node)) ++degree; return degree; } @@ -1469,15 +1456,15 @@ ArcIndexType ReverseArcListGraph::OppositeArc( } template -NodeIndexType -ReverseArcListGraph::Head(ArcIndexType arc) const { +NodeIndexType ReverseArcListGraph::Head( + ArcIndexType arc) const { DCHECK(IsArcValid(arc)); return head_[arc]; } template -NodeIndexType -ReverseArcListGraph::Tail(ArcIndexType arc) const { +NodeIndexType ReverseArcListGraph::Tail( + ArcIndexType arc) const { return head_[OppositeArc(arc)]; } @@ -1485,8 +1472,7 @@ template void ReverseArcListGraph::ReserveNodes( NodeIndexType bound) { Base::ReserveNodes(bound); - if (bound <= num_nodes_) - return; + if (bound <= num_nodes_) return; start_.reserve(bound); reverse_start_.reserve(bound); } @@ -1495,17 +1481,15 @@ template void ReverseArcListGraph::ReserveArcs( ArcIndexType bound) { Base::ReserveArcs(bound); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; head_.reserve(bound); next_.reserve(bound); } template -void -ReverseArcListGraph::AddNode(NodeIndexType node) { - if (node < num_nodes_) - return; +void ReverseArcListGraph::AddNode( + NodeIndexType node) { + if (node < num_nodes_) return; DCHECK(!const_capacities_ || node < node_capacity_); num_nodes_ = node + 1; start_.resize(num_nodes_, Base::kNilArc); @@ -1513,9 +1497,8 @@ ReverseArcListGraph::AddNode(NodeIndexType node) { } template -ArcIndexType -ReverseArcListGraph::AddArc(NodeIndexType tail, - NodeIndexType head) { +ArcIndexType ReverseArcListGraph::AddArc( + NodeIndexType tail, NodeIndexType head) { DCHECK_GE(tail, 0); DCHECK_GE(head, 0); AddNode(tail > head ? tail : head); @@ -1537,7 +1520,7 @@ void ReverseArcListGraph::Build( template class ReverseArcListGraph::OutgoingArcIterator { -public: + public: OutgoingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node) : graph_(graph), index_(graph.start_[node]) { DCHECK(graph.IsNodeValid(node)); @@ -1558,7 +1541,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator); -private: + private: const ReverseArcListGraph &graph_; ArcIndexType index_; }; @@ -1566,7 +1549,7 @@ private: template class ReverseArcListGraph::OppositeIncomingArcIterator { -public: + public: OppositeIncomingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node) : graph_(graph), index_(graph.reverse_start_[node]) { @@ -1589,7 +1572,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OppositeIncomingArcIterator); -protected: + protected: const ReverseArcListGraph &graph_; ArcIndexType index_; }; @@ -1597,15 +1580,14 @@ protected: template class ReverseArcListGraph::IncomingArcIterator : public OppositeIncomingArcIterator { -public: + public: IncomingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node) : OppositeIncomingArcIterator(graph, node) {} IncomingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node, ArcIndexType arc) - : OppositeIncomingArcIterator(graph, node, arc == Base::kNilArc - ? Base::kNilArc - : graph.OppositeArc(arc)) { - } + : OppositeIncomingArcIterator( + graph, node, + arc == Base::kNilArc ? Base::kNilArc : graph.OppositeArc(arc)) {} // We overwrite OppositeIncomingArcIterator::Index() here. ArcIndexType Index() const { @@ -1620,13 +1602,12 @@ public: template class ReverseArcListGraph::OutgoingOrOppositeIncomingArcIterator { -public: + public: OutgoingOrOppositeIncomingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node) : graph_(graph), index_(graph.reverse_start_[node]), node_(node) { DCHECK(graph.IsNodeValid(node)); - if (index_ == Base::kNilArc) - index_ = graph.start_[node]; + if (index_ == Base::kNilArc) index_ = graph.start_[node]; } OutgoingOrOppositeIncomingArcIterator(const ReverseArcListGraph &graph, NodeIndexType node, ArcIndexType arc) @@ -1651,7 +1632,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingOrOppositeIncomingArcIterator); -private: + private: const ReverseArcListGraph &graph_; ArcIndexType index_; const NodeIndexType node_; @@ -1659,7 +1640,7 @@ private: template class ReverseArcListGraph::OutgoingHeadIterator { -public: + public: OutgoingHeadIterator(const ReverseArcListGraph &graph, NodeIndexType node) : graph_(&graph), index_(graph.start_[node]) { DCHECK(graph.IsNodeValid(node)); @@ -1680,7 +1661,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingHeadIterator); -private: + private: const ReverseArcListGraph *graph_; ArcIndexType index_; }; @@ -1691,8 +1672,9 @@ DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcStaticGraph, Outgoing, DirectArcLimit(node)); DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcStaticGraph, Incoming, ReverseArcLimit(node)); -DEFINE_RANGE_BASED_ARC_ITERATION( - ReverseArcStaticGraph, OutgoingOrOppositeIncoming, DirectArcLimit(node)); +DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcStaticGraph, + OutgoingOrOppositeIncoming, + DirectArcLimit(node)); DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcStaticGraph, OppositeIncoming, ReverseArcLimit(node)); @@ -1709,8 +1691,9 @@ ArcIndexType ReverseArcStaticGraph::InDegree( } template -BeginEndWrapper ReverseArcStaticGraph< - NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const { +BeginEndWrapper +ReverseArcStaticGraph::operator[]( + NodeIndexType node) const { return BeginEndWrapper( head_.data() + start_[node], head_.data() + DirectArcLimit(node)); } @@ -1742,24 +1725,21 @@ template void ReverseArcStaticGraph::ReserveArcs( ArcIndexType bound) { Base::ReserveArcs(bound); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; head_.reserve(bound); } template void ReverseArcStaticGraph::AddNode( NodeIndexType node) { - if (node < num_nodes_) - return; + if (node < num_nodes_) return; DCHECK(!const_capacities_ || node < node_capacity_); num_nodes_ = node + 1; } template -ArcIndexType -ReverseArcStaticGraph::AddArc(NodeIndexType tail, - NodeIndexType head) { +ArcIndexType ReverseArcStaticGraph::AddArc( + NodeIndexType tail, NodeIndexType head) { DCHECK_GE(tail, 0); DCHECK_GE(head, 0); AddNode(tail > head ? tail : head); @@ -1775,8 +1755,7 @@ template void ReverseArcStaticGraph::Build( std::vector *permutation) { DCHECK(!is_built_); - if (is_built_) - return; + if (is_built_) return; is_built_ = true; node_capacity_ = num_nodes_; arc_capacity_ = num_arcs_; @@ -1819,7 +1798,7 @@ void ReverseArcStaticGraph::Build( template class ReverseArcStaticGraph::OutgoingArcIterator { -public: + public: OutgoingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node) : index_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) {} OutgoingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node, @@ -1839,7 +1818,7 @@ public: // iterator rather than a simple IntegerRange on the arc indices. DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator); -private: + private: ArcIndexType index_; const ArcIndexType limit_; }; @@ -1847,10 +1826,11 @@ private: template class ReverseArcStaticGraph::OppositeIncomingArcIterator { -public: + public: OppositeIncomingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node) - : graph_(graph), limit_(graph.ReverseArcLimit(node)), + : graph_(graph), + limit_(graph.ReverseArcLimit(node)), index_(graph.reverse_start_[node]) { DCHECK(graph.IsNodeValid(node)); DCHECK_LE(index_, limit_); @@ -1872,7 +1852,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OppositeIncomingArcIterator); -protected: + protected: const ReverseArcStaticGraph &graph_; const ArcIndexType limit_; ArcIndexType index_; @@ -1881,7 +1861,7 @@ protected: template class ReverseArcStaticGraph::IncomingArcIterator : public OppositeIncomingArcIterator { -public: + public: IncomingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node) : OppositeIncomingArcIterator(graph, node) {} IncomingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node, @@ -1903,21 +1883,23 @@ public: template class ReverseArcStaticGraph< NodeIndexType, ArcIndexType>::OutgoingOrOppositeIncomingArcIterator { -public: + public: OutgoingOrOppositeIncomingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node) : index_(graph.reverse_start_[node]), first_limit_(graph.ReverseArcLimit(node)), - next_start_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) { - if (index_ == first_limit_) - index_ = next_start_; + next_start_(graph.start_[node]), + limit_(graph.DirectArcLimit(node)) { + if (index_ == first_limit_) index_ = next_start_; DCHECK(graph.IsNodeValid(node)); DCHECK((index_ < first_limit_) || (index_ >= next_start_)); } OutgoingOrOppositeIncomingArcIterator(const ReverseArcStaticGraph &graph, NodeIndexType node, ArcIndexType arc) - : index_(arc), first_limit_(graph.ReverseArcLimit(node)), - next_start_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) { + : index_(arc), + first_limit_(graph.ReverseArcLimit(node)), + next_start_(graph.start_[node]), + limit_(graph.DirectArcLimit(node)) { DCHECK(graph.IsNodeValid(node)); DCHECK((index_ >= graph.reverse_start_[node] && index_ < first_limit_) || (index_ >= next_start_)); @@ -1935,7 +1917,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingOrOppositeIncomingArcIterator); -private: + private: ArcIndexType index_; const ArcIndexType first_limit_; const ArcIndexType next_start_; @@ -1947,8 +1929,9 @@ private: DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcMixedGraph, Outgoing, DirectArcLimit(node)); DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcMixedGraph, Incoming, Base::kNilArc); -DEFINE_RANGE_BASED_ARC_ITERATION( - ReverseArcMixedGraph, OutgoingOrOppositeIncoming, DirectArcLimit(node)); +DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcMixedGraph, + OutgoingOrOppositeIncoming, + DirectArcLimit(node)); DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcMixedGraph, OppositeIncoming, Base::kNilArc); @@ -1962,14 +1945,14 @@ template ArcIndexType ReverseArcMixedGraph::InDegree( NodeIndexType node) const { ArcIndexType degree(0); - for (auto arc ABSL_ATTRIBUTE_UNUSED : OppositeIncomingArcs(node)) - ++degree; + for (auto arc ABSL_ATTRIBUTE_UNUSED : OppositeIncomingArcs(node)) ++degree; return degree; } template -BeginEndWrapper ReverseArcMixedGraph< - NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const { +BeginEndWrapper +ReverseArcMixedGraph::operator[]( + NodeIndexType node) const { return BeginEndWrapper( head_.data() + start_[node], head_.data() + DirectArcLimit(node)); } @@ -2000,24 +1983,21 @@ template void ReverseArcMixedGraph::ReserveArcs( ArcIndexType bound) { Base::ReserveArcs(bound); - if (bound <= num_arcs_) - return; + if (bound <= num_arcs_) return; head_.reserve(bound); } template -void -ReverseArcMixedGraph::AddNode(NodeIndexType node) { - if (node < num_nodes_) - return; +void ReverseArcMixedGraph::AddNode( + NodeIndexType node) { + if (node < num_nodes_) return; DCHECK(!const_capacities_ || node < node_capacity_); num_nodes_ = node + 1; } template -ArcIndexType -ReverseArcMixedGraph::AddArc(NodeIndexType tail, - NodeIndexType head) { +ArcIndexType ReverseArcMixedGraph::AddArc( + NodeIndexType tail, NodeIndexType head) { DCHECK_GE(tail, 0); DCHECK_GE(head, 0); AddNode(tail > head ? tail : head); @@ -2033,8 +2013,7 @@ template void ReverseArcMixedGraph::Build( std::vector *permutation) { DCHECK(!is_built_); - if (is_built_) - return; + if (is_built_) return; is_built_ = true; node_capacity_ = num_nodes_; arc_capacity_ = num_arcs_; @@ -2059,7 +2038,7 @@ void ReverseArcMixedGraph::Build( template class ReverseArcMixedGraph::OutgoingArcIterator { -public: + public: OutgoingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node) : index_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) {} OutgoingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node, @@ -2079,7 +2058,7 @@ public: // iterator rather than a simple IntegerRange on the arc indices. DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator); -private: + private: ArcIndexType index_; const ArcIndexType limit_; }; @@ -2087,7 +2066,7 @@ private: template class ReverseArcMixedGraph::OppositeIncomingArcIterator { -public: + public: OppositeIncomingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node) : graph_(&graph) { @@ -2112,7 +2091,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OppositeIncomingArcIterator); -protected: + protected: const ReverseArcMixedGraph *graph_; ArcIndexType index_; }; @@ -2120,15 +2099,13 @@ protected: template class ReverseArcMixedGraph::IncomingArcIterator : public OppositeIncomingArcIterator { -public: + public: IncomingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node) : OppositeIncomingArcIterator(graph, node) {} IncomingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node, ArcIndexType arc) - : OppositeIncomingArcIterator(graph, node, arc == Base::kNilArc - ? arc - : graph.OppositeArc(arc)) { - } + : OppositeIncomingArcIterator( + graph, node, arc == Base::kNilArc ? arc : graph.OppositeArc(arc)) {} ArcIndexType Index() const { return this->index_ == Base::kNilArc ? Base::kNilArc @@ -2141,11 +2118,11 @@ public: template class ReverseArcMixedGraph< NodeIndexType, ArcIndexType>::OutgoingOrOppositeIncomingArcIterator { -public: + public: OutgoingOrOppositeIncomingArcIterator(const ReverseArcMixedGraph &graph, NodeIndexType node) : graph_(&graph) { - limit_ = graph.DirectArcLimit(node); // also DCHECKs node and is_built_. + limit_ = graph.DirectArcLimit(node); // also DCHECKs node and is_built_. index_ = graph.reverse_start_[node]; restart_ = graph.start_[node]; if (index_ == Base::kNilArc) { @@ -2179,7 +2156,7 @@ public: DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingOrOppositeIncomingArcIterator); -private: + private: const ReverseArcMixedGraph *graph_; ArcIndexType index_; ArcIndexType restart_; @@ -2198,7 +2175,7 @@ class CompleteGraph : public BaseGraph { using Base::num_arcs_; using Base::num_nodes_; -public: + public: // Builds a complete graph with num_nodes nodes. explicit CompleteGraph(NodeIndexType num_nodes) { this->Reserve(num_nodes, num_nodes * num_nodes); @@ -2217,15 +2194,15 @@ public: }; template -NodeIndexType -CompleteGraph::Head(ArcIndexType arc) const { +NodeIndexType CompleteGraph::Head( + ArcIndexType arc) const { DCHECK(this->IsArcValid(arc)); return arc % num_nodes_; } template -NodeIndexType -CompleteGraph::Tail(ArcIndexType arc) const { +NodeIndexType CompleteGraph::Tail( + ArcIndexType arc) const { DCHECK(this->IsArcValid(arc)); return arc / num_nodes_; } @@ -2237,8 +2214,9 @@ ArcIndexType CompleteGraph::OutDegree( } template -IntegerRange CompleteGraph< - NodeIndexType, ArcIndexType>::OutgoingArcs(NodeIndexType node) const { +IntegerRange +CompleteGraph::OutgoingArcs( + NodeIndexType node) const { DCHECK_LT(node, num_nodes_); return IntegerRange( static_cast(num_nodes_) * node, @@ -2255,8 +2233,9 @@ CompleteGraph::OutgoingArcsStartingFrom( } template -IntegerRange CompleteGraph< - NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const { +IntegerRange +CompleteGraph::operator[]( + NodeIndexType node) const { DCHECK_LT(node, num_nodes_); return IntegerRange(0, num_nodes_); } @@ -2274,7 +2253,7 @@ class CompleteBipartiteGraph using Base::num_arcs_; using Base::num_nodes_; -public: + public: // Builds a complete bipartite graph from a set of left nodes to a set of // right nodes. // Indices of left nodes of the bipartite graph range from 0 to left_nodes-1; @@ -2297,7 +2276,7 @@ public: // Deprecated interface. class OutgoingArcIterator { - public: + public: OutgoingArcIterator(const CompleteBipartiteGraph &graph, NodeIndexType node) : index_(graph.right_nodes_ * node), limit_(node >= graph.left_nodes_ ? index_ @@ -2307,12 +2286,12 @@ public: ArcIndexType Index() const { return index_; } void Next() { index_++; } - private: + private: ArcIndexType index_; const ArcIndexType limit_; }; -private: + private: const NodeIndexType left_nodes_; const NodeIndexType right_nodes_; }; @@ -2338,8 +2317,9 @@ ArcIndexType CompleteBipartiteGraph::OutDegree( } template -IntegerRange CompleteBipartiteGraph< - NodeIndexType, ArcIndexType>::OutgoingArcs(NodeIndexType node) const { +IntegerRange +CompleteBipartiteGraph::OutgoingArcs( + NodeIndexType node) const { if (node < left_nodes_) { return IntegerRange(right_nodes_ * node, right_nodes_ * (node + 1)); @@ -2360,8 +2340,9 @@ CompleteBipartiteGraph::OutgoingArcsStartingFrom( } template -IntegerRange CompleteBipartiteGraph< - NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const { +IntegerRange +CompleteBipartiteGraph::operator[]( + NodeIndexType node) const { if (node < left_nodes_) { return IntegerRange(left_nodes_, left_nodes_ + right_nodes_); } else { @@ -2372,9 +2353,9 @@ IntegerRange CompleteBipartiteGraph< // Defining the simplest Graph interface as Graph for convenience. typedef ListGraph<> Graph; -} // namespace util +} // namespace util #undef DEFINE_RANGE_BASED_ARC_ITERATION #undef DEFINE_STL_ITERATOR_FUNCTIONS -#endif // UTIL_GRAPH_GRAPH_H_ +#endif // UTIL_GRAPH_GRAPH_H_ diff --git a/ortools/graph/graphs.h b/ortools/graph/graphs.h index c97a2e1772..41a5b3aa51 100644 --- a/ortools/graph/graphs.h +++ b/ortools/graph/graphs.h @@ -23,7 +23,8 @@ namespace operations_research { // Since StarGraph does not have exactly the same interface as the other // graphs, we define a correspondence there. -template struct Graphs { +template +struct Graphs { typedef typename Graph::ArcIndex ArcIndex; typedef typename Graph::NodeIndex NodeIndex; static ArcIndex OppositeArc(const Graph &graph, ArcIndex arc) { @@ -44,7 +45,8 @@ template struct Graphs { } }; -template <> struct Graphs { +template <> +struct Graphs { typedef operations_research::StarGraph Graph; #if defined(_MSC_VER) typedef Graph::ArcIndex ArcIndex; @@ -71,6 +73,6 @@ template <> struct Graphs { } }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_GRAPHS_H_ +#endif // OR_TOOLS_GRAPH_GRAPHS_H_ diff --git a/ortools/graph/hamiltonian_path.h b/ortools/graph/hamiltonian_path.h index 369f380e87..e90c9b2005 100644 --- a/ortools/graph/hamiltonian_path.h +++ b/ortools/graph/hamiltonian_path.h @@ -100,8 +100,9 @@ namespace operations_research { // TODO(user): Move the Set-related classbelow to util/bitset.h // Iterates over the elements of a set represented as an unsigned integer, // starting from the smallest element. (See the class Set below.) -template class ElementIterator { -public: +template +class ElementIterator { + public: explicit ElementIterator(Set set) : current_set_(set) {} bool operator!=(const ElementIterator &other) const { return current_set_ != other.current_set_; @@ -116,21 +117,22 @@ public: return *this; } -private: + private: // The current position of the iterator. Stores the set consisting of the // not-yet iterated elements. Set current_set_; }; -template class Set { -public: +template +class Set { + public: // Make this visible to classes using this class. typedef Integer IntegerType; // Useful constants. static constexpr Integer One = static_cast(1); static constexpr Integer Zero = static_cast(0); - static const int MaxCardinality = 8 * sizeof(Integer); // NOLINT + static const int MaxCardinality = 8 * sizeof(Integer); // NOLINT // Construct a set from an Integer. explicit Set(Integer n) : value_(n) { @@ -199,24 +201,27 @@ public: ElementIterator end() const { return ElementIterator(Set(0)); } bool operator!=(const Set &other) const { return value_ != other.value_; } -private: + private: // The Integer representing the set. Integer value_; }; -template <> inline int Set::SmallestElement() const { +template <> +inline int Set::SmallestElement() const { return LeastSignificantBitPosition64(value_); } -template <> inline int Set::Cardinality() const { +template <> +inline int Set::Cardinality() const { return BitCount64(value_); } // An iterator for sets of increasing corresponding values that have the same // cardinality. For example, the sets with cardinality 3 will be listed as // ...00111, ...01011, ...01101, ...1110, etc... -template class SetRangeIterator { -public: +template +class SetRangeIterator { + public: // Make the parameter types visible to SetRangeWithCardinality. typedef typename SetRange::SetType SetType; typedef typename SetType::IntegerType IntegerType; @@ -243,13 +248,14 @@ public: return *this; } -private: + private: // The current set of iterator. SetType current_set_; }; -template class SetRangeWithCardinality { -public: +template +class SetRangeWithCardinality { + public: typedef Set SetType; // The end_ set is the first set with cardinality card, that does not fit // in max_card bits. Thus, its bit at position max_card is set, and the @@ -271,7 +277,7 @@ public: return SetRangeIterator(end_); } -private: + private: // Keep the beginning and end of the iterator. SetType begin_; SetType end_; @@ -281,8 +287,9 @@ private: // node in set, for all the subsets of cardinality <= max_card_. // LatticeMemoryManager manages the storage of f(set, node) so that the // DP iteration access memory in increasing addresses. -template class LatticeMemoryManager { -public: +template +class LatticeMemoryManager { + public: LatticeMemoryManager() : max_card_(0) {} // Reserves memory and fills in the data necessary to access memory. @@ -302,10 +309,9 @@ public: // node 'removed_node' is replaced by 'added_node' at 'rank' uint64 OffsetDelta(int card, int added_node, int removed_node, int rank) const { - return card * (binomial_coefficients_[added_node][ - rank] - // delta for added_node - binomial_coefficients_[removed_node][ - rank]); // for removed_node. + return card * + (binomial_coefficients_[added_node][rank] - // delta for added_node + binomial_coefficients_[removed_node][rank]); // for removed_node. } // Memorizes the value = f(s, node) at the correct offset. @@ -326,7 +332,7 @@ public: // This is useful in the Dynamic Programming iterations. CostType ValueAtOffset(uint64 offset) const { return memory_[offset]; } -private: + private: // Returns true if the values used to manage memory are set correctly. // This is intended to only be used in a DCHECK. bool CheckConsistency() const; @@ -351,8 +357,7 @@ template void LatticeMemoryManager::Init(int max_card) { DCHECK_LT(0, max_card); DCHECK_GE(Set::MaxCardinality, max_card); - if (max_card <= max_card_) - return; + if (max_card <= max_card_) return; max_card_ = max_card; binomial_coefficients_.resize(max_card_ + 1); @@ -459,7 +464,7 @@ class HamiltonianPathSolver { // mhp(cost_mat); // no computation done // printf("%d\n", mhp.TravelingSalesmanCost()); // computation done and // stored -public: + public: // In 2010, 26 was the maximum solvable with 24 Gigs of RAM, and it took // several minutes. With this 2014 version of the code, one may go a little // higher, but considering the complexity of the algorithm (n*2^n), and that @@ -507,22 +512,24 @@ public: // Returns true if the cost matrix verifies the triangle inequality. bool VerifiesTriangleInequality(); -private: + private: // Saturated arithmetic helper class. template // Returns the saturated addition of a and b. It is specialized below for - // int32 and int64. - struct SaturatedArithmetic { + // int32 and int64. + struct SaturatedArithmetic { static T Add(T a, T b) { return a + b; } static T Sub(T a, T b) { return a - b; } }; - template struct SaturatedArithmetic { + template + struct SaturatedArithmetic { static int64 Add(int64 a, int64 b) { return CapAdd(a, b); } static int64 Sub(int64 a, int64 b) { return CapSub(a, b); } }; // TODO(user): implement this natively in saturated_arithmetic.h - template struct SaturatedArithmetic { + template + struct SaturatedArithmetic { static int32 Add(int32 a, int32 b) { const int64 a64 = a; const int64 b64 = b; @@ -541,7 +548,8 @@ private: } }; - template using Saturated = SaturatedArithmetic; + template + using Saturated = SaturatedArithmetic; // Returns the cost value between two nodes. CostType Cost(int i, int j) { return cost_(i, j); } @@ -588,8 +596,8 @@ private: // Utility function to simplify building a HamiltonianPathSolver from a functor. template -HamiltonianPathSolver -MakeHamiltonianPathSolver(int num_nodes, CostFunction cost) { +HamiltonianPathSolver MakeHamiltonianPathSolver( + int num_nodes, CostFunction cost) { return HamiltonianPathSolver(num_nodes, std::move(cost)); } @@ -602,9 +610,14 @@ HamiltonianPathSolver::HamiltonianPathSolver( template HamiltonianPathSolver::HamiltonianPathSolver( int num_nodes, CostFunction cost) - : cost_(std::move(cost)), num_nodes_(num_nodes), tsp_cost_(0), - hamiltonian_costs_(0), robust_(true), triangle_inequality_ok_(true), - robustness_checked_(false), triangle_inequality_checked_(false), + : cost_(std::move(cost)), + num_nodes_(num_nodes), + tsp_cost_(0), + hamiltonian_costs_(0), + robust_(true), + triangle_inequality_ok_(true), + robustness_checked_(false), + triangle_inequality_checked_(false), solved_(false) { CHECK_GE(NodeSet::MaxCardinality, num_nodes_); CHECK(cost_.Check()); @@ -630,16 +643,15 @@ void HamiltonianPathSolver::ChangeCostMatrix( template void HamiltonianPathSolver::Solve() { - if (solved_) - return; + if (solved_) return; if (num_nodes_ == 0) { tsp_cost_ = 0; - tsp_path_ = { 0 }; + tsp_path_ = {0}; hamiltonian_paths_.resize(1); hamiltonian_costs_.resize(1); best_hamiltonian_path_end_node_ = 0; hamiltonian_costs_[0] = 0; - hamiltonian_paths_[0] = { 0 }; + hamiltonian_paths_[0] = {0}; return; } mem_.Init(num_nodes_); @@ -771,18 +783,15 @@ bool HamiltonianPathSolver::PathIsValid( template bool HamiltonianPathSolver::IsRobust() { - if (std::numeric_limits::is_integer) - return true; - if (robustness_checked_) - return robust_; + if (std::numeric_limits::is_integer) return true; + if (robustness_checked_) return robust_; CostType min_cost = std::numeric_limits::max(); CostType max_cost = std::numeric_limits::min(); // We compute the min and max for the cost matrix. for (int i = 0; i < num_nodes_; ++i) { for (int j = 0; j < num_nodes_; ++j) { - if (i == j) - continue; + if (i == j) continue; min_cost = std::min(min_cost, Cost(i, j)); max_cost = std::max(max_cost, Cost(i, j)); } @@ -797,10 +806,9 @@ bool HamiltonianPathSolver::IsRobust() { } template -bool -HamiltonianPathSolver::VerifiesTriangleInequality() { - if (triangle_inequality_checked_) - return triangle_inequality_ok_; +bool HamiltonianPathSolver::VerifiesTriangleInequality() { + if (triangle_inequality_checked_) return triangle_inequality_ok_; triangle_inequality_ok_ = true; triangle_inequality_checked_ = true; for (int k = 0; k < num_nodes_; ++k) { @@ -819,22 +827,22 @@ HamiltonianPathSolver::VerifiesTriangleInequality() { } template -int -HamiltonianPathSolver::BestHamiltonianPathEndNode() { +int HamiltonianPathSolver::BestHamiltonianPathEndNode() { Solve(); return best_hamiltonian_path_end_node_; } template -CostType -HamiltonianPathSolver::HamiltonianCost(int end_node) { +CostType HamiltonianPathSolver::HamiltonianCost( + int end_node) { Solve(); return hamiltonian_costs_[end_node]; } template -std::vector -HamiltonianPathSolver::HamiltonianPath(int end_node) { +std::vector HamiltonianPathSolver::HamiltonianPath( + int end_node) { Solve(); return hamiltonian_paths_[end_node]; } @@ -882,7 +890,7 @@ class PruningHamiltonianSolver { // TODO(user): Use generic map-based cache instead of lattice-based one. // TODO(user): Use SaturatedArithmetic for better precision. -public: + public: typedef uint32 Integer; typedef Set NodeSet; @@ -895,7 +903,7 @@ public: // TODO(user): Add function to return an actual path. // TODO(user): Add functions for Hamiltonian cycle. -private: + private: // Returns the cost value between two nodes. CostType Cost(int i, int j) { return cost_(i, j); } @@ -929,13 +937,14 @@ PruningHamiltonianSolver::PruningHamiltonianSolver( template PruningHamiltonianSolver::PruningHamiltonianSolver( int num_nodes, CostFunction cost) - : cost_(std::move(cost)), num_nodes_(num_nodes), tsp_cost_(0), + : cost_(std::move(cost)), + num_nodes_(num_nodes), + tsp_cost_(0), solved_(false) {} template void PruningHamiltonianSolver::Solve(int end_node) { - if (solved_ || num_nodes_ == 0) - return; + if (solved_ || num_nodes_ == 0) return; // TODO(user): Use an approximate solution as a base target before solving. // TODO(user): Instead of pure DFS, find out the order of sets to compute @@ -959,13 +968,11 @@ void PruningHamiltonianSolver::Solve(int end_node) { // Let's to as much check possible before adding to stack. // Skip if this node is already visited. - if (current_set.Contains(next_to_visit)) - continue; + if (current_set.Contains(next_to_visit)) continue; // Skip if the end node is prematurely visited. const int next_cardinality = current_set.Cardinality() + 1; - if (next_to_visit == end_node && next_cardinality != num_nodes_) - continue; + if (next_to_visit == end_node && next_cardinality != num_nodes_) continue; const NodeSet next_set = current_set.AddElement(next_to_visit); const CostType next_cost = @@ -973,15 +980,13 @@ void PruningHamiltonianSolver::Solve(int end_node) { // Compare with the best cost found so far, and skip if that is better. const CostType previous_best = mem_.Value(next_set, next_to_visit); - if (previous_best != 0 && next_cost >= previous_best) - continue; + if (previous_best != 0 && next_cost >= previous_best) continue; // Compute lower bound of Hamiltonian cost, and skip if this is greater // than the best Hamiltonian cost found so far. const CostType lower_bound = ComputeFutureLowerBound(next_set, next_to_visit); - if (tsp_cost_ != 0 && next_cost + lower_bound >= tsp_cost_) - continue; + if (tsp_cost_ != 0 && next_cost + lower_bound >= tsp_cost_) continue; // If next is the last node to visit, update tsp_cost_ and skip. if (next_cardinality == num_nodes_) { @@ -1010,8 +1015,8 @@ CostType PruningHamiltonianSolver::ComputeFutureLowerBound( NodeSet current_set, int last_visited) { // TODO(user): Compute MST. - return 0; // For now, return 0 as future lower bound. + return 0; // For now, return 0 as future lower bound. } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_ +#endif // OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_ diff --git a/ortools/graph/io.h b/ortools/graph/io.h index 1a0b1d8b22..da03846e51 100644 --- a/ortools/graph/io.h +++ b/ortools/graph/io.h @@ -80,9 +80,9 @@ std::string GraphToString(const Graph &graph, GraphToStringFormat format); // ... // } template -absl::StatusOr - ReadGraphFile(const std::string &filename, bool directed, - std::vector *num_nodes_with_color_or_null); +absl::StatusOr ReadGraphFile( + const std::string &filename, bool directed, + std::vector *num_nodes_with_color_or_null); // Writes a graph to the ".g" file format described above. If "directed" is // true, all arcs are written to the file. If it is false, the graph is expected @@ -110,11 +110,10 @@ std::string GraphToString(const Graph &graph, GraphToStringFormat format) { for (const typename Graph::NodeIndex node : graph.AllNodes()) { if (format == PRINT_GRAPH_ARCS) { for (const typename Graph::ArcIndex arc : graph.OutgoingArcs(node)) { - if (!out.empty()) - out += '\n'; + if (!out.empty()) out += '\n'; absl::StrAppend(&out, node, "->", graph.Head(arc)); } - } else { // PRINT_GRAPH_ADJACENCY_LISTS[_SORTED] + } else { // PRINT_GRAPH_ADJACENCY_LISTS[_SORTED] adj.clear(); for (const typename Graph::ArcIndex arc : graph.OutgoingArcs(node)) { adj.push_back(graph.Head(arc)); @@ -122,8 +121,7 @@ std::string GraphToString(const Graph &graph, GraphToStringFormat format) { if (format == PRINT_GRAPH_ADJACENCY_LISTS_SORTED) { std::sort(adj.begin(), adj.end()); } - if (node != 0) - out += '\n'; + if (node != 0) out += '\n'; absl::StrAppend(&out, node, ": ", absl::StrJoin(adj, " ")); } } @@ -131,9 +129,9 @@ std::string GraphToString(const Graph &graph, GraphToStringFormat format) { } template -absl::StatusOr -ReadGraphFile(const std::string &filename, bool directed, - std::vector *num_nodes_with_color_or_null) { +absl::StatusOr ReadGraphFile( + const std::string &filename, bool directed, + std::vector *num_nodes_with_color_or_null) { std::unique_ptr graph; int64 num_nodes = -1; int64 num_expected_lines = -1; @@ -204,11 +202,9 @@ ReadGraphFile(const std::string &filename, bool directed, // the file, to get better error messages: we want to know the actual // number of lines, and also want to check the validity of the superfluous // arcs (i.e. that their src/dst nodes are ok). - if (num_lines_read > num_expected_lines + 1) - continue; + if (num_lines_read > num_expected_lines + 1) continue; graph->AddArc(node1, node2); - if (!directed && node1 != node2) - graph->AddArc(node2, node1); + if (!directed && node1 != node2) graph->AddArc(node2, node1); } if (num_lines_read == 0) { return absl::Status(absl::StatusCode::kInvalidArgument, @@ -240,8 +236,7 @@ absl::Status WriteGraphToFile(const Graph &graph, const std::string &filename, if (!directed) { for (const typename Graph::NodeIndex node : graph.AllNodes()) { for (const typename Graph::ArcIndex arc : graph.OutgoingArcs(node)) { - if (graph.Head(arc) == node) - ++num_self_arcs; + if (graph.Head(arc) == node) ++num_self_arcs; } } if ((graph.num_arcs() - num_self_arcs) % 2 != 0) { @@ -258,8 +253,7 @@ absl::Status WriteGraphToFile(const Graph &graph, const std::string &filename, : (graph.num_arcs() + num_self_arcs) / 2)); if (!num_nodes_with_color.empty()) { if (std::accumulate(num_nodes_with_color.begin(), - num_nodes_with_color.end(), 0) != - graph.num_nodes() || + num_nodes_with_color.end(), 0) != graph.num_nodes() || *std::min_element(num_nodes_with_color.begin(), num_nodes_with_color.end()) <= 0) { return absl::Status(absl::StatusCode::kInvalidArgument, @@ -288,6 +282,6 @@ absl::Status WriteGraphToFile(const Graph &graph, const std::string &filename, return ::absl::OkStatus(); } -} // namespace util +} // namespace util -#endif // UTIL_GRAPH_IO_H_ +#endif // UTIL_GRAPH_IO_H_ diff --git a/ortools/graph/iterators.h b/ortools/graph/iterators.h index 1119f44ee1..dccf63d3a1 100644 --- a/ortools/graph/iterators.h +++ b/ortools/graph/iterators.h @@ -34,8 +34,9 @@ namespace util { // And a client will use it like this: // // for (const ArcIndex arc : graph.OutgoingArcs(node)) { ... } -template class BeginEndWrapper { -public: +template +class BeginEndWrapper { + public: using const_iterator = Iterator; using value_type = typename std::iterator_traits::value_type; @@ -45,7 +46,7 @@ public: bool empty() const { return begin() == end(); } -private: + private: const Iterator begin_; const Iterator end_; }; @@ -58,8 +59,8 @@ inline BeginEndWrapper BeginEndRange(Iterator begin, Iterator end) { return BeginEndWrapper(begin, end); } template -inline BeginEndWrapper -BeginEndRange(std::pair begin_end) { +inline BeginEndWrapper BeginEndRange( + std::pair begin_end) { return BeginEndWrapper(begin_end.first, begin_end.second); } @@ -67,13 +68,13 @@ BeginEndRange(std::pair begin_end) { // TODO(user): go further and expose only the values, not the pairs (key, // values) since the caller already knows the key. template -inline BeginEndWrapper -EqualRange(MultiMap &multi_map, const typename MultiMap::key_type &key) { +inline BeginEndWrapper EqualRange( + MultiMap &multi_map, const typename MultiMap::key_type &key) { return BeginEndRange(multi_map.equal_range(key)); } template -inline BeginEndWrapper -EqualRange(const MultiMap &multi_map, const typename MultiMap::key_type &key) { +inline BeginEndWrapper EqualRange( + const MultiMap &multi_map, const typename MultiMap::key_type &key) { return BeginEndRange(multi_map.equal_range(key)); } @@ -81,15 +82,16 @@ EqualRange(const MultiMap &multi_map, const typename MultiMap::key_type &key) { // for loop over a container that support STL reverse iterators. // The syntax is: // for (const type& t : Reverse(container_of_t)) { ... } -template class BeginEndReverseIteratorWrapper { -public: +template +class BeginEndReverseIteratorWrapper { + public: explicit BeginEndReverseIteratorWrapper(const Container &c) : c_(c) {} typename Container::const_reverse_iterator begin() const { return c_.rbegin(); } typename Container::const_reverse_iterator end() const { return c_.rend(); } -private: + private: const Container &c_; }; template @@ -101,7 +103,7 @@ BeginEndReverseIteratorWrapper Reverse(const Container &c) { template class IntegerRangeIterator : public std::iterator { -public: + public: explicit IntegerRangeIterator(IntegerType value) : index_(value) {} IntegerRangeIterator(const IntegerRangeIterator &other) : index_(other.index_) {} @@ -127,7 +129,7 @@ public: return previous_position; } -private: + private: IntegerType index_; }; @@ -143,7 +145,7 @@ private: template class IntegerRange : public BeginEndWrapper > { -public: + public: IntegerRange(IntegerType begin, IntegerType end) : BeginEndWrapper >( IntegerRangeIterator(begin), @@ -151,7 +153,8 @@ public: }; // Allow iterating over a vector as a mutable vector. -template struct MutableVectorIteration { +template +struct MutableVectorIteration { explicit MutableVectorIteration(std::vector *v) : v_(v) {} struct Iterator { explicit Iterator(typename std::vector::iterator it) : it_(it) {} @@ -162,15 +165,15 @@ template struct MutableVectorIteration { } bool operator!=(const Iterator &other) const { return other.it_ != it_; } - private: + private: typename std::vector::iterator it_; }; Iterator begin() { return Iterator(v_->begin()); } Iterator end() { return Iterator(v_->end()); } -private: + private: std::vector *const v_; }; -} // namespace util +} // namespace util -#endif // UTIL_GRAPH_ITERATORS_H_ +#endif // UTIL_GRAPH_ITERATORS_H_ diff --git a/ortools/graph/linear_assignment.cc b/ortools/graph/linear_assignment.cc index 9eb6f9c6a3..6f7ae5969b 100644 --- a/ortools/graph/linear_assignment.cc +++ b/ortools/graph/linear_assignment.cc @@ -15,8 +15,9 @@ #include "ortools/base/commandlineflags.h" -DEFINE_int64(assignment_alpha, 5, "Divisor for epsilon at each Refine " - "step of LinearSumAssignment."); +DEFINE_int64(assignment_alpha, 5, + "Divisor for epsilon at each Refine " + "step of LinearSumAssignment."); DEFINE_int32(assignment_progress_logging_period, 5000, "Number of relabelings to do between logging progress messages " "when verbose level is 4 or more."); diff --git a/ortools/graph/linear_assignment.h b/ortools/graph/linear_assignment.h index def14d2111..b691bbb1ea 100644 --- a/ortools/graph/linear_assignment.h +++ b/ortools/graph/linear_assignment.h @@ -222,8 +222,9 @@ DECLARE_bool(assignment_stack_order); namespace operations_research { // This class does not take ownership of its underlying graph. -template class LinearSumAssignment { -public: +template +class LinearSumAssignment { + public: typedef typename GraphType::NodeIndex NodeIndex; typedef typename GraphType::ArcIndex ArcIndex; @@ -258,8 +259,8 @@ public: // // Passes ownership of the cycle handler to the caller. // - operations_research::PermutationCycleHandler * - ArcAnnotationCycleHandler(); + operations_research::PermutationCycleHandler + *ArcAnnotationCycleHandler(); // Optimizes the layout of the graph for the access pattern our // implementation will use. @@ -356,7 +357,7 @@ public: std::string StatsString() const { return total_stats_.StatsString(); } class BipartiteLeftNodeIterator { - public: + public: BipartiteLeftNodeIterator(const GraphType &graph, NodeIndex num_left_nodes) : num_left_nodes_(num_left_nodes), node_iterator_(0) {} @@ -369,12 +370,12 @@ public: void Next() { ++node_iterator_; } - private: + private: const NodeIndex num_left_nodes_; typename GraphType::NodeIndex node_iterator_; }; -private: + private: struct Stats { Stats() : pushes_(0), double_pushes_(0), relabelings_(0), refinements_(0) {} void Clear() { @@ -390,10 +391,10 @@ private: refinements_ += that.refinements_; } std::string StatsString() const { - return absl::StrFormat("%d refinements; %d relabelings; " - "%d double pushes; %d pushes", - refinements_, relabelings_, double_pushes_, - pushes_); + return absl::StrFormat( + "%d refinements; %d relabelings; " + "%d double pushes; %d pushes", + refinements_, relabelings_, double_pushes_, pushes_); } int64 pushes_; int64 double_pushes_; @@ -403,7 +404,7 @@ private: #ifndef SWIG class ActiveNodeContainerInterface { - public: + public: virtual ~ActiveNodeContainerInterface() {} virtual bool Empty() const = 0; virtual void Add(NodeIndex node) = 0; @@ -411,7 +412,7 @@ private: }; class ActiveNodeStack : public ActiveNodeContainerInterface { - public: + public: ~ActiveNodeStack() override {} bool Empty() const override { return v_.empty(); } @@ -425,12 +426,12 @@ private: return result; } - private: + private: std::vector v_; }; class ActiveNodeQueue : public ActiveNodeContainerInterface { - public: + public: ~ActiveNodeQueue() override {} bool Empty() const override { return q_.empty(); } @@ -444,7 +445,7 @@ private: return result; } - private: + private: std::deque q_; }; #endif @@ -882,8 +883,7 @@ private: static_cast(std::numeric_limits::max()); if (result > limit) { // Our integer computations could overflow. - if (in_range != nullptr) - *in_range = false; + if (in_range != nullptr) *in_range = false; return std::numeric_limits::max(); } else { // Don't touch *in_range; other computations could already have @@ -962,11 +962,16 @@ const CostValue LinearSumAssignment::kMinEpsilon = 1; template LinearSumAssignment::LinearSumAssignment( const GraphType &graph, const NodeIndex num_left_nodes) - : graph_(&graph), num_left_nodes_(num_left_nodes), success_(false), + : graph_(&graph), + num_left_nodes_(num_left_nodes), + success_(false), cost_scaling_factor_(1 + num_left_nodes), - alpha_(absl::GetFlag(FLAGS_assignment_alpha)), epsilon_(0), - price_lower_bound_(0), slack_relabeling_price_(0), - largest_scaled_cost_magnitude_(0), total_excess_(0), + alpha_(absl::GetFlag(FLAGS_assignment_alpha)), + epsilon_(0), + price_lower_bound_(0), + slack_relabeling_price_(0), + largest_scaled_cost_magnitude_(0), + total_excess_(0), price_(num_left_nodes, 2 * num_left_nodes - 1), matched_arc_(num_left_nodes, 0), matched_node_(num_left_nodes, 2 * num_left_nodes - 1), @@ -980,11 +985,16 @@ LinearSumAssignment::LinearSumAssignment( template LinearSumAssignment::LinearSumAssignment( const NodeIndex num_left_nodes, const ArcIndex num_arcs) - : graph_(nullptr), num_left_nodes_(num_left_nodes), success_(false), + : graph_(nullptr), + num_left_nodes_(num_left_nodes), + success_(false), cost_scaling_factor_(1 + num_left_nodes), - alpha_(absl::GetFlag(FLAGS_assignment_alpha)), epsilon_(0), - price_lower_bound_(0), slack_relabeling_price_(0), - largest_scaled_cost_magnitude_(0), total_excess_(0), + alpha_(absl::GetFlag(FLAGS_assignment_alpha)), + epsilon_(0), + price_lower_bound_(0), + slack_relabeling_price_(0), + largest_scaled_cost_magnitude_(0), + total_excess_(0), price_(num_left_nodes, 2 * num_left_nodes - 1), matched_arc_(num_left_nodes, 0), matched_node_(num_left_nodes, 2 * num_left_nodes - 1), @@ -1012,7 +1022,7 @@ void LinearSumAssignment::SetArcCost(ArcIndex arc, CostValue cost) { template class CostValueCycleHandler : public PermutationCycleHandler { -public: + public: explicit CostValueCycleHandler(std::vector *cost) : temp_(0), cost_(cost) {} @@ -1020,8 +1030,8 @@ public: temp_ = (*cost_)[source]; } - void SetIndexFromIndex(ArcIndexType source, ArcIndexType destination) const - override { + void SetIndexFromIndex(ArcIndexType source, + ArcIndexType destination) const override { (*cost_)[destination] = (*cost_)[source]; } @@ -1031,7 +1041,7 @@ public: ~CostValueCycleHandler() override {} -private: + private: CostValue temp_; std::vector *const cost_; @@ -1043,8 +1053,9 @@ private: // instantiation of member templates with function-scoped types as // template parameters, which in turn is because those function-scoped // types lack linkage. -template class ArcIndexOrderingByTailNode { -public: +template +class ArcIndexOrderingByTailNode { + public: explicit ArcIndexOrderingByTailNode(const GraphType &graph) : graph_(graph) {} // Says ArcIndex a is less than ArcIndex b if arc a's tail is less @@ -1057,7 +1068,7 @@ public: (graph_.Head(a) < graph_.Head(b)))); } -private: + private: const GraphType &graph_; // Copy and assign are allowed; they have to be for STL to work @@ -1067,8 +1078,8 @@ private: // Passes ownership of the cycle handler to the caller. template -PermutationCycleHandler * -LinearSumAssignment::ArcAnnotationCycleHandler() { +PermutationCycleHandler + *LinearSumAssignment::ArcAnnotationCycleHandler() { return new CostValueCycleHandler( &scaled_arc_cost_); } @@ -1110,8 +1121,8 @@ bool LinearSumAssignment::UpdateEpsilon() { // For production code that checks whether a left-side node is active. template -inline bool -LinearSumAssignment::IsActive(NodeIndex left_node) const { +inline bool LinearSumAssignment::IsActive( + NodeIndex left_node) const { DCHECK_LT(left_node, num_left_nodes_); return matched_arc_[left_node] == GraphType::kNilArc; } @@ -1120,8 +1131,8 @@ LinearSumAssignment::IsActive(NodeIndex left_node) const { // so that method can assert that its argument is a left-side node, // while for debugging we need to be able to test any node. template -inline bool -LinearSumAssignment::IsActiveForDebugging(NodeIndex node) const { +inline bool LinearSumAssignment::IsActiveForDebugging( + NodeIndex node) const { if (node < num_left_nodes_) { return IsActive(node); } else { @@ -1210,7 +1221,8 @@ bool LinearSumAssignment::DoublePush(NodeIndex source) { return new_price >= price_lower_bound_; } -template bool LinearSumAssignment::Refine() { +template +bool LinearSumAssignment::Refine() { SaturateNegativeArcs(); InitializeActiveNodeContainer(); while (total_excess_ > 0) { @@ -1253,8 +1265,8 @@ template bool LinearSumAssignment::Refine() { template inline typename LinearSumAssignment::ImplicitPriceSummary LinearSumAssignment::BestArcAndGap(NodeIndex left_node) const { - DCHECK(IsActive(left_node)) << "Node " << left_node - << " must be active (unmatched)!"; + DCHECK(IsActive(left_node)) + << "Node " << left_node << " must be active (unmatched)!"; DCHECK_GT(epsilon_, 0); typename GraphType::OutgoingArcIterator arc_it(*graph_, left_node); ArcIndex best_arc = arc_it.Index(); @@ -1291,8 +1303,8 @@ LinearSumAssignment::BestArcAndGap(NodeIndex left_node) const { // Requires the precondition, explicitly computed in FinalizeSetup(), // that every left-side node has at least one incident arc. template -inline CostValue -LinearSumAssignment::ImplicitPrice(NodeIndex left_node) const { +inline CostValue LinearSumAssignment::ImplicitPrice( + NodeIndex left_node) const { DCHECK_GT(num_left_nodes_, left_node); DCHECK_GT(epsilon_, 0); typename GraphType::OutgoingArcIterator arc_it(*graph_, left_node); @@ -1379,9 +1391,8 @@ bool LinearSumAssignment::FinalizeSetup() { // where the largest arc cost is zero, we still do a Refine() // iteration. epsilon_ = std::max(largest_scaled_cost_magnitude_, kMinEpsilon + 1); - VLOG(2) - << "Largest given cost magnitude: " << largest_scaled_cost_magnitude_ / - cost_scaling_factor_; + VLOG(2) << "Largest given cost magnitude: " + << largest_scaled_cost_magnitude_ / cost_scaling_factor_; // Initialize left-side node-indexed arrays and check incidence // precondition. for (NodeIndex node = 0; node < num_left_nodes_; ++node) { @@ -1437,8 +1448,7 @@ template bool LinearSumAssignment::ComputeAssignment() { CHECK(graph_ != nullptr); bool ok = graph_->num_nodes() == 2 * num_left_nodes_; - if (!ok) - return false; + if (!ok) return false; // Note: FinalizeSetup() might have been called already by white-box // test code or by a client that wants to react to the possibility // of overflow before solving the given problem, but FinalizeSetup() @@ -1471,6 +1481,6 @@ CostValue LinearSumAssignment::GetCost() const { return cost; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_LINEAR_ASSIGNMENT_H_ +#endif // OR_TOOLS_GRAPH_LINEAR_ASSIGNMENT_H_ diff --git a/ortools/graph/max_flow.cc b/ortools/graph/max_flow.cc index a28331fec4..3c59f6e810 100644 --- a/ortools/graph/max_flow.cc +++ b/ortools/graph/max_flow.cc @@ -88,16 +88,16 @@ SimpleMaxFlow::Status SimpleMaxFlow::Solve(NodeIndex source, NodeIndex sink) { // Translate the GenericMaxFlow::Status. It is different because NOT_SOLVED // does not make sense in the simple api. switch (underlying_max_flow_->status()) { - case GenericMaxFlow::NOT_SOLVED: - return BAD_RESULT; - case GenericMaxFlow::OPTIMAL: - return OPTIMAL; - case GenericMaxFlow::INT_OVERFLOW: - return POSSIBLE_OVERFLOW; - case GenericMaxFlow::BAD_INPUT: - return BAD_INPUT; - case GenericMaxFlow::BAD_RESULT: - return BAD_RESULT; + case GenericMaxFlow::NOT_SOLVED: + return BAD_RESULT; + case GenericMaxFlow::OPTIMAL: + return OPTIMAL; + case GenericMaxFlow::INT_OVERFLOW: + return POSSIBLE_OVERFLOW; + case GenericMaxFlow::BAD_INPUT: + return BAD_INPUT; + case GenericMaxFlow::BAD_RESULT: + return BAD_RESULT; } return BAD_RESULT; } @@ -107,31 +107,37 @@ FlowQuantity SimpleMaxFlow::OptimalFlow() const { return optimal_flow_; } FlowQuantity SimpleMaxFlow::Flow(ArcIndex arc) const { return arc_flow_[arc]; } void SimpleMaxFlow::GetSourceSideMinCut(std::vector *result) { - if (underlying_max_flow_ == nullptr) - return; + if (underlying_max_flow_ == nullptr) return; underlying_max_flow_->GetSourceSideMinCut(result); } void SimpleMaxFlow::GetSinkSideMinCut(std::vector *result) { - if (underlying_max_flow_ == nullptr) - return; + if (underlying_max_flow_ == nullptr) return; underlying_max_flow_->GetSinkSideMinCut(result); } FlowModel SimpleMaxFlow::CreateFlowModelOfLastSolve() { - if (underlying_max_flow_ == nullptr) - return FlowModel(); + if (underlying_max_flow_ == nullptr) return FlowModel(); return underlying_max_flow_->CreateFlowModel(); } template GenericMaxFlow::GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink) - : graph_(graph), node_excess_(), node_potential_(), - residual_arc_capacity_(), first_admissible_arc_(), active_nodes_(), - source_(source), sink_(sink), use_global_update_(true), - use_two_phase_algorithm_(true), process_node_by_height_(true), - check_input_(true), check_result_(true), stats_("MaxFlow") { + : graph_(graph), + node_excess_(), + node_potential_(), + residual_arc_capacity_(), + first_admissible_arc_(), + active_nodes_(), + source_(source), + sink_(sink), + use_global_update_(true), + use_two_phase_algorithm_(true), + process_node_by_height_(true), + check_input_(true), + check_result_(true), + stats_("MaxFlow") { SCOPED_TIME_STAT(&stats_); DCHECK(graph->IsNodeValid(source)); DCHECK(graph->IsNodeValid(sink)); @@ -174,7 +180,7 @@ void GenericMaxFlow::SetArcCapacity(ArcIndex arc, const FlowQuantity free_capacity = residual_arc_capacity_[arc]; const FlowQuantity capacity_delta = new_capacity - Capacity(arc); if (capacity_delta == 0) { - return; // Nothing to do. + return; // Nothing to do. } status_ = NOT_SOLVED; if (free_capacity + capacity_delta >= 0) { @@ -216,8 +222,8 @@ void GenericMaxFlow::SetArcFlow(ArcIndex arc, FlowQuantity new_flow) { } template -void -GenericMaxFlow::GetSourceSideMinCut(std::vector *result) { +void GenericMaxFlow::GetSourceSideMinCut( + std::vector *result) { ComputeReachableNodes(source_, result); } @@ -226,7 +232,8 @@ void GenericMaxFlow::GetSinkSideMinCut(std::vector *result) { ComputeReachableNodes(sink_, result); } -template bool GenericMaxFlow::CheckResult() const { +template +bool GenericMaxFlow::CheckResult() const { SCOPED_TIME_STAT(&stats_); bool ok = true; if (node_excess_[source_] != -node_excess_[sink_]) { @@ -312,18 +319,19 @@ std::string GenericMaxFlow::DebugString(const std::string &context, ArcIndex arc) const { const NodeIndex tail = Tail(arc); const NodeIndex head = Head(arc); - return absl::StrFormat("%s Arc %d, from %d to %d, " - "Capacity = %d, Residual capacity = %d, " - "Flow = residual capacity for reverse arc = %d, " - "Height(tail) = %d, Height(head) = %d, " - "Excess(tail) = %d, Excess(head) = %d", - context, arc, tail, head, Capacity(arc), - residual_arc_capacity_[arc], Flow(arc), - node_potential_[tail], node_potential_[head], - node_excess_[tail], node_excess_[head]); + return absl::StrFormat( + "%s Arc %d, from %d to %d, " + "Capacity = %d, Residual capacity = %d, " + "Flow = residual capacity for reverse arc = %d, " + "Height(tail) = %d, Height(head) = %d, " + "Excess(tail) = %d, Excess(head) = %d", + context, arc, tail, head, Capacity(arc), residual_arc_capacity_[arc], + Flow(arc), node_potential_[tail], node_potential_[head], + node_excess_[tail], node_excess_[head]); } -template bool GenericMaxFlow::Solve() { +template +bool GenericMaxFlow::Solve() { status_ = NOT_SOLVED; if (check_input_ && !CheckInputConsistency()) { status_ = BAD_INPUT; @@ -367,7 +375,8 @@ template bool GenericMaxFlow::Solve() { return true; } -template void GenericMaxFlow::InitializePreflow() { +template +void GenericMaxFlow::InitializePreflow() { SCOPED_TIME_STAT(&stats_); // InitializePreflow() clears the whole flow that could have been computed // by a previous Solve(). This is not optimal in terms of complexity. @@ -537,16 +546,14 @@ void GenericMaxFlow::PushFlowExcessBackToSource() { // stored in reverse_topological_order. for (int i = 0; i < reverse_topological_order.size(); i++) { const NodeIndex node = reverse_topological_order[i]; - if (node_excess_[node] == 0) - continue; + if (node_excess_[node] == 0) continue; for (IncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) { const ArcIndex opposite_arc = Opposite(it.Index()); if (residual_arc_capacity_[opposite_arc] > 0) { const FlowQuantity flow = std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]); PushFlow(flow, opposite_arc); - if (node_excess_[node] == 0) - break; + if (node_excess_[node] == 0) break; } } DCHECK_EQ(0, node_excess_[node]); @@ -554,7 +561,8 @@ void GenericMaxFlow::PushFlowExcessBackToSource() { DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]); } -template void GenericMaxFlow::GlobalUpdate() { +template +void GenericMaxFlow::GlobalUpdate() { SCOPED_TIME_STAT(&stats_); bfs_queue_.clear(); int queue_index = 0; @@ -591,8 +599,7 @@ template void GenericMaxFlow::GlobalUpdate() { // Skip the arc if the height of head was already set to the correct // value (Remember we are doing reverse BFS). - if (node_in_bfs_queue_[head]) - continue; + if (node_in_bfs_queue_[head]) continue; // TODO(user): By using more memory we can speed this up quite a bit by // avoiding to take the opposite arc here, too options: @@ -622,8 +629,7 @@ template void GenericMaxFlow::GlobalUpdate() { // If the arc became saturated, it is no longer in the residual // graph, so we do not need to consider head at this time. - if (residual_arc_capacity_[opposite_arc] == 0) - continue; + if (residual_arc_capacity_[opposite_arc] == 0) continue; } // Note that there is no need to touch first_admissible_arc_[node] @@ -672,10 +678,8 @@ bool GenericMaxFlow::SaturateOutgoingArcsFromSource() { // If sink_ or source_ already have kMaxFlowQuantity, then there is no // point pushing more flow since it will cause an integer overflow. - if (node_excess_[sink_] == kMaxFlowQuantity) - return false; - if (node_excess_[source_] == -kMaxFlowQuantity) - return false; + if (node_excess_[sink_] == kMaxFlowQuantity) return false; + if (node_excess_[source_] == -kMaxFlowQuantity) return false; bool flow_pushed = false; for (OutgoingArcIterator it(*graph_, source_); it.Ok(); it.Next()) { @@ -683,8 +687,7 @@ bool GenericMaxFlow::SaturateOutgoingArcsFromSource() { const FlowQuantity flow = residual_arc_capacity_[arc]; // This is a special IsAdmissible() condition for the source. - if (flow == 0 || node_potential_[Head(arc)] >= num_nodes) - continue; + if (flow == 0 || node_potential_[Head(arc)] >= num_nodes) continue; // We are careful in case the sum of the flow out of the source is greater // than kMaxFlowQuantity to avoid overflow. @@ -700,8 +703,7 @@ bool GenericMaxFlow::SaturateOutgoingArcsFromSource() { // Since at the beginning of the function, current_flow_out_of_source // was different from kMaxFlowQuantity, we are sure to have pushed some // flow before if capped_flow is 0. - if (capped_flow == 0) - return true; + if (capped_flow == 0) return true; PushFlow(capped_flow, arc); return true; } @@ -749,7 +751,8 @@ void GenericMaxFlow::InitializeActiveNodeContainer() { } } -template void GenericMaxFlow::Refine() { +template +void GenericMaxFlow::Refine() { SCOPED_TIME_STAT(&stats_); // Usually SaturateOutgoingArcsFromSource() will saturate all the arcs from // the source in one go, and we will loop just once. But in case we can push @@ -778,8 +781,7 @@ template void GenericMaxFlow::Refine() { InitializeActiveNodeContainer(); while (!IsEmptyActiveNodeContainer()) { const NodeIndex node = GetAndRemoveFirstActiveNode(); - if (node == source_ || node == sink_) - continue; + if (node == source_ || node == sink_) continue; Discharge(node); } if (use_two_phase_algorithm_) { @@ -788,7 +790,8 @@ template void GenericMaxFlow::Refine() { } } -template void GenericMaxFlow::RefineWithGlobalUpdate() { +template +void GenericMaxFlow::RefineWithGlobalUpdate() { SCOPED_TIME_STAT(&stats_); // TODO(user): This should be graph_->num_nodes(), but ebert graph does not @@ -807,8 +810,7 @@ template void GenericMaxFlow::RefineWithGlobalUpdate() { while (!IsEmptyActiveNodeContainer()) { const NodeIndex node = GetAndRemoveFirstActiveNode(); if (skip_active_node[node] > 1) { - if (node != sink_ && node != source_) - ++num_skipped; + if (node != sink_ && node != source_) ++num_skipped; continue; } const NodeIndex old_height = node_potential_[node]; @@ -863,18 +865,18 @@ void GenericMaxFlow::Discharge(NodeIndex node) { std::min(node_excess_[node], residual_arc_capacity_[arc]); PushFlow(delta, arc); if (node_excess_[node] == 0) { - first_admissible_arc_[node] = arc; // arc may still be admissible. + first_admissible_arc_[node] = arc; // arc may still be admissible. return; } } } Relabel(node); - if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) - break; + if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) break; } } -template void GenericMaxFlow::Relabel(NodeIndex node) { +template +void GenericMaxFlow::Relabel(NodeIndex node) { SCOPED_TIME_STAT(&stats_); // Because we use a relaxed version, this is no longer true if the // first_admissible_arc_[node] was not actually the first arc! @@ -893,8 +895,7 @@ template void GenericMaxFlow::Relabel(NodeIndex node) { // We found an admissible arc at the current height, just stop there. // This is the true first_admissible_arc_[node]. - if (min_height + 1 == node_potential_[node]) - break; + if (min_height + 1 == node_potential_[node]) break; } } } @@ -928,9 +929,8 @@ const FlowQuantity GenericMaxFlow::kMaxFlowQuantity = template template -void -GenericMaxFlow::ComputeReachableNodes(NodeIndex start, - std::vector *result) { +void GenericMaxFlow::ComputeReachableNodes( + NodeIndex start, std::vector *result) { // If start is not a valid node index, it can reach only itself. // Note(user): This is needed because source and sink are given independently // of the graph and sometimes before it is even constructed. @@ -953,10 +953,8 @@ GenericMaxFlow::ComputeReachableNodes(NodeIndex start, it.Next()) { const ArcIndex arc = it.Index(); const NodeIndex head = Head(arc); - if (node_in_bfs_queue_[head]) - continue; - if (residual_arc_capacity_[reverse ? Opposite(arc) : arc] == 0) - continue; + if (node_in_bfs_queue_[head]) continue; + if (residual_arc_capacity_[reverse ? Opposite(arc) : arc] == 0) continue; node_in_bfs_queue_[head] = true; bfs_queue_.push_back(head); } @@ -964,16 +962,15 @@ GenericMaxFlow::ComputeReachableNodes(NodeIndex start, *result = bfs_queue_; } -template FlowModel GenericMaxFlow::CreateFlowModel() { +template +FlowModel GenericMaxFlow::CreateFlowModel() { FlowModel model; model.set_problem_type(FlowModel::MAX_FLOW); for (int n = 0; n < graph_->num_nodes(); ++n) { Node *node = model.add_node(); node->set_id(n); - if (n == source_) - node->set_supply(1); - if (n == sink_) - node->set_supply(-1); + if (n == source_) node->set_supply(1); + if (n == sink_) node->set_supply(-1); } for (int a = 0; a < graph_->num_arcs(); ++a) { Arc *arc = model.add_arc(); @@ -993,4 +990,4 @@ template class GenericMaxFlow< ::util::ReverseArcListGraph<> >; template class GenericMaxFlow< ::util::ReverseArcStaticGraph<> >; template class GenericMaxFlow< ::util::ReverseArcMixedGraph<> >; -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/max_flow.h b/ortools/graph/max_flow.h index 9dbd785489..d4b4b1661e 100644 --- a/ortools/graph/max_flow.h +++ b/ortools/graph/max_flow.h @@ -141,7 +141,8 @@ namespace operations_research { // Forward declaration. -template class GenericMaxFlow; +template +class GenericMaxFlow; // A simple and efficient max-cost flow interface. This is as fast as // GenericMaxFlow, which is the fastest, but uses @@ -150,7 +151,7 @@ template class GenericMaxFlow; // // TODO(user): If the need arises, extend this interface to support warm start. class SimpleMaxFlow { -public: + public: // The constructor takes no size. // New node indices will be created lazily by AddArcWithCapacity(). SimpleMaxFlow(); @@ -228,7 +229,7 @@ public: // TODO(user): Support incrementality in the max flow implementation. void SetArcCapacity(ArcIndex arc, FlowQuantity capacity); -private: + private: NodeIndex num_nodes_; std::vector arc_tail_; std::vector arc_head_; @@ -262,7 +263,7 @@ private: // maintaining the height distribution of all the node in the graph. template class PriorityQueueWithRestrictedPush { -public: + public: PriorityQueueWithRestrictedPush() : even_queue_(), odd_queue_() {} // Is the queue empty? @@ -280,7 +281,7 @@ public: // IsEmpty() must be false, this condition is DCHECKed. Element Pop(); -private: + private: // Helper function to get the last element of a vector and pop it. Element PopBack(std::vector > *queue); @@ -298,21 +299,22 @@ private: // doesn't handle templated enums very well, so we need a base, // untemplated class to hold it. class MaxFlowStatusClass { -public: + public: enum Status { - NOT_SOLVED, // The problem was not solved, or its data were edited. - OPTIMAL, // Solve() was called and found an optimal solution. - INT_OVERFLOW, // There is a feasible flow > max possible flow. - BAD_INPUT, // The input is inconsistent. - BAD_RESULT // There was an error. + NOT_SOLVED, // The problem was not solved, or its data were edited. + OPTIMAL, // Solve() was called and found an optimal solution. + INT_OVERFLOW, // There is a feasible flow > max possible flow. + BAD_INPUT, // The input is inconsistent. + BAD_RESULT // There was an error. }; }; // Generic MaxFlow (there is a default MaxFlow specialization defined below) // that works with StarGraph and all the reverse arc graphs from graph.h, see // the end of max_flow.cc for the exact types this class is compiled for. -template class GenericMaxFlow : public MaxFlowStatusClass { -public: +template +class GenericMaxFlow : public MaxFlowStatusClass { + public: typedef typename Graph::NodeIndex NodeIndex; typedef typename Graph::ArcIndex ArcIndex; typedef typename Graph::OutgoingArcIterator OutgoingArcIterator; @@ -412,8 +414,7 @@ public: // See the corresponding variable declaration below for more details. void SetUseGlobalUpdate(bool value) { use_global_update_ = value; - if (!use_global_update_) - process_node_by_height_ = false; + if (!use_global_update_) process_node_by_height_ = false; } void SetUseTwoPhaseAlgorithm(bool value) { use_two_phase_algorithm_ = value; } void SetCheckInput(bool value) { check_input_ = value; } @@ -425,7 +426,7 @@ public: // Returns the protocol buffer representation of the current problem. FlowModel CreateFlowModel(); -protected: + protected: // Returns true if arc is admissible. bool IsAdmissible(ArcIndex arc) const { return residual_arc_capacity_[arc] > 0 && @@ -458,8 +459,7 @@ protected: // Get the first element from the active node container. NodeIndex GetAndRemoveFirstActiveNode() { - if (process_node_by_height_) - return active_node_by_height_.Pop(); + if (process_node_by_height_) return active_node_by_height_.Pop(); const NodeIndex node = active_nodes_.back(); active_nodes_.pop_back(); return node; @@ -641,7 +641,7 @@ protected: // Statistics about this class. mutable StatsGroup stats_; -private: + private: DISALLOW_COPY_AND_ASSIGN(GenericMaxFlow); }; @@ -651,16 +651,16 @@ private: // typedef because of dependent code expecting MaxFlow to be a real class. // TODO(user): Modify this code and remove it. class MaxFlow : public GenericMaxFlow { -public: + public: MaxFlow(const StarGraph *graph, NodeIndex source, NodeIndex target) : GenericMaxFlow(graph, source, target) {} }; -#endif // SWIG +#endif // SWIG template -bool -PriorityQueueWithRestrictedPush::IsEmpty() const { +bool PriorityQueueWithRestrictedPush::IsEmpty() + const { return even_queue_.empty() && odd_queue_.empty(); } @@ -692,10 +692,8 @@ void PriorityQueueWithRestrictedPush::Push( template Element PriorityQueueWithRestrictedPush::Pop() { DCHECK(!IsEmpty()); - if (even_queue_.empty()) - return PopBack(&odd_queue_); - if (odd_queue_.empty()) - return PopBack(&even_queue_); + if (even_queue_.empty()) return PopBack(&odd_queue_); + if (odd_queue_.empty()) return PopBack(&even_queue_); if (odd_queue_.back().second > even_queue_.back().second) { return PopBack(&odd_queue_); } else { @@ -712,5 +710,5 @@ Element PriorityQueueWithRestrictedPush::PopBack( return element; } -} // namespace operations_research -#endif // OR_TOOLS_GRAPH_MAX_FLOW_H_ +} // namespace operations_research +#endif // OR_TOOLS_GRAPH_MAX_FLOW_H_ diff --git a/ortools/graph/min_cost_flow.cc b/ortools/graph/min_cost_flow.cc index db72738bd1..1d4d494595 100644 --- a/ortools/graph/min_cost_flow.cc +++ b/ortools/graph/min_cost_flow.cc @@ -46,12 +46,22 @@ namespace operations_research { template GenericMinCostFlow::GenericMinCostFlow( const Graph *graph) - : graph_(graph), node_excess_(), node_potential_(), - residual_arc_capacity_(), first_admissible_arc_(), active_nodes_(), - epsilon_(0), alpha_(absl::GetFlag(FLAGS_min_cost_flow_alpha)), - cost_scaling_factor_(1), scaled_arc_unit_cost_(), total_flow_cost_(0), - status_(NOT_SOLVED), initial_node_excess_(), feasible_node_excess_(), - stats_("MinCostFlow"), feasibility_checked_(false), + : graph_(graph), + node_excess_(), + node_potential_(), + residual_arc_capacity_(), + first_admissible_arc_(), + active_nodes_(), + epsilon_(0), + alpha_(absl::GetFlag(FLAGS_min_cost_flow_alpha)), + cost_scaling_factor_(1), + scaled_arc_unit_cost_(), + total_flow_cost_(0), + status_(NOT_SOLVED), + initial_node_excess_(), + feasible_node_excess_(), + stats_("MinCostFlow"), + feasibility_checked_(false), use_price_update_(false), check_feasibility_(absl::GetFlag(FLAGS_min_cost_flow_check_feasibility)) { const NodeIndex max_num_nodes = Graphs::NodeReservation(*graph_); @@ -104,7 +114,7 @@ void GenericMinCostFlow::SetArcCapacity( const FlowQuantity free_capacity = residual_arc_capacity_[arc]; const FlowQuantity capacity_delta = new_capacity - Capacity(arc); if (capacity_delta == 0) { - return; // Nothing to do. + return; // Nothing to do. } status_ = NOT_SOLVED; feasibility_checked_ = false; @@ -151,13 +161,13 @@ template bool GenericMinCostFlow::CheckInputConsistency() const { FlowQuantity total_supply = 0; - uint64 max_capacity = 0; // uint64 because it is positive and will be used - // to check against FlowQuantity overflows. + uint64 max_capacity = 0; // uint64 because it is positive and will be used + // to check against FlowQuantity overflows. for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) { const uint64 capacity = static_cast(residual_arc_capacity_[arc]); max_capacity = std::max(capacity, max_capacity); } - uint64 total_flow = 0; // uint64 for the same reason as max_capacity. + uint64 total_flow = 0; // uint64 for the same reason as max_capacity. for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) { const FlowQuantity excess = node_excess_[node]; total_supply += excess; @@ -179,8 +189,8 @@ bool GenericMinCostFlow -bool -GenericMinCostFlow::CheckResult() const { +bool GenericMinCostFlow::CheckResult() + const { for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) { if (node_excess_[node] != 0) { LOG(DFATAL) << "node_excess_[" << node << "] != 0"; @@ -210,8 +220,8 @@ GenericMinCostFlow::CheckResult() const { } template -bool GenericMinCostFlow::CheckCostRange() const { +bool GenericMinCostFlow::CheckCostRange() + const { CostValue min_cost_magnitude = std::numeric_limits::max(); CostValue max_cost_magnitude = 0; // Traverse the initial arcs of the graph: @@ -236,9 +246,8 @@ bool GenericMinCostFlow -bool GenericMinCostFlow::CheckRelabelPrecondition( - NodeIndex node) const { +bool GenericMinCostFlow:: + CheckRelabelPrecondition(NodeIndex node) const { // Note that the classical Relabel precondition assumes IsActive(node), i.e., // the node_excess_[node] > 0. However, to implement the Push Look-Ahead // heuristic, we can relax this condition as explained in the section 4.3 of @@ -280,10 +289,9 @@ GenericMinCostFlow::DebugString( } template -bool -GenericMinCostFlow::CheckFeasibility( - std::vector *const infeasible_supply_node, - std::vector *const infeasible_demand_node) { +bool GenericMinCostFlow:: + CheckFeasibility(std::vector *const infeasible_supply_node, + std::vector *const infeasible_demand_node) { SCOPED_TIME_STAT(&stats_); // Create a new graph, which is a copy of graph_, with the following // modifications: @@ -393,8 +401,9 @@ FlowQuantity GenericMinCostFlow::Flow( // We use the equations given in the comment of residual_arc_capacity_. template -FlowQuantity GenericMinCostFlow< - Graph, ArcFlowType, ArcScaledCostType>::Capacity(ArcIndex arc) const { +FlowQuantity +GenericMinCostFlow::Capacity( + ArcIndex arc) const { if (IsArcDirect(arc)) { return residual_arc_capacity_[arc] + residual_arc_capacity_[Opposite(arc)]; } else { @@ -406,10 +415,7 @@ template CostValue GenericMinCostFlow::UnitCost( ArcIndex arc) const { DCHECK(IsArcValid(arc)); - DCHECK_EQ(uint64 { - 1 - }, - cost_scaling_factor_); + DCHECK_EQ(uint64{1}, cost_scaling_factor_); return scaled_arc_unit_cost_[arc]; } @@ -441,9 +447,8 @@ bool GenericMinCostFlow::IsAdmissible( } template -bool -GenericMinCostFlow::FastIsAdmissible( - ArcIndex arc, CostValue tail_potential) const { +bool GenericMinCostFlow:: + FastIsAdmissible(ArcIndex arc, CostValue tail_potential) const { DCHECK_EQ(node_potential_[Tail(arc)], tail_potential); return residual_arc_capacity_[arc] > 0 && FastReducedCost(arc, tail_potential) < 0; @@ -456,8 +461,9 @@ bool GenericMinCostFlow::IsActive( } template -CostValue GenericMinCostFlow< - Graph, ArcFlowType, ArcScaledCostType>::ReducedCost(ArcIndex arc) const { +CostValue +GenericMinCostFlow::ReducedCost( + ArcIndex arc) const { return FastReducedCost(arc, node_potential_[Tail(arc)]); } @@ -476,9 +482,8 @@ GenericMinCostFlow::FastReducedCost( template typename GenericMinCostFlow::ArcIndex -GenericMinCostFlow::GetFirstOutgoingOrOppositeIncomingArc( - NodeIndex node) const { +GenericMinCostFlow:: + GetFirstOutgoingOrOppositeIncomingArc(NodeIndex node) const { OutgoingOrOppositeIncomingArcIterator arc_it(*graph_, node); return arc_it.Index(); } @@ -699,8 +704,7 @@ void GenericMinCostFlow::UpdatePrices() { for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) { const NodeIndex head = Head(it.Index()); - if (node_in_queue[head]) - continue; + if (node_in_queue[head]) continue; const ArcIndex opposite_arc = Opposite(it.Index()); if (residual_arc_capacity_[opposite_arc] > 0) { node_potential_[head] += potential_delta; @@ -734,24 +738,20 @@ void GenericMinCostFlow::UpdatePrices() { } } } - if (remaining_excess == 0) - break; + if (remaining_excess == 0) break; } - if (remaining_excess == 0) - break; + if (remaining_excess == 0) break; // Decrease by as much as possible instead of decreasing by epsilon. // TODO(user): Is it worth the extra loop? CostValue max_potential_diff = kMinCostValue; for (int i = 0; i < nodes_to_process.size(); ++i) { const NodeIndex node = nodes_to_process[i]; - if (node_in_queue[node]) - continue; + if (node_in_queue[node]) continue; max_potential_diff = std::max(max_potential_diff, min_non_admissible_potential[node] - node_potential_[node]); - if (max_potential_diff == potential_delta) - break; + if (max_potential_diff == potential_delta) break; } DCHECK_LE(max_potential_diff, potential_delta); potential_delta = max_potential_diff - epsilon_; @@ -765,8 +765,7 @@ void GenericMinCostFlow::UpdatePrices() { int index = 0; for (int i = 0; i < nodes_to_process.size(); ++i) { const NodeIndex node = nodes_to_process[i]; - if (node_in_queue[node]) - continue; + if (node_in_queue[node]) continue; if (node_potential_[node] + potential_delta < min_non_admissible_potential[node]) { node_potential_[node] += potential_delta; @@ -786,8 +785,7 @@ void GenericMinCostFlow::UpdatePrices() { } // Update the potentials of the nodes not yet processed. - if (potential_delta == 0) - return; + if (potential_delta == 0) return; for (NodeIndex node = 0; node < num_nodes; ++node) { if (!node_in_queue[node]) { node_potential_[node] += potential_delta; @@ -833,8 +831,7 @@ void GenericMinCostFlow::Discharge( const ArcIndex arc = it.Index(); if (FastIsAdmissible(arc, tail_potential)) { const NodeIndex head = Head(arc); - if (!LookAhead(arc, tail_potential, head)) - continue; + if (!LookAhead(arc, tail_potential, head)) continue; const bool head_active_before_push = IsActive(head); const FlowQuantity delta = std::min(node_excess_[node], @@ -860,8 +857,7 @@ bool GenericMinCostFlow::LookAhead( SCOPED_TIME_STAT(&stats_); DCHECK_EQ(Head(in_arc), node); DCHECK_EQ(node_potential_[Tail(in_arc)], in_tail_potential); - if (node_excess_[node] < 0) - return true; + if (node_excess_[node] < 0) return true; const CostValue tail_potential = node_potential_[node]; for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node, first_admissible_arc_[node]); @@ -962,8 +958,9 @@ void GenericMinCostFlow::Relabel( } template -typename Graph::ArcIndex GenericMinCostFlow< - Graph, ArcFlowType, ArcScaledCostType>::Opposite(ArcIndex arc) const { +typename Graph::ArcIndex +GenericMinCostFlow::Opposite( + ArcIndex arc) const { return Graphs::OppositeArc(*graph_, arc); } @@ -993,8 +990,8 @@ template class GenericMinCostFlow< // A more memory-efficient version for large graphs. template class GenericMinCostFlow< ::util::ReverseArcStaticGraph, - /*ArcFlowType=*/ int16, - /*ArcScaledCostType=*/ int32>; + /*ArcFlowType=*/int16, + /*ArcScaledCostType=*/int32>; SimpleMinCostFlow::SimpleMinCostFlow(NodeIndex reserve_num_nodes, ArcIndex reserve_num_arcs) { @@ -1033,15 +1030,14 @@ ArcIndex SimpleMinCostFlow::PermutedArc(ArcIndex arc) { return arc < arc_permutation_.size() ? arc_permutation_[arc] : arc; } -SimpleMinCostFlow::Status -SimpleMinCostFlow::SolveWithPossibleAdjustment(SupplyAdjustment adjustment) { +SimpleMinCostFlow::Status SimpleMinCostFlow::SolveWithPossibleAdjustment( + SupplyAdjustment adjustment) { optimal_cost_ = 0; maximum_flow_ = 0; arc_flow_.clear(); const NodeIndex num_nodes = node_supply_.size(); const ArcIndex num_arcs = arc_capacity_.size(); - if (num_nodes == 0) - return OPTIMAL; + if (num_nodes == 0) return OPTIMAL; int supply_node_count = 0, demand_node_count = 0; FlowQuantity total_supply = 0, total_demand = 0; @@ -1106,13 +1102,14 @@ SimpleMinCostFlow::SolveWithPossibleAdjustment(SupplyAdjustment adjustment) { if (!max_flow.Solve()) { LOG(ERROR) << "Max flow could not be computed."; switch (max_flow.status()) { - case MaxFlowStatusClass::NOT_SOLVED: - return NOT_SOLVED; - case MaxFlowStatusClass::OPTIMAL: - LOG(ERROR) << "Max flow failed but claimed to have an optimal solution"; - ABSL_FALLTHROUGH_INTENDED; - default: - return BAD_RESULT; + case MaxFlowStatusClass::NOT_SOLVED: + return NOT_SOLVED; + case MaxFlowStatusClass::OPTIMAL: + LOG(ERROR) + << "Max flow failed but claimed to have an optimal solution"; + ABSL_FALLTHROUGH_INTENDED; + default: + return BAD_RESULT; } } maximum_flow_ = max_flow.GetOptimalFlow(); @@ -1180,9 +1177,8 @@ FlowQuantity SimpleMinCostFlow::Supply(NodeIndex node) const { } void SimpleMinCostFlow::ResizeNodeVectors(NodeIndex node) { - if (node < node_supply_.size()) - return; + if (node < node_supply_.size()) return; node_supply_.resize(node + 1); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/min_cost_flow.h b/ortools/graph/min_cost_flow.h index 52ecbc8dab..f58e359ea5 100644 --- a/ortools/graph/min_cost_flow.h +++ b/ortools/graph/min_cost_flow.h @@ -191,7 +191,7 @@ class GenericMinCostFlow; // Different statuses for a solved problem. // We use a base class to share it between our different interfaces. class MinCostFlowBase { -public: + public: enum Status { NOT_SOLVED, OPTIMAL, @@ -212,7 +212,7 @@ public: // and incrementality between solves. Note that this is already supported by the // GenericMinCostFlow<> interface. class SimpleMinCostFlow : public MinCostFlowBase { -public: + public: // By default, the constructor takes no size. New node indices are created // lazily by AddArcWithCapacityAndUnitCost() or SetNodeSupply() such that the // set of valid nodes will always be [0, NumNodes()). @@ -280,12 +280,9 @@ public: FlowQuantity Supply(NodeIndex node) const; CostValue UnitCost(ArcIndex arc) const; -private: + private: typedef ::util::ReverseArcStaticGraph Graph; - enum SupplyAdjustment { - ADJUST, - DONT_ADJUST - }; + enum SupplyAdjustment { ADJUST, DONT_ADJUST }; // Applies the permutation in arc_permutation_ to the given arc index. ArcIndex PermutedArc(ArcIndex arc); @@ -328,7 +325,7 @@ private: template class GenericMinCostFlow : public MinCostFlowBase { -public: + public: typedef typename Graph::NodeIndex NodeIndex; typedef typename Graph::ArcIndex ArcIndex; typedef typename Graph::OutgoingArcIterator OutgoingArcIterator; @@ -421,7 +418,7 @@ public: // forever. void SetCheckFeasibility(bool value) { check_feasibility_ = value; } -private: + private: // Returns true if the given arc is admissible i.e. if its residual capacity // is strictly positive, and its reduced cost strictly negative, i.e., pushing // more flow into it will result in a reduction of the total cost. @@ -615,11 +612,11 @@ private: // Default MinCostFlow instance that uses StarGraph. // New clients should use SimpleMinCostFlow if they can. class MinCostFlow : public GenericMinCostFlow { -public: + public: explicit MinCostFlow(const StarGraph *graph) : GenericMinCostFlow(graph) {} }; -#endif // SWIG +#endif // SWIG -} // namespace operations_research -#endif // OR_TOOLS_GRAPH_MIN_COST_FLOW_H_ +} // namespace operations_research +#endif // OR_TOOLS_GRAPH_MIN_COST_FLOW_H_ diff --git a/ortools/graph/minimum_spanning_tree.h b/ortools/graph/minimum_spanning_tree.h index 63157d1205..da65262d76 100644 --- a/ortools/graph/minimum_spanning_tree.h +++ b/ortools/graph/minimum_spanning_tree.h @@ -86,9 +86,8 @@ BuildKruskalMinimumSpanningTreeFromSortedArcs( // [&arc_cost](int a, int b) { return arc_cost(a) < arc_cost(b); }); // template -std::vector -BuildKruskalMinimumSpanningTree(const Graph &graph, - const ArcComparator &arc_comparator) { +std::vector BuildKruskalMinimumSpanningTree( + const Graph &graph, const ArcComparator &arc_comparator) { using ArcIndex = typename Graph::ArcIndex; std::vector sorted_arcs(graph.num_arcs()); for (const ArcIndex arc : graph.AllForwardArcs()) { @@ -113,8 +112,8 @@ BuildKruskalMinimumSpanningTree(const Graph &graph, // std::vector mst = BuildPrimMinimumSpanningTree(graph, arc_cost); // template -std::vector -BuildPrimMinimumSpanningTree(const Graph &graph, const ArcValue &arc_value) { +std::vector BuildPrimMinimumSpanningTree( + const Graph &graph, const ArcValue &arc_value) { using ArcIndex = typename Graph::ArcIndex; using NodeIndex = typename Graph::NodeIndex; using ArcValueType = decltype(arc_value(0)); @@ -145,9 +144,7 @@ BuildPrimMinimumSpanningTree(const Graph &graph, const ArcValue &arc_value) { std::vector entries; std::vector touched_entry(graph.num_nodes(), false); for (NodeIndex node : graph.AllNodes()) { - entries.push_back({ - node, std::numeric_limits::max(), -1 - }); + entries.push_back({node, std::numeric_limits::max(), -1}); } entries[0].value = 0; pq.Add(&entries[0]); @@ -180,5 +177,5 @@ BuildPrimMinimumSpanningTree(const Graph &graph, const ArcValue &arc_value) { return tree_arcs; } -} // namespace operations_research -#endif // OR_TOOLS_GRAPH_MINIMUM_SPANNING_TREE_H_ +} // namespace operations_research +#endif // OR_TOOLS_GRAPH_MINIMUM_SPANNING_TREE_H_ diff --git a/ortools/graph/one_tree_lower_bound.h b/ortools/graph/one_tree_lower_bound.h index 261a731c40..e2e7ac5607 100644 --- a/ortools/graph/one_tree_lower_bound.h +++ b/ortools/graph/one_tree_lower_bound.h @@ -149,10 +149,13 @@ namespace operations_research { // Implementation of the Volgenant Jonker algorithm (see the comments at the // head of the file for explanations). -template class VolgenantJonkerEvaluator { -public: +template +class VolgenantJonkerEvaluator { + public: VolgenantJonkerEvaluator(int number_of_nodes, int max_iterations) - : step1_initialized_(false), step1_(0), iteration_(0), + : step1_initialized_(false), + step1_(0), + iteration_(0), max_iterations_(max_iterations > 0 ? max_iterations : MaxIterations(number_of_nodes)), number_of_nodes_(number_of_nodes) {} @@ -161,9 +164,12 @@ public: double GetStep() const { return (1.0 * (iteration_ - 1) * (2 * max_iterations_ - 5) / - (2 * (max_iterations_ - 1))) * step1_ - (iteration_ - 2) * step1_ + + (2 * (max_iterations_ - 1))) * + step1_ - + (iteration_ - 2) * step1_ + (0.5 * (iteration_ - 1) * (iteration_ - 2) / - ((max_iterations_ - 1) * (max_iterations_ - 2))) * step1_; + ((max_iterations_ - 1) * (max_iterations_ - 2))) * + step1_; } void OnOneTree(CostType one_tree_cost, double w, @@ -176,7 +182,7 @@ public: void OnNewWMax(CostType one_tree_cost) { UpdateStep(one_tree_cost); } -private: + private: // Automatic computation of the number of iterations based on empirical // results given in Valenzuela-Jones 1997. static int MaxIterations(int number_of_nodes) { @@ -198,10 +204,13 @@ private: // head of the file for explanations). template class HeldWolfeCrowderEvaluator { -public: + public: HeldWolfeCrowderEvaluator(int number_of_nodes, const CostFunction &cost) - : iteration_(0), number_of_iterations_(2 * number_of_nodes), - upper_bound_(0), lambda_(2.0), step_(0) { + : iteration_(0), + number_of_iterations_(2 * number_of_nodes), + upper_bound_(0), + lambda_(2.0), + step_(0) { // TODO(user): Improve upper bound with some local search; tighter upper // bounds lead to faster convergence. ChristofidesPathSolver solver( @@ -213,8 +222,7 @@ public: const int min_iterations = 2; if (iteration_ >= number_of_iterations_) { number_of_iterations_ /= 2; - if (number_of_iterations_ < min_iterations) - return false; + if (number_of_iterations_ < min_iterations) return false; iteration_ = 0; lambda_ /= 2; } else { @@ -237,7 +245,7 @@ public: void OnNewWMax(CostType one_tree_cost) {} -private: + private: int iteration_; int number_of_iterations_; CostType upper_bound_; @@ -272,12 +280,8 @@ std::set > NearestNeighbors(int number_of_nodes, size = number_of_neighbors; } for (int j = 0; j < size; ++j) { - nearest.insert({ - i, neighbors[j].second - }); - nearest.insert({ - neighbors[j].second, i - }); + nearest.insert({i, neighbors[j].second}); + nearest.insert({neighbors[j].second, i}); } } return nearest; @@ -292,15 +296,11 @@ void AddArcsFromMinimumSpanningTree(int number_of_nodes, util::CompleteGraph graph(number_of_nodes); const std::vector mst = BuildPrimMinimumSpanningTree(graph, [&cost, &graph](int arc) { - return cost(graph.Tail(arc), graph.Head(arc)); - }); + return cost(graph.Tail(arc), graph.Head(arc)); + }); for (int arc : mst) { - arcs->insert({ - graph.Tail(arc), graph.Head(arc) - }); - arcs->insert({ - graph.Head(arc), graph.Tail(arc) - }); + arcs->insert({graph.Tail(arc), graph.Head(arc)}); + arcs->insert({graph.Head(arc), graph.Tail(arc)}); } } @@ -335,8 +335,7 @@ std::vector ComputeOneTree(const GraphType &graph, CostType *one_tree_cost) { const auto weighed_cost = [&cost, &weights](int from, int to) { return cost(from, to) + weights[from] + weights[to]; - } - ; + }; // Compute MST on graph. std::vector mst; if (!sorted_arcs.empty()) { @@ -345,8 +344,8 @@ std::vector ComputeOneTree(const GraphType &graph, } else { mst = BuildPrimMinimumSpanningTree( graph, [&weighed_cost, &graph](int arc) { - return weighed_cost(graph.Tail(arc), graph.Head(arc)); - }); + return weighed_cost(graph.Tail(arc), graph.Head(arc)); + }); } std::vector degrees(graph.num_nodes() + 1, 0); *one_tree_cost = 0; @@ -358,22 +357,19 @@ std::vector ComputeOneTree(const GraphType &graph, // Add 2 cheapest edges from the nodes in the graph to the extra node not in // the graph. const int extra_node = graph.num_nodes(); - const auto update_one_tree = - [extra_node, one_tree_cost, °rees, &cost](int node) { + const auto update_one_tree = [extra_node, one_tree_cost, °rees, + &cost](int node) { *one_tree_cost += cost(node, extra_node); degrees.back()++; degrees[node]++; - } - ; + }; const int node = GetNodeMinimizingEdgeCostToSource( - graph, extra_node, weighed_cost, [extra_node](int n) { - return n != extra_node; - }); + graph, extra_node, weighed_cost, + [extra_node](int n) { return n != extra_node; }); update_one_tree(node); update_one_tree(GetNodeMinimizingEdgeCostToSource( - graph, extra_node, weighed_cost, [extra_node, node](int n) { - return n != extra_node && n != node; - })); + graph, extra_node, weighed_cost, + [extra_node, node](int n) { return n != extra_node && n != node; })); return degrees; } @@ -383,10 +379,8 @@ double ComputeOneTreeLowerBoundWithAlgorithm(int number_of_nodes, int nearest_neighbors, const CostFunction &cost, Algorithm *algorithm) { - if (number_of_nodes < 2) - return 0; - if (number_of_nodes == 2) - return cost(0, 1) + cost(1, 0); + if (number_of_nodes < 2) return 0; + if (number_of_nodes == 2) return cost(0, 1) + cost(1, 0); using CostType = decltype(cost(0, 0)); auto nearest = NearestNeighbors(number_of_nodes - 1, nearest_neighbors, cost); // Ensure nearest arcs result in a connected graph by adding arcs from the @@ -404,9 +398,8 @@ double ComputeOneTreeLowerBoundWithAlgorithm(int number_of_nodes, // Iteratively compute lower bound using a partial graph. while (algorithm->Next()) { CostType one_tree_cost = 0; - const std::vector degrees = ComputeOneTree(graph, cost, weights, { - }, - &one_tree_cost); + const std::vector degrees = + ComputeOneTree(graph, cost, weights, {}, &one_tree_cost); algorithm->OnOneTree(one_tree_cost, w, degrees); w = one_tree_cost; for (int j = 0; j < number_of_nodes; ++j) { @@ -431,9 +424,7 @@ double ComputeOneTreeLowerBoundWithAlgorithm(int number_of_nodes, // however the Kruskal algorithm will expand all arcs also consuming O(n^2) // memory; investigate alternatives to expanding all arcs (Prim's algorithm). const std::vector degrees = - ComputeOneTree(complete_graph, cost, best_weights, { - }, - &one_tree_cost); + ComputeOneTree(complete_graph, cost, best_weights, {}, &one_tree_cost); w = one_tree_cost; for (int j = 0; j < number_of_nodes; ++j) { w += best_weights[j] * (degrees[j] - 2); @@ -463,22 +454,22 @@ double ComputeOneTreeLowerBoundWithParameters( const TravelingSalesmanLowerBoundParameters ¶meters) { using CostType = decltype(cost(0, 0)); switch (parameters.algorithm) { - case TravelingSalesmanLowerBoundParameters::VolgenantJonker: { - VolgenantJonkerEvaluator algorithm( - number_of_nodes, parameters.volgenant_jonker_iterations); - return ComputeOneTreeLowerBoundWithAlgorithm( - number_of_nodes, parameters.nearest_neighbors, cost, &algorithm); - break; - } - case TravelingSalesmanLowerBoundParameters::HeldWolfeCrowder: { - HeldWolfeCrowderEvaluator algorithm(number_of_nodes, - cost); - return ComputeOneTreeLowerBoundWithAlgorithm( - number_of_nodes, parameters.nearest_neighbors, cost, &algorithm); - } - default: - LOG(ERROR) << "Unsupported algorithm: " << parameters.algorithm; - return 0; + case TravelingSalesmanLowerBoundParameters::VolgenantJonker: { + VolgenantJonkerEvaluator algorithm( + number_of_nodes, parameters.volgenant_jonker_iterations); + return ComputeOneTreeLowerBoundWithAlgorithm( + number_of_nodes, parameters.nearest_neighbors, cost, &algorithm); + break; + } + case TravelingSalesmanLowerBoundParameters::HeldWolfeCrowder: { + HeldWolfeCrowderEvaluator algorithm( + number_of_nodes, cost); + return ComputeOneTreeLowerBoundWithAlgorithm( + number_of_nodes, parameters.nearest_neighbors, cost, &algorithm); + } + default: + LOG(ERROR) << "Unsupported algorithm: " << parameters.algorithm; + return 0; } } @@ -492,6 +483,6 @@ double ComputeOneTreeLowerBound(int number_of_nodes, const CostFunction &cost) { parameters); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_ONE_TREE_LOWER_BOUND_H_ +#endif // OR_TOOLS_GRAPH_ONE_TREE_LOWER_BOUND_H_ diff --git a/ortools/graph/perfect_matching.cc b/ortools/graph/perfect_matching.cc index 32af496002..361c1dc057 100644 --- a/ortools/graph/perfect_matching.cc +++ b/ortools/graph/perfect_matching.cc @@ -56,8 +56,7 @@ MinCostPerfectMatching::Status MinCostPerfectMatching::Solve() { } const int num_nodes = matches_.size(); - if (!graph_->Initialize()) - return Status::INFEASIBLE; + if (!graph_->Initialize()) return Status::INFEASIBLE; VLOG(2) << graph_->DebugString(); VLOG(1) << "num_unmatched: " << num_nodes - graph_->NumMatched() << " dual_objective: " << graph_->DualObjective(); @@ -70,8 +69,7 @@ MinCostPerfectMatching::Status MinCostPerfectMatching::Solve() { VLOG(1) << "num_unmatched: " << num_nodes - graph_->NumMatched() << " dual_objective: " << graph_->DualObjective(); - if (graph_->NumMatched() == num_nodes) - break; + if (graph_->NumMatched() == num_nodes) break; const BlossomGraph::CostValue delta = graph_->ComputeMaxCommonTreeDualDeltaAndResetPrimalEdgeQueue(); @@ -80,8 +78,7 @@ MinCostPerfectMatching::Status MinCostPerfectMatching::Solve() { return Status::INTEGER_OVERFLOW; } - if (delta == 0) - break; // Infeasible! + if (delta == 0) break; // Infeasible! graph_->UpdateAllTrees(delta); } @@ -102,8 +99,7 @@ MinCostPerfectMatching::Status MinCostPerfectMatching::Solve() { optimal_solution_found_ = true; optimal_cost_ = graph_->DualObjective().value(); - if (optimal_cost_ == kint64max) - return Status::COST_OVERFLOW; + if (optimal_cost_ == kint64max) return Status::COST_OVERFLOW; return Status::OPTIMAL; } @@ -149,8 +145,7 @@ bool BlossomGraph::Initialize() { is_initialized_ = true; for (NodeIndex n(0); n < nodes_.size(); ++n) { - if (graph_[n].empty()) - return false; // INFEASIBLE. + if (graph_[n].empty()) return false; // INFEASIBLE. CostValue min_cost = kMaxCostValue; // Initialize the dual of each nodes to min_cost / 2. @@ -177,8 +172,7 @@ bool BlossomGraph::Initialize() { } for (NodeIndex n(0); n < nodes_.size(); ++n) { - if (NodeIsMatched(n)) - continue; + if (NodeIsMatched(n)) continue; // After this greedy update, there will be at least an edge with a // slack of zero. @@ -200,8 +194,7 @@ bool BlossomGraph::Initialize() { // TODO(user): Optimize by merging this loop with the one above? for (const EdgeIndex e : graph_[n]) { const Edge &edge = edges_[e]; - if (edge.pseudo_slack != 0) - continue; + if (edge.pseudo_slack != 0) continue; if (!NodeIsMatched(edge.OtherEnd(n))) { nodes_[edge.tail].type = 0; nodes_[edge.tail].match = edge.head; @@ -214,8 +207,7 @@ bool BlossomGraph::Initialize() { // Initialize unmatched_nodes_. for (NodeIndex n(0); n < nodes_.size(); ++n) { - if (NodeIsMatched(n)) - continue; + if (NodeIsMatched(n)) continue; unmatched_nodes_.push_back(n); } @@ -253,12 +245,10 @@ bool BlossomGraph::Initialize() { const bool head_is_plus = nodes_[edge.head].IsPlus(); if (tail_is_plus && head_is_plus) { plus_plus_pq_.Add(&edge); - if (edge.pseudo_slack == 0) - primal_update_edge_queue_.push_back(e); + if (edge.pseudo_slack == 0) primal_update_edge_queue_.push_back(e); } else if (tail_is_plus || head_is_plus) { plus_free_pq_.Add(&edge); - if (edge.pseudo_slack == 0) - primal_update_edge_queue_.push_back(e); + if (edge.pseudo_slack == 0) primal_update_edge_queue_.push_back(e); } } } @@ -292,8 +282,7 @@ CostValue BlossomGraph::ComputeMaxCommonTreeDualDeltaAndResetPrimalEdgeQueue() { } // This means infeasible, and returning zero will abort the search. - if (best_update == kMaxCostValue) - return CostValue(0); + if (best_update == kMaxCostValue) return CostValue(0); // Initialize primal_update_edge_queue_ with all the edges that will have a // slack of zero once we apply the update. @@ -331,10 +320,8 @@ void BlossomGraph::UpdateAllTrees(CostValue delta) { if (DEBUG_MODE) { for (NodeIndex n(0); n < nodes_.size(); ++n) { const Node &node = nodes_[n]; - if (node.IsPlus()) - DebugUpdateNodeDual(n, delta); - if (node.IsMinus()) - DebugUpdateNodeDual(n, -delta); + if (node.IsPlus()) DebugUpdateNodeDual(n, delta); + if (node.IsMinus()) DebugUpdateNodeDual(n, -delta); } } } @@ -349,10 +336,8 @@ bool BlossomGraph::NodeIsMatched(NodeIndex n) const { NodeIndex BlossomGraph::Match(NodeIndex n) const { const Node &node = nodes_[n]; if (DEBUG_MODE) { - if (node.IsMinus()) - CHECK_EQ(node.parent, node.match); - if (node.IsPlus()) - CHECK_EQ(n, node.match); + if (node.IsMinus()) CHECK_EQ(node.parent, node.match); + if (node.IsPlus()) CHECK_EQ(n, node.match); } return node.match; } @@ -362,21 +347,17 @@ NodeIndex BlossomGraph::Match(NodeIndex n) const { void BlossomGraph::DebugCheckNoPossiblePrimalUpdates() { for (EdgeIndex e(0); e < edges_.size(); ++e) { const Edge &edge = edges_[e]; - if (Head(edge) == Tail(edge)) - continue; + if (Head(edge) == Tail(edge)) continue; CHECK(!nodes_[Tail(edge)].is_internal); CHECK(!nodes_[Head(edge)].is_internal); - if (Slack(edge) != 0) - continue; + if (Slack(edge) != 0) continue; // Make sure tail is a plus node if possible. NodeIndex tail = Tail(edge); NodeIndex head = Head(edge); - if (!nodes_[tail].IsPlus()) - std::swap(tail, head); - if (!nodes_[tail].IsPlus()) - continue; + if (!nodes_[tail].IsPlus()) std::swap(tail, head); + if (!nodes_[tail].IsPlus()) continue; if (nodes_[head].IsFree()) { VLOG(2) << DebugString(); @@ -415,15 +396,12 @@ void BlossomGraph::PrimalUpdates() { // detect it here and skip it than it would be to dynamically update the // queue to only keep actually tight edges at all times. const Edge &edge = edges_[e]; - if (Slack(edge) != 0) - continue; + if (Slack(edge) != 0) continue; NodeIndex tail = Tail(edge); NodeIndex head = Head(edge); - if (!nodes_[tail].IsPlus()) - std::swap(tail, head); - if (!nodes_[tail].IsPlus()) - continue; + if (!nodes_[tail].IsPlus()) std::swap(tail, head); + if (!nodes_[tail].IsPlus()) continue; if (nodes_[head].IsFree()) { Grow(e, tail, head); @@ -450,8 +428,7 @@ void BlossomGraph::PrimalUpdates() { } // Delay expand if any blossom was created. - if (!primal_update_edge_queue_.empty()) - continue; + if (!primal_update_edge_queue_.empty()) continue; // Expand Blossom if any. // @@ -466,33 +443,27 @@ void BlossomGraph::PrimalUpdates() { Expand(n); } } - if (num_expands == 0) - break; + if (num_expands == 0) break; } } bool BlossomGraph::DebugDualsAreFeasible() const { // The slack of all edge must be non-negative. for (const Edge &edge : edges_) { - if (Slack(edge) < 0) - return false; + if (Slack(edge) < 0) return false; } // The dual of all Blossom must be non-negative. for (const Node &node : nodes_) { - if (node.IsBlossom() && Dual(node) < 0) - return false; + if (node.IsBlossom() && Dual(node) < 0) return false; } return true; } bool BlossomGraph::DebugEdgeIsTightAndExternal(const Edge &edge) const { - if (Tail(edge) == Head(edge)) - return false; - if (nodes_[Tail(edge)].IsInternal()) - return false; - if (nodes_[Head(edge)].IsInternal()) - return false; + if (Tail(edge) == Head(edge)) return false; + if (nodes_[Tail(edge)].IsInternal()) return false; + if (nodes_[Head(edge)].IsInternal()) return false; return Slack(edge) == 0; } @@ -520,11 +491,9 @@ void BlossomGraph::Grow(EdgeIndex e, NodeIndex tail, NodeIndex head) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == head) - continue; + if (other_end == head) continue; edge.pseudo_slack -= tree_dual; - if (plus_free_pq_.Contains(&edge)) - plus_free_pq_.Remove(&edge); + if (plus_free_pq_.Contains(&edge)) plus_free_pq_.Remove(&edge); } } @@ -539,8 +508,7 @@ void BlossomGraph::Grow(EdgeIndex e, NodeIndex tail, NodeIndex head) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == leaf) - continue; + if (other_end == leaf) continue; edge.pseudo_slack += tree_dual; const Node &other_node = nodes_[other_end]; if (other_node.IsPlus()) { @@ -572,8 +540,7 @@ void BlossomGraph::AppendNodePathToRoot(NodeIndex n, while (true) { path->push_back(n); n = nodes_[n].parent; - if (n == path->back()) - break; + if (n == path->back()) break; } } @@ -615,11 +582,9 @@ void BlossomGraph::Augment(EdgeIndex e) { // though. for (NodeIndex n(0); n < nodes_.size(); ++n) { Node &node = nodes_[n]; - if (node.IsInternal()) - continue; + if (node.IsInternal()) continue; const NodeIndex root = node.root; - if (root != root_a && root != root_b) - continue; + if (root != root_a && root != root_b) continue; const CostValue delta = node.type * (root == root_a ? delta_a : delta_b); node.pseudo_dual += delta; @@ -627,8 +592,7 @@ void BlossomGraph::Augment(EdgeIndex e) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == n) - continue; + if (other_end == n) continue; edge.pseudo_slack -= delta; // If the other end is not in one of the two trees, and it is a plus @@ -637,17 +601,13 @@ void BlossomGraph::Augment(EdgeIndex e) { const Node &other_node = nodes_[other_end]; if (other_node.root != root_a && other_node.root != root_b && other_node.IsPlus()) { - if (plus_plus_pq_.Contains(&edge)) - plus_plus_pq_.Remove(&edge); + if (plus_plus_pq_.Contains(&edge)) plus_plus_pq_.Remove(&edge); DCHECK(!plus_free_pq_.Contains(&edge)); plus_free_pq_.Add(&edge); - if (Slack(edge) == 0) - primal_update_edge_queue_.push_back(e); + if (Slack(edge) == 0) primal_update_edge_queue_.push_back(e); } else { - if (plus_plus_pq_.Contains(&edge)) - plus_plus_pq_.Remove(&edge); - if (plus_free_pq_.Contains(&edge)) - plus_free_pq_.Remove(&edge); + if (plus_plus_pq_.Contains(&edge)) plus_plus_pq_.Remove(&edge); + if (plus_free_pq_.Contains(&edge)) plus_free_pq_.Remove(&edge); } } } @@ -670,8 +630,7 @@ void BlossomGraph::Augment(EdgeIndex e) { // the same delta for all trees, this is not even needed. int new_size = 0; for (const NodeIndex n : unmatched_nodes_) { - if (!NodeIsMatched(n)) - unmatched_nodes_[new_size++] = n; + if (!NodeIsMatched(n)) unmatched_nodes_[new_size++] = n; } CHECK_EQ(unmatched_nodes_.size(), new_size + 2); unmatched_nodes_.resize(new_size); @@ -681,8 +640,7 @@ int BlossomGraph::GetDepth(NodeIndex n) const { int depth = 0; while (true) { const NodeIndex parent = nodes_[n].parent; - if (parent == n) - break; + if (parent == n) break; ++depth; n = parent; } @@ -742,7 +700,7 @@ void BlossomGraph::Shrink(EdgeIndex e) { DCHECK(lca.IsPlus()); // Fill the cycle. - std::vector blossom = { lca_index }; + std::vector blossom = {lca_index}; std::reverse(head_path.begin(), head_path.end()); blossom.insert(blossom.end(), head_path.begin(), head_path.end()); blossom.insert(blossom.end(), tail_path.begin(), tail_path.end()); @@ -799,8 +757,7 @@ void BlossomGraph::Shrink(EdgeIndex e) { const NodeIndex other_end = OtherEnd(edge, subnode); // Skip edge that are already internal. - if (other_end == n) - continue; + if (other_end == n) continue; // This internal edge was already processed from its other end, so we // can just skip it. @@ -820,8 +777,7 @@ void BlossomGraph::Shrink(EdgeIndex e) { Node &mutable_other_node = nodes_[other_end]; if (mutable_other_node.is_internal) { DCHECK(!plus_free_pq_.Contains(&edge)); - if (plus_plus_pq_.Contains(&edge)) - plus_plus_pq_.Remove(&edge); + if (plus_plus_pq_.Contains(&edge)) plus_plus_pq_.Remove(&edge); edge.pseudo_slack += slack_adjust; edge.pseudo_slack += mutable_other_node.IsMinus() ? tree_dual : -tree_dual; @@ -869,9 +825,8 @@ void BlossomGraph::Shrink(EdgeIndex e) { VLOG(2) << "S result " << NodeDebugString(lca_index); } -BlossomGraph::EdgeIndex -BlossomGraph::FindTightExternalEdgeBetweenNodes(NodeIndex tail, - NodeIndex head) { +BlossomGraph::EdgeIndex BlossomGraph::FindTightExternalEdgeBetweenNodes( + NodeIndex tail, NodeIndex head) { DCHECK_NE(tail, head); DCHECK_EQ(tail, root_blossom_node_[tail]); DCHECK_EQ(head, root_blossom_node_[head]); @@ -933,10 +888,8 @@ void BlossomGraph::Expand(NodeIndex to_expand) { const NodeIndex end_node = OtherEndFromExternalNode(edges_[match_edge_index], node_to_expand.match); for (int i = 0; i < blossom.size(); ++i) { - if (blossom[i] == start_node) - blossom_path_start = i; - if (blossom[i] == end_node) - blossom_path_end = i; + if (blossom[i] == start_node) blossom_path_start = i; + if (blossom[i] == end_node) blossom_path_end = i; } // Split the cycle in two halves: nodes in [start..end] in path1, and @@ -950,10 +903,8 @@ void BlossomGraph::Expand(NodeIndex to_expand) { for (int offset = 0; offset <= /*or equal*/ cycle.size(); ++offset) { const NodeIndex node = cycle[(blossom_path_start + offset) % cycle.size()]; - if (offset <= end_offset) - path1.push_back(node); - if (offset >= end_offset) - path2.push_back(node); + if (offset <= end_offset) path1.push_back(node); + if (offset >= end_offset) path2.push_back(node); } } @@ -961,8 +912,7 @@ void BlossomGraph::Expand(NodeIndex to_expand) { std::reverse(path2.begin(), path2.end()); // Swap if necessary so that path1 is the odd-length one. - if (path1.size() % 2 == 0) - path1.swap(path2); + if (path1.size() % 2 == 0) path1.swap(path2); // Use better aliases than 'path1' and 'path2' in the code below. std::vector &path_in_tree = path1; @@ -1006,8 +956,7 @@ void BlossomGraph::Expand(NodeIndex to_expand) { nodes_[n].match = path_in_tree[node_is_plus ? i - 1 : i + 1]; // Ignore the blossom_matched_node for the code below. - if (i + 1 == path_in_tree.size()) - continue; + if (i + 1 == path_in_tree.size()) continue; // Update the duals, depending on whether we have a new [+] or [-] node. // Note that this is also needed for the 'root' blossom node (i=0), because @@ -1018,8 +967,7 @@ void BlossomGraph::Expand(NodeIndex to_expand) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == n) - continue; + if (other_end == n) continue; edge.pseudo_slack -= adjust; @@ -1032,8 +980,7 @@ void BlossomGraph::Expand(NodeIndex to_expand) { // wait for its other end to have been processed by this loop already. // We detect that using the fact that the type of unprocessed internal // node is still zero. - if (nodes_[other_end].type == 0) - continue; + if (nodes_[other_end].type == 0) continue; } // Update edge queues. @@ -1068,8 +1015,7 @@ void BlossomGraph::Expand(NodeIndex to_expand) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == n) - continue; + if (other_end == n) continue; // non-internal edges used to be attached to the [-] node_to_expand, // so we adjust their dual. @@ -1110,14 +1056,12 @@ void BlossomGraph::ExpandAllBlossoms() { std::vector queue; for (NodeIndex n(0); n < nodes_.size(); ++n) { Node &node = nodes_[n]; - if (node.IsInternal()) - continue; + if (node.IsInternal()) continue; // When this is called, there should be no more trees. CHECK(node.IsFree()); - if (node.IsBlossom()) - queue.push_back(n); + if (node.IsBlossom()) queue.push_back(n); } // TODO(user): remove duplication with expand? @@ -1194,8 +1138,7 @@ void BlossomGraph::ExpandAllBlossoms() { // Now that the expansion is done, add to the queue any sub-blossoms. for (const NodeIndex n : blossom) { - if (nodes_[n].IsBlossom()) - queue.push_back(n); + if (nodes_[n].IsBlossom()) queue.push_back(n); } } } @@ -1208,7 +1151,7 @@ const std::vector &BlossomGraph::SubNodes(NodeIndex n) { // Expand all the inner nodes under the node n. This will not be n iff node is // is in fact a blossom. - subnodes_ = { n }; + subnodes_ = {n}; for (int i = 0; i < subnodes_.size(); ++i) { const Node &node = nodes_[subnodes_[i]]; @@ -1237,13 +1180,14 @@ std::string BlossomGraph::NodeDebugString(NodeIndex n) const { return absl::StrCat("[I] #", n.value()); } const std::string type = - !NodeIsMatched(n) ? "[*]" : node.type == 1 ? "[+]" : node.type == -1 - ? "[-]" - : "[0]"; + !NodeIsMatched(n) + ? "[*]" + : node.type == 1 ? "[+]" : node.type == -1 ? "[-]" : "[0]"; return absl::StrCat( - type, " #", n.value(), " dual: ", Dual(node).value(), " parent: ", - node.parent.value(), " match: ", node.match.value(), " blossom: [", - absl::StrJoin(node.blossom, ", ", absl::StreamFormatter()), "]"); + type, " #", n.value(), " dual: ", Dual(node).value(), + " parent: ", node.parent.value(), " match: ", node.match.value(), + " blossom: [", absl::StrJoin(node.blossom, ", ", absl::StreamFormatter()), + "]"); } std::string BlossomGraph::EdgeDebugString(EdgeIndex e) const { @@ -1252,8 +1196,8 @@ std::string BlossomGraph::EdgeDebugString(EdgeIndex e) const { return absl::StrCat(Tail(edge).value(), "<->", Head(edge).value(), " internal "); } - return absl::StrCat(Tail(edge).value(), "<->", Head(edge).value(), " slack: ", - Slack(edge).value()); + return absl::StrCat(Tail(edge).value(), "<->", Head(edge).value(), + " slack: ", Slack(edge).value()); } std::string BlossomGraph::DebugString() const { @@ -1274,8 +1218,7 @@ void BlossomGraph::DebugUpdateNodeDual(NodeIndex n, CostValue delta) { for (const EdgeIndex e : graph_[subnode]) { Edge &edge = edges_[e]; const NodeIndex other_end = OtherEnd(edge, subnode); - if (other_end == n) - continue; + if (other_end == n) continue; edges_[e].slack -= delta; } } @@ -1286,8 +1229,7 @@ CostValue BlossomGraph::Slack(const Edge &edge) const { const Node &tail_node = nodes_[Tail(edge)]; const Node &head_node = nodes_[Head(edge)]; CostValue slack = edge.pseudo_slack; - if (Tail(edge) == Head(edge)) - return slack; // Internal... + if (Tail(edge) == Head(edge)) return slack; // Internal... if (!tail_node.is_internal && !head_node.is_internal) { slack -= tail_node.type * nodes_[tail_node.root].tree_dual_delta + @@ -1311,8 +1253,7 @@ CostValue BlossomGraph::Dual(const Node &node) const { } CostValue BlossomGraph::DualObjective() const { - if (dual_objective_ == kint64max) - return CostValue(kint64max); + if (dual_objective_ == kint64max) return CostValue(kint64max); CHECK_EQ(dual_objective_ % 2, 0); return dual_objective_ / 2; } @@ -1330,4 +1271,4 @@ void BlossomGraph::DisplayStats() const { VLOG(1) << "num_dual_updates: " << num_dual_updates_; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/graph/perfect_matching.h b/ortools/graph/perfect_matching.h index 9688937b70..11b7832ebc 100644 --- a/ortools/graph/perfect_matching.h +++ b/ortools/graph/perfect_matching.h @@ -48,7 +48,7 @@ class BlossomGraph; // pairs of nodes connected by an edge. The matching is perfect if all nodes are // matched to each others. class MinCostPerfectMatching { -public: + public: // TODO(user): For now we ask the number of nodes at construction, but we // could automatically infer it from the added edges if needed. MinCostPerfectMatching() {} @@ -115,7 +115,7 @@ public: return matches_; } -private: + private: std::unique_ptr graph_; // Fields used to report the optimal solution. Most of it could be read on @@ -165,7 +165,7 @@ private: // TODO(user): For now we use CHECKs in many places to facilitate development. // Switch them to DCHECKs for speed once the code is more stable. class BlossomGraph { -public: + public: // Typed index used by this class. DEFINE_INT_TYPE(NodeIndex, int); DEFINE_INT_TYPE(EdgeIndex, int); @@ -262,7 +262,8 @@ public: #ifndef NDEBUG slack(c), #endif - tail(t), head(h) { + tail(t), + head(h) { } // Returns the "other" end of this edge. @@ -396,7 +397,7 @@ public: std::string EdgeDebugString(EdgeIndex e) const; std::string DebugString() const; -private: + private: // Returns the index of a tight edge between the two given external nodes. // Returns kNoEdgeIndex if none could be found. // @@ -493,6 +494,6 @@ private: int64 num_dual_updates_ = 0; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_PERFECT_MATCHING_H_ +#endif // OR_TOOLS_GRAPH_PERFECT_MATCHING_H_ diff --git a/ortools/graph/shortestpaths.h b/ortools/graph/shortestpaths.h index 35b3584454..5b284c8f94 100644 --- a/ortools/graph/shortestpaths.h +++ b/ortools/graph/shortestpaths.h @@ -76,6 +76,6 @@ bool AStarShortestPath(int node_count, int start_node, int end_node, std::function heuristic, int64 disconnected_distance, std::vector *nodes); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GRAPH_SHORTESTPATHS_H_ +#endif // OR_TOOLS_GRAPH_SHORTESTPATHS_H_ diff --git a/ortools/graph/strongly_connected_components.h b/ortools/graph/strongly_connected_components.h index 2aa9411d58..25a7bed85a 100644 --- a/ortools/graph/strongly_connected_components.h +++ b/ortools/graph/strongly_connected_components.h @@ -78,7 +78,8 @@ void FindStronglyConnectedComponents(const NodeIndex num_nodes, // Note: If this matters, you probably don't want to use vector> as // an input either. See StaticGraph in ortools/graph/graph.h // for an efficient graph data structure compatible with this algorithm. -template struct SccCounterOutput { +template +struct SccCounterOutput { int number_of_components = 0; void emplace_back(NodeIndex const *b, NodeIndex const *e) { ++number_of_components; @@ -100,7 +101,7 @@ template struct SccCounterOutput { // - Use an index rather than doing push_back(), pop_back() on them. template class StronglyConnectedComponentsFinder { -public: + public: void FindStronglyConnectedComponents(const NodeIndex num_nodes, const Graph &graph, SccOutput *components) { @@ -117,8 +118,7 @@ public: // Loop over all the nodes not yet settled and start a DFS from each of // them. for (NodeIndex base_node = 0; base_node < num_nodes; ++base_node) { - if (node_index_[base_node] != 0) - continue; + if (node_index_[base_node] != 0) continue; DCHECK_EQ(0, node_to_process_.size()); node_to_process_.push_back(base_node); do { @@ -177,7 +177,7 @@ public: return node_index_[node] > 0 && node_index_[node] < kSettledIndex; } -private: + private: static constexpr NodeIndex kSettledIndex = std::numeric_limits::max(); @@ -215,4 +215,4 @@ void FindStronglyConnectedComponents(const NodeIndex num_nodes, return helper.FindStronglyConnectedComponents(num_nodes, graph, components); } -#endif // UTIL_GRAPH_STRONGLY_CONNECTED_COMPONENTS_H_ +#endif // UTIL_GRAPH_STRONGLY_CONNECTED_COMPONENTS_H_ diff --git a/ortools/graph/topologicalsorter.cc b/ortools/graph/topologicalsorter.cc index 4dd08a491a..9d827f075b 100644 --- a/ortools/graph/topologicalsorter.cc +++ b/ortools/graph/topologicalsorter.cc @@ -26,7 +26,8 @@ namespace util { namespace internal { namespace { -template inline void PopTop(IntQueue *q, int *top) { +template +inline void PopTop(IntQueue *q, int *top) { *top = q->front(); q->pop(); } @@ -36,7 +37,7 @@ void PopTop(std::priority_queue *q, int *top) { *top = q->top(); q->pop(); } -} // namespace +} // namespace template void DenseIntTopologicalSorterTpl::AddNode(int node_index) { @@ -282,11 +283,10 @@ void DenseIntTopologicalSorterTpl::ExtractCycle( template class DenseIntTopologicalSorterTpl; template class DenseIntTopologicalSorterTpl; -} // namespace internal +} // namespace internal -std::vector -FindCycleInDenseIntGraph(int num_nodes, - const std::vector > &arcs) { +std::vector FindCycleInDenseIntGraph( + int num_nodes, const std::vector > &arcs) { std::vector cycle; if (num_nodes < 1) { return cycle; @@ -298,4 +298,4 @@ FindCycleInDenseIntGraph(int num_nodes, sorter.ExtractCycle(&cycle); return cycle; } -} // namespace util +} // namespace util diff --git a/ortools/graph/topologicalsorter.h b/ortools/graph/topologicalsorter.h index 652b9389b5..9ea5a2f9ae 100644 --- a/ortools/graph/topologicalsorter.h +++ b/ortools/graph/topologicalsorter.h @@ -76,16 +76,14 @@ namespace util { // Returns true if the graph was a DAG, and outputs the topological order in // "topological_order". Returns false if the graph is cyclic. // Works in O(num_nodes + arcs.size()), and is pretty fast. -inline ABSL_MUST_USE_RESULT bool - DenseIntTopologicalSort(int num_nodes, - const std::vector > &arcs, - std::vector *topological_order); +inline ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort( + int num_nodes, const std::vector > &arcs, + std::vector *topological_order); // Like DenseIntTopologicalSort, but stable. -inline ABSL_MUST_USE_RESULT bool - DenseIntStableTopologicalSort(int num_nodes, - const std::vector > &arcs, - std::vector *topological_order); +inline ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort( + int num_nodes, const std::vector > &arcs, + std::vector *topological_order); // Finds a cycle in the directed graph given as argument: nodes are dense // integers in 0..num_nodes-1, and (directed) arcs are pairs of nodes @@ -93,45 +91,39 @@ inline ABSL_MUST_USE_RESULT bool // The returned cycle is a list of nodes that form a cycle, eg. {1, 4, 3} // if the cycle 1->4->3->1 exists. // If the graph is acyclic, returns an empty vector. -ABSL_MUST_USE_RESULT std::vector - FindCycleInDenseIntGraph(int num_nodes, - const std::vector > &arcs); +ABSL_MUST_USE_RESULT std::vector FindCycleInDenseIntGraph( + int num_nodes, const std::vector > &arcs); // Like the two above, but with generic node types. The nodes must be provided. // Can be significantly slower, but still linear. template -ABSL_MUST_USE_RESULT bool - TopologicalSort(const std::vector &nodes, - const std::vector > &arcs, - std::vector *topological_order); +ABSL_MUST_USE_RESULT bool TopologicalSort( + const std::vector &nodes, const std::vector > &arcs, + std::vector *topological_order); template -ABSL_MUST_USE_RESULT bool - StableTopologicalSort(const std::vector &nodes, - const std::vector > &arcs, - std::vector *topological_order); +ABSL_MUST_USE_RESULT bool StableTopologicalSort( + const std::vector &nodes, const std::vector > &arcs, + std::vector *topological_order); // "OrDie()" versions of the 4 functions above. Those directly return the // topological order, which makes their API even simpler. -inline std::vector - DenseIntTopologicalSortOrDie(int num_nodes, - const std::vector > &arcs); +inline std::vector DenseIntTopologicalSortOrDie( + int num_nodes, const std::vector > &arcs); inline std::vector DenseIntStableTopologicalSortOrDie( int num_nodes, const std::vector > &arcs); template std::vector TopologicalSortOrDie(const std::vector &nodes, const std::vector > &arcs); template -std::vector - StableTopologicalSortOrDie(const std::vector &nodes, - const std::vector > &arcs); +std::vector StableTopologicalSortOrDie( + const std::vector &nodes, const std::vector > &arcs); namespace internal { // Internal wrapper around the *TopologicalSort classes. template -ABSL_MUST_USE_RESULT bool - RunTopologicalSorter(Sorter *sorter, - const std::vector > &arcs, - std::vector *topological_order_or_cycle); +ABSL_MUST_USE_RESULT bool RunTopologicalSorter( + Sorter *sorter, const std::vector > &arcs, + std::vector *topological_order_or_cycle); // Do not use the templated class directly, instead use one of the // typedefs DenseIntTopologicalSorter or DenseIntStableTopologicalSorter. @@ -145,22 +137,26 @@ ABSL_MUST_USE_RESULT bool // This means that the order of the nodes will be maintained as much as // possible. A non-stable sort is more efficient, since the complexity // of getting the next node is O(1) rather than O(log(Nodes)). -template class DenseIntTopologicalSorterTpl { -public: +template +class DenseIntTopologicalSorterTpl { + public: // To store the adjacency lists efficiently. typedef std::vector AdjacencyList; // For efficiency, it is best to specify how many nodes are required // by using the next constructor. DenseIntTopologicalSorterTpl() - : traversal_started_(false), num_edges_(0), + : traversal_started_(false), + num_edges_(0), num_edges_added_since_last_duplicate_removal_(0) {} // One may also construct a DenseIntTopologicalSorterTpl with a predefined // number of empty nodes. One can thus bypass the AddNode() API, // which may yield a lower memory usage. explicit DenseIntTopologicalSorterTpl(int num_nodes) - : adjacency_lists_(num_nodes), traversal_started_(false), num_edges_(0), + : adjacency_lists_(num_nodes), + traversal_started_(false), + num_edges_(0), num_edges_added_since_last_duplicate_removal_(0) {} // Performs in constant amortized time. Calling this will make all @@ -200,7 +196,7 @@ public: // To extract a cycle. When there is no cycle, cycle_nodes will be empty. void ExtractCycle(std::vector *cycle_nodes) const; -private: + private: // Outgoing adjacency lists. std::vector adjacency_lists_; @@ -217,21 +213,21 @@ private: // Used internally by AddEdge() to decide whether to trigger // RemoveDuplicates(). See the .cc. - int num_edges_; // current total number of edges. + int num_edges_; // current total number of edges. int num_edges_added_since_last_duplicate_removal_; -private: + private: DISALLOW_COPY_AND_ASSIGN(DenseIntTopologicalSorterTpl); }; extern template class DenseIntTopologicalSorterTpl; extern template class DenseIntTopologicalSorterTpl; -} // namespace internal +} // namespace internal // Recommended version for general usage. The stability makes it more // deterministic, and its behavior is guaranteed to never change. -typedef ::util::internal::DenseIntTopologicalSorterTpl +typedef ::util::internal::DenseIntTopologicalSorterTpl DenseIntStableTopologicalSorter; // Use this version if you are certain you don't care about the @@ -239,7 +235,7 @@ typedef ::util::internal::DenseIntTopologicalSorterTpl // performance gain can be more significant for large graphs with large // numbers of source nodes (for example 2 Million nodes with 2 Million // random edges sees a factor of 0.7 difference in completion time). -typedef ::util::internal::DenseIntTopologicalSorterTpl +typedef ::util::internal::DenseIntTopologicalSorterTpl DenseIntTopologicalSorter; // A copy of each Node is stored internally. Duplicated edges are allowed, @@ -263,12 +259,12 @@ typedef ::util::internal::DenseIntTopologicalSorterTpl // original order of the nodes as much as possible. Note, the order // which is preserved is the order in which the nodes are added (if you // use AddEdge it will add the first argument and then the second). -template < - typename T, bool stable_sort = false, - typename Hash = typename absl::flat_hash_map::hasher, - typename KeyEqual = typename absl::flat_hash_map::key_equal> +template ::hasher, + typename KeyEqual = + typename absl::flat_hash_map::key_equal> class TopologicalSorter { -public: + public: TopologicalSorter() {} ~TopologicalSorter() {} @@ -341,8 +337,7 @@ public: // + num_edges) time, users may want to call this at their convenience, // instead of making it happen with the first GetNext(). void StartTraversal() { - if (TraversalStarted()) - return; + if (TraversalStarted()) return; nodes_.resize(node_to_index_.size()); // We move elements from the absl::flat_hash_map to this vector, without // extra copy (if they are movable). @@ -357,7 +352,7 @@ public: // can no longer be called. bool TraversalStarted() const { return int_sorter_.TraversalStarted(); } -private: + private: // A simple mapping from node to their dense index, in 0..num_nodes-1, // which will be their index in nodes_[]. Cleared when a traversal // starts, and replaced by nodes_[]. @@ -386,9 +381,9 @@ namespace internal { // If successful, returns true and outputs the order in "topological_order". // If not, returns false and outputs a cycle in "cycle" (if not null). template -ABSL_MUST_USE_RESULT bool -RunTopologicalSorter(Sorter *sorter, const std::vector > &arcs, - std::vector *topological_order, std::vector *cycle) { +ABSL_MUST_USE_RESULT bool RunTopologicalSorter( + Sorter *sorter, const std::vector > &arcs, + std::vector *topological_order, std::vector *cycle) { topological_order->clear(); for (const auto &arc : arcs) { sorter->AddEdge(arc.first, arc.second); @@ -403,20 +398,18 @@ RunTopologicalSorter(Sorter *sorter, const std::vector > &arcs, } template -ABSL_MUST_USE_RESULT bool -DenseIntTopologicalSortImpl(int num_nodes, - const std::vector > &arcs, - std::vector *topological_order) { +ABSL_MUST_USE_RESULT bool DenseIntTopologicalSortImpl( + int num_nodes, const std::vector > &arcs, + std::vector *topological_order) { DenseIntTopologicalSorterTpl sorter(num_nodes); return RunTopologicalSorter( &sorter, arcs, topological_order, nullptr); } template -ABSL_MUST_USE_RESULT bool -TopologicalSortImpl(const std::vector &nodes, - const std::vector > &arcs, - std::vector *topological_order) { +ABSL_MUST_USE_RESULT bool TopologicalSortImpl( + const std::vector &nodes, const std::vector > &arcs, + std::vector *topological_order) { TopologicalSorter sorter; for (const T &node : nodes) { sorter.AddNode(node); @@ -427,9 +420,8 @@ TopologicalSortImpl(const std::vector &nodes, // Now, the OrDie() versions, which directly return the topological order. template -std::vector -RunTopologicalSorterOrDie(Sorter *sorter, - const std::vector > &arcs) { +std::vector RunTopologicalSorterOrDie( + Sorter *sorter, const std::vector > &arcs) { std::vector topo_order; CHECK(RunTopologicalSorter(sorter, arcs, &topo_order, &topo_order)) << "Found cycle: " << gtl::LogContainer(topo_order); @@ -444,30 +436,27 @@ std::vector DenseIntTopologicalSortOrDieImpl( } template -std::vector -TopologicalSortOrDieImpl(const std::vector &nodes, - const std::vector > &arcs) { +std::vector TopologicalSortOrDieImpl( + const std::vector &nodes, const std::vector > &arcs) { TopologicalSorter sorter; for (const T &node : nodes) { sorter.AddNode(node); } return RunTopologicalSorterOrDie(&sorter, arcs); } -} // namespace internal +} // namespace internal // Implementations of the "simple API" functions declared at the top. -inline bool -DenseIntTopologicalSort(int num_nodes, - const std::vector > &arcs, - std::vector *topological_order) { +inline bool DenseIntTopologicalSort( + int num_nodes, const std::vector > &arcs, + std::vector *topological_order) { return internal::DenseIntTopologicalSortImpl(num_nodes, arcs, topological_order); } -inline bool -DenseIntStableTopologicalSort(int num_nodes, - const std::vector > &arcs, - std::vector *topological_order) { +inline bool DenseIntStableTopologicalSort( + int num_nodes, const std::vector > &arcs, + std::vector *topological_order) { return internal::DenseIntTopologicalSortImpl(num_nodes, arcs, topological_order); } @@ -487,9 +476,8 @@ bool StableTopologicalSort(const std::vector &nodes, return internal::TopologicalSortImpl(nodes, arcs, topological_order); } -inline std::vector -DenseIntTopologicalSortOrDie(int num_nodes, - const std::vector > &arcs) { +inline std::vector DenseIntTopologicalSortOrDie( + int num_nodes, const std::vector > &arcs) { return internal::DenseIntTopologicalSortOrDieImpl(num_nodes, arcs); } @@ -505,13 +493,12 @@ std::vector TopologicalSortOrDie(const std::vector &nodes, } template -std::vector -StableTopologicalSortOrDie(const std::vector &nodes, - const std::vector > &arcs) { +std::vector StableTopologicalSortOrDie( + const std::vector &nodes, const std::vector > &arcs) { return internal::TopologicalSortOrDieImpl(nodes, arcs); } -} // namespace util +} // namespace util // BACKWARDS COMPATIBILITY // Some of the classes or functions have been exposed under the global namespace @@ -519,19 +506,17 @@ StableTopologicalSortOrDie(const std::vector &nodes, // util:: namespace, we keep those versions around. typedef ::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter; typedef ::util::DenseIntTopologicalSorter DenseIntTopologicalSorter; -template < - typename T, bool stable_sort = false, - typename Hash = typename absl::flat_hash_map::hasher, - typename KeyEqual = typename absl::flat_hash_map::key_equal> +template ::hasher, + typename KeyEqual = + typename absl::flat_hash_map::key_equal> class TopologicalSorter - : public ::util::TopologicalSorter { -}; + : public ::util::TopologicalSorter {}; namespace util { namespace graph { -inline std::vector -DenseIntTopologicalSortOrDie(int num_nodes, - const std::vector > &arcs) { +inline std::vector DenseIntTopologicalSortOrDie( + int num_nodes, const std::vector > &arcs) { return ::util::DenseIntTopologicalSortOrDie(num_nodes, arcs); } inline std::vector DenseIntStableTopologicalSortOrDie( @@ -539,13 +524,12 @@ inline std::vector DenseIntStableTopologicalSortOrDie( return ::util::DenseIntStableTopologicalSortOrDie(num_nodes, arcs); } template -std::vector -StableTopologicalSortOrDie(const std::vector &nodes, - const std::vector > &arcs) { +std::vector StableTopologicalSortOrDie( + const std::vector &nodes, const std::vector > &arcs) { return ::util::StableTopologicalSortOrDie(nodes, arcs); } -} // namespace graph -} // namespace util +} // namespace graph +} // namespace util -#endif // UTIL_GRAPH_TOPOLOGICALSORTER_H__ +#endif // UTIL_GRAPH_TOPOLOGICALSORTER_H__ diff --git a/ortools/graph/util.cc b/ortools/graph/util.cc index 7647e44e9c..f39d8eba17 100644 --- a/ortools/graph/util.cc +++ b/ortools/graph/util.cc @@ -18,11 +18,10 @@ namespace util { bool IsSubsetOf0N(const std::vector &v, int n) { std::vector mask(n, false); for (const int i : v) { - if (i < 0 || i >= n || mask[i]) - return false; + if (i < 0 || i >= n || mask[i]) return false; mask[i] = true; } return true; } -} // namespace util +} // namespace util diff --git a/ortools/graph/util.h b/ortools/graph/util.h index eeebd32459..9c80dbcf26 100644 --- a/ortools/graph/util.h +++ b/ortools/graph/util.h @@ -48,13 +48,18 @@ namespace util { // If the graph is a "static" kind, they must be finalized, except for // GraphHasSelfArcs() and GraphIsWeaklyConnected() which also support // non-finalized StaticGraph<>. -template bool GraphHasSelfArcs(const Graph &graph); -template bool GraphHasDuplicateArcs(const Graph &graph); -template bool GraphIsSymmetric(const Graph &graph); -template bool GraphIsWeaklyConnected(const Graph &graph); +template +bool GraphHasSelfArcs(const Graph &graph); +template +bool GraphHasDuplicateArcs(const Graph &graph); +template +bool GraphIsSymmetric(const Graph &graph); +template +bool GraphIsWeaklyConnected(const Graph &graph); // Returns a fresh copy of a given graph. -template std::unique_ptr CopyGraph(const Graph &graph); +template +std::unique_ptr CopyGraph(const Graph &graph); // Creates a remapped copy of graph "graph", where node i becomes node // new_node_index[i]. @@ -90,14 +95,15 @@ std::unique_ptr GetSubgraphOfNodes(const Graph &graph, // ... // UndirectedAdjacencyListsOfDirectedGraph ugraph(dgraph); // for (int neighbor_of_node_42 : ugraph[42]) { ... } -template class UndirectedAdjacencyListsOfDirectedGraph { -public: +template +class UndirectedAdjacencyListsOfDirectedGraph { + public: explicit UndirectedAdjacencyListsOfDirectedGraph(const Graph &graph) : graph_(graph) {} typedef typename Graph::OutgoingOrOppositeIncomingArcIterator ArcIterator; class AdjacencyListIterator : public ArcIterator { - public: + public: explicit AdjacencyListIterator(const Graph &graph, ArcIterator &&arc_it) : ArcIterator(arc_it), graph_(graph) {} // Overwrite operator* to return the heads of the arcs. @@ -105,18 +111,18 @@ public: return graph_.Head(ArcIterator::operator*()); } - private: + private: const Graph &graph_; }; // Returns a pseudo-container of all the nodes adjacent to "node". BeginEndWrapper operator[](int node) const { const auto &arc_range = graph_.OutgoingOrOppositeIncomingArcs(node); - return { AdjacencyListIterator(graph_, arc_range.begin()), - AdjacencyListIterator(graph_, arc_range.end()) }; + return {AdjacencyListIterator(graph_, arc_range.begin()), + AdjacencyListIterator(graph_, arc_range.end())}; } -private: + private: const Graph &graph_; }; @@ -181,23 +187,23 @@ std::vector ComputeOnePossibleReverseArcMapping(const Graph &graph, // Implementations of the templated methods. -template bool GraphHasSelfArcs(const Graph &graph) { +template +bool GraphHasSelfArcs(const Graph &graph) { for (const auto arc : graph.AllForwardArcs()) { - if (graph.Tail(arc) == graph.Head(arc)) - return true; + if (graph.Tail(arc) == graph.Head(arc)) return true; } return false; } -template bool GraphHasDuplicateArcs(const Graph &graph) { +template +bool GraphHasDuplicateArcs(const Graph &graph) { typedef typename Graph::ArcIndex ArcIndex; typedef typename Graph::NodeIndex NodeIndex; std::vector tmp_node_mask(graph.num_nodes(), false); for (const NodeIndex tail : graph.AllNodes()) { for (const ArcIndex arc : graph.OutgoingArcs(tail)) { const NodeIndex head = graph.Head(arc); - if (tmp_node_mask[head]) - return true; + if (tmp_node_mask[head]) return true; tmp_node_mask[head] = true; } for (const ArcIndex arc : graph.OutgoingArcs(tail)) { @@ -207,7 +213,8 @@ template bool GraphHasDuplicateArcs(const Graph &graph) { return false; } -template bool GraphIsSymmetric(const Graph &graph) { +template +bool GraphIsSymmetric(const Graph &graph) { typedef typename Graph::NodeIndex NodeIndex; typedef typename Graph::ArcIndex ArcIndex; // Create a reverse copy of the graph. @@ -226,25 +233,23 @@ template bool GraphIsSymmetric(const Graph &graph) { ++count[graph.Head(arc)]; } for (const ArcIndex arc : reverse_graph.OutgoingArcs(node)) { - if (--count[reverse_graph.Head(arc)] < 0) - return false; + if (--count[reverse_graph.Head(arc)] < 0) return false; } for (const ArcIndex arc : graph.OutgoingArcs(node)) { - if (count[graph.Head(arc)] != 0) - return false; + if (count[graph.Head(arc)] != 0) return false; } } return true; } -template bool GraphIsWeaklyConnected(const Graph &graph) { +template +bool GraphIsWeaklyConnected(const Graph &graph) { typedef typename Graph::NodeIndex NodeIndex; static_assert(std::numeric_limits::max() <= INT_MAX, "GraphIsWeaklyConnected() isn't yet implemented for graphs" " that support more than INT_MAX nodes. Reach out to" " or-core-team@ if you need this."); - if (graph.num_nodes() == 0) - return true; + if (graph.num_nodes() == 0) return true; DenseConnectedComponentsFinder union_find; union_find.SetNumberOfNodes(graph.num_nodes()); for (typename Graph::ArcIndex arc = 0; arc < graph.num_arcs(); ++arc) { @@ -253,7 +258,8 @@ template bool GraphIsWeaklyConnected(const Graph &graph) { return union_find.GetNumberOfComponents() == 1; } -template std::unique_ptr CopyGraph(const Graph &graph) { +template +std::unique_ptr CopyGraph(const Graph &graph) { std::unique_ptr new_graph( new Graph(graph.num_nodes(), graph.num_arcs())); for (const auto node : graph.AllNodes()) { @@ -299,8 +305,7 @@ std::unique_ptr GetSubgraphOfNodes(const Graph &old_graph, ArcIndex num_arcs = 0; for (const NodeIndex node : nodes) { for (const ArcIndex arc : old_graph.OutgoingArcs(node)) { - if (new_node_index[old_graph.Head(arc)] != -1) - ++num_arcs; + if (new_node_index[old_graph.Head(arc)] != -1) ++num_arcs; } } // A second pass where we actually copy the subgraph. @@ -312,8 +317,7 @@ std::unique_ptr GetSubgraphOfNodes(const Graph &old_graph, const NodeIndex old_tail = nodes[new_tail]; for (const ArcIndex arc : old_graph.OutgoingArcs(old_tail)) { const NodeIndex new_head = new_node_index[old_graph.Head(arc)]; - if (new_head != -1) - new_graph->AddArc(new_tail, new_head); + if (new_head != -1) new_graph->AddArc(new_tail, new_head); } } new_graph->Build(); @@ -344,13 +348,11 @@ std::unique_ptr RemoveSelfArcsAndDuplicateArcs(const Graph &graph) { template void RemoveCyclesFromPath(const Graph &graph, std::vector *arc_path) { - if (arc_path->empty()) - return; + if (arc_path->empty()) return; // This maps each node to the latest arc in the given path that leaves it. std::map last_arc_leaving_node; - for (const int arc : *arc_path) - last_arc_leaving_node[graph.Tail(arc)] = arc; + for (const int arc : *arc_path) last_arc_leaving_node[graph.Tail(arc)] = arc; // Special case for the destination. // Note that this requires that -1 is not a valid arc of Graph. @@ -360,10 +362,9 @@ void RemoveCyclesFromPath(const Graph &graph, std::vector *arc_path) { // "next" arcs. We override the given arc_path at the same time. int node = graph.Tail(arc_path->front()); int new_size = 0; - while (new_size < arc_path->size()) { // To prevent cycle on bad input. + while (new_size < arc_path->size()) { // To prevent cycle on bad input. const int arc = gtl::FindOrDie(last_arc_leaving_node, node); - if (arc == -1) - break; + if (arc == -1) break; (*arc_path)[new_size++] = arc; node = graph.Head(arc); } @@ -372,27 +373,25 @@ void RemoveCyclesFromPath(const Graph &graph, std::vector *arc_path) { template bool PathHasCycle(const Graph &graph, const std::vector &arc_path) { - if (arc_path.empty()) - return false; + if (arc_path.empty()) return false; std::set seen; seen.insert(graph.Tail(arc_path.front())); for (const int arc : arc_path) { - if (!gtl::InsertIfNotPresent(&seen, graph.Head(arc))) - return true; + if (!gtl::InsertIfNotPresent(&seen, graph.Head(arc))) return true; } return false; } template -std::vector -ComputeOnePossibleReverseArcMapping(const Graph &graph, - bool die_if_not_symmetric) { +std::vector ComputeOnePossibleReverseArcMapping( + const Graph &graph, bool die_if_not_symmetric) { std::vector reverse_arc(graph.num_arcs(), -1); // We need a multi-map since a given (tail,head) may appear several times. // NOTE(user): It's free, in terms of space, to use InlinedVector // rather than std::vector. See go/inlined-vector-size. absl::flat_hash_map, - absl::InlinedVector > arc_map; + absl::InlinedVector > + arc_map; for (int arc = 0; arc < graph.num_arcs(); ++arc) { const int tail = graph.Tail(arc); @@ -402,10 +401,8 @@ ComputeOnePossibleReverseArcMapping(const Graph &graph, reverse_arc[arc] = arc; continue; } - // Lookup for the reverse arc of the current one... - auto it = arc_map.find({ - head, tail - }); + // Lookup for the reverse arc of the current one... + auto it = arc_map.find({head, tail}); if (it != arc_map.end()) { // Found a reverse arc! Store the mapping and remove the // reverse arc from the map. @@ -418,9 +415,7 @@ ComputeOnePossibleReverseArcMapping(const Graph &graph, } } else { // Reverse arc not in the map. Add the current arc to the map. - arc_map[{ - tail, head - }].push_back(arc); + arc_map[{tail, head}].push_back(arc); } } // Algorithm check, for debugging. @@ -440,6 +435,6 @@ ComputeOnePossibleReverseArcMapping(const Graph &graph, return reverse_arc; } -} // namespace util +} // namespace util -#endif // UTIL_GRAPH_UTIL_H_ +#endif // UTIL_GRAPH_UTIL_H_ diff --git a/ortools/gscip/gscip.cc b/ortools/gscip/gscip.cc index 773e19237b..19bb8d7bce 100644 --- a/ortools/gscip/gscip.cc +++ b/ortools/gscip/gscip.cc @@ -34,9 +34,9 @@ namespace operations_research { -#define RETURN_ERROR_UNLESS(x) \ - if (!(x)) \ - return util::StatusBuilder(absl::InvalidArgumentError(absl::StrFormat( \ +#define RETURN_ERROR_UNLESS(x) \ + if (!(x)) \ + return util::StatusBuilder(absl::InvalidArgumentError(absl::StrFormat( \ "Condition violated at %s:%d: %s", __FILE__, __LINE__, #x))) namespace { @@ -45,112 +45,112 @@ constexpr absl::string_view kLinearConstraintHandlerName = "linear"; SCIP_VARTYPE ConvertVarType(const GScipVarType var_type) { switch (var_type) { - case GScipVarType::kContinuous: - return SCIP_VARTYPE_CONTINUOUS; - case GScipVarType::kImpliedInteger: - return SCIP_VARTYPE_IMPLINT; - case GScipVarType::kInteger: - return SCIP_VARTYPE_INTEGER; + case GScipVarType::kContinuous: + return SCIP_VARTYPE_CONTINUOUS; + case GScipVarType::kImpliedInteger: + return SCIP_VARTYPE_IMPLINT; + case GScipVarType::kInteger: + return SCIP_VARTYPE_INTEGER; } } GScipVarType ConvertVarType(const SCIP_VARTYPE var_type) { switch (var_type) { - case SCIP_VARTYPE_CONTINUOUS: - return GScipVarType::kContinuous; - case SCIP_VARTYPE_IMPLINT: - return GScipVarType::kImpliedInteger; - case SCIP_VARTYPE_INTEGER: - case SCIP_VARTYPE_BINARY: - return GScipVarType::kInteger; + case SCIP_VARTYPE_CONTINUOUS: + return GScipVarType::kContinuous; + case SCIP_VARTYPE_IMPLINT: + return GScipVarType::kImpliedInteger; + case SCIP_VARTYPE_INTEGER: + case SCIP_VARTYPE_BINARY: + return GScipVarType::kInteger; } } GScipOutput::Status ConvertStatus(const SCIP_STATUS scip_status) { switch (scip_status) { - case SCIP_STATUS_UNKNOWN: - return GScipOutput::UNKNOWN; - case SCIP_STATUS_USERINTERRUPT: - return GScipOutput::USER_INTERRUPT; - case SCIP_STATUS_BESTSOLLIMIT: - return GScipOutput::BEST_SOL_LIMIT; - case SCIP_STATUS_MEMLIMIT: - return GScipOutput::MEM_LIMIT; - case SCIP_STATUS_NODELIMIT: - return GScipOutput::NODE_LIMIT; - case SCIP_STATUS_RESTARTLIMIT: - return GScipOutput::RESTART_LIMIT; - case SCIP_STATUS_SOLLIMIT: - return GScipOutput::SOL_LIMIT; - case SCIP_STATUS_STALLNODELIMIT: - return GScipOutput::STALL_NODE_LIMIT; - case SCIP_STATUS_TIMELIMIT: - return GScipOutput::TIME_LIMIT; - case SCIP_STATUS_TOTALNODELIMIT: - return GScipOutput::TOTAL_NODE_LIMIT; - case SCIP_STATUS_OPTIMAL: - return GScipOutput::OPTIMAL; - case SCIP_STATUS_GAPLIMIT: - return GScipOutput::GAP_LIMIT; - case SCIP_STATUS_INFEASIBLE: - return GScipOutput::INFEASIBLE; - case SCIP_STATUS_UNBOUNDED: - return GScipOutput::UNBOUNDED; - case SCIP_STATUS_INFORUNBD: - return GScipOutput::INF_OR_UNBD; - case SCIP_STATUS_TERMINATE: - return GScipOutput::TERMINATE; - default: - LOG(FATAL) << "Unrecognized scip status: " << scip_status; + case SCIP_STATUS_UNKNOWN: + return GScipOutput::UNKNOWN; + case SCIP_STATUS_USERINTERRUPT: + return GScipOutput::USER_INTERRUPT; + case SCIP_STATUS_BESTSOLLIMIT: + return GScipOutput::BEST_SOL_LIMIT; + case SCIP_STATUS_MEMLIMIT: + return GScipOutput::MEM_LIMIT; + case SCIP_STATUS_NODELIMIT: + return GScipOutput::NODE_LIMIT; + case SCIP_STATUS_RESTARTLIMIT: + return GScipOutput::RESTART_LIMIT; + case SCIP_STATUS_SOLLIMIT: + return GScipOutput::SOL_LIMIT; + case SCIP_STATUS_STALLNODELIMIT: + return GScipOutput::STALL_NODE_LIMIT; + case SCIP_STATUS_TIMELIMIT: + return GScipOutput::TIME_LIMIT; + case SCIP_STATUS_TOTALNODELIMIT: + return GScipOutput::TOTAL_NODE_LIMIT; + case SCIP_STATUS_OPTIMAL: + return GScipOutput::OPTIMAL; + case SCIP_STATUS_GAPLIMIT: + return GScipOutput::GAP_LIMIT; + case SCIP_STATUS_INFEASIBLE: + return GScipOutput::INFEASIBLE; + case SCIP_STATUS_UNBOUNDED: + return GScipOutput::UNBOUNDED; + case SCIP_STATUS_INFORUNBD: + return GScipOutput::INF_OR_UNBD; + case SCIP_STATUS_TERMINATE: + return GScipOutput::TERMINATE; + default: + LOG(FATAL) << "Unrecognized scip status: " << scip_status; } } SCIP_PARAMEMPHASIS ConvertEmphasis(const GScipParameters::Emphasis gscip_emphasis) { switch (gscip_emphasis) { - case GScipParameters::DEFAULT_EMPHASIS: - return SCIP_PARAMEMPHASIS_DEFAULT; - case GScipParameters::CP_SOLVER: - return SCIP_PARAMEMPHASIS_CPSOLVER; - case GScipParameters::EASY_CIP: - return SCIP_PARAMEMPHASIS_EASYCIP; - case GScipParameters::FEASIBILITY: - return SCIP_PARAMEMPHASIS_FEASIBILITY; - case GScipParameters::HARD_LP: - return SCIP_PARAMEMPHASIS_HARDLP; - case GScipParameters::OPTIMALITY: - return SCIP_PARAMEMPHASIS_OPTIMALITY; - case GScipParameters::COUNTER: - return SCIP_PARAMEMPHASIS_COUNTER; - case GScipParameters::PHASE_FEAS: - return SCIP_PARAMEMPHASIS_PHASEFEAS; - case GScipParameters::PHASE_IMPROVE: - return SCIP_PARAMEMPHASIS_PHASEIMPROVE; - case GScipParameters::PHASE_PROOF: - return SCIP_PARAMEMPHASIS_PHASEPROOF; - default: - LOG(FATAL) - << "Unrecognized gscip_emphasis: " << ProtoEnumToString(gscip_emphasis); + case GScipParameters::DEFAULT_EMPHASIS: + return SCIP_PARAMEMPHASIS_DEFAULT; + case GScipParameters::CP_SOLVER: + return SCIP_PARAMEMPHASIS_CPSOLVER; + case GScipParameters::EASY_CIP: + return SCIP_PARAMEMPHASIS_EASYCIP; + case GScipParameters::FEASIBILITY: + return SCIP_PARAMEMPHASIS_FEASIBILITY; + case GScipParameters::HARD_LP: + return SCIP_PARAMEMPHASIS_HARDLP; + case GScipParameters::OPTIMALITY: + return SCIP_PARAMEMPHASIS_OPTIMALITY; + case GScipParameters::COUNTER: + return SCIP_PARAMEMPHASIS_COUNTER; + case GScipParameters::PHASE_FEAS: + return SCIP_PARAMEMPHASIS_PHASEFEAS; + case GScipParameters::PHASE_IMPROVE: + return SCIP_PARAMEMPHASIS_PHASEIMPROVE; + case GScipParameters::PHASE_PROOF: + return SCIP_PARAMEMPHASIS_PHASEPROOF; + default: + LOG(FATAL) << "Unrecognized gscip_emphasis: " + << ProtoEnumToString(gscip_emphasis); } } SCIP_PARAMSETTING ConvertMetaParamValue( const GScipParameters::MetaParamValue gscip_meta_param_value) { switch (gscip_meta_param_value) { - case GScipParameters::DEFAULT_META_PARAM_VALUE: - return SCIP_PARAMSETTING_DEFAULT; - case GScipParameters::AGGRESSIVE: - return SCIP_PARAMSETTING_AGGRESSIVE; - case GScipParameters::FAST: - return SCIP_PARAMSETTING_FAST; - case GScipParameters::OFF: - return SCIP_PARAMSETTING_OFF; - default: - LOG(FATAL) << "Unrecognized gscip_meta_param_value: " - << ProtoEnumToString(gscip_meta_param_value); + case GScipParameters::DEFAULT_META_PARAM_VALUE: + return SCIP_PARAMSETTING_DEFAULT; + case GScipParameters::AGGRESSIVE: + return SCIP_PARAMSETTING_AGGRESSIVE; + case GScipParameters::FAST: + return SCIP_PARAMSETTING_FAST; + case GScipParameters::OFF: + return SCIP_PARAMSETTING_OFF; + default: + LOG(FATAL) << "Unrecognized gscip_meta_param_value: " + << ProtoEnumToString(gscip_meta_param_value); } } -} // namespace +} // namespace const GScipVariableOptions &DefaultGScipVariableOptions() { static GScipVariableOptions var_options; @@ -215,8 +215,8 @@ absl::Status GScip::SetParams(const GScipParameters ¶ms, return absl::OkStatus(); } -absl::StatusOr > -GScip::Create(const std::string &problem_name) { +absl::StatusOr > GScip::Create( + const std::string &problem_name) { SCIP *scip = nullptr; RETURN_IF_SCIP_ERROR(SCIPcreate(&scip)); RETURN_IF_SCIP_ERROR(SCIPincludeDefaultPlugins(scip)); @@ -268,16 +268,15 @@ GScip::~GScip() { LOG_IF(DFATAL, !clean_up_status.ok()) << clean_up_status; } -absl::StatusOr -GScip::AddVariable(double lb, double ub, double obj_coef, GScipVarType var_type, - const std::string &var_name, - const GScipVariableOptions &options) { +absl::StatusOr GScip::AddVariable( + double lb, double ub, double obj_coef, GScipVarType var_type, + const std::string &var_name, const GScipVariableOptions &options) { SCIP_VAR *var = nullptr; lb = ScipInfClamp(lb); ub = ScipInfClamp(ub); RETURN_IF_SCIP_ERROR(SCIPcreateVarBasic( - scip_, /*var=*/ &var, /*name=*/ var_name.c_str(), /*lb=*/ lb, /*ub=*/ ub, - /*obj=*/ obj_coef, ConvertVarType(var_type))); + scip_, /*var=*/&var, /*name=*/var_name.c_str(), /*lb=*/lb, /*ub=*/ub, + /*obj=*/obj_coef, ConvertVarType(var_type))); RETURN_IF_SCIP_ERROR(SCIPvarSetInitial(var, options.initial)); RETURN_IF_SCIP_ERROR(SCIPvarSetRemovable(var, options.removable)); RETURN_IF_SCIP_ERROR(SCIPaddVar(scip_, var)); @@ -289,9 +288,8 @@ GScip::AddVariable(double lb, double ub, double obj_coef, GScipVarType var_type, return var; } -absl::Status -GScip::MaybeKeepConstraintAlive(SCIP_CONS *constraint, - const GScipConstraintOptions &options) { +absl::Status GScip::MaybeKeepConstraintAlive( + SCIP_CONS *constraint, const GScipConstraintOptions &options) { if (options.keep_alive) { constraints_.insert(constraint); } else { @@ -300,10 +298,9 @@ GScip::MaybeKeepConstraintAlive(SCIP_CONS *constraint, return absl::OkStatus(); } -absl::StatusOr -GScip::AddLinearConstraint(const GScipLinearRange &range, - const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddLinearConstraint( + const GScipLinearRange &range, const std::string &name, + const GScipConstraintOptions &options) { SCIP_CONS *constraint = nullptr; RETURN_ERROR_UNLESS(range.variables.size() == range.coefficients.size()) << "Error adding constraint: " << name << "."; @@ -312,21 +309,20 @@ GScip::AddLinearConstraint(const GScipLinearRange &range, const_cast(range.variables.data()), const_cast(range.coefficients.data()), ScipInfClamp(range.lower_bound), ScipInfClamp(range.upper_bound), - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*modifiable=*/ options.modifiable, /*dynamic=*/ options.dynamic, - /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*modifiable=*/options.modifiable, /*dynamic=*/options.dynamic, + /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; } -absl::StatusOr -GScip::AddQuadraticConstraint(const GScipQuadraticRange &range, - const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddQuadraticConstraint( + const GScipQuadraticRange &range, const std::string &name, + const GScipConstraintOptions &options) { SCIP_CONS *constraint = nullptr; const int num_lin_vars = range.linear_variables.size(); RETURN_ERROR_UNLESS(num_lin_vars == range.linear_coefficients.size()) @@ -344,11 +340,11 @@ GScip::AddQuadraticConstraint(const GScipQuadraticRange &range, const_cast(range.quadratic_variables2.data()), const_cast(range.quadratic_coefficients.data()), ScipInfClamp(range.lower_bound), ScipInfClamp(range.upper_bound), - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*modifiable=*/ options.modifiable, /*dynamic=*/ options.dynamic, - /*removable=*/ options.removable)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*modifiable=*/options.modifiable, /*dynamic=*/options.dynamic, + /*removable=*/options.removable)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; @@ -374,20 +370,19 @@ absl::StatusOr GScip::AddIndicatorConstraint( const_cast(indicator_constraint.variables.data()), const_cast(indicator_constraint.coefficients.data()), ScipInfClamp(indicator_constraint.upper_bound), - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*dynamic=*/ options.dynamic, /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*dynamic=*/options.dynamic, /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; } -absl::StatusOr -GScip::AddAndConstraint(const GScipLogicalConstraintData &logical_data, - const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddAndConstraint( + const GScipLogicalConstraintData &logical_data, const std::string &name, + const GScipConstraintOptions &options) { RETURN_ERROR_UNLESS(logical_data.resultant != nullptr) << "Error adding and constraint: " << name << "."; SCIP_CONS *constraint = nullptr; @@ -395,21 +390,20 @@ GScip::AddAndConstraint(const GScipLogicalConstraintData &logical_data, scip_, &constraint, name.c_str(), logical_data.resultant, logical_data.operators.size(), const_cast(logical_data.operators.data()), - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*modifiable=*/ options.modifiable, /*dynamic=*/ options.dynamic, - /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*modifiable=*/options.modifiable, /*dynamic=*/options.dynamic, + /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; } -absl::StatusOr -GScip::AddOrConstraint(const GScipLogicalConstraintData &logical_data, - const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddOrConstraint( + const GScipLogicalConstraintData &logical_data, const std::string &name, + const GScipConstraintOptions &options) { RETURN_ERROR_UNLESS(logical_data.resultant != nullptr) << "Error adding or constraint: " << name << "."; SCIP_CONS *constraint = nullptr; @@ -417,12 +411,12 @@ GScip::AddOrConstraint(const GScipLogicalConstraintData &logical_data, scip_, &constraint, name.c_str(), logical_data.resultant, logical_data.operators.size(), const_cast(logical_data.operators.data()), - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*modifiable=*/ options.modifiable, /*dynamic=*/ options.dynamic, - /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*modifiable=*/options.modifiable, /*dynamic=*/options.dynamic, + /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; @@ -448,11 +442,11 @@ absl::Status ValidateSOSData(const GScipSOSData &sos_data, return absl::OkStatus(); } -} // namespace +} // namespace -absl::StatusOr -GScip::AddSOS1Constraint(const GScipSOSData &sos_data, const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddSOS1Constraint( + const GScipSOSData &sos_data, const std::string &name, + const GScipConstraintOptions &options) { RETURN_IF_ERROR(ValidateSOSData(sos_data, name)); SCIP_CONS *constraint = nullptr; double *weights = nullptr; @@ -463,19 +457,19 @@ GScip::AddSOS1Constraint(const GScipSOSData &sos_data, const std::string &name, RETURN_IF_SCIP_ERROR(SCIPcreateConsSOS1( scip_, &constraint, name.c_str(), sos_data.variables.size(), const_cast(sos_data.variables.data()), weights, - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*dynamic=*/ options.dynamic, /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*dynamic=*/options.dynamic, /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; } -absl::StatusOr -GScip::AddSOS2Constraint(const GScipSOSData &sos_data, const std::string &name, - const GScipConstraintOptions &options) { +absl::StatusOr GScip::AddSOS2Constraint( + const GScipSOSData &sos_data, const std::string &name, + const GScipConstraintOptions &options) { RETURN_IF_ERROR(ValidateSOSData(sos_data, name)); SCIP_CONS *constraint = nullptr; double *weights = nullptr; @@ -485,11 +479,11 @@ GScip::AddSOS2Constraint(const GScipSOSData &sos_data, const std::string &name, RETURN_IF_SCIP_ERROR(SCIPcreateConsSOS2( scip_, &constraint, name.c_str(), sos_data.variables.size(), const_cast(sos_data.variables.data()), weights, - /*initial=*/ options.initial, /*separate=*/ options.separate, - /*enforce=*/ options.enforce, /*check=*/ options.check, - /*propagate=*/ options.propagate, /*local=*/ options.local, - /*dynamic=*/ options.dynamic, /*removable=*/ options.removable, - /*stickingatnode=*/ options.sticking_at_node)); + /*initial=*/options.initial, /*separate=*/options.separate, + /*enforce=*/options.enforce, /*check=*/options.check, + /*propagate=*/options.propagate, /*local=*/options.local, + /*dynamic=*/options.dynamic, /*removable=*/options.removable, + /*stickingatnode=*/options.sticking_at_node)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint)); RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options)); return constraint; @@ -553,8 +547,8 @@ absl::Status GScip::DeleteVariable(SCIP_VAR *var) { return absl::OkStatus(); } -absl::Status -GScip::CanSafeBulkDelete(const absl::flat_hash_set &vars) { +absl::Status GScip::CanSafeBulkDelete( + const absl::flat_hash_set &vars) { for (SCIP_CONS *constraint : constraints_) { if (!IsConstraintLinear(constraint)) { return absl::InvalidArgumentError(absl::StrCat( @@ -564,8 +558,8 @@ GScip::CanSafeBulkDelete(const absl::flat_hash_set &vars) { return absl::OkStatus(); } -absl::Status -GScip::SafeBulkDelete(const absl::flat_hash_set &vars) { +absl::Status GScip::SafeBulkDelete( + const absl::flat_hash_set &vars) { RETURN_IF_ERROR(CanSafeBulkDelete(vars)); // Now, we can assume that all constraints are linear. for (SCIP_CONS *constraint : constraints_) { @@ -609,14 +603,14 @@ bool GScip::IsConstraintLinear(SCIP_CONS *constraint) { return ConstraintType(constraint) == kLinearConstraintHandlerName; } -absl::Span -GScip::LinearConstraintCoefficients(SCIP_CONS *constraint) { +absl::Span GScip::LinearConstraintCoefficients( + SCIP_CONS *constraint) { int num_vars = SCIPgetNVarsLinear(scip_, constraint); return absl::MakeConstSpan(SCIPgetValsLinear(scip_, constraint), num_vars); } -absl::Span -GScip::LinearConstraintVariables(SCIP_CONS *constraint) { +absl::Span GScip::LinearConstraintVariables( + SCIP_CONS *constraint) { int num_vars = SCIPgetNVarsLinear(scip_, constraint); return absl::MakeConstSpan(SCIPgetVarsLinear(scip_, constraint), num_vars); } @@ -661,8 +655,8 @@ absl::Status GScip::SetLinearConstraintCoef(SCIP_CONS *constraint, return absl::OkStatus(); } -absl::StatusOr -GScip::SuggestHint(const GScipSolution &partial_solution) { +absl::StatusOr GScip::SuggestHint( + const GScipSolution &partial_solution) { SCIP_SOL *solution; const int scip_num_vars = SCIPgetNOrigVars(scip_); const bool is_solution_partial = partial_solution.size() < scip_num_vars; @@ -681,9 +675,9 @@ GScip::SuggestHint(const GScipSolution &partial_solution) { if (!is_solution_partial) { SCIP_Bool is_feasible; RETURN_IF_SCIP_ERROR(SCIPcheckSol( - scip_, solution, /*printreason=*/ false, /*completely=*/ true, - /*checkbounds=*/ true, /*checkintegrality=*/ true, - /*checklprows=*/ true, &is_feasible)); + scip_, solution, /*printreason=*/false, /*completely=*/true, + /*checkbounds=*/true, /*checkintegrality=*/true, + /*checklprows=*/true, &is_feasible)); if (!static_cast(is_feasible)) { RETURN_IF_SCIP_ERROR(SCIPfreeSol(scip_, &solution)); return GScipHintResult::kInfeasible; @@ -713,8 +707,8 @@ absl::StatusOr GScip::Solve(const GScipParameters ¶ms, if (!param_status.ok()) { result.gscip_output.set_status(GScipOutput::INVALID_SOLVER_PARAMETERS); // Conversion to std::string for open source build. - result.gscip_output - .set_status_detail(std::string(param_status.message())); // NOLINT + result.gscip_output.set_status_detail( + std::string(param_status.message())); // NOLINT return result; } if (params.print_scip_model()) { @@ -756,10 +750,10 @@ absl::StatusOr GScip::Solve(const GScipParameters ¶ms, RETURN_IF_SCIP_ERROR(SCIPprintStatistics(scip_, file)); int close_result = fclose(file); if (close_result != 0) { - return absl::InvalidArgumentError( - absl::StrCat("Error: ", close_result, " closing file: ", - params.detailed_solving_stats_filename(), - " when writing solve stats.")); + return absl::InvalidArgumentError(absl::StrCat( + "Error: ", close_result, + " closing file: ", params.detailed_solving_stats_filename(), + " when writing solve stats.")); } } // Step 3: Extract solution information. @@ -806,48 +800,48 @@ absl::StatusOr GScip::Solve(const GScipParameters ¶ms, return result; } -absl::StatusOr -GScip::DefaultBoolParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultBoolParamValue( + const std::string ¶meter_name) { SCIP_Bool default_value; RETURN_IF_SCIP_ERROR( SCIPgetBoolParam(scip_, parameter_name.c_str(), &default_value)); return static_cast(default_value); } -absl::StatusOr -GScip::DefaultIntParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultIntParamValue( + const std::string ¶meter_name) { int default_value; RETURN_IF_SCIP_ERROR( SCIPgetIntParam(scip_, parameter_name.c_str(), &default_value)); return default_value; } -absl::StatusOr -GScip::DefaultLongParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultLongParamValue( + const std::string ¶meter_name) { SCIP_Longint result; RETURN_IF_SCIP_ERROR( SCIPgetLongintParam(scip_, parameter_name.c_str(), &result)); return static_cast(result); } -absl::StatusOr -GScip::DefaultRealParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultRealParamValue( + const std::string ¶meter_name) { double result; RETURN_IF_SCIP_ERROR( SCIPgetRealParam(scip_, parameter_name.c_str(), &result)); return result; } -absl::StatusOr -GScip::DefaultCharParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultCharParamValue( + const std::string ¶meter_name) { char result; RETURN_IF_SCIP_ERROR( SCIPgetCharParam(scip_, parameter_name.c_str(), &result)); return result; } -absl::StatusOr -GScip::DefaultStringParamValue(const std::string ¶meter_name) { +absl::StatusOr GScip::DefaultStringParamValue( + const std::string ¶meter_name) { char *result; RETURN_IF_SCIP_ERROR( SCIPgetStringParam(scip_, parameter_name.c_str(), &result)); @@ -856,22 +850,18 @@ GScip::DefaultStringParamValue(const std::string ¶meter_name) { double GScip::ScipInfClamp(double d) { const double kScipInf = ScipInf(); - if (d > kScipInf) - return kScipInf; - if (d < -kScipInf) - return -kScipInf; + if (d > kScipInf) return kScipInf; + if (d < -kScipInf) return -kScipInf; return d; } double GScip::ScipInfUnclamp(double d) { const double kScipInf = ScipInf(); - if (d >= kScipInf) - return std::numeric_limits::infinity(); - if (d <= -kScipInf) - return -std::numeric_limits::infinity(); + if (d >= kScipInf) return std::numeric_limits::infinity(); + if (d <= -kScipInf) return -std::numeric_limits::infinity(); return d; } #undef RETURN_ERROR_UNLESS -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/gscip/gscip.h b/ortools/gscip/gscip.h index d950ca7e87..883025e183 100644 --- a/ortools/gscip/gscip.h +++ b/ortools/gscip/gscip.h @@ -100,9 +100,7 @@ struct GScipLinearRange { // A variable is implied integer if the integrality constraint is not required // for the model to be valid, but the variable takes an integer value in any // optimal solution to the problem. -enum class GScipVarType { - kContinuous, kInteger, kImpliedInteger -}; +enum class GScipVarType { kContinuous, kInteger, kImpliedInteger }; // Some advanced features, defined at the end of the header file. struct GScipQuadraticRange; @@ -120,11 +118,11 @@ enum class GScipHintResult; // idiomatic for Google. Unless callbacks are used, the SCIP stage is always // PROBLEM. class GScip { -public: + public: // Create a new GScip (the constructor is private). The default objective // direction is minimization. - static absl::StatusOr > - Create(const std::string &problem_name); + static absl::StatusOr > Create( + const std::string &problem_name); ~GScip(); static std::string ScipVersion(); @@ -137,9 +135,9 @@ public: // * There is an I/O error with managing SCIP output. // The above cases are not mutually exclusive. If the problem is infeasible, // this will be reflected in the value of GScipResult::gscip_output::status. - absl::StatusOr Solve(const GScipParameters ¶ms = - GScipParameters(), - const std::string &legacy_params = ""); + absl::StatusOr Solve( + const GScipParameters ¶ms = GScipParameters(), + const std::string &legacy_params = ""); // /////////////////////////////////////////////////////////////////////////// // Basic Model Construction @@ -153,11 +151,10 @@ public: // returned variable will have the same lifetime as GScip (if instead, // GScipVariableOptions::keep_alive is false, SCIP may free the variable at // any time, see GScipVariableOptions::keep_alive for details). - absl::StatusOr AddVariable(double lb, double ub, double obj_coef, - GScipVarType var_type, - const std::string &var_name = "", - const GScipVariableOptions &options = - DefaultGScipVariableOptions()); + absl::StatusOr AddVariable( + double lb, double ub, double obj_coef, GScipVarType var_type, + const std::string &var_name = "", + const GScipVariableOptions &options = DefaultGScipVariableOptions()); // The returned SCIP_CONS is owned by GScip. With default options, the // returned variable will have the same lifetime as GScip (if instead, @@ -261,21 +258,19 @@ public: // logical_data.resultant = AND_i logical_data.operators[i], // where logical_data.resultant and logical_data.operators[i] are all binary // variables. - absl::StatusOr - AddAndConstraint(const GScipLogicalConstraintData &logical_data, - const std::string &name = "", - const GScipConstraintOptions &options = - DefaultGScipConstraintOptions()); + absl::StatusOr AddAndConstraint( + const GScipLogicalConstraintData &logical_data, + const std::string &name = "", + const GScipConstraintOptions &options = DefaultGScipConstraintOptions()); // Adds the constraint: // logical_data.resultant = OR_i logical_data.operators[i], // where logical_data.resultant and logical_data.operators[i] must be binary // variables. - absl::StatusOr - AddOrConstraint(const GScipLogicalConstraintData &logical_data, - const std::string &name = "", - const GScipConstraintOptions &options = - DefaultGScipConstraintOptions()); + absl::StatusOr AddOrConstraint( + const GScipLogicalConstraintData &logical_data, + const std::string &name = "", + const GScipConstraintOptions &options = DefaultGScipConstraintOptions()); // Adds the constraint that at most one of the variables in sos_data can be // nonzero. The variables can be integer or continuous. See GScipSOSData for @@ -308,8 +303,8 @@ public: // or complete. Complete solutions will be checked for feasibility and // objective quality, and might be unused for these reasons. Partial solutions // will always be accepted. - absl::StatusOr - SuggestHint(const GScipSolution &partial_solution); + absl::StatusOr SuggestHint( + const GScipSolution &partial_solution); // All variables have a default branching priority of zero. Variables are // partitioned by their branching priority, and a fractional variable from the @@ -337,15 +332,15 @@ public: absl::StatusOr DefaultBoolParamValue(const std::string ¶meter_name); absl::StatusOr DefaultIntParamValue(const std::string ¶meter_name); - absl::StatusOr - DefaultLongParamValue(const std::string ¶meter_name); - absl::StatusOr - DefaultRealParamValue(const std::string ¶meter_name); + absl::StatusOr DefaultLongParamValue( + const std::string ¶meter_name); + absl::StatusOr DefaultRealParamValue( + const std::string ¶meter_name); absl::StatusOr DefaultCharParamValue(const std::string ¶meter_name); - absl::StatusOr - DefaultStringParamValue(const std::string ¶meter_name); + absl::StatusOr DefaultStringParamValue( + const std::string ¶meter_name); -private: + private: explicit GScip(SCIP *scip); // Releases SCIP memory. absl::Status CleanUp(); @@ -448,11 +443,11 @@ struct GScipLogicalConstraintData { enum class GScipHintResult { // Hint was not feasible. kInfeasible, - // Hint was not good enough to keep. - kRejected, - // Hint was kept. Partial solutions are not checked for feasibility, they - // are always accepted. - kAccepted + // Hint was not good enough to keep. + kRejected, + // Hint was kept. Partial solutions are not checked for feasibility, they + // are always accepted. + kAccepted }; // Advanced use. Options to use when creating a variable. @@ -537,6 +532,6 @@ struct GScipConstraintOptions { bool keep_alive = true; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GSCIP_GSCIP_H_ +#endif // OR_TOOLS_GSCIP_GSCIP_H_ diff --git a/ortools/gscip/gscip_ext.cc b/ortools/gscip/gscip_ext.cc index 006f2637bd..f1a268bee1 100644 --- a/ortools/gscip/gscip_ext.cc +++ b/ortools/gscip/gscip_ext.cc @@ -28,7 +28,7 @@ std::string MaybeExtendName(const std::string &base_name, return absl::StrCat(base_name, "/", extension); } -} // namespace +} // namespace GScipLinearExpr::GScipLinearExpr(SCIP_VAR *variable) { terms[variable] = 1.0; } @@ -66,10 +66,8 @@ GScipLinearRange Le(const GScipLinearExpr left, const GScipLinearExpr &right) { absl::Status CreateAbs(GScip *gscip, SCIP_Var *x, SCIP_Var *abs_x, const std::string &name) { - return CreateMaximum(gscip, GScipLinearExpr(abs_x), { - GScipLinearExpr(x), Negate(GScipLinearExpr(x)) - }, - name); + return CreateMaximum(gscip, GScipLinearExpr(abs_x), + {GScipLinearExpr(x), Negate(GScipLinearExpr(x))}, name); } absl::Status CreateMaximum(GScip *gscip, const GScipLinearExpr &resultant, @@ -93,9 +91,12 @@ absl::Status CreateMaximum(GScip *gscip, const GScipLinearExpr &resultant, for (int i = 0; i < terms.size(); ++i) { // x_i <= y - RETURN_IF_ERROR(gscip->AddLinearConstraint( - Le(terms.at(i), resultant), - MaybeExtendName(name, absl::StrCat("x_", i, "_le_y"))).status()); + RETURN_IF_ERROR( + gscip + ->AddLinearConstraint( + Le(terms.at(i), resultant), + MaybeExtendName(name, absl::StrCat("x_", i, "_le_y"))) + .status()); // z_i => y <= x_i { GScipLinearRange y_less_x = Le(resultant, terms.at(i)); @@ -105,9 +106,12 @@ absl::Status CreateMaximum(GScip *gscip, const GScipLinearExpr &resultant, ind.variables = y_less_x.variables; ind.coefficients = y_less_x.coefficients; ind.upper_bound = y_less_x.upper_bound; - RETURN_IF_ERROR(gscip->AddIndicatorConstraint( - ind, MaybeExtendName(name, absl::StrCat("y_le__x_", i, "_if_z_", i))) - .status()); + RETURN_IF_ERROR( + gscip + ->AddIndicatorConstraint( + ind, MaybeExtendName( + name, absl::StrCat("y_le__x_", i, "_if_z_", i))) + .status()); } } @@ -146,8 +150,8 @@ absl::Status AddQuadraticObjectiveTerm( range.quadratic_variables1 = quadratic_variables1; range.quadratic_variables2 = quadratic_variables2; range.quadratic_coefficients = quadratic_coefficients; - range.linear_coefficients = { -1.0 }; - range.linear_variables = { *obj_term }; + range.linear_coefficients = {-1.0}; + range.linear_variables = {*obj_term}; if (gscip->ObjectiveIsMaximize()) { // maximize z // z <= Q(x, y) @@ -173,8 +177,10 @@ absl::Status CreateIndicatorRange( ub_constraint.coefficients = indicator_range.range.coefficients; ub_constraint.indicator_variable = indicator_range.indicator_variable; ub_constraint.negate_indicator = indicator_range.negate_indicator; - RETURN_IF_ERROR(gscip->AddIndicatorConstraint( - ub_constraint, MaybeExtendName(name, "ub"), options).status()); + RETURN_IF_ERROR(gscip + ->AddIndicatorConstraint( + ub_constraint, MaybeExtendName(name, "ub"), options) + .status()); } if (std::isfinite(indicator_range.range.lower_bound)) { // want z -> lb <= a * x @@ -187,10 +193,12 @@ absl::Status CreateIndicatorRange( } lb_constraint.indicator_variable = indicator_range.indicator_variable; lb_constraint.negate_indicator = indicator_range.negate_indicator; - RETURN_IF_ERROR(gscip->AddIndicatorConstraint( - lb_constraint, MaybeExtendName(name, "lb"), options).status()); + RETURN_IF_ERROR(gscip + ->AddIndicatorConstraint( + lb_constraint, MaybeExtendName(name, "lb"), options) + .status()); } return absl::OkStatus(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/gscip/gscip_ext.h b/ortools/gscip/gscip_ext.h index 2ca579f470..629ad7687e 100644 --- a/ortools/gscip/gscip_ext.h +++ b/ortools/gscip/gscip_ext.h @@ -99,6 +99,6 @@ absl::Status AddQuadraticObjectiveTerm( std::vector quadratic_variables2, std::vector quadratic_coefficients, const std::string &name = ""); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GSCIP_GSCIP_EXT_H_ +#endif // OR_TOOLS_GSCIP_GSCIP_EXT_H_ diff --git a/ortools/gscip/gscip_parameters.cc b/ortools/gscip/gscip_parameters.cc index ac0e71fdfd..7fcd88e27e 100644 --- a/ortools/gscip/gscip_parameters.cc +++ b/ortools/gscip/gscip_parameters.cc @@ -25,7 +25,7 @@ constexpr absl::string_view kLimitsTime = "limits/time"; constexpr absl::string_view kParallelMaxNThreads = "parallel/maxnthreads"; constexpr absl::string_view kDisplayVerbLevel = "display/verblevel"; constexpr absl::string_view kRandomSeedParam = "randomization/randomseedshift"; -} // namespace +} // namespace void SetTimeLimit(const absl::Duration time_limit, GScipParameters *parameters) { @@ -115,10 +115,10 @@ int RandomSeed(const GScipParameters ¶meters) { if (RandomSeedSet(parameters)) { return parameters.int_params().at(std::string(kRandomSeedParam)); } - return -1; // Unset value. + return -1; // Unset value. } bool RandomSeedSet(const GScipParameters ¶meters) { return parameters.int_params().contains(std::string(kRandomSeedParam)); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/gscip/gscip_parameters.h b/ortools/gscip/gscip_parameters.h index bf85790552..fc11e35b59 100644 --- a/ortools/gscip/gscip_parameters.h +++ b/ortools/gscip/gscip_parameters.h @@ -51,6 +51,6 @@ void SetRandomSeed(GScipParameters *parameters, int random_seed); int RandomSeed(const GScipParameters ¶meters); bool RandomSeedSet(const GScipParameters ¶meters); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_GSCIP_GSCIP_PARAMETERS_H_ +#endif // OR_TOOLS_GSCIP_GSCIP_PARAMETERS_H_ diff --git a/ortools/gscip/legacy_scip_params.cc b/ortools/gscip/legacy_scip_params.cc index ab43f83d40..a976b03e2d 100644 --- a/ortools/gscip/legacy_scip_params.cc +++ b/ortools/gscip/legacy_scip_params.cc @@ -28,9 +28,8 @@ namespace operations_research { -absl::Status -LegacyScipSetSolverSpecificParameters(const std::string ¶meters, - SCIP *scip) { +absl::Status LegacyScipSetSolverSpecificParameters( + const std::string ¶meters, SCIP *scip) { for (const auto parameter : absl::StrSplit(parameters, absl::ByAnyChar(",\n"), absl::SkipWhitespace())) { std::vector key_value = absl::StrSplit( @@ -54,59 +53,59 @@ LegacyScipSetSolverSpecificParameters(const std::string ¶meters, absl::StrFormat("Invalid parameter name '%s'", name)); } switch (param->paramtype) { - case SCIP_PARAMTYPE_BOOL: { - bool parsed_value; - if (absl::SimpleAtob(value, &parsed_value)) { + case SCIP_PARAMTYPE_BOOL: { + bool parsed_value; + if (absl::SimpleAtob(value, &parsed_value)) { + RETURN_IF_SCIP_ERROR( + SCIPsetBoolParam(scip, name.c_str(), parsed_value)); + continue; + } + break; + } + case SCIP_PARAMTYPE_INT: { + int parsed_value; + if (absl::SimpleAtoi(value, &parsed_value)) { + RETURN_IF_SCIP_ERROR( + SCIPsetIntParam(scip, name.c_str(), parsed_value)); + continue; + } + break; + } + case SCIP_PARAMTYPE_LONGINT: { + int64_t parsed_value; + if (absl::SimpleAtoi(value, &parsed_value)) { + RETURN_IF_SCIP_ERROR(SCIPsetLongintParam( + scip, name.c_str(), static_cast(parsed_value))); + continue; + } + break; + } + case SCIP_PARAMTYPE_REAL: { + double parsed_value; + if (absl::SimpleAtod(value, &parsed_value)) { + if (parsed_value > infinity) parsed_value = infinity; + RETURN_IF_SCIP_ERROR( + SCIPsetRealParam(scip, name.c_str(), parsed_value)); + continue; + } + break; + } + case SCIP_PARAMTYPE_CHAR: { + if (value.size() == 1) { + RETURN_IF_SCIP_ERROR(SCIPsetCharParam(scip, name.c_str(), value[0])); + continue; + } + break; + } + case SCIP_PARAMTYPE_STRING: { + if (value.front() == '"' && value.back() == '"') { + value.erase(value.begin()); + value.erase(value.end() - 1); + } RETURN_IF_SCIP_ERROR( - SCIPsetBoolParam(scip, name.c_str(), parsed_value)); + SCIPsetStringParam(scip, name.c_str(), value.c_str())); continue; } - break; - } - case SCIP_PARAMTYPE_INT: { - int parsed_value; - if (absl::SimpleAtoi(value, &parsed_value)) { - RETURN_IF_SCIP_ERROR(SCIPsetIntParam(scip, name.c_str(), parsed_value)); - continue; - } - break; - } - case SCIP_PARAMTYPE_LONGINT: { - int64_t parsed_value; - if (absl::SimpleAtoi(value, &parsed_value)) { - RETURN_IF_SCIP_ERROR(SCIPsetLongintParam( - scip, name.c_str(), static_cast(parsed_value))); - continue; - } - break; - } - case SCIP_PARAMTYPE_REAL: { - double parsed_value; - if (absl::SimpleAtod(value, &parsed_value)) { - if (parsed_value > infinity) - parsed_value = infinity; - RETURN_IF_SCIP_ERROR( - SCIPsetRealParam(scip, name.c_str(), parsed_value)); - continue; - } - break; - } - case SCIP_PARAMTYPE_CHAR: { - if (value.size() == 1) { - RETURN_IF_SCIP_ERROR(SCIPsetCharParam(scip, name.c_str(), value[0])); - continue; - } - break; - } - case SCIP_PARAMTYPE_STRING: { - if (value.front() == '"' && value.back() == '"') { - value.erase(value.begin()); - value.erase(value.end() - 1); - } - RETURN_IF_SCIP_ERROR( - SCIPsetStringParam(scip, name.c_str(), value.c_str())); - continue; - } } return absl::InvalidArgumentError( absl::StrFormat("Invalid parameter value '%s'", parameter)); @@ -114,4 +113,4 @@ LegacyScipSetSolverSpecificParameters(const std::string ¶meters, return absl::OkStatus(); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/gscip/legacy_scip_params.h b/ortools/gscip/legacy_scip_params.h index 97af433cf4..f0548fd9f0 100644 --- a/ortools/gscip/legacy_scip_params.h +++ b/ortools/gscip/legacy_scip_params.h @@ -22,9 +22,8 @@ namespace operations_research { -absl::Status - LegacyScipSetSolverSpecificParameters(const std::string ¶meters, - SCIP *scip); +absl::Status LegacyScipSetSolverSpecificParameters( + const std::string ¶meters, SCIP *scip); } -#endif // OR_TOOLS_GSCIP_LEGACY_SCIP_PARAMS_H_ +#endif // OR_TOOLS_GSCIP_LEGACY_SCIP_PARAMS_H_ diff --git a/ortools/linear_solver/bop_interface.cc b/ortools/linear_solver/bop_interface.cc index 50270d26b2..826b5bedbc 100644 --- a/ortools/linear_solver/bop_interface.cc +++ b/ortools/linear_solver/bop_interface.cc @@ -30,25 +30,25 @@ namespace { MPSolver::ResultStatus TranslateProblemStatus(bop::BopSolveStatus status) { switch (status) { - case bop::BopSolveStatus::OPTIMAL_SOLUTION_FOUND: - return MPSolver::OPTIMAL; - case bop::BopSolveStatus::FEASIBLE_SOLUTION_FOUND: - return MPSolver::FEASIBLE; - case bop::BopSolveStatus::NO_SOLUTION_FOUND: - return MPSolver::NOT_SOLVED; - case bop::BopSolveStatus::INFEASIBLE_PROBLEM: - return MPSolver::INFEASIBLE; - case bop::BopSolveStatus::INVALID_PROBLEM: - return MPSolver::ABNORMAL; + case bop::BopSolveStatus::OPTIMAL_SOLUTION_FOUND: + return MPSolver::OPTIMAL; + case bop::BopSolveStatus::FEASIBLE_SOLUTION_FOUND: + return MPSolver::FEASIBLE; + case bop::BopSolveStatus::NO_SOLUTION_FOUND: + return MPSolver::NOT_SOLVED; + case bop::BopSolveStatus::INFEASIBLE_PROBLEM: + return MPSolver::INFEASIBLE; + case bop::BopSolveStatus::INVALID_PROBLEM: + return MPSolver::ABNORMAL; } LOG(DFATAL) << "Invalid bop::BopSolveStatus"; return MPSolver::ABNORMAL; } -} // Anonymous namespace +} // Anonymous namespace class BopInterface : public MPSolverInterface { -public: + public: explicit BopInterface(MPSolver *const solver); ~BopInterface() override; @@ -99,10 +99,10 @@ public: void SetPresolveMode(int value) override; void SetScalingMode(int value) override; void SetLpAlgorithm(int value) override; - bool SetSolverSpecificParametersAsString(const std::string ¶meters) - override; + bool SetSolverSpecificParametersAsString( + const std::string ¶meters) override; -private: + private: void NonIncrementalChange(); glop::LinearProgram linear_program_; @@ -115,9 +115,13 @@ private: }; BopInterface::BopInterface(MPSolver *const solver) - : MPSolverInterface(solver), linear_program_(), bop_solver_(), - column_status_(), row_status_(), parameters_(), interrupt_solver_(false) { -} + : MPSolverInterface(solver), + linear_program_(), + bop_solver_(), + column_status_(), + row_status_(), + parameters_(), + interrupt_solver_(false) {} BopInterface::~BopInterface() {} @@ -358,16 +362,16 @@ void BopInterface::SetRelativeMipGap(double value) {} void BopInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_OFF: - // TODO(user): add this to BopParameters. - break; - case MPSolverParameters::PRESOLVE_ON: - // TODO(user): add this to BopParameters. - break; - default: - if (value != MPSolverParameters::kDefaultIntegerParamValue) { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); - } + case MPSolverParameters::PRESOLVE_OFF: + // TODO(user): add this to BopParameters. + break; + case MPSolverParameters::PRESOLVE_ON: + // TODO(user): add this to BopParameters. + break; + default: + if (value != MPSolverParameters::kDefaultIntegerParamValue) { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + } } } @@ -389,4 +393,4 @@ MPSolverInterface *BuildBopInterface(MPSolver *const solver) { return new BopInterface(solver); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/cbc_interface.cc b/ortools/linear_solver/cbc_interface.cc index f56a35f709..c0408c8aa8 100644 --- a/ortools/linear_solver/cbc_interface.cc +++ b/ortools/linear_solver/cbc_interface.cc @@ -43,7 +43,7 @@ namespace operations_research { class CBCInterface : public MPSolverInterface { -public: + public: // Constructor that takes a name for the underlying glpk solver. explicit CBCInterface(MPSolver *const solver); ~CBCInterface() override; @@ -133,7 +133,7 @@ public: // so it is not possible right now. void *underlying_solver() override { return reinterpret_cast(&osi_); } -private: + private: // Reset best objective bound to +/- infinity depending on the // optimization direction. void ResetBestObjectiveBound(); @@ -162,7 +162,9 @@ private: // Creates a LP/MIP instance with the specified name and minimization objective. CBCInterface::CBCInterface(MPSolver *const solver) - : MPSolverInterface(solver), iterations_(0), nodes_(0), + : MPSolverInterface(solver), + iterations_(0), + nodes_(0), best_objective_bound_(-std::numeric_limits::infinity()), relative_mip_gap_(MPSolverParameters::kDefaultRelativeMipGap) { osi_.setStrParam(OsiProbName, solver_->name_); @@ -199,7 +201,7 @@ void CBCInterface::SetOptimizationDirection(bool maximize) { namespace { // CBC adds a "dummy" variable with index 0 to represent the objective offset. int MPSolverVarIndexToCbcVarIndex(int var_index) { return var_index + 1; } -} // namespace +} // namespace void CBCInterface::SetVariableBounds(int var_index, double lb, double ub) { InvalidateSolutionSynchronization(); @@ -276,60 +278,64 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters ¶m) { // Finish preparing the problem. // Define variables. switch (sync_status_) { - case MUST_RELOAD: { - Reset(); - CoinModel build; - // Create dummy variable for objective offset. - build.addColumn(0, nullptr, nullptr, 1.0, 1.0, - solver_->Objective().offset(), "dummy", false); - const int nb_vars = solver_->variables_.size(); - for (int i = 0; i < nb_vars; ++i) { - MPVariable *const var = solver_->variables_[i]; - set_variable_as_extracted(i, true); - const double obj_coeff = solver_->Objective().GetCoefficient(var); - if (var->name().empty()) { - build.addColumn(0, nullptr, nullptr, var->lb(), var->ub(), obj_coeff, - nullptr, var->integer()); - } else { - build.addColumn(0, nullptr, nullptr, var->lb(), var->ub(), obj_coeff, - var->name().c_str(), var->integer()); + case MUST_RELOAD: { + Reset(); + CoinModel build; + // Create dummy variable for objective offset. + build.addColumn(0, nullptr, nullptr, 1.0, 1.0, + solver_->Objective().offset(), "dummy", false); + const int nb_vars = solver_->variables_.size(); + for (int i = 0; i < nb_vars; ++i) { + MPVariable *const var = solver_->variables_[i]; + set_variable_as_extracted(i, true); + const double obj_coeff = solver_->Objective().GetCoefficient(var); + if (var->name().empty()) { + build.addColumn(0, nullptr, nullptr, var->lb(), var->ub(), obj_coeff, + nullptr, var->integer()); + } else { + build.addColumn(0, nullptr, nullptr, var->lb(), var->ub(), obj_coeff, + var->name().c_str(), var->integer()); + } } - } - // Define constraints. - int max_row_length = 0; - for (int i = 0; i < solver_->constraints_.size(); ++i) { - MPConstraint *const ct = solver_->constraints_[i]; - set_constraint_as_extracted(i, true); - if (ct->coefficients_.size() > max_row_length) { - max_row_length = ct->coefficients_.size(); + // Define constraints. + int max_row_length = 0; + for (int i = 0; i < solver_->constraints_.size(); ++i) { + MPConstraint *const ct = solver_->constraints_[i]; + set_constraint_as_extracted(i, true); + if (ct->coefficients_.size() > max_row_length) { + max_row_length = ct->coefficients_.size(); + } } - } - std::unique_ptr indices(new int[max_row_length]); - std::unique_ptr coefs(new double[max_row_length]); + std::unique_ptr indices(new int[max_row_length]); + std::unique_ptr coefs(new double[max_row_length]); - for (int i = 0; i < solver_->constraints_.size(); ++i) { - MPConstraint *const ct = solver_->constraints_[i]; - const int size = ct->coefficients_.size(); - int j = 0; - for (const auto &entry : ct->coefficients_) { - const int index = MPSolverVarIndexToCbcVarIndex(entry.first->index()); - indices[j] = index; - coefs[j] = entry.second; - j++; - } - if (ct->name().empty()) { - build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub()); - } else { - build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub(), - ct->name().c_str()); + for (int i = 0; i < solver_->constraints_.size(); ++i) { + MPConstraint *const ct = solver_->constraints_[i]; + const int size = ct->coefficients_.size(); + int j = 0; + for (const auto &entry : ct->coefficients_) { + const int index = MPSolverVarIndexToCbcVarIndex(entry.first->index()); + indices[j] = index; + coefs[j] = entry.second; + j++; + } + if (ct->name().empty()) { + build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub()); + } else { + build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub(), + ct->name().c_str()); + } } + osi_.loadFromCoinModel(build); + break; + } + case MODEL_SYNCHRONIZED: { + break; + } + case SOLUTION_SYNCHRONIZED: { + break; } - osi_.loadFromCoinModel(build); - break; - } - case MODEL_SYNCHRONIZED: { break; } - case SOLUTION_SYNCHRONIZED: { break; } } // Changing optimization direction through OSI so that the model file @@ -348,15 +354,15 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters ¶m) { CoinMessageHandler message_handler; model.passInMessageHandler(&message_handler); if (quiet_) { - message_handler.setLogLevel(0, 0); // Coin messages - message_handler.setLogLevel(1, 0); // Clp messages - message_handler.setLogLevel(2, 0); // Presolve messages - message_handler.setLogLevel(3, 0); // Cgl messages + message_handler.setLogLevel(0, 0); // Coin messages + message_handler.setLogLevel(1, 0); // Clp messages + message_handler.setLogLevel(2, 0); // Presolve messages + message_handler.setLogLevel(3, 0); // Cgl messages } else { - message_handler.setLogLevel(0, 1); // Coin messages - message_handler.setLogLevel(1, 1); // Clp messages - message_handler.setLogLevel(2, 1); // Presolve messages - message_handler.setLogLevel(3, 1); // Cgl messages + message_handler.setLogLevel(0, 1); // Coin messages + message_handler.setLogLevel(1, 1); // Clp messages + message_handler.setLogLevel(2, 1); // Presolve messages + message_handler.setLogLevel(3, 1); // Cgl messages } // Time limit. @@ -384,8 +390,8 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters ¶m) { ? callCbc("-solve ", model) : callCbc(absl::StrCat("-threads ", num_threads_, " -solve "), model); const int kBadReturnStatus = 777; - CHECK_NE(kBadReturnStatus, return_status); // Should never happen according - // to the CBC source + CHECK_NE(kBadReturnStatus, return_status); // Should never happen according + // to the CBC source VLOG(1) << absl::StrFormat("Solved in %.3f seconds.", timer.Get()); @@ -406,31 +412,31 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters ¶m) { (5 event user programmed event occurred) */ switch (tmp_status) { - case 0: - // Order of tests counts; if model.isContinuousUnbounded() returns true, - // then so does model.isProvenInfeasible()! - if (model.isProvenOptimal()) { - result_status_ = MPSolver::OPTIMAL; - } else if (model.isContinuousUnbounded()) { - result_status_ = MPSolver::UNBOUNDED; - } else if (model.isProvenInfeasible()) { - result_status_ = MPSolver::INFEASIBLE; - } else if (model.isAbandoned()) { + case 0: + // Order of tests counts; if model.isContinuousUnbounded() returns true, + // then so does model.isProvenInfeasible()! + if (model.isProvenOptimal()) { + result_status_ = MPSolver::OPTIMAL; + } else if (model.isContinuousUnbounded()) { + result_status_ = MPSolver::UNBOUNDED; + } else if (model.isProvenInfeasible()) { + result_status_ = MPSolver::INFEASIBLE; + } else if (model.isAbandoned()) { + result_status_ = MPSolver::ABNORMAL; + } else { + result_status_ = MPSolver::ABNORMAL; + } + break; + case 1: + if (model.bestSolution() != nullptr) { + result_status_ = MPSolver::FEASIBLE; + } else { + result_status_ = MPSolver::NOT_SOLVED; + } + break; + default: result_status_ = MPSolver::ABNORMAL; - } else { - result_status_ = MPSolver::ABNORMAL; - } - break; - case 1: - if (model.bestSolution() != nullptr) { - result_status_ = MPSolver::FEASIBLE; - } else { - result_status_ = MPSolver::NOT_SOLVED; - } - break; - default: - result_status_ = MPSolver::ABNORMAL; - break; + break; } if (result_status_ == MPSolver::OPTIMAL || @@ -466,14 +472,12 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters ¶m) { // ------ Query statistics on the solution and the solve ------ int64 CBCInterface::iterations() const { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; return iterations_; } int64 CBCInterface::nodes() const { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; return nodes_; } @@ -519,11 +523,13 @@ void CBCInterface::SetDualTolerance(double value) { void CBCInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_ON: { - // CBC presolve is always on. - break; - } - default: { SetUnsupportedIntegerParam(MPSolverParameters::PRESOLVE); } + case MPSolverParameters::PRESOLVE_ON: { + // CBC presolve is always on. + break; + } + default: { + SetUnsupportedIntegerParam(MPSolverParameters::PRESOLVE); + } } } @@ -539,5 +545,5 @@ MPSolverInterface *BuildCBCInterface(MPSolver *const solver) { return new CBCInterface(solver); } -} // namespace operations_research -#endif // #if defined(USE_CBC) +} // namespace operations_research +#endif // #if defined(USE_CBC) diff --git a/ortools/linear_solver/clp_interface.cc b/ortools/linear_solver/clp_interface.cc index 80ebdb9125..034f766508 100644 --- a/ortools/linear_solver/clp_interface.cc +++ b/ortools/linear_solver/clp_interface.cc @@ -40,7 +40,7 @@ namespace operations_research { class CLPInterface : public MPSolverInterface { -public: + public: // Constructor that takes a name for the underlying CLP solver. explicit CLPInterface(MPSolver *const solver); ~CLPInterface() override; @@ -109,7 +109,7 @@ public: return reinterpret_cast(clp_.get()); } -private: + private: // Create dummy variable to be able to create empty constraints. void CreateDummyVariableForEmptyConstraints(); @@ -128,11 +128,11 @@ private: void SetLpAlgorithm(int value) override; // Transforms basis status from CLP enum to MPSolver::BasisStatus. - MPSolver::BasisStatus - TransformCLPBasisStatus(ClpSimplex::Status clp_basis_status) const; + MPSolver::BasisStatus TransformCLPBasisStatus( + ClpSimplex::Status clp_basis_status) const; - std::unique_ptr clp_; // TODO(user) : remove pointer. - std::unique_ptr options_; // For parameter setting. + std::unique_ptr clp_; // TODO(user) : remove pointer. + std::unique_ptr options_; // For parameter setting. }; // ----- Solver ----- @@ -158,7 +158,7 @@ namespace { // Variable indices are shifted by 1 internally because of the dummy "objective // offset" variable (with internal index 0). int MPSolverVarIndexToClpVarIndex(int var_index) { return var_index + 1; } -} // namespace +} // namespace // Not cached void CLPInterface::SetOptimizationDirection(bool maximize) { @@ -215,8 +215,7 @@ void CLPInterface::SetCoefficient(MPConstraint *const constraint, void CLPInterface::ClearConstraint(MPConstraint *const constraint) { InvalidateSolutionSynchronization(); // Constraint may not have been extracted yet. - if (!constraint_is_extracted(constraint->index())) - return; + if (!constraint_is_extracted(constraint->index())) return; for (const auto &entry : constraint->coefficients_) { DCHECK(variable_is_extracted(entry.first->index())); clp_->modifyCoefficient(constraint->index(), @@ -277,7 +276,7 @@ void CLPInterface::CreateDummyVariableForEmptyConstraints() { // Workaround for peculiar signature of setColumnName. Note that we do need // std::string here, and not 'string', which aren't the same as of 2013-12 // (this will change later). - std::string dummy = "dummy"; // We do need to create this temporary variable. + std::string dummy = "dummy"; // We do need to create this temporary variable. clp_->setColumnName(kDummyVariableIndex, dummy); } @@ -458,21 +457,21 @@ MPSolver::ResultStatus CLPInterface::Solve(const MPSolverParameters ¶m) { int tmp_status = clp_->status(); VLOG(1) << "clp result status: " << tmp_status; switch (tmp_status) { - case CLP_SIMPLEX_FINISHED: - result_status_ = MPSolver::OPTIMAL; - break; - case CLP_SIMPLEX_INFEASIBLE: - result_status_ = MPSolver::INFEASIBLE; - break; - case CLP_SIMPLEX_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - case CLP_SIMPLEX_STOPPED: - result_status_ = MPSolver::FEASIBLE; - break; - default: - result_status_ = MPSolver::ABNORMAL; - break; + case CLP_SIMPLEX_FINISHED: + result_status_ = MPSolver::OPTIMAL; + break; + case CLP_SIMPLEX_INFEASIBLE: + result_status_ = MPSolver::INFEASIBLE; + break; + case CLP_SIMPLEX_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + case CLP_SIMPLEX_STOPPED: + result_status_ = MPSolver::FEASIBLE; + break; + default: + result_status_ = MPSolver::ABNORMAL; + break; } if (result_status_ == MPSolver::OPTIMAL || @@ -505,8 +504,7 @@ MPSolver::ResultStatus CLPInterface::Solve(const MPSolverParameters ¶m) { ResetParameters(); sync_status_ = SOLUTION_SYNCHRONIZED; return result_status_; - } - catch (CoinError & e) { + } catch (CoinError &e) { LOG(WARNING) << "Caught exception in Coin LP: " << e.message(); result_status_ = MPSolver::ABNORMAL; return result_status_; @@ -516,29 +514,28 @@ MPSolver::ResultStatus CLPInterface::Solve(const MPSolverParameters ¶m) { MPSolver::BasisStatus CLPInterface::TransformCLPBasisStatus( ClpSimplex::Status clp_basis_status) const { switch (clp_basis_status) { - case ClpSimplex::isFree: - return MPSolver::FREE; - case ClpSimplex::basic: - return MPSolver::BASIC; - case ClpSimplex::atUpperBound: - return MPSolver::AT_UPPER_BOUND; - case ClpSimplex::atLowerBound: - return MPSolver::AT_LOWER_BOUND; - case ClpSimplex::superBasic: - return MPSolver::FREE; - case ClpSimplex::isFixed: - return MPSolver::FIXED_VALUE; - default: - LOG(FATAL) << "Unknown CLP basis status"; - return MPSolver::FREE; + case ClpSimplex::isFree: + return MPSolver::FREE; + case ClpSimplex::basic: + return MPSolver::BASIC; + case ClpSimplex::atUpperBound: + return MPSolver::AT_UPPER_BOUND; + case ClpSimplex::atLowerBound: + return MPSolver::AT_LOWER_BOUND; + case ClpSimplex::superBasic: + return MPSolver::FREE; + case ClpSimplex::isFixed: + return MPSolver::FIXED_VALUE; + default: + LOG(FATAL) << "Unknown CLP basis status"; + return MPSolver::FREE; } } // ------ Query statistics on the solution and the solve ------ int64 CLPInterface::iterations() const { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; return clp_->getIterationCount(); } @@ -594,17 +591,17 @@ void CLPInterface::SetDualTolerance(double value) { void CLPInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_OFF: { - options_->setPresolveType(ClpSolve::presolveOff); - break; - } - case MPSolverParameters::PRESOLVE_ON: { - options_->setPresolveType(ClpSolve::presolveOn); - break; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); - } + case MPSolverParameters::PRESOLVE_OFF: { + options_->setPresolveType(ClpSolve::presolveOff); + break; + } + case MPSolverParameters::PRESOLVE_ON: { + options_->setPresolveType(ClpSolve::presolveOn); + break; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + } } } @@ -614,21 +611,22 @@ void CLPInterface::SetScalingMode(int value) { void CLPInterface::SetLpAlgorithm(int value) { switch (value) { - case MPSolverParameters::DUAL: { - options_->setSolveType(ClpSolve::useDual); - break; - } - case MPSolverParameters::PRIMAL: { - options_->setSolveType(ClpSolve::usePrimal); - break; - } - case MPSolverParameters::BARRIER: { - options_->setSolveType(ClpSolve::useBarrier); - break; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, value); - } + case MPSolverParameters::DUAL: { + options_->setSolveType(ClpSolve::useDual); + break; + } + case MPSolverParameters::PRIMAL: { + options_->setSolveType(ClpSolve::usePrimal); + break; + } + case MPSolverParameters::BARRIER: { + options_->setSolveType(ClpSolve::useBarrier); + break; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, + value); + } } } @@ -636,5 +634,5 @@ MPSolverInterface *BuildCLPInterface(MPSolver *const solver) { return new CLPInterface(solver); } -} // namespace operations_research -#endif // #if defined(USE_CBC) || defined(USE_CLP) +} // namespace operations_research +#endif // #if defined(USE_CBC) || defined(USE_CLP) diff --git a/ortools/linear_solver/cplex_interface.cc b/ortools/linear_solver/cplex_interface.cc index dc45bf5fea..a91572ec5b 100644 --- a/ortools/linear_solver/cplex_interface.cc +++ b/ortools/linear_solver/cplex_interface.cc @@ -41,10 +41,10 @@ CPXLIBAPI int CPXPUBLIC CPXEsetobjoffset(CPXCENVptr, CPXLPptr, double); // The argument to this macro is the invocation of a CPXX function that // returns a status. If the function returns non-zero the macro aborts // the program with an appropriate error message. -#define CHECK_STATUS(s) \ - do { \ - int const status_ = s; \ - CHECK_EQ(0, status_); \ +#define CHECK_STATUS(s) \ + do { \ + int const status_ = s; \ + CHECK_EQ(0, status_); \ } while (0) namespace operations_research { @@ -57,7 +57,7 @@ using std::unique_ptr; // Similiar for instances of MPConstraint: the index of the constraint in // the model is the row index in the CPLEX model. class CplexInterface : public MPSolverInterface { -public: + public: // NOTE: 'mip' specifies the type of the problem (either continuous or // mixed integer. This type is fixed for the lifetime of the // instance. There are no dynamic changes to the model type. @@ -141,7 +141,7 @@ public: return CPX_NAN; } -protected: + protected: // Set all parameters in the underlying solver. virtual void SetParameters(MPSolverParameters const ¶m); // Set each parameter in the underlying solver. @@ -155,7 +155,7 @@ protected: virtual bool ReadParameterFile(std::string const &filename); virtual std::string ValidFileExtensionForParameterFile() const; -private: + private: // Mark modeling object "out of sync". This implicitly invalidates // solution information as well. It is the counterpart of // MPSolverInterface::InvalidateSolutionSynchronization @@ -168,7 +168,7 @@ private: // Transform CPLEX basis status to MPSolver basis status. static MPSolver::BasisStatus xformBasisStatus(int cplex_basis_status); -private: + private: CPXLPptr mLp; CPXENVptr mEnv; bool const mMip; @@ -214,24 +214,28 @@ private: // Creates a LP/MIP instance. CplexInterface::CplexInterface(MPSolver *const solver, bool mip) - : MPSolverInterface(solver), mEnv(0), mLp(0), mMip(mip), + : MPSolverInterface(solver), + mEnv(0), + mLp(0), + mMip(mip), slowUpdates(static_cast(SlowSetObjectiveCoefficient | SlowClearObjective)), - supportIncrementalExtraction(false), mCstat(), mRstat() { + supportIncrementalExtraction(false), + mCstat(), + mRstat() { int status; mEnv = CPXXopenCPLEX(&status); CHECK_STATUS(status); - DCHECK(mEnv != nullptr); // should not be NULL if status=0 + DCHECK(mEnv != nullptr); // should not be NULL if status=0 char const *name = solver_->name_.c_str(); mLp = CPXXcreateprob(mEnv, &status, name); CHECK_STATUS(status); - DCHECK(mLp != nullptr); // should not be NULL if status=0 + DCHECK(mLp != nullptr); // should not be NULL if status=0 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp, maximize_ ? CPX_MAX : CPX_MIN)); - if (mMip) - CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP)); + if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP)); } CplexInterface::~CplexInterface() { @@ -268,11 +272,10 @@ void CplexInterface::Reset() { const char *const name = solver_->name_.c_str(); mLp = CPXXcreateprob(mEnv, &status, name); CHECK_STATUS(status); - DCHECK(mLp != nullptr); // should not be NULL if status=0 + DCHECK(mLp != nullptr); // should not be NULL if status=0 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp, maximize_ ? CPX_MAX : CPX_MIN)); - if (mMip) - CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP)); + if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP)); ResetExtractionInformation(); mCstat = 0; @@ -300,9 +303,9 @@ void CplexInterface::SetVariableBounds(int var_index, double lb, double ub) { // Variable has already been extracted, so we must modify the // modeling object. DCHECK_LT(var_index, last_variable_index_); - char const lu[2] = { 'L', 'U' }; - double const bd[2] = { lb, ub }; - CPXDIM const idx[2] = { var_index, var_index }; + char const lu[2] = {'L', 'U'}; + double const bd[2] = {lb, ub}; + CPXDIM const idx[2] = {var_index, var_index}; CHECK_STATUS(CPXXchgbds(mEnv, mLp, 2, idx, lu, bd)); } else { // Variable is not yet extracted. It is sufficient to just mark @@ -583,8 +586,7 @@ void CplexInterface::ClearObjective() { ++j; } } - if (j > 0) - CHECK_STATUS(CPXXchgobj(mEnv, mLp, j, ind.get(), zero.get())); + if (j > 0) CHECK_STATUS(CPXXchgobj(mEnv, mLp, j, ind.get(), zero.get())); CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp, 0.0)); } else InvalidateModelSynchronization(); @@ -594,8 +596,7 @@ void CplexInterface::ClearObjective() { int64 CplexInterface::iterations() const { int iter; - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; if (mMip) return static_cast(CPXXgetmipitcnt(mEnv, mLp)); else @@ -604,8 +605,7 @@ int64 CplexInterface::iterations() const { int64 CplexInterface::nodes() const { if (mMip) { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; return static_cast(CPXXgetnodecnt(mEnv, mLp)); } else { LOG(DFATAL) << "Number of nodes only available for discrete problems"; @@ -637,17 +637,17 @@ double CplexInterface::best_objective_bound() const { // Transform a CPLEX basis status to an MPSolver basis status. MPSolver::BasisStatus CplexInterface::xformBasisStatus(int cplex_basis_status) { switch (cplex_basis_status) { - case CPX_AT_LOWER: - return MPSolver::AT_LOWER_BOUND; - case CPX_BASIC: - return MPSolver::BASIC; - case CPX_AT_UPPER: - return MPSolver::AT_UPPER_BOUND; - case CPX_FREE_SUPER: - return MPSolver::FREE; - default: - LOG(DFATAL) << "Unknown CPLEX basis status"; - return MPSolver::FREE; + case CPX_AT_LOWER: + return MPSolver::AT_LOWER_BOUND; + case CPX_BASIC: + return MPSolver::BASIC; + case CPX_AT_UPPER: + return MPSolver::AT_UPPER_BOUND; + case CPX_FREE_SUPER: + return MPSolver::FREE; + default: + LOG(DFATAL) << "Unknown CPLEX basis status"; + return MPSolver::FREE; } } @@ -727,7 +727,7 @@ void CplexInterface::ExtractNewVariables() { unique_ptr lb(new double[newcols]); unique_ptr ub(new double[newcols]); unique_ptr ctype(new char[newcols]); - unique_ptr colname(new const char *[newcols]); + unique_ptr colname(new const char *[newcols]); bool have_names = false; for (int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) { @@ -764,8 +764,7 @@ void CplexInterface::ExtractNewVariables() { // For each column count the size of the intersection with // existing constraints. unique_ptr collen(new CPXDIM[newcols]); - for (CPXDIM j = 0; j < newcols; ++j) - collen[j] = 0; + for (CPXDIM j = 0; j < newcols; ++j) collen[j] = 0; CPXNNZ nonzeros = 0; // TODO: Use a bitarray to flag the constraints that actually // intersect new variables? @@ -821,10 +820,10 @@ void CplexInterface::ExtractNewVariables() { } } --cmatbeg; - CHECK_STATUS( - CPXXaddcols(mEnv, mLp, newcols, nonzeros, obj.get(), cmatbeg, - cmatind.get(), cmatval.get(), lb.get(), ub.get(), - have_names ? colname.get() : 0)); + CHECK_STATUS(CPXXaddcols(mEnv, mLp, newcols, nonzeros, obj.get(), + cmatbeg, cmatind.get(), cmatval.get(), + lb.get(), ub.get(), + have_names ? colname.get() : 0)); } } if (use_newcols) { @@ -849,12 +848,11 @@ void CplexInterface::ExtractNewVariables() { ctype.get())); } } - } - catch (...) { + } catch (...) { // Undo all changes in case of error. CPXDIM const cols = CPXXgetnumcols(mEnv, mLp); if (cols > last_extracted) - (void) CPXXdelcols(mEnv, mLp, last_extracted, cols - 1); + (void)CPXXdelcols(mEnv, mLp, last_extracted, cols - 1); std::vector const &variables = solver_->variables(); int const size = variables.size(); for (int j = last_extracted; j < size; ++j) @@ -889,7 +887,7 @@ void CplexInterface::ExtractNewConstraints() { CPXDIM newCons = total - offset; CPXDIM const cols = CPXXgetnumcols(mEnv, mLp); DCHECK_EQ(last_variable_index_, cols); - CPXDIM const chunk = 10; // max number of rows to add in one shot + CPXDIM const chunk = 10; // max number of rows to add in one shot // Update indices of new constraints _before_ actually extracting // them. In case of error we will just reset the indices. @@ -902,7 +900,7 @@ void CplexInterface::ExtractNewConstraints() { unique_ptr rmatbeg(new CPXNNZ[chunk]); unique_ptr sense(new char[chunk]); unique_ptr rhs(new double[chunk]); - unique_ptr name(new char const *[chunk]); + unique_ptr name(new char const *[chunk]); unique_ptr rngval(new double[chunk]); unique_ptr rngind(new CPXDIM[chunk]); bool haveRanges = false; @@ -957,16 +955,13 @@ void CplexInterface::ExtractNewConstraints() { } } } - } - catch (...) { + } catch (...) { // Undo all changes in case of error. CPXDIM const rows = CPXXgetnumrows(mEnv, mLp); - if (rows > offset) - (void) CPXXdelrows(mEnv, mLp, offset, rows - 1); + if (rows > offset) (void)CPXXdelrows(mEnv, mLp, offset, rows - 1); std::vector const &constraints = solver_->constraints(); int const size = constraints.size(); - for (int i = offset; i < size; ++i) - set_constraint_as_extracted(i, false); + for (int i = offset; i < size; ++i) set_constraint_as_extracted(i, false); throw; } } @@ -1004,8 +999,7 @@ void CplexInterface::ExtractObjective() { void CplexInterface::SetParameters(const MPSolverParameters ¶m) { SetCommonParameters(param); - if (mMip) - SetMIPParameters(param); + if (mMip) SetMIPParameters(param); } void CplexInterface::SetRelativeMipGap(double value) { @@ -1030,12 +1024,12 @@ void CplexInterface::SetPresolveMode(int value) { static_cast(value); switch (presolve) { - case MPSolverParameters::PRESOLVE_OFF: - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF)); - return; - case MPSolverParameters::PRESOLVE_ON: - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON)); - return; + case MPSolverParameters::PRESOLVE_OFF: + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF)); + return; + case MPSolverParameters::PRESOLVE_ON: + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON)); + return; } SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); } @@ -1046,14 +1040,14 @@ void CplexInterface::SetScalingMode(int value) { static_cast(value); switch (scaling) { - case MPSolverParameters::SCALING_OFF: - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1)); - break; - case MPSolverParameters::SCALING_ON: - // TODO: 0 is equilibrium scaling (the default), CPLEX also supports - // 1 aggressive scaling - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0)); - break; + case MPSolverParameters::SCALING_OFF: + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1)); + break; + case MPSolverParameters::SCALING_ON: + // TODO: 0 is equilibrium scaling (the default), CPLEX also supports + // 1 aggressive scaling + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0)); + break; } } @@ -1066,15 +1060,15 @@ void CplexInterface::SetLpAlgorithm(int value) { int alg = CPX_ALG_NONE; switch (algorithm) { - case MPSolverParameters::DUAL: - alg = CPX_ALG_DUAL; - break; - case MPSolverParameters::PRIMAL: - alg = CPX_ALG_PRIMAL; - break; - case MPSolverParameters::BARRIER: - alg = CPX_ALG_BARRIER; - break; + case MPSolverParameters::DUAL: + alg = CPX_ALG_DUAL; + break; + case MPSolverParameters::PRIMAL: + alg = CPX_ALG_PRIMAL; + break; + case MPSolverParameters::BARRIER: + alg = CPX_ALG_BARRIER; + break; } if (alg == CPX_ALG_NONE) @@ -1114,14 +1108,14 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { static_cast( param.GetIntegerParam(MPSolverParameters::INCREMENTALITY)); switch (inc) { - case MPSolverParameters::INCREMENTALITY_OFF: - Reset(); /* This should not be required but re-extracting everything - * may be faster, so we do it. */ - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0)); - break; - case MPSolverParameters::INCREMENTALITY_ON: - CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 2)); - break; + case MPSolverParameters::INCREMENTALITY_OFF: + Reset(); /* This should not be required but re-extracting everything + * may be faster, so we do it. */ + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0)); + break; + case MPSolverParameters::INCREMENTALITY_ON: + CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 2)); + break; } // Extract the model to be solved. @@ -1129,8 +1123,7 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { // is out of sync then we have to re-extract everything. Note that this // will lose MIP starts or advanced basis information from a previous // solve. - if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) - Reset(); + if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) Reset(); ExtractModel(); VLOG(1) << absl::StrFormat("Model build in %.3f seconds.", timer.Get()); @@ -1163,7 +1156,7 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { } // Disable screen output right after solve - (void) CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, CPX_OFF); + (void)CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, CPX_OFF); if (status) { VLOG(1) << absl::StrFormat("Failed to optimize MIP. Error %d", status); @@ -1189,8 +1182,7 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { // Capture objective function value. objective_value_ = CPX_NAN; - if (pfeas) - CHECK_STATUS(CPXXgetobjval(mEnv, mLp, &objective_value_)); + if (pfeas) CHECK_STATUS(CPXXgetobjval(mEnv, mLp, &objective_value_)); VLOG(1) << "objective = " << objective_value_; // Capture primal and dual solutions @@ -1221,10 +1213,8 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { if (cols > 0) { unique_ptr x(new double[cols]); unique_ptr dj(new double[cols]); - if (pfeas) - CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1)); - if (dfeas) - CHECK_STATUS(CPXXgetdj(mEnv, mLp, dj.get(), 0, cols - 1)); + if (pfeas) CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1)); + if (dfeas) CHECK_STATUS(CPXXgetdj(mEnv, mLp, dj.get(), 0, cols - 1)); for (int i = 0; i < solver_->variables_.size(); ++i) { MPVariable *const var = solver_->variables_[i]; var->set_solution_value(x[i]); @@ -1248,8 +1238,7 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { if (rows > 0) { unique_ptr pi(new double[rows]); - if (dfeas) - CHECK_STATUS(CPXXgetpi(mEnv, mLp, pi.get(), 0, rows - 1)); + if (dfeas) CHECK_STATUS(CPXXgetpi(mEnv, mLp, pi.get(), 0, rows - 1)); for (int i = 0; i < solver_->constraints_.size(); ++i) { MPConstraint *const ct = solver_->constraints_[i]; bool dual = false; @@ -1266,29 +1255,29 @@ MPSolver::ResultStatus CplexInterface::Solve(MPSolverParameters const ¶m) { // Map CPLEX status to more generic solution status in MPSolver switch (cpxstat) { - case CPX_STAT_OPTIMAL: - case CPXMIP_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case CPXMIP_OPTIMAL_TOL: - // To be consistent with the other solvers. - result_status_ = MPSolver::OPTIMAL; - break; - case CPX_STAT_INFEASIBLE: - case CPXMIP_INFEASIBLE: - result_status_ = MPSolver::INFEASIBLE; - break; - case CPX_STAT_UNBOUNDED: - case CPXMIP_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - case CPX_STAT_INForUNBD: - case CPXMIP_INForUNBD: - result_status_ = MPSolver::INFEASIBLE; - break; - default: - result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; - break; + case CPX_STAT_OPTIMAL: + case CPXMIP_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case CPXMIP_OPTIMAL_TOL: + // To be consistent with the other solvers. + result_status_ = MPSolver::OPTIMAL; + break; + case CPX_STAT_INFEASIBLE: + case CPXMIP_INFEASIBLE: + result_status_ = MPSolver::INFEASIBLE; + break; + case CPX_STAT_UNBOUNDED: + case CPXMIP_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + case CPX_STAT_INForUNBD: + case CPXMIP_INForUNBD: + result_status_ = MPSolver::INFEASIBLE; + break; + default: + result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; + break; } sync_status_ = SOLUTION_SYNCHRONIZED; @@ -1299,5 +1288,5 @@ MPSolverInterface *BuildCplexInterface(bool mip, MPSolver *const solver) { return new CplexInterface(solver, mip); } -} // namespace operations_research -#endif // #if defined(USE_CPLEX) +} // namespace operations_research +#endif // #if defined(USE_CPLEX) diff --git a/ortools/linear_solver/glop_interface.cc b/ortools/linear_solver/glop_interface.cc index c85dd043c4..db257d0811 100644 --- a/ortools/linear_solver/glop_interface.cc +++ b/ortools/linear_solver/glop_interface.cc @@ -29,11 +29,10 @@ namespace operations_research { -namespace { -} // Anonymous namespace +namespace {} // Anonymous namespace class GLOPInterface : public MPSolverInterface { -public: + public: explicit GLOPInterface(MPSolver *const solver); ~GLOPInterface() override; @@ -88,10 +87,10 @@ public: void SetPresolveMode(int value) override; void SetScalingMode(int value) override; void SetLpAlgorithm(int value) override; - bool SetSolverSpecificParametersAsString(const std::string ¶meters) - override; + bool SetSolverSpecificParametersAsString( + const std::string ¶meters) override; -private: + private: void NonIncrementalChange(); glop::LinearProgram linear_program_; @@ -103,9 +102,13 @@ private: }; GLOPInterface::GLOPInterface(MPSolver *const solver) - : MPSolverInterface(solver), linear_program_(), lp_solver_(), - column_status_(), row_status_(), parameters_(), interrupt_solver_(false) { -} + : MPSolverInterface(solver), + linear_program_(), + lp_solver_(), + column_status_(), + row_status_(), + parameters_(), + interrupt_solver_(false) {} GLOPInterface::~GLOPInterface() {} @@ -364,47 +367,47 @@ void GLOPInterface::SetDualTolerance(double value) { void GLOPInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_OFF: - parameters_.set_use_preprocessing(false); - break; - case MPSolverParameters::PRESOLVE_ON: - parameters_.set_use_preprocessing(true); - break; - default: - if (value != MPSolverParameters::kDefaultIntegerParamValue) { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); - } + case MPSolverParameters::PRESOLVE_OFF: + parameters_.set_use_preprocessing(false); + break; + case MPSolverParameters::PRESOLVE_ON: + parameters_.set_use_preprocessing(true); + break; + default: + if (value != MPSolverParameters::kDefaultIntegerParamValue) { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + } } } void GLOPInterface::SetScalingMode(int value) { switch (value) { - case MPSolverParameters::SCALING_OFF: - parameters_.set_use_scaling(false); - break; - case MPSolverParameters::SCALING_ON: - parameters_.set_use_scaling(true); - break; - default: - if (value != MPSolverParameters::kDefaultIntegerParamValue) { - SetIntegerParamToUnsupportedValue(MPSolverParameters::SCALING, value); - } + case MPSolverParameters::SCALING_OFF: + parameters_.set_use_scaling(false); + break; + case MPSolverParameters::SCALING_ON: + parameters_.set_use_scaling(true); + break; + default: + if (value != MPSolverParameters::kDefaultIntegerParamValue) { + SetIntegerParamToUnsupportedValue(MPSolverParameters::SCALING, value); + } } } void GLOPInterface::SetLpAlgorithm(int value) { switch (value) { - case MPSolverParameters::DUAL: - parameters_.set_use_dual_simplex(true); - break; - case MPSolverParameters::PRIMAL: - parameters_.set_use_dual_simplex(false); - break; - default: - if (value != MPSolverParameters::kDefaultIntegerParamValue) { - SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, - value); - } + case MPSolverParameters::DUAL: + parameters_.set_use_dual_simplex(true); + break; + case MPSolverParameters::PRIMAL: + parameters_.set_use_dual_simplex(false); + break; + default: + if (value != MPSolverParameters::kDefaultIntegerParamValue) { + SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, + value); + } } } @@ -431,4 +434,4 @@ MPSolverInterface *BuildGLOPInterface(MPSolver *const solver) { return new GLOPInterface(solver); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/glop_utils.cc b/ortools/linear_solver/glop_utils.cc index a0c3275b37..86a513b36f 100644 --- a/ortools/linear_solver/glop_utils.cc +++ b/ortools/linear_solver/glop_utils.cc @@ -17,38 +17,38 @@ namespace operations_research { MPSolver::ResultStatus GlopToMPSolverResultStatus(glop::ProblemStatus s) { switch (s) { - case glop::ProblemStatus::OPTIMAL: - return MPSolver::OPTIMAL; - case glop::ProblemStatus::PRIMAL_FEASIBLE: - return MPSolver::FEASIBLE; + case glop::ProblemStatus::OPTIMAL: + return MPSolver::OPTIMAL; + case glop::ProblemStatus::PRIMAL_FEASIBLE: + return MPSolver::FEASIBLE; - // Note(user): MPSolver does not have the equivalent of - // INFEASIBLE_OR_UNBOUNDED however UNBOUNDED is almost never relevant in - // applications, so we decided to report this status as INFEASIBLE since - // it should almost always be the case. Historically, we where reporting - // ABNORMAL, but that was more confusing than helpful. - // - // TODO(user): We could argue that it is infeasible to find the optimal of - // an unbounded problem. So it might just be simpler to completely get rid - // of the MpSolver::UNBOUNDED status that seems to never be used - // programmatically. - case glop::ProblemStatus::INFEASIBLE_OR_UNBOUNDED: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::PRIMAL_INFEASIBLE: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::DUAL_UNBOUNDED: - return MPSolver::INFEASIBLE; + // Note(user): MPSolver does not have the equivalent of + // INFEASIBLE_OR_UNBOUNDED however UNBOUNDED is almost never relevant in + // applications, so we decided to report this status as INFEASIBLE since + // it should almost always be the case. Historically, we where reporting + // ABNORMAL, but that was more confusing than helpful. + // + // TODO(user): We could argue that it is infeasible to find the optimal of + // an unbounded problem. So it might just be simpler to completely get rid + // of the MpSolver::UNBOUNDED status that seems to never be used + // programmatically. + case glop::ProblemStatus::INFEASIBLE_OR_UNBOUNDED: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::PRIMAL_INFEASIBLE: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::DUAL_UNBOUNDED: + return MPSolver::INFEASIBLE; - case glop::ProblemStatus::DUAL_INFEASIBLE: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::PRIMAL_UNBOUNDED: - return MPSolver::UNBOUNDED; + case glop::ProblemStatus::DUAL_INFEASIBLE: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::PRIMAL_UNBOUNDED: + return MPSolver::UNBOUNDED; - case glop::ProblemStatus::DUAL_FEASIBLE: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::INIT: - return MPSolver::NOT_SOLVED; + case glop::ProblemStatus::DUAL_FEASIBLE: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::INIT: + return MPSolver::NOT_SOLVED; - case glop::ProblemStatus::ABNORMAL: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::IMPRECISE: // PASS_THROUGH_INTENDED - case glop::ProblemStatus::INVALID_PROBLEM: - return MPSolver::ABNORMAL; + case glop::ProblemStatus::ABNORMAL: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::IMPRECISE: // PASS_THROUGH_INTENDED + case glop::ProblemStatus::INVALID_PROBLEM: + return MPSolver::ABNORMAL; } LOG(DFATAL) << "Invalid glop::ProblemStatus " << s; return MPSolver::ABNORMAL; @@ -56,16 +56,16 @@ MPSolver::ResultStatus GlopToMPSolverResultStatus(glop::ProblemStatus s) { MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s) { switch (s) { - case glop::VariableStatus::FREE: - return MPSolver::FREE; - case glop::VariableStatus::AT_LOWER_BOUND: - return MPSolver::AT_LOWER_BOUND; - case glop::VariableStatus::AT_UPPER_BOUND: - return MPSolver::AT_UPPER_BOUND; - case glop::VariableStatus::FIXED_VALUE: - return MPSolver::FIXED_VALUE; - case glop::VariableStatus::BASIC: - return MPSolver::BASIC; + case glop::VariableStatus::FREE: + return MPSolver::FREE; + case glop::VariableStatus::AT_LOWER_BOUND: + return MPSolver::AT_LOWER_BOUND; + case glop::VariableStatus::AT_UPPER_BOUND: + return MPSolver::AT_UPPER_BOUND; + case glop::VariableStatus::FIXED_VALUE: + return MPSolver::FIXED_VALUE; + case glop::VariableStatus::BASIC: + return MPSolver::BASIC; } LOG(DFATAL) << "Unknown variable status: " << s; return MPSolver::FREE; @@ -73,16 +73,16 @@ MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s) { glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s) { switch (s) { - case MPSolver::FREE: - return glop::VariableStatus::FREE; - case MPSolver::AT_LOWER_BOUND: - return glop::VariableStatus::AT_LOWER_BOUND; - case MPSolver::AT_UPPER_BOUND: - return glop::VariableStatus::AT_UPPER_BOUND; - case MPSolver::FIXED_VALUE: - return glop::VariableStatus::FIXED_VALUE; - case MPSolver::BASIC: - return glop::VariableStatus::BASIC; + case MPSolver::FREE: + return glop::VariableStatus::FREE; + case MPSolver::AT_LOWER_BOUND: + return glop::VariableStatus::AT_LOWER_BOUND; + case MPSolver::AT_UPPER_BOUND: + return glop::VariableStatus::AT_UPPER_BOUND; + case MPSolver::FIXED_VALUE: + return glop::VariableStatus::FIXED_VALUE; + case MPSolver::BASIC: + return glop::VariableStatus::BASIC; } LOG(DFATAL) << "Unknown variable status: " << s; return glop::VariableStatus::FREE; @@ -90,16 +90,16 @@ glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s) { MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s) { switch (s) { - case glop::ConstraintStatus::FREE: - return MPSolver::FREE; - case glop::ConstraintStatus::AT_LOWER_BOUND: - return MPSolver::AT_LOWER_BOUND; - case glop::ConstraintStatus::AT_UPPER_BOUND: - return MPSolver::AT_UPPER_BOUND; - case glop::ConstraintStatus::FIXED_VALUE: - return MPSolver::FIXED_VALUE; - case glop::ConstraintStatus::BASIC: - return MPSolver::BASIC; + case glop::ConstraintStatus::FREE: + return MPSolver::FREE; + case glop::ConstraintStatus::AT_LOWER_BOUND: + return MPSolver::AT_LOWER_BOUND; + case glop::ConstraintStatus::AT_UPPER_BOUND: + return MPSolver::AT_UPPER_BOUND; + case glop::ConstraintStatus::FIXED_VALUE: + return MPSolver::FIXED_VALUE; + case glop::ConstraintStatus::BASIC: + return MPSolver::BASIC; } LOG(DFATAL) << "Unknown constraint status: " << s; return MPSolver::FREE; @@ -107,19 +107,19 @@ MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s) { glop::ConstraintStatus MPSolverToGlopConstraintStatus(MPSolver::BasisStatus s) { switch (s) { - case MPSolver::FREE: - return glop::ConstraintStatus::FREE; - case MPSolver::AT_LOWER_BOUND: - return glop::ConstraintStatus::AT_LOWER_BOUND; - case MPSolver::AT_UPPER_BOUND: - return glop::ConstraintStatus::AT_UPPER_BOUND; - case MPSolver::FIXED_VALUE: - return glop::ConstraintStatus::FIXED_VALUE; - case MPSolver::BASIC: - return glop::ConstraintStatus::BASIC; + case MPSolver::FREE: + return glop::ConstraintStatus::FREE; + case MPSolver::AT_LOWER_BOUND: + return glop::ConstraintStatus::AT_LOWER_BOUND; + case MPSolver::AT_UPPER_BOUND: + return glop::ConstraintStatus::AT_UPPER_BOUND; + case MPSolver::FIXED_VALUE: + return glop::ConstraintStatus::FIXED_VALUE; + case MPSolver::BASIC: + return glop::ConstraintStatus::BASIC; } LOG(DFATAL) << "Unknown constraint status: " << s; return glop::ConstraintStatus::FREE; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/glop_utils.h b/ortools/linear_solver/glop_utils.h index 57ef6914e8..e1c7d9b97a 100644 --- a/ortools/linear_solver/glop_utils.h +++ b/ortools/linear_solver/glop_utils.h @@ -27,6 +27,6 @@ glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s); MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s); glop::ConstraintStatus MPSolverToGlopConstraintStatus(MPSolver::BasisStatus s); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_GLOP_UTILS_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_GLOP_UTILS_H_ diff --git a/ortools/linear_solver/glpk_interface.cc b/ortools/linear_solver/glpk_interface.cc index e5d37f9558..91471eab1d 100644 --- a/ortools/linear_solver/glpk_interface.cc +++ b/ortools/linear_solver/glpk_interface.cc @@ -39,7 +39,7 @@ extern "C" { namespace operations_research { // Class to store information gathered in the callback class GLPKInformation { -public: + public: explicit GLPKInformation(bool maximize) : num_all_nodes_(0) { ResetBestObjectiveBound(maximize); } @@ -64,22 +64,22 @@ void GLPKGatherInformationCallback(glp_tree *tree, void *info) { CHECK(info != nullptr); GLPKInformation *glpk_info = reinterpret_cast(info); switch (glp_ios_reason(tree)) { - // The best bound and the number of nodes change only when GLPK - // branches, generates cuts or finds an integer solution. - case GLP_ISELECT: - case GLP_IROWGEN: - case GLP_IBINGO: { - // Get total number of nodes - glp_ios_tree_size(tree, nullptr, nullptr, &glpk_info->num_all_nodes_); - // Get best bound - int node_id = glp_ios_best_node(tree); - if (node_id > 0) { - glpk_info->best_objective_bound_ = glp_ios_node_bound(tree, node_id); + // The best bound and the number of nodes change only when GLPK + // branches, generates cuts or finds an integer solution. + case GLP_ISELECT: + case GLP_IROWGEN: + case GLP_IBINGO: { + // Get total number of nodes + glp_ios_tree_size(tree, nullptr, nullptr, &glpk_info->num_all_nodes_); + // Get best bound + int node_id = glp_ios_best_node(tree); + if (node_id > 0) { + glpk_info->best_objective_bound_ = glp_ios_node_bound(tree, node_id); + } + break; } - break; - } - default: - break; + default: + break; } } @@ -88,10 +88,10 @@ void GLPKGatherInformationCallback(glp_tree *tree, void *info) { namespace { // GLPK indexes its variables and constraints starting at 1. int MPSolverIndexToGlpkIndex(int index) { return index + 1; } -} // namespace +} // namespace class GLPKInterface : public MPSolverInterface { -public: + public: // Constructor that takes a name for the underlying glpk solver. GLPKInterface(MPSolver *const solver, bool mip); ~GLPKInterface() override; @@ -110,8 +110,8 @@ public: // Modify bounds. void SetVariableBounds(int mpsolver_var_index, double lb, double ub) override; void SetVariableInteger(int mpsolver_var_index, bool integer) override; - void SetConstraintBounds(int mpsolver_constraint_index, double lb, double ub) - override; + void SetConstraintBounds(int mpsolver_constraint_index, double lb, + double ub) override; // Add Constraint incrementally. void AddRowConstraint(MPConstraint *const ct) override; @@ -167,7 +167,7 @@ public: double ComputeExactConditionNumber() const override; -private: + private: // Configure the solver's parameters. void ConfigureGLPKParameters(const MPSolverParameters ¶m); @@ -388,8 +388,8 @@ void GLPKInterface::ExtractNewVariables() { if (!var->name().empty()) { glp_set_col_name(lp_, MPSolverIndexToGlpkIndex(j), var->name().c_str()); } - SetVariableBounds(/*mpsolver_var_index=*/ j, var->lb(), var->ub()); - SetVariableInteger(/*mpsolver_var_index=*/ j, var->integer()); + SetVariableBounds(/*mpsolver_var_index=*/j, var->lb(), var->ub()); + SetVariableInteger(/*mpsolver_var_index=*/j, var->integer()); // The true objective coefficient will be set later in ExtractObjective. double tmp_obj_coef = 0.0; @@ -458,7 +458,7 @@ void GLPKInterface::ExtractNewConstraints() { glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i), ct->name().c_str()); } // All constraints are set to be of the type <= limit_ . - SetConstraintBounds(/*mpsolver_constraint_index=*/ i, ct->lb(), ct->ub()); + SetConstraintBounds(/*mpsolver_constraint_index=*/i, ct->lb(), ct->ub()); num_coefs += ct->coefficients_.size(); } @@ -648,22 +648,22 @@ MPSolver::ResultStatus GLPKInterface::Solve(const MPSolverParameters ¶m) { return result_status_; } -MPSolver::BasisStatus -GLPKInterface::TransformGLPKBasisStatus(int glpk_basis_status) const { +MPSolver::BasisStatus GLPKInterface::TransformGLPKBasisStatus( + int glpk_basis_status) const { switch (glpk_basis_status) { - case GLP_BS: - return MPSolver::BASIC; - case GLP_NL: - return MPSolver::AT_LOWER_BOUND; - case GLP_NU: - return MPSolver::AT_UPPER_BOUND; - case GLP_NF: - return MPSolver::FREE; - case GLP_NS: - return MPSolver::FIXED_VALUE; - default: - LOG(FATAL) << "Unknown GLPK basis status"; - return MPSolver::FREE; + case GLP_BS: + return MPSolver::BASIC; + case GLP_NL: + return MPSolver::AT_LOWER_BOUND; + case GLP_NU: + return MPSolver::AT_UPPER_BOUND; + case GLP_NF: + return MPSolver::FREE; + case GLP_NS: + return MPSolver::FIXED_VALUE; + default: + LOG(FATAL) << "Unknown GLPK basis status"; + return MPSolver::FREE; } } @@ -685,8 +685,7 @@ int64 GLPKInterface::iterations() const { int64 GLPKInterface::nodes() const { if (mip_) { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; return mip_callback_info_->num_all_nodes_; } else { LOG(DFATAL) << "Number of nodes only available for discrete problems"; @@ -757,8 +756,7 @@ double GLPKInterface::ComputeExactConditionNumber() const { << " GLPK_MIXED_INTEGER_PROGRAMMING"; return 0.0; } - if (!CheckSolutionIsSynchronized()) - return 0.0; + if (!CheckSolutionIsSynchronized()) return 0.0; // Simplex is the only LP algorithm supported in the wrapper for // GLPK, so when a solution exists, a basis exists. CheckSolutionExists(); @@ -780,10 +778,9 @@ double GLPKInterface::ComputeExactConditionNumber() const { column_scaling_factor.get()); } -double -GLPKInterface::ComputeScaledBasisL1Norm(int num_rows, int num_cols, - double *row_scaling_factor, - double *column_scaling_factor) const { +double GLPKInterface::ComputeScaledBasisL1Norm( + int num_rows, int num_cols, double *row_scaling_factor, + double *column_scaling_factor) const { double norm = 0.0; std::unique_ptr values(new double[num_rows + 1]); std::unique_ptr indices(new int[num_rows + 1]); @@ -825,23 +822,23 @@ double GLPKInterface::ComputeInverseScaledBasisL1Norm( if (!glp_bf_exists(lp_)) { const int factorize_status = glp_factorize(lp_); switch (factorize_status) { - case GLP_EBADB: { - LOG(FATAL) << "Not able to factorize: error GLP_EBADB."; - break; - } - case GLP_ESING: { - LOG(WARNING) - << "Not able to factorize: " - << "the basis matrix is singular within the working precision."; - return MPSolver::infinity(); - } - case GLP_ECOND: { - LOG(WARNING) - << "Not able to factorize: the basis matrix is ill-conditioned."; - return MPSolver::infinity(); - } - default: - break; + case GLP_EBADB: { + LOG(FATAL) << "Not able to factorize: error GLP_EBADB."; + break; + } + case GLP_ESING: { + LOG(WARNING) + << "Not able to factorize: " + << "the basis matrix is singular within the working precision."; + return MPSolver::infinity(); + } + case GLP_ECOND: { + LOG(WARNING) + << "Not able to factorize: the basis matrix is ill-conditioned."; + return MPSolver::infinity(); + } + default: + break; } } std::unique_ptr right_hand_side(new double[num_rows + 1]); @@ -952,19 +949,19 @@ void GLPKInterface::SetDualTolerance(double value) { lp_param_.tol_dj = value; } void GLPKInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_OFF: { - mip_param_.presolve = GLP_OFF; - lp_param_.presolve = GLP_OFF; - break; - } - case MPSolverParameters::PRESOLVE_ON: { - mip_param_.presolve = GLP_ON; - lp_param_.presolve = GLP_ON; - break; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); - } + case MPSolverParameters::PRESOLVE_OFF: { + mip_param_.presolve = GLP_OFF; + lp_param_.presolve = GLP_OFF; + break; + } + case MPSolverParameters::PRESOLVE_ON: { + mip_param_.presolve = GLP_ON; + lp_param_.presolve = GLP_ON; + break; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + } } } @@ -974,19 +971,20 @@ void GLPKInterface::SetScalingMode(int value) { void GLPKInterface::SetLpAlgorithm(int value) { switch (value) { - case MPSolverParameters::DUAL: { - // Use dual, and if it fails, switch to primal. - lp_param_.meth = GLP_DUALP; - break; - } - case MPSolverParameters::PRIMAL: { - lp_param_.meth = GLP_PRIMAL; - break; - } - case MPSolverParameters::BARRIER: - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, value); - } + case MPSolverParameters::DUAL: { + // Use dual, and if it fails, switch to primal. + lp_param_.meth = GLP_DUALP; + break; + } + case MPSolverParameters::PRIMAL: { + lp_param_.meth = GLP_PRIMAL; + break; + } + case MPSolverParameters::BARRIER: + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, + value); + } } } @@ -994,5 +992,5 @@ MPSolverInterface *BuildGLPKInterface(bool mip, MPSolver *const solver) { return new GLPKInterface(solver, mip); } -} // namespace operations_research -#endif // #if defined(USE_GLPK) +} // namespace operations_research +#endif // #if defined(USE_GLPK) diff --git a/ortools/linear_solver/gurobi_environment.cc b/ortools/linear_solver/gurobi_environment.cc index d1f9e17eaf..872e65805f 100644 --- a/ortools/linear_solver/gurobi_environment.cc +++ b/ortools/linear_solver/gurobi_environment.cc @@ -37,14 +37,18 @@ absl::Status LoadGurobiEnvironment(GRBenv **env) { } std::function GRBaddrangeconstr = nullptr; + const char *)> + GRBaddrangeconstr = nullptr; std::function GRBaddvar = nullptr; + const char *varname)> + GRBaddvar = nullptr; std::function GRBaddvars = nullptr; + double *, double *, char *, char **)> + GRBaddvars = nullptr; std::function GRBchgcoeffs = nullptr; + double *val)> + GRBchgcoeffs = nullptr; std::function GRBfreeenv = nullptr; std::function GRBfreemodel = nullptr; std::function @@ -62,7 +66,8 @@ std::function GRBgetintattrelement = nullptr; std::function GRBloadenv = nullptr; std::function GRBnewmodel = nullptr; + double *, double *, char *, char **)> + GRBnewmodel = nullptr; std::function GRBoptimize = nullptr; std::function GRBreadparams = nullptr; std::function GRBresetparams = nullptr; @@ -93,32 +98,39 @@ std::function GRBaddgenconstrIndicator = nullptr; + double rhs)> + GRBaddgenconstrIndicator = nullptr; std::function GRBsetintattrelement = nullptr; + int newvalue)> + GRBsetintattrelement = nullptr; std::function GRBsetcallbackfunc = nullptr; std::function GRBsetparam = nullptr; std::function GRBaddsos = nullptr; + int *beg, int *ind, double *weight)> + GRBaddsos = nullptr; std::function GRBaddqconstr = nullptr; + double rhs, const char *QCname)> + GRBaddqconstr = nullptr; std::function GRBaddgenconstrMax = - nullptr; + const int *vars, double constant)> + GRBaddgenconstrMax = nullptr; std::function GRBaddgenconstrMin = - nullptr; + const int *vars, double constant)> + GRBaddgenconstrMin = nullptr; std::function GRBaddgenconstrAbs = nullptr; std::function GRBaddgenconstrAnd = nullptr; + const int *vars)> + GRBaddgenconstrAnd = nullptr; std::function GRBaddgenconstrOr = nullptr; + const int *vars)> + GRBaddgenconstrOr = nullptr; std::function GRBaddqpterms = nullptr; + double *qval)> + GRBaddqpterms = nullptr; std::unique_ptr gurobi_dynamic_library; std::string gurobi_library_path; @@ -196,7 +208,7 @@ bool LoadSpecificGurobiLibrary(const std::string &full_library_path) { bool SearchForGurobiDynamicLibrary() { const char *gurobi_home_from_env = getenv("GUROBI_HOME"); -#if defined(_MSC_VER) // Windows +#if defined(_MSC_VER) // Windows if (!gurobi_library_path.empty() && LoadSpecificGurobiLibrary(gurobi_library_path)) { return true; @@ -210,7 +222,7 @@ bool SearchForGurobiDynamicLibrary() { "C:\\Program Files\\gurobi902\\win64\\bin\\gurobi90.dll")) { return true; } -#elif defined(__APPLE__) // OS X +#elif defined(__APPLE__) // OS X if (!gurobi_library_path.empty() && LoadSpecificGurobiLibrary(gurobi_library_path)) { return true; @@ -224,7 +236,7 @@ bool SearchForGurobiDynamicLibrary() { "/Library/gurobi902/mac64/lib/libgurobi90.dylib")) { return true; } -#elif defined(__GNUC__) // Linux +#elif defined(__GNUC__) // Linux if (gurobi_home_from_env != nullptr && LoadSpecificGurobiLibrary( absl::StrCat(gurobi_home_from_env, "/lib/libgurobi90.so"))) { @@ -259,13 +271,11 @@ void MPSolver::SetGurobiLibraryPath(const std::string &full_library_path) { } bool MPSolver::GurobiIsCorrectlyInstalled() { - if (!LoadGurobiSharedLibrary()) - return false; + if (!LoadGurobiSharedLibrary()) return false; GRBenv *env; - if (GRBloadenv(&env, nullptr) != 0 || env == nullptr) - return false; + if (GRBloadenv(&env, nullptr) != 0 || env == nullptr) return false; return true; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/gurobi_environment.h b/ortools/linear_solver/gurobi_environment.h index 6cc877cc65..848b8c7007 100644 --- a/ortools/linear_solver/gurobi_environment.h +++ b/ortools/linear_solver/gurobi_environment.h @@ -35,17 +35,21 @@ absl::Status LoadGurobiEnvironment(GRBenv **env); #define CB_ARGS GRBmodel *model, void *cbdata, int where, void *usrdata extern std::function GRBaddrangeconstr; + const char *)> + GRBaddrangeconstr; -extern std::function< - int(GRBmodel *model, int numnz, int *vind, double *vval, double obj, - double lb, double ub, char vtype, const char *varname)> GRBaddvar; +extern std::function + GRBaddvar; extern std::function GRBaddvars; + double *, double *, char *, char **)> + GRBaddvars; extern std::function GRBchgcoeffs; + double *val)> + GRBchgcoeffs; extern std::function GRBfreeenv; extern std::function GRBfreemodel; extern std::function @@ -93,14 +97,16 @@ extern std::function extern std::function GRBaddconstr; -extern std::function< - int(GRBmodel *model, const char *name, int binvar, int binval, int nvars, - const int *vars, const double *vals, char sense, double rhs)> +extern std::function GRBaddgenconstrIndicator; extern std::function GRBsetintattrelement; + int newvalue)> + GRBsetintattrelement; extern std::function GRBsetcallbackfunc; + void *usrdata)> + GRBsetcallbackfunc; extern std::function GRBsetparam; extern std::function GRBaddgenconstrMin; extern std::function GRBaddgenconstrAbs; + int argvar)> + GRBaddgenconstrAbs; extern std::function GRBaddgenconstrAnd; + int nvars, const int *vars)> + GRBaddgenconstrAnd; extern std::function GRBaddgenconstrOr; + int nvars, const int *vars)> + GRBaddgenconstrOr; extern std::function GRBaddqpterms; + double *qval)> + GRBaddqpterms; #define GRB_VERSION_MAJOR 9 #define GRB_VERSION_MINOR 0 @@ -183,10 +193,10 @@ extern std::function', or '=') */ #define GRB_STR_ATTR_QCNAME "QCName" /* QC name */ -#define GRB_INT_ATTR_GENCONSTRTYPE \ +#define GRB_INT_ATTR_GENCONSTRTYPE \ "GenConstrType" /* Type of general constraint */ -#define GRB_STR_ATTR_GENCONSTRNAME \ +#define GRB_STR_ATTR_GENCONSTRNAME \ "GenConstrName" /* Name of general constraint */ -#define GRB_INT_ATTR_FUNCPIECES \ - "FuncPieces" /* An option for PWL translation \ \ +#define GRB_INT_ATTR_FUNCPIECES \ + "FuncPieces" /* An option for PWL translation \ \ */ -#define GRB_DBL_ATTR_FUNCPIECEERROR \ +#define GRB_DBL_ATTR_FUNCPIECEERROR \ "FuncPieceError" /* An option for PWL translation */ -#define GRB_DBL_ATTR_FUNCPIECELENGTH \ +#define GRB_DBL_ATTR_FUNCPIECELENGTH \ "FuncPieceLength" /* An option for PWL translation */ -#define GRB_DBL_ATTR_FUNCPIECERATIO \ +#define GRB_DBL_ATTR_FUNCPIECERATIO \ "FuncPieceRatio" /* An option for PWL translation */ #define GRB_DBL_ATTR_MAX_COEFF "MaxCoeff" /* Max (abs) nz coeff in A */ #define GRB_DBL_ATTR_MIN_COEFF "MinCoeff" /* Min (abs) nz coeff in A */ @@ -260,13 +270,13 @@ extern std::function - DirectlySolveProto(const MPModelRequest &request) override; + absl::optional DirectlySolveProto( + const MPModelRequest &request) override; // Writes the model. void Write(const std::string &filename) override; @@ -147,8 +147,7 @@ public: } bool InterruptSolve() override { - if (model_ != nullptr) - GRBterminate(model_); + if (model_ != nullptr) GRBterminate(model_); return true; } @@ -185,7 +184,7 @@ public: void SetCallback(MPCallback *mp_callback) override; bool SupportsCallbacks() const override { return true; } -private: + private: // Sets all parameters in the underlying solver. void SetParameters(const MPSolverParameters ¶m) override; // Sets solver-specific parameters (avoiding using files). The previous @@ -199,8 +198,8 @@ private: // This implementations relies on SetSolverSpecificParameters, which has the // extra benefit of unifying the way we handle specific parameters for both // proto-based solves and for MPModel solves. - bool SetSolverSpecificParametersAsString(const std::string ¶meters) - override; + bool SetSolverSpecificParametersAsString( + const std::string ¶meters) override; // Sets each parameter in the underlying solver. void SetRelativeMipGap(double value) override; void SetPrimalTolerance(double value) override; @@ -212,11 +211,10 @@ private: bool ReadParameterFile(const std::string &filename) override; std::string ValidFileExtensionForParameterFile() const override; - MPSolver::BasisStatus - TransformGRBVarBasisStatus(int gurobi_basis_status) const; - MPSolver::BasisStatus - TransformGRBConstraintBasisStatus(int gurobi_basis_status, - int constraint_index) const; + MPSolver::BasisStatus TransformGRBVarBasisStatus( + int gurobi_basis_status) const; + MPSolver::BasisStatus TransformGRBConstraintBasisStatus( + int gurobi_basis_status, int constraint_index) const; // See the implementation note at the top of file on incrementalism. bool ModelIsNonincremental() const; @@ -278,7 +276,7 @@ struct GurobiInternalCallbackContext { }; class GurobiMPCallbackContext : public MPCallbackContext { -public: + public: GurobiMPCallbackContext(GRBenv *env, const std::vector *mp_var_to_gurobi_var, int num_gurobi_vars, bool might_add_cuts, @@ -299,7 +297,7 @@ public: void UpdateFromGurobiState( const GurobiInternalCallbackContext &gurobi_internal_context); -private: + private: // Wraps GRBcbget(), used to query the state of the solver. See // http://www.gurobi.com/documentation/8.0/refman/callback_codes.html#sec:CallbackCodes // for callback_code values. @@ -335,7 +333,8 @@ GurobiMPCallbackContext::GurobiMPCallbackContext( int num_gurobi_vars, bool might_add_cuts, bool might_add_lazy_constraints) : env_(ABSL_DIE_IF_NULL(env)), mp_var_to_gurobi_var_(ABSL_DIE_IF_NULL(mp_var_to_gurobi_var)), - num_gurobi_vars_(num_gurobi_vars), might_add_cuts_(might_add_cuts), + num_gurobi_vars_(num_gurobi_vars), + might_add_cuts_(might_add_cuts), might_add_lazy_constraints_(might_add_lazy_constraints) {} void GurobiMPCallbackContext::UpdateFromGurobiState( @@ -346,15 +345,16 @@ void GurobiMPCallbackContext::UpdateFromGurobiState( int64 GurobiMPCallbackContext::NumExploredNodes() { switch (Event()) { - case MPCallbackEvent::kMipNode: - return static_cast(GurobiCallbackGet( - current_gurobi_internal_callback_context_, GRB_CB_MIPNODE_NODCNT)); - case MPCallbackEvent::kMipSolution: - return static_cast(GurobiCallbackGet( - current_gurobi_internal_callback_context_, GRB_CB_MIPSOL_NODCNT)); - default: - LOG(FATAL) << "Node count is supported only for callback events MIP_NODE " - "and MIP_SOL, but was requested at: " << ToString(Event()); + case MPCallbackEvent::kMipNode: + return static_cast(GurobiCallbackGet( + current_gurobi_internal_callback_context_, GRB_CB_MIPNODE_NODCNT)); + case MPCallbackEvent::kMipSolution: + return static_cast(GurobiCallbackGet( + current_gurobi_internal_callback_context_, GRB_CB_MIPSOL_NODCNT)); + default: + LOG(FATAL) << "Node count is supported only for callback events MIP_NODE " + "and MIP_SOL, but was requested at: " + << ToString(Event()); } } @@ -372,29 +372,29 @@ T GurobiMPCallbackContext::GurobiCallbackGet( MPCallbackEvent GurobiMPCallbackContext::Event() { switch (current_gurobi_internal_callback_context_.where) { - case GRB_CB_POLLING: - return MPCallbackEvent::kPolling; - case GRB_CB_PRESOLVE: - return MPCallbackEvent::kPresolve; - case GRB_CB_SIMPLEX: - return MPCallbackEvent::kSimplex; - case GRB_CB_MIP: - return MPCallbackEvent::kMip; - case GRB_CB_MIPSOL: - return MPCallbackEvent::kMipSolution; - case GRB_CB_MIPNODE: - return MPCallbackEvent::kMipNode; - case GRB_CB_MESSAGE: - return MPCallbackEvent::kMessage; - case GRB_CB_BARRIER: - return MPCallbackEvent::kBarrier; - // TODO(b/112427356): in Gurobi 8.0, there is a new callback location. - // case GRB_CB_MULTIOBJ: - // return MPCallbackEvent::kMultiObj; - default: - LOG_FIRST_N(ERROR, 1) << "Gurobi callback at unknown where=" - << current_gurobi_internal_callback_context_.where; - return MPCallbackEvent::kUnknown; + case GRB_CB_POLLING: + return MPCallbackEvent::kPolling; + case GRB_CB_PRESOLVE: + return MPCallbackEvent::kPresolve; + case GRB_CB_SIMPLEX: + return MPCallbackEvent::kSimplex; + case GRB_CB_MIP: + return MPCallbackEvent::kMip; + case GRB_CB_MIPSOL: + return MPCallbackEvent::kMipSolution; + case GRB_CB_MIPNODE: + return MPCallbackEvent::kMipNode; + case GRB_CB_MESSAGE: + return MPCallbackEvent::kMessage; + case GRB_CB_BARRIER: + return MPCallbackEvent::kBarrier; + // TODO(b/112427356): in Gurobi 8.0, there is a new callback location. + // case GRB_CB_MULTIOBJ: + // return MPCallbackEvent::kMultiObj; + default: + LOG_FIRST_N(ERROR, 1) << "Gurobi callback at unknown where=" + << current_gurobi_internal_callback_context_.where; + return MPCallbackEvent::kUnknown; } } @@ -421,9 +421,9 @@ double GurobiMPCallbackContext::VariableValue(const MPVariable *variable) { << ToString(MPCallbackEvent::kMipSolution) << " or " << ToString(MPCallbackEvent::kMipNode) << " but called from: " << ToString(where); - const int gurobi_get_var_param = - where == MPCallbackEvent::kMipNode ? GRB_CB_MIPNODE_REL - : GRB_CB_MIPSOL_SOL; + const int gurobi_get_var_param = where == MPCallbackEvent::kMipNode + ? GRB_CB_MIPNODE_REL + : GRB_CB_MIPSOL_SOL; gurobi_variable_values_.resize(num_gurobi_vars_); CheckedGurobiCall(GRBcbget( @@ -474,14 +474,15 @@ void GurobiMPCallbackContext::AddCut(const LinearRange &cutting_plane) { AddGeneratedConstraint(cutting_plane, GRBcbcut); } -void -GurobiMPCallbackContext::AddLazyConstraint(const LinearRange &lazy_constraint) { +void GurobiMPCallbackContext::AddLazyConstraint( + const LinearRange &lazy_constraint) { CHECK(might_add_lazy_constraints_); const MPCallbackEvent where = Event(); CHECK(where == MPCallbackEvent::kMipNode || where == MPCallbackEvent::kMipSolution) << "Lazy constraints can only be added at MIP_NODE or MIP_SOL, tried to " - "add lazy constraint at: " << ToString(where); + "add lazy constraint at: " + << ToString(where); AddGeneratedConstraint(lazy_constraint, GRBcblazy); } @@ -490,7 +491,8 @@ double GurobiMPCallbackContext::SuggestSolution( const MPCallbackEvent where = Event(); CHECK(where == MPCallbackEvent::kMipNode) << "Feasible solutions can only be added at MIP_NODE, tried to add " - "solution at: " << ToString(where); + "solution at: " + << ToString(where); std::vector full_solution(num_gurobi_vars_, GRB_UNDEFINED); for (const auto &variable_value : solution) { @@ -521,17 +523,15 @@ int STDCALL CallbackImpl(GRBmodel *model, void *gurobi_internal_callback_data, CHECK(callback_with_context != nullptr); CHECK(callback_with_context->context != nullptr); CHECK(callback_with_context->callback != nullptr); - GurobiInternalCallbackContext gurobi_internal_context { - model, gurobi_internal_callback_data, where - } - ; - callback_with_context->context - ->UpdateFromGurobiState(gurobi_internal_context); + GurobiInternalCallbackContext gurobi_internal_context{ + model, gurobi_internal_callback_data, where}; + callback_with_context->context->UpdateFromGurobiState( + gurobi_internal_context); callback_with_context->callback->RunCallback(callback_with_context->context); return 0; } -} // namespace +} // namespace void GurobiInterface::CheckedGurobiCall(int err) const { ::operations_research::CheckedGurobiCall(err, env_); @@ -599,16 +599,19 @@ char GurobiInterface::GetCharAttrElement(const char *name, int index) const { // Creates a LP/MIP instance with the specified name and minimization objective. GurobiInterface::GurobiInterface(MPSolver *const solver, bool mip) - : MPSolverInterface(solver), model_(nullptr), env_(nullptr), mip_(mip), + : MPSolverInterface(solver), + model_(nullptr), + env_(nullptr), + mip_(mip), current_solution_index_(0) { CHECK_OK(LoadGurobiEnvironment(&env_)); - CheckedGurobiCall( - GRBnewmodel(env_, &model_, solver_->name_.c_str(), 0, // numvars - nullptr, // obj - nullptr, // lb - nullptr, // ub - nullptr, // vtype - nullptr)); // varnanes + CheckedGurobiCall(GRBnewmodel(env_, &model_, solver_->name_.c_str(), + 0, // numvars + nullptr, // obj + nullptr, // lb + nullptr, // ub + nullptr, // vtype + nullptr)); // varnanes SetIntAttr(GRB_INT_ATTR_MODELSENSE, maximize_ ? GRB_MAXIMIZE : GRB_MINIMIZE); CheckedGurobiCall(GRBsetintparam(env_, GRB_INT_PAR_THREADS, absl::GetFlag(FLAGS_num_gurobi_threads))); @@ -623,13 +626,13 @@ GurobiInterface::~GurobiInterface() { void GurobiInterface::Reset() { CheckedGurobiCall(GRBfreemodel(model_)); - CheckedGurobiCall( - GRBnewmodel(env_, &model_, solver_->name_.c_str(), 0, // numvars - nullptr, // obj - nullptr, // lb - nullptr, // ub - nullptr, // vtype - nullptr)); // varnames + CheckedGurobiCall(GRBnewmodel(env_, &model_, solver_->name_.c_str(), + 0, // numvars + nullptr, // obj + nullptr, // lb + nullptr, // ub + nullptr, // vtype + nullptr)); // varnames ResetExtractionInformation(); mp_var_to_gurobi_var_.clear(); mp_cons_to_gurobi_linear_cons_.clear(); @@ -771,16 +774,14 @@ void GurobiInterface::BranchingPriorityChangedForVariable(int var_index) { int64 GurobiInterface::iterations() const { double iter; - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; CheckedGurobiCall(GRBgetdblattr(model_, GRB_DBL_ATTR_ITERCOUNT, &iter)); return static_cast(iter); } int64 GurobiInterface::nodes() const { if (mip_) { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; return static_cast(GetDoubleAttr(GRB_DBL_ATTR_NODECOUNT)); } else { LOG(DFATAL) << "Number of nodes only available for discrete problems."; @@ -820,58 +821,57 @@ double GurobiInterface::best_objective_bound() const { } } -MPSolver::BasisStatus -GurobiInterface::TransformGRBVarBasisStatus(int gurobi_basis_status) const { +MPSolver::BasisStatus GurobiInterface::TransformGRBVarBasisStatus( + int gurobi_basis_status) const { switch (gurobi_basis_status) { - case GRB_BASIC: - return MPSolver::BASIC; - case GRB_NONBASIC_LOWER: - return MPSolver::AT_LOWER_BOUND; - case GRB_NONBASIC_UPPER: - return MPSolver::AT_UPPER_BOUND; - case GRB_SUPERBASIC: - return MPSolver::FREE; - default: - LOG(DFATAL) << "Unknown GRB basis status."; - return MPSolver::FREE; + case GRB_BASIC: + return MPSolver::BASIC; + case GRB_NONBASIC_LOWER: + return MPSolver::AT_LOWER_BOUND; + case GRB_NONBASIC_UPPER: + return MPSolver::AT_UPPER_BOUND; + case GRB_SUPERBASIC: + return MPSolver::FREE; + default: + LOG(DFATAL) << "Unknown GRB basis status."; + return MPSolver::FREE; } } -MPSolver::BasisStatus -GurobiInterface::TransformGRBConstraintBasisStatus(int gurobi_basis_status, - int constraint_index) const { +MPSolver::BasisStatus GurobiInterface::TransformGRBConstraintBasisStatus( + int gurobi_basis_status, int constraint_index) const { const int grb_index = mp_cons_to_gurobi_linear_cons_.at(constraint_index); if (grb_index < 0) { LOG(DFATAL) << "Basis status not available for nonlinear constraints."; return MPSolver::FREE; } switch (gurobi_basis_status) { - case GRB_BASIC: - return MPSolver::BASIC; - default: { - // Non basic. - double tolerance = 0.0; - CheckedGurobiCall(GRBgetdblparam(GRBgetenv(model_), - GRB_DBL_PAR_FEASIBILITYTOL, &tolerance)); - const double slack = GetDoubleAttrElement(GRB_DBL_ATTR_SLACK, grb_index); - const char sense = GetCharAttrElement(GRB_CHAR_ATTR_SENSE, grb_index); - VLOG(4) << "constraint " << constraint_index << " , slack = " << slack - << " , sense = " << sense; - if (fabs(slack) <= tolerance) { - switch (sense) { - case GRB_EQUAL: - case GRB_LESS_EQUAL: - return MPSolver::AT_UPPER_BOUND; - case GRB_GREATER_EQUAL: - return MPSolver::AT_LOWER_BOUND; - default: + case GRB_BASIC: + return MPSolver::BASIC; + default: { + // Non basic. + double tolerance = 0.0; + CheckedGurobiCall(GRBgetdblparam(GRBgetenv(model_), + GRB_DBL_PAR_FEASIBILITYTOL, &tolerance)); + const double slack = GetDoubleAttrElement(GRB_DBL_ATTR_SLACK, grb_index); + const char sense = GetCharAttrElement(GRB_CHAR_ATTR_SENSE, grb_index); + VLOG(4) << "constraint " << constraint_index << " , slack = " << slack + << " , sense = " << sense; + if (fabs(slack) <= tolerance) { + switch (sense) { + case GRB_EQUAL: + case GRB_LESS_EQUAL: + return MPSolver::AT_UPPER_BOUND; + case GRB_GREATER_EQUAL: + return MPSolver::AT_LOWER_BOUND; + default: + return MPSolver::FREE; + } + } else { return MPSolver::FREE; } - } else { - return MPSolver::FREE; } } - } } // Returns the basis status of a row. @@ -924,9 +924,9 @@ void GurobiInterface::ExtractNewVariables() { const MPVariable *const var = solver_->variables_.at(j); set_variable_as_extracted(var->index(), true); CheckedGurobiCall(GRBaddvar( - model_, 0, // numnz - nullptr, // vind - nullptr, // vval + model_, 0, // numnz + nullptr, // vind + nullptr, // vval solver_->objective_->GetCoefficient(var), var->lb(), var->ub(), var->integer() && mip_ ? GRB_INTEGER : GRB_CONTINUOUS, var->name().empty() ? nullptr : var->name().c_str())); @@ -958,9 +958,9 @@ void GurobiInterface::ExtractNewVariables() { } } if (!grb_cons_ind.empty()) { - CheckedGurobiCall( - GRBchgcoeffs(model_, grb_cons_ind.size(), grb_cons_ind.data(), - grb_var_ind.data(), coef.data())); + CheckedGurobiCall(GRBchgcoeffs(model_, grb_cons_ind.size(), + grb_cons_ind.data(), grb_var_ind.data(), + coef.data())); } } CheckedGurobiCall(GRBupdatemodel(model_)); @@ -1007,21 +1007,21 @@ void GurobiInterface::ExtractNewConstraints() { // Using GRBaddrangeconstr for constraints that don't require it adds // a slack which is not always removed by presolve. if (ct->lb() == ct->ub()) { - CheckedGurobiCall( - GRBaddconstr(model_, size, grb_vars.data(), coefs.data(), - GRB_EQUAL, ct->lb(), name)); + CheckedGurobiCall(GRBaddconstr(model_, size, grb_vars.data(), + coefs.data(), GRB_EQUAL, ct->lb(), + name)); } else if (ct->lb() == -std::numeric_limits::infinity()) { - CheckedGurobiCall( - GRBaddconstr(model_, size, grb_vars.data(), coefs.data(), - GRB_LESS_EQUAL, ct->ub(), name)); + CheckedGurobiCall(GRBaddconstr(model_, size, grb_vars.data(), + coefs.data(), GRB_LESS_EQUAL, ct->ub(), + name)); } else if (ct->ub() == std::numeric_limits::infinity()) { - CheckedGurobiCall( - GRBaddconstr(model_, size, grb_vars.data(), coefs.data(), - GRB_GREATER_EQUAL, ct->lb(), name)); + CheckedGurobiCall(GRBaddconstr(model_, size, grb_vars.data(), + coefs.data(), GRB_GREATER_EQUAL, + ct->lb(), name)); } else { - CheckedGurobiCall( - GRBaddrangeconstr(model_, size, grb_vars.data(), coefs.data(), - ct->lb(), ct->ub(), name)); + CheckedGurobiCall(GRBaddrangeconstr(model_, size, grb_vars.data(), + coefs.data(), ct->lb(), ct->ub(), + name)); // NOTE(user): range constraints implicitly add an extra variable // to the model. num_gurobi_vars_++; @@ -1087,38 +1087,38 @@ void GurobiInterface::SetDualTolerance(double value) { void GurobiInterface::SetPresolveMode(int value) { switch (value) { - case MPSolverParameters::PRESOLVE_OFF: { - CheckedGurobiCall( - GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_PRESOLVE, false)); - break; - } - case MPSolverParameters::PRESOLVE_ON: { - CheckedGurobiCall( - GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_PRESOLVE, true)); - break; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); - } + case MPSolverParameters::PRESOLVE_OFF: { + CheckedGurobiCall( + GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_PRESOLVE, false)); + break; + } + case MPSolverParameters::PRESOLVE_ON: { + CheckedGurobiCall( + GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_PRESOLVE, true)); + break; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + } } } // Sets the scaling mode. void GurobiInterface::SetScalingMode(int value) { switch (value) { - case MPSolverParameters::SCALING_OFF: - CheckedGurobiCall( - GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_SCALEFLAG, false)); - break; - case MPSolverParameters::SCALING_ON: - CheckedGurobiCall( - GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_SCALEFLAG, true)); - CheckedGurobiCall( - GRBsetdblparam(GRBgetenv(model_), GRB_DBL_PAR_OBJSCALE, 0.0)); - break; - default: - // Leave the parameters untouched. - break; + case MPSolverParameters::SCALING_OFF: + CheckedGurobiCall( + GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_SCALEFLAG, false)); + break; + case MPSolverParameters::SCALING_ON: + CheckedGurobiCall( + GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_SCALEFLAG, true)); + CheckedGurobiCall( + GRBsetdblparam(GRBgetenv(model_), GRB_DBL_PAR_OBJSCALE, 0.0)); + break; + default: + // Leave the parameters untouched. + break; } } @@ -1126,20 +1126,21 @@ void GurobiInterface::SetScalingMode(int value) { // offers automatic selection void GurobiInterface::SetLpAlgorithm(int value) { switch (value) { - case MPSolverParameters::DUAL: - CheckedGurobiCall( - GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, GRB_METHOD_DUAL)); - break; - case MPSolverParameters::PRIMAL: - CheckedGurobiCall(GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, - GRB_METHOD_PRIMAL)); - break; - case MPSolverParameters::BARRIER: - CheckedGurobiCall(GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, - GRB_METHOD_BARRIER)); - break; - default: - SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, value); + case MPSolverParameters::DUAL: + CheckedGurobiCall(GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, + GRB_METHOD_DUAL)); + break; + case MPSolverParameters::PRIMAL: + CheckedGurobiCall(GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, + GRB_METHOD_PRIMAL)); + break; + case MPSolverParameters::BARRIER: + CheckedGurobiCall(GRBsetintparam(GRBgetenv(model_), GRB_INT_PAR_METHOD, + GRB_METHOD_BARRIER)); + break; + default: + SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, + value); } } @@ -1161,8 +1162,8 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters ¶m) { timer.Start(); if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) == - MPSolverParameters::INCREMENTALITY_OFF || ModelIsNonincremental() || - had_nonincremental_change_) { + MPSolverParameters::INCREMENTALITY_OFF || + ModelIsNonincremental() || had_nonincremental_change_) { Reset(); } @@ -1248,28 +1249,28 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters ¶m) { const int solution_count = SolutionCount(); switch (optimization_status) { - case GRB_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case GRB_INFEASIBLE: - result_status_ = MPSolver::INFEASIBLE; - break; - case GRB_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - case GRB_INF_OR_UNBD: - // TODO(user,user): We could introduce our own "infeasible or - // unbounded" status. - result_status_ = MPSolver::INFEASIBLE; - break; - default: { - if (solution_count > 0) { - result_status_ = MPSolver::FEASIBLE; - } else { - result_status_ = MPSolver::NOT_SOLVED; + case GRB_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case GRB_INFEASIBLE: + result_status_ = MPSolver::INFEASIBLE; + break; + case GRB_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + case GRB_INF_OR_UNBD: + // TODO(user,user): We could introduce our own "infeasible or + // unbounded" status. + result_status_ = MPSolver::INFEASIBLE; + break; + default: { + if (solution_count > 0) { + result_status_ = MPSolver::FEASIBLE; + } else { + result_status_ = MPSolver::NOT_SOLVED; + } + break; } - break; - } } if (solution_count > 0 && (result_status_ == MPSolver::FEASIBLE || @@ -1320,17 +1321,15 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters ¶m) { return result_status_; } -absl::optional -GurobiInterface::DirectlySolveProto(const MPModelRequest &request) { +absl::optional GurobiInterface::DirectlySolveProto( + const MPModelRequest &request) { // Here we reuse the Gurobi environment to support single-use license that // forbids creating a second environment if one already exists. const auto status_or = GurobiSolveProto(request, env_); - if (status_or.ok()) - return status_or.value(); + if (status_or.ok()) return status_or.value(); // Special case: if something is not implemented yet, fall back to solving // through MPSolver. - if (absl::IsUnimplemented(status_or.status())) - return absl::nullopt; + if (absl::IsUnimplemented(status_or.status())) return absl::nullopt; if (request.enable_internal_solver_output()) { LOG(INFO) << "Invalid Gurobi status: " << status_or.status(); @@ -1343,8 +1342,7 @@ GurobiInterface::DirectlySolveProto(const MPModelRequest &request) { bool GurobiInterface::NextSolution() { // Next solution only supported for MIP - if (!mip_) - return false; + if (!mip_) return false; // Make sure we have successfully solved the problem and not modified it. if (!CheckSolutionIsSynchronizedAndExists()) { @@ -1404,4 +1402,4 @@ void GurobiInterface::SetCallback(MPCallback *mp_callback) { callback_ = mp_callback; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/gurobi_proto_solver.cc b/ortools/linear_solver/gurobi_proto_solver.cc index 3255ad3208..84e3f6d608 100644 --- a/ortools/linear_solver/gurobi_proto_solver.cc +++ b/ortools/linear_solver/gurobi_proto_solver.cc @@ -37,11 +37,12 @@ namespace operations_research { namespace { constexpr int GRB_OK = 0; -inline absl::Status -GurobiCodeToUtilStatus(int error_code, const char *source_file, int source_line, - const char *statement, GRBenv *const env) { - if (error_code == GRB_OK) - return absl::OkStatus(); +inline absl::Status GurobiCodeToUtilStatus(int error_code, + const char *source_file, + int source_line, + const char *statement, + GRBenv *const env) { + if (error_code == GRB_OK) return absl::OkStatus(); return absl::InvalidArgumentError(absl::StrFormat( "Gurobi error code %d (file '%s', line %d) on '%s': %s", error_code, source_file, source_line, statement, GRBgeterrormsg(env))); @@ -65,17 +66,16 @@ int AddIndicatorConstraint(const MPGeneralConstraintProto &gen_cst, cst.mutable_coefficient()->mutable_data(), cst.upper_bound() == cst.lower_bound() ? GRB_EQUAL : GRB_GREATER_EQUAL, cst.lower_bound()); - if (status != GRB_OK) - return status; + if (status != GRB_OK) return status; } if (cst.upper_bound() < std::numeric_limits::infinity() && cst.lower_bound() != cst.upper_bound()) { - return GRBaddgenconstrIndicator( - gurobi_model, gen_cst.name().c_str(), ind_cst.var_index(), - ind_cst.var_value(), cst.var_index_size(), - cst.mutable_var_index()->mutable_data(), - cst.mutable_coefficient()->mutable_data(), GRB_LESS_EQUAL, - cst.upper_bound()); + return GRBaddgenconstrIndicator(gurobi_model, gen_cst.name().c_str(), + ind_cst.var_index(), ind_cst.var_value(), + cst.var_index_size(), + cst.mutable_var_index()->mutable_data(), + cst.mutable_coefficient()->mutable_data(), + GRB_LESS_EQUAL, cst.upper_bound()); } return GRB_OK; @@ -103,14 +103,14 @@ int AddSosConstraint(const MPSosConstraint &sos_cst, GRBmodel *gurobi_model, std::iota(tmp_weights->begin(), tmp_weights->end(), 1); } - std::vector types = { sos_cst.type() == MPSosConstraint::SOS1_DEFAULT - ? GRB_SOS_TYPE1 - : GRB_SOS_TYPE2 }; - std::vector begins = { 0 }; + std::vector types = {sos_cst.type() == MPSosConstraint::SOS1_DEFAULT + ? GRB_SOS_TYPE1 + : GRB_SOS_TYPE2}; + std::vector begins = {0}; return GRBaddsos( - gurobi_model, /*numsos=*/ 1, /*nummembers=*/ sos_cst.var_index_size(), - /*types=*/ types.data(), /*beg=*/ begins.data(), - /*ind=*/ tmp_variables->data(), /*weight*/ tmp_weights->data()); + gurobi_model, /*numsos=*/1, /*nummembers=*/sos_cst.var_index_size(), + /*types=*/types.data(), /*beg=*/begins.data(), + /*ind=*/tmp_variables->data(), /*weight*/ tmp_weights->data()); } int AddQuadraticConstraint(const MPGeneralConstraintProto &gen_cst, @@ -121,35 +121,32 @@ int AddQuadraticConstraint(const MPGeneralConstraintProto &gen_cst, CHECK(gen_cst.has_quadratic_constraint()); const MPQuadraticConstraint &quad_cst = gen_cst.quadratic_constraint(); - auto addqconstr = [](GRBmodel * gurobi_model, MPQuadraticConstraint quad_cst, - char sense, double rhs, const std::string & name) { + auto addqconstr = [](GRBmodel *gurobi_model, MPQuadraticConstraint quad_cst, + char sense, double rhs, const std::string &name) { return GRBaddqconstr( - gurobi_model, /*numlnz=*/ quad_cst.var_index_size(), - /*lind=*/ quad_cst.mutable_var_index()->mutable_data(), - /*lval=*/ quad_cst.mutable_coefficient()->mutable_data(), - /*numqnz=*/ quad_cst.qvar1_index_size(), - /*qrow=*/ quad_cst.mutable_qvar1_index()->mutable_data(), - /*qcol=*/ quad_cst.mutable_qvar2_index()->mutable_data(), - /*qval=*/ quad_cst.mutable_qcoefficient()->mutable_data(), - /*sense=*/ sense, /*rhs=*/ rhs, /*QCname=*/ name.c_str()); - } - ; + gurobi_model, /*numlnz=*/quad_cst.var_index_size(), + /*lind=*/quad_cst.mutable_var_index()->mutable_data(), + /*lval=*/quad_cst.mutable_coefficient()->mutable_data(), + /*numqnz=*/quad_cst.qvar1_index_size(), + /*qrow=*/quad_cst.mutable_qvar1_index()->mutable_data(), + /*qcol=*/quad_cst.mutable_qvar2_index()->mutable_data(), + /*qval=*/quad_cst.mutable_qcoefficient()->mutable_data(), + /*sense=*/sense, /*rhs=*/rhs, /*QCname=*/name.c_str()); + }; if (quad_cst.has_lower_bound() && quad_cst.lower_bound() > -kInfinity) { const int grb_status = addqconstr(gurobi_model, gen_cst.quadratic_constraint(), GRB_GREATER_EQUAL, quad_cst.lower_bound(), gen_cst.has_name() ? gen_cst.name() + "_lb" : ""); - if (grb_status != GRB_OK) - return grb_status; + if (grb_status != GRB_OK) return grb_status; } if (quad_cst.has_upper_bound() && quad_cst.upper_bound() < kInfinity) { const int grb_status = addqconstr(gurobi_model, gen_cst.quadratic_constraint(), GRB_LESS_EQUAL, quad_cst.upper_bound(), gen_cst.has_name() ? gen_cst.name() + "_ub" : ""); - if (grb_status != GRB_OK) - return grb_status; + if (grb_status != GRB_OK) return grb_status; } return GRB_OK; @@ -162,10 +159,10 @@ int AddAndConstraint(const MPGeneralConstraintProto &gen_cst, auto and_cst = gen_cst.and_constraint(); return GRBaddgenconstrAnd( - gurobi_model, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ and_cst.resultant_var_index(), - /*nvars=*/ and_cst.var_index_size(), - /*vars=*/ and_cst.mutable_var_index()->mutable_data()); + gurobi_model, /*name=*/gen_cst.name().c_str(), + /*resvar=*/and_cst.resultant_var_index(), + /*nvars=*/and_cst.var_index_size(), + /*vars=*/and_cst.mutable_var_index()->mutable_data()); } int AddOrConstraint(const MPGeneralConstraintProto &gen_cst, @@ -174,11 +171,10 @@ int AddOrConstraint(const MPGeneralConstraintProto &gen_cst, CHECK(tmp_variables != nullptr); auto or_cst = gen_cst.or_constraint(); - return GRBaddgenconstrOr( - gurobi_model, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ or_cst.resultant_var_index(), - /*nvars=*/ or_cst.var_index_size(), - /*vars=*/ or_cst.mutable_var_index()->mutable_data()); + return GRBaddgenconstrOr(gurobi_model, /*name=*/gen_cst.name().c_str(), + /*resvar=*/or_cst.resultant_var_index(), + /*nvars=*/or_cst.var_index_size(), + /*vars=*/or_cst.mutable_var_index()->mutable_data()); } int AddMinConstraint(const MPGeneralConstraintProto &gen_cst, @@ -188,11 +184,11 @@ int AddMinConstraint(const MPGeneralConstraintProto &gen_cst, auto min_cst = gen_cst.min_constraint(); return GRBaddgenconstrMin( - gurobi_model, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ min_cst.resultant_var_index(), - /*nvars=*/ min_cst.var_index_size(), - /*vars=*/ min_cst.mutable_var_index()->mutable_data(), - /*constant=*/ min_cst.has_constant() + gurobi_model, /*name=*/gen_cst.name().c_str(), + /*resvar=*/min_cst.resultant_var_index(), + /*nvars=*/min_cst.var_index_size(), + /*vars=*/min_cst.mutable_var_index()->mutable_data(), + /*constant=*/min_cst.has_constant() ? min_cst.constant() : std::numeric_limits::infinity()); } @@ -204,15 +200,15 @@ int AddMaxConstraint(const MPGeneralConstraintProto &gen_cst, auto max_cst = gen_cst.max_constraint(); return GRBaddgenconstrMax( - gurobi_model, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ max_cst.resultant_var_index(), - /*nvars=*/ max_cst.var_index_size(), - /*vars=*/ max_cst.mutable_var_index()->mutable_data(), - /*constant=*/ max_cst.has_constant() + gurobi_model, /*name=*/gen_cst.name().c_str(), + /*resvar=*/max_cst.resultant_var_index(), + /*nvars=*/max_cst.var_index_size(), + /*vars=*/max_cst.mutable_var_index()->mutable_data(), + /*constant=*/max_cst.has_constant() ? max_cst.constant() : -std::numeric_limits::infinity()); } -} // namespace +} // namespace absl::Status SetSolverSpecificParameters(const std::string ¶meters, GRBenv *gurobi) { @@ -260,18 +256,16 @@ absl::Status SetSolverSpecificParameters(const std::string ¶meters, key_value[1]); } - if (error_message.empty()) - return absl::OkStatus(); + if (error_message.empty()) return absl::OkStatus(); return absl::InvalidArgumentError(error_message); } -absl::StatusOr -GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { +absl::StatusOr GurobiSolveProto( + const MPModelRequest &request, GRBenv *gurobi_env) { MPSolutionResponse response; const absl::optional > optional_model = ExtractValidMPModelOrPopulateResponseStatus(request, &response); - if (!optional_model) - return response; + if (!optional_model) return response; const MPModelProto &model = optional_model->get(); // We set `gurobi_env` to point to a new environment if no existing one is @@ -294,20 +288,20 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { GRBmodel *gurobi_model = nullptr; auto gurobi_model_deleter = absl::MakeCleanup([&]() { const int error_code = GRBfreemodel(gurobi_model); - LOG_IF(DFATAL, error_code != GRB_OK) << "GRBfreemodel failed with error " - << error_code << ": " - << GRBgeterrormsg(gurobi_env); + LOG_IF(DFATAL, error_code != GRB_OK) + << "GRBfreemodel failed with error " << error_code << ": " + << GRBgeterrormsg(gurobi_env); }); // `gurobi_env` references ther GRBenv argument. -#define RETURN_IF_GUROBI_ERROR(x) \ - RETURN_IF_ERROR( \ +#define RETURN_IF_GUROBI_ERROR(x) \ + RETURN_IF_ERROR( \ GurobiCodeToUtilStatus(x, __FILE__, __LINE__, #x, gurobi_env)); RETURN_IF_GUROBI_ERROR( GRBnewmodel(gurobi_env, &gurobi_model, model.name().c_str(), - /*numvars=*/ 0, /*obj=*/ nullptr, /*lb=*/ nullptr, - /*ub=*/ nullptr, /*vtype=*/ nullptr, /*varnames=*/ nullptr)); + /*numvars=*/0, /*obj=*/nullptr, /*lb=*/nullptr, + /*ub=*/nullptr, /*vtype=*/nullptr, /*varnames=*/nullptr)); if (request.has_solver_specific_parameters()) { const auto parameters_status = SetSolverSpecificParameters( @@ -319,9 +313,9 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { } } if (request.solver_time_limit_seconds() > 0) { - RETURN_IF_GUROBI_ERROR( - GRBsetdblparam(GRBgetenv(gurobi_model), GRB_DBL_PAR_TIMELIMIT, - request.solver_time_limit_seconds())); + RETURN_IF_GUROBI_ERROR(GRBsetdblparam(GRBgetenv(gurobi_model), + GRB_DBL_PAR_TIMELIMIT, + request.solver_time_limit_seconds())); } RETURN_IF_GUROBI_ERROR( GRBsetintparam(GRBgetenv(gurobi_model), GRB_INT_PAR_OUTPUTFLAG, @@ -341,17 +335,15 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { lb[v] = variable.lower_bound(); ub[v] = variable.upper_bound(); ctype[v] = variable.is_integer() ? GRB_INTEGER : GRB_CONTINUOUS; - if (variable.is_integer()) - has_integer_variables = true; - if (!variable.name().empty()) - varnames[v] = variable.name().c_str(); + if (variable.is_integer()) has_integer_variables = true; + if (!variable.name().empty()) varnames[v] = variable.name().c_str(); } RETURN_IF_GUROBI_ERROR( GRBaddvars(gurobi_model, variable_size, 0, nullptr, nullptr, nullptr, - /*obj=*/ obj_coeffs.data(), /*lb=*/ lb.data(), - /*ub=*/ ub.data(), /*vtype=*/ ctype.data(), - /*varnames=*/ const_cast(varnames.data()))); + /*obj=*/obj_coeffs.data(), /*lb=*/lb.data(), + /*ub=*/ub.data(), /*vtype=*/ctype.data(), + /*varnames=*/const_cast(varnames.data()))); // Set solution hints if any. for (int i = 0; i < model.solution_hint().var_index_size(); ++i) { @@ -377,82 +369,82 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { // a slack which is not always removed by presolve. if (constraint.lower_bound() == constraint.upper_bound()) { RETURN_IF_GUROBI_ERROR(GRBaddconstr( - gurobi_model, /*numnz=*/ size, /*cind=*/ ct_variables.data(), - /*cval=*/ ct_coefficients.data(), /*sense=*/ GRB_EQUAL, - /*rhs=*/ constraint.lower_bound(), - /*constrname=*/ constraint.name().c_str())); + gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(), + /*cval=*/ct_coefficients.data(), /*sense=*/GRB_EQUAL, + /*rhs=*/constraint.lower_bound(), + /*constrname=*/constraint.name().c_str())); } else if (constraint.lower_bound() == -std::numeric_limits::infinity()) { RETURN_IF_GUROBI_ERROR(GRBaddconstr( - gurobi_model, /*numnz=*/ size, /*cind=*/ ct_variables.data(), - /*cval=*/ ct_coefficients.data(), /*sense=*/ GRB_LESS_EQUAL, - /*rhs=*/ constraint.upper_bound(), - /*constrname=*/ constraint.name().c_str())); + gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(), + /*cval=*/ct_coefficients.data(), /*sense=*/GRB_LESS_EQUAL, + /*rhs=*/constraint.upper_bound(), + /*constrname=*/constraint.name().c_str())); } else if (constraint.upper_bound() == std::numeric_limits::infinity()) { RETURN_IF_GUROBI_ERROR(GRBaddconstr( - gurobi_model, /*numnz=*/ size, /*cind=*/ ct_variables.data(), - /*cval=*/ ct_coefficients.data(), /*sense=*/ GRB_GREATER_EQUAL, - /*rhs=*/ constraint.lower_bound(), - /*constrname=*/ constraint.name().c_str())); + gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(), + /*cval=*/ct_coefficients.data(), /*sense=*/GRB_GREATER_EQUAL, + /*rhs=*/constraint.lower_bound(), + /*constrname=*/constraint.name().c_str())); } else { RETURN_IF_GUROBI_ERROR(GRBaddrangeconstr( - gurobi_model, /*numnz=*/ size, /*cind=*/ ct_variables.data(), - /*cval=*/ ct_coefficients.data(), - /*lower=*/ constraint.lower_bound(), - /*upper=*/ constraint.upper_bound(), - /*constrname=*/ constraint.name().c_str())); + gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(), + /*cval=*/ct_coefficients.data(), + /*lower=*/constraint.lower_bound(), + /*upper=*/constraint.upper_bound(), + /*constrname=*/constraint.name().c_str())); } } for (const auto &gen_cst : model.general_constraint()) { switch (gen_cst.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: { - RETURN_IF_GUROBI_ERROR(AddIndicatorConstraint( - gen_cst, gurobi_model, &ct_variables, &ct_coefficients)); - break; - } - case MPGeneralConstraintProto::kSosConstraint: { - RETURN_IF_GUROBI_ERROR( - AddSosConstraint(gen_cst.sos_constraint(), gurobi_model, - &ct_variables, &ct_coefficients)); - break; - } - case MPGeneralConstraintProto::kQuadraticConstraint: { - RETURN_IF_GUROBI_ERROR(AddQuadraticConstraint(gen_cst, gurobi_model)); - break; - } - case MPGeneralConstraintProto::kAbsConstraint: { - RETURN_IF_GUROBI_ERROR(GRBaddgenconstrAbs( - gurobi_model, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ gen_cst.abs_constraint().resultant_var_index(), - /*argvar=*/ gen_cst.abs_constraint().var_index())); - break; - } - case MPGeneralConstraintProto::kAndConstraint: { - RETURN_IF_GUROBI_ERROR( - AddAndConstraint(gen_cst, gurobi_model, &ct_variables)); - break; - } - case MPGeneralConstraintProto::kOrConstraint: { - RETURN_IF_GUROBI_ERROR( - AddOrConstraint(gen_cst, gurobi_model, &ct_variables)); - break; - } - case MPGeneralConstraintProto::kMinConstraint: { - RETURN_IF_GUROBI_ERROR( - AddMinConstraint(gen_cst, gurobi_model, &ct_variables)); - break; - } - case MPGeneralConstraintProto::kMaxConstraint: { - RETURN_IF_GUROBI_ERROR( - AddMaxConstraint(gen_cst, gurobi_model, &ct_variables)); - break; - } - default: - return absl::UnimplementedError( - absl::StrFormat("General constraints of type %i not supported.", - gen_cst.general_constraint_case())); + case MPGeneralConstraintProto::kIndicatorConstraint: { + RETURN_IF_GUROBI_ERROR(AddIndicatorConstraint( + gen_cst, gurobi_model, &ct_variables, &ct_coefficients)); + break; + } + case MPGeneralConstraintProto::kSosConstraint: { + RETURN_IF_GUROBI_ERROR(AddSosConstraint(gen_cst.sos_constraint(), + gurobi_model, &ct_variables, + &ct_coefficients)); + break; + } + case MPGeneralConstraintProto::kQuadraticConstraint: { + RETURN_IF_GUROBI_ERROR(AddQuadraticConstraint(gen_cst, gurobi_model)); + break; + } + case MPGeneralConstraintProto::kAbsConstraint: { + RETURN_IF_GUROBI_ERROR(GRBaddgenconstrAbs( + gurobi_model, /*name=*/gen_cst.name().c_str(), + /*resvar=*/gen_cst.abs_constraint().resultant_var_index(), + /*argvar=*/gen_cst.abs_constraint().var_index())); + break; + } + case MPGeneralConstraintProto::kAndConstraint: { + RETURN_IF_GUROBI_ERROR( + AddAndConstraint(gen_cst, gurobi_model, &ct_variables)); + break; + } + case MPGeneralConstraintProto::kOrConstraint: { + RETURN_IF_GUROBI_ERROR( + AddOrConstraint(gen_cst, gurobi_model, &ct_variables)); + break; + } + case MPGeneralConstraintProto::kMinConstraint: { + RETURN_IF_GUROBI_ERROR( + AddMinConstraint(gen_cst, gurobi_model, &ct_variables)); + break; + } + case MPGeneralConstraintProto::kMaxConstraint: { + RETURN_IF_GUROBI_ERROR( + AddMaxConstraint(gen_cst, gurobi_model, &ct_variables)); + break; + } + default: + return absl::UnimplementedError( + absl::StrFormat("General constraints of type %i not supported.", + gen_cst.general_constraint_case())); } } } @@ -465,10 +457,10 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { MPQuadraticObjective qobj = model.quadratic_objective(); if (qobj.coefficient_size() > 0) { RETURN_IF_GUROBI_ERROR( - GRBaddqpterms(gurobi_model, /*numqnz=*/ qobj.coefficient_size(), - /*qrow=*/ qobj.mutable_qvar1_index()->mutable_data(), - /*qcol=*/ qobj.mutable_qvar2_index()->mutable_data(), - /*qval=*/ qobj.mutable_coefficient()->mutable_data())); + GRBaddqpterms(gurobi_model, /*numqnz=*/qobj.coefficient_size(), + /*qrow=*/qobj.mutable_qvar1_index()->mutable_data(), + /*qcol=*/qobj.mutable_qvar2_index()->mutable_data(), + /*qval=*/qobj.mutable_coefficient()->mutable_data())); } } @@ -482,32 +474,32 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { RETURN_IF_GUROBI_ERROR( GRBgetintattr(gurobi_model, GRB_INT_ATTR_SOLCOUNT, &solution_count)); switch (optimization_status) { - case GRB_OPTIMAL: - response.set_status(MPSOLVER_OPTIMAL); - break; - case GRB_INF_OR_UNBD: - DLOG(INFO) << "Gurobi solve returned GRB_INF_OR_UNBD, which we treat as " - "INFEASIBLE even though it may mean UNBOUNDED."; - response.set_status_str( - "The model may actually be unbounded: Gurobi returned " - "GRB_INF_OR_UNBD"); - ABSL_FALLTHROUGH_INTENDED; - case GRB_INFEASIBLE: - response.set_status(MPSOLVER_INFEASIBLE); - break; - case GRB_UNBOUNDED: - response.set_status(MPSOLVER_UNBOUNDED); - break; - default: { - if (solution_count > 0) { - response.set_status(MPSOLVER_FEASIBLE); - } else { - response.set_status(MPSOLVER_NOT_SOLVED); + case GRB_OPTIMAL: + response.set_status(MPSOLVER_OPTIMAL); + break; + case GRB_INF_OR_UNBD: + DLOG(INFO) << "Gurobi solve returned GRB_INF_OR_UNBD, which we treat as " + "INFEASIBLE even though it may mean UNBOUNDED."; response.set_status_str( - absl::StrFormat("Gurobi status code %d", optimization_status)); + "The model may actually be unbounded: Gurobi returned " + "GRB_INF_OR_UNBD"); + ABSL_FALLTHROUGH_INTENDED; + case GRB_INFEASIBLE: + response.set_status(MPSOLVER_INFEASIBLE); + break; + case GRB_UNBOUNDED: + response.set_status(MPSOLVER_UNBOUNDED); + break; + default: { + if (solution_count > 0) { + response.set_status(MPSOLVER_FEASIBLE); + } else { + response.set_status(MPSOLVER_NOT_SOLVED); + response.set_status_str( + absl::StrFormat("Gurobi status code %d", optimization_status)); + } + break; } - break; - } } if (solution_count > 0 && (response.status() == MPSOLVER_FEASIBLE || @@ -553,4 +545,4 @@ GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env) { return response; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/gurobi_proto_solver.h b/ortools/linear_solver/gurobi_proto_solver.h index 13b45a7757..845de30c20 100644 --- a/ortools/linear_solver/gurobi_proto_solver.h +++ b/ortools/linear_solver/gurobi_proto_solver.h @@ -15,8 +15,8 @@ #define OR_TOOLS_LINEAR_SOLVER_GUROBI_PROTO_SOLVER_H_ #include "absl/status/statusor.h" -#include "ortools/linear_solver/linear_solver.pb.h" #include "ortools/linear_solver/gurobi_environment.h" +#include "ortools/linear_solver/linear_solver.pb.h" namespace operations_research { @@ -29,9 +29,8 @@ namespace operations_research { // // Please note though that the provided environment should not be actively used // by another thread at the same time. -absl::StatusOr - GurobiSolveProto(const MPModelRequest &request, - GRBenv *gurobi_env = nullptr); +absl::StatusOr GurobiSolveProto( + const MPModelRequest &request, GRBenv *gurobi_env = nullptr); // Set parameters specified in the string. The format of the string is a series // of tokens separated by either '\n' or by ',' characters. @@ -45,5 +44,5 @@ absl::StatusOr // token is unrecognized. absl::Status SetSolverSpecificParameters(const std::string ¶meters, GRBenv *gurobi); -} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_GUROBI_PROTO_SOLVER_H_ +} // namespace operations_research +#endif // OR_TOOLS_LINEAR_SOLVER_GUROBI_PROTO_SOLVER_H_ diff --git a/ortools/linear_solver/linear_expr.cc b/ortools/linear_solver/linear_expr.cc index e61fa4faad..30b90b059d 100644 --- a/ortools/linear_solver/linear_expr.cc +++ b/ortools/linear_solver/linear_expr.cc @@ -114,7 +114,7 @@ void AppendOffset(const double offset, const bool is_first, std::string *s) { } } -} // namespace +} // namespace std::string LinearExpr::ToString() const { std::vector vars_in_order; @@ -122,9 +122,9 @@ std::string LinearExpr::ToString() const { vars_in_order.push_back(var_val_pair.first); } std::sort(vars_in_order.begin(), vars_in_order.end(), - [](const MPVariable * v, const MPVariable * u) { - return v->index() < u->index(); - }); + [](const MPVariable *v, const MPVariable *u) { + return v->index() < u->index(); + }); std::string result; bool is_first = true; for (const MPVariable *var : vars_in_order) { @@ -166,7 +166,8 @@ LinearExpr operator*(double lhs, LinearExpr rhs) { LinearRange::LinearRange(double lower_bound, const LinearExpr &linear_expr, double upper_bound) - : lower_bound_(lower_bound), linear_expr_(linear_expr), + : lower_bound_(lower_bound), + linear_expr_(linear_expr), upper_bound_(upper_bound) { lower_bound_ -= linear_expr_.offset(); upper_bound_ -= linear_expr_.offset(); @@ -183,4 +184,4 @@ LinearRange operator>=(const LinearExpr &lhs, const LinearExpr &rhs) { return LinearRange(0, lhs - rhs, std::numeric_limits::infinity()); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/linear_expr.h b/ortools/linear_solver/linear_expr.h index 89fb2eaf0b..e7238b3c25 100644 --- a/ortools/linear_solver/linear_expr.h +++ b/ortools/linear_solver/linear_expr.h @@ -112,17 +112,17 @@ class MPVariable; * but is not obligated to do so. */ class LinearExpr { -public: + public: LinearExpr(); /// Possible implicit conversions are intentional. - LinearExpr(double constant); // NOLINT + LinearExpr(double constant); // NOLINT /*** * Possible implicit conversions are intentional. * * Warning: var is not owned. */ - LinearExpr(const MPVariable *var); // NOLINT + LinearExpr(const MPVariable *var); // NOLINT /** * Returns 1-var. @@ -157,7 +157,7 @@ public: */ std::string ToString() const; -private: + private: double offset_; absl::flat_hash_map terms_; }; @@ -190,7 +190,7 @@ LinearExpr operator*(double lhs, LinearExpr rhs); \endcode */ class LinearRange { -public: + public: LinearRange() : lower_bound_(0), upper_bound_(0) {} /** * The bounds of the linear range are updated so that they include the offset @@ -206,7 +206,7 @@ public: const LinearExpr &linear_expr() const { return linear_expr_; } double upper_bound() const { return upper_bound_; } -private: + private: double lower_bound_; // invariant: linear_expr_.offset() == 0. LinearExpr linear_expr_; @@ -220,6 +220,6 @@ LinearRange operator>=(const LinearExpr &lhs, const LinearExpr &rhs); // TODO(user,user): explore defining more overloads to support: // solver.AddRowConstraint(0.0 <= x + y + z <= 1.0); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_EXPR_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_EXPR_H_ diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 3764d3bafa..f16dfd78fa 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -64,24 +64,24 @@ namespace operations_research { bool SolverTypeIsMip(MPModelRequest::SolverType solver_type) { switch (solver_type) { - case MPModelRequest::GLOP_LINEAR_PROGRAMMING: - case MPModelRequest::CLP_LINEAR_PROGRAMMING: - case MPModelRequest::GLPK_LINEAR_PROGRAMMING: - case MPModelRequest::GUROBI_LINEAR_PROGRAMMING: - case MPModelRequest::XPRESS_LINEAR_PROGRAMMING: - case MPModelRequest::CPLEX_LINEAR_PROGRAMMING: - return false; + case MPModelRequest::GLOP_LINEAR_PROGRAMMING: + case MPModelRequest::CLP_LINEAR_PROGRAMMING: + case MPModelRequest::GLPK_LINEAR_PROGRAMMING: + case MPModelRequest::GUROBI_LINEAR_PROGRAMMING: + case MPModelRequest::XPRESS_LINEAR_PROGRAMMING: + case MPModelRequest::CPLEX_LINEAR_PROGRAMMING: + return false; - case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::GLPK_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::CBC_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::KNAPSACK_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::BOP_INTEGER_PROGRAMMING: - case MPModelRequest::SAT_INTEGER_PROGRAMMING: - case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: - case MPModelRequest::CPLEX_MIXED_INTEGER_PROGRAMMING: - return true; + case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::GLPK_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::CBC_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::KNAPSACK_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::BOP_INTEGER_PROGRAMMING: + case MPModelRequest::SAT_INTEGER_PROGRAMMING: + case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: + case MPModelRequest::CPLEX_MIXED_INTEGER_PROGRAMMING: + return true; } LOG(DFATAL) << "Invalid SolverType: " << solver_type; return false; @@ -89,15 +89,13 @@ bool SolverTypeIsMip(MPModelRequest::SolverType solver_type) { double MPConstraint::GetCoefficient(const MPVariable *const var) const { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; - if (var == nullptr) - return 0.0; + if (var == nullptr) return 0.0; return gtl::FindWithDefault(coefficients_, var, 0.0); } void MPConstraint::SetCoefficient(const MPVariable *const var, double coeff) { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; - if (var == nullptr) - return; + if (var == nullptr) return; if (coeff == 0.0) { auto it = coefficients_.find(var); // If setting a coefficient to 0 when this coefficient did not @@ -140,8 +138,7 @@ double MPConstraint::dual_value() const { LOG(DFATAL) << "Dual value only available for continuous problems"; return 0.0; } - if (!interface_->CheckSolutionIsSynchronizedAndExists()) - return 0.0; + if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0; return dual_value_; } @@ -173,21 +170,18 @@ bool MPConstraint::ContainsNewVariables() { double MPObjective::GetCoefficient(const MPVariable *const var) const { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; - if (var == nullptr) - return 0.0; + if (var == nullptr) return 0.0; return gtl::FindWithDefault(coefficients_, var, 0.0); } void MPObjective::SetCoefficient(const MPVariable *const var, double coeff) { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; - if (var == nullptr) - return; + if (var == nullptr) return; if (coeff == 0.0) { auto it = coefficients_.find(var); // See the discussion on MPConstraint::SetCoefficient() for 0 coefficients, // the same reasoning applies here. - if (it == coefficients_.end() || it->second == 0.0) - return; + if (it == coefficients_.end() || it->second == 0.0) return; it->second = 0.0; } else { coefficients_[var] = coeff; @@ -208,7 +202,7 @@ void CheckLinearExpr(const MPSolver &solver, const LinearExpr &linear_expr) { "MPVariable* directly?"; } } -} // namespace +} // namespace void MPObjective::OptimizeLinearExpr(const LinearExpr &linear_expr, bool is_maximization) { @@ -268,8 +262,7 @@ double MPObjective::BestBound() const { // ----- MPVariable ----- double MPVariable::solution_value() const { - if (!interface_->CheckSolutionIsSynchronizedAndExists()) - return 0.0; + if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0; // If the underlying solver supports integer variables, and this is an integer // variable, we round the solution value (i.e., clients usually expect precise // integer values for integer variables). @@ -278,8 +271,7 @@ double MPVariable::solution_value() const { } double MPVariable::unrounded_solution_value() const { - if (!interface_->CheckSolutionIsSynchronizedAndExists()) - return 0.0; + if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0; return solution_value_; } @@ -288,8 +280,7 @@ double MPVariable::reduced_cost() const { LOG(DFATAL) << "Reduced cost only available for continuous problems"; return 0.0; } - if (!interface_->CheckSolutionIsSynchronizedAndExists()) - return 0.0; + if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0; return reduced_cost_; } @@ -324,8 +315,7 @@ void MPVariable::SetInteger(bool integer) { } void MPVariable::SetBranchingPriority(int priority) { - if (priority == branching_priority_) - return; + if (priority == branching_priority_) return; branching_priority_ = priority; interface_->BranchingPriorityChangedForVariable(index_); } @@ -353,8 +343,8 @@ absl::Status MPSolver::SetNumThreads(int num_threads) { return status; } -bool -MPSolver::SetSolverSpecificParametersAsString(const std::string ¶meters) { +bool MPSolver::SetSolverSpecificParametersAsString( + const std::string ¶meters) { solver_specific_parameter_string_ = parameters; return interface_->SetSolverSpecificParametersAsString(parameters); } @@ -392,53 +382,53 @@ namespace { MPSolverInterface *BuildSolverInterface(MPSolver *const solver) { DCHECK(solver != nullptr); switch (solver->ProblemType()) { - case MPSolver::BOP_INTEGER_PROGRAMMING: - return BuildBopInterface(solver); - case MPSolver::SAT_INTEGER_PROGRAMMING: - return BuildSatInterface(solver); - case MPSolver::GLOP_LINEAR_PROGRAMMING: - return BuildGLOPInterface(solver); + case MPSolver::BOP_INTEGER_PROGRAMMING: + return BuildBopInterface(solver); + case MPSolver::SAT_INTEGER_PROGRAMMING: + return BuildSatInterface(solver); + case MPSolver::GLOP_LINEAR_PROGRAMMING: + return BuildGLOPInterface(solver); #if defined(USE_GLPK) - case MPSolver::GLPK_LINEAR_PROGRAMMING: - return BuildGLPKInterface(false, solver); - case MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING: - return BuildGLPKInterface(true, solver); + case MPSolver::GLPK_LINEAR_PROGRAMMING: + return BuildGLPKInterface(false, solver); + case MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING: + return BuildGLPKInterface(true, solver); #endif #if defined(USE_CLP) || defined(USE_CBC) - case MPSolver::CLP_LINEAR_PROGRAMMING: - return BuildCLPInterface(solver); + case MPSolver::CLP_LINEAR_PROGRAMMING: + return BuildCLPInterface(solver); #endif #if defined(USE_CBC) - case MPSolver::CBC_MIXED_INTEGER_PROGRAMMING: - return BuildCBCInterface(solver); + case MPSolver::CBC_MIXED_INTEGER_PROGRAMMING: + return BuildCBCInterface(solver); #endif #if defined(USE_SCIP) - case MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING: - return BuildSCIPInterface(solver); + case MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING: + return BuildSCIPInterface(solver); #endif - case MPSolver::GUROBI_LINEAR_PROGRAMMING: - return BuildGurobiInterface(false, solver); - case MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING: - return BuildGurobiInterface(true, solver); + case MPSolver::GUROBI_LINEAR_PROGRAMMING: + return BuildGurobiInterface(false, solver); + case MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING: + return BuildGurobiInterface(true, solver); #if defined(USE_CPLEX) - case MPSolver::CPLEX_LINEAR_PROGRAMMING: - return BuildCplexInterface(false, solver); - case MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING: - return BuildCplexInterface(true, solver); + case MPSolver::CPLEX_LINEAR_PROGRAMMING: + return BuildCplexInterface(false, solver); + case MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING: + return BuildCplexInterface(true, solver); #endif #if defined(USE_XPRESS) - case MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING: - return BuildXpressInterface(true, solver); - case MPSolver::XPRESS_LINEAR_PROGRAMMING: - return BuildXpressInterface(false, solver); + case MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING: + return BuildXpressInterface(true, solver); + case MPSolver::XPRESS_LINEAR_PROGRAMMING: + return BuildXpressInterface(false, solver); #endif - default: - // TODO(user): Revert to the best *available* interface. - LOG(FATAL) << "Linear solver not recognized."; + default: + // TODO(user): Revert to the best *available* interface. + LOG(FATAL) << "Linear solver not recognized."; } return nullptr; } -} // namespace +} // namespace namespace { int NumDigits(int n) { @@ -450,11 +440,12 @@ int NumDigits(int n) { return static_cast(std::max(1.0, log10(static_cast(n)) + 1.0)); #endif } -} // namespace +} // namespace MPSolver::MPSolver(const std::string &name, OptimizationProblemType problem_type) - : name_(name), problem_type_(problem_type), + : name_(name), + problem_type_(problem_type), construction_time_(absl::Now()) { interface_.reset(BuildSolverInterface(this)); if (absl::GetFlag(FLAGS_linear_solver_enable_verbose_output)) { @@ -468,8 +459,7 @@ MPSolver::~MPSolver() { Clear(); } // static bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) { #ifdef USE_CLP - if (problem_type == CLP_LINEAR_PROGRAMMING) - return true; + if (problem_type == CLP_LINEAR_PROGRAMMING) return true; #endif #ifdef USE_GLPK if (problem_type == GLPK_LINEAR_PROGRAMMING || @@ -477,23 +467,18 @@ bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) { return true; } #endif - if (problem_type == BOP_INTEGER_PROGRAMMING) - return true; - if (problem_type == SAT_INTEGER_PROGRAMMING) - return true; - if (problem_type == GLOP_LINEAR_PROGRAMMING) - return true; + if (problem_type == BOP_INTEGER_PROGRAMMING) return true; + if (problem_type == SAT_INTEGER_PROGRAMMING) return true; + if (problem_type == GLOP_LINEAR_PROGRAMMING) return true; if (problem_type == GUROBI_LINEAR_PROGRAMMING || problem_type == GUROBI_MIXED_INTEGER_PROGRAMMING) { return MPSolver::GurobiIsCorrectlyInstalled(); } #ifdef USE_SCIP - if (problem_type == SCIP_MIXED_INTEGER_PROGRAMMING) - return true; + if (problem_type == SCIP_MIXED_INTEGER_PROGRAMMING) return true; #endif #ifdef USE_CBC - if (problem_type == CBC_MIXED_INTEGER_PROGRAMMING) - return true; + if (problem_type == CBC_MIXED_INTEGER_PROGRAMMING) return true; #endif #ifdef USE_XPRESS if (problem_type == XPRESS_MIXED_INTEGER_PROGRAMMING || @@ -518,37 +503,36 @@ struct NamedOptimizationProblemType { MPSolver::OptimizationProblemType problem_type; absl::string_view name; }; -} // namespace +} // namespace #if defined(_MSC_VER) const #else - constexpr +constexpr #endif NamedOptimizationProblemType kOptimizationProblemTypeNames[] = { - { MPSolver::GLOP_LINEAR_PROGRAMMING, "glop" }, - { MPSolver::CLP_LINEAR_PROGRAMMING, "clp" }, - { MPSolver::GUROBI_LINEAR_PROGRAMMING, "gurobi_lp" }, - { MPSolver::GLPK_LINEAR_PROGRAMMING, "glpk_lp" }, - { MPSolver::CPLEX_LINEAR_PROGRAMMING, "cplex_lp" }, - { MPSolver::XPRESS_LINEAR_PROGRAMMING, "xpress_lp" }, - { MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING, "scip" }, - { MPSolver::CBC_MIXED_INTEGER_PROGRAMMING, "cbc" }, - { MPSolver::SAT_INTEGER_PROGRAMMING, "sat" }, - { MPSolver::BOP_INTEGER_PROGRAMMING, "bop" }, - { MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING, "gurobi" }, - { MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING, "glpk" }, - { MPSolver::KNAPSACK_MIXED_INTEGER_PROGRAMMING, "knapsack" }, - { MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, "cplex" }, - { MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, "xpress" }, + {MPSolver::GLOP_LINEAR_PROGRAMMING, "glop"}, + {MPSolver::CLP_LINEAR_PROGRAMMING, "clp"}, + {MPSolver::GUROBI_LINEAR_PROGRAMMING, "gurobi_lp"}, + {MPSolver::GLPK_LINEAR_PROGRAMMING, "glpk_lp"}, + {MPSolver::CPLEX_LINEAR_PROGRAMMING, "cplex_lp"}, + {MPSolver::XPRESS_LINEAR_PROGRAMMING, "xpress_lp"}, + {MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING, "scip"}, + {MPSolver::CBC_MIXED_INTEGER_PROGRAMMING, "cbc"}, + {MPSolver::SAT_INTEGER_PROGRAMMING, "sat"}, + {MPSolver::BOP_INTEGER_PROGRAMMING, "bop"}, + {MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING, "gurobi"}, + {MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING, "glpk"}, + {MPSolver::KNAPSACK_MIXED_INTEGER_PROGRAMMING, "knapsack"}, + {MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, "cplex"}, + {MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, "xpress"}, }; // static bool MPSolver::ParseSolverType(absl::string_view solver_id, MPSolver::OptimizationProblemType *type) { - // Normalize the solver id. - const std::string id = absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), { - { "-", "_" } - }); + // Normalize the solver id. + const std::string id = + absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{"-", "_"}}); // Support the full enum name MPModelRequest::SolverType solver_type; @@ -581,15 +565,15 @@ bool MPSolver::ParseSolverType(absl::string_view solver_id, return false; } -const absl::string_view -ToString(MPSolver::OptimizationProblemType optimization_problem_type) { +const absl::string_view ToString( + MPSolver::OptimizationProblemType optimization_problem_type) { for (const auto &named_solver : kOptimizationProblemTypeNames) { if (named_solver.problem_type == optimization_problem_type) { return named_solver.name; } } - LOG(FATAL) << "Unrecognized solver type: " << static_cast( - optimization_problem_type); + LOG(FATAL) << "Unrecognized solver type: " + << static_cast(optimization_problem_type); return ""; } @@ -606,8 +590,8 @@ bool AbslParseFlag(const absl::string_view text, } /* static */ -MPSolver::OptimizationProblemType -MPSolver::ParseSolverTypeOrDie(const std::string &solver_id) { +MPSolver::OptimizationProblemType MPSolver::ParseSolverTypeOrDie( + const std::string &solver_id) { MPSolver::OptimizationProblemType problem_type; CHECK(MPSolver::ParseSolverType(solver_id, &problem_type)) << solver_id; return problem_type; @@ -629,38 +613,33 @@ MPSolver *MPSolver::CreateSolver(const std::string &solver_id) { } MPVariable *MPSolver::LookupVariableOrNull(const std::string &var_name) const { - if (!variable_name_to_index_) - GenerateVariableNameIndex(); + if (!variable_name_to_index_) GenerateVariableNameIndex(); absl::flat_hash_map::const_iterator it = variable_name_to_index_->find(var_name); - if (it == variable_name_to_index_->end()) - return nullptr; + if (it == variable_name_to_index_->end()) return nullptr; return variables_[it->second]; } -MPConstraint * -MPSolver::LookupConstraintOrNull(const std::string &constraint_name) const { - if (!constraint_name_to_index_) - GenerateConstraintNameIndex(); +MPConstraint *MPSolver::LookupConstraintOrNull( + const std::string &constraint_name) const { + if (!constraint_name_to_index_) GenerateConstraintNameIndex(); const auto it = constraint_name_to_index_->find(constraint_name); - if (it == constraint_name_to_index_->end()) - return nullptr; + if (it == constraint_name_to_index_->end()) return nullptr; return constraints_[it->second]; } // ----- Methods using protocol buffers ----- -MPSolverResponseStatus -MPSolver::LoadModelFromProto(const MPModelProto &input_model, - std::string *error_message) { +MPSolverResponseStatus MPSolver::LoadModelFromProto( + const MPModelProto &input_model, std::string *error_message) { // The variable and constraint names are dropped, because we allow // duplicate names in the proto (they're not considered as 'ids'), // unlike the MPSolver C++ API which crashes if there are duplicate names. // Clearing the names makes the MPSolver generate unique names. - return LoadModelFromProtoInternal(input_model, /*clear_names=*/ true, - /*check_model_validity=*/ true, + return LoadModelFromProtoInternal(input_model, /*clear_names=*/true, + /*check_model_validity=*/true, error_message); } @@ -670,8 +649,8 @@ MPSolverResponseStatus MPSolver::LoadModelFromProtoWithUniqueNamesOrDie( GenerateVariableNameIndex(); GenerateConstraintNameIndex(); - return LoadModelFromProtoInternal(input_model, /*clear_names=*/ false, - /*check_model_validity=*/ true, + return LoadModelFromProtoInternal(input_model, /*clear_names=*/false, + /*check_model_validity=*/true, error_message); } @@ -738,50 +717,50 @@ MPSolverResponseStatus MPSolver::LoadModelFromProtoInternal( for (const MPGeneralConstraintProto &general_constraint : input_model.general_constraint()) { switch (general_constraint.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: { - const auto &proto = - general_constraint.indicator_constraint().constraint(); - if (proto.lower_bound() == -infinity() && - proto.upper_bound() == infinity()) { - continue; + case MPGeneralConstraintProto::kIndicatorConstraint: { + const auto &proto = + general_constraint.indicator_constraint().constraint(); + if (proto.lower_bound() == -infinity() && + proto.upper_bound() == infinity()) { + continue; + } + + const int constraint_index = NumConstraints(); + MPConstraint *const constraint = new MPConstraint( + constraint_index, proto.lower_bound(), proto.upper_bound(), + clear_names ? "" : proto.name(), interface_.get()); + if (constraint_name_to_index_) { + gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(), + constraint_index); + } + constraints_.push_back(constraint); + constraint_is_extracted_.push_back(false); + + constraint->set_is_lazy(proto.is_lazy()); + for (int j = 0; j < proto.var_index_size(); ++j) { + constraint->SetCoefficient(variables_[proto.var_index(j)], + proto.coefficient(j)); + } + + MPVariable *const variable = + variables_[general_constraint.indicator_constraint().var_index()]; + constraint->indicator_variable_ = variable; + constraint->indicator_value_ = + general_constraint.indicator_constraint().var_value(); + + if (!interface_->AddIndicatorConstraint(constraint)) { + *error_message = "Solver doesn't support indicator constraints"; + return MPSOLVER_MODEL_INVALID; + } + break; } - - const int constraint_index = NumConstraints(); - MPConstraint *const constraint = new MPConstraint( - constraint_index, proto.lower_bound(), proto.upper_bound(), - clear_names ? "" : proto.name(), interface_.get()); - if (constraint_name_to_index_) { - gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(), - constraint_index); - } - constraints_.push_back(constraint); - constraint_is_extracted_.push_back(false); - - constraint->set_is_lazy(proto.is_lazy()); - for (int j = 0; j < proto.var_index_size(); ++j) { - constraint->SetCoefficient(variables_[proto.var_index(j)], - proto.coefficient(j)); - } - - MPVariable *const variable = - variables_[general_constraint.indicator_constraint().var_index()]; - constraint->indicator_variable_ = variable; - constraint->indicator_value_ = - general_constraint.indicator_constraint().var_value(); - - if (!interface_->AddIndicatorConstraint(constraint)) { - *error_message = "Solver doesn't support indicator constraints"; + default: + *error_message = absl::StrFormat( + "Optimizing general constraints of type %i is only supported " + "through direct proto solves. Please use MPSolver::SolveWithProto, " + "or the solver's direct proto solve function.", + general_constraint.general_constraint_case()); return MPSOLVER_MODEL_INVALID; - } - break; - } - default: - *error_message = absl::StrFormat( - "Optimizing general constraints of type %i is only supported " - "through direct proto solves. Please use MPSolver::SolveWithProto, " - "or the solver's direct proto solve function.", - general_constraint.general_constraint_case()); - return MPSOLVER_MODEL_INVALID; } } @@ -801,27 +780,27 @@ MPSolverResponseStatus MPSolver::LoadModelFromProtoInternal( } namespace { -MPSolverResponseStatus -ResultStatusToMPSolverResponseStatus(MPSolver::ResultStatus status) { +MPSolverResponseStatus ResultStatusToMPSolverResponseStatus( + MPSolver::ResultStatus status) { switch (status) { - case MPSolver::OPTIMAL: - return MPSOLVER_OPTIMAL; - case MPSolver::FEASIBLE: - return MPSOLVER_FEASIBLE; - case MPSolver::INFEASIBLE: - return MPSOLVER_INFEASIBLE; - case MPSolver::UNBOUNDED: - return MPSOLVER_UNBOUNDED; - case MPSolver::ABNORMAL: - return MPSOLVER_ABNORMAL; - case MPSolver::MODEL_INVALID: - return MPSOLVER_MODEL_INVALID; - case MPSolver::NOT_SOLVED: - return MPSOLVER_NOT_SOLVED; + case MPSolver::OPTIMAL: + return MPSOLVER_OPTIMAL; + case MPSolver::FEASIBLE: + return MPSOLVER_FEASIBLE; + case MPSolver::INFEASIBLE: + return MPSOLVER_INFEASIBLE; + case MPSolver::UNBOUNDED: + return MPSOLVER_UNBOUNDED; + case MPSolver::ABNORMAL: + return MPSOLVER_ABNORMAL; + case MPSolver::MODEL_INVALID: + return MPSOLVER_MODEL_INVALID; + case MPSolver::NOT_SOLVED: + return MPSOLVER_NOT_SOLVED; } return MPSOLVER_UNKNOWN_STATUS; } -} // namespace +} // namespace void MPSolver::FillSolutionResponseProto(MPSolutionResponse *response) const { CHECK(response != nullptr); @@ -878,16 +857,16 @@ void MPSolver::SolveWithProto(const MPModelRequest &model_request, } std::string error_message; response->set_status(solver.LoadModelFromProtoInternal( - optional_model->get(), /*clear_names=*/ true, - /*check_model_validity=*/ false, &error_message)); + optional_model->get(), /*clear_names=*/true, + /*check_model_validity=*/false, &error_message)); // Even though we don't re-check model validity here, there can be some // problems found by LoadModelFromProto, eg. unsupported features. if (response->status() != MPSOLVER_MODEL_IS_VALID) { response->set_status_str(error_message); LOG_IF(WARNING, model_request.enable_internal_solver_output()) << "LoadModelFromProtoInternal() failed even though the model was " - << "valid! Status: " << ProtoEnumToString( - response->status()) << " (" + << "valid! Status: " + << ProtoEnumToString(response->status()) << " (" << response->status() << "); Error: " << error_message; return; } @@ -1131,8 +1110,7 @@ void MPSolver::MakeVarArray(int nb, double lb, double ub, bool integer, const std::string &name, std::vector *vars) { DCHECK_GE(nb, 0); - if (nb <= 0) - return; + if (nb <= 0) return; const int num_digits = NumDigits(nb); for (int i = 0; i < nb; ++i) { if (name.empty()) { @@ -1234,8 +1212,7 @@ bool MPSolver::HasInfeasibleConstraints() const { bool MPSolver::HasIntegerVariables() const { for (const MPVariable *const variable : variables_) { - if (variable->integer()) - return true; + if (variable->integer()) return true; } return false; } @@ -1281,7 +1258,7 @@ std::string PrettyPrintVar(const MPVariable &var) { const std::string prefix = "Variable '" + var.name() + "': domain = "; if (var.lb() >= MPSolver::infinity() || var.ub() <= -MPSolver::infinity() || var.lb() > var.ub()) { - return prefix + "∅"; // Empty set. + return prefix + "∅"; // Empty set. } // Special case: integer variable with at most two possible values // (and potentially none). @@ -1303,7 +1280,8 @@ std::string PrettyPrintVar(const MPVariable &var) { return prefix + (var.integer() ? "Integer" : "Real") + " in " + (var.lb() <= -MPSolver::infinity() ? std::string("]-∞") - : absl::StrFormat("[%f", var.lb())) + ", " + + : absl::StrFormat("[%f", var.lb())) + + ", " + (var.ub() >= MPSolver::infinity() ? std::string("+∞[") : absl::StrFormat("%f]", var.ub())); } @@ -1334,7 +1312,7 @@ std::string PrettyPrintConstraint(const MPConstraint &constraint) { return absl::StrFormat("%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(), constraint.ub()); } -} // namespace +} // namespace absl::Status MPSolver::ClampSolutionWithinBounds() { interface_->ExtractModel(); @@ -1356,8 +1334,7 @@ absl::Status MPSolver::ClampSolutionWithinBounds() { std::vector MPSolver::ComputeConstraintActivities() const { // TODO(user): test this failure case. - if (!interface_->CheckSolutionIsSynchronizedAndExists()) - return {}; + if (!interface_->CheckSolutionIsSynchronizedAndExists()) return {}; std::vector activities(constraints_.size(), 0.0); for (int i = 0; i < constraints_.size(); ++i) { const MPConstraint &constraint = *constraints_[i]; @@ -1373,8 +1350,7 @@ std::vector MPSolver::ComputeConstraintActivities() const { // TODO(user): split. bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { double max_observed_error = 0; - if (tolerance < 0) - tolerance = infinity(); + if (tolerance < 0) tolerance = infinity(); int num_errors = 0; // Verify variables. @@ -1393,8 +1369,8 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { if (value < var.lb() - tolerance) { ++num_errors; max_observed_error = std::max(max_observed_error, var.lb() - value); - LOG_IF(ERROR, log_errors) << "Value " << value << " too low for " - << PrettyPrintVar(var); + LOG_IF(ERROR, log_errors) + << "Value " << value << " too low for " << PrettyPrintVar(var); } } // Check upper bound. @@ -1402,8 +1378,8 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { if (value > var.ub() + tolerance) { ++num_errors; max_observed_error = std::max(max_observed_error, value - var.ub()); - LOG_IF(ERROR, log_errors) << "Value " << value << " too high for " - << PrettyPrintVar(var); + LOG_IF(ERROR, log_errors) + << "Value " << value << " too high for " << PrettyPrintVar(var); } } // Check integrality. @@ -1412,8 +1388,8 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { ++num_errors; max_observed_error = std::max(max_observed_error, fabs(value - round(value))); - LOG_IF(ERROR, log_errors) << "Non-integer value " << value << " for " - << PrettyPrintVar(var); + LOG_IF(ERROR, log_errors) + << "Non-integer value " << value << " for " << PrettyPrintVar(var); } } } @@ -1438,8 +1414,8 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { if (std::isnan(activity) || std::isnan(inaccurate_activity)) { ++num_errors; max_observed_error = infinity(); - LOG_IF(ERROR, log_errors) << "NaN value for " - << PrettyPrintConstraint(constraint); + LOG_IF(ERROR, log_errors) + << "NaN value for " << PrettyPrintConstraint(constraint); continue; } // Check bounds. @@ -1451,9 +1427,9 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { ++num_errors; max_observed_error = std::max(max_observed_error, constraint.lb() - activity); - LOG_IF(ERROR, log_errors) << "Activity " << activity - << " too low for " - << PrettyPrintConstraint(constraint); + LOG_IF(ERROR, log_errors) + << "Activity " << activity << " too low for " + << PrettyPrintConstraint(constraint); } else if (inaccurate_activity < constraint.lb() - tolerance) { LOG_IF(WARNING, log_errors) << "Activity " << activity << ", computed with the (inaccurate)" @@ -1466,9 +1442,9 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { ++num_errors; max_observed_error = std::max(max_observed_error, activity - constraint.ub()); - LOG_IF(ERROR, log_errors) << "Activity " << activity - << " too high for " - << PrettyPrintConstraint(constraint); + LOG_IF(ERROR, log_errors) + << "Activity " << activity << " too high for " + << PrettyPrintConstraint(constraint); } else if (inaccurate_activity > constraint.ub() + tolerance) { LOG_IF(WARNING, log_errors) << "Activity " << activity << ", computed with the (inaccurate)" @@ -1499,18 +1475,18 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { << "Objective value " << objective.Value() << " isn't accurate" << ", it should be " << actual_objective_value << " (delta=" << actual_objective_value - objective.Value() << ")."; - } else if (!AreWithinAbsoluteOrRelativeTolerances( - objective.Value(), inaccurate_objective_value, tolerance, - tolerance)) { + } else if (!AreWithinAbsoluteOrRelativeTolerances(objective.Value(), + inaccurate_objective_value, + tolerance, tolerance)) { LOG_IF(WARNING, log_errors) << "Objective value " << objective.Value() << " doesn't correspond" << " to the value computed with the standard (and therefore inaccurate)" << " sum of its terms."; } if (num_errors > 0) { - LOG_IF(ERROR, log_errors) << "There were " << num_errors - << " errors above the tolerance (" << tolerance - << "), the largest was " << max_observed_error; + LOG_IF(ERROR, log_errors) + << "There were " << num_errors << " errors above the tolerance (" + << tolerance << "), the largest was " << max_observed_error; return false; } return true; @@ -1531,8 +1507,7 @@ double MPSolver::ComputeExactConditionNumber() const { } bool MPSolver::OwnsVariable(const MPVariable *var) const { - if (var == nullptr) - return false; + if (var == nullptr) return false; if (var->index() >= 0 && var->index() < variables_.size()) { // Then, verify that the variable with this index has the same address. return variables_[var->index()] == var; @@ -1569,8 +1544,8 @@ bool MPSolver::ExportModelAsMpsFormat(bool fixed_format, bool obfuscate, return status_or.ok(); } -void -MPSolver::SetHint(std::vector > hint) { +void MPSolver::SetHint( + std::vector > hint) { for (const auto &var_value_pair : hint) { CHECK(OwnsVariable(var_value_pair.first)) << "hint variable does not belong to this solver"; @@ -1579,8 +1554,7 @@ MPSolver::SetHint(std::vector > hint) { } void MPSolver::GenerateVariableNameIndex() const { - if (variable_name_to_index_) - return; + if (variable_name_to_index_) return; variable_name_to_index_ = absl::flat_hash_map(); for (const MPVariable *const var : variables_) { gtl::InsertOrDie(&*variable_name_to_index_, var->name(), var->index()); @@ -1588,8 +1562,7 @@ void MPSolver::GenerateVariableNameIndex() const { } void MPSolver::GenerateConstraintNameIndex() const { - if (constraint_name_to_index_) - return; + if (constraint_name_to_index_) return; constraint_name_to_index_ = absl::flat_hash_map(); for (const MPConstraint *const cst : constraints_) { gtl::InsertOrDie(&*constraint_name_to_index_, cst->name(), cst->index()); @@ -1608,25 +1581,25 @@ bool MPSolver::SupportsCallbacks() const { bool MPSolverResponseStatusIsRpcError(MPSolverResponseStatus status) { switch (status) { - // Cases that don't yield an RPC error when they happen on the server. - case MPSOLVER_OPTIMAL: - case MPSOLVER_FEASIBLE: - case MPSOLVER_INFEASIBLE: - case MPSOLVER_NOT_SOLVED: - case MPSOLVER_UNBOUNDED: - case MPSOLVER_ABNORMAL: - case MPSOLVER_UNKNOWN_STATUS: - return false; - // Cases that should never happen with the linear solver server. We prefer - // to consider those as "not RPC errors". - case MPSOLVER_MODEL_IS_VALID: - return false; - // Cases that yield an RPC error when they happen on the server. - case MPSOLVER_MODEL_INVALID: - case MPSOLVER_MODEL_INVALID_SOLUTION_HINT: - case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS: - case MPSOLVER_SOLVER_TYPE_UNAVAILABLE: - return true; + // Cases that don't yield an RPC error when they happen on the server. + case MPSOLVER_OPTIMAL: + case MPSOLVER_FEASIBLE: + case MPSOLVER_INFEASIBLE: + case MPSOLVER_NOT_SOLVED: + case MPSOLVER_UNBOUNDED: + case MPSOLVER_ABNORMAL: + case MPSOLVER_UNKNOWN_STATUS: + return false; + // Cases that should never happen with the linear solver server. We prefer + // to consider those as "not RPC errors". + case MPSOLVER_MODEL_IS_VALID: + return false; + // Cases that yield an RPC error when they happen on the server. + case MPSOLVER_MODEL_INVALID: + case MPSOLVER_MODEL_INVALID_SOLUTION_HINT: + case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS: + case MPSOLVER_SOLVER_TYPE_UNAVAILABLE: + return true; } LOG(DFATAL) << "MPSolverResponseStatusIsRpcError() called with invalid status " @@ -1639,9 +1612,13 @@ bool MPSolverResponseStatusIsRpcError(MPSolverResponseStatus status) { const int MPSolverInterface::kDummyVariableIndex = 0; MPSolverInterface::MPSolverInterface(MPSolver *const solver) - : solver_(solver), sync_status_(MODEL_SYNCHRONIZED), - result_status_(MPSolver::NOT_SOLVED), maximize_(false), - last_constraint_index_(0), last_variable_index_(0), objective_value_(0.0), + : solver_(solver), + sync_status_(MODEL_SYNCHRONIZED), + result_status_(MPSolver::NOT_SOLVED), + maximize_(false), + last_constraint_index_(0), + last_variable_index_(0), + objective_value_(0.0), quiet_(true) {} MPSolverInterface::~MPSolverInterface() {} @@ -1652,28 +1629,28 @@ void MPSolverInterface::Write(const std::string &filename) { void MPSolverInterface::ExtractModel() { switch (sync_status_) { - case MUST_RELOAD: { - ExtractNewVariables(); - ExtractNewConstraints(); - ExtractObjective(); + case MUST_RELOAD: { + ExtractNewVariables(); + ExtractNewConstraints(); + ExtractObjective(); - last_constraint_index_ = solver_->constraints_.size(); - last_variable_index_ = solver_->variables_.size(); - sync_status_ = MODEL_SYNCHRONIZED; - break; - } - case MODEL_SYNCHRONIZED: { - // Everything has already been extracted. - DCHECK_EQ(last_constraint_index_, solver_->constraints_.size()); - DCHECK_EQ(last_variable_index_, solver_->variables_.size()); - break; - } - case SOLUTION_SYNCHRONIZED: { - // Nothing has changed since last solve. - DCHECK_EQ(last_constraint_index_, solver_->constraints_.size()); - DCHECK_EQ(last_variable_index_, solver_->variables_.size()); - break; - } + last_constraint_index_ = solver_->constraints_.size(); + last_variable_index_ = solver_->variables_.size(); + sync_status_ = MODEL_SYNCHRONIZED; + break; + } + case MODEL_SYNCHRONIZED: { + // Everything has already been extracted. + DCHECK_EQ(last_constraint_index_, solver_->constraints_.size()); + DCHECK_EQ(last_variable_index_, solver_->variables_.size()); + break; + } + case SOLUTION_SYNCHRONIZED: { + // Nothing has changed since last solve. + DCHECK_EQ(last_constraint_index_, solver_->constraints_.size()); + DCHECK_EQ(last_variable_index_, solver_->variables_.size()); + break; + } } } @@ -1726,8 +1703,7 @@ double MPSolverInterface::trivial_worst_objective_bound() const { } double MPSolverInterface::objective_value() const { - if (!CheckSolutionIsSynchronizedAndExists()) - return 0; + if (!CheckSolutionIsSynchronizedAndExists()) return 0; return objective_value_; } @@ -1739,10 +1715,10 @@ void MPSolverInterface::InvalidateSolutionSynchronization() { double MPSolverInterface::ComputeExactConditionNumber() const { // Override this method in interfaces that actually support it. - LOG(DFATAL) - << "ComputeExactConditionNumber not implemented for " - << ProtoEnumToString( - static_cast(solver_->ProblemType())); + LOG(DFATAL) << "ComputeExactConditionNumber not implemented for " + << ProtoEnumToString( + static_cast( + solver_->ProblemType())); return 0.0; } @@ -1809,8 +1785,7 @@ bool MPSolverInterface::SetSolverSpecificParametersAsString( // Note(user): This is not implemented on Android because there is no // temporary directory to write files to without a pointer to the Java // environment. - if (parameters.empty()) - return true; + if (parameters.empty()) return true; std::string extension = ValidFileExtensionForParameterFile(); std::string filename; @@ -1828,11 +1803,11 @@ bool MPSolverInterface::SetSolverSpecificParametersAsString( } } if (!no_error_so_far) { - LOG(WARNING) - << "Error in SetSolverSpecificParametersAsString() " - << "for solver type: " << ProtoEnumToString( - static_cast( - solver_->ProblemType())); + LOG(WARNING) << "Error in SetSolverSpecificParametersAsString() " + << "for solver type: " + << ProtoEnumToString( + static_cast( + solver_->ProblemType())); } return no_error_so_far; } @@ -1878,109 +1853,109 @@ MPSolverParameters::MPSolverParameters() void MPSolverParameters::SetDoubleParam(MPSolverParameters::DoubleParam param, double value) { switch (param) { - case RELATIVE_MIP_GAP: { - relative_mip_gap_value_ = value; - break; - } - case PRIMAL_TOLERANCE: { - primal_tolerance_value_ = value; - break; - } - case DUAL_TOLERANCE: { - dual_tolerance_value_ = value; - break; - } - default: { - LOG(ERROR) << "Trying to set an unknown parameter: " << param << "."; - } + case RELATIVE_MIP_GAP: { + relative_mip_gap_value_ = value; + break; + } + case PRIMAL_TOLERANCE: { + primal_tolerance_value_ = value; + break; + } + case DUAL_TOLERANCE: { + dual_tolerance_value_ = value; + break; + } + default: { + LOG(ERROR) << "Trying to set an unknown parameter: " << param << "."; + } } } void MPSolverParameters::SetIntegerParam(MPSolverParameters::IntegerParam param, int value) { switch (param) { - case PRESOLVE: { - if (value != PRESOLVE_OFF && value != PRESOLVE_ON) { - LOG(ERROR) << "Trying to set a supported parameter: " << param - << " to an unknown value: " << value; + case PRESOLVE: { + if (value != PRESOLVE_OFF && value != PRESOLVE_ON) { + LOG(ERROR) << "Trying to set a supported parameter: " << param + << " to an unknown value: " << value; + } + presolve_value_ = value; + break; } - presolve_value_ = value; - break; - } - case SCALING: { - if (value != SCALING_OFF && value != SCALING_ON) { - LOG(ERROR) << "Trying to set a supported parameter: " << param - << " to an unknown value: " << value; + case SCALING: { + if (value != SCALING_OFF && value != SCALING_ON) { + LOG(ERROR) << "Trying to set a supported parameter: " << param + << " to an unknown value: " << value; + } + scaling_value_ = value; + break; } - scaling_value_ = value; - break; - } - case LP_ALGORITHM: { - if (value != DUAL && value != PRIMAL && value != BARRIER) { - LOG(ERROR) << "Trying to set a supported parameter: " << param - << " to an unknown value: " << value; + case LP_ALGORITHM: { + if (value != DUAL && value != PRIMAL && value != BARRIER) { + LOG(ERROR) << "Trying to set a supported parameter: " << param + << " to an unknown value: " << value; + } + lp_algorithm_value_ = value; + lp_algorithm_is_default_ = false; + break; } - lp_algorithm_value_ = value; - lp_algorithm_is_default_ = false; - break; - } - case INCREMENTALITY: { - if (value != INCREMENTALITY_OFF && value != INCREMENTALITY_ON) { - LOG(ERROR) << "Trying to set a supported parameter: " << param - << " to an unknown value: " << value; + case INCREMENTALITY: { + if (value != INCREMENTALITY_OFF && value != INCREMENTALITY_ON) { + LOG(ERROR) << "Trying to set a supported parameter: " << param + << " to an unknown value: " << value; + } + incrementality_value_ = value; + break; + } + default: { + LOG(ERROR) << "Trying to set an unknown parameter: " << param << "."; } - incrementality_value_ = value; - break; - } - default: { - LOG(ERROR) << "Trying to set an unknown parameter: " << param << "."; - } } } -void -MPSolverParameters::ResetDoubleParam(MPSolverParameters::DoubleParam param) { +void MPSolverParameters::ResetDoubleParam( + MPSolverParameters::DoubleParam param) { switch (param) { - case RELATIVE_MIP_GAP: { - relative_mip_gap_value_ = kDefaultRelativeMipGap; - break; - } - case PRIMAL_TOLERANCE: { - primal_tolerance_value_ = kDefaultPrimalTolerance; - break; - } - case DUAL_TOLERANCE: { - dual_tolerance_value_ = kDefaultDualTolerance; - break; - } - default: { - LOG(ERROR) << "Trying to reset an unknown parameter: " << param << "."; - } + case RELATIVE_MIP_GAP: { + relative_mip_gap_value_ = kDefaultRelativeMipGap; + break; + } + case PRIMAL_TOLERANCE: { + primal_tolerance_value_ = kDefaultPrimalTolerance; + break; + } + case DUAL_TOLERANCE: { + dual_tolerance_value_ = kDefaultDualTolerance; + break; + } + default: { + LOG(ERROR) << "Trying to reset an unknown parameter: " << param << "."; + } } } -void -MPSolverParameters::ResetIntegerParam(MPSolverParameters::IntegerParam param) { +void MPSolverParameters::ResetIntegerParam( + MPSolverParameters::IntegerParam param) { switch (param) { - case PRESOLVE: { - presolve_value_ = kDefaultPresolve; - break; - } - case SCALING: { - scaling_value_ = kDefaultIntegerParamValue; - break; - } - case LP_ALGORITHM: { - lp_algorithm_is_default_ = true; - break; - } - case INCREMENTALITY: { - incrementality_value_ = kDefaultIncrementality; - break; - } - default: { - LOG(ERROR) << "Trying to reset an unknown parameter: " << param << "."; - } + case PRESOLVE: { + presolve_value_ = kDefaultPresolve; + break; + } + case SCALING: { + scaling_value_ = kDefaultIntegerParamValue; + break; + } + case LP_ALGORITHM: { + lp_algorithm_is_default_ = true; + break; + } + case INCREMENTALITY: { + incrementality_value_ = kDefaultIncrementality; + break; + } + default: { + LOG(ERROR) << "Trying to reset an unknown parameter: " << param << "."; + } } } @@ -1997,32 +1972,43 @@ void MPSolverParameters::Reset() { double MPSolverParameters::GetDoubleParam( MPSolverParameters::DoubleParam param) const { switch (param) { - case RELATIVE_MIP_GAP: { return relative_mip_gap_value_; } - case PRIMAL_TOLERANCE: { return primal_tolerance_value_; } - case DUAL_TOLERANCE: { return dual_tolerance_value_; } - default: { - LOG(ERROR) << "Trying to get an unknown parameter: " << param << "."; - return kUnknownDoubleParamValue; - } + case RELATIVE_MIP_GAP: { + return relative_mip_gap_value_; + } + case PRIMAL_TOLERANCE: { + return primal_tolerance_value_; + } + case DUAL_TOLERANCE: { + return dual_tolerance_value_; + } + default: { + LOG(ERROR) << "Trying to get an unknown parameter: " << param << "."; + return kUnknownDoubleParamValue; + } } } int MPSolverParameters::GetIntegerParam( MPSolverParameters::IntegerParam param) const { switch (param) { - case PRESOLVE: { return presolve_value_; } - case LP_ALGORITHM: { - if (lp_algorithm_is_default_) - return kDefaultIntegerParamValue; - return lp_algorithm_value_; - } - case INCREMENTALITY: { return incrementality_value_; } - case SCALING: { return scaling_value_; } - default: { - LOG(ERROR) << "Trying to get an unknown parameter: " << param << "."; - return kUnknownIntegerParamValue; - } + case PRESOLVE: { + return presolve_value_; + } + case LP_ALGORITHM: { + if (lp_algorithm_is_default_) return kDefaultIntegerParamValue; + return lp_algorithm_value_; + } + case INCREMENTALITY: { + return incrementality_value_; + } + case SCALING: { + return scaling_value_; + } + default: { + LOG(ERROR) << "Trying to get an unknown parameter: " << param << "."; + return kUnknownIntegerParamValue; + } } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index a1f4c07e14..055348751c 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -175,7 +175,7 @@ bool SolverTypeIsMip(MPModelRequest::SolverType solver_type); * though which users build and solve problems. */ class MPSolver { -public: + public: /** * The type of problems (LP or MIP) that will be solved and the underlying * solver (GLOP, GLPK, CLP, CBC or SCIP) that will solve them. This must @@ -187,11 +187,11 @@ public: // ---------------------------- CLP_LINEAR_PROGRAMMING = 0, GLPK_LINEAR_PROGRAMMING = 1, - GLOP_LINEAR_PROGRAMMING = 2, // Recommended default value. Made in Google. + GLOP_LINEAR_PROGRAMMING = 2, // Recommended default value. Made in Google. // Integer programming problems. // ----------------------------- - SCIP_MIXED_INTEGER_PROGRAMMING = 3, // Recommended default value. + SCIP_MIXED_INTEGER_PROGRAMMING = 3, // Recommended default value. GLPK_MIXED_INTEGER_PROGRAMMING = 4, CBC_MIXED_INTEGER_PROGRAMMING = 5, @@ -268,19 +268,19 @@ public: * Parses the name of the solver and returns the correct optimization type or * dies. Invariant: ParseSolverTypeOrDie(ToString(type)) = type. */ - static OptimizationProblemType - ParseSolverTypeOrDie(const std::string &solver_id); + static OptimizationProblemType ParseSolverTypeOrDie( + const std::string &solver_id); bool IsMIP() const; /// Returns the name of the model set at construction. const std::string &Name() const { - return name_; // Set at construction. + return name_; // Set at construction. } /// Returns the optimization problem type set at construction. virtual OptimizationProblemType ProblemType() const { - return problem_type_; // Set at construction. + return problem_type_; // Set at construction. } /** @@ -374,8 +374,8 @@ public: * lazily created upon first use. Will crash if constraint names are not * unique. */ - MPConstraint * - LookupConstraintOrNull(const std::string &constraint_name) const; + MPConstraint *LookupConstraintOrNull( + const std::string &constraint_name) const; /** * Creates a linear constraint with given bounds. @@ -516,9 +516,8 @@ public: * constraint names. Caller should make sure that all variable names and * constraint names are unique, respectively. */ - MPSolverResponseStatus - LoadModelFromProtoWithUniqueNamesOrDie(const MPModelProto &input_model, - std::string *error_message); + MPSolverResponseStatus LoadModelFromProtoWithUniqueNamesOrDie( + const MPModelProto &input_model, std::string *error_message); /// Encodes the current solution in a solution response protocol buffer. void FillSolutionResponseProto(MPSolutionResponse *response) const; @@ -575,9 +574,9 @@ public: * Note: the objective value isn't checked. You can use VerifySolution() for * that. */ - absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, - double tolerance = - kDefaultPrimalTolerance); + absl::Status LoadSolutionFromProto( + const MPSolutionResponse &response, + double tolerance = kDefaultPrimalTolerance); /** * Resets values of out of bound variables to the corresponding bound and @@ -817,7 +816,7 @@ public: // Debugging: verify that the given MPVariable* belongs to this solver. bool OwnsVariable(const MPVariable *var) const; -private: + private: // Computes the size of the constraint with the largest number of // coefficients with index in [min_constraint_index, // max_constraint_index) @@ -877,7 +876,7 @@ private: // hint is provided and a std::vector for the hint value. std::vector > solution_hint_; - absl::Duration time_limit_ = absl::InfiniteDuration(); // Default = No limit. + absl::Duration time_limit_ = absl::InfiniteDuration(); // Default = No limit. const absl::Time construction_time_; @@ -887,10 +886,9 @@ private: // Permanent storage for SetSolverSpecificParametersAsString(). std::string solver_specific_parameter_string_; - MPSolverResponseStatus - LoadModelFromProtoInternal(const MPModelProto &input_model, - bool clear_names, bool check_model_validity, - std::string *error_message); + MPSolverResponseStatus LoadModelFromProtoInternal( + const MPModelProto &input_model, bool clear_names, + bool check_model_validity, std::string *error_message); DISALLOW_COPY_AND_ASSIGN(MPSolver); }; @@ -899,33 +897,33 @@ inline bool SolverTypeIsMip(MPSolver::OptimizationProblemType solver_type) { return SolverTypeIsMip(static_cast(solver_type)); } -const absl::string_view - ToString(MPSolver::OptimizationProblemType optimization_problem_type); +const absl::string_view ToString( + MPSolver::OptimizationProblemType optimization_problem_type); -inline std::ostream &operator<<(std::ostream &os, - MPSolver::OptimizationProblemType - optimization_problem_type) { +inline std::ostream &operator<<( + std::ostream &os, + MPSolver::OptimizationProblemType optimization_problem_type) { return os << ToString(optimization_problem_type); } inline std::ostream &operator<<(std::ostream &os, MPSolver::ResultStatus status) { return os << ProtoEnumToString( - static_cast(status)); + static_cast(status)); } bool AbslParseFlag(absl::string_view text, MPSolver::OptimizationProblemType *solver_type, std::string *error); -inline std::string -AbslUnparseFlag(MPSolver::OptimizationProblemType solver_type) { +inline std::string AbslUnparseFlag( + MPSolver::OptimizationProblemType solver_type) { return std::string(ToString(solver_type)); } /// A class to express a linear objective. class MPObjective { -public: + public: /** * Clears the offset, all variables and coefficients, and the optimization * direction. @@ -1016,7 +1014,7 @@ public: */ double BestBound() const; -private: + private: friend class MPSolver; friend class MPSolverInterface; friend class CBCInterface; @@ -1052,7 +1050,7 @@ private: /// The class for variables of a Mathematical Programming (MP) model. class MPVariable { -public: + public: /// Returns the name of the variable. const std::string &name() const { return name_; } @@ -1124,7 +1122,7 @@ public: int branching_priority() const { return branching_priority_; } void SetBranchingPriority(int priority); -protected: + protected: friend class MPSolver; friend class MPSolverInterface; friend class CBCInterface; @@ -1146,14 +1144,19 @@ protected: // several models. MPVariable(int index, double lb, double ub, bool integer, const std::string &name, MPSolverInterface *const interface_in) - : index_(index), lb_(lb), ub_(ub), integer_(integer), + : index_(index), + lb_(lb), + ub_(ub), + integer_(integer), name_(name.empty() ? absl::StrFormat("auto_v_%09d", index) : name), - solution_value_(0.0), reduced_cost_(0.0), interface_(interface_in) {} + solution_value_(0.0), + reduced_cost_(0.0), + interface_(interface_in) {} void set_solution_value(double value) { solution_value_ = value; } void set_reduced_cost(double reduced_cost) { reduced_cost_ = reduced_cost; } -private: + private: const int index_; double lb_; double ub_; @@ -1172,7 +1175,7 @@ private: * A constraint is represented as a linear equation or inequality. */ class MPConstraint { -public: + public: /// Returns the name of the constraint. const std::string &name() const { return name_; } @@ -1261,7 +1264,7 @@ public: */ MPSolver::BasisStatus basis_status() const; -protected: + protected: friend class MPSolver; friend class MPSolverInterface; friend class CBCInterface; @@ -1282,14 +1285,19 @@ protected: // to several models. MPConstraint(int index, double lb, double ub, const std::string &name, MPSolverInterface *const interface_in) - : coefficients_(1), index_(index), lb_(lb), ub_(ub), + : coefficients_(1), + index_(index), + lb_(lb), + ub_(ub), name_(name.empty() ? absl::StrFormat("auto_c_%09d", index) : name), - is_lazy_(false), indicator_variable_(nullptr), dual_value_(0.0), + is_lazy_(false), + indicator_variable_(nullptr), + dual_value_(0.0), interface_(interface_in) {} void set_dual_value(double dual_value) { dual_value_ = dual_value; } -private: + private: // Returns true if the constraint contains variables that have not // been extracted yet. bool ContainsNewVariables(); @@ -1297,7 +1305,7 @@ private: // Mapping var -> coefficient. absl::flat_hash_map coefficients_; - const int index_; // See index(). + const int index_; // See index(). // The lower bound for the linear constraint. double lb_; @@ -1350,7 +1358,7 @@ private: * the default values. */ class MPSolverParameters { -public: + public: /// Enumeration of parameters that take continuous values. enum DoubleParam { /// Limit for relative MIP gap. @@ -1469,7 +1477,7 @@ public: /// Returns the value of an integer parameter. int GetIntegerParam(MPSolverParameters::IntegerParam param) const; -private: + private: // Parameter value for each parameter. // @see DoubleParam // @see IntegerParam @@ -1506,7 +1514,7 @@ bool MPSolverResponseStatusIsRpcError(MPSolverResponseStatus status); // @see glpk_interface.cc // @see scip_interface.cc class MPSolverInterface { -public: + public: enum SynchronizationStatus { // The underlying solver (CLP, GLPK, ...) and MPSolver are not in // sync for the model nor for the solution. @@ -1540,8 +1548,8 @@ public: // Directly solves a MPModelRequest, bypassing the MPSolver data structures // entirely. Returns {} (eg. absl::nullopt) if the feature is not supported by // the underlying solver. - virtual absl::optional - DirectlySolveProto(const MPModelRequest &request) { + virtual absl::optional DirectlySolveProto( + const MPModelRequest &request) { return absl::nullopt; } @@ -1708,7 +1716,7 @@ public: friend class MPConstraint; friend class MPObjective; -protected: + protected: MPSolver *const solver_; // Indicates whether the model and the solution are synchronized. SynchronizationStatus sync_status_; @@ -1756,15 +1764,14 @@ protected: // Sets an unsupported double parameter. void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param); // Sets an unsupported integer parameter. - virtual void - SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param); + virtual void SetUnsupportedIntegerParam( + MPSolverParameters::IntegerParam param); // Sets a supported double parameter to an unsupported value. void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value); // Sets a supported integer parameter to an unsupported value. - virtual void - SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, - int value); + virtual void SetIntegerParamToUnsupportedValue( + MPSolverParameters::IntegerParam param, int value); // Sets each parameter in the underlying solver. virtual void SetRelativeMipGap(double value) = 0; virtual void SetPrimalTolerance(double value) = 0; @@ -1782,8 +1789,8 @@ protected: // temporary file and calls ReadParameterFile to import the parameter file // into the solver. Solvers that support passing the parameters directly can // override this method to skip the temporary file logic. - virtual bool - SetSolverSpecificParametersAsString(const std::string ¶meters); + virtual bool SetSolverSpecificParametersAsString( + const std::string ¶meters); // Reads a solver-specific file of parameters and set them. // Returns true if there was no errors. @@ -1799,6 +1806,6 @@ protected: virtual void SetLpAlgorithm(int value) = 0; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_H_ diff --git a/ortools/linear_solver/linear_solver_callback.cc b/ortools/linear_solver/linear_solver_callback.cc index a7080803c5..65198a54d4 100644 --- a/ortools/linear_solver/linear_solver_callback.cc +++ b/ortools/linear_solver/linear_solver_callback.cc @@ -19,28 +19,28 @@ namespace operations_research { std::string ToString(MPCallbackEvent event) { switch (event) { - case MPCallbackEvent::kMipSolution: - return "MIP_SOLUTION"; - case MPCallbackEvent::kMip: - return "MIP"; - case MPCallbackEvent::kMipNode: - return "MIP_NODE"; - case MPCallbackEvent::kBarrier: - return "BARRIER"; - case MPCallbackEvent::kMessage: - return "MESSAGE"; - case MPCallbackEvent::kPresolve: - return "PRESOLVE"; - case MPCallbackEvent::kPolling: - return "POLLING"; - case MPCallbackEvent::kMultiObj: - return "MULTI_OBJ"; - case MPCallbackEvent::kSimplex: - return "SIMPLEX"; - case MPCallbackEvent::kUnknown: - return "UNKNOWN"; - default: - LOG(FATAL) << "Unrecognized callback event: " << static_cast(event); + case MPCallbackEvent::kMipSolution: + return "MIP_SOLUTION"; + case MPCallbackEvent::kMip: + return "MIP"; + case MPCallbackEvent::kMipNode: + return "MIP_NODE"; + case MPCallbackEvent::kBarrier: + return "BARRIER"; + case MPCallbackEvent::kMessage: + return "MESSAGE"; + case MPCallbackEvent::kPresolve: + return "PRESOLVE"; + case MPCallbackEvent::kPolling: + return "POLLING"; + case MPCallbackEvent::kMultiObj: + return "MULTI_OBJ"; + case MPCallbackEvent::kSimplex: + return "SIMPLEX"; + case MPCallbackEvent::kUnknown: + return "UNKNOWN"; + default: + LOG(FATAL) << "Unrecognized callback event: " << static_cast(event); } } @@ -57,8 +57,8 @@ bool CallbacksMightAddCuts(const std::vector &callbacks) { } // Returns true if any of the callbacks in a list might add lazy constraints. -bool -CallbacksMightAddLazyConstraints(const std::vector &callbacks) { +bool CallbacksMightAddLazyConstraints( + const std::vector &callbacks) { for (MPCallback *callback : callbacks) { if (callback->might_add_lazy_constraints()) { return true; @@ -67,7 +67,7 @@ CallbacksMightAddLazyConstraints(const std::vector &callbacks) { return false; } -} // namespace +} // namespace MPCallbackList::MPCallbackList(const std::vector &callbacks) : MPCallback(CallbacksMightAddCuts(callbacks), @@ -80,4 +80,4 @@ void MPCallbackList::RunCallback(MPCallbackContext *context) { } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/linear_solver_callback.h b/ortools/linear_solver/linear_solver_callback.h index 49266cfc5b..e3b22dd6fd 100644 --- a/ortools/linear_solver/linear_solver_callback.h +++ b/ortools/linear_solver/linear_solver_callback.h @@ -34,29 +34,29 @@ class LinearRange; // for details. enum class MPCallbackEvent { kUnknown, - // For regaining control of the main thread in single threaded - // applications, - // not for interacting with the solver. - kPolling, - // The solver is currently running presolve. - kPresolve, - // The solver is currently running the simplex method. - kSimplex, - // The solver is in the MIP loop (called periodically before starting a - // new - // node). Useful to early termination. - kMip, - // Called every time a new MIP incumbent is found. - kMipSolution, - // Called once per pass of the cut loop inside each MIP node. - kMipNode, - // Called in each iterate of IPM/barrier method. - kBarrier, - // The solver is about to log out a message, use this callback to capture - // it. - kMessage, - // The solver is in multi-objective optimization. - kMultiObj, + // For regaining control of the main thread in single threaded + // applications, + // not for interacting with the solver. + kPolling, + // The solver is currently running presolve. + kPresolve, + // The solver is currently running the simplex method. + kSimplex, + // The solver is in the MIP loop (called periodically before starting a + // new + // node). Useful to early termination. + kMip, + // Called every time a new MIP incumbent is found. + kMipSolution, + // Called once per pass of the cut loop inside each MIP node. + kMipNode, + // Called in each iterate of IPM/barrier method. + kBarrier, + // The solver is about to log out a message, use this callback to capture + // it. + kMessage, + // The solver is in multi-objective optimization. + kMultiObj, }; std::string ToString(MPCallbackEvent event); @@ -65,7 +65,7 @@ std::string ToString(MPCallbackEvent event); // this API, rather than manipulating MPSolver directly. You should only // interact with this object from within MPCallback::RunCallback(). class MPCallbackContext { -public: + public: virtual ~MPCallbackContext() {} // What the solver is currently doing. How you can interact with the solver @@ -141,7 +141,7 @@ public: // // See go/mpsolver-callbacks for additional documentation. class MPCallback { -public: + public: // If you intend to call call MPCallbackContext::AddCut(), you must set // might_add_cuts below to be true. Likewise for // MPCallbackContext::AddLazyConstraint() and might_add_lazy_constraints. @@ -160,7 +160,7 @@ public: return might_add_lazy_constraints_; } -private: + private: bool might_add_cuts_; bool might_add_lazy_constraints_; }; @@ -168,16 +168,16 @@ private: // Single callback that runs the list of callbacks given at construction, in // sequence. class MPCallbackList : public MPCallback { -public: + public: explicit MPCallbackList(const std::vector &callbacks); // Runs all callbacks from the list given at construction, in sequence. void RunCallback(MPCallbackContext *context) override; -private: + private: const std::vector callbacks_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_ diff --git a/ortools/linear_solver/model_exporter.cc b/ortools/linear_solver/model_exporter.cc index 6a61538ecf..f970bf462f 100644 --- a/ortools/linear_solver/model_exporter.cc +++ b/ortools/linear_solver/model_exporter.cc @@ -38,7 +38,7 @@ namespace { constexpr double kInfinity = std::numeric_limits::infinity(); class LineBreaker { -public: + public: explicit LineBreaker(int max_line_size) : max_line_size_(max_line_size), line_size_(0), output_() {} // Lines are broken in such a way that: @@ -60,7 +60,7 @@ public: std::string GetOutput() const { return output_; } -private: + private: int max_line_size_; int line_size_; std::string output_; @@ -76,14 +76,14 @@ void LineBreaker::Append(const std::string &s) { } class MPModelProtoExporter { -public: + public: explicit MPModelProtoExporter(const MPModelProto &model); bool ExportModelAsLpFormat(const MPModelExportOptions &options, std::string *output); bool ExportModelAsMpsFormat(const MPModelExportOptions &options, std::string *output); -private: + private: // Computes the number of continuous, integer and binary variables. // Called by ExportModelAsLpFormat() and ExportModelAsMpsFormat(). void Setup(); @@ -108,12 +108,11 @@ private: // // Therefore, a name "$20<=40" for proto #3 could be "_$20__40_1". template - std::vector - ExtractAndProcessNames(const ListOfProtosWithNameFields &proto, - const std::string &prefix, bool obfuscate, - bool log_invalid_names, - const std::string &forbidden_first_chars, - const std::string &forbidden_chars); + std::vector ExtractAndProcessNames( + const ListOfProtosWithNameFields &proto, const std::string &prefix, + bool obfuscate, bool log_invalid_names, + const std::string &forbidden_first_chars, + const std::string &forbidden_chars); // Appends a general "Comment" section with useful metadata about the model // to "output". @@ -210,11 +209,10 @@ private: DISALLOW_COPY_AND_ASSIGN(MPModelProtoExporter); }; -} // namespace +} // namespace -absl::StatusOr -ExportModelAsLpFormat(const MPModelProto &model, - const MPModelExportOptions &options) { +absl::StatusOr ExportModelAsLpFormat( + const MPModelProto &model, const MPModelExportOptions &options) { for (const MPGeneralConstraintProto &general_constraint : model.general_constraint()) { if (!general_constraint.has_indicator_constraint()) { @@ -230,9 +228,8 @@ ExportModelAsLpFormat(const MPModelProto &model, return output; } -absl::StatusOr -ExportModelAsMpsFormat(const MPModelProto &model, - const MPModelExportOptions &options) { +absl::StatusOr ExportModelAsMpsFormat( + const MPModelProto &model, const MPModelExportOptions &options) { if (model.general_constraint_size() > 0) { return absl::InvalidArgumentError("General constraints are not supported."); } @@ -246,16 +243,19 @@ ExportModelAsMpsFormat(const MPModelProto &model, namespace { MPModelProtoExporter::MPModelProtoExporter(const MPModelProto &model) - : proto_(model), num_integer_variables_(0), num_binary_variables_(0), - num_continuous_variables_(0), current_mps_column_(0) {} + : proto_(model), + num_integer_variables_(0), + num_binary_variables_(0), + num_continuous_variables_(0), + current_mps_column_(0) {} namespace { class NameManager { -public: + public: NameManager() : names_set_(), last_n_(1) {} std::string MakeUniqueName(const std::string &name); -private: + private: absl::flat_hash_set names_set_; int last_n_; }; @@ -293,7 +293,7 @@ std::string MakeExportableName(const std::string &name, } return exportable_name; } -} // namespace +} // namespace template std::vector MPModelProtoExporter::ExtractAndProcessNames( @@ -371,7 +371,7 @@ std::string DoubleToStringWithForcedSign(double d) { std::string DoubleToString(double d) { return absl::StrCat((d)); } -} // namespace +} // namespace bool MPModelProtoExporter::AppendConstraint(const MPConstraintProto &ct_proto, const std::string &name, @@ -406,8 +406,7 @@ bool MPModelProtoExporter::AppendConstraint(const MPConstraintProto &ct_proto, absl::StrCat(" <= ", DoubleToString(ub), "\n"); // Here we have to make sure we do not add the relation to the contents // of line_breaker, which may be used in the subsequent clause. - if (!line_breaker.WillFit(relation)) - absl::StrAppend(output, "\n "); + if (!line_breaker.WillFit(relation)) absl::StrAppend(output, "\n "); absl::StrAppend(output, relation); } if (lb != -kInfinity) { @@ -418,8 +417,7 @@ bool MPModelProtoExporter::AppendConstraint(const MPConstraintProto &ct_proto, absl::StrAppend(output, " ", lhs_name, ": ", line_breaker.GetOutput()); const std::string relation = absl::StrCat(" >= ", DoubleToString(lb), "\n"); - if (!line_breaker.WillFit(relation)) - absl::StrAppend(output, "\n "); + if (!line_breaker.WillFit(relation)) absl::StrAppend(output, "\n "); absl::StrAppend(output, relation); } } @@ -448,14 +446,13 @@ bool IsBoolean(const MPVariableProto &var) { } void UpdateMaxSize(const std::string &new_string, int *size) { - if (new_string.size() > *size) - *size = new_string.size(); + if (new_string.size() > *size) *size = new_string.size(); } void UpdateMaxSize(double new_number, int *size) { UpdateMaxSize(DoubleToString(new_number), size); } -} // namespace +} // namespace void MPModelProtoExporter::Setup() { if (absl::GetFlag(FLAGS_lp_log_invalid_name)) { @@ -507,8 +504,10 @@ void MPModelProtoExporter::ComputeMpsSmartColumnWidths(bool obfuscated) { // If the model is obfuscated, all names will have the same size, which we // compute here. if (obfuscated) { - int max_digits = absl::StrCat( - std::max(proto_.variable_size(), proto_.constraint_size()) - 1).size(); + int max_digits = + absl::StrCat( + std::max(proto_.variable_size(), proto_.constraint_size()) - 1) + .size(); string_field_size = std::max(6, max_digits + 1); } @@ -518,9 +517,8 @@ void MPModelProtoExporter::ComputeMpsSmartColumnWidths(bool obfuscated) { absl::StrCat(" %-", string_field_size, "s %", number_field_size, "s")); } -bool -MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, - std::string *output) { +bool MPModelProtoExporter::ExportModelAsLpFormat( + const MPModelExportOptions &options, std::string *output) { output->clear(); Setup(); const std::string kForbiddenFirstChars = "$.0123456789"; @@ -566,7 +564,7 @@ MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, const MPConstraintProto &ct_proto = proto_.constraint(cst_index); const std::string &name = exported_constraint_names_[cst_index]; LineBreaker line_breaker(options.max_line_length); - const int kNumFormattingChars = 10; // Overevaluated. + const int kNumFormattingChars = 10; // Overevaluated. // Account for the size of the constraint name + possibly "_rhs" + // the formatting characters here. line_breaker.Consume(kNumFormattingChars + name.size()); @@ -583,13 +581,12 @@ MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, proto_.general_constraint(cst_index); const std::string &name = exported_general_constraint_names_[cst_index]; LineBreaker line_breaker(options.max_line_length); - const int kNumFormattingChars = 10; // Overevaluated. + const int kNumFormattingChars = 10; // Overevaluated. // Account for the size of the constraint name + possibly "_rhs" + // the formatting characters here. line_breaker.Consume(kNumFormattingChars + name.size()); - if (!ct_proto.has_indicator_constraint()) - return false; + if (!ct_proto.has_indicator_constraint()) return false; const MPIndicatorConstraint &indicator_ct = ct_proto.indicator_constraint(); const int binary_var_index = indicator_ct.var_index(); const int binary_var_value = indicator_ct.var_value(); @@ -611,8 +608,7 @@ MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, absl::StrAppend(output, " 1 <= Constant <= 1\n"); } for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) { - if (!show_variable[var_index]) - continue; + if (!show_variable[var_index]) continue; const MPVariableProto &var_proto = proto_.variable(var_index); const double lb = var_proto.lower_bound(); const double ub = var_proto.upper_bound(); @@ -640,8 +636,7 @@ MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, if (num_binary_variables_ > 0) { absl::StrAppend(output, "Binaries\n"); for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) { - if (!show_variable[var_index]) - continue; + if (!show_variable[var_index]) continue; const MPVariableProto &var_proto = proto_.variable(var_index); if (IsBoolean(var_proto)) { absl::StrAppendFormat(output, " %s\n", @@ -654,8 +649,7 @@ MPModelProtoExporter::ExportModelAsLpFormat(const MPModelExportOptions &options, if (num_integer_variables_ > 0) { absl::StrAppend(output, "Generals\n"); for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) { - if (!show_variable[var_index]) - continue; + if (!show_variable[var_index]) continue; const MPVariableProto &var_proto = proto_.variable(var_index); if (var_proto.is_integer() && !IsBoolean(var_proto)) { absl::StrAppend(output, " ", exported_variable_names_[var_index], "\n"); @@ -719,8 +713,7 @@ void MPModelProtoExporter::AppendMpsColumns( current_mps_column_ = 0; for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) { const MPVariableProto &var_proto = proto_.variable(var_index); - if (var_proto.is_integer() != integrality) - continue; + if (var_proto.is_integer() != integrality) continue; const std::string &var_name = exported_variable_names_[var_index]; current_mps_column_ = 0; if (var_proto.objective_coefficient() != 0.0) { @@ -802,23 +795,24 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat( } const double coeff = ct_proto.coefficient(k); if (coeff != 0.0) { - transpose[var_index] - .push_back(std::pair(cst_index, coeff)); + transpose[var_index].push_back( + std::pair(cst_index, coeff)); } } } // COLUMNS section. std::string columns_section; - AppendMpsColumns(/*integrality=*/ true, transpose, &columns_section); + AppendMpsColumns(/*integrality=*/true, transpose, &columns_section); if (!columns_section.empty()) { constexpr const char kIntMarkerFormat[] = " %-10s%-36s%-8s\n"; - columns_section = absl::StrFormat(kIntMarkerFormat, "INTSTART", "'MARKER'", - "'INTORG'") + columns_section; + columns_section = + absl::StrFormat(kIntMarkerFormat, "INTSTART", "'MARKER'", "'INTORG'") + + columns_section; absl::StrAppendFormat(&columns_section, kIntMarkerFormat, "INTEND", "'MARKER'", "'INTEND'"); } - AppendMpsColumns(/*integrality=*/ false, transpose, &columns_section); + AppendMpsColumns(/*integrality=*/false, transpose, &columns_section); if (!columns_section.empty()) { absl::StrAppend(output, "COLUMNS\n", columns_section); } @@ -922,5 +916,5 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat( return true; } -} // namespace -} // namespace operations_research +} // namespace +} // namespace operations_research diff --git a/ortools/linear_solver/model_exporter.h b/ortools/linear_solver/model_exporter.h index 28ff8ef746..3dccbcd5a1 100644 --- a/ortools/linear_solver/model_exporter.h +++ b/ortools/linear_solver/model_exporter.h @@ -68,10 +68,9 @@ struct MPModelExportOptions { * http://tinyurl.com/cplex-lp-format * http://www.gurobi.com/documentation/5.1/reference-manual/node871 */ -absl::StatusOr - ExportModelAsLpFormat(const MPModelProto &model, - const MPModelExportOptions &options = - MPModelExportOptions()); +absl::StatusOr ExportModelAsLpFormat( + const MPModelProto &model, + const MPModelExportOptions &options = MPModelExportOptions()); /** * Outputs the current model (variables, constraints, objective) as a string @@ -98,11 +97,10 @@ absl::StatusOr * Gurobi's description: * http://www.gurobi.com/documentation/5.1/reference-manual/node869 */ -absl::StatusOr - ExportModelAsMpsFormat(const MPModelProto &model, - const MPModelExportOptions &options = - MPModelExportOptions()); +absl::StatusOr ExportModelAsMpsFormat( + const MPModelProto &model, + const MPModelExportOptions &options = MPModelExportOptions()); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_EXPORTER_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_EXPORTER_H_ diff --git a/ortools/linear_solver/model_exporter_swig_helper.h b/ortools/linear_solver/model_exporter_swig_helper.h index d3bb953256..35d8deb877 100644 --- a/ortools/linear_solver/model_exporter_swig_helper.h +++ b/ortools/linear_solver/model_exporter_swig_helper.h @@ -21,21 +21,19 @@ namespace operations_research { -inline std::string -ExportModelAsLpFormatReturnString(const MPModelProto &input_model, - const MPModelExportOptions &options = - MPModelExportOptions()) { +inline std::string ExportModelAsLpFormatReturnString( + const MPModelProto &input_model, + const MPModelExportOptions &options = MPModelExportOptions()) { return operations_research::ExportModelAsLpFormat(input_model, options) .value_or(""); } -inline std::string -ExportModelAsMpsFormatReturnString(const MPModelProto &input_model, - const MPModelExportOptions &options = - MPModelExportOptions()) { +inline std::string ExportModelAsMpsFormatReturnString( + const MPModelProto &input_model, + const MPModelExportOptions &options = MPModelExportOptions()) { return operations_research::ExportModelAsMpsFormat(input_model, options) .value_or(""); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_EXPORTER_SWIG_HELPER_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_EXPORTER_SWIG_HELPER_H_ diff --git a/ortools/linear_solver/model_validator.cc b/ortools/linear_solver/model_validator.cc index 4471716e08..b7eb3ac4a5 100644 --- a/ortools/linear_solver/model_validator.cc +++ b/ortools/linear_solver/model_validator.cc @@ -62,8 +62,7 @@ std::string FindErrorInBounds(const BoundedElement &element) { // Internal method to detect errors in a single variable. std::string FindErrorInMPVariable(const MPVariableProto &variable) { const std::string bound_error = FindErrorInBounds(variable); - if (!bound_error.empty()) - return bound_error; + if (!bound_error.empty()) return bound_error; if (variable.is_integer() && ceil(variable.lower_bound()) > floor(variable.upper_bound())) { @@ -84,8 +83,7 @@ std::string FindDuplicateVarIndex(const Iterable &var_indices, std::vector *var_mask) { int duplicate_var_index = -1; for (const int var_index : var_indices) { - if ((*var_mask)[var_index]) - duplicate_var_index = var_index; + if ((*var_mask)[var_index]) duplicate_var_index = var_index; (*var_mask)[var_index] = true; } // Reset "var_mask" to all false, sparsely. @@ -105,8 +103,7 @@ std::string FindDuplicateVarIndex(const Iterable &var_indices, std::string FindErrorInMPConstraint(const MPConstraintProto &constraint, std::vector *var_mask) { const std::string bound_error = FindErrorInBounds(constraint); - if (!bound_error.empty()) - return bound_error; + if (!bound_error.empty()) return bound_error; // TODO(user): clarify explicitly, at least in a comment, whether we want // to accept empty constraints (i.e. without variables). @@ -132,8 +129,7 @@ std::string FindErrorInMPConstraint(const MPConstraintProto &constraint, const std::string error = FindDuplicateVarIndex(constraint.var_index(), var_mask); - if (!error.empty()) - return error; + if (!error.empty()) return error; // We found no error, all is fine. return std::string(); @@ -146,8 +142,9 @@ std::string CroppedConstraintDebugString(const MPConstraintProto &constraint) { std::string suffix_str; if (constraint.var_index_size() > kMaxPrintedVars) { constraint_light.mutable_var_index()->Truncate(kMaxPrintedVars); - absl::StrAppend(&suffix_str, " (var_index cropped; size=", - constraint.var_index_size(), ")."); + absl::StrAppend(&suffix_str, + " (var_index cropped; size=", constraint.var_index_size(), + ")."); } if (constraint.coefficient_size() > kMaxPrintedVars) { constraint_light.mutable_coefficient()->Truncate(kMaxPrintedVars); @@ -159,17 +156,14 @@ std::string CroppedConstraintDebugString(const MPConstraintProto &constraint) { } bool IsBoolean(const MPVariableProto &variable) { - if (variable.lower_bound() < 0) - return false; - if (variable.upper_bound() > 1) - return false; + if (variable.lower_bound() < 0) return false; + if (variable.upper_bound() > 1) return false; return variable.is_integer(); } -std::string -FindErrorInMPIndicatorConstraint(const MPModelProto &model, - const MPIndicatorConstraint &indicator, - std::vector *var_mask) { +std::string FindErrorInMPIndicatorConstraint( + const MPModelProto &model, const MPIndicatorConstraint &indicator, + std::vector *var_mask) { if (!indicator.has_var_index()) { return "var_index is required."; } @@ -210,16 +204,14 @@ std::string FindErrorInMPSosConstraint(const MPModelProto &model, if (!IsFinite(sos.weight(i))) { return absl::StrCat("Invalid weight: ", sos.weight(i)); } - if (i == 0) - continue; + if (i == 0) continue; if (sos.weight(i - 1) >= sos.weight(i)) { return "SOS weights must be strictly increasing"; } } const std::string error = FindDuplicateVarIndex(sos.var_index(), var_mask); - if (!error.empty()) - return error; + if (!error.empty()) return error; return ""; } @@ -234,8 +226,7 @@ std::string FindErrorInMPQuadraticConstraint(const MPModelProto &model, } const std::string bound_error = FindErrorInBounds(qcst); - if (!bound_error.empty()) - return bound_error; + if (!bound_error.empty()) return bound_error; for (int i = 0; i < qcst.var_index_size(); ++i) { if (qcst.var_index(i) < 0 || qcst.var_index(i) >= num_vars) { @@ -250,8 +241,7 @@ std::string FindErrorInMPQuadraticConstraint(const MPModelProto &model, } const std::string duplicate_error = FindDuplicateVarIndex(qcst.var_index(), var_mask); - if (!duplicate_error.empty()) - return duplicate_error; + if (!duplicate_error.empty()) return duplicate_error; if (qcst.qvar1_index_size() != qcst.qvar2_index_size() || qcst.qvar1_index_size() != qcst.qcoefficient_size()) { @@ -328,9 +318,8 @@ std::string FindErrorInMPAndOrConstraint(const MPModelProto &model, return ""; } -std::string -FindErrorInMPMinMaxConstraint(const MPModelProto &model, - const MPArrayWithConstantConstraint &min_max) { +std::string FindErrorInMPMinMaxConstraint( + const MPModelProto &model, const MPArrayWithConstantConstraint &min_max) { if (min_max.var_index_size() == 0) { return "var_index cannot be empty."; } @@ -383,9 +372,8 @@ std::string FindErrorInQuadraticObjective(const MPQuadraticObjective &qobj, return ""; } -std::string -FindErrorInSolutionHint(const PartialVariableAssignment &solution_hint, - int num_vars) { +std::string FindErrorInSolutionHint( + const PartialVariableAssignment &solution_hint, int num_vars) { if (solution_hint.var_index_size() != solution_hint.var_value_size()) { return absl::StrCat("var_index_size() != var_value_size() [", solution_hint.var_index_size(), " VS ", @@ -409,7 +397,7 @@ FindErrorInSolutionHint(const PartialVariableAssignment &solution_hint, } return std::string(); } -} // namespace +} // namespace std::string FindErrorInMPModelProto(const MPModelProto &model) { // NOTE(user): Empty models are considered fine by this function, although @@ -451,48 +439,48 @@ std::string FindErrorInMPModelProto(const MPModelProto &model) { model.general_constraint(i); std::string error; switch (gen_constraint.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: - error = FindErrorInMPIndicatorConstraint( - model, gen_constraint.indicator_constraint(), &variable_appears); - break; + case MPGeneralConstraintProto::kIndicatorConstraint: + error = FindErrorInMPIndicatorConstraint( + model, gen_constraint.indicator_constraint(), &variable_appears); + break; - case MPGeneralConstraintProto::kSosConstraint: - error = FindErrorInMPSosConstraint(model, gen_constraint.sos_constraint(), - &variable_appears); - break; + case MPGeneralConstraintProto::kSosConstraint: + error = FindErrorInMPSosConstraint( + model, gen_constraint.sos_constraint(), &variable_appears); + break; - case MPGeneralConstraintProto::kQuadraticConstraint: - error = FindErrorInMPQuadraticConstraint( - model, gen_constraint.quadratic_constraint(), &variable_appears); - break; + case MPGeneralConstraintProto::kQuadraticConstraint: + error = FindErrorInMPQuadraticConstraint( + model, gen_constraint.quadratic_constraint(), &variable_appears); + break; - case MPGeneralConstraintProto::kAbsConstraint: - error = - FindErrorInMPAbsConstraint(model, gen_constraint.abs_constraint()); - break; + case MPGeneralConstraintProto::kAbsConstraint: + error = + FindErrorInMPAbsConstraint(model, gen_constraint.abs_constraint()); + break; - case MPGeneralConstraintProto::kAndConstraint: - error = - FindErrorInMPAndOrConstraint(model, gen_constraint.and_constraint()); - break; + case MPGeneralConstraintProto::kAndConstraint: + error = FindErrorInMPAndOrConstraint(model, + gen_constraint.and_constraint()); + break; - case MPGeneralConstraintProto::kOrConstraint: - error = - FindErrorInMPAndOrConstraint(model, gen_constraint.or_constraint()); - break; + case MPGeneralConstraintProto::kOrConstraint: + error = + FindErrorInMPAndOrConstraint(model, gen_constraint.or_constraint()); + break; - case MPGeneralConstraintProto::kMinConstraint: - error = - FindErrorInMPMinMaxConstraint(model, gen_constraint.min_constraint()); - break; + case MPGeneralConstraintProto::kMinConstraint: + error = FindErrorInMPMinMaxConstraint(model, + gen_constraint.min_constraint()); + break; - case MPGeneralConstraintProto::kMaxConstraint: - error = - FindErrorInMPMinMaxConstraint(model, gen_constraint.max_constraint()); - break; - default: - return absl::StrCat("Unknown general constraint type ", - gen_constraint.general_constraint_case()); + case MPGeneralConstraintProto::kMaxConstraint: + error = FindErrorInMPMinMaxConstraint(model, + gen_constraint.max_constraint()); + break; + default: + return absl::StrCat("Unknown general constraint type ", + gen_constraint.general_constraint_case()); } if (!error.empty()) { return absl::StrCat("In general constraint #", i, ": ", error); @@ -503,8 +491,7 @@ std::string FindErrorInMPModelProto(const MPModelProto &model) { if (model.has_quadratic_objective()) { error = FindErrorInQuadraticObjective(model.quadratic_objective(), num_vars); - if (!error.empty()) - return absl::StrCat("In quadratic_objective: ", error); + if (!error.empty()) return absl::StrCat("In quadratic_objective: ", error); } // Validate the solution hint. @@ -566,8 +553,7 @@ ExtractValidMPModelOrPopulateResponseStatus(const MPModelRequest &request, if (error.empty() && request.has_model_delta()) { const MPModelDeltaProto &delta = request.model_delta(); error = FindErrorInMPModelDeltaProto(delta, model.get()); - if (error.empty()) - ApplyVerifiedMPModelDelta(delta, model.get_mutable()); + if (error.empty()) ApplyVerifiedMPModelDelta(delta, model.get_mutable()); } // Deal with errors. @@ -599,8 +585,7 @@ bool ExtractValidMPModelInPlaceOrPopulateResponseStatus( MPModelRequest *request, MPSolutionResponse *response) { absl::optional > lazy_copy = ExtractValidMPModelOrPopulateResponseStatus(*request, response); - if (!lazy_copy) - return false; + if (!lazy_copy) return false; if (lazy_copy->was_copied()) { lazy_copy->get_mutable()->Swap(request->mutable_model()); } @@ -615,8 +600,7 @@ std::string FindFeasibilityErrorInSolutionHint(const MPModelProto &model, // First, we validate the solution hint. std::string error = FindErrorInSolutionHint(model.solution_hint(), num_vars); - if (!error.empty()) - return absl::StrCat("Invalid solution_hint: ", error); + if (!error.empty()) return absl::StrCat("Invalid solution_hint: ", error); // Special error message for the empty case. if (num_vars > 0 && model.solution_hint().var_index_size() == 0) { @@ -640,10 +624,10 @@ std::string FindFeasibilityErrorInSolutionHint(const MPModelProto &model, const double ub = model.variable(var_index).upper_bound(); if (!IsSmallerWithinTolerance(value, ub, tolerance) || !IsSmallerWithinTolerance(lb, value, tolerance)) { - return absl::StrCat( - "Variable '", model.variable(var_index).name(), "' is set to ", - (value), " which is not in the variable bounds [", (lb), ", ", (ub), - "] modulo a tolerance of ", (tolerance), "."); + return absl::StrCat("Variable '", model.variable(var_index).name(), + "' is set to ", (value), + " which is not in the variable bounds [", (lb), ", ", + (ub), "] modulo a tolerance of ", (tolerance), "."); } } @@ -760,9 +744,8 @@ std::string FindErrorInMPModelDeltaProto(const MPModelDeltaProto &delta, void MergeMPConstraintProtoExceptTerms(const MPConstraintProto &from, MPConstraintProto *to) { -#define COPY_FIELD_IF_PRESENT(field) \ - if (from.has_##field()) \ - to->set_##field(from.field()) +#define COPY_FIELD_IF_PRESENT(field) \ + if (from.has_##field()) to->set_##field(from.field()) COPY_FIELD_IF_PRESENT(lower_bound); COPY_FIELD_IF_PRESENT(upper_bound); COPY_FIELD_IF_PRESENT(name); @@ -781,8 +764,7 @@ void PruneZeroTermsInMpConstraint(MPConstraintProto *ct) { } int num_kept = first_zero; for (int i = first_zero; i < ct->var_index_size(); ++i) { - if (ct->coefficient(i) == 0.0) - continue; + if (ct->coefficient(i) == 0.0) continue; if (num_kept != i) { ct->set_var_index(num_kept, ct->var_index(i)); ct->set_coefficient(num_kept, ct->coefficient(i)); @@ -799,10 +781,9 @@ void PruneZeroTermsInMpConstraint(MPConstraintProto *ct) { template void ExtendRepeatedPtrFieldToSize(const int size, T *repeated_messages) { DCHECK_GE(size, repeated_messages->size()); - while (repeated_messages->size() < size) - repeated_messages->Add(); + while (repeated_messages->size() < size) repeated_messages->Add(); } -} // namespace +} // namespace void ApplyVerifiedMPModelDelta(const MPModelDeltaProto &delta, MPModelProto *model) { @@ -837,7 +818,7 @@ void ApplyVerifiedMPModelDelta(const MPModelDeltaProto &delta, *baseline = override_ct; continue; } - MergeMPConstraintProtoExceptTerms(/*from=*/ override_ct, /*to=*/ baseline); + MergeMPConstraintProtoExceptTerms(/*from=*/override_ct, /*to=*/baseline); // Special case: the override is neutralized. if (override_ct.has_lower_bound() && override_ct.lower_bound() <= @@ -860,10 +841,9 @@ void ApplyVerifiedMPModelDelta(const MPModelDeltaProto &delta, } for (int i = 0; i < baseline->var_index_size(); ++i) { auto it = term_overrides.find(baseline->var_index(i)); - if (it == term_overrides.end()) - continue; + if (it == term_overrides.end()) continue; baseline->set_coefficient(i, it->second); - it->second = 0.0; // To mark this term override as 'has been applied'. + it->second = 0.0; // To mark this term override as 'has been applied'. } PruneZeroTermsInMpConstraint(baseline); // Add the term overrides which haven't been used: those are added terms. @@ -876,4 +856,4 @@ void ApplyVerifiedMPModelDelta(const MPModelDeltaProto &delta, } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/model_validator.h b/ortools/linear_solver/model_validator.h index c996049fc5..3ca3d83f04 100644 --- a/ortools/linear_solver/model_validator.h +++ b/ortools/linear_solver/model_validator.h @@ -46,8 +46,8 @@ std::string FindErrorInMPModelDeltaProto(const MPModelDeltaProto &delta, * the model_delta). If invalid or empty, updates `response` and returns null. */ absl::optional > - ExtractValidMPModelOrPopulateResponseStatus(const MPModelRequest &request, - MPSolutionResponse *response); +ExtractValidMPModelOrPopulateResponseStatus(const MPModelRequest &request, + MPSolutionResponse *response); /** * Like ExtractValidMPModelOrPopulateResponseStatus(), but works in-place: @@ -84,6 +84,6 @@ void MergeMPConstraintProtoExceptTerms(const MPConstraintProto &from, void ApplyVerifiedMPModelDelta(const MPModelDeltaProto &delta, MPModelProto *model); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_VALIDATOR_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_MODEL_VALIDATOR_H_ diff --git a/ortools/linear_solver/sat_interface.cc b/ortools/linear_solver/sat_interface.cc index 313de63767..098de7c695 100644 --- a/ortools/linear_solver/sat_interface.cc +++ b/ortools/linear_solver/sat_interface.cc @@ -39,7 +39,7 @@ using google::protobuf::Message; #endif class SatInterface : public MPSolverInterface { -public: + public: explicit SatInterface(MPSolver *const solver); ~SatInterface() override; @@ -92,11 +92,11 @@ public: void SetPresolveMode(int value) override; void SetScalingMode(int value) override; void SetLpAlgorithm(int value) override; - bool SetSolverSpecificParametersAsString(const std::string ¶meters) - override; + bool SetSolverSpecificParametersAsString( + const std::string ¶meters) override; absl::Status SetNumThreads(int num_threads) override; -private: + private: void NonIncrementalChange(); std::atomic interrupt_solve_; @@ -151,28 +151,27 @@ MPSolver::ResultStatus SatInterface::Solve(const MPSolverParameters ¶m) { const absl::StatusOr status_or = SatSolveProto(std::move(request), &interrupt_solve_); - if (!status_or.ok()) - return MPSolver::ABNORMAL; + if (!status_or.ok()) return MPSolver::ABNORMAL; const MPSolutionResponse &response = status_or.value(); // The solution must be marked as synchronized even when no solution exists. sync_status_ = SOLUTION_SYNCHRONIZED; switch (response.status()) { - case MPSOLVER_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case MPSOLVER_FEASIBLE: - result_status_ = MPSolver::FEASIBLE; - break; - case MPSOLVER_INFEASIBLE: - result_status_ = MPSolver::INFEASIBLE; - break; - case MPSOLVER_MODEL_INVALID: - result_status_ = MPSolver::MODEL_INVALID; - break; - default: - result_status_ = MPSolver::NOT_SOLVED; - break; + case MPSOLVER_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case MPSOLVER_FEASIBLE: + result_status_ = MPSolver::FEASIBLE; + break; + case MPSOLVER_INFEASIBLE: + result_status_ = MPSolver::INFEASIBLE; + break; + case MPSOLVER_MODEL_INVALID: + result_status_ = MPSolver::MODEL_INVALID; + break; + default: + result_status_ = MPSolver::NOT_SOLVED; + break; } // TODO(user): Just use LoadSolutionFromProto(), but fix that function first @@ -242,7 +241,7 @@ void SatInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); } void SatInterface::ClearObjective() { NonIncrementalChange(); } int64 SatInterface::iterations() const { - return 0; // FIXME + return 0; // FIXME } int64 SatInterface::nodes() const { return 0; } @@ -255,11 +254,11 @@ double SatInterface::best_objective_bound() const { } MPSolver::BasisStatus SatInterface::row_status(int constraint_index) const { - return MPSolver::BasisStatus::FREE; // FIXME + return MPSolver::BasisStatus::FREE; // FIXME } MPSolver::BasisStatus SatInterface::column_status(int variable_index) const { - return MPSolver::BasisStatus::FREE; // FIXME + return MPSolver::BasisStatus::FREE; // FIXME } bool SatInterface::IsContinuous() const { return false; } @@ -316,4 +315,4 @@ MPSolverInterface *BuildSatInterface(MPSolver *const solver) { return new SatInterface(solver); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/sat_proto_solver.cc b/ortools/linear_solver/sat_proto_solver.cc index 4640f0f662..bbb9acfb6f 100644 --- a/ortools/linear_solver/sat_proto_solver.cc +++ b/ortools/linear_solver/sat_proto_solver.cc @@ -39,24 +39,25 @@ using google::protobuf::Message; MPSolverResponseStatus ToMPSolverResponseStatus(sat::CpSolverStatus status, bool has_objective) { switch (status) { - case sat::CpSolverStatus::UNKNOWN: - return MPSOLVER_NOT_SOLVED; - case sat::CpSolverStatus::MODEL_INVALID: - return MPSOLVER_MODEL_INVALID; - case sat::CpSolverStatus::FEASIBLE: - return has_objective ? MPSOLVER_FEASIBLE : MPSOLVER_OPTIMAL; - case sat::CpSolverStatus::INFEASIBLE: - return MPSOLVER_INFEASIBLE; - case sat::CpSolverStatus::OPTIMAL: - return MPSOLVER_OPTIMAL; - default: {} + case sat::CpSolverStatus::UNKNOWN: + return MPSOLVER_NOT_SOLVED; + case sat::CpSolverStatus::MODEL_INVALID: + return MPSOLVER_MODEL_INVALID; + case sat::CpSolverStatus::FEASIBLE: + return has_objective ? MPSOLVER_FEASIBLE : MPSOLVER_OPTIMAL; + case sat::CpSolverStatus::INFEASIBLE: + return MPSOLVER_INFEASIBLE; + case sat::CpSolverStatus::OPTIMAL: + return MPSOLVER_OPTIMAL; + default: { + } } return MPSOLVER_ABNORMAL; } -} // namespace +} // namespace -absl::StatusOr -SatSolveProto(MPModelRequest request, std::atomic *interrupt_solve) { +absl::StatusOr SatSolveProto( + MPModelRequest request, std::atomic *interrupt_solve) { // By default, we use 8 threads as it allows to try a good set of orthogonal // parameters. This can be overridden by the user. sat::SatParameters params; @@ -143,8 +144,7 @@ SatSolveProto(MPModelRequest request, std::atomic *interrupt_solve) { const int size = request.model().solution_hint().var_index().size(); for (int i = 0; i < size; ++i) { const int var = request.model().solution_hint().var_index(i); - if (var >= var_scaling.size()) - continue; + if (var >= var_scaling.size()) continue; cp_model_hint->add_vars(var); cp_model_hint->add_values(static_cast(std::round( (request.model().solution_hint().var_value(i)) * var_scaling[var]))); @@ -160,8 +160,8 @@ SatSolveProto(MPModelRequest request, std::atomic *interrupt_solve) { sat::Model sat_model; sat_model.Add(NewSatParameters(params)); if (interrupt_solve != nullptr) { - sat_model.GetOrCreate() - ->RegisterExternalBooleanAsLimit(interrupt_solve); + sat_model.GetOrCreate()->RegisterExternalBooleanAsLimit( + interrupt_solve); } const sat::CpSolverResponse cp_response = sat::SolveCpModel(cp_model, &sat_model); @@ -193,4 +193,4 @@ SatSolveProto(MPModelRequest request, std::atomic *interrupt_solve) { return response; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/sat_proto_solver.h b/ortools/linear_solver/sat_proto_solver.h index 87fe89924f..fa3ca60044 100644 --- a/ortools/linear_solver/sat_proto_solver.h +++ b/ortools/linear_solver/sat_proto_solver.h @@ -20,10 +20,9 @@ namespace operations_research { // If possible, std::move the request into this function call to avoid a copy. -absl::StatusOr - SatSolveProto(MPModelRequest request, - std::atomic *interrupt_solve = nullptr); +absl::StatusOr SatSolveProto( + MPModelRequest request, std::atomic *interrupt_solve = nullptr); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_SAT_PROTO_SOLVER_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_SAT_PROTO_SOLVER_H_ diff --git a/ortools/linear_solver/sat_solver_utils.cc b/ortools/linear_solver/sat_solver_utils.cc index a948da0d42..b912044798 100644 --- a/ortools/linear_solver/sat_solver_utils.cc +++ b/ortools/linear_solver/sat_solver_utils.cc @@ -20,8 +20,8 @@ namespace operations_research { -#define ADD_LP_PREPROCESSOR(name) \ - names.push_back(#name); \ +#define ADD_LP_PREPROCESSOR(name) \ + names.push_back(#name); \ lp_preprocessors.push_back(absl::make_unique(&glop_params)); MPSolverResponseStatus ApplyMipPresolveSteps( @@ -68,7 +68,7 @@ MPSolverResponseStatus ApplyMipPresolveSteps( auto &preprocessor = lp_preprocessors[i]; preprocessor->UseInMipContext(); const bool need_postsolve = preprocessor->Run(&lp); - names[i].resize(header.size(), ' '); // padding. + names[i].resize(header.size(), ' '); // padding. LOG_IF(INFO, log_info) << names[i] << lp.GetDimensionString(); const glop::ProblemStatus status = preprocessor->status(); if (status != glop::ProblemStatus::INIT) { @@ -78,8 +78,7 @@ MPSolverResponseStatus ApplyMipPresolveSteps( } return MPSolverResponseStatus::MPSOLVER_NOT_SOLVED; } - if (need_postsolve) - for_postsolve->push_back(std::move(preprocessor)); + if (need_postsolve) for_postsolve->push_back(std::move(preprocessor)); } } @@ -106,4 +105,4 @@ MPSolverResponseStatus ApplyMipPresolveSteps( #undef ADD_LP_PREPROCESSOR -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/linear_solver/sat_solver_utils.h b/ortools/linear_solver/sat_solver_utils.h index 82f4c51d91..5c022bcd51 100644 --- a/ortools/linear_solver/sat_solver_utils.h +++ b/ortools/linear_solver/sat_solver_utils.h @@ -32,5 +32,5 @@ MPSolverResponseStatus ApplyMipPresolveSteps( bool log_info, const glop::GlopParameters &glop_params, MPModelProto *model, std::vector > *for_postsolve); -} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_SAT_SOLVER_UTILS_H_ +} // namespace operations_research +#endif // OR_TOOLS_LINEAR_SOLVER_SAT_SOLVER_UTILS_H_ diff --git a/ortools/linear_solver/scip_callback.cc b/ortools/linear_solver/scip_callback.cc index 31bdbb3a4f..e8c1fe8920 100644 --- a/ortools/linear_solver/scip_callback.cc +++ b/ortools/linear_solver/scip_callback.cc @@ -64,15 +64,16 @@ SCIP_VAR *ScipGetVar(SCIP *scip, int var_index) { return SCIPgetOrigVars(scip)[var_index]; } -} // namespace +} // namespace ScipConstraintHandlerContext::ScipConstraintHandlerContext( SCIP *scip, SCIP_SOL *solution, bool is_pseudo_solution) - : scip_(scip), solution_(solution), + : scip_(scip), + solution_(solution), is_pseudo_solution_(is_pseudo_solution) {} -double -ScipConstraintHandlerContext::VariableValue(const MPVariable *variable) const { +double ScipConstraintHandlerContext::VariableValue( + const MPVariable *variable) const { return SCIPgetSolVal(scip_, solution_, ScipGetVar(scip_, variable->index())); } @@ -85,7 +86,9 @@ int64 ScipConstraintHandlerContext::CurrentNodeId() const { } enum class ScipSeparationResult { - kLazyConstraintAdded, kCuttingPlaneAdded, kDidNotFind + kLazyConstraintAdded, + kCuttingPlaneAdded, + kDidNotFind }; bool LinearConstraintIsViolated(const ScipConstraintHandlerContext &context, @@ -184,11 +187,11 @@ ScipSeparationResult RunSeparation(internal::ScipCallbackRunner *runner, scip, &scip_cons, user_suggested_constraint.name.c_str(), num_vars, vars.data(), coefs.data(), user_suggested_constraint.range.lower_bound(), - user_suggested_constraint.range.upper_bound(), /*initial=*/ true, - /*separate=*/ true, /*enforce=*/ true, /*check=*/ true, - /*propagate=*/ true, /*local=*/ user_suggested_constraint.local, - /*modifiable=*/ false, /*dynamic=*/ false, /*removable=*/ true, - /*stickingatnode=*/ false))); + user_suggested_constraint.range.upper_bound(), /*initial=*/true, + /*separate=*/true, /*enforce=*/true, /*check=*/true, + /*propagate=*/true, /*local=*/user_suggested_constraint.local, + /*modifiable=*/false, /*dynamic=*/false, /*removable=*/true, + /*stickingatnode=*/false))); if (user_suggested_constraint.local) { CHECK_OK(SCIP_TO_STATUS(SCIPaddConsLocal(scip, scip_cons, nullptr))); } else { @@ -216,14 +219,14 @@ struct CallbackSetup { callback_runner(scip_handler_data->runner.get()), context(scip, sol, is_pseudo_solution), useful_constraints(absl::MakeSpan(conss, nusefulconss)), - unlikely_useful_constraints(absl::MakeSpan(conss, nconss) - .subspan(nusefulconss)) { + unlikely_useful_constraints( + absl::MakeSpan(conss, nconss).subspan(nusefulconss)) { CHECK(scip_handler_data != nullptr); CHECK(callback_runner != nullptr); } }; -} // namespace operations_research +} // namespace operations_research extern "C" { /** destructor of constraint handler to free user data (called when SCIP is @@ -254,23 +257,23 @@ static SCIP_DECL_CONSENFOLP(EnforceLpC) { operations_research::ScipSeparationResult separation_result = operations_research::RunSeparation(setup.callback_runner, setup.context, setup.useful_constraints, - /*is_integral=*/ true); + /*is_integral=*/true); if (separation_result == operations_research::ScipSeparationResult::kDidNotFind) { separation_result = operations_research::RunSeparation( setup.callback_runner, setup.context, setup.unlikely_useful_constraints, - /*is_integral=*/ true); + /*is_integral=*/true); } switch (separation_result) { - case operations_research::ScipSeparationResult::kLazyConstraintAdded: - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kCuttingPlaneAdded: - *result = SCIP_SEPARATED; - break; - case operations_research::ScipSeparationResult::kDidNotFind: - *result = SCIP_FEASIBLE; - break; + case operations_research::ScipSeparationResult::kLazyConstraintAdded: + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kCuttingPlaneAdded: + *result = SCIP_SEPARATED; + break; + case operations_research::ScipSeparationResult::kDidNotFind: + *result = SCIP_FEASIBLE; + break; } return SCIP_OKAY; } @@ -282,23 +285,23 @@ static SCIP_DECL_CONSSEPALP(SeparateLpC) { operations_research::ScipSeparationResult separation_result = operations_research::RunSeparation(setup.callback_runner, setup.context, setup.useful_constraints, - /*is_integral=*/ false); + /*is_integral=*/false); if (separation_result == operations_research::ScipSeparationResult::kDidNotFind) { separation_result = operations_research::RunSeparation( setup.callback_runner, setup.context, setup.unlikely_useful_constraints, - /*is_integral=*/ false); + /*is_integral=*/false); } switch (separation_result) { - case operations_research::ScipSeparationResult::kLazyConstraintAdded: - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kCuttingPlaneAdded: - *result = SCIP_SEPARATED; - break; - case operations_research::ScipSeparationResult::kDidNotFind: - *result = SCIP_DIDNOTFIND; - break; + case operations_research::ScipSeparationResult::kLazyConstraintAdded: + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kCuttingPlaneAdded: + *result = SCIP_SEPARATED; + break; + case operations_research::ScipSeparationResult::kDidNotFind: + *result = SCIP_DIDNOTFIND; + break; } return SCIP_OKAY; } @@ -310,25 +313,25 @@ static SCIP_DECL_CONSSEPASOL(SeparatePrimalSolutionC) { operations_research::ScipSeparationResult separation_result = operations_research::RunSeparation(setup.callback_runner, setup.context, setup.useful_constraints, - /*is_integral=*/ true); + /*is_integral=*/true); if (separation_result == operations_research::ScipSeparationResult::kDidNotFind) { separation_result = operations_research::RunSeparation( setup.callback_runner, setup.context, setup.unlikely_useful_constraints, - /*is_integral=*/ true); + /*is_integral=*/true); } switch (separation_result) { - case operations_research::ScipSeparationResult::kLazyConstraintAdded: - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kCuttingPlaneAdded: - LOG(ERROR) << "Cutting planes cannot be added on integer solutions, " - "treating as a constraint."; - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kDidNotFind: - *result = SCIP_DIDNOTFIND; - break; + case operations_research::ScipSeparationResult::kLazyConstraintAdded: + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kCuttingPlaneAdded: + LOG(ERROR) << "Cutting planes cannot be added on integer solutions, " + "treating as a constraint."; + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kDidNotFind: + *result = SCIP_DIDNOTFIND; + break; } return SCIP_OKAY; } @@ -359,25 +362,25 @@ static SCIP_DECL_CONSENFOPS(EnforcePseudoSolutionC) { operations_research::ScipSeparationResult separation_result = operations_research::RunSeparation(setup.callback_runner, setup.context, setup.useful_constraints, - /*is_integral=*/ false); + /*is_integral=*/false); if (separation_result == operations_research::ScipSeparationResult::kDidNotFind) { separation_result = operations_research::RunSeparation( setup.callback_runner, setup.context, setup.unlikely_useful_constraints, - /*is_integral=*/ false); + /*is_integral=*/false); } switch (separation_result) { - case operations_research::ScipSeparationResult::kLazyConstraintAdded: - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kCuttingPlaneAdded: - LOG(ERROR) << "Cutting planes cannot be added on pseudo solutions, " - "treating as a constraint."; - *result = SCIP_CONSADDED; - break; - case operations_research::ScipSeparationResult::kDidNotFind: - *result = SCIP_FEASIBLE; - break; + case operations_research::ScipSeparationResult::kLazyConstraintAdded: + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kCuttingPlaneAdded: + LOG(ERROR) << "Cutting planes cannot be added on pseudo solutions, " + "treating as a constraint."; + *result = SCIP_CONSADDED; + break; + case operations_research::ScipSeparationResult::kDidNotFind: + *result = SCIP_FEASIBLE; + break; } return SCIP_OKAY; } @@ -403,10 +406,9 @@ static SCIP_DECL_CONSLOCK(VariableRoundingLockC) { namespace operations_research { namespace internal { -void -AddConstraintHandlerImpl(const ScipConstraintHandlerDescription &description, - std::unique_ptr runner, - SCIP *scip) { +void AddConstraintHandlerImpl( + const ScipConstraintHandlerDescription &description, + std::unique_ptr runner, SCIP *scip) { SCIP_CONSHDLR *c_scip_handler; SCIP_CONSHDLRDATA *scip_handler_data = new SCIP_CONSHDLRDATA; scip_handler_data->runner = std::move(runner); @@ -421,7 +423,7 @@ AddConstraintHandlerImpl(const ScipConstraintHandlerDescription &description, CHECK_OK(SCIP_TO_STATUS(SCIPsetConshdlrSepa( scip, c_scip_handler, SeparateLpC, SeparatePrimalSolutionC, description.separation_frequency, description.separation_priority, - /*delaysepa=*/ false))); + /*delaysepa=*/false))); CHECK_OK(SCIP_TO_STATUS( SCIPsetConshdlrFree(scip, c_scip_handler, ConstraintHandlerFreeC))); CHECK_OK(SCIP_TO_STATUS( @@ -433,8 +435,8 @@ void AddCallbackConstraintImpl(SCIP *scip, const std::string &handler_name, void *constraint_data, const ScipCallbackConstraintOptions &options) { SCIP_CONSHDLR *conshdlr = SCIPfindConshdlr(scip, handler_name.c_str()); - CHECK(conshdlr != nullptr) << "Constraint handler " << handler_name - << " not registered with scip."; + CHECK(conshdlr != nullptr) + << "Constraint handler " << handler_name << " not registered with scip."; SCIP_ConsData *consdata = new SCIP_ConsData; consdata->data = constraint_data; SCIP_CONS *constraint = nullptr; @@ -448,6 +450,6 @@ void AddCallbackConstraintImpl(SCIP *scip, const std::string &handler_name, CHECK_OK(SCIP_TO_STATUS(SCIPreleaseCons(scip, &constraint))); } -} // namespace internal -} // namespace operations_research -#endif // #if defined(USE_SCIP) +} // namespace internal +} // namespace operations_research +#endif // #if defined(USE_SCIP) diff --git a/ortools/linear_solver/scip_callback.h b/ortools/linear_solver/scip_callback.h index 8f4e8a2df5..d25866b722 100644 --- a/ortools/linear_solver/scip_callback.h +++ b/ortools/linear_solver/scip_callback.h @@ -80,7 +80,7 @@ struct ScipConstraintHandlerDescription { }; class ScipConstraintHandlerContext { -public: + public: // A value of nullptr for solution means to use the current LP solution. ScipConstraintHandlerContext(SCIP *scip, SCIP_SOL *solution, bool is_pseudo_solution); @@ -100,7 +100,7 @@ public: // TODO(user): maybe this can be abstracted away. bool is_pseudo_solution() const { return is_pseudo_solution_; } -private: + private: SCIP *scip_; SCIP_SOL *solution_; bool is_pseudo_solution_; @@ -108,14 +108,15 @@ private: struct CallbackRangeConstraint { LinearRange range; - bool is_cut = false; // Does not remove any integer points. - std::string name; // can be empty + bool is_cut = false; // Does not remove any integer points. + std::string name; // can be empty bool local = false; }; // See go/scip-callbacks for additional documentation. -template class ScipConstraintHandler { -public: +template +class ScipConstraintHandler { + public: explicit ScipConstraintHandler( const ScipConstraintHandlerDescription &description) : description_(description) {} @@ -126,33 +127,33 @@ public: // Unless SeparateIntegerSolution() below is overridden, this must find a // violated lazy constraint if one exists when given an integral solution. - virtual std::vector - SeparateFractionalSolution(const ScipConstraintHandlerContext &context, - const Constraint &constraint) = 0; + virtual std::vector SeparateFractionalSolution( + const ScipConstraintHandlerContext &context, + const Constraint &constraint) = 0; // This MUST find a violated lazy constraint if one exists. // All constraints returned must have is_cut as false. - virtual std::vector - SeparateIntegerSolution(const ScipConstraintHandlerContext &context, - const Constraint &constraint) { + virtual std::vector SeparateIntegerSolution( + const ScipConstraintHandlerContext &context, + const Constraint &constraint) { return SeparateFractionalSolution(context, constraint); } // Returns true if no constraints are violated. - virtual bool - FractionalSolutionFeasible(const ScipConstraintHandlerContext &context, - const Constraint &constraint) { + virtual bool FractionalSolutionFeasible( + const ScipConstraintHandlerContext &context, + const Constraint &constraint) { return SeparateFractionalSolution(context, constraint).empty(); } // This MUST find a violated constraint if one exists. - virtual bool - IntegerSolutionFeasible(const ScipConstraintHandlerContext &context, - const Constraint &constraint) { + virtual bool IntegerSolutionFeasible( + const ScipConstraintHandlerContext &context, + const Constraint &constraint) { return SeparateIntegerSolution(context, constraint).empty(); } -private: + private: ScipConstraintHandlerDescription description_; }; @@ -187,42 +188,38 @@ void AddCallbackConstraint(SCIP *scip, namespace internal { class ScipCallbackRunner { -public: + public: virtual ~ScipCallbackRunner() {} - virtual std::vector - SeparateFractionalSolution(const ScipConstraintHandlerContext &context, - void *constraint) = 0; + virtual std::vector SeparateFractionalSolution( + const ScipConstraintHandlerContext &context, void *constraint) = 0; - virtual std::vector - SeparateIntegerSolution(const ScipConstraintHandlerContext &context, - void *constraint) = 0; + virtual std::vector SeparateIntegerSolution( + const ScipConstraintHandlerContext &context, void *constraint) = 0; - virtual bool - FractionalSolutionFeasible(const ScipConstraintHandlerContext &context, - void *constraint) = 0; + virtual bool FractionalSolutionFeasible( + const ScipConstraintHandlerContext &context, void *constraint) = 0; - virtual bool - IntegerSolutionFeasible(const ScipConstraintHandlerContext &context, - void *constraint) = 0; + virtual bool IntegerSolutionFeasible( + const ScipConstraintHandlerContext &context, void *constraint) = 0; }; template class ScipCallbackRunnerImpl : public ScipCallbackRunner { -public: + public: explicit ScipCallbackRunnerImpl( ScipConstraintHandler *handler) : handler_(handler) {} - std::vector - SeparateFractionalSolution(const ScipConstraintHandlerContext &context, - void *constraint_data) override { + std::vector SeparateFractionalSolution( + const ScipConstraintHandlerContext &context, + void *constraint_data) override { return handler_->SeparateFractionalSolution( context, *static_cast(constraint_data)); } - std::vector - SeparateIntegerSolution(const ScipConstraintHandlerContext &context, - void *constraint_data) override { + std::vector SeparateIntegerSolution( + const ScipConstraintHandlerContext &context, + void *constraint_data) override { return handler_->SeparateIntegerSolution( context, *static_cast(constraint_data)); } @@ -239,7 +236,7 @@ public: context, *static_cast(constraint_data)); } -private: + private: ScipConstraintHandler *handler_; }; @@ -252,7 +249,7 @@ void AddCallbackConstraintImpl(SCIP *scip, const std::string &handler_name, void *constraint_data, const ScipCallbackConstraintOptions &options); -} // namespace internal +} // namespace internal template void RegisterConstraintHandler(ScipConstraintHandler *handler, @@ -276,6 +273,6 @@ void AddCallbackConstraint(SCIP *scip, options); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_CALLBACK_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_CALLBACK_H_ diff --git a/ortools/linear_solver/scip_helper_macros.h b/ortools/linear_solver/scip_helper_macros.h index cfee4f9a3d..750aeae83e 100644 --- a/ortools/linear_solver/scip_helper_macros.h +++ b/ortools/linear_solver/scip_helper_macros.h @@ -29,13 +29,12 @@ inline absl::Status ScipCodeToUtilStatus(/*SCIP_Retcode*/ int retcode, const char *source_file, int source_line, const char *scip_statement) { - if (retcode == /*SCIP_OKAY*/ 1) - return absl::OkStatus(); + if (retcode == /*SCIP_OKAY*/ 1) return absl::OkStatus(); return absl::InvalidArgumentError( absl::StrFormat("SCIP error code %d (file '%s', line %d) on '%s'", retcode, source_file, source_line, scip_statement)); } -} // namespace internal +} // namespace internal #define SCIP_TO_STATUS(x) \ ::operations_research::internal::ScipCodeToUtilStatus(x, __FILE__, __LINE__, \ @@ -43,6 +42,6 @@ inline absl::Status ScipCodeToUtilStatus(/*SCIP_Retcode*/ int retcode, #define RETURN_IF_SCIP_ERROR(x) RETURN_IF_ERROR(SCIP_TO_STATUS(x)); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_HELPER_MACROS_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_HELPER_MACROS_H_ diff --git a/ortools/linear_solver/scip_interface.cc b/ortools/linear_solver/scip_interface.cc index 16b295ba99..442766f74a 100644 --- a/ortools/linear_solver/scip_interface.cc +++ b/ortools/linear_solver/scip_interface.cc @@ -50,21 +50,20 @@ DEFINE_bool(scip_feasibility_emphasis, false, namespace operations_research { namespace { // See the class ScipConstraintHandlerForMPCallback below. -struct EmptyStruct { -}; -} // namespace +struct EmptyStruct {}; +} // namespace class ScipConstraintHandlerForMPCallback; class SCIPInterface : public MPSolverInterface { -public: + public: explicit SCIPInterface(MPSolver *solver); ~SCIPInterface() override; void SetOptimizationDirection(bool maximize) override; MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override; - absl::optional - DirectlySolveProto(const MPModelRequest &request) override; + absl::optional DirectlySolveProto( + const MPModelRequest &request) override; void Reset() override; void SetVariableBounds(int var_index, double lb, double ub) override; @@ -77,8 +76,8 @@ public: void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override; void ClearConstraint(MPConstraint *constraint) override; - void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) - override; + void SetObjectiveCoefficient(const MPVariable *variable, + double coefficient) override; void SetObjectiveOffset(double value) override; void ClearObjective() override; void BranchingPriorityChangedForVariable(int var_index) override; @@ -110,8 +109,7 @@ public: } bool InterruptSolve() override { - if (scip_ == nullptr) - return true; // NOTE(user): Is this weird? + if (scip_ == nullptr) return true; // NOTE(user): Is this weird? return SCIPinterruptSolve(scip_) == SCIP_OKAY; } @@ -144,7 +142,7 @@ public: void SetCallback(MPCallback *mp_callback) override; bool SupportsCallbacks() const override { return true; } -private: + private: void SetParameters(const MPSolverParameters ¶m) override; void SetRelativeMipGap(double value) override; void SetPrimalTolerance(double value) override; @@ -163,11 +161,11 @@ private: // necessery to enable multi-threading. absl::Status SetNumThreads(int num_threads) override; - bool SetSolverSpecificParametersAsString(const std::string ¶meters) - override; + bool SetSolverSpecificParametersAsString( + const std::string ¶meters) override; - void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param) - override; + void SetUnsupportedIntegerParam( + MPSolverParameters::IntegerParam param) override; void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value) override; // How many solutions SCIP found. @@ -200,21 +198,21 @@ private: class ScipConstraintHandlerForMPCallback : public ScipConstraintHandler { -public: + public: explicit ScipConstraintHandlerForMPCallback(MPCallback *mp_callback); - std::vector - SeparateFractionalSolution(const ScipConstraintHandlerContext &context, - const EmptyStruct &) override; + std::vector SeparateFractionalSolution( + const ScipConstraintHandlerContext &context, + const EmptyStruct &) override; - std::vector - SeparateIntegerSolution(const ScipConstraintHandlerContext &context, - const EmptyStruct &) override; + std::vector SeparateIntegerSolution( + const ScipConstraintHandlerContext &context, + const EmptyStruct &) override; -private: - std::vector - SeparateSolution(const ScipConstraintHandlerContext &context, - const bool at_integer_solution); + private: + std::vector SeparateSolution( + const ScipConstraintHandlerContext &context, + const bool at_integer_solution); MPCallback *mp_callback_; }; @@ -240,7 +238,7 @@ absl::Status SCIPInterface::CreateSCIP() { // the new parameter (quiet = true). if (absl::GetFlag(FLAGS_scip_feasibility_emphasis)) { RETURN_IF_SCIP_ERROR(SCIPsetEmphasis(scip_, SCIP_PARAMEMPHASIS_FEASIBILITY, - /*quiet=*/ true)); + /*quiet=*/true)); } // Default clock type. We use wall clock time because getting CPU user seconds // involves calling times() which is very expensive. @@ -250,9 +248,9 @@ absl::Status SCIPInterface::CreateSCIP() { // running SCIP with time limit 10s each will both terminate after ~5s. RETURN_IF_SCIP_ERROR( SCIPsetIntParam(scip_, "timing/clocktype", SCIP_CLOCKTYPE_WALL)); - RETURN_IF_SCIP_ERROR( - SCIPcreateProb(scip_, solver_->name_.c_str(), nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr)); + RETURN_IF_SCIP_ERROR(SCIPcreateProb(scip_, solver_->name_.c_str(), nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr)); RETURN_IF_SCIP_ERROR(SCIPsetObjsense( scip_, maximize_ ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE)); return absl::OkStatus(); @@ -276,19 +274,18 @@ void SCIPInterface::DeleteSCIP() { scip_ = nullptr; } -#define RETURN_IF_ALREADY_IN_ERROR_STATE \ - do { \ - if (!status_.ok()) { \ - VLOG_EVERY_N(1, 10) << "Early abort: SCIP is in error state."; \ - return; \ - } \ +#define RETURN_IF_ALREADY_IN_ERROR_STATE \ + do { \ + if (!status_.ok()) { \ + VLOG_EVERY_N(1, 10) << "Early abort: SCIP is in error state."; \ + return; \ + } \ } while (false) -#define RETURN_AND_STORE_IF_SCIP_ERROR(x) \ - do { \ - status_ = SCIP_TO_STATUS(x); \ - if (!status_.ok()) \ - return; \ +#define RETURN_AND_STORE_IF_SCIP_ERROR(x) \ + do { \ + status_ = SCIP_TO_STATUS(x); \ + if (!status_.ok()) return; \ } while (false) // Not cached. @@ -331,7 +328,7 @@ void SCIPInterface::SetVariableInteger(int var_index, bool integer) { RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarType( scip_, scip_variables_[var_index], integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS)); -#endif // SCIP_VERSION >= 210 +#endif // SCIP_VERSION >= 210 } else { sync_status_ = MUST_RELOAD; } @@ -383,8 +380,7 @@ void SCIPInterface::ClearConstraint(MPConstraint *constraint) { InvalidateSolutionSynchronization(); const int constraint_index = constraint->index(); // Constraint may not have been extracted yet. - if (!constraint_is_extracted(constraint_index)) - return; + if (!constraint_is_extracted(constraint_index)) return; for (const auto &entry : constraint->coefficients_) { const int var_index = entry.first->index(); const double old_coef_value = entry.second; @@ -516,7 +512,7 @@ void SCIPInterface::ExtractNewConstraints() { max_row_length = ct->coefficients_.size(); } } - std::unique_ptr vars(new SCIP_VAR *[max_row_length]); + std::unique_ptr vars(new SCIP_VAR *[max_row_length]); std::unique_ptr coeffs(new double[max_row_length]); // Add each new constraint. for (int i = last_constraint_index_; i < total_num_rows; ++i) { @@ -545,10 +541,10 @@ void SCIPInterface::ExtractNewConstraints() { if (ct->ub() < std::numeric_limits::infinity()) { RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator( scip_, &scip_constraint, ct->name().c_str(), ind_var, size, - vars.get(), coeffs.get(), ct->ub(), /*initial=*/ !is_lazy, - /*separate=*/ true, /*enforce=*/ true, /*check=*/ true, - /*propagate=*/ true, /*local=*/ false, /*dynamic=*/ false, - /*removable=*/ is_lazy, /*stickingatnode=*/ false)); + vars.get(), coeffs.get(), ct->ub(), /*initial=*/!is_lazy, + /*separate=*/true, /*enforce=*/true, /*check=*/true, + /*propagate=*/true, /*local=*/false, /*dynamic=*/false, + /*removable=*/is_lazy, /*stickingatnode=*/false)); RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint)); scip_constraints_.push_back(scip_constraint); } @@ -558,10 +554,10 @@ void SCIPInterface::ExtractNewConstraints() { } RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator( scip_, &scip_constraint, ct->name().c_str(), ind_var, size, - vars.get(), coeffs.get(), -ct->lb(), /*initial=*/ !is_lazy, - /*separate=*/ true, /*enforce=*/ true, /*check=*/ true, - /*propagate=*/ true, /*local=*/ false, /*dynamic=*/ false, - /*removable=*/ is_lazy, /*stickingatnode=*/ false)); + vars.get(), coeffs.get(), -ct->lb(), /*initial=*/!is_lazy, + /*separate=*/true, /*enforce=*/true, /*check=*/true, + /*propagate=*/true, /*local=*/false, /*dynamic=*/false, + /*removable=*/is_lazy, /*stickingatnode=*/false)); RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint)); scip_constraints_.push_back(scip_constraint); } @@ -571,11 +567,11 @@ void SCIPInterface::ExtractNewConstraints() { // for an explanation of the parameters. RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsLinear( scip_, &scip_constraint, ct->name().c_str(), size, vars.get(), - coeffs.get(), ct->lb(), ct->ub(), /*initial=*/ !is_lazy, - /*separate=*/ true, /*enforce=*/ true, /*check=*/ true, - /*propagate=*/ true, /*local=*/ false, /*modifiable=*/ false, - /*dynamic=*/ false, /*removable=*/ is_lazy, - /*stickingatnode=*/ false)); + coeffs.get(), ct->lb(), ct->ub(), /*initial=*/!is_lazy, + /*separate=*/true, /*enforce=*/true, /*check=*/true, + /*propagate=*/true, /*local=*/false, /*modifiable=*/false, + /*dynamic=*/false, /*removable=*/is_lazy, + /*stickingatnode=*/false)); RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint)); scip_constraints_.push_back(scip_constraint); } @@ -600,20 +596,20 @@ void SCIPInterface::ExtractObjective() { scip_, solver_->Objective().offset() - SCIPgetOrigObjoffset(scip_))); } -#define RETURN_ABNORMAL_IF_BAD_STATUS \ - do { \ - if (!status_.ok()) { \ - LOG_IF(INFO, solver_->OutputIsEnabled()) \ - << "Invalid SCIP status: " << status_; \ - return result_status_ = MPSolver::ABNORMAL; \ - } \ +#define RETURN_ABNORMAL_IF_BAD_STATUS \ + do { \ + if (!status_.ok()) { \ + LOG_IF(INFO, solver_->OutputIsEnabled()) \ + << "Invalid SCIP status: " << status_; \ + return result_status_ = MPSolver::ABNORMAL; \ + } \ } while (false) -#define RETURN_ABNORMAL_IF_SCIP_ERROR(x) \ - do { \ - RETURN_ABNORMAL_IF_BAD_STATUS; \ - status_ = SCIP_TO_STATUS(x); \ - RETURN_ABNORMAL_IF_BAD_STATUS; \ +#define RETURN_ABNORMAL_IF_SCIP_ERROR(x) \ + do { \ + RETURN_ABNORMAL_IF_BAD_STATUS; \ + status_ = SCIP_TO_STATUS(x); \ + RETURN_ABNORMAL_IF_BAD_STATUS; \ } while (false); MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters ¶m) { @@ -629,8 +625,8 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters ¶m) { // Note that SCIP does not provide any incrementality. // TODO(user): Is that still true now (2018) ? if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) == - MPSolverParameters::INCREMENTALITY_OFF || branching_priority_reset_ || - callback_reset_) { + MPSolverParameters::INCREMENTALITY_OFF || + branching_priority_reset_ || callback_reset_) { Reset(); branching_priority_reset_ = false; callback_reset_ = false; @@ -704,9 +700,9 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters ¶m) { if (!is_solution_partial) { SCIP_Bool is_feasible; RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPcheckSol( - scip_, solution, /*printreason=*/ false, /*completely=*/ true, - /*checkbounds=*/ true, /*checkintegrality=*/ true, - /*checklprows=*/ true, &is_feasible)); + scip_, solution, /*printreason=*/false, /*completely=*/true, + /*checkbounds=*/true, /*checkintegrality=*/true, + /*checklprows=*/true, &is_feasible)); VLOG(1) << "Solution hint is " << (is_feasible ? "FEASIBLE" : "INFEASIBLE"); } @@ -718,9 +714,9 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters ¶m) { SCIP_Bool is_stored; if (!is_solution_partial && SCIPisTransformed(scip_)) { RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPtrySolFree( - scip_, &solution, /*printreason=*/ false, /*completely=*/ true, - /*checkbounds=*/ true, /*checkintegrality=*/ true, - /*checklprows=*/ true, &is_stored)); + scip_, &solution, /*printreason=*/false, /*completely=*/true, + /*checkbounds=*/true, /*checkintegrality=*/true, + /*checklprows=*/true, &is_stored)); } else { RETURN_ABNORMAL_IF_SCIP_ERROR( SCIPaddSolFree(scip_, &solution, &is_stored)); @@ -747,34 +743,34 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters ¶m) { // Check the status: optimal, infeasible, etc. SCIP_STATUS scip_status = SCIPgetStatus(scip_); switch (scip_status) { - case SCIP_STATUS_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case SCIP_STATUS_GAPLIMIT: - // To be consistent with the other solvers. - result_status_ = MPSolver::OPTIMAL; - break; - case SCIP_STATUS_INFEASIBLE: - result_status_ = MPSolver::INFEASIBLE; - break; - case SCIP_STATUS_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - case SCIP_STATUS_INFORUNBD: - // TODO(user): We could introduce our own "infeasible or - // unbounded" status. - result_status_ = MPSolver::INFEASIBLE; - break; - default: - if (solution != nullptr) { - result_status_ = MPSolver::FEASIBLE; - } else if (scip_status == SCIP_STATUS_TIMELIMIT || - scip_status == SCIP_STATUS_TOTALNODELIMIT) { - result_status_ = MPSolver::NOT_SOLVED; - } else { - result_status_ = MPSolver::ABNORMAL; - } - break; + case SCIP_STATUS_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case SCIP_STATUS_GAPLIMIT: + // To be consistent with the other solvers. + result_status_ = MPSolver::OPTIMAL; + break; + case SCIP_STATUS_INFEASIBLE: + result_status_ = MPSolver::INFEASIBLE; + break; + case SCIP_STATUS_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + case SCIP_STATUS_INFORUNBD: + // TODO(user): We could introduce our own "infeasible or + // unbounded" status. + result_status_ = MPSolver::INFEASIBLE; + break; + default: + if (solution != nullptr) { + result_status_ = MPSolver::FEASIBLE; + } else if (scip_status == SCIP_STATUS_TIMELIMIT || + scip_status == SCIP_STATUS_TOTALNODELIMIT) { + result_status_ = MPSolver::NOT_SOLVED; + } else { + result_status_ = MPSolver::ABNORMAL; + } + break; } RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPresetParams(scip_)); @@ -796,19 +792,16 @@ void SCIPInterface::SetSolution(SCIP_SOL *solution) { } } -absl::optional -SCIPInterface::DirectlySolveProto(const MPModelRequest &request) { +absl::optional SCIPInterface::DirectlySolveProto( + const MPModelRequest &request) { // ScipSolveProto doesn't solve concurrently. - if (solver_->GetNumThreads() > 1) - return absl::nullopt; + if (solver_->GetNumThreads() > 1) return absl::nullopt; const auto status_or = ScipSolveProto(request); - if (status_or.ok()) - return status_or.value(); + if (status_or.ok()) return status_or.value(); // Special case: if something is not implemented yet, fall back to solving // through MPSolver. - if (absl::IsUnimplemented(status_or.status())) - return absl::nullopt; + if (absl::IsUnimplemented(status_or.status())) return absl::nullopt; if (request.enable_internal_solver_output()) { LOG(INFO) << "Invalid SCIP status: " << status_or.status(); @@ -838,15 +831,13 @@ bool SCIPInterface::NextSolution() { int64 SCIPInterface::iterations() const { // NOTE(user): As of 2018-12 it doesn't run in the stubby server, and is // a specialized call, so it's ok to crash if the status is broken. - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; return SCIPgetNLPIterations(scip_); } int64 SCIPInterface::nodes() const { // NOTE(user): Same story as iterations(): it's OK to crash here. - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; // This is the total number of nodes used in the solve, potentially across // multiple branch-and-bound trees. Use limits/totalnodes (rather than // limits/nodes) to control this value. @@ -884,46 +875,41 @@ void SCIPInterface::SetRelativeMipGap(double value) { // set the state to that error we just got. const auto status = SCIP_TO_STATUS(SCIPsetRealParam(scip_, "limits/gap", value)); - if (status_.ok()) - status_ = status; + if (status_.ok()) status_ = status; } void SCIPInterface::SetPrimalTolerance(double value) { // See the NOTE on SetRelativeMipGap(). const auto status = SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/feastol", value)); - if (status_.ok()) - status_ = status; + if (status_.ok()) status_ = status; } void SCIPInterface::SetDualTolerance(double value) { const auto status = SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/dualfeastol", value)); - if (status_.ok()) - status_ = status; + if (status_.ok()) status_ = status; } void SCIPInterface::SetPresolveMode(int presolve) { // See the NOTE on SetRelativeMipGap(). switch (presolve) { - case MPSolverParameters::PRESOLVE_OFF: { - const auto status = - SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", 0)); - if (status_.ok()) - status_ = status; - return; - } - case MPSolverParameters::PRESOLVE_ON: { - const auto status = - SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", -1)); - if (status_.ok()) - status_ = status; - return; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, presolve); - return; - } + case MPSolverParameters::PRESOLVE_OFF: { + const auto status = + SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", 0)); + if (status_.ok()) status_ = status; + return; + } + case MPSolverParameters::PRESOLVE_ON: { + const auto status = + SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", -1)); + if (status_.ok()) status_ = status; + return; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, presolve); + return; + } } } @@ -937,33 +923,30 @@ void SCIPInterface::SetScalingMode(int scaling) { void SCIPInterface::SetLpAlgorithm(int lp_algorithm) { // See the NOTE on SetRelativeMipGap(). switch (lp_algorithm) { - case MPSolverParameters::DUAL: { - const auto status = - SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'd')); - if (status_.ok()) - status_ = status; - return; - } - case MPSolverParameters::PRIMAL: { - const auto status = - SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p')); - if (status_.ok()) - status_ = status; - return; - } - case MPSolverParameters::BARRIER: { - // Barrier with crossover. - const auto status = - SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p')); - if (status_.ok()) - status_ = status; - return; - } - default: { - SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, - lp_algorithm); - return; - } + case MPSolverParameters::DUAL: { + const auto status = + SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'd')); + if (status_.ok()) status_ = status; + return; + } + case MPSolverParameters::PRIMAL: { + const auto status = + SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p')); + if (status_.ok()) status_ = status; + return; + } + case MPSolverParameters::BARRIER: { + // Barrier with crossover. + const auto status = + SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p')); + if (status_.ok()) status_ = status; + return; + } + default: { + SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM, + lp_algorithm); + return; + } } } @@ -991,8 +974,9 @@ absl::Status SCIPInterface::SetNumThreads(int num_threads) { absl::StrFormat("parallel/maxnthreads = %d\n", num_threads))) { return absl::OkStatus(); } - return absl::InternalError("Could not set parallel/maxnthreads, which may " - "indicate that SCIP API has changed."); + return absl::InternalError( + "Could not set parallel/maxnthreads, which may " + "indicate that SCIP API has changed."); } bool SCIPInterface::SetSolverSpecificParametersAsString( @@ -1007,11 +991,11 @@ bool SCIPInterface::SetSolverSpecificParametersAsString( } class ScipMPCallbackContext : public MPCallbackContext { -public: + public: ScipMPCallbackContext(const ScipConstraintHandlerContext *scip_context, bool at_integer_solution) - : scip_context_(scip_context), at_integer_solution_(at_integer_solution) { - } + : scip_context_(scip_context), + at_integer_solution_(at_integer_solution) {} MPCallbackEvent Event() override { if (at_integer_solution_) { @@ -1045,33 +1029,29 @@ public: constraints_added_.push_back(std::move(constraint)); } - double SuggestSolution( - const absl::flat_hash_map &solution) - override { + double SuggestSolution(const absl::flat_hash_map + &solution) override { LOG(FATAL) << "SuggestSolution() not currently supported for SCIP."; } int64 NumExploredNodes() override { - // scip_context_->NumNodesProcessed() returns: - // 0 before the root node is solved, e.g. if a heuristic finds a - // solution. - // 1 at the root node - // > 1 after the root node. - // The NumExploredNodes spec requires that we return 0 at the root node, - // (this is consistent with gurobi). Below is a bandaid to try and make - // the - // behavior consistent, although some information is lost. - return std::max(int64 { - 0 - }, - scip_context_->NumNodesProcessed() - 1); + // scip_context_->NumNodesProcessed() returns: + // 0 before the root node is solved, e.g. if a heuristic finds a + // solution. + // 1 at the root node + // > 1 after the root node. + // The NumExploredNodes spec requires that we return 0 at the root node, + // (this is consistent with gurobi). Below is a bandaid to try and make + // the + // behavior consistent, although some information is lost. + return std::max(int64{0}, scip_context_->NumNodesProcessed() - 1); } const std::vector &constraints_added() { return constraints_added_; } -private: + private: const ScipConstraintHandlerContext *scip_context_; bool at_integer_solution_; // second value of pair is true for cuts and false for lazy constraints. @@ -1082,10 +1062,9 @@ ScipConstraintHandlerForMPCallback::ScipConstraintHandlerForMPCallback( MPCallback *mp_callback) : ScipConstraintHandler( // MOE(begin-strip): - { /*name=*/ - "mp_solver_constraint_handler", /*description=*/ - "A single constraint handler for all MPSolver models." -} + { /*name=*/ + "mp_solver_constraint_handler", /*description=*/ + "A single constraint handler for all MPSolver models."} // MOE(end-strip-and-replace): ScipConstraintHandlerDescription() ), mp_callback_(mp_callback) {} @@ -1093,13 +1072,13 @@ ScipConstraintHandlerForMPCallback::ScipConstraintHandlerForMPCallback( std::vector ScipConstraintHandlerForMPCallback::SeparateFractionalSolution( const ScipConstraintHandlerContext &context, const EmptyStruct &) { - return SeparateSolution(context, /*at_integer_solution=*/ false); + return SeparateSolution(context, /*at_integer_solution=*/false); } std::vector ScipConstraintHandlerForMPCallback::SeparateIntegerSolution( const ScipConstraintHandlerContext &context, const EmptyStruct &) { - return SeparateSolution(context, /*at_integer_solution=*/ true); + return SeparateSolution(context, /*at_integer_solution=*/true); } std::vector @@ -1122,8 +1101,8 @@ MPSolverInterface *BuildSCIPInterface(MPSolver *const solver) { return new SCIPInterface(solver); } -} // namespace operations_research -#endif // #if defined(USE_SCIP) +} // namespace operations_research +#endif // #if defined(USE_SCIP) #undef RETURN_AND_STORE_IF_SCIP_ERROR #undef RETURN_IF_ALREADY_IN_ERROR_STATE diff --git a/ortools/linear_solver/scip_proto_solver.cc b/ortools/linear_solver/scip_proto_solver.cc index d20ef7e3d8..f02d50878c 100644 --- a/ortools/linear_solver/scip_proto_solver.cc +++ b/ortools/linear_solver/scip_proto_solver.cc @@ -77,8 +77,7 @@ absl::Status AddIndicatorConstraint(const MPGeneralConstraintProto &gen_cst, constexpr double kInfinity = std::numeric_limits::infinity(); const auto &ind = gen_cst.indicator_constraint(); - if (!ind.has_constraint()) - return absl::OkStatus(); + if (!ind.has_constraint()) return absl::OkStatus(); const MPConstraintProto &constraint = ind.constraint(); const int size = constraint.var_index_size(); @@ -100,10 +99,10 @@ absl::Status AddIndicatorConstraint(const MPGeneralConstraintProto &gen_cst, scip, scip_cst, gen_cst.name().c_str(), ind_var, size, tmp_variables->data(), tmp_coefficients->data(), ind.constraint().upper_bound(), - /*initial=*/ !ind.constraint().is_lazy(), /*separate=*/ true, - /*enforce=*/ true, /*check=*/ true, /*propagate=*/ true, - /*local=*/ false, /*dynamic=*/ false, - /*removable=*/ ind.constraint().is_lazy(), /*stickingatnode=*/ false)); + /*initial=*/!ind.constraint().is_lazy(), /*separate=*/true, + /*enforce=*/true, /*check=*/true, /*propagate=*/true, + /*local=*/false, /*dynamic=*/false, + /*removable=*/ind.constraint().is_lazy(), /*stickingatnode=*/false)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); scip_constraints->push_back(nullptr); scip_cst = &scip_constraints->back(); @@ -116,10 +115,10 @@ absl::Status AddIndicatorConstraint(const MPGeneralConstraintProto &gen_cst, scip, scip_cst, gen_cst.name().c_str(), ind_var, size, tmp_variables->data(), tmp_coefficients->data(), -ind.constraint().lower_bound(), - /*initial=*/ !ind.constraint().is_lazy(), /*separate=*/ true, - /*enforce=*/ true, /*check=*/ true, /*propagate=*/ true, - /*local=*/ false, /*dynamic=*/ false, - /*removable=*/ ind.constraint().is_lazy(), /*stickingatnode=*/ false)); + /*initial=*/!ind.constraint().is_lazy(), /*separate=*/true, + /*enforce=*/true, /*check=*/true, /*propagate=*/true, + /*local=*/false, /*dynamic=*/false, + /*removable=*/ind.constraint().is_lazy(), /*stickingatnode=*/false)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); } @@ -142,8 +141,7 @@ absl::Status AddSosConstraint(const MPGeneralConstraintProto &gen_cst, // SOS constraints of type N indicate at most N variables are non-zero. // Constraints with N variables or less are valid, but useless. They also // crash SCIP, so we skip them. - if (sos_cst.var_index_size() <= 1) - return absl::OkStatus(); + if (sos_cst.var_index_size() <= 1) return absl::OkStatus(); if (sos_cst.type() == MPSosConstraint::SOS2 && sos_cst.var_index_size() <= 2) { return absl::OkStatus(); @@ -164,32 +162,31 @@ absl::Status AddSosConstraint(const MPGeneralConstraintProto &gen_cst, std::iota(tmp_weights->begin(), tmp_weights->end(), 1); } switch (sos_cst.type()) { - case MPSosConstraint::SOS1_DEFAULT: - RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicSOS1( - scip, /*cons=*/ scip_cst, /*name=*/ gen_cst.name().c_str(), - /*nvars=*/ sos_cst.var_index_size(), /*vars=*/ tmp_variables->data(), - /*weights=*/ tmp_weights->data())); - break; - case MPSosConstraint::SOS2: - RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicSOS2( - scip, /*cons=*/ scip_cst, /*name=*/ gen_cst.name().c_str(), - /*nvars=*/ sos_cst.var_index_size(), /*vars=*/ tmp_variables->data(), - /*weights=*/ tmp_weights->data())); - break; + case MPSosConstraint::SOS1_DEFAULT: + RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicSOS1( + scip, /*cons=*/scip_cst, /*name=*/gen_cst.name().c_str(), + /*nvars=*/sos_cst.var_index_size(), /*vars=*/tmp_variables->data(), + /*weights=*/tmp_weights->data())); + break; + case MPSosConstraint::SOS2: + RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicSOS2( + scip, /*cons=*/scip_cst, /*name=*/gen_cst.name().c_str(), + /*nvars=*/sos_cst.var_index_size(), /*vars=*/tmp_variables->data(), + /*weights=*/tmp_weights->data())); + break; } RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); return absl::OkStatus(); } -absl::Status -AddQuadraticConstraint(const MPGeneralConstraintProto &gen_cst, - const std::vector &scip_variables, - SCIP *scip, SCIP_CONS **scip_cst, - std::vector *tmp_variables, - std::vector *tmp_coefficients, - std::vector *tmp_qvariables1, - std::vector *tmp_qvariables2, - std::vector *tmp_qcoefficients) { +absl::Status AddQuadraticConstraint( + const MPGeneralConstraintProto &gen_cst, + const std::vector &scip_variables, SCIP *scip, + SCIP_CONS **scip_cst, std::vector *tmp_variables, + std::vector *tmp_coefficients, + std::vector *tmp_qvariables1, + std::vector *tmp_qvariables2, + std::vector *tmp_qcoefficients) { CHECK(scip != nullptr); CHECK(scip_cst != nullptr); CHECK(tmp_variables != nullptr); @@ -225,13 +222,13 @@ AddQuadraticConstraint(const MPGeneralConstraintProto &gen_cst, } RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicQuadratic( - scip, /*cons=*/ scip_cst, /*name=*/ gen_cst.name().c_str(), - /*nlinvars=*/ lsize, /*linvars=*/ tmp_variables->data(), - /*lincoefs=*/ tmp_coefficients->data(), /*nquadterms=*/ qsize, - /*quadvars1=*/ tmp_qvariables1->data(), - /*quadvars2=*/ tmp_qvariables2->data(), - /*quadcoefs=*/ tmp_qcoefficients->data(), /*lhs=*/ quad_cst.lower_bound(), - /*rhs=*/ quad_cst.upper_bound())); + scip, /*cons=*/scip_cst, /*name=*/gen_cst.name().c_str(), + /*nlinvars=*/lsize, /*linvars=*/tmp_variables->data(), + /*lincoefs=*/tmp_coefficients->data(), /*nquadterms=*/qsize, + /*quadvars1=*/tmp_qvariables1->data(), + /*quadvars2=*/tmp_qvariables2->data(), + /*quadcoefs=*/tmp_qcoefficients->data(), /*lhs=*/quad_cst.lower_bound(), + /*rhs=*/quad_cst.upper_bound())); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); return absl::OkStatus(); } @@ -256,37 +253,37 @@ absl::Status AddAbsConstraint(const MPGeneralConstraintProto &gen_cst, std::vector vars; std::vector vals; std::vector cons; - auto add_abs_constraint = [&](const std::string & name_prefix)->absl::Status { + auto add_abs_constraint = + [&](const std::string &name_prefix) -> absl::Status { SCIP_CONS *scip_cons = nullptr; CHECK(vars.size() == vals.size()); const std::string name = gen_cst.has_name() ? absl::StrCat(gen_cst.name(), name_prefix) : ""; RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicLinear( - scip, /*cons=*/ &scip_cons, /*name=*/ name.c_str(), - /*nvars=*/ vars.size(), /*vars=*/ vars.data(), /*vals=*/ vals.data(), - /*lhs=*/ 0.0, /*rhs=*/ 0.0)); + scip, /*cons=*/&scip_cons, /*name=*/name.c_str(), + /*nvars=*/vars.size(), /*vars=*/vars.data(), /*vals=*/vals.data(), + /*lhs=*/0.0, /*rhs=*/0.0)); // Note that the constraints are, by design, not added into the model using // SCIPaddCons. cons.push_back(scip_cons); return absl::OkStatus(); - } - ; + }; // Create an intermediary constraint such that y = -x - vars = { scip_resultant_var, scip_var }; - vals = { 1, 1 }; + vars = {scip_resultant_var, scip_var}; + vals = {1, 1}; RETURN_IF_ERROR(add_abs_constraint("_neg")); // Create an intermediary constraint such that y = x - vals = { 1, -1 }; + vals = {1, -1}; RETURN_IF_ERROR(add_abs_constraint("_pos")); // Activate at least one of the two above constraints. const std::string name = gen_cst.has_name() ? absl::StrCat(gen_cst.name(), "_disj") : ""; RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicDisjunction( - scip, /*cons=*/ scip_cst, /*name=*/ name.c_str(), /*nconss=*/ cons.size(), - /*conss=*/ cons.data(), /*relaxcons=*/ nullptr)); + scip, /*cons=*/scip_cst, /*name=*/name.c_str(), /*nconss=*/cons.size(), + /*conss=*/cons.data(), /*relaxcons=*/nullptr)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); return absl::OkStatus(); @@ -307,9 +304,9 @@ absl::Status AddAndConstraint(const MPGeneralConstraintProto &gen_cst, (*tmp_variables)[i] = scip_variables[andcst.var_index(i)]; } RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicAnd( - scip, /*cons=*/ scip_cst, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ scip_variables[andcst.resultant_var_index()], - /*nvars=*/ andcst.var_index_size(), /*vars=*/ tmp_variables->data())); + scip, /*cons=*/scip_cst, /*name=*/gen_cst.name().c_str(), + /*resvar=*/scip_variables[andcst.resultant_var_index()], + /*nvars=*/andcst.var_index_size(), /*vars=*/tmp_variables->data())); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); return absl::OkStatus(); } @@ -329,9 +326,9 @@ absl::Status AddOrConstraint(const MPGeneralConstraintProto &gen_cst, (*tmp_variables)[i] = scip_variables[orcst.var_index(i)]; } RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicOr( - scip, /*cons=*/ scip_cst, /*name=*/ gen_cst.name().c_str(), - /*resvar=*/ scip_variables[orcst.resultant_var_index()], - /*nvars=*/ orcst.var_index_size(), /*vars=*/ tmp_variables->data())); + scip, /*cons=*/scip_cst, /*name=*/gen_cst.name().c_str(), + /*resvar=*/scip_variables[orcst.resultant_var_index()], + /*nvars=*/orcst.var_index_size(), /*vars=*/tmp_variables->data())); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); return absl::OkStatus(); } @@ -359,35 +356,34 @@ absl::Status AddMinMaxConstraint(const MPGeneralConstraintProto &gen_cst, std::vector vars; std::vector vals; std::vector cons; - auto add_lin_constraint = - [&](const std::string & name_prefix, double lower_bound = 0.0, - double upper_bound = 0.0)->absl::Status { + auto add_lin_constraint = [&](const std::string &name_prefix, + double lower_bound = 0.0, + double upper_bound = 0.0) -> absl::Status { SCIP_CONS *scip_cons = nullptr; CHECK(vars.size() == vals.size()); const std::string name = gen_cst.has_name() ? absl::StrCat(gen_cst.name(), name_prefix) : ""; RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicLinear( - scip, /*cons=*/ &scip_cons, /*name=*/ name.c_str(), - /*nvars=*/ vars.size(), /*vars=*/ vars.data(), /*vals=*/ vals.data(), - /*lhs=*/ lower_bound, /*rhs=*/ upper_bound)); + scip, /*cons=*/&scip_cons, /*name=*/name.c_str(), + /*nvars=*/vars.size(), /*vars=*/vars.data(), /*vals=*/vals.data(), + /*lhs=*/lower_bound, /*rhs=*/upper_bound)); // Note that the constraints are, by design, not added into the model using // SCIPaddCons. cons.push_back(scip_cons); return absl::OkStatus(); - } - ; + }; // Create intermediary constraints such that y = xi for (const int var_index : unique_var_indices) { - vars = { scip_resultant_var, scip_variables[var_index] }; - vals = { 1, -1 }; + vars = {scip_resultant_var, scip_variables[var_index]}; + vals = {1, -1}; RETURN_IF_ERROR(add_lin_constraint(absl::StrCat("_", var_index))); } // Create an intermediary constraint such that y = c if (minmax.has_constant()) { - vars = { scip_resultant_var }; - vals = { 1 }; + vars = {scip_resultant_var}; + vals = {1}; RETURN_IF_ERROR( add_lin_constraint("_constant", minmax.constant(), minmax.constant())); } @@ -396,16 +392,16 @@ absl::Status AddMinMaxConstraint(const MPGeneralConstraintProto &gen_cst, const std::string name = gen_cst.has_name() ? absl::StrCat(gen_cst.name(), "_disj") : ""; RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicDisjunction( - scip, /*cons=*/ scip_cst, /*name=*/ name.c_str(), /*nconss=*/ cons.size(), - /*conss=*/ cons.data(), /*relaxcons=*/ nullptr)); + scip, /*cons=*/scip_cst, /*name=*/name.c_str(), /*nconss=*/cons.size(), + /*conss=*/cons.data(), /*relaxcons=*/nullptr)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, *scip_cst)); // Add all of the inequality constraints. constexpr double kInfinity = std::numeric_limits::infinity(); cons.clear(); for (const int var_index : unique_var_indices) { - vars = { scip_resultant_var, scip_variables[var_index] }; - vals = { 1, -1 }; + vars = {scip_resultant_var, scip_variables[var_index]}; + vals = {1, -1}; if (gen_cst.has_min_constraint()) { RETURN_IF_ERROR(add_lin_constraint(absl::StrCat("_ineq_", var_index), -kInfinity, 0.0)); @@ -415,8 +411,8 @@ absl::Status AddMinMaxConstraint(const MPGeneralConstraintProto &gen_cst, } } if (minmax.has_constant()) { - vars = { scip_resultant_var }; - vals = { 1 }; + vars = {scip_resultant_var}; + vals = {1}; if (gen_cst.has_min_constraint()) { RETURN_IF_ERROR(add_lin_constraint(absl::StrCat("_ineq_constant"), -kInfinity, minmax.constant())); @@ -443,21 +439,20 @@ absl::Status AddQuadraticObjective(const MPQuadraticObjective &quadobj, constexpr double kInfinity = std::numeric_limits::infinity(); const int size = quadobj.coefficient_size(); - if (size == 0) - return absl::OkStatus(); + if (size == 0) return absl::OkStatus(); // SCIP supports quadratic objectives by adding a quadratic constraint. We // need to create an extra variable to hold this quadratic objective. scip_variables->push_back(nullptr); RETURN_IF_SCIP_ERROR(SCIPcreateVarBasic( - scip, /*var=*/ &scip_variables->back(), /*name=*/ "quadobj", - /*lb=*/ -kInfinity, /*ub=*/ kInfinity, /*obj=*/ 1, - /*vartype=*/ SCIP_VARTYPE_CONTINUOUS)); + scip, /*var=*/&scip_variables->back(), /*name=*/"quadobj", + /*lb=*/-kInfinity, /*ub=*/kInfinity, /*obj=*/1, + /*vartype=*/SCIP_VARTYPE_CONTINUOUS)); RETURN_IF_SCIP_ERROR(SCIPaddVar(scip, scip_variables->back())); scip_constraints->push_back(nullptr); - SCIP_VAR *linvars[1] = { scip_variables->back() }; - double lincoefs[1] = { -1 }; + SCIP_VAR *linvars[1] = {scip_variables->back()}; + double lincoefs[1] = {-1}; std::vector quadvars1(size, nullptr); std::vector quadvars2(size, nullptr); std::vector quadcoefs(size, 0); @@ -467,11 +462,11 @@ absl::Status AddQuadraticObjective(const MPQuadraticObjective &quadobj, quadcoefs[i] = quadobj.coefficient(i); } RETURN_IF_SCIP_ERROR(SCIPcreateConsBasicQuadratic( - scip, /*cons=*/ &scip_constraints->back(), /*name=*/ "quadobj", - /*nlinvars=*/ 1, /*linvars=*/ linvars, /*lincoefs=*/ lincoefs, - /*nquadterms=*/ size, /*quadvars1=*/ quadvars1.data(), - /*quadvars2=*/ quadvars2.data(), /*quadcoefs=*/ quadcoefs.data(), - /*lhs=*/ 0, /*rhs=*/ 0)); + scip, /*cons=*/&scip_constraints->back(), /*name=*/"quadobj", + /*nlinvars=*/1, /*linvars=*/linvars, /*lincoefs=*/lincoefs, + /*nquadterms=*/size, /*quadvars1=*/quadvars1.data(), + /*quadvars2=*/quadvars2.data(), /*quadcoefs=*/quadcoefs.data(), + /*lhs=*/0, /*rhs=*/0)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, scip_constraints->back())); return absl::OkStatus(); @@ -480,8 +475,7 @@ absl::Status AddQuadraticObjective(const MPQuadraticObjective &quadobj, absl::Status AddSolutionHint(const MPModelProto &model, SCIP *scip, const std::vector &scip_variables) { CHECK(scip != nullptr); - if (!model.has_solution_hint()) - return absl::OkStatus(); + if (!model.has_solution_hint()) return absl::OkStatus(); const PartialVariableAssignment &solution_hint = model.solution_hint(); SCIP_SOL *solution; @@ -489,10 +483,10 @@ absl::Status AddSolutionHint(const MPModelProto &model, SCIP *scip, solution_hint.var_index_size() != model.variable_size(); if (is_solution_partial) { RETURN_IF_SCIP_ERROR( - SCIPcreatePartialSol(scip, /*sol=*/ &solution, /*heur=*/ nullptr)); + SCIPcreatePartialSol(scip, /*sol=*/&solution, /*heur=*/nullptr)); } else { RETURN_IF_SCIP_ERROR( - SCIPcreateSol(scip, /*sol=*/ &solution, /*heur=*/ nullptr)); + SCIPcreateSol(scip, /*sol=*/&solution, /*heur=*/nullptr)); } for (int i = 0; i < solution_hint.var_index_size(); ++i) { @@ -506,7 +500,7 @@ absl::Status AddSolutionHint(const MPModelProto &model, SCIP *scip, return absl::OkStatus(); } -} // namespace +} // namespace // Returns "" iff the model seems valid for SCIP, else returns a human-readable // error message. Assumes that FindErrorInMPModelProto(model) found no error. @@ -552,50 +546,57 @@ std::string FindErrorInMPModelForScip(const MPModelProto &model, SCIP *scip) { for (int c = 0; c < model.general_constraint_size(); ++c) { const MPGeneralConstraintProto &cst = model.general_constraint(c); switch (cst.general_constraint_case()) { - case MPGeneralConstraintProto::kQuadraticConstraint: - if (cst.quadratic_constraint().lower_bound() >= infinity) { - return absl::StrFormat( - "Quadratic constraint %d's lower_bound is considered +infinity", c); - } - if (cst.quadratic_constraint().upper_bound() <= -infinity) { - return absl::StrFormat( - "Quadratic constraint %d's upper_bound is considered -infinity", c); - } - for (int i = 0; i < cst.quadratic_constraint().coefficient_size(); ++i) { - const double coefficient = cst.quadratic_constraint().coefficient(i); - if (coefficient >= infinity || coefficient <= -infinity) { + case MPGeneralConstraintProto::kQuadraticConstraint: + if (cst.quadratic_constraint().lower_bound() >= infinity) { return absl::StrFormat( - "Quadratic constraint %d's linear coefficient #%d considered " - "infinite", - c, i); + "Quadratic constraint %d's lower_bound is considered +infinity", + c); } - } - for (int i = 0; i < cst.quadratic_constraint().qcoefficient_size(); ++i) { - const double qcoefficient = cst.quadratic_constraint().qcoefficient(i); - if (qcoefficient >= infinity || qcoefficient <= -infinity) { + if (cst.quadratic_constraint().upper_bound() <= -infinity) { return absl::StrFormat( - "Quadratic constraint %d's quadratic coefficient #%d " - "considered infinite", - c, i); + "Quadratic constraint %d's upper_bound is considered -infinity", + c); } - } - break; - case MPGeneralConstraintProto::kMinConstraint: - if (cst.min_constraint().constant() >= infinity || - cst.min_constraint().constant() <= -infinity) { - return absl::StrFormat( - "Min constraint %d's coefficient constant considered infinite", c); - } - break; - case MPGeneralConstraintProto::kMaxConstraint: - if (cst.max_constraint().constant() >= infinity || - cst.max_constraint().constant() <= -infinity) { - return absl::StrFormat( - "Max constraint %d's coefficient constant considered infinite", c); - } - break; - default: - continue; + for (int i = 0; i < cst.quadratic_constraint().coefficient_size(); + ++i) { + const double coefficient = cst.quadratic_constraint().coefficient(i); + if (coefficient >= infinity || coefficient <= -infinity) { + return absl::StrFormat( + "Quadratic constraint %d's linear coefficient #%d considered " + "infinite", + c, i); + } + } + for (int i = 0; i < cst.quadratic_constraint().qcoefficient_size(); + ++i) { + const double qcoefficient = + cst.quadratic_constraint().qcoefficient(i); + if (qcoefficient >= infinity || qcoefficient <= -infinity) { + return absl::StrFormat( + "Quadratic constraint %d's quadratic coefficient #%d " + "considered infinite", + c, i); + } + } + break; + case MPGeneralConstraintProto::kMinConstraint: + if (cst.min_constraint().constant() >= infinity || + cst.min_constraint().constant() <= -infinity) { + return absl::StrFormat( + "Min constraint %d's coefficient constant considered infinite", + c); + } + break; + case MPGeneralConstraintProto::kMaxConstraint: + if (cst.max_constraint().constant() >= infinity || + cst.max_constraint().constant() <= -infinity) { + return absl::StrFormat( + "Max constraint %d's coefficient constant considered infinite", + c); + } + break; + default: + continue; } } @@ -627,23 +628,21 @@ std::string FindErrorInMPModelForScip(const MPModelProto &model, SCIP *scip) { return ""; } -absl::StatusOr -ScipSolveProto(const MPModelRequest &request) { +absl::StatusOr ScipSolveProto( + const MPModelRequest &request) { MPSolutionResponse response; const absl::optional > optional_model = ExtractValidMPModelOrPopulateResponseStatus(request, &response); - if (!optional_model) - return response; + if (!optional_model) return response; const MPModelProto &model = optional_model->get(); SCIP *scip = nullptr; std::vector scip_variables(model.variable_size(), nullptr); std::vector scip_constraints( model.constraint_size() + model.general_constraint_size(), nullptr); - auto delete_scip_objects = [&]()->absl::Status { + auto delete_scip_objects = [&]() -> absl::Status { // Release all created pointers. - if (scip == nullptr) - return absl::OkStatus(); + if (scip == nullptr) return absl::OkStatus(); for (SCIP_VAR *variable : scip_variables) { if (variable != nullptr) { RETURN_IF_SCIP_ERROR(SCIPreleaseVar(scip, &variable)); @@ -656,8 +655,7 @@ ScipSolveProto(const MPModelRequest &request) { } RETURN_IF_SCIP_ERROR(SCIPfree(&scip)); return absl::OkStatus(); - } - ; + }; auto scip_deleter = absl::MakeCleanup([delete_scip_objects]() { const absl::Status deleter_status = delete_scip_objects(); @@ -704,11 +702,11 @@ ScipSolveProto(const MPModelRequest &request) { for (int v = 0; v < model.variable_size(); ++v) { const MPVariableProto &variable = model.variable(v); RETURN_IF_SCIP_ERROR(SCIPcreateVarBasic( - scip, /*var=*/ &scip_variables[v], /*name=*/ variable.name().c_str(), - /*lb=*/ variable.lower_bound(), /*ub=*/ variable.upper_bound(), - /*obj=*/ variable.objective_coefficient(), - /*vartype=*/ variable.is_integer() ? SCIP_VARTYPE_INTEGER - : SCIP_VARTYPE_CONTINUOUS)); + scip, /*var=*/&scip_variables[v], /*name=*/variable.name().c_str(), + /*lb=*/variable.lower_bound(), /*ub=*/variable.upper_bound(), + /*obj=*/variable.objective_coefficient(), + /*vartype=*/variable.is_integer() ? SCIP_VARTYPE_INTEGER + : SCIP_VARTYPE_CONTINUOUS)); RETURN_IF_SCIP_ERROR(SCIPaddVar(scip, scip_variables[v])); } @@ -725,15 +723,15 @@ ScipSolveProto(const MPModelRequest &request) { ct_coefficients[i] = constraint.coefficient(i); } RETURN_IF_SCIP_ERROR(SCIPcreateConsLinear( - scip, /*cons=*/ &scip_constraints[c], - /*name=*/ constraint.name().c_str(), - /*nvars=*/ constraint.var_index_size(), /*vars=*/ ct_variables.data(), - /*vals=*/ ct_coefficients.data(), /*lhs=*/ constraint.lower_bound(), - /*rhs=*/ constraint.upper_bound(), /*initial=*/ !constraint.is_lazy(), - /*separate=*/ true, /*enforce=*/ true, /*check=*/ true, - /*propagate=*/ true, /*local=*/ false, /*modifiable=*/ false, - /*dynamic=*/ false, /*removable=*/ constraint.is_lazy(), - /*stickingatnode=*/ false)); + scip, /*cons=*/&scip_constraints[c], + /*name=*/constraint.name().c_str(), + /*nvars=*/constraint.var_index_size(), /*vars=*/ct_variables.data(), + /*vals=*/ct_coefficients.data(), /*lhs=*/constraint.lower_bound(), + /*rhs=*/constraint.upper_bound(), /*initial=*/!constraint.is_lazy(), + /*separate=*/true, /*enforce=*/true, /*check=*/true, + /*propagate=*/true, /*local=*/false, /*modifiable=*/false, + /*dynamic=*/false, /*removable=*/constraint.is_lazy(), + /*stickingatnode=*/false)); RETURN_IF_SCIP_ERROR(SCIPaddCons(scip, scip_constraints[c])); } @@ -745,53 +743,54 @@ ScipSolveProto(const MPModelRequest &request) { for (int c = 0; c < model.general_constraint_size(); ++c) { const MPGeneralConstraintProto &gen_cst = model.general_constraint(c); switch (gen_cst.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: { - RETURN_IF_ERROR(AddIndicatorConstraint( - gen_cst, scip, &scip_constraints[lincst_size + c], &scip_variables, - &scip_constraints, &ct_variables, &ct_coefficients)); - break; - } - case MPGeneralConstraintProto::kSosConstraint: { - RETURN_IF_ERROR(AddSosConstraint(gen_cst, scip_variables, scip, - &scip_constraints[lincst_size + c], - &ct_variables, &ct_coefficients)); - break; - } - case MPGeneralConstraintProto::kQuadraticConstraint: { - RETURN_IF_ERROR(AddQuadraticConstraint( - gen_cst, scip_variables, scip, &scip_constraints[lincst_size + c], - &ct_variables, &ct_coefficients, &ct_qvariables1, &ct_qvariables2, - &ct_qcoefficients)); - break; - } - case MPGeneralConstraintProto::kAbsConstraint: { - RETURN_IF_ERROR(AddAbsConstraint(gen_cst, scip_variables, scip, - &scip_constraints[lincst_size + c])); - break; - } - case MPGeneralConstraintProto::kAndConstraint: { - RETURN_IF_ERROR(AddAndConstraint(gen_cst, scip_variables, scip, - &scip_constraints[lincst_size + c], - &ct_variables)); - break; - } - case MPGeneralConstraintProto::kOrConstraint: { - RETURN_IF_ERROR( - AddOrConstraint(gen_cst, scip_variables, scip, - &scip_constraints[lincst_size + c], &ct_variables)); - break; - } - case MPGeneralConstraintProto::kMinConstraint: - case MPGeneralConstraintProto::kMaxConstraint: { - RETURN_IF_ERROR(AddMinMaxConstraint(gen_cst, scip_variables, scip, - &scip_constraints[lincst_size + c], - &scip_constraints, &ct_variables)); - break; - } - default: - return absl::UnimplementedError( - absl::StrFormat("General constraints of type %i not supported.", - gen_cst.general_constraint_case())); + case MPGeneralConstraintProto::kIndicatorConstraint: { + RETURN_IF_ERROR(AddIndicatorConstraint( + gen_cst, scip, &scip_constraints[lincst_size + c], + &scip_variables, &scip_constraints, &ct_variables, + &ct_coefficients)); + break; + } + case MPGeneralConstraintProto::kSosConstraint: { + RETURN_IF_ERROR(AddSosConstraint(gen_cst, scip_variables, scip, + &scip_constraints[lincst_size + c], + &ct_variables, &ct_coefficients)); + break; + } + case MPGeneralConstraintProto::kQuadraticConstraint: { + RETURN_IF_ERROR(AddQuadraticConstraint( + gen_cst, scip_variables, scip, &scip_constraints[lincst_size + c], + &ct_variables, &ct_coefficients, &ct_qvariables1, &ct_qvariables2, + &ct_qcoefficients)); + break; + } + case MPGeneralConstraintProto::kAbsConstraint: { + RETURN_IF_ERROR(AddAbsConstraint(gen_cst, scip_variables, scip, + &scip_constraints[lincst_size + c])); + break; + } + case MPGeneralConstraintProto::kAndConstraint: { + RETURN_IF_ERROR(AddAndConstraint(gen_cst, scip_variables, scip, + &scip_constraints[lincst_size + c], + &ct_variables)); + break; + } + case MPGeneralConstraintProto::kOrConstraint: { + RETURN_IF_ERROR(AddOrConstraint(gen_cst, scip_variables, scip, + &scip_constraints[lincst_size + c], + &ct_variables)); + break; + } + case MPGeneralConstraintProto::kMinConstraint: + case MPGeneralConstraintProto::kMaxConstraint: { + RETURN_IF_ERROR(AddMinMaxConstraint( + gen_cst, scip_variables, scip, &scip_constraints[lincst_size + c], + &scip_constraints, &ct_variables)); + break; + } + default: + return absl::UnimplementedError( + absl::StrFormat("General constraints of type %i not supported.", + gen_cst.general_constraint_case())); } } } @@ -816,56 +815,55 @@ ScipSolveProto(const MPModelRequest &request) { response.set_best_objective_bound(SCIPgetDualbound(scip)); for (int v = 0; v < model.variable_size(); ++v) { double value = SCIPgetSolVal(scip, solution, scip_variables[v]); - if (model.variable(v).is_integer()) - value = std::round(value); + if (model.variable(v).is_integer()) value = std::round(value); response.add_variable_value(value); } } const SCIP_STATUS scip_status = SCIPgetStatus(scip); switch (scip_status) { - case SCIP_STATUS_OPTIMAL: - response.set_status(MPSOLVER_OPTIMAL); - break; - case SCIP_STATUS_GAPLIMIT: - // To be consistent with the other solvers. - response.set_status(MPSOLVER_OPTIMAL); - break; - case SCIP_STATUS_INFORUNBD: - // NOTE(user): After looking at the SCIP code on 2019-06-14, it seems - // that this will mostly happen for INFEASIBLE problems in practice. - // Since most (all?) users shouldn't have their application behave very - // differently upon INFEASIBLE or UNBOUNDED, the potential error that we - // are making here seems reasonable (and not worth a LOG, unless in - // debug mode). - DLOG(INFO) << "SCIP solve returned SCIP_STATUS_INFORUNBD, which we treat " - "as INFEASIBLE even though it may mean UNBOUNDED."; - response.set_status_str( - "The model may actually be unbounded: SCIP returned " - "SCIP_STATUS_INFORUNBD"); - ABSL_FALLTHROUGH_INTENDED; - case SCIP_STATUS_INFEASIBLE: - response.set_status(MPSOLVER_INFEASIBLE); - break; - case SCIP_STATUS_UNBOUNDED: - response.set_status(MPSOLVER_UNBOUNDED); - break; - default: - if (solution != nullptr) { - response.set_status(MPSOLVER_FEASIBLE); - } else { - response.set_status(MPSOLVER_NOT_SOLVED); - response.set_status_str(absl::StrFormat("SCIP status code %d", - static_cast(scip_status))); - } - break; + case SCIP_STATUS_OPTIMAL: + response.set_status(MPSOLVER_OPTIMAL); + break; + case SCIP_STATUS_GAPLIMIT: + // To be consistent with the other solvers. + response.set_status(MPSOLVER_OPTIMAL); + break; + case SCIP_STATUS_INFORUNBD: + // NOTE(user): After looking at the SCIP code on 2019-06-14, it seems + // that this will mostly happen for INFEASIBLE problems in practice. + // Since most (all?) users shouldn't have their application behave very + // differently upon INFEASIBLE or UNBOUNDED, the potential error that we + // are making here seems reasonable (and not worth a LOG, unless in + // debug mode). + DLOG(INFO) << "SCIP solve returned SCIP_STATUS_INFORUNBD, which we treat " + "as INFEASIBLE even though it may mean UNBOUNDED."; + response.set_status_str( + "The model may actually be unbounded: SCIP returned " + "SCIP_STATUS_INFORUNBD"); + ABSL_FALLTHROUGH_INTENDED; + case SCIP_STATUS_INFEASIBLE: + response.set_status(MPSOLVER_INFEASIBLE); + break; + case SCIP_STATUS_UNBOUNDED: + response.set_status(MPSOLVER_UNBOUNDED); + break; + default: + if (solution != nullptr) { + response.set_status(MPSOLVER_FEASIBLE); + } else { + response.set_status(MPSOLVER_NOT_SOLVED); + response.set_status_str(absl::StrFormat("SCIP status code %d", + static_cast(scip_status))); + } + break; } - VLOG(1) << "ScipSolveProto() status=" << MPSolverResponseStatus_Name( - response.status()) << "."; + VLOG(1) << "ScipSolveProto() status=" + << MPSolverResponseStatus_Name(response.status()) << "."; return response; } -} // namespace operations_research +} // namespace operations_research -#endif // #if defined(USE_SCIP) +#endif // #if defined(USE_SCIP) diff --git a/ortools/linear_solver/scip_proto_solver.h b/ortools/linear_solver/scip_proto_solver.h index 60c1370bff..bceb6f8830 100644 --- a/ortools/linear_solver/scip_proto_solver.h +++ b/ortools/linear_solver/scip_proto_solver.h @@ -24,11 +24,11 @@ namespace operations_research { // *differs* from `MPSolver::Solve()` which sets the feasibility tolerance to // 1e-7, and the gap limit to 0.0001 (whereas SCIP defaults are 1e-6 and 0, // respectively, and they are being used here). -absl::StatusOr - ScipSolveProto(const MPModelRequest &request); +absl::StatusOr ScipSolveProto( + const MPModelRequest &request); std::string FindErrorInMPModelForScip(const MPModelProto &model, SCIP *scip); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_PROTO_SOLVER_H_ +#endif // OR_TOOLS_LINEAR_SOLVER_SCIP_PROTO_SOLVER_H_ diff --git a/ortools/linear_solver/xpress_interface.cc b/ortools/linear_solver/xpress_interface.cc index 32f1054894..00abeb2889 100644 --- a/ortools/linear_solver/xpress_interface.cc +++ b/ortools/linear_solver/xpress_interface.cc @@ -88,10 +88,10 @@ enum XPRS_BASIS_STATUS { // The argument to this macro is the invocation of a XPRS function that // returns a status. If the function returns non-zero the macro aborts // the program with an appropriate error message. -#define CHECK_STATUS(s) \ - do { \ - int const status_ = s; \ - CHECK_EQ(0, status_); \ +#define CHECK_STATUS(s) \ + do { \ + int const status_ = s; \ + CHECK_EQ(0, status_); \ } while (0) namespace operations_research { @@ -104,7 +104,7 @@ using std::unique_ptr; // Similar for instances of MPConstraint: the index of the constraint in // the model is the row index in the XPRESS model. class XpressInterface : public MPSolverInterface { -public: + public: // NOTE: 'mip' specifies the type of the problem (either continuous or // mixed integer. This type is fixed for the lifetime of the // instance. There are no dynamic changes to the model type. @@ -185,7 +185,7 @@ public: return 0.0; } -protected: + protected: // Set all parameters in the underlying solver. virtual void SetParameters(MPSolverParameters const ¶m); // Set each parameter in the underlying solver. @@ -199,7 +199,7 @@ protected: virtual bool ReadParameterFile(std::string const &filename); virtual std::string ValidFileExtensionForParameterFile() const; -private: + private: // Mark modeling object "out of sync". This implicitly invalidates // solution information as well. It is the counterpart of // MPSolverInterface::InvalidateSolutionSynchronization @@ -212,7 +212,7 @@ private: // Transform XPRESS basis status to MPSolver basis status. static MPSolver::BasisStatus xformBasisStatus(int xpress_basis_status); -private: + private: XPRSprob mLp; bool const mMip; // Incremental extraction. @@ -272,9 +272,9 @@ int init_xpress_env(int xpress_oem_license_key = 0) { // need to remove the enclosing '\"' from the string itself. path.erase(std::remove(path.begin(), path.end(), '\"'), path.end()); xpresspath = path + "\\bin"; -#else // _MSC_VER +#else // _MSC_VER xpresspath = path + "/bin"; -#endif // _MSC_VER +#endif // _MSC_VER #else LOG(WARNING) << "XpressInterface Error : Environment variable XPRESS undefined.\n"; @@ -296,8 +296,8 @@ int init_xpress_env(int xpress_oem_license_key = 0) { char banner[1000]; XPRSgetbanner(banner); - LOG(WARNING) << "XpressInterface : Xpress banner :\n" << banner - << std::endl; + LOG(WARNING) << "XpressInterface : Xpress banner :\n" + << banner << std::endl; return 0; } else { char errmsg[256]; @@ -354,16 +354,19 @@ int init_xpress_env(int xpress_oem_license_key = 0) { // Creates a LP/MIP instance. XpressInterface::XpressInterface(MPSolver *const solver, bool mip) - : MPSolverInterface(solver), mLp(0), mMip(mip), + : MPSolverInterface(solver), + mLp(0), + mMip(mip), supportIncrementalExtraction(false), slowUpdates(static_cast(SlowSetObjectiveCoefficient | SlowClearObjective)), - mCstat(), mRstat() { + mCstat(), + mRstat() { int status = init_xpress_env(); CHECK_STATUS(status); status = XPRScreateprob(&mLp); CHECK_STATUS(status); - DCHECK(mLp != nullptr); // should not be NULL if status=0 + DCHECK(mLp != nullptr); // should not be NULL if status=0 CHECK_STATUS(XPRSloadlp(mLp, "newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); CHECK_STATUS( @@ -403,7 +406,7 @@ void XpressInterface::Reset() { int status; status = XPRScreateprob(&mLp); CHECK_STATUS(status); - DCHECK(mLp != nullptr); // should not be NULL if status=0 + DCHECK(mLp != nullptr); // should not be NULL if status=0 CHECK_STATUS(XPRSloadlp(mLp, "newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); CHECK_STATUS( @@ -435,9 +438,9 @@ void XpressInterface::SetVariableBounds(int var_index, double lb, double ub) { // Variable has already been extracted, so we must modify the // modeling object. DCHECK_LT(var_index, last_variable_index_); - char const lu[2] = { 'L', 'U' }; - double const bd[2] = { lb, ub }; - int const idx[2] = { var_index, var_index }; + char const lu[2] = {'L', 'U'}; + double const bd[2] = {lb, ub}; + int const idx[2] = {var_index, var_index}; CHECK_STATUS(XPRSchgbounds(mLp, 2, idx, lu, bd)); } else { // Variable is not yet extracted. It is sufficient to just mark @@ -719,8 +722,7 @@ void XpressInterface::ClearObjective() { ++j; } } - if (j > 0) - CHECK_STATUS(XPRSchgobj(mLp, j, ind.get(), zero.get())); + if (j > 0) CHECK_STATUS(XPRSchgobj(mLp, j, ind.get(), zero.get())); CHECK_STATUS(XPRSsetobjoffset(mLp, 0.0)); } else { InvalidateModelSynchronization(); @@ -730,15 +732,13 @@ void XpressInterface::ClearObjective() { // ------ Query statistics on the solution and the solve ------ int64 XpressInterface::iterations() const { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfIterations; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; return static_cast(XPRSgetitcnt(mLp)); } int64 XpressInterface::nodes() const { if (mMip) { - if (!CheckSolutionIsSynchronized()) - return kUnknownNumberOfNodes; + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; return static_cast(XPRSgetnodecnt(mLp)); } else { LOG(DFATAL) << "Number of nodes only available for discrete problems"; @@ -768,20 +768,20 @@ double XpressInterface::best_objective_bound() const { } // Transform a XPRESS basis status to an MPSolver basis status. -MPSolver::BasisStatus -XpressInterface::xformBasisStatus(int xpress_basis_status) { +MPSolver::BasisStatus XpressInterface::xformBasisStatus( + int xpress_basis_status) { switch (xpress_basis_status) { - case XPRS_AT_LOWER: - return MPSolver::AT_LOWER_BOUND; - case XPRS_BASIC: - return MPSolver::BASIC; - case XPRS_AT_UPPER: - return MPSolver::AT_UPPER_BOUND; - case XPRS_FREE_SUPER: - return MPSolver::FREE; - default: - LOG(DFATAL) << "Unknown XPRESS basis status"; - return MPSolver::FREE; + case XPRS_AT_LOWER: + return MPSolver::AT_LOWER_BOUND; + case XPRS_BASIC: + return MPSolver::BASIC; + case XPRS_AT_UPPER: + return MPSolver::AT_UPPER_BOUND; + case XPRS_FREE_SUPER: + return MPSolver::FREE; + default: + LOG(DFATAL) << "Unknown XPRESS basis status"; + return MPSolver::FREE; } } @@ -863,7 +863,7 @@ void XpressInterface::ExtractNewVariables() { unique_ptr lb(new double[newcols]); unique_ptr ub(new double[newcols]); unique_ptr ctype(new char[newcols]); - unique_ptr colname(new const char *[newcols]); + unique_ptr colname(new const char *[newcols]); bool have_names = false; for (int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) { @@ -900,8 +900,7 @@ void XpressInterface::ExtractNewVariables() { // For each column count the size of the intersection with // existing constraints. unique_ptr collen(new int[newcols]); - for (int j = 0; j < newcols; ++j) - collen[j] = 0; + for (int j = 0; j < newcols; ++j) collen[j] = 0; int nonzeros = 0; // TODO: Use a bitarray to flag the constraints that actually // intersect new variables? @@ -957,9 +956,9 @@ void XpressInterface::ExtractNewVariables() { } } --cmatbeg; - CHECK_STATUS( - XPRSaddcols(mLp, newcols, nonzeros, obj.get(), cmatbeg, - cmatind.get(), cmatval.get(), lb.get(), ub.get())); + CHECK_STATUS(XPRSaddcols(mLp, newcols, nonzeros, obj.get(), cmatbeg, + cmatind.get(), cmatval.get(), lb.get(), + ub.get())); } } @@ -974,13 +973,12 @@ void XpressInterface::ExtractNewVariables() { cmatind[0] = 0; cmatval[0] = 1.0; - CHECK_STATUS( - XPRSaddcols(mLp, newcols, 0, obj.get(), cmatbeg.data(), - cmatind.get(), cmatval.get(), lb.get(), ub.get())); + CHECK_STATUS(XPRSaddcols(mLp, newcols, 0, obj.get(), cmatbeg.data(), + cmatind.get(), cmatval.get(), lb.get(), + ub.get())); int const cols = XPRSgetnumcols(mLp); unique_ptr ind(new int[newcols]); - for (int j = 0; j < cols; ++j) - ind[j] = j; + for (int j = 0; j < cols; ++j) ind[j] = j; CHECK_STATUS( XPRSchgcoltype(mLp, cols - last_extracted, ind.get(), ctype.get())); } else { @@ -998,15 +996,13 @@ void XpressInterface::ExtractNewVariables() { ctype.get())); } } - } - catch (...) { + } catch (...) { // Undo all changes in case of error. int const cols = XPRSgetnumcols(mLp); if (cols > last_extracted) { std::vector colsToDelete; - for (int i = last_extracted; i < cols; ++i) - colsToDelete.push_back(i); - (void) XPRSdelcols(mLp, colsToDelete.size(), colsToDelete.data()); + for (int i = last_extracted; i < cols; ++i) colsToDelete.push_back(i); + (void)XPRSdelcols(mLp, colsToDelete.size(), colsToDelete.data()); } std::vector const &variables = solver_->variables(); int const size = variables.size(); @@ -1041,12 +1037,11 @@ void XpressInterface::ExtractNewConstraints() { int newCons = total - offset; int const cols = XPRSgetnumcols(mLp); DCHECK_EQ(last_variable_index_, cols); - int const chunk = newCons; // 10; // max number of rows to add in one shot + int const chunk = newCons; // 10; // max number of rows to add in one shot // Update indices of new constraints _before_ actually extracting // them. In case of error we will just reset the indices. - for (int c = offset; c < total; ++c) - set_constraint_as_extracted(c, true); + for (int c = offset; c < total; ++c) set_constraint_as_extracted(c, true); try { unique_ptr rmatind(new int[cols]); @@ -1054,7 +1049,7 @@ void XpressInterface::ExtractNewConstraints() { unique_ptr rmatbeg(new int[chunk]); unique_ptr sense(new char[chunk]); unique_ptr rhs(new double[chunk]); - unique_ptr name(new char const *[chunk]); + unique_ptr name(new char const *[chunk]); unique_ptr rngval(new double[chunk]); unique_ptr rngind(new int[chunk]); bool haveRanges = false; @@ -1109,19 +1104,16 @@ void XpressInterface::ExtractNewConstraints() { } } } - } - catch (...) { + } catch (...) { // Undo all changes in case of error. int const rows = XPRSgetnumrows(mLp); std::vector rowsToDelete; - for (int i = offset; i < rows; ++i) - rowsToDelete.push_back(i); + for (int i = offset; i < rows; ++i) rowsToDelete.push_back(i); if (rows > offset) - (void) XPRSdelrows(mLp, rowsToDelete.size(), rowsToDelete.data()); + (void)XPRSdelrows(mLp, rowsToDelete.size(), rowsToDelete.data()); std::vector const &constraints = solver_->constraints(); int const size = constraints.size(); - for (int i = offset; i < size; ++i) - set_constraint_as_extracted(i, false); + for (int i = offset; i < size; ++i) set_constraint_as_extracted(i, false); throw; } } @@ -1159,8 +1151,7 @@ void XpressInterface::ExtractObjective() { void XpressInterface::SetParameters(const MPSolverParameters ¶m) { SetCommonParameters(param); - if (mMip) - SetMIPParameters(param); + if (mMip) SetMIPParameters(param); } void XpressInterface::SetRelativeMipGap(double value) { @@ -1185,12 +1176,12 @@ void XpressInterface::SetPresolveMode(int value) { static_cast(value); switch (presolve) { - case MPSolverParameters::PRESOLVE_OFF: - CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 0)); - return; - case MPSolverParameters::PRESOLVE_ON: - CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 1)); - return; + case MPSolverParameters::PRESOLVE_OFF: + CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 0)); + return; + case MPSolverParameters::PRESOLVE_ON: + CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 1)); + return; } SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); } @@ -1201,16 +1192,16 @@ void XpressInterface::SetScalingMode(int value) { static_cast(value); switch (scaling) { - case MPSolverParameters::SCALING_OFF: - CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 0)); - break; - case MPSolverParameters::SCALING_ON: - CHECK_STATUS(XPRSsetdefaultcontrol(mLp, XPRS_SCALING)); - // In Xpress, scaling is not a binary on/off control, but a bit vector - // control setting it to 1 would only enable bit 1. Instead we reset it to - // its default (163 for the current version 8.6) Alternatively, we could - // call CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 163)); - break; + case MPSolverParameters::SCALING_OFF: + CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 0)); + break; + case MPSolverParameters::SCALING_ON: + CHECK_STATUS(XPRSsetdefaultcontrol(mLp, XPRS_SCALING)); + // In Xpress, scaling is not a binary on/off control, but a bit vector + // control setting it to 1 would only enable bit 1. Instead we reset it to + // its default (163 for the current version 8.6) Alternatively, we could + // call CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 163)); + break; } } @@ -1223,15 +1214,15 @@ void XpressInterface::SetLpAlgorithm(int value) { int alg = 1; switch (algorithm) { - case MPSolverParameters::DUAL: - alg = 2; - break; - case MPSolverParameters::PRIMAL: - alg = 3; - break; - case MPSolverParameters::BARRIER: - alg = 4; - break; + case MPSolverParameters::DUAL: + alg = 2; + break; + case MPSolverParameters::PRIMAL: + alg = 3; + break; + case MPSolverParameters::BARRIER: + alg = 4; + break; } if (alg == XPRS_DEFAULTALG) { @@ -1266,15 +1257,15 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const ¶m) { static_cast( param.GetIntegerParam(MPSolverParameters::INCREMENTALITY)); switch (inc) { - case MPSolverParameters::INCREMENTALITY_OFF: { - Reset(); // This should not be required but re-extracting everything - // may be faster, so we do it. - break; - } - case MPSolverParameters::INCREMENTALITY_ON: { - XPRSsetintcontrol(mLp, XPRS_CRASH, 0); - break; - } + case MPSolverParameters::INCREMENTALITY_OFF: { + Reset(); // This should not be required but re-extracting everything + // may be faster, so we do it. + break; + } + case MPSolverParameters::INCREMENTALITY_ON: { + XPRSsetintcontrol(mLp, XPRS_CRASH, 0); + break; + } } // Extract the model to be solved. @@ -1282,8 +1273,7 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const ¶m) { // is out of sync then we have to re-extract everything. Note that this // will lose MIP starts or advanced basis information from a previous // solve. - if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) - Reset(); + if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) Reset(); ExtractModel(); VLOG(1) << absl::StrFormat("Model build in %.3f seconds.", timer.Get()); @@ -1388,8 +1378,7 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const ¶m) { if (cols > 0) { unique_ptr x(new double[cols]); unique_ptr dj(new double[cols]); - if (feasible) - CHECK_STATUS(XPRSgetlpsol(mLp, x.get(), 0, 0, dj.get())); + if (feasible) CHECK_STATUS(XPRSgetlpsol(mLp, x.get(), 0, 0, dj.get())); for (int i = 0; i < solver_->variables_.size(); ++i) { MPVariable *const var = solver_->variables_[i]; var->set_solution_value(x[i]); @@ -1436,33 +1425,33 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const ¶m) { // Map XPRESS status to more generic solution status in MPSolver if (mMip) { switch (xpressstat) { - case XPRS_MIP_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case XPRS_MIP_INFEAS: - result_status_ = MPSolver::INFEASIBLE; - break; - case XPRS_MIP_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - default: - result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; - break; + case XPRS_MIP_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case XPRS_MIP_INFEAS: + result_status_ = MPSolver::INFEASIBLE; + break; + case XPRS_MIP_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + default: + result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; + break; } } else { switch (xpressstat) { - case XPRS_LP_OPTIMAL: - result_status_ = MPSolver::OPTIMAL; - break; - case XPRS_LP_INFEAS: - result_status_ = MPSolver::INFEASIBLE; - break; - case XPRS_LP_UNBOUNDED: - result_status_ = MPSolver::UNBOUNDED; - break; - default: - result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; - break; + case XPRS_LP_OPTIMAL: + result_status_ = MPSolver::OPTIMAL; + break; + case XPRS_LP_INFEAS: + result_status_ = MPSolver::INFEASIBLE; + break; + case XPRS_LP_UNBOUNDED: + result_status_ = MPSolver::UNBOUNDED; + break; + default: + result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL; + break; } } @@ -1474,5 +1463,5 @@ MPSolverInterface *BuildXpressInterface(bool mip, MPSolver *const solver) { return new XpressInterface(solver, mip); } -} // namespace operations_research -#endif // #if defined(USE_XPRESS) +} // namespace operations_research +#endif // #if defined(USE_XPRESS) diff --git a/ortools/lp_data/lp_data.cc b/ortools/lp_data/lp_data.cc index 556e0cdb12..31391635da 100644 --- a/ortools/lp_data/lp_data.cc +++ b/ortools/lp_data/lp_data.cc @@ -46,8 +46,7 @@ void DebugCheckBoundsValid(Fractional lower_bound, Fractional upper_bound) { // Returns true if the bounds are the ones of a free or boxed row. Note that // a fixed row is not counted as boxed. bool AreBoundsFreeOrBoxed(Fractional lower_bound, Fractional upper_bound) { - if (lower_bound == -kInfinity && upper_bound == kInfinity) - return true; + if (lower_bound == -kInfinity && upper_bound == kInfinity) return true; if (lower_bound != -kInfinity && upper_bound != kInfinity && lower_bound != upper_bound) { return true; @@ -55,14 +54,14 @@ bool AreBoundsFreeOrBoxed(Fractional lower_bound, Fractional upper_bound) { return false; } -template double Average(const gtl::ITIVector &v) { +template +double Average(const gtl::ITIVector &v) { const size_t size = v.size(); DCHECK_LT(0, size); double sum = 0.0; - double n = 0.0; // n is used in a calculation involving doubles. + double n = 0.0; // n is used in a calculation involving doubles. for (I i(0); i < size; ++i) { - if (v[i] == 0.0) - continue; + if (v[i] == 0.0) continue; ++n; sum += static_cast(v[i].value()); } @@ -72,13 +71,12 @@ template double Average(const gtl::ITIVector &v) { template double StandardDeviation(const gtl::ITIVector &v) { const size_t size = v.size(); - double n = 0.0; // n is used in a calculation involving doubles. + double n = 0.0; // n is used in a calculation involving doubles. double sigma_square = 0.0; double sigma = 0.0; for (I i(0); i < size; ++i) { double sample = static_cast(v[i].value()); - if (sample == 0.0) - continue; + if (sample == 0.0) continue; sigma_square += sample * sample; sigma += sample; ++n; @@ -87,7 +85,8 @@ double StandardDeviation(const gtl::ITIVector &v) { } // Returns 0 when the vector is empty. -template T GetMaxElement(const gtl::ITIVector &v) { +template +T GetMaxElement(const gtl::ITIVector &v) { const size_t size = v.size(); if (size == 0) { return T(0); @@ -102,21 +101,32 @@ template T GetMaxElement(const gtl::ITIVector &v) { return max_index; } -} // anonymous namespace +} // anonymous namespace // -------------------------------------------------------- // LinearProgram // -------------------------------------------------------- LinearProgram::LinearProgram() - : matrix_(), transpose_matrix_(), constraint_lower_bounds_(), - constraint_upper_bounds_(), constraint_names_(), - objective_coefficients_(), variable_lower_bounds_(), - variable_upper_bounds_(), variable_names_(), variable_types_(), - integer_variables_list_(), variable_table_(), constraint_table_(), - objective_offset_(0.0), objective_scaling_factor_(1.0), maximize_(false), + : matrix_(), + transpose_matrix_(), + constraint_lower_bounds_(), + constraint_upper_bounds_(), + constraint_names_(), + objective_coefficients_(), + variable_lower_bounds_(), + variable_upper_bounds_(), + variable_names_(), + variable_types_(), + integer_variables_list_(), + variable_table_(), + constraint_table_(), + objective_offset_(0.0), + objective_scaling_factor_(1.0), + maximize_(false), columns_are_known_to_be_clean_(true), transpose_matrix_is_consistent_(true), - integer_variables_list_is_consistent_(true), name_(), + integer_variables_list_is_consistent_(true), + name_(), first_slack_variable_(kInvalidCol) {} void LinearProgram::Clear() { @@ -203,8 +213,8 @@ ColIndex LinearProgram::FindOrCreateVariable(const std::string &variable_id) { } } -RowIndex -LinearProgram::FindOrCreateConstraint(const std::string &constraint_id) { +RowIndex LinearProgram::FindOrCreateConstraint( + const std::string &constraint_id) { const absl::flat_hash_map::iterator it = constraint_table_.find(constraint_id); if (it != constraint_table_.end()) { @@ -236,8 +246,7 @@ void LinearProgram::SetConstraintName(RowIndex row, absl::string_view name) { void LinearProgram::SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound) { - if (dcheck_bounds_) - DebugCheckBoundsValid(lower_bound, upper_bound); + if (dcheck_bounds_) DebugCheckBoundsValid(lower_bound, upper_bound); const bool var_was_binary = IsVariableBinary(col); variable_lower_bounds_[col] = lower_bound; variable_upper_bounds_[col] = upper_bound; @@ -248,8 +257,7 @@ void LinearProgram::SetVariableBounds(ColIndex col, Fractional lower_bound, } void LinearProgram::UpdateAllIntegerVariableLists() const { - if (integer_variables_list_is_consistent_) - return; + if (integer_variables_list_is_consistent_) return; integer_variables_list_.clear(); binary_variables_list_.clear(); non_binary_variables_list_.clear(); @@ -298,8 +306,7 @@ bool LinearProgram::IsVariableBinary(ColIndex col) const { void LinearProgram::SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound) { - if (dcheck_bounds_) - DebugCheckBoundsValid(lower_bound, upper_bound); + if (dcheck_bounds_) DebugCheckBoundsValid(lower_bound, upper_bound); ResizeRowsIfNeeded(row); constraint_lower_bounds_[row] = lower_bound; constraint_upper_bounds_[row] = upper_bound; @@ -324,8 +331,8 @@ void LinearProgram::SetObjectiveOffset(Fractional objective_offset) { objective_offset_ = objective_offset; } -void -LinearProgram::SetObjectiveScalingFactor(Fractional objective_scaling_factor) { +void LinearProgram::SetObjectiveScalingFactor( + Fractional objective_scaling_factor) { DCHECK(IsFinite(objective_scaling_factor)); DCHECK_NE(0.0, objective_scaling_factor); objective_scaling_factor_ = objective_scaling_factor; @@ -336,16 +343,14 @@ void LinearProgram::SetMaximizationProblem(bool maximize) { } void LinearProgram::CleanUp() { - if (columns_are_known_to_be_clean_) - return; + if (columns_are_known_to_be_clean_) return; matrix_.CleanUp(); columns_are_known_to_be_clean_ = true; transpose_matrix_is_consistent_ = false; } bool LinearProgram::IsCleanedUp() const { - if (columns_are_known_to_be_clean_) - return true; + if (columns_are_known_to_be_clean_) return true; columns_are_known_to_be_clean_ = matrix_.IsCleanedUp(); return columns_are_known_to_be_clean_; } @@ -429,8 +434,7 @@ std::string LinearProgram::GetObjectiveStatsString() const { Fractional max_value = -kInfinity; for (ColIndex col(0); col < objective_coefficients_.size(); ++col) { const Fractional value = objective_coefficients_[col]; - if (value == 0) - continue; + if (value == 0) continue; min_value = std::min(min_value, value); max_value = std::max(max_value, value); ++num_non_zeros; @@ -446,12 +450,10 @@ std::string LinearProgram::GetObjectiveStatsString() const { bool LinearProgram::SolutionIsWithinVariableBounds( const DenseRow &solution, Fractional absolute_tolerance) const { DCHECK_EQ(solution.size(), num_variables()); - if (solution.size() != num_variables()) - return false; + if (solution.size() != num_variables()) return false; const ColIndex num_cols = num_variables(); for (ColIndex col = ColIndex(0); col < num_cols; ++col) { - if (!IsFinite(solution[col])) - return false; + if (!IsFinite(solution[col])) return false; const Fractional lb_error = variable_lower_bounds()[col] - solution[col]; const Fractional ub_error = solution[col] - variable_upper_bounds()[col]; if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) { @@ -471,8 +473,7 @@ bool LinearProgram::SolutionIsLPFeasible(const DenseRow &solution, for (RowIndex row = RowIndex(0); row < num_rows; ++row) { const Fractional sum = ScalarProduct(solution, transpose.column(RowToColIndex(row))); - if (!IsFinite(sum)) - return false; + if (!IsFinite(sum)) return false; const Fractional lb_error = constraint_lower_bounds()[row] - sum; const Fractional ub_error = sum - constraint_upper_bounds()[row]; if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) { @@ -485,14 +486,11 @@ bool LinearProgram::SolutionIsLPFeasible(const DenseRow &solution, bool LinearProgram::SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const { DCHECK_EQ(solution.size(), num_variables()); - if (solution.size() != num_variables()) - return false; + if (solution.size() != num_variables()) return false; for (ColIndex col : IntegerVariablesList()) { - if (!IsFinite(solution[col])) - return false; + if (!IsFinite(solution[col])) return false; const Fractional fractionality = fabs(solution[col] - round(solution[col])); - if (fractionality > absolute_tolerance) - return false; + if (fractionality > absolute_tolerance) return false; } return true; } @@ -518,13 +516,13 @@ void LinearProgram::ComputeSlackVariableValues(DenseRow *solution) const { } } -Fractional -LinearProgram::ApplyObjectiveScalingAndOffset(Fractional value) const { +Fractional LinearProgram::ApplyObjectiveScalingAndOffset( + Fractional value) const { return objective_scaling_factor() * (value + objective_offset()); } -Fractional -LinearProgram::RemoveObjectiveScalingAndOffset(Fractional value) const { +Fractional LinearProgram::RemoveObjectiveScalingAndOffset( + Fractional value) const { return value / objective_scaling_factor() - objective_offset(); } @@ -619,8 +617,7 @@ std::string LinearProgram::DumpSolution(const DenseRow &variable_values) const { DCHECK_EQ(variable_values.size(), num_variables()); std::string output; for (ColIndex col(0); col < variable_values.size(); ++col) { - if (!output.empty()) - absl::StrAppend(&output, ", "); + if (!output.empty()) absl::StrAppend(&output, ", "); absl::StrAppend(&output, GetVariableName(col), " = ", (variable_values[col])); } @@ -628,8 +625,9 @@ std::string LinearProgram::DumpSolution(const DenseRow &variable_values) const { } std::string LinearProgram::GetProblemStats() const { - return ProblemStatFormatter("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," - "%d,%d,%d,%d"); + return ProblemStatFormatter( + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," + "%d,%d,%d,%d"); } std::string LinearProgram::GetPrettyProblemStats() const { @@ -819,8 +817,8 @@ void LinearProgram::PopulateFromDual(const LinearProgram &dual, const ColIndex col = CreateNewVariable(); SetVariableBounds(col, 0.0, kInfinity); SetObjectiveCoefficient(col, lower_bound); - matrix_.mutable_column(col) - ->PopulateFromSparseVector(matrix_.column(RowToColIndex(dual_row))); + matrix_.mutable_column(col)->PopulateFromSparseVector( + matrix_.column(RowToColIndex(dual_row))); (*duplicated_rows)[dual_row] = col; } } @@ -830,8 +828,8 @@ void LinearProgram::PopulateFromDual(const LinearProgram &dual, transpose_matrix_is_consistent_ = false; } -void -LinearProgram::PopulateFromLinearProgram(const LinearProgram &linear_program) { +void LinearProgram::PopulateFromLinearProgram( + const LinearProgram &linear_program) { matrix_.PopulateFromSparseMatrix(linear_program.matrix_); if (linear_program.transpose_matrix_is_consistent_) { transpose_matrix_is_consistent_ = true; @@ -1034,8 +1032,7 @@ void LinearProgram::Swap(LinearProgram *linear_program) { } void LinearProgram::DeleteColumns(const DenseBooleanRow &columns_to_delete) { - if (columns_to_delete.empty()) - return; + if (columns_to_delete.empty()) return; integer_variables_list_is_consistent_ = false; const ColIndex num_cols = num_variables(); ColumnPermutation permutation(num_cols); @@ -1116,8 +1113,7 @@ void UpdateMinAndMaxMagnitude(const FractionalRange &range, Fractional *max_magnitude) { for (const Fractional value : range) { const Fractional magnitude = std::abs(value); - if (magnitude == 0 || magnitude == kInfinity) - continue; + if (magnitude == 0 || magnitude == kInfinity) continue; *min_magnitude = std::min(*min_magnitude, magnitude); *max_magnitude = std::max(*max_magnitude, magnitude); } @@ -1126,12 +1122,10 @@ void UpdateMinAndMaxMagnitude(const FractionalRange &range, Fractional GetMedianScalingFactor(const DenseRow &range) { std::vector median; for (const Fractional value : range) { - if (value == 0.0) - continue; + if (value == 0.0) continue; median.push_back(std::abs(value)); } - if (median.empty()) - return 1.0; + if (median.empty()) return 1.0; std::sort(median.begin(), median.end()); return median[median.size() / 2]; } @@ -1140,13 +1134,11 @@ Fractional GetMeanScalingFactor(const DenseRow &range) { Fractional mean = 0.0; int num_non_zeros = 0; for (const Fractional value : range) { - if (value == 0.0) - continue; + if (value == 0.0) continue; ++num_non_zeros; mean += std::abs(value); } - if (num_non_zeros == 0.0) - return 1.0; + if (num_non_zeros == 0.0) return 1.0; return mean / static_cast(num_non_zeros); } @@ -1160,33 +1152,32 @@ Fractional ComputeDivisorSoThatRangeContainsOne(Fractional min_magnitude, return 1.0; } -} // namespace +} // namespace -Fractional -LinearProgram::ScaleObjective(GlopParameters::CostScalingAlgorithm method) { +Fractional LinearProgram::ScaleObjective( + GlopParameters::CostScalingAlgorithm method) { Fractional min_magnitude = kInfinity; Fractional max_magnitude = 0.0; UpdateMinAndMaxMagnitude(objective_coefficients(), &min_magnitude, &max_magnitude); Fractional cost_scaling_factor = 1.0; switch (method) { - case GlopParameters::NO_COST_SCALING: - break; - case GlopParameters::CONTAIN_ONE_COST_SCALING: - cost_scaling_factor = - ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude); - break; - case GlopParameters::MEAN_COST_SCALING: - cost_scaling_factor = GetMeanScalingFactor(objective_coefficients()); - break; - case GlopParameters::MEDIAN_COST_SCALING: - cost_scaling_factor = GetMedianScalingFactor(objective_coefficients()); - break; + case GlopParameters::NO_COST_SCALING: + break; + case GlopParameters::CONTAIN_ONE_COST_SCALING: + cost_scaling_factor = + ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude); + break; + case GlopParameters::MEAN_COST_SCALING: + cost_scaling_factor = GetMeanScalingFactor(objective_coefficients()); + break; + case GlopParameters::MEDIAN_COST_SCALING: + cost_scaling_factor = GetMedianScalingFactor(objective_coefficients()); + break; } if (cost_scaling_factor != 1.0) { for (ColIndex col(0); col < num_variables(); ++col) { - if (objective_coefficients()[col] == 0.0) - continue; + if (objective_coefficients()[col] == 0.0) continue; SetObjectiveCoefficient( col, objective_coefficients()[col] / cost_scaling_factor); } @@ -1234,8 +1225,7 @@ Fractional LinearProgram::ScaleBounds() { } void LinearProgram::DeleteRows(const DenseBooleanColumn &rows_to_delete) { - if (rows_to_delete.empty()) - return; + if (rows_to_delete.empty()) return; // Deal with row-indexed data and construct the row mapping that will need to // be applied to every column entry. @@ -1282,12 +1272,9 @@ void LinearProgram::DeleteRows(const DenseBooleanColumn &rows_to_delete) { } bool LinearProgram::IsValid() const { - if (!IsFinite(objective_offset_)) - return false; - if (!IsFinite(objective_scaling_factor_)) - return false; - if (objective_scaling_factor_ == 0.0) - return false; + if (!IsFinite(objective_offset_)) return false; + if (!IsFinite(objective_scaling_factor_)) return false; + if (objective_scaling_factor_ == 0.0) return false; const ColIndex num_cols = num_variables(); for (ColIndex col(0); col < num_cols; ++col) { if (!AreBoundsValid(variable_lower_bounds()[col], @@ -1298,8 +1285,7 @@ bool LinearProgram::IsValid() const { return false; } for (const SparseColumn::Entry e : GetSparseColumn(col)) { - if (!IsFinite(e.coefficient())) - return false; + if (!IsFinite(e.coefficient())) return false; } } if (constraint_upper_bounds_.size() != constraint_lower_bounds_.size()) { @@ -1314,8 +1300,8 @@ bool LinearProgram::IsValid() const { return true; } -std::string -LinearProgram::ProblemStatFormatter(const absl::string_view format) const { +std::string LinearProgram::ProblemStatFormatter( + const absl::string_view format) const { int num_objective_non_zeros = 0; int num_non_negative_variables = 0; int num_boxed_variables = 0; @@ -1383,7 +1369,8 @@ LinearProgram::ProblemStatFormatter(const absl::string_view format) const { continue; } LOG(DFATAL) << "There is a bug since all possible cases for the row bounds " - "should have been accounted for. row=" << row; + "should have been accounted for. row=" + << row; } const int num_integer_variables = IntegerVariablesList().size(); @@ -1406,8 +1393,8 @@ LinearProgram::ProblemStatFormatter(const absl::string_view format) const { num_continuous_variables); } -std::string -LinearProgram::NonZeroStatFormatter(const absl::string_view format) const { +std::string LinearProgram::NonZeroStatFormatter( + const absl::string_view format) const { StrictITIVector num_entries_in_row(num_constraints(), EntryIndex(0)); StrictITIVector num_entries_in_column(num_variables(), @@ -1463,8 +1450,8 @@ bool LinearProgram::IsInEquationForm() const { IsRightMostSquareMatrixIdentity(matrix_); } -bool -LinearProgram::BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const { +bool LinearProgram::BoundsOfIntegerVariablesAreInteger( + Fractional tolerance) const { for (const ColIndex col : IntegerVariablesList()) { if ((IsFinite(variable_lower_bounds_[col]) && !IsIntegerWithinTolerance(variable_lower_bounds_[col], tolerance)) || @@ -1533,5 +1520,5 @@ std::string ProblemSolution::DebugString() const { return s; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_data.h b/ortools/lp_data/lp_data.h index 8e5a7ae985..517e4da2ba 100644 --- a/ortools/lp_data/lp_data.h +++ b/ortools/lp_data/lp_data.h @@ -24,18 +24,18 @@ #ifndef OR_TOOLS_LP_DATA_LP_DATA_H_ #define OR_TOOLS_LP_DATA_LP_DATA_H_ -#include // for max +#include // for max #include -#include // for string -#include // for vector +#include // for string +#include // for vector #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "ortools/base/hash.h" #include "ortools/base/int_type.h" #include "ortools/base/int_type_indexed_vector.h" -#include "ortools/base/logging.h" // for CHECK* -#include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL +#include "ortools/base/logging.h" // for CHECK* +#include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL #include "ortools/glop/parameters.pb.h" #include "ortools/lp_data/lp_types.h" #include "ortools/lp_data/sparse.h" @@ -53,17 +53,17 @@ class SparseMatrixScaler; // class also contains a few more advanced modification functions used primarily // by preprocessors. A client shouldn't need to use them directly. class LinearProgram { -public: + public: enum class VariableType { // The variable can take any value between and including its lower and upper // bound. CONTINUOUS, - // The variable must only take integer values. - INTEGER, - // The variable is implied integer variable i.e. it was continuous - // variable - // in the LP and was detected to take only integer values. - IMPLIED_INTEGER + // The variable must only take integer values. + INTEGER, + // The variable is implied integer variable i.e. it was continuous + // variable + // in the LP and was detected to take only integer values. + IMPLIED_INTEGER }; LinearProgram(); @@ -515,9 +515,9 @@ public: // bounds and the bounds specified by variable_lower_bounds and // variable_upper_bounds. If the new bounds of all variables are non-empty, // returns true; otherwise, returns false. - bool - UpdateVariableBoundsToIntersection(const DenseRow &variable_lower_bounds, - const DenseRow &variable_upper_bounds); + bool UpdateVariableBoundsToIntersection( + const DenseRow &variable_lower_bounds, + const DenseRow &variable_upper_bounds); // Returns true if the linear program is in equation form Ax = 0 and all slack // variables have been added. This is also called "computational form" in some @@ -545,7 +545,7 @@ public: // If true, checks bound validity in debug mode. void SetDcheckBounds(bool dcheck_bounds) { dcheck_bounds_ = dcheck_bounds; } -private: + private: // A helper function that updates the vectors integer_variables_list_, // binary_variables_list_, and non_binary_variables_list_. void UpdateAllIntegerVariableLists() const; @@ -647,7 +647,8 @@ private: // Contains the solution of a LinearProgram as returned by a preprocessor. struct ProblemSolution { ProblemSolution(RowIndex num_rows, ColIndex num_cols) - : status(ProblemStatus::OPTIMAL), primal_values(num_cols, 0.0), + : status(ProblemStatus::OPTIMAL), + primal_values(num_cols, 0.0), dual_values(num_rows, 0.0), variable_statuses(num_cols, VariableStatus::FREE), constraint_statuses(num_rows, ConstraintStatus::FREE) {} @@ -681,20 +682,15 @@ struct ProblemSolution { // Helper function to check the bounds of the SetVariableBounds() and // SetConstraintBounds() functions. inline bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound) { - if (std::isnan(lower_bound)) - return false; - if (std::isnan(upper_bound)) - return false; - if (lower_bound == kInfinity && upper_bound == kInfinity) - return false; - if (lower_bound == -kInfinity && upper_bound == -kInfinity) - return false; - if (lower_bound > upper_bound) - return false; + if (std::isnan(lower_bound)) return false; + if (std::isnan(upper_bound)) return false; + if (lower_bound == kInfinity && upper_bound == kInfinity) return false; + if (lower_bound == -kInfinity && upper_bound == -kInfinity) return false; + if (lower_bound > upper_bound) return false; return true; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_DATA_H_ +#endif // OR_TOOLS_LP_DATA_LP_DATA_H_ diff --git a/ortools/lp_data/lp_data_utils.cc b/ortools/lp_data/lp_data_utils.cc index 9670f6aff9..b5d13ba378 100644 --- a/ortools/lp_data/lp_data_utils.cc +++ b/ortools/lp_data/lp_data_utils.cc @@ -22,15 +22,13 @@ void ComputeSlackVariablesValues(const LinearProgram &linear_program, DCHECK_EQ(linear_program.num_variables(), values->size()); // If there are no slack variable, we can give up. - if (linear_program.GetFirstSlackVariable() == kInvalidCol) - return; + if (linear_program.GetFirstSlackVariable() == kInvalidCol) return; const auto &transposed_matrix = linear_program.GetTransposeSparseMatrix(); for (RowIndex row(0); row < linear_program.num_constraints(); row++) { const ColIndex slack_variable = linear_program.GetSlackVariable(row); - if (slack_variable == kInvalidCol) - continue; + if (slack_variable == kInvalidCol) continue; DCHECK_EQ(0.0, linear_program.constraint_lower_bounds()[row]); DCHECK_EQ(0.0, linear_program.constraint_upper_bounds()[row]); @@ -41,8 +39,7 @@ void ComputeSlackVariablesValues(const LinearProgram &linear_program, const SparseColumn &sparse_row = transposed_matrix.column(RowToColIndex(row)); for (const auto &entry : sparse_row) { - if (transposed_slack == entry.index()) - continue; + if (transposed_slack == entry.index()) continue; activation += (*values)[RowToColIndex(entry.index())] * entry.coefficient(); } @@ -64,12 +61,12 @@ void Scale(LinearProgram *lp, SparseMatrixScaler *scaler, GlopParameters::ScalingAlgorithm scaling_method) { scaler->Init(&lp->matrix_); scaler->Scale( - scaling_method); // Compute R and C, and replace the matrix A by R.A.C - scaler->ScaleRowVector(false, &lp->objective_coefficients_); // oc = oc.C - scaler->ScaleRowVector(true, &lp->variable_upper_bounds_); // cl = cl.C^-1 - scaler->ScaleRowVector(true, &lp->variable_lower_bounds_); // cu = cu.C^-1 - scaler->ScaleColumnVector(false, &lp->constraint_upper_bounds_); // rl = R.rl - scaler->ScaleColumnVector(false, &lp->constraint_lower_bounds_); // ru = R.ru + scaling_method); // Compute R and C, and replace the matrix A by R.A.C + scaler->ScaleRowVector(false, &lp->objective_coefficients_); // oc = oc.C + scaler->ScaleRowVector(true, &lp->variable_upper_bounds_); // cl = cl.C^-1 + scaler->ScaleRowVector(true, &lp->variable_lower_bounds_); // cu = cu.C^-1 + scaler->ScaleColumnVector(false, &lp->constraint_upper_bounds_); // rl = R.rl + scaler->ScaleColumnVector(false, &lp->constraint_lower_bounds_); // ru = R.ru lp->transpose_matrix_is_consistent_ = false; } @@ -118,9 +115,8 @@ Fractional LpScalingHelper::UnscaleConstraintActivity(RowIndex row, return value * scaler_.RowUnscalingFactor(row) / bound_scaling_factor_; } -void -LpScalingHelper::UnscaleUnitRowLeftSolve(ColIndex basis_col, - ScatteredRow *left_inverse) const { +void LpScalingHelper::UnscaleUnitRowLeftSolve( + ColIndex basis_col, ScatteredRow *left_inverse) const { const Fractional global_factor = scaler_.ColUnscalingFactor(basis_col); // We have left_inverse * [RowScale * B * ColScale] = unit_row. @@ -138,10 +134,9 @@ LpScalingHelper::UnscaleUnitRowLeftSolve(ColIndex basis_col, } } -void -LpScalingHelper::UnscaleColumnRightSolve(const RowToColMapping &basis, - ColIndex col, - ScatteredColumn *right_inverse) const { +void LpScalingHelper::UnscaleColumnRightSolve( + const RowToColMapping &basis, ColIndex col, + ScatteredColumn *right_inverse) const { const Fractional global_factor = scaler_.ColScalingFactor(col); // [RowScale * B * BColScale] * inverse = RowScale * column * ColScale. @@ -160,5 +155,5 @@ LpScalingHelper::UnscaleColumnRightSolve(const RowToColMapping &basis, } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_data_utils.h b/ortools/lp_data/lp_data_utils.h index 115bb00a8e..692bfc75d0 100644 --- a/ortools/lp_data/lp_data_utils.h +++ b/ortools/lp_data/lp_data_utils.h @@ -49,7 +49,7 @@ void Scale(LinearProgram *lp, SparseMatrixScaler *scaler); // and its scaled version. It is easy to get the direction wrong, so it make // sense to have a single place where all the scaling formulas are kept. class LpScalingHelper { -public: + public: // Scale the given LP. void Scale(LinearProgram *lp); void Scale(const GlopParameters ¶ms, LinearProgram *lp); @@ -86,13 +86,13 @@ public: return objective_scaling_factor_; } -private: + private: SparseMatrixScaler scaler_; Fractional bound_scaling_factor_ = 1.0; Fractional objective_scaling_factor_ = 1.0; }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_DATA_UTILS_H_ +#endif // OR_TOOLS_LP_DATA_LP_DATA_UTILS_H_ diff --git a/ortools/lp_data/lp_decomposer.cc b/ortools/lp_data/lp_decomposer.cc index 8cd9ed9c94..1199d116d4 100644 --- a/ortools/lp_data/lp_decomposer.cc +++ b/ortools/lp_data/lp_decomposer.cc @@ -167,5 +167,5 @@ DenseRow LPDecomposer::ExtractLocalAssignment(int problem_index, return local_assignment; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_decomposer.h b/ortools/lp_data/lp_decomposer.h index b0dd23a891..a09420dcf9 100644 --- a/ortools/lp_data/lp_decomposer.h +++ b/ortools/lp_data/lp_decomposer.h @@ -48,7 +48,7 @@ namespace glop { // Note that a solution to those two independent problems is a solution to the // original problem. class LPDecomposer { -public: + public: LPDecomposer(); // Decomposes the problem into independent problems. @@ -79,7 +79,7 @@ public: DenseRow ExtractLocalAssignment(int problem_index, const DenseRow &assignment) ABSL_LOCKS_EXCLUDED(mutex_); -private: + private: const LinearProgram *original_problem_; std::vector > clusters_; @@ -88,7 +88,7 @@ private: DISALLOW_COPY_AND_ASSIGN(LPDecomposer); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_DECOMPOSER_H_ +#endif // OR_TOOLS_LP_DATA_LP_DECOMPOSER_H_ diff --git a/ortools/lp_data/lp_print_utils.cc b/ortools/lp_data/lp_print_utils.cc index b911890daa..6f42c53237 100644 --- a/ortools/lp_data/lp_print_utils.cc +++ b/ortools/lp_data/lp_print_utils.cc @@ -52,16 +52,16 @@ std::string Stringify(const Fractional x, bool fraction) { // a and variable name x std::string StringifyMonomial(const Fractional a, const std::string &x, bool fraction) { - if (a == 0.0) - return ""; + if (a == 0.0) return ""; return a > 0.0 ? absl::StrCat( " + ", a == 1.0 ? x : absl::StrCat(Stringify(a, fraction), " ", x)) : absl::StrCat( - " - ", a == -1.0 ? x : absl::StrCat(Stringify(-a, fraction), - " ", x)); + " - ", a == -1.0 + ? x + : absl::StrCat(Stringify(-a, fraction), " ", x)); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_print_utils.h b/ortools/lp_data/lp_print_utils.h index b21a07ac76..2eebd99420 100644 --- a/ortools/lp_data/lp_print_utils.h +++ b/ortools/lp_data/lp_print_utils.h @@ -57,7 +57,7 @@ std::string Stringify(const Fractional x, bool fraction); std::string StringifyMonomial(const Fractional a, const std::string &x, bool fraction); -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_PRINT_UTILS_H_ +#endif // OR_TOOLS_LP_DATA_LP_PRINT_UTILS_H_ diff --git a/ortools/lp_data/lp_types.cc b/ortools/lp_data/lp_types.cc index d029872f8c..3962ac4c76 100644 --- a/ortools/lp_data/lp_types.cc +++ b/ortools/lp_data/lp_types.cc @@ -18,30 +18,30 @@ namespace glop { std::string GetProblemStatusString(ProblemStatus problem_status) { switch (problem_status) { - case ProblemStatus::OPTIMAL: - return "OPTIMAL"; - case ProblemStatus::PRIMAL_INFEASIBLE: - return "PRIMAL_INFEASIBLE"; - case ProblemStatus::DUAL_INFEASIBLE: - return "DUAL_INFEASIBLE"; - case ProblemStatus::INFEASIBLE_OR_UNBOUNDED: - return "INFEASIBLE_OR_UNBOUNDED"; - case ProblemStatus::PRIMAL_UNBOUNDED: - return "PRIMAL_UNBOUNDED"; - case ProblemStatus::DUAL_UNBOUNDED: - return "DUAL_UNBOUNDED"; - case ProblemStatus::INIT: - return "INIT"; - case ProblemStatus::PRIMAL_FEASIBLE: - return "PRIMAL_FEASIBLE"; - case ProblemStatus::DUAL_FEASIBLE: - return "DUAL_FEASIBLE"; - case ProblemStatus::ABNORMAL: - return "ABNORMAL"; - case ProblemStatus::INVALID_PROBLEM: - return "INVALID_PROBLEM"; - case ProblemStatus::IMPRECISE: - return "IMPRECISE"; + case ProblemStatus::OPTIMAL: + return "OPTIMAL"; + case ProblemStatus::PRIMAL_INFEASIBLE: + return "PRIMAL_INFEASIBLE"; + case ProblemStatus::DUAL_INFEASIBLE: + return "DUAL_INFEASIBLE"; + case ProblemStatus::INFEASIBLE_OR_UNBOUNDED: + return "INFEASIBLE_OR_UNBOUNDED"; + case ProblemStatus::PRIMAL_UNBOUNDED: + return "PRIMAL_UNBOUNDED"; + case ProblemStatus::DUAL_UNBOUNDED: + return "DUAL_UNBOUNDED"; + case ProblemStatus::INIT: + return "INIT"; + case ProblemStatus::PRIMAL_FEASIBLE: + return "PRIMAL_FEASIBLE"; + case ProblemStatus::DUAL_FEASIBLE: + return "DUAL_FEASIBLE"; + case ProblemStatus::ABNORMAL: + return "ABNORMAL"; + case ProblemStatus::INVALID_PROBLEM: + return "INVALID_PROBLEM"; + case ProblemStatus::IMPRECISE: + return "IMPRECISE"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -51,16 +51,16 @@ std::string GetProblemStatusString(ProblemStatus problem_status) { std::string GetVariableTypeString(VariableType variable_type) { switch (variable_type) { - case VariableType::UNCONSTRAINED: - return "UNCONSTRAINED"; - case VariableType::LOWER_BOUNDED: - return "LOWER_BOUNDED"; - case VariableType::UPPER_BOUNDED: - return "UPPER_BOUNDED"; - case VariableType::UPPER_AND_LOWER_BOUNDED: - return "UPPER_AND_LOWER_BOUNDED"; - case VariableType::FIXED_VARIABLE: - return "FIXED_VARIABLE"; + case VariableType::UNCONSTRAINED: + return "UNCONSTRAINED"; + case VariableType::LOWER_BOUNDED: + return "LOWER_BOUNDED"; + case VariableType::UPPER_BOUNDED: + return "UPPER_BOUNDED"; + case VariableType::UPPER_AND_LOWER_BOUNDED: + return "UPPER_AND_LOWER_BOUNDED"; + case VariableType::FIXED_VARIABLE: + return "FIXED_VARIABLE"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -70,16 +70,16 @@ std::string GetVariableTypeString(VariableType variable_type) { std::string GetVariableStatusString(VariableStatus status) { switch (status) { - case VariableStatus::FREE: - return "FREE"; - case VariableStatus::AT_LOWER_BOUND: - return "AT_LOWER_BOUND"; - case VariableStatus::AT_UPPER_BOUND: - return "AT_UPPER_BOUND"; - case VariableStatus::FIXED_VALUE: - return "FIXED_VALUE"; - case VariableStatus::BASIC: - return "BASIC"; + case VariableStatus::FREE: + return "FREE"; + case VariableStatus::AT_LOWER_BOUND: + return "AT_LOWER_BOUND"; + case VariableStatus::AT_UPPER_BOUND: + return "AT_UPPER_BOUND"; + case VariableStatus::FIXED_VALUE: + return "FIXED_VALUE"; + case VariableStatus::BASIC: + return "BASIC"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -89,16 +89,16 @@ std::string GetVariableStatusString(VariableStatus status) { std::string GetConstraintStatusString(ConstraintStatus status) { switch (status) { - case ConstraintStatus::FREE: - return "FREE"; - case ConstraintStatus::AT_LOWER_BOUND: - return "AT_LOWER_BOUND"; - case ConstraintStatus::AT_UPPER_BOUND: - return "AT_UPPER_BOUND"; - case ConstraintStatus::FIXED_VALUE: - return "FIXED_VALUE"; - case ConstraintStatus::BASIC: - return "BASIC"; + case ConstraintStatus::FREE: + return "FREE"; + case ConstraintStatus::AT_LOWER_BOUND: + return "AT_LOWER_BOUND"; + case ConstraintStatus::AT_UPPER_BOUND: + return "AT_UPPER_BOUND"; + case ConstraintStatus::FIXED_VALUE: + return "FIXED_VALUE"; + case ConstraintStatus::BASIC: + return "BASIC"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -108,16 +108,16 @@ std::string GetConstraintStatusString(ConstraintStatus status) { ConstraintStatus VariableToConstraintStatus(VariableStatus status) { switch (status) { - case VariableStatus::FREE: - return ConstraintStatus::FREE; - case VariableStatus::AT_LOWER_BOUND: - return ConstraintStatus::AT_LOWER_BOUND; - case VariableStatus::AT_UPPER_BOUND: - return ConstraintStatus::AT_UPPER_BOUND; - case VariableStatus::FIXED_VALUE: - return ConstraintStatus::FIXED_VALUE; - case VariableStatus::BASIC: - return ConstraintStatus::BASIC; + case VariableStatus::FREE: + return ConstraintStatus::FREE; + case VariableStatus::AT_LOWER_BOUND: + return ConstraintStatus::AT_LOWER_BOUND; + case VariableStatus::AT_UPPER_BOUND: + return ConstraintStatus::AT_UPPER_BOUND; + case VariableStatus::FIXED_VALUE: + return ConstraintStatus::FIXED_VALUE; + case VariableStatus::BASIC: + return ConstraintStatus::BASIC; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -126,5 +126,5 @@ ConstraintStatus VariableToConstraintStatus(VariableStatus status) { return ConstraintStatus::FREE; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_types.h b/ortools/lp_data/lp_types.h index e1cd2b1d00..7f9b5c8c61 100644 --- a/ortools/lp_data/lp_types.h +++ b/ortools/lp_data/lp_types.h @@ -103,75 +103,75 @@ enum class ProblemStatus : int8 { // a feasible solution. OPTIMAL, - // The problem has been proven primal-infeasible. Note that the problem is - // not - // necessarily DUAL_UNBOUNDED (See Chvatal p.60). The solver does not have - // a - // dual unbounded ray in this case. - PRIMAL_INFEASIBLE, + // The problem has been proven primal-infeasible. Note that the problem is + // not + // necessarily DUAL_UNBOUNDED (See Chvatal p.60). The solver does not have + // a + // dual unbounded ray in this case. + PRIMAL_INFEASIBLE, - // The problem has been proven dual-infeasible. Note that the problem is - // not - // necessarily PRIMAL_UNBOUNDED (See Chvatal p.60). The solver does - // note have a primal unbounded ray in this case, - DUAL_INFEASIBLE, + // The problem has been proven dual-infeasible. Note that the problem is + // not + // necessarily PRIMAL_UNBOUNDED (See Chvatal p.60). The solver does + // note have a primal unbounded ray in this case, + DUAL_INFEASIBLE, - // The problem is either INFEASIBLE or UNBOUNDED (this applies to both the - // primal and dual algorithms). This status is only returned by the - // presolve - // step and means that a primal or dual unbounded ray was found during - // presolve. Note that because some presolve techniques assume that a - // feasible - // solution exists to simplify the problem further, it is difficult to - // distinguish between infeasibility and unboundedness. - // - // If a client needs to distinguish, it is possible to run the primal - // algorithm on the same problem with a 0 objective function to know if - // the - // problem was PRIMAL_INFEASIBLE. - INFEASIBLE_OR_UNBOUNDED, + // The problem is either INFEASIBLE or UNBOUNDED (this applies to both the + // primal and dual algorithms). This status is only returned by the + // presolve + // step and means that a primal or dual unbounded ray was found during + // presolve. Note that because some presolve techniques assume that a + // feasible + // solution exists to simplify the problem further, it is difficult to + // distinguish between infeasibility and unboundedness. + // + // If a client needs to distinguish, it is possible to run the primal + // algorithm on the same problem with a 0 objective function to know if + // the + // problem was PRIMAL_INFEASIBLE. + INFEASIBLE_OR_UNBOUNDED, - // The problem has been proven feasible and unbounded. That means that the - // problem is DUAL_INFEASIBLE and that the solver has a primal unbounded - // ray. - PRIMAL_UNBOUNDED, + // The problem has been proven feasible and unbounded. That means that the + // problem is DUAL_INFEASIBLE and that the solver has a primal unbounded + // ray. + PRIMAL_UNBOUNDED, - // The problem has been proven dual-feasible and dual-unbounded. That - // means - // the problem is PRIMAL_INFEASIBLE and that the solver has a dual - // unbounded - // ray to prove it. - DUAL_UNBOUNDED, + // The problem has been proven dual-feasible and dual-unbounded. That + // means + // the problem is PRIMAL_INFEASIBLE and that the solver has a dual + // unbounded + // ray to prove it. + DUAL_UNBOUNDED, - // All the statuses below correspond to a case where the solver was - // interrupted. This can happen because of a timeout, an iteration limit - // or an - // error. + // All the statuses below correspond to a case where the solver was + // interrupted. This can happen because of a timeout, an iteration limit + // or an + // error. - // The solver didn't had a chance to prove anything. - INIT, + // The solver didn't had a chance to prove anything. + INIT, - // The problem has been proven primal-feasible but may still be - // PRIMAL_UNBOUNDED. - PRIMAL_FEASIBLE, + // The problem has been proven primal-feasible but may still be + // PRIMAL_UNBOUNDED. + PRIMAL_FEASIBLE, - // The problem has been proven dual-feasible, but may still be - // DUAL_UNBOUNDED. - // That means that if the primal is feasible, then it has a finite optimal - // solution. - DUAL_FEASIBLE, + // The problem has been proven dual-feasible, but may still be + // DUAL_UNBOUNDED. + // That means that if the primal is feasible, then it has a finite optimal + // solution. + DUAL_FEASIBLE, - // An error occurred during the solving process. - ABNORMAL, + // An error occurred during the solving process. + ABNORMAL, - // The input problem was invalid (see LinearProgram.IsValid()). - INVALID_PROBLEM, + // The input problem was invalid (see LinearProgram.IsValid()). + INVALID_PROBLEM, - // The problem was solved to a feasible status, but the solution checker - // found - // the primal and/or dual infeasibilities too important for the specified - // parameters. - IMPRECISE, + // The problem was solved to a feasible status, but the solution checker + // found + // the primal and/or dual infeasibilities too important for the specified + // parameters. + IMPRECISE, }; // Returns the string representation of the ProblemStatus enum. @@ -184,8 +184,11 @@ inline std::ostream &operator<<(std::ostream &os, ProblemStatus status) { // Different types of variables. enum class VariableType : int8 { - UNCONSTRAINED, LOWER_BOUNDED, UPPER_BOUNDED, UPPER_AND_LOWER_BOUNDED, - FIXED_VARIABLE + UNCONSTRAINED, + LOWER_BOUNDED, + UPPER_BOUNDED, + UPPER_AND_LOWER_BOUNDED, + FIXED_VARIABLE }; // Returns the string representation of the VariableType enum. @@ -206,19 +209,19 @@ enum class VariableStatus : int8 { // The basic status is special and takes precedence over all the other // statuses. It means that the variable is part of the basis. BASIC, - // Only possible status of a FIXED_VARIABLE not in the basis. The variable - // value should be exactly equal to its bounds (which are the same). - FIXED_VALUE, - // Only possible statuses of a non-basic variable which is not - // UNCONSTRAINED - // or FIXED. The variable value should be at its exact specified bound - // (which - // must be finite). - AT_LOWER_BOUND, - AT_UPPER_BOUND, - // Only possible status of an UNCONSTRAINED non-basic variable. - // Its value should be zero. - FREE, + // Only possible status of a FIXED_VARIABLE not in the basis. The variable + // value should be exactly equal to its bounds (which are the same). + FIXED_VALUE, + // Only possible statuses of a non-basic variable which is not + // UNCONSTRAINED + // or FIXED. The variable value should be at its exact specified bound + // (which + // must be finite). + AT_LOWER_BOUND, + AT_UPPER_BOUND, + // Only possible status of an UNCONSTRAINED non-basic variable. + // Its value should be zero. + FREE, }; // Returns the string representation of the VariableStatus enum. @@ -236,7 +239,11 @@ inline std::ostream &operator<<(std::ostream &os, VariableStatus status) { // change of sign. The difference is that because of precision error, a // constraint activity cannot exactly be equal to one of its bounds or to zero. enum class ConstraintStatus : int8 { - BASIC, FIXED_VALUE, AT_LOWER_BOUND, AT_UPPER_BOUND, FREE, + BASIC, + FIXED_VALUE, + AT_LOWER_BOUND, + AT_UPPER_BOUND, + FREE, }; // Returns the string representation of the ConstraintStatus enum. @@ -257,13 +264,13 @@ ConstraintStatus VariableToConstraintStatus(VariableStatus status); // version is more strict and does not allow any other size types. template class StrictITIVector : public gtl::ITIVector { -public: - typedef IntType IndexType; // g++ 4.8.1 needs this. + public: + typedef IntType IndexType; // g++ 4.8.1 needs this. typedef gtl::ITIVector ParentType; // This allows for brace initialization, which is really useful in tests. // It is not 'explicit' by design, so one can do vector = {...}; #if !defined(__ANDROID__) && (!defined(_MSC_VER) || (_MSC_VER >= 1800)) - StrictITIVector(std::initializer_list init_list) // NOLINT + StrictITIVector(std::initializer_list init_list) // NOLINT : ParentType(init_list.begin(), init_list.end()) {} #endif StrictITIVector() : ParentType() {} @@ -359,8 +366,9 @@ typedef StrictITIVector ConstraintStatusColumn; // elements in arrays for indices and coefficients. The iterator is // built as a wrapper over a sparse vector entry class; the concrete entry class // is provided through the template argument EntryType. -template class VectorIterator : EntryType { -public: +template +class VectorIterator : EntryType { + public: using Index = typename EntryType::Index; using Entry = EntryType; @@ -387,7 +395,7 @@ static inline double DeterministicTimeForFpOperations(int64 n) { return kConversionFactor * static_cast(n); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_TYPES_H_ +#endif // OR_TOOLS_LP_DATA_LP_TYPES_H_ diff --git a/ortools/lp_data/lp_utils.cc b/ortools/lp_data/lp_utils.cc index 9857e63ad4..91cdb0310d 100644 --- a/ortools/lp_data/lp_utils.cc +++ b/ortools/lp_data/lp_utils.cc @@ -104,19 +104,16 @@ Fractional InfinityNorm(const ColumnView &v) { } double Density(const DenseRow &row) { - if (row.empty()) - return 0.0; + if (row.empty()) return 0.0; int sum = 0.0; for (ColIndex col(0); col < row.size(); ++col) { - if (row[col] != Fractional(0.0)) - ++sum; + if (row[col] != Fractional(0.0)) ++sum; } return static_cast(sum) / row.size().value(); } void RemoveNearZeroEntries(Fractional threshold, DenseRow *row) { - if (threshold == Fractional(0.0)) - return; + if (threshold == Fractional(0.0)) return; for (ColIndex col(0); col < row->size(); ++col) { if (fabs((*row)[col]) < threshold) { (*row)[col] = Fractional(0.0); @@ -125,8 +122,7 @@ void RemoveNearZeroEntries(Fractional threshold, DenseRow *row) { } void RemoveNearZeroEntries(Fractional threshold, DenseColumn *column) { - if (threshold == Fractional(0.0)) - return; + if (threshold == Fractional(0.0)) return; for (RowIndex row(0); row < column->size(); ++row) { if (fabs((*column)[row]) < threshold) { (*column)[row] = Fractional(0.0); @@ -158,11 +154,10 @@ void SetSupportToFalse(const ColumnView &column, DenseBooleanColumn *b) { bool IsDominated(const ColumnView &column, const DenseColumn &radius) { for (const SparseColumn::Entry e : column) { DCHECK_GE(radius[e.row()], 0.0); - if (fabs(e.coefficient()) > radius[e.row()]) - return false; + if (fabs(e.coefficient()) > radius[e.row()]) return false; } return true; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/lp_utils.h b/ortools/lp_data/lp_utils.h index 9811ffffb5..ffc5eaf778 100644 --- a/ortools/lp_data/lp_utils.h +++ b/ortools/lp_data/lp_utils.h @@ -218,27 +218,26 @@ inline void ComputeNonZeros(const StrictITIVector &input, } // Returns true if the given Fractional container is all zeros. -template inline bool IsAllZero(const Container &input) { +template +inline bool IsAllZero(const Container &input) { for (Fractional value : input) { - if (value != 0.0) - return false; + if (value != 0.0) return false; } return true; } // Returns true if the given vector of bool is all false. -template bool IsAllFalse(const BoolVector &v) { - return std::all_of(v.begin(), v.end(), [](bool value) { - return !value; - }); +template +bool IsAllFalse(const BoolVector &v) { + return std::all_of(v.begin(), v.end(), [](bool value) { return !value; }); } // Permutes the given dense vector. It uses for this an all zero scratchpad. template -inline void -PermuteWithScratchpad(const Permutation &permutation, - StrictITIVector *zero_scratchpad, - StrictITIVector *input_output) { +inline void PermuteWithScratchpad( + const Permutation &permutation, + StrictITIVector *zero_scratchpad, + StrictITIVector *input_output) { DCHECK(IsAllZero(*zero_scratchpad)); const IndexType size = input_output->size(); zero_scratchpad->swap(*input_output); @@ -318,13 +317,13 @@ inline void ChangeSign(StrictITIVector *data) { // The numerical accuracy suffers however. If X is 1e100 and SumWithout(X) // should be 1e-100, then the value actually returned by SumWithout(X) is likely // to be wrong (by up to std::numeric_limits::epsilon() ^ 2). -template class SumWithOneMissing { -public: +template +class SumWithOneMissing { + public: SumWithOneMissing() : num_infinities_(0), sum_() {} void Add(Fractional x) { - if (num_infinities_ > 1) - return; + if (num_infinities_ > 1) return; if (IsFinite(x)) { sum_.Add(x); return; @@ -334,24 +333,21 @@ public: } Fractional Sum() const { - if (num_infinities_ > 0) - return Infinity(); + if (num_infinities_ > 0) return Infinity(); return sum_.Value(); } Fractional SumWithout(Fractional x) const { if (IsFinite(x)) { - if (num_infinities_ > 0) - return Infinity(); + if (num_infinities_ > 0) return Infinity(); return sum_.Value() - x; } DCHECK_EQ(Infinity(), x); - if (num_infinities_ > 1) - return Infinity(); + if (num_infinities_ > 1) return Infinity(); return sum_.Value(); } -private: + private: Fractional Infinity() const { return supported_infinity_is_positive ? kInfinity : -kInfinity; } @@ -359,12 +355,12 @@ private: // Count how many times Add() was called with an infinite value. The count is // stopped at 2 to be a bit faster. int num_infinities_; - KahanSum sum_; // stripped of all the infinite values. + KahanSum sum_; // stripped of all the infinite values. }; typedef SumWithOneMissing SumWithPositiveInfiniteAndOneMissing; typedef SumWithOneMissing SumWithNegativeInfiniteAndOneMissing; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_LP_UTILS_H_ +#endif // OR_TOOLS_LP_DATA_LP_UTILS_H_ diff --git a/ortools/lp_data/matrix_scaler.cc b/ortools/lp_data/matrix_scaler.cc index 51cbca9615..2f475a0bed 100644 --- a/ortools/lp_data/matrix_scaler.cc +++ b/ortools/lp_data/matrix_scaler.cc @@ -71,18 +71,18 @@ std::string SparseMatrixScaler::DebugInformationString() const { Fractional min_magnitude; matrix_->ComputeMinAndMaxMagnitudes(&min_magnitude, &max_magnitude); const Fractional dynamic_range = max_magnitude / min_magnitude; - std::string output = - absl::StrFormat("Min magnitude = %g, max magnitude = %g\n" - "Dynamic range = %g\n" - "Variance = %g\n" - "Minimum row scale = %g, maximum row scale = %g\n" - "Minimum col scale = %g, maximum col scale = %g\n", - min_magnitude, max_magnitude, dynamic_range, - VarianceOfAbsoluteValueOfNonZeros(), - *std::min_element(row_scale_.begin(), row_scale_.end()), - *std::max_element(row_scale_.begin(), row_scale_.end()), - *std::min_element(col_scale_.begin(), col_scale_.end()), - *std::max_element(col_scale_.begin(), col_scale_.end())); + std::string output = absl::StrFormat( + "Min magnitude = %g, max magnitude = %g\n" + "Dynamic range = %g\n" + "Variance = %g\n" + "Minimum row scale = %g, maximum row scale = %g\n" + "Minimum col scale = %g, maximum col scale = %g\n", + min_magnitude, max_magnitude, dynamic_range, + VarianceOfAbsoluteValueOfNonZeros(), + *std::min_element(row_scale_.begin(), row_scale_.end()), + *std::max_element(row_scale_.begin(), row_scale_.end()), + *std::min_element(col_scale_.begin(), col_scale_.end()), + *std::max_element(col_scale_.begin(), col_scale_.end())); return output; } @@ -99,7 +99,7 @@ void SparseMatrixScaler::Scale(GlopParameters::ScalingAlgorithm method) { matrix_->ComputeMinAndMaxMagnitudes(&min_magnitude, &max_magnitude); if (min_magnitude == 0.0) { DCHECK_EQ(0.0, max_magnitude); - return; // Null matrix: nothing to do. + return; // Null matrix: nothing to do. } VLOG(1) << "Before scaling:\n" << DebugInformationString(); if (method == GlopParameters::LINEAR_PROGRAM) { @@ -165,7 +165,7 @@ ColIndex CreateOrGetScaleIndex( } return (*scale_var_indices)[num]; } -} // anonymous namespace +} // anonymous namespace void SparseMatrixScaler::ScaleRowVector(bool up, DenseRow *row_vector) const { DCHECK(row_vector != nullptr); @@ -182,7 +182,7 @@ Fractional SparseMatrixScaler::VarianceOfAbsoluteValueOfNonZeros() const { DCHECK(matrix_ != nullptr); Fractional sigma_square(0.0); Fractional sigma_abs(0.0); - double n = 0.0; // n is used in a calculation involving doubles. + double n = 0.0; // n is used in a calculation involving doubles. const ColIndex num_cols = matrix_->num_cols(); for (ColIndex col(0); col < num_cols; ++col) { for (const SparseColumn::Entry e : matrix_->column(col)) { @@ -194,8 +194,7 @@ Fractional SparseMatrixScaler::VarianceOfAbsoluteValueOfNonZeros() const { } } } - if (n == 0.0) - return 0.0; + if (n == 0.0) return 0.0; // Since we know all the population (the non-zeros) and we are not using a // sample, the variance is defined as below. // For an explanation, see: @@ -473,5 +472,5 @@ Status SparseMatrixScaler::LPScale() { } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/matrix_scaler.h b/ortools/lp_data/matrix_scaler.h index fcf6fc72f5..50b1146310 100644 --- a/ortools/lp_data/matrix_scaler.h +++ b/ortools/lp_data/matrix_scaler.h @@ -77,7 +77,7 @@ namespace glop { class SparseMatrix; class SparseMatrixScaler { -public: + public: SparseMatrixScaler(); // Initializes the object with the SparseMatrix passed as argument. @@ -148,7 +148,7 @@ public: // scaled. Helper function to Scale(). ColIndex EquilibrateColumns(); -private: + private: // Convert the matrix to be scaled into a linear program. void GenerateLinearProgram(LinearProgram *); @@ -188,7 +188,7 @@ private: DISALLOW_COPY_AND_ASSIGN(SparseMatrixScaler); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_MATRIX_SCALER_H_ +#endif // OR_TOOLS_LP_DATA_MATRIX_SCALER_H_ diff --git a/ortools/lp_data/matrix_utils.cc b/ortools/lp_data/matrix_utils.cc index e93dddd46e..79c55a21fe 100644 --- a/ortools/lp_data/matrix_utils.cc +++ b/ortools/lp_data/matrix_utils.cc @@ -31,13 +31,11 @@ bool AreColumnsProportional(const SparseColumn &a, const SparseColumn &b, Fractional tolerance) { DCHECK(a.IsCleanedUp()); DCHECK(b.IsCleanedUp()); - if (a.num_entries() != b.num_entries()) - return false; + if (a.num_entries() != b.num_entries()) return false; Fractional multiple = 0.0; bool a_is_larger = true; for (const EntryIndex i : a.AllEntryIndices()) { - if (a.EntryRow(i) != b.EntryRow(i)) - return false; + if (a.EntryRow(i) != b.EntryRow(i)) return false; const Fractional coeff_a = a.EntryCoefficient(i); const Fractional coeff_b = b.EntryCoefficient(i); if (multiple == 0.0) { @@ -45,11 +43,9 @@ bool AreColumnsProportional(const SparseColumn &a, const SparseColumn &b, multiple = a_is_larger ? coeff_a / coeff_b : coeff_b / coeff_a; } else { if (a_is_larger) { - if (std::abs(coeff_a / coeff_b - multiple) > tolerance) - return false; + if (std::abs(coeff_a / coeff_b - multiple) > tolerance) return false; } else { - if (std::abs(coeff_b / coeff_a - multiple) > tolerance) - return false; + if (std::abs(coeff_b / coeff_a - multiple) > tolerance) return false; } } } @@ -81,8 +77,7 @@ struct ColumnFingerprint { // - Their double fingerprints are close to each other. bool AreProportionalCandidates(ColumnFingerprint a, ColumnFingerprint b, Fractional tolerance) { - if (a.hash != b.hash) - return false; + if (a.hash != b.hash) return false; return std::abs(a.value - b.value) < tolerance; } @@ -115,7 +110,7 @@ ColumnFingerprint ComputeFingerprint(ColIndex col, const SparseColumn &column) { inverse_dynamic_range + scaled_average); } -} // namespace +} // namespace ColMapping FindProportionalColumns(const SparseMatrix &matrix, Fractional tolerance) { @@ -135,12 +130,10 @@ ColMapping FindProportionalColumns(const SparseMatrix &matrix, // compares columns with a close-enough fingerprint. for (int i = 0; i < fingerprints.size(); ++i) { const ColIndex col_a = fingerprints[i].col; - if (mapping[col_a] != kInvalidCol) - continue; + if (mapping[col_a] != kInvalidCol) continue; for (int j = i + 1; j < fingerprints.size(); ++j) { const ColIndex col_b = fingerprints[j].col; - if (mapping[col_b] != kInvalidCol) - continue; + if (mapping[col_b] != kInvalidCol) continue; // Note that we use the same tolerance for the fingerprints. // TODO(user): Derive precise bounds on what this tolerance should be so @@ -160,8 +153,7 @@ ColMapping FindProportionalColumns(const SparseMatrix &matrix, // column. To achieve this, the current representative is used as a pointer // to the new one, a bit like in an union find algorithm. for (ColIndex col(0); col < num_cols; ++col) { - if (mapping[col] == kInvalidCol) - continue; + if (mapping[col] == kInvalidCol) continue; const ColIndex new_representative = mapping[mapping[col]]; if (new_representative != kInvalidCol) { mapping[col] = new_representative; @@ -176,21 +168,16 @@ ColMapping FindProportionalColumns(const SparseMatrix &matrix, return mapping; } -ColMapping -FindProportionalColumnsUsingSimpleAlgorithm(const SparseMatrix &matrix, - Fractional tolerance) { +ColMapping FindProportionalColumnsUsingSimpleAlgorithm( + const SparseMatrix &matrix, Fractional tolerance) { const ColIndex num_cols = matrix.num_cols(); ColMapping mapping(num_cols, kInvalidCol); for (ColIndex col_a(0); col_a < num_cols; ++col_a) { - if (matrix.column(col_a).IsEmpty()) - continue; - if (mapping[col_a] != kInvalidCol) - continue; + if (matrix.column(col_a).IsEmpty()) continue; + if (mapping[col_a] != kInvalidCol) continue; for (ColIndex col_b(col_a + 1); col_b < num_cols; ++col_b) { - if (matrix.column(col_b).IsEmpty()) - continue; - if (mapping[col_b] != kInvalidCol) - continue; + if (matrix.column(col_b).IsEmpty()) continue; + if (mapping[col_b] != kInvalidCol) continue; if (AreColumnsProportional(matrix.column(col_a), matrix.column(col_b), tolerance)) { mapping[col_b] = col_a; @@ -243,8 +230,7 @@ bool AreFirstColumnsAndRowsExactlyEquals(RowIndex num_rows, ColIndex num_cols, bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix) { DCHECK(matrix.IsCleanedUp()); - if (matrix.num_rows().value() > matrix.num_cols().value()) - return false; + if (matrix.num_rows().value() > matrix.num_cols().value()) return false; const ColIndex first_identity_col = matrix.num_cols() - RowToColIndex(matrix.num_rows()); for (ColIndex col = first_identity_col; col < matrix.num_cols(); ++col) { @@ -257,5 +243,5 @@ bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix) { return true; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/matrix_utils.h b/ortools/lp_data/matrix_utils.h index 2745547162..9e384e7a74 100644 --- a/ortools/lp_data/matrix_utils.h +++ b/ortools/lp_data/matrix_utils.h @@ -39,9 +39,8 @@ ColMapping FindProportionalColumns(const SparseMatrix &matrix, // A simple version of FindProportionalColumns() that compares all the columns // pairs one by one. This is slow, but here for reference. The complexity is // O(num_cols * num_entries). -ColMapping - FindProportionalColumnsUsingSimpleAlgorithm(const SparseMatrix &matrix, - Fractional tolerance); +ColMapping FindProportionalColumnsUsingSimpleAlgorithm( + const SparseMatrix &matrix, Fractional tolerance); // Returns true iff the two given matrices have exactly the same first num_rows // entries on the first num_cols columns. The two given matrices must be ordered @@ -53,7 +52,7 @@ bool AreFirstColumnsAndRowsExactlyEquals(RowIndex num_rows, ColIndex num_cols, // Returns true iff the rightmost square matrix is an identity matrix. bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix); -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_MATRIX_UTILS_H_ +#endif // OR_TOOLS_LP_DATA_MATRIX_UTILS_H_ diff --git a/ortools/lp_data/model_reader.cc b/ortools/lp_data/model_reader.cc index 25accfb73e..6ffee483ca 100644 --- a/ortools/lp_data/model_reader.cc +++ b/ortools/lp_data/model_reader.cc @@ -63,5 +63,5 @@ bool LoadLinearProgramFromModelOrRequest(const std::string &input_file_path, return false; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/model_reader.h b/ortools/lp_data/model_reader.h index 981040adbf..d28bd8cce2 100644 --- a/ortools/lp_data/model_reader.h +++ b/ortools/lp_data/model_reader.h @@ -29,7 +29,7 @@ bool LoadMPModelProtoFromModelOrRequest(const std::string &input_file_path, bool LoadLinearProgramFromModelOrRequest(const std::string &input_file_path, LinearProgram *linear_program); -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_MODEL_READER_H_ +#endif // OR_TOOLS_LP_DATA_MODEL_READER_H_ diff --git a/ortools/lp_data/mps_reader.cc b/ortools/lp_data/mps_reader.cc index ddec959cdc..e8cbaefee0 100644 --- a/ortools/lp_data/mps_reader.cc +++ b/ortools/lp_data/mps_reader.cc @@ -24,7 +24,7 @@ namespace operations_research { namespace glop { class MPSReaderImpl { -public: + public: MPSReaderImpl(); // Parses instance from a file. We currently support LinearProgram and @@ -33,7 +33,7 @@ public: absl::Status ParseFile(const std::string &file_name, Data *data, MPSReader::Form form); -private: + private: // Number of fields in one line of MPS file. static const int kNumFields; @@ -237,11 +237,12 @@ private: // Data templates. -template class DataWrapper { -}; +template +class DataWrapper {}; -template <> class DataWrapper { -public: +template <> +class DataWrapper { + public: explicit DataWrapper(LinearProgram *data) { data_ = data; } void SetUp() { @@ -309,12 +310,13 @@ public: void CleanUp() { data_->CleanUp(); } -private: + private: LinearProgram *data_; }; -template <> class DataWrapper { -public: +template <> +class DataWrapper { + public: explicit DataWrapper(MPModelProto *data) { data_ = data; } void SetUp() { data_->Clear(); } @@ -325,8 +327,7 @@ public: int FindOrCreateConstraint(const std::string &name) { const auto it = constraint_indices_by_name_.find(name); - if (it != constraint_indices_by_name_.end()) - return it->second; + if (it != constraint_indices_by_name_.end()) return it->second; const int index = data_->constraint_size(); MPConstraintProto *const constraint = data_->add_constraint(); @@ -362,8 +363,7 @@ public: int FindOrCreateVariable(const std::string &name) { const auto it = variable_indices_by_name_.find(name); - if (it != variable_indices_by_name_.end()) - return it->second; + if (it != variable_indices_by_name_.end()) return it->second; const int index = data_->variable_size(); MPVariableProto *const variable = data_->add_variable(); @@ -420,7 +420,7 @@ public: constraints_to_delete_); } -private: + private: MPModelProto *data_; absl::flat_hash_map variable_indices_by_name_; @@ -462,7 +462,7 @@ absl::Status MPSReaderImpl::ProcessLine(const std::string &line, ++line_num_; line_ = line; if (IsCommentOrBlank()) { - return absl::OkStatus(); // Skip blank lines and comments. + return absl::OkStatus(); // Skip blank lines and comments. } if (!free_form_ && line_.find('\t') != std::string::npos) { return InvalidArgumentError("File contains tabs."); @@ -511,30 +511,30 @@ absl::Status MPSReaderImpl::ProcessLine(const std::string &line, } RETURN_IF_ERROR(SplitLineIntoFields()); switch (section_) { - case NAME: - return InvalidArgumentError("Second NAME field."); - case OBJSENSE: - return ProcessObjectiveSenseSection(data); - case ROWS: - return ProcessRowsSection(/*is_lazy=*/ false, data); - case LAZYCONS: - return ProcessRowsSection(/*is_lazy=*/ true, data); - case COLUMNS: - return ProcessColumnsSection(data); - case RHS: - return ProcessRhsSection(data); - case RANGES: - return ProcessRangesSection(data); - case BOUNDS: - return ProcessBoundsSection(data); - case INDICATORS: - return ProcessIndicatorsSection(data); - case SOS: - return ProcessSosSection(); - case ENDATA: // Do nothing. - break; - default: - return InvalidArgumentError("Unknown section."); + case NAME: + return InvalidArgumentError("Second NAME field."); + case OBJSENSE: + return ProcessObjectiveSenseSection(data); + case ROWS: + return ProcessRowsSection(/*is_lazy=*/false, data); + case LAZYCONS: + return ProcessRowsSection(/*is_lazy=*/true, data); + case COLUMNS: + return ProcessColumnsSection(data); + case RHS: + return ProcessRhsSection(data); + case RANGES: + return ProcessRangesSection(data); + case BOUNDS: + return ProcessBoundsSection(data); + case INDICATORS: + return ProcessIndicatorsSection(data); + case SOS: + return ProcessSosSection(); + case ENDATA: // Do nothing. + break; + default: + return InvalidArgumentError("Unknown section."); } return absl::OkStatus(); } @@ -544,7 +544,7 @@ absl::Status MPSReaderImpl::ProcessObjectiveSenseSection(DataWrapper *data) { if (fields_.size() != 1 && fields_[0] != "MIN" && fields_[0] != "MAX") { return InvalidArgumentError("Expected objective sense (MAX or MIN)."); } - data->SetObjectiveDirection(/*maximize=*/ fields_[0] == "MAX"); + data->SetObjectiveDirection(/*maximize=*/fields_[0] == "MAX"); return absl::OkStatus(); } @@ -571,26 +571,25 @@ absl::Status MPSReaderImpl::ProcessRowsSection(bool is_lazy, ++num_unconstrained_rows_; } const int row = data->FindOrCreateConstraint(row_name); - if (is_lazy) - data->SetIsLazy(row); + if (is_lazy) data->SetIsLazy(row); // The initial row range is [0, 0]. We encode the type in the range by // setting one of the bounds to +/- infinity. switch (row_type) { - case LESS_THAN: - data->SetConstraintBounds(row, -kInfinity, - data->ConstraintUpperBound(row)); - break; - case GREATER_THAN: - data->SetConstraintBounds(row, data->ConstraintLowerBound(row), - kInfinity); - break; - case NONE: - data->SetConstraintBounds(row, -kInfinity, kInfinity); - break; - case EQUALITY: - default: - break; + case LESS_THAN: + data->SetConstraintBounds(row, -kInfinity, + data->ConstraintUpperBound(row)); + break; + case GREATER_THAN: + data->SetConstraintBounds(row, data->ConstraintLowerBound(row), + kInfinity); + break; + case NONE: + data->SetConstraintBounds(row, -kInfinity, kInfinity); + break; + case EQUALITY: + default: + break; } } return absl::OkStatus(); @@ -745,8 +744,7 @@ absl::Status MPSReaderImpl::StoreCoefficient(int col, if (value == kInfinity || value == -kInfinity) { return InvalidArgumentError("Constraint coefficients cannot be infinity."); } - if (value == 0.0) - return absl::OkStatus(); + if (value == 0.0) return absl::OkStatus(); if (row_name == objective_name_) { data->SetObjectiveCoefficient(col, value); } else { @@ -760,8 +758,7 @@ template absl::Status MPSReaderImpl::StoreRightHandSide(const std::string &row_name, const std::string &row_value, DataWrapper *data) { - if (row_name.empty()) - return absl::OkStatus(); + if (row_name.empty()) return absl::OkStatus(); if (row_name != objective_name_) { const int row = data->FindOrCreateConstraint(row_name); @@ -784,8 +781,7 @@ template absl::Status MPSReaderImpl::StoreRange(const std::string &row_name, const std::string &range_value, DataWrapper *data) { - if (row_name.empty()) - return absl::OkStatus(); + if (row_name.empty()) return absl::OkStatus(); const int row = data->FindOrCreateConstraint(row_name); Fractional range; @@ -840,42 +836,42 @@ absl::Status MPSReaderImpl::StoreBound(const std::string &bound_type_mnemonic, upper_bound = kInfinity; } switch (bound_type_id) { - case LOWER_BOUND: { - ASSIGN_OR_RETURN(lower_bound, GetDoubleFromString(bound_value)); - // LI with the value 0.0 specifies general integers with no upper bound. - if (bound_type_mnemonic == "LI" && lower_bound == 0.0) { - upper_bound = kInfinity; + case LOWER_BOUND: { + ASSIGN_OR_RETURN(lower_bound, GetDoubleFromString(bound_value)); + // LI with the value 0.0 specifies general integers with no upper bound. + if (bound_type_mnemonic == "LI" && lower_bound == 0.0) { + upper_bound = kInfinity; + } + break; } - break; - } - case UPPER_BOUND: { - ASSIGN_OR_RETURN(upper_bound, GetDoubleFromString(bound_value)); - break; - } - case FIXED_VARIABLE: { - ASSIGN_OR_RETURN(lower_bound, GetDoubleFromString(bound_value)); - upper_bound = lower_bound; - break; - } - case FREE_VARIABLE: - lower_bound = -kInfinity; - upper_bound = +kInfinity; - break; - case NEGATIVE: - lower_bound = -kInfinity; - upper_bound = Fractional(0.0); - break; - case POSITIVE: - lower_bound = Fractional(0.0); - upper_bound = +kInfinity; - break; - case BINARY: - lower_bound = Fractional(0.0); - upper_bound = Fractional(1.0); - break; - case UNKNOWN_BOUND_TYPE: - default: - return InvalidArgumentError("Unknown bound type."); + case UPPER_BOUND: { + ASSIGN_OR_RETURN(upper_bound, GetDoubleFromString(bound_value)); + break; + } + case FIXED_VARIABLE: { + ASSIGN_OR_RETURN(lower_bound, GetDoubleFromString(bound_value)); + upper_bound = lower_bound; + break; + } + case FREE_VARIABLE: + lower_bound = -kInfinity; + upper_bound = +kInfinity; + break; + case NEGATIVE: + lower_bound = -kInfinity; + upper_bound = Fractional(0.0); + break; + case POSITIVE: + lower_bound = Fractional(0.0); + upper_bound = +kInfinity; + break; + case BINARY: + lower_bound = Fractional(0.0); + upper_bound = Fractional(1.0); + break; + case UNKNOWN_BOUND_TYPE: + default: + return InvalidArgumentError("Unknown bound type."); } is_binary_by_default_[col] = false; data->SetVariableBounds(col, lower_bound, upper_bound); @@ -883,16 +879,23 @@ absl::Status MPSReaderImpl::StoreBound(const std::string &bound_type_mnemonic, } const int MPSReaderImpl::kNumFields = 6; -const int MPSReaderImpl::kFieldStartPos[kNumFields] = { 1, 4, 14, 24, 39, 49 }; -const int MPSReaderImpl::kFieldLength[kNumFields] = { 2, 8, 8, 12, 8, 12 }; -const int MPSReaderImpl::kSpacePos[12] = { 12, 13, 22, 23, 36, 37, 38, 47, 48, - 61, 62, 63 }; +const int MPSReaderImpl::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49}; +const int MPSReaderImpl::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12}; +const int MPSReaderImpl::kSpacePos[12] = {12, 13, 22, 23, 36, 37, + 38, 47, 48, 61, 62, 63}; MPSReaderImpl::MPSReaderImpl() - : free_form_(true), fields_(kNumFields), section_(UNKNOWN_SECTION), - section_name_to_id_map_(), row_name_to_id_map_(), bound_name_to_id_map_(), - integer_type_names_set_(), line_num_(0), line_(), - in_integer_section_(false), num_unconstrained_rows_(0) { + : free_form_(true), + fields_(kNumFields), + section_(UNKNOWN_SECTION), + section_name_to_id_map_(), + row_name_to_id_map_(), + bound_name_to_id_map_(), + integer_type_names_set_(), + line_num_(0), + line_(), + in_integer_section_(false), + num_unconstrained_rows_(0) { section_name_to_id_map_["*"] = COMMENT; section_name_to_id_map_["NAME"] = NAME; section_name_to_id_map_["OBJSENSE"] = OBJSENSE; @@ -940,10 +943,8 @@ void MPSReaderImpl::DisplaySummary() { bool MPSReaderImpl::IsFixedFormat() { for (const int i : kSpacePos) { - if (i >= line_.length()) - break; - if (line_[i] != ' ') - return false; + if (i >= line_.length()) break; + if (line_[i] != ' ') return false; } return true; } @@ -997,8 +998,8 @@ bool MPSReaderImpl::IsCommentOrBlank() const { return true; } -absl::StatusOr -MPSReaderImpl::GetDoubleFromString(const std::string &str) { +absl::StatusOr MPSReaderImpl::GetDoubleFromString( + const std::string &str) { double result; if (!absl::SimpleAtod(str, &result)) { return InvalidArgumentError( @@ -1023,14 +1024,14 @@ absl::Status MPSReaderImpl::ProcessSosSection() { return InvalidArgumentError("Section SOS currently not supported."); } -absl::Status -MPSReaderImpl::InvalidArgumentError(const std::string &error_message) { +absl::Status MPSReaderImpl::InvalidArgumentError( + const std::string &error_message) { return AppendLineToError(absl::InvalidArgumentError(error_message)); } absl::Status MPSReaderImpl::AppendLineToError(const absl::Status &status) { - return util::StatusBuilder(status).SetAppend() << " Line " << line_num_ - << ": \"" << line_ << "\"."; + return util::StatusBuilder(status).SetAppend() + << " Line " << line_num_ << ": \"" << line_ << "\"."; } // Parses instance from a file. @@ -1044,5 +1045,5 @@ absl::Status MPSReader::ParseFile(const std::string &file_name, return MPSReaderImpl().ParseFile(file_name, data, form); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/mps_reader.h b/ortools/lp_data/mps_reader.h index fc0bbe31dc..a37555945d 100644 --- a/ortools/lp_data/mps_reader.h +++ b/ortools/lp_data/mps_reader.h @@ -41,7 +41,7 @@ #include "ortools/base/int_type.h" #include "ortools/base/int_type_indexed_vector.h" #include "ortools/base/logging.h" -#include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL +#include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL #include "ortools/base/map_util.h" #include "ortools/base/protobuf_util.h" #include "ortools/base/status_macros.h" @@ -58,12 +58,8 @@ namespace glop { // in the given Data class. class MPSReader { -public: - enum Form { - AUTO_DETECT, - FREE, - FIXED - }; + public: + enum Form { AUTO_DETECT, FREE, FIXED }; // Parses instance from a file. absl::Status ParseFile(const std::string &file_name, LinearProgram *data, @@ -73,7 +69,7 @@ public: Form form = AUTO_DETECT); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_MPS_READER_H_ +#endif // OR_TOOLS_LP_DATA_MPS_READER_H_ diff --git a/ortools/lp_data/permutation.h b/ortools/lp_data/permutation.h index 943ccf668c..bc5682834b 100644 --- a/ortools/lp_data/permutation.h +++ b/ortools/lp_data/permutation.h @@ -39,8 +39,9 @@ namespace glop { // // So to be clear, if P and Q are permutation matrices, the matrix P.A.Q^{-1} // is the image of A through the row permutation P and column permutation Q. -template class Permutation { -public: +template +class Permutation { + public: Permutation() : perm_() {} explicit Permutation(IndexType size) : perm_(size.value(), IndexType(0)) {} @@ -83,7 +84,7 @@ public: // is -1. (Remembering hint: the signature of a swap (a 2-cycle) is -1.) int ComputeSignature() const; -private: + private: gtl::ITIVector perm_; DISALLOW_COPY_AND_ASSIGN(Permutation); @@ -111,9 +112,8 @@ void ApplyInversePermutation(const Permutation &perm, // Specialization of ApplyPermutation(): apply a column permutation to a // row-indexed vector v. template -void -ApplyColumnPermutationToRowIndexedVector(const Permutation &col_perm, - RowIndexedVector *v) { +void ApplyColumnPermutationToRowIndexedVector( + const Permutation &col_perm, RowIndexedVector *v) { RowIndexedVector temp_v = *v; ApplyPermutation(col_perm, temp_v, v); } @@ -140,12 +140,14 @@ void Permutation::PopulateFromIdentity() { } } -template void Permutation::PopulateRandomly() { +template +void Permutation::PopulateRandomly() { PopulateFromIdentity(); std::shuffle(perm_.begin(), perm_.end()); } -template bool Permutation::Check() const { +template +bool Permutation::Check() const { const size_t size = perm_.size(); gtl::ITIVector visited(size, false); for (IndexType i(0); i < size; ++i) { @@ -190,8 +192,7 @@ void ApplyPermutation(const Permutation &perm, const ITIVectorType &b, ITIVectorType *result) { RETURN_IF_NULL(result); const IndexType size(perm.size()); - if (size == 0) - return; + if (size == 0) return; DCHECK_EQ(size.value(), b.size().value()); result->resize(b.size(), /*whatever junk value*/ b.back()); for (IndexType i(0); i < size; ++i) { @@ -206,8 +207,7 @@ void ApplyInversePermutation(const Permutation &perm, const ITIVectorType &b, ITIVectorType *result) { RETURN_IF_NULL(result); const IndexType size(perm.size().value()); - if (size == 0) - return; + if (size == 0) return; DCHECK_EQ(size.value(), b.size().value()); result->resize(b.size(), /*whatever junk value*/ b.back()); for (IndexType i(0); i < size; ++i) { @@ -217,7 +217,7 @@ void ApplyInversePermutation(const Permutation &perm, } } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_PERMUTATION_H_ +#endif // OR_TOOLS_LP_DATA_PERMUTATION_H_ diff --git a/ortools/lp_data/proto_utils.cc b/ortools/lp_data/proto_utils.cc index 05d394833b..6613bd3bac 100644 --- a/ortools/lp_data/proto_utils.cc +++ b/ortools/lp_data/proto_utils.cc @@ -81,5 +81,5 @@ void MPModelProtoToLinearProgram(const MPModelProto &input, output->CleanUp(); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/proto_utils.h b/ortools/lp_data/proto_utils.h index ea78909077..25d3773968 100644 --- a/ortools/lp_data/proto_utils.h +++ b/ortools/lp_data/proto_utils.h @@ -28,7 +28,7 @@ void LinearProgramToMPModelProto(const LinearProgram &input, void MPModelProtoToLinearProgram(const MPModelProto &input, LinearProgram *output); -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_PROTO_UTILS_H_ +#endif // OR_TOOLS_LP_DATA_PROTO_UTILS_H_ diff --git a/ortools/lp_data/scattered_vector.h b/ortools/lp_data/scattered_vector.h index 43e7600953..eb0ff8516f 100644 --- a/ortools/lp_data/scattered_vector.h +++ b/ortools/lp_data/scattered_vector.h @@ -30,8 +30,9 @@ namespace glop { // A class representing an entry of a scattered vector. The i-th nonzero // element of the vector is assumed to be located at indices[i] and its value is // coefficients[indices[i]], i.e., coefficients is a dense array. -template class ScatteredVectorEntry { -public: +template +class ScatteredVectorEntry { + public: using Index = IndexType; Index index() const { return index_[i_.value()]; } @@ -39,7 +40,7 @@ public: return coefficient_[index_[i_.value()].value()]; } -protected: + protected: ScatteredVectorEntry(const Index *indices, const Fractional *coefficients, EntryIndex i) : i_(i), index_(indices), coefficient_(coefficients) {} @@ -116,10 +117,9 @@ struct ScatteredVector { // Returns true if it is more advantageous to use a dense iteration rather // than using the non-zeros positions. - bool - ShouldUseDenseIteration(double ratio_for_using_dense_representation) const { - if (non_zeros.empty()) - return true; + bool ShouldUseDenseIteration( + double ratio_for_using_dense_representation) const { + if (non_zeros.empty()) return true; return static_cast(non_zeros.size()) > ratio_for_using_dense_representation * static_cast(values.size().value()); @@ -145,8 +145,7 @@ struct ScatteredVector { // Update the is_non_zero vector to be consistent with the non_zeros vector. void RepopulateSparseMask() { ClearSparseMask(); - for (const Index index : non_zeros) - is_non_zero[index] = true; + for (const Index index : non_zeros) is_non_zero[index] = true; } // If the proportion of non-zero entries is too large, clears the vector of @@ -165,22 +164,22 @@ struct ScatteredVector { // Specializations used in the code. class ScatteredColumnEntry : public ScatteredVectorEntry { -public: + public: // Returns the row of the current entry. RowIndex row() const { return index(); } -protected: + protected: ScatteredColumnEntry(const RowIndex *indices, const Fractional *coefficients, EntryIndex i) : ScatteredVectorEntry(indices, coefficients, i) {} }; class ScatteredRowEntry : public ScatteredVectorEntry { -public: + public: // Returns the column of the current entry. ColIndex column() const { return index(); } -protected: + protected: ScatteredRowEntry(const ColIndex *indices, const Fractional *coefficients, EntryIndex i) : ScatteredVectorEntry(indices, coefficients, i) {} @@ -190,10 +189,8 @@ using ScatteredColumnIterator = VectorIterator; using ScatteredRowIterator = VectorIterator; struct ScatteredColumn - : public ScatteredVector { -}; -struct ScatteredRow : public ScatteredVector { -}; + : public ScatteredVector {}; +struct ScatteredRow : public ScatteredVector {}; inline const ScatteredRow &TransposedView(const ScatteredColumn &c) { return reinterpret_cast(c); @@ -202,7 +199,7 @@ inline const ScatteredColumn &TransposedView(const ScatteredRow &r) { return reinterpret_cast(r); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_ +#endif // OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_ diff --git a/ortools/lp_data/sparse.cc b/ortools/lp_data/sparse.cc index b21fa48a4c..486e881889 100644 --- a/ortools/lp_data/sparse.cc +++ b/ortools/lp_data/sparse.cc @@ -27,7 +27,8 @@ namespace { using ::util::Reverse; -template EntryIndex ComputeNumEntries(const Matrix &matrix) { +template +EntryIndex ComputeNumEntries(const Matrix &matrix) { EntryIndex num_entries(0); const ColIndex num_cols(matrix.num_cols()); for (ColIndex col(0); col < num_cols; ++col) { @@ -78,7 +79,7 @@ Fractional ComputeInfinityNormTemplate(const Matrix &matrix) { return norm; } -} // namespace +} // namespace // -------------------------------------------------------- // SparseMatrix @@ -126,8 +127,7 @@ bool SparseMatrix::CheckNoDuplicates() const { DenseBooleanColumn boolean_column; const ColIndex num_cols(columns_.size()); for (ColIndex col(0); col < num_cols; ++col) { - if (!columns_[col].CheckNoDuplicates(&boolean_column)) - return false; + if (!columns_[col].CheckNoDuplicates(&boolean_column)) return false; } return true; } @@ -135,8 +135,7 @@ bool SparseMatrix::CheckNoDuplicates() const { bool SparseMatrix::IsCleanedUp() const { const ColIndex num_cols(columns_.size()); for (ColIndex col(0); col < num_cols; ++col) { - if (!columns_[col].IsCleanedUp()) - return false; + if (!columns_[col].IsCleanedUp()) return false; } return true; } @@ -275,8 +274,7 @@ void SparseMatrix::PopulateFromProduct(const SparseMatrix &a, } void SparseMatrix::DeleteColumns(const DenseBooleanRow &columns_to_delete) { - if (columns_to_delete.empty()) - return; + if (columns_to_delete.empty()) return; ColIndex new_index(0); const ColIndex num_cols = columns_.size(); for (ColIndex col(0); col < num_cols; ++col) { @@ -455,8 +453,8 @@ void CompactSparseMatrix::PopulateFromMatrixView(const MatrixView &input) { starts_[input.num_cols()] = index; } -void -CompactSparseMatrix::PopulateFromTranspose(const CompactSparseMatrix &input) { +void CompactSparseMatrix::PopulateFromTranspose( + const CompactSparseMatrix &input) { num_cols_ = RowToColIndex(input.num_rows()); num_rows_ = ColToRowIndex(input.num_cols()); @@ -539,9 +537,8 @@ ColIndex CompactSparseMatrix::AddDenseColumn(const DenseColumn &dense_column) { return AddDenseColumnPrefix(dense_column, RowIndex(0)); } -ColIndex -CompactSparseMatrix::AddDenseColumnPrefix(const DenseColumn &dense_column, - RowIndex start) { +ColIndex CompactSparseMatrix::AddDenseColumnPrefix( + const DenseColumn &dense_column, RowIndex start) { const RowIndex num_rows(dense_column.size()); for (RowIndex row(start); row < num_rows; ++row) { if (dense_column[row] != 0.0) { @@ -556,8 +553,7 @@ CompactSparseMatrix::AddDenseColumnPrefix(const DenseColumn &dense_column, ColIndex CompactSparseMatrix::AddDenseColumnWithNonZeros( const DenseColumn &dense_column, const std::vector &non_zeros) { - if (non_zeros.empty()) - return AddDenseColumn(dense_column); + if (non_zeros.empty()) return AddDenseColumn(dense_column); for (const RowIndex row : non_zeros) { const Fractional value = dense_column[row]; if (value != 0.0) { @@ -695,11 +691,9 @@ void TriangularMatrix::PopulateFromTriangularSparseMatrix( bool TriangularMatrix::IsLowerTriangular() const { for (ColIndex col(0); col < num_cols_; ++col) { - if (diagonal_coefficients_[col] == 0.0) - return false; + if (diagonal_coefficients_[col] == 0.0) return false; for (EntryIndex i : Column(col)) { - if (EntryRow(i) <= ColToRowIndex(col)) - return false; + if (EntryRow(i) <= ColToRowIndex(col)) return false; } } return true; @@ -707,11 +701,9 @@ bool TriangularMatrix::IsLowerTriangular() const { bool TriangularMatrix::IsUpperTriangular() const { for (ColIndex col(0); col < num_cols_; ++col) { - if (diagonal_coefficients_[col] == 0.0) - return false; + if (diagonal_coefficients_[col] == 0.0) return false; for (EntryIndex i : Column(col)) { - if (EntryRow(i) >= ColToRowIndex(col)) - return false; + if (EntryRow(i) >= ColToRowIndex(col)) return false; } } return true; @@ -763,8 +755,7 @@ void TriangularMatrix::LowerSolveStartingAtInternal(ColIndex start, const ColIndex end = diagonal_coefficients_.size(); for (ColIndex col(begin); col < end; ++col) { const Fractional value = (*rhs)[ColToRowIndex(col)]; - if (value == 0.0) - continue; + if (value == 0.0) continue; const Fractional coeff = diagonal_of_ones ? value : value / diagonal_coefficients_[col]; if (!diagonal_of_ones) { @@ -790,8 +781,7 @@ void TriangularMatrix::UpperSolveInternal(DenseColumn *rhs) const { const ColIndex end = first_non_identity_column_; for (ColIndex col(diagonal_coefficients_.size() - 1); col >= end; --col) { const Fractional value = (*rhs)[ColToRowIndex(col)]; - if (value == 0.0) - continue; + if (value == 0.0) continue; const Fractional coeff = diagonal_of_ones ? value : value / diagonal_coefficients_[col]; if (!diagonal_of_ones) { @@ -891,8 +881,7 @@ void TriangularMatrix::HyperSparseSolveInternal( RETURN_IF_NULL(rhs); int new_size = 0; for (const RowIndex row : *non_zero_rows) { - if ((*rhs)[row] == 0.0) - continue; + if ((*rhs)[row] == 0.0) continue; const ColIndex row_as_col = RowToColIndex(row); const Fractional coeff = diagonal_of_ones ? (*rhs)[row] @@ -922,8 +911,7 @@ void TriangularMatrix::HyperSparseSolveWithReversedNonZerosInternal( RETURN_IF_NULL(rhs); int new_start = non_zero_rows->size(); for (const RowIndex row : Reverse(*non_zero_rows)) { - if ((*rhs)[row] == 0.0) - continue; + if ((*rhs)[row] == 0.0) continue; const ColIndex row_as_col = RowToColIndex(row); const Fractional coeff = diagonal_of_ones ? (*rhs)[row] @@ -1025,8 +1013,7 @@ void TriangularMatrix::PermutedLowerSolve( ++row) { const RowIndex permuted_row = partial_inverse_row_perm[row]; const Fractional pivot = initially_all_zero_scratchpad_[permuted_row]; - if (pivot == 0.0) - continue; + if (pivot == 0.0) continue; for (EntryIndex i : Column(RowToColIndex(row))) { initially_all_zero_scratchpad_[EntryRow(i)] -= EntryCoefficient(i) * pivot; @@ -1079,8 +1066,7 @@ void TriangularMatrix::PermutedLowerSparseSolve(const ColumnView &rhs, EntryIndex(upper_column_rows_.size())); for (const RowIndex permuted_row : Reverse(upper_column_rows_)) { const Fractional pivot = initially_all_zero_scratchpad_[permuted_row]; - if (pivot == 0.0) - continue; + if (pivot == 0.0) continue; // Note that permuted_row will not appear in the loop below so we // already know the value of the solution at this position. initially_all_zero_scratchpad_[permuted_row] = 0.0; @@ -1242,8 +1228,7 @@ void TriangularMatrix::PermutedComputeRowsToConsider( void TriangularMatrix::ComputeRowsToConsiderWithDfs( RowIndexVector *non_zero_rows) const { - if (non_zero_rows->empty()) - return; + if (non_zero_rows->empty()) return; // We don't start the DFS if the initial number of non-zeros is under the // sparsity_threshold. During the DFS, we abort it if the number of floating @@ -1306,8 +1291,7 @@ void TriangularMatrix::ComputeRowsToConsiderWithDfs( // Abort if the number of operations is not negligible compared to the // number of rows. Note that this test also prevents the code from cycling // in case the matrix is actually not triangular. - if (num_ops > num_ops_threshold) - break; + if (num_ops > num_ops_threshold) break; } // Clear stored_. @@ -1316,8 +1300,7 @@ void TriangularMatrix::ComputeRowsToConsiderWithDfs( } // If we aborted, clear the result. - if (num_ops > num_ops_threshold) - non_zero_rows->clear(); + if (num_ops > num_ops_threshold) non_zero_rows->clear(); } void TriangularMatrix::ComputeRowsToConsiderInSortedOrder( @@ -1331,8 +1314,7 @@ void TriangularMatrix::ComputeRowsToConsiderInSortedOrder( void TriangularMatrix::ComputeRowsToConsiderInSortedOrder( RowIndexVector *non_zero_rows, Fractional sparsity_ratio, Fractional num_ops_ratio) const { - if (non_zero_rows->empty()) - return; + if (non_zero_rows->empty()) return; // TODO(user): Investigate the best thresholds. const int sparsity_threshold = @@ -1346,8 +1328,7 @@ void TriangularMatrix::ComputeRowsToConsiderInSortedOrder( } stored_.resize(num_rows_, false); - for (const RowIndex row : *non_zero_rows) - stored_[row] = true; + for (const RowIndex row : *non_zero_rows) stored_[row] = true; for (int i = 0; i < non_zero_rows->size(); ++i) { const RowIndex row = (*non_zero_rows)[i]; for (const EntryIndex i : Column(RowToColIndex(row))) { @@ -1358,12 +1339,10 @@ void TriangularMatrix::ComputeRowsToConsiderInSortedOrder( stored_[entry_row] = true; } } - if (num_ops > num_ops_threshold) - break; + if (num_ops > num_ops_threshold) break; } - for (const RowIndex row : *non_zero_rows) - stored_[row] = false; + for (const RowIndex row : *non_zero_rows) stored_[row] = false; if (num_ops > num_ops_threshold) { non_zero_rows->clear(); } else { @@ -1429,5 +1408,5 @@ Fractional TriangularMatrix::ComputeInverseInfinityNorm() const { return norm; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/sparse.h b/ortools/lp_data/sparse.h index de333e599a..79785a68ad 100644 --- a/ortools/lp_data/sparse.h +++ b/ortools/lp_data/sparse.h @@ -59,7 +59,7 @@ class CompactSparseMatrixView; // // Note that no special ordering of entries is assumed. class SparseMatrix { -public: + public: SparseMatrix(); // Useful for testing. This makes it possible to write: @@ -118,7 +118,8 @@ public: // Note that this preserve the property of lower/upper triangular matrix // to have the diagonal coefficients first/last in each columns. It actually // sorts the entries in each columns by their indices. - template void PopulateFromTranspose(const Matrix &input); + template + void PopulateFromTranspose(const Matrix &input); // Populates a SparseMatrix from another one (copy), note that this run in // O(number of entries in the matrix). @@ -196,7 +197,7 @@ public: // Returns a dense representation of the matrix. std::string Dump() const; -private: + private: // Resets the internal data structure and create an empty rectangular // matrix of size num_rows x num_cols. void Reset(ColIndex num_cols, RowIndex num_rows); @@ -215,7 +216,7 @@ private: // does not take ownership of the underlying columns, and thus they must outlive // this class (and keep the same address in memory). class MatrixView { -public: + public: MatrixView() {} explicit MatrixView(const SparseMatrix &matrix) { PopulateFromMatrix(matrix); @@ -265,7 +266,7 @@ public: Fractional ComputeOneNorm() const; Fractional ComputeInfinityNorm() const; -private: + private: RowIndex num_rows_; StrictITIVector columns_; }; @@ -276,16 +277,16 @@ extern template void SparseMatrix::PopulateFromPermutedMatrix( const SparseMatrix &a, const RowPermutation &row_perm, const ColumnPermutation &inverse_col_perm); extern template void - SparseMatrix::PopulateFromPermutedMatrix( - const CompactSparseMatrixView &a, const RowPermutation &row_perm, - const ColumnPermutation &inverse_col_perm); +SparseMatrix::PopulateFromPermutedMatrix( + const CompactSparseMatrixView &a, const RowPermutation &row_perm, + const ColumnPermutation &inverse_col_perm); // Another matrix representation which is more efficient than a SparseMatrix but // doesn't allow matrix modification. It is faster to construct, uses less // memory and provides a better cache locality when iterating over the non-zeros // of the matrix columns. class CompactSparseMatrix { -public: + public: CompactSparseMatrix() {} // Convenient constructors for tests. @@ -391,8 +392,7 @@ public: // function is declared in the .h for efficiency. void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const { - if (multiplier == 0.0) - return; + if (multiplier == 0.0) return; RETURN_IF_NULL(dense_column); for (const EntryIndex i : Column(col)) { (*dense_column)[EntryRow(i)] += multiplier * EntryCoefficient(i); @@ -405,8 +405,7 @@ public: void ColumnAddMultipleToSparseScatteredColumn(ColIndex col, Fractional multiplier, ScatteredColumn *column) const { - if (multiplier == 0.0) - return; + if (multiplier == 0.0) return; RETURN_IF_NULL(column); for (const EntryIndex i : Column(col)) { const RowIndex row = EntryRow(i); @@ -434,10 +433,9 @@ public: } // Same as ColumnCopyToClearedDenseColumn() but also fills non_zeros. - void - ColumnCopyToClearedDenseColumnWithNonZeros(ColIndex col, - DenseColumn *dense_column, - RowIndexVector *non_zeros) const { + void ColumnCopyToClearedDenseColumnWithNonZeros( + ColIndex col, DenseColumn *dense_column, + RowIndexVector *non_zeros) const { RETURN_IF_NULL(dense_column); dense_column->resize(num_rows_, 0.0); non_zeros->clear(); @@ -450,7 +448,7 @@ public: void Swap(CompactSparseMatrix *other); -protected: + protected: // The matrix dimensions, properly updated by full and incremental builders. RowIndex num_rows_; ColIndex num_cols_; @@ -462,7 +460,7 @@ protected: StrictITIVector rows_; StrictITIVector starts_; -private: + private: DISALLOW_COPY_AND_ASSIGN(CompactSparseMatrix); }; @@ -471,7 +469,7 @@ private: // underlying matrix or basis, and thus they must outlive this class (and keep // the same address in memory). class CompactSparseMatrixView { -public: + public: CompactSparseMatrixView(const CompactSparseMatrix *compact_matrix, const RowToColMapping *basis) : compact_matrix_(*compact_matrix), basis_(*basis) {} @@ -487,7 +485,7 @@ public: Fractional ComputeOneNorm() const; Fractional ComputeInfinityNorm() const; -private: + private: // We require that the underlying CompactSparseMatrix and RowToColMapping // continue to own the (potentially large) data accessed via this view. const CompactSparseMatrix &compact_matrix_; @@ -502,7 +500,7 @@ private: // Advanced usage: this class also support matrices that can be permuted into a // triangular matrix and some functions work directly on such matrices. class TriangularMatrix : private CompactSparseMatrix { -public: + public: TriangularMatrix() : all_diagonal_coefficients_are_one_(true) {} // Only a subset of the functions from CompactSparseMatrix are exposed (note @@ -635,9 +633,8 @@ public: // simplex method", December 1999, MS 99-014. // http://www.maths.ed.ac.uk/hall/MS-99/MS9914.pdf void HyperSparseSolve(DenseColumn *rhs, RowIndexVector *non_zero_rows) const; - void - HyperSparseSolveWithReversedNonZeros(DenseColumn *rhs, - RowIndexVector *non_zero_rows) const; + void HyperSparseSolveWithReversedNonZeros( + DenseColumn *rhs, RowIndexVector *non_zero_rows) const; void TransposeHyperSparseSolve(DenseColumn *rhs, RowIndexVector *non_zero_rows) const; void TransposeHyperSparseSolveWithReversedNonZeros( @@ -732,7 +729,7 @@ public: Fractional ComputeInverseInfinityNormUpperBound() const; Fractional ComputeInverseInfinityNorm() const; -private: + private: // Internal versions of some Solve() functions to avoid code duplication. template void LowerSolveStartingAtInternal(ColIndex start, DenseColumn *rhs) const; @@ -836,7 +833,7 @@ private: DISALLOW_COPY_AND_ASSIGN(TriangularMatrix); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_SPARSE_H_ +#endif // OR_TOOLS_LP_DATA_SPARSE_H_ diff --git a/ortools/lp_data/sparse_column.cc b/ortools/lp_data/sparse_column.cc index 87a015ceab..ed86614058 100644 --- a/ortools/lp_data/sparse_column.cc +++ b/ortools/lp_data/sparse_column.cc @@ -71,5 +71,5 @@ void RandomAccessSparseColumn::PopulateSparseColumn( DCHECK(sparse_column->CheckNoDuplicates()); } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research diff --git a/ortools/lp_data/sparse_column.h b/ortools/lp_data/sparse_column.h index 233e4519b4..28f8a1a8ba 100644 --- a/ortools/lp_data/sparse_column.h +++ b/ortools/lp_data/sparse_column.h @@ -26,11 +26,11 @@ const RowIndex kNonPivotal(-1); // SparseColumn class. In addition to index(), it also provides row() for better // readability on the client side. class SparseColumnEntry : public SparseVectorEntry { -public: + public: // Returns the row of the current entry. RowIndex row() const { return index(); } -protected: + protected: SparseColumnEntry(const RowIndex *indices, const Fractional *coefficients, EntryIndex i) : SparseVectorEntry(indices, coefficients, i) {} @@ -44,7 +44,7 @@ class ColumnView; class SparseColumn : public SparseVector { friend class ColumnView; -public: + public: SparseColumn() : SparseVector() {} // Use a separate API to get the row and coefficient of entry #i. @@ -63,7 +63,7 @@ public: // Class to iterate on the entries of a given column with the same interface // as for SparseColumn. class ColumnView { -public: + public: // Clients should pass Entry by value rather than by reference. // This is because SparseColumnEntry is small (2 pointers and an index) and // previous profiling of this type of use showed no performance penalty @@ -76,7 +76,8 @@ public: const Fractional *const coefficients) : num_entries_(num_entries), rows_(rows), coefficients_(coefficients) {} explicit ColumnView(const SparseColumn &column) - : num_entries_(column.num_entries()), rows_(column.index_), + : num_entries_(column.num_entries()), + rows_(column.index_), coefficients_(column.coefficient_) {} EntryIndex num_entries() const { return num_entries_; } Fractional EntryCoefficient(EntryIndex i) const { @@ -112,7 +113,7 @@ public: bool IsEmpty() const { return num_entries_ == EntryIndex(0); } -private: + private: const EntryIndex num_entries_; const RowIndex *const rows_; const Fractional *const coefficients_; @@ -127,7 +128,7 @@ private: // As the constructor runs in O(num_rows), a RandomAccessSparseColumn should be // used several times to amortize the creation cost. class RandomAccessSparseColumn { -public: + public: // Creates a RandomAccessSparseColumn. // Runs in O(num_rows). explicit RandomAccessSparseColumn(RowIndex num_rows); @@ -169,7 +170,7 @@ public: // Runs in O(1). Fractional GetCoefficient(RowIndex row) const { return column_[row]; } -private: + private: // Keeps a trace of which rows have been changed. void MarkRowAsChanged(RowIndex row) { if (!changed_[row]) { @@ -190,7 +191,7 @@ private: DISALLOW_COPY_AND_ASSIGN(RandomAccessSparseColumn); }; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_SPARSE_COLUMN_H_ +#endif // OR_TOOLS_LP_DATA_SPARSE_COLUMN_H_ diff --git a/ortools/lp_data/sparse_row.h b/ortools/lp_data/sparse_row.h index 7eadaeb601..7708c44789 100644 --- a/ortools/lp_data/sparse_row.h +++ b/ortools/lp_data/sparse_row.h @@ -23,11 +23,11 @@ namespace glop { // SparseRow class. In addition to index(), it also provides col() for better // readability on the client side. class SparseRowEntry : public SparseVectorEntry { -public: + public: // Returns the row of the current entry. ColIndex col() const { return index(); } -protected: + protected: SparseRowEntry(const ColIndex *indices, const Fractional *coefficients, EntryIndex i) : SparseVectorEntry(indices, coefficients, i) {} @@ -40,7 +40,7 @@ using SparseRowIterator = VectorIterator; // A SparseRow is a SparseVector, with a few methods renamed // to help readability on the client side. class SparseRow : public SparseVector { -public: + public: SparseRow() : SparseVector() {} // Use a separate API to get the column and coefficient of entry #i. @@ -59,7 +59,7 @@ public: // A matrix stored by rows. typedef gtl::ITIVector RowMajorSparseMatrix; -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_SPARSE_ROW_H_ +#endif // OR_TOOLS_LP_DATA_SPARSE_ROW_H_ diff --git a/ortools/lp_data/sparse_vector.h b/ortools/lp_data/sparse_vector.h index 12cf80b0eb..0962d2bf0d 100644 --- a/ortools/lp_data/sparse_vector.h +++ b/ortools/lp_data/sparse_vector.h @@ -37,7 +37,7 @@ #include "absl/strings/str_format.h" #include "ortools/base/integral_types.h" -#include "ortools/base/logging.h" // for CHECK* +#include "ortools/base/logging.h" // for CHECK* #include "ortools/graph/iterators.h" #include "ortools/lp_data/lp_types.h" #include "ortools/lp_data/permutation.h" @@ -46,7 +46,8 @@ namespace operations_research { namespace glop { -template class SparseVectorEntry; +template +class SparseVectorEntry; // -------------------------------------------------------- // SparseVector @@ -77,10 +78,11 @@ template class SparseVectorEntry; // // TODO(user): un-expose this type to client; by getting rid of the // index-based APIs and leveraging iterator-based APIs; if possible. -template > > +template > > class SparseVector { -public: + public: typedef IndexType Index; typedef StrictITIVector DenseVector; @@ -310,7 +312,7 @@ public: // internal order. a.DebugString() == b.DebugString() iff a.IsEqualTo(b). std::string DebugString() const; -protected: + protected: // Adds a new entry to the sparse vector, growing the internal buffer if // needed. It does not set may_contain_duplicates_ to true. void AddEntry(Index index, Fractional value) { @@ -387,7 +389,7 @@ protected: // so we can perform checks on const argument. mutable bool may_contain_duplicates_; -private: + private: // Actual implementation of AddMultipleToSparseVectorAndDeleteCommonIndex() // and AddMultipleToSparseVectorAndIgnoreCommonIndex() which is shared. void AddMultipleToSparseVectorInternal( @@ -406,14 +408,15 @@ private: // Note that the entry object does not own the data, and it is valid only as // long as the underlying sparse data structure; it may also be invalidated if // the underlying sparse data structure is modified. -template class SparseVectorEntry { -public: +template +class SparseVectorEntry { + public: using Index = IndexType; Index index() const { return index_[i_.value()]; } Fractional coefficient() const { return coefficient_[i_.value()]; } -protected: + protected: // Creates the sparse vector entry from the given base pointers and the index. // We accept the low-level data structures rather than a SparseVector // reference to make it possible to use the SparseVectorEntry and @@ -455,7 +458,10 @@ IteratorType SparseVector::end() const { // -------------------------------------------------------- template SparseVector::SparseVector() - : num_entries_(0), capacity_(0), index_(nullptr), coefficient_(nullptr), + : num_entries_(0), + capacity_(0), + index_(nullptr), + coefficient_(nullptr), may_contain_duplicates_(false) {} template @@ -488,8 +494,7 @@ void SparseVector::ClearAndRelease() { template void SparseVector::Reserve(EntryIndex new_capacity) { - if (new_capacity <= capacity_) - return; + if (new_capacity <= capacity_) return; // Round up the capacity to a multiple of four. This way, the start of the // coefficient array will be aligned to 16-bytes, provided that the buffer // used for storing the data is aligned in that way. @@ -553,17 +558,15 @@ void SparseVector::CleanUp() { for (EntryIndex i(0); i < num_entries_; ++i) { entries.emplace_back(GetIndex(i), GetCoefficient(i)); } - std::stable_sort(entries.begin(), entries.end(), - [](const std::pair & a, - const std::pair & b) { - return a.first < b.first; - }); + std::stable_sort( + entries.begin(), entries.end(), + [](const std::pair &a, + const std::pair &b) { return a.first < b.first; }); EntryIndex new_size(0); for (int i = 0; i < num_entries_; ++i) { const std::pair entry = entries[i]; - if (entry.second == 0.0) - continue; + if (entry.second == 0.0) continue; if (i + 1 == num_entries_ || entry.first != entries[i + 1].first) { MutableIndex(new_size) = entry.first; MutableCoefficient(new_size) = entry.second; @@ -579,8 +582,7 @@ bool SparseVector::IsCleanedUp() const { Index previous_index(-1); for (const EntryIndex i : AllEntryIndices()) { const Index index = GetIndex(i); - if (index <= previous_index || GetCoefficient(i) == 0.0) - return false; + if (index <= previous_index || GetCoefficient(i) == 0.0) return false; previous_index = index; } may_contain_duplicates_ = false; @@ -638,8 +640,7 @@ bool SparseVector::CheckNoDuplicates( RETURN_VALUE_IF_NULL(boolean_vector, false); // Note(user): Using num_entries() or any function that call // CheckNoDuplicates() again will cause an infinite loop! - if (!may_contain_duplicates_ || num_entries_ <= 1) - return true; + if (!may_contain_duplicates_ || num_entries_ <= 1) return true; // Update size if needed. const Index max_index = @@ -669,8 +670,7 @@ template bool SparseVector::CheckNoDuplicates() const { // Using num_entries() or any function in that will call CheckNoDuplicates() // again will cause an infinite loop! - if (!may_contain_duplicates_ || num_entries_ <= 1) - return true; + if (!may_contain_duplicates_ || num_entries_ <= 1) return true; StrictITIVector boolean_vector; return CheckNoDuplicates(&boolean_vector); } @@ -692,8 +692,7 @@ void SparseVector::DeleteEntry(Index index) { while (i < end && GetIndex(i) != index) { ++i; } - if (i == end) - return; + if (i == end) return; const int num_moved_entries = (num_entries_ - i).value() - 1; std::memmove(index_ + i.value(), index_ + i.value() + 1, sizeof(Index) * num_moved_entries); @@ -734,8 +733,8 @@ void SparseVector::RemoveNearZeroEntriesWithWeights( } template -void -SparseVector::MoveEntryToFirstPosition(Index index) { +void SparseVector::MoveEntryToFirstPosition( + Index index) { DCHECK(CheckNoDuplicates()); for (const EntryIndex i : AllEntryIndices()) { if (GetIndex(i) == index) { @@ -747,8 +746,8 @@ SparseVector::MoveEntryToFirstPosition(Index index) { } template -void -SparseVector::MoveEntryToLastPosition(Index index) { +void SparseVector::MoveEntryToLastPosition( + Index index) { DCHECK(CheckNoDuplicates()); const EntryIndex last_entry = num_entries() - 1; for (const EntryIndex i : AllEntryIndices()) { @@ -761,8 +760,8 @@ SparseVector::MoveEntryToLastPosition(Index index) { } template -void -SparseVector::MultiplyByConstant(Fractional factor) { +void SparseVector::MultiplyByConstant( + Fractional factor) { for (const EntryIndex i : AllEntryIndices()) { MutableCoefficient(i) *= factor; } @@ -777,8 +776,8 @@ void SparseVector::ComponentWiseMultiply( } template -void -SparseVector::DivideByConstant(Fractional factor) { +void SparseVector::DivideByConstant( + Fractional factor) { for (const EntryIndex i : AllEntryIndices()) { MutableCoefficient(i) /= factor; } @@ -817,27 +816,26 @@ template void SparseVector::AddMultipleToDenseVector( Fractional multiplier, DenseVector *dense_vector) const { RETURN_IF_NULL(dense_vector); - if (multiplier == 0.0) - return; + if (multiplier == 0.0) return; for (const EntryIndex i : AllEntryIndices()) { (*dense_vector)[GetIndex(i)] += multiplier * GetCoefficient(i); } } template -void SparseVector::AddMultipleToSparseVectorAndDeleteCommonIndex( - Fractional multiplier, Index removed_common_index, - Fractional drop_tolerance, SparseVector *accumulator_vector) const { +void SparseVector:: + AddMultipleToSparseVectorAndDeleteCommonIndex( + Fractional multiplier, Index removed_common_index, + Fractional drop_tolerance, SparseVector *accumulator_vector) const { AddMultipleToSparseVectorInternal(true, multiplier, removed_common_index, drop_tolerance, accumulator_vector); } template -void SparseVector::AddMultipleToSparseVectorAndIgnoreCommonIndex( - Fractional multiplier, Index removed_common_index, - Fractional drop_tolerance, SparseVector *accumulator_vector) const { +void SparseVector:: + AddMultipleToSparseVectorAndIgnoreCommonIndex( + Fractional multiplier, Index removed_common_index, + Fractional drop_tolerance, SparseVector *accumulator_vector) const { AddMultipleToSparseVectorInternal(false, multiplier, removed_common_index, drop_tolerance, accumulator_vector); } @@ -862,9 +860,9 @@ void SparseVector::AddMultipleToSparseVectorInternal( const SparseVector &a = *this; const SparseVector &b = *accumulator_vector; SparseVector c; - EntryIndex ia(0); // Index in the vector "a" - EntryIndex ib(0); // ... and "b" - EntryIndex ic(0); // ... and "c" + EntryIndex ia(0); // Index in the vector "a" + EntryIndex ib(0); // ... and "b" + EntryIndex ic(0); // ... and "c" const EntryIndex size_a = a.num_entries(); const EntryIndex size_b = b.num_entries(); const int size_adjustment = delete_common_index ? -2 : 0; @@ -901,7 +899,7 @@ void SparseVector::AddMultipleToSparseVectorInternal( c.MutableCoefficient(ic) = multiplier * a.GetCoefficient(ia); ++ia; ++ic; - } else { // index_b < index_a + } else { // index_b < index_a c.MutableIndex(ic) = b.GetIndex(ib); c.MutableCoefficient(ic) = b.GetCoefficient(ib); ++ib; @@ -956,10 +954,8 @@ void SparseVector::MoveTaggedEntriesTo( const EntryIndex end(num_entries_); EntryIndex i(0); while (true) { - if (i >= end) - return; // "nothing to do" case. - if (index_perm[GetIndex(i)] >= 0) - break; + if (i >= end) return; // "nothing to do" case. + if (index_perm[GetIndex(i)] >= 0) break; ++i; } output->AddEntry(GetIndex(i), GetCoefficient(i)); @@ -981,8 +977,8 @@ void SparseVector::MoveTaggedEntriesTo( } template -Fractional -SparseVector::LookUpCoefficient(Index index) const { +Fractional SparseVector::LookUpCoefficient( + Index index) const { Fractional value(0.0); for (const EntryIndex i : AllEntryIndices()) { if (GetIndex(i) == index) { @@ -1000,13 +996,10 @@ template bool SparseVector::IsEqualTo( const SparseVector &other) const { // We do not take into account the mutable value may_contain_duplicates_. - if (num_entries() != other.num_entries()) - return false; + if (num_entries() != other.num_entries()) return false; for (const EntryIndex i : AllEntryIndices()) { - if (GetIndex(i) != other.GetIndex(i)) - return false; - if (GetCoefficient(i) != other.GetCoefficient(i)) - return false; + if (GetIndex(i) != other.GetIndex(i)) return false; + if (GetCoefficient(i) != other.GetCoefficient(i)) return false; } return true; } @@ -1015,15 +1008,14 @@ template std::string SparseVector::DebugString() const { std::string s; for (const EntryIndex i : AllEntryIndices()) { - if (i != 0) - s += ", "; + if (i != 0) s += ", "; absl::StrAppendFormat(&s, "[%d]=%g", GetIndex(i).value(), GetCoefficient(i)); } return s; } -} // namespace glop -} // namespace operations_research +} // namespace glop +} // namespace operations_research -#endif // OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_ +#endif // OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_ diff --git a/ortools/port/file.h b/ortools/port/file.h index 0f7e4e59a6..7bb359b377 100644 --- a/ortools/port/file.h +++ b/ortools/port/file.h @@ -32,6 +32,6 @@ namespace operations_research { bool PortableTemporaryFile(const char *directory_prefix, std::string *filename_out); -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_PORT_FILE_H_ +#endif // OR_TOOLS_PORT_FILE_H_ diff --git a/ortools/port/file_nonport.cc b/ortools/port/file_nonport.cc index 2b80cc2359..f01b7ed124 100644 --- a/ortools/port/file_nonport.cc +++ b/ortools/port/file_nonport.cc @@ -38,14 +38,14 @@ bool PortableTemporaryFile(const char *directory_prefix, std::string *filename_out) { #if defined(__linux) int32 tid = static_cast(pthread_self()); -#else // defined(__linux__) +#else // defined(__linux__) int32 tid = 123; -#endif // defined(__linux__) +#endif // defined(__linux__) #if !defined(_MSC_VER) int32 pid = static_cast(getpid()); -#else // _MSC_VER +#else // _MSC_VER int32 pid = 456; -#endif // _MSC_VER +#endif // _MSC_VER int64 now = absl::GetCurrentTimeNanos(); std::string filename = absl::StrFormat("/tmp/parameters-tempfile-%x-%d-%llx", tid, pid, now); @@ -56,4 +56,4 @@ bool PortableTemporaryFile(const char *directory_prefix, return file::Delete(file_name, file::Defaults()); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/port/proto_utils.h b/ortools/port/proto_utils.h index fddd121f1d..181571c21f 100644 --- a/ortools/port/proto_utils.h +++ b/ortools/port/proto_utils.h @@ -25,11 +25,13 @@ namespace operations_research { #if defined(__PORTABLE_PLATFORM__) -template std::string ProtobufDebugString(const P &message) { +template +std::string ProtobufDebugString(const P &message) { return message.GetTypeName(); } -template std::string ProtobufShortDebugString(const P &message) { +template +std::string ProtobufShortDebugString(const P &message) { return message.GetTypeName(); } @@ -39,19 +41,21 @@ std::string ProtoEnumToString(ProtoEnumType enum_value) { } template -bool ProtobufTextFormatMergeFromString( - const std::string &proto_text_string ABSL_ATTRIBUTE_UNUSED, - ProtoType *proto ABSL_ATTRIBUTE_UNUSED) { +bool ProtobufTextFormatMergeFromString(const std::string &proto_text_string + ABSL_ATTRIBUTE_UNUSED, + ProtoType *proto ABSL_ATTRIBUTE_UNUSED) { return false; } -#else // __PORTABLE_PLATFORM__ +#else // __PORTABLE_PLATFORM__ -template std::string ProtobufDebugString(const P &message) { +template +std::string ProtobufDebugString(const P &message) { return message.DebugString(); } -template std::string ProtobufShortDebugString(const P &message) { +template +std::string ProtobufShortDebugString(const P &message) { return message.ShortDebugString(); } @@ -74,8 +78,8 @@ bool ProtobufTextFormatMergeFromString(const std::string &proto_text_string, proto); } -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_PORT_PROTO_UTILS_H_ +#endif // OR_TOOLS_PORT_PROTO_UTILS_H_ diff --git a/ortools/port/sysinfo.h b/ortools/port/sysinfo.h index 87d251f7e2..64b9ea5c18 100644 --- a/ortools/port/sysinfo.h +++ b/ortools/port/sysinfo.h @@ -29,7 +29,7 @@ namespace sysinfo { // See base/sysinfo.h MemoryUsage int64 MemoryUsageProcess(); -} // namespace sysinfo -} // namespace operations_research +} // namespace sysinfo +} // namespace operations_research -#endif // OR_TOOLS_PORT_SYSINFO_H_ +#endif // OR_TOOLS_PORT_SYSINFO_H_ diff --git a/ortools/port/sysinfo_nonport.cc b/ortools/port/sysinfo_nonport.cc index f4b2a98648..1ef2cb3862 100644 --- a/ortools/port/sysinfo_nonport.cc +++ b/ortools/port/sysinfo_nonport.cc @@ -19,5 +19,5 @@ namespace sysinfo { int64 MemoryUsageProcess() { return ::MemoryUsage(0); } -} // namespace sysinfo -} // namespace operations_research +} // namespace sysinfo +} // namespace operations_research diff --git a/ortools/port/utf8.h b/ortools/port/utf8.h index 3a91dce1c0..044e884bc9 100644 --- a/ortools/port/utf8.h +++ b/ortools/port/utf8.h @@ -24,7 +24,8 @@ namespace operations_research { namespace utf8 { // str_type should be string/StringPiece/Cord -template int UTF8StrLen(StrType str_type) { +template +int UTF8StrLen(StrType str_type) { #if defined(__PORTABLE_PLATFORM__) return str_type.size(); #else @@ -32,7 +33,7 @@ template int UTF8StrLen(StrType str_type) { #endif } -} // namespace utf8 -} // namespace operations_research +} // namespace utf8 +} // namespace operations_research -#endif // OR_TOOLS_PORT_UTF8_H_ +#endif // OR_TOOLS_PORT_UTF8_H_ diff --git a/ortools/sat/all_different.cc b/ortools/sat/all_different.cc index 8561d2ce5d..619bc39e76 100644 --- a/ortools/sat/all_different.cc +++ b/ortools/sat/all_different.cc @@ -28,9 +28,9 @@ namespace operations_research { namespace sat { -std::function -AllDifferentBinary(const std::vector &vars) { - return[ = ](Model * model) { +std::function AllDifferentBinary( + const std::vector &vars) { + return [=](Model *model) { // Fully encode all the given variables and construct a mapping value -> // List of literal each indicating that a given variable takes this value. // @@ -59,39 +59,40 @@ AllDifferentBinary(const std::vector &vars) { model->Add(ClauseConstraint(entry.second)); } } - } - ; + }; } -std::function -AllDifferentOnBounds(const std::vector &vars) { - return[ = ](Model * model) { if (vars.empty()) return; +std::function AllDifferentOnBounds( + const std::vector &vars) { + return [=](Model *model) { + if (vars.empty()) return; auto *constraint = new AllDifferentBoundsPropagator( vars, model->GetOrCreate()); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -std::function -AllDifferentAC(const std::vector &variables) { - return[ = ](Model * model) { if (variables.size() < 3) return; +std::function AllDifferentAC( + const std::vector &variables) { + return [=](Model *model) { + if (variables.size() < 3) return; AllDifferentConstraint *constraint = new AllDifferentConstraint( variables, model->GetOrCreate(), model->GetOrCreate(), model->GetOrCreate()); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } AllDifferentConstraint::AllDifferentConstraint( std::vector variables, IntegerEncoder *encoder, Trail *trail, IntegerTrail *integer_trail) - : num_variables_(variables.size()), variables_(std::move(variables)), - trail_(trail), integer_trail_(integer_trail) { + : num_variables_(variables.size()), + variables_(std::move(variables)), + trail_(trail), + integer_trail_(integer_trail) { // Initialize literals cache. int64 min_value = kint64max; int64 max_value = kint64min; @@ -169,10 +170,8 @@ LiteralIndex AllDifferentConstraint::VariableLiteralIndexOf(int x, inline bool AllDifferentConstraint::VariableHasPossibleValue(int x, int64 value) { LiteralIndex li = VariableLiteralIndexOf(x, value); - if (li == kFalseLiteralIndex) - return false; - if (li == kTrueLiteralIndex) - return true; + if (li == kFalseLiteralIndex) return false; + if (li == kTrueLiteralIndex) return true; DCHECK_GE(li, 0); return !trail_->Assignment().LiteralIsFalse(Literal(li)); } @@ -194,8 +193,7 @@ bool AllDifferentConstraint::MakeAugmentingPath(int start) { const int node = visiting_[num_visited++]; for (const int value : successor_[node]) { - if (value_visited_[value]) - continue; + if (value_visited_[value]) continue; value_visited_[value] = true; if (value_to_variable_[value] == -1) { // value is not matched: change path from node to start, and return. @@ -276,11 +274,9 @@ bool AllDifferentConstraint::Propagate() { // Seed with previous matching. for (int x = 0; x < num_variables_; x++) { - if (variable_to_value_[x] != -1) - continue; + if (variable_to_value_[x] != -1) continue; const int prev_value = prev_matching_[x]; - if (prev_value == -1 || value_to_variable_[prev_value] != -1) - continue; + if (prev_value == -1 || value_to_variable_[prev_value] != -1) continue; if (VariableHasPossibleValue(x, prev_matching_[x] + min_all_values_)) { variable_to_value_[x] = prev_matching_[x]; @@ -296,8 +292,7 @@ bool AllDifferentConstraint::Propagate() { variable_visited_.assign(num_variables_, false); MakeAugmentingPath(x); } - if (variable_to_value_[x] == -1) - break; // No augmenting path exists. + if (variable_to_value_[x] == -1) break; // No augmenting path exists. } // Fail if covering variables impossible. @@ -308,8 +303,7 @@ bool AllDifferentConstraint::Propagate() { std::vector *conflict = trail_->MutableConflict(); conflict->clear(); for (int y = 0; y < num_variables_; y++) { - if (!variable_visited_[y]) - continue; + if (!variable_visited_[y]) continue; for (int value = variable_min_value_[y]; value <= variable_max_value_[y]; value++) { const LiteralIndex li = VariableLiteralIndexOf(y, value); @@ -335,8 +329,8 @@ bool AllDifferentConstraint::Propagate() { for (int offset_value = 0; offset_value < num_all_values_; offset_value++) { residual_graph_successors_[num_variables_ + offset_value].clear(); if (value_to_variable_[offset_value] != -1) { - residual_graph_successors_[num_variables_ + offset_value] - .push_back(value_to_variable_[offset_value]); + residual_graph_successors_[num_variables_ + offset_value].push_back( + value_to_variable_[offset_value]); } } const int dummy_node = num_variables_ + num_all_values_; @@ -347,8 +341,8 @@ bool AllDifferentConstraint::Propagate() { } for (int offset_value = 0; offset_value < num_all_values_; offset_value++) { if (value_to_variable_[offset_value] == -1) { - residual_graph_successors_[num_variables_ + offset_value] - .push_back(dummy_node); + residual_graph_successors_[num_variables_ + offset_value].push_back( + dummy_node); } } } @@ -372,8 +366,7 @@ bool AllDifferentConstraint::Propagate() { // Remove arcs var -> val where SCC(var) -/->* SCC(val). for (int x = 0; x < num_variables_; x++) { - if (successor_[x].size() == 1) - continue; + if (successor_[x].size() == 1) continue; for (const int offset_value : successor_[x]) { const int value_node = offset_value + num_variables_; if (variable_to_value_[x] != offset_value && @@ -395,12 +388,11 @@ bool AllDifferentConstraint::Propagate() { value_visited_[offset_value] = true; MakeAugmentingPath(old_variable); - DCHECK_EQ(variable_to_value_[old_variable], -1); // No reassignment. + DCHECK_EQ(variable_to_value_[old_variable], -1); // No reassignment. std::vector *reason = trail_->GetEmptyVectorToStoreReason(); for (int y = 0; y < num_variables_; y++) { - if (!variable_visited_[y]) - continue; + if (!variable_visited_[y]) continue; for (int value = variable_min_value_[y]; value <= variable_max_value_[y]; value++) { const LiteralIndex li = VariableLiteralIndexOf(y, value); @@ -435,18 +427,13 @@ AllDifferentBoundsPropagator::AllDifferentBoundsPropagator( index_to_var_.resize(capacity, kNoIntegerVariable); for (int i = 0; i < vars.size(); ++i) { - vars_.push_back({ - vars[i] - }); - negated_vars_.push_back({ - NegationOf(vars[i]) - }); + vars_.push_back({vars[i]}); + negated_vars_.push_back({NegationOf(vars[i])}); } } bool AllDifferentBoundsPropagator::Propagate() { - if (!PropagateLowerBounds()) - return false; + if (!PropagateLowerBounds()) return false; // Note that it is not required to swap back vars_ and negated_vars_. // TODO(user): investigate the impact. @@ -472,16 +459,14 @@ int AllDifferentBoundsPropagator::FindStartIndexAndCompressPath(int index) { int start_index = index; while (true) { const int next = index_to_start_index_[start_index]; - if (start_index == next) - break; + if (start_index == next) break; start_index = next; } // Second, redo the same thing and make everyone point to the representative. while (true) { const int next = index_to_start_index_[index]; - if (start_index == next) - break; + if (start_index == next) break; index_to_start_index_[index] = start_index; index = next; } @@ -494,9 +479,8 @@ bool AllDifferentBoundsPropagator::PropagateLowerBounds() { entry.lb = integer_trail_->LowerBound(entry.var); entry.ub = integer_trail_->UpperBound(entry.var); } - IncrementalSort(vars_.begin(), vars_.end(), [](VarValue a, VarValue b) { - return a.lb < b.lb; - }); + IncrementalSort(vars_.begin(), vars_.end(), + [](VarValue a, VarValue b) { return a.lb < b.lb; }); // We will split the variable in vars sorted by lb in contiguous subset with // index of the form [start, start + num_in_window). @@ -557,9 +541,8 @@ bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal( indices_to_clear_.clear(); // Sort vars by increasing ub. - std::sort(vars.begin(), vars.end(), [](VarValue a, VarValue b) { - return a.ub < b.ub; - }); + std::sort(vars.begin(), vars.end(), + [](VarValue a, VarValue b) { return a.ub < b.ub; }); for (const VarValue entry : vars) { const IntegerVariable var = entry.var; @@ -572,8 +555,9 @@ bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal( // Check if lb is in an Hall interval, and push it if this is the case. if (value_is_covered) { - const int hall_index = std::lower_bound( - hall_ends_.begin(), hall_ends_.end(), lb) - hall_ends_.begin(); + const int hall_index = + std::lower_bound(hall_ends_.begin(), hall_ends_.end(), lb) - + hall_ends_.begin(); if (hall_index < hall_ends_.size() && hall_starts_[hall_index] <= lb) { const IntegerValue hs = hall_starts_[hall_index]; const IntegerValue he = hall_ends_[hall_index]; @@ -581,9 +565,7 @@ bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal( integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, hs)); if (!integer_trail_->Enqueue( IntegerLiteral::GreaterOrEqual(var, he + 1), - /*literal_reason=*/ { - }, - integer_reason_)) { + /*literal_reason=*/{}, integer_reason_)) { return false; } } @@ -650,8 +632,8 @@ bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal( return true; } -void -AllDifferentBoundsPropagator::RegisterWith(GenericLiteralWatcher *watcher) { +void AllDifferentBoundsPropagator::RegisterWith( + GenericLiteralWatcher *watcher) { const int id = watcher->Register(this); for (const VarValue entry : vars_) { watcher->WatchIntegerVariable(entry.var, id); @@ -659,5 +641,5 @@ AllDifferentBoundsPropagator::RegisterWith(GenericLiteralWatcher *watcher) { watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(id); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/all_different.h b/ortools/sat/all_different.h index f759f38da8..75742a1752 100644 --- a/ortools/sat/all_different.h +++ b/ortools/sat/all_different.h @@ -31,8 +31,8 @@ namespace sat { // Enforces that the given tuple of variables takes different values. This fully // encodes all the variables and simply enforces a <= 1 constraint on each // possible values. -std::function - AllDifferentBinary(const std::vector &vars); +std::function AllDifferentBinary( + const std::vector &vars); // Enforces that the given tuple of variables takes different values. // Same as AllDifferentBinary() but use a different propagator that only enforce @@ -42,8 +42,8 @@ std::function // variables and it is also quite fast. Note that the propagation is different, // this will not remove already taken values from inside a domain, but it will // propagates more the domain bounds. -std::function - AllDifferentOnBounds(const std::vector &vars); +std::function AllDifferentOnBounds( + const std::vector &vars); // This constraint forces all variables to take different values. This is meant // to be used as a complement to an alldifferent decomposition like @@ -55,12 +55,12 @@ std::function // "A filtering algorithm for constraints of difference in CSPs". // // This will fully encode variables. -std::function - AllDifferentAC(const std::vector &variables); +std::function AllDifferentAC( + const std::vector &variables); // Implementation of AllDifferentAC(). class AllDifferentConstraint : PropagatorInterface { -public: + public: AllDifferentConstraint(std::vector variables, IntegerEncoder *encoder, Trail *trail, IntegerTrail *integer_trail); @@ -68,7 +68,7 @@ public: bool Propagate() final; void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // MakeAugmentingPath() is a step in Ford-Fulkerson's augmenting path // algorithm. It changes its current internal state (see vectors below) // to assign a value to the start vertex using an augmenting path. @@ -145,14 +145,14 @@ private: // implemented here. Some related reference: // https://cs.uwaterloo.ca/~vanbeek/Publications/ijcai03_TR.pdf class AllDifferentBoundsPropagator : public PropagatorInterface { -public: + public: AllDifferentBoundsPropagator(const std::vector &vars, IntegerTrail *integer_trail); bool Propagate() final; void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // We locally cache the lb/ub for faster sorting and to guarantee some // invariant when we push bounds. struct VarValue { @@ -223,7 +223,7 @@ private: DISALLOW_COPY_AND_ASSIGN(AllDifferentBoundsPropagator); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_ALL_DIFFERENT_H_ +#endif // OR_TOOLS_SAT_ALL_DIFFERENT_H_ diff --git a/ortools/sat/boolean_problem.cc b/ortools/sat/boolean_problem.cc index b97a78e05a..28e35b0af4 100644 --- a/ortools/sat/boolean_problem.cc +++ b/ortools/sat/boolean_problem.cc @@ -27,7 +27,7 @@ #include "ortools/base/logging.h" #if !defined(__PORTABLE_PLATFORM__) #include "ortools/graph/io.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ #include "ortools/algorithms/find_graph_symmetries.h" #include "ortools/base/hash.h" #include "ortools/base/int_type.h" @@ -105,7 +105,8 @@ std::string ValidateLinearTerms(const LinearTerms &terms, } else { err_str = absl::StrFormat("%d validation errors; here are the first %d:\n", - num_errs, max_num_errs) + err_str; + num_errs, max_num_errs) + + err_str; } } return err_str; @@ -114,8 +115,8 @@ std::string ValidateLinearTerms(const LinearTerms &terms, // Converts a linear expression from the protocol buffer format to a vector // of LiteralWithCoeff. template -std::vector -ConvertLinearExpression(const ProtoFormat &input) { +std::vector ConvertLinearExpression( + const ProtoFormat &input) { std::vector cst; cst.reserve(input.literals_size()); for (int i = 0; i < input.literals_size(); ++i) { @@ -125,7 +126,7 @@ ConvertLinearExpression(const ProtoFormat &input) { return cst; } -} // namespace +} // namespace absl::Status ValidateBooleanProblem(const LinearBooleanProblem &problem) { std::vector variable_seen(problem.num_variables(), false); @@ -386,8 +387,8 @@ bool IsAssignmentValid(const LinearBooleanProblem &problem, // Note(user): This function makes a few assumptions about the format of the // given LinearBooleanProblem. All constraint coefficients must be 1 (and of the // form >= 1) and all objective weights must be strictly positive. -std::string -LinearBooleanProblemToCnfString(const LinearBooleanProblem &problem) { +std::string LinearBooleanProblemToCnfString( + const LinearBooleanProblem &problem) { std::string output; const bool is_wcnf = (problem.objective().coefficients_size() > 0); const LinearObjective &objective = problem.objective(); @@ -440,18 +441,15 @@ LinearBooleanProblemToCnfString(const LinearBooleanProblem &problem) { std::string constraint_output; for (const LinearBooleanConstraint &constraint : problem.constraints()) { - if (constraint.literals_size() == 0) - return ""; // Assumption. + if (constraint.literals_size() == 0) return ""; // Assumption. constraint_output.clear(); int64 weight = hard_weight; for (int i = 0; i < constraint.literals_size(); ++i) { - if (constraint.coefficients(i) != 1) - return ""; // Assumption. + if (constraint.coefficients(i) != 1) return ""; // Assumption. if (is_wcnf && abs(constraint.literals(i)) - 1 >= first_slack_variable) { weight = literal_to_weight[constraint.literals(i)]; } else { - if (i > 0) - constraint_output += " "; + if (i > 0) constraint_output += " "; constraint_output += Literal(constraint.literals(i)).DebugString(); } } @@ -479,8 +477,8 @@ void StoreAssignment(const VariablesAssignment &assignment, output->clear_literals(); for (BooleanVariable var(0); var < assignment.NumberOfVariables(); ++var) { if (assignment.VariableIsAssigned(var)) { - output->add_literals(assignment.GetTrueLiteralForAssignedVariable(var) - .SignedValue()); + output->add_literals( + assignment.GetTrueLiteralForAssignedVariable(var).SignedValue()); } } } @@ -501,7 +499,7 @@ namespace { // A simple class to generate equivalence class number for // GenerateGraphForSymmetryDetection(). class IdGenerator { -public: + public: IdGenerator() {} // If the pair (type, coefficient) was never seen before, then generate @@ -511,10 +509,10 @@ public: return gtl::LookupOrInsert(&id_map_, key, id_map_.size()); } -private: + private: absl::flat_hash_map, int> id_map_; }; -} // namespace. +} // namespace. // Returns a graph whose automorphisms can be mapped back to the symmetries of // the given LinearBooleanProblem. @@ -553,11 +551,7 @@ Graph *GenerateGraphForSymmetryDetection( // We will construct a graph with 3 different types of node that must be // in different equivalent classes. - enum NodeType { - LITERAL_NODE, - CONSTRAINT_NODE, - CONSTRAINT_COEFFICIENT_NODE - }; + enum NodeType { LITERAL_NODE, CONSTRAINT_NODE, CONSTRAINT_COEFFICIENT_NODE }; IdGenerator id_generator; // First, we need one node per literal with an edge between each literal @@ -689,8 +683,7 @@ void FindLinearBooleanProblemSymmetries( const int num_classes = 1 + *std::max_element(equivalence_classes.begin(), equivalence_classes.end()); std::vector class_size(num_classes, 0); - for (const int c : equivalence_classes) - ++class_size[c]; + for (const int c : equivalence_classes) ++class_size[c]; std::vector next_index_by_class(num_classes, 0); std::partial_sum(class_size.begin(), class_size.end() - 1, next_index_by_class.begin() + 1); @@ -700,18 +693,18 @@ void FindLinearBooleanProblemSymmetries( std::unique_ptr remapped_graph = RemapGraph(*graph, new_node_index); const absl::Status status = util::WriteGraphToFile( *remapped_graph, absl::GetFlag(FLAGS_debug_dump_symmetry_graph_to_file), - /*directed=*/ false, class_size); + /*directed=*/false, class_size); if (!status.ok()) { - LOG(DFATAL) - << "Error when writing the symmetry graph to file: " << status; + LOG(DFATAL) << "Error when writing the symmetry graph to file: " + << status; } } -#endif // __PORTABLE_PLATFORM__ - GraphSymmetryFinder symmetry_finder(*graph, /*is_undirected=*/ true); +#endif // __PORTABLE_PLATFORM__ + GraphSymmetryFinder symmetry_finder(*graph, /*is_undirected=*/true); std::vector factorized_automorphism_group_size; // TODO(user): inject the appropriate time limit here. CHECK_OK(symmetry_finder.FindSymmetries( - /*time_limit_seconds=*/ std::numeric_limits::infinity(), + /*time_limit_seconds=*/std::numeric_limits::infinity(), &equivalence_classes, generators, &factorized_automorphism_group_size)); // Remove from the permutations the part not concerning the literals. @@ -808,8 +801,8 @@ void ApplyLiteralMappingToBooleanProblem( ++new_index; } } - problem->mutable_constraints() - ->DeleteSubrange(new_index, num_constraints - new_index); + problem->mutable_constraints()->DeleteSubrange(new_index, + num_constraints - new_index); // Computes the new number of variables and set it. int num_vars = 0; @@ -822,8 +815,8 @@ void ApplyLiteralMappingToBooleanProblem( // TODO(user): The names is currently all scrambled. Do something about it // so that non-fixed variables keep their names. - problem->mutable_var_names() - ->DeleteSubrange(num_vars, problem->var_names_size() - num_vars); + problem->mutable_var_names()->DeleteSubrange( + num_vars, problem->var_names_size() - num_vars); } // A simple preprocessing step that does basic probing and removes the @@ -838,12 +831,11 @@ void ProbeAndSimplifyProblem(SatPostsolver *postsolver, } gtl::ITIVector equiv_map; - ProbeAndFindEquivalentLiteral(&solver, postsolver, /*drat_writer=*/ nullptr, + ProbeAndFindEquivalentLiteral(&solver, postsolver, /*drat_writer=*/nullptr, &equiv_map); // We can abort if no information is learned. - if (equiv_map.empty() && solver.LiteralTrail().Index() == 0) - break; + if (equiv_map.empty() && solver.LiteralTrail().Index() == 0) break; if (equiv_map.empty()) { const int num_literals = 2 * solver.NumVariables(); @@ -888,5 +880,5 @@ void ProbeAndSimplifyProblem(SatPostsolver *postsolver, } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/boolean_problem.h b/ortools/sat/boolean_problem.h index 5ec0932577..9fbd24ebfb 100644 --- a/ortools/sat/boolean_problem.h +++ b/ortools/sat/boolean_problem.h @@ -36,9 +36,8 @@ namespace sat { CpModelProto BooleanProblemToCpModelproto(const LinearBooleanProblem &problem); // Adds the offset and returns the scaled version of the given objective value. -inline double -AddOffsetAndScaleObjectiveValue(const LinearBooleanProblem &problem, - Coefficient v) { +inline double AddOffsetAndScaleObjectiveValue( + const LinearBooleanProblem &problem, Coefficient v) { return (static_cast(v.value()) + problem.objective().offset()) * problem.objective().scaling_factor(); } @@ -96,8 +95,8 @@ bool IsAssignmentValid(const LinearBooleanProblem &problem, // Converts a LinearBooleanProblem to the cnf file format. // Note that this only works for pure SAT problems (only clauses), max-sat or // weighted max-sat problems. Returns an empty string on error. -std::string - LinearBooleanProblemToCnfString(const LinearBooleanProblem &problem); +std::string LinearBooleanProblemToCnfString( + const LinearBooleanProblem &problem); // Store a variable assignment into the given BooleanAssignement proto. // Note that only the assigned variables are stored, so the assignment may be @@ -140,7 +139,7 @@ void ApplyLiteralMappingToBooleanProblem( void ProbeAndSimplifyProblem(SatPostsolver *postsolver, LinearBooleanProblem *problem); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_BOOLEAN_PROBLEM_H_ +#endif // OR_TOOLS_SAT_BOOLEAN_PROBLEM_H_ diff --git a/ortools/sat/circuit.cc b/ortools/sat/circuit.cc index 636f49a277..2b4a3bcd42 100644 --- a/ortools/sat/circuit.cc +++ b/ortools/sat/circuit.cc @@ -27,8 +27,10 @@ CircuitPropagator::CircuitPropagator(const int num_nodes, const std::vector &heads, const std::vector &literals, Options options, Model *model) - : num_nodes_(num_nodes), options_(options), - trail_(model->GetOrCreate()), assignment_(trail_->Assignment()) { + : num_nodes_(num_nodes), + options_(options), + trail_(model->GetOrCreate()), + assignment_(trail_->Assignment()) { CHECK(!tails.empty()) << "Empty constraint, shouldn't be constructed!"; next_.resize(num_nodes_, -1); prev_.resize(num_nodes_, -1); @@ -44,15 +46,12 @@ CircuitPropagator::CircuitPropagator(const int num_nodes, const int head = heads[arc]; const int tail = tails[arc]; const Literal literal = literals[arc]; - if (assignment_.LiteralIsFalse(literal)) - continue; + if (assignment_.LiteralIsFalse(literal)) continue; if (tail == head) { self_arcs_[tail] = literal; } else { - graph_[{ - tail, head - }] = literal; + graph_[{tail, head}] = literal; } if (assignment_.LiteralIsTrue(literal)) { @@ -76,9 +75,7 @@ CircuitPropagator::CircuitPropagator(const int num_nodes, watch_index_to_literal_.push_back(watched_literal); watch_index_to_arcs_.push_back(std::vector()); } - watch_index_to_arcs_[watch_index].push_back({ - tail, head - }); + watch_index_to_arcs_[watch_index].push_back({tail, head}); } for (int node = 0; node < num_nodes_; ++node) { @@ -109,8 +106,7 @@ void CircuitPropagator::RegisterWith(GenericLiteralWatcher *watcher) { } void CircuitPropagator::SetLevel(int level) { - if (level == level_ends_.size()) - return; + if (level == level_ends_.size()) return; if (level > level_ends_.size()) { while (level > level_ends_.size()) { level_ends_.push_back(added_arcs_.size()); @@ -138,8 +134,7 @@ void CircuitPropagator::FillReasonForPath(int start_node, reason->push_back(Literal(next_literal_[node]).Negated()); } node = next_[node]; - if (node == start_node) - break; + if (node == start_node) break; } } @@ -155,8 +150,8 @@ void CircuitPropagator::AddArc(int tail, int head, LiteralIndex literal_index) { } } -bool -CircuitPropagator::IncrementalPropagate(const std::vector &watch_indices) { +bool CircuitPropagator::IncrementalPropagate( + const std::vector &watch_indices) { for (const int w : watch_indices) { const Literal literal = watch_index_to_literal_[w]; for (const Arc arc : watch_index_to_arcs_[w]) { @@ -171,20 +166,20 @@ CircuitPropagator::IncrementalPropagate(const std::vector &watch_indices) { if (next_[arc.tail] != -1) { std::vector *conflict = trail_->MutableConflict(); if (next_literal_[arc.tail] != kNoLiteralIndex) { - *conflict = { Literal(next_literal_[arc.tail]).Negated(), - literal.Negated() }; + *conflict = {Literal(next_literal_[arc.tail]).Negated(), + literal.Negated()}; } else { - *conflict = { literal.Negated() }; + *conflict = {literal.Negated()}; } return false; } if (prev_[arc.head] != -1) { std::vector *conflict = trail_->MutableConflict(); if (next_literal_[prev_[arc.head]] != kNoLiteralIndex) { - *conflict = { Literal(next_literal_[prev_[arc.head]]).Negated(), - literal.Negated() }; + *conflict = {Literal(next_literal_[prev_[arc.head]]).Negated(), + literal.Negated()}; } else { - *conflict = { literal.Negated() }; + *conflict = {literal.Negated()}; } return false; } @@ -202,12 +197,9 @@ CircuitPropagator::IncrementalPropagate(const std::vector &watch_indices) { bool CircuitPropagator::Propagate() { processed_.assign(num_nodes_, false); for (int n = 0; n < num_nodes_; ++n) { - if (processed_[n]) - continue; - if (next_[n] == n) - continue; - if (next_[n] == -1 && prev_[n] == -1) - continue; + if (processed_[n]) continue; + if (next_[n] == n) continue; + if (next_[n] == -1 && prev_[n] == -1) continue; // TODO(user): both this and the loop on must_be_in_cycle_ might take some // time on large graph. Optimize if this become an issue. @@ -223,15 +215,13 @@ bool CircuitPropagator::Propagate() { end_node = next_[end_node]; in_current_path_[end_node] = true; processed_[end_node] = true; - if (end_node == n) - break; + if (end_node == n) break; } while (prev_[start_node] != -1) { start_node = prev_[start_node]; in_current_path_[start_node] = true; processed_[start_node] = true; - if (start_node == n) - break; + if (start_node == n) break; } // Check if we miss any node that must be in the circuit. Note that the ones @@ -262,14 +252,10 @@ bool CircuitPropagator::Propagate() { // We have an unclosed path. Propagate the fact that it cannot // be closed into a cycle, i.e. not(end_node -> start_node). if (start_node != end_node) { - const auto it = graph_.find({ - end_node, start_node - }); - if (it == graph_.end()) - continue; + const auto it = graph_.find({end_node, start_node}); + if (it == graph_.end()) continue; const Literal literal = it->second; - if (assignment_.LiteralIsFalse(literal)) - continue; + if (assignment_.LiteralIsFalse(literal)) continue; std::vector *reason = trail_->GetEmptyVectorToStoreReason(); FillReasonForPath(start_node, reason); @@ -277,24 +263,19 @@ bool CircuitPropagator::Propagate() { reason->push_back(Literal(extra_reason)); } const bool ok = trail_->EnqueueWithStoredReason(literal.Negated()); - if (!ok) - return false; + if (!ok) return false; continue; } } // If we have a cycle, we can propagate all the other nodes to point to // themselves. Otherwise there is nothing else to do. - if (start_node != end_node) - continue; - if (options_.multiple_subcircuit_through_zero) - continue; + if (start_node != end_node) continue; + if (options_.multiple_subcircuit_through_zero) continue; BooleanVariable variable_with_same_reason = kNoBooleanVariable; for (int node = 0; node < num_nodes_; ++node) { - if (in_current_path_[node]) - continue; - if (assignment_.LiteralIsTrue(self_arcs_[node])) - continue; + if (in_current_path_[node]) continue; + if (assignment_.LiteralIsTrue(self_arcs_[node])) continue; // This shouldn't happen because ExactlyOnePerRowAndPerColumn() should // have executed first and propagated self_arcs_[node] to false. @@ -315,8 +296,7 @@ bool CircuitPropagator::Propagate() { variable_with_same_reason = literal.Variable(); FillReasonForPath(start_node, trail_->GetEmptyVectorToStoreReason()); const bool ok = trail_->EnqueueWithStoredReason(literal); - if (!ok) - return false; + if (!ok) return false; } else { trail_->EnqueueWithSameReasonAs(literal, variable_with_same_reason); } @@ -328,7 +308,8 @@ bool CircuitPropagator::Propagate() { CircuitCoveringPropagator::CircuitCoveringPropagator( std::vector > graph, const std::vector &distinguished_nodes, Model *model) - : graph_(std::move(graph)), num_nodes_(graph_.size()), + : graph_(std::move(graph)), + num_nodes_(graph_.size()), trail_(model->GetOrCreate()) { node_is_distinguished_.resize(num_nodes_, false); for (const int node : distinguished_nodes) { @@ -344,8 +325,7 @@ void CircuitCoveringPropagator::RegisterWith(GenericLiteralWatcher *watcher) { for (int node1 = 0; node1 < num_nodes_; node1++) { for (int node2 = 0; node2 < num_nodes_; node2++) { const Literal l = graph_[node1][node2]; - if (trail_->Assignment().LiteralIsFalse(l)) - continue; + if (trail_->Assignment().LiteralIsFalse(l)) continue; if (trail_->Assignment().LiteralIsTrue(l)) { fixed_arcs_.emplace_back(node1, node2); } else { @@ -358,8 +338,7 @@ void CircuitCoveringPropagator::RegisterWith(GenericLiteralWatcher *watcher) { } void CircuitCoveringPropagator::SetLevel(int level) { - if (level == level_ends_.size()) - return; + if (level == level_ends_.size()) return; if (level > level_ends_.size()) { while (level > level_ends_.size()) { level_ends_.push_back(fixed_arcs_.size()); @@ -380,9 +359,8 @@ bool CircuitCoveringPropagator::IncrementalPropagate( return Propagate(); } -void -CircuitCoveringPropagator::FillFixedPathInReason(int start, int end, - std::vector *reason) { +void CircuitCoveringPropagator::FillFixedPathInReason( + int start, int end, std::vector *reason) { reason->clear(); int current = start; do { @@ -400,17 +378,17 @@ bool CircuitCoveringPropagator::Propagate() { for (const auto &arc : fixed_arcs_) { // Two arcs go out of arc.first, forbidden. if (next_[arc.first] != -1) { - *trail_->MutableConflict() = { graph_[arc.first][next_[arc.first]] - .Negated(), - graph_[arc.first][arc.second].Negated() }; + *trail_->MutableConflict() = { + graph_[arc.first][next_[arc.first]].Negated(), + graph_[arc.first][arc.second].Negated()}; return false; } next_[arc.first] = arc.second; // Two arcs come into arc.second, forbidden. if (prev_[arc.second] != -1) { - *trail_->MutableConflict() = { graph_[prev_[arc.second]][arc.second] - .Negated(), - graph_[arc.first][arc.second].Negated() }; + *trail_->MutableConflict() = { + graph_[prev_[arc.second]][arc.second].Negated(), + graph_[arc.first][arc.second].Negated()}; return false; } prev_[arc.second] = arc.first; @@ -421,12 +399,9 @@ bool CircuitCoveringPropagator::Propagate() { visited_.assign(num_nodes_, false); for (int node = 0; node < num_nodes_; node++) { // Skip if already visited, isolated or loop. - if (visited_[node]) - continue; - if (prev_[node] == -1 && next_[node] == -1) - continue; - if (prev_[node] == node) - continue; + if (visited_[node]) continue; + if (prev_[node] == -1 && next_[node] == -1) continue; + if (prev_[node] == node) continue; // Find start of path/circuit. int start = node; @@ -468,21 +443,19 @@ bool CircuitCoveringPropagator::Propagate() { FillFixedPathInReason(start, end, reason); const bool ok = trail_->EnqueueWithStoredReason(graph_[end][start].Negated()); - if (!ok) - return false; + if (!ok) return false; } } return true; } -std::function -ExactlyOnePerRowAndPerColumn(const std::vector > &graph) { - return[ = ](Model *model) { const int n = graph.size(); +std::function ExactlyOnePerRowAndPerColumn( + const std::vector > &graph) { + return [=](Model *model) { + const int n = graph.size(); std::vector exactly_one_constraint; exactly_one_constraint.reserve(n); - for (const bool transpose : { - false, true - }) { + for (const bool transpose : {false, true}) { for (int i = 0; i < n; ++i) { exactly_one_constraint.clear(); for (int j = 0; j < n; ++j) { @@ -492,15 +465,13 @@ ExactlyOnePerRowAndPerColumn(const std::vector > &graph) { model->Add(ExactlyOneConstraint(exactly_one_constraint)); } } - } - ; + }; } int ReindexArcs(std::vector *tails, std::vector *heads, std::vector *literals) { const int num_arcs = tails->size(); - if (num_arcs == 0) - return 0; + if (num_arcs == 0) return 0; // Put all nodes in a set. std::set nodes; @@ -524,12 +495,12 @@ int ReindexArcs(std::vector *tails, std::vector *heads, return nodes.size(); } -std::function -SubcircuitConstraint(int num_nodes, const std::vector &tails, - const std::vector &heads, - const std::vector &literals, - bool multiple_subcircuit_through_zero) { - return[ = ](Model *model) { const int num_arcs = tails.size(); +std::function SubcircuitConstraint( + int num_nodes, const std::vector &tails, const std::vector &heads, + const std::vector &literals, + bool multiple_subcircuit_through_zero) { + return [=](Model *model) { + const int num_arcs = tails.size(); CHECK_GT(num_arcs, 0); CHECK_EQ(heads.size(), num_arcs); CHECK_EQ(literals.size(), num_arcs); @@ -547,18 +518,14 @@ SubcircuitConstraint(int num_nodes, const std::vector &tails, exactly_one_incoming[head].push_back(literals[arc]); } for (int i = 0; i < exactly_one_incoming.size(); ++i) { - if (i == 0 && multiple_subcircuit_through_zero) - continue; + if (i == 0 && multiple_subcircuit_through_zero) continue; model->Add(ExactlyOneConstraint(exactly_one_incoming[i])); - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; } for (int i = 0; i < exactly_one_outgoing.size(); ++i) { - if (i == 0 && multiple_subcircuit_through_zero) - continue; + if (i == 0 && multiple_subcircuit_through_zero) continue; model->Add(ExactlyOneConstraint(exactly_one_outgoing[i])); - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; } CircuitPropagator::Options options; @@ -567,21 +534,19 @@ SubcircuitConstraint(int num_nodes, const std::vector &tails, num_nodes, tails, heads, literals, options, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -std::function -CircuitCovering(const std::vector > &graph, - const std::vector &distinguished_nodes) { - return[ = ](Model *model) { +std::function CircuitCovering( + const std::vector > &graph, + const std::vector &distinguished_nodes) { + return [=](Model *model) { CircuitCoveringPropagator *constraint = new CircuitCoveringPropagator(graph, distinguished_nodes, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/circuit.h b/ortools/sat/circuit.h index ca2c590679..a3c014f816 100644 --- a/ortools/sat/circuit.h +++ b/ortools/sat/circuit.h @@ -42,7 +42,7 @@ namespace sat { // constraints have been added for all the incoming (resp. outgoing) arcs of // each node. Also, such constraint must propagate before this one. class CircuitPropagator : PropagatorInterface, ReversibleInterface { -public: + public: struct Options { // Hack for the VRP to allow for more than one sub-circuit and forces all // the subcircuits to go through the node zero. @@ -61,7 +61,7 @@ public: bool IncrementalPropagate(const std::vector &watch_indices) final; void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // Updates the structures when the given arc is added to the paths. void AddArc(int tail, int head, LiteralIndex literal_index); @@ -96,8 +96,8 @@ private: int propagation_trail_index_ = 0; // Current partial chains of arc that are present. - std::vector next_; // -1 if not assigned yet. - std::vector prev_; // -1 if not assigned yet. + std::vector next_; // -1 if not assigned yet. + std::vector prev_; // -1 if not assigned yet. std::vector next_literal_; // Backtrack support for the partial chains of arcs, level_ends_[level] is an @@ -129,7 +129,7 @@ private: // TODO(user): Make distinguished nodes an array of Boolean variables, // so this can be used for facility location problems. class CircuitCoveringPropagator : PropagatorInterface, ReversibleInterface { -public: + public: CircuitCoveringPropagator(std::vector > graph, const std::vector &distinguished_nodes, Model *model); @@ -139,7 +139,7 @@ public: bool IncrementalPropagate(const std::vector &watch_indices) final; void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // Adds all literals on the path/circuit from tail to head in the graph of // literals set to true. // next_[i] should be filled with a node j s.t. graph_[i][j] is true, or -1. @@ -174,20 +174,19 @@ int ReindexArcs(std::vector *tails, std::vector *heads, // This just wraps CircuitPropagator. See the comment there to see what this // does. Note that any nodes with no outoing or no incoming arc will cause the // problem to be UNSAT. One can call ReindexArcs() first to ignore such nodes. -std::function - SubcircuitConstraint(int num_nodes, const std::vector &tails, - const std::vector &heads, - const std::vector &literals, - bool multiple_subcircuit_through_zero = false); +std::function SubcircuitConstraint( + int num_nodes, const std::vector &tails, const std::vector &heads, + const std::vector &literals, + bool multiple_subcircuit_through_zero = false); // TODO(user): Change to a sparse API like for the function above. std::function ExactlyOnePerRowAndPerColumn( const std::vector > &graph); -std::function - CircuitCovering(const std::vector > &graph, - const std::vector &distinguished_nodes); +std::function CircuitCovering( + const std::vector > &graph, + const std::vector &distinguished_nodes); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CIRCUIT_H_ +#endif // OR_TOOLS_SAT_CIRCUIT_H_ diff --git a/ortools/sat/clause.cc b/ortools/sat/clause.cc index 49df70dde5..4787f0eb53 100644 --- a/ortools/sat/clause.cc +++ b/ortools/sat/clause.cc @@ -34,8 +34,7 @@ template bool WatcherListContains(const std::vector &list, const SatClause &candidate) { for (const Watcher &watcher : list) { - if (watcher.clause == &candidate) - return true; + if (watcher.clause == &candidate) return true; } return false; } @@ -46,15 +45,17 @@ void RemoveIf(Container c, Predicate p) { c->erase(std::remove_if(c->begin(), c->end(), p), c->end()); } -} // namespace +} // namespace // ----- LiteralWatchers ----- LiteralWatchers::LiteralWatchers(Model *model) : SatPropagator("LiteralWatchers"), implication_graph_(model->GetOrCreate()), - trail_(model->GetOrCreate()), num_inspected_clauses_(0), - num_inspected_clause_literals_(0), num_watched_clauses_(0), + trail_(model->GetOrCreate()), + num_inspected_clauses_(0), + num_inspected_clause_literals_(0), + num_watched_clauses_(0), stats_("LiteralWatchers") { trail_->RegisterPropagator(this); } @@ -78,8 +79,8 @@ void LiteralWatchers::AttachOnFalse(Literal literal, Literal blocking_literal, SCOPED_TIME_STAT(&stats_); DCHECK(is_clean_); DCHECK(!WatcherListContains(watchers_on_false_[literal.Index()], *clause)); - watchers_on_false_[literal.Index()] - .push_back(Watcher(clause, blocking_literal)); + watchers_on_false_[literal.Index()].push_back( + Watcher(clause, blocking_literal)); } bool LiteralWatchers::PropagateOnFalse(Literal false_literal, Trail *trail) { @@ -128,16 +129,13 @@ bool LiteralWatchers::PropagateOnFalse(Literal false_literal, Trail *trail) { DCHECK_GE(start, 2); int i = start; - while (i < size && assignment.LiteralIsFalse(literals[i])) - ++i; + while (i < size && assignment.LiteralIsFalse(literals[i])) ++i; num_inspected_clause_literals_ += i - start + 2; if (i >= size) { i = 2; - while (i < start && assignment.LiteralIsFalse(literals[i])) - ++i; + while (i < start && assignment.LiteralIsFalse(literals[i])) ++i; num_inspected_clause_literals_ += i - 2; - if (i >= start) - i = size; + if (i >= start) i = size; } if (i < size) { // literal[i] is unassigned or true, it's now the new literal to watch. @@ -146,8 +144,8 @@ bool LiteralWatchers::PropagateOnFalse(Literal false_literal, Trail *trail) { literals[0] = other_watched_literal; literals[1] = literals[i]; literals[i] = false_literal; - watchers_on_false_[literals[1].Index()] - .emplace_back(it->clause, other_watched_literal, i + 1); + watchers_on_false_[literals[1].Index()].emplace_back( + it->clause, other_watched_literal, i + 1); continue; } } @@ -176,7 +174,7 @@ bool LiteralWatchers::PropagateOnFalse(Literal false_literal, Trail *trail) { *new_it++ = *it; } } - num_inspected_clause_literals_ += watchers.size(); // The blocking ones. + num_inspected_clause_literals_ += watchers.size(); // The blocking ones. watchers.erase(new_it, end); return true; } @@ -185,8 +183,7 @@ bool LiteralWatchers::Propagate(Trail *trail) { const int old_index = trail->Index(); while (trail->Index() == old_index && propagation_trail_index_ < old_index) { const Literal literal = (*trail)[propagation_trail_index_++]; - if (!PropagateOnFalse(literal.Negated(), trail)) - return false; + if (!PropagateOnFalse(literal.Negated(), trail)) return false; } return true; } @@ -211,9 +208,8 @@ bool LiteralWatchers::AddClause(absl::Span literals, return AttachAndPropagate(clause, trail); } -SatClause * -LiteralWatchers::AddRemovableClause(const std::vector &literals, - Trail *trail) { +SatClause *LiteralWatchers::AddRemovableClause( + const std::vector &literals, Trail *trail) { SatClause *clause = SatClause::Create(literals); clauses_.push_back(clause); CHECK(AttachAndPropagate(clause, trail)); @@ -247,8 +243,7 @@ bool LiteralWatchers::AttachAndPropagate(SatClause *clause, Trail *trail) { // Returns false if all the literals were false. // This should only happen on an UNSAT problem, and there is no need to attach // the clause in this case. - if (num_literal_not_false == 0) - return false; + if (num_literal_not_false == 0) return false; if (num_literal_not_false == 1) { // To maintain the validity of the 2-watcher algorithm, we need to watch @@ -289,9 +284,7 @@ void LiteralWatchers::InternalDetach(SatClause *clause) { --num_watched_clauses_; const size_t size = clause->size(); if (drat_proof_handler_ != nullptr && size > 2) { - drat_proof_handler_->DeleteClause({ - clause->begin(), size - }); + drat_proof_handler_->DeleteClause({clause->begin(), size}); } clauses_info_.erase(clause); clause->Clear(); @@ -306,19 +299,16 @@ void LiteralWatchers::LazyDetach(SatClause *clause) { void LiteralWatchers::Detach(SatClause *clause) { InternalDetach(clause); - for (const Literal l : { - clause->FirstLiteral(), clause->SecondLiteral() - }) { + for (const Literal l : {clause->FirstLiteral(), clause->SecondLiteral()}) { needs_cleaning_.Clear(l.Index()); - RemoveIf(&(watchers_on_false_[l.Index()]), [](const Watcher & watcher) { + RemoveIf(&(watchers_on_false_[l.Index()]), [](const Watcher &watcher) { return !watcher.clause->IsAttached(); }); } } void LiteralWatchers::DetachAllClauses() { - if (!all_clauses_are_attached_) - return; + if (!all_clauses_are_attached_) return; all_clauses_are_attached_ = false; // This is easy, and this allows to reset memory if some watcher lists where @@ -329,11 +319,10 @@ void LiteralWatchers::DetachAllClauses() { } void LiteralWatchers::AttachAllClauses() { - if (all_clauses_are_attached_) - return; + if (all_clauses_are_attached_) return; all_clauses_are_attached_ = true; - needs_cleaning_.ClearAll(); // This doesn't resize it. + needs_cleaning_.ClearAll(); // This doesn't resize it. watchers_on_false_.resize(needs_cleaning_.size().value()); DeleteRemovedClauses(); @@ -349,9 +338,7 @@ void LiteralWatchers::AttachAllClauses() { bool LiteralWatchers::InprocessingFixLiteral(Literal true_literal) { CHECK_EQ(trail_->CurrentDecisionLevel(), 0); if (drat_proof_handler_ != nullptr) { - drat_proof_handler_->AddClause({ - true_literal - }); + drat_proof_handler_->AddClause({true_literal}); } // TODO(user): remove the test when the DRAT issue with fixed literal is // resolved. @@ -378,8 +365,7 @@ void LiteralWatchers::InprocessingRemoveClause(SatClause *clause) { bool LiteralWatchers::InprocessingRewriteClause( SatClause *clause, absl::Span new_clause) { - if (new_clause.empty()) - return false; // UNSAT. + if (new_clause.empty()) return false; // UNSAT. if (DEBUG_MODE) { for (const Literal l : new_clause) { @@ -388,8 +374,7 @@ bool LiteralWatchers::InprocessingRewriteClause( } if (new_clause.size() == 1) { - if (!InprocessingFixLiteral(new_clause[0])) - return false; + if (!InprocessingFixLiteral(new_clause[0])) return false; InprocessingRemoveClause(clause); return true; } @@ -411,11 +396,9 @@ bool LiteralWatchers::InprocessingRewriteClause( // detach it in a non-lazy way. --num_watched_clauses_; clause->Clear(); - for (const Literal l : { - clause->FirstLiteral(), clause->SecondLiteral() - }) { + for (const Literal l : {clause->FirstLiteral(), clause->SecondLiteral()}) { needs_cleaning_.Clear(l.Index()); - RemoveIf(&(watchers_on_false_[l.Index()]), [](const Watcher & watcher) { + RemoveIf(&(watchers_on_false_[l.Index()]), [](const Watcher &watcher) { return !watcher.clause->IsAttached(); }); } @@ -424,13 +407,12 @@ bool LiteralWatchers::InprocessingRewriteClause( clause->Rewrite(new_clause); // And we re-attach it. - if (all_clauses_are_attached_) - Attach(clause, trail_); + if (all_clauses_are_attached_) Attach(clause, trail_); return true; } -SatClause * -LiteralWatchers::InprocessingAddClause(absl::Span new_clause) { +SatClause *LiteralWatchers::InprocessingAddClause( + absl::Span new_clause) { CHECK(!new_clause.empty()); CHECK(!all_clauses_are_attached_); if (DEBUG_MODE) { @@ -441,8 +423,7 @@ LiteralWatchers::InprocessingAddClause(absl::Span new_clause) { if (new_clause.size() == 1) { // TODO(user): We should return false... - if (!InprocessingFixLiteral(new_clause[0])) - return nullptr; + if (!InprocessingFixLiteral(new_clause[0])) return nullptr; return nullptr; } @@ -460,7 +441,7 @@ void LiteralWatchers::CleanUpWatchers() { SCOPED_TIME_STAT(&stats_); for (LiteralIndex index : needs_cleaning_.PositionsSetAtLeastOnce()) { DCHECK(needs_cleaning_[index]); - RemoveIf(&(watchers_on_false_[index]), [](const Watcher & watcher) { + RemoveIf(&(watchers_on_false_[index]), [](const Watcher &watcher) { return !watcher.clause->IsAttached(); }); needs_cleaning_.Clear(index); @@ -476,17 +457,16 @@ void LiteralWatchers::DeleteRemovedClauses() { if (to_minimize_index_ >= clauses_.size()) { to_minimize_index_ = clauses_.size(); } - to_minimize_index_ = std::stable_partition( - clauses_.begin(), clauses_.begin() + to_minimize_index_, - [](SatClause * a) { - return a->IsAttached(); - }) - clauses_.begin(); + to_minimize_index_ = + std::stable_partition(clauses_.begin(), + clauses_.begin() + to_minimize_index_, + [](SatClause *a) { return a->IsAttached(); }) - + clauses_.begin(); - // Do the proper deletion. - std::vector::iterator iter = std::stable_partition( - clauses_.begin(), clauses_.end(), [](SatClause * a) { - return a->IsAttached(); - }); + // Do the proper deletion. + std::vector::iterator iter = + std::stable_partition(clauses_.begin(), clauses_.end(), + [](SatClause *a) { return a->IsAttached(); }); gtl::STLDeleteContainerPointers(iter, clauses_.end()); clauses_.erase(iter, clauses_.end()); } @@ -510,14 +490,12 @@ void BinaryImplicationGraph::Resize(int num_variables) { void BinaryImplicationGraph::AddBinaryClause(Literal a, Literal b) { SCOPED_TIME_STAT(&stats_); if (drat_proof_handler_ != nullptr) { - // TODO(user): Like this we will duplicate all binary clause from the - // problem. However this leads to a simpler API (since we don't need to - // special case the loading of the original clauses) and we mainly use - // drat - // proof for testing anyway. - drat_proof_handler_->AddClause({ - a, b - }); + // TODO(user): Like this we will duplicate all binary clause from the + // problem. However this leads to a simpler API (since we don't need to + // special case the loading of the original clauses) and we mainly use + // drat + // proof for testing anyway. + drat_proof_handler_->AddClause({a, b}); } estimated_sizes_[a.NegatedIndex()]++; estimated_sizes_[b.NegatedIndex()]++; @@ -529,15 +507,13 @@ void BinaryImplicationGraph::AddBinaryClause(Literal a, Literal b) { bool BinaryImplicationGraph::AddBinaryClauseDuringSearch(Literal a, Literal b) { SCOPED_TIME_STAT(&stats_); - if (num_implications_ == 0) - propagation_trail_index_ = trail_->Index(); + if (num_implications_ == 0) propagation_trail_index_ = trail_->Index(); AddBinaryClause(a, b); const auto &assignment = trail_->Assignment(); if (assignment.LiteralIsFalse(a)) { if (assignment.LiteralIsAssigned(b)) { - if (assignment.LiteralIsFalse(b)) - return false; + if (assignment.LiteralIsFalse(b)) return false; } else { reasons_[trail_->Index()] = a; trail_->Enqueue(b, propagator_id_); @@ -552,11 +528,10 @@ bool BinaryImplicationGraph::AddBinaryClauseDuringSearch(Literal a, Literal b) { return true; } -bool -BinaryImplicationGraph::AddAtMostOne(absl::Span at_most_one) { +bool BinaryImplicationGraph::AddAtMostOne( + absl::Span at_most_one) { CHECK_EQ(trail_->CurrentDecisionLevel(), 0); - if (at_most_one.size() <= 1) - return true; + if (at_most_one.size() <= 1) return true; // Temporarily copy the at_most_one constraint at the end of // at_most_one_buffer_. It will be cleaned up and added by @@ -573,15 +548,11 @@ BinaryImplicationGraph::AddAtMostOne(absl::Span at_most_one) { // TODO(user): remove duplication with // LiteralWatchers::InprocessingFixLiteral(); bool BinaryImplicationGraph::FixLiteral(Literal true_literal) { - if (trail_->Assignment().LiteralIsTrue(true_literal)) - return true; - if (trail_->Assignment().LiteralIsFalse(true_literal)) - return false; + if (trail_->Assignment().LiteralIsTrue(true_literal)) return true; + if (trail_->Assignment().LiteralIsFalse(true_literal)) return false; if (drat_proof_handler_ != nullptr) { - drat_proof_handler_->AddClause({ - true_literal - }); + drat_proof_handler_->AddClause({true_literal}); } trail_->EnqueueWithUnitReason(true_literal); @@ -596,8 +567,7 @@ bool BinaryImplicationGraph::CleanUpAndAddAtMostOnes(const int base_index) { int local_end = base_index; const int buffer_size = at_most_one_buffer_.size(); for (int i = base_index; i < buffer_size; ++i) { - if (at_most_one_buffer_[i].Index() == kNoLiteralIndex) - continue; + if (at_most_one_buffer_[i].Index() == kNoLiteralIndex) continue; // Process a new at most one. // It will be copied into buffer[local_start, local_end]. @@ -605,12 +575,9 @@ bool BinaryImplicationGraph::CleanUpAndAddAtMostOnes(const int base_index) { bool set_all_left_to_false = false; for (;; ++i) { const Literal l = at_most_one_buffer_[i]; - if (l.Index() == kNoLiteralIndex) - break; - if (assignment.LiteralIsFalse(l)) - continue; - if (is_removed_[l.Index()]) - continue; + if (l.Index() == kNoLiteralIndex) break; + if (assignment.LiteralIsFalse(l)) continue; + if (is_removed_[l.Index()]) continue; if (!set_all_left_to_false && assignment.LiteralIsTrue(l)) { set_all_left_to_false = true; continue; @@ -622,12 +589,9 @@ bool BinaryImplicationGraph::CleanUpAndAddAtMostOnes(const int base_index) { if (set_all_left_to_false) { for (int j = local_start; j < local_end; ++j) { const Literal l = at_most_one_buffer_[j]; - if (assignment.LiteralIsFalse(l)) - continue; - if (assignment.LiteralIsTrue(l)) - return false; - if (!FixLiteral(l.Negated())) - return false; + if (assignment.LiteralIsFalse(l)) continue; + if (assignment.LiteralIsTrue(l)) return false; + if (!FixLiteral(l.Negated())) return false; } local_end = local_start; continue; @@ -643,11 +607,9 @@ bool BinaryImplicationGraph::CleanUpAndAddAtMostOnes(const int base_index) { const Literal l = at_most_one_buffer_[j]; if (new_local_end > local_start && l == at_most_one_buffer_[new_local_end - 1]) { - if (assignment.LiteralIsTrue(l)) - return false; + if (assignment.LiteralIsTrue(l)) return false; if (!assignment.LiteralIsFalse(l)) { - if (!FixLiteral(l.Negated())) - return false; + if (!FixLiteral(l.Negated())) return false; } --new_local_end; continue; @@ -667,8 +629,7 @@ bool BinaryImplicationGraph::CleanUpAndAddAtMostOnes(const int base_index) { // Note that his automatically skip size 0 and 1. for (const Literal a : at_most_one) { for (const Literal b : at_most_one) { - if (a == b) - continue; + if (a == b) continue; implications_[a.Index()].push_back(b.Negated()); } } @@ -721,7 +682,7 @@ bool BinaryImplicationGraph::PropagateOnTrue(Literal true_literal, ++num_propagations_; if (assignment.LiteralIsFalse(literal)) { // Conflict. - *(trail->MutableConflict()) = { true_literal.Negated(), literal }; + *(trail->MutableConflict()) = {true_literal.Negated(), literal}; return false; } else { // Propagation. @@ -736,8 +697,7 @@ bool BinaryImplicationGraph::PropagateOnTrue(Literal true_literal, bool seen = false; for (int i = start;; ++i) { const Literal literal = at_most_one_buffer_[i]; - if (literal.Index() == kNoLiteralIndex) - break; + if (literal.Index() == kNoLiteralIndex) break; ++num_inspections_; if (literal == true_literal) { @@ -747,14 +707,13 @@ bool BinaryImplicationGraph::PropagateOnTrue(Literal true_literal, } continue; } - if (assignment.LiteralIsFalse(literal)) - continue; + if (assignment.LiteralIsFalse(literal)) continue; ++num_propagations_; if (assignment.LiteralIsTrue(literal)) { // Conflict. - *(trail->MutableConflict()) = { true_literal.Negated(), - literal.Negated() }; + *(trail->MutableConflict()) = {true_literal.Negated(), + literal.Negated()}; return false; } else { // Propagation. @@ -775,15 +734,14 @@ bool BinaryImplicationGraph::Propagate(Trail *trail) { } while (propagation_trail_index_ < trail->Index()) { const Literal literal = (*trail)[propagation_trail_index_++]; - if (!PropagateOnTrue(literal, trail)) - return false; + if (!PropagateOnTrue(literal, trail)) return false; } return true; } -absl::Span -BinaryImplicationGraph::Reason(const Trail &trail, int trail_index) const { - return { &reasons_[trail_index], 1 }; +absl::Span BinaryImplicationGraph::Reason( + const Trail &trail, int trail_index) const { + return {&reasons_[trail_index], 1}; } // Here, we remove all the literal whose negation are implied by the negation of @@ -817,8 +775,7 @@ void BinaryImplicationGraph::MinimizeConflictWithReachability( // redundant implications from this list at the same time. auto &direct_implications = implications_[root_literal_index]; for (const Literal l : direct_implications) { - if (is_marked_[l.Index()]) - continue; + if (is_marked_[l.Index()]) continue; dfs_stack_.push_back(l); while (!dfs_stack_.empty()) { const LiteralIndex index = dfs_stack_.back().Index(); @@ -826,8 +783,7 @@ void BinaryImplicationGraph::MinimizeConflictWithReachability( if (!is_marked_[index]) { is_marked_.Set(index); for (Literal implied : implications_[index]) { - if (!is_marked_[implied.Index()]) - dfs_stack_.push_back(implied); + if (!is_marked_[implied.Index()]) dfs_stack_.push_back(implied); } } } @@ -922,8 +878,7 @@ void BinaryImplicationGraph::MinimizeConflictFirstWithTransitiveReduction( if (!is_marked_[index]) { is_marked_.Set(index); for (Literal implied : implications_[index]) { - if (!is_marked_[implied.Index()]) - dfs_stack_.push_back(implied); + if (!is_marked_[implied.Index()]) dfs_stack_.push_back(implied); } } } @@ -1010,8 +965,7 @@ void BinaryImplicationGraph::RemoveFixedVariables() { // Nothing to do if nothing changed since last call. const int new_num_fixed = trail_->Index(); - if (num_processed_fixed_variables_ == new_num_fixed) - return; + if (num_processed_fixed_variables_ == new_num_fixed) return; const VariablesAssignment &assignment = trail_->Assignment(); is_marked_.ClearAndResize(LiteralIndex(implications_.size())); @@ -1048,7 +1002,7 @@ void BinaryImplicationGraph::RemoveFixedVariables() { } } for (const LiteralIndex i : is_marked_.PositionsSetAtLeastOnce()) { - RemoveIf(&implications_[i], [&assignment](const Literal & lit) { + RemoveIf(&implications_[i], [&assignment](const Literal &lit) { return assignment.LiteralIsTrue(lit); }); } @@ -1056,22 +1010,25 @@ void BinaryImplicationGraph::RemoveFixedVariables() { // TODO(user): This might be a bit slow. Do not call all the time if needed, // this shouldn't change the correctness of the code. at_most_ones_.clear(); - CleanUpAndAddAtMostOnes(/*base_index=*/ 0); + CleanUpAndAddAtMostOnes(/*base_index=*/0); } class SccGraph { -public: + public: using Implication = gtl::ITIVector >; using AtMostOne = gtl::ITIVector >; - using SccFinder = StronglyConnectedComponentsFinder< - int32, SccGraph, std::vector > >; + using SccFinder = + StronglyConnectedComponentsFinder > >; explicit SccGraph(SccFinder *finder, Implication *graph, AtMostOne *at_most_ones, std::vector *at_most_one_buffer) - : finder_(*finder), implications_(*graph), at_most_ones_(*at_most_ones), + : finder_(*finder), + implications_(*graph), + at_most_ones_(*at_most_ones), at_most_one_buffer_(*at_most_one_buffer) {} const std::vector &operator[](int32 node) const { @@ -1121,8 +1078,8 @@ public: } else { // The first node is already settled and so are all its child. Only // not(first_node) might still need exploring. - tmp_.push_back(Literal(LiteralIndex(first_node)) - .NegatedIndex().value()); + tmp_.push_back( + Literal(LiteralIndex(first_node)).NegatedIndex().value()); continue; } } else { @@ -1132,10 +1089,8 @@ public: for (int i = start;; ++i) { const Literal l = at_most_one_buffer_[i]; - if (l.Index() == kNoLiteralIndex) - break; - if (l.Index() == node) - continue; + if (l.Index() == kNoLiteralIndex) break; + if (l.Index() == node) continue; tmp_.push_back(l.NegatedIndex().value()); if (finder_.NodeIsInCurrentDfsPath(l.Index().value())) { to_fix_.push_back(l.Negated()); @@ -1153,7 +1108,7 @@ public: // For the deterministic time. mutable int64 work_done_ = 0; -private: + private: const SccFinder &finder_; const Implication &implications_; const AtMostOne &at_most_ones_; @@ -1169,15 +1124,13 @@ private: bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { // This was already called, and no new constraint where added. Note that new // fixed variable cannote create new equivalence, only new binary clauses do. - if (is_dag_) - return true; + if (is_dag_) return true; WallTimer wall_timer; wall_timer.Start(); log_info |= VLOG_IS_ON(1); // Lets remove all fixed variables first. - if (!Propagate(trail_)) - return false; + if (!Propagate(trail_)) return false; RemoveFixedVariables(); const VariablesAssignment &assignment = trail_->Assignment(); @@ -1194,13 +1147,10 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { dtime += 4e-8 * graph.work_done_; for (const Literal l : graph.to_fix_) { - if (assignment.LiteralIsFalse(l)) - return false; - if (assignment.LiteralIsTrue(l)) - continue; + if (assignment.LiteralIsFalse(l)) return false; + if (assignment.LiteralIsTrue(l)) continue; ++num_fixed_during_scc; - if (!FixLiteral(l)) - return false; + if (!FixLiteral(l)) return false; } } @@ -1236,13 +1186,10 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { is_redundant_[l.Index()] = true; } const Literal to_fix = all_true ? l : l.Negated(); - if (assignment.LiteralIsFalse(to_fix)) - return false; - if (assignment.LiteralIsTrue(to_fix)) - continue; + if (assignment.LiteralIsFalse(to_fix)) return false; + if (assignment.LiteralIsTrue(to_fix)) continue; ++num_fixed_during_scc; - if (!FixLiteral(l)) - return false; + if (!FixLiteral(l)) return false; } // Next component. @@ -1271,10 +1218,8 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { auto &representative_list = implications_[representative]; for (Literal &ref : representative_list) { const LiteralIndex rep = representative_of_[ref.Index()]; - if (rep == representative) - continue; - if (rep == kNoLiteralIndex) - continue; + if (rep == representative) continue; + if (rep == kNoLiteralIndex) continue; ref = Literal(rep); } gtl::STLSortAndRemoveDuplicates(&representative_list); @@ -1305,8 +1250,7 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { int new_size = 0; for (const Literal l : representative_list) { const Literal rep = RepresentativeOf(l); - if (rep.Index() == representative) - continue; + if (rep.Index() == representative) continue; representative_list[new_size++] = rep; } representative_list.resize(new_size); @@ -1315,8 +1259,7 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { auto &ref = implications_[literal.Index()]; for (const Literal l : ref) { const Literal rep = RepresentativeOf(l); - if (rep.Index() != representative) - representative_list.push_back(rep); + if (rep.Index() != representative) representative_list.push_back(rep); } // Add representative <=> literal. @@ -1338,7 +1281,7 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { // that this might result in more implications when we expand small at most // one. at_most_ones_.clear(); - CleanUpAndAddAtMostOnes(/*base_index=*/ 0); + CleanUpAndAddAtMostOnes(/*base_index=*/0); num_implications_ = 0; for (LiteralIndex i(0); i < size; ++i) { @@ -1348,12 +1291,15 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { } time_limit_->AdvanceDeterministicTime(dtime); - LOG_IF(INFO, log_info) - << "SCC. " << num_equivalences << " redundant equivalent literals. " - << num_fixed_during_scc << " fixed. " << num_implications_ - << " implications left. " << implications_.size() << " literals." - << " size of at_most_one buffer = " << at_most_one_buffer_.size() << "." - << " dtime: " << dtime << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "SCC. " << num_equivalences + << " redundant equivalent literals. " + << num_fixed_during_scc << " fixed. " + << num_implications_ << " implications left. " + << implications_.size() << " literals." + << " size of at_most_one buffer = " + << at_most_one_buffer_.size() << "." + << " dtime: " << dtime + << " wtime: " << wall_timer.Get(); return true; } @@ -1364,14 +1310,12 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) { // the antecedants of these. bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { CHECK_EQ(trail_->CurrentDecisionLevel(), 0); - if (!DetectEquivalences()) - return false; + if (!DetectEquivalences()) return false; // TODO(user): the situation with fixed variable is not really "clean". // Simplify the code so we are sure we don't run into issue or have to deal // with any of that here. - if (!Propagate(trail_)) - return false; + if (!Propagate(trail_)) return false; RemoveFixedVariables(); log_info |= VLOG_IS_ON(1); @@ -1407,14 +1351,11 @@ bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { // or removed variables. But the reverse_topological_order_ is only // recomputed when new binary are added to the graph, not when new variable // are fixed. - if (is_redundant_[root]) - continue; - if (trail_->Assignment().LiteralIsAssigned(Literal(root))) - continue; + if (is_redundant_[root]) continue; + if (trail_->Assignment().LiteralIsAssigned(Literal(root))) continue; auto &direct_implications = implications_[root]; - if (direct_implications.empty()) - continue; + if (direct_implications.empty()) continue; // This is a "poor" version of the tree look stuff, but it does show good // improvement. If we just processed one of the child of root, we don't @@ -1438,15 +1379,12 @@ bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { previous = root; for (const Literal direct_child : direct_implications) { - if (is_redundant_[direct_child.Index()]) - continue; - if (is_marked_[direct_child.Index()]) - continue; + if (is_redundant_[direct_child.Index()]) continue; + if (is_marked_[direct_child.Index()]) continue; // This is a corner case where because of equivalent literal, root // appear in implications_[root], we will remove it below. - if (direct_child.Index() == root) - continue; + if (direct_child.Index() == root) continue; // When this happens, then root must be false, we handle this just after // the loop. @@ -1478,8 +1416,7 @@ bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { // need to consider all antecedants of root in the transitive // reduction. ++num_fixed; - if (!FixLiteral(Literal(root).Negated())) - return false; + if (!FixLiteral(Literal(root).Negated())) return false; break; } } @@ -1487,8 +1424,7 @@ bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { // Note that direct_implications will be cleared by // RemoveFixedVariables() that will need to inspect it to completely // remove Literal(root) from all lists. - if (trail_->Assignment().LiteralIsAssigned(Literal(root))) - continue; + if (trail_->Assignment().LiteralIsAssigned(Literal(root))) continue; // Only keep the non-marked literal (and the redundant one which are never // marked). We mark root to remove it in the corner case where it was @@ -1519,12 +1455,14 @@ bool BinaryImplicationGraph::ComputeTransitiveReduction(bool log_info) { const double dtime = 1e-8 * work_done_in_mark_descendants_; time_limit_->AdvanceDeterministicTime(dtime); num_redundant_implications_ += num_new_redundant_implications; - LOG_IF(INFO, log_info) - << "Transitive reduction removed " << num_new_redundant_implications - << " literals. " << num_fixed << " fixed. " << num_implications_ - << " implications left. " << implications_.size() << " literals." - << " dtime: " << dtime << " wtime: " << wall_timer.Get() - << (aborted ? " Aborted." : ""); + LOG_IF(INFO, log_info) << "Transitive reduction removed " + << num_new_redundant_implications << " literals. " + << num_fixed << " fixed. " << num_implications_ + << " implications left. " << implications_.size() + << " literals." + << " dtime: " << dtime + << " wtime: " << wall_timer.Get() + << (aborted ? " Aborted." : ""); return true; } @@ -1536,8 +1474,7 @@ bool IntersectionIsEmpty(const std::vector &a, const std::vector &b) { int i = 0; int j = 0; for (; i < a.size() && j < b.size();) { - if (a[i] == b[j]) - return false; + if (a[i] == b[j]) return false; if (a[i] < b[j]) { ++i; } else { @@ -1558,14 +1495,13 @@ struct VectorHash { } }; -} // namespace +} // namespace bool BinaryImplicationGraph::TransformIntoMaxCliques( std::vector > *at_most_ones, int64 max_num_explored_nodes) { // The code below assumes a DAG. - if (!DetectEquivalences()) - return false; + if (!DetectEquivalences()) return false; work_done_in_mark_descendants_ = 0; int num_extended = 0; @@ -1576,11 +1512,11 @@ bool BinaryImplicationGraph::TransformIntoMaxCliques( gtl::ITIVector > max_cliques_containing( implications_.size()); - // We starts by processing larger constraints first. + // We starts by processing larger constraints first. std::sort(at_most_ones->begin(), at_most_ones->end(), [](const std::vector a, const std::vector b) { - return a.size() > b.size(); - }); + return a.size() > b.size(); + }); for (std::vector &clique : *at_most_ones) { const int old_size = clique.size(); @@ -1593,8 +1529,7 @@ bool BinaryImplicationGraph::TransformIntoMaxCliques( for (Literal &ref : clique) { DCHECK_LT(ref.Index(), representative_of_.size()); const LiteralIndex rep = representative_of_[ref.Index()]; - if (rep == kNoLiteralIndex) - continue; + if (rep == kNoLiteralIndex) continue; ref = Literal(rep); } @@ -1626,8 +1561,7 @@ bool BinaryImplicationGraph::TransformIntoMaxCliques( for (const Literal l : clique) { max_cliques_containing[l.Index()].push_back(clique_index); } - if (clique.size() > old_size) - ++num_extended; + if (clique.size() > old_size) ++num_extended; ++num_added; } @@ -1649,22 +1583,18 @@ std::vector BinaryImplicationGraph::ExpandAtMostOneWithWeight( std::vector intersection; double clique_weight = 0.0; const int64 old_work = work_done_in_mark_descendants_; - for (const Literal l : clique) - clique_weight += expanded_lp_values[l.Index()]; + for (const Literal l : clique) clique_weight += expanded_lp_values[l.Index()]; for (int i = 0; i < clique.size(); ++i) { // Do not spend too much time here. - if (work_done_in_mark_descendants_ - old_work > 1e8) - break; + if (work_done_in_mark_descendants_ - old_work > 1e8) break; is_marked_.ClearAndResize(LiteralIndex(implications_.size())); MarkDescendants(clique[i]); if (i == 0) { for (const LiteralIndex index : is_marked_.PositionsSetAtLeastOnce()) { - if (can_be_included[index]) - intersection.push_back(index); + if (can_be_included[index]) intersection.push_back(index); } - for (const Literal l : clique) - is_marked_.Clear(l.NegatedIndex()); + for (const Literal l : clique) is_marked_.Clear(l.NegatedIndex()); } int new_size = 0; @@ -1672,14 +1602,12 @@ std::vector BinaryImplicationGraph::ExpandAtMostOneWithWeight( is_marked_.Clear(clique[i].Index()); is_marked_.Clear(clique[i].NegatedIndex()); for (const LiteralIndex index : intersection) { - if (!is_marked_[index]) - continue; + if (!is_marked_[index]) continue; intersection[new_size++] = index; intersection_weight += expanded_lp_values[index]; } intersection.resize(new_size); - if (intersection.empty()) - break; + if (intersection.empty()) break; // We can't generate a violated cut this way. This is because intersection // contains all the possible ways to extend the current clique. @@ -1713,10 +1641,10 @@ std::vector BinaryImplicationGraph::ExpandAtMostOneWithWeight( return clique; } -const std::vector > & -BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( - const std::vector &literals, - const std::vector &lp_values) { +const std::vector > + &BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( + const std::vector &literals, + const std::vector &lp_values) { // We only want to generate a cut with literals from the LP, not extra ones. const int num_literals = implications_.size(); gtl::ITIVector can_be_included(num_literals, false); @@ -1750,10 +1678,8 @@ BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( for (int i = 0; i < size; ++i) { Literal current_literal = literals[i]; double current_value = lp_values[i]; - if (trail_->Assignment().LiteralIsAssigned(current_literal)) - continue; - if (is_redundant_[current_literal.Index()]) - continue; + if (trail_->Assignment().LiteralIsAssigned(current_literal)) continue; + if (is_redundant_[current_literal.Index()]) continue; if (current_value < 0.5) { current_literal = current_literal.Negated(); @@ -1764,12 +1690,10 @@ BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( LiteralIndex best = kNoLiteralIndex; double best_value = 0.0; for (const Literal l : implications_[current_literal.Index()]) { - if (!can_be_included[l.Index()]) - continue; + if (!can_be_included[l.Index()]) continue; const double activity = current_value + expanded_lp_values[l.NegatedIndex()]; - if (activity <= 1.01) - continue; + if (activity <= 1.01) continue; const double v = activity + absl::Uniform(*random_, 0.0, 1e-4); if (best == kNoLiteralIndex || v > best_value) { best_value = v; @@ -1778,9 +1702,7 @@ BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( } if (best != kNoLiteralIndex) { const double activity = current_value + expanded_lp_values[best]; - candidates.push_back({ - current_literal, Literal(best), activity - }); + candidates.push_back({current_literal, Literal(best), activity}); } } @@ -1796,23 +1718,18 @@ BinaryImplicationGraph::GenerateAtMostOnesWithLargeWeight( tmp_cuts_.clear(); std::vector at_most_one; for (const Candidate &candidate : candidates) { - at_most_one = - ExpandAtMostOneWithWeight({ - candidate.a, candidate.b - }, - can_be_included, expanded_lp_values); - if (!at_most_one.empty()) - tmp_cuts_.push_back(at_most_one); + at_most_one = ExpandAtMostOneWithWeight( + {candidate.a, candidate.b}, can_be_included, expanded_lp_values); + if (!at_most_one.empty()) tmp_cuts_.push_back(at_most_one); } return tmp_cuts_; } // We use dfs_stack_ but we actually do a BFS. void BinaryImplicationGraph::MarkDescendants(Literal root) { - dfs_stack_ = { root }; + dfs_stack_ = {root}; is_marked_.Set(root.Index()); - if (is_redundant_[root.Index()]) - return; + if (is_redundant_[root.Index()]) return; for (int j = 0; j < dfs_stack_.size(); ++j) { const Literal current = dfs_stack_[j]; for (const Literal l : implications_[current.Index()]) { @@ -1822,15 +1739,12 @@ void BinaryImplicationGraph::MarkDescendants(Literal root) { } } - if (current.Index() >= at_most_ones_.size()) - continue; + if (current.Index() >= at_most_ones_.size()) continue; for (const int start : at_most_ones_[current.Index()]) { for (int i = start;; ++i) { const Literal l = at_most_one_buffer_[i]; - if (l.Index() == kNoLiteralIndex) - break; - if (l == current) - continue; + if (l.Index() == kNoLiteralIndex) break; + if (l == current) continue; if (!is_marked_[l.NegatedIndex()] && !is_redundant_[l.NegatedIndex()]) { dfs_stack_.push_back(l.Negated()); is_marked_.Set(l.NegatedIndex()); @@ -1859,19 +1773,16 @@ std::vector BinaryImplicationGraph::ExpandAtMostOne( MarkDescendants(clique[i]); if (i == 0) { intersection = is_marked_.PositionsSetAtLeastOnce(); - for (const Literal l : clique) - is_marked_.Clear(l.NegatedIndex()); + for (const Literal l : clique) is_marked_.Clear(l.NegatedIndex()); } int new_size = 0; - is_marked_.Clear(clique[i].NegatedIndex()); // TODO(user): explain. + is_marked_.Clear(clique[i].NegatedIndex()); // TODO(user): explain. for (const LiteralIndex index : intersection) { - if (is_marked_[index]) - intersection[new_size++] = index; + if (is_marked_[index]) intersection[new_size++] = index; } intersection.resize(new_size); - if (intersection.empty()) - break; + if (intersection.empty()) break; // Expand? if (i + 1 == clique.size()) { @@ -1884,8 +1795,8 @@ std::vector BinaryImplicationGraph::ExpandAtMostOne( // TODO(user): lazy cleanup the lists on is_removed_? // TODO(user): Mark fixed variable as is_removed_ for faster iteration? -const std::vector & -BinaryImplicationGraph::DirectImplications(Literal literal) { +const std::vector &BinaryImplicationGraph::DirectImplications( + Literal literal) { CHECK(!is_removed_[literal.Index()]); // Clear old state. @@ -1898,10 +1809,8 @@ BinaryImplicationGraph::DirectImplications(Literal literal) { const VariablesAssignment &assignment = trail_->Assignment(); CHECK(!assignment.LiteralIsAssigned(literal)); for (const Literal l : implications_[literal.Index()]) { - if (l == literal) - continue; - if (assignment.LiteralIsAssigned(l)) - continue; + if (l == literal) continue; + if (assignment.LiteralIsAssigned(l)) continue; if (!is_removed_[l.Index()] && !in_direct_implications_[l.Index()]) { in_direct_implications_[l.Index()] = true; direct_implications_.push_back(l); @@ -1914,12 +1823,9 @@ BinaryImplicationGraph::DirectImplications(Literal literal) { for (const int start : at_most_ones_[literal.Index()]) { for (int i = start;; ++i) { const Literal l = at_most_one_buffer_[i]; - if (l.Index() == kNoLiteralIndex) - break; - if (l == literal) - continue; - if (assignment.LiteralIsAssigned(l)) - continue; + if (l.Index() == kNoLiteralIndex) break; + if (l == literal) continue; + if (assignment.LiteralIsAssigned(l)) continue; if (!is_removed_[l.Index()] && !in_direct_implications_[l.NegatedIndex()]) { in_direct_implications_[l.NegatedIndex()] = true; @@ -1935,16 +1841,15 @@ BinaryImplicationGraph::DirectImplications(Literal literal) { bool BinaryImplicationGraph::FindFailedLiteralAroundVar(BooleanVariable var, bool *is_unsat) { const int saved_index = propagation_trail_index_; - CHECK_EQ(propagation_trail_index_, trail_->Index()); // Propagation done. + CHECK_EQ(propagation_trail_index_, trail_->Index()); // Propagation done. const VariablesAssignment &assignment = trail_->Assignment(); - if (assignment.VariableIsAssigned(var)) - return false; + if (assignment.VariableIsAssigned(var)) return false; const Literal literal(var, true); direct_implications_of_negated_literal_ = DirectImplications(literal.Negated()); - DirectImplications(literal); // Fill in_direct_implications_. + DirectImplications(literal); // Fill in_direct_implications_. for (const Literal l : direct_implications_of_negated_literal_) { if (in_direct_implications_[l.Index()]) { // not(l) => literal => l. @@ -1958,8 +1863,8 @@ bool BinaryImplicationGraph::FindFailedLiteralAroundVar(BooleanVariable var, return propagation_trail_index_ > saved_index; } -int64 -BinaryImplicationGraph::NumImplicationOnVariableRemoval(BooleanVariable var) { +int64 BinaryImplicationGraph::NumImplicationOnVariableRemoval( + BooleanVariable var) { const Literal literal(var, true); int64 result = 0; direct_implications_of_negated_literal_ = @@ -1972,8 +1877,7 @@ BinaryImplicationGraph::NumImplicationOnVariableRemoval(BooleanVariable var) { CHECK(!in_direct_implications_[l.Index()]); // l => literal => l: equivalent variable! - if (in_direct_implications_[l.NegatedIndex()]) - result--; + if (in_direct_implications_[l.NegatedIndex()]) result--; } return result; } @@ -1987,8 +1891,7 @@ void BinaryImplicationGraph::RemoveBooleanVariable( for (const Literal b : DirectImplications(literal)) { estimated_sizes_[b.NegatedIndex()]--; for (const Literal a_negated : direct_implications_of_negated_literal_) { - if (a_negated.Negated() == b) - continue; + if (a_negated.Negated() == b) continue; AddImplication(a_negated.Negated(), b); } } @@ -2000,31 +1903,21 @@ void BinaryImplicationGraph::RemoveBooleanVariable( // Note that we want var first in these clauses for the postsolve. for (const Literal b : direct_implications_) { if (drat_proof_handler_ != nullptr) { - drat_proof_handler_->DeleteClause({ - Literal(var, false), b - }); + drat_proof_handler_->DeleteClause({Literal(var, false), b}); } - postsolve_clauses->push_back({ - Literal(var, false), b - }); + postsolve_clauses->push_back({Literal(var, false), b}); } for (const Literal a_negated : direct_implications_of_negated_literal_) { if (drat_proof_handler_ != nullptr) { - drat_proof_handler_->DeleteClause({ - Literal(var, true), a_negated - }); + drat_proof_handler_->DeleteClause({Literal(var, true), a_negated}); } - postsolve_clauses->push_back({ - Literal(var, true), a_negated - }); + postsolve_clauses->push_back({Literal(var, true), a_negated}); } - // We need to remove any occurrence of var in our implication lists, this - // will - // be delayed to the CleanupAllRemovedVariables() call. - for (LiteralIndex index : { - literal.Index(), literal.NegatedIndex() - }) { + // We need to remove any occurrence of var in our implication lists, this + // will + // be delayed to the CleanupAllRemovedVariables() call. + for (LiteralIndex index : {literal.Index(), literal.NegatedIndex()}) { is_removed_[index] = true; if (!is_redundant_[index]) { ++num_redundant_literals_; @@ -2038,15 +1931,14 @@ void BinaryImplicationGraph::CleanupAllRemovedVariables() { for (auto &implication : implications_) { int new_size = 0; for (const Literal l : implication) { - if (!is_removed_[l.Index()]) - implication[new_size++] = l; + if (!is_removed_[l.Index()]) implication[new_size++] = l; } implication.resize(new_size); } // Clean-up at most ones. at_most_ones_.clear(); - CleanUpAndAddAtMostOnes(/*base_index=*/ 0); + CleanUpAndAddAtMostOnes(/*base_index=*/0); } // ----- SatClause ----- @@ -2079,8 +1971,7 @@ bool SatClause::RemoveFixedLiteralsAndTestIfTrue( } for (int i = j; i < size_; ++i) { if (assignment.VariableIsAssigned(literals_[i].Variable())) { - if (assignment.LiteralIsTrue(literals_[i])) - return true; + if (assignment.LiteralIsTrue(literals_[i])) return true; } else { std::swap(literals_[j], literals_[i]); ++j; @@ -2092,8 +1983,7 @@ bool SatClause::RemoveFixedLiteralsAndTestIfTrue( bool SatClause::IsSatisfied(const VariablesAssignment &assignment) const { for (const Literal literal : *this) { - if (assignment.LiteralIsTrue(literal)) - return true; + if (assignment.LiteralIsTrue(literal)) return true; } return false; } @@ -2101,12 +1991,11 @@ bool SatClause::IsSatisfied(const VariablesAssignment &assignment) const { std::string SatClause::DebugString() const { std::string result; for (const Literal literal : *this) { - if (!result.empty()) - result.append(" "); + if (!result.empty()) result.append(" "); result.append(literal.DebugString()); } return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/clause.h b/ortools/sat/clause.h index ef64a9957b..df0fd3a12a 100644 --- a/ortools/sat/clause.h +++ b/ortools/sat/clause.h @@ -49,7 +49,7 @@ namespace sat { // the critical propagation code, we use this class to remove one memory // indirection. class SatClause { -public: + public: // Creates a sat clause. There must be at least 2 literals. Smaller clause are // treated separatly and never constructed. In practice, we do use // BinaryImplicationGraph for the clause of size 2, so this is mainly used for @@ -58,7 +58,7 @@ public: // Non-sized delete because this is a tail-padded class. void operator delete(void *p) { - ::operator delete(p); // non-sized delete + ::operator delete(p); // non-sized delete } // Number of literals in the clause. @@ -109,7 +109,7 @@ public: std::string DebugString() const; -private: + private: // LiteralWatchers needs to permute the order of literals in the clause and // call Clear()/Rewrite. friend class LiteralWatchers; @@ -125,8 +125,7 @@ private: // be attached when this is called. void Rewrite(absl::Span new_clause) { size_ = 0; - for (const Literal l : new_clause) - literals_[size_++] = l; + for (const Literal l : new_clause) literals_[size_++] = l; } int32 size_; @@ -159,7 +158,7 @@ class BinaryImplicationGraph; // TODO(user): Rename ClauseManager. This does more than just watching the // clauses and is the place where all the clauses are stored. class LiteralWatchers : public SatPropagator { -public: + public: explicit LiteralWatchers(Model *model); ~LiteralWatchers() override; @@ -168,8 +167,8 @@ public: // SatPropagator API. bool Propagate(Trail *trail) final; - absl::Span Reason(const Trail &trail, int trail_index) const - final; + absl::Span Reason(const Trail &trail, + int trail_index) const final; // Returns the reason of the variable at given trail_index. This only works // for variable propagated by this class and is almost the same as Reason() @@ -246,8 +245,7 @@ public: // by the problem clauses and then the learned one that we keep forever. SatClause *NextClauseToMinimize() { for (; to_minimize_index_ < clauses_.size(); ++to_minimize_index_) { - if (!clauses_[to_minimize_index_]->IsAttached()) - continue; + if (!clauses_[to_minimize_index_]->IsAttached()) continue; if (!IsRemovable(clauses_[to_minimize_index_])) { return clauses_[to_minimize_index_++]; } @@ -276,9 +274,8 @@ public: // These must only be called between [Detach/Attach]AllClauses() calls. void InprocessingRemoveClause(SatClause *clause); ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(Literal true_literal); - ABSL_MUST_USE_RESULT bool - InprocessingRewriteClause(SatClause *clause, - absl::Span new_clause); + ABSL_MUST_USE_RESULT bool InprocessingRewriteClause( + SatClause *clause, absl::Span new_clause); // This can return nullptr if new_clause was of size one or two as these are // treated differently. Note that none of the variable should be fixed in the @@ -316,7 +313,7 @@ public: return watchers_on_false_[false_literal.Index()]; } -private: + private: // Attaches the given clause. This eventually propagates a literal which is // enqueued on the trail. Returns false if a contradiction was encountered. bool AttachAndPropagate(SatClause *clause, Trail *trail); @@ -385,7 +382,7 @@ struct BinaryClause { // A simple class to manage a set of binary clauses. class BinaryClauseManager { -public: + public: BinaryClauseManager() {} int NumClauses() const { return set_.size(); } @@ -393,8 +390,7 @@ public: // already present. bool Add(BinaryClause c) { std::pair p(c.a.SignedValue(), c.b.SignedValue()); - if (p.first > p.second) - std::swap(p.first, p.second); + if (p.first > p.second) std::swap(p.first, p.second); if (set_.find(p) == set_.end()) { set_.insert(p); newly_added_.push_back(c); @@ -407,7 +403,7 @@ public: const std::vector &newly_added() const { return newly_added_; } void ClearNewlyAdded() { newly_added_.clear(); } -private: + private: absl::flat_hash_set > set_; std::vector newly_added_; DISALLOW_COPY_AND_ASSIGN(BinaryClauseManager); @@ -458,7 +454,7 @@ private: // Volume 6695, 2011, pp 201-215 // http://www.cs.helsinki.fi/u/mjarvisa/papers/heule-jarvisalo-biere.sat11.pdf class BinaryImplicationGraph : public SatPropagator { -public: + public: explicit BinaryImplicationGraph(Model *model) : SatPropagator("BinaryImplicationGraph"), stats_("BinaryImplicationGraph"), @@ -477,8 +473,8 @@ public: // SatPropagator interface. bool Propagate(Trail *trail) final; - absl::Span Reason(const Trail &trail, int trail_index) const - final; + absl::Span Reason(const Trail &trail, + int trail_index) const final; // Resizes the data structure. void Resize(int num_variables); @@ -563,10 +559,8 @@ public: // is on its own). Note that DetectEquivalences() should have been called to // get any non-trival results. Literal RepresentativeOf(Literal l) const { - if (l.Index() >= representative_of_.size()) - return l; - if (representative_of_[l.Index()] == kNoLiteralIndex) - return l; + if (l.Index() >= representative_of_.size()) return l; + if (representative_of_[l.Index()] == kNoLiteralIndex) return l; return Literal(representative_of_[l.Index()]); } @@ -603,9 +597,9 @@ public: // only generate clique with these literals or their negation. // // TODO(user): Refine the heuristic and unit test! - const std::vector > & - GenerateAtMostOnesWithLargeWeight(const std::vector &literals, - const std::vector &lp_values); + const std::vector > &GenerateAtMostOnesWithLargeWeight( + const std::vector &literals, + const std::vector &lp_values); // Number of literal propagated by this class (including conflicts). int64 num_propagations() const { return num_propagations_; } @@ -648,7 +642,8 @@ public: // // TODO(user): When extracting to cp_model.proto we could be more efficient // by extracting bool_and constraint with many lhs terms. - template void ExtractAllBinaryClauses(Output *out) const { + template + void ExtractAllBinaryClauses(Output *out) const { // TODO(user): Ideally we should just never have duplicate clauses in this // class. But it seems we do in some corner cases, so lets not output them // twice. @@ -657,14 +652,13 @@ public: for (LiteralIndex i(0); i < implications_.size(); ++i) { const Literal a = Literal(i).Negated(); for (const Literal b : implications_[i]) { - // Note(user): We almost always have both a => b and not(b) => not(a) - // in - // our implications_ database. Except if ComputeTransitiveReduction() - // was aborted early, but in this case, if only one is present, the - // other could be removed, so we shouldn't need to output it. - if (a < b && duplicate_detection.insert({ - a.Index(), b.Index() - }).second) { + // Note(user): We almost always have both a => b and not(b) => not(a) + // in + // our implications_ database. Except if ComputeTransitiveReduction() + // was aborted early, but in this case, if only one is present, the + // other could be removed, so we shouldn't need to output it. + if (a < b && + duplicate_detection.insert({a.Index(), b.Index()}).second) { out->AddBinaryClause(a, b); } } @@ -718,7 +712,7 @@ public: // TODO(user): consider at most ones. void CleanupAllRemovedVariables(); -private: + private: // Simple wrapper to not forget to output newly fixed variable to the DRAT // proof if needed. This will propagate rigth away the implications. bool FixLiteral(Literal true_literal); @@ -740,8 +734,8 @@ private: // the underlying incompatibility graph. Note that there is no guarantee that // if this is called with any sub-clique of the result we will get the same // maximal clique. - std::vector - ExpandAtMostOne(const absl::Span at_most_one); + std::vector ExpandAtMostOne( + const absl::Span at_most_one); // Same as ExpandAtMostOne() but try to maximize the weight in the clique. std::vector ExpandAtMostOneWithWeight( @@ -832,7 +826,7 @@ private: DISALLOW_COPY_AND_ASSIGN(BinaryImplicationGraph); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CLAUSE_H_ +#endif // OR_TOOLS_SAT_CLAUSE_H_ diff --git a/ortools/sat/cp_constraints.cc b/ortools/sat/cp_constraints.cc index 65eda96796..04f6409f32 100644 --- a/ortools/sat/cp_constraints.cc +++ b/ortools/sat/cp_constraints.cc @@ -34,8 +34,7 @@ bool BooleanXorPropagator::Propagate() { sum ^= true; } else { // If we have more than one unassigned literal, we can't deduce anything. - if (unassigned_index != -1) - return true; + if (unassigned_index != -1) return true; unassigned_index = i; } } @@ -44,22 +43,19 @@ bool BooleanXorPropagator::Propagate() { if (unassigned_index != -1) { literal_reason_.clear(); for (int i = 0; i < literals_.size(); ++i) { - if (i == unassigned_index) - continue; + if (i == unassigned_index) continue; const Literal l = literals_[i]; literal_reason_.push_back( trail_->Assignment().LiteralIsFalse(l) ? l : l.Negated()); } const Literal u = literals_[unassigned_index]; integer_trail_->EnqueueLiteral(sum == value_ ? u.Negated() : u, - literal_reason_, { - }); + literal_reason_, {}); return true; } // Ok. - if (sum == value_) - return true; + if (sum == value_) return true; // Conflict. std::vector *conflict = trail_->MutableConflict(); @@ -85,7 +81,8 @@ GreaterThanAtLeastOneOfPropagator::GreaterThanAtLeastOneOfPropagator( const absl::Span offsets, const absl::Span selectors, const absl::Span enforcements, Model *model) - : target_var_(target_var), vars_(vars.begin(), vars.end()), + : target_var_(target_var), + vars_(vars.begin(), vars.end()), offsets_(offsets.begin(), offsets.end()), selectors_(selectors.begin(), selectors.end()), enforcements_(enforcements.begin(), enforcements.end()), @@ -96,8 +93,7 @@ bool GreaterThanAtLeastOneOfPropagator::Propagate() { // TODO(user): In case of a conflict, we could push one of them to false if // it is the only one. for (const Literal l : enforcements_) { - if (!trail_->Assignment().LiteralIsTrue(l)) - return true; + if (!trail_->Assignment().LiteralIsTrue(l)) return true; } // Compute the min of the lower-bound for the still possible variables. @@ -106,16 +102,13 @@ bool GreaterThanAtLeastOneOfPropagator::Propagate() { IntegerValue target_min = kMaxIntegerValue; const IntegerValue current_min = integer_trail_->LowerBound(target_var_); for (int i = 0; i < vars_.size(); ++i) { - if (trail_->Assignment().LiteralIsTrue(selectors_[i])) - return true; - if (trail_->Assignment().LiteralIsFalse(selectors_[i])) - continue; + if (trail_->Assignment().LiteralIsTrue(selectors_[i])) return true; + if (trail_->Assignment().LiteralIsFalse(selectors_[i])) continue; target_min = std::min(target_min, integer_trail_->LowerBound(vars_[i]) + offsets_[i]); // Abort if we can't get a better bound. - if (target_min <= current_min) - return true; + if (target_min <= current_min) return true; } if (target_min == kMaxIntegerValue) { // All false, conflit. @@ -144,13 +137,10 @@ bool GreaterThanAtLeastOneOfPropagator::Propagate() { void GreaterThanAtLeastOneOfPropagator::RegisterWith( GenericLiteralWatcher *watcher) { const int id = watcher->Register(this); - for (const Literal l : selectors_) - watcher->WatchLiteral(l.Negated(), id); - for (const Literal l : enforcements_) - watcher->WatchLiteral(l, id); - for (const IntegerVariable v : vars_) - watcher->WatchLowerBound(v, id); + for (const Literal l : selectors_) watcher->WatchLiteral(l.Negated(), id); + for (const Literal l : enforcements_) watcher->WatchLiteral(l, id); + for (const IntegerVariable v : vars_) watcher->WatchLowerBound(v, id); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_constraints.h b/ortools/sat/cp_constraints.h index fe63ef6f6c..3ce4b3073b 100644 --- a/ortools/sat/cp_constraints.h +++ b/ortools/sat/cp_constraints.h @@ -39,7 +39,9 @@ class BooleanXorPropagator : public PropagatorInterface { public: BooleanXorPropagator(const std::vector &literals, bool value, Trail *trail, IntegerTrail *integer_trail) - : literals_(literals), value_(value), trail_(trail), + : literals_(literals), + value_(value), + trail_(trail), integer_trail_(integer_trail) {} bool Propagate() final; @@ -96,8 +98,8 @@ class GreaterThanAtLeastOneOfPropagator : public PropagatorInterface { // Model based functions. // ============================================================================ -inline std::vector -ToIntegerValueVector(const std::vector &input) { +inline std::vector ToIntegerValueVector( + const std::vector &input) { std::vector result(input.size()); for (int i = 0; i < input.size(); ++i) { result[i] = IntegerValue(input[i]); @@ -106,47 +108,43 @@ ToIntegerValueVector(const std::vector &input) { } // Enforces the XOR of a set of literals to be equal to the given value. -inline std::function -LiteralXorIs(const std::vector &literals, bool value) { - return[ = ](Model *model) { Trail *trail = model->GetOrCreate(); +inline std::function LiteralXorIs( + const std::vector &literals, bool value) { + return [=](Model *model) { + Trail *trail = model->GetOrCreate(); IntegerTrail *integer_trail = model->GetOrCreate(); BooleanXorPropagator *constraint = new BooleanXorPropagator(literals, value, trail, integer_trail); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -inline std::function -GreaterThanAtLeastOneOf(IntegerVariable target_var, - const absl::Span vars, - const absl::Span offsets, - const absl::Span selectors) { - return[ = ](Model *model) { +inline std::function GreaterThanAtLeastOneOf( + IntegerVariable target_var, const absl::Span vars, + const absl::Span offsets, + const absl::Span selectors) { + return [=](Model *model) { GreaterThanAtLeastOneOfPropagator *constraint = new GreaterThanAtLeastOneOfPropagator(target_var, vars, offsets, selectors, {}, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -inline std::function -GreaterThanAtLeastOneOf(IntegerVariable target_var, - const absl::Span vars, - const absl::Span offsets, - const absl::Span selectors, - const absl::Span enforcements) { - return[ = ](Model *model) { +inline std::function GreaterThanAtLeastOneOf( + IntegerVariable target_var, const absl::Span vars, + const absl::Span offsets, + const absl::Span selectors, + const absl::Span enforcements) { + return [=](Model *model) { GreaterThanAtLeastOneOfPropagator *constraint = new GreaterThanAtLeastOneOfPropagator(target_var, vars, offsets, selectors, enforcements, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // The target variable is equal to exactly one of the candidate variable. The @@ -158,12 +156,11 @@ GreaterThanAtLeastOneOf(IntegerVariable target_var, // // Note(user): If there is just one or two candidates, this doesn't add // anything. -inline std::function -PartialIsOneOfVar(IntegerVariable target_var, - const std::vector &vars, - const std::vector &selectors) { +inline std::function PartialIsOneOfVar( + IntegerVariable target_var, const std::vector &vars, + const std::vector &selectors) { CHECK_EQ(vars.size(), selectors.size()); - return[ = ](Model * model) { + return [=](Model *model) { const std::vector offsets(vars.size(), IntegerValue(0)); if (vars.size() > 2) { // Propagate the min. @@ -174,11 +171,10 @@ PartialIsOneOfVar(IntegerVariable target_var, model->Add(GreaterThanAtLeastOneOf(NegationOf(target_var), NegationOf(vars), offsets, selectors)); } - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_CONSTRAINTS_H_ +#endif // OR_TOOLS_SAT_CP_CONSTRAINTS_H_ diff --git a/ortools/sat/cp_model.cc b/ortools/sat/cp_model.cc index 842a57957c..14c35f05b8 100644 --- a/ortools/sat/cp_model.cc +++ b/ortools/sat/cp_model.cc @@ -246,16 +246,16 @@ ReservoirConstraint::ReservoirConstraint(ConstraintProto *proto, : Constraint(proto), builder_(builder) {} void ReservoirConstraint::AddEvent(IntVar time, int64 demand) { - proto_->mutable_reservoir() - ->add_times(builder_->GetOrCreateIntegerIndex(time.index_)); + proto_->mutable_reservoir()->add_times( + builder_->GetOrCreateIntegerIndex(time.index_)); proto_->mutable_reservoir()->add_demands(demand); proto_->mutable_reservoir()->add_actives(builder_->IndexFromConstant(1)); } void ReservoirConstraint::AddOptionalEvent(IntVar time, int64 demand, BoolVar is_active) { - proto_->mutable_reservoir() - ->add_times(builder_->GetOrCreateIntegerIndex(time.index_)); + proto_->mutable_reservoir()->add_times( + builder_->GetOrCreateIntegerIndex(time.index_)); proto_->mutable_reservoir()->add_demands(demand); proto_->mutable_reservoir()->add_actives(is_active.index_); } @@ -279,8 +279,8 @@ CumulativeConstraint::CumulativeConstraint(ConstraintProto *proto, void CumulativeConstraint::AddDemand(IntervalVar interval, IntVar demand) { proto_->mutable_cumulative()->add_intervals(interval.index_); - proto_->mutable_cumulative() - ->add_demands(builder_->GetOrCreateIntegerIndex(demand.index_)); + proto_->mutable_cumulative()->add_demands( + builder_->GetOrCreateIntegerIndex(demand.index_)); } IntervalVar::IntervalVar() : cp_model_(nullptr), index_() {} @@ -571,8 +571,8 @@ MultipleCircuitConstraint CpModelBuilder::AddMultipleCircuitConstraint() { return MultipleCircuitConstraint(cp_model_.add_constraints()); } -TableConstraint -CpModelBuilder::AddAllowedAssignments(absl::Span vars) { +TableConstraint CpModelBuilder::AddAllowedAssignments( + absl::Span vars) { ConstraintProto *const proto = cp_model_.add_constraints(); for (const IntVar &var : vars) { proto->mutable_table()->add_vars(GetOrCreateIntegerIndex(var.index_)); @@ -580,8 +580,8 @@ CpModelBuilder::AddAllowedAssignments(absl::Span vars) { return TableConstraint(proto); } -TableConstraint -CpModelBuilder::AddForbiddenAssignments(absl::Span vars) { +TableConstraint CpModelBuilder::AddForbiddenAssignments( + absl::Span vars) { ConstraintProto *const proto = cp_model_.add_constraints(); for (const IntVar &var : vars) { proto->mutable_table()->add_vars(GetOrCreateIntegerIndex(var.index_)); @@ -598,8 +598,8 @@ Constraint CpModelBuilder::AddInverseConstraint( proto->mutable_inverse()->add_f_direct(GetOrCreateIntegerIndex(var.index_)); } for (const IntVar &var : inverse_variables) { - proto->mutable_inverse() - ->add_f_inverse(GetOrCreateIntegerIndex(var.index_)); + proto->mutable_inverse()->add_f_inverse( + GetOrCreateIntegerIndex(var.index_)); } return Constraint(proto); } @@ -612,10 +612,9 @@ ReservoirConstraint CpModelBuilder::AddReservoirConstraint(int64 min_level, return ReservoirConstraint(proto, this); } -AutomatonConstraint -CpModelBuilder::AddAutomaton(absl::Span transition_variables, - int starting_state, - absl::Span final_states) { +AutomatonConstraint CpModelBuilder::AddAutomaton( + absl::Span transition_variables, int starting_state, + absl::Span final_states) { ConstraintProto *const proto = cp_model_.add_constraints(); for (const IntVar &var : transition_variables) { proto->mutable_automaton()->add_vars(GetOrCreateIntegerIndex(var.index_)); @@ -648,9 +647,8 @@ void CpModelBuilder::LinearExprToProto(const LinearExpr &expr, expr_proto->set_offset(expr.constant()); } -Constraint -CpModelBuilder::AddLinMinEquality(const LinearExpr &target, - absl::Span exprs) { +Constraint CpModelBuilder::AddLinMinEquality( + const LinearExpr &target, absl::Span exprs) { ConstraintProto *const proto = cp_model_.add_constraints(); LinearExprToProto(target, proto->mutable_lin_min()->mutable_target()); for (const LinearExpr &expr : exprs) { @@ -670,9 +668,8 @@ Constraint CpModelBuilder::AddMaxEquality(IntVar target, return Constraint(proto); } -Constraint -CpModelBuilder::AddLinMaxEquality(const LinearExpr &target, - absl::Span exprs) { +Constraint CpModelBuilder::AddLinMaxEquality( + const LinearExpr &target, absl::Span exprs) { ConstraintProto *const proto = cp_model_.add_constraints(); LinearExprToProto(target, proto->mutable_lin_max()->mutable_target()); for (const LinearExpr &expr : exprs) { @@ -687,8 +684,8 @@ Constraint CpModelBuilder::AddDivisionEquality(IntVar target, IntVar numerator, ConstraintProto *const proto = cp_model_.add_constraints(); proto->mutable_int_div()->set_target(GetOrCreateIntegerIndex(target.index_)); proto->mutable_int_div()->add_vars(GetOrCreateIntegerIndex(numerator.index_)); - proto->mutable_int_div() - ->add_vars(GetOrCreateIntegerIndex(denominator.index_)); + proto->mutable_int_div()->add_vars( + GetOrCreateIntegerIndex(denominator.index_)); return Constraint(proto); } @@ -696,8 +693,8 @@ Constraint CpModelBuilder::AddAbsEquality(IntVar target, IntVar var) { ConstraintProto *const proto = cp_model_.add_constraints(); proto->mutable_int_max()->set_target(GetOrCreateIntegerIndex(target.index_)); proto->mutable_int_max()->add_vars(GetOrCreateIntegerIndex(var.index_)); - proto->mutable_int_max() - ->add_vars(NegatedRef(GetOrCreateIntegerIndex(var.index_))); + proto->mutable_int_max()->add_vars( + NegatedRef(GetOrCreateIntegerIndex(var.index_))); return Constraint(proto); } @@ -723,8 +720,8 @@ Constraint CpModelBuilder::AddProductEquality(IntVar target, Constraint CpModelBuilder::AddNoOverlap(absl::Span vars) { ConstraintProto *const proto = cp_model_.add_constraints(); for (const IntervalVar &var : vars) { - proto->mutable_no_overlap() - ->add_intervals(GetOrCreateIntegerIndex(var.index_)); + proto->mutable_no_overlap()->add_intervals( + GetOrCreateIntegerIndex(var.index_)); } return Constraint(proto); } @@ -735,8 +732,8 @@ NoOverlap2DConstraint CpModelBuilder::AddNoOverlap2D() { CumulativeConstraint CpModelBuilder::AddCumulative(IntVar capacity) { ConstraintProto *const proto = cp_model_.add_constraints(); - proto->mutable_cumulative() - ->set_capacity(GetOrCreateIntegerIndex(capacity.index_)); + proto->mutable_cumulative()->set_capacity( + GetOrCreateIntegerIndex(capacity.index_)); return CumulativeConstraint(proto, this); } @@ -765,8 +762,8 @@ void CpModelBuilder::Maximize(const LinearExpr &expr) { void CpModelBuilder::ScaleObjectiveBy(double scaling) { CHECK(cp_model_.has_objective()); - cp_model_.mutable_objective() - ->set_scaling_factor(scaling * cp_model_.objective().scaling_factor()); + cp_model_.mutable_objective()->set_scaling_factor( + scaling * cp_model_.objective().scaling_factor()); } void CpModelBuilder::AddDecisionStrategy( @@ -794,8 +791,8 @@ void CpModelBuilder::AddDecisionStrategy( } void CpModelBuilder::AddHint(IntVar var, int64 value) { - cp_model_.mutable_solution_hint() - ->add_vars(GetOrCreateIntegerIndex(var.index_)); + cp_model_.mutable_solution_hint()->add_vars( + GetOrCreateIntegerIndex(var.index_)); cp_model_.mutable_solution_hint()->add_values(value); } @@ -832,5 +829,5 @@ bool SolutionBooleanValue(const CpSolverResponse &r, BoolVar x) { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model.h b/ortools/sat/cp_model.h index cb1472472d..9d5b9a1d05 100644 --- a/ortools/sat/cp_model.h +++ b/ortools/sat/cp_model.h @@ -65,7 +65,7 @@ class IntVar; * This can only be constructed via \c CpModelBuilder.NewBoolVar(). */ class BoolVar { -public: + public: BoolVar(); /// Sets the name of the variable. @@ -108,7 +108,7 @@ public: */ int index() const { return index_; } -private: + private: friend class CircuitConstraint; friend class Constraint; friend class CpModelBuilder; @@ -144,11 +144,11 @@ BoolVar Not(BoolVar x); * 0 (when false) or 1 (when true). */ class IntVar { -public: + public: IntVar(); /// Implicit cast BoolVar -> IntVar. - IntVar(const BoolVar &var); // NOLINT(runtime/explicit) + IntVar(const BoolVar &var); // NOLINT(runtime/explicit) /// Cast IntVar -> BoolVar. /// Checks that the domain of the var is within {0,1}. @@ -190,7 +190,7 @@ public: /// Returns the index of the variable in the model. int index() const { return index_; } -private: + private: friend class BoolVar; friend class CpModelBuilder; friend class CumulativeConstraint; @@ -246,7 +246,7 @@ std::ostream &operator<<(std::ostream &os, const IntVar &var); \endcode */ class LinearExpr { -public: + public: LinearExpr(); /** @@ -254,13 +254,13 @@ public: * * It deals with logical negation correctly. */ - LinearExpr(BoolVar var); // NOLINT(runtime/explicit) + LinearExpr(BoolVar var); // NOLINT(runtime/explicit) /// Constructs a linear expression from an integer variable. - LinearExpr(IntVar var); // NOLINT(runtime/explicit) + LinearExpr(IntVar var); // NOLINT(runtime/explicit) /// Constructs a constant linear expression. - LinearExpr(int64 constant); // NOLINT(runtime/explicit) + LinearExpr(int64 constant); // NOLINT(runtime/explicit) /// Adds a constant value to the linear expression. LinearExpr &AddConstant(int64 value); @@ -298,7 +298,7 @@ public: // TODO(user): LinearExpr.DebugString() and operator<<. -private: + private: std::vector variables_; std::vector coefficients_; int64 constant_ = 0; @@ -324,7 +324,7 @@ private: * It can only be constructed via \c CpModelBuilder.NewIntervalVar(). */ class IntervalVar { -public: + public: /// Default ctor. IntervalVar(); @@ -376,7 +376,7 @@ public: /// Returns the index of the interval constraint in the model. int index() const { return index_; } -private: + private: friend class CpModelBuilder; friend class CumulativeConstraint; friend class NoOverlap2DConstraint; @@ -400,7 +400,7 @@ std::ostream &operator<<(std::ostream &os, const IntervalVar &var); * methods. */ class Constraint { -public: + public: /** * The constraint will be enforced iff all literals listed here are true. * @@ -435,7 +435,7 @@ public: /// Returns the mutable underlying protobuf object (useful for model edition). ConstraintProto *MutableProto() const { return proto_; } -protected: + protected: friend class CpModelBuilder; explicit Constraint(ConstraintProto *proto); @@ -449,7 +449,7 @@ protected: * This constraint allows adding arcs to the circuit constraint incrementally. */ class CircuitConstraint : public Constraint { -public: + public: /** * Add an arc to the circuit. * @@ -459,7 +459,7 @@ public: */ void AddArc(int tail, int head, BoolVar literal); -private: + private: friend class CpModelBuilder; using Constraint::Constraint; @@ -472,7 +472,7 @@ private: * incrementally. */ class MultipleCircuitConstraint : public Constraint { -public: + public: /** * Add an arc to the circuit. * @@ -482,7 +482,7 @@ public: */ void AddArc(int tail, int head, BoolVar literal); -private: + private: friend class CpModelBuilder; using Constraint::Constraint; @@ -495,11 +495,11 @@ private: * constraint incrementally. */ class TableConstraint : public Constraint { -public: + public: /// Adds a tuple of possible values to the constraint. void AddTuple(absl::Span tuple); -private: + private: friend class CpModelBuilder; using Constraint::Constraint; @@ -512,7 +512,7 @@ private: * constraint incrementally. */ class ReservoirConstraint : public Constraint { -public: + public: /** * Adds a mandatory event * @@ -528,7 +528,7 @@ public: */ void AddOptionalEvent(IntVar time, int64 demand, BoolVar is_active); -private: + private: friend class CpModelBuilder; ReservoirConstraint(ConstraintProto *proto, CpModelBuilder *builder); @@ -543,11 +543,11 @@ private: * incrementally. */ class AutomatonConstraint : public Constraint { -public: + public: /// Adds a transitions to the automaton. void AddTransition(int tail, int head, int64 transition_label); -private: + private: friend class CpModelBuilder; using Constraint::Constraint; @@ -560,11 +560,11 @@ private: * constraint incrementally. */ class NoOverlap2DConstraint : public Constraint { -public: + public: /// Adds a rectangle (parallel to the axis) to the constraint. void AddRectangle(IntervalVar x_coordinate, IntervalVar y_coordinate); -private: + private: friend class CpModelBuilder; using Constraint::Constraint; @@ -577,11 +577,11 @@ private: * constraint incrementally. */ class CumulativeConstraint : public Constraint { -public: + public: /// Adds a pair (interval, demand) to the constraint. void AddDemand(IntervalVar interval, IntVar demand); -private: + private: friend class CpModelBuilder; CumulativeConstraint(ConstraintProto *proto, CpModelBuilder *builder); @@ -597,7 +597,7 @@ private: * - AddXXX to create new constraints and add them to the model. */ class CpModelBuilder { -public: + public: /// Creates an integer variable with the given domain. IntVar NewIntVar(const Domain &domain); @@ -631,9 +631,7 @@ public: /// Adds a => b. Constraint AddImplication(BoolVar a, BoolVar b) { - return AddBoolOr({ - a.Not(), b - }); + return AddBoolOr({a.Not(), b}); } /// Adds left == right. @@ -782,9 +780,9 @@ public: * It returns an AutomatonConstraint that allows adding transition * incrementally after construction. */ - AutomatonConstraint - AddAutomaton(absl::Span transition_variables, - int starting_state, absl::Span final_states); + AutomatonConstraint AddAutomaton( + absl::Span transition_variables, int starting_state, + absl::Span final_states); /// Adds target == min(vars). Constraint AddMinEquality(IntVar target, absl::Span vars); @@ -868,7 +866,7 @@ public: const CpModelProto &Proto() const { return cp_model_; } CpModelProto *MutableProto() { return &cp_model_; } -private: + private: friend class CumulativeConstraint; friend class ReservoirConstraint; @@ -906,7 +904,7 @@ int64 SolutionIntegerMax(const CpSolverResponse &r, IntVar x); /// Evaluates the value of a Boolean literal in a solver response. bool SolutionBooleanValue(const CpSolverResponse &r, BoolVar x); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_H_ diff --git a/ortools/sat/cp_model_checker.cc b/ortools/sat/cp_model_checker.cc index 3f866b8c51..7cc33496a5 100644 --- a/ortools/sat/cp_model_checker.cc +++ b/ortools/sat/cp_model_checker.cc @@ -38,38 +38,31 @@ namespace { // ============================================================================= // If the string returned by "statement" is not empty, returns it. -#define RETURN_IF_NOT_EMPTY(statement) \ - do { \ - const std::string error_message = statement; \ - if (!error_message.empty()) \ - return error_message; \ +#define RETURN_IF_NOT_EMPTY(statement) \ + do { \ + const std::string error_message = statement; \ + if (!error_message.empty()) return error_message; \ } while (false) template bool DomainInProtoIsValid(const ProtoWithDomain &proto) { - if (proto.domain().size() % 2) - return false; + if (proto.domain().size() % 2) return false; std::vector domain; for (int i = 0; i < proto.domain_size(); i += 2) { - if (proto.domain(i) > proto.domain(i + 1)) - return false; - domain.push_back({ - proto.domain(i), proto.domain(i + 1) - }); + if (proto.domain(i) > proto.domain(i + 1)) return false; + domain.push_back({proto.domain(i), proto.domain(i + 1)}); } return IntervalsAreSortedAndNonAdjacent(domain); } bool VariableReferenceIsValid(const CpModelProto &model, int reference) { // We do it this way to avoid overflow if reference is kint64min for instance. - if (reference >= model.variables_size()) - return false; + if (reference >= model.variables_size()) return false; return reference >= -static_cast(model.variables_size()); } bool LiteralReferenceIsValid(const CpModelProto &model, int reference) { - if (!VariableReferenceIsValid(model, reference)) - return false; + if (!VariableReferenceIsValid(model, reference)) return false; const auto &var_proto = model.variables(PositiveRef(reference)); const int64 min_domain = var_proto.domain(0); const int64 max_domain = var_proto.domain(var_proto.domain_size() - 1); @@ -79,8 +72,8 @@ bool LiteralReferenceIsValid(const CpModelProto &model, int reference) { std::string ValidateIntegerVariable(const CpModelProto &model, int v) { const IntegerVariableProto &proto = model.variables(v); if (proto.domain_size() == 0) { - return absl::StrCat("var #", v, " has no domain(): ", - ProtobufShortDebugString(proto)); + return absl::StrCat("var #", v, + " has no domain(): ", ProtobufShortDebugString(proto)); } if (proto.domain_size() % 2 != 0) { return absl::StrCat("var #", v, " has an odd domain() size: ", @@ -168,22 +161,13 @@ bool PossibleIntegerOverflow(const CpModelProto &model, const int64 prod1 = CapProd(min_domain, coeff); const int64 prod2 = CapProd(max_domain, coeff); - // Note that we use min/max with zero to disallow "alternative" terms and - // be sure that we cannot have an overflow if we do the computation in a - // different order. - sum_min = CapAdd(sum_min, std::min(int64 { - 0 - }, - std::min(prod1, prod2))); - sum_max = CapAdd(sum_max, std::max(int64 { - 0 - }, - std::max(prod1, prod2))); - for (const int64 v : { - prod1, prod2, sum_min, sum_max - }) { - if (v == kint64max || v == kint64min) - return true; + // Note that we use min/max with zero to disallow "alternative" terms and + // be sure that we cannot have an overflow if we do the computation in a + // different order. + sum_min = CapAdd(sum_min, std::min(int64{0}, std::min(prod1, prod2))); + sum_max = CapAdd(sum_max, std::max(int64{0}, std::max(prod1, prod2))); + for (const int64 v : {prod1, prod2, sum_min, sum_max}) { + if (v == kint64max || v == kint64min) return true; } } @@ -202,16 +186,16 @@ std::string ValidateIntervalConstraint(const CpModelProto &model, const IntegerVariableProto &size_var_proto = model.variables(NegatedRef(arg.size())); if (size_var_proto.domain(size_var_proto.domain_size() - 1) > 0) { - return absl::StrCat("Negative value in interval size domain: ", - ProtobufDebugString(ct), "negation of size var: ", - ProtobufDebugString(size_var_proto)); + return absl::StrCat( + "Negative value in interval size domain: ", ProtobufDebugString(ct), + "negation of size var: ", ProtobufDebugString(size_var_proto)); } } else { const IntegerVariableProto &size_var_proto = model.variables(arg.size()); if (size_var_proto.domain(0) < 0) { - return absl::StrCat("Negative value in interval size domain: ", - ProtobufDebugString(ct), "size var: ", - ProtobufDebugString(size_var_proto)); + return absl::StrCat( + "Negative value in interval size domain: ", ProtobufDebugString(ct), + "size var: ", ProtobufDebugString(size_var_proto)); } } return ""; @@ -373,8 +357,7 @@ std::string ValidateSearchStrategies(const CpModelProto &model) { } std::string ValidateSolutionHint(const CpModelProto &model) { - if (!model.has_solution_hint()) - return ""; + if (!model.has_solution_hint()) return ""; const auto &hint = model.solution_hint(); if (hint.vars().size() != hint.values().size()) { return "Invalid solution hint: vars and values do not have the same size."; @@ -387,7 +370,7 @@ std::string ValidateSolutionHint(const CpModelProto &model) { return ""; } -} // namespace +} // namespace std::string ValidateCpModel(const CpModelProto &model) { for (int v = 0; v < model.variables_size(); ++v) { @@ -405,92 +388,89 @@ std::string ValidateCpModel(const CpModelProto &model) { const ConstraintProto &ct = model.constraints(c); const ConstraintProto::ConstraintCase type = ct.constraint_case(); switch (type) { - case ConstraintProto::ConstraintCase::kIntDiv: - if (ct.int_div().vars().size() != 2) { - return absl::StrCat( - "An int_div constraint should have exactly 2 terms: ", - ProtobufShortDebugString(ct)); + case ConstraintProto::ConstraintCase::kIntDiv: + if (ct.int_div().vars().size() != 2) { + return absl::StrCat( + "An int_div constraint should have exactly 2 terms: ", + ProtobufShortDebugString(ct)); + } + break; + case ConstraintProto::ConstraintCase::kIntMod: + RETURN_IF_NOT_EMPTY(ValidateIntModConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kBoolOr: + support_enforcement = true; + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + support_enforcement = true; + break; + case ConstraintProto::ConstraintCase::kLinear: + support_enforcement = true; + if (!DomainInProtoIsValid(ct.linear())) { + return absl::StrCat("Invalid domain in constraint #", c, " : ", + ProtobufShortDebugString(ct)); + } + if (ct.linear().coeffs_size() != ct.linear().vars_size()) { + return absl::StrCat("coeffs_size() != vars_size() in constraint #", c, + " : ", ProtobufShortDebugString(ct)); + } + RETURN_IF_NOT_EMPTY(ValidateLinearConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kLinMax: { + const std::string target_error = + ValidateLinearExpression(model, ct.lin_min().target()); + if (!target_error.empty()) return target_error; + for (int i = 0; i < ct.lin_max().exprs_size(); ++i) { + const std::string expr_error = + ValidateLinearExpression(model, ct.lin_max().exprs(i)); + if (!expr_error.empty()) return expr_error; + } + break; } - break; - case ConstraintProto::ConstraintCase::kIntMod: - RETURN_IF_NOT_EMPTY(ValidateIntModConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kBoolOr: - support_enforcement = true; - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - support_enforcement = true; - break; - case ConstraintProto::ConstraintCase::kLinear: - support_enforcement = true; - if (!DomainInProtoIsValid(ct.linear())) { - return absl::StrCat("Invalid domain in constraint #", c, " : ", - ProtobufShortDebugString(ct)); + case ConstraintProto::ConstraintCase::kLinMin: { + const std::string target_error = + ValidateLinearExpression(model, ct.lin_min().target()); + if (!target_error.empty()) return target_error; + for (int i = 0; i < ct.lin_min().exprs_size(); ++i) { + const std::string expr_error = + ValidateLinearExpression(model, ct.lin_min().exprs(i)); + if (!expr_error.empty()) return expr_error; + } + break; } - if (ct.linear().coeffs_size() != ct.linear().vars_size()) { - return absl::StrCat("coeffs_size() != vars_size() in constraint #", c, - " : ", ProtobufShortDebugString(ct)); - } - RETURN_IF_NOT_EMPTY(ValidateLinearConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kLinMax: { - const std::string target_error = - ValidateLinearExpression(model, ct.lin_min().target()); - if (!target_error.empty()) - return target_error; - for (int i = 0; i < ct.lin_max().exprs_size(); ++i) { - const std::string expr_error = - ValidateLinearExpression(model, ct.lin_max().exprs(i)); - if (!expr_error.empty()) - return expr_error; - } - break; - } - case ConstraintProto::ConstraintCase::kLinMin: { - const std::string target_error = - ValidateLinearExpression(model, ct.lin_min().target()); - if (!target_error.empty()) - return target_error; - for (int i = 0; i < ct.lin_min().exprs_size(); ++i) { - const std::string expr_error = - ValidateLinearExpression(model, ct.lin_min().exprs(i)); - if (!expr_error.empty()) - return expr_error; - } - break; - } - case ConstraintProto::ConstraintCase::kInterval: - support_enforcement = true; - RETURN_IF_NOT_EMPTY(ValidateIntervalConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kCumulative: - if (ct.cumulative().intervals_size() != ct.cumulative().demands_size()) { - return absl::StrCat( - "intervals_size() != demands_size() in constraint #", c, " : ", - ProtobufShortDebugString(ct)); - } - break; - case ConstraintProto::ConstraintCase::kInverse: - if (ct.inverse().f_direct().size() != ct.inverse().f_inverse().size()) { - return absl::StrCat("Non-matching fields size in inverse: ", - ProtobufShortDebugString(ct)); - } - break; - case ConstraintProto::ConstraintCase::kCircuit: - RETURN_IF_NOT_EMPTY(ValidateCircuitConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kRoutes: - RETURN_IF_NOT_EMPTY(ValidateRoutesConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kReservoir: - RETURN_IF_NOT_EMPTY(ValidateReservoirConstraint(model, ct)); - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - RETURN_IF_NOT_EMPTY(ValidateCircuitCoveringConstraint(ct)); - break; - default: - break; + case ConstraintProto::ConstraintCase::kInterval: + support_enforcement = true; + RETURN_IF_NOT_EMPTY(ValidateIntervalConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kCumulative: + if (ct.cumulative().intervals_size() != + ct.cumulative().demands_size()) { + return absl::StrCat( + "intervals_size() != demands_size() in constraint #", c, " : ", + ProtobufShortDebugString(ct)); + } + break; + case ConstraintProto::ConstraintCase::kInverse: + if (ct.inverse().f_direct().size() != ct.inverse().f_inverse().size()) { + return absl::StrCat("Non-matching fields size in inverse: ", + ProtobufShortDebugString(ct)); + } + break; + case ConstraintProto::ConstraintCase::kCircuit: + RETURN_IF_NOT_EMPTY(ValidateCircuitConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kRoutes: + RETURN_IF_NOT_EMPTY(ValidateRoutesConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kReservoir: + RETURN_IF_NOT_EMPTY(ValidateReservoirConstraint(model, ct)); + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + RETURN_IF_NOT_EMPTY(ValidateCircuitCoveringConstraint(ct)); + break; + default: + break; } // Because some client set fixed enforcement literal which are supported @@ -531,44 +511,39 @@ std::string ValidateCpModel(const CpModelProto &model) { namespace { class ConstraintChecker { -public: + public: explicit ConstraintChecker(const std::vector &variable_values) : variable_values_(variable_values) {} bool LiteralIsTrue(int l) const { - if (l >= 0) - return variable_values_[l] != 0; + if (l >= 0) return variable_values_[l] != 0; return variable_values_[-l - 1] == 0; } bool LiteralIsFalse(int l) const { return !LiteralIsTrue(l); } int64 Value(int var) const { - if (var >= 0) - return variable_values_[var]; + if (var >= 0) return variable_values_[var]; return -variable_values_[-var - 1]; } bool ConstraintIsEnforced(const ConstraintProto &ct) { for (const int lit : ct.enforcement_literal()) { - if (LiteralIsFalse(lit)) - return false; + if (LiteralIsFalse(lit)) return false; } return true; } bool BoolOrConstraintIsFeasible(const ConstraintProto &ct) { for (const int lit : ct.bool_or().literals()) { - if (LiteralIsTrue(lit)) - return true; + if (LiteralIsTrue(lit)) return true; } return false; } bool BoolAndConstraintIsFeasible(const ConstraintProto &ct) { for (const int lit : ct.bool_and().literals()) { - if (LiteralIsFalse(lit)) - return false; + if (LiteralIsFalse(lit)) return false; } return true; } @@ -576,8 +551,7 @@ public: bool AtMostOneConstraintIsFeasible(const ConstraintProto &ct) { int num_true_literals = 0; for (const int lit : ct.at_most_one().literals()) { - if (LiteralIsTrue(lit)) - ++num_true_literals; + if (LiteralIsTrue(lit)) ++num_true_literals; } return num_true_literals <= 1; } @@ -668,8 +642,7 @@ public: bool AllDiffConstraintIsFeasible(const ConstraintProto &ct) { absl::flat_hash_set values; for (const int v : ct.all_diff().vars()) { - if (gtl::ContainsKey(values, Value(v))) - return false; + if (gtl::ContainsKey(values, Value(v))) return false; values.insert(Value(v)); } return true; @@ -677,8 +650,7 @@ public: bool IntervalConstraintIsFeasible(const ConstraintProto &ct) { const int64 size = Value(ct.interval().size()); - if (size < 0) - return false; + if (size < 0) return false; return Value(ct.interval().start()) + size == Value(ct.interval().end()); } @@ -690,16 +662,14 @@ public: if (ConstraintIsEnforced(interval_constraint)) { const IntervalConstraintProto &interval = interval_constraint.interval(); - start_durations_pairs.push_back({ - Value(interval.start()), Value(interval.size()) - }); + start_durations_pairs.push_back( + {Value(interval.start()), Value(interval.size())}); } } std::sort(start_durations_pairs.begin(), start_durations_pairs.end()); int64 previous_end = kint64min; for (const auto pair : start_durations_pairs) { - if (pair.first < previous_end) - return false; + if (pair.first < previous_end) return false; previous_end = pair.first + pair.second; } return true; @@ -733,9 +703,7 @@ public: (!arg.boxes_with_null_area_can_overlap() || (!IntervalIsEmpty(x.interval()) && !IntervalIsEmpty(y.interval())))) { - enforced_intervals_xy.push_back({ - &x.interval(), &y.interval() - }); + enforced_intervals_xy.push_back({&x.interval(), &y.interval()}); } } } @@ -779,8 +747,7 @@ public: const int64 demand = Value(ct.cumulative().demands(i)); for (int64 t = start; t < start + duration; ++t) { usage[t] += demand; - if (usage[t] > capacity) - return false; + if (usage[t] > capacity) return false; } } } @@ -794,15 +761,13 @@ public: bool TableConstraintIsFeasible(const ConstraintProto &ct) { const int size = ct.table().vars_size(); - if (size == 0) - return true; + if (size == 0) return true; for (int row_start = 0; row_start < ct.table().values_size(); row_start += size) { int i = 0; while (Value(ct.table().vars(i)) == ct.table().values(row_start + i)) { ++i; - if (i == size) - return !ct.table().negated(); + if (i == size) return !ct.table().negated(); } } return ct.table().negated(); @@ -813,9 +778,8 @@ public: absl::flat_hash_map, int64> transition_map; const int num_transitions = ct.automaton().transition_tail().size(); for (int i = 0; i < num_transitions; ++i) { - transition_map[{ - ct.automaton().transition_tail(i), ct.automaton().transition_label(i) - }] = + transition_map[{ct.automaton().transition_tail(i), + ct.automaton().transition_label(i)}] = ct.automaton().transition_head(i); } @@ -823,8 +787,8 @@ public: int64 current_state = ct.automaton().starting_state(); const int num_steps = ct.automaton().vars_size(); for (int i = 0; i < num_steps; ++i) { - const std::pair key = { current_state, - Value(ct.automaton().vars(i)) }; + const std::pair key = {current_state, + Value(ct.automaton().vars(i))}; if (!gtl::ContainsKey(transition_map, key)) { return false; } @@ -833,8 +797,7 @@ public: // Check we are now in a final state. for (const int64 final : ct.automaton().final_states()) { - if (current_state == final) - return true; + if (current_state == final) return true; } return false; } @@ -850,10 +813,8 @@ public: const int head = ct.circuit().heads(i); nodes.insert(tail); nodes.insert(head); - if (LiteralIsFalse(ct.circuit().literals(i))) - continue; - if (nexts.contains(tail)) - return false; // Duplicate. + if (LiteralIsFalse(ct.circuit().literals(i))) continue; + if (nexts.contains(tail)) return false; // Duplicate. nexts[tail] = head; } @@ -861,15 +822,12 @@ public: int in_cycle; int cycle_size = 0; for (const int node : nodes) { - if (!nexts.contains(node)) - return false; // No next. - if (nexts[node] == node) - continue; // skip self-loop. + if (!nexts.contains(node)) return false; // No next. + if (nexts[node] == node) continue; // skip self-loop. in_cycle = node; ++cycle_size; } - if (cycle_size == 0) - return true; + if (cycle_size == 0) return true; // Check that we have only one cycle. visited is used to not loop forever if // we have a "rho" shape instead of a cycle. @@ -881,9 +839,8 @@ public: visited.insert(current); current = nexts[current]; } - if (current != in_cycle) - return false; // Rho shape. - return num_visited == cycle_size; // Another cycle somewhere if false. + if (current != in_cycle) return false; // Rho shape. + return num_visited == cycle_size; // Another cycle somewhere if false. } bool RoutesConstraintIsFeasible(const ConstraintProto &ct) { @@ -901,8 +858,7 @@ public: tail_to_head.resize(num_nodes, -1); if (LiteralIsTrue(ct.routes().literals(i))) { if (tail == head) { - if (tail == 0) - return false; + if (tail == 0) return false; ++num_self_arcs; continue; } @@ -910,24 +866,21 @@ public: if (tail == 0) { depot_nexts.push_back(head); } else { - if (tail_to_head[tail] != -1) - return false; + if (tail_to_head[tail] != -1) return false; tail_to_head[tail] = head; } } } // An empty constraint with no node to visit should be feasible. - if (num_nodes == 0) - return true; + if (num_nodes == 0) return true; // Make sure each routes from the depot go back to it, and count such arcs. int count = 0; for (int start : depot_nexts) { ++count; while (start != 0) { - if (tail_to_head[start] == -1) - return false; + if (tail_to_head[start] == -1) return false; start = tail_to_head[start]; ++count; } @@ -966,8 +919,7 @@ public: visited[d] = true; for (int node = Value(ct.circuit_covering().nexts(d)); node != d; node = Value(ct.circuit_covering().nexts(node))) { - if (distinguished[node]) - return false; + if (distinguished[node]) return false; CHECK(!visited[node]); visited[node] = true; } @@ -984,15 +936,12 @@ public: bool InverseConstraintIsFeasible(const ConstraintProto &ct) { const int num_variables = ct.inverse().f_direct_size(); - if (num_variables != ct.inverse().f_inverse_size()) - return false; + if (num_variables != ct.inverse().f_inverse_size()) return false; // Check that f_inverse(f_direct(i)) == i; this is sufficient. for (int i = 0; i < num_variables; i++) { const int fi = Value(ct.inverse().f_direct(i)); - if (fi < 0 || num_variables <= fi) - return false; - if (i != Value(ct.inverse().f_inverse(fi))) - return false; + if (fi < 0 || num_variables <= fi) return false; + if (i != Value(ct.inverse().f_inverse(fi))) return false; } return true; } @@ -1026,11 +975,11 @@ public: return true; } -private: + private: std::vector variable_values_; }; -} // namespace +} // namespace bool SolutionIsFeasible(const CpModelProto &model, const std::vector &variable_values, @@ -1044,10 +993,9 @@ bool SolutionIsFeasible(const CpModelProto &model, // Check that all values fall in the variable domains. for (int i = 0; i < model.variables_size(); ++i) { if (!DomainInProtoContains(model.variables(i), variable_values[i])) { - VLOG(1) - << "Variable #" << i << " has value " << variable_values[i] - << " which do not fall in its domain: " << ProtobufShortDebugString( - model.variables(i)); + VLOG(1) << "Variable #" << i << " has value " << variable_values[i] + << " which do not fall in its domain: " + << ProtobufShortDebugString(model.variables(i)); return false; } } @@ -1058,108 +1006,104 @@ bool SolutionIsFeasible(const CpModelProto &model, for (int c = 0; c < model.constraints_size(); ++c) { const ConstraintProto &ct = model.constraints(c); - if (!checker.ConstraintIsEnforced(ct)) - continue; + if (!checker.ConstraintIsEnforced(ct)) continue; bool is_feasible = true; const ConstraintProto::ConstraintCase type = ct.constraint_case(); switch (type) { - case ConstraintProto::ConstraintCase::kBoolOr: - is_feasible = checker.BoolOrConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - is_feasible = checker.BoolAndConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - is_feasible = checker.AtMostOneConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kBoolXor: - is_feasible = checker.BoolXorConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kLinear: - is_feasible = checker.LinearConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kIntProd: - is_feasible = checker.IntProdConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kIntDiv: - is_feasible = checker.IntDivConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kIntMod: - is_feasible = checker.IntModConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kIntMin: - is_feasible = checker.IntMinConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kLinMin: - is_feasible = checker.LinMinConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kIntMax: - is_feasible = checker.IntMaxConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kLinMax: - is_feasible = checker.LinMaxConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kAllDiff: - is_feasible = checker.AllDiffConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kInterval: - is_feasible = checker.IntervalConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - is_feasible = checker.NoOverlapConstraintIsFeasible(model, ct); - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - is_feasible = checker.NoOverlap2DConstraintIsFeasible(model, ct); - break; - case ConstraintProto::ConstraintCase::kCumulative: - is_feasible = checker.CumulativeConstraintIsFeasible(model, ct); - break; - case ConstraintProto::ConstraintCase::kElement: - is_feasible = checker.ElementConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kTable: - is_feasible = checker.TableConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kAutomaton: - is_feasible = checker.AutomatonConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kCircuit: - is_feasible = checker.CircuitConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kRoutes: - is_feasible = checker.RoutesConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - is_feasible = checker.CircuitCoveringConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kInverse: - is_feasible = checker.InverseConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::kReservoir: - is_feasible = checker.ReservoirConstraintIsFeasible(ct); - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - // Empty constraint is always feasible. - break; - default: - LOG(FATAL) << "Unuspported constraint: " << ConstraintCaseName(type); + case ConstraintProto::ConstraintCase::kBoolOr: + is_feasible = checker.BoolOrConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + is_feasible = checker.BoolAndConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + is_feasible = checker.AtMostOneConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kBoolXor: + is_feasible = checker.BoolXorConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kLinear: + is_feasible = checker.LinearConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kIntProd: + is_feasible = checker.IntProdConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kIntDiv: + is_feasible = checker.IntDivConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kIntMod: + is_feasible = checker.IntModConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kIntMin: + is_feasible = checker.IntMinConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kLinMin: + is_feasible = checker.LinMinConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kIntMax: + is_feasible = checker.IntMaxConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kLinMax: + is_feasible = checker.LinMaxConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kAllDiff: + is_feasible = checker.AllDiffConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kInterval: + is_feasible = checker.IntervalConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + is_feasible = checker.NoOverlapConstraintIsFeasible(model, ct); + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + is_feasible = checker.NoOverlap2DConstraintIsFeasible(model, ct); + break; + case ConstraintProto::ConstraintCase::kCumulative: + is_feasible = checker.CumulativeConstraintIsFeasible(model, ct); + break; + case ConstraintProto::ConstraintCase::kElement: + is_feasible = checker.ElementConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kTable: + is_feasible = checker.TableConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kAutomaton: + is_feasible = checker.AutomatonConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kCircuit: + is_feasible = checker.CircuitConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kRoutes: + is_feasible = checker.RoutesConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + is_feasible = checker.CircuitCoveringConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kInverse: + is_feasible = checker.InverseConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::kReservoir: + is_feasible = checker.ReservoirConstraintIsFeasible(ct); + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + // Empty constraint is always feasible. + break; + default: + LOG(FATAL) << "Unuspported constraint: " << ConstraintCaseName(type); } if (!is_feasible) { VLOG(1) << "Failing constraint #" << c << " : " << ProtobufShortDebugString(model.constraints(c)); if (mapping_proto != nullptr && postsolve_mapping != nullptr) { std::vector fixed(mapping_proto->variables().size(), false); - for (const int var : *postsolve_mapping) - fixed[var] = true; + for (const int var : *postsolve_mapping) fixed[var] = true; for (const int var : UsedVariables(model.constraints(c))) { - VLOG(1) - << "var: " << var << " value: " << variable_values[var] - << " was_fixed: " << fixed[var] - << " initial_domain: " << ReadDomainFromProto( - model.variables(var)) - << " postsolved_domain: " << ReadDomainFromProto( - mapping_proto->variables(var)); + VLOG(1) << "var: " << var << " value: " << variable_values[var] + << " was_fixed: " << fixed[var] << " initial_domain: " + << ReadDomainFromProto(model.variables(var)) + << " postsolved_domain: " + << ReadDomainFromProto(mapping_proto->variables(var)); } } @@ -1169,5 +1113,5 @@ bool SolutionIsFeasible(const CpModelProto &model, return true; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_checker.h b/ortools/sat/cp_model_checker.h index 2923bab716..999903eb83 100644 --- a/ortools/sat/cp_model_checker.h +++ b/ortools/sat/cp_model_checker.h @@ -44,7 +44,7 @@ bool SolutionIsFeasible(const CpModelProto &model, const CpModelProto *mapping_proto = nullptr, const std::vector *postsolve_mapping = nullptr); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_CHECKER_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_CHECKER_H_ diff --git a/ortools/sat/cp_model_expand.cc b/ortools/sat/cp_model_expand.cc index ff4bf47c73..8fd8ef4389 100644 --- a/ortools/sat/cp_model_expand.cc +++ b/ortools/sat/cp_model_expand.cc @@ -33,7 +33,7 @@ namespace { void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { if (ct->reservoir().min_level() > ct->reservoir().max_level()) { VLOG(1) << "Empty level domain in reservoir constraint."; - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } // TODO(user): Support sharing constraints in the model across constraints. @@ -44,15 +44,13 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { const int true_literal = context->GetOrCreateConstantVar(1); const auto is_active_literal = [&reservoir, true_literal](int index) { - if (reservoir.actives_size() == 0) - return true_literal; + if (reservoir.actives_size() == 0) return true_literal; return reservoir.actives(index); - } - ; + }; // x_lesseq_y <=> (x <= y && l_x is true && l_y is true). - const auto add_reified_precedence = - [&context](int x_lesseq_y, int x, int y, int l_x, int l_y) { + const auto add_reified_precedence = [&context](int x_lesseq_y, int x, int y, + int l_x, int l_y) { // x_lesseq_y => (x <= y) && l_x is true && l_y is true. ConstraintProto *const lesseq = context->working_model->add_constraints(); lesseq->add_enforcement_literal(x_lesseq_y); @@ -82,8 +80,7 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { greater->add_enforcement_literal(NegatedRef(x_lesseq_y)); greater->add_enforcement_literal(l_x); greater->add_enforcement_literal(l_y); - } - ; + }; int num_positives = 0; int num_negatives = 0; @@ -99,20 +96,17 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { // Creates Boolean variables equivalent to (start[i] <= start[j]) i != j for (int i = 0; i < num_events - 1; ++i) { const int active_i = is_active_literal(i); - if (context->LiteralIsFalse(active_i)) - continue; + if (context->LiteralIsFalse(active_i)) continue; const int time_i = reservoir.times(i); for (int j = i + 1; j < num_events; ++j) { const int active_j = is_active_literal(j); - if (context->LiteralIsFalse(active_j)) - continue; + if (context->LiteralIsFalse(active_j)) continue; const int time_j = reservoir.times(j); const std::pair p = std::make_pair(time_i, time_j); const std::pair rev_p = std::make_pair(time_j, time_i); - if (gtl::ContainsKey(precedence_cache, p)) - continue; + if (gtl::ContainsKey(precedence_cache, p)) continue; const int i_lesseq_j = context->NewBoolVar(); context->working_model->mutable_variables(i_lesseq_j) @@ -142,8 +136,7 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { // (added below). for (int i = 0; i < num_events; ++i) { const int active_i = is_active_literal(i); - if (context->LiteralIsFalse(active_i)) - continue; + if (context->LiteralIsFalse(active_i)) continue; const int time_i = reservoir.times(i); // Accumulates demands of all predecessors. @@ -152,11 +145,9 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { // Add contributions from previous events. for (int j = 0; j < num_events; ++j) { - if (i == j) - continue; + if (i == j) continue; const int active_j = is_active_literal(j); - if (context->LiteralIsFalse(active_j)) - continue; + if (context->LiteralIsFalse(active_j)) continue; const int time_j = reservoir.times(j); level->mutable_linear()->add_vars(gtl::FindOrDieNoPrint( @@ -166,10 +157,10 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { // Accounts for own demand in the domain of the sum. const int64 demand_i = reservoir.demands(i); - level->mutable_linear() - ->add_domain(CapSub(reservoir.min_level(), demand_i)); - level->mutable_linear() - ->add_domain(CapSub(reservoir.max_level(), demand_i)); + level->mutable_linear()->add_domain( + CapSub(reservoir.min_level(), demand_i)); + level->mutable_linear()->add_domain( + CapSub(reservoir.max_level(), demand_i)); } } else { // If all demands have the same sign, we do not care about the order, just @@ -192,8 +183,7 @@ void ExpandReservoir(ConstraintProto *ct, PresolveContext *context) { context->working_model->add_constraints()->mutable_linear(); for (int i = 0; i < num_events; ++i) { const int active_i = is_active_literal(i); - if (context->LiteralIsFalse(active_i)) - continue; + if (context->LiteralIsFalse(active_i)) continue; const int time_i = reservoir.times(i); const int lesseq_0 = context->NewBoolVar(); @@ -250,14 +240,12 @@ void ExpandIntMod(ConstraintProto *ct, PresolveContext *context) { context->NewIntVar(Domain(var_lb / mod_ub, var_ub / mod_lb)); auto add_enforcement_literal_if_needed = [&]() { - if (ct->enforcement_literal_size() == 0) - return; + if (ct->enforcement_literal_size() == 0) return; const int literal = ct->enforcement_literal(0); - ConstraintProto *const last = context->working_model - ->mutable_constraints(context->working_model->constraints_size() - 1); + ConstraintProto *const last = context->working_model->mutable_constraints( + context->working_model->constraints_size() - 1); last->add_enforcement_literal(literal); - } - ; + }; // div = var / mod. IntegerArgumentProto *const div_proto = @@ -339,9 +327,7 @@ void AddXEqualYOrXEqualZero(int x_eq_y, int x, int y, equality->mutable_linear()->add_coeffs(-1); equality->mutable_linear()->add_domain(0); equality->mutable_linear()->add_domain(0); - context->AddImplyInDomain(NegatedRef(x_eq_y), x, { - 0, 0 - }); + context->AddImplyInDomain(NegatedRef(x_eq_y), x, {0, 0}); } // a_ref spans across 0, b_ref does not. @@ -353,30 +339,19 @@ void ExpandIntProdWithOneAcrossZero(int a_ref, int b_ref, int product_ref, // Split the domain of a in two, controlled by a new literal. const int a_is_positive = context->NewBoolVar(); - context->AddImplyInDomain(a_is_positive, a_ref, { - 0, kint64max - }); - context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, { - kint64min, -1 - }); - const int pos_a_ref = context->NewIntVar({ - 0, context->MaxOf(a_ref) - }); + context->AddImplyInDomain(a_is_positive, a_ref, {0, kint64max}); + context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, {kint64min, -1}); + const int pos_a_ref = context->NewIntVar({0, context->MaxOf(a_ref)}); AddXEqualYOrXEqualZero(a_is_positive, pos_a_ref, a_ref, context); - const int neg_a_ref = context->NewIntVar({ - context->MinOf(a_ref), 0 - }); + const int neg_a_ref = context->NewIntVar({context->MinOf(a_ref), 0}); AddXEqualYOrXEqualZero(NegatedRef(a_is_positive), neg_a_ref, a_ref, context); // Create product with the positive part ofa_ref. const bool b_is_positive = context->MinOf(b_ref) >= 0; - const Domain pos_a_product_domain = b_is_positive ? Domain({ - 0, context->MaxOf(product_ref) - }) - : Domain({ - context->MinOf(product_ref), 0 - }); + const Domain pos_a_product_domain = + b_is_positive ? Domain({0, context->MaxOf(product_ref)}) + : Domain({context->MinOf(product_ref), 0}); const int pos_a_product = context->NewIntVar(pos_a_product_domain); IntegerArgumentProto *pos_product = context->working_model->add_constraints()->mutable_int_prod(); @@ -384,13 +359,10 @@ void ExpandIntProdWithOneAcrossZero(int a_ref, int b_ref, int product_ref, pos_product->add_vars(pos_a_ref); pos_product->add_vars(b_ref); - // Create product with the negative part of a_ref. - const Domain neg_a_product_domain = b_is_positive ? Domain({ - context->MinOf(product_ref), 0 - }) - : Domain({ - 0, context->MaxOf(product_ref) - }); + // Create product with the negative part of a_ref. + const Domain neg_a_product_domain = + b_is_positive ? Domain({context->MinOf(product_ref), 0}) + : Domain({0, context->MaxOf(product_ref)}); const int neg_a_product = context->NewIntVar(neg_a_product_domain); IntegerArgumentProto *neg_product = context->working_model->add_constraints()->mutable_int_prod(); @@ -415,23 +387,15 @@ void ExpandIntProdWithTwoAcrossZero(int a_ref, int b_ref, int product_ref, PresolveContext *context) { // Split a_ref domain in two, controlled by a new literal. const int a_is_positive = context->NewBoolVar(); - context->AddImplyInDomain(a_is_positive, a_ref, { - 0, kint64max - }); - context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, { - kint64min, -1 - }); + context->AddImplyInDomain(a_is_positive, a_ref, {0, kint64max}); + context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, {kint64min, -1}); const int64 min_of_a = context->MinOf(a_ref); const int64 max_of_a = context->MaxOf(a_ref); - const int pos_a_ref = context->NewIntVar({ - 0, max_of_a - }); + const int pos_a_ref = context->NewIntVar({0, max_of_a}); AddXEqualYOrXEqualZero(a_is_positive, pos_a_ref, a_ref, context); - const int neg_a_ref = context->NewIntVar({ - min_of_a, 0 - }); + const int neg_a_ref = context->NewIntVar({min_of_a, 0}); AddXEqualYOrXEqualZero(NegatedRef(a_is_positive), neg_a_ref, a_ref, context); // Create product with two sub parts of a_ref. @@ -457,8 +421,7 @@ void ExpandIntProdWithTwoAcrossZero(int a_ref, int b_ref, int product_ref, void ExpandIntProd(ConstraintProto *ct, PresolveContext *context) { const IntegerArgumentProto &int_prod = ct->int_prod(); - if (int_prod.vars_size() != 2) - return; + if (int_prod.vars_size() != 2) return; const int a = int_prod.vars(0); const int b = int_prod.vars(1); const int p = int_prod.target(); @@ -537,7 +500,8 @@ void ExpandInverse(ConstraintProto *ct, PresolveContext *context) { // Note this reaches the fixpoint as there is a one to one mapping between // (variable-value) pairs in each vector. const auto filter_inverse_domain = [context, size, &possible_values]( - const auto & direct, const auto & inverse) { + const auto &direct, + const auto &inverse) { // Propagate for the inverse vector to the direct vector. for (int i = 0; i < size; ++i) { possible_values.clear(); @@ -561,8 +525,7 @@ void ExpandInverse(ConstraintProto *ct, PresolveContext *context) { } } return true; - } - ; + }; if (!filter_inverse_domain(ct->inverse().f_direct(), ct->inverse().f_inverse())) { @@ -606,7 +569,7 @@ void ExpandElement(ConstraintProto *ct, PresolveContext *context) { if (!context->IntersectDomainWith(index_ref, Domain(0, size - 1))) { VLOG(1) << "Empty domain for the index variable in ExpandElement()"; - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } bool all_constants = true; @@ -639,7 +602,7 @@ void ExpandElement(ConstraintProto *ct, PresolveContext *context) { if (!context->IntersectDomainWith( index_ref, Domain::FromValues(invalid_indices).Complement())) { VLOG(1) << "No compatible variable domains in ExpandElement()"; - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } // Re-read the domain. @@ -791,11 +754,10 @@ void ExpandElement(ConstraintProto *ct, PresolveContext *context) { // Adds clauses so that literals[i] true <=> encoding[value[i]] true. // This also implicitly use the fact that exactly one alternative is true. -void -LinkLiteralsAndValues(const std::vector &value_literals, - const std::vector &values, - const absl::flat_hash_map &target_encoding, - PresolveContext *context) { +void LinkLiteralsAndValues( + const std::vector &value_literals, const std::vector &values, + const absl::flat_hash_map &target_encoding, + PresolveContext *context) { CHECK_EQ(value_literals.size(), values.size()); // TODO(user): Make sure this does not appear in the profile. @@ -817,25 +779,26 @@ LinkLiteralsAndValues(const std::vector &value_literals, for (const auto &it : value_literals_per_target_literal) { const int target_literal = it.first; switch (it.second.size()) { - case 0: { - if (!context->SetLiteralToFalse(target_literal)) { - return; + case 0: { + if (!context->SetLiteralToFalse(target_literal)) { + return; + } + break; } - break; - } - case 1: { - context->StoreBooleanEqualityRelation(target_literal, it.second.front()); - break; - } - default: { - BoolArgumentProto *const bool_or = - context->working_model->add_constraints()->mutable_bool_or(); - bool_or->add_literals(NegatedRef(target_literal)); - for (const int value_literal : it.second) { - bool_or->add_literals(value_literal); - context->AddImplication(value_literal, target_literal); + case 1: { + context->StoreBooleanEqualityRelation(target_literal, + it.second.front()); + break; + } + default: { + BoolArgumentProto *const bool_or = + context->working_model->add_constraints()->mutable_bool_or(); + bool_or->add_literals(NegatedRef(target_literal)); + for (const int value_literal : it.second) { + bool_or->add_literals(value_literal); + context->AddImplication(value_literal, target_literal); + } } - } } } } @@ -853,19 +816,18 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { } } // The initial state is not in the final state. The model is unsat. - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } else if (proto.transition_label_size() == 0) { // Not transitions. The constraint is infeasible. - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } const int n = proto.vars_size(); - const std::vector vars = { proto.vars().begin(), proto.vars().end() }; + const std::vector vars = {proto.vars().begin(), proto.vars().end()}; - // Compute the set of reachable state at each time point. - const absl::flat_hash_set final_states({ - proto.final_states().begin(), proto.final_states().end() - }); + // Compute the set of reachable state at each time point. + const absl::flat_hash_set final_states( + {proto.final_states().begin(), proto.final_states().end()}); std::vector > reachable_states(n + 1); reachable_states[0].insert(proto.starting_state()); @@ -875,12 +837,9 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { const int64 tail = proto.transition_tail(t); const int64 label = proto.transition_label(t); const int64 head = proto.transition_head(t); - if (!reachable_states[time].contains(tail)) - continue; - if (!context->DomainContains(vars[time], label)) - continue; - if (time == n - 1 && !final_states.contains(head)) - continue; + if (!reachable_states[time].contains(tail)) continue; + if (!context->DomainContains(vars[time], label)) continue; + if (time == n - 1 && !final_states.contains(head)) continue; reachable_states[time + 1].insert(head); } } @@ -893,12 +852,9 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { const int64 label = proto.transition_label(t); const int64 head = proto.transition_head(t); - if (!reachable_states[time].contains(tail)) - continue; - if (!context->DomainContains(vars[time], label)) - continue; - if (!reachable_states[time + 1].contains(head)) - continue; + if (!reachable_states[time].contains(tail)) continue; + if (!context->DomainContains(vars[time], label)) continue; + if (!reachable_states[time + 1].contains(head)) continue; new_set.insert(tail); } reachable_states[time].swap(new_set); @@ -926,12 +882,9 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { const int64 label = proto.transition_label(i); const int64 head = proto.transition_head(i); - if (!reachable_states[time].contains(tail)) - continue; - if (!reachable_states[time + 1].contains(head)) - continue; - if (!context->DomainContains(vars[time], label)) - continue; + if (!reachable_states[time].contains(tail)) continue; + if (!reachable_states[time + 1].contains(head)) continue; + if (!context->DomainContains(vars[time], label)) continue; // TODO(user): if this transition correspond to just one in-state or // one-out state or one variable value, we could reuse the corresponding @@ -952,7 +905,7 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { if (!context->IntersectDomainWith(vars[time], Domain(transition_values.front()), &tmp_removed_values)) { - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } in_encoding.clear(); continue; @@ -984,7 +937,7 @@ void ExpandAutomaton(ConstraintProto *ct, PresolveContext *context) { encoding.clear(); if (!context->IntersectDomainWith(vars[time], Domain::FromValues(s), &removed_values)) { - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } // Fully encode the variable. @@ -1045,7 +998,7 @@ void ExpandNegativeTable(ConstraintProto *ct, PresolveContext *context) { } } - if (tuples.empty()) { // Early exit. + if (tuples.empty()) { // Early exit. context->UpdateRuleStats("table: empty negated constraint"); ct->Clear(); return; @@ -1065,8 +1018,7 @@ void ExpandNegativeTable(ConstraintProto *ct, PresolveContext *context) { clause.clear(); for (int i = 0; i < num_vars; ++i) { const int64 value = tuple[i]; - if (value == any_value) - continue; + if (value == any_value) continue; const int literal = context->GetOrCreateVarValueEncoding(table.vars(i), value); @@ -1157,11 +1109,11 @@ void ProcessOneVariable(const std::vector &tuple_literals, } // Simpler encoding for table constraints with 2 variables. -void -AddSizeTwoTable(const std::vector &vars, - const std::vector > &tuples, - const std::vector > &values_per_var, - PresolveContext *context) { +void AddSizeTwoTable( + const std::vector &vars, + const std::vector > &tuples, + const std::vector > &values_per_var, + PresolveContext *context) { CHECK_EQ(vars.size(), 2); const int left_var = vars[0]; const int right_var = vars[1]; @@ -1194,27 +1146,25 @@ AddSizeTwoTable(const std::vector &vars, int num_large_clause_added = 0; auto add_support_constraint = [context, &num_clause_added, &num_large_clause_added, &num_implications]( - int lit, const std::vector & support_literals, + int lit, const std::vector &support_literals, int max_support_size) { - if (support_literals.size() == max_support_size) - return; - if (support_literals.size() == 1) { - context->AddImplication(lit, support_literals.front()); - num_implications++; - } else { - BoolArgumentProto *bool_or = - context->working_model->add_constraints()->mutable_bool_or(); - for (const int support_literal : support_literals) { - bool_or->add_literals(support_literal); - } - bool_or->add_literals(NegatedRef(lit)); - num_clause_added++; - if (support_literals.size() > max_support_size / 2) { - num_large_clause_added++; - } - } - } - ; + if (support_literals.size() == max_support_size) return; + if (support_literals.size() == 1) { + context->AddImplication(lit, support_literals.front()); + num_implications++; + } else { + BoolArgumentProto *bool_or = + context->working_model->add_constraints()->mutable_bool_or(); + for (const int support_literal : support_literals) { + bool_or->add_literals(support_literal); + } + bool_or->add_literals(NegatedRef(lit)); + num_clause_added++; + if (support_literals.size() > max_support_size / 2) { + num_large_clause_added++; + } + } + }; for (const auto &it : left_to_right) { add_support_constraint(it.first, it.second, values_per_var[1].size()); @@ -1269,7 +1219,7 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { if (tuples.empty()) { context->UpdateRuleStats("table: empty"); - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } // Update variable domains. It is redundant with presolve, but we could be @@ -1277,9 +1227,10 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { // Also counts the number of fixed variables. int num_fixed_variables = 0; for (int var_index = 0; var_index < num_vars; ++var_index) { - CHECK(context->IntersectDomainWith(vars[var_index], Domain::FromValues({ - values_per_var[var_index].begin(), values_per_var[var_index].end() - }))); + CHECK(context->IntersectDomainWith( + vars[var_index], + Domain::FromValues({values_per_var[var_index].begin(), + values_per_var[var_index].end()}))); if (context->DomainOf(vars[var_index]).Size() == 1) { num_fixed_variables++; } @@ -1354,8 +1305,8 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { } std::string message = - absl::StrCat("Table: ", num_vars, " variables, original tuples = ", - num_original_tuples); + absl::StrCat("Table: ", num_vars, + " variables, original tuples = ", num_original_tuples); if (num_valid_tuples != num_original_tuples) { absl::StrAppend(&message, ", valid tuples = ", num_valid_tuples); } @@ -1370,8 +1321,8 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { absl::StrAppend(&message, ", num prefix tuples = ", num_prefix_tuples); } if (num_compressed_tuples != num_valid_tuples) { - absl::StrAppend(&message, ", compressed tuples = ", - num_compressed_tuples); + absl::StrAppend(&message, + ", compressed tuples = ", num_compressed_tuples); } VLOG(2) << message; } @@ -1423,8 +1374,7 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { std::vector active_values; std::vector any_tuple_literals; for (int var_index = 0; var_index < num_vars; ++var_index) { - if (values_per_var[var_index].size() == 1) - continue; + if (values_per_var[var_index].size() == 1) continue; active_tuple_literals.clear(); active_values.clear(); @@ -1455,8 +1405,7 @@ void ExpandPositiveTable(ConstraintProto *ct, PresolveContext *context) { void ExpandAllDiff(bool expand_non_permutations, ConstraintProto *ct, PresolveContext *context) { AllDifferentConstraintProto &proto = *ct->mutable_all_diff(); - if (proto.vars_size() <= 2) - return; + if (proto.vars_size() <= 2) return; const int num_vars = proto.vars_size(); @@ -1468,8 +1417,7 @@ void ExpandAllDiff(bool expand_non_permutations, ConstraintProto *ct, const bool is_permutation = proto.vars_size() == union_of_domains.Size(); - if (!is_permutation && !expand_non_permutations) - return; + if (!is_permutation && !expand_non_permutations) return; // Collect all possible variables that can take each value, and add one linear // equation per value stating that this value can be assigned at most once, or @@ -1480,8 +1428,7 @@ void ExpandAllDiff(bool expand_non_permutations, ConstraintProto *ct, std::vector possible_refs; int fixed_variable_count = 0; for (const int ref : proto.vars()) { - if (!context->DomainContains(ref, v)) - continue; + if (!context->DomainContains(ref, v)) continue; possible_refs.push_back(ref); if (context->DomainOf(ref).Size() == 1) { fixed_variable_count++; @@ -1490,12 +1437,11 @@ void ExpandAllDiff(bool expand_non_permutations, ConstraintProto *ct, if (fixed_variable_count > 1) { // Violates the definition of AllDifferent. - return (void) context->NotifyThatModelIsUnsat(); + return (void)context->NotifyThatModelIsUnsat(); } else if (fixed_variable_count == 1) { // Remove values from other domains. for (const int ref : possible_refs) { - if (context->DomainOf(ref).Size() == 1) - continue; + if (context->DomainOf(ref).Size() == 1) continue; if (!context->IntersectDomainWith(ref, Domain(v).Complement())) { VLOG(1) << "Empty domain for a variable in ExpandAllDiff()"; return; @@ -1533,11 +1479,10 @@ void ExpandAllDiff(bool expand_non_permutations, ConstraintProto *ct, ct->Clear(); } -} // namespace +} // namespace void ExpandCpModel(PresolveOptions options, PresolveContext *context) { - if (context->ModelIsUnsat()) - return; + if (context->ModelIsUnsat()) return; // Make sure all domains are initialized. context->InitializeNewDomains(); @@ -1547,48 +1492,47 @@ void ExpandCpModel(PresolveOptions options, PresolveContext *context) { ConstraintProto *const ct = context->working_model->mutable_constraints(i); bool skip = false; switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kReservoir: - ExpandReservoir(ct, context); - break; - case ConstraintProto::ConstraintCase::kIntMod: - ExpandIntMod(ct, context); - break; - case ConstraintProto::ConstraintCase::kIntProd: - ExpandIntProd(ct, context); - break; - case ConstraintProto::ConstraintCase::kLinMin: - ExpandLinMin(ct, context); - break; - case ConstraintProto::ConstraintCase::kElement: - if (options.parameters.expand_element_constraints()) { - ExpandElement(ct, context); - } - break; - case ConstraintProto::ConstraintCase::kInverse: - ExpandInverse(ct, context); - break; - case ConstraintProto::ConstraintCase::kAutomaton: - if (options.parameters.expand_automaton_constraints()) { - ExpandAutomaton(ct, context); - } - break; - case ConstraintProto::ConstraintCase::kTable: - if (ct->table().negated()) { - ExpandNegativeTable(ct, context); - } else if (options.parameters.expand_table_constraints()) { - ExpandPositiveTable(ct, context); - } - break; - case ConstraintProto::ConstraintCase::kAllDiff: - ExpandAllDiff(options.parameters.expand_alldiff_constraints(), ct, - context); - break; - default: - skip = true; - break; + case ConstraintProto::ConstraintCase::kReservoir: + ExpandReservoir(ct, context); + break; + case ConstraintProto::ConstraintCase::kIntMod: + ExpandIntMod(ct, context); + break; + case ConstraintProto::ConstraintCase::kIntProd: + ExpandIntProd(ct, context); + break; + case ConstraintProto::ConstraintCase::kLinMin: + ExpandLinMin(ct, context); + break; + case ConstraintProto::ConstraintCase::kElement: + if (options.parameters.expand_element_constraints()) { + ExpandElement(ct, context); + } + break; + case ConstraintProto::ConstraintCase::kInverse: + ExpandInverse(ct, context); + break; + case ConstraintProto::ConstraintCase::kAutomaton: + if (options.parameters.expand_automaton_constraints()) { + ExpandAutomaton(ct, context); + } + break; + case ConstraintProto::ConstraintCase::kTable: + if (ct->table().negated()) { + ExpandNegativeTable(ct, context); + } else if (options.parameters.expand_table_constraints()) { + ExpandPositiveTable(ct, context); + } + break; + case ConstraintProto::ConstraintCase::kAllDiff: + ExpandAllDiff(options.parameters.expand_alldiff_constraints(), ct, + context); + break; + default: + skip = true; + break; } - if (skip) - continue; // Nothing was done for this constraint. + if (skip) continue; // Nothing was done for this constraint. // Update variable-contraint graph. context->UpdateNewConstraintsVariableUsage(); @@ -1597,8 +1541,7 @@ void ExpandCpModel(PresolveOptions options, PresolveContext *context) { } // Early exit if the model is unsat. - if (context->ModelIsUnsat()) - return; + if (context->ModelIsUnsat()) return; } // Make sure the context is consistent. @@ -1611,5 +1554,5 @@ void ExpandCpModel(PresolveOptions options, PresolveContext *context) { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_expand.h b/ortools/sat/cp_model_expand.h index 21c8b184f0..781c4e5c90 100644 --- a/ortools/sat/cp_model_expand.h +++ b/ortools/sat/cp_model_expand.h @@ -26,7 +26,7 @@ namespace sat { // simplification of the model. Furthermore, this expansion is mandatory. void ExpandCpModel(PresolveOptions options, PresolveContext *context); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_EXPAND_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_EXPAND_H_ diff --git a/ortools/sat/cp_model_lns.cc b/ortools/sat/cp_model_lns.cc index ccc4cb92c0..c3c63dd1d4 100644 --- a/ortools/sat/cp_model_lns.cc +++ b/ortools/sat/cp_model_lns.cc @@ -34,8 +34,11 @@ NeighborhoodGeneratorHelper::NeighborhoodGeneratorHelper( CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, SharedTimeLimit *shared_time_limit, SharedBoundsManager *shared_bounds) - : SubSolver(""), parameters_(*parameters), model_proto_(*model_proto), - shared_time_limit_(shared_time_limit), shared_bounds_(shared_bounds), + : SubSolver(""), + parameters_(*parameters), + model_proto_(*model_proto), + shared_time_limit_(shared_time_limit), + shared_bounds_(shared_bounds), shared_response_(shared_response) { CHECK(shared_response_ != nullptr); if (shared_bounds_ != nullptr) { @@ -107,15 +110,12 @@ void NeighborhoodGeneratorHelper::RecomputeHelperData() { // this will duplicate already existing code :-( we should probably still do // at least enforcement literal and clauses? We could maybe run a light // presolve? - var_to_constraint_.assign(model_proto_.variables_size(), { - }); - constraint_to_var_.assign(model_proto_.constraints_size(), { - }); + var_to_constraint_.assign(model_proto_.variables_size(), {}); + constraint_to_var_.assign(model_proto_.constraints_size(), {}); for (int ct_index = 0; ct_index < model_proto_.constraints_size(); ++ct_index) { for (const int var : UsedVariables(model_proto_.constraints(ct_index))) { - if (IsConstant(var)) - continue; + if (IsConstant(var)) continue; var_to_constraint_[var].push_back(ct_index); constraint_to_var_[ct_index].push_back(var); CHECK_GE(var, 0); @@ -148,8 +148,7 @@ void NeighborhoodGeneratorHelper::RecomputeHelperData() { } // Revert to no focus if active_variables_ is empty(). - if (!active_variables_.empty()) - return; + if (!active_variables_.empty()) return; } // Add all non-constant variables. @@ -192,21 +191,20 @@ Neighborhood NeighborhoodGeneratorHelper::FixGivenVariables( neighborhood.cp_model.clear_solution_hint(); for (int var = 0; var < neighborhood.cp_model.variables_size(); ++var) { neighborhood.cp_model.mutable_solution_hint()->add_vars(var); - neighborhood.cp_model.mutable_solution_hint() - ->add_values(initial_solution.solution(var)); + neighborhood.cp_model.mutable_solution_hint()->add_values( + initial_solution.solution(var)); } neighborhood.is_reduced = !variables_to_fix.empty(); - if (!neighborhood.is_reduced) - return neighborhood; + if (!neighborhood.is_reduced) return neighborhood; CHECK_EQ(initial_solution.solution_size(), neighborhood.cp_model.variables_size()); for (const int var : variables_to_fix) { neighborhood.cp_model.mutable_variables(var)->clear_domain(); - neighborhood.cp_model.mutable_variables(var) - ->add_domain(initial_solution.solution(var)); - neighborhood.cp_model.mutable_variables(var) - ->add_domain(initial_solution.solution(var)); + neighborhood.cp_model.mutable_variables(var)->add_domain( + initial_solution.solution(var)); + neighborhood.cp_model.mutable_variables(var)->add_domain( + initial_solution.solution(var)); } // TODO(user): force better objective? Note that this is already done when the @@ -222,8 +220,7 @@ Neighborhood NeighborhoodGeneratorHelper::RemoveMarkedConstraints( // save memory and speed-up LNS presolving. Neighborhood neighborhood = FullNeighborhood(); - if (constraints_to_remove.empty()) - return neighborhood; + if (constraints_to_remove.empty()) return neighborhood; neighborhood.is_reduced = false; for (const int constraint : constraints_to_remove) { neighborhood.cp_model.mutable_constraints(constraint)->Clear(); @@ -236,8 +233,7 @@ Neighborhood NeighborhoodGeneratorHelper::RelaxGivenVariables( const CpSolverResponse &initial_solution, const std::vector &relaxed_variables) const { std::vector relaxed_variables_set(model_proto_.variables_size(), false); - for (const int var : relaxed_variables) - relaxed_variables_set[var] = true; + for (const int var : relaxed_variables) relaxed_variables_set[var] = true; std::vector fixed_variables; for (const int i : active_variables_) { if (!relaxed_variables_set[i]) { @@ -263,8 +259,7 @@ bool NeighborhoodGenerator::ReadyToGenerate() const { double NeighborhoodGenerator::GetUCBScore(int64 total_num_calls) const { absl::MutexLock mutex_lock(&mutex_); DCHECK_GE(total_num_calls, num_calls_); - if (num_calls_ <= 10) - return std::numeric_limits::infinity(); + if (num_calls_ <= 10) return std::numeric_limits::infinity(); return current_average_ + sqrt((2 * log(total_num_calls)) / num_calls_); } @@ -327,8 +322,8 @@ void NeighborhoodGenerator::Synchronize() { } // Update the difficulty. - difficulty_.Update(/*num_decreases=*/ num_not_fully_solved_in_batch, - /*num_increases=*/ num_fully_solved_in_batch); + difficulty_.Update(/*num_decreases=*/num_not_fully_solved_in_batch, + /*num_increases=*/num_fully_solved_in_batch); // Bump the time limit if we saw no better solution in the last few calls. // This means that as the search progress, we likely spend more and more time @@ -360,12 +355,11 @@ void GetRandomSubset(double relative_size, std::vector *base, base->resize(target_size); } -} // namespace +} // namespace -Neighborhood -SimpleNeighborhoodGenerator::Generate(const CpSolverResponse &initial_solution, - double difficulty, - random_engine_t *random) { +Neighborhood SimpleNeighborhoodGenerator::Generate( + const CpSolverResponse &initial_solution, double difficulty, + random_engine_t *random) { std::vector fixed_variables = helper_.ActiveVariables(); GetRandomSubset(1.0 - difficulty, &fixed_variables, random); return helper_.FixGivenVariables(initial_solution, fixed_variables); @@ -386,8 +380,9 @@ Neighborhood VariableGraphNeighborhoodGenerator::Generate( std::vector relaxed_variables; std::vector visited_variables; - const int first_var = helper_ - .ActiveVariables()[absl::Uniform(*random, 0, num_active_vars)]; + const int first_var = + helper_ + .ActiveVariables()[absl::Uniform(*random, 0, num_active_vars)]; visited_variables_set[first_var] = true; visited_variables.push_back(first_var); relaxed_variables.push_back(first_var); @@ -399,8 +394,7 @@ Neighborhood VariableGraphNeighborhoodGenerator::Generate( // visited_variables[i]. for (const int ct : helper_.VarToConstraint()[visited_variables[i]]) { for (const int var : helper_.ConstraintToVar()[ct]) { - if (visited_variables_set[var]) - continue; + if (visited_variables_set[var]) continue; visited_variables_set[var] = true; random_variables.push_back(var); } @@ -417,8 +411,7 @@ Neighborhood VariableGraphNeighborhoodGenerator::Generate( break; } } - if (relaxed_variables.size() >= target_size) - break; + if (relaxed_variables.size() >= target_size) break; } return helper_.RelaxGivenVariables(initial_solution, relaxed_variables); @@ -448,8 +441,7 @@ Neighborhood ConstraintGraphNeighborhoodGenerator::Generate( std::vector random_variables; while (relaxed_variables.size() < target_size) { // Stop if we have a full connected component. - if (next_constraints.empty()) - break; + if (next_constraints.empty()) break; // Pick a random unprocessed constraint. const int i = absl::Uniform(*random, 0, next_constraints.size()); @@ -463,18 +455,15 @@ Neighborhood ConstraintGraphNeighborhoodGenerator::Generate( random_variables = helper_.ConstraintToVar()[contraint_index]; std::shuffle(random_variables.begin(), random_variables.end(), *random); for (const int var : random_variables) { - if (visited_variables_set[var]) - continue; + if (visited_variables_set[var]) continue; visited_variables_set[var] = true; if (helper_.IsActive(var)) { relaxed_variables.push_back(var); } - if (relaxed_variables.size() == target_size) - break; + if (relaxed_variables.size() == target_size) break; for (const int ct : helper_.VarToConstraint()[var]) { - if (added_constraints[ct]) - continue; + if (added_constraints[ct]) continue; added_constraints[ct] = true; next_constraints.push_back(ct); } @@ -498,12 +487,10 @@ Neighborhood GenerateSchedulingNeighborhoodForRelaxation( // Fix the presence/absence of non-relaxed intervals. for (const int i : helper.TypeToConstraints(ConstraintProto::kInterval)) { - if (ignored_intervals.count(i)) - continue; + if (ignored_intervals.count(i)) continue; const ConstraintProto &interval_ct = neighborhood.cp_model.constraints(i); - if (interval_ct.enforcement_literal().empty()) - continue; + if (interval_ct.enforcement_literal().empty()) continue; CHECK_EQ(interval_ct.enforcement_literal().size(), 1); const int enforcement_ref = interval_ct.enforcement_literal(0); @@ -527,29 +514,29 @@ Neighborhood GenerateSchedulingNeighborhoodForRelaxation( std::vector > start_interval_pairs; for (const int i : neighborhood.cp_model.constraints(c).no_overlap().intervals()) { - if (ignored_intervals.count(i)) - continue; + if (ignored_intervals.count(i)) continue; const ConstraintProto &interval_ct = neighborhood.cp_model.constraints(i); // TODO(user): we ignore size zero for now. const int size_var = interval_ct.interval().size(); - if (initial_solution.solution(size_var) == 0) - continue; + if (initial_solution.solution(size_var) == 0) continue; const int start_var = interval_ct.interval().start(); const int64 start_value = initial_solution.solution(start_var); - start_interval_pairs.push_back({ - start_value, i - }); + start_interval_pairs.push_back({start_value, i}); } std::sort(start_interval_pairs.begin(), start_interval_pairs.end()); // Add precedence between the remaining intervals, forcing their order. for (int i = 0; i + 1 < start_interval_pairs.size(); ++i) { - const int before_var = neighborhood.cp_model - .constraints(start_interval_pairs[i].second).interval().end(); - const int after_var = neighborhood.cp_model - .constraints(start_interval_pairs[i + 1].second).interval().start(); + const int before_var = + neighborhood.cp_model.constraints(start_interval_pairs[i].second) + .interval() + .end(); + const int after_var = + neighborhood.cp_model.constraints(start_interval_pairs[i + 1].second) + .interval() + .start(); CHECK_LE(initial_solution.solution(before_var), initial_solution.solution(after_var)); @@ -570,8 +557,8 @@ Neighborhood GenerateSchedulingNeighborhoodForRelaxation( neighborhood.cp_model.clear_solution_hint(); for (int var = 0; var < neighborhood.cp_model.variables_size(); ++var) { neighborhood.cp_model.mutable_solution_hint()->add_vars(var); - neighborhood.cp_model.mutable_solution_hint() - ->add_values(initial_solution.solution(var)); + neighborhood.cp_model.mutable_solution_hint()->add_values( + initial_solution.solution(var)); } neighborhood.is_generated = true; @@ -598,9 +585,7 @@ Neighborhood SchedulingTimeWindowNeighborhoodGenerator::Generate( const int start_var = interval_ct.interval().start(); const int64 start_value = initial_solution.solution(start_var); - start_interval_pairs.push_back({ - start_value, i - }); + start_interval_pairs.push_back({start_value, i}); } std::sort(start_interval_pairs.begin(), start_interval_pairs.end()); const int relaxed_size = std::floor(difficulty * start_interval_pairs.size()); @@ -674,15 +659,15 @@ Neighborhood RelaxationInducedNeighborhoodGenerator::Generate( ? random_bool(*random) : lp_solution_available; if (use_lp_relaxation) { - rins_neighborhood = GetRINSNeighborhood( - response_manager_, /*relaxation_solutions=*/ nullptr, lp_solutions_, - incomplete_solutions_, random); + rins_neighborhood = + GetRINSNeighborhood(response_manager_, /*relaxation_solutions=*/nullptr, + lp_solutions_, incomplete_solutions_, random); neighborhood.source_info = incomplete_solution_available ? "incomplete" : "lp"; } else { CHECK(relaxation_solution_available || incomplete_solution_available); rins_neighborhood = GetRINSNeighborhood( - response_manager_, relaxation_solutions_, /*lp_solutions=*/ nullptr, + response_manager_, relaxation_solutions_, /*lp_solutions=*/nullptr, incomplete_solutions_, random); neighborhood.source_info = incomplete_solution_available ? "incomplete" : "relaxation"; @@ -698,10 +683,8 @@ Neighborhood RelaxationInducedNeighborhoodGenerator::Generate( rins_neighborhood.fixed_vars) { const int var = fixed_var.first; const int64 value = fixed_var.second; - if (var >= neighborhood.cp_model.variables_size()) - continue; - if (!helper_.IsActive(var)) - continue; + if (var >= neighborhood.cp_model.variables_size()) continue; + if (!helper_.IsActive(var)) continue; const Domain domain = ReadDomainFromProto(neighborhood.cp_model.variables(var)); @@ -721,10 +704,8 @@ Neighborhood RelaxationInducedNeighborhoodGenerator::Generate( const int var = reduced_var.first; const int64 lb = reduced_var.second.first; const int64 ub = reduced_var.second.second; - if (var >= neighborhood.cp_model.variables_size()) - continue; - if (!helper_.IsActive(var)) - continue; + if (var >= neighborhood.cp_model.variables_size()) continue; + if (!helper_.IsActive(var)) continue; Domain domain = ReadDomainFromProto(neighborhood.cp_model.variables(var)); domain = domain.IntersectionWith(Domain(lb, ub)); if (domain.IsEmpty()) { @@ -783,45 +764,45 @@ WeightedRandomRelaxationNeighborhoodGenerator:: // TODO(user): Experiment with different starting weights. for (int c = 0; c < num_constraints; ++c) { switch (helper_.ModelProto().constraints(c).constraint_case()) { - case ConstraintProto::kCumulative: - case ConstraintProto::kAllDiff: - case ConstraintProto::kElement: - case ConstraintProto::kRoutes: - case ConstraintProto::kCircuit: - case ConstraintProto::kCircuitCovering: - constraint_weights_.push_back(3.0); - num_removable_constraints_++; - break; - case ConstraintProto::kBoolOr: - case ConstraintProto::kBoolAnd: - case ConstraintProto::kBoolXor: - case ConstraintProto::kIntProd: - case ConstraintProto::kIntDiv: - case ConstraintProto::kIntMod: - case ConstraintProto::kIntMax: - case ConstraintProto::kLinMax: - case ConstraintProto::kIntMin: - case ConstraintProto::kLinMin: - case ConstraintProto::kNoOverlap: - case ConstraintProto::kNoOverlap2D: - constraint_weights_.push_back(2.0); - num_removable_constraints_++; - break; - case ConstraintProto::kLinear: - case ConstraintProto::kTable: - case ConstraintProto::kAutomaton: - case ConstraintProto::kInverse: - case ConstraintProto::kReservoir: - case ConstraintProto::kAtMostOne: - constraint_weights_.push_back(1.0); - num_removable_constraints_++; - break; - case ConstraintProto::CONSTRAINT_NOT_SET: - case ConstraintProto::kInterval: - // Removing intervals is not easy because other constraint might require - // them, so for now, we don't remove them. - constraint_weights_.push_back(0.0); - break; + case ConstraintProto::kCumulative: + case ConstraintProto::kAllDiff: + case ConstraintProto::kElement: + case ConstraintProto::kRoutes: + case ConstraintProto::kCircuit: + case ConstraintProto::kCircuitCovering: + constraint_weights_.push_back(3.0); + num_removable_constraints_++; + break; + case ConstraintProto::kBoolOr: + case ConstraintProto::kBoolAnd: + case ConstraintProto::kBoolXor: + case ConstraintProto::kIntProd: + case ConstraintProto::kIntDiv: + case ConstraintProto::kIntMod: + case ConstraintProto::kIntMax: + case ConstraintProto::kLinMax: + case ConstraintProto::kIntMin: + case ConstraintProto::kLinMin: + case ConstraintProto::kNoOverlap: + case ConstraintProto::kNoOverlap2D: + constraint_weights_.push_back(2.0); + num_removable_constraints_++; + break; + case ConstraintProto::kLinear: + case ConstraintProto::kTable: + case ConstraintProto::kAutomaton: + case ConstraintProto::kInverse: + case ConstraintProto::kReservoir: + case ConstraintProto::kAtMostOne: + constraint_weights_.push_back(1.0); + num_removable_constraints_++; + break; + case ConstraintProto::CONSTRAINT_NOT_SET: + case ConstraintProto::kInterval: + // Removing intervals is not easy because other constraint might require + // them, so for now, we don't remove them. + constraint_weights_.push_back(0.0); + break; } } } @@ -881,13 +862,10 @@ Neighborhood WeightedRandomRelaxationNeighborhoodGenerator::Generate( std::vector > constraint_removal_scores; std::uniform_real_distribution random_var(0.0, 1.0); for (int c = 0; c < constraint_weights_.size(); ++c) { - if (constraint_weights_[c] <= 0) - continue; + if (constraint_weights_[c] <= 0) continue; const double u = random_var(*random); const double score = std::pow(u, (1 / constraint_weights_[c])); - constraint_removal_scores.push_back({ - score, c - }); + constraint_removal_scores.push_back({score, c}); } std::sort(constraint_removal_scores.rbegin(), constraint_removal_scores.rend()); @@ -899,11 +877,9 @@ Neighborhood WeightedRandomRelaxationNeighborhoodGenerator::Generate( absl::MutexLock mutex_lock(&mutex_); result.id = next_available_id_; next_available_id_++; - removed_constraints_.insert({ - result.id, removed_constraints - }); + removed_constraints_.insert({result.id, removed_constraints}); return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_lns.h b/ortools/sat/cp_model_lns.h index 27a4022ce2..b6e764d71d 100644 --- a/ortools/sat/cp_model_lns.h +++ b/ortools/sat/cp_model_lns.h @@ -62,7 +62,7 @@ struct Neighborhood { // Note that its implement the SubSolver interface to be able to Synchronize() // the bounds of the base problem with the external world. class NeighborhoodGeneratorHelper : public SubSolver { -public: + public: NeighborhoodGeneratorHelper(CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, @@ -71,16 +71,14 @@ public: // SubSolver interface. bool TaskIsAvailable() override { return false; } - std::function GenerateTask(int64 task_id) override { - return {}; - } + std::function GenerateTask(int64 task_id) override { return {}; } void Synchronize() override; // Returns the LNS fragment where the given variables are fixed to the value // they take in the given solution. - Neighborhood - FixGivenVariables(const CpSolverResponse &initial_solution, - const std::vector &variables_to_fix) const; + Neighborhood FixGivenVariables( + const CpSolverResponse &initial_solution, + const std::vector &variables_to_fix) const; // Returns the neighborhood where the given constraints are removed. Neighborhood RemoveMarkedConstraints( @@ -88,9 +86,9 @@ public: // Returns the LNS fragment which will relax all inactive variables and all // variables in relaxed_variables. - Neighborhood - RelaxGivenVariables(const CpSolverResponse &initial_solution, - const std::vector &relaxed_variables) const; + Neighborhood RelaxGivenVariables( + const CpSolverResponse &initial_solution, + const std::vector &relaxed_variables) const; // Returns a trivial model by fixing all active variables to the initial // solution values. @@ -117,10 +115,9 @@ public: } // Returns all the constraints indices of a given type. - const absl::Span - TypeToConstraints(ConstraintProto::ConstraintCase type) const { - if (type >= type_to_constraints_.size()) - return {}; + const absl::Span TypeToConstraints( + ConstraintProto::ConstraintCase type) const { + if (type >= type_to_constraints_.size()) return {}; return absl::MakeSpan(type_to_constraints_[type]); } @@ -141,7 +138,7 @@ public: return *shared_response_; } -private: + private: // Recompute most of the class member. This needs to be called when the // domains of the variables are updated. void RecomputeHelperData(); @@ -183,7 +180,7 @@ private: // Base class for a CpModelProto neighborhood generator. class NeighborhoodGenerator { -public: + public: NeighborhoodGenerator(const std::string &name, NeighborhoodGeneratorHelper const *helper) : name_(name), helper_(*helper), difficulty_(0.5) {} @@ -314,7 +311,7 @@ public: return deterministic_time_; } -protected: + protected: // Triggered with each call to Synchronize() for each recently added // SolveData. This is meant to be used for processing feedbacks by specific // neighborhood generators to adjust the neighborhood generation process. @@ -324,7 +321,7 @@ protected: const NeighborhoodGeneratorHelper &helper_; mutable absl::Mutex mutex_; -private: + private: std::vector solve_data_; // Current parameters to be used when generating/solving a neighborhood with @@ -343,7 +340,7 @@ private: // Pick a random subset of variables. class SimpleNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit SimpleNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -356,7 +353,7 @@ public: // variable connected by some constraint to the first one, and so on. The // variable of the last "level" are selected randomly. class VariableGraphNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit VariableGraphNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -369,7 +366,7 @@ public: // select constraints that share at least one variable with the already selected // constraints. The variable from the "last" constraint are selected randomly. class ConstraintGraphNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit ConstraintGraphNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -391,7 +388,7 @@ Neighborhood GenerateSchedulingNeighborhoodForRelaxation( // // TODO(user): Also deal with cumulative constraint. class SchedulingNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit SchedulingNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -403,7 +400,7 @@ public: // Similar to SchedulingNeighborhoodGenerator except the set of intervals that // are relaxed are from a specific random time interval. class SchedulingTimeWindowNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit SchedulingTimeWindowNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -427,7 +424,7 @@ public: // solution values. This was published in "RENS – The Relaxation Enforced // Neighborhood" 2009 by Timo Berthold. class RelaxationInducedNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit RelaxationInducedNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const SharedResponseManager *response_manager, @@ -451,7 +448,7 @@ public: // Returns true if the required solutions are available. bool ReadyToGenerate() const override; -private: + private: const SharedResponseManager *response_manager_; const SharedRelaxationSolutionRepository *relaxation_solutions_; const SharedLPSolutionRepository *lp_solutions_; @@ -463,7 +460,7 @@ private: // is in sync with the difficulty passed to the generator. class ConsecutiveConstraintsRelaxationNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: explicit ConsecutiveConstraintsRelaxationNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name) : NeighborhoodGenerator(name, helper) {} @@ -481,7 +478,7 @@ public: // constraints are more likely to get removed. class WeightedRandomRelaxationNeighborhoodGenerator : public NeighborhoodGenerator { -public: + public: WeightedRandomRelaxationNeighborhoodGenerator( NeighborhoodGeneratorHelper const *helper, const std::string &name); @@ -493,11 +490,11 @@ public: bool IsRelaxationGenerator() const override { return true; } bool ReadyToGenerate() const override { return true; } -private: + private: // Adjusts the weights of the constraints removed to get the neighborhood // based on the solve_data. - void AdditionalProcessingOnSynchronize(const SolveData &solve_data) - override ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void AdditionalProcessingOnSynchronize(const SolveData &solve_data) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Higher weighted constraints are more likely to get removed. std::vector constraint_weights_; @@ -512,7 +509,7 @@ private: int64 next_available_id_ ABSL_GUARDED_BY(mutex_) = 0; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_LNS_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_LNS_H_ diff --git a/ortools/sat/cp_model_loader.cc b/ortools/sat/cp_model_loader.cc index ad75c2a7de..6b289e8af5 100644 --- a/ortools/sat/cp_model_loader.cc +++ b/ortools/sat/cp_model_loader.cc @@ -93,10 +93,10 @@ bool ConstraintIsNEq(const LinearConstraintProto &proto, int64 sum_max = 0; ComputeLinearBounds(proto, mapping, integer_trail, &sum_min, &sum_max); - const Domain complement = Domain(sum_min, sum_max) - .IntersectionWith(ReadDomainFromProto(proto).Complement()); - if (complement.IsEmpty()) - return false; + const Domain complement = + Domain(sum_min, sum_max) + .IntersectionWith(ReadDomainFromProto(proto).Complement()); + if (complement.IsEmpty()) return false; const int64 value = complement.Min(); if (complement.Size() == 1) { @@ -108,7 +108,7 @@ bool ConstraintIsNEq(const LinearConstraintProto &proto, return false; } -} // namespace +} // namespace void CpModelMapping::CreateVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, @@ -129,8 +129,7 @@ void CpModelMapping::CreateVariables(const CpModelProto &model_proto, reverse_boolean_map_.resize(num_proto_variables, -1); for (int i = 0; i < num_proto_variables; ++i) { const auto &domain = model_proto.variables(i).domain(); - if (domain.size() != 2) - continue; + if (domain.size() != 2) continue; if (domain[0] >= 0 && domain[1] <= 1) { booleans_[i] = new_var; reverse_boolean_map_[new_var] = i; @@ -145,14 +144,10 @@ void CpModelMapping::CreateVariables(const CpModelProto &model_proto, sat_solver->SetNumVariables(new_var.value()); for (const BooleanVariable var : true_variables) { - m->Add(ClauseConstraint({ - sat::Literal(var, true) - })); + m->Add(ClauseConstraint({sat::Literal(var, true)})); } for (const BooleanVariable var : false_variables) { - m->Add(ClauseConstraint({ - sat::Literal(var, false) - })); + m->Add(ClauseConstraint({sat::Literal(var, false)})); } } @@ -222,10 +217,8 @@ void CpModelMapping::CreateVariables(const CpModelProto &model_proto, // Link any variable that has both views. for (int i = 0; i < num_proto_variables; ++i) { - if (integers_[i] == kNoIntegerVariable) - continue; - if (booleans_[i] == kNoBooleanVariable) - continue; + if (integers_[i] == kNoIntegerVariable) continue; + if (booleans_[i] == kNoBooleanVariable) continue; // Associate with corresponding integer variable. encoder->AssociateToIntegerEqualValue(sat::Literal(booleans_[i], true), @@ -270,8 +263,7 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, auto *sat_solver = m->GetOrCreate(); // TODO(user): Debug what makes it unsat at this point. - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; // Detection of literal equivalent to (i_var == value). We collect all the // half-reified constraint lit => equality or lit => inequality for a given @@ -280,12 +272,11 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, const ConstraintProto *ct; sat::Literal literal; int64 value; - bool is_equality; // false if != instead. + bool is_equality; // false if != instead. bool operator<(const EqualityDetectionHelper &o) const { if (literal.Variable() == o.literal.Variable()) { - if (value == o.value) - return is_equality && !o.is_equality; + if (value == o.value) return is_equality && !o.is_equality; return value < o.value; } return literal.Variable() < o.literal.Variable(); @@ -322,10 +313,8 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, if (ct.constraint_case() != ConstraintProto::ConstraintCase::kLinear) { continue; } - if (ct.enforcement_literal().size() != 1) - continue; - if (ct.linear().vars_size() != 1) - continue; + if (ct.enforcement_literal().size() != 1) continue; + if (ct.linear().vars_size() != 1) continue; // ct is a linear constraint with one term and one enforcement literal. const sat::Literal enforcement_literal = Literal(ct.enforcement_literal(0)); @@ -334,26 +323,25 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, const Domain domain = ReadDomainFromProto(model_proto.variables(var)); const Domain domain_if_enforced = - ReadDomainFromProto(ct.linear()).InverseMultiplicationBy( - ct.linear().coeffs(0) * (RefIsPositive(ref) ? 1 : -1)); + ReadDomainFromProto(ct.linear()) + .InverseMultiplicationBy(ct.linear().coeffs(0) * + (RefIsPositive(ref) ? 1 : -1)); // Detect enforcement_literal => (var >= value or var <= value). if (domain_if_enforced.NumIntervals() == 1) { if (domain_if_enforced.Max() >= domain.Max() && domain_if_enforced.Min() > domain.Min()) { - inequalities.push_back({ - &ct, enforcement_literal, - IntegerLiteral::GreaterOrEqual( - Integer(var), IntegerValue(domain_if_enforced.Min())) - }); + inequalities.push_back( + {&ct, enforcement_literal, + IntegerLiteral::GreaterOrEqual( + Integer(var), IntegerValue(domain_if_enforced.Min()))}); implied_bounds->Add(enforcement_literal, inequalities.back().i_lit); } else if (domain_if_enforced.Min() <= domain.Min() && domain_if_enforced.Max() < domain.Max()) { - inequalities.push_back({ - &ct, enforcement_literal, - IntegerLiteral::LowerOrEqual( - Integer(var), IntegerValue(domain_if_enforced.Max())) - }); + inequalities.push_back( + {&ct, enforcement_literal, + IntegerLiteral::LowerOrEqual( + Integer(var), IntegerValue(domain_if_enforced.Max()))}); implied_bounds->Add(enforcement_literal, inequalities.back().i_lit); } } @@ -366,9 +354,8 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, { const Domain inter = domain.IntersectionWith(domain_if_enforced); if (!inter.IsEmpty() && inter.Min() == inter.Max()) { - var_to_equalities[var].push_back({ - &ct, enforcement_literal, inter.Min(), true - }); + var_to_equalities[var].push_back( + {&ct, enforcement_literal, inter.Min(), true}); if (domain.Contains(inter.Min())) { variables_to_encoded_values_[var].insert(inter.Min()); } @@ -378,9 +365,8 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, const Domain inter = domain.IntersectionWith(domain_if_enforced.Complement()); if (!inter.IsEmpty() && inter.Min() == inter.Max()) { - var_to_equalities[var].push_back({ - &ct, enforcement_literal, inter.Min(), false - }); + var_to_equalities[var].push_back( + {&ct, enforcement_literal, inter.Min(), false}); if (domain.Contains(inter.Min())) { variables_to_encoded_values_[var].insert(inter.Min()); } @@ -422,13 +408,11 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, // Encode the half-inequalities. int num_half_inequalities = 0; for (const auto inequality : inequalities) { - if (ConstraintIsAlreadyLoaded(inequality.ct)) - continue; + if (ConstraintIsAlreadyLoaded(inequality.ct)) continue; m->Add( Implication(inequality.literal, encoder->GetOrCreateAssociatedLiteral(inequality.i_lit))); - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; ++num_half_inequalities; already_loaded_ct_.insert(inequality.ct); @@ -451,8 +435,7 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, for (int i = 0; i < var_to_equalities.size(); ++i) { std::vector &encoding = var_to_equalities[i]; std::sort(encoding.begin(), encoding.end()); - if (encoding.empty()) - continue; + if (encoding.empty()) continue; num_constraints += encoding.size(); absl::flat_hash_set values; @@ -475,8 +458,7 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, // TODO(user): Try to remove it. Normally we caught UNSAT above, but // tests are very flaky (it only happens in parallel). Keeping it there for // the time being. - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; // Encode the half-equalities. // @@ -485,8 +467,7 @@ void CpModelMapping::ExtractEncoding(const CpModelProto &model_proto, // however, that in the presolve, we should only use the "representative" in // linear constraints, so we should be fine. for (const auto equality : encoding) { - if (ConstraintIsAlreadyLoaded(equality.ct)) - continue; + if (ConstraintIsAlreadyLoaded(equality.ct)) continue; const class Literal eq = encoder->GetOrCreateLiteralAssociatedToEquality( integers_[i], IntegerValue(equality.value)); if (equality.is_equality) { @@ -531,14 +512,10 @@ void CpModelMapping::PropagateEncodingFromEquivalenceRelations( int64 num_associations = 0; int64 num_set_to_false = 0; for (const ConstraintProto &ct : model_proto.constraints()) { - if (!ct.enforcement_literal().empty()) - continue; - if (ct.constraint_case() != ConstraintProto::kLinear) - continue; - if (ct.linear().vars_size() != 2) - continue; - if (!ConstraintIsEq(ct.linear())) - continue; + if (!ct.enforcement_literal().empty()) continue; + if (ct.constraint_case() != ConstraintProto::kLinear) continue; + if (ct.linear().vars_size() != 2) continue; + if (!ConstraintIsEq(ct.linear())) continue; const IntegerValue rhs(ct.linear().domain(0)); @@ -558,8 +535,7 @@ void CpModelMapping::PropagateEncodingFromEquivalenceRelations( // TODO(user): This is not supposed to happen, but apparently it did on // once on routing_GCM_0001_sat.fzn. Investigate and fix. - if (coeff1 == 0 || coeff2 == 0) - continue; + if (coeff1 == 0 || coeff2 == 0) continue; // We first map the >= literals. // It is important to do that first, since otherwise mapping a == literal @@ -605,18 +581,16 @@ void CpModelMapping::PropagateEncodingFromEquivalenceRelations( VLOG(1) << "Num associations from equivalences = " << num_associations; } if (num_set_to_false > 0) { - VLOG(1) - << "Num literals set to false from equivalences = " << num_set_to_false; + VLOG(1) << "Num literals set to false from equivalences = " + << num_set_to_false; } } void CpModelMapping::DetectOptionalVariables(const CpModelProto &model_proto, Model *m) { const SatParameters ¶meters = *(m->GetOrCreate()); - if (!parameters.use_optional_variables()) - return; - if (parameters.enumerate_all_solutions()) - return; + if (!parameters.use_optional_variables()) return; + if (parameters.enumerate_all_solutions()) return; // The variables from the objective cannot be marked as optional! const int num_proto_variables = model_proto.variables_size(); @@ -675,12 +649,9 @@ void CpModelMapping::DetectOptionalVariables(const CpModelProto &model_proto, const IntegerVariableProto &var_proto = model_proto.variables(var); const int64 min = var_proto.domain(0); const int64 max = var_proto.domain(var_proto.domain().size() - 1); - if (min == max) - continue; - if (min == 0 && max == 1) - continue; - if (enforcement_intersection[var].empty()) - continue; + if (min == max) continue; + if (min == 0 && max == 1) continue; + if (enforcement_intersection[var].empty()) continue; ++num_optionals; integer_trail->MarkIntegerVariableAsOptional( @@ -695,17 +666,18 @@ void CpModelMapping::DetectOptionalVariables(const CpModelProto &model_proto, // ============================================================================ class FullEncodingFixedPointComputer { -public: + public: FullEncodingFixedPointComputer(const CpModelProto &model_proto, Model *model) : model_proto_(model_proto), - parameters_(*(model->GetOrCreate())), model_(model), + parameters_(*(model->GetOrCreate())), + model_(model), mapping_(model->GetOrCreate()), integer_encoder_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()) {} void ComputeFixedPoint(); -private: + private: DEFINE_INT_TYPE(ConstraintIndex, int32); // Constraint ct is interested by (full-encoding) state of variable. @@ -734,24 +706,21 @@ private: // Note that we always consider a fixed variable to be fully encoded here. const bool IsFullyEncoded(int v) { const IntegerVariable variable = mapping_->Integer(v); - if (v == kNoIntegerVariable) - return false; + if (v == kNoIntegerVariable) return false; return integer_trail_->IsFixed(variable) || integer_encoder_->VariableIsFullyEncoded(variable); } const bool VariableIsFixed(int v) { const IntegerVariable variable = mapping_->Integer(v); - if (v == kNoIntegerVariable) - return false; + if (v == kNoIntegerVariable) return false; return integer_trail_->IsFixed(variable); } void FullyEncode(int v) { v = PositiveRef(v); const IntegerVariable variable = mapping_->Integer(v); - if (v == kNoIntegerVariable) - return; + if (v == kNoIntegerVariable) return; if (!integer_trail_->IsFixed(variable)) { model_->Add(FullyEncodeVariable(variable)); } @@ -805,16 +774,14 @@ void FullEncodingFixedPointComputer::ComputeFixedPoint() { // . - the size of the domain is > 2 int num_variables_fully_encoded_by_heuristics = 0; for (int var = 0; var < num_vars; ++var) { - if (!mapping_->IsInteger(var) || IsFullyEncoded(var)) - continue; + if (!mapping_->IsInteger(var) || IsFullyEncoded(var)) continue; const IntegerVariableProto &int_var_proto = model_proto_.variables(var); const Domain domain = ReadDomainFromProto(int_var_proto); int64 domain_size = domain.Size(); int64 num_diff_or_equal_var_constraints = 0; int64 num_potential_encoded_values_without_bounds = 0; - if (domain_size <= 2) - continue; + if (domain_size <= 2) continue; const absl::flat_hash_set &value_set = mapping_->PotentialEncodedValues(var); @@ -859,28 +826,27 @@ void FullEncodingFixedPointComputer::ComputeFixedPoint() { const int variable = variables_to_propagate_.back(); variables_to_propagate_.pop_back(); for (const ConstraintIndex ct_index : variable_watchers_[variable]) { - if (constraint_is_finished_[ct_index]) - continue; + if (constraint_is_finished_[ct_index]) continue; constraint_is_finished_[ct_index] = ProcessConstraint(ct_index); } } } // Returns true if the constraint has finished encoding what it wants. -bool -FullEncodingFixedPointComputer::ProcessConstraint(ConstraintIndex ct_index) { +bool FullEncodingFixedPointComputer::ProcessConstraint( + ConstraintIndex ct_index) { const ConstraintProto &ct = model_proto_.constraints(ct_index.value()); switch (ct.constraint_case()) { - case ConstraintProto::ConstraintProto::kElement: - return ProcessElement(ct_index); - case ConstraintProto::ConstraintProto::kTable: - return ProcessTable(ct_index); - case ConstraintProto::ConstraintProto::kAutomaton: - return ProcessAutomaton(ct_index); - case ConstraintProto::ConstraintProto::kLinear: - return ProcessLinear(ct_index); - default: - return true; + case ConstraintProto::ConstraintProto::kElement: + return ProcessElement(ct_index); + case ConstraintProto::ConstraintProto::kTable: + return ProcessTable(ct_index); + case ConstraintProto::ConstraintProto::kAutomaton: + return ProcessAutomaton(ct_index); + case ConstraintProto::ConstraintProto::kLinear: + return ProcessLinear(ct_index); + default: + return true; } } @@ -893,35 +859,30 @@ bool FullEncodingFixedPointComputer::ProcessElement(ConstraintIndex ct_index) { const int target = ct.element().target(); // If target is fixed, do not encode variables. - if (VariableIsFixed(target)) - return true; + if (VariableIsFixed(target)) return true; // If target is a constant or fully encoded, variables must be fully encoded. if (IsFullyEncoded(target)) { - for (const int v : ct.element().vars()) - FullyEncode(v); + for (const int v : ct.element().vars()) FullyEncode(v); } // If all non-target variables are fully encoded, target must be too. bool all_variables_are_fully_encoded = true; for (const int v : ct.element().vars()) { - if (v == target) - continue; + if (v == target) continue; if (!IsFullyEncoded(v)) { all_variables_are_fully_encoded = false; break; } } if (all_variables_are_fully_encoded) { - if (!IsFullyEncoded(target)) - FullyEncode(target); + if (!IsFullyEncoded(target)) FullyEncode(target); return true; } // If some variables are not fully encoded, register on those. if (constraint_is_registered_[ct_index]) { - for (const int v : ct.element().vars()) - Register(ct_index, v); + for (const int v : ct.element().vars()) Register(ct_index, v); Register(ct_index, target); } return false; @@ -930,8 +891,7 @@ bool FullEncodingFixedPointComputer::ProcessElement(ConstraintIndex ct_index) { bool FullEncodingFixedPointComputer::ProcessTable(ConstraintIndex ct_index) { const ConstraintProto &ct = model_proto_.constraints(ct_index.value()); - if (ct.table().negated()) - return true; + if (ct.table().negated()) return true; for (const int variable : ct.table().vars()) { FullyEncode(variable); @@ -940,8 +900,8 @@ bool FullEncodingFixedPointComputer::ProcessTable(ConstraintIndex ct_index) { return true; } -bool -FullEncodingFixedPointComputer::ProcessAutomaton(ConstraintIndex ct_index) { +bool FullEncodingFixedPointComputer::ProcessAutomaton( + ConstraintIndex ct_index) { const ConstraintProto &ct = model_proto_.constraints(ct_index.value()); for (const int variable : ct.automaton().vars()) { FullyEncode(variable); @@ -1037,17 +997,14 @@ void LoadEquivalenceAC(const std::vector enforcement_literal, for (const auto value_literal : encoder->FullDomainEncoding(var2)) { const IntegerValue target = rhs - value_literal.value * coeff2; if (!gtl::ContainsKey(term1_value_to_literal, target)) { - m->Add(EnforcedClause(enforcement_literal, { - value_literal.literal.Negated() - })); + m->Add(EnforcedClause(enforcement_literal, + {value_literal.literal.Negated()})); } else { const Literal target_literal = term1_value_to_literal[target]; - m->Add(EnforcedClause(enforcement_literal, { - value_literal.literal.Negated(), target_literal - })); - m->Add(EnforcedClause(enforcement_literal, { - value_literal.literal, target_literal.Negated() - })); + m->Add(EnforcedClause(enforcement_literal, + {value_literal.literal.Negated(), target_literal})); + m->Add(EnforcedClause(enforcement_literal, + {value_literal.literal, target_literal.Negated()})); // This "target" can never be reached again, so it is safe to remove it. // We do that so we know the term1 values that are never reached. @@ -1063,9 +1020,7 @@ void LoadEquivalenceAC(const std::vector enforcement_literal, } std::sort(implied_false.begin(), implied_false.end()); for (const Literal l : implied_false) { - m->Add(EnforcedClause(enforcement_literal, { - l.Negated() - })); + m->Add(EnforcedClause(enforcement_literal, {l.Negated()})); } } @@ -1088,22 +1043,21 @@ void LoadEquivalenceNeqAC(const std::vector enforcement_literal, const auto &it = term1_value_to_literal.find(target_value); if (it != term1_value_to_literal.end()) { const Literal target_literal = it->second; - m->Add(EnforcedClause(enforcement_literal, { - value_literal.literal.Negated(), target_literal.Negated() - })); + m->Add(EnforcedClause( + enforcement_literal, + {value_literal.literal.Negated(), target_literal.Negated()})); } } } -} // namespace +} // namespace void LoadLinearConstraint(const ConstraintProto &ct, Model *m) { auto *mapping = m->GetOrCreate(); if (ct.linear().vars().empty()) { const Domain rhs = ReadDomainFromProto(ct.linear()); - if (rhs.Contains(0)) - return; + if (rhs.Contains(0)) return; if (HasEnforcementLiteral(ct)) { std::vector clause; for (const int ref : ct.enforcement_literal()) { @@ -1151,11 +1105,10 @@ void LoadLinearConstraint(const ConstraintProto &ct, Model *m) { ct.linear().domain(0) != min_sum && ct.linear().domain(0) != max_sum && encoder->VariableIsFullyEncoded(vars[0]) && encoder->VariableIsFullyEncoded(vars[1])) { - VLOG(3) - << "Load AC version of " << ct.DebugString() - << ", var0 domain = " << integer_trail->InitialVariableDomain(vars[0]) - << ", var1 domain = " << integer_trail->InitialVariableDomain( - vars[1]); + VLOG(3) << "Load AC version of " << ct.DebugString() << ", var0 domain = " + << integer_trail->InitialVariableDomain(vars[0]) + << ", var1 domain = " + << integer_trail->InitialVariableDomain(vars[1]); return LoadEquivalenceAC(mapping->Literals(ct.enforcement_literal()), IntegerValue(coeffs[0]), vars[0], IntegerValue(coeffs[1]), vars[1], @@ -1168,25 +1121,24 @@ void LoadLinearConstraint(const ConstraintProto &ct, Model *m) { single_value != min_sum && single_value != max_sum && encoder->VariableIsFullyEncoded(vars[0]) && encoder->VariableIsFullyEncoded(vars[1])) { - VLOG(3) - << "Load NAC version of " << ct.DebugString() - << ", var0 domain = " << integer_trail->InitialVariableDomain(vars[0]) - << ", var1 domain = " << integer_trail->InitialVariableDomain(vars[1]) - << ", value = " << single_value; - return LoadEquivalenceNeqAC( - mapping->Literals(ct.enforcement_literal()), IntegerValue(coeffs[0]), - vars[0], IntegerValue(coeffs[1]), vars[1], IntegerValue(single_value), - m); + VLOG(3) << "Load NAC version of " << ct.DebugString() + << ", var0 domain = " + << integer_trail->InitialVariableDomain(vars[0]) + << ", var1 domain = " + << integer_trail->InitialVariableDomain(vars[1]) + << ", value = " << single_value; + return LoadEquivalenceNeqAC(mapping->Literals(ct.enforcement_literal()), + IntegerValue(coeffs[0]), vars[0], + IntegerValue(coeffs[1]), vars[1], + IntegerValue(single_value), m); } } if (ct.linear().domain_size() == 2) { int64 lb = ct.linear().domain(0); int64 ub = ct.linear().domain(1); - if (min_sum >= lb) - lb = kint64min; - if (max_sum <= ub) - ub = kint64max; + if (min_sum >= lb) lb = kint64min; + if (max_sum <= ub) ub = kint64max; if (!HasEnforcementLiteral(ct)) { if (all_booleans) { @@ -1195,9 +1147,7 @@ void LoadLinearConstraint(const ConstraintProto &ct, Model *m) { std::vector cst; for (int i = 0; i < vars.size(); ++i) { const int ref = ct.linear().vars(i); - cst.push_back({ - mapping->Literal(ref), coeffs[i] - }); + cst.push_back({mapping->Literal(ref), coeffs[i]}); } m->Add(BooleanLinearConstraint(lb, ub, &cst)); } else { @@ -1225,24 +1175,18 @@ void LoadLinearConstraint(const ConstraintProto &ct, Model *m) { for (int i = 0; i < ct.linear().domain_size(); i += 2) { int64 lb = ct.linear().domain(i); int64 ub = ct.linear().domain(i + 1); - if (min_sum >= lb) - lb = kint64min; - if (max_sum <= ub) - ub = kint64max; + if (min_sum >= lb) lb = kint64min; + if (max_sum <= ub) ub = kint64max; const Literal subdomain_literal(m->Add(NewBooleanVariable()), true); clause.push_back(subdomain_literal); if (lb != kint64min) { - m->Add(ConditionalWeightedSumGreaterOrEqual({ - subdomain_literal - }, - vars, coeffs, lb)); + m->Add(ConditionalWeightedSumGreaterOrEqual({subdomain_literal}, vars, + coeffs, lb)); } if (ub != kint64max) { - m->Add(ConditionalWeightedSumLowerOrEqual({ - subdomain_literal - }, - vars, coeffs, ub)); + m->Add(ConditionalWeightedSumLowerOrEqual({subdomain_literal}, vars, + coeffs, ub)); } } for (const int ref : ct.enforcement_literal()) { @@ -1266,8 +1210,7 @@ void LoadAllDiffConstraint(const ConstraintProto &ct, Model *m) { int num_fully_encoded = 0; int64 max_domain_size = 0; for (const IntegerVariable variable : vars) { - if (encoder->VariableIsFullyEncoded(variable)) - num_fully_encoded++; + if (encoder->VariableIsFullyEncoded(variable)) num_fully_encoded++; IntegerValue lb = integer_trail->LowerBound(variable); IntegerValue ub = integer_trail->UpperBound(variable); @@ -1356,8 +1299,7 @@ void LoadNoOverlapConstraint(const ConstraintProto &ct, Model *m) { } void LoadNoOverlap2dConstraint(const ConstraintProto &ct, Model *m) { - if (ct.no_overlap_2d().x_intervals().empty()) - return; + if (ct.no_overlap_2d().x_intervals().empty()) return; auto *mapping = m->GetOrCreate(); const std::vector x_intervals = mapping->Intervals(ct.no_overlap_2d().x_intervals()); @@ -1462,8 +1404,7 @@ void LoadElementConstraintBounds(const ConstraintProto &ct, Model *m) { selectors.push_back(literal_value.literal); const Literal r = literal_value.literal; - if (vars[i] == target) - continue; + if (vars[i] == target) continue; if (m->Get(IsFixed(target))) { const int64 value = m->Get(Value(target)); m->Add(ImpliesInInterval(r, vars[i], value, value)); @@ -1540,10 +1481,7 @@ void LoadElementConstraintAC(const ConstraintProto &ct, Model *m) { const Literal var_is_value_and_selected = Literal(m->Add(NewBooleanVariable()), true); - m->Add(ReifiedBoolAnd({ - i_lit, var_is_value - }, - var_is_value_and_selected)); + m->Add(ReifiedBoolAnd({i_lit, var_is_value}, var_is_value_and_selected)); value_to_literals[value].push_back(var_is_value_and_selected); var_selected_literals.push_back(var_is_value_and_selected); } @@ -1557,9 +1495,7 @@ void LoadElementConstraintAC(const ConstraintProto &ct, Model *m) { const Literal target_is_value = entry.second; if (!gtl::ContainsKey(value_to_literals, value)) { - m->Add(ClauseConstraint({ - target_is_value.Negated() - })); + m->Add(ClauseConstraint({target_is_value.Negated()})); } else { m->Add(ReifiedBoolOr(value_to_literals[value], target_is_value)); } @@ -1587,11 +1523,8 @@ void LoadElementConstraintHalfAC(const ConstraintProto &ct, Model *m) { for (const auto value_literal : m->Add(FullyEncodeVariable(index))) { const int i = value_literal.value.value(); m->Add(FullyEncodeVariable(vars[i])); - LoadEquivalenceAC({ - value_literal.literal - }, - IntegerValue(1), vars[i], IntegerValue(-1), target, - IntegerValue(0), m); + LoadEquivalenceAC({value_literal.literal}, IntegerValue(1), vars[i], + IntegerValue(-1), target, IntegerValue(0), m); } } @@ -1611,12 +1544,8 @@ void LoadBooleanElement(const ConstraintProto &ct, Model *m) { for (const auto value_literal : m->Add(FullyEncodeVariable(index))) { const Literal a_lit = literals[value_literal.value.value()]; const Literal i_lit = value_literal.literal; - m->Add(ClauseConstraint({ - i_lit.Negated(), a_lit.Negated(), target - })); - m->Add(ClauseConstraint({ - i_lit.Negated(), a_lit, target.Negated() - })); + m->Add(ClauseConstraint({i_lit.Negated(), a_lit.Negated(), target})); + m->Add(ClauseConstraint({i_lit.Negated(), a_lit, target.Negated()})); all_true.push_back(a_lit.Negated()); all_false.push_back(a_lit); } @@ -1627,7 +1556,7 @@ void LoadBooleanElement(const ConstraintProto &ct, Model *m) { // TODO(user): Investigate filtering this with active literals. } -} // namespace +} // namespace void LoadElementConstraint(const ConstraintProto &ct, Model *m) { auto *mapping = m->GetOrCreate(); @@ -1690,8 +1619,7 @@ void LoadElementConstraint(const ConstraintProto &ct, Model *m) { IntegerVariable variable = mapping->Integer(v); const bool is_full = m->Get(IsFixed(variable)) || encoder->VariableIsFullyEncoded(variable); - if (is_full) - num_AC_variables++; + if (is_full) num_AC_variables++; } const SatParameters ¶ms = *m->GetOrCreate(); @@ -1737,10 +1665,9 @@ void LoadAutomatonConstraint(const ConstraintProto &ct, Model *m) { std::vector > transitions; transitions.reserve(num_transitions); for (int i = 0; i < num_transitions; ++i) { - transitions.push_back({ - ct.automaton().transition_tail(i), ct.automaton().transition_label(i), - ct.automaton().transition_head(i) - }); + transitions.push_back({ct.automaton().transition_tail(i), + ct.automaton().transition_label(i), + ct.automaton().transition_head(i)}); } const int64 starting_state = ct.automaton().starting_state(); @@ -1751,9 +1678,8 @@ void LoadAutomatonConstraint(const ConstraintProto &ct, Model *m) { // From vector of n IntegerVariables, returns an n x n matrix of Literal // such that matrix[i][j] is the Literal corresponding to vars[i] == j. -std::vector > -GetSquareMatrixFromIntegerVariables(const std::vector &vars, - Model *m) { +std::vector > GetSquareMatrixFromIntegerVariables( + const std::vector &vars, Model *m) { const int n = vars.size(); const Literal kTrueLiteral = m->GetOrCreate()->GetTrueLiteral(); @@ -1784,8 +1710,7 @@ GetSquareMatrixFromIntegerVariables(const std::vector &vars, void LoadCircuitConstraint(const ConstraintProto &ct, Model *m) { const auto &circuit = ct.circuit(); - if (circuit.tails().empty()) - return; + if (circuit.tails().empty()) return; std::vector tails(circuit.tails().begin(), circuit.tails().end()); std::vector heads(circuit.heads().begin(), circuit.heads().end()); @@ -1797,8 +1722,7 @@ void LoadCircuitConstraint(const ConstraintProto &ct, Model *m) { void LoadRoutesConstraint(const ConstraintProto &ct, Model *m) { const auto &routes = ct.routes(); - if (routes.tails().empty()) - return; + if (routes.tails().empty()) return; std::vector tails(routes.tails().begin(), routes.tails().end()); std::vector heads(routes.heads().begin(), routes.heads().end()); @@ -1806,7 +1730,7 @@ void LoadRoutesConstraint(const ConstraintProto &ct, Model *m) { m->GetOrCreate()->Literals(routes.literals()); const int num_nodes = ReindexArcs(&tails, &heads, &literals); m->Add(SubcircuitConstraint(num_nodes, tails, heads, literals, - /*multiple_subcircuit_through_zero=*/ true)); + /*multiple_subcircuit_through_zero=*/true)); } void LoadCircuitCoveringConstraint(const ConstraintProto &ct, Model *m) { @@ -1824,75 +1748,75 @@ void LoadCircuitCoveringConstraint(const ConstraintProto &ct, Model *m) { bool LoadConstraint(const ConstraintProto &ct, Model *m) { switch (ct.constraint_case()) { - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - return true; - case ConstraintProto::ConstraintCase::kBoolOr: - LoadBoolOrConstraint(ct, m); - return true; - case ConstraintProto::ConstraintCase::kBoolAnd: - LoadBoolAndConstraint(ct, m); - return true; - case ConstraintProto::ConstraintCase::kAtMostOne: - LoadAtMostOneConstraint(ct, m); - return true; - case ConstraintProto::ConstraintCase::kBoolXor: - LoadBoolXorConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kLinear: - LoadLinearConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kAllDiff: - LoadAllDiffConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kIntProd: - LoadIntProdConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kIntDiv: - LoadIntDivConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kIntMin: - LoadIntMinConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kLinMax: - LoadLinMaxConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kIntMax: - LoadIntMaxConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kInterval: - // Already dealt with. - return true; - case ConstraintProto::ConstraintProto::kNoOverlap: - LoadNoOverlapConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kNoOverlap2D: - LoadNoOverlap2dConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kCumulative: - LoadCumulativeConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kElement: - LoadElementConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kTable: - LoadTableConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kAutomaton: - LoadAutomatonConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kCircuit: - LoadCircuitConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kRoutes: - LoadRoutesConstraint(ct, m); - return true; - case ConstraintProto::ConstraintProto::kCircuitCovering: - LoadCircuitCoveringConstraint(ct, m); - return true; - default: - return false; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + return true; + case ConstraintProto::ConstraintCase::kBoolOr: + LoadBoolOrConstraint(ct, m); + return true; + case ConstraintProto::ConstraintCase::kBoolAnd: + LoadBoolAndConstraint(ct, m); + return true; + case ConstraintProto::ConstraintCase::kAtMostOne: + LoadAtMostOneConstraint(ct, m); + return true; + case ConstraintProto::ConstraintCase::kBoolXor: + LoadBoolXorConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kLinear: + LoadLinearConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kAllDiff: + LoadAllDiffConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kIntProd: + LoadIntProdConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kIntDiv: + LoadIntDivConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kIntMin: + LoadIntMinConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kLinMax: + LoadLinMaxConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kIntMax: + LoadIntMaxConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kInterval: + // Already dealt with. + return true; + case ConstraintProto::ConstraintProto::kNoOverlap: + LoadNoOverlapConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kNoOverlap2D: + LoadNoOverlap2dConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kCumulative: + LoadCumulativeConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kElement: + LoadElementConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kTable: + LoadTableConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kAutomaton: + LoadAutomatonConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kCircuit: + LoadCircuitConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kRoutes: + LoadRoutesConstraint(ct, m); + return true; + case ConstraintProto::ConstraintProto::kCircuitCovering: + LoadCircuitCoveringConstraint(ct, m); + return true; + default: + return false; } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_loader.h b/ortools/sat/cp_model_loader.h index 57e337bf8e..ff62b485a4 100644 --- a/ortools/sat/cp_model_loader.h +++ b/ortools/sat/cp_model_loader.h @@ -61,7 +61,7 @@ struct ObjectiveDefinition { // // This also holds some information used when loading a CpModel proto. class CpModelMapping { -public: + public: // Extracts all the used variables in the CpModelProto and creates a // sat::Model representation for them. More precisely // - All Boolean variables will be mapped. @@ -91,9 +91,8 @@ public: // // TODO(user): In an ideal world, all affine relations like this should be // removed in the presolve. - void - PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, - Model *m); + void PropagateEncodingFromEquivalenceRelations( + const CpModelProto &model_proto, Model *m); // Returns true if the given CpModelProto variable reference refers to a // Boolean varaible. Such variable will always have an associated Literal(), @@ -129,24 +128,21 @@ public: template std::vector Integers(const List &list) const { std::vector result; - for (const auto i : list) - result.push_back(Integer(i)); + for (const auto i : list) result.push_back(Integer(i)); return result; } template std::vector Literals(const ProtoIndices &indices) const { std::vector result; - for (const int i : indices) - result.push_back(CpModelMapping::Literal(i)); + for (const int i : indices) result.push_back(CpModelMapping::Literal(i)); return result; } template std::vector Intervals(const ProtoIndices &indices) const { std::vector result; - for (const int i : indices) - result.push_back(Interval(i)); + for (const int i : indices) result.push_back(Interval(i)); return result; } @@ -169,13 +165,11 @@ public: // Note that both these functions returns positive reference or -1. int GetProtoVariableFromBooleanVariable(BooleanVariable var) const { - if (var.value() >= reverse_boolean_map_.size()) - return -1; + if (var.value() >= reverse_boolean_map_.size()) return -1; return reverse_boolean_map_[var]; } int GetProtoVariableFromIntegerVariable(IntegerVariable var) const { - if (var.value() >= reverse_integer_map_.size()) - return -1; + if (var.value() >= reverse_integer_map_.size()) return -1; return reverse_integer_map_[var]; } @@ -187,16 +181,14 @@ public: int NumIntegerVariables() const { int result = 0; for (const IntegerVariable var : integers_) { - if (var != kNoIntegerVariable) - result++; + if (var != kNoIntegerVariable) result++; } return result; } int NumBooleanVariables() const { int result = 0; for (const BooleanVariable var : booleans_) { - if (var != kNoBooleanVariable) - result++; + if (var != kNoBooleanVariable) result++; } return result; } @@ -213,7 +205,7 @@ public: return empty_set_; } -private: + private: // Note that only the variables used by at least one constraint will be // created, the other will have a kNo[Integer,Interval,Boolean]VariableValue. std::vector integers_; @@ -277,7 +269,7 @@ void LoadInverseConstraint(const ConstraintProto &ct, Model *m); LinearExpression GetExprFromProto(const LinearExpressionProto &expr_proto, const CpModelMapping &mapping); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_LOADER_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_LOADER_H_ diff --git a/ortools/sat/cp_model_objective.cc b/ortools/sat/cp_model_objective.cc index 5b74c5cb05..b1397484ea 100644 --- a/ortools/sat/cp_model_objective.cc +++ b/ortools/sat/cp_model_objective.cc @@ -19,8 +19,7 @@ namespace operations_research { namespace sat { void EncodeObjectiveAsSingleVariable(CpModelProto *cp_model) { - if (!cp_model->has_objective()) - return; + if (!cp_model->has_objective()) return; if (cp_model->objective().vars_size() == 1) { // Canonicalize the objective to make it easier on us by always making the @@ -36,8 +35,7 @@ void EncodeObjectiveAsSingleVariable(CpModelProto *cp_model) { CHECK(cp_model->objective().domain().empty()); double old_factor = cp_model->objective().scaling_factor(); - if (old_factor == 0.0) - old_factor = 1.0; + if (old_factor == 0.0) old_factor = 1.0; const double old_offset = cp_model->objective().offset(); cp_model->mutable_objective()->set_scaling_factor(old_factor * muliplier); cp_model->mutable_objective()->set_offset(old_offset / muliplier); @@ -59,7 +57,8 @@ void EncodeObjectiveAsSingleVariable(CpModelProto *cp_model) { cp_model->objective().coeffs(i) * (RefIsPositive(ref) ? 1 : -1); const int64 value1 = cp_model->variables(var).domain(0) * coeff; const int64 value2 = cp_model->variables(var).domain( - cp_model->variables(var).domain_size() - 1) * coeff; + cp_model->variables(var).domain_size() - 1) * + coeff; min_obj += std::min(value1, value2); max_obj += std::max(value1, value2); } @@ -93,5 +92,5 @@ void EncodeObjectiveAsSingleVariable(CpModelProto *cp_model) { cp_model->mutable_objective()->clear_domain(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_objective.h b/ortools/sat/cp_model_objective.h index e6087e839b..1ad442f3cf 100644 --- a/ortools/sat/cp_model_objective.h +++ b/ortools/sat/cp_model_objective.h @@ -34,7 +34,7 @@ namespace sat { // presolve, we can always do this optimization just before solving the model. void EncodeObjectiveAsSingleVariable(CpModelProto *cp_model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_OBJECTIVE_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_OBJECTIVE_H_ diff --git a/ortools/sat/cp_model_postsolve.cc b/ortools/sat/cp_model_postsolve.cc index 01a5c70cee..b1465ba498 100644 --- a/ortools/sat/cp_model_postsolve.cc +++ b/ortools/sat/cp_model_postsolve.cc @@ -40,8 +40,7 @@ void PostsolveClause(const ConstraintProto &ct, std::vector *domains) { (*domains)[PositiveRef(ref)] = Domain(0); } } - if (satisfied) - return; + if (satisfied) return; // Change the value of the first variable (which was chosen at presolve). const int first_ref = ct.bool_or().literals(0); @@ -61,8 +60,7 @@ void PostsolveLinear(const ConstraintProto &ct, const int var = ct.linear().vars(i); const int64 coeff = ct.linear().coeffs(i); CHECK_LT(var, domains->size()); - if (coeff == 0) - continue; + if (coeff == 0) continue; if ((*domains)[var].IsFixed()) { fixed_activity += (*domains)[var].FixedValue() * coeff; } else { @@ -70,8 +68,7 @@ void PostsolveLinear(const ConstraintProto &ct, free_coeffs.push_back(coeff); } } - if (free_vars.empty()) - return; + if (free_vars.empty()) return; Domain rhs = ReadDomainFromProto(ct.linear()).AdditionWith(Domain(-fixed_activity)); @@ -80,7 +77,7 @@ void PostsolveLinear(const ConstraintProto &ct, if (free_vars.size() == 1) { const int var = free_vars[0]; const Domain domain = rhs.InverseMultiplicationBy(free_coeffs[0]) - .IntersectionWith((*domains)[var]); + .IntersectionWith((*domains)[var]); const int64 value = prefer_lower_value[var] ? domain.Min() : domain.Max(); (*domains)[var] = Domain(value); return; @@ -103,7 +100,8 @@ void PostsolveLinear(const ConstraintProto &ct, const int var = free_vars[i]; const int64 coeff = free_coeffs[i]; const Domain domain = rhs.AdditionWith(to_add[i]) - .InverseMultiplicationBy(coeff).IntersectionWith((*domains)[var]); + .InverseMultiplicationBy(coeff) + .IntersectionWith((*domains)[var]); CHECK(!domain.IsEmpty()) << ct.ShortDebugString(); const int64 value = prefer_lower_value[var] ? domain.Min() : domain.Max(); (*domains)[var] = Domain(value); @@ -157,8 +155,8 @@ void PostsolveElement(const ConstraintProto &ct, std::vector *domains) { (*domains)[index_var] = Domain(index_value); // If the selected variable is not fixed, we also need to fix it. - const int selected_ref = ct.element() - .vars(RefIsPositive(index_ref) ? index_value : -index_value); + const int selected_ref = ct.element().vars( + RefIsPositive(index_ref) ? index_value : -index_value); const int selected_var = PositiveRef(selected_ref); if (!(*domains)[selected_var].IsFixed()) { (*domains)[selected_var] = Domain((*domains)[selected_var].Min()); @@ -168,8 +166,8 @@ void PostsolveElement(const ConstraintProto &ct, std::vector *domains) { // Deal with fixed index (and constant vars). if ((*domains)[index_var].IsFixed()) { const int64 index_value = (*domains)[index_var].FixedValue(); - const int selected_ref = ct.element() - .vars(RefIsPositive(index_ref) ? index_value : -index_value); + const int selected_ref = ct.element().vars( + RefIsPositive(index_ref) ? index_value : -index_value); const int selected_var = PositiveRef(selected_ref); const int64 selected_value = (*domains)[selected_var].FixedValue(); (*domains)[target_var] = (*domains)[target_var].IntersectionWith( @@ -215,8 +213,7 @@ void PostsolveResponse(const int64 num_variables_in_original_model, response->status() != CpSolverStatus::OPTIMAL) { return; } - if (response->solution_size() != postsolve_mapping.size()) - return; + if (response->solution_size() != postsolve_mapping.size()) return; // Read the initial variable domains, either from the fixed solution of the // presolved problems or from the mapping model. @@ -265,26 +262,25 @@ void PostsolveResponse(const int64 num_variables_in_original_model, break; } } - if (!enforced) - continue; + if (!enforced) continue; switch (ct.constraint_case()) { - case ConstraintProto::kBoolOr: - PostsolveClause(ct, &domains); - break; - case ConstraintProto::kLinear: - PostsolveLinear(ct, prefer_lower_value, &domains); - break; - case ConstraintProto::kIntMax: - PostsolveIntMax(ct, &domains); - break; - case ConstraintProto::kElement: - PostsolveElement(ct, &domains); - break; - default: - // This should never happen as we control what kind of constraint we - // add to the mapping_proto; - LOG(FATAL) << "Unsupported constraint: " << ct.ShortDebugString(); + case ConstraintProto::kBoolOr: + PostsolveClause(ct, &domains); + break; + case ConstraintProto::kLinear: + PostsolveLinear(ct, prefer_lower_value, &domains); + break; + case ConstraintProto::kIntMax: + PostsolveIntMax(ct, &domains); + break; + case ConstraintProto::kElement: + PostsolveElement(ct, &domains); + break; + default: + // This should never happen as we control what kind of constraint we + // add to the mapping_proto; + LOG(FATAL) << "Unsupported constraint: " << ct.ShortDebugString(); } } @@ -300,5 +296,5 @@ void PostsolveResponse(const int64 num_variables_in_original_model, } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_postsolve.h b/ortools/sat/cp_model_postsolve.h index 70096fd922..7d516a771d 100644 --- a/ortools/sat/cp_model_postsolve.h +++ b/ortools/sat/cp_model_postsolve.h @@ -45,7 +45,7 @@ void PostsolveResponse(const int64 num_variables_in_original_model, const std::vector &postsolve_mapping, CpSolverResponse *response); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_POSTSOLVE_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_POSTSOLVE_H_ diff --git a/ortools/sat/cp_model_presolve.cc b/ortools/sat/cp_model_presolve.cc index 68ff7d1535..d009529428 100644 --- a/ortools/sat/cp_model_presolve.cc +++ b/ortools/sat/cp_model_presolve.cc @@ -67,8 +67,7 @@ void CpModelPresolver::RemoveEmptyConstraints() { context_->working_model->constraints_size(); for (int c = 0; c < old_num_non_empty_constraints; ++c) { const auto type = context_->working_model->constraints(c).constraint_case(); - if (type == ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) - continue; + if (type == ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) continue; if (type == ConstraintProto::ConstraintCase::kInterval) { interval_mapping[c] = new_num_constraints; } @@ -79,19 +78,18 @@ void CpModelPresolver::RemoveEmptyConstraints() { new_num_constraints, old_num_non_empty_constraints - new_num_constraints); for (ConstraintProto &ct_ref : *context_->working_model->mutable_constraints()) { - ApplyToAllIntervalIndices([&interval_mapping](int * ref) { - *ref = interval_mapping[*ref]; - CHECK_NE(-1, *ref); - }, - &ct_ref); + ApplyToAllIntervalIndices( + [&interval_mapping](int *ref) { + *ref = interval_mapping[*ref]; + CHECK_NE(-1, *ref); + }, + &ct_ref); } } bool CpModelPresolver::PresolveEnforcementLiteral(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (!HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (!HasEnforcementLiteral(*ct)) return false; int new_size = 0; const int old_size = ct->enforcement_literal().size(); @@ -135,10 +133,8 @@ bool CpModelPresolver::PresolveEnforcementLiteral(ConstraintProto *ct) { } bool CpModelPresolver::PresolveBoolXor(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; int new_size = 0; bool changed = false; @@ -160,7 +156,7 @@ bool CpModelPresolver::PresolveBoolXor(ConstraintProto *ct) { changed = true; continue; } else if (context_->LiteralIsTrue(literal)) { - true_literal = literal; // Keep if we need to put one back. + true_literal = literal; // Keep if we need to put one back. num_true_literals++; continue; } @@ -185,8 +181,7 @@ bool CpModelPresolver::PresolveBoolXor(ConstraintProto *ct) { } bool CpModelPresolver::PresolveBoolOr(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; // Move the enforcement literal inside the clause if any. Note that we do not // mark this as a change since the literal in the constraint are the same. @@ -216,8 +211,7 @@ bool CpModelPresolver::PresolveBoolOr(ConstraintProto *ct) { // objective var usage by 1). if (context_->VariableIsUniqueAndRemovable(literal)) { context_->UpdateRuleStats("bool_or: singleton"); - if (!context_->SetLiteralToTrue(literal)) - return true; + if (!context_->SetLiteralToTrue(literal)) return true; return RemoveConstraint(ct); } if (context_->tmp_literal_set.contains(NegatedRef(literal))) { @@ -240,8 +234,7 @@ bool CpModelPresolver::PresolveBoolOr(ConstraintProto *ct) { } if (context_->tmp_literals.size() == 1) { context_->UpdateRuleStats("bool_or: only one literal"); - if (!context_->SetLiteralToTrue(context_->tmp_literals[0])) - return true; + if (!context_->SetLiteralToTrue(context_->tmp_literals[0])) return true; return RemoveConstraint(ct); } if (context_->tmp_literals.size() == 2) { @@ -263,8 +256,8 @@ bool CpModelPresolver::PresolveBoolOr(ConstraintProto *ct) { return changed; } -ABSL_MUST_USE_RESULT bool -CpModelPresolver::MarkConstraintAsFalse(ConstraintProto *ct) { +ABSL_MUST_USE_RESULT bool CpModelPresolver::MarkConstraintAsFalse( + ConstraintProto *ct) { if (HasEnforcementLiteral(*ct)) { // Change the constraint to a bool_or. ct->mutable_bool_or()->clear_literals(); @@ -280,14 +273,12 @@ CpModelPresolver::MarkConstraintAsFalse(ConstraintProto *ct) { } bool CpModelPresolver::PresolveBoolAnd(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; if (!HasEnforcementLiteral(*ct)) { context_->UpdateRuleStats("bool_and: non-reified."); for (const int literal : ct->bool_and().literals()) { - if (!context_->SetLiteralToTrue(literal)) - return true; + if (!context_->SetLiteralToTrue(literal)) return true; } return RemoveConstraint(ct); } @@ -305,8 +296,7 @@ bool CpModelPresolver::PresolveBoolAnd(ConstraintProto *ct) { } if (context_->VariableIsUniqueAndRemovable(literal)) { changed = true; - if (!context_->SetLiteralToTrue(literal)) - return true; + if (!context_->SetLiteralToTrue(literal)) return true; continue; } context_->tmp_literals.push_back(literal); @@ -315,8 +305,7 @@ bool CpModelPresolver::PresolveBoolAnd(ConstraintProto *ct) { // Note that this is not the same behavior as a bool_or: // - bool_or means "at least one", so it is false if empty. // - bool_and means "all literals inside true", so it is true if empty. - if (context_->tmp_literals.empty()) - return RemoveConstraint(ct); + if (context_->tmp_literals.empty()) return RemoveConstraint(ct); if (changed) { ct->mutable_bool_and()->mutable_literals()->Clear(); @@ -329,8 +318,7 @@ bool CpModelPresolver::PresolveBoolAnd(ConstraintProto *ct) { } bool CpModelPresolver::PresolveAtMostOne(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; CHECK(!HasEnforcementLiteral(*ct)); // Fix to false any duplicate literals. @@ -339,8 +327,7 @@ bool CpModelPresolver::PresolveAtMostOne(ConstraintProto *ct) { int previous = kint32max; for (const int literal : ct->at_most_one().literals()) { if (literal == previous) { - if (!context_->SetLiteralToFalse(literal)) - return true; + if (!context_->SetLiteralToFalse(literal)) return true; context_->UpdateRuleStats("at_most_one: duplicate literals"); } previous = literal; @@ -353,8 +340,7 @@ bool CpModelPresolver::PresolveAtMostOne(ConstraintProto *ct) { context_->UpdateRuleStats("at_most_one: satisfied"); for (const int other : ct->at_most_one().literals()) { if (other != literal) { - if (!context_->SetLiteralToFalse(other)) - return true; + if (!context_->SetLiteralToFalse(other)) return true; } } return RemoveConstraint(ct); @@ -383,8 +369,7 @@ bool CpModelPresolver::PresolveAtMostOne(ConstraintProto *ct) { } bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; if (ct->int_max().vars().empty()) { context_->UpdateRuleStats("int_max: no variables!"); return MarkConstraintAsFalse(ct); @@ -398,15 +383,11 @@ bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { std::set used_ref; int new_size = 0; for (const int ref : ct->int_max().vars()) { - if (ref == target_ref) - contains_target_ref = true; - if (gtl::ContainsKey(used_ref, ref)) - continue; + if (ref == target_ref) contains_target_ref = true; + if (gtl::ContainsKey(used_ref, ref)) continue; if (gtl::ContainsKey(used_ref, NegatedRef(ref)) || ref == NegatedRef(target_ref)) { - infered_min = std::max(infered_min, int64 { - 0 - }); + infered_min = std::max(infered_min, int64{0}); } used_ref.insert(ref); ct->mutable_int_max()->set_vars(new_size++, ref); @@ -420,8 +401,7 @@ bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { if (contains_target_ref) { context_->UpdateRuleStats("int_max: x = max(x, ...)"); for (const int ref : ct->int_max().vars()) { - if (ref == target_ref) - continue; + if (ref == target_ref) continue; ConstraintProto *new_ct = context_->working_model->add_constraints(); *new_ct->mutable_enforcement_literal() = ct->enforcement_literal(); auto *arg = new_ct->mutable_linear(); @@ -438,10 +418,8 @@ bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { // Compute the infered target_domain. Domain infered_domain; for (const int ref : ct->int_max().vars()) { - infered_domain = - infered_domain.UnionWith(context_->DomainOf(ref).IntersectionWith({ - infered_min, infered_max - })); + infered_domain = infered_domain.UnionWith( + context_->DomainOf(ref).IntersectionWith({infered_min, infered_max})); } // Update the target domain. @@ -528,7 +506,7 @@ bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { // might not be processed again. context_->UpdateRuleStats("int_max: converted to equality"); ConstraintProto *new_ct = context_->working_model->add_constraints(); - *new_ct = *ct; // copy name and potential reification. + *new_ct = *ct; // copy name and potential reification. auto *arg = new_ct->mutable_linear(); arg->add_vars(target_ref); arg->add_coeffs(1); @@ -543,8 +521,7 @@ bool CpModelPresolver::PresolveIntMax(ConstraintProto *ct) { } bool CpModelPresolver::PresolveLinMin(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; // Convert to lin_max and presolve lin_max. const auto copy = ct->lin_min(); SetToNegatedLinearExpression(copy.target(), @@ -557,8 +534,7 @@ bool CpModelPresolver::PresolveLinMin(ConstraintProto *ct) { } bool CpModelPresolver::PresolveLinMax(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; if (ct->lin_max().exprs().empty()) { context_->UpdateRuleStats("lin_max: no exprs"); return MarkConstraintAsFalse(ct); @@ -589,8 +565,8 @@ bool CpModelPresolver::PresolveLinMax(ConstraintProto *ct) { if (new_size < ct->lin_max().exprs_size()) { context_->UpdateRuleStats("lin_max: Removed exprs"); - ct->mutable_lin_max()->mutable_exprs() - ->DeleteSubrange(new_size, ct->lin_max().exprs_size() - new_size); + ct->mutable_lin_max()->mutable_exprs()->DeleteSubrange( + new_size, ct->lin_max().exprs_size() - new_size); return true; } @@ -599,17 +575,14 @@ bool CpModelPresolver::PresolveLinMax(ConstraintProto *ct) { bool CpModelPresolver::PresolveIntAbs(ConstraintProto *ct) { CHECK_EQ(ct->enforcement_literal_size(), 0); - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const int target_ref = ct->int_max().target(); const int var = PositiveRef(ct->int_max().vars(0)); // Propagate from the variable domain to the target variable. const Domain var_domain = context_->DomainOf(var); - const Domain new_target_domain = - var_domain.UnionWith(var_domain.Negation()).IntersectionWith({ - 0, kint64max - }); + const Domain new_target_domain = var_domain.UnionWith(var_domain.Negation()) + .IntersectionWith({0, kint64max}); if (!context_->DomainOf(target_ref).IsIncludedIn(new_target_domain)) { if (!context_->IntersectDomainWith(target_ref, new_target_domain)) { return true; @@ -678,8 +651,7 @@ bool CpModelPresolver::PresolveIntAbs(ConstraintProto *ct) { } bool CpModelPresolver::PresolveIntMin(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const auto copy = ct->int_min(); ct->mutable_int_max()->set_target(NegatedRef(copy.target())); @@ -690,10 +662,8 @@ bool CpModelPresolver::PresolveIntMin(ConstraintProto *ct) { } bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; bool changed = false; @@ -728,8 +698,7 @@ bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { context_->DomainOf(old_target).InverseMultiplicationBy(constant), var_proto); context_->InitializeNewDomains(); - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; ct->mutable_int_prod()->set_target(new_target); if (context_->IsFixed(new_target)) { @@ -776,8 +745,7 @@ bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { int b = ct->int_prod().vars(1); const int product = ct->int_prod().target(); - if (context_->IsFixed(b)) - std::swap(a, b); + if (context_->IsFixed(b)) std::swap(a, b); if (context_->IsFixed(a)) { if (b != product) { ConstraintProto *const lin = context_->working_model->add_constraints(); @@ -802,7 +770,7 @@ bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { context_->UpdateRuleStats("int_prod: remove identity."); return RemoveConstraint(ct); } - } else if (a == b && a == product) { // x = x * x, only true for {0, 1}. + } else if (a == b && a == product) { // x = x * x, only true for {0, 1}. if (!context_->IntersectDomainWith(product, Domain(0, 1))) { return false; } @@ -813,15 +781,11 @@ bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { // For now, we only presolve the case where all variables are Booleans. const int target_ref = ct->int_prod().target(); - if (!RefIsPositive(target_ref)) - return changed; + if (!RefIsPositive(target_ref)) return changed; for (const int var : ct->int_prod().vars()) { - if (!RefIsPositive(var)) - return changed; - if (context_->MinOf(var) < 0) - return changed; - if (context_->MaxOf(var) > 1) - return changed; + if (!RefIsPositive(var)) return changed; + if (context_->MinOf(var) < 0) return changed; + if (context_->MaxOf(var) > 1) return changed; } // This is a bool constraint! @@ -850,8 +814,7 @@ bool CpModelPresolver::PresolveIntProd(ConstraintProto *ct) { } bool CpModelPresolver::PresolveIntDiv(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; // For now, we only presolve the case where the divisor is constant. const int target = ct->int_div().target(); @@ -942,34 +905,34 @@ bool CpModelPresolver::ExploitEquivalenceRelations(int c, ConstraintProto *ct) { break; } } - if (!work_to_do) - return false; + if (!work_to_do) return false; - // Remap equal and negated variables to their representative. - ApplyToAllVariableIndices([&changed, this](int * ref) { - const int rep = context_->GetVariableRepresentative(*ref); - if (rep != *ref) { - changed = true; - *ref = rep; - } - }, - ct); + // Remap equal and negated variables to their representative. + ApplyToAllVariableIndices( + [&changed, this](int *ref) { + const int rep = context_->GetVariableRepresentative(*ref); + if (rep != *ref) { + changed = true; + *ref = rep; + } + }, + ct); - // Remap literal and negated literal to their representative. - ApplyToAllLiteralIndices([&changed, this](int * ref) { - const int rep = this->context_->GetLiteralRepresentative(*ref); - if (rep != *ref) { - changed = true; - *ref = rep; - } - }, - ct); + // Remap literal and negated literal to their representative. + ApplyToAllLiteralIndices( + [&changed, this](int *ref) { + const int rep = this->context_->GetLiteralRepresentative(*ref); + if (rep != *ref) { + changed = true; + *ref = rep; + } + }, + ct); return changed; } void CpModelPresolver::DivideLinearByGcd(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; // Compute the GCD of all coefficients. int64 gcd = 0; @@ -977,8 +940,7 @@ void CpModelPresolver::DivideLinearByGcd(ConstraintProto *ct) { for (int i = 0; i < num_vars; ++i) { const int64 magnitude = std::abs(ct->linear().coeffs(i)); gcd = MathUtil::GCD64(gcd, magnitude); - if (gcd == 1) - break; + if (gcd == 1) break; } if (gcd > 1) { context_->UpdateRuleStats("linear: divide by GCD"); @@ -988,7 +950,7 @@ void CpModelPresolver::DivideLinearByGcd(ConstraintProto *ct) { const Domain rhs = ReadDomainFromProto(ct->linear()); FillDomainInProto(rhs.InverseMultiplicationBy(gcd), ct->mutable_linear()); if (ct->linear().domain_size() == 0) { - return (void) MarkConstraintAsFalse(ct); + return (void)MarkConstraintAsFalse(ct); } } } @@ -1015,8 +977,7 @@ bool CpModelPresolver::CanonicalizeLinear(ConstraintProto *ct) { const int var = PositiveRef(ref); const int64 coeff = RefIsPositive(ref) ? ct->linear().coeffs(i) : -ct->linear().coeffs(i); - if (coeff == 0) - continue; + if (coeff == 0) continue; if (context_->IsFixed(var)) { sum_of_fixed_terms += coeff * context_->MinOf(var); @@ -1048,16 +1009,12 @@ bool CpModelPresolver::CanonicalizeLinear(ConstraintProto *ct) { remapped = true; sum_of_fixed_terms += coeff * r.offset; } - tmp_terms_.push_back({ - r.representative, coeff *r.coeff - }); + tmp_terms_.push_back({r.representative, coeff * r.coeff}); } if (sum_of_fixed_terms != 0) { Domain rhs = ReadDomainFromProto(ct->linear()); - rhs = rhs.AdditionWith({ - -sum_of_fixed_terms, -sum_of_fixed_terms - }); + rhs = rhs.AdditionWith({-sum_of_fixed_terms, -sum_of_fixed_terms}); FillDomainInProto(rhs, ct->mutable_linear()); } @@ -1116,13 +1073,11 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { bool exact; const auto term_domain = context_->DomainOf(var).MultiplicationBy(-coeff, &exact); - if (!exact) - continue; + if (!exact) continue; // We do not do that if the domain of rhs becomes too complex. const Domain new_rhs = rhs.AdditionWith(term_domain); - if (new_rhs.NumIntervals() > 100) - continue; + if (new_rhs.NumIntervals() > 100) continue; // Note that we can't do that if we loose information in the // multiplication above because the new domain might not be as strict @@ -1138,15 +1093,12 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { // If we didn't find any, look for the one appearing in the objective. if (index_to_erase.empty()) { // Note that we only do that if we have a non-reified equality. - if (options_.parameters.presolve_substitution_level() <= 0) - return false; - if (!ct->enforcement_literal().empty()) - return false; + if (options_.parameters.presolve_substitution_level() <= 0) return false; + if (!ct->enforcement_literal().empty()) return false; // If it is possible to do so, note that we can transform constraint into // equalities in PropagateDomainsInLinear(). - if (rhs.Min() != rhs.Max()) - return false; + if (rhs.Min() != rhs.Max()) return false; for (int i = 0; i < num_vars; ++i) { const int var = ct->linear().vars(i); @@ -1160,8 +1112,7 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { // Note that is similar to the substitution code in PresolveLinear() but // it doesn't require the variable to be implied free since we do not // remove the constraints afterwards, just the variable. - if (!context_->VariableWithCostIsUniqueAndRemovable(var)) - continue; + if (!context_->VariableWithCostIsUniqueAndRemovable(var)) continue; DCHECK(context_->ObjectiveMap().contains(var)); // We only support substitution that does not require to multiply the @@ -1172,18 +1123,15 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { const int64 objective_coeff = gtl::FindOrDie(context_->ObjectiveMap(), var); CHECK_NE(coeff, 0); - if (objective_coeff % coeff != 0) - continue; + if (objective_coeff % coeff != 0) continue; // We do not do that if the domain of rhs becomes too complex. bool exact; const auto term_domain = context_->DomainOf(var).MultiplicationBy(-coeff, &exact); - if (!exact) - continue; + if (!exact) continue; const Domain new_rhs = rhs.AdditionWith(term_domain); - if (new_rhs.NumIntervals() > 100) - continue; + if (new_rhs.NumIntervals() > 100) continue; // Special case: If the objective was a single variable, we can transfer // the domain of var to the objective, and just completely remove this @@ -1196,8 +1144,7 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { } // The intersection above might fix var, in which case, we just abort. - if (context_->IsFixed(var)) - continue; + if (context_->IsFixed(var)) continue; // This makes sure the domain of var is propagated back to the // objective. @@ -1230,8 +1177,7 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto *ct) { break; } } - if (index_to_erase.empty()) - return false; + if (index_to_erase.empty()) return false; // TODO(user): we could add the constraint to mapping_model only once // instead of adding a reduced version of it each time a new singleton @@ -1282,17 +1228,18 @@ bool CpModelPresolver::PresolveSmallLinear(ConstraintProto *ct) { // TODO(user): Deal with coeff = -1, here or during canonicalization. context_->UpdateRuleStats("linear: remove abs from abs(x) in domain"); const Domain implied_abs_target_domain = - ReadDomainFromProto(ct->linear()).IntersectionWith({ - 0, kint64max - }).IntersectionWith(context_->DomainOf(ct->linear().vars(0))); + ReadDomainFromProto(ct->linear()) + .IntersectionWith({0, kint64max}) + .IntersectionWith(context_->DomainOf(ct->linear().vars(0))); if (implied_abs_target_domain.IsEmpty()) { return MarkConstraintAsFalse(ct); } - const Domain new_abs_var_domain = implied_abs_target_domain - .UnionWith(implied_abs_target_domain.Negation()) - .IntersectionWith(context_->DomainOf(abs_arg)); + const Domain new_abs_var_domain = + implied_abs_target_domain + .UnionWith(implied_abs_target_domain.Negation()) + .IntersectionWith(context_->DomainOf(abs_arg)); if (new_abs_var_domain.IsEmpty()) { return MarkConstraintAsFalse(ct); @@ -1333,10 +1280,9 @@ bool CpModelPresolver::PresolveSmallLinear(ConstraintProto *ct) { context_->modified_domains.Set(var); } } else { - const Domain complement = context_->DomainOf(ref) - .IntersectionWith(ReadDomainFromProto(linear).Complement()); - if (complement.Size() != 1) - return false; + const Domain complement = context_->DomainOf(ref).IntersectionWith( + ReadDomainFromProto(linear).Complement()); + if (complement.Size() != 1) return false; const int64 value = RefIsPositive(ref) ? complement.Min() * coeff : -complement.Min() * coeff; if (context_->StoreLiteralImpliesVarNEqValue(literal, var, value)) { @@ -1354,9 +1300,9 @@ bool CpModelPresolver::PresolveSmallLinear(ConstraintProto *ct) { // Size one constraint? if (ct->linear().vars().size() == 1) { - const int64 coeff = - RefIsPositive(ct->linear().vars(0)) ? ct->linear().coeffs(0) - : -ct->linear().coeffs(0); + const int64 coeff = RefIsPositive(ct->linear().vars(0)) + ? ct->linear().coeffs(0) + : -ct->linear().coeffs(0); context_->UpdateRuleStats("linear: size one"); const int var = PositiveRef(ct->linear().vars(0)); const Domain rhs = ReadDomainFromProto(ct->linear()); @@ -1391,8 +1337,7 @@ bool CpModelPresolver::PresolveSmallLinear(ConstraintProto *ct) { } else if (coeff2 == -1) { added = context_->StoreAffineRelation(v2, v1, coeff1, -rhs_max); } - if (added) - return RemoveConstraint(ct); + if (added) return RemoveConstraint(ct); } } @@ -1418,10 +1363,8 @@ bool IsGeConstraint(const Domain &domain, const Domain &all_values) { // not be as generic as possible here. bool RhsCanBeFixedToMin(int64 coeff, const Domain &var_domain, const Domain &terms, const Domain &rhs) { - if (var_domain.NumIntervals() != 1) - return false; - if (std::abs(coeff) != 1) - return false; + if (var_domain.NumIntervals() != 1) return false; + if (std::abs(coeff) != 1) return false; // If for all values in terms, there is one value below rhs.Min(), then // because we add only one integer interval, if there is a feasible value, it @@ -1440,10 +1383,8 @@ bool RhsCanBeFixedToMin(int64 coeff, const Domain &var_domain, bool RhsCanBeFixedToMax(int64 coeff, const Domain &var_domain, const Domain &terms, const Domain &rhs) { - if (var_domain.NumIntervals() != 1) - return false; - if (std::abs(coeff) != 1) - return false; + if (var_domain.NumIntervals() != 1) return false; + if (std::abs(coeff) != 1) return false; if (coeff == 1 && terms.Min() + var_domain.Max() >= rhs.Max()) { return true; @@ -1459,15 +1400,13 @@ void TakeIntersectionWith(const absl::flat_hash_set ¤t, absl::flat_hash_set *to_clear) { std::vector new_set; for (const int c : *to_clear) { - if (current.contains(c)) - new_set.push_back(c); + if (current.contains(c)) new_set.push_back(c); } to_clear->clear(); - for (const int c : new_set) - to_clear->insert(c); + for (const int c : new_set) to_clear->insert(c); } -} // namespace +} // namespace bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { if (ct->constraint_case() != ConstraintProto::ConstraintCase::kLinear || @@ -1517,8 +1456,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { bool is_ge_constraint = IsGeConstraint(rhs, implied_rhs); // Propagate the variable bounds. - if (ct->enforcement_literal().size() > 1) - return false; + if (ct->enforcement_literal().size() > 1) return false; bool new_bounds = false; bool recanonicalize = false; @@ -1534,7 +1472,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { right_domain.AdditionWith(term_domains[i + 1]).RelaxIfTooComplex(); implied_term_domain = left_domains[i].AdditionWith(right_domain); new_domain = implied_term_domain.AdditionWith(negated_rhs) - .InverseMultiplicationBy(-var_coeff); + .InverseMultiplicationBy(-var_coeff); if (ct->enforcement_literal().empty()) { // Push the new domain. @@ -1545,8 +1483,8 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { // We cannot push the new domain, but we can add some deduction. CHECK(RefIsPositive(var)); if (!context_->DomainOfVarIsIncludedIn(var, new_domain)) { - context_->deductions - .AddDeduction(ct->enforcement_literal(0), var, new_domain); + context_->deductions.AddDeduction(ct->enforcement_literal(0), var, + new_domain); } } @@ -1618,8 +1556,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { } // The other transformations below require a non-reified constraint. - if (!ct->enforcement_literal().empty()) - continue; + if (!ct->enforcement_literal().empty()) continue; // Given a variable that only appear in one constraint and in the // objective, for any feasible solution, it will be always better to move @@ -1677,30 +1614,24 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { // when we process other constraints. Note that if we relax the fact that // we substitute only equalities, we can deal with inequality of size 2 // here. - if (ct->linear().vars().size() <= 2) - continue; + if (ct->linear().vars().size() <= 2) continue; // TODO(user): We actually do not need a strict equality when // keep_all_feasible_solutions is false, but that simplifies things as the // SubstituteVariable() function cannot fail this way. - if (rhs.Min() != rhs.Max()) - continue; + if (rhs.Min() != rhs.Max()) continue; // Only consider "implied free" variables. Note that the coefficient of // magnitude 1 is important otherwise we can't easily remove the // constraint since the fact that the sum of the other terms must be a // multiple of coeff will not be enforced anymore. - if (context_->DomainOf(var) != new_domain) - continue; - if (std::abs(var_coeff) != 1) - continue; - if (options_.parameters.presolve_substitution_level() <= 0) - continue; + if (context_->DomainOf(var) != new_domain) continue; + if (std::abs(var_coeff) != 1) continue; + if (options_.parameters.presolve_substitution_level() <= 0) continue; // NOTE: The mapping doesn't allow us to remove a variable if // 'keep_all_feasible_solutions' is true. - if (context_->keep_all_feasible_solutions) - continue; + if (context_->keep_all_feasible_solutions) continue; bool is_in_objective = false; if (context_->VarToConstraints(var).contains(-1)) { @@ -1710,8 +1641,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { // Only consider low degree columns. int col_size = context_->VarToConstraints(var).size(); - if (is_in_objective) - col_size--; + if (is_in_objective) col_size--; const int row_size = ct->linear().vars_size(); // This is actually an upper bound on the number of entries added since @@ -1728,14 +1658,12 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { std::vector others; bool abort = false; for (const int c : context_->VarToConstraints(var)) { - if (c == kObjectiveConstraint) - continue; + if (c == kObjectiveConstraint) continue; if (c == kAffineRelationConstraint) { abort = true; break; } - if (context_->working_model->mutable_constraints(c) == ct) - continue; + if (context_->working_model->mutable_constraints(c) == ct) continue; if (context_->working_model->constraints(c).constraint_case() != ConstraintProto::ConstraintCase::kLinear) { abort = true; @@ -1750,8 +1678,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { } others.push_back(c); } - if (abort) - continue; + if (abort) continue; // Do the actual substitution. for (const int c : others) { @@ -1784,8 +1711,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto *ct) { if (new_bounds) { context_->UpdateRuleStats("linear: reduced variable domains"); } - if (recanonicalize) - return CanonicalizeLinear(ct); + if (recanonicalize) return CanonicalizeLinear(ct); return false; } @@ -1809,8 +1735,7 @@ void CpModelPresolver::ExtractEnforcementLiteralFromLinearConstraint( // No need to process size one constraints, they will be presolved separately. // We also do not want to split them in two. - if (num_vars <= 1) - return; + if (num_vars <= 1) return; int64 min_sum = 0; int64 max_sum = 0; @@ -1853,8 +1778,7 @@ void CpModelPresolver::ExtractEnforcementLiteralFromLinearConstraint( // constraints are just redundant... const bool lower_bounded = min_sum < rhs_domain.Min(); const bool upper_bounded = max_sum > rhs_domain.Max(); - if (!lower_bounded && !upper_bounded) - return; + if (!lower_bounded && !upper_bounded) return; if (lower_bounded && upper_bounded) { context_->UpdateRuleStats("linear: split boxed constraint"); ConstraintProto *new_ct1 = context_->working_model->add_constraints(); @@ -1874,7 +1798,7 @@ void CpModelPresolver::ExtractEnforcementLiteralFromLinearConstraint( new_ct2->mutable_linear()); context_->UpdateNewConstraintsVariableUsage(); - return (void) RemoveConstraint(ct); + return (void)RemoveConstraint(ct); } // To avoid a quadratic loop, we will rewrite the linear expression at the @@ -1942,10 +1866,8 @@ void CpModelPresolver::ExtractEnforcementLiteralFromLinearConstraint( } void CpModelPresolver::ExtractAtMostOneFromLinear(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return; - if (HasEnforcementLiteral(*ct)) - return; + if (context_->ModelIsUnsat()) return; + if (HasEnforcementLiteral(*ct)) return; const Domain rhs = ReadDomainFromProto(ct->linear()); const LinearConstraintProto &arg = ct->linear(); @@ -1960,17 +1882,13 @@ void CpModelPresolver::ExtractAtMostOneFromLinear(ConstraintProto *ct) { min_sum += std::min(term_a, term_b); max_sum += std::max(term_a, term_b); } - for (const int type : { - 0, 1 - }) { + for (const int type : {0, 1}) { std::vector at_most_one; for (int i = 0; i < num_vars; ++i) { const int ref = arg.vars(i); const int64 coeff = arg.coeffs(i); - if (context_->MinOf(ref) != 0) - continue; - if (context_->MaxOf(ref) != 1) - continue; + if (context_->MinOf(ref) != 0) continue; + if (context_->MaxOf(ref) != 1) continue; if (type == 0) { // TODO(user): we could add one more Boolean with a lower coeff as long @@ -2020,10 +1938,8 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { const int64 coeff = arg.coeffs(i); CHECK(RefIsPositive(var)); CHECK_NE(coeff, 0); - if (context_->MinOf(var) != 0) - return false; - if (context_->MaxOf(var) != 1) - return false; + if (context_->MinOf(var) != 0) return false; + if (context_->MaxOf(var) != 1) return false; if (coeff > 0) { max_sum += coeff; @@ -2104,8 +2020,9 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { copy.coeffs(i) > 0 ? NegatedRef(copy.vars(i)) : copy.vars(i)); } return PresolveBoolOr(ct); - } else if (!HasEnforcementLiteral(*ct) && min_sum + max_coeff <= - rhs_domain.Max() && min_sum + 2 * min_coeff > rhs_domain.Max() && + } else if (!HasEnforcementLiteral(*ct) && + min_sum + max_coeff <= rhs_domain.Max() && + min_sum + 2 * min_coeff > rhs_domain.Max() && rhs_domain.back().start <= min_sum) { // At most one Boolean is true. context_->UpdateRuleStats("linear: positive at most one"); @@ -2116,8 +2033,9 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { copy.coeffs(i) > 0 ? copy.vars(i) : NegatedRef(copy.vars(i))); } return true; - } else if (!HasEnforcementLiteral(*ct) && max_sum - max_coeff >= - rhs_domain.Min() && max_sum - 2 * min_coeff < rhs_domain.Min() && + } else if (!HasEnforcementLiteral(*ct) && + max_sum - max_coeff >= rhs_domain.Min() && + max_sum - 2 * min_coeff < rhs_domain.Min() && rhs_domain.front().end >= max_sum) { // At most one Boolean is false. context_->UpdateRuleStats("linear: negative at most one"); @@ -2129,8 +2047,9 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { } return true; } else if (!HasEnforcementLiteral(*ct) && rhs_domain.NumIntervals() == 1 && - min_sum < rhs_domain.Min() && min_sum + min_coeff >= - rhs_domain.Min() && min_sum + 2 * min_coeff > rhs_domain.Max() && + min_sum < rhs_domain.Min() && + min_sum + min_coeff >= rhs_domain.Min() && + min_sum + 2 * min_coeff > rhs_domain.Max() && min_sum + max_coeff <= rhs_domain.Max()) { context_->UpdateRuleStats("linear: positive equal one"); ConstraintProto *at_least_one = context_->working_model->add_constraints(); @@ -2146,8 +2065,9 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { context_->UpdateNewConstraintsVariableUsage(); return RemoveConstraint(ct); } else if (!HasEnforcementLiteral(*ct) && rhs_domain.NumIntervals() == 1 && - max_sum > rhs_domain.Max() && max_sum - min_coeff <= - rhs_domain.Max() && max_sum - 2 * min_coeff < rhs_domain.Min() && + max_sum > rhs_domain.Max() && + max_sum - min_coeff <= rhs_domain.Max() && + max_sum - 2 * min_coeff < rhs_domain.Min() && max_sum - max_coeff >= rhs_domain.Min()) { context_->UpdateRuleStats("linear: negative equal one"); ConstraintProto *at_least_one = context_->working_model->add_constraints(); @@ -2168,8 +2088,7 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { // // TODO(user): This is bad from a LP relaxation perspective. Do not do that // now? On another hand it is good for the SAT presolving. - if (num_vars > 3) - return false; + if (num_vars > 3) return false; context_->UpdateRuleStats("linear: small Boolean expression"); // Enumerate all possible value of the Booleans and add a clause if constraint @@ -2178,11 +2097,9 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { for (int mask = 0; mask < max_mask; ++mask) { int64 value = 0; for (int i = 0; i < num_vars; ++i) { - if ((mask >> i) & 1) - value += arg.coeffs(i); + if ((mask >> i) & 1) value += arg.coeffs(i); } - if (rhs_domain.Contains(value)) - continue; + if (rhs_domain.Contains(value)) continue; // Add a new clause to exclude this bad assignment. ConstraintProto *new_ct = context_->working_model->add_constraints(); @@ -2201,8 +2118,7 @@ bool CpModelPresolver::PresolveLinearOnBooleans(ConstraintProto *ct) { } bool CpModelPresolver::PresolveInterval(int c, ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const int start = ct->interval().start(); const int end = ct->interval().end(); @@ -2258,7 +2174,7 @@ bool CpModelPresolver::PresolveInterval(int c, ConstraintProto *ct) { // // TODO(user): This will currently add another linear relation to the proto // in addition to the interval at the end of the presolve though. - if (/* DISABLES CODE */(false) && ct->enforcement_literal().empty() && + if (/* DISABLES CODE */ (false) && ct->enforcement_literal().empty() && context_->IsFixed(size)) { context_->StoreAffineRelation(ct->interval().end(), ct->interval().start(), 1, context_->MinOf(size)); @@ -2269,15 +2185,13 @@ bool CpModelPresolver::PresolveInterval(int c, ConstraintProto *ct) { } bool CpModelPresolver::PresolveElement(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const int index_ref = ct->element().index(); const int target_ref = ct->element().target(); // TODO(user): think about this once we do have such constraint. - if (HasEnforcementLiteral(*ct)) - return false; + if (HasEnforcementLiteral(*ct)) return false; int num_vars = 0; bool all_constants = true; @@ -2482,10 +2396,8 @@ bool CpModelPresolver::PresolveElement(ConstraintProto *ct) { } bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; if (ct->table().vars().empty()) { context_->UpdateRuleStats("table: empty constraint"); return RemoveConstraint(ct); @@ -2543,8 +2455,7 @@ bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { break; } } - if (delete_row) - continue; + if (delete_row) continue; new_tuples.push_back(tuple); for (int j = 0; j < num_vars; ++j) { const int64 v = tuple[j]; @@ -2578,8 +2489,7 @@ bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { } // Nothing more to do for negated tables. - if (ct->table().negated()) - return modified_variables; + if (ct->table().negated()) return modified_variables; // Filter the variable domains. bool changed = false; @@ -2604,8 +2514,7 @@ bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { // Check that the table is not complete or just here to exclude a few tuples. double prod = 1.0; - for (int j = 0; j < num_vars; ++j) - prod *= new_domains[j].size(); + for (int j = 0; j < num_vars; ++j) prod *= new_domains[j].size(); if (prod == new_tuples.size()) { context_->UpdateRuleStats("table: all tuples!"); return RemoveConstraint(ct); @@ -2640,8 +2549,7 @@ bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { ct->mutable_table()->set_negated(!ct->table().negated()); ct->mutable_table()->clear_values(); for (const std::vector &t : diff) { - for (const int64 v : t) - ct->mutable_table()->add_values(v); + for (const int64 v : t) ct->mutable_table()->add_values(v); } context_->UpdateRuleStats("table: negated"); } @@ -2649,10 +2557,8 @@ bool CpModelPresolver::PresolveTable(ConstraintProto *ct) { } bool CpModelPresolver::PresolveAllDiff(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; AllDifferentConstraintProto &all_diff = *ct->mutable_all_diff(); @@ -2679,8 +2585,7 @@ bool CpModelPresolver::PresolveAllDiff(ConstraintProto *ct) { const int64 value = context_->MinOf(all_diff.vars(i)); bool propagated = false; for (int j = 0; j < size; ++j) { - if (i == j) - continue; + if (i == j) continue; if (context_->DomainContains(all_diff.vars(j), value)) { if (!context_->IntersectDomainWith(all_diff.vars(j), Domain(value).Complement())) { @@ -2711,8 +2616,7 @@ bool CpModelPresolver::PresolveAllDiff(ConstraintProto *ct) { context_->UpdateRuleStats("all_diff: removed fixed variables"); something_was_propagated = true; constraint_has_changed = true; - if (new_variables.size() <= 1) - continue; + if (new_variables.size() <= 1) continue; } // Propagate mandatory value if the all diff is actually a permutation. @@ -2747,8 +2651,7 @@ bool CpModelPresolver::PresolveAllDiff(ConstraintProto *ct) { something_was_propagated = true; } } - if (!something_was_propagated) - break; + if (!something_was_propagated) break; } return constraint_has_changed; @@ -2783,8 +2686,8 @@ void AddImplication(int lhs, int rhs, CpModelProto *proto, proto->mutable_constraints(ct_index)->mutable_bool_and()->add_literals(rhs); } else if (ref_to_bool_and->contains(NegatedRef(rhs))) { const int ct_index = (*ref_to_bool_and)[NegatedRef(rhs)]; - proto->mutable_constraints(ct_index)->mutable_bool_and() - ->add_literals(NegatedRef(lhs)); + proto->mutable_constraints(ct_index)->mutable_bool_and()->add_literals( + NegatedRef(lhs)); } else { (*ref_to_bool_and)[lhs] = proto->constraints_size(); ConstraintProto *ct = proto->add_constraints(); @@ -2805,17 +2708,16 @@ void ExtractClauses(bool use_bool_and, const ClauseContainer &container, absl::flat_hash_map ref_to_bool_and; for (int i = 0; i < container.NumClauses(); ++i) { const std::vector &clause = container.Clause(i); - if (clause.empty()) - continue; + if (clause.empty()) continue; // bool_and. if (use_bool_and && clause.size() == 2) { - const int a = - clause[0].IsPositive() ? clause[0].Variable().value() - : NegatedRef(clause[0].Variable().value()); - const int b = - clause[1].IsPositive() ? clause[1].Variable().value() - : NegatedRef(clause[1].Variable().value()); + const int a = clause[0].IsPositive() + ? clause[0].Variable().value() + : NegatedRef(clause[0].Variable().value()); + const int b = clause[1].IsPositive() + ? clause[1].Variable().value() + : NegatedRef(clause[1].Variable().value()); AddImplication(NegatedRef(a), b, proto, &ref_to_bool_and); continue; } @@ -2832,11 +2734,10 @@ void ExtractClauses(bool use_bool_and, const ClauseContainer &container, } } -} // namespace +} // namespace bool CpModelPresolver::PresolveNoOverlap(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const NoOverlapConstraintProto &proto = ct->no_overlap(); @@ -2853,15 +2754,17 @@ bool CpModelPresolver::PresolveNoOverlap(ConstraintProto *ct) { } ct->mutable_no_overlap()->mutable_intervals()->Truncate(new_size); - // Sort by start min. - std::sort(ct->mutable_no_overlap()->mutable_intervals()->begin(), - ct->mutable_no_overlap()->mutable_intervals()->end(), - [this](int i1, int i2) { - return context_->MinOf(context_->working_model->constraints(i1) - .interval().start()) < - context_->MinOf(context_->working_model->constraints(i2) - .interval().start()); - }); + // Sort by start min. + std::sort( + ct->mutable_no_overlap()->mutable_intervals()->begin(), + ct->mutable_no_overlap()->mutable_intervals()->end(), + [this](int i1, int i2) { + return context_->MinOf(context_->working_model->constraints(i1) + .interval() + .start()) < + context_->MinOf( + context_->working_model->constraints(i2).interval().start()); + }); // Remove intervals that cannot overlap any others. // @@ -2877,8 +2780,11 @@ bool CpModelPresolver::PresolveNoOverlap(ConstraintProto *ct) { end_max_so_far = std::max(end_max_so_far, context_->MaxOf(interval.end())); if (context_->MinOf(interval.start()) >= end_max_of_previous_intervals && (i + 1 == proto.intervals_size() || - end_max_so_far <= context_->MinOf(context_->working_model->constraints( - proto.intervals(i + 1)).interval().start()))) { + end_max_so_far <= + context_->MinOf( + context_->working_model->constraints(proto.intervals(i + 1)) + .interval() + .start()))) { context_->UpdateRuleStats("no_overlap: removed redundant intervals"); continue; } @@ -2898,8 +2804,7 @@ bool CpModelPresolver::PresolveNoOverlap(ConstraintProto *ct) { } bool CpModelPresolver::PresolveCumulative(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; const CumulativeConstraintProto &proto = ct->cumulative(); @@ -2940,10 +2845,8 @@ bool CpModelPresolver::PresolveCumulative(ConstraintProto *ct) { return RemoveConstraint(ct); } - if (HasEnforcementLiteral(*ct)) - return changed; - if (!context_->IsFixed(proto.capacity())) - return changed; + if (HasEnforcementLiteral(*ct)) return changed; + if (!context_->IsFixed(proto.capacity())) return changed; const int64 capacity = context_->MinOf(proto.capacity()); const int size = proto.intervals_size(); @@ -2957,8 +2860,7 @@ bool CpModelPresolver::PresolveCumulative(ConstraintProto *ct) { // TODO(user): adapt in the presence of optional intervals. const ConstraintProto &ct = context_->working_model->constraints(proto.intervals(i)); - if (!ct.enforcement_literal().empty()) - has_optional_interval = true; + if (!ct.enforcement_literal().empty()) has_optional_interval = true; const IntervalConstraintProto &interval = ct.interval(); start_indices[i] = interval.start(); const int duration_ref = interval.size(); @@ -3030,10 +2932,8 @@ bool CpModelPresolver::PresolveCumulative(ConstraintProto *ct) { } bool CpModelPresolver::PresolveRoutes(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; RoutesConstraintProto &proto = *ct->mutable_routes(); int new_size = 0; @@ -3061,10 +2961,8 @@ bool CpModelPresolver::PresolveRoutes(ConstraintProto *ct) { } bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; CircuitConstraintProto &proto = *ct->mutable_circuit(); // Convert the flat structure to a graph, note that we includes all the arcs @@ -3095,15 +2993,12 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { int num_fixed_at_true = 0; while (loop_again) { loop_again = false; - for (const auto *node_to_refs : { - &incoming_arcs, &outgoing_arcs - }) { + for (const auto *node_to_refs : {&incoming_arcs, &outgoing_arcs}) { for (const std::vector &refs : *node_to_refs) { if (refs.size() == 1) { if (!context_->LiteralIsTrue(refs.front())) { ++num_fixed_at_true; - if (!context_->SetLiteralToTrue(refs.front())) - return true; + if (!context_->SetLiteralToTrue(refs.front())) return true; } continue; } @@ -3128,8 +3023,7 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { context_->UpdateRuleStats("circuit: set literal to false."); loop_again = true; } - if (!context_->SetLiteralToFalse(ref)) - return true; + if (!context_->SetLiteralToFalse(ref)) return true; } } } @@ -3149,8 +3043,7 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { std::vector new_out_degree(num_nodes, 0); for (int i = 0; i < num_arcs; ++i) { const int ref = proto.literals(i); - if (context_->LiteralIsFalse(ref)) - continue; + if (context_->LiteralIsFalse(ref)) continue; if (context_->LiteralIsTrue(ref)) { if (next[proto.tails(i)] != -1) { return context_->NotifyThatModelIsUnsat(); @@ -3177,8 +3070,7 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { // infeasible! for (int i = 0; i < num_nodes; ++i) { // Skip initially ignored node. - if (incoming_arcs[i].empty() && outgoing_arcs[i].empty()) - continue; + if (incoming_arcs[i].empty() && outgoing_arcs[i].empty()) continue; if (new_in_degree[i] == 0 || new_out_degree[i] == 0) { return context_->NotifyThatModelIsUnsat(); @@ -3197,14 +3089,11 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { // We have a sub-circuit! mark all other arc false except self-loop not in // circuit. for (int i = 0; i < num_arcs; ++i) { - if (visited[proto.tails(i)]) - continue; + if (visited[proto.tails(i)]) continue; if (proto.tails(i) == proto.heads(i)) { - if (!context_->SetLiteralToTrue(proto.literals(i))) - return true; + if (!context_->SetLiteralToTrue(proto.literals(i))) return true; } else { - if (!context_->SetLiteralToFalse(proto.literals(i))) - return true; + if (!context_->SetLiteralToFalse(proto.literals(i))) return true; } } context_->UpdateRuleStats("circuit: fully specified."); @@ -3221,13 +3110,11 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { // Look for in/out-degree of two, this will imply that one of the indicator // Boolean is equal to the negation of the other. for (int i = 0; i < num_nodes; ++i) { - for (const std::vector *arc_literals : { - &incoming_arcs[i], &outgoing_arcs[i] - }) { + for (const std::vector *arc_literals : + {&incoming_arcs[i], &outgoing_arcs[i]}) { std::vector literals; for (const int ref : *arc_literals) { - if (context_->LiteralIsFalse(ref)) - continue; + if (context_->LiteralIsFalse(ref)) continue; if (context_->LiteralIsTrue(ref)) { literals.clear(); break; @@ -3254,10 +3141,8 @@ bool CpModelPresolver::PresolveCircuit(ConstraintProto *ct) { } bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { - if (context_->ModelIsUnsat()) - return false; - if (HasEnforcementLiteral(*ct)) - return false; + if (context_->ModelIsUnsat()) return false; + if (HasEnforcementLiteral(*ct)) return false; AutomatonConstraintProto &proto = *ct->mutable_automaton(); if (proto.vars_size() == 0 || proto.transition_label_size() == 0) { return false; @@ -3280,7 +3165,7 @@ bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { } } - if (all_affine) { // Unscale labels. + if (all_affine) { // Unscale labels. for (int v = 0; v < proto.vars_size(); ++v) { proto.set_vars(v, affine_relations[v].representative); } @@ -3334,13 +3219,13 @@ bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { } const int n = proto.vars_size(); - const std::vector vars = { proto.vars().begin(), proto.vars().end() }; + const std::vector vars = {proto.vars().begin(), proto.vars().end()}; // Compute the set of reachable state at each time point. std::vector > reachable_states(n + 1); reachable_states[0].insert(proto.starting_state()); - reachable_states[n] = { proto.final_states().begin(), - proto.final_states().end() }; + reachable_states[n] = {proto.final_states().begin(), + proto.final_states().end()}; // Forward. // @@ -3351,10 +3236,8 @@ bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { const int64 tail = proto.transition_tail(t); const int64 label = proto.transition_label(t); const int64 head = proto.transition_head(t); - if (!gtl::ContainsKey(reachable_states[time], tail)) - continue; - if (!context_->DomainContains(vars[time], label)) - continue; + if (!gtl::ContainsKey(reachable_states[time], tail)) continue; + if (!context_->DomainContains(vars[time], label)) continue; reachable_states[time + 1].insert(head); } } @@ -3369,12 +3252,9 @@ bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { const int64 label = proto.transition_label(t); const int64 head = proto.transition_head(t); - if (!gtl::ContainsKey(reachable_states[time], tail)) - continue; - if (!context_->DomainContains(vars[time], label)) - continue; - if (!gtl::ContainsKey(reachable_states[time + 1], head)) - continue; + if (!gtl::ContainsKey(reachable_states[time], tail)) continue; + if (!context_->DomainContains(vars[time], label)) continue; + if (!gtl::ContainsKey(reachable_states[time + 1], head)) continue; new_set.insert(tail); reached_values[time].insert(label); } @@ -3383,10 +3263,11 @@ bool CpModelPresolver::PresolveAutomaton(ConstraintProto *ct) { bool removed_values = false; for (int time = 0; time < n; ++time) { - if (!context_->IntersectDomainWith(vars[time], Domain::FromValues({ - reached_values[time].begin(), reached_values[time].end() - }), - &removed_values)) { + if (!context_->IntersectDomainWith( + vars[time], + Domain::FromValues( + {reached_values[time].begin(), reached_values[time].end()}), + &removed_values)) { return false; } } @@ -3405,8 +3286,7 @@ void CpModelPresolver::ExtractBoolAnd() { std::vector to_remove; for (int c = 0; c < num_constraints; ++c) { const ConstraintProto &ct = context_->working_model->constraints(c); - if (HasEnforcementLiteral(ct)) - continue; + if (HasEnforcementLiteral(ct)) continue; if (ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr && ct.bool_or().literals().size() == 2) { @@ -3436,8 +3316,7 @@ void CpModelPresolver::ExtractBoolAnd() { } void CpModelPresolver::Probe() { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; // Update the domain in the current CpModelProto. for (int i = 0; i < context_->working_model->variables_size(); ++i) { @@ -3469,16 +3348,15 @@ void CpModelPresolver::Probe() { mapping->ExtractEncoding(model_proto, &model); auto *sat_solver = model.GetOrCreate(); for (const ConstraintProto &ct : model_proto.constraints()) { - if (mapping->ConstraintIsAlreadyLoaded(&ct)) - continue; + if (mapping->ConstraintIsAlreadyLoaded(&ct)) continue; CHECK(LoadConstraint(ct, &model)); if (sat_solver->IsModelUnsat()) { - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } } encoder->AddAllImplicationsBetweenAssociatedLiterals(); if (!sat_solver->Propagate()) { - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } // Probe. @@ -3486,13 +3364,13 @@ void CpModelPresolver::Probe() { // TODO(user): Compute the transitive reduction instead of just the // equivalences, and use the newly learned binary clauses? auto *implication_graph = model.GetOrCreate(); - ProbeBooleanVariables(/*deterministic_time_limit=*/ 1.0, &model); + ProbeBooleanVariables(/*deterministic_time_limit=*/1.0, &model); if (options_.time_limit != nullptr) { options_.time_limit->AdvanceDeterministicTime( model.GetOrCreate()->GetElapsedDeterministicTime()); } if (sat_solver->IsModelUnsat() || !implication_graph->DetectEquivalences()) { - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } // Update the presolve context with fixed Boolean variables. @@ -3502,8 +3380,7 @@ void CpModelPresolver::Probe() { const int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable()); if (var >= 0) { const int ref = l.IsPositive() ? var : NegatedRef(var); - if (!context_->SetLiteralToTrue(ref)) - return; + if (!context_->SetLiteralToTrue(ref)) return; } } @@ -3540,8 +3417,7 @@ void CpModelPresolver::Probe() { void CpModelPresolver::PresolvePureSatPart() { // TODO(user,user): Reenable some SAT presolve with // keep_all_feasible_solutions set to true. - if (context_->ModelIsUnsat() || context_->keep_all_feasible_solutions) - return; + if (context_->ModelIsUnsat() || context_->keep_all_feasible_solutions) return; const int num_variables = context_->working_model->variables_size(); SatPostsolver sat_postsolver(num_variables); @@ -3570,11 +3446,9 @@ void CpModelPresolver::PresolvePureSatPart() { absl::flat_hash_set used_variables; auto convert = [&used_variables](int ref) { used_variables.insert(PositiveRef(ref)); - if (RefIsPositive(ref)) - return Literal(BooleanVariable(ref), true); + if (RefIsPositive(ref)) return Literal(BooleanVariable(ref), true); return Literal(BooleanVariable(NegatedRef(ref)), false); - } - ; + }; // We need all Boolean constraints to be presolved before loading them below. // Otherwise duplicate literals might result in a wrong outcome. @@ -3588,8 +3462,7 @@ void CpModelPresolver::PresolvePureSatPart() { if (PresolveOneConstraint(c)) { context_->UpdateConstraintVariableUsage(c); } - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; } } @@ -3631,7 +3504,7 @@ void CpModelPresolver::PresolvePureSatPart() { for (const int ref : ct.enforcement_literal()) { clause.push_back(convert(ref).Negated()); } - clause.push_back(Literal(kNoLiteralIndex)); // will be replaced below. + clause.push_back(Literal(kNoLiteralIndex)); // will be replaced below. for (const int ref : ct.bool_and().literals()) { clause.back() = convert(ref); sat_presolver.AddClause(clause); @@ -3644,8 +3517,7 @@ void CpModelPresolver::PresolvePureSatPart() { } // Abort early if there was no Boolean constraints. - if (num_removed_constraints == 0) - return; + if (num_removed_constraints == 0) return; // Mark the variables appearing elsewhere or in the objective as non-removable // by the sat presolver. @@ -3666,13 +3538,9 @@ void CpModelPresolver::PresolvePureSatPart() { // the SAT presolver. if (used_variables.contains(i) && context_->IsFixed(i)) { if (context_->LiteralIsTrue(i)) { - sat_presolver.AddClause({ - convert(i) - }); + sat_presolver.AddClause({convert(i)}); } else { - sat_presolver.AddClause({ - convert(NegatedRef(i)) - }); + sat_presolver.AddClause({convert(NegatedRef(i))}); } } } @@ -3685,10 +3553,9 @@ void CpModelPresolver::PresolvePureSatPart() { const int old_num_clause = sat_postsolver.NumClauses(); if (!sat_presolver.Presolve(can_be_removed, options_.log_info)) { VLOG(1) << "UNSAT during SAT presolve."; - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } - if (old_num_clause == sat_postsolver.NumClauses()) - break; + if (old_num_clause == sat_postsolver.NumClauses()) break; } // Add any new variables to our internal structure. @@ -3706,8 +3573,7 @@ void CpModelPresolver::PresolvePureSatPart() { } // Add the presolver clauses back into the model. - ExtractClauses(/*use_bool_and=*/ true, sat_presolver, - context_->working_model); + ExtractClauses(/*use_bool_and=*/true, sat_presolver, context_->working_model); // Update the constraints <-> variables graph. context_->UpdateNewConstraintsVariableUsage(); @@ -3715,7 +3581,7 @@ void CpModelPresolver::PresolvePureSatPart() { // Add the sat_postsolver clauses to mapping_model. // // TODO(user): Mark removed variable as removed to detect any potential bugs. - ExtractClauses(/*use_bool_and=*/ false, sat_postsolver, + ExtractClauses(/*use_bool_and=*/false, sat_postsolver, context_->mapping_model); } @@ -3724,13 +3590,12 @@ void CpModelPresolver::PresolvePureSatPart() { // effect. Like on a triangular matrix where each expansion reduced the size // of the objective by one. Investigate and fix? void CpModelPresolver::ExpandObjective() { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; // The objective is already loaded in the constext, but we re-canonicalize // it with the latest information. if (!context_->CanonicalizeObjective()) { - (void) context_->NotifyThatModelIsUnsat(); + (void)context_->NotifyThatModelIsUnsat(); return; } @@ -3803,8 +3668,7 @@ void CpModelPresolver::ExpandObjective() { break; } - if (objective_var == -1) - break; + if (objective_var == -1) break; CHECK(RefIsPositive(objective_var)); processed_vars.insert(objective_var); var_to_process.erase(objective_var); @@ -3819,8 +3683,7 @@ void CpModelPresolver::ExpandObjective() { std::sort(constraints_with_objective.begin(), constraints_with_objective.end()); for (const int ct_index : constraints_with_objective) { - if (relevant_constraints.count(ct_index) == 0) - continue; + if (relevant_constraints.count(ct_index) == 0) continue; const ConstraintProto &ct = context_->working_model->constraints(ct_index); @@ -3884,8 +3747,7 @@ void CpModelPresolver::ExpandObjective() { // Add not yet processed new variables. for (const int var : new_vars_in_objective) { - if (!processed_vars.contains(var)) - var_to_process.insert(var); + if (!processed_vars.contains(var)) var_to_process.insert(var); } // If the objective variable wasn't used in other constraints and it can @@ -3900,11 +3762,12 @@ void CpModelPresolver::ExpandObjective() { Domain implied_domain = ReadDomainFromProto(ct.linear()); for (int i = 0; i < size_of_expanded_constraint; ++i) { const int ref = ct.linear().vars(i); - if (PositiveRef(ref) == objective_var) - continue; - implied_domain = implied_domain - .AdditionWith(context_->DomainOf(ref).MultiplicationBy( - -ct.linear().coeffs(i))).RelaxIfTooComplex(); + if (PositiveRef(ref) == objective_var) continue; + implied_domain = + implied_domain + .AdditionWith(context_->DomainOf(ref).MultiplicationBy( + -ct.linear().coeffs(i))) + .RelaxIfTooComplex(); } implied_domain = implied_domain.InverseMultiplicationBy( objective_coeff_in_expanded_constraint); @@ -3932,8 +3795,8 @@ void CpModelPresolver::ExpandObjective() { unique_expanded_constraint != -1) { context_->UpdateRuleStats( "objective: removed unique objective constraint."); - ConstraintProto *mutable_ct = context_->working_model - ->mutable_constraints(unique_expanded_constraint); + ConstraintProto *mutable_ct = context_->working_model->mutable_constraints( + unique_expanded_constraint); *(context_->mapping_model->add_constraints()) = *mutable_ct; mutable_ct->Clear(); context_->UpdateConstraintVariableUsage(unique_expanded_constraint); @@ -3941,15 +3804,14 @@ void CpModelPresolver::ExpandObjective() { // We re-do a canonicalization with the final linear expression. if (!context_->CanonicalizeObjective()) { - (void) context_->NotifyThatModelIsUnsat(); + (void)context_->NotifyThatModelIsUnsat(); return; } context_->WriteObjectiveToProto(); } void CpModelPresolver::MergeNoOverlapConstraints() { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; const int num_constraints = context_->working_model->constraints_size(); int old_num_no_overlaps = 0; @@ -3973,8 +3835,7 @@ void CpModelPresolver::MergeNoOverlapConstraints() { old_num_no_overlaps++; old_num_intervals += clique.size(); } - if (old_num_no_overlaps == 0) - return; + if (old_num_no_overlaps == 0) return; // We reuse the max-clique code from sat. Model local_model; @@ -3998,8 +3859,7 @@ void CpModelPresolver::MergeNoOverlapConstraints() { ConstraintProto *ct = context_->working_model->mutable_constraints(ct_index); ct->Clear(); - if (cliques[i].empty()) - continue; + if (cliques[i].empty()) continue; for (const Literal l : cliques[i]) { CHECK(l.IsPositive()); ct->mutable_no_overlap()->add_intervals(l.Variable().value()); @@ -4018,15 +3878,12 @@ void CpModelPresolver::MergeNoOverlapConstraints() { } void CpModelPresolver::TransformIntoMaxCliques() { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; auto convert = [](int ref) { - if (RefIsPositive(ref)) - return Literal(BooleanVariable(ref), true); + if (RefIsPositive(ref)) return Literal(BooleanVariable(ref), true); return Literal(BooleanVariable(NegatedRef(ref)), false); - } - ; + }; const int num_constraints = context_->working_model->constraints_size(); // Extract the bool_and and at_most_one constraints. @@ -4045,13 +3902,10 @@ void CpModelPresolver::TransformIntoMaxCliques() { } } else if (ct->constraint_case() == ConstraintProto::ConstraintCase::kBoolAnd) { - if (ct->enforcement_literal().size() != 1) - continue; + if (ct->enforcement_literal().size() != 1) continue; const Literal enforcement = convert(ct->enforcement_literal(0)); for (const int ref : ct->bool_and().literals()) { - cliques.push_back({ - enforcement, convert(ref).Negated() - }); + cliques.push_back({enforcement, convert(ref).Negated()}); } if (RemoveConstraint(ct)) { context_->UpdateConstraintVariableUsage(c); @@ -4069,11 +3923,11 @@ void CpModelPresolver::TransformIntoMaxCliques() { graph->Resize(num_variables); for (const std::vector &clique : cliques) { if (!graph->AddAtMostOne(clique)) { - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } } if (!graph->DetectEquivalences()) { - return (void) context_->NotifyThatModelIsUnsat(); + return (void)context_->NotifyThatModelIsUnsat(); } graph->TransformIntoMaxCliques( &cliques, options_.parameters.merge_at_most_one_work_limit()); @@ -4093,16 +3947,15 @@ void CpModelPresolver::TransformIntoMaxCliques() { int num_new_cliques = 0; for (const std::vector &clique : cliques) { - if (clique.empty()) - continue; + if (clique.empty()) continue; num_new_cliques++; ConstraintProto *ct = context_->working_model->add_constraints(); for (const Literal literal : clique) { if (literal.IsPositive()) { ct->mutable_at_most_one()->add_literals(literal.Variable().value()); } else { - ct->mutable_at_most_one() - ->add_literals(NegatedRef(literal.Variable().value())); + ct->mutable_at_most_one()->add_literals( + NegatedRef(literal.Variable().value())); } } } @@ -4118,8 +3971,7 @@ void CpModelPresolver::TransformIntoMaxCliques() { } bool CpModelPresolver::PresolveOneConstraint(int c) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; ConstraintProto *ct = context_->working_model->mutable_constraints(c); // Generic presolve to exploit variable/literal equivalence. @@ -4134,92 +3986,92 @@ bool CpModelPresolver::PresolveOneConstraint(int c) { // Call the presolve function for this constraint if any. switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - return PresolveBoolOr(ct); - case ConstraintProto::ConstraintCase::kBoolAnd: - return PresolveBoolAnd(ct); - case ConstraintProto::ConstraintCase::kAtMostOne: - return PresolveAtMostOne(ct); - case ConstraintProto::ConstraintCase::kBoolXor: - return PresolveBoolXor(ct); - case ConstraintProto::ConstraintCase::kIntMax: - if (ct->int_max().vars_size() == 2 && - NegatedRef(ct->int_max().vars(0)) == ct->int_max().vars(1)) { - return PresolveIntAbs(ct); - } else { - return PresolveIntMax(ct); - } - case ConstraintProto::ConstraintCase::kIntMin: - return PresolveIntMin(ct); - case ConstraintProto::ConstraintCase::kLinMax: - return PresolveLinMax(ct); - case ConstraintProto::ConstraintCase::kLinMin: - return PresolveLinMin(ct); - case ConstraintProto::ConstraintCase::kIntProd: - return PresolveIntProd(ct); - case ConstraintProto::ConstraintCase::kIntDiv: - return PresolveIntDiv(ct); - case ConstraintProto::ConstraintCase::kLinear: { - if (CanonicalizeLinear(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - if (PresolveSmallLinear(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - if (PropagateDomainsInLinear(c, ct)) { - context_->UpdateConstraintVariableUsage(c); - } - if (PresolveSmallLinear(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - // We first propagate the domains before calling this presolve rule. - if (RemoveSingletonInLinear(ct)) { - context_->UpdateConstraintVariableUsage(c); - - // There is no need to re-do a propagation here, but the constraint - // size might have been reduced. + case ConstraintProto::ConstraintCase::kBoolOr: + return PresolveBoolOr(ct); + case ConstraintProto::ConstraintCase::kBoolAnd: + return PresolveBoolAnd(ct); + case ConstraintProto::ConstraintCase::kAtMostOne: + return PresolveAtMostOne(ct); + case ConstraintProto::ConstraintCase::kBoolXor: + return PresolveBoolXor(ct); + case ConstraintProto::ConstraintCase::kIntMax: + if (ct->int_max().vars_size() == 2 && + NegatedRef(ct->int_max().vars(0)) == ct->int_max().vars(1)) { + return PresolveIntAbs(ct); + } else { + return PresolveIntMax(ct); + } + case ConstraintProto::ConstraintCase::kIntMin: + return PresolveIntMin(ct); + case ConstraintProto::ConstraintCase::kLinMax: + return PresolveLinMax(ct); + case ConstraintProto::ConstraintCase::kLinMin: + return PresolveLinMin(ct); + case ConstraintProto::ConstraintCase::kIntProd: + return PresolveIntProd(ct); + case ConstraintProto::ConstraintCase::kIntDiv: + return PresolveIntDiv(ct); + case ConstraintProto::ConstraintCase::kLinear: { + if (CanonicalizeLinear(ct)) { + context_->UpdateConstraintVariableUsage(c); + } if (PresolveSmallLinear(ct)) { context_->UpdateConstraintVariableUsage(c); } - } - if (PresolveLinearOnBooleans(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - if (ct->constraint_case() == ConstraintProto::ConstraintCase::kLinear) { - const int old_num_enforcement_literals = ct->enforcement_literal_size(); - ExtractEnforcementLiteralFromLinearConstraint(ct); - if (ct->constraint_case() == - ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) { - context_->UpdateConstraintVariableUsage(c); - return true; - } - if (ct->enforcement_literal_size() > old_num_enforcement_literals && - PresolveSmallLinear(ct)) { + if (PropagateDomainsInLinear(c, ct)) { context_->UpdateConstraintVariableUsage(c); } + if (PresolveSmallLinear(ct)) { + context_->UpdateConstraintVariableUsage(c); + } + // We first propagate the domains before calling this presolve rule. + if (RemoveSingletonInLinear(ct)) { + context_->UpdateConstraintVariableUsage(c); + + // There is no need to re-do a propagation here, but the constraint + // size might have been reduced. + if (PresolveSmallLinear(ct)) { + context_->UpdateConstraintVariableUsage(c); + } + } + if (PresolveLinearOnBooleans(ct)) { + context_->UpdateConstraintVariableUsage(c); + } + if (ct->constraint_case() == ConstraintProto::ConstraintCase::kLinear) { + const int old_num_enforcement_literals = ct->enforcement_literal_size(); + ExtractEnforcementLiteralFromLinearConstraint(ct); + if (ct->constraint_case() == + ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) { + context_->UpdateConstraintVariableUsage(c); + return true; + } + if (ct->enforcement_literal_size() > old_num_enforcement_literals && + PresolveSmallLinear(ct)) { + context_->UpdateConstraintVariableUsage(c); + } + } + return false; } - return false; - } - case ConstraintProto::ConstraintCase::kInterval: - return PresolveInterval(c, ct); - case ConstraintProto::ConstraintCase::kElement: - return PresolveElement(ct); - case ConstraintProto::ConstraintCase::kTable: - return PresolveTable(ct); - case ConstraintProto::ConstraintCase::kAllDiff: - return PresolveAllDiff(ct); - case ConstraintProto::ConstraintCase::kNoOverlap: - return PresolveNoOverlap(ct); - case ConstraintProto::ConstraintCase::kCumulative: - return PresolveCumulative(ct); - case ConstraintProto::ConstraintCase::kCircuit: - return PresolveCircuit(ct); - case ConstraintProto::ConstraintCase::kRoutes: - return PresolveRoutes(ct); - case ConstraintProto::ConstraintCase::kAutomaton: - return PresolveAutomaton(ct); - default: - return false; + case ConstraintProto::ConstraintCase::kInterval: + return PresolveInterval(c, ct); + case ConstraintProto::ConstraintCase::kElement: + return PresolveElement(ct); + case ConstraintProto::ConstraintCase::kTable: + return PresolveTable(ct); + case ConstraintProto::ConstraintCase::kAllDiff: + return PresolveAllDiff(ct); + case ConstraintProto::ConstraintCase::kNoOverlap: + return PresolveNoOverlap(ct); + case ConstraintProto::ConstraintCase::kCumulative: + return PresolveCumulative(ct); + case ConstraintProto::ConstraintCase::kCircuit: + return PresolveCircuit(ct); + case ConstraintProto::ConstraintCase::kRoutes: + return PresolveRoutes(ct); + case ConstraintProto::ConstraintCase::kAutomaton: + return PresolveAutomaton(ct); + default: + return false; } } @@ -4227,20 +4079,18 @@ bool CpModelPresolver::ProcessSetPPCSubset( int c1, int c2, const std::vector &c2_minus_c1, const std::vector &original_constraint_index, std::vector *marked_for_removal) { - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; CHECK(!(*marked_for_removal)[c1]); CHECK(!(*marked_for_removal)[c2]); - ConstraintProto *ct1 = context_->working_model - ->mutable_constraints(original_constraint_index[c1]); - ConstraintProto *ct2 = context_->working_model - ->mutable_constraints(original_constraint_index[c2]); + ConstraintProto *ct1 = context_->working_model->mutable_constraints( + original_constraint_index[c1]); + ConstraintProto *ct2 = context_->working_model->mutable_constraints( + original_constraint_index[c2]); if (ct1->constraint_case() == ConstraintProto::ConstraintCase::kBoolOr && ct2->constraint_case() == ConstraintProto::ConstraintCase::kAtMostOne) { // fix extras in c2 to 0 for (const int literal : c2_minus_c1) { - if (!context_->SetLiteralToFalse(literal)) - return true; + if (!context_->SetLiteralToFalse(literal)) return true; context_->UpdateRuleStats("setppc: fixed variables"); } return true; @@ -4301,8 +4151,7 @@ bool CpModelPresolver::ProcessSetPPC() { if (PresolveOneConstraint(c)) { context_->UpdateConstraintVariableUsage(c); } - if (context_->ModelIsUnsat()) - return false; + if (context_->ModelIsUnsat()) return false; } if (ct->constraint_case() == ConstraintProto::ConstraintCase::kBoolOr || ct->constraint_case() == ConstraintProto::ConstraintCase::kAtMostOne) { @@ -4311,15 +4160,13 @@ bool CpModelPresolver::ProcessSetPPC() { uint64 signature = 0; for (const int literal : constraint_literals.back()) { const int positive_literal = PositiveRef(literal); - signature |= (int64 { - 1 - } << (positive_literal % 64)); + signature |= (int64{1} << (positive_literal % 64)); DCHECK_GE(positive_literal, 0); if (positive_literal >= literals_to_constraints.size()) { literals_to_constraints.resize(positive_literal + 1); } - literals_to_constraints[positive_literal] - .push_back(num_setppc_constraints); + literals_to_constraints[positive_literal].push_back( + num_setppc_constraints); } signatures.push_back(signature); marked_for_removal.push_back(false); @@ -4339,35 +4186,28 @@ bool CpModelPresolver::ProcessSetPPC() { return changed; } const int c1 = literal_to_constraints[index1]; - if (marked_for_removal[c1]) - continue; + if (marked_for_removal[c1]) continue; const std::vector &c1_literals = constraint_literals[c1]; - ConstraintProto *ct1 = context_->working_model - ->mutable_constraints(original_constraint_index[c1]); + ConstraintProto *ct1 = context_->working_model->mutable_constraints( + original_constraint_index[c1]); for (int index2 = index1 + 1; index2 < literal_to_constraints.size(); ++index2) { const int c2 = literal_to_constraints[index2]; - if (marked_for_removal[c2]) - continue; - if (marked_for_removal[c1]) - break; + if (marked_for_removal[c2]) continue; + if (marked_for_removal[c1]) break; // TODO(user): This should not happen. Investigate. - if (c1 == c2) - continue; + if (c1 == c2) continue; CHECK_LT(c1, c2); if (gtl::ContainsKey(compared_constraints, std::pair(c1, c2))) { continue; } - compared_constraints.insert({ - c1, c2 - }); + compared_constraints.insert({c1, c2}); // Hard limit on number of comparisions to avoid spending too much time // here. - if (compared_constraints.size() >= 50000) - return changed; + if (compared_constraints.size() >= 50000) return changed; const bool smaller = (signatures[c1] & ~signatures[c2]) == 0; const bool larger = (signatures[c2] & ~signatures[c1]) == 0; @@ -4378,8 +4218,8 @@ bool CpModelPresolver::ProcessSetPPC() { // Check if literals in c1 is subset of literals in c2 or vice versa. const std::vector &c2_literals = constraint_literals[c2]; - ConstraintProto *ct2 = context_->working_model - ->mutable_constraints(original_constraint_index[c2]); + ConstraintProto *ct2 = context_->working_model->mutable_constraints( + original_constraint_index[c2]); // TODO(user): Try avoiding computation of set differences if // possible. std::vector c1_minus_c2; @@ -4416,8 +4256,8 @@ bool CpModelPresolver::ProcessSetPPC() { } for (int c = 0; c < num_setppc_constraints; ++c) { if (marked_for_removal[c]) { - ConstraintProto *ct = context_->working_model - ->mutable_constraints(original_constraint_index[c]); + ConstraintProto *ct = context_->working_model->mutable_constraints( + original_constraint_index[c]); changed = RemoveConstraint(ct); context_->UpdateConstraintVariableUsage(original_constraint_index[c]); } @@ -4429,16 +4269,12 @@ bool CpModelPresolver::ProcessSetPPC() { void CpModelPresolver::TryToSimplifyDomain(int var) { CHECK(RefIsPositive(var)); CHECK(context_->ConstraintVariableGraphIsUpToDate()); - if (context_->ModelIsUnsat()) - return; - if (context_->IsFixed(var)) - return; - if (context_->VariableIsNotUsedAnymore(var)) - return; + if (context_->ModelIsUnsat()) return; + if (context_->IsFixed(var)) return; + if (context_->VariableIsNotUsedAnymore(var)) return; const AffineRelation::Relation r = context_->GetAffineRelation(var); - if (r.representative != var) - return; + if (r.representative != var) return; if (context_->VariableIsOnlyUsedInEncoding(var)) { // TODO(user): We can remove such variable and its constraints by: @@ -4458,8 +4294,7 @@ void CpModelPresolver::TryToSimplifyDomain(int var) { return; } - if (domain.NumIntervals() != domain.Size()) - return; + if (domain.NumIntervals() != domain.Size()) return; const int64 var_min = domain.Min(); int64 gcd = domain[1].start - var_min; @@ -4470,11 +4305,9 @@ void CpModelPresolver::TryToSimplifyDomain(int var) { CHECK_GE(shifted_value, 0); gcd = MathUtil::GCD64(gcd, shifted_value); - if (gcd == 1) - break; + if (gcd == 1) break; } - if (gcd == 1) - return; + if (gcd == 1) return; int new_var_index; { @@ -4487,8 +4320,7 @@ void CpModelPresolver::TryToSimplifyDomain(int var) { } new_var_index = context_->NewIntVar(Domain::FromValues(scaled_values)); } - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; CHECK(context_->StoreAffineRelation(var, new_var_index, gcd, var_min)); context_->UpdateRuleStats("variables: canonicalize affine domain"); @@ -4499,25 +4331,19 @@ void CpModelPresolver::TryToSimplifyDomain(int var) { void CpModelPresolver::EncodeAllAffineRelations() { int64 num_added = 0; for (int var = 0; var < context_->working_model->variables_size(); ++var) { - if (context_->IsFixed(var)) - continue; + if (context_->IsFixed(var)) continue; const AffineRelation::Relation r = context_->GetAffineRelation(var); - if (r.representative == var) - continue; + if (r.representative == var) continue; if (!context_->keep_all_feasible_solutions) { // TODO(user): It seems some affine relation are still removable at this // stage even though they should be removed inside PresolveToFixPoint(). // Investigate. For now, we just remove such relations. - if (context_->VariableIsNotUsedAnymore(var)) - continue; - if (!PresolveAffineRelationIfAny(var)) - break; - if (context_->VariableIsNotUsedAnymore(var)) - continue; - if (context_->IsFixed(var)) - continue; + if (context_->VariableIsNotUsedAnymore(var)) continue; + if (!PresolveAffineRelationIfAny(var)) break; + if (context_->VariableIsNotUsedAnymore(var)) continue; + if (context_->IsFixed(var)) continue; } ++num_added; @@ -4543,23 +4369,19 @@ void CpModelPresolver::EncodeAllAffineRelations() { // Presolve a variable in relation with its representative. bool CpModelPresolver::PresolveAffineRelationIfAny(int var) { - if (context_->VariableIsNotUsedAnymore(var)) - return true; + if (context_->VariableIsNotUsedAnymore(var)) return true; const AffineRelation::Relation r = context_->GetAffineRelation(var); - if (r.representative == var) - return true; + if (r.representative == var) return true; // Propagate domains. - if (!context_->PropagateAffineRelation(var)) - return false; + if (!context_->PropagateAffineRelation(var)) return false; // Once an affine relation is detected, the variables should be added to // the kAffineRelationConstraint. The only way to be unmarked is if the // variable do not appear in any other constraint and is not a representative, // in which case it should never be added back. - if (context_->IsFixed(var)) - return true; + if (context_->IsFixed(var)) return true; CHECK(context_->VarToConstraints(var).contains(kAffineRelationConstraint)); CHECK(!context_->VariableIsNotUsedAnymore(r.representative)); @@ -4582,8 +4404,7 @@ bool CpModelPresolver::PresolveAffineRelationIfAny(int var) { } void CpModelPresolver::PresolveToFixPoint() { - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; // Limit on number of operations. const int64 max_num_operations = @@ -4610,11 +4431,11 @@ void CpModelPresolver::PresolveToFixPoint() { } } - // When thinking about how the presolve works, it seems like a good idea to - // process the "simple" constraints first in order to be more efficient. - // In September 2019, experiment on the flatzinc problems shows no changes - // in - // the results. We should actually count the number of rules triggered. + // When thinking about how the presolve works, it seems like a good idea to + // process the "simple" constraints first in order to be more efficient. + // In September 2019, experiment on the flatzinc problems shows no changes + // in + // the results. We should actually count the number of rules triggered. std::sort(queue.begin(), queue.end(), [this](int a, int b) { const int score_a = context_->ConstraintToVars(a).size(); const int score_b = context_->ConstraintToVars(b).size(); @@ -4622,15 +4443,11 @@ void CpModelPresolver::PresolveToFixPoint() { }); while (!queue.empty() && !context_->ModelIsUnsat()) { - if (time_limit != nullptr && time_limit->LimitReached()) - break; - if (context_->num_presolve_operations > max_num_operations) - break; + if (time_limit != nullptr && time_limit->LimitReached()) break; + if (context_->num_presolve_operations > max_num_operations) break; while (!queue.empty() && !context_->ModelIsUnsat()) { - if (time_limit != nullptr && time_limit->LimitReached()) - break; - if (context_->num_presolve_operations > max_num_operations) - break; + if (time_limit != nullptr && time_limit->LimitReached()) break; + if (context_->num_presolve_operations > max_num_operations) break; const int c = queue.front(); in_queue[c] = false; queue.pop_front(); @@ -4669,10 +4486,8 @@ void CpModelPresolver::PresolveToFixPoint() { // we already do that below. const int current_num_variables = context_->working_model->variables_size(); for (int v = 0; v < current_num_variables; ++v) { - if (context_->ModelIsUnsat()) - return; - if (!PresolveAffineRelationIfAny(v)) - return; + if (context_->ModelIsUnsat()) return; + if (!PresolveAffineRelationIfAny(v)) return; // Try to canonicalize the domain, note that we should have detected all // affine relations before, so we don't recreate "canononical" variables @@ -4685,14 +4500,11 @@ void CpModelPresolver::PresolveToFixPoint() { // // TODO(user): Avoid reprocessing the constraints that changed the variables // with the use of timestamp. - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; in_queue.resize(context_->working_model->constraints_size(), false); for (const int v : context_->modified_domains.PositionsSetAtLeastOnce()) { - if (context_->VariableIsNotUsedAnymore(v)) - continue; - if (context_->IsFixed(v)) - context_->ExploitFixedDomain(v); + if (context_->VariableIsNotUsedAnymore(v)) continue; + if (context_->IsFixed(v)) context_->ExploitFixedDomain(v); for (const int c : context_->VarToConstraints(v)) { if (c >= 0 && !in_queue[c]) { in_queue[c] = true; @@ -4707,11 +4519,9 @@ void CpModelPresolver::PresolveToFixPoint() { const int num_vars = context_->working_model->variables_size(); for (int v = 0; v < num_vars; ++v) { const auto &constraints = context_->VarToConstraints(v); - if (constraints.size() != 1) - continue; + if (constraints.size() != 1) continue; const int c = *constraints.begin(); - if (c < 0) - continue; + if (c < 0) continue; // Note that to avoid bad complexity in problem like a TSP with just one // big constraint. we mark all the singleton variables of a constraint @@ -4720,9 +4530,7 @@ void CpModelPresolver::PresolveToFixPoint() { std::pair(v, c))) { continue; } - var_constraint_pair_already_called.insert({ - v, c - }); + var_constraint_pair_already_called.insert({v, c}); if (!in_queue[c]) { in_queue[c] = true; @@ -4736,8 +4544,7 @@ void CpModelPresolver::PresolveToFixPoint() { context_->modified_domains.SparseClearAll(); } - if (context_->ModelIsUnsat()) - return; + if (context_->ModelIsUnsat()) return; // Second "pass" for transformation better done after all of the above and // that do not need a fix-point loop. @@ -4751,40 +4558,40 @@ void CpModelPresolver::PresolveToFixPoint() { for (int c = 0; c < num_constraints; ++c) { ConstraintProto *ct = context_->working_model->mutable_constraints(c); switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kNoOverlap: - // Filter out absent intervals. - if (PresolveNoOverlap(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - // TODO(user): Implement if we ever support optional intervals in - // this constraint. Currently we do not. - break; - case ConstraintProto::ConstraintCase::kCumulative: - // Filter out absent intervals. - if (PresolveCumulative(ct)) { - context_->UpdateConstraintVariableUsage(c); - } - break; - case ConstraintProto::ConstraintCase::kBoolOr: { - // Try to infer domain reductions from clauses and the saved "implies in - // domain" relations. - for (const auto &pair : - context_->deductions.ProcessClause(ct->bool_or().literals())) { - bool modified = false; - if (!context_->IntersectDomainWith(pair.first, pair.second, - &modified)) { - return; + case ConstraintProto::ConstraintCase::kNoOverlap: + // Filter out absent intervals. + if (PresolveNoOverlap(ct)) { + context_->UpdateConstraintVariableUsage(c); } - if (modified) { - context_->UpdateRuleStats("deductions: reduced variable domain"); + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + // TODO(user): Implement if we ever support optional intervals in + // this constraint. Currently we do not. + break; + case ConstraintProto::ConstraintCase::kCumulative: + // Filter out absent intervals. + if (PresolveCumulative(ct)) { + context_->UpdateConstraintVariableUsage(c); } + break; + case ConstraintProto::ConstraintCase::kBoolOr: { + // Try to infer domain reductions from clauses and the saved "implies in + // domain" relations. + for (const auto &pair : + context_->deductions.ProcessClause(ct->bool_or().literals())) { + bool modified = false; + if (!context_->IntersectDomainWith(pair.first, pair.second, + &modified)) { + return; + } + if (modified) { + context_->UpdateRuleStats("deductions: reduced variable domain"); + } + } + break; } - break; - } - default: - break; + default: + break; } } @@ -4821,7 +4628,8 @@ bool PresolveCpModel(const PresolveOptions &options, PresolveContext *context, CpModelPresolver::CpModelPresolver(const PresolveOptions &options, PresolveContext *context, std::vector *postsolve_mapping) - : options_(options), postsolve_mapping_(postsolve_mapping), + : options_(options), + postsolve_mapping_(postsolve_mapping), context_(context) { context_->keep_all_feasible_solutions = options.parameters.enumerate_all_solutions() || @@ -4840,7 +4648,7 @@ CpModelPresolver::CpModelPresolver(const PresolveOptions &options, // Initialize the objective. context_->ReadObjectiveFromProto(); if (!context_->CanonicalizeObjective()) { - (void) context_->NotifyThatModelIsUnsat(); + (void)context_->NotifyThatModelIsUnsat(); } // Note that we delay the call to UpdateNewConstraintsVariableUsage() for @@ -4869,8 +4677,7 @@ bool CpModelPresolver::Presolve() { if (!options_.parameters.cp_model_presolve()) { context_->UpdateNewConstraintsVariableUsage(); ExpandCpModel(options_, context_); - if (options_.log_info) - LogInfoFromContext(context_); + if (options_.log_info) LogInfoFromContext(context_); return true; } @@ -4883,23 +4690,22 @@ bool CpModelPresolver::Presolve() { ConstraintProto *ct = context_->working_model->mutable_constraints(c); PresolveEnforcementLiteral(ct); switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - PresolveBoolOr(ct); - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - PresolveBoolAnd(ct); - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - PresolveAtMostOne(ct); - break; - case ConstraintProto::ConstraintCase::kLinear: - CanonicalizeLinear(ct); - break; - default: - break; + case ConstraintProto::ConstraintCase::kBoolOr: + PresolveBoolOr(ct); + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + PresolveBoolAnd(ct); + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + PresolveAtMostOne(ct); + break; + case ConstraintProto::ConstraintCase::kLinear: + CanonicalizeLinear(ct); + break; + default: + break; } - if (context_->ModelIsUnsat()) - break; + if (context_->ModelIsUnsat()) break; } context_->UpdateNewConstraintsVariableUsage(); context_->RegisterVariablesUsedInAssumptions(); @@ -4915,8 +4721,7 @@ bool CpModelPresolver::Presolve() { for (int c = 0; c < context_->working_model->constraints_size(); ++c) { const auto type = context_->working_model->constraints(c).constraint_case(); - if (type == ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) - continue; + if (type == ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET) continue; old_num_non_empty_constraints++; } @@ -4969,8 +4774,7 @@ bool CpModelPresolver::Presolve() { context_->UpdateNewConstraintsVariableUsage(); } - if (iter == 0) - TransformIntoMaxCliques(); + if (iter == 0) TransformIntoMaxCliques(); // Process set packing, partitioning and covering constraint. if (options_.time_limit == nullptr || @@ -5029,8 +4833,7 @@ bool CpModelPresolver::Presolve() { } if (context_->ModelIsUnsat()) { - if (options_.log_info) - LogInfoFromContext(context_); + if (options_.log_info) LogInfoFromContext(context_); // Set presolved_model to the simplest UNSAT problem (empty clause). context_->working_model->Clear(); @@ -5055,13 +4858,11 @@ bool CpModelPresolver::Presolve() { const int var = PositiveRef(ref); // Remove fixed variables. - if (context_->IsFixed(var)) - continue; + if (context_->IsFixed(var)) continue; // There is not point having a variable appear twice, so we only keep // the first occurrence in the first strategy in which it occurs. - if (gtl::ContainsKey(used_variables, var)) - continue; + if (gtl::ContainsKey(used_variables, var)) continue; used_variables.insert(var); if (context_->VarToConstraints(var).empty()) { @@ -5098,8 +4899,8 @@ bool CpModelPresolver::Presolve() { } // Set the variables of the mapping_model. - context_->mapping_model->mutable_variables() - ->CopyFrom(context_->working_model->variables()); + context_->mapping_model->mutable_variables()->CopyFrom( + context_->working_model->variables()); // Remove all the unused variables from the presolved model. postsolve_mapping_->clear(); @@ -5126,8 +4927,7 @@ bool CpModelPresolver::Presolve() { } // Stats and checks. - if (options_.log_info) - LogInfoFromContext(context_); + if (options_.log_info) LogInfoFromContext(context_); // One possible error that is difficult to avoid here: because of our // objective expansion, we might detect a possible overflow... @@ -5160,12 +4960,11 @@ void ApplyVariableMapping(const std::vector &mapping, // Remap all the variable/literal references in the constraints and the // enforcement literals in the variables. - auto mapping_function = [&mapping](int * ref) { + auto mapping_function = [&mapping](int *ref) { const int image = mapping[PositiveRef(*ref)]; CHECK_GE(image, 0); *ref = RefIsPositive(*ref) ? image : NegatedRef(image); - } - ; + }; for (ConstraintProto &ct_ref : *proto->mutable_constraints()) { ApplyToAllVariableIndices(mapping_function, &ct_ref); ApplyToAllLiteralIndices(mapping_function, &ct_ref); @@ -5239,8 +5038,7 @@ void ApplyVariableMapping(const std::vector &mapping, std::vector new_variables; for (int i = 0; i < mapping.size(); ++i) { const int image = mapping[i]; - if (image < 0) - continue; + if (image < 0) continue; if (image >= new_variables.size()) { new_variables.resize(image + 1, IntegerVariableProto()); } @@ -5272,9 +5070,7 @@ std::vector FindDuplicateConstraints(const CpModelProto &model_proto) { } s = model_proto.constraints(c).SerializeAsString(); const int64 hash = std::hash()(s); - const auto insert = equiv_constraints.insert({ - hash, c - }); + const auto insert = equiv_constraints.insert({hash, c}); if (!insert.second) { // Already present! const int other_c_with_same_hash = insert.first->second; @@ -5288,5 +5084,5 @@ std::vector FindDuplicateConstraints(const CpModelProto &model_proto) { return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_presolve.h b/ortools/sat/cp_model_presolve.h index b8be5cd07e..54d35c018d 100644 --- a/ortools/sat/cp_model_presolve.h +++ b/ortools/sat/cp_model_presolve.h @@ -61,7 +61,7 @@ void ApplyVariableMapping(const std::vector &mapping, // presolved model? If we go this route, it may be nicer to store the indices // inside the model. We can add a IntegerVariableProto::initial_index; class CpModelPresolver { -public: + public: CpModelPresolver(const PresolveOptions &options, PresolveContext *context, std::vector *postsolve_mapping); @@ -77,7 +77,7 @@ public: // Public for testing only. void RemoveEmptyConstraints(); -private: + private: void PresolveToFixPoint(); // Runs the probing. @@ -191,7 +191,7 @@ bool PresolveCpModel(const PresolveOptions &options, PresolveContext *context, // enforcement literal list for instance... std::vector FindDuplicateConstraints(const CpModelProto &model_proto); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_PRESOLVE_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_PRESOLVE_H_ diff --git a/ortools/sat/cp_model_search.cc b/ortools/sat/cp_model_search.cc index cb25d7bedc..f6d19a6f22 100644 --- a/ortools/sat/cp_model_search.cc +++ b/ortools/sat/cp_model_search.cc @@ -40,17 +40,17 @@ struct VarValue { }; const std::function ConstructSearchStrategyInternal( - const absl::flat_hash_map > & - var_to_coeff_offset_pair, + const absl::flat_hash_map > + &var_to_coeff_offset_pair, const std::vector &strategies, Model *model) { IntegerEncoder *const integer_encoder = model->GetOrCreate(); IntegerTrail *const integer_trail = model->GetOrCreate(); // Note that we copy strategies to keep the return function validity // independently of the life of the passed vector. - return[integer_encoder, integer_trail, strategies, var_to_coeff_offset_pair, - model]() { const SatParameters *const parameters = - model->GetOrCreate(); + return [integer_encoder, integer_trail, strategies, var_to_coeff_offset_pair, + model]() { + const SatParameters *const parameters = model->GetOrCreate(); for (const Strategy &strategy : strategies) { IntegerVariable candidate = kNoIntegerVariable; @@ -65,12 +65,10 @@ const std::function ConstructSearchStrategyInternal( std::vector active_vars; for (const IntegerVariable var : strategy.variables) { - if (integer_trail->IsCurrentlyIgnored(var)) - continue; + if (integer_trail->IsCurrentlyIgnored(var)) continue; const IntegerValue lb = integer_trail->LowerBound(var); const IntegerValue ub = integer_trail->UpperBound(var); - if (lb == ub) - continue; + if (lb == ub) continue; IntegerValue value(0); IntegerValue coeff(1); IntegerValue offset(0); @@ -118,22 +116,18 @@ const std::function ConstructSearchStrategyInternal( if (active_vars.empty() || value <= candidate_value + parameters->search_randomization_tolerance()) { - active_vars.push_back({ - var, value - }); + active_vars.push_back({var, value}); } } } - if (candidate == kNoIntegerVariable) - continue; + if (candidate == kNoIntegerVariable) continue; if (parameters->randomize_search()) { CHECK(!active_vars.empty()); const IntegerValue threshold( candidate_value + parameters->search_randomization_tolerance()); - auto is_above_tolerance = [threshold](const VarValue & entry) { + auto is_above_tolerance = [threshold](const VarValue &entry) { return entry.value > threshold; - } - ; + }; // Remove all values above tolerance. active_vars.erase(std::remove_if(active_vars.begin(), active_vars.end(), is_above_tolerance), @@ -173,14 +167,13 @@ const std::function ConstructSearchStrategyInternal( return BooleanOrIntegerLiteral(literal); } return BooleanOrIntegerLiteral(); - } - ; + }; } -std::function -ConstructSearchStrategy(const CpModelProto &cp_model_proto, - const std::vector &variable_mapping, - IntegerVariable objective_var, Model *model) { +std::function ConstructSearchStrategy( + const CpModelProto &cp_model_proto, + const std::vector &variable_mapping, + IntegerVariable objective_var, Model *model) { // Default strategy is to instantiate the IntegerVariable in order. std::function default_search_strategy = nullptr; const bool instantiate_all_variables = @@ -189,8 +182,7 @@ ConstructSearchStrategy(const CpModelProto &cp_model_proto, if (instantiate_all_variables) { std::vector decisions; for (const IntegerVariable var : variable_mapping) { - if (var == kNoIntegerVariable) - continue; + if (var == kNoIntegerVariable) continue; // Make sure we try to fix the objective to its lowest value first. if (var == NegationOf(objective_var)) { @@ -221,17 +213,15 @@ ConstructSearchStrategy(const CpModelProto &cp_model_proto, RefIsPositive(ref) ? variable_mapping[ref] : NegationOf(variable_mapping[PositiveRef(ref)]); if (!gtl::ContainsKey(var_to_coeff_offset_pair, var.value())) { - var_to_coeff_offset_pair[var.value()] = { transform.positive_coeff(), - transform.offset() }; + var_to_coeff_offset_pair[var.value()] = {transform.positive_coeff(), + transform.offset()}; } } } if (instantiate_all_variables) { - return SequentialSearch({ - ConstructSearchStrategyInternal(var_to_coeff_offset_pair, strategies, - model), - default_search_strategy - }); + return SequentialSearch({ConstructSearchStrategyInternal( + var_to_coeff_offset_pair, strategies, model), + default_search_strategy}); } else { return ConstructSearchStrategyInternal(var_to_coeff_offset_pair, strategies, model); @@ -245,10 +235,8 @@ std::function InstrumentSearchStrategy( Model *model) { std::vector ref_to_display; for (int i = 0; i < cp_model_proto.variables_size(); ++i) { - if (variable_mapping[i] == kNoIntegerVariable) - continue; - if (cp_model_proto.variables(i).name().empty()) - continue; + if (variable_mapping[i] == kNoIntegerVariable) continue; + if (cp_model_proto.variables(i).name().empty()) continue; ref_to_display.push_back(i); } std::sort(ref_to_display.begin(), ref_to_display.end(), [&](int i, int j) { @@ -257,11 +245,10 @@ std::function InstrumentSearchStrategy( }); std::vector > old_domains(variable_mapping.size()); - return[instrumented_strategy, model, variable_mapping, cp_model_proto, - old_domains, ref_to_display]() mutable { + return [instrumented_strategy, model, variable_mapping, cp_model_proto, + old_domains, ref_to_display]() mutable { const BooleanOrIntegerLiteral decision = instrumented_strategy(); - if (!decision.HasValue()) - return decision; + if (!decision.HasValue()) return decision; if (decision.boolean_literal_index != kNoLiteralIndex) { const Literal l = Literal(decision.boolean_literal_index); @@ -292,8 +279,7 @@ std::function InstrumentSearchStrategy( } LOG(INFO) << to_display; return decision; - } - ; + }; } // Note: in flatzinc setting, we know we always have a fixed search defined. @@ -303,9 +289,9 @@ std::function InstrumentSearchStrategy( // - Disable linearization_level options for non linear problems // - Fast restart in randomized search // - Different propatation levels for scheduling constraints -std::vector -GetDiverseSetOfParameters(const SatParameters &base_params, - const CpModelProto &cp_model, const int num_workers) { +std::vector GetDiverseSetOfParameters( + const SatParameters &base_params, const CpModelProto &cp_model, + const int num_workers) { // Defines a set of named strategies so it is easier to read in one place // the one that are used. See below. std::map strategies; @@ -395,8 +381,7 @@ GetDiverseSetOfParameters(const SatParameters &base_params, names.push_back("pseudo_costs"); names.push_back("no_lp"); names.push_back("max_lp"); - if (cp_model.objective().vars_size() > 1) - names.push_back("core"); + if (cp_model.objective().vars_size() > 1) names.push_back("core"); // Only add this strategy if we have enough worker left for LNS. if (num_workers > 8 || base_params.interleave_search()) { @@ -404,8 +389,7 @@ GetDiverseSetOfParameters(const SatParameters &base_params, } } else { names.push_back("default_lp"); - if (cp_model.search_strategy_size() > 0) - names.push_back("fixed"); + if (cp_model.search_strategy_size() > 0) names.push_back("fixed"); names.push_back("less_encoding"); names.push_back("no_lp"); names.push_back("max_lp"); @@ -460,5 +444,5 @@ GetDiverseSetOfParameters(const SatParameters &base_params, return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_search.h b/ortools/sat/cp_model_search.h index 2181887c4b..88add75c58 100644 --- a/ortools/sat/cp_model_search.h +++ b/ortools/sat/cp_model_search.h @@ -48,12 +48,11 @@ std::function InstrumentSearchStrategy( // Returns up to "num_workers" different parameters. We do not always return // num_worker parameters to leave room for strategies like LNS that do not // consume a full worker and can always be interleaved. -std::vector - GetDiverseSetOfParameters(const SatParameters &base_params, - const CpModelProto &cp_model, - const int num_workers); +std::vector GetDiverseSetOfParameters( + const SatParameters &base_params, const CpModelProto &cp_model, + const int num_workers); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_SEARCH_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_SEARCH_H_ diff --git a/ortools/sat/cp_model_solver.cc b/ortools/sat/cp_model_solver.cc index ab203faa8d..a318e25242 100644 --- a/ortools/sat/cp_model_solver.cc +++ b/ortools/sat/cp_model_solver.cc @@ -33,7 +33,7 @@ #include "google/protobuf/text_format.h" #include "ortools/base/file.h" #include "ortools/util/sigint.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ #include "absl/container/flat_hash_set.h" #include "absl/memory/memory.h" @@ -138,14 +138,13 @@ namespace { // Makes the string fit in one line by cutting it in the middle if necessary. std::string Summarize(const std::string &input) { - if (input.size() < 105) - return input; + if (input.size() < 105) return input; const int half = 50; return absl::StrCat(input.substr(0, half), " ... ", input.substr(input.size() - half, half)); } -} // namespace. +} // namespace. // ============================================================================= // Public API. @@ -162,14 +161,10 @@ std::string CpModelStats(const CpModelProto &model_proto) { // We split the linear constraints into 3 buckets has it gives more insight // on the type of problem we are facing. if (ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) { - if (ct.linear().vars_size() == 1) - name += "1"; - if (ct.linear().vars_size() == 2) - name += "2"; - if (ct.linear().vars_size() == 3) - name += "3"; - if (ct.linear().vars_size() > 3) - name += "N"; + if (ct.linear().vars_size() == 1) name += "1"; + if (ct.linear().vars_size() == 2) name += "2"; + if (ct.linear().vars_size() == 3) name += "3"; + if (ct.linear().vars_size() > 3) name += "N"; } num_constraints_by_name[name]++; @@ -222,8 +217,9 @@ std::string CpModelStats(const CpModelProto &model_proto) { " variables, ", ProtoEnumToString( strategy.variable_selection_strategy()), - ", ", ProtoEnumToString( - strategy.domain_reduction_strategy()), + ", ", + ProtoEnumToString( + strategy.domain_reduction_strategy()), "\n"); } @@ -268,16 +264,16 @@ std::string CpModelStats(const CpModelProto &model_proto) { const std::string &name = entry.first; constraints.push_back(absl::StrCat("#", name, ": ", entry.second)); if (gtl::ContainsKey(num_reif_constraints_by_name, name)) { - absl::StrAppend(&constraints.back(), " (#enforced: ", - num_reif_constraints_by_name[name], ")"); + absl::StrAppend(&constraints.back(), + " (#enforced: ", num_reif_constraints_by_name[name], ")"); } if (gtl::ContainsKey(name_to_num_literals, name)) { - absl::StrAppend(&constraints.back(), " (#literals: ", - name_to_num_literals[name], ")"); + absl::StrAppend(&constraints.back(), + " (#literals: ", name_to_num_literals[name], ")"); } if (gtl::ContainsKey(name_to_num_terms, name)) { - absl::StrAppend(&constraints.back(), " (#terms: ", - name_to_num_terms[name], ")"); + absl::StrAppend(&constraints.back(), + " (#terms: ", name_to_num_terms[name], ")"); } } std::sort(constraints.begin(), constraints.end()); @@ -309,14 +305,14 @@ std::string CpSolverResponseStats(const CpSolverResponse &response, // TODO(user): This is probably better named "binary_propagation", but we just // output "propagations" to be consistent with sat/analyze.sh. - absl::StrAppend(&result, "\npropagations: ", - response.num_binary_propagations()); - absl::StrAppend(&result, "\ninteger_propagations: ", - response.num_integer_propagations()); + absl::StrAppend(&result, + "\npropagations: ", response.num_binary_propagations()); + absl::StrAppend( + &result, "\ninteger_propagations: ", response.num_integer_propagations()); absl::StrAppend(&result, "\nwalltime: ", response.wall_time()); absl::StrAppend(&result, "\nusertime: ", response.user_time()); - absl::StrAppend(&result, "\ndeterministic_time: ", - response.deterministic_time()); + absl::StrAppend(&result, + "\ndeterministic_time: ", response.deterministic_time()); absl::StrAppend(&result, "\nprimal_integral: ", response.primal_integral()); absl::StrAppend(&result, "\n"); return result; @@ -368,8 +364,7 @@ void FillSolutionInResponse(const CpModelProto &model_proto, const Model &model, // TODO(user): Checks against initial model. CHECK(SolutionIsFeasible(model_proto, solution)); } - for (const int64 value : solution) - response->add_solution(value); + for (const int64 value : solution) response->add_solution(value); } else { // Not all variables are fixed. // We fill instead the lb/ub of each variables. @@ -399,8 +394,7 @@ namespace { IntegerVariable GetOrCreateVariableWithTightBound( const std::vector > &terms, Model *model) { - if (terms.empty()) - return model->Add(ConstantIntegerVariable(0)); + if (terms.empty()) return model->Add(ConstantIntegerVariable(0)); if (terms.size() == 1 && terms.front().second == 1) { return terms.front().first; } @@ -425,8 +419,7 @@ IntegerVariable GetOrCreateVariableWithTightBound( IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf( const std::vector > &terms, Model *model) { - if (terms.empty()) - return model->Add(ConstantIntegerVariable(0)); + if (terms.empty()) return model->Add(ConstantIntegerVariable(0)); if (terms.size() == 1 && terms.front().second == 1) { return terms.front().first; } @@ -464,9 +457,9 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, std::vector literals = mapping->Literals(ct.circuit().literals()); const int num_nodes = ReindexArcs(&tails, &heads, &literals); - relaxation->cut_generators - .push_back(CreateStronglyConnectedGraphCutGenerator( - num_nodes, tails, heads, literals, m)); + relaxation->cut_generators.push_back( + CreateStronglyConnectedGraphCutGenerator(num_nodes, tails, heads, + literals, m)); } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kRoutes && linearization_level > 1) { @@ -482,9 +475,9 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, num_nodes = std::max(num_nodes, 1 + ct.routes().heads(i)); } if (ct.routes().demands().empty() || ct.routes().capacity() == 0) { - relaxation->cut_generators - .push_back(CreateStronglyConnectedGraphCutGenerator( - num_nodes, tails, heads, literals, m)); + relaxation->cut_generators.push_back( + CreateStronglyConnectedGraphCutGenerator(num_nodes, tails, heads, + literals, m)); } else { const std::vector demands(ct.routes().demands().begin(), ct.routes().demands().end()); @@ -494,10 +487,8 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, } } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntProd) { - if (HasEnforcementLiteral(ct)) - return; - if (ct.int_prod().vars_size() != 2) - return; + if (HasEnforcementLiteral(ct)) return; + if (ct.int_prod().vars_size() != 2) return; // Constraint is z == x * y. @@ -513,8 +504,7 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, if (x == y) { // We currently only support variables with non-negative domains. - if (x_lb < 0 && x_ub > 0) - return; + if (x_lb < 0 && x_ub > 0) return; // Change the sigh of x if its domain is non-positive. if (x_ub <= 0) { @@ -524,10 +514,8 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, relaxation->cut_generators.push_back(CreateSquareCutGenerator(z, x, m)); } else { // We currently only support variables with non-negative domains. - if (x_lb < 0 && x_ub > 0) - return; - if (y_lb < 0 && y_ub > 0) - return; + if (x_lb < 0 && x_ub > 0) return; + if (y_lb < 0 && y_ub > 0) return; // Change signs to return to the case where all variables are a domain // with non negative values only. @@ -540,29 +528,25 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, z = NegationOf(z); } - relaxation->cut_generators - .push_back(CreatePositiveMultiplicationCutGenerator(z, x, y, m)); + relaxation->cut_generators.push_back( + CreatePositiveMultiplicationCutGenerator(z, x, y, m)); } } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kAllDiff) { - if (linearization_level < 2) - return; - if (HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (HasEnforcementLiteral(ct)) return; const int num_vars = ct.all_diff().vars_size(); if (num_vars <= m->GetOrCreate()->max_all_diff_cut_size()) { std::vector vars = mapping->Integers(ct.all_diff().vars()); - relaxation->cut_generators - .push_back(CreateAllDifferentCutGenerator(vars, m)); + relaxation->cut_generators.push_back( + CreateAllDifferentCutGenerator(vars, m)); } } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kCumulative) { - if (linearization_level < 2) - return; - if (HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (HasEnforcementLiteral(ct)) return; std::vector demands = mapping->Integers(ct.cumulative().demands()); @@ -570,37 +554,31 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, mapping->Intervals(ct.cumulative().intervals()); const IntegerVariable capacity = mapping->Integer(ct.cumulative().capacity()); - relaxation->cut_generators - .push_back(CreateOverlappingCumulativeCutGenerator(intervals, capacity, - demands, m)); + relaxation->cut_generators.push_back( + CreateOverlappingCumulativeCutGenerator(intervals, capacity, demands, + m)); relaxation->cut_generators.push_back( CreateCumulativeCutGenerator(intervals, capacity, demands, m)); } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kNoOverlap) { - if (linearization_level < 2) - return; - if (HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (HasEnforcementLiteral(ct)) return; std::vector intervals = mapping->Intervals(ct.no_overlap().intervals()); - relaxation->cut_generators - .push_back(CreateNoOverlapCutGenerator(intervals, m)); - relaxation->cut_generators - .push_back(CreateNoOverlapPrecedenceCutGenerator(intervals, m)); + relaxation->cut_generators.push_back( + CreateNoOverlapCutGenerator(intervals, m)); + relaxation->cut_generators.push_back( + CreateNoOverlapPrecedenceCutGenerator(intervals, m)); } if (ct.constraint_case() == ConstraintProto::ConstraintCase::kLinMax) { - if (!m->GetOrCreate()->add_lin_max_cuts()) - return; - if (HasEnforcementLiteral(ct)) - return; + if (!m->GetOrCreate()->add_lin_max_cuts()) return; + if (HasEnforcementLiteral(ct)) return; // TODO(user): Support linearization of general target expression. - if (ct.lin_max().target().vars_size() != 1) - return; - if (ct.lin_max().target().coeffs(0) != 1) - return; + if (ct.lin_max().target().vars_size() != 1) return; + if (ct.lin_max().target().coeffs(0) != 1) return; const IntegerVariable target = mapping->Integer(ct.lin_max().target().vars(0)); @@ -619,13 +597,13 @@ void TryToAddCutGenerators(const CpModelProto &model_proto, AppendLinMaxRelaxation(target, exprs, m, relaxation); if (linearization_level >= 2) { - relaxation->cut_generators - .push_back(CreateLinMaxCutGenerator(target, exprs, z_vars, m)); + relaxation->cut_generators.push_back( + CreateLinMaxCutGenerator(target, exprs, z_vars, m)); } } } -} // namespace +} // namespace LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, int linearization_level, Model *m) { @@ -663,13 +641,12 @@ LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, m->Add(NewIntegerVariableFromLiteral(literal)); } else if (encoder->GetLiteralView(literal) == kNoIntegerVariable && encoder->GetLiteralView(literal.Negated()) == - kNoIntegerVariable) { + kNoIntegerVariable) { ok = false; break; } } - if (!ok) - continue; + if (!ok) continue; TryToLinearizeConstraint(model_proto, ct, m, linearization_level, &relaxation); @@ -680,17 +657,15 @@ LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, int num_full_encoding_relaxations = 0; int num_partial_encoding_relaxations = 0; for (int i = 0; i < model_proto.variables_size(); ++i) { - if (mapping->IsBoolean(i)) - continue; + if (mapping->IsBoolean(i)) continue; const IntegerVariable var = mapping->Integer(i); - if (m->Get(IsFixed(var))) - continue; + if (m->Get(IsFixed(var))) continue; // TODO(user): This different encoding for the partial variable might be // better (less LP constraints), but we do need more investigation to // decide. - if (/* DISABLES CODE */(false)) { + if (/* DISABLES CODE */ (false)) { AppendPartialEncodingRelaxation(var, *m, &relaxation); continue; } @@ -717,11 +692,10 @@ LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, // Linearize the at most one constraints. Note that we transform them // into maximum "at most one" first and we removes redundant ones. - m->GetOrCreate() - ->TransformIntoMaxCliques(&relaxation.at_most_ones); + m->GetOrCreate()->TransformIntoMaxCliques( + &relaxation.at_most_ones); for (const std::vector &at_most_one : relaxation.at_most_ones) { - if (at_most_one.empty()) - continue; + if (at_most_one.empty()) continue; LinearConstraintBuilder lc(m, kMinIntegerValue, IntegerValue(1)); for (const Literal literal : at_most_one) { @@ -741,8 +715,7 @@ LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, { int new_size = 0; for (int i = 0; i < relaxation.linear_constraints.size(); ++i) { - if (relaxation.linear_constraints[i].vars.size() <= 1) - continue; + if (relaxation.linear_constraints[i].vars.size() <= 1) continue; std::swap(relaxation.linear_constraints[new_size++], relaxation.linear_constraints[i]); } @@ -777,17 +750,14 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, DenseConnectedComponentsFinder components; components.SetNumberOfNodes(num_lp_constraints + num_lp_cut_generators + num_integer_variables); - auto get_constraint_index = [](int ct_index) { return ct_index; } - ; + auto get_constraint_index = [](int ct_index) { return ct_index; }; auto get_cut_generator_index = [num_lp_constraints](int cut_index) { return num_lp_constraints + cut_index; - } - ; - auto get_var_index = - [num_lp_constraints, num_lp_cut_generators](IntegerVariable var) { + }; + auto get_var_index = [num_lp_constraints, + num_lp_cut_generators](IntegerVariable var) { return num_lp_constraints + num_lp_cut_generators + var.value(); - } - ; + }; for (int i = 0; i < num_lp_constraints; i++) { for (const IntegerVariable var : relaxation.linear_constraints[i].vars) { components.AddEdge(get_constraint_index(i), get_var_index(var)); @@ -846,8 +816,7 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, num_components); for (int i = 0; i < num_lp_constraints; i++) { const int c = index_to_component[get_constraint_index(i)]; - if (component_sizes[c] <= 1) - continue; + if (component_sizes[c] <= 1) continue; component_to_constraints[c].push_back(relaxation.linear_constraints[i]); if (lp_constraints[c] == nullptr) { lp_constraints[c] = m->Create(); @@ -869,16 +838,14 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, const SatParameters ¶ms = *(m->GetOrCreate()); if (params.add_clique_cuts() && params.linearization_level() > 1) { for (LinearProgrammingConstraint *lp : lp_constraints) { - if (lp == nullptr) - continue; + if (lp == nullptr) continue; lp->AddCutGenerator(CreateCliqueCutGenerator(lp->integer_variables(), m)); } } if (params.add_knapsack_cuts() && params.linearization_level() > 1) { for (int c = 0; c < num_components; ++c) { - if (component_to_constraints[c].empty()) - continue; + if (component_to_constraints[c].empty()) continue; lp_constraints[c]->AddCutGenerator(CreateKnapsackCoverCutGenerator( component_to_constraints[c], lp_constraints[c]->integer_variables(), m)); @@ -908,8 +875,7 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, } // Second pass: Build the cp sub-objectives per component. for (int c = 0; c < num_components; ++c) { - if (component_to_cp_terms[c].empty()) - continue; + if (component_to_cp_terms[c].empty()) continue; const IntegerVariable sub_obj_var = GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m); top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1)); @@ -926,8 +892,7 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, // Register LP constraints. Note that this needs to be done after all the // constraints have been added. for (LinearProgrammingConstraint *lp_constraint : lp_constraints) { - if (lp_constraint == nullptr) - continue; + if (lp_constraint == nullptr) continue; lp_constraint->RegisterWith(m); VLOG(3) << "LP constraint: " << lp_constraint->DimensionString() << "."; } @@ -938,7 +903,7 @@ IntegerVariable AddLPConstraints(const CpModelProto &model_proto, return main_objective_var; } -} // namespace +} // namespace // Used by NewFeasibleSolutionObserver to register observers. struct SolutionObservers { @@ -948,16 +913,15 @@ struct SolutionObservers { std::function NewFeasibleSolutionObserver( const std::function &observer) { - return[ = ](Model * model) { + return [=](Model *model) { model->GetOrCreate()->observers.push_back(observer); - } - ; + }; } #if !defined(__PORTABLE_PLATFORM__) // TODO(user): Support it on android. -std::function -NewSatParameters(const std::string ¶ms) { +std::function NewSatParameters( + const std::string ¶ms) { sat::SatParameters parameters; if (!params.empty()) { CHECK(google::protobuf::TextFormat::ParseFromString(params, ¶meters)) @@ -965,19 +929,18 @@ NewSatParameters(const std::string ¶ms) { } return NewSatParameters(parameters); } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ -std::function -NewSatParameters(const sat::SatParameters ¶meters) { - return[ = ](Model *model) { +std::function NewSatParameters( + const sat::SatParameters ¶meters) { + return [=](Model *model) { // Tricky: It is important to initialize the model parameters before any // of the solver object are created, so that by default they use the given // parameters. *model->GetOrCreate() = parameters; model->GetOrCreate()->SetParameters(parameters); return parameters; - } - ; + }; } namespace { @@ -991,7 +954,7 @@ void RegisterVariableBoundsLevelZeroExport( int saved_trail_index = 0; const auto broadcast_level_zero_bounds = [&model_proto, saved_trail_index, model, shared_bounds_manager]( - const std::vector & modified_vars) mutable { + const std::vector &modified_vars) mutable { CpModelMapping *const mapping = model->GetOrCreate(); std::vector model_variables; @@ -1058,8 +1021,7 @@ void RegisterVariableBoundsLevelZeroExport( if (!model->Get()->interleave_search()) { shared_bounds_manager->Synchronize(); } - } - ; + }; model->GetOrCreate() ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds); @@ -1088,8 +1050,7 @@ void RegisterVariableBoundsLevelZeroImport( const int model_var = model_variables[i]; // This can happen if a boolean variables is forced to have an // integer view in one thread, and not in another thread. - if (!mapping->IsInteger(model_var)) - continue; + if (!mapping->IsInteger(model_var)) continue; const IntegerVariable var = mapping->Integer(model_var); const IntegerValue new_lb(new_lower_bounds[i]); const IntegerValue new_ub(new_upper_bounds[i]); @@ -1097,8 +1058,7 @@ void RegisterVariableBoundsLevelZeroImport( const IntegerValue old_ub = integer_trail->UpperBound(var); const bool changed_lb = new_lb > old_lb; const bool changed_ub = new_ub < old_ub; - if (!changed_lb && !changed_ub) - continue; + if (!changed_lb && !changed_ub) continue; new_bounds_have_been_imported = true; if (VLOG_IS_ON(3)) { @@ -1114,17 +1074,13 @@ void RegisterVariableBoundsLevelZeroImport( } if (changed_lb && - !integer_trail->Enqueue(IntegerLiteral::GreaterOrEqual(var, new_lb), { - }, - { - })) { + !integer_trail->Enqueue(IntegerLiteral::GreaterOrEqual(var, new_lb), + {}, {})) { return false; } if (changed_ub && - !integer_trail->Enqueue(IntegerLiteral::LowerOrEqual(var, new_ub), { - }, - { - })) { + !integer_trail->Enqueue(IntegerLiteral::LowerOrEqual(var, new_ub), {}, + {})) { return false; } } @@ -1133,22 +1089,20 @@ void RegisterVariableBoundsLevelZeroImport( return false; } return true; - } - ; - model->GetOrCreate()->callbacks - .push_back(import_level_zero_bounds); + }; + model->GetOrCreate()->callbacks.push_back( + import_level_zero_bounds); } // Registers a callback that will report improving objective best bound. // It will be called each time new objective bound are propagated at level zero. -void -RegisterObjectiveBestBoundExport(IntegerVariable objective_var, - SharedResponseManager *shared_response_manager, - Model *model) { +void RegisterObjectiveBestBoundExport( + IntegerVariable objective_var, + SharedResponseManager *shared_response_manager, Model *model) { auto *integer_trail = model->Get(); const auto broadcast_objective_lower_bound = - [objective_var, integer_trail, shared_response_manager, model]( - const std::vector & unused) { + [objective_var, integer_trail, shared_response_manager, + model](const std::vector &unused) { shared_response_manager->UpdateInnerObjectiveBounds( model->Name(), integer_trail->LevelZeroLowerBound(objective_var), integer_trail->LevelZeroUpperBound(objective_var)); @@ -1156,8 +1110,7 @@ RegisterObjectiveBestBoundExport(IntegerVariable objective_var, if (!model->Get()->interleave_search()) { shared_response_manager->Synchronize(); } - } - ; + }; model->GetOrCreate() ->RegisterLevelZeroModifiedVariablesCallback( broadcast_objective_lower_bound); @@ -1166,17 +1119,15 @@ RegisterObjectiveBestBoundExport(IntegerVariable objective_var, // Registers a callback to import new objective bounds. It will be called each // time the search main loop is back to level zero. Note that it the presence of // assumptions, this will not happen until the set of assumptions is changed. -void -RegisterObjectiveBoundsImport(SharedResponseManager *shared_response_manager, - Model *model) { +void RegisterObjectiveBoundsImport( + SharedResponseManager *shared_response_manager, Model *model) { auto *solver = model->GetOrCreate(); auto *integer_trail = model->GetOrCreate(); auto *objective = model->GetOrCreate(); const std::string name = model->Name(); - const auto import_objective_bounds = - [name, solver, integer_trail, objective, shared_response_manager]() { - if (solver->AssumptionLevel() != 0) - return true; + const auto import_objective_bounds = [name, solver, integer_trail, objective, + shared_response_manager]() { + if (solver->AssumptionLevel() != 0) return true; bool propagate = false; const IntegerValue external_lb = @@ -1186,10 +1137,7 @@ RegisterObjectiveBoundsImport(SharedResponseManager *shared_response_manager, if (external_lb > current_lb) { if (!integer_trail->Enqueue(IntegerLiteral::GreaterOrEqual( objective->objective_var, external_lb), - { - }, - { - })) { + {}, {})) { return false; } propagate = true; @@ -1202,17 +1150,13 @@ RegisterObjectiveBoundsImport(SharedResponseManager *shared_response_manager, if (external_ub < current_ub) { if (!integer_trail->Enqueue(IntegerLiteral::LowerOrEqual( objective->objective_var, external_ub), - { - }, - { - })) { + {}, {})) { return false; } propagate = true; } - if (!propagate) - return true; + if (!propagate) return true; VLOG(2) << "'" << name << "' imports objective bounds: external [" << objective->ScaleIntegerObjective(external_lb) << ", " @@ -1221,11 +1165,10 @@ RegisterObjectiveBoundsImport(SharedResponseManager *shared_response_manager, << objective->ScaleIntegerObjective(current_ub) << "]"; return solver->FinishPropagation(); - } - ; + }; - model->GetOrCreate()->callbacks - .push_back(import_objective_bounds); + model->GetOrCreate()->callbacks.push_back( + import_objective_bounds); } void LoadBaseModel(const CpModelProto &model_proto, @@ -1239,8 +1182,7 @@ void LoadBaseModel(const CpModelProto &model_proto, sat_solver->NotifyThatModelIsUnsat(); shared_response_manager->NotifyThatImprovingProblemIsInfeasible( absl::StrCat(model->Name(), " [loading]")); - } - ; + }; // We will add them all at once after model_proto is loaded. model->GetOrCreate()->DisableImplicationBetweenLiteral(); @@ -1257,8 +1199,7 @@ void LoadBaseModel(const CpModelProto &model_proto, mapping->PropagateEncodingFromEquivalenceRelations(model_proto, model); // Check the model is still feasible before continuing. - if (sat_solver->IsModelUnsat()) - return unsat(); + if (sat_solver->IsModelUnsat()) return unsat(); // Force some variables to be fully encoded. MaybeFullyEncodeMoreVariables(model_proto, model); @@ -1312,8 +1253,7 @@ void LoadBaseModel(const CpModelProto &model_proto, model->GetOrCreate() ->AddAllImplicationsBetweenAssociatedLiterals(); - if (!sat_solver->FinishPropagation()) - return unsat(); + if (!sat_solver->FinishPropagation()) return unsat(); } void LoadFeasibilityPump(const CpModelProto &model_proto, @@ -1325,15 +1265,13 @@ void LoadFeasibilityPump(const CpModelProto &model_proto, auto *mapping = model->GetOrCreate(); const SatParameters ¶meters = *(model->GetOrCreate()); - if (parameters.linearization_level() == 0) - return; + if (parameters.linearization_level() == 0) return; // Add linear constraints to Feasibility Pump. const LinearRelaxation relaxation = ComputeLinearRelaxation( model_proto, parameters.linearization_level(), model); const int num_lp_constraints = relaxation.linear_constraints.size(); - if (num_lp_constraints == 0) - return; + if (num_lp_constraints == 0) return; auto *feasibility_pump = model->GetOrCreate(); for (int i = 0; i < num_lp_constraints; i++) { feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]); @@ -1365,8 +1303,7 @@ void LoadCpModel(const CpModelProto &model_proto, sat_solver->NotifyThatModelIsUnsat(); shared_response_manager->NotifyThatImprovingProblemIsInfeasible( absl::StrCat(model->Name(), " [loading]")); - } - ; + }; auto *mapping = model->GetOrCreate(); const SatParameters ¶meters = *(model->GetOrCreate()); @@ -1379,20 +1316,19 @@ void LoadCpModel(const CpModelProto &model_proto, parameters.auto_detect_greater_than_at_least_one_of()) { model->Mutable() ->AddGreaterThanAtLeastOneOfConstraints(model); - if (!sat_solver->FinishPropagation()) - return unsat(); + if (!sat_solver->FinishPropagation()) return unsat(); } // TODO(user): This should be done in the presolve instead. // TODO(user): We don't have a good deterministic time on all constraints, // so this might take more time than wanted. if (parameters.cp_model_probing_level() > 1) { - ProbeBooleanVariables(/*deterministic_time_limit=*/ 1.0, model); + ProbeBooleanVariables(/*deterministic_time_limit=*/1.0, model); if (model->GetOrCreate()->IsModelUnsat()) { return unsat(); } if (!model->GetOrCreate() - ->ComputeTransitiveReduction()) { + ->ComputeTransitiveReduction()) { return unsat(); } } @@ -1445,8 +1381,8 @@ void LoadCpModel(const CpModelProto &model_proto, const int ref = objective_proto.vars(i); if (mapping->IsInteger(ref)) { const IntegerVariable var = mapping->Integer(objective_proto.vars(i)); - objective_definition->objective_impacting_variables - .insert(objective_proto.coeffs(i) > 0 ? var : NegationOf(var)); + objective_definition->objective_impacting_variables.insert( + objective_proto.coeffs(i) > 0 ? var : NegationOf(var)); } } @@ -1459,15 +1395,16 @@ void LoadCpModel(const CpModelProto &model_proto, // Intersect the objective domain with the given one if any. if (!model_proto.objective().domain().empty()) { const Domain user_domain = ReadDomainFromProto(model_proto.objective()); - const Domain automatic_domain = model->GetOrCreate() - ->InitialVariableDomain(objective_var); + const Domain automatic_domain = + model->GetOrCreate()->InitialVariableDomain( + objective_var); VLOG(3) << "Objective offset:" << model_proto.objective().offset() << " scaling_factor:" << model_proto.objective().scaling_factor(); VLOG(3) << "Automatic internal objective domain: " << automatic_domain; VLOG(3) << "User specified internal objective domain: " << user_domain; CHECK_NE(objective_var, kNoIntegerVariable); - const bool ok = model->GetOrCreate() - ->UpdateInitialDomain(objective_var, user_domain); + const bool ok = model->GetOrCreate()->UpdateInitialDomain( + objective_var, user_domain); if (!ok) { VLOG(2) << "UNSAT due to the objective domain."; return unsat(); @@ -1496,8 +1433,7 @@ void LoadCpModel(const CpModelProto &model_proto, // Note that we do one last propagation at level zero once all the // constraints were added. - if (!sat_solver->FinishPropagation()) - return unsat(); + if (!sat_solver->FinishPropagation()) return unsat(); if (model_proto.has_objective()) { // Report the initial objective variable bounds. @@ -1571,14 +1507,13 @@ void LoadCpModel(const CpModelProto &model_proto, // TODO(user): Remove code duplication with the solution_observer in // SolveLoadedCpModel(). const std::string solution_info = model->Name(); - const auto solution_observer = - [&model_proto, model, solution_info, shared_response_manager]() { + const auto solution_observer = [&model_proto, model, solution_info, + shared_response_manager]() { CpSolverResponse response; FillSolutionInResponse(model_proto, *model, &response); response.set_solution_info(solution_info); shared_response_manager->NewSolution(response, model); - } - ; + }; const auto &objective = *model->GetOrCreate(); CoreBasedOptimizer *core = @@ -1598,18 +1533,16 @@ void LoadCpModel(const CpModelProto &model_proto, void SolveLoadedCpModel(const CpModelProto &model_proto, SharedResponseManager *shared_response_manager, Model *model) { - if (shared_response_manager->ProblemIsSolved()) - return; + if (shared_response_manager->ProblemIsSolved()) return; const std::string &solution_info = model->Name(); - const auto solution_observer = - [&model_proto, &model, &solution_info, &shared_response_manager]() { + const auto solution_observer = [&model_proto, &model, &solution_info, + &shared_response_manager]() { CpSolverResponse response; FillSolutionInResponse(model_proto, *model, &response); response.set_solution_info(solution_info); shared_response_manager->NewSolution(response, model); - } - ; + }; // Reconfigure search heuristic if it was changed. ConfigureSearchHeuristics(model); @@ -1621,11 +1554,9 @@ void SolveLoadedCpModel(const CpModelProto &model_proto, while (true) { status = ResetAndSolveIntegerProblem( mapping.Literals(model_proto.assumptions()), model); - if (status != SatSolver::Status::FEASIBLE) - break; + if (status != SatSolver::Status::FEASIBLE) break; solution_observer(); - if (!parameters.enumerate_all_solutions()) - break; + if (!parameters.enumerate_all_solutions()) break; model->Add(ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack()); } if (status == SatSolver::INFEASIBLE) { @@ -1696,10 +1627,8 @@ void SolveLoadedCpModel(const CpModelProto &model_proto, void QuickSolveWithHint(const CpModelProto &model_proto, SharedResponseManager *shared_response_manager, Model *model) { - if (!model_proto.has_solution_hint()) - return; - if (shared_response_manager->ProblemIsSolved()) - return; + if (!model_proto.has_solution_hint()) return; + if (shared_response_manager->ProblemIsSolved()) return; // Temporarily change the parameters. auto *parameters = model->GetOrCreate(); @@ -1707,9 +1636,8 @@ void QuickSolveWithHint(const CpModelProto &model_proto, parameters->set_max_number_of_conflicts(parameters->hint_conflict_limit()); parameters->set_search_branching(SatParameters::HINT_SEARCH); parameters->set_optimize_with_core(false); - auto cleanup = ::absl::MakeCleanup([parameters, saved_params]() { - *parameters = saved_params; - }); + auto cleanup = ::absl::MakeCleanup( + [parameters, saved_params]() { *parameters = saved_params; }); // Solve decision problem. ConfigureSearchHeuristics(model); @@ -1738,10 +1666,7 @@ void QuickSolveWithHint(const CpModelProto &model_proto, IntegerLiteral::LowerOrEqual( objective_var, shared_response_manager->GetInnerObjectiveUpperBound()), - { - }, - { - })) { + {}, {})) { shared_response_manager->NotifyThatImprovingProblemIsInfeasible( absl::StrCat(solution_info, " [hint]")); shared_response_manager->SetStatsFromModel(model); @@ -1760,17 +1685,14 @@ void MinimizeL1DistanceWithHint(const CpModelProto &model_proto, SharedTimeLimit *shared_time_limit, Model *model) { Model local_model; - if (!model_proto.has_solution_hint()) - return; - if (shared_response_manager->ProblemIsSolved()) - return; + if (!model_proto.has_solution_hint()) return; + if (shared_response_manager->ProblemIsSolved()) return; auto *parameters = local_model.GetOrCreate(); // TODO(user): As of now the repair hint doesn't support when // enumerate_all_solutions is set since the solution is created on a different // model. - if (parameters->enumerate_all_solutions()) - return; + if (parameters->enumerate_all_solutions()) return; // Change the parameters. const SatParameters saved_params = *model->GetOrCreate(); @@ -1792,7 +1714,8 @@ void MinimizeL1DistanceWithHint(const CpModelProto &model_proto, IntegerVariableProto *var_proto = updated_model_proto.add_variables(); const int64 min_domain = model_proto.variables(var).domain(0) - value; const int64 max_domain = model_proto.variables(var).domain( - model_proto.variables(var).domain_size() - 1) - value; + model_proto.variables(var).domain_size() - 1) - + value; var_proto->add_domain(min_domain); var_proto->add_domain(max_domain); @@ -1819,15 +1742,15 @@ void MinimizeL1DistanceWithHint(const CpModelProto &model_proto, updated_model_proto.add_constraints(); abs_constraint_proto->mutable_int_max()->set_target(abs_var_index); abs_constraint_proto->mutable_int_max()->add_vars(new_var_index); - abs_constraint_proto->mutable_int_max() - ->add_vars(NegatedRef(new_var_index)); + abs_constraint_proto->mutable_int_max()->add_vars( + NegatedRef(new_var_index)); updated_model_proto.mutable_objective()->add_vars(abs_var_index); updated_model_proto.mutable_objective()->add_coeffs(1); } SharedResponseManager local_response_manager( - /*log_updates=*/ false, parameters->enumerate_all_solutions(), + /*log_updates=*/false, parameters->enumerate_all_solutions(), &updated_model_proto, wall_timer, shared_time_limit); local_model.Register(&local_response_manager); @@ -1884,10 +1807,11 @@ void PostsolveResponseWithFullSolver( } for (int i = 0; i < response->solution_lower_bounds_size(); ++i) { auto *var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]); - FillDomainInProto(ReadDomainFromProto(*var_proto).IntersectionWith({ - response->solution_lower_bounds(i), response->solution_upper_bounds(i) - }), - var_proto); + FillDomainInProto( + ReadDomainFromProto(*var_proto) + .IntersectionWith({response->solution_lower_bounds(i), + response->solution_upper_bounds(i)}), + var_proto); } // Postosolve parameters. @@ -1904,8 +1828,8 @@ void PostsolveResponseWithFullSolver( std::unique_ptr time_limit(TimeLimit::Infinite()); SharedTimeLimit shared_time_limit(time_limit.get()); SharedResponseManager local_response_manager( - /*log_updates=*/ false, /*enumerate_all_solutions=*/ false, - &mapping_proto, wall_timer, &shared_time_limit); + /*log_updates=*/false, /*enumerate_all_solutions=*/false, &mapping_proto, + wall_timer, &shared_time_limit); LoadCpModel(mapping_proto, &local_response_manager, &postsolve_model); SolveLoadedCpModel(mapping_proto, &local_response_manager, &postsolve_model); const CpSolverResponse postsolve_response = @@ -1965,20 +1889,18 @@ CpSolverResponse SolvePureSatModel(const CpModelProto &model_proto, CHECK_OK(file::Open(absl::GetFlag(FLAGS_drat_output), "w", &output, file::Defaults())); drat_proof_handler = absl::make_unique( - /*in_binary_format=*/ false, output, absl::GetFlag(FLAGS_drat_check)); + /*in_binary_format=*/false, output, absl::GetFlag(FLAGS_drat_check)); } else { drat_proof_handler = absl::make_unique(); } solver->SetDratProofHandler(drat_proof_handler.get()); } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ auto get_literal = [](int ref) { - if (ref >= 0) - return Literal(BooleanVariable(ref), true); + if (ref >= 0) return Literal(BooleanVariable(ref), true); return Literal(BooleanVariable(NegatedRef(ref)), false); - } - ; + }; std::vector temp; const int num_variables = model_proto.variables_size(); @@ -1993,9 +1915,7 @@ CpSolverResponse SolvePureSatModel(const CpModelProto &model_proto, if (domain.IsFixed()) { const Literal ref_literal = domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref); - drat_proof_handler->AddProblemClause({ - ref_literal - }); + drat_proof_handler->AddProblemClause({ref_literal}); } } for (const ConstraintProto &ct : model_proto.constraints()) { @@ -2003,18 +1923,14 @@ CpSolverResponse SolvePureSatModel(const CpModelProto &model_proto, case ConstraintProto::ConstraintCase::kBoolAnd: { if (ct.enforcement_literal_size() == 0) { for (const int ref : ct.bool_and().literals()) { - drat_proof_handler->AddProblemClause({ - get_literal(ref) - }); + drat_proof_handler->AddProblemClause({get_literal(ref)}); } } else { // a => b const Literal not_a = get_literal(ct.enforcement_literal(0)).Negated(); for (const int ref : ct.bool_and().literals()) { - drat_proof_handler->AddProblemClause({ - not_a, get_literal(ref) - }); + drat_proof_handler->AddProblemClause({not_a, get_literal(ref)}); } } break; @@ -2046,9 +1962,7 @@ CpSolverResponse SolvePureSatModel(const CpModelProto &model_proto, get_literal(ct.enforcement_literal(0)).Negated(); for (const int ref : ct.bool_and().literals()) { const Literal b = get_literal(ref); - solver->AddProblemClause({ - not_a, b - }); + solver->AddProblemClause({not_a, b}); } } break; @@ -2175,10 +2089,8 @@ struct SharedClasses { SharedIncompleteSolutionManager *incomplete_solutions; bool SearchIsDone() { - if (response->ProblemIsSolved()) - return true; - if (time_limit->LimitReached()) - return true; + if (response->ProblemIsSolved()) return true; + if (time_limit->LimitReached()) return true; return false; } }; @@ -2189,12 +2101,14 @@ class FullProblemSolver : public SubSolver { FullProblemSolver(const std::string &name, const SatParameters &local_parameters, bool split_in_chunks, SharedClasses *shared) - : SubSolver(name), shared_(shared), split_in_chunks_(split_in_chunks), + : SubSolver(name), + shared_(shared), + split_in_chunks_(split_in_chunks), local_model_(absl::make_unique(name)) { // Setup the local model parameters and time limit. local_model_->Add(NewSatParameters(local_parameters)); - shared_->time_limit - ->UpdateLocalLimit(local_model_->GetOrCreate()); + shared_->time_limit->UpdateLocalLimit( + local_model_->GetOrCreate()); if (shared->response != nullptr) { local_model_->Register(shared->response); @@ -2224,8 +2138,7 @@ class FullProblemSolver : public SubSolver { } bool TaskIsAvailable() override { - if (shared_->SearchIsDone()) - return false; + if (shared_->SearchIsDone()) return false; absl::MutexLock mutex_lock(&mutex_); return previous_task_is_completed_; @@ -2236,8 +2149,8 @@ class FullProblemSolver : public SubSolver { absl::MutexLock mutex_lock(&mutex_); previous_task_is_completed_ = false; } - return[this]() { if (solving_first_chunk_) - { + return [this]() { + if (solving_first_chunk_) { LoadCpModel(*shared_->model_proto, shared_->response, local_model_.get()); if (local_model_->GetOrCreate()->repair_hint()) { @@ -2297,20 +2210,19 @@ class FullProblemSolver : public SubSolver { // might not be done at all, for instance this might have been configured // with stop_after_first_solution. local_model_.reset(); - } - ; + }; } - // TODO(user): A few of the information sharing we do between threads does - // not - // happen here (bound sharing, RINS neighborhood, objective). Fix that so - // we - // can have a deterministic parallel mode. - void Synchronize() override { + // TODO(user): A few of the information sharing we do between threads does + // not + // happen here (bound sharing, RINS neighborhood, objective). Fix that so + // we + // can have a deterministic parallel mode. + void Synchronize() override { absl::MutexLock mutex_lock(&mutex_); deterministic_time_ += deterministic_time_since_last_synchronize_; - shared_->time_limit - ->AdvanceDeterministicTime(deterministic_time_since_last_synchronize_); + shared_->time_limit->AdvanceDeterministicTime( + deterministic_time_since_last_synchronize_); deterministic_time_since_last_synchronize_ = 0.0; } @@ -2333,12 +2245,13 @@ class FeasibilityPumpSolver : public SubSolver { public: FeasibilityPumpSolver(const SatParameters &local_parameters, SharedClasses *shared) - : SubSolver("feasibility_pump"), shared_(shared), + : SubSolver("feasibility_pump"), + shared_(shared), local_model_(absl::make_unique(name_)) { // Setup the local model parameters and time limit. local_model_->Add(NewSatParameters(local_parameters)); - shared_->time_limit - ->UpdateLocalLimit(local_model_->GetOrCreate()); + shared_->time_limit->UpdateLocalLimit( + local_model_->GetOrCreate()); if (shared->response != nullptr) { local_model_->Register(shared->response); @@ -2366,16 +2279,16 @@ class FeasibilityPumpSolver : public SubSolver { } bool TaskIsAvailable() override { - if (shared_->SearchIsDone()) - return false; + if (shared_->SearchIsDone()) return false; absl::MutexLock mutex_lock(&mutex_); return previous_task_is_completed_; } std::function GenerateTask(int64 task_id) override { - return[this]() { { absl::MutexLock mutex_lock(&mutex_); - if (!previous_task_is_completed_) - return; + return [this]() { + { + absl::MutexLock mutex_lock(&mutex_); + if (!previous_task_is_completed_) return; previous_task_is_completed_ = false; } { @@ -2385,8 +2298,7 @@ class FeasibilityPumpSolver : public SubSolver { local_model_.get()); // No new task will be scheduled for this worker if there is no // linear relaxation. - if (local_model_->Get() == nullptr) - return; + if (local_model_->Get() == nullptr) return; solving_first_chunk_ = false; // Abort first chunk and allow to schedule the next. previous_task_is_completed_ = true; @@ -2413,7 +2325,7 @@ class FeasibilityPumpSolver : public SubSolver { return; } - absl::MutexLock mutex_lock (&mutex_); + absl::MutexLock mutex_lock(&mutex_); previous_task_is_completed_ = true; }; } @@ -2421,8 +2333,8 @@ class FeasibilityPumpSolver : public SubSolver { void Synchronize() override { absl::MutexLock mutex_lock(&mutex_); deterministic_time_ += deterministic_time_since_last_synchronize_; - shared_->time_limit - ->AdvanceDeterministicTime(deterministic_time_since_last_synchronize_); + shared_->time_limit->AdvanceDeterministicTime( + deterministic_time_since_last_synchronize_); deterministic_time_since_last_synchronize_ = 0.0; } @@ -2439,8 +2351,7 @@ class FeasibilityPumpSolver : public SubSolver { double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) = 0.0; bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) = true; -} -; +}; // A Subsolver that generate LNS solve from a given neighborhood. class LnsSolver : public SubSolver { @@ -2448,25 +2359,27 @@ class LnsSolver : public SubSolver { LnsSolver(std::unique_ptr generator, const SatParameters ¶meters, NeighborhoodGeneratorHelper *helper, SharedClasses *shared) - : SubSolver(generator->name()), generator_(std::move(generator)), - helper_(helper), parameters_(parameters), shared_(shared) {} + : SubSolver(generator->name()), + generator_(std::move(generator)), + helper_(helper), + parameters_(parameters), + shared_(shared) {} bool TaskIsAvailable() override { - if (shared_->SearchIsDone()) - return false; + if (shared_->SearchIsDone()) return false; return generator_->ReadyToGenerate(); } std::function GenerateTask(int64 task_id) override { - return[task_id, this]() { if (shared_->SearchIsDone()) return; + return [task_id, this]() { + if (shared_->SearchIsDone()) return; // Create a random number generator whose seed depends both on the task_id // and on the parameters_.random_seed() so that changing the later will // change the LNS behavior. const int32 low = static_cast(task_id); const int32 high = task_id >> 32; - std::seed_seq seed { low, high, parameters_.random_seed() } - ; + std::seed_seq seed{low, high, parameters_.random_seed()}; random_engine_t random(seed); NeighborhoodGenerator::SolveData data; @@ -2510,16 +2423,12 @@ class LnsSolver : public SubSolver { generator_->Generate(base_response, data.difficulty, &random); } neighborhood.cp_model.set_name(absl::StrCat("lns_", task_id)); - if (!neighborhood.is_generated) - return; + if (!neighborhood.is_generated) return; data.neighborhood_id = neighborhood.id; const double fully_solved_proportion = static_cast(generator_->num_fully_solved_calls()) / - std::max(int64 { - 1 - }, - generator_->num_calls()); + std::max(int64{1}, generator_->num_calls()); std::string source_info = name(); if (!neighborhood.source_info.empty()) { absl::StrAppend(&source_info, "_", neighborhood.source_info); @@ -2568,7 +2477,7 @@ class LnsSolver : public SubSolver { // parameters that work bests (core, linearization_level, etc...) or // maybe we can just randomize them like for the base solution used. SharedResponseManager local_response_manager( - /*log_updates=*/ false, /*enumerate_all_solutions=*/ false, + /*log_updates=*/false, /*enumerate_all_solutions=*/false, &neighborhood.cp_model, shared_->wall_timer, shared_->time_limit); LoadCpModel(neighborhood.cp_model, &local_response_manager, &local_model); QuickSolveWithHint(neighborhood.cp_model, &local_response_manager, @@ -2618,7 +2527,8 @@ class LnsSolver : public SubSolver { // Update the bound. const IntegerValue new_inner_obj_lb = IntegerValue( std::ceil(UnscaleObjectiveValue(shared_->model_proto->objective(), - scaled_local_obj_bound) - 1e-6)); + scaled_local_obj_bound) - + 1e-6)); data.new_objective_bound = new_inner_obj_lb; data.initial_best_objective_bound = current_obj_lb; if (new_inner_obj_lb > current_obj_lb) { @@ -2634,7 +2544,7 @@ class LnsSolver : public SubSolver { *shared_->model_proto, std::vector(local_response.solution().begin(), local_response.solution().end()))) { - shared_->response->NewSolution(local_response, /*model=*/ nullptr); + shared_->response->NewSolution(local_response, /*model=*/nullptr); // Mark the solution optimal if the relaxation status is optimal. if (local_response.status() == CpSolverStatus::OPTIMAL) { @@ -2665,7 +2575,7 @@ class LnsSolver : public SubSolver { // Report any feasible solution we have. if (local_response.status() == CpSolverStatus::OPTIMAL || local_response.status() == CpSolverStatus::FEASIBLE) { - shared_->response->NewSolution(local_response, /*model=*/ nullptr); + shared_->response->NewSolution(local_response, /*model=*/nullptr); } if (!neighborhood.is_reduced && (local_response.status() == CpSolverStatus::OPTIMAL || @@ -2688,9 +2598,9 @@ class LnsSolver : public SubSolver { << ", num calls: " << generator_->num_calls() << ", UCB1 Score: " << generator_->GetUCBScore(total_num_calls) << ", p: " << fully_solved_proportion << "]"; - } - ; - } void Synchronize() override { + }; + } + void Synchronize() override { generator_->Synchronize(); const double old = deterministic_time_; deterministic_time_ = generator_->deterministic_time(); @@ -2702,8 +2612,7 @@ class LnsSolver : public SubSolver { NeighborhoodGeneratorHelper *helper_; const SatParameters parameters_; SharedClasses *shared_; -} -; +}; void SolveCpModelParallel(const CpModelProto &model_proto, SharedResponseManager *shared_response_manager, @@ -2726,22 +2635,22 @@ void SolveCpModelParallel(const CpModelProto &model_proto, if (parameters.use_relaxation_lns()) { shared_relaxation_solutions = absl::make_unique( - /*num_solutions_to_keep=*/ 10); + /*num_solutions_to_keep=*/10); global_model->Register( shared_relaxation_solutions.get()); } auto shared_lp_solutions = absl::make_unique( - /*num_solutions_to_keep=*/ 10); + /*num_solutions_to_keep=*/10); global_model->Register(shared_lp_solutions.get()); // We currently only use the feasiblity pump if it is enabled and some other // parameters are not on. std::unique_ptr shared_incomplete_solutions; - const bool use_feasibility_pump = - parameters.use_feasibility_pump() && - parameters.linearization_level() > 0 && !parameters.use_lns_only() && - !parameters.interleave_search(); + const bool use_feasibility_pump = parameters.use_feasibility_pump() && + parameters.linearization_level() > 0 && + !parameters.use_lns_only() && + !parameters.interleave_search(); if (use_feasibility_pump) { shared_incomplete_solutions = absl::make_unique(); @@ -2777,7 +2686,7 @@ void SolveCpModelParallel(const CpModelProto &model_proto, if (shared_lp_solutions != nullptr) { shared_lp_solutions->Synchronize(); } - })); + })); if (parameters.use_lns_only()) { // Register something to find a first solution. Note that this is mainly @@ -2787,17 +2696,16 @@ void SolveCpModelParallel(const CpModelProto &model_proto, local_params.set_stop_after_first_solution(true); local_params.set_linearization_level(0); subsolvers.push_back(absl::make_unique( - "first_solution", local_params, /*split_in_chunks=*/ false, &shared)); + "first_solution", local_params, /*split_in_chunks=*/false, &shared)); } else { for (const SatParameters &local_params : GetDiverseSetOfParameters( parameters, model_proto, num_search_workers)) { // TODO(user): This is currently not supported here. - if (parameters.optimize_with_max_hs()) - continue; + if (parameters.optimize_with_max_hs()) continue; subsolvers.push_back(absl::make_unique( local_params.name(), local_params, - /*split_in_chunks=*/ parameters.interleave_search(), &shared)); + /*split_in_chunks=*/parameters.interleave_search(), &shared)); } } @@ -2864,14 +2772,14 @@ void SolveCpModelParallel(const CpModelProto &model_proto, subsolvers.push_back(absl::make_unique( absl::make_unique( helper, shared.response, shared.relaxation_solutions, - shared.lp_solutions, /*incomplete_solutions=*/ nullptr, + shared.lp_solutions, /*incomplete_solutions=*/nullptr, absl::StrCat("rins_lns_", local_params.name())), local_params, helper, &shared)); // RENS. subsolvers.push_back(absl::make_unique( absl::make_unique( - helper, /*respons_manager=*/ nullptr, shared.relaxation_solutions, + helper, /*respons_manager=*/nullptr, shared.relaxation_solutions, shared.lp_solutions, shared.incomplete_solutions, absl::StrCat("rens_lns_", local_params.name())), local_params, helper, &shared)); @@ -2897,19 +2805,18 @@ void SolveCpModelParallel(const CpModelProto &model_proto, subsolvers.push_back( absl::make_unique([shared_response_manager]() { shared_response_manager->UpdatePrimalIntegral(); - })); + })); // Log the name of all our SubSolvers. if (log_search) { std::vector names; for (const auto &subsolver : subsolvers) { - if (!subsolver->name().empty()) - names.push_back(subsolver->name()); + if (!subsolver->name().empty()) names.push_back(subsolver->name()); } - LOG(INFO) << absl::StrFormat("*** starting Search at %.2fs with %i workers " - "and subsolvers: [ %s ]", - wall_timer->Get(), num_search_workers, - absl::StrJoin(names, ", ")); + LOG(INFO) << absl::StrFormat( + "*** starting Search at %.2fs with %i workers " + "and subsolvers: [ %s ]", + wall_timer->Get(), num_search_workers, absl::StrJoin(names, ", ")); } // Launch the main search loop. @@ -2921,7 +2828,7 @@ void SolveCpModelParallel(const CpModelProto &model_proto, } } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ // If the option use_sat_inprocessing is true, then before postsolving a // solution, we need to make sure we add any new clause required for postsolving @@ -2942,7 +2849,7 @@ void AddPostsolveClauses(const std::vector &postsolve_mapping, postsolve->clauses.clear(); } -} // namespace +} // namespace CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { WallTimer wall_timer; @@ -2984,11 +2891,9 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { // Register SIGINT handler if requested by the parameters. SigintHandler handler; if (model->GetOrCreate()->catch_sigint_signal()) { - handler.Register([&shared_time_limit]() { - shared_time_limit.Stop(); - }); + handler.Register([&shared_time_limit]() { shared_time_limit.Stop(); }); } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ const SatParameters ¶ms = *model->GetOrCreate(); const bool log_search = params.log_search_progress() || VLOG_IS_ON(1); @@ -3001,7 +2906,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { absl::MakeCleanup([&final_response, &model_proto] { LOG(INFO) << CpSolverResponseStats(final_response, model_proto.has_objective()); - }); + }); } // Validate model_proto. @@ -3057,10 +2962,9 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { } // Presolve and expansions. - LOG_IF(INFO, log_search) - << absl::StrFormat("*** starting model presolve at %.2fs", - wall_timer.Get()); - CpModelProto new_cp_model_proto = model_proto; // Copy. + LOG_IF(INFO, log_search) << absl::StrFormat( + "*** starting model presolve at %.2fs", wall_timer.Get()); + CpModelProto new_cp_model_proto = model_proto; // Copy. CpModelProto mapping_proto; PresolveOptions options; @@ -3103,19 +3007,20 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { } LOG_IF(INFO, log_search) << CpModelStats(new_cp_model_proto); if (params.cp_model_presolve()) { - postprocess_solution = - [&model_proto, ¶ms, &mapping_proto, &shared_time_limit, - &postsolve_mapping, &wall_timer, &user_timer, model](CpSolverResponse * - response) { + postprocess_solution = [&model_proto, ¶ms, &mapping_proto, + &shared_time_limit, &postsolve_mapping, &wall_timer, + &user_timer, model](CpSolverResponse *response) { AddPostsolveClauses(postsolve_mapping, model, &mapping_proto); PostsolveResponseWrapper(params, model_proto.variables_size(), mapping_proto, postsolve_mapping, &wall_timer, response); if (!response->solution().empty()) { - CHECK(SolutionIsFeasible( - model_proto, std::vector(response->solution().begin(), - response->solution().end()), - &mapping_proto, &postsolve_mapping)) << "final postsolved solution"; + CHECK( + SolutionIsFeasible(model_proto, + std::vector(response->solution().begin(), + response->solution().end()), + &mapping_proto, &postsolve_mapping)) + << "final postsolved solution"; } if (params.fill_tightened_domains_in_response()) { // TODO(user): for now, we just use the domain infered during presolve. @@ -3130,12 +3035,11 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { response->set_user_time(user_timer.Get()); response->set_deterministic_time( shared_time_limit.GetElapsedDeterministicTime()); - } - ; + }; } else { - postprocess_solution = - [&model_proto, ¶ms, &wall_timer, &shared_time_limit, &user_timer]( - CpSolverResponse * response) { + postprocess_solution = [&model_proto, ¶ms, &wall_timer, + &shared_time_limit, + &user_timer](CpSolverResponse *response) { // Truncate the solution in case model expansion added more variables. const int initial_size = model_proto.variables_size(); if (response->solution_size() > 0) { @@ -3151,8 +3055,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { response->set_user_time(user_timer.Get()); response->set_deterministic_time( shared_time_limit.GetElapsedDeterministicTime()); - } - ; + }; } // Delete the context. @@ -3170,7 +3073,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { shared_response_manager.AddSolutionCallback( [&model_proto, &observers, &wall_timer, &user_timer, &postprocess_solution, &shared_time_limit]( - const CpSolverResponse & response_of_presolved_problem) { + const CpSolverResponse &response_of_presolved_problem) { CpSolverResponse response = response_of_presolved_problem; postprocess_solution(&response); if (!response.solution().empty()) { @@ -3185,7 +3088,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { for (const auto &observer : observers) { observer(response); } - }); + }); } #if !defined(__PORTABLE_PLATFORM__) @@ -3202,7 +3105,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { LOG(INFO) << "Dumping mapping cp model proto to '" << mapping_file << "'."; CHECK_OK(file::SetTextProto(mapping_file, mapping_proto, file::Defaults())); } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ if (params.stop_after_presolve() || shared_time_limit.LimitReached()) { int64 num_terms = 0; @@ -3225,20 +3128,21 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { // Make sure everything stops when we have a first solution if requested. if (params.stop_after_first_solution()) { - shared_response_manager.AddSolutionCallback([&shared_time_limit]( - const CpSolverResponse & response_of_presolved_problem) { + shared_response_manager.AddSolutionCallback( + [&shared_time_limit]( + const CpSolverResponse &response_of_presolved_problem) { shared_time_limit.Stop(); - }); + }); } #if defined(__PORTABLE_PLATFORM__) - if (/* DISABLES CODE */(false)) { + if (/* DISABLES CODE */ (false)) { // We ignore the multithreading parameter in this case. -#else // __PORTABLE_PLATFORM__ +#else // __PORTABLE_PLATFORM__ if (params.num_search_workers() > 1 || params.interleave_search()) { SolveCpModelParallel(new_cp_model_proto, &shared_response_manager, &shared_time_limit, &wall_timer, model); -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ } else { if (log_search) { LOG(INFO) << absl::StrFormat("*** starting to load the model at %.2fs", @@ -3249,8 +3153,8 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { if (log_search) { LOG(INFO) << absl::StrFormat("*** starting sequential search at %.2fs", wall_timer.Get()); - LOG(INFO) - << "Initial num_bool: " << model->Get()->NumVariables(); + LOG(INFO) << "Initial num_bool: " + << model->Get()->NumVariables(); } if (params.repair_hint()) { MinimizeL1DistanceWithHint(new_cp_model_proto, &shared_response_manager, @@ -3277,26 +3181,26 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model) { return final_response; } -CpSolverResponse Solve(const CpModelProto & model_proto) { +CpSolverResponse Solve(const CpModelProto &model_proto) { Model model; return SolveCpModel(model_proto, &model); } -CpSolverResponse SolveWithParameters(const CpModelProto & model_proto, - const SatParameters & params) { +CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, + const SatParameters ¶ms) { Model model; model.Add(NewSatParameters(params)); return SolveCpModel(model_proto, &model); } #if !defined(__PORTABLE_PLATFORM__) -CpSolverResponse SolveWithParameters(const CpModelProto & model_proto, - const std::string & params) { +CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, + const std::string ¶ms) { Model model; model.Add(NewSatParameters(params)); return SolveCpModel(model_proto, &model); } -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_solver.h b/ortools/sat/cp_model_solver.h index 19fcf60146..bb04deabd8 100644 --- a/ortools/sat/cp_model_solver.h +++ b/ortools/sat/cp_model_solver.h @@ -65,7 +65,7 @@ CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model); */ CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, const std::string ¶ms); -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ /** * Creates a solution observer with the model with @@ -100,13 +100,13 @@ void SetSynchronizationFunction(std::function f, * before calling \c SolveCpModel(). */ #if !defined(__PORTABLE_PLATFORM__) -std::function - NewSatParameters(const std::string ¶ms); -#endif // !__PORTABLE_PLATFORM__ -std::function - NewSatParameters(const SatParameters ¶meters); +std::function NewSatParameters( + const std::string ¶ms); +#endif // !__PORTABLE_PLATFORM__ +std::function NewSatParameters( + const SatParameters ¶meters); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_SOLVER_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_SOLVER_H_ diff --git a/ortools/sat/cp_model_symmetries.cc b/ortools/sat/cp_model_symmetries.cc index 3ca8d674a2..cc7ff8bb10 100644 --- a/ortools/sat/cp_model_symmetries.cc +++ b/ortools/sat/cp_model_symmetries.cc @@ -40,7 +40,7 @@ struct VectorHash { // A simple class to generate equivalence class number for // GenerateGraphForSymmetryDetection(). class IdGenerator { -public: + public: IdGenerator() {} // If the key was never seen before, then generate a new id, otherwise return @@ -49,7 +49,7 @@ public: return gtl::LookupOrInsert(&id_map_, key, id_map_.size()); } -private: + private: absl::flat_hash_map, int, VectorHash> id_map_; }; @@ -57,9 +57,9 @@ private: // // We use a template as proto int64 != C++ int64 in open source. template -void -Append(const google::protobuf::RepeatedField &repeated_field, - std::vector *vector) { +void Append( + const google::protobuf::RepeatedField &repeated_field, + std::vector *vector) { CHECK(vector != nullptr); for (const FieldInt64Type value : repeated_field) { vector->push_back(value); @@ -105,19 +105,18 @@ std::unique_ptr GenerateGraphForSymmetryDetection( problem.objective().coeffs(i); } - auto new_node = [&initial_equivalence_classes, &id_generator]( - const std::vector & key) { + auto new_node = [&initial_equivalence_classes, + &id_generator](const std::vector &key) { // Since we add nodes one by one, initial_equivalence_classes->size() gives // the number of nodes at any point, which we use as the next node index. const int node = initial_equivalence_classes->size(); initial_equivalence_classes->push_back(id_generator.GetId(key)); return node; - } - ; + }; for (int v = 0; v < num_variables; ++v) { const IntegerVariableProto &variable = problem.variables(v); - std::vector key = { VARIABLE_NODE, objective_by_var[v] }; + std::vector key = {VARIABLE_NODE, objective_by_var[v]}; Append(variable.domain(), &key); CHECK_EQ(v, new_node(key)); // Make sure the graph contains all the variable nodes, even if no edges are @@ -128,113 +127,107 @@ std::unique_ptr GenerateGraphForSymmetryDetection( auto add_edge = [&graph](int node_1, int node_2) { graph->AddArc(node_1, node_2); graph->AddArc(node_2, node_1); - } - ; + }; auto add_literal_edge = [&add_edge, &new_node](int ref, int constraint_node) { const int variable_node = PositiveRef(ref); if (RefIsPositive(ref)) { add_edge(variable_node, constraint_node); } else { - const int coefficient_node = new_node({ - CONSTRAINT_COEFFICIENT_NODE, -1 - }); + const int coefficient_node = new_node({CONSTRAINT_COEFFICIENT_NODE, -1}); add_edge(variable_node, coefficient_node); add_edge(coefficient_node, constraint_node); } - } - ; + }; // Add constraints to the graph. for (const ConstraintProto &constraint : problem.constraints()) { const int constraint_node = initial_equivalence_classes->size(); - std::vector key = { CONSTRAINT_NODE, constraint.constraint_case() }; + std::vector key = {CONSTRAINT_NODE, constraint.constraint_case()}; switch (constraint.constraint_case()) { - case ConstraintProto::kLinear: { - Append(constraint.linear().domain(), &key); - CHECK_EQ(constraint_node, new_node(key)); - - for (int i = 0; i < constraint.linear().vars_size(); ++i) { - if (constraint.linear().coeffs(i) == 0) - continue; - const int ref = constraint.linear().vars(i); - const int variable_node = PositiveRef(ref); - const int64 coeff = RefIsPositive(ref) ? constraint.linear().coeffs(i) - : -constraint.linear().coeffs(i); - if (coeff == 1) { - // For all coefficients equal to one, which are the most common, we - // can optimize the size of the graph by omitting the coefficient - // node altogether. - add_edge(variable_node, constraint_node); - } else { - const int coefficient_node = new_node({ - CONSTRAINT_COEFFICIENT_NODE, coeff - }); - - add_edge(variable_node, coefficient_node); - add_edge(coefficient_node, constraint_node); - } - } - break; - } - case ConstraintProto::kBoolOr: { - CHECK_EQ(constraint_node, new_node(key)); - for (const int ref : constraint.bool_or().literals()) { - add_literal_edge(ref, constraint_node); - } - break; - } - case ConstraintProto::kBoolXor: { - CHECK_EQ(constraint_node, new_node(key)); - for (const int ref : constraint.bool_xor().literals()) { - add_literal_edge(ref, constraint_node); - } - break; - } - case ConstraintProto::kBoolAnd: { - if (constraint.enforcement_literal_size() == 0) { - // All literals are true in this case. + case ConstraintProto::kLinear: { + Append(constraint.linear().domain(), &key); CHECK_EQ(constraint_node, new_node(key)); - for (const int ref : constraint.bool_and().literals()) { + + for (int i = 0; i < constraint.linear().vars_size(); ++i) { + if (constraint.linear().coeffs(i) == 0) continue; + const int ref = constraint.linear().vars(i); + const int variable_node = PositiveRef(ref); + const int64 coeff = RefIsPositive(ref) + ? constraint.linear().coeffs(i) + : -constraint.linear().coeffs(i); + if (coeff == 1) { + // For all coefficients equal to one, which are the most common, we + // can optimize the size of the graph by omitting the coefficient + // node altogether. + add_edge(variable_node, constraint_node); + } else { + const int coefficient_node = + new_node({CONSTRAINT_COEFFICIENT_NODE, coeff}); + + add_edge(variable_node, coefficient_node); + add_edge(coefficient_node, constraint_node); + } + } + break; + } + case ConstraintProto::kBoolOr: { + CHECK_EQ(constraint_node, new_node(key)); + for (const int ref : constraint.bool_or().literals()) { add_literal_edge(ref, constraint_node); } break; } - - // To make the BoolAnd constraint more generic in the graph, we expand - // it into a set of BoolOr constraints where - // not(enforcement_literal) OR literal = true - // for all constraint's literals. This is equivalent to - // enforcement_literal => literal - // for all literals. - std::vector key = { CONSTRAINT_NODE, ConstraintProto::kBoolOr }; - const int non_enforcement_literal = - NegatedRef(constraint.enforcement_literal(0)); - for (const int literal : constraint.bool_and().literals()) { - const int constraint_node = new_node(key); - add_literal_edge(non_enforcement_literal, constraint_node); - add_literal_edge(literal, constraint_node); + case ConstraintProto::kBoolXor: { + CHECK_EQ(constraint_node, new_node(key)); + for (const int ref : constraint.bool_xor().literals()) { + add_literal_edge(ref, constraint_node); + } + break; + } + case ConstraintProto::kBoolAnd: { + if (constraint.enforcement_literal_size() == 0) { + // All literals are true in this case. + CHECK_EQ(constraint_node, new_node(key)); + for (const int ref : constraint.bool_and().literals()) { + add_literal_edge(ref, constraint_node); + } + break; + } + + // To make the BoolAnd constraint more generic in the graph, we expand + // it into a set of BoolOr constraints where + // not(enforcement_literal) OR literal = true + // for all constraint's literals. This is equivalent to + // enforcement_literal => literal + // for all literals. + std::vector key = {CONSTRAINT_NODE, ConstraintProto::kBoolOr}; + const int non_enforcement_literal = + NegatedRef(constraint.enforcement_literal(0)); + for (const int literal : constraint.bool_and().literals()) { + const int constraint_node = new_node(key); + add_literal_edge(non_enforcement_literal, constraint_node); + add_literal_edge(literal, constraint_node); + } + break; + } + default: { + // If the model contains any non-supported constraints, return an empty + // graph. + // TODO(user): support other types of constraints. + LOG(ERROR) << "Unsupported constraint type " + << constraint.constraint_case(); + return nullptr; } - break; - } - default: { - // If the model contains any non-supported constraints, return an empty - // graph. - // TODO(user): support other types of constraints. - LOG(ERROR) << "Unsupported constraint type " - << constraint.constraint_case(); - return nullptr; - } } if (constraint.constraint_case() != ConstraintProto::kBoolAnd && constraint.enforcement_literal_size() > 0) { const int ref = constraint.enforcement_literal(0); const int enforcement_literal_node = PositiveRef(ref); - const int enforcement_type_node = new_node({ - ENFORCEMENT_LITERAL, RefIsPositive(ref) - }); + const int enforcement_type_node = + new_node({ENFORCEMENT_LITERAL, RefIsPositive(ref)}); add_edge(constraint_node, enforcement_type_node); add_edge(enforcement_type_node, enforcement_literal_node); @@ -245,7 +238,7 @@ std::unique_ptr GenerateGraphForSymmetryDetection( DCHECK_EQ(graph->num_nodes(), initial_equivalence_classes->size()); return graph; } -} // namespace +} // namespace void FindCpModelSymmetries( const CpModelProto &problem, @@ -259,13 +252,12 @@ void FindCpModelSymmetries( std::vector equivalence_classes; std::unique_ptr graph( GenerateGraphForSymmetryDetection(problem, &equivalence_classes)); - if (graph == nullptr) - return; + if (graph == nullptr) return; LOG(INFO) << "Graph has " << graph->num_nodes() << " nodes and " << graph->num_arcs() / 2 << " edges."; - GraphSymmetryFinder symmetry_finder(*graph, /*is_undirected=*/ true); + GraphSymmetryFinder symmetry_finder(*graph, /*is_undirected=*/true); std::vector factorized_automorphism_group_size; CHECK_OK(symmetry_finder.FindSymmetries(time_limit_seconds, &equivalence_classes, generators, @@ -308,5 +300,5 @@ void FindCpModelSymmetries( LOG(INFO) << "Average support size: " << average_support_size; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_symmetries.h b/ortools/sat/cp_model_symmetries.h index d2cde52c03..d8d527965b 100644 --- a/ortools/sat/cp_model_symmetries.h +++ b/ortools/sat/cp_model_symmetries.h @@ -33,7 +33,7 @@ void FindCpModelSymmetries( std::vector > *generators, double time_limit_seconds = std::numeric_limits::infinity()); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_SYMMETRIES_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_SYMMETRIES_H_ diff --git a/ortools/sat/cp_model_utils.cc b/ortools/sat/cp_model_utils.cc index 63c4d20918..b766b85316 100644 --- a/ortools/sat/cp_model_utils.cc +++ b/ortools/sat/cp_model_utils.cc @@ -31,7 +31,7 @@ void AddIndices(const IntList &indices, std::vector *output) { output->insert(output->end(), indices.begin(), indices.end()); } -} // namespace +} // namespace void SetToNegatedLinearExpression(const LinearExpressionProto &input_expr, LinearExpressionProto *output_negated_expr) { @@ -46,397 +46,395 @@ void SetToNegatedLinearExpression(const LinearExpressionProto &input_expr, IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct) { IndexReferences output; switch (ct.constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - AddIndices(ct.bool_or().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - AddIndices(ct.bool_and().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - AddIndices(ct.at_most_one().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kBoolXor: - AddIndices(ct.bool_xor().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kIntDiv: - output.variables.push_back(ct.int_div().target()); - AddIndices(ct.int_div().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kIntMod: - output.variables.push_back(ct.int_mod().target()); - AddIndices(ct.int_mod().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kIntMax: - output.variables.push_back(ct.int_max().target()); - AddIndices(ct.int_max().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kLinMax: { - AddIndices(ct.lin_max().target().vars(), &output.variables); - for (int i = 0; i < ct.lin_max().exprs_size(); ++i) { - AddIndices(ct.lin_max().exprs(i).vars(), &output.variables); + case ConstraintProto::ConstraintCase::kBoolOr: + AddIndices(ct.bool_or().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + AddIndices(ct.bool_and().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + AddIndices(ct.at_most_one().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kBoolXor: + AddIndices(ct.bool_xor().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kIntDiv: + output.variables.push_back(ct.int_div().target()); + AddIndices(ct.int_div().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kIntMod: + output.variables.push_back(ct.int_mod().target()); + AddIndices(ct.int_mod().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kIntMax: + output.variables.push_back(ct.int_max().target()); + AddIndices(ct.int_max().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kLinMax: { + AddIndices(ct.lin_max().target().vars(), &output.variables); + for (int i = 0; i < ct.lin_max().exprs_size(); ++i) { + AddIndices(ct.lin_max().exprs(i).vars(), &output.variables); + } + break; } - break; - } - case ConstraintProto::ConstraintCase::kIntMin: - output.variables.push_back(ct.int_min().target()); - AddIndices(ct.int_min().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kLinMin: { - AddIndices(ct.lin_min().target().vars(), &output.variables); - for (int i = 0; i < ct.lin_min().exprs_size(); ++i) { - AddIndices(ct.lin_min().exprs(i).vars(), &output.variables); + case ConstraintProto::ConstraintCase::kIntMin: + output.variables.push_back(ct.int_min().target()); + AddIndices(ct.int_min().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kLinMin: { + AddIndices(ct.lin_min().target().vars(), &output.variables); + for (int i = 0; i < ct.lin_min().exprs_size(); ++i) { + AddIndices(ct.lin_min().exprs(i).vars(), &output.variables); + } + break; } - break; - } - case ConstraintProto::ConstraintCase::kIntProd: - output.variables.push_back(ct.int_prod().target()); - AddIndices(ct.int_prod().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kLinear: - AddIndices(ct.linear().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kAllDiff: - AddIndices(ct.all_diff().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kElement: - output.variables.push_back(ct.element().index()); - output.variables.push_back(ct.element().target()); - AddIndices(ct.element().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kCircuit: - AddIndices(ct.circuit().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kRoutes: - AddIndices(ct.routes().literals(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - AddIndices(ct.circuit_covering().nexts(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kInverse: - AddIndices(ct.inverse().f_direct(), &output.variables); - AddIndices(ct.inverse().f_inverse(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kReservoir: - AddIndices(ct.reservoir().times(), &output.variables); - AddIndices(ct.reservoir().actives(), &output.literals); - break; - case ConstraintProto::ConstraintCase::kTable: - AddIndices(ct.table().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kAutomaton: - AddIndices(ct.automaton().vars(), &output.variables); - break; - case ConstraintProto::ConstraintCase::kInterval: - output.variables.push_back(ct.interval().start()); - output.variables.push_back(ct.interval().end()); - output.variables.push_back(ct.interval().size()); - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - break; - case ConstraintProto::ConstraintCase::kCumulative: - output.variables.push_back(ct.cumulative().capacity()); - AddIndices(ct.cumulative().demands(), &output.variables); - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - break; + case ConstraintProto::ConstraintCase::kIntProd: + output.variables.push_back(ct.int_prod().target()); + AddIndices(ct.int_prod().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kLinear: + AddIndices(ct.linear().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kAllDiff: + AddIndices(ct.all_diff().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kElement: + output.variables.push_back(ct.element().index()); + output.variables.push_back(ct.element().target()); + AddIndices(ct.element().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kCircuit: + AddIndices(ct.circuit().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kRoutes: + AddIndices(ct.routes().literals(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + AddIndices(ct.circuit_covering().nexts(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kInverse: + AddIndices(ct.inverse().f_direct(), &output.variables); + AddIndices(ct.inverse().f_inverse(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kReservoir: + AddIndices(ct.reservoir().times(), &output.variables); + AddIndices(ct.reservoir().actives(), &output.literals); + break; + case ConstraintProto::ConstraintCase::kTable: + AddIndices(ct.table().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kAutomaton: + AddIndices(ct.automaton().vars(), &output.variables); + break; + case ConstraintProto::ConstraintCase::kInterval: + output.variables.push_back(ct.interval().start()); + output.variables.push_back(ct.interval().end()); + output.variables.push_back(ct.interval().size()); + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + break; + case ConstraintProto::ConstraintCase::kCumulative: + output.variables.push_back(ct.cumulative().capacity()); + AddIndices(ct.cumulative().demands(), &output.variables); + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + break; } return output; } -#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \ - { \ - int temp = ct->mutable_##ct_name()->field_name(); \ - f(&temp); \ - ct->mutable_##ct_name()->set_##field_name(temp); \ +#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \ + { \ + int temp = ct->mutable_##ct_name()->field_name(); \ + f(&temp); \ + ct->mutable_##ct_name()->set_##field_name(temp); \ } -#define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \ - { \ - for (int &r : *ct->mutable_##ct_name()->mutable_##field_name()) \ - f(&r); \ +#define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \ + { \ + for (int &r : *ct->mutable_##ct_name()->mutable_##field_name()) f(&r); \ } void ApplyToAllLiteralIndices(const std::function &f, ConstraintProto *ct) { - for (int &r : *ct->mutable_enforcement_literal()) - f(&r); + for (int &r : *ct->mutable_enforcement_literal()) f(&r); switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - APPLY_TO_REPEATED_FIELD(bool_or, literals); - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - APPLY_TO_REPEATED_FIELD(bool_and, literals); - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - APPLY_TO_REPEATED_FIELD(at_most_one, literals); - break; - case ConstraintProto::ConstraintCase::kBoolXor: - APPLY_TO_REPEATED_FIELD(bool_xor, literals); - break; - case ConstraintProto::ConstraintCase::kIntDiv: - break; - case ConstraintProto::ConstraintCase::kIntMod: - break; - case ConstraintProto::ConstraintCase::kIntMax: - break; - case ConstraintProto::ConstraintCase::kLinMax: - break; - case ConstraintProto::ConstraintCase::kIntMin: - break; - case ConstraintProto::ConstraintCase::kLinMin: - break; - case ConstraintProto::ConstraintCase::kIntProd: - break; - case ConstraintProto::ConstraintCase::kLinear: - break; - case ConstraintProto::ConstraintCase::kAllDiff: - break; - case ConstraintProto::ConstraintCase::kElement: - break; - case ConstraintProto::ConstraintCase::kCircuit: - APPLY_TO_REPEATED_FIELD(circuit, literals); - break; - case ConstraintProto::ConstraintCase::kRoutes: - APPLY_TO_REPEATED_FIELD(routes, literals); - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - break; - case ConstraintProto::ConstraintCase::kInverse: - break; - case ConstraintProto::ConstraintCase::kReservoir: - APPLY_TO_REPEATED_FIELD(reservoir, actives); - break; - case ConstraintProto::ConstraintCase::kTable: - break; - case ConstraintProto::ConstraintCase::kAutomaton: - break; - case ConstraintProto::ConstraintCase::kInterval: - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - break; - case ConstraintProto::ConstraintCase::kCumulative: - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - break; + case ConstraintProto::ConstraintCase::kBoolOr: + APPLY_TO_REPEATED_FIELD(bool_or, literals); + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + APPLY_TO_REPEATED_FIELD(bool_and, literals); + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + APPLY_TO_REPEATED_FIELD(at_most_one, literals); + break; + case ConstraintProto::ConstraintCase::kBoolXor: + APPLY_TO_REPEATED_FIELD(bool_xor, literals); + break; + case ConstraintProto::ConstraintCase::kIntDiv: + break; + case ConstraintProto::ConstraintCase::kIntMod: + break; + case ConstraintProto::ConstraintCase::kIntMax: + break; + case ConstraintProto::ConstraintCase::kLinMax: + break; + case ConstraintProto::ConstraintCase::kIntMin: + break; + case ConstraintProto::ConstraintCase::kLinMin: + break; + case ConstraintProto::ConstraintCase::kIntProd: + break; + case ConstraintProto::ConstraintCase::kLinear: + break; + case ConstraintProto::ConstraintCase::kAllDiff: + break; + case ConstraintProto::ConstraintCase::kElement: + break; + case ConstraintProto::ConstraintCase::kCircuit: + APPLY_TO_REPEATED_FIELD(circuit, literals); + break; + case ConstraintProto::ConstraintCase::kRoutes: + APPLY_TO_REPEATED_FIELD(routes, literals); + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + break; + case ConstraintProto::ConstraintCase::kInverse: + break; + case ConstraintProto::ConstraintCase::kReservoir: + APPLY_TO_REPEATED_FIELD(reservoir, actives); + break; + case ConstraintProto::ConstraintCase::kTable: + break; + case ConstraintProto::ConstraintCase::kAutomaton: + break; + case ConstraintProto::ConstraintCase::kInterval: + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + break; + case ConstraintProto::ConstraintCase::kCumulative: + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + break; } } void ApplyToAllVariableIndices(const std::function &f, ConstraintProto *ct) { switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - break; - case ConstraintProto::ConstraintCase::kBoolXor: - break; - case ConstraintProto::ConstraintCase::kIntDiv: - APPLY_TO_SINGULAR_FIELD(int_div, target); - APPLY_TO_REPEATED_FIELD(int_div, vars); - break; - case ConstraintProto::ConstraintCase::kIntMod: - APPLY_TO_SINGULAR_FIELD(int_mod, target); - APPLY_TO_REPEATED_FIELD(int_mod, vars); - break; - case ConstraintProto::ConstraintCase::kIntMax: - APPLY_TO_SINGULAR_FIELD(int_max, target); - APPLY_TO_REPEATED_FIELD(int_max, vars); - break; - case ConstraintProto::ConstraintCase::kLinMax: - APPLY_TO_REPEATED_FIELD(lin_max, target()->mutable_vars); - for (int i = 0; i < ct->lin_max().exprs_size(); ++i) { - APPLY_TO_REPEATED_FIELD(lin_max, exprs(i)->mutable_vars); - } - break; - case ConstraintProto::ConstraintCase::kIntMin: - APPLY_TO_SINGULAR_FIELD(int_min, target); - APPLY_TO_REPEATED_FIELD(int_min, vars); - break; - case ConstraintProto::ConstraintCase::kLinMin: - APPLY_TO_REPEATED_FIELD(lin_min, target()->mutable_vars); - for (int i = 0; i < ct->lin_min().exprs_size(); ++i) { - APPLY_TO_REPEATED_FIELD(lin_min, exprs(i)->mutable_vars); - } - break; - case ConstraintProto::ConstraintCase::kIntProd: - APPLY_TO_SINGULAR_FIELD(int_prod, target); - APPLY_TO_REPEATED_FIELD(int_prod, vars); - break; - case ConstraintProto::ConstraintCase::kLinear: - APPLY_TO_REPEATED_FIELD(linear, vars); - break; - case ConstraintProto::ConstraintCase::kAllDiff: - APPLY_TO_REPEATED_FIELD(all_diff, vars); - break; - case ConstraintProto::ConstraintCase::kElement: - APPLY_TO_SINGULAR_FIELD(element, index); - APPLY_TO_SINGULAR_FIELD(element, target); - APPLY_TO_REPEATED_FIELD(element, vars); - break; - case ConstraintProto::ConstraintCase::kCircuit: - break; - case ConstraintProto::ConstraintCase::kRoutes: - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - APPLY_TO_REPEATED_FIELD(circuit_covering, nexts); - break; - case ConstraintProto::ConstraintCase::kInverse: - APPLY_TO_REPEATED_FIELD(inverse, f_direct); - APPLY_TO_REPEATED_FIELD(inverse, f_inverse); - break; - case ConstraintProto::ConstraintCase::kReservoir: - APPLY_TO_REPEATED_FIELD(reservoir, times); - break; - case ConstraintProto::ConstraintCase::kTable: - APPLY_TO_REPEATED_FIELD(table, vars); - break; - case ConstraintProto::ConstraintCase::kAutomaton: - APPLY_TO_REPEATED_FIELD(automaton, vars); - break; - case ConstraintProto::ConstraintCase::kInterval: - APPLY_TO_SINGULAR_FIELD(interval, start); - APPLY_TO_SINGULAR_FIELD(interval, end); - APPLY_TO_SINGULAR_FIELD(interval, size); - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - break; - case ConstraintProto::ConstraintCase::kCumulative: - APPLY_TO_SINGULAR_FIELD(cumulative, capacity); - APPLY_TO_REPEATED_FIELD(cumulative, demands); - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - break; + case ConstraintProto::ConstraintCase::kBoolOr: + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + break; + case ConstraintProto::ConstraintCase::kBoolXor: + break; + case ConstraintProto::ConstraintCase::kIntDiv: + APPLY_TO_SINGULAR_FIELD(int_div, target); + APPLY_TO_REPEATED_FIELD(int_div, vars); + break; + case ConstraintProto::ConstraintCase::kIntMod: + APPLY_TO_SINGULAR_FIELD(int_mod, target); + APPLY_TO_REPEATED_FIELD(int_mod, vars); + break; + case ConstraintProto::ConstraintCase::kIntMax: + APPLY_TO_SINGULAR_FIELD(int_max, target); + APPLY_TO_REPEATED_FIELD(int_max, vars); + break; + case ConstraintProto::ConstraintCase::kLinMax: + APPLY_TO_REPEATED_FIELD(lin_max, target()->mutable_vars); + for (int i = 0; i < ct->lin_max().exprs_size(); ++i) { + APPLY_TO_REPEATED_FIELD(lin_max, exprs(i)->mutable_vars); + } + break; + case ConstraintProto::ConstraintCase::kIntMin: + APPLY_TO_SINGULAR_FIELD(int_min, target); + APPLY_TO_REPEATED_FIELD(int_min, vars); + break; + case ConstraintProto::ConstraintCase::kLinMin: + APPLY_TO_REPEATED_FIELD(lin_min, target()->mutable_vars); + for (int i = 0; i < ct->lin_min().exprs_size(); ++i) { + APPLY_TO_REPEATED_FIELD(lin_min, exprs(i)->mutable_vars); + } + break; + case ConstraintProto::ConstraintCase::kIntProd: + APPLY_TO_SINGULAR_FIELD(int_prod, target); + APPLY_TO_REPEATED_FIELD(int_prod, vars); + break; + case ConstraintProto::ConstraintCase::kLinear: + APPLY_TO_REPEATED_FIELD(linear, vars); + break; + case ConstraintProto::ConstraintCase::kAllDiff: + APPLY_TO_REPEATED_FIELD(all_diff, vars); + break; + case ConstraintProto::ConstraintCase::kElement: + APPLY_TO_SINGULAR_FIELD(element, index); + APPLY_TO_SINGULAR_FIELD(element, target); + APPLY_TO_REPEATED_FIELD(element, vars); + break; + case ConstraintProto::ConstraintCase::kCircuit: + break; + case ConstraintProto::ConstraintCase::kRoutes: + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + APPLY_TO_REPEATED_FIELD(circuit_covering, nexts); + break; + case ConstraintProto::ConstraintCase::kInverse: + APPLY_TO_REPEATED_FIELD(inverse, f_direct); + APPLY_TO_REPEATED_FIELD(inverse, f_inverse); + break; + case ConstraintProto::ConstraintCase::kReservoir: + APPLY_TO_REPEATED_FIELD(reservoir, times); + break; + case ConstraintProto::ConstraintCase::kTable: + APPLY_TO_REPEATED_FIELD(table, vars); + break; + case ConstraintProto::ConstraintCase::kAutomaton: + APPLY_TO_REPEATED_FIELD(automaton, vars); + break; + case ConstraintProto::ConstraintCase::kInterval: + APPLY_TO_SINGULAR_FIELD(interval, start); + APPLY_TO_SINGULAR_FIELD(interval, end); + APPLY_TO_SINGULAR_FIELD(interval, size); + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + break; + case ConstraintProto::ConstraintCase::kCumulative: + APPLY_TO_SINGULAR_FIELD(cumulative, capacity); + APPLY_TO_REPEATED_FIELD(cumulative, demands); + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + break; } } void ApplyToAllIntervalIndices(const std::function &f, ConstraintProto *ct) { switch (ct->constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - break; - case ConstraintProto::ConstraintCase::kBoolXor: - break; - case ConstraintProto::ConstraintCase::kIntDiv: - break; - case ConstraintProto::ConstraintCase::kIntMod: - break; - case ConstraintProto::ConstraintCase::kIntMax: - break; - case ConstraintProto::ConstraintCase::kLinMax: - break; - case ConstraintProto::ConstraintCase::kIntMin: - break; - case ConstraintProto::ConstraintCase::kLinMin: - break; - case ConstraintProto::ConstraintCase::kIntProd: - break; - case ConstraintProto::ConstraintCase::kLinear: - break; - case ConstraintProto::ConstraintCase::kAllDiff: - break; - case ConstraintProto::ConstraintCase::kElement: - break; - case ConstraintProto::ConstraintCase::kCircuit: - break; - case ConstraintProto::ConstraintCase::kRoutes: - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - break; - case ConstraintProto::ConstraintCase::kInverse: - break; - case ConstraintProto::ConstraintCase::kReservoir: - break; - case ConstraintProto::ConstraintCase::kTable: - break; - case ConstraintProto::ConstraintCase::kAutomaton: - break; - case ConstraintProto::ConstraintCase::kInterval: - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - APPLY_TO_REPEATED_FIELD(no_overlap, intervals); - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - APPLY_TO_REPEATED_FIELD(no_overlap_2d, x_intervals); - APPLY_TO_REPEATED_FIELD(no_overlap_2d, y_intervals); - break; - case ConstraintProto::ConstraintCase::kCumulative: - APPLY_TO_REPEATED_FIELD(cumulative, intervals); - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - break; + case ConstraintProto::ConstraintCase::kBoolOr: + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + break; + case ConstraintProto::ConstraintCase::kBoolXor: + break; + case ConstraintProto::ConstraintCase::kIntDiv: + break; + case ConstraintProto::ConstraintCase::kIntMod: + break; + case ConstraintProto::ConstraintCase::kIntMax: + break; + case ConstraintProto::ConstraintCase::kLinMax: + break; + case ConstraintProto::ConstraintCase::kIntMin: + break; + case ConstraintProto::ConstraintCase::kLinMin: + break; + case ConstraintProto::ConstraintCase::kIntProd: + break; + case ConstraintProto::ConstraintCase::kLinear: + break; + case ConstraintProto::ConstraintCase::kAllDiff: + break; + case ConstraintProto::ConstraintCase::kElement: + break; + case ConstraintProto::ConstraintCase::kCircuit: + break; + case ConstraintProto::ConstraintCase::kRoutes: + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + break; + case ConstraintProto::ConstraintCase::kInverse: + break; + case ConstraintProto::ConstraintCase::kReservoir: + break; + case ConstraintProto::ConstraintCase::kTable: + break; + case ConstraintProto::ConstraintCase::kAutomaton: + break; + case ConstraintProto::ConstraintCase::kInterval: + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + APPLY_TO_REPEATED_FIELD(no_overlap, intervals); + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + APPLY_TO_REPEATED_FIELD(no_overlap_2d, x_intervals); + APPLY_TO_REPEATED_FIELD(no_overlap_2d, y_intervals); + break; + case ConstraintProto::ConstraintCase::kCumulative: + APPLY_TO_REPEATED_FIELD(cumulative, intervals); + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + break; } } #undef APPLY_TO_SINGULAR_FIELD #undef APPLY_TO_REPEATED_FIELD -std::string -ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case) { +std::string ConstraintCaseName( + ConstraintProto::ConstraintCase constraint_case) { switch (constraint_case) { - case ConstraintProto::ConstraintCase::kBoolOr: - return "kBoolOr"; - case ConstraintProto::ConstraintCase::kBoolAnd: - return "kBoolAnd"; - case ConstraintProto::ConstraintCase::kAtMostOne: - return "kAtMostOne"; - case ConstraintProto::ConstraintCase::kBoolXor: - return "kBoolXor"; - case ConstraintProto::ConstraintCase::kIntDiv: - return "kIntDiv"; - case ConstraintProto::ConstraintCase::kIntMod: - return "kIntMod"; - case ConstraintProto::ConstraintCase::kIntMax: - return "kIntMax"; - case ConstraintProto::ConstraintCase::kLinMax: - return "kLinMax"; - case ConstraintProto::ConstraintCase::kIntMin: - return "kIntMin"; - case ConstraintProto::ConstraintCase::kLinMin: - return "kLinMin"; - case ConstraintProto::ConstraintCase::kIntProd: - return "kIntProd"; - case ConstraintProto::ConstraintCase::kLinear: - return "kLinear"; - case ConstraintProto::ConstraintCase::kAllDiff: - return "kAllDiff"; - case ConstraintProto::ConstraintCase::kElement: - return "kElement"; - case ConstraintProto::ConstraintCase::kCircuit: - return "kCircuit"; - case ConstraintProto::ConstraintCase::kRoutes: - return "kRoutes"; - case ConstraintProto::ConstraintCase::kCircuitCovering: - return "kCircuitCovering"; - case ConstraintProto::ConstraintCase::kInverse: - return "kInverse"; - case ConstraintProto::ConstraintCase::kReservoir: - return "kReservoir"; - case ConstraintProto::ConstraintCase::kTable: - return "kTable"; - case ConstraintProto::ConstraintCase::kAutomaton: - return "kAutomaton"; - case ConstraintProto::ConstraintCase::kInterval: - return "kInterval"; - case ConstraintProto::ConstraintCase::kNoOverlap: - return "kNoOverlap"; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - return "kNoOverlap2D"; - case ConstraintProto::ConstraintCase::kCumulative: - return "kCumulative"; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - return "kEmpty"; + case ConstraintProto::ConstraintCase::kBoolOr: + return "kBoolOr"; + case ConstraintProto::ConstraintCase::kBoolAnd: + return "kBoolAnd"; + case ConstraintProto::ConstraintCase::kAtMostOne: + return "kAtMostOne"; + case ConstraintProto::ConstraintCase::kBoolXor: + return "kBoolXor"; + case ConstraintProto::ConstraintCase::kIntDiv: + return "kIntDiv"; + case ConstraintProto::ConstraintCase::kIntMod: + return "kIntMod"; + case ConstraintProto::ConstraintCase::kIntMax: + return "kIntMax"; + case ConstraintProto::ConstraintCase::kLinMax: + return "kLinMax"; + case ConstraintProto::ConstraintCase::kIntMin: + return "kIntMin"; + case ConstraintProto::ConstraintCase::kLinMin: + return "kLinMin"; + case ConstraintProto::ConstraintCase::kIntProd: + return "kIntProd"; + case ConstraintProto::ConstraintCase::kLinear: + return "kLinear"; + case ConstraintProto::ConstraintCase::kAllDiff: + return "kAllDiff"; + case ConstraintProto::ConstraintCase::kElement: + return "kElement"; + case ConstraintProto::ConstraintCase::kCircuit: + return "kCircuit"; + case ConstraintProto::ConstraintCase::kRoutes: + return "kRoutes"; + case ConstraintProto::ConstraintCase::kCircuitCovering: + return "kCircuitCovering"; + case ConstraintProto::ConstraintCase::kInverse: + return "kInverse"; + case ConstraintProto::ConstraintCase::kReservoir: + return "kReservoir"; + case ConstraintProto::ConstraintCase::kTable: + return "kTable"; + case ConstraintProto::ConstraintCase::kAutomaton: + return "kAutomaton"; + case ConstraintProto::ConstraintCase::kInterval: + return "kInterval"; + case ConstraintProto::ConstraintCase::kNoOverlap: + return "kNoOverlap"; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + return "kNoOverlap2D"; + case ConstraintProto::ConstraintCase::kCumulative: + return "kCumulative"; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + return "kEmpty"; } } @@ -458,62 +456,62 @@ std::vector UsedVariables(const ConstraintProto &ct) { std::vector UsedIntervals(const ConstraintProto &ct) { std::vector used_intervals; switch (ct.constraint_case()) { - case ConstraintProto::ConstraintCase::kBoolOr: - break; - case ConstraintProto::ConstraintCase::kBoolAnd: - break; - case ConstraintProto::ConstraintCase::kAtMostOne: - break; - case ConstraintProto::ConstraintCase::kBoolXor: - break; - case ConstraintProto::ConstraintCase::kIntDiv: - break; - case ConstraintProto::ConstraintCase::kIntMod: - break; - case ConstraintProto::ConstraintCase::kIntMax: - break; - case ConstraintProto::ConstraintCase::kLinMax: - break; - case ConstraintProto::ConstraintCase::kIntMin: - break; - case ConstraintProto::ConstraintCase::kLinMin: - break; - case ConstraintProto::ConstraintCase::kIntProd: - break; - case ConstraintProto::ConstraintCase::kLinear: - break; - case ConstraintProto::ConstraintCase::kAllDiff: - break; - case ConstraintProto::ConstraintCase::kElement: - break; - case ConstraintProto::ConstraintCase::kCircuit: - break; - case ConstraintProto::ConstraintCase::kRoutes: - break; - case ConstraintProto::ConstraintCase::kCircuitCovering: - break; - case ConstraintProto::ConstraintCase::kInverse: - break; - case ConstraintProto::ConstraintCase::kReservoir: - break; - case ConstraintProto::ConstraintCase::kTable: - break; - case ConstraintProto::ConstraintCase::kAutomaton: - break; - case ConstraintProto::ConstraintCase::kInterval: - break; - case ConstraintProto::ConstraintCase::kNoOverlap: - AddIndices(ct.no_overlap().intervals(), &used_intervals); - break; - case ConstraintProto::ConstraintCase::kNoOverlap2D: - AddIndices(ct.no_overlap_2d().x_intervals(), &used_intervals); - AddIndices(ct.no_overlap_2d().y_intervals(), &used_intervals); - break; - case ConstraintProto::ConstraintCase::kCumulative: - AddIndices(ct.cumulative().intervals(), &used_intervals); - break; - case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: - break; + case ConstraintProto::ConstraintCase::kBoolOr: + break; + case ConstraintProto::ConstraintCase::kBoolAnd: + break; + case ConstraintProto::ConstraintCase::kAtMostOne: + break; + case ConstraintProto::ConstraintCase::kBoolXor: + break; + case ConstraintProto::ConstraintCase::kIntDiv: + break; + case ConstraintProto::ConstraintCase::kIntMod: + break; + case ConstraintProto::ConstraintCase::kIntMax: + break; + case ConstraintProto::ConstraintCase::kLinMax: + break; + case ConstraintProto::ConstraintCase::kIntMin: + break; + case ConstraintProto::ConstraintCase::kLinMin: + break; + case ConstraintProto::ConstraintCase::kIntProd: + break; + case ConstraintProto::ConstraintCase::kLinear: + break; + case ConstraintProto::ConstraintCase::kAllDiff: + break; + case ConstraintProto::ConstraintCase::kElement: + break; + case ConstraintProto::ConstraintCase::kCircuit: + break; + case ConstraintProto::ConstraintCase::kRoutes: + break; + case ConstraintProto::ConstraintCase::kCircuitCovering: + break; + case ConstraintProto::ConstraintCase::kInverse: + break; + case ConstraintProto::ConstraintCase::kReservoir: + break; + case ConstraintProto::ConstraintCase::kTable: + break; + case ConstraintProto::ConstraintCase::kAutomaton: + break; + case ConstraintProto::ConstraintCase::kInterval: + break; + case ConstraintProto::ConstraintCase::kNoOverlap: + AddIndices(ct.no_overlap().intervals(), &used_intervals); + break; + case ConstraintProto::ConstraintCase::kNoOverlap2D: + AddIndices(ct.no_overlap_2d().x_intervals(), &used_intervals); + AddIndices(ct.no_overlap_2d().y_intervals(), &used_intervals); + break; + case ConstraintProto::ConstraintCase::kCumulative: + AddIndices(ct.cumulative().intervals(), &used_intervals); + break; + case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET: + break; } gtl::STLSortAndRemoveDuplicates(&used_intervals); return used_intervals; @@ -522,19 +520,18 @@ std::vector UsedIntervals(const ConstraintProto &ct) { int64 ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response) { int64 objective_value = 0; - auto &repeated_field_values = - response.solution().empty() ? response.solution_lower_bounds() - : response.solution(); + auto &repeated_field_values = response.solution().empty() + ? response.solution_lower_bounds() + : response.solution(); for (int i = 0; i < objective.vars_size(); ++i) { int64 coeff = objective.coeffs(i); const int ref = objective.vars(i); const int var = PositiveRef(ref); - if (!RefIsPositive(ref)) - coeff = -coeff; + if (!RefIsPositive(ref)) coeff = -coeff; objective_value += coeff * repeated_field_values[var]; } return objective_value; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cp_model_utils.h b/ortools/sat/cp_model_utils.h index 7535ea183b..533fdf7392 100644 --- a/ortools/sat/cp_model_utils.h +++ b/ortools/sat/cp_model_utils.h @@ -81,8 +81,7 @@ std::vector UsedIntervals(const ConstraintProto &ct); template bool DomainInProtoContains(const ProtoWithDomain &proto, int64 value) { for (int i = 0; i < proto.domain_size(); i += 2) { - if (value >= proto.domain(i) && value <= proto.domain(i + 1)) - return true; + if (value >= proto.domain(i) && value <= proto.domain(i + 1)) return true; } return false; } @@ -102,9 +101,8 @@ void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto) { template Domain ReadDomainFromProto(const ProtoWithDomain &proto) { #if defined(__PORTABLE_PLATFORM__) - return Domain::FromFlatIntervals({ - proto.domain().begin(), proto.domain().end() - }); + return Domain::FromFlatIntervals( + {proto.domain().begin(), proto.domain().end()}); #else return Domain::FromFlatSpanOfIntervals(proto.domain()); #endif @@ -129,13 +127,10 @@ std::vector AllValuesInDomain(const ProtoWithDomain &proto) { // Scales back a objective value to a double value from the original model. inline double ScaleObjectiveValue(const CpObjectiveProto &proto, int64 value) { double result = static_cast(value); - if (value == kint64min) - result = -std::numeric_limits::infinity(); - if (value == kint64max) - result = std::numeric_limits::infinity(); + if (value == kint64min) result = -std::numeric_limits::infinity(); + if (value == kint64max) result = std::numeric_limits::infinity(); result += proto.offset(); - if (proto.scaling_factor() == 0) - return result; + if (proto.scaling_factor() == 0) return result; return proto.scaling_factor() * result; } @@ -155,7 +150,7 @@ inline double UnscaleObjectiveValue(const CpObjectiveProto &proto, int64 ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CP_MODEL_UTILS_H_ +#endif // OR_TOOLS_SAT_CP_MODEL_UTILS_H_ diff --git a/ortools/sat/cumulative.cc b/ortools/sat/cumulative.cc index 6b24c56b5e..91416a78b9 100644 --- a/ortools/sat/cumulative.cc +++ b/ortools/sat/cumulative.cc @@ -32,11 +32,12 @@ namespace operations_research { namespace sat { -std::function -Cumulative(const std::vector &vars, - const std::vector &demands, - AffineExpression capacity, SchedulingConstraintHelper *helper) { - return[ = ](Model * model) mutable { if (vars.empty()) return; +std::function Cumulative( + const std::vector &vars, + const std::vector &demands, AffineExpression capacity, + SchedulingConstraintHelper *helper) { + return [=](Model *model) mutable { + if (vars.empty()) return; auto *intervals = model->GetOrCreate(); auto *encoder = model->GetOrCreate(); @@ -48,8 +49,7 @@ Cumulative(const std::vector &vars, // is available. This is useful because the subsequent propagators do not // filter the capacity variable very well. for (int i = 0; i < demands.size(); ++i) { - if (intervals->MaxSize(vars[i]) == 0) - continue; + if (intervals->MaxSize(vars[i]) == 0) continue; LinearConstraintBuilder builder(model, kMinIntegerValue, IntegerValue(0)); builder.AddTerm(demands[i], IntegerValue(1)); @@ -77,8 +77,7 @@ Cumulative(const std::vector &vars, } } - if (vars.size() == 1) - return; + if (vars.size() == 1) return; const SatParameters ¶meters = *(model->GetOrCreate()); @@ -117,10 +116,8 @@ Cumulative(const std::vector &vars, // // TODO(user): A better place for stuff like this could be in the // presolver so that it is easier to disable and play with alternatives. - if (in_disjunction.size() > 1) - model->Add(Disjunctive(in_disjunction)); - if (in_disjunction.size() == vars.size()) - return; + if (in_disjunction.size() > 1) model->Add(Disjunctive(in_disjunction)); + if (in_disjunction.size() == vars.size()) return; } if (helper == nullptr) { @@ -151,21 +148,20 @@ Cumulative(const std::vector &vars, time_table_edge_finding->RegisterWith(watcher); model->TakeOwnership(time_table_edge_finding); } - } - ; + }; } -std::function -CumulativeTimeDecomposition(const std::vector &vars, - const std::vector &demands, - AffineExpression capacity, - SchedulingConstraintHelper *helper) { - return[ = ](Model * model) { if (vars.empty()) return; +std::function CumulativeTimeDecomposition( + const std::vector &vars, + const std::vector &demands, AffineExpression capacity, + SchedulingConstraintHelper *helper) { + return [=](Model *model) { + if (vars.empty()) return; IntegerTrail *integer_trail = model->GetOrCreate(); CHECK(integer_trail->IsFixed(capacity)); - const Coefficient fixed_capacity(integer_trail->UpperBound(capacity) - .value()); + const Coefficient fixed_capacity( + integer_trail->UpperBound(capacity).value()); const int num_tasks = vars.size(); SatSolver *sat_solver = model->GetOrCreate(); @@ -221,8 +217,7 @@ CumulativeTimeDecomposition(const std::vector &vars, // TODO(user): this is needed because we currently can't create a // boolean variable if the model is unsat. - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; literals_with_coeff.push_back( LiteralWithCoeff(consume, Coefficient(fixed_demands[t].value()))); @@ -232,12 +227,10 @@ CumulativeTimeDecomposition(const std::vector &vars, fixed_capacity, &literals_with_coeff); // Abort if UNSAT. - if (sat_solver->IsModelUnsat()) - return; + if (sat_solver->IsModelUnsat()) return; } - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cumulative.h b/ortools/sat/cumulative.h index 704cf5586a..1c42a3cb9c 100644 --- a/ortools/sat/cumulative.h +++ b/ortools/sat/cumulative.h @@ -42,24 +42,22 @@ namespace sat { // // Optimization: If one already have an helper constructed from the interval // variable, it can be passed as last argument. -std::function - Cumulative(const std::vector &vars, - const std::vector &demands, - AffineExpression capacity, - SchedulingConstraintHelper *helper = nullptr); +std::function Cumulative( + const std::vector &vars, + const std::vector &demands, AffineExpression capacity, + SchedulingConstraintHelper *helper = nullptr); // Adds a simple cumulative constraint. See the comment of Cumulative() above // for a definition of the constraint. This is only used for testing. // // This constraint assumes that task demands and the resource capacity are fixed // to non-negative number. -std::function - CumulativeTimeDecomposition(const std::vector &vars, - const std::vector &demands, - AffineExpression capacity, - SchedulingConstraintHelper *helper = nullptr); +std::function CumulativeTimeDecomposition( + const std::vector &vars, + const std::vector &demands, AffineExpression capacity, + SchedulingConstraintHelper *helper = nullptr); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CUMULATIVE_H_ +#endif // OR_TOOLS_SAT_CUMULATIVE_H_ diff --git a/ortools/sat/cumulative_energy.cc b/ortools/sat/cumulative_energy.cc index 55e48f248f..6172cba855 100644 --- a/ortools/sat/cumulative_energy.cc +++ b/ortools/sat/cumulative_energy.cc @@ -91,8 +91,11 @@ void AddCumulativeOverloadChecker(const std::vector &demands, CumulativeEnergyConstraint::CumulativeEnergyConstraint( std::vector energies, AffineExpression capacity, IntegerTrail *integer_trail, SchedulingConstraintHelper *helper) - : energies_(std::move(energies)), capacity_(capacity), - integer_trail_(integer_trail), helper_(helper), theta_tree_() { + : energies_(std::move(energies)), + capacity_(capacity), + integer_trail_(integer_trail), + helper_(helper), + theta_tree_() { const int num_tasks = helper_->NumTasks(); CHECK_EQ(energies_.size(), num_tasks); task_to_start_event_.resize(num_tasks); @@ -111,8 +114,7 @@ bool CumulativeEnergyConstraint::Propagate() { const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_); // TODO(user): force capacity_max >= 0, fail/remove optionals when 0. - if (capacity_max <= 0) - return true; + if (capacity_max <= 0) return true; // Set up theta tree. start_event_task_time_.clear(); @@ -138,8 +140,7 @@ bool CumulativeEnergyConstraint::Propagate() { ::gtl::reversed_view(helper_->TaskByDecreasingEndMax())) { const int current_task = task_time.task_index; const IntegerValue current_end = task_time.time; - if (task_to_start_event_[current_task] == -1) - continue; + if (task_to_start_event_[current_task] == -1) continue; // Add the current task to the tree. { @@ -169,8 +170,7 @@ bool CumulativeEnergyConstraint::Propagate() { start_event_task_time_[critical_event].time; const IntegerValue window_end = current_end; const IntegerValue window_size = window_end - window_start; - if (window_size == 0) - continue; + if (window_size == 0) continue; const IntegerValue new_capacity_min = CeilRatio(envelope - window_start * capacity_max, window_size); @@ -232,8 +232,7 @@ bool CumulativeEnergyConstraint::Propagate() { const IntegerValue window_end = current_end; for (int event = critical_event; event < num_events; event++) { if (start_event_is_present_[event]) { - if (event == event_with_new_energy_max) - continue; + if (event == event_with_new_energy_max) continue; const int task = start_event_task_time_[event].task_index; helper_->AddPresenceReason(task); helper_->AddStartMinReason(task, window_start); @@ -245,8 +244,8 @@ bool CumulativeEnergyConstraint::Propagate() { } } if (capacity_.var != kNoIntegerVariable) { - helper_->MutableIntegerReason() - ->push_back(integer_trail_->UpperBoundAsLiteral(capacity_.var)); + helper_->MutableIntegerReason()->push_back( + integer_trail_->UpperBoundAsLiteral(capacity_.var)); } const int task_with_new_energy_max = @@ -285,5 +284,5 @@ bool CumulativeEnergyConstraint::Propagate() { return true; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cumulative_energy.h b/ortools/sat/cumulative_energy.h index 60c6bb0366..ed6506a251 100644 --- a/ortools/sat/cumulative_energy.h +++ b/ortools/sat/cumulative_energy.h @@ -48,7 +48,7 @@ void AddCumulativeOverloadChecker(const std::vector &demands, Model *model); class CumulativeEnergyConstraint : public PropagatorInterface { -public: + public: CumulativeEnergyConstraint(std::vector energies, AffineExpression capacity, IntegerTrail *integer_trail, @@ -56,7 +56,7 @@ public: bool Propagate() final; void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: const std::vector energies_; const AffineExpression capacity_; IntegerTrail *integer_trail_; @@ -71,7 +71,7 @@ private: std::vector start_event_is_present_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CUMULATIVE_ENERGY_H_ +#endif // OR_TOOLS_SAT_CUMULATIVE_ENERGY_H_ diff --git a/ortools/sat/cuts.cc b/ortools/sat/cuts.cc index b51a8ae219..3a1e2161b5 100644 --- a/ortools/sat/cuts.cc +++ b/ortools/sat/cuts.cc @@ -39,10 +39,9 @@ namespace { const double kMinCutViolation = 1e-4; // Returns the lp value of a Literal. -double -GetLiteralLpValue(const Literal lit, - const gtl::ITIVector &lp_values, - const IntegerEncoder *encoder) { +double GetLiteralLpValue( + const Literal lit, const gtl::ITIVector &lp_values, + const IntegerEncoder *encoder) { const IntegerVariable direct_view = encoder->GetLiteralView(lit); if (direct_view != kNoIntegerVariable) { return lp_values[direct_view]; @@ -55,11 +54,10 @@ GetLiteralLpValue(const Literal lit, // Returns a constraint that disallow all given variables to be at their current // upper bound. The arguments must form a non-trival constraint of the form // sum terms (coeff * var) <= upper_bound. -LinearConstraint -GenerateKnapsackCutForCover(const std::vector &vars, - const std::vector &coeffs, - const IntegerValue upper_bound, - const IntegerTrail &integer_trail) { +LinearConstraint GenerateKnapsackCutForCover( + const std::vector &vars, + const std::vector &coeffs, const IntegerValue upper_bound, + const IntegerTrail &integer_trail) { CHECK_EQ(vars.size(), coeffs.size()); CHECK_GT(vars.size(), 0); LinearConstraint cut; @@ -97,14 +95,14 @@ bool SolutionSatisfiesConstraint( bool SmallRangeAndAllCoefficientsMagnitudeAreTheSame( const LinearConstraint &constraint, IntegerTrail *integer_trail) { - if (constraint.vars.empty()) - return true; + if (constraint.vars.empty()) return true; const int64 magnitude = std::abs(constraint.coeffs[0].value()); for (int i = 1; i < constraint.coeffs.size(); ++i) { const IntegerVariable var = constraint.vars[i]; if (integer_trail->LevelZeroUpperBound(var) - - integer_trail->LevelZeroLowerBound(var) > 1) { + integer_trail->LevelZeroLowerBound(var) > + 1) { return false; } if (std::abs(constraint.coeffs[i].value()) != magnitude) { @@ -167,14 +165,14 @@ bool ConstraintIsEligibleForLifting(const LinearConstraint &constraint, } return true; } -} // namespace +} // namespace -bool -LiftKnapsackCut(const LinearConstraint &constraint, - const gtl::ITIVector &lp_values, - const std::vector &cut_vars_original_coefficients, - const IntegerTrail &integer_trail, TimeLimit *time_limit, - LinearConstraint *cut) { +bool LiftKnapsackCut( + const LinearConstraint &constraint, + const gtl::ITIVector &lp_values, + const std::vector &cut_vars_original_coefficients, + const IntegerTrail &integer_trail, TimeLimit *time_limit, + LinearConstraint *cut) { std::set vars_in_cut; for (IntegerVariable var : cut->vars) { vars_in_cut.insert(var); @@ -188,17 +186,12 @@ LiftKnapsackCut(const LinearConstraint &constraint, integer_trail.LevelZeroUpperBound(var) != IntegerValue(1)) { continue; } - if (vars_in_cut.find(var) != vars_in_cut.end()) - continue; + if (vars_in_cut.find(var) != vars_in_cut.end()) continue; const IntegerValue coeff = constraint.coeffs[i]; if (lp_values[var] <= 1e-6) { - zero_vars.push_back({ - coeff, var - }); + zero_vars.push_back({coeff, var}); } else { - non_zero_vars.push_back({ - coeff, var - }); + non_zero_vars.push_back({coeff, var}); } } @@ -230,8 +223,7 @@ LiftKnapsackCut(const LinearConstraint &constraint, const IntegerValue var_original_coeff = entry.first; const IntegerVariable var = entry.second; const IntegerValue lifting_capacity = constraint.ub - entry.first; - if (lifting_capacity <= IntegerValue(0)) - continue; + if (lifting_capacity <= IntegerValue(0)) continue; knapsack_solver.Init(lifting_profits, lifting_weights, lifting_capacity.value()); knapsack_solver.set_node_limit(100); @@ -361,8 +353,7 @@ bool CanBeFilteredUsingKnapsackUpperBound( // Return early if the required upper bound is negative since all the profits // are non negative. - if (sum_variable_profit - 1.0 + kMinCutViolation < 0.0) - return false; + if (sum_variable_profit - 1.0 + kMinCutViolation < 0.0) return false; // Get the knapsack upper bound. const double knapsack_upper_bound = @@ -456,8 +447,7 @@ CutGenerator CreateKnapsackCoverCutGenerator( // // TODO(user): The case of size 2 is a bit less clear. investigate more if // it is useful. - if (constraint.vars.size() <= 2) - continue; + if (constraint.vars.size() <= 2) continue; ConvertToKnapsackForm(constraint, &knapsack_constraints, integer_trail); } @@ -471,15 +461,15 @@ CutGenerator CreateKnapsackCoverCutGenerator( vars, integer_trail, model->GetOrCreate()); // TODO(user): do not add generator if there are no knapsack constraints. - result.generate_cuts = - [implied_bounds_processor, knapsack_constraints, vars, model, - integer_trail](const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) mutable { + result.generate_cuts = [implied_bounds_processor, knapsack_constraints, vars, + model, integer_trail]( + const gtl::ITIVector + &lp_values, + LinearConstraintManager *manager) mutable { // TODO(user): When we use implied-bound substitution, we might still infer // an interesting cut even if all variables are integer. See if we still // want to skip all such constraints. - if (AllVarsTakeIntegerValue(vars, lp_values)) - return; + if (AllVarsTakeIntegerValue(vars, lp_values)) return; KnapsackSolverForCuts knapsack_solver( "Knapsack on demand cover cut generator"); @@ -489,8 +479,7 @@ CutGenerator CreateKnapsackCoverCutGenerator( // Iterate through all knapsack constraints. implied_bounds_processor.ClearCache(); for (const LinearConstraint &constraint : knapsack_constraints) { - if (model->GetOrCreate()->LimitReached()) - break; + if (model->GetOrCreate()->LimitReached()) break; VLOG(2) << "Processing constraint: " << constraint.DebugString(); mutable_constraint = constraint; @@ -501,8 +490,7 @@ CutGenerator CreateKnapsackCoverCutGenerator( const LinearConstraint preprocessed_constraint = GetPreprocessedLinearConstraint(mutable_constraint, lp_values, *integer_trail); - if (preprocessed_constraint.vars.empty()) - continue; + if (preprocessed_constraint.vars.empty()) continue; if (!CanFormValidKnapsackCover(preprocessed_constraint, lp_values, *integer_trail)) { @@ -542,8 +530,7 @@ CutGenerator CreateKnapsackCoverCutGenerator( weights.push_back(weight); capacity += weight + coefficient * var_lb; } - if (capacity < 0.0) - continue; + if (capacity < 0.0) continue; std::vector cut_vars; std::vector cut_vars_original_coefficients; @@ -615,8 +602,7 @@ CutGenerator CreateKnapsackCoverCutGenerator( if (skipped_constraints > 0) { VLOG(2) << "Skipped constraints: " << skipped_constraints; } - } - ; + }; return result; } @@ -633,10 +619,9 @@ IntegerValue GetFactorT(IntegerValue rhs_remainder, IntegerValue divisor, : std::min(max_t, CeilRatio(divisor / 2, rhs_remainder)); } -std::function -GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, - IntegerValue divisor, IntegerValue t, - IntegerValue max_scaling) { +std::function GetSuperAdditiveRoundingFunction( + IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue t, + IntegerValue max_scaling) { DCHECK_GE(max_scaling, 1); // Adjust after the multiplication by t. @@ -653,21 +638,17 @@ GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, // TODO(user): Use everywhere a two step computation to avoid overflow? // First divide by divisor, then multiply by t. For now, we limit t so that // we never have an overflow instead. - return[t, divisor](IntegerValue coeff) { + return [t, divisor](IntegerValue coeff) { return FloorRatio(t * coeff, divisor); - } - ; - } - else if (size <= max_scaling) { - return[size, rhs_remainder, t, divisor](IntegerValue coeff) { + }; + } else if (size <= max_scaling) { + return [size, rhs_remainder, t, divisor](IntegerValue coeff) { const IntegerValue ratio = FloorRatio(t * coeff, divisor); const IntegerValue remainder = t * coeff - ratio * divisor; const IntegerValue diff = remainder - rhs_remainder; return size * ratio + std::max(IntegerValue(0), diff); - } - ; - } - else if (max_scaling.value() * rhs_remainder.value() < divisor) { + }; + } else if (max_scaling.value() * rhs_remainder.value() < divisor) { // Because of our max_t limitation, the rhs_remainder might stay small. // // If it is "too small" we cannot use the code below because it will not be @@ -677,15 +658,13 @@ GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, // Note(user): This seems the same as just increasing t, modulo integer // overflows. Maybe we should just always do the computation like this so // that we can use larger t even if coeff is close to kint64max. - return[t, divisor, max_scaling](IntegerValue coeff) { + return [t, divisor, max_scaling](IntegerValue coeff) { const IntegerValue ratio = FloorRatio(t * coeff, divisor); const IntegerValue remainder = t * coeff - ratio * divisor; const IntegerValue bucket = FloorRatio(remainder * max_scaling, divisor); return max_scaling * ratio + bucket; - } - ; - } - else { + }; + } else { // We divide (size = divisor - rhs_remainder) into (max_scaling - 1) buckets // and increase the function by 1 / max_scaling for each of them. // @@ -708,7 +687,7 @@ GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, // // TODO(user): This function is not always maximal when // size % (max_scaling - 1) == 0. Improve? - return[size, rhs_remainder, t, divisor, max_scaling](IntegerValue coeff) { + return [size, rhs_remainder, t, divisor, max_scaling](IntegerValue coeff) { const IntegerValue ratio = FloorRatio(t * coeff, divisor); const IntegerValue remainder = t * coeff - ratio * divisor; const IntegerValue diff = remainder - rhs_remainder; @@ -716,8 +695,7 @@ GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, diff > 0 ? CeilRatio(diff * (max_scaling - 1), size) : IntegerValue(0); return max_scaling * ratio + bucket; - } - ; + }; } } @@ -730,8 +708,7 @@ void IntegerRoundingCutHelper::ComputeCut( const std::vector &upper_bounds, ImpliedBoundsProcessor *ib_processor, LinearConstraint *cut) { const int size = lp_values.size(); - if (size == 0) - return; + if (size == 0) return; CHECK_EQ(lower_bounds.size(), size); CHECK_EQ(upper_bounds.size(), size); CHECK_EQ(cut->vars.size(), size); @@ -754,8 +731,7 @@ void IntegerRoundingCutHelper::ComputeCut( // Compute the maximum magnitude for non-fixed variables. IntegerValue max_magnitude(0); for (int i = 0; i < size; ++i) { - if (lower_bounds[i] == upper_bounds[i]) - continue; + if (lower_bounds[i] == upper_bounds[i]) continue; const IntegerValue magnitude = IntTypeAbs(cut->coeffs[i]); max_magnitude = std::max(max_magnitude, magnitude); } @@ -766,8 +742,7 @@ void IntegerRoundingCutHelper::ComputeCut( bool overflow = false; change_sign_at_postprocessing_.assign(size, false); for (int i = 0; i < size; ++i) { - if (cut->coeffs[i] == 0) - continue; + if (cut->coeffs[i] == 0) continue; const IntegerValue magnitude = IntTypeAbs(cut->coeffs[i]); // We might change them below. @@ -878,8 +853,7 @@ void IntegerRoundingCutHelper::ComputeCut( int new_size = 0; const IntegerValue divisor_threshold = max_magnitude / 10; for (int i = 0; i < divisors_.size(); ++i) { - if (divisors_[i] <= divisor_threshold) - continue; + if (divisors_[i] <= divisor_threshold) continue; divisors_[new_size++] = divisors_[i]; } divisors_.resize(new_size); @@ -894,8 +868,7 @@ void IntegerRoundingCutHelper::ComputeCut( // Skip if we don't have the potential to generate a good enough cut. const IntegerValue initial_rhs_remainder = cut->ub - FloorRatio(cut->ub, divisor) * divisor; - if (initial_rhs_remainder <= remainder_threshold) - continue; + if (initial_rhs_remainder <= remainder_threshold) continue; IntegerValue temp_ub = cut->ub; adjusted_coeffs_.clear(); @@ -946,21 +919,17 @@ void IntegerRoundingCutHelper::ComputeCut( if (remainder > 0 && remainder <= adjust_threshold && CapProd(diff.value(), remainder.value()) <= adjust_threshold) { temp_ub += remainder * diff; - adjusted_coeffs_.push_back({ - i, coeff + remainder - }); + adjusted_coeffs_.push_back({i, coeff + remainder}); } } - if (early_abort) - continue; + if (early_abort) continue; } // Create the super-additive function f(). const IntegerValue rhs_remainder = temp_ub - FloorRatio(temp_ub, divisor) * divisor; - if (rhs_remainder == 0) - continue; + if (rhs_remainder == 0) continue; const auto f = GetSuperAdditiveRoundingFunction( rhs_remainder, divisor, GetFactorT(rhs_remainder, divisor, max_t), @@ -995,8 +964,7 @@ void IntegerRoundingCutHelper::ComputeCut( adjusted_coeffs_index++; } - if (coeff == 0) - continue; + if (coeff == 0) continue; const IntegerValue new_coeff = f(coeff); const double new_coeff_double = ToDouble(new_coeff); const double lp_value = relevant_lp_values_[i]; @@ -1009,8 +977,7 @@ void IntegerRoundingCutHelper::ComputeCut( break; } } - if (early_abort) - continue; + if (early_abort) continue; // Here we scale by the L2 norm over the "relevant" positions. This seems // to work slighly better in practice. @@ -1039,8 +1006,7 @@ void IntegerRoundingCutHelper::ComputeCut( for (int i = 0; i < relevant_indices_.size(); ++i) { const int index = relevant_indices_[i]; const IntegerValue diff = relevant_bound_diffs_[i]; - if (diff > adjust_threshold) - continue; + if (diff > adjust_threshold) continue; // Adjust coeff of the form k * best_divisor - epsilon. const IntegerValue coeff = cut->coeffs[index]; @@ -1074,8 +1040,7 @@ void IntegerRoundingCutHelper::ComputeCut( const IntegerValue coeff = cut->coeffs[i]; const IntegerValue r = coeff - FloorRatio(coeff, best_divisor) * best_divisor; - if (r > rhs_remainder) - remainders_.push_back(r); + if (r > rhs_remainder) remainders_.push_back(r); } gtl::STLSortAndRemoveDuplicates(&remainders_); if (remainders_.size() <= 100) { @@ -1088,9 +1053,8 @@ void IntegerRoundingCutHelper::ComputeCut( // Note that the complexity seems high 100 * 2 * options.max_scaling, but // this only run on cuts that are already efficient and the inner loop tend // to abort quickly. I didn't see this code in the cpu profile so far. - for (const IntegerValue t : { - IntegerValue(1), GetFactorT(rhs_remainder, best_divisor, max_t) - }) { + for (const IntegerValue t : + {IntegerValue(1), GetFactorT(rhs_remainder, best_divisor, max_t)}) { for (IntegerValue s(2); s <= options.max_scaling; ++s) { const auto g = GetSuperAdditiveRoundingFunction(rhs_remainder, best_divisor, t, s); @@ -1099,10 +1063,8 @@ void IntegerRoundingCutHelper::ComputeCut( const IntegerValue d = g(best_divisor); for (int i = 0; i < best_rs_.size(); ++i) { const IntegerValue temp = g(remainders_[i]); - if (temp * best_d < best_rs_[i] * d) - break; - if (temp * best_d > best_rs_[i] * d) - num_strictly_better++; + if (temp * best_d < best_rs_[i] * d) break; + if (temp * best_d > best_rs_[i] * d) num_strictly_better++; rs_.push_back(temp); } if (rs_.size() == best_rs_.size() && num_strictly_better > 0) { @@ -1126,8 +1088,7 @@ void IntegerRoundingCutHelper::ComputeCut( if (ib_processor != nullptr) { for (int i = 0; i < size; ++i) { const IntegerValue coeff = cut->coeffs[i]; - if (coeff == 0) - continue; + if (coeff == 0) continue; IntegerVariable var = cut->vars[i]; if (change_sign_at_postprocessing_[i]) { @@ -1151,18 +1112,13 @@ void IntegerRoundingCutHelper::ComputeCut( const IntegerValue coeff_b = f(coeff * info.bound_diff) - f(coeff) * info.bound_diff; CHECK_GE(coeff_b, 0); - if (coeff_b == 0) - continue; + if (coeff_b == 0) continue; ++num_lifted_booleans_; if (info.is_positive) { - tmp_terms_.push_back({ - info.bool_var, coeff_b - }); + tmp_terms_.push_back({info.bool_var, coeff_b}); } else { - tmp_terms_.push_back({ - info.bool_var, -coeff_b - }); + tmp_terms_.push_back({info.bool_var, -coeff_b}); cut->ub = CapAdd(-coeff_b.value(), cut->ub.value()); } } @@ -1174,23 +1130,17 @@ void IntegerRoundingCutHelper::ComputeCut( // variables. for (int i = 0; i < size; ++i) { IntegerValue coeff = cut->coeffs[i]; - if (coeff == 0) - continue; + if (coeff == 0) continue; coeff = f(coeff); - if (coeff == 0) - continue; + if (coeff == 0) continue; if (change_sign_at_postprocessing_[i]) { cut->ub = IntegerValue( CapAdd((coeff * -upper_bounds[i]).value(), cut->ub.value())); - tmp_terms_.push_back({ - cut->vars[i], -coeff - }); + tmp_terms_.push_back({cut->vars[i], -coeff}); } else { cut->ub = IntegerValue( CapAdd((coeff * lower_bounds[i]).value(), cut->ub.value())); - tmp_terms_.push_back({ - cut->vars[i], coeff - }); + tmp_terms_.push_back({cut->vars[i], coeff}); } } @@ -1223,17 +1173,13 @@ bool CoverCutHelper::TrySimpleKnapsack( } const IntegerValue diff = positive_coeff * bound_diff; if (coeff > 0) { - if (!AddProductTo(-coeff, lower_bounds[i], &rhs)) - return false; - terms_.push_back({ - i, ToDouble(upper_bounds[i]) - lp_values[i], positive_coeff, diff - }); + if (!AddProductTo(-coeff, lower_bounds[i], &rhs)) return false; + terms_.push_back( + {i, ToDouble(upper_bounds[i]) - lp_values[i], positive_coeff, diff}); } else { - if (!AddProductTo(-coeff, upper_bounds[i], &rhs)) - return false; - terms_.push_back({ - i, lp_values[i] - ToDouble(lower_bounds[i]), positive_coeff, diff - }); + if (!AddProductTo(-coeff, upper_bounds[i], &rhs)) return false; + terms_.push_back( + {i, lp_values[i] - ToDouble(lower_bounds[i]), positive_coeff, diff}); } } @@ -1241,7 +1187,7 @@ bool CoverCutHelper::TrySimpleKnapsack( // Look for violated CUT of the form: sum (UB - X) or (X - LB) >= 1. double activity = 0.0; int new_size = 0; - std::sort(terms_.begin(), terms_.end(), [](const Term & a, const Term & b) { + std::sort(terms_.begin(), terms_.end(), [](const Term &a, const Term &b) { if (a.dist_to_max_value == b.dist_to_max_value) { // Prefer low coefficients if the distance is the same. return a.positive_coeff < b.positive_coeff; @@ -1260,7 +1206,7 @@ bool CoverCutHelper::TrySimpleKnapsack( // TODO(user): experiment with different threshold (even greater than one). // Or come up with an algo that incorporate the lifting into the heuristic. if (activity > 1.0) { - new_size = i; // before this entry. + new_size = i; // before this entry. break; } @@ -1274,10 +1220,8 @@ bool CoverCutHelper::TrySimpleKnapsack( // possible violation. Note also that we lift as much as possible, so we don't // necessarilly optimize for the cut efficacity though. But we do get a // stronger cut. - if (rhs >= 0) - return false; - if (new_size == 0) - return false; + if (rhs >= 0) return false; + if (new_size == 0) return false; // Transform to a minimal cover. We want to greedily remove the largest coeff // first, so we have more chance for the "lifting" below which can increase @@ -1286,7 +1230,7 @@ bool CoverCutHelper::TrySimpleKnapsack( // // We compute the cut at the same time. terms_.resize(new_size); - std::sort(terms_.begin(), terms_.end(), [](const Term & a, const Term & b) { + std::sort(terms_.begin(), terms_.end(), [](const Term &a, const Term &b) { if (a.positive_coeff == b.positive_coeff) { return a.dist_to_max_value > b.dist_to_max_value; } @@ -1318,8 +1262,7 @@ bool CoverCutHelper::TrySimpleKnapsack( // tighten the cut a bit more. // // Note(user): I never observed this on the miplib so far. - if (max_coeff == 0) - return true; + if (max_coeff == 0) return true; if (max_coeff < -rhs) { const IntegerValue m = FloorRatio(-rhs - 1, max_coeff); rhs += max_coeff * m; @@ -1350,19 +1293,16 @@ bool CoverCutHelper::TrySimpleKnapsack( const IntegerValue scaling = f(max_coeff); if (scaling > 1) { - for (int i = 0; i < cut_.coeffs.size(); ++i) - cut_.coeffs[i] *= scaling; + for (int i = 0; i < cut_.coeffs.size(); ++i) cut_.coeffs[i] *= scaling; cut_.ub *= scaling; } num_lifting_ = 0; for (int i = 0; i < base_size; ++i) { - if (in_cut_[i]) - continue; + if (in_cut_[i]) continue; const IntegerValue positive_coeff = IntTypeAbs(base_ct.coeffs[i]); const IntegerValue new_coeff = f(positive_coeff); - if (new_coeff == 0) - continue; + if (new_coeff == 0) continue; ++num_lifting_; if (base_ct.coeffs[i] > 0) { @@ -1378,8 +1318,7 @@ bool CoverCutHelper::TrySimpleKnapsack( } } - if (scaling > 1) - DivideByGCD(&cut_); + if (scaling > 1) DivideByGCD(&cut_); return true; } @@ -1388,21 +1327,20 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, IntegerVariable y, Model *model) { CutGenerator result; - result.vars = { z, x, y }; + result.vars = {z, x, y}; IntegerTrail *const integer_trail = model->GetOrCreate(); - result.generate_cuts = [z, x, y, integer_trail]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + result.generate_cuts = + [z, x, y, integer_trail]( + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { const int64 x_lb = integer_trail->LevelZeroLowerBound(x).value(); const int64 x_ub = integer_trail->LevelZeroUpperBound(x).value(); const int64 y_lb = integer_trail->LevelZeroLowerBound(y).value(); const int64 y_ub = integer_trail->LevelZeroUpperBound(y).value(); // TODO(user): Compute a better bound (int_max / 4 ?). - const int64 kMaxSafeInteger = (int64 { - 1 - } << 53) - 1; + const int64 kMaxSafeInteger = (int64{1} << 53) - 1; if (CapProd(x_ub, y_ub) >= kMaxSafeInteger) { VLOG(3) << "Potential overflow in PositiveMultiplicationCutGenerator"; @@ -1419,9 +1357,9 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, // callback. // Cut -z + x_coeff * x + y_coeff* y <= rhs - auto try_add_above_cut = - [manager, z_lp_value, x_lp_value, y_lp_value, x, y, z, &lp_values]( - int64 x_coeff, int64 y_coeff, int64 rhs) { + auto try_add_above_cut = [manager, z_lp_value, x_lp_value, y_lp_value, + x, y, z, &lp_values]( + int64 x_coeff, int64 y_coeff, int64 rhs) { if (-z_lp_value + x_lp_value * x_coeff + y_lp_value * y_coeff >= rhs + kMinCutViolation) { LinearConstraint cut; @@ -1439,13 +1377,12 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, cut.ub = IntegerValue(rhs); manager->AddCut(cut, "PositiveProduct", lp_values); } - } - ; + }; // Cut -z + x_coeff * x + y_coeff* y >= rhs - auto try_add_below_cut = - [manager, z_lp_value, x_lp_value, y_lp_value, x, y, z, &lp_values]( - int64 x_coeff, int64 y_coeff, int64 rhs) { + auto try_add_below_cut = [manager, z_lp_value, x_lp_value, y_lp_value, + x, y, z, &lp_values]( + int64 x_coeff, int64 y_coeff, int64 rhs) { if (-z_lp_value + x_lp_value * x_coeff + y_lp_value * y_coeff <= rhs - kMinCutViolation) { LinearConstraint cut; @@ -1463,8 +1400,7 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, cut.ub = kMaxIntegerValue; manager->AddCut(cut, "PositiveProduct", lp_values); } - } - ; + }; // McCormick relaxation of bilinear constraints. These 4 cuts are the // exact facets of the x * y polyhedron for a bounded x and y. @@ -1477,8 +1413,7 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, try_add_above_cut(y_ub, x_ub, x_ub * y_ub); try_add_below_cut(y_ub, x_lb, x_lb * y_ub); try_add_below_cut(y_lb, x_ub, x_ub * y_lb); - } - ; + }; return result; } @@ -1486,23 +1421,20 @@ CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, CutGenerator CreateSquareCutGenerator(IntegerVariable y, IntegerVariable x, Model *model) { CutGenerator result; - result.vars = { y, x }; + result.vars = {y, x}; IntegerTrail *integer_trail = model->GetOrCreate(); - result.generate_cuts = [y, x, integer_trail]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + result.generate_cuts = + [y, x, integer_trail]( + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { const int64 x_ub = integer_trail->LevelZeroUpperBound(x).value(); const int64 x_lb = integer_trail->LevelZeroLowerBound(x).value(); - if (x_lb == x_ub) - return; + if (x_lb == x_ub) return; // Check for potential overflows. - if (x_ub > (int64 { - 1 - } << 31)) - return; + if (x_ub > (int64{1} << 31)) return; DCHECK_GE(x_lb, 0); const double y_lp_value = lp_values[y]; @@ -1548,8 +1480,7 @@ CutGenerator CreateSquareCutGenerator(IntegerVariable y, IntegerVariable x, below_cut.ub = kMaxIntegerValue; manager->AddCut(below_cut, "SquareLower", lp_values); } - } - ; + }; return result; } @@ -1558,15 +1489,14 @@ void ImpliedBoundsProcessor::ProcessUpperBoundedConstraint( const gtl::ITIVector &lp_values, LinearConstraint *cut) { ProcessUpperBoundedConstraintWithSlackCreation( - /*substitute_only_inner_variables=*/ false, IntegerVariable(0), lp_values, + /*substitute_only_inner_variables=*/false, IntegerVariable(0), lp_values, cut, nullptr); } ImpliedBoundsProcessor::BestImpliedBoundInfo ImpliedBoundsProcessor::GetCachedImpliedBoundInfo(IntegerVariable var) { auto it = cache_.find(var); - if (it != cache_.end()) - return it->second; + if (it != cache_.end()) return it->second; return BestImpliedBoundInfo(); } @@ -1575,8 +1505,7 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound( IntegerVariable var, const gtl::ITIVector &lp_values) { auto it = cache_.find(var); - if (it != cache_.end()) - return it->second; + if (it != cache_.end()) return it->second; BestImpliedBoundInfo result; const IntegerValue lb = integer_trail_->LevelZeroLowerBound(var); for (const ImpliedBoundEntry &entry : @@ -1594,9 +1523,9 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound( // and slack in [0, ub - lb]. const IntegerValue diff = entry.lower_bound - lb; CHECK_GE(diff, 0); - const double bool_lp_value = - entry.is_positive ? lp_values[entry.literal_view] - : 1.0 - lp_values[entry.literal_view]; + const double bool_lp_value = entry.is_positive + ? lp_values[entry.literal_view] + : 1.0 - lp_values[entry.literal_view]; const double slack_lp_value = lp_values[var] - ToDouble(lb) - bool_lp_value * ToDouble(diff); @@ -1608,21 +1537,13 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound( std::vector > terms; if (entry.is_positive) { // X >= Indicator * (bound - lb) + lb - terms.push_back({ - entry.literal_view, diff - }); - terms.push_back({ - var, IntegerValue(-1) - }); + terms.push_back({entry.literal_view, diff}); + terms.push_back({var, IntegerValue(-1)}); ib_cut.ub = -lb; } else { // X >= -Indicator * (bound - lb) + bound - terms.push_back({ - entry.literal_view, -diff - }); - terms.push_back({ - var, IntegerValue(-1) - }); + terms.push_back({entry.literal_view, -diff}); + terms.push_back({var, IntegerValue(-1)}); ib_cut.ub = -entry.lower_bound; } CleanTermsAndFillConstraint(&terms, &ib_cut); @@ -1652,8 +1573,7 @@ void ImpliedBoundsProcessor::SeparateSomeImpliedBoundCuts( const gtl::ITIVector &lp_values) { for (const IntegerVariable var : implied_bounds_->VariablesWithImpliedBounds()) { - if (!lp_vars_.contains(PositiveVariable(var))) - continue; + if (!lp_vars_.contains(PositiveVariable(var))) continue; ComputeBestImpliedBound(var, lp_values); } } @@ -1698,8 +1618,7 @@ void ImpliedBoundsProcessor::ProcessUpperBoundedConstraintWithSlackCreation( // Shall we keep the original term ? bool keep_term = false; - if (info.bool_var == kNoIntegerVariable) - keep_term = true; + if (info.bool_var == kNoIntegerVariable) keep_term = true; if (CapProd(std::abs(coeff.value()), info.bound_diff.value()) == kint64max) { keep_term = true; @@ -1715,24 +1634,19 @@ void ImpliedBoundsProcessor::ProcessUpperBoundedConstraintWithSlackCreation( if (substitute_only_inner_variables) { const IntegerValue lb = integer_trail_->LevelZeroLowerBound(var); const IntegerValue ub = integer_trail_->LevelZeroUpperBound(var); - if (lp_values[var] - ToDouble(lb) < 1e-2) - keep_term = true; - if (ToDouble(ub) - lp_values[var] < 1e-2) - keep_term = true; + if (lp_values[var] - ToDouble(lb) < 1e-2) keep_term = true; + if (ToDouble(ub) - lp_values[var] < 1e-2) keep_term = true; } // This is when we do not add slack. if (slack_infos == nullptr) { // We do not want to loose anything, so we only replace if the slack lp is // zero. - if (info.slack_lp_value > 1e-6) - keep_term = true; + if (info.slack_lp_value > 1e-6) keep_term = true; } if (keep_term) { - tmp_terms_.push_back({ - var, coeff - }); + tmp_terms_.push_back({var, coeff}); } else { // Substitute. const IntegerValue lb = integer_trail_->LevelZeroLowerBound(var); @@ -1745,52 +1659,36 @@ void ImpliedBoundsProcessor::ProcessUpperBoundedConstraintWithSlackCreation( if (info.is_positive) { // X = Indicator * diff + lb + Slack - tmp_terms_.push_back({ - info.bool_var, coeff *info.bound_diff - }); + tmp_terms_.push_back({info.bool_var, coeff * info.bound_diff}); if (!AddProductTo(-coeff, lb, &new_ub)) { VLOG(2) << "Overflow"; return; } if (slack_infos != nullptr) { - tmp_terms_.push_back({ - first_slack, coeff - }); + tmp_terms_.push_back({first_slack, coeff}); first_slack += 2; // slack = X - Indicator * info.bound_diff - lb; - slack_info.terms.push_back({ - var, IntegerValue(1) - }); - slack_info.terms.push_back({ - info.bool_var, -info.bound_diff - }); + slack_info.terms.push_back({var, IntegerValue(1)}); + slack_info.terms.push_back({info.bool_var, -info.bound_diff}); slack_info.offset = -lb; slack_infos->push_back(slack_info); } } else { // X = (1 - Indicator) * (diff) + lb + Slack // X = -Indicator * (diff) + lb + diff + Slack - tmp_terms_.push_back({ - info.bool_var, -coeff *info.bound_diff - }); + tmp_terms_.push_back({info.bool_var, -coeff * info.bound_diff}); if (!AddProductTo(-coeff, lb + info.bound_diff, &new_ub)) { VLOG(2) << "Overflow"; return; } if (slack_infos != nullptr) { - tmp_terms_.push_back({ - first_slack, coeff - }); + tmp_terms_.push_back({first_slack, coeff}); first_slack += 2; // slack = X + Indicator * info.bound_diff - lb - diff; - slack_info.terms.push_back({ - var, IntegerValue(1) - }); - slack_info.terms.push_back({ - info.bool_var, +info.bound_diff - }); + slack_info.terms.push_back({var, IntegerValue(1)}); + slack_info.terms.push_back({info.bool_var, +info.bound_diff}); slack_info.offset = -lb - info.bound_diff; slack_infos->push_back(slack_info); } @@ -1810,14 +1708,13 @@ void ImpliedBoundsProcessor::ProcessUpperBoundedConstraintWithSlackCreation( VLOG(2) << "Overflow"; return; } - if (!changed) - return; + if (!changed) return; // Update the cut. // // Note that because of our overflow_detection variable, there should be // no integer overflow when we merge identical terms. - cut->lb = kMinIntegerValue; // Not relevant. + cut->lb = kMinIntegerValue; // Not relevant. cut->ub = new_ub; CleanTermsAndFillConstraint(&tmp_terms_, cut); } @@ -1831,9 +1728,7 @@ bool ImpliedBoundsProcessor::DebugSlack(IntegerVariable first_slack, for (int i = 0; i < cut.vars.size(); ++i) { // Simple copy for non-slack variables. if (cut.vars[i] < first_slack) { - tmp_terms_.push_back({ - cut.vars[i], cut.coeffs[i] - }); + tmp_terms_.push_back({cut.vars[i], cut.coeffs[i]}); continue; } @@ -1842,15 +1737,13 @@ bool ImpliedBoundsProcessor::DebugSlack(IntegerVariable first_slack, const int index = (cut.vars[i].value() - first_slack.value()) / 2; for (const std::pair &term : info[index].terms) { - tmp_terms_.push_back({ - term.first, term.second *multiplier - }); + tmp_terms_.push_back({term.first, term.second * multiplier}); } new_ub -= multiplier * info[index].offset; } LinearConstraint tmp_cut; - tmp_cut.lb = kMinIntegerValue; // Not relevant. + tmp_cut.lb = kMinIntegerValue; // Not relevant. tmp_cut.ub = new_ub; CleanTermsAndFillConstraint(&tmp_terms_, &tmp_cut); MakeAllVariablesPositive(&tmp_cut); @@ -1862,17 +1755,14 @@ bool ImpliedBoundsProcessor::DebugSlack(IntegerVariable first_slack, LinearConstraint tmp_copy; tmp_terms_.clear(); for (int i = 0; i < initial_cut.vars.size(); ++i) { - tmp_terms_.push_back({ - initial_cut.vars[i], initial_cut.coeffs[i] - }); + tmp_terms_.push_back({initial_cut.vars[i], initial_cut.coeffs[i]}); } - tmp_copy.lb = kMinIntegerValue; // Not relevant. + tmp_copy.lb = kMinIntegerValue; // Not relevant. tmp_copy.ub = new_ub; CleanTermsAndFillConstraint(&tmp_terms_, &tmp_copy); MakeAllVariablesPositive(&tmp_copy); - if (tmp_cut == tmp_copy) - return true; + if (tmp_cut == tmp_copy) return true; LOG(INFO) << first_slack; LOG(INFO) << tmp_copy.DebugString(); @@ -1920,23 +1810,22 @@ void TryToGenerateAllDiffCut( } } -} // namespace +} // namespace -CutGenerator -CreateAllDifferentCutGenerator(const std::vector &vars, - Model *model) { +CutGenerator CreateAllDifferentCutGenerator( + const std::vector &vars, Model *model) { CutGenerator result; result.vars = vars; IntegerTrail *integer_trail = model->GetOrCreate(); Trail *trail = model->GetOrCreate(); - result.generate_cuts = [vars, integer_trail, trail]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + result.generate_cuts = + [vars, integer_trail, trail]( + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { // These cuts work at all levels but the generator adds too many cuts on // some instances and degrade the performance so we only use it at level // 0. - if (trail->CurrentDecisionLevel() > 0) - return; + if (trail->CurrentDecisionLevel() > 0) return; std::vector > sorted_vars; for (const IntegerVariable var : vars) { if (integer_trail->LevelZeroLowerBound(var) == @@ -1952,8 +1841,7 @@ CreateAllDifferentCutGenerator(const std::vector &vars, std::reverse(sorted_vars.begin(), sorted_vars.end()); TryToGenerateAllDiffCut(sorted_vars, *integer_trail, lp_values, manager); - } - ; + }; VLOG(1) << "Created all_diff cut generator of size: " << vars.size(); return result; } @@ -1975,11 +1863,11 @@ IntegerValue MaxCornerDifference(const IntegerVariable var, // = max corner difference for variable i, // target expr I(i), max expr k. // The coefficient of zk is Sum(i=1..n)(MPlusCoefficient_ki) + bk -IntegerValue -MPlusCoefficient(const std::vector &x_vars, - const std::vector &exprs, - const gtl::ITIVector &variable_partition, - const int max_index, const IntegerTrail &integer_trail) { +IntegerValue MPlusCoefficient( + const std::vector &x_vars, + const std::vector &exprs, + const gtl::ITIVector &variable_partition, + const int max_index, const IntegerTrail &integer_trail) { IntegerValue coeff = exprs[max_index].offset; // TODO(user): This algo is quadratic since GetCoefficientOfPositiveVar() // is linear. This can be optimized (better complexity) if needed. @@ -1997,12 +1885,11 @@ MPlusCoefficient(const std::vector &x_vars, // Compute the value of // rhs = wI(i)i * xi + Sum(k=1..d)(MPlusCoefficient_ki * zk) // for variable xi for given target index I(i). -double -ComputeContribution(const IntegerVariable xi_var, - const std::vector &z_vars, - const std::vector &exprs, - const gtl::ITIVector &lp_values, - const IntegerTrail &integer_trail, const int target_index) { +double ComputeContribution( + const IntegerVariable xi_var, const std::vector &z_vars, + const std::vector &exprs, + const gtl::ITIVector &lp_values, + const IntegerTrail &integer_trail, const int target_index) { CHECK_GE(target_index, 0); CHECK_LT(target_index, exprs.size()); const LinearExpression &target_expr = exprs[target_index]; @@ -2010,8 +1897,7 @@ ComputeContribution(const IntegerVariable xi_var, const IntegerValue wt_i = GetCoefficientOfPositiveVar(xi_var, target_expr); double contrib = wt_i.value() * xi_value; for (int expr_index = 0; expr_index < exprs.size(); ++expr_index) { - if (expr_index == target_index) - continue; + if (expr_index == target_index) continue; const LinearExpression &max_expr = exprs[expr_index]; const double z_max_value = lp_values[z_vars[expr_index]]; const IntegerValue corner_value = MaxCornerDifference( @@ -2021,14 +1907,14 @@ ComputeContribution(const IntegerVariable xi_var, } return contrib; } -} // namespace +} // namespace CutGenerator CreateLinMaxCutGenerator( const IntegerVariable target, const std::vector &exprs, const std::vector &z_vars, Model *model) { CutGenerator result; std::vector x_vars; - result.vars = { target }; + result.vars = {target}; const int num_exprs = exprs.size(); for (int i = 0; i < num_exprs; ++i) { result.vars.push_back(z_vars[i]); @@ -2044,8 +1930,8 @@ CutGenerator CreateLinMaxCutGenerator( IntegerTrail *integer_trail = model->GetOrCreate(); result.generate_cuts = [x_vars, z_vars, target, num_exprs, exprs, integer_trail, model]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { gtl::ITIVector variable_partition( lp_values.size(), -1); gtl::ITIVector variable_partition_contrib( @@ -2062,8 +1948,8 @@ CutGenerator CreateLinMaxCutGenerator( } } - LinearConstraintBuilder cut(model, /*lb=*/ IntegerValue(0), - /*ub=*/ kMaxIntegerValue); + LinearConstraintBuilder cut(model, /*lb=*/IntegerValue(0), + /*ub=*/kMaxIntegerValue); double violation = lp_values[target]; cut.AddTerm(target, IntegerValue(-1)); @@ -2088,8 +1974,7 @@ CutGenerator CreateLinMaxCutGenerator( if (violation > 1e-2) { manager->AddCut(cut.Build(), "LinMax", lp_values); } - } - ; + }; return result; } @@ -2132,25 +2017,22 @@ GenerateCumulativeCut(const std::string &cut_name, IntegerTrail *integer_trail = model->GetOrCreate(); IntegerEncoder *encoder = model->GetOrCreate(); - return[capacity, demands, trail, integer_trail, helper, model, cut_name, - encoder](const gtl::ITIVector & lp_values, - LinearConstraintManager * - manager) { if (trail->CurrentDecisionLevel() > 0) return; + return [capacity, demands, trail, integer_trail, helper, model, cut_name, + encoder](const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { + if (trail->CurrentDecisionLevel() > 0) return; const auto demand_is_fixed = [integer_trail, &demands](int i) { return demands.empty() || integer_trail->IsFixed(demands[i]); - } - ; + }; const auto demand_min = [integer_trail, &demands](int i) { return demands.empty() ? IntegerValue(1) : integer_trail->LowerBound(demands[i]); - } - ; + }; const auto demand_max = [integer_trail, &demands](int i) { return demands.empty() ? IntegerValue(1) : integer_trail->UpperBound(demands[i]); - } - ; + }; std::vector active_intervals; for (int i = 0; i < helper->NumTasks(); ++i) { @@ -2159,15 +2041,14 @@ GenerateCumulativeCut(const std::string &cut_name, } } - if (active_intervals.size() < 2) - return; + if (active_intervals.size() < 2) return; std::sort(active_intervals.begin(), active_intervals.end(), [helper](int a, int b) { return helper->StartMin(a) < helper->StartMin(b) || (helper->StartMin(a) == helper->StartMin(b) && helper->EndMax(a) < helper->EndMax(b)); - }); + }); const IntegerValue capacity_max = integer_trail->UpperBound(capacity); IntegerValue processed_start = kMinIntegerValue; @@ -2198,10 +2079,9 @@ GenerateCumulativeCut(const std::string &cut_name, // increasing end max. std::vector residual_tasks(active_intervals.begin() + i1, active_intervals.end()); - std::sort(residual_tasks.begin(), residual_tasks.end(), - [&](int a, int b) { - return helper->EndMax(a) < helper->EndMax(b); - }); + std::sort( + residual_tasks.begin(), residual_tasks.end(), + [&](int a, int b) { return helper->EndMax(a) < helper->EndMax(b); }); // Let's process residual tasks and evaluate the cut violation of the cut // at each step. We follow the same structure as the cut creation code @@ -2219,7 +2099,7 @@ GenerateCumulativeCut(const std::string &cut_name, } else if (helper->SizeIsFixed(t)) { DCHECK(!demands.empty()); energy_lp += lp_values[demands[t]] * ToDouble(helper->SizeMin(t)); - } else { // demand and size are not fixed. + } else { // demand and size are not fixed. DCHECK(!demands.empty()); energy_lp += ToDouble(demand_min(t)) * lp_values[helper->SizeVars()[t]]; @@ -2245,8 +2125,7 @@ GenerateCumulativeCut(const std::string &cut_name, } } - if (end_index_of_max_violation == -1) - continue; + if (end_index_of_max_violation == -1) continue; // A maximal violated cut has been found. bool cut_generated = true; @@ -2269,7 +2148,7 @@ GenerateCumulativeCut(const std::string &cut_name, } else if (helper->SizeIsFixed(t)) { DCHECK(!demands.empty()); cut.AddTerm(demands[t], helper->SizeMin(t)); - } else { // demand and size are not fixed. + } else { // demand and size are not fixed. DCHECK(!demands.empty()); // We use McCormick equation. // demand * size = (demand_min + delta_d) * (min_size + @@ -2300,23 +2179,19 @@ GenerateCumulativeCut(const std::string &cut_name, if (cut_generated) { std::string full_name = cut_name; - if (has_opt_cuts) - full_name.append("_opt"); - if (has_quadratic_cuts) - full_name.append("_quad"); + if (has_opt_cuts) full_name.append("_opt"); + if (has_quadratic_cuts) full_name.append("_quad"); manager->AddCut(cut.Build(), cut_name, lp_values); } } - } - ; + }; } -CutGenerator -CreateCumulativeCutGenerator(const std::vector &intervals, - const IntegerVariable capacity, - const std::vector &demands, - Model *model) { +CutGenerator CreateCumulativeCutGenerator( + const std::vector &intervals, + const IntegerVariable capacity, const std::vector &demands, + Model *model) { CutGenerator result; SchedulingConstraintHelper *helper = @@ -2358,23 +2233,20 @@ CutGenerator CreateOverlappingCumulativeCutGenerator( result.generate_cuts = [helper, capacity, demands, trail, integer_trail, model]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { - if (trail->CurrentDecisionLevel() > 0) - return; + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { + if (trail->CurrentDecisionLevel() > 0) return; std::vector events; // Iterate through the intervals. If start_max < end_min, the demand // is mandatory. for (int i = 0; i < helper->NumTasks(); ++i) { - if (helper->IsAbsent(i)) - continue; + if (helper->IsAbsent(i)) continue; const IntegerValue start_max = helper->StartMax(i); const IntegerValue end_min = helper->EndMin(i); - if (start_max >= end_min) - continue; + if (start_max >= end_min) continue; Event e1; e1.interval_index = i; @@ -2401,7 +2273,7 @@ CutGenerator CreateOverlappingCumulativeCutGenerator( return !i.positive; } return i.time < j.time; - }); + }); std::vector cut_events; bool added_positive_event = false; @@ -2424,8 +2296,7 @@ CutGenerator CreateOverlappingCumulativeCutGenerator( cut_generated &= cut.AddLiteralTerm( helper->PresenceLiteral(cut_event.interval_index), integer_trail->LowerBound(cut_event.demand)); - if (!cut_generated) - break; + if (!cut_generated) break; } } if (cut_generated) { @@ -2446,14 +2317,12 @@ CutGenerator CreateOverlappingCumulativeCutGenerator( cut_events.resize(new_size); added_positive_event = false; } - } - ; + }; return result; } -CutGenerator -CreateNoOverlapCutGenerator(const std::vector &intervals, - Model *model) { +CutGenerator CreateNoOverlapCutGenerator( + const std::vector &intervals, Model *model) { CutGenerator result; SchedulingConstraintHelper *helper = @@ -2463,9 +2332,8 @@ CreateNoOverlapCutGenerator(const std::vector &intervals, AddIntegerVariableFromIntervals(helper, model, &result.vars); result.generate_cuts = GenerateCumulativeCut( - "NoOverlapEnergy", helper, /*demands=*/ { - }, - /*capacity=*/ AffineExpression(IntegerValue(1)), model); + "NoOverlapEnergy", helper, /*demands=*/{}, + /*capacity=*/AffineExpression(IntegerValue(1)), model); return result; } @@ -2481,11 +2349,11 @@ CutGenerator CreateNoOverlapPrecedenceCutGenerator( Trail *trail = model->GetOrCreate(); - result.generate_cuts = [trail, helper, model]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { - if (trail->CurrentDecisionLevel() > 0) - return; + result.generate_cuts = + [trail, helper, model]( + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { + if (trail->CurrentDecisionLevel() > 0) return; // TODO(user): We can do much better in term of complexity: // Sort all tasks by min start time, loop other them 1 by 1, @@ -2496,11 +2364,9 @@ CutGenerator CreateNoOverlapPrecedenceCutGenerator( // the same cuts over and over again. It is okay because AddCut() will // not add duplicate cuts, but it might not be the most efficient way. for (int index1 = 0; index1 < helper->NumTasks(); ++index1) { - if (!helper->IsPresent(index1)) - continue; + if (!helper->IsPresent(index1)) continue; for (int index2 = index1 + 1; index2 < helper->NumTasks(); ++index2) { - if (!helper->IsPresent(index2)) - continue; + if (!helper->IsPresent(index2)) continue; // Encode only the interesting pairs. if (helper->EndMax(index1) <= helper->StartMin(index2) || @@ -2530,14 +2396,12 @@ CutGenerator CreateNoOverlapPrecedenceCutGenerator( } } } - } - ; + }; return result; } -CutGenerator -CreateCliqueCutGenerator(const std::vector &base_variables, - Model *model) { +CutGenerator CreateCliqueCutGenerator( + const std::vector &base_variables, Model *model) { // Filter base_variables to only keep the one with a literal view, and // do the conversion. std::vector variables; @@ -2547,10 +2411,8 @@ CreateCliqueCutGenerator(const std::vector &base_variables, auto *integer_trail = model->GetOrCreate(); auto *encoder = model->GetOrCreate(); for (const IntegerVariable var : base_variables) { - if (integer_trail->LowerBound(var) != IntegerValue(0)) - continue; - if (integer_trail->UpperBound(var) != IntegerValue(1)) - continue; + if (integer_trail->LowerBound(var) != IntegerValue(0)) continue; + if (integer_trail->UpperBound(var) != IntegerValue(1)) continue; const LiteralIndex literal_index = encoder->GetAssociatedLiteral( IntegerLiteral::GreaterOrEqual(var, IntegerValue(1))); if (literal_index != kNoLiteralIndex) { @@ -2565,8 +2427,8 @@ CreateCliqueCutGenerator(const std::vector &base_variables, auto *implication_graph = model->GetOrCreate(); result.generate_cuts = [variables, literals, implication_graph, positive_map, negative_map, - model](const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + model](const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { std::vector packed_values; for (int i = 0; i < literals.size(); ++i) { packed_values.push_back(lp_values[variables[i]]); @@ -2593,10 +2455,9 @@ CreateCliqueCutGenerator(const std::vector &base_variables, manager->AddCut(builder.Build(), "clique", lp_values); } - } - ; + }; return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/cuts.h b/ortools/sat/cuts.h index 8a10c784a2..c0508d396b 100644 --- a/ortools/sat/cuts.h +++ b/ortools/sat/cuts.h @@ -40,7 +40,8 @@ namespace sat { struct CutGenerator { std::vector vars; std::function &lp_values, - LinearConstraintManager *manager)> generate_cuts; + LinearConstraintManager *manager)> + generate_cuts; }; // Given an upper-bounded linear relation (sum terms <= ub), this algorithm @@ -51,13 +52,14 @@ struct CutGenerator { // // We use a class to reuse memory of the tmp terms. class ImpliedBoundsProcessor { -public: + public: // We will only replace IntegerVariable appearing in lp_vars_. ImpliedBoundsProcessor(absl::Span lp_vars_, IntegerTrail *integer_trail, ImpliedBounds *implied_bounds) : lp_vars_(lp_vars_.begin(), lp_vars_.end()), - integer_trail_(integer_trail), implied_bounds_(implied_bounds) {} + integer_trail_(integer_trail), + implied_bounds_(implied_bounds) {} // Processes and updates the given cut. void ProcessUpperBoundedConstraint( @@ -120,7 +122,7 @@ public: // cuts here. TopNCuts &IbCutPool() { return ib_cut_pool_; } -private: + private: BestImpliedBoundInfo ComputeBestImpliedBound( IntegerVariable var, const gtl::ITIVector &lp_values); @@ -169,10 +171,9 @@ private: // max_scaling. IntegerValue GetFactorT(IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue max_t); -std::function - GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, - IntegerValue divisor, IntegerValue t, - IntegerValue max_scaling); +std::function GetSuperAdditiveRoundingFunction( + IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue t, + IntegerValue max_scaling); // Given an upper bounded linear constraint, this function tries to transform it // to a valid cut that violate the given LP solution using integer rounding. @@ -207,7 +208,7 @@ struct RoundingOptions { IntegerValue max_scaling = IntegerValue(60); }; class IntegerRoundingCutHelper { -public: + public: void ComputeCut(RoundingOptions options, const std::vector &lp_values, const std::vector &lower_bounds, const std::vector &upper_bounds, @@ -217,7 +218,7 @@ public: // ComputeCut() call. Useful for investigation. int NumLiftedBooleans() const { return num_lifted_booleans_; } -private: + private: // The helper is just here to reuse the memory for these vectors. std::vector relevant_indices_; std::vector relevant_lp_values_; @@ -236,7 +237,7 @@ private: // Helper to find knapsack or flow cover cuts (not yet implemented). class CoverCutHelper { -public: + public: // Try to find a cut with a knapsack heuristic. // If this returns true, you can get the cut via cut(). bool TrySimpleKnapsack(const LinearConstraint base_ct, @@ -251,11 +252,11 @@ public: // Single line of text that we append to the cut log line. const std::string Info() { return absl::StrCat("lift=", num_lifting_); } -private: + private: struct Term { int index; double dist_to_max_value; - IntegerValue positive_coeff; // abs(coeff in original constraint). + IntegerValue positive_coeff; // abs(coeff in original constraint). IntegerValue diff; }; std::vector terms_; @@ -425,9 +426,8 @@ CutGenerator CreateSquareCutGenerator(IntegerVariable y, IntegerVariable x, // D. The cut generator first sorts the variables based on LP values and adds // cuts of the form described above if they are violated by lp solution. Note // that all the fixed variables are ignored while generating cuts. -CutGenerator - CreateAllDifferentCutGenerator(const std::vector &vars, - Model *model); +CutGenerator CreateAllDifferentCutGenerator( + const std::vector &vars, Model *model); // Consider the Lin Max constraint with d expressions and n variables in the // form: target = max {exprs[k] = Sum (wki * xi + bk)}. k in {1,..,d}. @@ -482,11 +482,10 @@ CutGenerator CreateLinMaxCutGenerator( // demand * min_size. We choose the most violated formulation. // // The maximum energy is capacity * span of intervals at level 0. -CutGenerator - CreateCumulativeCutGenerator(const std::vector &intervals, - const IntegerVariable capacity, - const std::vector &demands, - Model *model); +CutGenerator CreateCumulativeCutGenerator( + const std::vector &intervals, + const IntegerVariable capacity, const std::vector &demands, + Model *model); // For a given set of intervals and demands, we first compute the mandatory part // of the interval as [start_max , end_min]. We use this to calculate mandatory @@ -513,9 +512,8 @@ CutGenerator CreateOverlappingCumulativeCutGenerator( // as follows: // sum(sizes of always present intervals) // + sum(presence_literal * min_of_size) <= span of all intervals. -CutGenerator - CreateNoOverlapCutGenerator(const std::vector &intervals, - Model *model); +CutGenerator CreateNoOverlapCutGenerator( + const std::vector &intervals, Model *model); // For a given set of intervals in a no_overlap constraint, we detect violated // mandatory precedences and create a cut for these. @@ -525,11 +523,10 @@ CutGenerator CreateNoOverlapPrecedenceCutGenerator( // Extracts the variables that have a Literal view from base variables and // create a generator that will returns constraint of the form "at_most_one" // between such literals. -CutGenerator - CreateCliqueCutGenerator(const std::vector &base_variables, - Model *model); +CutGenerator CreateCliqueCutGenerator( + const std::vector &base_variables, Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_CUTS_H_ +#endif // OR_TOOLS_SAT_CUTS_H_ diff --git a/ortools/sat/diffn.cc b/ortools/sat/diffn.cc index 96dd121ad6..e7d8c22cbc 100644 --- a/ortools/sat/diffn.cc +++ b/ortools/sat/diffn.cc @@ -60,11 +60,10 @@ void AddCumulativeRelaxation(const std::vector &x_intervals, // (max_end - min_start) >= capacity. const AffineExpression capacity( model->Add(NewIntegerVariable(0, CapSub(max_ends, min_starts)))); - const std::vector coeffs = { -capacity.coeff.value(), -1, 1 }; - model->Add(WeightedSumGreaterOrEqual({ - capacity.var, min_start_var, max_end_var - }, - coeffs, capacity.constant.value())); + const std::vector coeffs = {-capacity.coeff.value(), -1, 1}; + model->Add( + WeightedSumGreaterOrEqual({capacity.var, min_start_var, max_end_var}, + coeffs, capacity.constant.value())); model->Add(Cumulative(x_intervals, sizes, capacity, x)); } @@ -76,10 +75,8 @@ namespace { // when explaining that boxes overlap on the 'y_dim' dimension. We compute // the multiple of the biggest power of two that is common to all boxes. IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) { - if (lb == ub) - return lb; - if (lb <= 0 && ub > 0) - return IntegerValue(0); + if (lb == ub) return lb; + if (lb <= 0 && ub > 0) return IntegerValue(0); if (lb < 0 && ub <= 0) { return -FindCanonicalValue(-ub, -lb); } @@ -102,9 +99,8 @@ void SplitDisjointBoxes(const SchedulingConstraintHelper &x, absl::Span boxes, std::vector > *result) { result->clear(); - std::sort(boxes.begin(), boxes.end(), [&x](int a, int b) { - return x.StartMin(a) < x.StartMin(b); - }); + std::sort(boxes.begin(), boxes.end(), + [&x](int a, int b) { return x.StartMin(a) < x.StartMin(b); }); int current_start = 0; std::size_t current_length = 1; IntegerValue current_max_end = x.EndMax(boxes[0]); @@ -116,7 +112,7 @@ void SplitDisjointBoxes(const SchedulingConstraintHelper &x, current_length++; current_max_end = std::max(current_max_end, x.EndMax(box)); } else { - if (current_length > 1) { // Ignore lists of size 1. + if (current_length > 1) { // Ignore lists of size 1. result->emplace_back(&boxes[current_start], current_length); } current_start = b; @@ -131,11 +127,10 @@ void SplitDisjointBoxes(const SchedulingConstraintHelper &x, } } -} // namespace +} // namespace -#define RETURN_IF_FALSE(f) \ - if (!(f)) \ - return false; +#define RETURN_IF_FALSE(f) \ + if (!(f)) return false; NonOverlappingRectanglesEnergyPropagator:: ~NonOverlappingRectanglesEnergyPropagator() {} @@ -150,8 +145,7 @@ bool NonOverlappingRectanglesEnergyPropagator::Propagate() { cached_dimensions_.resize(num_boxes); for (int box = 0; box < num_boxes; ++box) { cached_areas_[box] = x_.SizeMin(box) * y_.SizeMin(box); - if (cached_areas_[box] == 0) - continue; + if (cached_areas_[box] == 0) continue; // TODO(user): Also consider shifted end max. Dimension &dimension = cached_dimensions_[box]; @@ -162,8 +156,7 @@ bool NonOverlappingRectanglesEnergyPropagator::Propagate() { active_boxes_.push_back(box); } - if (active_boxes_.size() <= 1) - return true; + if (active_boxes_.size() <= 1) return true; SplitDisjointBoxes(x_, absl::MakeSpan(active_boxes_), &x_split_); for (absl::Span x_boxes : x_split_) { @@ -186,10 +179,10 @@ bool NonOverlappingRectanglesEnergyPropagator::Propagate() { int NonOverlappingRectanglesEnergyPropagator::RegisterWith( GenericLiteralWatcher *watcher) { const int id = watcher->Register(this); - x_.WatchAllTasks(id, watcher, /*watch_start_max=*/ false, - /*watch_end_max=*/ true); - y_.WatchAllTasks(id, watcher, /*watch_start_max=*/ false, - /*watch_end_max=*/ true); + x_.WatchAllTasks(id, watcher, /*watch_start_max=*/false, + /*watch_end_max=*/true); + y_.WatchAllTasks(id, watcher, /*watch_start_max=*/false, + /*watch_end_max=*/true); return id; } @@ -200,8 +193,7 @@ void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors( neighbors_.clear(); for (const int other_box : local_boxes) { - if (other_box == box) - continue; + if (other_box == box) continue; const Dimension &other_dim = cached_dimensions_[other_box]; const IntegerValue span_x = std::max(box_dim.x_max, other_dim.x_max) - std::min(box_dim.x_min, other_dim.x_min); @@ -209,9 +201,7 @@ void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors( std::min(box_dim.y_min, other_dim.y_min); const IntegerValue bounding_area = span_x * span_y; if (bounding_area < total_sum_of_areas) { - neighbors_.push_back({ - other_box, bounding_area - }); + neighbors_.push_back({other_box, bounding_area}); } } std::sort(neighbors_.begin(), neighbors_.end()); @@ -230,8 +220,7 @@ bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge( x_.AddEndMaxReason(b, area.x_max); y_.AddEnergyAfterReason(b, y_.SizeMin(b), area.y_min); y_.AddEndMaxReason(b, area.y_max); - } - ; + }; for (int i = 0; i < neighbors_.size(); ++i) { const int other_box = neighbors_[i].box; @@ -270,20 +259,25 @@ NonOverlappingRectanglesDisjunctivePropagator:: SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model) - : global_x_(*x), global_y_(*y), x_(x->NumTasks(), model), - y_(y->NumTasks(), model), strict_(strict), + : global_x_(*x), + global_y_(*y), + x_(x->NumTasks(), model), + y_(y->NumTasks(), model), + strict_(strict), watcher_(model->GetOrCreate()), - overload_checker_(&x_), forward_detectable_precedences_(true, &x_), + overload_checker_(&x_), + forward_detectable_precedences_(true, &x_), backward_detectable_precedences_(false, &x_), - forward_not_last_(true, &x_), backward_not_last_(false, &x_), - forward_edge_finding_(true, &x_), backward_edge_finding_(false, &x_) {} + forward_not_last_(true, &x_), + backward_not_last_(false, &x_), + forward_edge_finding_(true, &x_), + backward_edge_finding_(false, &x_) {} NonOverlappingRectanglesDisjunctivePropagator:: ~NonOverlappingRectanglesDisjunctivePropagator() {} -void -NonOverlappingRectanglesDisjunctivePropagator::Register(int fast_priority, - int slow_priority) { +void NonOverlappingRectanglesDisjunctivePropagator::Register( + int fast_priority, int slow_priority) { fast_id_ = watcher_->Register(this); watcher_->SetPropagatorPriority(fast_id_, fast_priority); global_x_.WatchAllTasks(fast_id_, watcher_); @@ -317,8 +311,7 @@ bool NonOverlappingRectanglesDisjunctivePropagator:: } // Less than 2 boxes, no propagation. - if (active_boxes_.size() < 2) - return true; + if (active_boxes_.size() < 2) return true; // Add boxes to the event lists they always overlap with. gtl::STLSortAndRemoveDuplicates(&events_time_); @@ -332,10 +325,8 @@ bool NonOverlappingRectanglesDisjunctivePropagator:: for (int i = 0; i < events_time_.size(); ++i) { const IntegerValue t = events_time_[i]; - if (t < start_max) - continue; - if (t >= end_min) - break; + if (t < start_max) continue; + if (t >= end_min) break; events_overlapping_boxes_[i].push_back(box); } } @@ -350,7 +341,7 @@ bool NonOverlappingRectanglesDisjunctivePropagator:: { for (std::vector &overlapping_boxes : events_overlapping_boxes_) { if (overlapping_boxes.size() < 2) { - continue; // Remove current event. + continue; // Remove current event. } if (new_size > 0) { const std::vector &previous_overlapping_boxes = @@ -385,8 +376,7 @@ bool NonOverlappingRectanglesDisjunctivePropagator:: // Note that we do not use reduced_overlapping_boxes_ directly so that // the order of iteration is deterministic. const auto &insertion = reduced_overlapping_boxes_.insert(sub_boxes); - if (insertion.second) - boxes_to_propagate_.push_back(sub_boxes); + if (insertion.second) boxes_to_propagate_.push_back(sub_boxes); } } @@ -442,19 +432,16 @@ bool NonOverlappingRectanglesDisjunctivePropagator::Propagate() { RETURN_IF_FALSE(backward_detectable_precedences_.Propagate()); } return true; - } - ; + }; } else { inner_propagate = [this]() { - if (x_.NumTasks() <= 2) - return true; + if (x_.NumTasks() <= 2) return true; RETURN_IF_FALSE(forward_not_last_.Propagate()); RETURN_IF_FALSE(backward_not_last_.Propagate()); RETURN_IF_FALSE(backward_edge_finding_.Propagate()); RETURN_IF_FALSE(forward_edge_finding_.Propagate()); return true; - } - ; + }; } RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate( @@ -494,28 +481,27 @@ bool NonOverlappingRectanglesDisjunctivePropagator::PropagateTwoBoxes() { } return true; - } - ; + }; switch (state) { - case 0: { // Conflict. - x_.ClearReason(); - x_.AddReasonForBeingBefore(0, 1); - x_.AddReasonForBeingBefore(1, 0); - return x_.ReportConflict(); - } - case 1: { // b1 is left of b2. - return left_box_before_right_box(0, 1); - } - case 2: { // b2 is left of b1. - return left_box_before_right_box(1, 0); - } - default: { // Nothing to deduce. - return true; - } + case 0: { // Conflict. + x_.ClearReason(); + x_.AddReasonForBeingBefore(0, 1); + x_.AddReasonForBeingBefore(1, 0); + return x_.ReportConflict(); + } + case 1: { // b1 is left of b2. + return left_box_before_right_box(0, 1); + } + case 2: { // b2 is left of b1. + return left_box_before_right_box(1, 0); + } + default: { // Nothing to deduce. + return true; + } } } #undef RETURN_IF_FALSE -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/diffn.h b/ortools/sat/diffn.h index bca139fbc6..501c1b3af9 100644 --- a/ortools/sat/diffn.h +++ b/ortools/sat/diffn.h @@ -118,7 +118,7 @@ class NonOverlappingRectanglesDisjunctivePropagator const bool strict_; GenericLiteralWatcher *watcher_; - int fast_id_; // Propagator id of the "fast" version. + int fast_id_; // Propagator id of the "fast" version. std::vector active_boxes_; std::vector events_time_; @@ -152,12 +152,12 @@ void AddCumulativeRelaxation(const std::vector &x_intervals, // and (x + dx, y + dy) do not overlap. // If strict is true, and if one box has a zero dimension, it still cannot // intersect another box. -inline std::function -NonOverlappingRectangles(const std::vector &x, - const std::vector &y, - bool is_strict) { - return[ = ](Model *model) { SchedulingConstraintHelper *x_helper = - new SchedulingConstraintHelper(x, model); +inline std::function NonOverlappingRectangles( + const std::vector &x, + const std::vector &y, bool is_strict) { + return [=](Model *model) { + SchedulingConstraintHelper *x_helper = + new SchedulingConstraintHelper(x, model); SchedulingConstraintHelper *y_helper = new SchedulingConstraintHelper(y, model); model->TakeOwnership(x_helper); @@ -173,16 +173,15 @@ NonOverlappingRectangles(const std::vector &x, NonOverlappingRectanglesDisjunctivePropagator *constraint = new NonOverlappingRectanglesDisjunctivePropagator(is_strict, x_helper, y_helper, model); - constraint->Register(/*fast_priority=*/ 3, /*slow_priority=*/ 4); + constraint->Register(/*fast_priority=*/3, /*slow_priority=*/4); model->TakeOwnership(constraint); AddCumulativeRelaxation(x, x_helper, y_helper, model); AddCumulativeRelaxation(y, y_helper, x_helper, model); - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_DIFFN_H_ +#endif // OR_TOOLS_SAT_DIFFN_H_ diff --git a/ortools/sat/disjunctive.cc b/ortools/sat/disjunctive.cc index 08eb93d663..e5a86bdfb8 100644 --- a/ortools/sat/disjunctive.cc +++ b/ortools/sat/disjunctive.cc @@ -27,9 +27,10 @@ namespace operations_research { namespace sat { -std::function -Disjunctive(const std::vector &vars) { - return[ = ](Model *model) { bool is_all_different = true; +std::function Disjunctive( + const std::vector &vars) { + return [=](Model *model) { + bool is_all_different = true; IntervalsRepository *repository = model->GetOrCreate(); for (const IntervalVariable var : vars) { if (repository->IsOptional(var) || repository->MinSize(var) != 1 || @@ -61,7 +62,7 @@ Disjunctive(const std::vector &vars) { model->TakeOwnership(helper); // Experiments to use the timetable only to propagate the disjunctive. - if (/*DISABLES_CODE*/(false)) { + if (/*DISABLES_CODE*/ (false)) { const AffineExpression one(IntegerValue(1)); std::vector demands(vars.size(), one); TimeTablingPerTask *timetable = new TimeTablingPerTask( @@ -86,27 +87,21 @@ Disjunctive(const std::vector &vars) { watcher->SetPropagatorPriority(id, 1); model->TakeOwnership(overload_checker); } - for (const bool time_direction : { - true, false - }) { + for (const bool time_direction : {true, false}) { DisjunctiveDetectablePrecedences *detectable_precedences = new DisjunctiveDetectablePrecedences(time_direction, helper); const int id = detectable_precedences->RegisterWith(watcher); watcher->SetPropagatorPriority(id, 2); model->TakeOwnership(detectable_precedences); } - for (const bool time_direction : { - true, false - }) { + for (const bool time_direction : {true, false}) { DisjunctiveNotLast *not_last = new DisjunctiveNotLast(time_direction, helper); const int id = not_last->RegisterWith(watcher); watcher->SetPropagatorPriority(id, 3); model->TakeOwnership(not_last); } - for (const bool time_direction : { - true, false - }) { + for (const bool time_direction : {true, false}) { DisjunctiveEdgeFinding *edge_finding = new DisjunctiveEdgeFinding(time_direction, helper); const int id = edge_finding->RegisterWith(watcher); @@ -120,9 +115,7 @@ Disjunctive(const std::vector &vars) { // using the fact that they are in disjunction. if (sat_parameters.use_precedences_in_disjunctive_constraint() && !sat_parameters.use_combined_no_overlap()) { - for (const bool time_direction : { - true, false - }) { + for (const bool time_direction : {true, false}) { DisjunctivePrecedences *precedences = new DisjunctivePrecedences( time_direction, helper, model->GetOrCreate(), model->GetOrCreate()); @@ -131,14 +124,13 @@ Disjunctive(const std::vector &vars) { model->TakeOwnership(precedences); } } - } - ; + }; } std::function DisjunctiveWithBooleanPrecedencesOnly( const std::vector &vars) { - return[ = ](Model *model) { SatSolver *sat_solver = - model->GetOrCreate(); + return [=](Model *model) { + SatSolver *sat_solver = model->GetOrCreate(); IntervalsRepository *repository = model->GetOrCreate(); PrecedencesPropagator *precedences = model->GetOrCreate(); @@ -155,17 +147,15 @@ std::function DisjunctiveWithBooleanPrecedencesOnly( j_before_i); } } - } - ; + }; } -std::function -DisjunctiveWithBooleanPrecedences(const std::vector &vars) { - return[ = ](Model * - model) { model->Add(DisjunctiveWithBooleanPrecedencesOnly(vars)); +std::function DisjunctiveWithBooleanPrecedences( + const std::vector &vars) { + return [=](Model *model) { + model->Add(DisjunctiveWithBooleanPrecedencesOnly(vars)); model->Add(Disjunctive(vars)); - } - ; + }; } void TaskSet::AddEntry(const Entry &e) { @@ -180,23 +170,19 @@ void TaskSet::AddEntry(const Entry &e) { // If the task is added after optimized_restart_, we know that we don't need // to scan the task before optimized_restart_ in the next ComputeEndMin(). - if (j <= optimized_restart_) - optimized_restart_ = 0; + if (j <= optimized_restart_) optimized_restart_ = 0; } void TaskSet::AddShiftedStartMinEntry(const SchedulingConstraintHelper &helper, int t) { const IntegerValue dmin = helper.SizeMin(t); - AddEntry({ - t, std::max(helper.StartMin(t), helper.EndMin(t) - dmin), dmin - }); + AddEntry({t, std::max(helper.StartMin(t), helper.EndMin(t) - dmin), dmin}); } void TaskSet::NotifyEntryIsNowLastIfPresent(const Entry &e) { const int size = sorted_tasks_.size(); for (int i = 0;; ++i) { - if (i == size) - return; + if (i == size) return; if (sorted_tasks_[i].task == e.task) { sorted_tasks_.erase(sorted_tasks_.begin() + i); break; @@ -252,8 +238,7 @@ IntegerValue TaskSet::ComputeEndMin(int task_to_ignore, } if (e.start_min >= end_min) { *critical_index = i; - if (!ignored) - optimized_restart_ = i; + if (!ignored) optimized_restart_ = i; end_min = e.start_min + e.size_min; } else { end_min += e.size_min; @@ -266,8 +251,7 @@ bool DisjunctiveWithTwoItems::Propagate() { DCHECK_EQ(helper_->NumTasks(), 2); // We can't propagate anything if one of the interval is absent for sure. - if (helper_->IsAbsent(0) || helper_->IsAbsent(1)) - return true; + if (helper_->IsAbsent(0) || helper_->IsAbsent(1)) return true; // Note that this propagation also take care of the "overload checker" part. // It also propagates as much as possible, even in the presence of task with @@ -338,8 +322,8 @@ CombinedDisjunctive::CombinedDisjunctive(Model *model) auto *watcher = model->GetOrCreate(); const int id = watcher->Register(this); - helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/ true, - /*watch_end_max=*/ false); + helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/true, + /*watch_end_max=*/false); watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(id); } @@ -361,8 +345,7 @@ bool CombinedDisjunctive::Propagate() { const auto &task_by_decreasing_start_max = helper_->TaskByDecreasingStartMax(); - for (auto &task_set : task_sets_) - task_set.Clear(); + for (auto &task_set : task_sets_) task_set.Clear(); end_mins_.assign(end_mins_.size(), kMinIntegerValue); IntegerValue max_of_end_min = kMinIntegerValue; @@ -372,25 +355,21 @@ bool CombinedDisjunctive::Propagate() { for (const auto task_time : task_by_increasing_end_min) { const int t = task_time.task_index; const IntegerValue end_min = task_time.time; - if (helper_->IsAbsent(t)) - continue; + if (helper_->IsAbsent(t)) continue; // Update all task sets. while (queue_index >= 0) { const auto to_insert = task_by_decreasing_start_max[queue_index]; const int task_index = to_insert.task_index; const IntegerValue start_max = to_insert.time; - if (end_min <= start_max) - break; + if (end_min <= start_max) break; if (helper_->IsPresent(task_index)) { task_is_added_[task_index] = true; const IntegerValue shifted_smin = helper_->ShiftedStartMin(task_index); const IntegerValue size_min = helper_->SizeMin(task_index); for (const int d_index : task_to_disjunctives_[task_index]) { // TODO(user): AddEntry() and ComputeEndMin() could be combined. - task_sets_[d_index].AddEntry({ - task_index, shifted_smin, size_min - }); + task_sets_[d_index].AddEntry({task_index, shifted_smin, size_min}); end_mins_[d_index] = task_sets_[d_index].ComputeEndMin(); max_of_end_min = std::max(max_of_end_min, end_mins_[d_index]); } @@ -401,17 +380,16 @@ bool CombinedDisjunctive::Propagate() { // Find out amongst the disjunctives in which t appear, the one with the // largest end_min, ignoring t itself. This will be the new start min for t. IntegerValue new_start_min = helper_->StartMin(t); - if (new_start_min >= max_of_end_min) - continue; + if (new_start_min >= max_of_end_min) continue; int best_critical_index = 0; int best_d_index = -1; if (task_is_added_[t]) { for (const int d_index : task_to_disjunctives_[t]) { - if (new_start_min >= end_mins_[d_index]) - continue; + if (new_start_min >= end_mins_[d_index]) continue; int critical_index = 0; - const IntegerValue end_min_of_critical_tasks = task_sets_[d_index] - .ComputeEndMin(/*task_to_ignore=*/ t, &critical_index); + const IntegerValue end_min_of_critical_tasks = + task_sets_[d_index].ComputeEndMin(/*task_to_ignore=*/t, + &critical_index); DCHECK_LE(end_min_of_critical_tasks, max_of_end_min); if (end_min_of_critical_tasks > new_start_min) { new_start_min = end_min_of_critical_tasks; @@ -429,15 +407,15 @@ bool CombinedDisjunctive::Propagate() { } } if (best_d_index != -1) { - const IntegerValue end_min_of_critical_tasks = task_sets_[best_d_index] - .ComputeEndMin(/*task_to_ignore=*/ t, &best_critical_index); + const IntegerValue end_min_of_critical_tasks = + task_sets_[best_d_index].ComputeEndMin(/*task_to_ignore=*/t, + &best_critical_index); CHECK_EQ(end_min_of_critical_tasks, new_start_min); } } // Do we push something? - if (best_d_index == -1) - continue; + if (best_d_index == -1) continue; // Same reason as DisjunctiveDetectablePrecedences. // TODO(user): Maybe factor out the code? It does require a function with a @@ -449,8 +427,7 @@ bool CombinedDisjunctive::Propagate() { sorted_tasks[best_critical_index].start_min; for (int i = best_critical_index; i < sorted_tasks.size(); ++i) { const int ct = sorted_tasks[i].task; - if (ct == t) - continue; + if (ct == t) continue; helper_->AddPresenceReason(ct); helper_->AddEnergyAfterReason(ct, sorted_tasks[i].size_min, window_start); helper_->AddStartMaxReason(ct, end_min - 1); @@ -468,9 +445,8 @@ bool CombinedDisjunctive::Propagate() { const IntegerValue shifted_smin = helper_->ShiftedStartMin(t); const IntegerValue size_min = helper_->SizeMin(t); for (const int d_index : task_to_disjunctives_[t]) { - task_sets_[d_index].NotifyEntryIsNowLastIfPresent({ - t, shifted_smin, size_min - }); + task_sets_[d_index].NotifyEntryIsNowLastIfPresent( + {t, shifted_smin, size_min}); end_mins_[d_index] = task_sets_[d_index].ComputeEndMin(); max_of_end_min = std::max(max_of_end_min, end_mins_[d_index]); } @@ -480,7 +456,7 @@ bool CombinedDisjunctive::Propagate() { } bool DisjunctiveOverloadChecker::Propagate() { - helper_->SetTimeDirection(/*is_forward=*/ true); + helper_->SetTimeDirection(/*is_forward=*/true); // Split problem into independent part. // @@ -499,8 +475,7 @@ bool DisjunctiveOverloadChecker::Propagate() { int relevant_size = 0; for (const TaskTime task_time : helper_->TaskByIncreasingShiftedStartMin()) { const int task = task_time.task_index; - if (helper_->IsAbsent(task)) - continue; + if (helper_->IsAbsent(task)) continue; const IntegerValue start_min = task_time.time; if (start_min < window_end) { @@ -544,8 +519,8 @@ bool DisjunctiveOverloadChecker::Propagate() { // set. This is useless for the overload checker as is since we need to check // overload after every insertion, but we could use an upper bound of the // theta envelope to save us from checking the actual value. -bool -DisjunctiveOverloadChecker::PropagateSubwindow(IntegerValue global_window_end) { +bool DisjunctiveOverloadChecker::PropagateSubwindow( + IntegerValue global_window_end) { // Set up theta tree and task_by_increasing_end_max_. const int window_size = window_.size(); theta_tree_.Reset(window_size); @@ -556,9 +531,7 @@ DisjunctiveOverloadChecker::PropagateSubwindow(IntegerValue global_window_end) { const IntegerValue end_max = helper_->EndMax(task); if (end_max < global_window_end) { task_to_event_[task] = i; - task_by_increasing_end_max_.push_back({ - task, end_max - }); + task_by_increasing_end_max_.push_back({task, end_max}); } } @@ -571,8 +544,7 @@ DisjunctiveOverloadChecker::PropagateSubwindow(IntegerValue global_window_end) { // We filtered absent task while constructing the subwindow, but it is // possible that as we propagate task absence below, other task also become // absent (if they share the same presence Boolean). - if (helper_->IsAbsent(current_task)) - continue; + if (helper_->IsAbsent(current_task)) continue; DCHECK_NE(task_to_event_[current_task], -1); { @@ -645,8 +617,7 @@ DisjunctiveOverloadChecker::PropagateSubwindow(IntegerValue global_window_end) { // If tasks shares the same presence literal, it is possible that we // already pushed this task absence. if (!helper_->IsAbsent(optional_task)) { - if (!helper_->PushTaskAbsence(optional_task)) - return false; + if (!helper_->PushTaskAbsence(optional_task)) return false; } theta_tree_.RemoveEvent(optional_event); } @@ -658,9 +629,9 @@ DisjunctiveOverloadChecker::PropagateSubwindow(IntegerValue global_window_end) { int DisjunctiveOverloadChecker::RegisterWith(GenericLiteralWatcher *watcher) { // This propagator reach the fix point in one pass. const int id = watcher->Register(this); - helper_->SetTimeDirection(/*is_forward=*/ true); - helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/ false, - /*watch_end_max=*/ true); + helper_->SetTimeDirection(/*is_forward=*/true); + helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/false, + /*watch_end_max=*/true); return id; } @@ -681,8 +652,7 @@ bool DisjunctiveDetectablePrecedences::Propagate() { IntegerValue window_end = kMinIntegerValue; for (const TaskTime task_time : helper_->TaskByIncreasingShiftedStartMin()) { const int task = task_time.task_index; - if (helper_->IsAbsent(task)) - continue; + if (helper_->IsAbsent(task)) continue; const IntegerValue shifted_smin = task_time.time; const IntegerValue size_min = helper_->SizeMin(task); @@ -701,9 +671,7 @@ bool DisjunctiveDetectablePrecedences::Propagate() { // Note that we use the real StartMin() here, as this is the one we will // push. if (helper_->StartMin(task) < window_end) { - task_by_increasing_end_min_.push_back({ - task, end_min_if_present - }); + task_by_increasing_end_min_.push_back({task, end_min_if_present}); window_end = std::max(window_end, shifted_smin) + size_min; continue; } @@ -715,9 +683,7 @@ bool DisjunctiveDetectablePrecedences::Propagate() { // Start of the next window. task_by_increasing_end_min_.clear(); - task_by_increasing_end_min_.push_back({ - task, end_min_if_present - }); + task_by_increasing_end_min_.push_back({task, end_min_if_present}); window_end = end_min_if_present; } @@ -746,13 +712,10 @@ bool DisjunctiveDetectablePrecedences::PropagateSubwindow() { const int task = entry.task_index; const IntegerValue start_max = helper_->StartMax(task); if (start_max < max_end_min && helper_->IsPresent(task)) { - task_by_increasing_start_max_.push_back({ - task, start_max - }); + task_by_increasing_start_max_.push_back({task, start_max}); } } - if (task_by_increasing_start_max_.empty()) - return true; + if (task_by_increasing_start_max_.empty()) return true; std::sort(task_by_increasing_start_max_.begin(), task_by_increasing_start_max_.end()); @@ -781,8 +744,7 @@ bool DisjunctiveDetectablePrecedences::PropagateSubwindow() { for (; queue_index < queue_size; ++queue_index) { const auto to_insert = task_by_increasing_start_max_[queue_index]; const IntegerValue start_max = to_insert.time; - if (current_end_min <= start_max) - break; + if (current_end_min <= start_max) break; const int t = to_insert.task_index; DCHECK(helper_->IsPresent(t)); @@ -809,8 +771,8 @@ bool DisjunctiveDetectablePrecedences::PropagateSubwindow() { return helper_->ReportConflict(); } DCHECK_LT(start_max, helper_->ShiftedStartMin(t) + helper_->SizeMin(t)) - << " task should have mandatory part: " << helper_->TaskDebugString( - t); + << " task should have mandatory part: " + << helper_->TaskDebugString(t); DCHECK(to_propagate_.empty()); blocking_task = t; to_propagate_.push_back(t); @@ -824,8 +786,7 @@ bool DisjunctiveDetectablePrecedences::PropagateSubwindow() { // is the blocking task. if (blocking_task != current_task) { to_propagate_.push_back(current_task); - if (blocking_task != -1) - continue; + if (blocking_task != -1) continue; } for (const int t : to_propagate_) { DCHECK(!processed_[t]); @@ -892,12 +853,12 @@ bool DisjunctiveDetectablePrecedences::PropagateSubwindow() { return true; } -int -DisjunctiveDetectablePrecedences::RegisterWith(GenericLiteralWatcher *watcher) { +int DisjunctiveDetectablePrecedences::RegisterWith( + GenericLiteralWatcher *watcher) { const int id = watcher->Register(this); helper_->SetTimeDirection(time_direction_); - helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/ true, - /*watch_end_max=*/ false); + helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/true, + /*watch_end_max=*/false); watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(id); return id; } @@ -908,8 +869,7 @@ bool DisjunctivePrecedences::Propagate() { IntegerValue window_end = kMinIntegerValue; for (const TaskTime task_time : helper_->TaskByIncreasingShiftedStartMin()) { const int task = task_time.task_index; - if (!helper_->IsPresent(task)) - continue; + if (!helper_->IsPresent(task)) continue; const IntegerValue start_min = task_time.time; if (start_min < window_end) { @@ -955,14 +915,11 @@ bool DisjunctivePrecedences::PropagateSubwindow() { // The task are actually in sorted order, so we do not need to call // task_set_.Sort(). This property is DCHECKed. - task_set_.AddUnsortedEntry({ - task_time.task_index, task_time.time, - helper_->SizeMin(task_time.task_index) - }); + task_set_.AddUnsortedEntry({task_time.task_index, task_time.time, + helper_->SizeMin(task_time.task_index)}); } DCHECK_GE(task_set_.SortedTasks().size(), 2); - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; // TODO(user): Only use the min_offset of the critical task? Or maybe do a // more general computation to find by how much we can push var? @@ -1005,8 +962,8 @@ int DisjunctivePrecedences::RegisterWith(GenericLiteralWatcher *watcher) { // This propagator reach the fixed point in one go. const int id = watcher->Register(this); helper_->SetTimeDirection(time_direction_); - helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/ false, - /*watch_end_max=*/ false); + helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/false, + /*watch_end_max=*/false); return id; } @@ -1037,8 +994,7 @@ bool DisjunctiveNotLast::Propagate() { for (; i < num_tasks; ++i) { const TaskTime task_time = task_by_increasing_shifted_start_min[i]; const int task = task_time.task_index; - if (!helper_->IsPresent(task)) - continue; + if (!helper_->IsPresent(task)) continue; const IntegerValue start_min = task_time.time; if (start_min_window_.empty()) { @@ -1059,18 +1015,15 @@ bool DisjunctiveNotLast::Propagate() { const auto task_time = task_by_decreasing_start_max[queue_index]; // Note that we add task whose presence is still unknown here. - if (task_time.time >= window_end) - break; - if (helper_->IsAbsent(task_time.task_index)) - continue; + if (task_time.time >= window_end) break; + if (helper_->IsAbsent(task_time.task_index)) continue; start_max_window_.push_back(task_time); } // If this is the case, we cannot propagate more than the detectable // precedence propagator. Note that this continue must happen after we // computed start_max_window_ though. - if (start_min_window_.size() <= 1) - continue; + if (start_min_window_.size() <= 1) continue; // Process current window. if (!start_max_window_.empty() && !PropagateSubwindow()) { @@ -1096,14 +1049,13 @@ bool DisjunctiveNotLast::PropagateSubwindow() { const IntegerValue start_max = helper_->StartMax(task); DCHECK(helper_->IsPresent(task)); if (start_max < threshold) { - task_by_increasing_start_max[queue_size++] = { task, start_max }; + task_by_increasing_start_max[queue_size++] = {task, start_max}; } } // If the size is one, we cannot propagate more than the detectable precedence // propagator. - if (queue_size <= 1) - return true; + if (queue_size <= 1) return true; task_by_increasing_start_max.resize(queue_size); std::sort(task_by_increasing_start_max.begin(), @@ -1122,15 +1074,12 @@ bool DisjunctiveNotLast::PropagateSubwindow() { while (queue_index < queue_size) { const auto to_insert = task_by_increasing_start_max[queue_index]; const IntegerValue start_max = to_insert.time; - if (end_max <= start_max) - break; + if (end_max <= start_max) break; const int task_index = to_insert.task_index; DCHECK(helper_->IsPresent(task_index)); - task_set_.AddEntry({ - task_index, helper_->ShiftedStartMin(task_index), - helper_->SizeMin(task_index) - }); + task_set_.AddEntry({task_index, helper_->ShiftedStartMin(task_index), + helper_->SizeMin(task_index)}); ++queue_index; } @@ -1146,9 +1095,8 @@ bool DisjunctiveNotLast::PropagateSubwindow() { // Note that this works as well when the presence of t is still unknown. int critical_index = 0; const IntegerValue end_min_of_critical_tasks = - task_set_.ComputeEndMin(/*task_to_ignore=*/ t, &critical_index); - if (end_min_of_critical_tasks <= helper_->StartMax(t)) - continue; + task_set_.ComputeEndMin(/*task_to_ignore=*/t, &critical_index); + if (end_min_of_critical_tasks <= helper_->StartMax(t)) continue; // Find the largest start-max of the critical tasks (excluding t). The // end-max for t need to be smaller than or equal to this. @@ -1157,8 +1105,7 @@ bool DisjunctiveNotLast::PropagateSubwindow() { const int sorted_tasks_size = sorted_tasks.size(); for (int i = critical_index; i < sorted_tasks_size; ++i) { const int ct = sorted_tasks[i].task; - if (t == ct) - continue; + if (t == ct) continue; const IntegerValue start_max = helper_->StartMax(ct); if (start_max > largest_ct_start_max) { largest_ct_start_max = start_max; @@ -1175,8 +1122,7 @@ bool DisjunctiveNotLast::PropagateSubwindow() { const IntegerValue window_start = sorted_tasks[critical_index].start_min; for (int i = critical_index; i < sorted_tasks_size; ++i) { const int ct = sorted_tasks[i].task; - if (ct == t) - continue; + if (ct == t) continue; helper_->AddPresenceReason(ct); helper_->AddEnergyAfterReason(ct, sorted_tasks[i].size_min, window_start); @@ -1188,8 +1134,7 @@ bool DisjunctiveNotLast::PropagateSubwindow() { // Enqueue the new end-max for t. // Note that changing it will not influence the rest of the loop. - if (!helper_->DecreaseEndMax(t, largest_ct_start_max)) - return false; + if (!helper_->DecreaseEndMax(t, largest_ct_start_max)) return false; } } return true; @@ -1212,8 +1157,7 @@ bool DisjunctiveEdgeFinding::Propagate() { IntegerValue window_end = kMinIntegerValue; for (const TaskTime task_time : helper_->TaskByIncreasingShiftedStartMin()) { const int task = task_time.task_index; - if (helper_->IsAbsent(task)) - continue; + if (helper_->IsAbsent(task)) continue; // Note that we use the real start min here not the shifted one. This is // because we might be able to push it if it is smaller than window end. @@ -1258,9 +1202,7 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { const IntegerValue end_max = helper_->EndMax(task); if (helper_->IsPresent(task) && end_max < window_end_min) { is_gray_[task] = false; - task_by_increasing_end_max_.push_back({ - task, end_max - }); + task_by_increasing_end_max_.push_back({task, end_max}); } else { is_gray_[task] = true; } @@ -1268,8 +1210,7 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { // If we have just 1 non-gray task, then this propagator does not propagate // more than the detectable precedences, so we abort early. - if (task_by_increasing_end_max_.size() < 2) - return true; + if (task_by_increasing_end_max_.size() < 2) return true; std::sort(task_by_increasing_end_max_.begin(), task_by_increasing_end_max_.end()); @@ -1319,8 +1260,7 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { theta_tree_.GetEnvelopeOf(critical_event) - 1; for (int event = critical_event; event < window_size; event++) { const int task = window_[event].task_index; - if (is_gray_[task]) - continue; + if (is_gray_[task]) continue; helper_->AddPresenceReason(task); helper_->AddEnergyAfterReason(task, event_size_[event], window_start); helper_->AddEndMaxReason(task, window_end); @@ -1371,8 +1311,7 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { helper_->ClearReason(); for (int event = first_event; event < window_size; event++) { const int task = window_[event].task_index; - if (is_gray_[task]) - continue; + if (is_gray_[task]) continue; helper_->AddPresenceReason(task); helper_->AddEnergyAfterReason( task, event_size_[event], @@ -1400,8 +1339,7 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { } // Stop before we get just one non-gray task. - if (task_by_increasing_end_max_.size() <= 2) - break; + if (task_by_increasing_end_max_.size() <= 2) break; // Stop if the min of end_max is too big. if (task_by_increasing_end_max_[0].time >= @@ -1426,11 +1364,11 @@ bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) { int DisjunctiveEdgeFinding::RegisterWith(GenericLiteralWatcher *watcher) { const int id = watcher->Register(this); helper_->SetTimeDirection(time_direction_); - helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/ false, - /*watch_end_max=*/ true); + helper_->WatchAllTasks(id, watcher, /*watch_start_max=*/false, + /*watch_end_max=*/true); watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(id); return id; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/disjunctive.h b/ortools/sat/disjunctive.h index 107b83c536..7424e01e8b 100644 --- a/ortools/sat/disjunctive.h +++ b/ortools/sat/disjunctive.h @@ -36,8 +36,8 @@ namespace sat { // // TODO(user): This is not completely true for empty intervals (start == end). // Make sure such intervals are ignored by the constraint. -std::function - Disjunctive(const std::vector &vars); +std::function Disjunctive( + const std::vector &vars); // Creates Boolean variables for all the possible precedences of the form (task // i is before task j) and forces that, for each couple of task (i,j), either i @@ -54,7 +54,7 @@ std::function DisjunctiveWithBooleanPrecedences( // this corresponds to his Theta-tree except that we use a O(n) implementation // for most of the function here, not a O(log(n)) one. class TaskSet { -public: + public: explicit TaskSet(int num_tasks) { sorted_tasks_.reserve(num_tasks); } struct Entry { @@ -118,7 +118,7 @@ public: const std::vector &SortedTasks() const { return sorted_tasks_; } -private: + private: std::vector sorted_tasks_; mutable int optimized_restart_ = 0; }; @@ -134,7 +134,7 @@ private: // ============================================================================ class DisjunctiveOverloadChecker : public PropagatorInterface { -public: + public: explicit DisjunctiveOverloadChecker(SchedulingConstraintHelper *helper) : helper_(helper) { // Resize this once and for all. @@ -143,7 +143,7 @@ public: bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: bool PropagateSubwindow(IntegerValue global_window_end); SchedulingConstraintHelper *helper_; @@ -156,15 +156,16 @@ private: }; class DisjunctiveDetectablePrecedences : public PropagatorInterface { -public: + public: DisjunctiveDetectablePrecedences(bool time_direction, SchedulingConstraintHelper *helper) - : time_direction_(time_direction), helper_(helper), + : time_direction_(time_direction), + helper_(helper), task_set_(helper->NumTasks()) {} bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: bool PropagateSubwindow(); std::vector task_by_increasing_end_min_; @@ -181,7 +182,7 @@ private: // Singleton model class which is just a SchedulingConstraintHelper will all // the intervals. class AllIntervalsHelper : public SchedulingConstraintHelper { -public: + public: explicit AllIntervalsHelper(Model *model) : SchedulingConstraintHelper( model->GetOrCreate()->AllIntervals(), model) {} @@ -192,7 +193,7 @@ public: // set of disjunctives. template class CombinedDisjunctive : public PropagatorInterface { -public: + public: explicit CombinedDisjunctive(Model *model); // After creation, this must be called for all the disjunctive constraints @@ -201,7 +202,7 @@ public: bool Propagate() final; -private: + private: AllIntervalsHelper *helper_; std::vector > task_to_disjunctives_; std::vector task_is_added_; @@ -210,14 +211,15 @@ private: }; class DisjunctiveNotLast : public PropagatorInterface { -public: + public: DisjunctiveNotLast(bool time_direction, SchedulingConstraintHelper *helper) - : time_direction_(time_direction), helper_(helper), + : time_direction_(time_direction), + helper_(helper), task_set_(helper->NumTasks()) {} bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: bool PropagateSubwindow(); std::vector start_min_window_; @@ -229,14 +231,14 @@ private: }; class DisjunctiveEdgeFinding : public PropagatorInterface { -public: + public: DisjunctiveEdgeFinding(bool time_direction, SchedulingConstraintHelper *helper) : time_direction_(time_direction), helper_(helper) {} bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: bool PropagateSubwindow(IntegerValue window_end_min); const bool time_direction_; @@ -259,18 +261,21 @@ private: // IntervalVariables must be performed before a given IntegerVariable". The // relations are computed with PrecedencesPropagator::ComputePrecedences(). class DisjunctivePrecedences : public PropagatorInterface { -public: + public: DisjunctivePrecedences(bool time_direction, SchedulingConstraintHelper *helper, IntegerTrail *integer_trail, PrecedencesPropagator *precedences) - : time_direction_(time_direction), helper_(helper), - integer_trail_(integer_trail), precedences_(precedences), - task_set_(helper->NumTasks()), task_to_arc_index_(helper->NumTasks()) {} + : time_direction_(time_direction), + helper_(helper), + integer_trail_(integer_trail), + precedences_(precedences), + task_set_(helper->NumTasks()), + task_to_arc_index_(helper->NumTasks()) {} bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: bool PropagateSubwindow(); const bool time_direction_; @@ -291,17 +296,17 @@ private: // disjunctive case is doing, but it dealt with variable size better and has a // lot less overhead. class DisjunctiveWithTwoItems : public PropagatorInterface { -public: + public: explicit DisjunctiveWithTwoItems(SchedulingConstraintHelper *helper) : helper_(helper) {} bool Propagate() final; int RegisterWith(GenericLiteralWatcher *watcher); -private: + private: SchedulingConstraintHelper *helper_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_DISJUNCTIVE_H_ +#endif // OR_TOOLS_SAT_DISJUNCTIVE_H_ diff --git a/ortools/sat/drat_checker.cc b/ortools/sat/drat_checker.cc index b67fe8cab9..6c9584f452 100644 --- a/ortools/sat/drat_checker.cc +++ b/ortools/sat/drat_checker.cc @@ -29,8 +29,8 @@ namespace sat { DratChecker::Clause::Clause(int first_literal_index, int num_literals) : first_literal_index(first_literal_index), num_literals(num_literals) {} -std::size_t -DratChecker::ClauseHash::operator()(const ClauseIndex clause_index) const { +std::size_t DratChecker::ClauseHash::operator()( + const ClauseIndex clause_index) const { size_t hash = 0; for (Literal literal : checker->Literals(checker->clauses_[clause_index])) { hash = util_hash::Hash(literal.Index().value(), hash); @@ -38,16 +38,16 @@ DratChecker::ClauseHash::operator()(const ClauseIndex clause_index) const { return hash; } -bool -DratChecker::ClauseEquiv::operator()(const ClauseIndex clause_index1, - const ClauseIndex clause_index2) const { +bool DratChecker::ClauseEquiv::operator()( + const ClauseIndex clause_index1, const ClauseIndex clause_index2) const { return checker->Literals(checker->clauses_[clause_index1]) == checker->Literals(checker->clauses_[clause_index2]); } DratChecker::DratChecker() : first_infered_clause_index_(kNoClauseIndex), - clause_set_(0, ClauseHash(this), ClauseEquiv(this)), num_variables_(0) {} + clause_set_(0, ClauseHash(this), ClauseEquiv(this)), + num_variables_(0) {} bool DratChecker::Clause::IsDeleted(ClauseIndex clause_index) const { return deleted_index <= clause_index; @@ -118,8 +118,8 @@ void DratChecker::DeleteClause(absl::Span clause) { DCHECK(existing_clause.deleted_index == std::numeric_limits::max()); existing_clause.deleted_index = clauses_.size() - 1; if (clauses_.back().num_literals >= 2) { - clauses_[ClauseIndex(clauses_.size() - 2)].deleted_clauses - .push_back(*it); + clauses_[ClauseIndex(clauses_.size() - 2)].deleted_clauses.push_back( + *it); } clause_set_.erase(it); } @@ -184,8 +184,7 @@ DratChecker::Status DratChecker::Check(double max_time_in_seconds) { // the lookup table potentially doubles the memory usage of the tool. // Since most lemmas emitted by state-of-the-art SAT solvers can be // validated using the RUP check, such a lookup table has been omitted." - if (clause.rat_literal_index == kNoLiteralIndex) - return Status::INVALID; + if (clause.rat_literal_index == kNoLiteralIndex) return Status::INVALID; ++num_rat_checks_; std::vector resolvent; for (ClauseIndex j(0); j < i; ++j) { @@ -195,7 +194,8 @@ DratChecker::Status DratChecker::Check(double max_time_in_seconds) { // Check that the resolvent has the RUP property. if (!Resolve(Literals(clause), Literals(clauses_[j]), Literal(clause.rat_literal_index), &tmp_assignment_, - &resolvent) || !HasRupProperty(i, resolvent)) { + &resolvent) || + !HasRupProperty(i, resolvent)) { return Status::INVALID; } } @@ -214,9 +214,8 @@ std::vector > DratChecker::GetOptimizedProof() const { ClauseIndex(clauses_.size())); } -std::vector > -DratChecker::GetClausesNeededForProof(ClauseIndex begin, - ClauseIndex end) const { +std::vector > DratChecker::GetClausesNeededForProof( + ClauseIndex begin, ClauseIndex end) const { std::vector > result; for (ClauseIndex i = begin; i < end; ++i) { const Clause &clause = clauses_[i]; @@ -226,7 +225,8 @@ DratChecker::GetClausesNeededForProof(ClauseIndex begin, if (clause.rat_literal_index != kNoLiteralIndex) { const int rat_literal_clause_index = std::find(literals.begin(), literals.end(), - Literal(clause.rat_literal_index)) - literals.begin(); + Literal(clause.rat_literal_index)) - + literals.begin(); std::swap(result.back()[0], result.back()[rat_literal_clause_index]); } } @@ -291,13 +291,11 @@ bool DratChecker::HasRupProperty(ClauseIndex num_clauses, // as done in drat-trim. if (clause_index < num_clauses && !clause.IsDeleted(num_clauses)) { if (clause.is_needed_for_proof) { - high_priority_literals_to_assign_.push_back({ - literals_[clause.first_literal_index], clause_index - }); + high_priority_literals_to_assign_.push_back( + {literals_[clause.first_literal_index], clause_index}); } else { - low_priority_literals_to_assign_.push_back({ - literals_[clause.first_literal_index], clause_index - }); + low_priority_literals_to_assign_.push_back( + {literals_[clause.first_literal_index], clause_index}); } } } @@ -399,13 +397,11 @@ ClauseIndex DratChecker::AssignAndPropagate(ClauseIndex num_clauses, // 'literals_to_assign_low_priority' to assign it to true and propagate // it in a later call to AssignAndPropagate(). if (clause.is_needed_for_proof) { - high_priority_literals_to_assign_.push_back({ - other_watched_literal, clause_index - }); + high_priority_literals_to_assign_.push_back( + {other_watched_literal, clause_index}); } else { - low_priority_literals_to_assign_.push_back({ - other_watched_literal, clause_index - }); + low_priority_literals_to_assign_.push_back( + {other_watched_literal, clause_index}); } } watched[new_watched_size++] = clause_index; @@ -416,7 +412,7 @@ ClauseIndex DratChecker::AssignAndPropagate(ClauseIndex num_clauses, } void DratChecker::MarkAsNeededForProof(Clause *clause) { - const auto mark_clause_and_sources = [&](Clause * clause) { + const auto mark_clause_and_sources = [&](Clause *clause) { clause->is_needed_for_proof = true; for (const Literal literal : Literals(*clause)) { const ClauseIndex source_clause_index = @@ -425,8 +421,7 @@ void DratChecker::MarkAsNeededForProof(Clause *clause) { clauses_[source_clause_index].tmp_is_needed_for_proof_step = true; } } - } - ; + }; mark_clause_and_sources(clause); for (int i = unit_stack_.size() - 1; i >= 0; --i) { Clause &unit_clause = clauses_[unit_stack_[i]]; @@ -588,8 +583,7 @@ bool AddInferedAndDeletedClauses(const std::string &file_path, } } if (!ends_with_empty_clause) { - drat_checker->AddInferedClause({ - }); + drat_checker->AddInferedClause({}); } file.close(); return result; @@ -612,5 +606,5 @@ bool PrintClauses(const std::string &file_path, SatFormat format, return output_stream.good(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/drat_checker.h b/ortools/sat/drat_checker.h index e2ff1a6465..c14b0a9278 100644 --- a/ortools/sat/drat_checker.h +++ b/ortools/sat/drat_checker.h @@ -38,7 +38,7 @@ const ClauseIndex kNoClauseIndex(-1); // Note that DRAT proofs are often huge (can be GB), and can take about as much // time to check as it takes to find the proof in the first place! class DratChecker { -public: + public: DratChecker(); ~DratChecker() {} @@ -89,7 +89,7 @@ public: // undefined if Check() was not previously called, or did not return true. std::vector > GetOptimizedProof() const; -private: + private: // A problem or infered clause. The literals are specified as a subrange of // 'literals_' (namely the subrange from 'first_literal_index' to // 'first_literal_index' + 'num_literals' - 1), and are sorted in increasing @@ -213,8 +213,8 @@ private: // Returns the clauses whose index is in [begin,end) which are needed for the // proof. The result is undefined if Check() was not previously called, or did // not return true. - std::vector > - GetClausesNeededForProof(ClauseIndex begin, ClauseIndex end) const; + std::vector > GetClausesNeededForProof( + ClauseIndex begin, ClauseIndex end) const; void LogStatistics(int64 duration_nanos) const; @@ -334,7 +334,7 @@ bool PrintClauses(const std::string &file_path, SatFormat format, const std::vector > &clauses, int num_variables); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_DRAT_CHECKER_H_ +#endif // OR_TOOLS_SAT_DRAT_CHECKER_H_ diff --git a/ortools/sat/drat_proof_handler.cc b/ortools/sat/drat_proof_handler.cc index c2ddfcffc7..1f6e0ce129 100644 --- a/ortools/sat/drat_proof_handler.cc +++ b/ortools/sat/drat_proof_handler.cc @@ -91,8 +91,7 @@ void DratProofHandler::DeleteClause(absl::Span clause) { DratChecker::Status DratProofHandler::Check(double max_time_in_seconds) { if (drat_checker_ != nullptr) { // The empty clause is not explicitly added by the solver. - drat_checker_->AddInferedClause({ - }); + drat_checker_->AddInferedClause({}); return drat_checker_->Check(max_time_in_seconds); } return DratChecker::Status::UNKNOWN; @@ -107,14 +106,14 @@ void DratProofHandler::MapClause(absl::Span clause) { values_.push_back(original_literal); } - // The sorting is such that new variables appear first. This is important - // for - // BVA since DRAT-trim only check the RAT property with respect to the first - // variable of the clause. + // The sorting is such that new variables appear first. This is important + // for + // BVA since DRAT-trim only check the RAT property with respect to the first + // variable of the clause. std::sort(values_.begin(), values_.end(), [](Literal a, Literal b) { return std::abs(a.SignedValue()) > std::abs(b.SignedValue()); }); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/drat_proof_handler.h b/ortools/sat/drat_proof_handler.h index 2c333f54c4..d659db9342 100644 --- a/ortools/sat/drat_proof_handler.h +++ b/ortools/sat/drat_proof_handler.h @@ -38,7 +38,7 @@ namespace sat { // and/or store it in memory (in which case the proof can be checked when it is // complete). class DratProofHandler { -public: + public: // Use this constructor to store the DRAT proof in memory. The proof will not // be written to disk, and can be checked with Check() when it is complete. DratProofHandler(); @@ -91,7 +91,7 @@ public: // called. DratChecker::Status Check(double max_time_in_seconds); -private: + private: void MapClause(absl::Span clause); // We need to keep track of the variable newly created. @@ -108,7 +108,7 @@ private: std::unique_ptr drat_writer_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_DRAT_PROOF_HANDLER_H_ +#endif // OR_TOOLS_SAT_DRAT_PROOF_HANDLER_H_ diff --git a/ortools/sat/drat_writer.cc b/ortools/sat/drat_writer.cc index c497f0a8d5..46b6be81ae 100644 --- a/ortools/sat/drat_writer.cc +++ b/ortools/sat/drat_writer.cc @@ -18,7 +18,7 @@ #include "absl/strings/str_format.h" #include "ortools/base/logging.h" #if !defined(__PORTABLE_PLATFORM__) -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ #include "absl/status/status.h" namespace operations_research { @@ -29,7 +29,7 @@ DratWriter::~DratWriter() { #if !defined(__PORTABLE_PLATFORM__) CHECK_OK(file::WriteString(output_, buffer_, file::Defaults())); CHECK_OK(output_->Close(file::Defaults())); -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ } } @@ -50,10 +50,10 @@ void DratWriter::WriteClause(absl::Span clause) { if (buffer_.size() > 10000) { #if !defined(__PORTABLE_PLATFORM__) CHECK_OK(file::WriteString(output_, buffer_, file::Defaults())); -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ buffer_.clear(); } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/drat_writer.h b/ortools/sat/drat_writer.h index b33bf278ae..bdaa5e7ac0 100644 --- a/ortools/sat/drat_writer.h +++ b/ortools/sat/drat_writer.h @@ -19,9 +19,8 @@ #if !defined(__PORTABLE_PLATFORM__) #include "ortools/base/file.h" #else -class File { -}; -#endif // !__PORTABLE_PLATFORM__ +class File {}; +#endif // !__PORTABLE_PLATFORM__ #include "absl/types/span.h" #include "ortools/sat/sat_base.h" @@ -35,7 +34,7 @@ namespace sat { // Note that DRAT proofs are often huge (can be GB), and take about as much time // to check as it takes for the solver to find the proof in the first place! class DratWriter { -public: + public: DratWriter(bool in_binary_format, File *output) : in_binary_format_(in_binary_format), output_(output) {} ~DratWriter(); @@ -49,7 +48,7 @@ public: // the problem. void DeleteClause(absl::Span clause); -private: + private: void WriteClause(absl::Span clause); // TODO(user): Support binary format as proof in text format can be large. @@ -59,7 +58,7 @@ private: std::string buffer_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_DRAT_WRITER_H_ +#endif // OR_TOOLS_SAT_DRAT_WRITER_H_ diff --git a/ortools/sat/encoding.cc b/ortools/sat/encoding.cc index 1976d64cc2..3fdd7ec389 100644 --- a/ortools/sat/encoding.cc +++ b/ortools/sat/encoding.cc @@ -24,8 +24,13 @@ namespace operations_research { namespace sat { EncodingNode::EncodingNode(Literal l) - : depth_(0), lb_(0), ub_(1), for_sorting_(l.Variable()), child_a_(nullptr), - child_b_(nullptr), literals_(1, l) {} + : depth_(0), + lb_(0), + ub_(1), + for_sorting_(l.Variable()), + child_a_(nullptr), + child_b_(nullptr), + literals_(1, l) {} void EncodingNode::InitializeFullNode(int n, EncodingNode *a, EncodingNode *b, SatSolver *solver) { @@ -65,8 +70,7 @@ void EncodingNode::InitializeLazyNode(EncodingNode *a, EncodingNode *b, bool EncodingNode::IncreaseCurrentUB(SatSolver *solver) { CHECK(!literals_.empty()); - if (current_ub() == ub_) - return false; + if (current_ub() == ub_) return false; literals_.emplace_back(BooleanVariable(solver->NumVariables()), true); solver->SetNumVariables(solver->NumVariables() + 1); solver->AddBinaryClause(literals_.back().Negated(), @@ -91,8 +95,7 @@ int EncodingNode::Reduce(const SatSolver &solver) { } void EncodingNode::ApplyUpperBound(int64 upper_bound, SatSolver *solver) { - if (size() <= upper_bound) - return; + if (size() <= upper_bound) return; for (int i = upper_bound; i < size(); ++i) { solver->AddUnitClause(literal(i).Negated()); } @@ -111,8 +114,7 @@ EncodingNode LazyMerge(EncodingNode *a, EncodingNode *b, SatSolver *solver) { } void IncreaseNodeSize(EncodingNode *node, SatSolver *solver) { - if (!node->IncreaseCurrentUB(solver)) - return; + if (!node->IncreaseCurrentUB(solver)) return; std::vector to_process; to_process.push_back(node); @@ -278,13 +280,14 @@ namespace { struct SortEncodingNodePointers { bool operator()(EncodingNode *a, EncodingNode *b) const { return *a < *b; } }; -} // namespace +} // namespace EncodingNode *LazyMergeAllNodeWithPQ(const std::vector &nodes, SatSolver *solver, std::deque *repository) { std::priority_queue, - SortEncodingNodePointers> pq(nodes.begin(), nodes.end()); + SortEncodingNodePointers> + pq(nodes.begin(), nodes.end()); while (pq.size() > 1) { EncodingNode *a = pq.top(); pq.pop(); @@ -296,11 +299,10 @@ EncodingNode *LazyMergeAllNodeWithPQ(const std::vector &nodes, return pq.top(); } -std::vector -CreateInitialEncodingNodes(const std::vector &literals, - const std::vector &coeffs, - Coefficient *offset, - std::deque *repository) { +std::vector CreateInitialEncodingNodes( + const std::vector &literals, + const std::vector &coeffs, Coefficient *offset, + std::deque *repository) { CHECK_EQ(literals.size(), coeffs.size()); *offset = 0; std::vector nodes; @@ -322,10 +324,9 @@ CreateInitialEncodingNodes(const std::vector &literals, return nodes; } -std::vector -CreateInitialEncodingNodes(const LinearObjective &objective_proto, - Coefficient *offset, - std::deque *repository) { +std::vector CreateInitialEncodingNodes( + const LinearObjective &objective_proto, Coefficient *offset, + std::deque *repository) { *offset = 0; std::vector nodes; for (int i = 0; i < objective_proto.literals_size(); ++i) { @@ -360,7 +361,7 @@ bool EncodingNodeByDepth(const EncodingNode *a, const EncodingNode *b) { bool EmptyEncodingNode(const EncodingNode *a) { return a->size() == 0; } -} // namespace +} // namespace std::vector ReduceNodesAndExtractAssumptions( Coefficient upper_bound, Coefficient stratified_lower_bound, @@ -377,8 +378,7 @@ std::vector ReduceNodesAndExtractAssumptions( // Fix the nodes right-most variables that are above the gap. if (upper_bound != kCoefficientMax) { const Coefficient gap = upper_bound - *lower_bound; - if (gap <= 0) - return {}; + if (gap <= 0) return {}; for (EncodingNode *n : *nodes) { n->ApplyUpperBound((gap / n->weight()).value(), solver); } @@ -390,14 +390,14 @@ std::vector ReduceNodesAndExtractAssumptions( // Sort the nodes. switch (solver->parameters().max_sat_assumption_order()) { - case SatParameters::DEFAULT_ASSUMPTION_ORDER: - break; - case SatParameters::ORDER_ASSUMPTION_BY_DEPTH: - std::sort(nodes->begin(), nodes->end(), EncodingNodeByDepth); - break; - case SatParameters::ORDER_ASSUMPTION_BY_WEIGHT: - std::sort(nodes->begin(), nodes->end(), EncodingNodeByWeight); - break; + case SatParameters::DEFAULT_ASSUMPTION_ORDER: + break; + case SatParameters::ORDER_ASSUMPTION_BY_DEPTH: + std::sort(nodes->begin(), nodes->end(), EncodingNodeByDepth); + break; + case SatParameters::ORDER_ASSUMPTION_BY_WEIGHT: + std::sort(nodes->begin(), nodes->end(), EncodingNodeByWeight); + break; } if (solver->parameters().max_sat_reverse_assumption_order()) { // TODO(user): with DEFAULT_ASSUMPTION_ORDER, this will lead to a somewhat @@ -501,5 +501,5 @@ void ProcessCore(const std::vector &core, Coefficient min_weight, CHECK(solver->AddUnitClause(nodes->back()->literal(0))); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/encoding.h b/ortools/sat/encoding.h index 2d9bc183a3..42330b3a9f 100644 --- a/ortools/sat/encoding.h +++ b/ortools/sat/encoding.h @@ -51,7 +51,7 @@ namespace sat { // Bailleux and Yacine Boufkhad, "Efficient CNF Encoding of Boolean Cardinality // Constraints", In Proc. of CP 2003, pages 108-122, 2003. class EncodingNode { -public: + public: EncodingNode() {} // Constructs a EncodingNode of size one, just formed by the given literal. @@ -112,7 +112,7 @@ public: EncodingNode *child_a() const { return child_a_; } EncodingNode *child_b() const { return child_b_; } -private: + private: int depth_; int lb_; int ub_; @@ -173,15 +173,13 @@ EncodingNode *LazyMergeAllNodeWithPQ(const std::vector &nodes, // objective. Sets the offset to the negated sum of the negative coefficient, // because in this case we negate the literals to have only positive // coefficients. -std::vector - CreateInitialEncodingNodes(const std::vector &literals, - const std::vector &coeffs, - Coefficient *offset, - std::deque *repository); -std::vector - CreateInitialEncodingNodes(const LinearObjective &objective_proto, - Coefficient *offset, - std::deque *repository); +std::vector CreateInitialEncodingNodes( + const std::vector &literals, + const std::vector &coeffs, Coefficient *offset, + std::deque *repository); +std::vector CreateInitialEncodingNodes( + const LinearObjective &objective_proto, Coefficient *offset, + std::deque *repository); // Reduces the nodes using the now fixed literals, update the lower-bound, and // returns the set of assumptions for the next round of the core-based @@ -208,7 +206,7 @@ void ProcessCore(const std::vector &core, Coefficient min_weight, std::deque *repository, std::vector *nodes, SatSolver *solver); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_ENCODING_H_ +#endif // OR_TOOLS_SAT_ENCODING_H_ diff --git a/ortools/sat/feasibility_pump.cc b/ortools/sat/feasibility_pump.cc index 2521e686a7..ea6f5f311f 100644 --- a/ortools/sat/feasibility_pump.cc +++ b/ortools/sat/feasibility_pump.cc @@ -81,9 +81,7 @@ void FeasibilityPump::AddLinearConstraint(const LinearConstraint &ct) { var = NegationOf(var); coeff = -coeff; } - new_ct.terms.push_back({ - GetOrCreateMirrorVariable(var), coeff - }); + new_ct.terms.push_back({GetOrCreateMirrorVariable(var), coeff}); } // Important to keep lp_data_ "clean". std::sort(new_ct.terms.begin(), new_ct.terms.end()); @@ -94,22 +92,18 @@ void FeasibilityPump::SetObjectiveCoefficient(IntegerVariable ivar, objective_is_defined_ = true; const IntegerVariable pos_var = VariableIsPositive(ivar) ? ivar : NegationOf(ivar); - if (ivar != pos_var) - coeff = -coeff; + if (ivar != pos_var) coeff = -coeff; const auto it = mirror_lp_variable_.find(pos_var); - if (it == mirror_lp_variable_.end()) - return; + if (it == mirror_lp_variable_.end()) return; const ColIndex col = it->second; - integer_objective_.push_back({ - col, coeff - }); + integer_objective_.push_back({col, coeff}); objective_infinity_norm_ = std::max(objective_infinity_norm_, IntTypeAbs(coeff)); } -ColIndex -FeasibilityPump::GetOrCreateMirrorVariable(IntegerVariable positive_variable) { +ColIndex FeasibilityPump::GetOrCreateMirrorVariable( + IntegerVariable positive_variable) { DCHECK(VariableIsPositive(positive_variable)); const auto it = mirror_lp_variable_.find(positive_variable); @@ -164,23 +158,17 @@ bool FeasibilityPump::Solve() { mixing_factor_ = 1.0; for (int i = 0; i < max_fp_iterations_; ++i) { - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; L1DistanceMinimize(); - if (!SolveLp()) - break; - if (lp_solution_is_integer_) - break; - if (!Round()) - break; + if (!SolveLp()) break; + if (lp_solution_is_integer_) break; + if (!Round()) break; // We don't end this loop if the integer solutions is feasible in hope to // get better solution. - if (integer_solution_is_feasible_) - MaybePushToRepo(); + if (integer_solution_is_feasible_) MaybePushToRepo(); } - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; PrintStats(); MaybePushToRepo(); @@ -188,8 +176,7 @@ bool FeasibilityPump::Solve() { } void FeasibilityPump::MaybePushToRepo() { - if (incomplete_solutions_ == nullptr) - return; + if (incomplete_solutions_ == nullptr) return; std::vector lp_solution(model_vars_size_, std::numeric_limits::infinity()); @@ -310,7 +297,7 @@ void FeasibilityPump::InitializeWorkingLP() { scaler_.Scale(&lp_data_); lp_data_.AddSlackVariablesWhereNecessary( - /*detect_integer_constraints=*/ false); + /*detect_integer_constraints=*/false); } void FeasibilityPump::L1DistanceMinimize() { @@ -333,11 +320,11 @@ void FeasibilityPump::L1DistanceMinimize() { (1 - mixing_factor_) * objective_normalization_factor_ * (1 - 2 * integer_solution_[col.value()]); new_obj_coeffs[col.value()] = objective_coefficient; - } else { // The variable is integer. - // Update the bounds of the constraints added in - // InitializeIntegerVariables() (see there for more details): - // d_i - x_i >= -round(x'_i) - // d_i + x_i >= +round(x'_i) + } else { // The variable is integer. + // Update the bounds of the constraints added in + // InitializeIntegerVariables() (see there for more details): + // d_i - x_i >= -round(x'_i) + // d_i + x_i >= +round(x'_i) // TODO(user): We change both the objective and the bounds, thus // breaking the incrementality. Handle integer variables differently, @@ -456,15 +443,13 @@ bool FeasibilityPump::Round() { SatParameters::PROPAGATION_ASSISTED) { rounding_successful = PropagationRounding(); } - if (!rounding_successful) - return false; + if (!rounding_successful) return false; FillIntegerSolutionStats(); return true; } bool FeasibilityPump::NearestIntegerRounding() { - if (!lp_solution_is_set_) - return false; + if (!lp_solution_is_set_) return false; for (int i = 0; i < lp_solution_.size(); ++i) { integer_solution_[i] = static_cast(std::round(lp_solution_[i])); } @@ -473,8 +458,7 @@ bool FeasibilityPump::NearestIntegerRounding() { } bool FeasibilityPump::LockBasedRounding() { - if (!lp_solution_is_set_) - return false; + if (!lp_solution_is_set_) return false; const int num_vars = integer_variables_.size(); // We compute the number of locks based on variable coefficient in constraints @@ -517,8 +501,7 @@ bool FeasibilityPump::LockBasedRounding() { } bool FeasibilityPump::ActiveLockBasedRounding() { - if (!lp_solution_is_set_) - return false; + if (!lp_solution_is_set_) return false; const int num_vars = integer_variables_.size(); // We compute the number of locks based on variable coefficient in constraints @@ -562,8 +545,7 @@ bool FeasibilityPump::ActiveLockBasedRounding() { } bool FeasibilityPump::PropagationRounding() { - if (!lp_solution_is_set_) - return false; + if (!lp_solution_is_set_) return false; sat_solver_->ResetToLevelZero(); // Compute an order in which we will fix variables and do the propagation. @@ -575,13 +557,9 @@ bool FeasibilityPump::PropagationRounding() { const double fractionality = std::abs(std::round(lp_solution_[i]) - lp_solution_[i]); if (var_is_binary_[i]) { - binary_fractionality_vars.push_back({ - fractionality, i - }); + binary_fractionality_vars.push_back({fractionality, i}); } else { - general_fractionality_vars.push_back({ - fractionality, i - }); + general_fractionality_vars.push_back({fractionality, i}); } } std::sort(binary_fractionality_vars.begin(), @@ -598,8 +576,7 @@ bool FeasibilityPump::PropagationRounding() { } for (const int var_index : rounding_order) { - if (time_limit_->LimitReached()) - return false; + if (time_limit_->LimitReached()) return false; // Get the bounds of the variable. const IntegerVariable var = integer_variables_[var_index]; const Domain &domain = (*domains_)[var]; @@ -716,8 +693,7 @@ void FeasibilityPump::FillIntegerSolutionStats() { break; } activity = CapAdd(activity, prod); - if (activity <= kint64min || activity >= kint64max) - break; + if (activity <= kint64min || activity >= kint64max) break; } if (activity > integer_lp_[i].ub || activity < integer_lp_[i].lb) { integer_solution_is_feasible_ = false; @@ -735,5 +711,5 @@ void FeasibilityPump::FillIntegerSolutionStats() { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/feasibility_pump.h b/ortools/sat/feasibility_pump.h index 25a37aae39..e28ed9835c 100644 --- a/ortools/sat/feasibility_pump.h +++ b/ortools/sat/feasibility_pump.h @@ -29,7 +29,7 @@ namespace operations_research { namespace sat { class FeasibilityPump { -public: + public: explicit FeasibilityPump(Model *model); ~FeasibilityPump(); @@ -71,7 +71,7 @@ public: // Returns false if the model is proven to be infeasible. bool Solve(); -private: + private: // Solve the LP, returns false if something went wrong in the LP solver. bool SolveLp(); @@ -230,7 +230,7 @@ private: bool model_is_unsat_ = false; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_FEASIBILITY_PUMP_H_ +#endif // OR_TOOLS_SAT_FEASIBILITY_PUMP_H_ diff --git a/ortools/sat/implied_bounds.cc b/ortools/sat/implied_bounds.cc index 5252bffbbd..caf2a70287 100644 --- a/ortools/sat/implied_bounds.cc +++ b/ortools/sat/implied_bounds.cc @@ -25,8 +25,7 @@ ImpliedBounds::~ImpliedBounds() { } void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { - if (!parameters_.use_implied_bounds()) - return; + if (!parameters_.use_implied_bounds()) return; const IntegerVariable var = integer_literal.var; // Update our local level-zero bound. @@ -53,9 +52,7 @@ void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { // Add or update the current bound. const auto key = std::make_pair(literal.Index(), var); - auto insert_result = bounds_.insert({ - key, integer_literal.bound - }); + auto insert_result = bounds_.insert({key, integer_literal.bound}); if (!insert_result.second) { if (insert_result.first->second < integer_literal.bound) { insert_result.first->second = integer_literal.bound; @@ -92,11 +89,10 @@ void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { level_zero_lower_bounds_[var] = deduction; new_level_zero_bounds_.Set(var); - VLOG(1) - << "Deduction old: " << IntegerLiteral::GreaterOrEqual( - var, - integer_trail_->LevelZeroLowerBound(var)) - << " new: " << IntegerLiteral::GreaterOrEqual(var, deduction); + VLOG(1) << "Deduction old: " + << IntegerLiteral::GreaterOrEqual( + var, integer_trail_->LevelZeroLowerBound(var)) + << " new: " << IntegerLiteral::GreaterOrEqual(var, deduction); // The entries that are equal to the min no longer need to be stored once // the level zero bound is enqueued. @@ -120,8 +116,7 @@ void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { // constraint using this bound is protected by the variable optional literal. // Alternativelly we could disable optional variable when we are at // linearization level 2. - if (integer_trail_->IsOptional(var)) - return; + if (integer_trail_->IsOptional(var)) return; // If we have a new implied bound and the literal has a view, add it to // var_to_bounds_. Note that we might add more than one entry with the same @@ -133,9 +128,8 @@ void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { } ++num_enqueued_in_var_to_bounds_; has_implied_bounds_.Set(var); - var_to_bounds_[var].push_back({ - integer_encoder_->GetLiteralView(literal), integer_literal.bound, true - }); + var_to_bounds_[var].push_back({integer_encoder_->GetLiteralView(literal), + integer_literal.bound, true}); } else if (integer_encoder_->GetLiteralView(literal.Negated()) != kNoIntegerVariable) { if (var_to_bounds_.size() <= var) { @@ -144,17 +138,15 @@ void ImpliedBounds::Add(Literal literal, IntegerLiteral integer_literal) { } ++num_enqueued_in_var_to_bounds_; has_implied_bounds_.Set(var); - var_to_bounds_[var].push_back({ - integer_encoder_->GetLiteralView(literal.Negated()), - integer_literal.bound, false - }); + var_to_bounds_[var].push_back( + {integer_encoder_->GetLiteralView(literal.Negated()), + integer_literal.bound, false}); } } -const std::vector & -ImpliedBounds::GetImpliedBounds(IntegerVariable var) { - if (var >= var_to_bounds_.size()) - return empty_implied_bounds_; +const std::vector &ImpliedBounds::GetImpliedBounds( + IntegerVariable var) { + if (var >= var_to_bounds_.size()) return empty_implied_bounds_; // Lazily remove obsolete entries from the vector. // @@ -166,8 +158,7 @@ ImpliedBounds::GetImpliedBounds(IntegerVariable var) { level_zero_lower_bounds_[var], integer_trail_->LevelZeroLowerBound(var)); level_zero_lower_bounds_[var] = level_zero_lb; for (const ImpliedBoundEntry &entry : ref) { - if (entry.lower_bound <= level_zero_lb) - continue; + if (entry.lower_bound <= level_zero_lb) continue; ref[new_size++] = entry; } ref.resize(new_size); @@ -176,8 +167,7 @@ ImpliedBounds::GetImpliedBounds(IntegerVariable var) { } void ImpliedBounds::ProcessIntegerTrail(Literal first_decision) { - if (!parameters_.use_implied_bounds()) - return; + if (!parameters_.use_implied_bounds()) return; CHECK_EQ(sat_solver_->CurrentDecisionLevel(), 1); tmp_integer_literals_.clear(); @@ -193,10 +183,7 @@ bool ImpliedBounds::EnqueueNewDeductions() { new_level_zero_bounds_.PositionsSetAtLeastOnce()) { if (!integer_trail_->Enqueue( IntegerLiteral::GreaterOrEqual(var, level_zero_lower_bounds_[var]), - { - }, - { - })) { + {}, {})) { return false; } } @@ -204,5 +191,5 @@ bool ImpliedBounds::EnqueueNewDeductions() { return sat_solver_->FinishPropagation(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/implied_bounds.h b/ortools/sat/implied_bounds.h index 62bf4e14be..f7960fbf7c 100644 --- a/ortools/sat/implied_bounds.h +++ b/ortools/sat/implied_bounds.h @@ -75,7 +75,7 @@ struct ImpliedBoundEntry { // TODO(user): Add an implied bound cut generator to add these simple // constraints to the LP when needed. class ImpliedBounds { -public: + public: explicit ImpliedBounds(Model *model) : parameters_(*model->GetOrCreate()), sat_solver_(model->GetOrCreate()), @@ -121,7 +121,7 @@ public: // relaxation. void NotifyNewIntegerView(Literal literal) {} -private: + private: const SatParameters ¶meters_; SatSolver *sat_solver_; IntegerTrail *integer_trail_; @@ -161,7 +161,7 @@ private: int64 num_enqueued_in_var_to_bounds_ = 0; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_IMPLIED_BOUNDS_H_ +#endif // OR_TOOLS_SAT_IMPLIED_BOUNDS_H_ diff --git a/ortools/sat/integer.cc b/ortools/sat/integer.cc index d327e73778..01a6f4f969 100644 --- a/ortools/sat/integer.cc +++ b/ortools/sat/integer.cc @@ -39,8 +39,8 @@ IntegerLiteral AffineExpression::LowerOrEqual(IntegerValue bound) const { return IntegerLiteral::LowerOrEqual(var, FloorRatio(bound - constant, coeff)); } -std::vector -NegationOf(const std::vector &vars) { +std::vector NegationOf( + const std::vector &vars) { std::vector result(vars.size()); for (int i = 0; i < vars.size(); ++i) { result[i] = NegationOf(vars[i]); @@ -49,11 +49,10 @@ NegationOf(const std::vector &vars) { } void IntegerEncoder::FullyEncodeVariable(IntegerVariable var) { - if (VariableIsFullyEncoded(var)) - return; + if (VariableIsFullyEncoded(var)) return; CHECK_EQ(0, sat_solver_->CurrentDecisionLevel()); - CHECK(!(*domains_)[var].IsEmpty()); // UNSAT. We don't deal with that here. + CHECK(!(*domains_)[var].IsEmpty()); // UNSAT. We don't deal with that here. CHECK_LT((*domains_)[var].Size(), 100000) << "Domain too large for full encoding."; @@ -83,22 +82,18 @@ void IntegerEncoder::FullyEncodeVariable(IntegerVariable var) { bool IntegerEncoder::VariableIsFullyEncoded(IntegerVariable var) const { const PositiveOnlyIndex index = GetPositiveOnlyIndex(var); - if (index >= is_fully_encoded_.size()) - return false; + if (index >= is_fully_encoded_.size()) return false; // Once fully encoded, the status never changes. - if (is_fully_encoded_[index]) - return true; - if (!VariableIsPositive(var)) - var = PositiveVariable(var); + if (is_fully_encoded_[index]) return true; + if (!VariableIsPositive(var)) var = PositiveVariable(var); // TODO(user): Cache result as long as equality_by_var_[index] is unchanged? // It might not be needed since if the variable is not fully encoded, then // PartialDomainEncoding() will filter unreachable values, and so the size // check will be false until further value have been encoded. const int64 initial_domain_size = (*domains_)[var].Size(); - if (equality_by_var_[index].size() < initial_domain_size) - return false; + if (equality_by_var_[index].size() < initial_domain_size) return false; // This cleans equality_by_var_[index] as a side effect and in particular, // sorts it by values. @@ -132,15 +127,13 @@ std::vector IntegerEncoder::PartialDomainEncoding(IntegerVariable var) const { CHECK_EQ(sat_solver_->CurrentDecisionLevel(), 0); const PositiveOnlyIndex index = GetPositiveOnlyIndex(var); - if (index >= equality_by_var_.size()) - return {}; + if (index >= equality_by_var_.size()) return {}; int new_size = 0; std::vector &ref = equality_by_var_[index]; for (int i = 0; i < ref.size(); ++i) { const ValueLiteralPair pair = ref[i]; - if (sat_solver_->Assignment().LiteralIsFalse(pair.literal)) - continue; + if (sat_solver_->Assignment().LiteralIsFalse(pair.literal)) continue; if (sat_solver_->Assignment().LiteralIsTrue(pair.literal)) { ref.clear(); ref.push_back(pair); @@ -155,8 +148,7 @@ IntegerEncoder::PartialDomainEncoding(IntegerVariable var) const { std::vector result = ref; if (!VariableIsPositive(var)) { std::reverse(result.begin(), result.end()); - for (ValueLiteralPair &ref : result) - ref.value = -ref.value; + for (ValueLiteralPair &ref : result) ref.value = -ref.value; } return result; } @@ -168,26 +160,23 @@ void IntegerEncoder::AddImplications( const std::map &map, std::map::const_iterator it, Literal associated_lit) { - if (!add_implications_) - return; + if (!add_implications_) return; DCHECK_EQ(it->second, associated_lit); // Literal(after) => associated_lit auto after_it = it; ++after_it; if (after_it != map.end()) { - sat_solver_->AddClauseDuringSearch({ - after_it->second.Negated(), associated_lit - }); + sat_solver_->AddClauseDuringSearch( + {after_it->second.Negated(), associated_lit}); } // associated_lit => Literal(before) if (it != map.begin()) { auto before_it = it; --before_it; - sat_solver_->AddClauseDuringSearch({ - associated_lit.Negated(), before_it->second - }); + sat_solver_->AddClauseDuringSearch( + {associated_lit.Negated(), before_it->second}); } } @@ -207,8 +196,8 @@ void IntegerEncoder::AddAllImplicationsBetweenAssociatedLiterals() { } } -std::pair -IntegerEncoder::Canonicalize(IntegerLiteral i_lit) const { +std::pair IntegerEncoder::Canonicalize( + IntegerLiteral i_lit) const { const IntegerVariable var(i_lit.var); IntegerValue after(i_lit.bound); IntegerValue before(i_lit.bound - 1); @@ -216,16 +205,13 @@ IntegerEncoder::Canonicalize(IntegerLiteral i_lit) const { CHECK_LE(after, (*domains_)[var].Max()); int64 previous = kint64min; for (const ClosedInterval &interval : (*domains_)[var]) { - if (before > previous && before < interval.start) - before = previous; - if (after > previous && after < interval.start) - after = interval.start; - if (after <= interval.end) - break; + if (before > previous && before < interval.start) before = previous; + if (after > previous && after < interval.start) after = interval.start; + if (after <= interval.end) break; previous = interval.end; } - return { IntegerLiteral::GreaterOrEqual(var, after), - IntegerLiteral::LowerOrEqual(var, before) }; + return {IntegerLiteral::GreaterOrEqual(var, after), + IntegerLiteral::LowerOrEqual(var, before)}; } Literal IntegerEncoder::GetOrCreateAssociatedLiteral(IntegerLiteral i_lit) { @@ -240,11 +226,9 @@ Literal IntegerEncoder::GetOrCreateAssociatedLiteral(IntegerLiteral i_lit) { const IntegerLiteral new_lit = canonicalization.first; const LiteralIndex index = GetAssociatedLiteral(new_lit); - if (index != kNoLiteralIndex) - return Literal(index); + if (index != kNoLiteralIndex) return Literal(index); const LiteralIndex n_index = GetAssociatedLiteral(canonicalization.second); - if (n_index != kNoLiteralIndex) - return Literal(n_index).Negated(); + if (n_index != kNoLiteralIndex) return Literal(n_index).Negated(); ++num_created_variables_; const Literal literal(sat_solver_->NewBooleanVariable(), true); @@ -264,11 +248,10 @@ std::pair PositiveVarKey(IntegerVariable var, return std::make_pair(GetPositiveOnlyIndex(var), VariableIsPositive(var) ? value : -value); } -} // namespace +} // namespace -LiteralIndex -IntegerEncoder::GetAssociatedEqualityLiteral(IntegerVariable var, - IntegerValue value) const { +LiteralIndex IntegerEncoder::GetAssociatedEqualityLiteral( + IntegerVariable var, IntegerValue value) const { const auto it = equality_to_associated_literal_.find(PositiveVarKey(var, value)); if (it != equality_to_associated_literal_.end()) { @@ -277,9 +260,8 @@ IntegerEncoder::GetAssociatedEqualityLiteral(IntegerVariable var, return kNoLiteralIndex; } -Literal -IntegerEncoder::GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, - IntegerValue value) { +Literal IntegerEncoder::GetOrCreateLiteralAssociatedToEquality( + IntegerVariable var, IntegerValue value) { { const auto it = equality_to_associated_literal_.find(PositiveVarKey(var, value)); @@ -291,8 +273,7 @@ IntegerEncoder::GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, // Check for trivial true/false literal to avoid creating variable for no // reasons. const Domain &domain = (*domains_)[var]; - if (!domain.Contains(value.value())) - return GetFalseLiteral(); + if (!domain.Contains(value.value())) return GetFalseLiteral(); if (value == domain.Min() && value == domain.Max()) { AssociateToIntegerEqualValue(GetTrueLiteral(), var, value); return GetTrueLiteral(); @@ -365,20 +346,15 @@ void IntegerEncoder::AssociateToIntegerEqualValue(Literal literal, // We use the "do not insert if present" behavior of .insert() to do just one // lookup. - const auto insert_result = equality_to_associated_literal_.insert({ - PositiveVarKey(var, value), literal - }); + const auto insert_result = equality_to_associated_literal_.insert( + {PositiveVarKey(var, value), literal}); if (!insert_result.second) { // If this key is already associated, make the two literals equal. const Literal representative = insert_result.first->second; if (representative != literal) { DCHECK_EQ(sat_solver_->CurrentDecisionLevel(), 0); - sat_solver_->AddClauseDuringSearch({ - literal, representative.Negated() - }); - sat_solver_->AddClauseDuringSearch({ - literal.Negated(), representative - }); + sat_solver_->AddClauseDuringSearch({literal, representative.Negated()}); + sat_solver_->AddClauseDuringSearch({literal.Negated(), representative}); } return; } @@ -427,15 +403,9 @@ void IntegerEncoder::AssociateToIntegerEqualValue(Literal literal, // (var == value) <=> (var >= value) and (var <= value). const Literal a(GetOrCreateAssociatedLiteral(ge)); const Literal b(GetOrCreateAssociatedLiteral(le)); - sat_solver_->AddClauseDuringSearch({ - a, literal.Negated() - }); - sat_solver_->AddClauseDuringSearch({ - b, literal.Negated() - }); - sat_solver_->AddClauseDuringSearch({ - a.Negated(), b.Negated(), literal - }); + sat_solver_->AddClauseDuringSearch({a, literal.Negated()}); + sat_solver_->AddClauseDuringSearch({b, literal.Negated()}); + sat_solver_->AddClauseDuringSearch({a.Negated(), b.Negated(), literal}); // Update reverse encoding. const int new_size = 1 + literal.Index().value(); @@ -466,10 +436,8 @@ void IntegerEncoder::HalfAssociateGivenLiteral(IntegerLiteral i_lit, encoding_by_var_.resize(i_lit.var.value() + 1); } auto &var_encoding = encoding_by_var_[i_lit.var]; - auto insert_result = var_encoding.insert({ - i_lit.bound, literal - }); - if (insert_result.second) { // New item. + auto insert_result = var_encoding.insert({i_lit.bound, literal}); + if (insert_result.second) { // New item. AddImplications(var_encoding, insert_result.first, literal); if (sat_solver_->Assignment().LiteralIsTrue(literal)) { if (sat_solver_->CurrentDecisionLevel() == 0) { @@ -484,44 +452,34 @@ void IntegerEncoder::HalfAssociateGivenLiteral(IntegerLiteral i_lit, const Literal associated(insert_result.first->second); if (associated != literal) { DCHECK_EQ(sat_solver_->CurrentDecisionLevel(), 0); - sat_solver_->AddClauseDuringSearch({ - literal, associated.Negated() - }); - sat_solver_->AddClauseDuringSearch({ - literal.Negated(), associated - }); + sat_solver_->AddClauseDuringSearch({literal, associated.Negated()}); + sat_solver_->AddClauseDuringSearch({literal.Negated(), associated}); } } } bool IntegerEncoder::LiteralIsAssociated(IntegerLiteral i) const { - if (i.var >= encoding_by_var_.size()) - return false; + if (i.var >= encoding_by_var_.size()) return false; const std::map &encoding = encoding_by_var_[i.var]; return encoding.find(i.bound) != encoding.end(); } LiteralIndex IntegerEncoder::GetAssociatedLiteral(IntegerLiteral i) const { - if (i.var >= encoding_by_var_.size()) - return kNoLiteralIndex; + if (i.var >= encoding_by_var_.size()) return kNoLiteralIndex; const std::map &encoding = encoding_by_var_[i.var]; const auto result = encoding.find(i.bound); - if (result == encoding.end()) - return kNoLiteralIndex; + if (result == encoding.end()) return kNoLiteralIndex; return result->second.Index(); } -LiteralIndex -IntegerEncoder::SearchForLiteralAtOrBefore(IntegerLiteral i, - IntegerValue *bound) const { +LiteralIndex IntegerEncoder::SearchForLiteralAtOrBefore( + IntegerLiteral i, IntegerValue *bound) const { // We take the element before the upper_bound() which is either the encoding // of i if it already exists, or the encoding just before it. - if (i.var >= encoding_by_var_.size()) - return kNoLiteralIndex; + if (i.var >= encoding_by_var_.size()) return kNoLiteralIndex; const std::map &encoding = encoding_by_var_[i.var]; auto after_it = encoding.upper_bound(i.bound); - if (after_it == encoding.begin()) - return kNoLiteralIndex; + if (after_it == encoding.begin()) return kNoLiteralIndex; --after_it; *bound = after_it->first; return after_it->second.Index(); @@ -536,8 +494,7 @@ IntegerTrail::~IntegerTrail() { bool IntegerTrail::Propagate(Trail *trail) { const int level = trail->CurrentDecisionLevel(); - for (ReversibleInterface *rev : reversible_classes_) - rev->SetLevel(level); + for (ReversibleInterface *rev : reversible_classes_) rev->SetLevel(level); // Make sure that our internal "integer_search_levels_" size matches the // sat decision levels. At the level zero, integer_search_levels_ should @@ -562,13 +519,8 @@ bool IntegerTrail::Propagate(Trail *trail) { // a big chunck of work. if (level == 0) { for (const IntegerLiteral i_lit : encoder_->NewlyFixedIntegerLiterals()) { - if (IsCurrentlyIgnored(i_lit.var)) - continue; - if (!Enqueue(i_lit, { - }, - { - })) - return false; + if (IsCurrentlyIgnored(i_lit.var)) continue; + if (!Enqueue(i_lit, {}, {})) return false; } encoder_->ClearNewlyFixedIntegerLiterals(); } @@ -578,8 +530,7 @@ bool IntegerTrail::Propagate(Trail *trail) { while (propagation_trail_index_ < trail->Index()) { const Literal literal = (*trail)[propagation_trail_index_++]; for (const IntegerLiteral i_lit : encoder_->GetIntegerLiterals(literal)) { - if (IsCurrentlyIgnored(i_lit.var)) - continue; + if (IsCurrentlyIgnored(i_lit.var)) continue; // The reason is simply the associated literal. if (!EnqueueAssociatedIntegerLiteral(i_lit, literal)) { @@ -594,8 +545,7 @@ bool IntegerTrail::Propagate(Trail *trail) { void IntegerTrail::Untrail(const Trail &trail, int literal_trail_index) { ++num_untrails_; const int level = trail.CurrentDecisionLevel(); - for (ReversibleInterface *rev : reversible_classes_) - rev->SetLevel(level); + for (ReversibleInterface *rev : reversible_classes_) rev->SetLevel(level); var_to_current_lb_interval_index_.SetLevel(level); propagation_trail_index_ = std::min(propagation_trail_index_, literal_trail_index); @@ -606,8 +556,7 @@ void IntegerTrail::Untrail(const Trail &trail, int literal_trail_index) { // Note that if a conflict was detected before Propagate() of this class was // even called, it is possible that there is nothing to backtrack. - if (level >= integer_search_levels_.size()) - return; + if (level >= integer_search_levels_.size()) return; const int target = integer_search_levels_[level]; integer_search_levels_.resize(level); CHECK_GE(target, vars_.size()); @@ -615,8 +564,7 @@ void IntegerTrail::Untrail(const Trail &trail, int literal_trail_index) { for (int index = integer_trail_.size() - 1; index >= target; --index) { const TrailEntry &entry = integer_trail_[index]; - if (entry.var < 0) - continue; // entry used by EnqueueLiteral(). + if (entry.var < 0) continue; // entry used by EnqueueLiteral(). vars_[entry.var].current_trail_index = entry.prev_trail_index; vars_[entry.var].current_bound = integer_trail_[entry.prev_trail_index].bound; @@ -662,12 +610,8 @@ IntegerVariable IntegerTrail::AddIntegerVariable(IntegerValue lower_bound, const IntegerVariable i(vars_.size()); is_ignored_literals_.push_back(kNoLiteralIndex); - vars_.push_back({ - lower_bound, static_cast(integer_trail_.size()) - }); - integer_trail_.push_back({ - lower_bound, i - }); + vars_.push_back({lower_bound, static_cast(integer_trail_.size())}); + integer_trail_.push_back({lower_bound, i}); domains_->push_back(Domain(lower_bound.value(), upper_bound.value())); // TODO(user): the is_ignored_literals_ Booleans are currently always the same @@ -675,12 +619,8 @@ IntegerVariable IntegerTrail::AddIntegerVariable(IntegerValue lower_bound, // so that we don't have to be careful when setting them. CHECK_EQ(NegationOf(i).value(), vars_.size()); is_ignored_literals_.push_back(kNoLiteralIndex); - vars_.push_back({ - -upper_bound, static_cast(integer_trail_.size()) - }); - integer_trail_.push_back({ - -upper_bound, NegationOf(i) - }); + vars_.push_back({-upper_bound, static_cast(integer_trail_.size())}); + integer_trail_.push_back({-upper_bound, NegationOf(i)}); domains_->push_back(Domain(-upper_bound.value(), -lower_bound.value())); var_trail_index_cache_.resize(vars_.size(), integer_trail_.size()); @@ -709,11 +649,9 @@ bool IntegerTrail::UpdateInitialDomain(IntegerVariable var, Domain domain) { const Domain &old_domain = InitialVariableDomain(var); domain = domain.IntersectionWith(old_domain); - if (old_domain == domain) - return true; + if (old_domain == domain) return true; - if (domain.IsEmpty()) - return false; + if (domain.IsEmpty()) return false; (*domains_)[var] = domain; (*domains_)[NegationOf(var)] = domain.Negation(); if (domain.NumIntervals() > 1) { @@ -725,27 +663,20 @@ bool IntegerTrail::UpdateInitialDomain(IntegerVariable var, Domain domain) { // bounds here directly. This is because these function might call again // UpdateInitialDomain(), and we will abort after realizing that the domain // didn't change this time. - CHECK( - Enqueue(IntegerLiteral::GreaterOrEqual(var, IntegerValue(domain.Min())), { - }, - { - })); - CHECK(Enqueue(IntegerLiteral::LowerOrEqual(var, IntegerValue(domain.Max())), { - }, - { - })); + CHECK(Enqueue(IntegerLiteral::GreaterOrEqual(var, IntegerValue(domain.Min())), + {}, {})); + CHECK(Enqueue(IntegerLiteral::LowerOrEqual(var, IntegerValue(domain.Max())), + {}, {})); // Set to false excluded literals. int i = 0; int num_fixed = 0; for (const IntegerEncoder::ValueLiteralPair pair : encoder_->PartialDomainEncoding(var)) { - while (i < domain.NumIntervals() && pair.value > domain[i].end) - ++i; + while (i < domain.NumIntervals() && pair.value > domain[i].end) ++i; if (i == domain.NumIntervals() || pair.value < domain[i].start) { ++num_fixed; - if (trail_->Assignment().LiteralIsTrue(pair.literal)) - return false; + if (trail_->Assignment().LiteralIsTrue(pair.literal)) return false; if (!trail_->Assignment().LiteralIsFalse(pair.literal)) { trail_->EnqueueWithUnitReason(pair.literal.Negated()); } @@ -760,10 +691,10 @@ bool IntegerTrail::UpdateInitialDomain(IntegerVariable var, Domain domain) { return true; } -IntegerVariable -IntegerTrail::GetOrCreateConstantIntegerVariable(IntegerValue value) { +IntegerVariable IntegerTrail::GetOrCreateConstantIntegerVariable( + IntegerValue value) { auto insert = constant_map_.insert(std::make_pair(value, kNoIntegerVariable)); - if (insert.second) { // new element. + if (insert.second) { // new element. const IntegerVariable new_var = AddIntegerVariable(value, value); insert.first->second = new_var; if (value != 0) { @@ -788,8 +719,7 @@ int IntegerTrail::FindTrailIndexOfVarBefore(IntegerVariable var, // for this var. const int index_in_queue = tmp_var_to_trail_index_in_queue_[var]; if (threshold <= index_in_queue) { - if (index_in_queue != kint32max) - has_dependency_ = true; + if (index_in_queue != kint32max) has_dependency_ = true; return -1; } @@ -816,11 +746,10 @@ int IntegerTrail::FindTrailIndexOfVarBefore(IntegerVariable var, return trail_index < num_vars ? -1 : trail_index; } -int -IntegerTrail::FindLowestTrailIndexThatExplainBound(IntegerLiteral i_lit) const { +int IntegerTrail::FindLowestTrailIndexThatExplainBound( + IntegerLiteral i_lit) const { DCHECK_LE(i_lit.bound, vars_[i_lit.var].current_bound); - if (i_lit.bound <= LevelZeroLowerBound(i_lit.var)) - return -1; + if (i_lit.bound <= LevelZeroLowerBound(i_lit.var)) return -1; int trail_index = vars_[i_lit.var].current_trail_index; // Check the validity of the cached index and use it if possible. This caching @@ -844,23 +773,19 @@ IntegerTrail::FindLowestTrailIndexThatExplainBound(IntegerLiteral i_lit) const { var_trail_index_cache_[i_lit.var] = trail_index; } const TrailEntry &entry = integer_trail_[trail_index]; - if (entry.bound == i_lit.bound) - return trail_index; - if (entry.bound < i_lit.bound) - return prev_trail_index; + if (entry.bound == i_lit.bound) return trail_index; + if (entry.bound < i_lit.bound) return prev_trail_index; prev_trail_index = trail_index; trail_index = entry.prev_trail_index; } } // TODO(user): Get rid of this function and only keep the trail index one? -void -IntegerTrail::RelaxLinearReason(IntegerValue slack, - absl::Span coeffs, - std::vector *reason) const { +void IntegerTrail::RelaxLinearReason( + IntegerValue slack, absl::Span coeffs, + std::vector *reason) const { CHECK_GE(slack, 0); - if (slack == 0) - return; + if (slack == 0) return; const int size = reason->size(); tmp_indices_.resize(size); for (int i = 0; i < size; ++i) { @@ -886,8 +811,7 @@ void IntegerTrail::AppendRelaxedLinearReason( for (const IntegerVariable var : vars) { tmp_indices_.push_back(vars_[var].current_trail_index); } - if (slack > 0) - RelaxLinearReason(slack, coeffs, &tmp_indices_); + if (slack > 0) RelaxLinearReason(slack, coeffs, &tmp_indices_); for (const int i : tmp_indices_) { reason->push_back(IntegerLiteral::GreaterOrEqual(integer_trail_[i].var, integer_trail_[i].bound)); @@ -911,8 +835,7 @@ void IntegerTrail::RelaxLinearReason(IntegerValue slack, const int index = (*trail_indices)[i]; // We ignore level zero entries. - if (index < num_vars) - continue; + if (index < num_vars) continue; // If the coeff is too large, we cannot relax this entry. const IntegerValue coeff = coeffs[i]; @@ -940,9 +863,7 @@ void IntegerTrail::RelaxLinearReason(IntegerValue slack, continue; } - relax_heap_.push_back({ - index, coeff, diff - }); + relax_heap_.push_back({index, coeff, diff}); } trail_indices->resize(new_size); std::make_heap(relax_heap_.begin(), relax_heap_.end()); @@ -963,8 +884,7 @@ void IntegerTrail::RelaxLinearReason(IntegerValue slack, const int index = integer_trail_[heap_entry.index].prev_trail_index; // Same code as in the first block. - if (index < num_vars) - continue; + if (index < num_vars) continue; if (heap_entry.coeff > slack) { trail_indices->push_back(index); continue; @@ -983,9 +903,7 @@ void IntegerTrail::RelaxLinearReason(IntegerValue slack, trail_indices->push_back(index); continue; } - relax_heap_.push_back({ - index, heap_entry.coeff, diff - }); + relax_heap_.push_back({index, heap_entry.coeff, diff}); std::push_heap(relax_heap_.begin(), relax_heap_.end()); } @@ -997,12 +915,11 @@ void IntegerTrail::RelaxLinearReason(IntegerValue slack, relax_heap_.clear(); } -void -IntegerTrail::RemoveLevelZeroBounds(std::vector *reason) const { +void IntegerTrail::RemoveLevelZeroBounds( + std::vector *reason) const { int new_size = 0; for (const IntegerLiteral literal : *reason) { - if (literal.bound <= LevelZeroLowerBound(literal.var)) - continue; + if (literal.bound <= LevelZeroLowerBound(literal.var)) continue; (*reason)[new_size++] = literal; } reason->resize(new_size); @@ -1019,8 +936,7 @@ std::vector *IntegerTrail::InitializeConflict( const int num_vars = vars_.size(); for (const IntegerLiteral &literal : bounds_reason) { const int trail_index = FindLowestTrailIndexThatExplainBound(literal); - if (trail_index >= num_vars) - tmp_queue_.push_back(trail_index); + if (trail_index >= num_vars) tmp_queue_.push_back(trail_index); } } else { // We use the current trail index here. @@ -1036,21 +952,19 @@ std::string ReasonDebugString(absl::Span literal_reason, absl::Span integer_reason) { std::string result = "literals:{"; for (const Literal l : literal_reason) { - if (result.back() != '{') - result += ","; + if (result.back() != '{') result += ","; result += l.DebugString(); } result += "} bounds:{"; for (const IntegerLiteral l : integer_reason) { - if (result.back() != '{') - result += ","; + if (result.back() != '{') result += ","; result += l.DebugString(); } result += "}"; return result; } -} // namespace +} // namespace std::string IntegerTrail::DebugString() { std::string result = "trail:{"; @@ -1058,11 +972,11 @@ std::string IntegerTrail::DebugString() { const int limit = std::min(num_vars + 30, static_cast(integer_trail_.size())); for (int i = num_vars; i < limit; ++i) { - if (result.back() != '{') - result += ","; + if (result.back() != '{') result += ","; result += IntegerLiteral::GreaterOrEqual(IntegerVariable(integer_trail_[i].var), - integer_trail_[i].bound).DebugString(); + integer_trail_[i].bound) + .DebugString(); } if (limit < integer_trail_.size()) { result += ", ..."; @@ -1088,20 +1002,15 @@ bool IntegerTrail::Enqueue(IntegerLiteral i_lit, bool IntegerTrail::Enqueue(IntegerLiteral i_lit, LazyReasonFunction lazy_reason) { - return EnqueueInternal(i_lit, lazy_reason, { - }, - { - }, - integer_trail_.size()); + return EnqueueInternal(i_lit, lazy_reason, {}, {}, integer_trail_.size()); } -bool -IntegerTrail::ReasonIsValid(absl::Span literal_reason, - absl::Span integer_reason) { +bool IntegerTrail::ReasonIsValid( + absl::Span literal_reason, + absl::Span integer_reason) { const VariablesAssignment &assignment = trail_->Assignment(); for (const Literal lit : literal_reason) { - if (!assignment.LiteralIsFalse(lit)) - return false; + if (!assignment.LiteralIsFalse(lit)) return false; } for (const IntegerLiteral i_lit : integer_reason) { if (i_lit.bound > vars_[i_lit.var].current_bound) { @@ -1145,10 +1054,9 @@ IntegerTrail::ReasonIsValid(absl::Span literal_reason, return true; } -void -IntegerTrail::EnqueueLiteral(Literal literal, - absl::Span literal_reason, - absl::Span integer_reason) { +void IntegerTrail::EnqueueLiteral( + Literal literal, absl::Span literal_reason, + absl::Span integer_reason) { EnqueueLiteralInternal(literal, nullptr, literal_reason, integer_reason); } @@ -1189,10 +1097,10 @@ void IntegerTrail::EnqueueLiteralInternal( integer_reason.begin(), integer_reason.end()); } - integer_trail_.push_back({ /*bound=*/ - IntegerValue(0), /*var=*/ kNoIntegerVariable, /*prev_trail_index=*/ -1, - /*reason_index=*/ reason_index - }); + integer_trail_.push_back({/*bound=*/ + IntegerValue(0), /*var=*/kNoIntegerVariable, + /*prev_trail_index=*/-1, + /*reason_index=*/reason_index}); trail_->Enqueue(literal, propagator_id_); } @@ -1216,14 +1124,11 @@ IntegerVariable IntegerTrail::NextVariableToBranchOnInPropagationLoop() const { std::vector vars; for (int i = integer_search_levels_.back(); i < integer_trail_.size(); ++i) { const IntegerVariable var = integer_trail_[i].var; - if (var == kNoIntegerVariable) - continue; - if (UpperBound(var) - LowerBound(var) <= 100) - continue; + if (var == kNoIntegerVariable) continue; + if (UpperBound(var) - LowerBound(var) <= 100) continue; vars.push_back(var); } - if (vars.empty()) - return kNoIntegerVariable; + if (vars.empty()) return kNoIntegerVariable; std::sort(vars.begin(), vars.end()); IntegerVariable best_var = vars[0]; int best_count = 1; @@ -1248,34 +1153,29 @@ bool IntegerTrail::CurrentBranchHadAnIncompletePropagation() { IntegerVariable IntegerTrail::FirstUnassignedVariable() const { for (IntegerVariable var(0); var < vars_.size(); var += 2) { - if (IsCurrentlyIgnored(var)) - continue; - if (!IsFixed(var)) - return var; + if (IsCurrentlyIgnored(var)) continue; + if (!IsFixed(var)) return var; } return kNoIntegerVariable; } -bool -IntegerTrail::EnqueueInternal(IntegerLiteral i_lit, - LazyReasonFunction lazy_reason, - absl::Span literal_reason, - absl::Span integer_reason, - int trail_index_with_same_reason) { +bool IntegerTrail::EnqueueInternal( + IntegerLiteral i_lit, LazyReasonFunction lazy_reason, + absl::Span literal_reason, + absl::Span integer_reason, + int trail_index_with_same_reason) { DCHECK(lazy_reason != nullptr || ReasonIsValid(literal_reason, integer_reason)); const IntegerVariable var(i_lit.var); // No point doing work if the variable is already ignored. - if (IsCurrentlyIgnored(var)) - return true; + if (IsCurrentlyIgnored(var)) return true; // Nothing to do if the bound is not better than the current one. // TODO(user): Change this to a CHECK? propagator shouldn't try to push such // bound and waste time explaining it. - if (i_lit.bound <= vars_[var].current_bound) - return true; + if (i_lit.bound <= vars_[var].current_bound) return true; ++num_enqueues_; // If the domain of var is not a single intervals and i_lit.bound fall into a @@ -1315,9 +1215,8 @@ IntegerTrail::EnqueueInternal(IntegerLiteral i_lit, } { const int trail_index = FindLowestTrailIndexThatExplainBound(ub_reason); - const int num_vars = vars_.size(); // must be signed. - if (trail_index >= num_vars) - tmp_queue_.push_back(trail_index); + const int num_vars = vars_.size(); // must be signed. + if (trail_index >= num_vars) tmp_queue_.push_back(trail_index); } MergeReasonIntoInternal(conflict); return false; @@ -1477,10 +1376,10 @@ IntegerTrail::EnqueueInternal(IntegerLiteral i_lit, } const int prev_trail_index = vars_[i_lit.var].current_trail_index; - integer_trail_.push_back({ /*bound=*/ - i_lit.bound, /*var=*/ i_lit.var, /*prev_trail_index=*/ prev_trail_index, - /*reason_index=*/ reason_index - }); + integer_trail_.push_back({/*bound=*/ + i_lit.bound, /*var=*/i_lit.var, + /*prev_trail_index=*/prev_trail_index, + /*reason_index=*/reason_index}); vars_[i_lit.var].current_bound = i_lit.bound; vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1; @@ -1489,16 +1388,11 @@ IntegerTrail::EnqueueInternal(IntegerLiteral i_lit, bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit, Literal literal_reason) { - DCHECK(ReasonIsValid({ - literal_reason.Negated() - }, - { - })); + DCHECK(ReasonIsValid({literal_reason.Negated()}, {})); DCHECK(!IsCurrentlyIgnored(i_lit.var)); // Nothing to do if the bound is not better than the current one. - if (i_lit.bound <= vars_[i_lit.var].current_bound) - return true; + if (i_lit.bound <= vars_[i_lit.var].current_bound) return true; ++num_enqueues_; // Check if the integer variable has an empty domain. Note that this should @@ -1506,11 +1400,7 @@ bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit, // have resulted in this literal beeing false. Because of this we revert to // the "generic" Enqueue() to avoid some code duplication. if (i_lit.bound > UpperBound(i_lit.var)) { - return Enqueue(i_lit, { - literal_reason.Negated() - }, - { - }); + return Enqueue(i_lit, {literal_reason.Negated()}, {}); } // Notify the watchers. @@ -1539,10 +1429,10 @@ bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit, literals_reason_buffer_.push_back(literal_reason.Negated()); const int prev_trail_index = vars_[i_lit.var].current_trail_index; - integer_trail_.push_back({ /*bound=*/ - i_lit.bound, /*var=*/ i_lit.var, /*prev_trail_index=*/ prev_trail_index, - /*reason_index=*/ reason_index - }); + integer_trail_.push_back({/*bound=*/ + i_lit.bound, /*var=*/i_lit.var, + /*prev_trail_index=*/prev_trail_index, + /*reason_index=*/reason_index}); vars_[i_lit.var].current_bound = i_lit.bound; vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1; @@ -1569,8 +1459,7 @@ absl::Span IntegerTrail::Dependencies(int trail_index) const { const int end = reason_index + 1 < bounds_reason_starts_.size() ? bounds_reason_starts_[reason_index + 1] : bounds_reason_buffer_.size(); - if (start == end) - return {}; + if (start == end) return {}; // Cache the result if not already computed. Remark, if the result was never // computed then the span trail_index_reason_buffer_[start, end) will either @@ -1630,10 +1519,7 @@ void IntegerTrail::AppendLiteralsReason(int trail_index, std::vector IntegerTrail::ReasonFor(IntegerLiteral literal) const { std::vector reason; - MergeReasonInto({ - literal - }, - &reason); + MergeReasonInto({literal}, &reason); return reason; } @@ -1648,8 +1534,7 @@ void IntegerTrail::MergeReasonInto(absl::Span literals, // Any indices lower than that means that there is no reason needed. // Note that it is important for size to be signed because of -1 indices. - if (trail_index >= num_vars) - tmp_queue_.push_back(trail_index); + if (trail_index >= num_vars) tmp_queue_.push_back(trail_index); } return MergeReasonIntoInternal(output); } @@ -1660,9 +1545,8 @@ void IntegerTrail::MergeReasonIntoInternal(std::vector *output) const { // All relevant trail indices will be >= vars_.size(), so we can safely use // zero to means that no literal refering to this variable is in the queue. DCHECK(std::all_of(tmp_var_to_trail_index_in_queue_.begin(), - tmp_var_to_trail_index_in_queue_.end(), [](int v) { - return v == 0; - })); + tmp_var_to_trail_index_in_queue_.end(), + [](int v) { return v == 0; })); added_variables_.ClearAndResize(BooleanVariable(trail_->NumVariables())); for (const Literal l : *output) { @@ -1748,8 +1632,7 @@ void IntegerTrail::MergeReasonIntoInternal(std::vector *output) const { ComputeLazyReasonIfNeeded(trail_index); AppendLiteralsReason(trail_index, output); for (const int next_trail_index : Dependencies(trail_index)) { - if (next_trail_index < 0) - break; + if (next_trail_index < 0) break; DCHECK_LT(next_trail_index, trail_index); const TrailEntry &next_entry = integer_trail_[next_trail_index]; @@ -1759,8 +1642,7 @@ void IntegerTrail::MergeReasonIntoInternal(std::vector *output) const { // in the queue refering to the same variable. const int index_in_queue = tmp_var_to_trail_index_in_queue_[next_entry.var]; - if (index_in_queue != kint32max) - has_dependency_ = true; + if (index_in_queue != kint32max) has_dependency_ = true; if (next_trail_index > index_in_queue) { tmp_var_to_trail_index_in_queue_[next_entry.var] = next_trail_index; tmp_queue_.push_back(next_trail_index); @@ -1791,8 +1673,7 @@ absl::Span IntegerTrail::Reason(const Trail &trail, AppendLiteralsReason(index, reason); DCHECK(tmp_queue_.empty()); for (const int prev_trail_index : Dependencies(index)) { - if (prev_trail_index < 0) - break; + if (prev_trail_index < 0) break; DCHECK_GE(prev_trail_index, vars_.size()); tmp_queue_.push_back(prev_trail_index); } @@ -1809,10 +1690,8 @@ void IntegerTrail::AppendNewBounds(std::vector *output) const { const int end = vars_.size(); for (int i = integer_trail_.size(); --i >= end;) { const TrailEntry &entry = integer_trail_[i]; - if (entry.var == kNoIntegerVariable) - continue; - if (tmp_marked_[entry.var]) - continue; + if (entry.var == kNoIntegerVariable) continue; + if (tmp_marked_[entry.var]) continue; tmp_marked_.Set(entry.var); output->push_back(IntegerLiteral::GreaterOrEqual(entry.var, entry.bound)); @@ -1833,15 +1712,14 @@ GenericLiteralWatcher::GenericLiteralWatcher(Model *model) integer_trail_->RegisterReversibleClass( &id_to_greatest_common_level_since_last_call_); integer_trail_->RegisterWatcher(&modified_vars_); - queue_by_priority_.resize(2); // Because default priority is 1. + queue_by_priority_.resize(2); // Because default priority is 1. } void GenericLiteralWatcher::UpdateCallingNeeds(Trail *trail) { // Process any new Literal on the trail. while (propagation_trail_index_ < trail->Index()) { const Literal literal = (*trail)[propagation_trail_index_++]; - if (literal.Index() >= literal_to_watcher_.size()) - continue; + if (literal.Index() >= literal_to_watcher_.size()) continue; for (const auto entry : literal_to_watcher_[literal.Index()]) { if (!in_queue_[entry.id]) { in_queue_[entry.id] = true; @@ -1855,8 +1733,7 @@ void GenericLiteralWatcher::UpdateCallingNeeds(Trail *trail) { // Process the newly changed variables lower bounds. for (const IntegerVariable var : modified_vars_.PositionsSetAtLeastOnce()) { - if (var.value() >= var_to_watcher_.size()) - continue; + if (var.value() >= var_to_watcher_.size()) continue; for (const auto entry : var_to_watcher_[var]) { if (!in_queue_[entry.id]) { in_queue_[entry.id] = true; @@ -1885,8 +1762,7 @@ bool GenericLiteralWatcher::Propagate(Trail *trail) { const int level = trail->CurrentDecisionLevel(); if (level == 0) { for (const int id : propagator_ids_to_call_at_level_zero_) { - if (in_queue_[id]) - continue; + if (in_queue_[id]) continue; in_queue_[id] = true; queue_by_priority_[id_to_priority_[id]].push_back(id); } @@ -1906,8 +1782,7 @@ bool GenericLiteralWatcher::Propagate(Trail *trail) { // the solve from the last time it was interupted. if (test_limit > 100) { test_limit = 0; - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; } std::deque &queue = queue_by_priority_[priority]; @@ -1922,15 +1797,13 @@ bool GenericLiteralWatcher::Propagate(Trail *trail) { const int low = id_to_greatest_common_level_since_last_call_[IdType(id)]; const int high = id_to_level_at_last_call_[id]; - if (low < high || level > low) { // Equivalent to not all equal. + if (low < high || level > low) { // Equivalent to not all equal. id_to_level_at_last_call_[id] = level; id_to_greatest_common_level_since_last_call_.MutableRef(IdType(id)) = level; for (ReversibleInterface *rev : id_to_reversible_classes_[id]) { - if (low < high) - rev->SetLevel(low); - if (level > low) - rev->SetLevel(level); + if (low < high) rev->SetLevel(low); + if (level > low) rev->SetLevel(level); } for (int *rev_int : id_to_reversible_ints_[id]) { rev_int_repository_->SaveState(rev_int); @@ -1989,7 +1862,7 @@ bool GenericLiteralWatcher::Propagate(Trail *trail) { // If the propagator pushed an integer bound, we revert to priority = 0. if (integer_trail_->num_enqueues() > old_integer_timestamp) { ++test_limit; - priority = -1; // Because of the ++priority in the for loop. + priority = -1; // Because of the ++priority in the for loop. break; } } @@ -2072,8 +1945,8 @@ void GenericLiteralWatcher::RegisterReversibleInt(int id, int *rev) { // This is really close to ExcludeCurrentSolutionAndBacktrack(). std::function ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack() { - return[ = ](Model *model) { SatSolver *sat_solver = - model->GetOrCreate(); + return [=](Model *model) { + SatSolver *sat_solver = model->GetOrCreate(); IntegerTrail *integer_trail = model->GetOrCreate(); IntegerEncoder *encoder = model->GetOrCreate(); @@ -2110,9 +1983,8 @@ ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack() { // the clause will be preprocessed correctly. sat_solver->Backtrack(0); model->Add(ClauseConstraint(clause_to_exclude_solution)); - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/integer.h b/ortools/sat/integer.h index 39fb9fbe62..a495426644 100644 --- a/ortools/sat/integer.h +++ b/ortools/sat/integer.h @@ -62,20 +62,19 @@ DEFINE_INT_TYPE(IntegerValue, int64); // this range on both side so that we can usally take care of integer overflow // by simply doing "saturated arithmetic" and if one of the bound overflow, the // two bounds will "cross" each others and we will get an empty range. -constexpr IntegerValue - kMaxIntegerValue(std::numeric_limits::max() - 1); +constexpr IntegerValue kMaxIntegerValue( + std::numeric_limits::max() - 1); constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue); inline double ToDouble(IntegerValue value) { const double kInfinity = std::numeric_limits::infinity(); - if (value >= kMaxIntegerValue) - return kInfinity; - if (value <= kMinIntegerValue) - return -kInfinity; + if (value >= kMaxIntegerValue) return kInfinity; + if (value <= kMinIntegerValue) return -kInfinity; return static_cast(value.value()); } -template inline IntType IntTypeAbs(IntType t) { +template +inline IntType IntTypeAbs(IntType t) { return IntType(std::abs(t.value())); } @@ -110,11 +109,9 @@ inline IntegerValue PositiveRemainder(IntegerValue dividend, // Computes result += a * b, and return false iff there is an overflow. inline bool AddProductTo(IntegerValue a, IntegerValue b, IntegerValue *result) { const int64 prod = CapProd(a.value(), b.value()); - if (prod == kint64min || prod == kint64max) - return false; + if (prod == kint64min || prod == kint64max) return false; const int64 add = CapAdd(prod, result->value()); - if (add == kint64min || add == kint64max) - return false; + if (add == kint64min || add == kint64max) return false; *result = IntegerValue(add); return true; } @@ -145,8 +142,8 @@ inline PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var) { } // Returns the vector of the negated variables. -std::vector - NegationOf(const std::vector &vars); +std::vector NegationOf( + const std::vector &vars); // The integer equivalent of a literal. // It represents an IntegerVariable and an upper/lower bound on it. @@ -227,8 +224,8 @@ struct AffineExpression { } // The coefficient MUST be positive. Use NegationOf(var) if needed. - IntegerVariable var = kNoIntegerVariable; // kNoIntegerVariable for constant. - IntegerValue coeff = IntegerValue(0); // Zero for constant. + IntegerVariable var = kNoIntegerVariable; // kNoIntegerVariable for constant. + IntegerValue coeff = IntegerValue(0); // Zero for constant. IntegerValue constant = IntegerValue(0); }; @@ -318,8 +315,8 @@ class IntegerEncoder { // Same as FullDomainEncoding() but only returns the list of value that are // currently associated to a literal. In particular this has no guarantee to // span the full domain of the given variable (but it might). - std::vector - PartialDomainEncoding(IntegerVariable var) const; + std::vector PartialDomainEncoding( + IntegerVariable var) const; // Returns the "canonical" (i_lit, negation of i_lit) pair. This mainly // deal with domain with initial hole like [1,2][5,6] so that if one ask @@ -331,8 +328,8 @@ class IntegerEncoder { // // TODO(user): This is linear in the domain "complexity", we can do better if // needed. - std::pair - Canonicalize(IntegerLiteral i_lit) const; + std::pair Canonicalize( + IntegerLiteral i_lit) const; // Returns, after creating it if needed, a Boolean literal such that: // - if true, then the IntegerLiteral is true. @@ -407,8 +404,7 @@ class IntegerEncoder { // exist. Note that one can create one by creating a new IntegerVariable and // calling AssociateToIntegerEqualValue(). const IntegerVariable GetLiteralView(Literal lit) const { - if (lit.Index() >= literal_view_.size()) - return kNoIntegerVariable; + if (lit.Index() >= literal_view_.size()) return kNoIntegerVariable; return literal_view_[lit.Index()]; } @@ -439,8 +435,8 @@ class IntegerEncoder { // Returns the set of Literal associated to IntegerLiteral of the form var >= // value. We make a copy, because this can be easily invalidated when calling // any function of this class. So it is less efficient but safer. - std::map - PartialGreaterThanEncoding(IntegerVariable var) const { + std::map PartialGreaterThanEncoding( + IntegerVariable var) const { if (var >= encoding_by_var_.size()) { return std::map(); } @@ -537,8 +533,8 @@ class IntegerTrail : public SatPropagator { // correct state before calling any of its functions. bool Propagate(Trail *trail) final; void Untrail(const Trail &trail, int literal_trail_index) final; - absl::Span Reason(const Trail &trail, int trail_index) const - final; + absl::Span Reason(const Trail &trail, + int trail_index) const final; // Returns the number of created integer variables. // @@ -709,9 +705,9 @@ class IntegerTrail : public SatPropagator { // TODO(user): If the given bound is equal to the current bound, maybe the new // reason is better? how to decide and what to do in this case? to think about // it. Currently we simply don't do anything. - ABSL_MUST_USE_RESULT bool - Enqueue(IntegerLiteral i_lit, absl::Span literal_reason, - absl::Span integer_reason); + ABSL_MUST_USE_RESULT bool Enqueue( + IntegerLiteral i_lit, absl::Span literal_reason, + absl::Span integer_reason); // Same as Enqueue(), but takes an extra argument which if smaller than // integer_trail_.size() is interpreted as the trail index of an old Enqueue() @@ -720,10 +716,10 @@ class IntegerTrail : public SatPropagator { // // TODO(user): This currently cannot refer to a trail_index with a lazy // reason. Fix or at least check that this is the case. - ABSL_MUST_USE_RESULT bool - Enqueue(IntegerLiteral i_lit, absl::Span literal_reason, - absl::Span integer_reason, - int trail_index_with_same_reason); + ABSL_MUST_USE_RESULT bool Enqueue( + IntegerLiteral i_lit, absl::Span literal_reason, + absl::Span integer_reason, + int trail_index_with_same_reason); // Lazy reason API. // @@ -736,9 +732,9 @@ class IntegerTrail : public SatPropagator { // to explain is propagated. In this case, trail_index_of_literal will be // the current trail index, and we cannot assume that there is anything filled // yet in integer_literal[trail_index_of_literal]. - using LazyReasonFunction = std::function< - void(IntegerLiteral literal_to_explain, int trail_index_of_literal, - std::vector *literals, std::vector *dependencies)>; + using LazyReasonFunction = std::function *literals, std::vector *dependencies)>; ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, LazyReasonFunction lazy_reason); @@ -788,9 +784,7 @@ class IntegerTrail : public SatPropagator { return false; } bool ReportConflict(absl::Span integer_reason) { - DCHECK(ReasonIsValid({ - }, - integer_reason)); + DCHECK(ReasonIsValid({}, integer_reason)); std::vector *conflict = trail_->MutableConflict(); conflict->clear(); MergeReasonInto(integer_reason, conflict); @@ -843,18 +837,17 @@ class IntegerTrail : public SatPropagator { // Called by the Enqueue() functions that detected a conflict. This does some // common conflict initialization that must terminate by a call to // MergeReasonIntoInternal(conflict) where conflict is the returned vector. - std::vector * - InitializeConflict(IntegerLiteral integer_literal, - const LazyReasonFunction &lazy_reason, - absl::Span literals_reason, - absl::Span bounds_reason); + std::vector *InitializeConflict( + IntegerLiteral integer_literal, const LazyReasonFunction &lazy_reason, + absl::Span literals_reason, + absl::Span bounds_reason); // Internal implementation of the different public Enqueue() functions. - ABSL_MUST_USE_RESULT bool - EnqueueInternal(IntegerLiteral i_lit, LazyReasonFunction lazy_reason, - absl::Span literal_reason, - absl::Span integer_reason, - int trail_index_with_same_reason); + ABSL_MUST_USE_RESULT bool EnqueueInternal( + IntegerLiteral i_lit, LazyReasonFunction lazy_reason, + absl::Span literal_reason, + absl::Span integer_reason, + int trail_index_with_same_reason); // Internal implementation of the EnqueueLiteral() functions. void EnqueueLiteralInternal(Literal literal, LazyReasonFunction lazy_reason, @@ -864,9 +857,8 @@ class IntegerTrail : public SatPropagator { // Same as EnqueueInternal() but for the case where we push an IntegerLiteral // because an associated Literal is true (and we know it). In this case, we // have less work to do, so this has the same effect but is faster. - ABSL_MUST_USE_RESULT bool - EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit, - Literal literal_reason); + ABSL_MUST_USE_RESULT bool EnqueueAssociatedIntegerLiteral( + IntegerLiteral i_lit, Literal literal_reason); // Does the work of MergeReasonInto() when queue_ is already initialized. void MergeReasonIntoInternal(std::vector *output) const; @@ -1044,7 +1036,7 @@ class PropagatorInterface { // indices of the literals modified after the registration will be present. virtual bool IncrementalPropagate(const std::vector &watch_indices) { LOG(FATAL) << "Not implemented."; - return false; // Remove warning in Windows + return false; // Remove warning in Windows } }; @@ -1243,31 +1235,28 @@ inline bool IntegerTrail::IsFixed(IntegerVariable i) const { // TODO(user): Use capped arithmetic? It might be slow though and we better just // make sure there is no overflow at model creation. inline IntegerValue IntegerTrail::LowerBound(AffineExpression expr) const { - if (expr.var == kNoIntegerVariable) - return expr.constant; + if (expr.var == kNoIntegerVariable) return expr.constant; return LowerBound(expr.var) * expr.coeff + expr.constant; } // TODO(user): Use capped arithmetic? same remark as for LowerBound(). inline IntegerValue IntegerTrail::UpperBound(AffineExpression expr) const { - if (expr.var == kNoIntegerVariable) - return expr.constant; + if (expr.var == kNoIntegerVariable) return expr.constant; return UpperBound(expr.var) * expr.coeff + expr.constant; } inline bool IntegerTrail::IsFixed(AffineExpression expr) const { - if (expr.var == kNoIntegerVariable) - return true; + if (expr.var == kNoIntegerVariable) return true; return IsFixed(expr.var); } -inline IntegerLiteral -IntegerTrail::LowerBoundAsLiteral(IntegerVariable i) const { +inline IntegerLiteral IntegerTrail::LowerBoundAsLiteral( + IntegerVariable i) const { return IntegerLiteral::GreaterOrEqual(i, LowerBound(i)); } -inline IntegerLiteral -IntegerTrail::UpperBoundAsLiteral(IntegerVariable i) const { +inline IntegerLiteral IntegerTrail::UpperBoundAsLiteral( + IntegerVariable i) const { return IntegerLiteral::LowerOrEqual(i, UpperBound(i)); } @@ -1281,13 +1270,13 @@ inline bool IntegerTrail::IntegerLiteralIsFalse(IntegerLiteral l) const { // The level zero bounds are stored at the beginning of the trail and they also // serves as sentinels. Their index match the variables index. -inline IntegerValue -IntegerTrail::LevelZeroLowerBound(IntegerVariable var) const { +inline IntegerValue IntegerTrail::LevelZeroLowerBound( + IntegerVariable var) const { return integer_trail_[var.value()].bound; } -inline IntegerValue -IntegerTrail::LevelZeroUpperBound(IntegerVariable var) const { +inline IntegerValue IntegerTrail::LevelZeroUpperBound( + IntegerVariable var) const { return -integer_trail_[NegationOf(var).value()].bound; } @@ -1301,27 +1290,21 @@ inline void GenericLiteralWatcher::WatchLiteral(Literal l, int id, if (l.Index() >= literal_to_watcher_.size()) { literal_to_watcher_.resize(l.Index().value() + 1); } - literal_to_watcher_[l.Index()].push_back({ - id, watch_index - }); + literal_to_watcher_[l.Index()].push_back({id, watch_index}); } inline void GenericLiteralWatcher::WatchLowerBound(IntegerVariable var, int id, int watch_index) { - if (var == kNoIntegerVariable) - return; + if (var == kNoIntegerVariable) return; if (var.value() >= var_to_watcher_.size()) { var_to_watcher_.resize(var.value() + 1); } - var_to_watcher_[var].push_back({ - id, watch_index - }); + var_to_watcher_[var].push_back({id, watch_index}); } inline void GenericLiteralWatcher::WatchUpperBound(IntegerVariable var, int id, int watch_index) { - if (var == kNoIntegerVariable) - return; + if (var == kNoIntegerVariable) return; WatchLowerBound(NegationOf(var), id, watch_index); } @@ -1341,47 +1324,43 @@ inline void GenericLiteralWatcher::WatchIntegerVariable(IntegerVariable i, // ============================================================================ inline std::function NewBooleanVariable() { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->NewBooleanVariable(); - } - ; + }; } -inline std::function -ConstantIntegerVariable(int64 value) { - return[ = ](Model * model) { +inline std::function ConstantIntegerVariable( + int64 value) { + return [=](Model *model) { return model->GetOrCreate() ->GetOrCreateConstantIntegerVariable(IntegerValue(value)); - } - ; + }; } inline std::function NewIntegerVariable(int64 lb, int64 ub) { - return[ = ](Model * model) { CHECK_LE(lb, ub); - return model->GetOrCreate() - ->AddIntegerVariable(IntegerValue(lb), IntegerValue(ub)); - } - ; + return [=](Model *model) { + CHECK_LE(lb, ub); + return model->GetOrCreate()->AddIntegerVariable( + IntegerValue(lb), IntegerValue(ub)); + }; } -inline std::function -NewIntegerVariable(const Domain &domain) { - return[ = ](Model * model) { +inline std::function NewIntegerVariable( + const Domain &domain) { + return [=](Model *model) { return model->GetOrCreate()->AddIntegerVariable(domain); - } - ; + }; } // Creates a 0-1 integer variable "view" of the given literal. It will have a // value of 1 when the literal is true, and 0 when the literal is false. -inline std::function -NewIntegerVariableFromLiteral(Literal lit) { - return[ = ](Model *model) { auto *encoder = - model->GetOrCreate(); +inline std::function NewIntegerVariableFromLiteral( + Literal lit) { + return [=](Model *model) { + auto *encoder = model->GetOrCreate(); const IntegerVariable candidate = encoder->GetLiteralView(lit); - if (candidate != kNoIntegerVariable) - return candidate; + if (candidate != kNoIntegerVariable) return candidate; IntegerVariable var; const auto &assignment = model->GetOrCreate()->Assignment(); @@ -1396,81 +1375,72 @@ NewIntegerVariableFromLiteral(Literal lit) { encoder->AssociateToIntegerEqualValue(lit, var, IntegerValue(1)); DCHECK_NE(encoder->GetLiteralView(lit), kNoIntegerVariable); return var; - } - ; + }; } inline std::function LowerBound(IntegerVariable v) { - return[ = ](const Model & - model) { return model.Get()->LowerBound(v).value(); - } - ; + return [=](const Model &model) { + return model.Get()->LowerBound(v).value(); + }; } inline std::function UpperBound(IntegerVariable v) { - return[ = ](const Model & - model) { return model.Get()->UpperBound(v).value(); - } - ; + return [=](const Model &model) { + return model.Get()->UpperBound(v).value(); + }; } inline std::function IsFixed(IntegerVariable v) { - return[ = ](const Model &model) { const IntegerTrail *trail = - model.Get(); + return [=](const Model &model) { + const IntegerTrail *trail = model.Get(); return trail->LowerBound(v) == trail->UpperBound(v); - } - ; + }; } // This checks that the variable is fixed. inline std::function Value(IntegerVariable v) { - return[ = ](const Model &model) { const IntegerTrail *trail = - model.Get(); + return [=](const Model &model) { + const IntegerTrail *trail = model.Get(); CHECK_EQ(trail->LowerBound(v), trail->UpperBound(v)) << v; return trail->LowerBound(v).value(); - } - ; + }; } inline std::function GreaterOrEqual(IntegerVariable v, int64 lb) { - return[ = ](Model * model) { + return [=](Model *model) { if (!model->GetOrCreate()->Enqueue( IntegerLiteral::GreaterOrEqual(v, IntegerValue(lb)), - std::vector(), std::vector())) - { + std::vector(), std::vector())) { model->GetOrCreate()->NotifyThatModelIsUnsat(); VLOG(1) << "Model trivially infeasible, variable " << v << " has upper bound " << model->Get(UpperBound(v)) << " and GreaterOrEqual() was called with a lower bound of " << lb; } - } - ; + }; } inline std::function LowerOrEqual(IntegerVariable v, int64 ub) { - return[ = ](Model * model) { + return [=](Model *model) { if (!model->GetOrCreate()->Enqueue( IntegerLiteral::LowerOrEqual(v, IntegerValue(ub)), - std::vector(), std::vector())) - { + std::vector(), std::vector())) { model->GetOrCreate()->NotifyThatModelIsUnsat(); LOG(WARNING) << "Model trivially infeasible, variable " << v << " has lower bound " << model->Get(LowerBound(v)) << " and LowerOrEqual() was called with an upper bound of " << ub; } - } - ; + }; } // Fix v to a given value. inline std::function Equality(IntegerVariable v, int64 value) { - return[ = ](Model * model) { model->Add(LowerOrEqual(v, value)); + return [=](Model *model) { + model->Add(LowerOrEqual(v, value)); model->Add(GreaterOrEqual(v, value)); - } - ; + }; } // TODO(user): This is one of the rare case where it is better to use Equality() @@ -1479,11 +1449,10 @@ inline std::function Equality(IntegerVariable v, int64 value) { // direction integer-bound => literal, but just literal => integer-bound? This // is the same as using different underlying variable for an integer literal and // its negation. -inline std::function -Implication(const std::vector &enforcement_literals, - IntegerLiteral i) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); +inline std::function Implication( + const std::vector &enforcement_literals, IntegerLiteral i) { + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); if (i.bound <= integer_trail->LowerBound(i.var)) { // Always true! nothing to do. } else if (i.bound > integer_trail->UpperBound(i.var)) { @@ -1497,42 +1466,32 @@ Implication(const std::vector &enforcement_literals, // TODO(user): Double check what happen when we associate a trivially // true or false literal. IntegerEncoder *encoder = model->GetOrCreate(); - std::vector clause { encoder->GetOrCreateAssociatedLiteral(i) } - ; + std::vector clause{encoder->GetOrCreateAssociatedLiteral(i)}; for (const Literal literal : enforcement_literals) { clause.push_back(literal.Negated()); } model->Add(ClauseConstraint(clause)); } - } - ; + }; } // in_interval => v in [lb, ub]. inline std::function ImpliesInInterval(Literal in_interval, IntegerVariable v, int64 lb, int64 ub) { - return[ = ](Model * model) { if (lb == ub) - { + return [=](Model *model) { + if (lb == ub) { IntegerEncoder *encoder = model->GetOrCreate(); - model->Add(Implication({ - in_interval - }, + model->Add(Implication({in_interval}, encoder->GetOrCreateLiteralAssociatedToEquality( v, IntegerValue(lb)))); return; } - model->Add( - Implication({ - in_interval - }, - IntegerLiteral::GreaterOrEqual(v, IntegerValue(lb)))); - model->Add(Implication({ - in_interval - }, + model->Add(Implication( + {in_interval}, IntegerLiteral::GreaterOrEqual(v, IntegerValue(lb)))); + model->Add(Implication({in_interval}, IntegerLiteral::LowerOrEqual(v, IntegerValue(ub)))); - } - ; + }; } // Calling model.Add(FullyEncodeVariable(var)) will create one literal per value @@ -1541,14 +1500,13 @@ inline std::function ImpliesInInterval(Literal in_interval, // the IntegerEncoder class. inline std::function(Model *)> FullyEncodeVariable(IntegerVariable var) { - return[ = ](Model *model) { IntegerEncoder *encoder = - model->GetOrCreate(); + return [=](Model *model) { + IntegerEncoder *encoder = model->GetOrCreate(); if (!encoder->VariableIsFullyEncoded(var)) { encoder->FullyEncodeVariable(var); } return encoder->FullDomainEncoding(var); - } - ; + }; } // Same as ExcludeCurrentSolutionAndBacktrack() but this version works for an @@ -1557,9 +1515,9 @@ FullyEncodeVariable(IntegerVariable var) { // want to enumerate them. This function should exclude all solutions where // only the ignored variable values change. std::function - ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack(); +ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack(); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_INTEGER_H_ +#endif // OR_TOOLS_SAT_INTEGER_H_ diff --git a/ortools/sat/integer_expr.cc b/ortools/sat/integer_expr.cc index ce331c18b7..6513eda5da 100644 --- a/ortools/sat/integer_expr.cc +++ b/ortools/sat/integer_expr.cc @@ -31,13 +31,15 @@ IntegerSumLE::IntegerSumLE(const std::vector &enforcement_literals, const std::vector &vars, const std::vector &coeffs, IntegerValue upper, Model *model) - : enforcement_literals_(enforcement_literals), upper_bound_(upper), + : enforcement_literals_(enforcement_literals), + upper_bound_(upper), trail_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()), time_limit_(model->GetOrCreate()), rev_integer_value_repository_( model->GetOrCreate()), - vars_(vars), coeffs_(coeffs) { + vars_(vars), + coeffs_(coeffs) { // TODO(user): deal with this corner case. CHECK(!vars_.empty()); max_variations_.resize(vars_.size()); @@ -79,8 +81,7 @@ bool IntegerSumLE::Propagate() { int num_unassigned_enforcement_literal = 0; LiteralIndex unique_unnasigned_literal = kNoLiteralIndex; for (const Literal literal : enforcement_literals_) { - if (trail_->Assignment().LiteralIsFalse(literal)) - return true; + if (trail_->Assignment().LiteralIsFalse(literal)) return true; if (!trail_->Assignment().LiteralIsTrue(literal)) { ++num_unassigned_enforcement_literal; unique_unnasigned_literal = literal.Index(); @@ -89,8 +90,7 @@ bool IntegerSumLE::Propagate() { // Unfortunately, we can't propagate anything if we have more than one // unassigned enforcement literal. - if (num_unassigned_enforcement_literal > 1) - return true; + if (num_unassigned_enforcement_literal > 1) return true; // Save the current sum of fixed variables. if (is_registered_) { @@ -140,25 +140,24 @@ bool IntegerSumLE::Propagate() { } // We can only propagate more if all the enforcement literals are true. - if (num_unassigned_enforcement_literal > 0) - return true; + if (num_unassigned_enforcement_literal > 0) return true; // The lower bound of all the variables except one can be used to update the // upper bound of the last one. for (int i = rev_num_fixed_vars_; i < num_vars; ++i) { - if (max_variations_[i] <= slack) - continue; + if (max_variations_[i] <= slack) continue; const IntegerVariable var = vars_[i]; const IntegerValue coeff = coeffs_[i]; const IntegerValue div = slack / coeff; const IntegerValue new_ub = integer_trail_->LowerBound(var) + div; const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1; - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(var, new_ub), - /*lazy_reason=*/[this, propagation_slack]( - IntegerLiteral i_lit, int trail_index, - std::vector * literal_reason, - std::vector * trail_indices_reason) { + if (!integer_trail_->Enqueue( + IntegerLiteral::LowerOrEqual(var, new_ub), + /*lazy_reason=*/[this, propagation_slack]( + IntegerLiteral i_lit, int trail_index, + std::vector *literal_reason, + std::vector *trail_indices_reason) { *literal_reason = literal_reason_; trail_indices_reason->clear(); reason_coeffs_.clear(); @@ -181,7 +180,7 @@ bool IntegerSumLE::Propagate() { integer_trail_->RelaxLinearReason( propagation_slack, reason_coeffs_, trail_indices_reason); } - })) { + })) { return false; } } @@ -209,7 +208,9 @@ LevelZeroEquality::LevelZeroEquality(IntegerVariable target, const std::vector &vars, const std::vector &coeffs, Model *model) - : target_(target), vars_(vars), coeffs_(coeffs), + : target_(target), + vars_(vars), + coeffs_(coeffs), trail_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()) { auto *watcher = model->GetOrCreate(); @@ -231,8 +232,7 @@ bool LevelZeroEquality::Propagate() { // TODO(user): Once the GCD is not 1, we could at any level make sure the // objective is of the correct form. For now, this only happen in a few // miplib problem that we close quickly, so I didn't add the extra code yet. - if (trail_->CurrentDecisionLevel() != 0) - return true; + if (trail_->CurrentDecisionLevel() != 0) return true; int64 gcd = 0; IntegerValue sum(0); @@ -242,11 +242,9 @@ bool LevelZeroEquality::Propagate() { continue; } gcd = MathUtil::GCD64(gcd, std::abs(coeffs_[i].value())); - if (gcd == 1) - break; + if (gcd == 1) break; } - if (gcd == 0) - return true; // All fixed. + if (gcd == 0) return true; // All fixed. if (gcd > gcd_) { VLOG(1) << "Objective gcd: " << gcd; @@ -258,10 +256,8 @@ bool LevelZeroEquality::Propagate() { const IntegerValue lb_remainder = PositiveRemainder(lb - sum, gcd_); if (lb_remainder != 0) { if (!integer_trail_->Enqueue( - IntegerLiteral::GreaterOrEqual(target_, lb + gcd_ - lb_remainder), { - }, - { - })) + IntegerLiteral::GreaterOrEqual(target_, lb + gcd_ - lb_remainder), + {}, {})) return false; } @@ -270,10 +266,7 @@ bool LevelZeroEquality::Propagate() { PositiveRemainder(ub - sum, IntegerValue(gcd)); if (ub_remainder != 0) { if (!integer_trail_->Enqueue( - IntegerLiteral::LowerOrEqual(target_, ub - ub_remainder), { - }, - { - })) + IntegerLiteral::LowerOrEqual(target_, ub - ub_remainder), {}, {})) return false; } @@ -286,8 +279,7 @@ MinPropagator::MinPropagator(const std::vector &vars, : vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {} bool MinPropagator::Propagate() { - if (vars_.empty()) - return true; + if (vars_.empty()) return true; // Count the number of interval that are possible candidate for the min. // Only the intervals for which lb > current_min_ub cannot. @@ -314,9 +306,7 @@ bool MinPropagator::Propagate() { integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, min)); } if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(min_var_, min), - { - }, - integer_reason_)) { + {}, integer_reason_)) { return false; } } @@ -332,17 +322,14 @@ bool MinPropagator::Propagate() { // And that min_ub has its current value. integer_reason_.push_back(min_ub_literal); for (const IntegerVariable var : vars_) { - if (var == vars_[last_possible_min_interval]) - continue; + if (var == vars_[last_possible_min_interval]) continue; integer_reason_.push_back( IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1)); } if (!integer_trail_->Enqueue( IntegerLiteral::LowerOrEqual(vars_[last_possible_min_interval], current_min_ub), - { - }, - integer_reason_)) { + {}, integer_reason_)) { return false; } } @@ -379,7 +366,9 @@ void MinPropagator::RegisterWith(GenericLiteralWatcher *watcher) { LinMinPropagator::LinMinPropagator(const std::vector &exprs, IntegerVariable min_var, Model *model) - : exprs_(exprs), min_var_(min_var), model_(model), + : exprs_(exprs), + min_var_(min_var), + model_(model), integer_trail_(model_->GetOrCreate()) {} bool LinMinPropagator::PropagateLinearUpperBound( @@ -399,8 +388,8 @@ bool LinMinPropagator::PropagateLinearUpperBound( sum_lb += lb * coeff; } - model_->GetOrCreate() - ->AdvanceDeterministicTime(static_cast(num_vars) * 1e-9); + model_->GetOrCreate()->AdvanceDeterministicTime( + static_cast(num_vars) * 1e-9); const IntegerValue slack = upper_bound - sum_lb; @@ -421,16 +410,13 @@ bool LinMinPropagator::PropagateLinearUpperBound( integer_reason_for_unique_candidate_; local_reason.insert(local_reason.end(), linear_sum_reason.begin(), linear_sum_reason.end()); - return integer_trail_->ReportConflict({ - }, - local_reason); + return integer_trail_->ReportConflict({}, local_reason); } // The lower bound of all the variables except one can be used to update the // upper bound of the last one. for (int i = 0; i < num_vars; ++i) { - if (max_variations[i] <= slack) - continue; + if (max_variations[i] <= slack) continue; const IntegerVariable var = vars[i]; const IntegerValue coeff = coeffs[i]; @@ -441,9 +427,9 @@ bool LinMinPropagator::PropagateLinearUpperBound( if (!integer_trail_->Enqueue( IntegerLiteral::LowerOrEqual(var, new_ub), /*lazy_reason=*/[this, &vars, &coeffs, propagation_slack]( - IntegerLiteral i_lit, int trail_index, - std::vector * literal_reason, - std::vector * trail_indices_reason) { + IntegerLiteral i_lit, int trail_index, + std::vector *literal_reason, + std::vector *trail_indices_reason) { literal_reason->clear(); trail_indices_reason->clear(); std::vector reason_coeffs; @@ -475,7 +461,7 @@ bool LinMinPropagator::PropagateLinearUpperBound( trail_indices_reason->push_back(index); } } - })) { + })) { return false; } } @@ -483,8 +469,7 @@ bool LinMinPropagator::PropagateLinearUpperBound( } bool LinMinPropagator::Propagate() { - if (exprs_.empty()) - return true; + if (exprs_.empty()) return true; expr_lbs_.clear(); @@ -528,9 +513,7 @@ bool LinMinPropagator::Propagate() { } if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual( min_var_, min_of_linear_expression_lb), - { - }, - local_reason)) { + {}, local_reason)) { return false; } } @@ -552,8 +535,7 @@ bool LinMinPropagator::Propagate() { // And that min_ub has its current value. integer_reason_for_unique_candidate_.push_back(min_ub_literal); for (int i = 0; i < exprs_.size(); ++i) { - if (i == last_possible_min_interval) - continue; + if (i == last_possible_min_interval) continue; const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1); integer_trail_->AppendRelaxedLinearReason( (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs, @@ -607,12 +589,9 @@ bool PositiveProductPropagator::Propagate() { const IntegerValue max_b = integer_trail_->UpperBound(b_); const IntegerValue new_max(CapProd(max_a.value(), max_b.value())); if (new_max < integer_trail_->UpperBound(p_)) { - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(p_, new_max), { - }, - { - integer_trail_->UpperBoundAsLiteral(a_), - integer_trail_->UpperBoundAsLiteral(b_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(p_, new_max), {}, + {integer_trail_->UpperBoundAsLiteral(a_), + integer_trail_->UpperBoundAsLiteral(b_)})) { return false; } } @@ -621,12 +600,10 @@ bool PositiveProductPropagator::Propagate() { const IntegerValue min_b = integer_trail_->LowerBound(b_); const IntegerValue new_min(CapProd(min_a.value(), min_b.value())); if (new_min > integer_trail_->LowerBound(p_)) { - if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(p_, new_min), { - }, - { - integer_trail_->LowerBoundAsLiteral(a_), - integer_trail_->LowerBoundAsLiteral(b_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(p_, new_min), + {}, + {integer_trail_->LowerBoundAsLiteral(a_), + integer_trail_->LowerBoundAsLiteral(b_)})) { return false; } } @@ -641,22 +618,16 @@ bool PositiveProductPropagator::Propagate() { const IntegerValue prod(CapProd(max_a.value(), min_b.value())); if (prod > max_p) { if (!integer_trail_->Enqueue( - IntegerLiteral::LowerOrEqual(a, FloorRatio(max_p, min_b)), { - }, - { - integer_trail_->LowerBoundAsLiteral(b), - integer_trail_->UpperBoundAsLiteral(p_) - })) { + IntegerLiteral::LowerOrEqual(a, FloorRatio(max_p, min_b)), {}, + {integer_trail_->LowerBoundAsLiteral(b), + integer_trail_->UpperBoundAsLiteral(p_)})) { return false; } } else if (prod < min_p) { if (!integer_trail_->Enqueue( - IntegerLiteral::GreaterOrEqual(b, CeilRatio(min_p, max_a)), { - }, - { - integer_trail_->UpperBoundAsLiteral(a), - integer_trail_->LowerBoundAsLiteral(p_) - })) { + IntegerLiteral::GreaterOrEqual(b, CeilRatio(min_p, max_a)), {}, + {integer_trail_->UpperBoundAsLiteral(a), + integer_trail_->LowerBoundAsLiteral(p_)})) { return false; } } @@ -678,24 +649,20 @@ namespace { // TODO(user): Find better implementation? IntegerValue FloorSquareRoot(IntegerValue a) { IntegerValue result(static_cast(std::floor(std::sqrt(ToDouble(a))))); - while (result * result > a) - --result; - while ((result + 1) * (result + 1) <= a) - ++result; + while (result * result > a) --result; + while ((result + 1) * (result + 1) <= a) ++result; return result; } // TODO(user): Find better implementation? IntegerValue CeilSquareRoot(IntegerValue a) { IntegerValue result(static_cast(std::ceil(std::sqrt(ToDouble(a))))); - while (result * result < a) - ++result; - while ((result - 1) * (result - 1) >= a) - --result; + while (result * result < a) ++result; + while ((result - 1) * (result - 1) >= a) --result; return result; } -} // namespace +} // namespace SquarePropagator::SquarePropagator(IntegerVariable x, IntegerVariable s, IntegerTrail *integer_trail) @@ -711,20 +678,16 @@ bool SquarePropagator::Propagate() { const IntegerValue min_x_square(CapProd(min_x.value(), min_x.value())); if (min_x_square > min_s) { if (!integer_trail_->Enqueue( - IntegerLiteral::GreaterOrEqual(s_, min_x_square), { - }, - { - IntegerLiteral::GreaterOrEqual(x_, min_x) - })) { + IntegerLiteral::GreaterOrEqual(s_, min_x_square), {}, + {IntegerLiteral::GreaterOrEqual(x_, min_x)})) { return false; } } else if (min_x_square < min_s) { const IntegerValue new_min = CeilSquareRoot(min_s); - if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(x_, new_min), { - }, - { - IntegerLiteral::GreaterOrEqual(s_, (new_min - 1) * (new_min - 1) + 1) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(x_, new_min), + {}, + {IntegerLiteral::GreaterOrEqual( + s_, (new_min - 1) * (new_min - 1) + 1)})) { return false; } } @@ -734,20 +697,15 @@ bool SquarePropagator::Propagate() { const IntegerValue max_x_square(CapProd(max_x.value(), max_x.value())); if (max_x_square < max_s) { if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(s_, max_x_square), - { - }, - { - IntegerLiteral::LowerOrEqual(x_, max_x) - })) { + {}, + {IntegerLiteral::LowerOrEqual(x_, max_x)})) { return false; } } else if (max_x_square > max_s) { const IntegerValue new_max = FloorSquareRoot(max_s); - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(x_, new_max), { - }, - { - IntegerLiteral::LowerOrEqual(s_, (new_max + 1) * (new_max + 1) - 1) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(x_, new_max), {}, + {IntegerLiteral::LowerOrEqual( + s_, (new_max + 1) * (new_max + 1) - 1)})) { return false; } } @@ -768,7 +726,7 @@ DivisionPropagator::DivisionPropagator(IntegerVariable a, IntegerVariable b, : a_(a), b_(b), c_(c), integer_trail_(integer_trail) { // TODO(user): support these cases. CHECK_GE(integer_trail->LevelZeroLowerBound(a), 0); - CHECK_GT(integer_trail->LevelZeroLowerBound(b), 0); // b can never be zero. + CHECK_GT(integer_trail->LevelZeroLowerBound(b), 0); // b can never be zero. } bool DivisionPropagator::Propagate() { @@ -781,23 +739,17 @@ bool DivisionPropagator::Propagate() { if (max_a / min_b < max_c) { max_c = max_a / min_b; - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), { - }, - { - integer_trail_->UpperBoundAsLiteral(a_), - integer_trail_->LowerBoundAsLiteral(b_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), {}, + {integer_trail_->UpperBoundAsLiteral(a_), + integer_trail_->LowerBoundAsLiteral(b_)})) { return false; } } if (min_a / max_b > min_c) { min_c = min_a / max_b; - if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), { - }, - { - integer_trail_->LowerBoundAsLiteral(a_), - integer_trail_->UpperBoundAsLiteral(b_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), {}, + {integer_trail_->LowerBoundAsLiteral(a_), + integer_trail_->UpperBoundAsLiteral(b_)})) { return false; } } @@ -832,11 +784,8 @@ bool FixedDivisionPropagator::Propagate() { if (max_a / b_ < max_c) { max_c = max_a / b_; - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), { - }, - { - integer_trail_->UpperBoundAsLiteral(a_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), {}, + {integer_trail_->UpperBoundAsLiteral(a_)})) { return false; } } else if (max_a / b_ > max_c) { @@ -844,22 +793,17 @@ bool FixedDivisionPropagator::Propagate() { max_c >= 0 ? max_c * b_ + b_ - 1 : IntegerValue(CapProd(max_c.value(), b_.value())); CHECK_LT(new_max_a, max_a); - if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(a_, new_max_a), { - }, - { - integer_trail_->UpperBoundAsLiteral(c_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(a_, new_max_a), + {}, + {integer_trail_->UpperBoundAsLiteral(c_)})) { return false; } } if (min_a / b_ > min_c) { min_c = min_a / b_; - if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), { - }, - { - integer_trail_->LowerBoundAsLiteral(a_) - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), {}, + {integer_trail_->LowerBoundAsLiteral(a_)})) { return false; } } else if (min_a / b_ < min_c) { @@ -868,11 +812,8 @@ bool FixedDivisionPropagator::Propagate() { : min_c * b_ - b_ + 1; CHECK_GT(new_min_a, min_a); if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(a_, new_min_a), - { - }, - { - integer_trail_->LowerBoundAsLiteral(c_) - })) { + {}, + {integer_trail_->LowerBoundAsLiteral(c_)})) { return false; } } @@ -889,8 +830,8 @@ void FixedDivisionPropagator::RegisterWith(GenericLiteralWatcher *watcher) { std::function IsOneOf(IntegerVariable var, const std::vector &selectors, const std::vector &values) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); IntegerEncoder *encoder = model->GetOrCreate(); CHECK(!values.empty()); @@ -922,9 +863,8 @@ std::function IsOneOf(IntegerVariable var, encoder->AssociateToIntegerEqualValue(l, var, IntegerValue(v)); } } - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/integer_expr.h b/ortools/sat/integer_expr.h index 2320d47b65..e6eef57050 100644 --- a/ortools/sat/integer_expr.h +++ b/ortools/sat/integer_expr.h @@ -291,20 +291,22 @@ class SquarePropagator : public PropagatorInterface { // Weighted sum <= constant. template -inline std::function -WeightedSumLowerOrEqual(const std::vector &vars, - const VectorInt &coefficients, int64 upper_bound) { +inline std::function WeightedSumLowerOrEqual( + const std::vector &vars, const VectorInt &coefficients, + int64 upper_bound) { // Special cases. CHECK_GE(vars.size(), 1); if (vars.size() == 1) { const int64 c = coefficients[0]; CHECK_NE(c, 0); if (c > 0) { - return LowerOrEqual(vars[0], FloorRatio(IntegerValue(upper_bound), - IntegerValue(c)).value()); + return LowerOrEqual( + vars[0], + FloorRatio(IntegerValue(upper_bound), IntegerValue(c)).value()); } else { - return GreaterOrEqual(vars[0], CeilRatio(IntegerValue(-upper_bound), - IntegerValue(-c)).value()); + return GreaterOrEqual( + vars[0], + CeilRatio(IntegerValue(-upper_bound), IntegerValue(-c)).value()); } } if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) && @@ -322,7 +324,7 @@ WeightedSumLowerOrEqual(const std::vector &vars, coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound); } - return[ = ](Model *model) { + return [=](Model *model) { // We split large constraints into a square root number of parts. // This is to avoid a bad complexity while propagating them since our // algorithm is not in O(num_changes). @@ -363,10 +365,8 @@ WeightedSumLowerOrEqual(const std::vector &vars, bucket_sum_vars.push_back(bucket_sum); local_vars.push_back(bucket_sum); local_coeffs.push_back(IntegerValue(-1)); - IntegerSumLE *constraint = - new IntegerSumLE({ - }, - local_vars, local_coeffs, IntegerValue(0), model); + IntegerSumLE *constraint = new IntegerSumLE( + {}, local_vars, local_coeffs, IntegerValue(0), model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); } @@ -379,48 +379,41 @@ WeightedSumLowerOrEqual(const std::vector &vars, local_coeffs.push_back(IntegerValue(1)); } IntegerSumLE *constraint = new IntegerSumLE( - { - }, - local_vars, local_coeffs, IntegerValue(upper_bound), model); + {}, local_vars, local_coeffs, IntegerValue(upper_bound), model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); return; } IntegerSumLE *constraint = new IntegerSumLE( - { - }, - vars, + {}, vars, std::vector(coefficients.begin(), coefficients.end()), IntegerValue(upper_bound), model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // Weighted sum >= constant. template -inline std::function -WeightedSumGreaterOrEqual(const std::vector &vars, - const VectorInt &coefficients, int64 lower_bound) { +inline std::function WeightedSumGreaterOrEqual( + const std::vector &vars, const VectorInt &coefficients, + int64 lower_bound) { // We just negate everything and use an <= constraints. std::vector negated_coeffs(coefficients.begin(), coefficients.end()); - for (int64 &ref : negated_coeffs) - ref = -ref; + for (int64 &ref : negated_coeffs) ref = -ref; return WeightedSumLowerOrEqual(vars, negated_coeffs, -lower_bound); } // Weighted sum == constant. template -inline std::function -FixedWeightedSum(const std::vector &vars, - const VectorInt &coefficients, int64 value) { - return[ = ](Model * model) { +inline std::function FixedWeightedSum( + const std::vector &vars, const VectorInt &coefficients, + int64 value) { + return [=](Model *model) { model->Add(WeightedSumGreaterOrEqual(vars, coefficients, value)); model->Add(WeightedSumLowerOrEqual(vars, coefficients, value)); - } - ; + }; } // enforcement_literals => sum <= upper_bound @@ -465,15 +458,15 @@ inline std::function ConditionalWeightedSumLowerOrEqual( enforcement_literals); } - return[ = ](Model * model) { + return [=](Model *model) { // If value == min(expression), then we can avoid creating the sum. IntegerValue expression_min(0); auto *integer_trail = model->GetOrCreate(); for (int i = 0; i < vars.size(); ++i) { expression_min += - coefficients[i] * - (coefficients[i] >= 0 ? integer_trail->LowerBound(vars[i]) - : integer_trail->UpperBound(vars[i])); + coefficients[i] * (coefficients[i] >= 0 + ? integer_trail->LowerBound(vars[i]) + : integer_trail->UpperBound(vars[i])); } if (expression_min == upper_bound) { for (int i = 0; i < vars.size(); ++i) { @@ -497,8 +490,7 @@ inline std::function ConditionalWeightedSumLowerOrEqual( constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); } - } - ; + }; } // enforcement_literals => sum >= lower_bound @@ -509,29 +501,22 @@ inline std::function ConditionalWeightedSumGreaterOrEqual( int64 lower_bound) { // We just negate everything and use an <= constraint. std::vector negated_coeffs(coefficients.begin(), coefficients.end()); - for (int64 &ref : negated_coeffs) - ref = -ref; + for (int64 &ref : negated_coeffs) ref = -ref; return ConditionalWeightedSumLowerOrEqual(enforcement_literals, vars, negated_coeffs, -lower_bound); } // Weighted sum <= constant reified. template -inline std::function -WeightedSumLowerOrEqualReif(Literal is_le, - const std::vector &vars, - const VectorInt &coefficients, int64 upper_bound) { - return [=](Model* model) { - model->Add(ConditionalWeightedSumLowerOrEqual( - { is_le }, vars, coefficients, +inline std::function WeightedSumLowerOrEqualReif( + Literal is_le, const std::vector &vars, + const VectorInt &coefficients, int64 upper_bound) { + return [=](Model *model) { + model->Add(ConditionalWeightedSumLowerOrEqual({is_le}, vars, coefficients, upper_bound)); - model->Add(ConditionalWeightedSumGreaterOrEqual({ - is_le.Negated() - }, - vars, coefficients, - upper_bound + 1)); - } - ; + model->Add(ConditionalWeightedSumGreaterOrEqual( + {is_le.Negated()}, vars, coefficients, upper_bound + 1)); + }; } // Weighted sum >= constant reified. @@ -539,32 +524,25 @@ template inline std::function WeightedSumGreaterOrEqualReif( Literal is_ge, const std::vector &vars, const VectorInt &coefficients, int64 lower_bound) { - return [=](Model* model) { - model->Add(ConditionalWeightedSumGreaterOrEqual( - { is_ge }, vars, coefficients, + return [=](Model *model) { + model->Add(ConditionalWeightedSumGreaterOrEqual({is_ge}, vars, coefficients, lower_bound)); - model->Add(ConditionalWeightedSumLowerOrEqual({ - is_ge.Negated() - }, - vars, coefficients, - lower_bound - 1)); - } - ; + model->Add(ConditionalWeightedSumLowerOrEqual( + {is_ge.Negated()}, vars, coefficients, lower_bound - 1)); + }; } // LinearConstraint version. inline void LoadLinearConstraint(const LinearConstraint &cst, Model *model) { if (cst.vars.empty()) { - if (cst.lb <= 0 && cst.ub >= 0) - return; + if (cst.lb <= 0 && cst.ub >= 0) return; model->GetOrCreate()->NotifyThatModelIsUnsat(); return; } // TODO(user): Remove the conversion! std::vector converted_coeffs; - for (const IntegerValue v : cst.coeffs) - converted_coeffs.push_back(v.value()); + for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value()); if (cst.ub < kMaxIntegerValue) { model->Add( WeightedSumLowerOrEqual(cst.vars, converted_coeffs, cst.ub.value())); @@ -582,8 +560,7 @@ inline void LoadConditionalLinearConstraint( return LoadLinearConstraint(cst, model); } if (cst.vars.empty()) { - if (cst.lb <= 0 && cst.ub >= 0) - return; + if (cst.lb <= 0 && cst.ub >= 0) return; return model->Add(ClauseConstraint(enforcement_literals)); } @@ -591,8 +568,7 @@ inline void LoadConditionalLinearConstraint( std::vector converted_literals(enforcement_literals.begin(), enforcement_literals.end()); std::vector converted_coeffs; - for (const IntegerValue v : cst.coeffs) - converted_coeffs.push_back(v.value()); + for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value()); if (cst.ub < kMaxIntegerValue) { model->Add(ConditionalWeightedSumLowerOrEqual( @@ -607,31 +583,27 @@ inline void LoadConditionalLinearConstraint( // Weighted sum == constant reified. // TODO(user): Simplify if the constant is at the edge of the possible values. template -inline std::function -FixedWeightedSumReif(Literal is_eq, const std::vector &vars, - const VectorInt &coefficients, int64 value) { - return[ = ](Model *model) { +inline std::function FixedWeightedSumReif( + Literal is_eq, const std::vector &vars, + const VectorInt &coefficients, int64 value) { + return [=](Model *model) { // We creates two extra Boolean variables in this case. The alternative is // to code a custom propagator for the direction equality => reified. const Literal is_le = Literal(model->Add(NewBooleanVariable()), true); const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true); - model->Add(ReifiedBoolAnd({ - is_le, is_ge - }, - is_eq)); + model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq)); model->Add(WeightedSumLowerOrEqualReif(is_le, vars, coefficients, value)); model->Add(WeightedSumGreaterOrEqualReif(is_ge, vars, coefficients, value)); - } - ; + }; } // Weighted sum != constant. // TODO(user): Simplify if the constant is at the edge of the possible values. template -inline std::function -WeightedSumNotEqual(const std::vector &vars, - const VectorInt &coefficients, int64 value) { - return[ = ](Model *model) { +inline std::function WeightedSumNotEqual( + const std::vector &vars, const VectorInt &coefficients, + int64 value) { + return [=](Model *model) { // Exactly one of these alternative must be true. const Literal is_lt = Literal(model->Add(NewBooleanVariable()), true); const Literal is_gt = is_lt.Negated(); @@ -639,8 +611,7 @@ WeightedSumNotEqual(const std::vector &vars, value - 1)); model->Add(ConditionalWeightedSumGreaterOrEqual(is_gt, vars, coefficients, value + 1)); - } - ; + }; } // Model-based function to create an IntegerVariable that corresponds to the @@ -651,10 +622,10 @@ WeightedSumNotEqual(const std::vector &vars, // // TODO(user): invert the coefficients/vars arguments. template -inline std::function -NewWeightedSum(const VectorInt &coefficients, - const std::vector &vars) { - return[ = ](Model *model) { std::vector new_vars = vars; +inline std::function NewWeightedSum( + const VectorInt &coefficients, const std::vector &vars) { + return [=](Model *model) { + std::vector new_vars = vars; // To avoid overflow in the FixedWeightedSum() constraint, we need to // compute the basic bounds on the sum. // @@ -677,34 +648,33 @@ NewWeightedSum(const VectorInt &coefficients, new_coeffs.push_back(-1); model->Add(FixedWeightedSum(new_vars, new_coeffs, 0)); return sum; - } - ; + }; } // Expresses the fact that an existing integer variable is equal to the minimum // of other integer variables. -inline std::function -IsEqualToMinOf(IntegerVariable min_var, - const std::vector &vars) { - return[ = ](Model * model) { for (const IntegerVariable & var : vars) - { model->Add(LowerOrEqual(min_var, var)); } +inline std::function IsEqualToMinOf( + IntegerVariable min_var, const std::vector &vars) { + return [=](Model *model) { + for (const IntegerVariable &var : vars) { + model->Add(LowerOrEqual(min_var, var)); + } MinPropagator *constraint = new MinPropagator(vars, min_var, model->GetOrCreate()); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // Expresses the fact that an existing integer variable is equal to the minimum // of linear expressions. Assumes Canonical expressions (all positive // coefficients). -inline std::function -IsEqualToMinOf(const LinearExpression &min_expr, - const std::vector &exprs) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); +inline std::function IsEqualToMinOf( + const LinearExpression &min_expr, + const std::vector &exprs) { + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); IntegerVariable min_var; if (min_expr.vars.size() == 1 && @@ -747,16 +717,15 @@ IsEqualToMinOf(const LinearExpression &min_expr, LinMinPropagator *constraint = new LinMinPropagator(exprs, min_var, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // Expresses the fact that an existing integer variable is equal to the maximum // of other integer variables. -inline std::function -IsEqualToMaxOf(IntegerVariable max_var, - const std::vector &vars) { - return[ = ](Model * model) { std::vector negated_vars; +inline std::function IsEqualToMaxOf( + IntegerVariable max_var, const std::vector &vars) { + return [=](Model *model) { + std::vector negated_vars; for (const IntegerVariable &var : vars) { negated_vars.push_back(NegationOf(var)); model->Add(GreaterOrEqual(max_var, var)); @@ -766,8 +735,7 @@ IsEqualToMaxOf(IntegerVariable max_var, negated_vars, NegationOf(max_var), model->GetOrCreate()); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // Expresses the fact that an existing integer variable is equal to one of @@ -776,7 +744,8 @@ std::function IsOneOf(IntegerVariable var, const std::vector &selectors, const std::vector &values); -template void RegisterAndTransferOwnership(Model *model, T *ct) { +template +void RegisterAndTransferOwnership(Model *model, T *ct) { ct->RegisterWith(model->GetOrCreate()); model->TakeOwnership(ct); } @@ -784,8 +753,8 @@ template void RegisterAndTransferOwnership(Model *model, T *ct) { inline std::function ProductConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable p) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); if (a == b) { if (model->Get(LowerBound(a)) >= 0) { RegisterAndTransferOwnership(model, @@ -818,41 +787,38 @@ inline std::function ProductConstraint(IntegerVariable a, } else { LOG(FATAL) << "Not supported"; } - } - ; + }; } // Adds the constraint: a / b = c. inline std::function DivisionConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable c) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); DivisionPropagator *constraint = new DivisionPropagator(a, b, c, integer_trail); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } // Adds the constraint: a / b = c where b is a constant. inline std::function FixedDivisionConstraint(IntegerVariable a, IntegerValue b, IntegerVariable c) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); FixedDivisionPropagator *constraint = b > 0 ? new FixedDivisionPropagator(a, b, c, integer_trail) : new FixedDivisionPropagator(NegationOf(a), -b, c, integer_trail); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_INTEGER_EXPR_H_ +#endif // OR_TOOLS_SAT_INTEGER_EXPR_H_ diff --git a/ortools/sat/integer_search.cc b/ortools/sat/integer_search.cc index e76e955087..dd3ec7a2bf 100644 --- a/ortools/sat/integer_search.cc +++ b/ortools/sat/integer_search.cc @@ -38,8 +38,7 @@ IntegerLiteral AtMinValue(IntegerVariable var, IntegerTrail *integer_trail) { DCHECK(!integer_trail->IsCurrentlyIgnored(var)); const IntegerValue lb = integer_trail->LowerBound(var); DCHECK_LE(lb, integer_trail->UpperBound(var)); - if (lb == integer_trail->UpperBound(var)) - return IntegerLiteral(); + if (lb == integer_trail->UpperBound(var)) return IntegerLiteral(); return IntegerLiteral::LowerOrEqual(var, lb); } @@ -106,8 +105,7 @@ IntegerLiteral SplitAroundLpValue(IntegerVariable var, Model *model) { // We only use this if the sub-lp has a solution, and depending on the value // of exploit_all_lp_solution() if it is a pure-integer solution. - if (lp == nullptr || !lp->HasSolution()) - return IntegerLiteral(); + if (lp == nullptr || !lp->HasSolution()) return IntegerLiteral(); if (!parameters->exploit_all_lp_solution() && !lp->SolutionIsInteger()) { return IntegerLiteral(); } @@ -129,8 +127,9 @@ IntegerLiteral SplitUsingBestSolutionValueInRepository( } const IntegerVariable positive_var = PositiveVariable(var); - const int proto_var = model->Get() - ->GetProtoVariableFromIntegerVariable(positive_var); + const int proto_var = + model->Get()->GetProtoVariableFromIntegerVariable( + positive_var); if (proto_var < 0) { return IntegerLiteral(); @@ -138,7 +137,7 @@ IntegerLiteral SplitUsingBestSolutionValueInRepository( VLOG(2) << "Using solution value for branching."; const IntegerValue value(solution_repo.GetVariableValueInSolution( - proto_var, /*solution_index=*/ 0)); + proto_var, /*solution_index=*/0)); return SplitAroundGivenValue(positive_var, value, model); } @@ -146,35 +145,29 @@ IntegerLiteral SplitUsingBestSolutionValueInRepository( // the one below is ok when search_branching is set to SAT_SEARCH because it is // not executed often, but otherwise it is done for each search decision, // which seems expensive. Improve. -std::function -FirstUnassignedVarAtItsMinHeuristic(const std::vector &vars, - Model *model) { +std::function FirstUnassignedVarAtItsMinHeuristic( + const std::vector &vars, Model *model) { auto *integer_trail = model->GetOrCreate(); - return[/*copy*/ vars, integer_trail]() { for (const IntegerVariable var - : vars) - { + return [/*copy*/ vars, integer_trail]() { + for (const IntegerVariable var : vars) { // Note that there is no point trying to fix a currently ignored variable. - if (integer_trail->IsCurrentlyIgnored(var)) - continue; + if (integer_trail->IsCurrentlyIgnored(var)) continue; const IntegerLiteral decision = AtMinValue(var, integer_trail); - if (decision.IsValid()) - return BooleanOrIntegerLiteral(decision); + if (decision.IsValid()) return BooleanOrIntegerLiteral(decision); } return BooleanOrIntegerLiteral(); - } - ; + }; } std::function UnassignedVarWithLowestMinAtItsMinHeuristic( const std::vector &vars, Model *model) { auto *integer_trail = model->GetOrCreate(); - return[/*copy */ vars, integer_trail]() { IntegerVariable candidate = - kNoIntegerVariable; + return [/*copy */ vars, integer_trail]() { + IntegerVariable candidate = kNoIntegerVariable; IntegerValue candidate_lb; for (const IntegerVariable var : vars) { - if (integer_trail->IsCurrentlyIgnored(var)) - continue; + if (integer_trail->IsCurrentlyIgnored(var)) continue; const IntegerValue lb = integer_trail->LowerBound(var); if (lb < integer_trail->UpperBound(var) && (candidate == kNoIntegerVariable || lb < candidate_lb)) { @@ -182,24 +175,20 @@ UnassignedVarWithLowestMinAtItsMinHeuristic( candidate_lb = lb; } } - if (candidate == kNoIntegerVariable) - return BooleanOrIntegerLiteral(); + if (candidate == kNoIntegerVariable) return BooleanOrIntegerLiteral(); return BooleanOrIntegerLiteral(AtMinValue(candidate, integer_trail)); - } - ; + }; } std::function SequentialSearch( std::vector > heuristics) { - return[heuristics]() { for (const auto & h : heuristics) - { + return [heuristics]() { + for (const auto &h : heuristics) { const BooleanOrIntegerLiteral decision = h(); - if (decision.HasValue()) - return decision; + if (decision.HasValue()) return decision; } return BooleanOrIntegerLiteral(); - } - ; + }; } std::function SequentialValueSelection( @@ -209,19 +198,17 @@ std::function SequentialValueSelection( Model *model) { auto *encoder = model->GetOrCreate(); auto *integer_trail = model->GetOrCreate(); - return[ = ]() { + return [=]() { // Get the current decision. const BooleanOrIntegerLiteral current_decision = var_selection_heuristic(); - if (!current_decision.HasValue()) - return current_decision; + if (!current_decision.HasValue()) return current_decision; // IntegerLiteral case. if (current_decision.boolean_literal_index == kNoLiteralIndex) { for (const auto &value_heuristic : value_selection_heuristics) { const IntegerLiteral decision = value_heuristic(current_decision.integer_literal.var); - if (decision.IsValid()) - return BooleanOrIntegerLiteral(decision); + if (decision.IsValid()) return BooleanOrIntegerLiteral(decision); } return current_decision; } @@ -230,21 +217,18 @@ std::function SequentialValueSelection( // associated with an integer variable. for (const IntegerLiteral l : encoder->GetAllIntegerLiterals( Literal(current_decision.boolean_literal_index))) { - if (integer_trail->IsCurrentlyIgnored(l.var)) - continue; + if (integer_trail->IsCurrentlyIgnored(l.var)) continue; // Sequentially try the value selection heuristics. for (const auto &value_heuristic : value_selection_heuristics) { const IntegerLiteral decision = value_heuristic(l.var); - if (decision.IsValid()) - return BooleanOrIntegerLiteral(decision); + if (decision.IsValid()) return BooleanOrIntegerLiteral(decision); } } VLOG(2) << "Value selection: using default decision."; return current_decision; - } - ; + }; } bool LinearizedPartIsLarge(Model *model) { @@ -289,7 +273,7 @@ std::function IntegerValueSelectionHeuristic( [model, response_manager](IntegerVariable var) { return SplitUsingBestSolutionValueInRepository( var, response_manager->SolutionsRepository(), model); - }); + }); } } @@ -303,7 +287,7 @@ std::function IntegerValueSelectionHeuristic( VLOG(1) << "Using relaxation solution value selection heuristic."; return SplitUsingBestSolutionValueInRepository( var, *relaxation_solutions, model); - }); + }); } } @@ -325,13 +309,11 @@ std::function SatSolverHeuristic(Model *model) { SatDecisionPolicy *decision_policy = model->GetOrCreate(); return [sat_solver, trail, decision_policy] { const bool all_assigned = trail->Index() == sat_solver->NumVariables(); - if (all_assigned) - return BooleanOrIntegerLiteral(); + if (all_assigned) return BooleanOrIntegerLiteral(); const Literal result = decision_policy->NextBranch(); CHECK(!sat_solver->Assignment().LiteralIsAssigned(result)); return BooleanOrIntegerLiteral(result.Index()); - } - ; + }; } std::function PseudoCost(Model *model) { @@ -339,44 +321,35 @@ std::function PseudoCost(Model *model) { const bool has_objective = objective != nullptr && objective->objective_var != kNoIntegerVariable; if (!has_objective) { - return[]() { return BooleanOrIntegerLiteral(); - } - ; + return []() { return BooleanOrIntegerLiteral(); }; } auto *pseudo_costs = model->GetOrCreate(); auto *integer_trail = model->GetOrCreate(); - return[pseudo_costs, integer_trail]() { + return [pseudo_costs, integer_trail]() { const IntegerVariable chosen_var = pseudo_costs->GetBestDecisionVar(); - if (chosen_var == kNoIntegerVariable) - return BooleanOrIntegerLiteral(); + if (chosen_var == kNoIntegerVariable) return BooleanOrIntegerLiteral(); return BooleanOrIntegerLiteral( GreaterOrEqualToMiddleValue(chosen_var, integer_trail)); - } - ; + }; } -std::function -RandomizeOnRestartHeuristic(Model *model) { +std::function RandomizeOnRestartHeuristic( + Model *model) { SatSolver *sat_solver = model->GetOrCreate(); SatDecisionPolicy *decision_policy = model->GetOrCreate(); // TODO(user): Add other policy and perform more experiments. std::function sat_policy = SatSolverHeuristic(model); - std::vector > policies { - sat_policy, SequentialSearch({ - PseudoCost(model), sat_policy - }) - } - ; + std::vector > policies{ + sat_policy, SequentialSearch({PseudoCost(model), sat_policy})}; // The higher weight for the sat policy is because this policy actually // contains a lot of variation as we randomize the sat parameters. // TODO(user,user): Do more experiments to find better distribution. - std::discrete_distribution var_dist { - 3 /*sat_policy*/, 1 /*Pseudo cost*/ - } - ; + std::discrete_distribution var_dist{ + 3 /*sat_policy*/, 1 /*Pseudo cost*/ + }; // Value selection. std::vector > @@ -396,7 +369,7 @@ RandomizeOnRestartHeuristic(Model *model) { [model, response_manager](IntegerVariable var) { return SplitUsingBestSolutionValueInRepository( var, response_manager->SolutionsRepository(), model); - }); + }); value_selection_weight.push_back(5); } @@ -407,7 +380,7 @@ RandomizeOnRestartHeuristic(Model *model) { [model, relaxation_solutions](IntegerVariable var) { return SplitUsingBestSolutionValueInRepository( var, *relaxation_solutions, model); - }); + }); value_selection_weight.push_back(3); } @@ -435,8 +408,8 @@ RandomizeOnRestartHeuristic(Model *model) { int policy_index = 0; int val_policy_index = 0; auto *encoder = model->GetOrCreate(); - return[ = ]() mutable { if (sat_solver->CurrentDecisionLevel() == 0) - { + return [=]() mutable { + if (sat_solver->CurrentDecisionLevel() == 0) { auto *random = model->GetOrCreate(); RandomizeDecisionHeuristic(random, model->GetOrCreate()); decision_policy->ResetDecisionHeuristic(); @@ -450,8 +423,7 @@ RandomizeOnRestartHeuristic(Model *model) { // Get the current decision. const BooleanOrIntegerLiteral current_decision = policies[policy_index](); - if (!current_decision.HasValue()) - return current_decision; + if (!current_decision.HasValue()) return current_decision; // Special case: Don't override the decision value. if (val_policy_index >= value_selection_heuristics.size()) { @@ -462,100 +434,84 @@ RandomizeOnRestartHeuristic(Model *model) { const IntegerLiteral new_decision = value_selection_heuristics[val_policy_index]( current_decision.integer_literal.var); - if (new_decision.IsValid()) - return BooleanOrIntegerLiteral(new_decision); + if (new_decision.IsValid()) return BooleanOrIntegerLiteral(new_decision); return current_decision; } // Decode the decision and get the variable. for (const IntegerLiteral l : encoder->GetAllIntegerLiterals( Literal(current_decision.boolean_literal_index))) { - if (integer_trail->IsCurrentlyIgnored(l.var)) - continue; + if (integer_trail->IsCurrentlyIgnored(l.var)) continue; // Try the selected policy. const IntegerLiteral new_decision = value_selection_heuristics[val_policy_index](l.var); - if (new_decision.IsValid()) - return BooleanOrIntegerLiteral(new_decision); + if (new_decision.IsValid()) return BooleanOrIntegerLiteral(new_decision); } // Selected policy failed. Revert back to original decision. return current_decision; - } - ; + }; } // TODO(user): Avoid the quadratic algorithm!! -std::function -FollowHint(const std::vector &vars, - const std::vector &values, Model *model) { +std::function FollowHint( + const std::vector &vars, + const std::vector &values, Model *model) { const Trail *trail = model->GetOrCreate(); const IntegerTrail *integer_trail = model->GetOrCreate(); return [=] { // copy - for (int i = 0; - i < vars.size(); ++i) { + for (int i = 0; i < vars.size(); ++i) { const IntegerValue value = values[i]; if (vars[i].bool_var != kNoBooleanVariable) { - if (trail->Assignment().VariableIsAssigned(vars[i].bool_var)) - continue; - return BooleanOrIntegerLiteral(Literal(vars[i].bool_var, value == 1) - .Index()); + if (trail->Assignment().VariableIsAssigned(vars[i].bool_var)) continue; + return BooleanOrIntegerLiteral( + Literal(vars[i].bool_var, value == 1).Index()); } else { const IntegerVariable integer_var = vars[i].int_var; - if (integer_trail->IsCurrentlyIgnored(integer_var)) - continue; - if (integer_trail->IsFixed(integer_var)) - continue; + if (integer_trail->IsCurrentlyIgnored(integer_var)) continue; + if (integer_trail->IsFixed(integer_var)) continue; const IntegerVariable positive_var = PositiveVariable(integer_var); const IntegerLiteral decision = SplitAroundGivenValue( positive_var, positive_var != integer_var ? -value : value, model); - if (decision.IsValid()) - return BooleanOrIntegerLiteral(decision); + if (decision.IsValid()) return BooleanOrIntegerLiteral(decision); // If the value is outside the current possible domain, we skip it. continue; } } return BooleanOrIntegerLiteral(); - } - ; + }; } std::function RestartEveryKFailures(int k, SatSolver *solver) { bool reset_at_next_call = true; int next_num_failures = 0; - return[ = ]() mutable { if (reset_at_next_call) - { + return [=]() mutable { + if (reset_at_next_call) { next_num_failures = solver->num_failures() + k; reset_at_next_call = false; - } - else if (solver->num_failures() >= next_num_failures) { + } else if (solver->num_failures() >= next_num_failures) { reset_at_next_call = true; } return reset_at_next_call; - } - ; + }; } std::function SatSolverRestartPolicy(Model *model) { auto policy = model->GetOrCreate(); - return[policy]() { return policy->ShouldRestart(); -} -; + return [policy]() { return policy->ShouldRestart(); }; } namespace { -std::function -WrapIntegerLiteralHeuristic(std::function f) { - return[f]() { return BooleanOrIntegerLiteral(f()); -} -; +std::function WrapIntegerLiteralHeuristic( + std::function f) { + return [f]() { return BooleanOrIntegerLiteral(f()); }; } -} // namespace +} // namespace void ConfigureSearchHeuristics(Model *model) { SearchHeuristics &heuristics = *model->GetOrCreate(); @@ -573,47 +529,37 @@ void ConfigureSearchHeuristics(Model *model) { } else { decision_policy = SatSolverHeuristic(model); } - decision_policy = SequentialSearch({ - decision_policy, heuristics.fixed_search - }); + decision_policy = + SequentialSearch({decision_policy, heuristics.fixed_search}); decision_policy = IntegerValueSelectionHeuristic(decision_policy, model); - heuristics.decision_policies = { decision_policy }; - heuristics.restart_policies = { SatSolverRestartPolicy(model) }; + heuristics.decision_policies = {decision_policy}; + heuristics.restart_policies = {SatSolverRestartPolicy(model)}; return; } case SatParameters::FIXED_SEARCH: { // Not all Boolean might appear in fixed_search(), so once there is no // decision left, we fix all Booleans that are still undecided. heuristics.decision_policies = {SequentialSearch( - { heuristics.fixed_search, SatSolverHeuristic(model) }) - } - ; + {heuristics.fixed_search, SatSolverHeuristic(model)})}; if (parameters.randomize_search()) { - heuristics.restart_policies = { SatSolverRestartPolicy(model) }; + heuristics.restart_policies = {SatSolverRestartPolicy(model)}; return; } // TODO(user): We might want to restart if external info is available. // Code a custom restart for this? - auto no_restart = []() { return false; } - ; - heuristics.restart_policies = { no_restart }; + auto no_restart = []() { return false; }; + heuristics.restart_policies = {no_restart}; return; } case SatParameters::HINT_SEARCH: { CHECK(heuristics.hint_search != nullptr); heuristics.decision_policies = { - SequentialSearch( - { - heuristics.hint_search, SatSolverHeuristic(model), - heuristics.fixed_search - }) - } - ; - auto no_restart = []() { return false; } - ; - heuristics.restart_policies = { no_restart }; + SequentialSearch({heuristics.hint_search, SatSolverHeuristic(model), + heuristics.fixed_search})}; + auto no_restart = []() { return false; }; + heuristics.restart_policies = {no_restart}; return; } case SatParameters::PORTFOLIO_SEARCH: { @@ -629,10 +575,9 @@ void ConfigureSearchHeuristics(Model *model) { base_heuristics.push_back(WrapIntegerLiteralHeuristic( ct->HeuristicLpMostInfeasibleBinary(model))); } - heuristics.decision_policies = - CompleteHeuristics(base_heuristics, SequentialSearch({ - SatSolverHeuristic(model), heuristics.fixed_search - })); + heuristics.decision_policies = CompleteHeuristics( + base_heuristics, SequentialSearch({SatSolverHeuristic(model), + heuristics.fixed_search})); for (auto &ref : heuristics.decision_policies) { ref = IntegerValueSelectionHeuristic(ref, model); } @@ -647,60 +592,55 @@ void ConfigureSearchHeuristics(Model *model) { lp_heuristics.push_back(WrapIntegerLiteralHeuristic( ct->HeuristicLpReducedCostAverageBranching())); } - if (lp_heuristics.empty()) { // Revert to fixed search. + if (lp_heuristics.empty()) { // Revert to fixed search. heuristics.decision_policies = {SequentialSearch( - { heuristics.fixed_search, SatSolverHeuristic(model) }) - } - , heuristics.restart_policies = { SatSolverRestartPolicy(model) }; + {heuristics.fixed_search, SatSolverHeuristic(model)})}, + heuristics.restart_policies = {SatSolverRestartPolicy(model)}; return; } - heuristics.decision_policies = - CompleteHeuristics(lp_heuristics, SequentialSearch({ - SatSolverHeuristic(model), heuristics.fixed_search -})); + heuristics.decision_policies = CompleteHeuristics( + lp_heuristics, SequentialSearch({SatSolverHeuristic(model), + heuristics.fixed_search})); heuristics.restart_policies.assign(heuristics.decision_policies.size(), SatSolverRestartPolicy(model)); return; } case SatParameters::PSEUDO_COST_SEARCH: { - std::function search = SequentialSearch({ - PseudoCost(model), SatSolverHeuristic(model), heuristics.fixed_search - }); - heuristics.decision_policies = { IntegerValueSelectionHeuristic(search, - model) }; - heuristics.restart_policies = { SatSolverRestartPolicy(model) }; + std::function search = + SequentialSearch({PseudoCost(model), SatSolverHeuristic(model), + heuristics.fixed_search}); + heuristics.decision_policies = { + IntegerValueSelectionHeuristic(search, model)}; + heuristics.restart_policies = {SatSolverRestartPolicy(model)}; return; } case SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH: { - std::function search = SequentialSearch({ - RandomizeOnRestartHeuristic(model), heuristics.fixed_search - }); - heuristics.decision_policies = { search }; - heuristics.restart_policies = { RestartEveryKFailures( - 10, model->GetOrCreate()) }; + std::function search = SequentialSearch( + {RandomizeOnRestartHeuristic(model), heuristics.fixed_search}); + heuristics.decision_policies = {search}; + heuristics.restart_policies = { + RestartEveryKFailures(10, model->GetOrCreate())}; return; } } } std::vector > CompleteHeuristics( - const std::vector > & - incomplete_heuristics, + const std::vector > + &incomplete_heuristics, const std::function &completion_heuristic) { std::vector > complete_heuristics; complete_heuristics.reserve(incomplete_heuristics.size()); for (const auto &incomplete : incomplete_heuristics) { - complete_heuristics.push_back(SequentialSearch({ - incomplete, completion_heuristic - })); + complete_heuristics.push_back( + SequentialSearch({incomplete, completion_heuristic})); } return complete_heuristics; } SatSolver::Status SolveIntegerProblem(Model *model) { TimeLimit *time_limit = model->GetOrCreate(); - if (time_limit->LimitReached()) - return SatSolver::LIMIT_REACHED; + if (time_limit->LimitReached()) return SatSolver::LIMIT_REACHED; SearchHeuristics &heuristics = *model->GetOrCreate(); const int num_policies = heuristics.decision_policies.size(); @@ -711,8 +651,7 @@ SatSolver::Status SolveIntegerProblem(Model *model) { IntegerVariable objective_var = kNoIntegerVariable; { const ObjectiveDefinition *objective = model->Get(); - if (objective != nullptr) - objective_var = objective->objective_var; + if (objective != nullptr) objective_var = objective->objective_var; } // Note that it is important to do the level-zero propagation if it wasn't @@ -726,8 +665,7 @@ SatSolver::Status SolveIntegerProblem(Model *model) { // CHECKs() to fail in multithread (rarely) because when we associate new // literals to integer ones, Propagate() is indirectly called. Not sure yet // how to fix. - if (!sat_solver->FinishPropagation()) - return sat_solver->UnsatStatus(); + if (!sat_solver->FinishPropagation()) return sat_solver->UnsatStatus(); // Create and initialize pseudo costs. // TODO(user): If this ever shows up in a cpu profile, find a way to not @@ -795,8 +733,7 @@ SatSolver::Status SolveIntegerProblem(Model *model) { new_decision.integer_literal = AtMinValue(var, integer_trail); } } - if (!new_decision.HasValue()) - break; + if (!new_decision.HasValue()) break; // Convert integer decision to literal one if needed. // @@ -830,9 +767,7 @@ SatSolver::Status SolveIntegerProblem(Model *model) { // TODO(user): Be smarter about what variables we probe, we can also // do more than one. - if (!ProbeBooleanVariables(0.1, { - Literal(decision).Variable() - }, + if (!ProbeBooleanVariables(0.1, {Literal(decision).Variable()}, model)) { return SatSolver::INFEASIBLE; } @@ -926,18 +861,15 @@ SatSolver::Status SolveIntegerProblem(Model *model) { return SatSolver::Status::LIMIT_REACHED; } -SatSolver::Status -ResetAndSolveIntegerProblem(const std::vector &assumptions, - Model *model) { +SatSolver::Status ResetAndSolveIntegerProblem( + const std::vector &assumptions, Model *model) { SatSolver *const solver = model->GetOrCreate(); // Sync the bound first. - if (!solver->ResetToLevelZero()) - return solver->UnsatStatus(); + if (!solver->ResetToLevelZero()) return solver->UnsatStatus(); auto *level_zero_callbacks = model->GetOrCreate(); for (const auto &cb : level_zero_callbacks->callbacks) { - if (!cb()) - return SatSolver::INFEASIBLE; + if (!cb()) return SatSolver::INFEASIBLE; } // Add the assumptions if any and solve. @@ -958,17 +890,11 @@ SatSolver::Status SolveIntegerProblemWithLazyEncoding(Model *model) { SearchHeuristics &heuristics = *model->GetOrCreate(); heuristics.policy_index = 0; heuristics.decision_policies = {SequentialSearch( - { - SatSolverHeuristic(model), - FirstUnassignedVarAtItsMinHeuristic(all_variables, model) - }) -} -; - heuristics.restart_policies = { SatSolverRestartPolicy(model) }; - return ResetAndSolveIntegerProblem(/*assumptions=*/ { -}, - model); + {SatSolverHeuristic(model), + FirstUnassignedVarAtItsMinHeuristic(all_variables, model)})}; + heuristics.restart_policies = {SatSolverRestartPolicy(model)}; + return ResetAndSolveIntegerProblem(/*assumptions=*/{}, model); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/integer_search.h b/ortools/sat/integer_search.h index f89517d76d..1bf7c49775 100644 --- a/ortools/sat/integer_search.h +++ b/ortools/sat/integer_search.h @@ -98,9 +98,8 @@ SatSolver::Status SolveIntegerProblem(Model *model); // Resets the solver to the given assumptions before calling // SolveIntegerProblem(). -SatSolver::Status - ResetAndSolveIntegerProblem(const std::vector &assumptions, - Model *model); +SatSolver::Status ResetAndSolveIntegerProblem( + const std::vector &assumptions, Model *model); // Only used in tests. Move to a test utility file. // @@ -151,8 +150,8 @@ std::function FirstUnassignedVarAtItsMinHeuristic( // literal corresponding to the fact that the currently non-assigned variable // with the lowest min has a value <= this min. std::function - UnassignedVarWithLowestMinAtItsMinHeuristic( - const std::vector &vars, Model *model); +UnassignedVarWithLowestMinAtItsMinHeuristic( + const std::vector &vars, Model *model); // Set the first unassigned Literal/Variable to its value. // @@ -163,9 +162,9 @@ struct BooleanOrIntegerVariable { BooleanVariable bool_var = kNoBooleanVariable; IntegerVariable int_var = kNoIntegerVariable; }; -std::function - FollowHint(const std::vector &vars, - const std::vector &values, Model *model); +std::function FollowHint( + const std::vector &vars, + const std::vector &values, Model *model); // Combines search heuristics in order: if the i-th one returns kNoLiteralIndex, // ask the (i+1)-th. If every heuristic returned kNoLiteralIndex, @@ -211,11 +210,11 @@ std::function SatSolverRestartPolicy(Model *model); // Concatenates each input_heuristic with a default heuristic that instantiate // all the problem's Boolean variables, into a new vector. std::vector > CompleteHeuristics( - const std::vector > & - incomplete_heuristics, + const std::vector > + &incomplete_heuristics, const std::function &completion_heuristic); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_INTEGER_SEARCH_H_ +#endif // OR_TOOLS_SAT_INTEGER_SEARCH_H_ diff --git a/ortools/sat/intervals.cc b/ortools/sat/intervals.cc index 4ad3a0d49b..91beee7887 100644 --- a/ortools/sat/intervals.cc +++ b/ortools/sat/intervals.cc @@ -42,11 +42,11 @@ IntervalVariable IntervalsRepository::CreateInterval(IntegerVariable start, // Link properly all its components. precedences_->AddPrecedenceWithAllOptions(StartVar(i), EndVar(i), fixed_size, SizeVar(i), enforcement_literals); - precedences_->AddPrecedenceWithAllOptions( - EndVar(i), StartVar(i), -fixed_size, - SizeVar(i) == kNoIntegerVariable ? kNoIntegerVariable - : NegationOf(SizeVar(i)), - enforcement_literals); + precedences_->AddPrecedenceWithAllOptions(EndVar(i), StartVar(i), -fixed_size, + SizeVar(i) == kNoIntegerVariable + ? kNoIntegerVariable + : NegationOf(SizeVar(i)), + enforcement_literals); return i; } @@ -141,8 +141,7 @@ void SchedulingConstraintHelper::InitSortedVectors() { } void SchedulingConstraintHelper::SetTimeDirection(bool is_forward) { - if (current_time_direction_ == is_forward) - return; + if (current_time_direction_ == is_forward) return; current_time_direction_ = is_forward; std::swap(start_vars_, minus_end_vars_); @@ -154,8 +153,8 @@ void SchedulingConstraintHelper::SetTimeDirection(bool is_forward) { std::swap(shifted_start_min_timestamp_, negated_shifted_end_max_timestamp_); } -const std::vector & -SchedulingConstraintHelper::TaskByIncreasingStartMin() { +const std::vector + &SchedulingConstraintHelper::TaskByIncreasingStartMin() { const int num_tasks = NumTasks(); for (int i = 0; i < num_tasks; ++i) { TaskTime &ref = task_by_increasing_start_min_[i]; @@ -166,8 +165,8 @@ SchedulingConstraintHelper::TaskByIncreasingStartMin() { return task_by_increasing_start_min_; } -const std::vector & -SchedulingConstraintHelper::TaskByIncreasingEndMin() { +const std::vector + &SchedulingConstraintHelper::TaskByIncreasingEndMin() { const int num_tasks = NumTasks(); for (int i = 0; i < num_tasks; ++i) { TaskTime &ref = task_by_increasing_end_min_[i]; @@ -178,8 +177,8 @@ SchedulingConstraintHelper::TaskByIncreasingEndMin() { return task_by_increasing_end_min_; } -const std::vector & -SchedulingConstraintHelper::TaskByDecreasingStartMax() { +const std::vector + &SchedulingConstraintHelper::TaskByDecreasingStartMax() { const int num_tasks = NumTasks(); for (int i = 0; i < num_tasks; ++i) { TaskTime &ref = task_by_decreasing_start_max_[i]; @@ -191,8 +190,8 @@ SchedulingConstraintHelper::TaskByDecreasingStartMax() { return task_by_decreasing_start_max_; } -const std::vector & -SchedulingConstraintHelper::TaskByDecreasingEndMax() { +const std::vector + &SchedulingConstraintHelper::TaskByDecreasingEndMax() { const int num_tasks = NumTasks(); for (int i = 0; i < num_tasks; ++i) { TaskTime &ref = task_by_decreasing_end_max_[i]; @@ -203,8 +202,8 @@ SchedulingConstraintHelper::TaskByDecreasingEndMax() { return task_by_decreasing_end_max_; } -const std::vector & -SchedulingConstraintHelper::TaskByIncreasingShiftedStartMin() { +const std::vector + &SchedulingConstraintHelper::TaskByIncreasingShiftedStartMin() { const int64 new_timestamp = integer_trail_->timestamp(); if (new_timestamp > shifted_start_min_timestamp_) { shifted_start_min_timestamp_ = new_timestamp; @@ -217,8 +216,7 @@ SchedulingConstraintHelper::TaskByIncreasingShiftedStartMin() { is_sorted = is_sorted && ref.time >= previous; previous = ref.time; } - if (is_sorted) - return task_by_increasing_shifted_start_min_; + if (is_sorted) return task_by_increasing_shifted_start_min_; IncrementalSort(task_by_increasing_shifted_start_min_.begin(), task_by_increasing_shifted_start_min_.end()); } @@ -261,13 +259,9 @@ void SchedulingConstraintHelper::AddReasonForBeingBefore(int before, integer_reason_.push_back(start_max_lit); return; } - integer_trail_->AppendRelaxedLinearReason(slack, { - IntegerValue(1), IntegerValue(1) - }, - { - end_min_lit.var, start_max_lit.var - }, - &integer_reason_); + integer_trail_->AppendRelaxedLinearReason( + slack, {IntegerValue(1), IntegerValue(1)}, + {end_min_lit.var, start_max_lit.var}, &integer_reason_); } bool SchedulingConstraintHelper::PushIntegerLiteral(IntegerLiteral lit) { @@ -277,8 +271,7 @@ bool SchedulingConstraintHelper::PushIntegerLiteral(IntegerLiteral lit) { bool SchedulingConstraintHelper::PushIntegerLiteralIfTaskPresent( int t, IntegerLiteral lit) { - if (IsAbsent(t)) - return true; + if (IsAbsent(t)) return true; AddOtherReason(t); // TODO(user): we can also push lit.var if its presence implies the interval @@ -294,8 +287,7 @@ bool SchedulingConstraintHelper::PushIntegerLiteralIfTaskPresent( if (lit.bound > integer_trail_->UpperBound(lit.var)) { integer_reason_.push_back( IntegerLiteral::LowerOrEqual(lit.var, lit.bound - 1)); - if (!PushTaskAbsence(t)) - return false; + if (!PushTaskAbsence(t)) return false; } return true; } @@ -311,10 +303,8 @@ bool SchedulingConstraintHelper::PushIntegerLiteralIfTaskPresent( // We also run directly the precedence propagator for this variable so that when // we push an interval start for example, we have a chance to push its end. bool SchedulingConstraintHelper::PushIntervalBound(int t, IntegerLiteral lit) { - if (!PushIntegerLiteralIfTaskPresent(t, lit)) - return false; - if (IsAbsent(t)) - return true; + if (!PushIntegerLiteralIfTaskPresent(t, lit)) return false; + if (IsAbsent(t)) return true; return precedences_->PropagateOutgoingArcs(lit.var); } @@ -391,16 +381,14 @@ void SchedulingConstraintHelper::WatchAllTasks(int id, } void SchedulingConstraintHelper::AddOtherReason(int t) { - if (other_helper_ == nullptr || already_added_to_other_reasons_[t]) - return; + if (other_helper_ == nullptr || already_added_to_other_reasons_[t]) return; already_added_to_other_reasons_[t] = true; other_helper_->AddStartMaxReason(t, event_for_other_helper_); other_helper_->AddEndMinReason(t, event_for_other_helper_ + 1); } void SchedulingConstraintHelper::ImportOtherReasons() { - if (other_helper_ != nullptr) - ImportOtherReasons(*other_helper_); + if (other_helper_ != nullptr) ImportOtherReasons(*other_helper_); } void SchedulingConstraintHelper::ImportOtherReasons( @@ -414,11 +402,11 @@ void SchedulingConstraintHelper::ImportOtherReasons( } std::string SchedulingConstraintHelper::TaskDebugString(int t) const { - return absl::StrCat("t=", t, " is_present=", IsPresent(t), " min_size=", - SizeMin(t).value(), " start=[", StartMin(t).value(), ",", - StartMax(t).value(), "]", " end=[", EndMin(t).value(), - ",", EndMax(t).value(), "]"); + return absl::StrCat("t=", t, " is_present=", IsPresent(t), + " min_size=", SizeMin(t).value(), " start=[", + StartMin(t).value(), ",", StartMax(t).value(), "]", + " end=[", EndMin(t).value(), ",", EndMax(t).value(), "]"); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/intervals.h b/ortools/sat/intervals.h index 1327aa4f04..f48c529b23 100644 --- a/ortools/sat/intervals.h +++ b/ortools/sat/intervals.h @@ -81,16 +81,14 @@ class IntervalsRepository { // Return the minimum size of the given IntervalVariable. IntegerValue MinSize(IntervalVariable i) const { const IntegerVariable size_var = size_vars_[i]; - if (size_var == kNoIntegerVariable) - return fixed_sizes_[i]; + if (size_var == kNoIntegerVariable) return fixed_sizes_[i]; return integer_trail_->LowerBound(size_var); } // Return the maximum size of the given IntervalVariable. IntegerValue MaxSize(IntervalVariable i) const { const IntegerVariable size_var = size_vars_[i]; - if (size_var == kNoIntegerVariable) - return fixed_sizes_[i]; + if (size_var == kNoIntegerVariable) return fixed_sizes_[i]; return integer_trail_->UpperBound(size_var); } @@ -407,14 +405,12 @@ inline bool SchedulingConstraintHelper::IsOptional(int t) const { } inline bool SchedulingConstraintHelper::IsPresent(int t) const { - if (reason_for_presence_[t] == kNoLiteralIndex) - return true; + if (reason_for_presence_[t] == kNoLiteralIndex) return true; return trail_->Assignment().LiteralIsTrue(Literal(reason_for_presence_[t])); } inline bool SchedulingConstraintHelper::IsAbsent(int t) const { - if (reason_for_presence_[t] == kNoLiteralIndex) - return false; + if (reason_for_presence_[t] == kNoLiteralIndex) return false; return trail_->Assignment().LiteralIsFalse(Literal(reason_for_presence_[t])); } @@ -451,8 +447,8 @@ inline void SchedulingConstraintHelper::AddSizeMinReason(int t) { } } -inline void -SchedulingConstraintHelper::AddSizeMinReason(int t, IntegerValue lower_bound) { +inline void SchedulingConstraintHelper::AddSizeMinReason( + int t, IntegerValue lower_bound) { AddOtherReason(t); if (size_vars_[t] != kNoIntegerVariable) { DCHECK_GE(SizeMin(t), lower_bound); @@ -461,24 +457,24 @@ SchedulingConstraintHelper::AddSizeMinReason(int t, IntegerValue lower_bound) { } } -inline void -SchedulingConstraintHelper::AddStartMinReason(int t, IntegerValue lower_bound) { +inline void SchedulingConstraintHelper::AddStartMinReason( + int t, IntegerValue lower_bound) { DCHECK_GE(StartMin(t), lower_bound); AddOtherReason(t); integer_reason_.push_back( IntegerLiteral::GreaterOrEqual(start_vars_[t], lower_bound)); } -inline void -SchedulingConstraintHelper::AddStartMaxReason(int t, IntegerValue upper_bound) { +inline void SchedulingConstraintHelper::AddStartMaxReason( + int t, IntegerValue upper_bound) { DCHECK_LE(StartMax(t), upper_bound); AddOtherReason(t); integer_reason_.push_back( IntegerLiteral::LowerOrEqual(start_vars_[t], upper_bound)); } -inline void -SchedulingConstraintHelper::AddEndMinReason(int t, IntegerValue lower_bound) { +inline void SchedulingConstraintHelper::AddEndMinReason( + int t, IntegerValue lower_bound) { AddOtherReason(t); if (EndMin(t) < lower_bound) { // This might happen if we used for the end_min the max between end_min @@ -497,17 +493,16 @@ SchedulingConstraintHelper::AddEndMinReason(int t, IntegerValue lower_bound) { IntegerLiteral::GreaterOrEqual(end_vars_[t], lower_bound)); } -inline void -SchedulingConstraintHelper::AddEndMaxReason(int t, IntegerValue upper_bound) { +inline void SchedulingConstraintHelper::AddEndMaxReason( + int t, IntegerValue upper_bound) { DCHECK_LE(EndMax(t), upper_bound); AddOtherReason(t); integer_reason_.push_back( IntegerLiteral::LowerOrEqual(end_vars_[t], upper_bound)); } -inline void -SchedulingConstraintHelper::AddEnergyAfterReason(int t, IntegerValue energy_min, - IntegerValue time) { +inline void SchedulingConstraintHelper::AddEnergyAfterReason( + int t, IntegerValue energy_min, IntegerValue time) { AddOtherReason(t); if (StartMin(t) >= time) { integer_reason_.push_back( @@ -526,109 +521,96 @@ SchedulingConstraintHelper::AddEnergyAfterReason(int t, IntegerValue energy_min, // Model based functions. // ============================================================================= -inline std::function -StartVar(IntervalVariable v) { - return[ = ](const Model & - model) { return model.Get()->StartVar(v); - } - ; +inline std::function StartVar( + IntervalVariable v) { + return [=](const Model &model) { + return model.Get()->StartVar(v); + }; } -inline std::function -EndVar(IntervalVariable v) { - return[ = ](const Model & - model) { return model.Get()->EndVar(v); - } - ; +inline std::function EndVar( + IntervalVariable v) { + return [=](const Model &model) { + return model.Get()->EndVar(v); + }; } -inline std::function -SizeVar(IntervalVariable v) { - return[ = ](const Model & - model) { return model.Get()->SizeVar(v); - } - ; +inline std::function SizeVar( + IntervalVariable v) { + return [=](const Model &model) { + return model.Get()->SizeVar(v); + }; } inline std::function MinSize(IntervalVariable v) { - return[ = ](const Model & model) { + return [=](const Model &model) { return model.Get()->MinSize(v).value(); - } - ; + }; } inline std::function MaxSize(IntervalVariable v) { - return[ = ](const Model & model) { + return [=](const Model &model) { return model.Get()->MaxSize(v).value(); - } - ; + }; } inline std::function IsOptional(IntervalVariable v) { - return[ = ](const Model & - model) { return model.Get()->IsOptional(v); - } - ; + return [=](const Model &model) { + return model.Get()->IsOptional(v); + }; } -inline std::function -IsPresentLiteral(IntervalVariable v) { - return[ = ](const Model & model) { +inline std::function IsPresentLiteral( + IntervalVariable v) { + return [=](const Model &model) { return model.Get()->IsPresentLiteral(v); - } - ; + }; } inline std::function NewInterval(int64 min_start, int64 max_end, int64 size) { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable, IntegerValue(size), kNoLiteralIndex); - } - ; + }; } -inline std::function -NewInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size) { - return[ = ](Model * model) { +inline std::function NewInterval( + IntegerVariable start, IntegerVariable end, IntegerVariable size) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( start, end, size, IntegerValue(0), kNoLiteralIndex); - } - ; + }; } -inline std::function -NewIntervalWithVariableSize(int64 min_start, int64 max_end, int64 min_size, - int64 max_size) { - return[ = ](Model * model) { +inline std::function NewIntervalWithVariableSize( + int64 min_start, int64 max_end, int64 min_size, int64 max_size) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0), kNoLiteralIndex); - } - ; + }; } -inline std::function -NewOptionalInterval(int64 min_start, int64 max_end, int64 size, - Literal is_present) { - return[ = ](Model * model) { +inline std::function NewOptionalInterval( + int64 min_start, int64 max_end, int64 size, Literal is_present) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable, IntegerValue(size), is_present.Index()); - } - ; + }; } inline std::function NewOptionalIntervalWithOptionalVariables(int64 min_start, int64 max_end, int64 size, Literal is_present) { - return[ = ](Model *model) { + return [=](Model *model) { // Note that we need to mark the optionality first. const IntegerVariable start = model->Add(NewIntegerVariable(min_start, max_end)); @@ -639,40 +621,36 @@ NewOptionalIntervalWithOptionalVariables(int64 min_start, int64 max_end, integer_trail->MarkIntegerVariableAsOptional(end, is_present); return model->GetOrCreate()->CreateInterval( start, end, kNoIntegerVariable, IntegerValue(size), is_present.Index()); - } - ; + }; } -inline std::function -NewOptionalInterval(IntegerVariable start, IntegerVariable end, - IntegerVariable size, Literal is_present) { - return[ = ](Model * model) { +inline std::function NewOptionalInterval( + IntegerVariable start, IntegerVariable end, IntegerVariable size, + Literal is_present) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( start, end, size, IntegerValue(0), is_present.Index()); - } - ; + }; } inline std::function NewOptionalIntervalWithVariableSize(int64 min_start, int64 max_end, int64 min_size, int64 max_size, Literal is_present) { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->CreateInterval( model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_start, max_end)), model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0), is_present.Index()); - } - ; + }; } // This requires that all the alternatives are optional tasks. -inline std::function -IntervalWithAlternatives(IntervalVariable master, - const std::vector &members) { - return[ = ](Model *model) { IntervalsRepository *intervals = - model->GetOrCreate(); +inline std::function IntervalWithAlternatives( + IntervalVariable master, const std::vector &members) { + return [=](Model *model) { + IntervalsRepository *intervals = model->GetOrCreate(); std::vector presences; std::vector sizes; @@ -682,9 +660,7 @@ IntervalWithAlternatives(IntervalVariable master, for (const IntervalVariable member : members) { CHECK(intervals->IsOptional(member)); const Literal is_present = intervals->IsPresentLiteral(member); - sat_ct.push_back({ - is_present, Coefficient(1) - }); + sat_ct.push_back({is_present, Coefficient(1)}); model->Add( Equality(model->Get(StartVar(master)), model->Get(StartVar(member)))); model->Add( @@ -719,11 +695,10 @@ IntervalWithAlternatives(IntervalVariable master, } model->Add(PartialIsOneOfVar(intervals->EndVar(master), ends, presences)); } - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_INTERVALS_H_ +#endif // OR_TOOLS_SAT_INTERVALS_H_ diff --git a/ortools/sat/linear_constraint.cc b/ortools/sat/linear_constraint.cc index 184b82e6da..ef0258ed31 100644 --- a/ortools/sat/linear_constraint.cc +++ b/ortools/sat/linear_constraint.cc @@ -23,13 +23,9 @@ void LinearConstraintBuilder::AddTerm(IntegerVariable var, IntegerValue coeff) { // We can either add var or NegationOf(var), and we always choose the // positive one. if (VariableIsPositive(var)) { - terms_.push_back({ - var, coeff - }); + terms_.push_back({var, coeff}); } else { - terms_.push_back({ - NegationOf(var), -coeff - }); + terms_.push_back({NegationOf(var), -coeff}); } } @@ -39,30 +35,22 @@ void LinearConstraintBuilder::AddTerm(AffineExpression expr, // positive one. if (expr.var != kNoIntegerVariable) { if (VariableIsPositive(expr.var)) { - terms_.push_back({ - expr.var, coeff *expr.coeff - }); + terms_.push_back({expr.var, coeff * expr.coeff}); } else { - terms_.push_back({ - NegationOf(expr.var), -coeff * expr.coeff - }); + terms_.push_back({NegationOf(expr.var), -coeff * expr.coeff}); } } - if (lb_ > kMinIntegerValue) - lb_ -= coeff * expr.constant; - if (ub_ < kMaxIntegerValue) - ub_ -= coeff * expr.constant; + if (lb_ > kMinIntegerValue) lb_ -= coeff * expr.constant; + if (ub_ < kMaxIntegerValue) ub_ -= coeff * expr.constant; } void LinearConstraintBuilder::AddConstant(IntegerValue value) { - if (lb_ > kMinIntegerValue) - lb_ -= value; - if (ub_ < kMaxIntegerValue) - ub_ -= value; + if (lb_ > kMinIntegerValue) lb_ -= value; + if (ub_ < kMaxIntegerValue) ub_ -= value; } -ABSL_MUST_USE_RESULT bool -LinearConstraintBuilder::AddLiteralTerm(Literal lit, IntegerValue coeff) { +ABSL_MUST_USE_RESULT bool LinearConstraintBuilder::AddLiteralTerm( + Literal lit, IntegerValue coeff) { bool has_direct_view = encoder_.GetLiteralView(lit) != kNoIntegerVariable; bool has_opposite_view = encoder_.GetLiteralView(lit.Negated()) != kNoIntegerVariable; @@ -84,10 +72,8 @@ LinearConstraintBuilder::AddLiteralTerm(Literal lit, IntegerValue coeff) { } if (has_opposite_view) { AddTerm(encoder_.GetLiteralView(lit.Negated()), -coeff); - if (lb_ > kMinIntegerValue) - lb_ -= coeff; - if (ub_ < kMaxIntegerValue) - ub_ -= coeff; + if (lb_ > kMinIntegerValue) lb_ -= coeff; + if (ub_ < kMaxIntegerValue) ub_ -= coeff; return true; } return false; @@ -186,27 +172,22 @@ namespace { // TODO(user): Template for any integer type and expose this? IntegerValue ComputeGcd(const std::vector &values) { - if (values.empty()) - return IntegerValue(1); + if (values.empty()) return IntegerValue(1); int64 gcd = 0; for (const IntegerValue value : values) { gcd = MathUtil::GCD64(gcd, std::abs(value.value())); - if (gcd == 1) - break; + if (gcd == 1) break; } - if (gcd < 0) - return IntegerValue(1); // Can happen with kint64min. + if (gcd < 0) return IntegerValue(1); // Can happen with kint64min. return IntegerValue(gcd); } -} // namespace +} // namespace void DivideByGCD(LinearConstraint *constraint) { - if (constraint->coeffs.empty()) - return; + if (constraint->coeffs.empty()) return; const IntegerValue gcd = ComputeGcd(constraint->coeffs); - if (gcd == 1) - return; + if (gcd == 1) return; if (constraint->lb > kMinIntegerValue) { constraint->lb = CeilRatio(constraint->lb, gcd); @@ -214,16 +195,14 @@ void DivideByGCD(LinearConstraint *constraint) { if (constraint->ub < kMaxIntegerValue) { constraint->ub = FloorRatio(constraint->ub, gcd); } - for (IntegerValue &coeff : constraint->coeffs) - coeff /= gcd; + for (IntegerValue &coeff : constraint->coeffs) coeff /= gcd; } void RemoveZeroTerms(LinearConstraint *constraint) { int new_size = 0; const int size = constraint->vars.size(); for (int i = 0; i < size; ++i) { - if (constraint->coeffs[i] == 0) - continue; + if (constraint->coeffs[i] == 0) continue; constraint->vars[new_size] = constraint->vars[i]; constraint->coeffs[new_size] = constraint->coeffs[i]; ++new_size; @@ -266,13 +245,9 @@ void CanonicalizeConstraint(LinearConstraint *ct) { const int size = ct->vars.size(); for (int i = 0; i < size; ++i) { if (VariableIsPositive(ct->vars[i])) { - terms.push_back({ - ct->vars[i], ct->coeffs[i] - }); + terms.push_back({ct->vars[i], ct->coeffs[i]}); } else { - terms.push_back({ - NegationOf(ct->vars[i]), -ct->coeffs[i] - }); + terms.push_back({NegationOf(ct->vars[i]), -ct->coeffs[i]}); } } std::sort(terms.begin(), terms.end()); @@ -290,11 +265,9 @@ bool NoDuplicateVariable(const LinearConstraint &ct) { const int size = ct.vars.size(); for (int i = 0; i < size; ++i) { if (VariableIsPositive(ct.vars[i])) { - if (!seen_variables.insert(ct.vars[i]).second) - return false; + if (!seen_variables.insert(ct.vars[i]).second) return false; } else { - if (!seen_variables.insert(NegationOf(ct.vars[i])).second) - return false; + if (!seen_variables.insert(NegationOf(ct.vars[i])).second) return false; } } return true; @@ -381,5 +354,5 @@ IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var, return IntegerValue(0); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/linear_constraint.h b/ortools/sat/linear_constraint.h index 533ea865a4..89c2fe0094 100644 --- a/ortools/sat/linear_constraint.h +++ b/ortools/sat/linear_constraint.h @@ -73,14 +73,10 @@ struct LinearConstraint { } bool operator==(const LinearConstraint other) const { - if (this->lb != other.lb) - return false; - if (this->ub != other.ub) - return false; - if (this->vars != other.vars) - return false; - if (this->coeffs != other.coeffs) - return false; + if (this->lb != other.lb) return false; + if (this->ub != other.ub) return false; + if (this->vars != other.vars) return false; + if (this->coeffs != other.coeffs) return false; return true; } }; @@ -89,7 +85,7 @@ struct LinearConstraint { // variables. Note that we do not simplify literal/variable that are currently // fixed here. class LinearConstraintBuilder { -public: + public: // We support "sticky" kMinIntegerValue for lb and kMaxIntegerValue for ub // for one-sided constraints. // @@ -117,7 +113,7 @@ public: // algorithm needs to be optimized of that. LinearConstraint Build(); -private: + private: const IntegerEncoder &encoder_; IntegerValue lb_; IntegerValue ub_; @@ -209,7 +205,7 @@ IntegerValue GetCoefficient(const IntegerVariable var, IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var, const LinearExpression &expr); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_LINEAR_CONSTRAINT_H_ +#endif // OR_TOOLS_SAT_LINEAR_CONSTRAINT_H_ diff --git a/ortools/sat/linear_constraint_manager.cc b/ortools/sat/linear_constraint_manager.cc index 79dd995ccd..1c8ed336e3 100644 --- a/ortools/sat/linear_constraint_manager.cc +++ b/ortools/sat/linear_constraint_manager.cc @@ -40,7 +40,7 @@ size_t ComputeHashOfTerms(const LinearConstraint &ct) { return hash; } -} // namespace +} // namespace LinearConstraintManager::~LinearConstraintManager() { if (num_merged_constraints_ > 0) { @@ -77,8 +77,7 @@ void LinearConstraintManager::RescaleActiveCounts(const double scaling_factor) { bool LinearConstraintManager::MaybeRemoveSomeInactiveConstraints( glop::BasisState *solution_state) { - if (solution_state->IsEmpty()) - return false; // Mainly to simplify tests. + if (solution_state->IsEmpty()) return false; // Mainly to simplify tests. const glop::RowIndex num_rows(lp_constraints_.size()); const glop::ColIndex num_cols = solution_state->statuses.size() - RowToColIndex(num_rows); @@ -99,7 +98,7 @@ bool LinearConstraintManager::MaybeRemoveSomeInactiveConstraints( if (constraint_infos_[constraint_index].inactive_count > sat_parameters_.max_consecutive_inactive_count()) { constraint_infos_[constraint_index].is_in_lp = false; - continue; // Remove it. + continue; // Remove it. } } else { // Only count consecutive inactivities. @@ -122,8 +121,8 @@ bool LinearConstraintManager::MaybeRemoveSomeInactiveConstraints( // Because sometimes we split a == constraint in two (>= and <=), it makes sense // to detect duplicate constraints and merge bounds. This is also relevant if // we regenerate identical cuts for some reason. -LinearConstraintManager::ConstraintIndex -LinearConstraintManager::Add(LinearConstraint ct, bool *added) { +LinearConstraintManager::ConstraintIndex LinearConstraintManager::Add( + LinearConstraint ct, bool *added) { CHECK(!ct.vars.empty()); DCHECK(NoDuplicateVariable(ct)); SimplifyConstraint(&ct); @@ -137,29 +136,23 @@ LinearConstraintManager::Add(LinearConstraint ct, bool *added) { const ConstraintIndex ct_index = equiv_constraints_[key]; if (constraint_infos_[ct_index].constraint.vars == ct.vars && constraint_infos_[ct_index].constraint.coeffs == ct.coeffs) { - if (added != nullptr) - *added = false; + if (added != nullptr) *added = false; if (ct.lb > constraint_infos_[ct_index].constraint.lb) { - if (constraint_infos_[ct_index].is_in_lp) - current_lp_is_changed_ = true; + if (constraint_infos_[ct_index].is_in_lp) current_lp_is_changed_ = true; constraint_infos_[ct_index].constraint.lb = ct.lb; - if (added != nullptr) - *added = true; + if (added != nullptr) *added = true; } if (ct.ub < constraint_infos_[ct_index].constraint.ub) { - if (constraint_infos_[ct_index].is_in_lp) - current_lp_is_changed_ = true; + if (constraint_infos_[ct_index].is_in_lp) current_lp_is_changed_ = true; constraint_infos_[ct_index].constraint.ub = ct.ub; - if (added != nullptr) - *added = true; + if (added != nullptr) *added = true; } ++num_merged_constraints_; return ct_index; } } - if (added != nullptr) - *added = true; + if (added != nullptr) *added = true; const ConstraintIndex ct_index(constraint_infos_.size()); ConstraintInfo ct_info; ct_info.constraint = std::move(ct); @@ -215,8 +208,7 @@ bool LinearConstraintManager::AddCut( const gtl::ITIVector &lp_solution, std::string extra_info) { ++num_add_cut_calls_; - if (ct.vars.empty()) - return false; + if (ct.vars.empty()) return false; const double activity = ComputeActivity(ct, lp_solution); const double violation = @@ -224,16 +216,14 @@ bool LinearConstraintManager::AddCut( const double l2_norm = ComputeL2Norm(ct); // Only add cut with sufficient efficacy. - if (violation / l2_norm < 1e-5) - return false; + if (violation / l2_norm < 1e-5) return false; bool added = false; const ConstraintIndex ct_index = Add(std::move(ct), &added); // We only mark the constraint as a cut if it is not an update of an already // existing one. - if (!added) - return false; + if (!added) return false; // TODO(user): Use better heuristic here for detecting good cuts and mark // them undeletable. @@ -241,8 +231,8 @@ bool LinearConstraintManager::AddCut( VLOG(1) << "Cut '" << type_name << "'" << " size=" << constraint_infos_[ct_index].constraint.vars.size() - << " max_magnitude=" << ComputeInfinityNorm( - constraint_infos_[ct_index].constraint) + << " max_magnitude=" + << ComputeInfinityNorm(constraint_infos_[ct_index].constraint) << " norm=" << l2_norm << " violation=" << violation << " eff=" << violation / l2_norm << " " << extra_info; @@ -259,8 +249,7 @@ void LinearConstraintManager::PermanentlyRemoveSomeConstraints() { deletable_constraint_counts.push_back(constraint_infos_[i].active_count); } } - if (deletable_constraint_counts.empty()) - return; + if (deletable_constraint_counts.empty()) return; std::sort(deletable_constraint_counts.begin(), deletable_constraint_counts.end()); @@ -303,16 +292,15 @@ void LinearConstraintManager::PermanentlyRemoveSomeConstraints() { } if (num_deleted_constraints > 0) { - VLOG(1) - << "Constraint manager cleanup: #deleted:" << num_deleted_constraints; + VLOG(1) << "Constraint manager cleanup: #deleted:" + << num_deleted_constraints; } num_deletable_constraints_ -= num_deleted_constraints; } void LinearConstraintManager::SetObjectiveCoefficient(IntegerVariable var, IntegerValue coeff) { - if (coeff == IntegerValue(0)) - return; + if (coeff == IntegerValue(0)) return; objective_is_defined_ = true; if (!VariableIsPositive(var)) { var = NegationOf(var); @@ -340,8 +328,7 @@ bool LinearConstraintManager::SimplifyConstraint(LinearConstraint *ct) { // For now we do not change ct, but just compute its new_size if we where // to remove a fixed term. - if (lb == ub) - continue; + if (lb == ub) continue; ++new_size; max_magnitude = std::max(max_magnitude, IntTypeAbs(coeff)); @@ -366,10 +353,8 @@ bool LinearConstraintManager::SimplifyConstraint(LinearConstraint *ct) { const IntegerValue ub = integer_trail_.LevelZeroUpperBound(var); if (lb == ub) { const IntegerValue rhs_adjust = lb * coeff; - if (ct->lb > kMinIntegerValue) - ct->lb -= rhs_adjust; - if (ct->ub < kMaxIntegerValue) - ct->ub -= rhs_adjust; + if (ct->lb > kMinIntegerValue) ct->lb -= rhs_adjust; + if (ct->ub < kMaxIntegerValue) ct->ub -= rhs_adjust; continue; } ct->vars[new_size] = var; @@ -382,10 +367,8 @@ bool LinearConstraintManager::SimplifyConstraint(LinearConstraint *ct) { // Relax the bound if needed, note that this doesn't require a change to // the equiv map. - if (min_sum >= ct->lb) - ct->lb = kMinIntegerValue; - if (max_sum <= ct->ub) - ct->ub = kMaxIntegerValue; + if (min_sum >= ct->lb) ct->lb = kMinIntegerValue; + if (max_sum <= ct->ub) ct->ub = kMaxIntegerValue; // Clear constraints that are always true. // We rely on the deletion code to remove them eventually. @@ -489,8 +472,7 @@ bool LinearConstraintManager::ChangeLp( constraint_infos_[i].l2_norm = ComputeL2Norm(constraint_infos_[i].constraint); - if (constraint_infos_[i].is_in_lp) - current_lp_is_changed_ = true; + if (constraint_infos_[i].is_in_lp) current_lp_is_changed_ = true; equiv_constraints_.erase(constraint_infos_[i].hash); constraint_infos_[i].hash = ComputeHashOfTerms(constraint_infos_[i].constraint); @@ -500,8 +482,7 @@ bool LinearConstraintManager::ChangeLp( equiv_constraints_[constraint_infos_[i].hash] = i; } - if (constraint_infos_[i].is_in_lp) - continue; + if (constraint_infos_[i].is_in_lp) continue; // ComputeActivity() often represent the bulk of the time spent in // ChangeLP(). @@ -601,9 +582,9 @@ bool LinearConstraintManager::ChangeLp( std::stable_sort(new_constraints.begin(), new_constraints.end(), [&](ConstraintIndex a, ConstraintIndex b) { - return constraint_infos_[a].current_score > - constraint_infos_[b].current_score; - }); + return constraint_infos_[a].current_score > + constraint_infos_[b].current_score; + }); if (new_constraints.size() > kBlowupFactor * constraint_limit) { VLOG(3) << "Resize candidate constraints from " << new_constraints.size() << " down to " << kBlowupFactor * constraint_limit; @@ -622,20 +603,18 @@ bool LinearConstraintManager::ChangeLp( for (int j = 0; j < new_constraints.size(); ++j) { // Checks the time limit, and returns if the lp has changed. if (++num_skipped_checks >= kCheckFrequency) { - if (time_limit_->LimitReached()) - return current_lp_is_changed_; + if (time_limit_->LimitReached()) return current_lp_is_changed_; num_skipped_checks = 0; } const ConstraintIndex new_constraint = new_constraints[j]; - if (constraint_infos_[new_constraint].is_in_lp) - continue; + if (constraint_infos_[new_constraint].is_in_lp) continue; if (last_added_candidate != kInvalidConstraintIndex) { const double current_orthogonality = 1.0 - (std::abs(ScalarProduct( - constraint_infos_[last_added_candidate].constraint, - constraint_infos_[new_constraint].constraint)) / + constraint_infos_[last_added_candidate].constraint, + constraint_infos_[new_constraint].constraint)) / (constraint_infos_[last_added_candidate].l2_norm * constraint_infos_[new_constraint].l2_norm)); new_constraints_orthogonalities[j] = @@ -702,20 +681,17 @@ bool LinearConstraintManager::ChangeLp( void LinearConstraintManager::AddAllConstraintsToLp() { for (ConstraintIndex i(0); i < constraint_infos_.size(); ++i) { - if (constraint_infos_[i].is_in_lp) - continue; + if (constraint_infos_[i].is_in_lp) continue; constraint_infos_[i].is_in_lp = true; lp_constraints_.push_back(i); } } -bool -LinearConstraintManager::DebugCheckConstraint(const LinearConstraint &cut) { - if (model_->Get() == nullptr) - return true; +bool LinearConstraintManager::DebugCheckConstraint( + const LinearConstraint &cut) { + if (model_->Get() == nullptr) return true; const auto &debug_solution = *(model_->Get()); - if (debug_solution.empty()) - return true; + if (debug_solution.empty()) return true; IntegerValue activity(0); for (int i = 0; i < cut.vars.size(); ++i) { @@ -731,19 +707,15 @@ LinearConstraintManager::DebugCheckConstraint(const LinearConstraint &cut) { return true; } -void -TopNCuts::AddCut(LinearConstraint ct, const std::string &name, - const gtl::ITIVector &lp_solution) { - if (ct.vars.empty()) - return; +void TopNCuts::AddCut( + LinearConstraint ct, const std::string &name, + const gtl::ITIVector &lp_solution) { + if (ct.vars.empty()) return; const double activity = ComputeActivity(ct, lp_solution); const double violation = std::max(activity - ToDouble(ct.ub), ToDouble(ct.lb) - activity); const double l2_norm = ComputeL2Norm(ct); - cuts_.Add({ - name, ct - }, - violation / l2_norm); + cuts_.Add({name, ct}, violation / l2_norm); } void TopNCuts::TransferToManager( @@ -755,5 +727,5 @@ void TopNCuts::TransferToManager( cuts_.Clear(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/linear_constraint_manager.h b/ortools/sat/linear_constraint_manager.h index 642facec5a..0db6bb162c 100644 --- a/ortools/sat/linear_constraint_manager.h +++ b/ortools/sat/linear_constraint_manager.h @@ -38,7 +38,7 @@ namespace sat { // manage cuts but also only add the initial constraints lazily if there is too // many of them. class LinearConstraintManager { -public: + public: struct ConstraintInfo { LinearConstraint constraint; double l2_norm = 0.0; @@ -65,7 +65,8 @@ public: explicit LinearConstraintManager(Model *model) : sat_parameters_(*model->GetOrCreate()), integer_trail_(*model->GetOrCreate()), - time_limit_(model->GetOrCreate()), model_(model) {} + time_limit_(model->GetOrCreate()), + model_(model) {} ~LinearConstraintManager(); // Add a new constraint to the manager. Note that we canonicalize constraints @@ -106,8 +107,8 @@ public: void AddAllConstraintsToLp(); // All the constraints managed by this class. - const gtl::ITIVector & - AllConstraints() const { + const gtl::ITIVector &AllConstraints() + const { return constraint_infos_; } @@ -126,7 +127,7 @@ public: // the loaded solution. bool DebugCheckConstraint(const LinearConstraint &cut); -private: + private: // Heuristic that decide which constraints we should remove from the current // LP. Note that such constraints can be added back later by the heuristic // responsible for adding new constraints from the pool. @@ -221,8 +222,9 @@ private: // TODO(user): We could use gtl::TopN when/if it gets open sourced. Note that // we might be slighlty faster here since we use an indirection and don't move // the Element class around as much. -template class TopN { -public: +template +class TopN { + public: explicit TopN(int n) : n_(n) {} void Clear() { @@ -233,35 +235,32 @@ public: void Add(Element e, double score) { if (heap_.size() < n_) { const int index = elements_.size(); - heap_.push_back({ - index, score - }); + heap_.push_back({index, score}); elements_.push_back(std::move(e)); if (heap_.size() == n_) { // TODO(user): We could delay that on the n + 1 push. std::make_heap(heap_.begin(), heap_.end()); } } else { - if (score <= heap_.front().score) - return; + if (score <= heap_.front().score) return; const int index_to_replace = heap_.front().index; elements_[index_to_replace] = std::move(e); // If needed, we could be faster here with an update operation. std::pop_heap(heap_.begin(), heap_.end()); - heap_.back() = { index_to_replace, score }; + heap_.back() = {index_to_replace, score}; std::push_heap(heap_.begin(), heap_.end()); } } const std::vector &UnorderedElements() const { return elements_; } -private: + private: const int n_; // We keep a heap of the n lowest score. struct HeapElement { - int index; // in elements_; + int index; // in elements_; double score; const double operator<(const HeapElement &other) const { return score > other.score; @@ -279,7 +278,7 @@ private: // TODO(user): We don't use any orthogonality consideration here. // TODO(user): Detect duplicate cuts? class TopNCuts { -public: + public: explicit TopNCuts(int n) : cuts_(n) {} // Add a cut to the local pool @@ -291,7 +290,7 @@ public: const gtl::ITIVector &lp_solution, LinearConstraintManager *manager); -private: + private: struct CutCandidate { std::string name; LinearConstraint cut; @@ -299,7 +298,7 @@ private: TopN cuts_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_LINEAR_CONSTRAINT_MANAGER_H_ +#endif // OR_TOOLS_SAT_LINEAR_CONSTRAINT_MANAGER_H_ diff --git a/ortools/sat/linear_programming_constraint.cc b/ortools/sat/linear_programming_constraint.cc index aac3ea19a4..86b952a1fc 100644 --- a/ortools/sat/linear_programming_constraint.cc +++ b/ortools/sat/linear_programming_constraint.cc @@ -69,8 +69,7 @@ void ScatteredIntegerVector::ClearAndResize(int size) { bool ScatteredIntegerVector::Add(glop::ColIndex col, IntegerValue value) { const int64 add = CapAdd(value.value(), dense_vector_[col].value()); - if (add == kint64min || add == kint64max) - return false; + if (add == kint64min || add == kint64max) return false; dense_vector_[col] = IntegerValue(add); if (is_sparse_ && is_zeros_[col]) { is_zeros_[col] = false; @@ -116,8 +115,7 @@ void ScatteredIntegerVector::ConvertToLinearConstraint( std::sort(non_zeros_.begin(), non_zeros_.end()); for (const glop::ColIndex col : non_zeros_) { const IntegerValue coeff = dense_vector_[col]; - if (coeff == 0) - continue; + if (coeff == 0) continue; result->vars.push_back(integer_variables[col.value()]); result->coeffs.push_back(coeff); } @@ -125,8 +123,7 @@ void ScatteredIntegerVector::ConvertToLinearConstraint( const int size = dense_vector_.size(); for (glop::ColIndex col(0); col < size; ++col) { const IntegerValue coeff = dense_vector_[col]; - if (coeff == 0) - continue; + if (coeff == 0) continue; result->vars.push_back(integer_variables[col.value()]); result->coeffs.push_back(coeff); } @@ -142,19 +139,13 @@ ScatteredIntegerVector::GetTerms() { std::sort(non_zeros_.begin(), non_zeros_.end()); for (const glop::ColIndex col : non_zeros_) { const IntegerValue coeff = dense_vector_[col]; - if (coeff != 0) - result.push_back({ - col, coeff - }); + if (coeff != 0) result.push_back({col, coeff}); } } else { const int size = dense_vector_.size(); for (glop::ColIndex col(0); col < size; ++col) { const IntegerValue coeff = dense_vector_[col]; - if (coeff != 0) - result.push_back({ - col, coeff - }); + if (coeff != 0) result.push_back({col, coeff}); } } return result; @@ -164,15 +155,14 @@ ScatteredIntegerVector::GetTerms() { // a constraint was added will have no effect on this class. LinearProgrammingConstraint::LinearProgrammingConstraint(Model *model) : constraint_manager_(model), - sat_parameters_(*(model->GetOrCreate())), model_(model), + sat_parameters_(*(model->GetOrCreate())), + model_(model), time_limit_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()), trail_(model->GetOrCreate()), integer_encoder_(model->GetOrCreate()), random_(model->GetOrCreate()), - implied_bounds_processor_({ -}, - integer_trail_, + implied_bounds_processor_({}, integer_trail_, model->GetOrCreate()), dispatcher_(model->GetOrCreate()), expanded_lp_solution_( @@ -195,8 +185,8 @@ LinearProgrammingConstraint::~LinearProgrammingConstraint() { << total_num_simplex_iterations_; } -void -LinearProgrammingConstraint::AddLinearConstraint(const LinearConstraint &ct) { +void LinearProgrammingConstraint::AddLinearConstraint( + const LinearConstraint &ct) { DCHECK(!lp_constraint_is_registered_); constraint_manager_.Add(ct); @@ -238,14 +228,11 @@ void LinearProgrammingConstraint::SetObjectiveCoefficient(IntegerVariable ivar, CHECK(!lp_constraint_is_registered_); objective_is_defined_ = true; IntegerVariable pos_var = VariableIsPositive(ivar) ? ivar : NegationOf(ivar); - if (ivar != pos_var) - coeff = -coeff; + if (ivar != pos_var) coeff = -coeff; constraint_manager_.SetObjectiveCoefficient(pos_var, coeff); const glop::ColIndex col = GetOrCreateMirrorVariable(pos_var); - integer_objective_.push_back({ - col, coeff - }); + integer_objective_.push_back({col, coeff}); objective_infinity_norm_ = std::max(objective_infinity_norm_, IntTypeAbs(coeff)); } @@ -296,9 +283,7 @@ bool LinearProgrammingConstraint::CreateLpFromConstraintManager() { coeff = -coeff; } infinity_norm = std::max(infinity_norm, IntTypeAbs(coeff)); - new_ct.terms.push_back({ - GetOrCreateMirrorVariable(var), coeff - }); + new_ct.terms.push_back({GetOrCreateMirrorVariable(var), coeff}); } infinity_norms_.push_back(infinity_norm); @@ -435,9 +420,7 @@ bool LinearProgrammingConstraint::BranchOnVar(IntegerVariable positive_var) { // Push the other branch. const IntegerLiteral deduction = IntegerLiteral::GreaterOrEqual( positive_var, IntegerValue(std::ceil(current_value))); - if (!integer_trail_->Enqueue(deduction, { - }, - integer_reason_)) { + if (!integer_trail_->Enqueue(deduction, {}, integer_reason_)) { return false; } deductions_were_made = true; @@ -461,9 +444,7 @@ bool LinearProgrammingConstraint::BranchOnVar(IntegerVariable positive_var) { if (lower_branch_info.status != glop::ProblemStatus::DUAL_UNBOUNDED) { const IntegerLiteral deduction = IntegerLiteral::LowerOrEqual( positive_var, IntegerValue(std::floor(current_value))); - if (!integer_trail_->Enqueue(deduction, { - }, - integer_reason_)) { + if (!integer_trail_->Enqueue(deduction, {}, integer_reason_)) { return deductions_were_made; } deductions_were_made = true; @@ -488,15 +469,12 @@ bool LinearProgrammingConstraint::BranchOnVar(IntegerVariable positive_var) { // NOTE: On some problems, the approximate_obj_lb could be inexact which add // some tolerance to CP-SAT where currently there is none. - if (approximate_obj_lb <= current_obj_lb) - return deductions_were_made; + if (approximate_obj_lb <= current_obj_lb) return deductions_were_made; // Push the bound to the trail. const IntegerLiteral deduction = IntegerLiteral::GreaterOrEqual(objective_cp_, approximate_obj_lb); - if (!integer_trail_->Enqueue(deduction, { - }, - integer_reason_)) { + if (!integer_trail_->Enqueue(deduction, {}, integer_reason_)) { return deductions_were_made; } @@ -571,8 +549,7 @@ void LinearProgrammingConstraint::AddCutGenerator(CutGenerator generator) { bool LinearProgrammingConstraint::IncrementalPropagate( const std::vector &watch_indices) { - if (!lp_solution_is_set_) - return Propagate(); + if (!lp_solution_is_set_) return Propagate(); // At level zero, if there is still a chance to add cuts or lazy constraints, // we re-run the LP. @@ -588,8 +565,7 @@ bool LinearProgrammingConstraint::IncrementalPropagate( const double ub = ToDouble(integer_trail_->UpperBound(integer_variables_[index])); const double value = lp_solution_[index]; - if (value < lb - kCpEpsilon || value > ub + kCpEpsilon) - return Propagate(); + if (value < lb - kCpEpsilon || value > ub + kCpEpsilon) return Propagate(); } // TODO(user): The saved lp solution is still valid given the current variable @@ -603,13 +579,13 @@ bool LinearProgrammingConstraint::IncrementalPropagate( return true; } -glop::Fractional -LinearProgrammingConstraint::GetVariableValueAtCpScale(glop::ColIndex var) { +glop::Fractional LinearProgrammingConstraint::GetVariableValueAtCpScale( + glop::ColIndex var) { return scaler_.UnscaleVariableValue(var, simplex_.GetVariableValue(var)); } -double -LinearProgrammingConstraint::GetSolutionValue(IntegerVariable variable) const { +double LinearProgrammingConstraint::GetSolutionValue( + IntegerVariable variable) const { return lp_solution_[gtl::FindOrDie(mirror_lp_variable_, variable).value()]; } @@ -644,8 +620,8 @@ bool LinearProgrammingConstraint::SolveLp() { } average_degeneracy_.AddData(CalculateDegeneracy()); if (average_degeneracy_.CurrentAverage() >= 1000.0) { - VLOG(2) - << "High average degeneracy: " << average_degeneracy_.CurrentAverage(); + VLOG(2) << "High average degeneracy: " + << average_degeneracy_.CurrentAverage(); } if (simplex_.GetProblemStatus() == glop::ProblemStatus::OPTIMAL) { @@ -669,8 +645,8 @@ bool LinearProgrammingConstraint::SolveLp() { bool LinearProgrammingConstraint::AddCutFromConstraints( const std::string &name, - const std::vector > & - integer_multipliers) { + const std::vector > + &integer_multipliers) { // This is initialized to a valid linear contraint (by taking linear // combination of the LP rows) and will be transformed into a cut if // possible. @@ -730,7 +706,7 @@ bool LinearProgrammingConstraint::AddCutFromConstraints( // don't. Try this too. std::vector ib_slack_infos; implied_bounds_processor_.ProcessUpperBoundedConstraintWithSlackCreation( - /*substitute_only_inner_variables=*/ false, first_new_var, + /*substitute_only_inner_variables=*/false, first_new_var, expanded_lp_solution_, &cut_, &ib_slack_infos); DCHECK(implied_bounds_processor_.DebugSlack(first_new_var, copy_in_debug, cut_, ib_slack_infos)); @@ -769,12 +745,11 @@ bool LinearProgrammingConstraint::AddCutFromConstraints( const RowIndex row = pair.first; const IntegerValue coeff = pair.second; const auto status = simplex_.GetConstraintStatus(row); - if (status == glop::ConstraintStatus::FIXED_VALUE) - continue; + if (status == glop::ConstraintStatus::FIXED_VALUE) continue; tmp_lp_values_.push_back(0.0); - cut_.vars - .push_back(first_slack + 2 * IntegerVariable(tmp_slack_rows_.size())); + cut_.vars.push_back(first_slack + + 2 * IntegerVariable(tmp_slack_rows_.size())); tmp_slack_rows_.push_back(row); cut_.coeffs.push_back(coeff); @@ -811,8 +786,9 @@ bool LinearProgrammingConstraint::AddCutFromConstraints( tmp_var_lbs_, tmp_var_ubs_, &implied_bounds_processor_, &cut_); at_least_one_added |= PostprocessAndAddCut( - name, absl::StrCat("num_lifted_booleans=", - integer_rounding_cut_helper_.NumLiftedBooleans()), + name, + absl::StrCat("num_lifted_booleans=", + integer_rounding_cut_helper_.NumLiftedBooleans()), first_new_var, first_slack, ib_slack_infos, &cut_); } return at_least_one_added; @@ -870,10 +846,10 @@ bool LinearProgrammingConstraint::PostprocessAndAddCut( std::vector > terms; for (const std::pair &term : ib_slack_infos[index].terms) { - terms.push_back({ - gtl::FindOrDie(mirror_lp_variable_, PositiveVariable(term.first)), - VariableIsPositive(term.first) ? term.second : -term.second - }); + terms.push_back( + {gtl::FindOrDie(mirror_lp_variable_, + PositiveVariable(term.first)), + VariableIsPositive(term.first) ? term.second : -term.second}); } if (!tmp_scattered_vector_.AddLinearExpressionMultiple(multiplier, terms)) { @@ -941,16 +917,13 @@ void LinearProgrammingConstraint::AddCGCuts() { // TODO(user): We could just look at the diff with std::floor() in the hope // that when we are just under an integer, the exact computation below will // also be just under it. - if (std::abs(lp_value - std::round(lp_value)) < 0.01) - continue; + if (std::abs(lp_value - std::round(lp_value)) < 0.01) continue; // If this variable is a slack, we ignore it. This is because the // corresponding row is not tight under the given lp values. - if (basis_col >= integer_variables_.size()) - continue; + if (basis_col >= integer_variables_.size()) continue; - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; const glop::ScatteredRow &lambda = simplex_.GetUnitRowLeftInverse(row); glop::DenseColumn lp_multipliers(num_rows, 0.0); @@ -972,11 +945,9 @@ void LinearProgrammingConstraint::AddCGCuts() { } magnitude = std::max(magnitude, std::abs(lp_multipliers[row])); - if (lp_multipliers[row] != 0.0) - ++num_non_zeros; + if (lp_multipliers[row] != 0.0) ++num_non_zeros; } - if (num_non_zeros == 0) - continue; + if (num_non_zeros == 0) continue; Fractional scaling; for (int i = 0; i < 2; ++i) { @@ -994,8 +965,8 @@ void LinearProgrammingConstraint::AddCGCuts() { // overflow while computing the cut. This should be fixable. const std::vector > integer_multipliers = - ScaleLpMultiplier(/*take_objective_into_account=*/ false, - lp_multipliers, &scaling, /*max_pow=*/ 52); + ScaleLpMultiplier(/*take_objective_into_account=*/false, + lp_multipliers, &scaling, /*max_pow=*/52); AddCutFromConstraints("CG", integer_multipliers); } } @@ -1007,14 +978,11 @@ namespace { void RandomPick(const std::vector &a, const std::vector &b, ModelRandomGenerator *random, std::vector > *output) { - if (a.empty() || b.empty()) - return; + if (a.empty() || b.empty()) return; for (const RowIndex row : a) { const RowIndex other = b[absl::Uniform(*random, 0, b.size())]; if (other != row) { - output->push_back({ - row, other - }); + output->push_back({row, other}); } } } @@ -1022,13 +990,12 @@ void RandomPick(const std::vector &a, const std::vector &b, template IntegerValue GetCoeff(ColIndex col, const ListOfTerms &terms) { for (const auto &term : terms) { - if (term.first == col) - return term.second; + if (term.first == col) return term.second; } return IntegerValue(0); } -} // namespace +} // namespace void LinearProgrammingConstraint::AddMirCuts() { CHECK_EQ(trail_->CurrentDecisionLevel(), 0); @@ -1058,22 +1025,16 @@ void LinearProgrammingConstraint::AddMirCuts() { gtl::ITIVector row_weights(num_rows.value(), 0.0); for (RowIndex row(0); row < num_rows; ++row) { const auto status = simplex_.GetConstraintStatus(row); - if (status == glop::ConstraintStatus::BASIC) - continue; - if (status == glop::ConstraintStatus::FREE) - continue; + if (status == glop::ConstraintStatus::BASIC) continue; + if (status == glop::ConstraintStatus::FREE) continue; if (status == glop::ConstraintStatus::AT_UPPER_BOUND || status == glop::ConstraintStatus::FIXED_VALUE) { - base_rows.push_back({ - row, IntegerValue(1) - }); + base_rows.push_back({row, IntegerValue(1)}); } if (status == glop::ConstraintStatus::AT_LOWER_BOUND || status == glop::ConstraintStatus::FIXED_VALUE) { - base_rows.push_back({ - row, IntegerValue(-1) - }); + base_rows.push_back({row, IntegerValue(-1)}); } // For now, we use the dual values for the row "weights". @@ -1098,8 +1059,7 @@ void LinearProgrammingConstraint::AddMirCuts() { gtl::ITIVector used_rows; std::vector > integer_multipliers; for (const std::pair &entry : base_rows) { - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; // First try to generate a cut directly from this base row (MIR1). // @@ -1108,7 +1068,7 @@ void LinearProgrammingConstraint::AddMirCuts() { // efficient cut, so I am not sure aborting will make a big difference // speedwise. We might generate similar cuts though, but hopefully the cut // management can deal with that. - integer_multipliers = { entry }; + integer_multipliers = {entry}; if (AddCutFromConstraints("MIR_1", integer_multipliers)) { continue; } @@ -1143,14 +1103,12 @@ void LinearProgrammingConstraint::AddMirCuts() { weights.clear(); std::vector col_candidates; for (const ColIndex col : non_zeros_.PositionsSetAtLeastOnce()) { - if (dense_cut[col] == 0) - continue; + if (dense_cut[col] == 0) continue; max_magnitude = std::max(max_magnitude, IntTypeAbs(dense_cut[col])); const int col_degree = lp_data_.GetSparseColumn(col).num_entries().value(); - if (col_degree <= 1) - continue; + if (col_degree <= 1) continue; if (simplex_.GetVariableStatus(col) != glop::VariableStatus::BASIC) { continue; } @@ -1165,8 +1123,7 @@ void LinearProgrammingConstraint::AddMirCuts() { col_candidates.push_back(col); } } - if (col_candidates.empty()) - break; + if (col_candidates.empty()) break; const ColIndex var_to_eliminate = col_candidates[std::discrete_distribution<>(weights.begin(), @@ -1178,16 +1135,13 @@ void LinearProgrammingConstraint::AddMirCuts() { for (const auto entry : lp_data_.GetSparseColumn(var_to_eliminate)) { const RowIndex row = entry.row(); const auto status = simplex_.GetConstraintStatus(row); - if (status == glop::ConstraintStatus::BASIC) - continue; - if (status == glop::ConstraintStatus::FREE) - continue; + if (status == glop::ConstraintStatus::BASIC) continue; + if (status == glop::ConstraintStatus::FREE) continue; // We disallow all the rows that contain a variable that we already // eliminated (or are about to). This mean that we choose rows that // form a "triangular" matrix on the position we choose to eliminate. - if (used_rows[row]) - continue; + if (used_rows[row]) continue; used_rows[row] = true; // TODO(user): Instead of using FIXED_VALUE consider also both direction @@ -1200,21 +1154,17 @@ void LinearProgrammingConstraint::AddMirCuts() { if (status == glop::ConstraintStatus::FIXED_VALUE || status == glop::ConstraintStatus::AT_UPPER_BOUND) { if (entry.coefficient() > 0.0) { - if (dense_cut[var_to_eliminate] < 0) - add_row = true; + if (dense_cut[var_to_eliminate] < 0) add_row = true; } else { - if (dense_cut[var_to_eliminate] > 0) - add_row = true; + if (dense_cut[var_to_eliminate] > 0) add_row = true; } } if (status == glop::ConstraintStatus::FIXED_VALUE || status == glop::ConstraintStatus::AT_LOWER_BOUND) { if (entry.coefficient() > 0.0) { - if (dense_cut[var_to_eliminate] > 0) - add_row = true; + if (dense_cut[var_to_eliminate] > 0) add_row = true; } else { - if (dense_cut[var_to_eliminate] < 0) - add_row = true; + if (dense_cut[var_to_eliminate] < 0) add_row = true; } } if (add_row) { @@ -1222,8 +1172,7 @@ void LinearProgrammingConstraint::AddMirCuts() { weights.push_back(row_weights[row]); } } - if (possible_rows.empty()) - break; + if (possible_rows.empty()) break; const RowIndex row_to_combine = possible_rows[std::discrete_distribution<>(weights.begin(), @@ -1262,9 +1211,7 @@ void LinearProgrammingConstraint::AddMirCuts() { for (std::pair &entry : integer_multipliers) { entry.second *= mult1; } - integer_multipliers.push_back({ - row_to_combine, mult2 - }); + integer_multipliers.push_back({row_to_combine, mult2}); // TODO(user): Not supper efficient to recombine the rows. if (AddCutFromConstraints(absl::StrCat("MIR_", i + 2), @@ -1274,8 +1221,7 @@ void LinearProgrammingConstraint::AddMirCuts() { // Minor optim: the computation below is only needed if we do one more // iteration. - if (i + 1 == kMaxAggregation) - break; + if (i + 1 == kMaxAggregation) break; for (ColIndex col : non_zeros_.PositionsSetAtLeastOnce()) { dense_cut[col] *= mult1; @@ -1293,8 +1239,7 @@ void LinearProgrammingConstraint::AddMirCuts() { void LinearProgrammingConstraint::AddZeroHalfCuts() { CHECK_EQ(trail_->CurrentDecisionLevel(), 0); - if (time_limit_->LimitReached()) - return; + if (time_limit_->LimitReached()) return; tmp_lp_values_.clear(); tmp_var_lbs_.clear(); @@ -1312,18 +1257,15 @@ void LinearProgrammingConstraint::AddZeroHalfCuts() { // Even though we could use non-tight row, for now we prefer to use tight // ones. const auto status = simplex_.GetConstraintStatus(row); - if (status == glop::ConstraintStatus::BASIC) - continue; - if (status == glop::ConstraintStatus::FREE) - continue; + if (status == glop::ConstraintStatus::BASIC) continue; + if (status == glop::ConstraintStatus::FREE) continue; zero_half_cut_helper_.AddOneConstraint( row, integer_lp_[row].terms, integer_lp_[row].lb, integer_lp_[row].ub); } for (const std::vector > &multipliers : zero_half_cut_helper_.InterestingCandidates(random_)) { - if (time_limit_->LimitReached()) - break; + if (time_limit_->LimitReached()) break; // TODO(user): Make sure that if the resulting linear coefficients are not // too high, we do try a "divisor" of two and thus try a true zero-half cut @@ -1333,11 +1275,9 @@ void LinearProgrammingConstraint::AddZeroHalfCuts() { } } -void -LinearProgrammingConstraint::UpdateSimplexIterationLimit(const int64 min_iter, - const int64 max_iter) { - if (sat_parameters_.linearization_level() < 2) - return; +void LinearProgrammingConstraint::UpdateSimplexIterationLimit( + const int64 min_iter, const int64 max_iter) { + if (sat_parameters_.linearization_level() < 2) return; const int64 num_degenerate_columns = CalculateDegeneracy(); const int64 num_cols = simplex_.GetProblemNumCols().value(); if (num_cols <= 0) { @@ -1350,19 +1290,13 @@ LinearProgrammingConstraint::UpdateSimplexIterationLimit(const int64 min_iter, // signal to increase the iterations or punish less for degeneracy compare // to the other part. if (is_degenerate_) { - next_simplex_iter_ /= std::max(int64 { - 1 - }, - decrease_factor); + next_simplex_iter_ /= std::max(int64{1}, decrease_factor); } else { next_simplex_iter_ *= 2; } } else if (simplex_.GetProblemStatus() == glop::ProblemStatus::OPTIMAL) { if (is_degenerate_) { - next_simplex_iter_ /= std::max(int64 { - 1 - }, - 2 * decrease_factor); + next_simplex_iter_ /= std::max(int64{1}, 2 * decrease_factor); } else { // This is the most common case. We use the size of the problem to // determine the limit and ignore the previous limit. @@ -1379,7 +1313,7 @@ bool LinearProgrammingConstraint::Propagate() { // TODO(user): It seems the time we loose by not stopping early might be worth // it because we end up with a better explanation at optimality. glop::GlopParameters parameters = simplex_.GetParameters(); - if (/* DISABLES CODE */(false) && objective_is_defined_) { + if (/* DISABLES CODE */ (false) && objective_is_defined_) { // We put a limit on the dual objective since there is no point increasing // it past our current objective upper-bound (we will already fail as soon // as we pass it). Note that this limit is properly transformed using the @@ -1410,8 +1344,7 @@ bool LinearProgrammingConstraint::Propagate() { simplex_.SetParameters(parameters); simplex_.NotifyThatMatrixIsUnchangedForNextSolve(); - if (!SolveLp()) - return true; + if (!SolveLp()) return true; // Add new constraints to the LP and resolve? const int max_cuts_rounds = @@ -1434,12 +1367,9 @@ bool LinearProgrammingConstraint::Propagate() { // // TODO(user): Refactor so that they are just normal cut generators? if (trail_->CurrentDecisionLevel() == 0) { - if (sat_parameters_.add_mir_cuts()) - AddMirCuts(); - if (sat_parameters_.add_cg_cuts()) - AddCGCuts(); - if (sat_parameters_.add_zero_half_cuts()) - AddZeroHalfCuts(); + if (sat_parameters_.add_mir_cuts()) AddMirCuts(); + if (sat_parameters_.add_cg_cuts()) AddCGCuts(); + if (sat_parameters_.add_zero_half_cuts()) AddZeroHalfCuts(); } // Try to add cuts. @@ -1451,20 +1381,18 @@ bool LinearProgrammingConstraint::Propagate() { } } - implied_bounds_processor_.IbCutPool() - .TransferToManager(expanded_lp_solution_, &constraint_manager_); + implied_bounds_processor_.IbCutPool().TransferToManager( + expanded_lp_solution_, &constraint_manager_); } glop::BasisState state = simplex_.GetState(); if (constraint_manager_.ChangeLp(expanded_lp_solution_, &state)) { simplex_.LoadStateForNextSolve(state); if (!CreateLpFromConstraintManager()) { - return integer_trail_->ReportConflict({ - }); + return integer_trail_->ReportConflict({}); } const double old_obj = simplex_.GetObjectiveValue(); - if (!SolveLp()) - return true; + if (!SolveLp()) return true; if (simplex_.GetProblemStatus() == glop::ProblemStatus::OPTIMAL) { VLOG(1) << "Relaxation improvement " << old_obj << " -> " << simplex_.GetObjectiveValue() @@ -1482,8 +1410,7 @@ bool LinearProgrammingConstraint::Propagate() { // A dual-unbounded problem is infeasible. We use the dual ray reason. if (simplex_.GetProblemStatus() == glop::ProblemStatus::DUAL_UNBOUNDED) { if (sat_parameters_.use_exact_lp_reason()) { - if (!FillExactDualRayReason()) - return true; + if (!FillExactDualRayReason()) return true; } else { FillReducedCostReasonIn(simplex_.GetDualRayRowCombination(), &integer_reason_); @@ -1492,7 +1419,7 @@ bool LinearProgrammingConstraint::Propagate() { } // TODO(user): Update limits for DUAL_UNBOUNDED status as well. - UpdateSimplexIterationLimit(/*min_iter=*/ 10, /*max_iter=*/ 1000); + UpdateSimplexIterationLimit(/*min_iter=*/10, /*max_iter=*/1000); // Optimality deductions if problem has an objective. if (objective_is_defined_ && @@ -1508,8 +1435,7 @@ bool LinearProgrammingConstraint::Propagate() { // TODO(user): Maybe do a bit less computation when we cannot propagate // anything. if (sat_parameters_.use_exact_lp_reason()) { - if (!ExactLpReasonning()) - return false; + if (!ExactLpReasonning()) return false; // Display when the inexact bound would have propagated more. const IntegerValue propagated_lb = @@ -1517,10 +1443,9 @@ bool LinearProgrammingConstraint::Propagate() { if (approximate_new_lb > propagated_lb) { VLOG(2) << "LP objective [ " << ToDouble(propagated_lb) << ", " << ToDouble(integer_trail_->UpperBound(objective_cp_)) - << " ] approx_lb += " << ToDouble(approximate_new_lb - - propagated_lb) - << " gap: " << integer_trail_->UpperBound(objective_cp_) - - propagated_lb; + << " ] approx_lb += " + << ToDouble(approximate_new_lb - propagated_lb) << " gap: " + << integer_trail_->UpperBound(objective_cp_) - propagated_lb; } } else { FillReducedCostReasonIn(simplex_.GetReducedCosts(), &integer_reason_); @@ -1538,9 +1463,7 @@ bool LinearProgrammingConstraint::Propagate() { if (approximate_new_lb > integer_trail_->LowerBound(objective_cp_)) { const IntegerLiteral deduction = IntegerLiteral::GreaterOrEqual(objective_cp_, approximate_new_lb); - if (!integer_trail_->Enqueue(deduction, { - }, - integer_reason_)) { + if (!integer_trail_->Enqueue(deduction, {}, integer_reason_)) { return false; } } @@ -1549,9 +1472,7 @@ bool LinearProgrammingConstraint::Propagate() { if (!deductions_.empty()) { const int trail_index_with_same_reason = integer_trail_->Index(); for (const IntegerLiteral deduction : deductions_) { - if (!integer_trail_->Enqueue(deduction, { - }, - deductions_reason_, + if (!integer_trail_->Enqueue(deduction, {}, deductions_reason_, trail_index_with_same_reason)) { return false; } @@ -1609,8 +1530,7 @@ bool LinearProgrammingConstraint::Propagate() { } // Skip ignored variables. - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; // We can use any metric to select a variable to branch on. Reduced cost // average is one of the most promissing metric. It captures the history @@ -1662,8 +1582,7 @@ IntegerValue LinearProgrammingConstraint::GetImpliedLowerBound( CHECK_NE(coeff, 0); const IntegerValue bound = coeff > 0 ? integer_trail_->LowerBound(var) : integer_trail_->UpperBound(var); - if (!AddProductTo(bound, coeff, &lower_bound)) - return kMinIntegerValue; + if (!AddProductTo(bound, coeff, &lower_bound)) return kMinIntegerValue; } return lower_bound; } @@ -1694,12 +1613,11 @@ namespace { absl::int128 FloorRatio128(absl::int128 x, IntegerValue positive_div) { absl::int128 div128(positive_div.value()); absl::int128 result = x / div128; - if (result * div128 > x) - return result - 1; + if (result * div128 > x) return result - 1; return result; } -} // namespace +} // namespace void LinearProgrammingConstraint::PreventOverflow(LinearConstraint *constraint, int max_pow) { @@ -1722,8 +1640,7 @@ void LinearProgrammingConstraint::PreventOverflow(LinearConstraint *constraint, const double max_value = std::max(sum_max, -sum_min); const IntegerValue divisor(std::ceil(std::ldexp(max_value, -max_pow))); - if (divisor <= 1) - return; + if (divisor <= 1) return; // To be correct, we need to shift all variable so that they are positive. // @@ -1747,11 +1664,12 @@ void LinearProgrammingConstraint::PreventOverflow(LinearConstraint *constraint, const absl::int128 remainder = absl::int128(old_coeff.value()) - absl::int128(new_coeff.value()) * absl::int128(divisor.value()); - adjust += remainder * absl::int128(integer_trail_->LevelZeroLowerBound( - constraint->vars[i]).value()); + adjust += + remainder * + absl::int128( + integer_trail_->LevelZeroLowerBound(constraint->vars[i]).value()); - if (new_coeff == 0) - continue; + if (new_coeff == 0) continue; constraint->vars[new_size] = constraint->vars[i]; constraint->coeffs[new_size] = new_coeff; ++new_size; @@ -1802,8 +1720,7 @@ LinearProgrammingConstraint::ScaleLpMultiplier( // We ignore small values since these are likely errors and will not // contribute much to the new lp constraint anyway. - if (std::abs(lp_multi) < 1e-12) - continue; + if (std::abs(lp_multi) < 1e-12) continue; // Remove trivial bad cases. // @@ -1819,9 +1736,7 @@ LinearProgrammingConstraint::ScaleLpMultiplier( } const Fractional cp_multi = scaler_.UnscaleDualValue(row, lp_multi); - cp_multipliers.push_back({ - row, cp_multi - }); + cp_multipliers.push_back({row, cp_multi}); max_sum += ToDouble(infinity_norms_[row]) * std::abs(cp_multi); } @@ -1846,18 +1761,14 @@ LinearProgrammingConstraint::ScaleLpMultiplier( // in this case. return integer_multipliers; } - while (2 * *scaling <= threshold) - *scaling *= 2; + while (2 * *scaling <= threshold) *scaling *= 2; // Scale the multipliers by *scaling. // // TODO(user): Maybe use int128 to avoid overflow? for (const auto entry : cp_multipliers) { const IntegerValue coeff(std::round(entry.second * (*scaling))); - if (coeff != 0) - integer_multipliers.push_back({ - entry.first, coeff - }); + if (coeff != 0) integer_multipliers.push_back({entry.first, coeff}); } return integer_multipliers; } @@ -1885,8 +1796,7 @@ bool LinearProgrammingConstraint::ComputeNewLinearConstraint( // Update the upper bound. const IntegerValue bound = multiplier > 0 ? integer_lp_[row].ub : integer_lp_[row].lb; - if (!AddProductTo(multiplier, bound, upper_bound)) - return false; + if (!AddProductTo(multiplier, bound, upper_bound)) return false; } return true; @@ -1900,8 +1810,7 @@ void LinearProgrammingConstraint::AdjustNewLinearConstraint( for (std::pair &term : *integer_multipliers) { const RowIndex row = term.first; const IntegerValue multiplier = term.second; - if (multiplier == 0) - continue; + if (multiplier == 0) continue; // We will only allow change of the form "multiplier += to_add" with to_add // in [-negative_limit, positive_limit]. @@ -1927,7 +1836,7 @@ void LinearProgrammingConstraint::AdjustNewLinearConstraint( IntTypeAbs(row_bound)); const IntegerValue limit2 = FloorRatio(kMaxWantedCoeff, IntTypeAbs(row_bound)); - if (*upper_bound > 0 == row_bound > 0) { // Same sign. + if (*upper_bound > 0 == row_bound > 0) { // Same sign. positive_limit = std::min(positive_limit, limit1); negative_limit = std::min(negative_limit, limit2); } else { @@ -1986,16 +1895,16 @@ void LinearProgrammingConstraint::AdjustNewLinearConstraint( // - IntTypeAbs(current) can be larger than kMaxWantedCoeff! // - The code assumes that 2 * kMaxWantedCoeff do not overflow. const IntegerValue current_magnitude = IntTypeAbs(current); - const IntegerValue other_direction_limit = - FloorRatio(lb == ub ? kMaxWantedCoeff + - std::min(current_magnitude, - kMaxIntegerValue - kMaxWantedCoeff) - : current_magnitude, - abs_coef); + const IntegerValue other_direction_limit = FloorRatio( + lb == ub + ? kMaxWantedCoeff + std::min(current_magnitude, + kMaxIntegerValue - kMaxWantedCoeff) + : current_magnitude, + abs_coef); const IntegerValue same_direction_limit(FloorRatio( std::max(IntegerValue(0), kMaxWantedCoeff - current_magnitude), abs_coef)); - if (current > 0 == coeff > 0) { // Same sign. + if (current > 0 == coeff > 0) { // Same sign. negative_limit = std::min(negative_limit, other_direction_limit); positive_limit = std::min(positive_limit, same_direction_limit); } else { @@ -2070,7 +1979,7 @@ bool LinearProgrammingConstraint::ExactLpReasonning() { Fractional scaling; std::vector > integer_multipliers = - ScaleLpMultiplier(/*take_objective_into_account=*/ true, lp_multipliers, + ScaleLpMultiplier(/*take_objective_into_account=*/true, lp_multipliers, &scaling); IntegerValue rc_ub; @@ -2104,10 +2013,9 @@ bool LinearProgrammingConstraint::ExactLpReasonning() { DCHECK(!PossibleOverflow(new_constraint)); DCHECK(constraint_manager_.DebugCheckConstraint(new_constraint)); - IntegerSumLE *cp_constraint = new IntegerSumLE( - { - }, - new_constraint.vars, new_constraint.coeffs, new_constraint.ub, model_); + IntegerSumLE *cp_constraint = + new IntegerSumLE({}, new_constraint.vars, new_constraint.coeffs, + new_constraint.ub, model_); if (trail_->CurrentDecisionLevel() == 0) { // Since we will never ask the reason for a constraint at level 0, we just // keep the last one. @@ -2121,7 +2029,7 @@ bool LinearProgrammingConstraint::ExactLpReasonning() { bool LinearProgrammingConstraint::FillExactDualRayReason() { Fractional scaling; std::vector > integer_multipliers = - ScaleLpMultiplier(/*take_objective_into_account=*/ false, + ScaleLpMultiplier(/*take_objective_into_account=*/false, simplex_.GetDualRay(), &scaling); IntegerValue new_constraint_ub; @@ -2159,8 +2067,7 @@ int64 LinearProgrammingConstraint::CalculateDegeneracy() { int num_non_basic_with_zero_rc = 0; for (glop::ColIndex i(0); i < num_vars; ++i) { const double rc = simplex_.GetReducedCost(i); - if (rc != 0.0) - continue; + if (rc != 0.0) continue; if (simplex_.GetVariableStatus(i) == glop::VariableStatus::BASIC) { continue; } @@ -2187,8 +2094,7 @@ void LinearProgrammingConstraint::ReducedCostStrengtheningDeductions( const double rc = simplex_.GetReducedCost(lp_var); const double value = simplex_.GetVariableValue(lp_var); - if (rc == 0.0) - continue; + if (rc == 0.0) continue; const double lp_other_bound = value + lp_objective_delta / rc; const double cp_other_bound = scaler_.UnscaleVariableValue(lp_var, lp_other_bound); @@ -2242,8 +2148,7 @@ void AddOutgoingCut(int num_nodes, int subset_size, int optional_loop_in = -1; int optional_loop_out = -1; for (int i = 0; i < tails.size(); ++i) { - if (tails[i] != heads[i]) - continue; + if (tails[i] != heads[i]) continue; if (in_subset[tails[i]]) { num_optional_nodes_in++; if (optional_loop_in == -1 || @@ -2312,7 +2217,7 @@ void AddOutgoingCut(int num_nodes, int subset_size, } } -} // namespace +} // namespace // We roughly follow the algorithm described in section 6 of "The Traveling // Salesman Problem, A computational Study", David L. Applegate, Robert E. @@ -2326,8 +2231,7 @@ void SeparateSubtourInequalities( const gtl::ITIVector &lp_values, absl::Span demands, int64 capacity, LinearConstraintManager *manager, Model *model) { - if (num_nodes <= 2) - return; + if (num_nodes <= 2) return; // We will collect only the arcs with a positive lp_values to speed up some // computation below. @@ -2353,14 +2257,9 @@ void SeparateSubtourInequalities( } literal_lp_values[i] = lp_value; - if (lp_value < 1e-6) - continue; - relevant_arcs.push_back({ - tails[i], heads[i], lp_value - }); - arc_by_decreasing_lp_values.push_back({ - lp_value, i - }); + if (lp_value < 1e-6) continue; + relevant_arcs.push_back({tails[i], heads[i], lp_value}); + arc_by_decreasing_lp_values.push_back({lp_value, i}); } std::sort(arc_by_decreasing_lp_values.begin(), arc_by_decreasing_lp_values.end(), @@ -2383,19 +2282,16 @@ void SeparateSubtourInequalities( } auto get_root_and_compress_path = [&root](int node) { int r = node; - while (root[r] != r) - r = root[r]; + while (root[r] != r) r = root[r]; while (root[node] != r) { const int next = root[node]; root[node] = r; node = next; } return r; - } - ; + }; for (const auto pair : arc_by_decreasing_lp_values) { - if (num_components == 2) - break; + if (num_components == 2) break; const int tail = get_root_and_compress_path(tails[pair.second]); const int head = get_root_and_compress_path(heads[pair.second]); if (tail != head) { @@ -2426,8 +2322,7 @@ void SeparateSubtourInequalities( { std::vector > graph(parent.size()); for (int i = 0; i < parent.size(); ++i) { - if (parent[i] != i) - graph[parent[i]].push_back(i); + if (parent[i] != i) graph[parent[i]].push_back(i); } std::vector queue; std::vector seen(graph.size(), false); @@ -2437,8 +2332,7 @@ void SeparateSubtourInequalities( // binary tree. This is not required for the correctness of the algorithm // here though. CHECK(graph[i].empty() || graph[i].size() == 2); - if (parent[i] != i) - continue; + if (parent[i] != i) continue; // Explore the subtree rooted at node i. CHECK(!seen[i]); @@ -2457,11 +2351,9 @@ void SeparateSubtourInequalities( } seen[node] = true; start_index[node] = new_size; - if (node < num_nodes) - pre_order[new_size++] = node; + if (node < num_nodes) pre_order[new_size++] = node; for (const int child : graph[node]) { - if (!seen[child]) - queue.push_back(child); + if (!seen[child]) queue.push_back(child); } } } @@ -2471,8 +2363,7 @@ void SeparateSubtourInequalities( // flow. int64 total_demands = 0; if (!demands.empty()) { - for (const int64 demand : demands) - total_demands += demand; + for (const int64 demand : demands) total_demands += demand; } // Process each subsets and add any violated cut. @@ -2490,8 +2381,7 @@ void SeparateSubtourInequalities( for (const int n : subset) { in_subset[n] = true; if (!demands.empty()) { - if (n == 0) - contain_depot = true; + if (n == 0) contain_depot = true; subset_demand += demands[n]; } } @@ -2520,9 +2410,7 @@ void SeparateSubtourInequalities( // We still need to serve nodes with a demand of zero, and in the corner // case where all node in subset have a zero demand, the formula above // result in a min_outgoing_flow of zero. - min_outgoing_flow = std::max(min_outgoing_flow, int64 { - 1 - }); + min_outgoing_flow = std::max(min_outgoing_flow, int64{1}); // Compute the current outgoing flow out of the subset. // @@ -2545,21 +2433,20 @@ void SeparateSubtourInequalities( if (outgoing_flow < min_outgoing_flow - 1e-6) { AddOutgoingCut(num_nodes, subset.size(), in_subset, tails, heads, literals, literal_lp_values, - /*rhs_lower_bound=*/ min_outgoing_flow, lp_values, manager, + /*rhs_lower_bound=*/min_outgoing_flow, lp_values, manager, model); } // Sparse clean up. - for (const int n : subset) - in_subset[n] = false; + for (const int n : subset) in_subset[n] = false; } } namespace { // Returns for each literal its integer view, or the view of its negation. -std::vector -GetAssociatedVariables(const std::vector &literals, Model *model) { +std::vector GetAssociatedVariables( + const std::vector &literals, Model *model) { auto *encoder = model->GetOrCreate(); std::vector result; for (const Literal l : literals) { @@ -2574,7 +2461,7 @@ GetAssociatedVariables(const std::vector &literals, Model *model) { return result; } -} // namespace +} // namespace // We use a basic algorithm to detect components that are not connected to the // rest of the graph in the LP solution, and add cuts to force some arcs to @@ -2584,15 +2471,14 @@ CutGenerator CreateStronglyConnectedGraphCutGenerator( const std::vector &literals, Model *model) { CutGenerator result; result.vars = GetAssociatedVariables(literals, model); - result.generate_cuts = [num_nodes, tails, heads, literals, model]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + result.generate_cuts = + [num_nodes, tails, heads, literals, model]( + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { SeparateSubtourInequalities(num_nodes, tails, heads, literals, - lp_values, /*demands=*/ { - }, - /*capacity=*/ 0, manager, model); - } - ; + lp_values, /*demands=*/{}, + /*capacity=*/0, manager, model); + }; return result; } @@ -2606,13 +2492,12 @@ CutGenerator CreateCVRPCutGenerator(int num_nodes, result.vars = GetAssociatedVariables(literals, model); result.generate_cuts = [num_nodes, tails, heads, demands, capacity, literals, model]( - const gtl::ITIVector & lp_values, - LinearConstraintManager * manager) { + const gtl::ITIVector &lp_values, + LinearConstraintManager *manager) { SeparateSubtourInequalities(num_nodes, tails, heads, literals, lp_values, demands, capacity, manager, model); - } - ; + }; return result; } @@ -2629,26 +2514,24 @@ LinearProgrammingConstraint::HeuristicLpMostInfeasibleBinary(Model *model) { VLOG(1) << "HeuristicLPMostInfeasibleBinary has " << variables.size() << " variables."; - return[this, variables]() { const double kEpsilon = 1e-6; + return [this, variables]() { + const double kEpsilon = 1e-6; // Find most fractional value. IntegerVariable fractional_var = kNoIntegerVariable; double fractional_distance_best = -1.0; for (const IntegerVariable var : variables) { // Skip ignored and fixed variables. - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; const IntegerValue lb = integer_trail_->LowerBound(var); const IntegerValue ub = integer_trail_->UpperBound(var); - if (lb == ub) - continue; + if (lb == ub) continue; // Check variable's support is fractional. const double lp_value = this->GetSolutionValue(var); const double fractional_distance = std::min(std::ceil(lp_value - kEpsilon) - lp_value, lp_value - std::floor(lp_value + kEpsilon)); - if (fractional_distance < kEpsilon) - continue; + if (fractional_distance < kEpsilon) continue; // Keep variable if it is farther from integrality than the previous. if (fractional_distance > fractional_distance_best) { @@ -2661,8 +2544,7 @@ LinearProgrammingConstraint::HeuristicLpMostInfeasibleBinary(Model *model) { IntegerLiteral::GreaterOrEqual(fractional_var, IntegerValue(1)); } return IntegerLiteral(); - } - ; + }; } std::function @@ -2686,7 +2568,8 @@ LinearProgrammingConstraint::HeuristicLpReducedCostBinary(Model *model) { std::vector num_cost_to_zero(num_vars); int num_calls = 0; - return[ = ]() mutable { const double kEpsilon = 1e-6; + return [=]() mutable { + const double kEpsilon = 1e-6; // Every 10000 calls, decay pseudocosts. num_calls++; @@ -2702,17 +2585,14 @@ LinearProgrammingConstraint::HeuristicLpReducedCostBinary(Model *model) { for (int i = 0; i < num_vars; i++) { const IntegerVariable var = variables[i]; // Skip ignored and fixed variables. - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; const IntegerValue lb = integer_trail_->LowerBound(var); const IntegerValue ub = integer_trail_->UpperBound(var); - if (lb == ub) - continue; + if (lb == ub) continue; const double rc = this->GetSolutionReducedCost(var); // Skip reduced costs that are nonzero because of numerical issues. - if (std::abs(rc) < kEpsilon) - continue; + if (std::abs(rc) < kEpsilon) continue; const double value = std::round(this->GetSolutionValue(var)); if (value == 1.0 && rc < 0.0) { @@ -2727,10 +2607,8 @@ LinearProgrammingConstraint::HeuristicLpReducedCostBinary(Model *model) { for (int i = 0; i < num_vars; i++) { const IntegerVariable var = variables[i]; // Skip ignored and fixed variables. - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; - if (integer_trail_->IsFixed(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; + if (integer_trail_->IsFixed(var)) continue; if (num_cost_to_zero[i] > 0 && best_cost < cost_to_zero[i] / num_cost_to_zero[i]) { @@ -2744,8 +2622,7 @@ LinearProgrammingConstraint::HeuristicLpReducedCostBinary(Model *model) { IntegerValue(1)); } return IntegerLiteral(); - } - ; + }; } void LinearProgrammingConstraint::UpdateAverageReducedCosts() { @@ -2775,15 +2652,12 @@ void LinearProgrammingConstraint::UpdateAverageReducedCosts() { const IntegerVariable var = integer_variables_[i]; // Skip ignored and fixed variables. - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; - if (integer_trail_->IsFixed(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; + if (integer_trail_->IsFixed(var)) continue; // Skip reduced costs that are zero or close. const double rc = lp_reduced_cost_[i]; - if (std::abs(rc) < kCpEpsilon) - continue; + if (std::abs(rc) < kCpEpsilon) continue; if (rc < 0.0) { sum_cost_down_[i] -= rc; @@ -2820,9 +2694,7 @@ void LinearProgrammingConstraint::UpdateAverageReducedCosts() { // We ignore scores of zero (i.e. no data) and will follow the default // search heuristic if all variables are like this. if (rc_scores_[i] > 0.0) { - positions_by_decreasing_rc_score_.push_back({ - -rc_scores_[i], i - }); + positions_by_decreasing_rc_score_.push_back({-rc_scores_[i], i}); } } std::sort(positions_by_decreasing_rc_score_.begin(), @@ -2832,9 +2704,7 @@ void LinearProgrammingConstraint::UpdateAverageReducedCosts() { // TODO(user): Remove duplication with HeuristicLpReducedCostBinary(). std::function LinearProgrammingConstraint::HeuristicLpReducedCostAverageBranching() { - return[this]() { return this->LPReducedCostAverageDecision(); -} -; + return [this]() { return this->LPReducedCostAverageDecision(); }; } IntegerLiteral LinearProgrammingConstraint::LPReducedCostAverageDecision() { @@ -2845,17 +2715,14 @@ IntegerLiteral LinearProgrammingConstraint::LPReducedCostAverageDecision() { for (int i = rev_rc_start_; i < size; ++i) { const int index = positions_by_decreasing_rc_score_[i].second; const IntegerVariable var = integer_variables_[index]; - if (integer_trail_->IsCurrentlyIgnored(var)) - continue; - if (integer_trail_->IsFixed(var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(var)) continue; + if (integer_trail_->IsFixed(var)) continue; selected_index = index; rev_rc_start_ = i; break; } - if (selected_index == -1) - return IntegerLiteral(); + if (selected_index == -1) return IntegerLiteral(); const IntegerVariable var = integer_variables_[selected_index]; // If ceil(value) is current upper bound, try var == upper bound first. @@ -2895,5 +2762,5 @@ IntegerLiteral LinearProgrammingConstraint::LPReducedCostAverageDecision() { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/linear_programming_constraint.h b/ortools/sat/linear_programming_constraint.h index ad95b00944..7a210da7db 100644 --- a/ortools/sat/linear_programming_constraint.h +++ b/ortools/sat/linear_programming_constraint.h @@ -62,7 +62,7 @@ struct LPSolveInfo { // Simple class to combine linear expression efficiently. First in a sparse // way that switch to dense when the number of non-zeros grows. class ScatteredIntegerVector { -public: + public: // This must be called with the correct size before any other functions are // used. void ClearAndResize(int size); @@ -94,7 +94,7 @@ public: return dense_vector_[col]; } -private: + private: // If is_sparse is true we maintain the non_zeros positions and bool vector // of dense_vector_. Otherwise we don't. Note that we automatically switch // from sparse to dense as needed. @@ -126,7 +126,7 @@ private: class LinearProgrammingDispatcher; class LinearProgrammingConstraint : public PropagatorInterface, ReversibleInterface { -public: + public: typedef glop::RowIndex ConstraintIndex; explicit LinearProgrammingConstraint(Model *model); @@ -214,7 +214,7 @@ public: return average_degeneracy_.CurrentAverage(); } -private: + private: // Helper methods for branching. Returns true if branching on the given // variable helps with more propagation or finds a conflict. bool BranchOnVar(IntegerVariable var); @@ -244,8 +244,8 @@ private: // Return true if a new cut was added to the cut manager. bool AddCutFromConstraints( const std::string &name, - const std::vector > & - integer_multipliers); + const std::vector > + &integer_multipliers); // Second half of AddCutFromConstraints(). bool PostprocessAndAddCut( @@ -282,10 +282,10 @@ private: // // Note that this will loose some precision, but our subsequent computation // will still be exact as it will work for any set of multiplier. - std::vector > - ScaleLpMultiplier(bool take_objective_into_account, - const glop::DenseColumn &dense_lp_multipliers, - glop::Fractional *scaling, int max_pow = 62) const; + std::vector > ScaleLpMultiplier( + bool take_objective_into_account, + const glop::DenseColumn &dense_lp_multipliers, glop::Fractional *scaling, + int max_pow = 62) const; // Computes from an integer linear combination of the integer rows of the LP a // new constraint of the form "sum terms <= upper_bound". All computation are @@ -293,8 +293,8 @@ private: // // Returns false if we encountered any integer overflow. bool ComputeNewLinearConstraint( - const std::vector > & - integer_multipliers, + const std::vector > + &integer_multipliers, ScatteredIntegerVector *scattered_vector, IntegerValue *upper_bound) const; @@ -302,8 +302,8 @@ private: // should make the new constraint tighter and correct a bit the imprecision // introduced by rounding the floating points values. void AdjustNewLinearConstraint( - std::vector > * - integer_multipliers, + std::vector > + *integer_multipliers, ScatteredIntegerVector *scattered_vector, IntegerValue *upper_bound) const; @@ -514,16 +514,17 @@ private: // model. // // Important: only positive variable do appear here. -class LinearProgrammingDispatcher : public absl::flat_hash_map< - IntegerVariable, LinearProgrammingConstraint *> { -public: +class LinearProgrammingDispatcher + : public absl::flat_hash_map { + public: explicit LinearProgrammingDispatcher(Model *model) {} }; // A class that stores the collection of all LP constraints in a model. class LinearProgrammingConstraintCollection : public std::vector { -public: + public: LinearProgrammingConstraintCollection() {} }; @@ -548,7 +549,7 @@ CutGenerator CreateCVRPCutGenerator(int num_nodes, const std::vector &literals, const std::vector &demands, int64 capacity, Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_ +#endif // OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_ diff --git a/ortools/sat/linear_relaxation.cc b/ortools/sat/linear_relaxation.cc index 4b5f87d10d..db2ef7d2cf 100644 --- a/ortools/sat/linear_relaxation.cc +++ b/ortools/sat/linear_relaxation.cc @@ -33,10 +33,8 @@ namespace sat { bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation) { const auto *encoder = model.Get(); - if (encoder == nullptr) - return false; - if (!encoder->VariableIsFullyEncoded(var)) - return false; + if (encoder == nullptr) return false; + if (!encoder->VariableIsFullyEncoded(var)) return false; const auto &encoding = encoder->FullDomainEncoding(var); const IntegerValue var_min = model.Get()->LowerBound(var); @@ -54,11 +52,9 @@ bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, const IntegerValue delta = value_literal.value - var_min; DCHECK_GE(delta, IntegerValue(0)); at_most_one.push_back(lit); - if (!at_least_one.AddLiteralTerm(lit, IntegerValue(1))) - return false; + if (!at_least_one.AddLiteralTerm(lit, IntegerValue(1))) return false; if (delta != IntegerValue(0)) { - if (!encoding_ct.AddLiteralTerm(lit, -delta)) - return false; + if (!encoding_ct.AddLiteralTerm(lit, -delta)) return false; } } @@ -71,13 +67,13 @@ bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, namespace { // TODO(user): Not super efficient. -std::pair -GetMinAndMaxNotEncoded(IntegerVariable var, - const absl::flat_hash_set &encoded_values, - const Model &model) { +std::pair GetMinAndMaxNotEncoded( + IntegerVariable var, + const absl::flat_hash_set &encoded_values, + const Model &model) { const auto *domains = model.Get(); if (domains == nullptr || var >= domains->size()) { - return { kMaxIntegerValue, kMinIntegerValue }; + return {kMaxIntegerValue, kMinIntegerValue}; } // The domain can be large, but the list of values shouldn't, so this @@ -90,8 +86,7 @@ GetMinAndMaxNotEncoded(IntegerVariable var, break; } } - if (min != kMaxIntegerValue) - break; + if (min != kMaxIntegerValue) break; } IntegerValue max = kMinIntegerValue; @@ -104,26 +99,23 @@ GetMinAndMaxNotEncoded(IntegerVariable var, break; } } - if (max != kMinIntegerValue) - break; + if (max != kMinIntegerValue) break; } - return { min, max }; + return {min, max}; } -} // namespace +} // namespace void AppendPartialEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation) { const auto *encoder = model.Get(); const auto *integer_trail = model.Get(); - if (encoder == nullptr || integer_trail == nullptr) - return; + if (encoder == nullptr || integer_trail == nullptr) return; const std::vector &encoding = encoder->PartialDomainEncoding(var); - if (encoding.empty()) - return; + if (encoding.empty()) return; std::vector at_most_one_ct; absl::flat_hash_set encoded_values; @@ -139,8 +131,7 @@ void AppendPartialEncodingRelaxation(IntegerVariable var, const Model &model, at_most_one_ct.push_back(literal); encoded_values.insert(value_literal.value); } - if (encoded_values.empty()) - return; + if (encoded_values.empty()) return; // TODO(user): The PartialDomainEncoding() function automatically exclude // values that are no longer in the initial domain, so we could be a bit @@ -196,13 +187,11 @@ void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, LinearRelaxation *relaxation) { const auto *integer_trail = model.Get(); const auto *encoder = model.Get(); - if (integer_trail == nullptr || encoder == nullptr) - return; + if (integer_trail == nullptr || encoder == nullptr) return; const std::map &greater_than_encoding = encoder->PartialGreaterThanEncoding(var); - if (greater_than_encoding.empty()) - return; + if (greater_than_encoding.empty()) return; // Start by the var >= side. // And also add the implications between used literals. @@ -213,20 +202,17 @@ void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, lb_constraint.AddTerm(var, IntegerValue(1)); LiteralIndex prev_literal_index = kNoLiteralIndex; for (const auto entry : greater_than_encoding) { - if (entry.first <= prev_used_bound) - continue; + if (entry.first <= prev_used_bound) continue; const LiteralIndex literal_index = entry.second.Index(); const IntegerValue diff = prev_used_bound - entry.first; // Skip the entry if the literal doesn't have a view. - if (!lb_constraint.AddLiteralTerm(entry.second, diff)) - continue; + if (!lb_constraint.AddLiteralTerm(entry.second, diff)) continue; if (prev_literal_index != kNoLiteralIndex) { - // Add var <= prev_var, which is the same as var + not(prev_var) <= 1 - relaxation->at_most_ones.push_back({ - Literal(literal_index), Literal(prev_literal_index).Negated() - }); + // Add var <= prev_var, which is the same as var + not(prev_var) <= 1 + relaxation->at_most_ones.push_back( + {Literal(literal_index), Literal(prev_literal_index).Negated()}); } prev_used_bound = entry.first; prev_literal_index = literal_index; @@ -243,13 +229,11 @@ void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, lb_constraint.AddTerm(var, IntegerValue(-1)); for (const auto entry : encoder->PartialGreaterThanEncoding(NegationOf(var))) { - if (entry.first <= prev_used_bound) - continue; + if (entry.first <= prev_used_bound) continue; const IntegerValue diff = prev_used_bound - entry.first; // Skip the entry if the literal doesn't have a view. - if (!lb_constraint.AddLiteralTerm(entry.second, diff)) - continue; + if (!lb_constraint.AddLiteralTerm(entry.second, diff)) continue; prev_used_bound = entry.first; } relaxation->linear_constraints.push_back(lb_constraint.Build()); @@ -318,7 +302,7 @@ void AppendEnforcedLinearExpression( } } -} // namespace +} // namespace // Add a linear relaxation of the CP constraint to the set of linear // constraints. The highest linearization_level is, the more types of constraint @@ -336,8 +320,7 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, DCHECK_GT(linearization_level, 0); auto *mapping = model->GetOrCreate(); if (ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) { - if (linearization_level < 2) - return; + if (linearization_level < 2) return; LinearConstraintBuilder lc(model, IntegerValue(1), kMaxIntegerValue); for (const int enforcement_ref : ct.enforcement_literal()) { CHECK(lc.AddLiteralTerm(mapping->Literal(NegatedRef(enforcement_ref)), @@ -352,16 +335,13 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, // TODO(user): These constraints can be many, and if they are not regrouped // in big at most ones, then they should probably only added lazily as cuts. // Regroup this with future clique-cut separation logic. - if (linearization_level < 2) - return; - if (!HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (!HasEnforcementLiteral(ct)) return; if (ct.enforcement_literal().size() == 1) { const Literal enforcement = mapping->Literal(ct.enforcement_literal(0)); for (const int ref : ct.bool_and().literals()) { - relaxation->at_most_ones.push_back({ - enforcement, mapping->Literal(ref).Negated() - }); + relaxation->at_most_ones.push_back( + {enforcement, mapping->Literal(ref).Negated()}); } return; } @@ -381,24 +361,21 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, relaxation->linear_constraints.push_back(lc.Build()); } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kAtMostOne) { - if (HasEnforcementLiteral(ct)) - return; + if (HasEnforcementLiteral(ct)) return; std::vector at_most_one; for (const int ref : ct.at_most_one().literals()) { at_most_one.push_back(mapping->Literal(ref)); } relaxation->at_most_ones.push_back(at_most_one); } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMax) { - if (HasEnforcementLiteral(ct)) - return; + if (HasEnforcementLiteral(ct)) return; const IntegerVariable target = mapping->Integer(ct.int_max().target()); const std::vector vars = mapping->Integers(ct.int_max().vars()); AppendMaxRelaxation(target, vars, linearization_level, model, relaxation); } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMin) { - if (HasEnforcementLiteral(ct)) - return; + if (HasEnforcementLiteral(ct)) return; const IntegerVariable negative_target = NegationOf(mapping->Integer(ct.int_min().target())); const std::vector negative_vars = @@ -410,8 +387,7 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, relaxation); } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit) { - if (HasEnforcementLiteral(ct)) - return; + if (HasEnforcementLiteral(ct)) return; const int num_arcs = ct.circuit().literals_size(); CHECK_EQ(num_arcs, ct.circuit().tails_size()); CHECK_EQ(num_arcs, ct.circuit().heads_size()); @@ -430,9 +406,8 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, outgoing_arc_constraints[tail].push_back(arc); incoming_arc_constraints[head].push_back(arc); } - for (const auto *node_map : { - &outgoing_arc_constraints, &incoming_arc_constraints - }) { + for (const auto *node_map : + {&outgoing_arc_constraints, &incoming_arc_constraints}) { for (const auto &entry : *node_map) { const std::vector &exactly_one = entry.second; if (exactly_one.size() > 1) { @@ -462,8 +437,7 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, IntegerTrail *integer_trail = model->GetOrCreate(); for (const auto literal_value : model->Add(FullyEncodeVariable((index)))) { const IntegerVariable var = vars[literal_value.value.value()]; - if (!model->Get(IsFixed(var))) - return; + if (!model->Get(IsFixed(var))) return; // Make sure this literal has a view. model->Add(NewIntegerVariableFromLiteral(literal_value.literal)); @@ -474,8 +448,7 @@ void TryToLinearizeConstraint(const CpModelProto &model_proto, relaxation->linear_constraints.push_back(constraint.Build()); } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kInterval) { - if (linearization_level < 2) - return; + if (linearization_level < 2) return; const IntegerVariable start = mapping->Integer(ct.interval().start()); const IntegerVariable size = mapping->Integer(ct.interval().size()); const IntegerVariable end = mapping->Integer(ct.interval().end()); @@ -545,8 +518,7 @@ void AddCumulativeCut(const std::vector &intervals, << " variable size intervals out of " << num_intervals << " intervals"; - if (num_variable_sizes + num_optionals == 0) - return; + if (num_variable_sizes + num_optionals == 0) return; const IntegerVariable span_start = integer_trail->AddIntegerVariable(min_of_starts, max_of_ends); @@ -579,7 +551,7 @@ void AddCumulativeCut(const std::vector &intervals, lc.AddTerm(demands[i], helper.SizeMin(i)); } else if (demand_is_fixed) { lc.AddTerm(helper.SizeVars()[i], demand_lower_bound); - } else { // demand and size are not fixed. + } else { // demand and size are not fixed. DCHECK(!demands.empty()); // We use McCormick equation. // demand * size = (demand_min + delta_d) * (size_min + delta_s) = @@ -606,18 +578,17 @@ void AppendCumulativeRelaxation(const CpModelProto &model_proto, int linearization_level, Model *model, LinearRelaxation *relaxation) { CHECK(ct.has_cumulative()); - if (linearization_level < 2) - return; - if (HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (HasEnforcementLiteral(ct)) return; auto *mapping = model->GetOrCreate(); const std::vector demands = mapping->Integers(ct.cumulative().demands()); std::vector intervals = mapping->Intervals(ct.cumulative().intervals()); - const IntegerValue capacity_lower_bound = model->GetOrCreate() - ->LowerBound(mapping->Integer(ct.cumulative().capacity())); + const IntegerValue capacity_lower_bound = + model->GetOrCreate()->LowerBound( + mapping->Integer(ct.cumulative().capacity())); AddCumulativeCut(intervals, demands, capacity_lower_bound, model, relaxation); } @@ -626,18 +597,14 @@ void AppendNoOverlapRelaxation(const CpModelProto &model_proto, int linearization_level, Model *model, LinearRelaxation *relaxation) { CHECK(ct.has_no_overlap()); - if (linearization_level < 2) - return; - if (HasEnforcementLiteral(ct)) - return; + if (linearization_level < 2) return; + if (HasEnforcementLiteral(ct)) return; auto *mapping = model->GetOrCreate(); std::vector intervals = mapping->Intervals(ct.no_overlap().intervals()); - AddCumulativeCut(intervals, /*demands=*/ { - }, - /*capacity_lower_bound=*/ IntegerValue(1), model, - relaxation); + AddCumulativeCut(intervals, /*demands=*/{}, + /*capacity_lower_bound=*/IntegerValue(1), model, relaxation); } void AppendMaxRelaxation(IntegerVariable target, @@ -649,8 +616,7 @@ void AppendMaxRelaxation(IntegerVariable target, for (const IntegerVariable var : vars) { // This deal with the corner case X = max(X, Y, Z, ..) ! // Note that this can be presolved into X >= Y, X >= Z, ... - if (target == var) - continue; + if (target == var) continue; LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0)); lc.AddTerm(var, IntegerValue(1)); lc.AddTerm(target, IntegerValue(-1)); @@ -658,8 +624,7 @@ void AppendMaxRelaxation(IntegerVariable target, } // Part 2: Encode upper bound on X. - if (linearization_level < 2) - return; + if (linearization_level < 2) return; GenericLiteralWatcher *watcher = model->GetOrCreate(); // For size = 2, we do this with 1 less variable. IntegerEncoder *encoder = model->GetOrCreate(); @@ -669,32 +634,18 @@ void AppendMaxRelaxation(IntegerVariable target, encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1)); AppendEnforcedUpperBound(y_lit, target, vars[0], model, relaxation); - // TODO(user,user): It makes more sense to use ConditionalLowerOrEqual() - // here, but that degrades perf on the road*.fzn problem. Understand why. - IntegerSumLE *upper_bound1 = new IntegerSumLE({ - y_lit - }, - { - target, vars[0] - }, - { - IntegerValue(1), IntegerValue(-1) - }, - IntegerValue(0), model); + // TODO(user,user): It makes more sense to use ConditionalLowerOrEqual() + // here, but that degrades perf on the road*.fzn problem. Understand why. + IntegerSumLE *upper_bound1 = new IntegerSumLE( + {y_lit}, {target, vars[0]}, {IntegerValue(1), IntegerValue(-1)}, + IntegerValue(0), model); upper_bound1->RegisterWith(watcher); model->TakeOwnership(upper_bound1); AppendEnforcedUpperBound(y_lit.Negated(), target, vars[1], model, relaxation); - IntegerSumLE *upper_bound2 = new IntegerSumLE({ - y_lit.Negated() - }, - { - target, vars[1] - }, - { - IntegerValue(1), IntegerValue(-1) - }, - IntegerValue(0), model); + IntegerSumLE *upper_bound2 = new IntegerSumLE( + {y_lit.Negated()}, {target, vars[1]}, + {IntegerValue(1), IntegerValue(-1)}, IntegerValue(0), model); upper_bound2->RegisterWith(watcher); model->TakeOwnership(upper_bound2); return; @@ -708,8 +659,7 @@ void AppendMaxRelaxation(IntegerVariable target, std::vector exactly_one_literals; exactly_one_literals.reserve(vars.size()); for (const IntegerVariable var : vars) { - if (target == var) - continue; + if (target == var) continue; // y => X <= X_i. // <=> max_term_value * y + X - X_i <= max_term_value. // where max_tern_value is X_ub - X_i_lb. @@ -718,17 +668,9 @@ void AppendMaxRelaxation(IntegerVariable target, encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1)); AppendEnforcedUpperBound(y_lit, target, var, model, relaxation); - IntegerSumLE *upper_bound_constraint = - new IntegerSumLE({ - y_lit - }, - { - target, var - }, - { - IntegerValue(1), IntegerValue(-1) - }, - IntegerValue(0), model); + IntegerSumLE *upper_bound_constraint = new IntegerSumLE( + {y_lit}, {target, var}, {IntegerValue(1), IntegerValue(-1)}, + IntegerValue(0), model); upper_bound_constraint->RegisterWith(watcher); model->TakeOwnership(upper_bound_constraint); exactly_one_literals.push_back(y_lit); @@ -739,10 +681,9 @@ void AppendMaxRelaxation(IntegerVariable target, relaxation->linear_constraints.push_back(lc_exactly_one.Build()); } -std::vector -AppendLinMaxRelaxation(IntegerVariable target, - const std::vector &exprs, Model *model, - LinearRelaxation *relaxation) { +std::vector AppendLinMaxRelaxation( + IntegerVariable target, const std::vector &exprs, + Model *model, LinearRelaxation *relaxation) { // We want to linearize X = max(exprs[1], exprs[2], ..., exprs[d]). // Part 1: Encode X >= max(exprs[1], exprs[2], ..., exprs[d]) for (const LinearExpression &expr : exprs) { @@ -782,10 +723,7 @@ AppendLinMaxRelaxation(IntegerVariable target, local_expr.coeffs = exprs[i].coeffs; local_expr.coeffs.push_back(IntegerValue(1)); IntegerSumLE *upper_bound = new IntegerSumLE( - { - z_lit - }, - local_expr.vars, local_expr.coeffs, exprs[i].offset, model); + {z_lit}, local_expr.vars, local_expr.coeffs, exprs[i].offset, model); upper_bound->RegisterWith(watcher); model->TakeOwnership(upper_bound); @@ -802,7 +740,7 @@ AppendLinMaxRelaxation(IntegerVariable target, x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end()); } gtl::STLSortAndRemoveDuplicates(&x_vars); - // All expressions should only contain positive variables. + // All expressions should only contain positive variables. DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable var) { return VariableIsPositive(var); })); @@ -813,8 +751,7 @@ AppendLinMaxRelaxation(IntegerVariable target, IntegerTrail *integer_trail = model->GetOrCreate(); for (int i = 0; i < num_exprs; ++i) { for (int j = 0; j < num_exprs; ++j) { - if (i == j) - continue; + if (i == j) continue; for (const IntegerVariable x_var : x_vars) { const IntegerValue lb = integer_trail->LevelZeroLowerBound(x_var); const IntegerValue ub = integer_trail->LevelZeroUpperBound(x_var); @@ -859,8 +796,7 @@ void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, const IntegerValue rhs_domain_max = IntegerValue(constraint_proto.linear().domain( constraint_proto.linear().domain_size() - 1)); - if (rhs_domain_min == kint64min && rhs_domain_max == kint64max) - return; + if (rhs_domain_min == kint64min && rhs_domain_max == kint64max) return; if (!HasEnforcementLiteral(constraint_proto)) { LinearConstraintBuilder lc(&model, rhs_domain_min, rhs_domain_max); @@ -874,8 +810,7 @@ void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, } // Reified version. - if (linearization_level < 2) - return; + if (linearization_level < 2) return; // We linearize fully reified constraints of size 1 all together for a given // variable. But we need to process half-reified ones. @@ -907,5 +842,5 @@ void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, rhs_domain_max, model, relaxation); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/linear_relaxation.h b/ortools/sat/linear_relaxation.h index af76f87d4d..dcfff0c878 100644 --- a/ortools/sat/linear_relaxation.h +++ b/ortools/sat/linear_relaxation.h @@ -118,10 +118,9 @@ void AppendMaxRelaxation(IntegerVariable target, // Reference: "Strong mixed-integer programming formulations for trained neural // networks" by Ross Anderson et. (https://arxiv.org/pdf/1811.01988.pdf). // TODO(user): Support linear expression as target. -std::vector - AppendLinMaxRelaxation(IntegerVariable target, - const std::vector &exprs, - Model *model, LinearRelaxation *relaxation); +std::vector AppendLinMaxRelaxation( + IntegerVariable target, const std::vector &exprs, + Model *model, LinearRelaxation *relaxation); // Appends linear constraints to the relaxation. This also handles the // relaxation of linear constraints with enforcement literals. @@ -136,7 +135,7 @@ void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, const Model &model, LinearRelaxation *relaxation); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_LINEAR_RELAXATION_H_ +#endif // OR_TOOLS_SAT_LINEAR_RELAXATION_H_ diff --git a/ortools/sat/lp_utils.cc b/ortools/sat/lp_utils.cc index 6ffa06ff63..a62d1853ec 100644 --- a/ortools/sat/lp_utils.cc +++ b/ortools/sat/lp_utils.cc @@ -78,37 +78,35 @@ void ApplyVarScaling(const std::vector var_scaling, for (MPGeneralConstraintProto &general_constraint : *mp_model->mutable_general_constraint()) { switch (general_constraint.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: - ScaleConstraint(var_scaling, - general_constraint.mutable_indicator_constraint() - ->mutable_constraint()); - break; - case MPGeneralConstraintProto::kAndConstraint: - case MPGeneralConstraintProto::kOrConstraint: - // These constraints have only Boolean variables and no constants. They - // don't need scaling. - break; - default: - LOG(FATAL) << "Scaling unsupported for general constraint of type " - << general_constraint.general_constraint_case(); + case MPGeneralConstraintProto::kIndicatorConstraint: + ScaleConstraint(var_scaling, + general_constraint.mutable_indicator_constraint() + ->mutable_constraint()); + break; + case MPGeneralConstraintProto::kAndConstraint: + case MPGeneralConstraintProto::kOrConstraint: + // These constraints have only Boolean variables and no constants. They + // don't need scaling. + break; + default: + LOG(FATAL) << "Scaling unsupported for general constraint of type " + << general_constraint.general_constraint_case(); } } } -} // namespace +} // namespace std::vector ScaleContinuousVariables(double scaling, double max_bound, MPModelProto *mp_model) { const int num_variables = mp_model->variable_size(); std::vector var_scaling(num_variables, 1.0); for (int i = 0; i < num_variables; ++i) { - if (mp_model->variable(i).is_integer()) - continue; + if (mp_model->variable(i).is_integer()) continue; const double lb = mp_model->variable(i).lower_bound(); const double ub = mp_model->variable(i).upper_bound(); const double magnitude = std::max(std::abs(lb), std::abs(ub)); - if (magnitude == 0 || magnitude > max_bound) - continue; + if (magnitude == 0 || magnitude > max_bound) continue; var_scaling[i] = std::min(scaling, max_bound / magnitude); } ApplyVarScaling(var_scaling, mp_model); @@ -163,18 +161,14 @@ double GetIntegralityMultiplier(const MPModelProto &mp_model, const double coeff = multiplier * ct.coefficient(i) / var_scaling[ct.var_index(i)]; multiplier *= - FindRationalFactor(coeff, /*limit=*/ 100, multiplier * tolerance); - if (multiplier == 0 || multiplier > max_multiplier) - return 0.0; + FindRationalFactor(coeff, /*limit=*/100, multiplier * tolerance); + if (multiplier == 0 || multiplier > max_multiplier) return 0.0; } DCHECK_NE(var_coeff, 0.0); - // The constraint bound need to be infinite or integer. - for (const double bound : { - ct.lower_bound(), ct.upper_bound() - }) { - if (!std::isfinite(bound)) - continue; + // The constraint bound need to be infinite or integer. + for (const double bound : {ct.lower_bound(), ct.upper_bound()}) { + if (!std::isfinite(bound)) continue; if (std::abs(std::round(bound * multiplier) - bound * multiplier) > tolerance * multiplier) { return 0.0; @@ -183,7 +177,7 @@ double GetIntegralityMultiplier(const MPModelProto &mp_model, return std::abs(multiplier * var_coeff); } -} // namespace +} // namespace std::vector DetectImpliedIntegers(bool log_info, MPModelProto *mp_model) { @@ -192,8 +186,7 @@ std::vector DetectImpliedIntegers(bool log_info, int initial_num_integers = 0; for (int i = 0; i < num_variables; ++i) { - if (mp_model->variable(i).is_integer()) - ++initial_num_integers; + if (mp_model->variable(i).is_integer()) ++initial_num_integers; } VLOG(1) << "Initial num integers: " << initial_num_integers; @@ -245,8 +238,7 @@ std::vector DetectImpliedIntegers(bool log_info, constraint_queue.push_back(ct_index); } } - } - ; + }; int num_fail_due_to_rhs = 0; int num_fail_due_to_large_multiplier = 0; @@ -257,13 +249,11 @@ std::vector DetectImpliedIntegers(bool log_info, // The non integer variable was already made integer by one other // constraint. - if (constraint_to_num_non_integer[top_ct_index] == 0) - continue; + if (constraint_to_num_non_integer[top_ct_index] == 0) continue; // Ignore non-equality here. const MPConstraintProto &ct = mp_model->constraint(top_ct_index); - if (ct.lower_bound() + tolerance < ct.upper_bound()) - continue; + if (ct.lower_bound() + tolerance < ct.upper_bound()) continue; ++num_processed_constraints; @@ -291,7 +281,7 @@ std::vector DetectImpliedIntegers(bool log_info, const double coeff = multiplier * ct.coefficient(i) / var_scaling[ct.var_index(i)]; multiplier *= - FindRationalFactor(coeff, /*limit=*/ 100, multiplier * tolerance); + FindRationalFactor(coeff, /*limit=*/100, multiplier * tolerance); if (multiplier == 0 || multiplier > max_multiplier) { break; } @@ -319,15 +309,12 @@ std::vector DetectImpliedIntegers(bool log_info, // for an instance of this. double best_scaling = std::abs(var_coeff * multiplier); for (const int ct_index : var_to_constraints[var]) { - if (ct_index == top_ct_index) - continue; - if (constraint_to_num_non_integer[ct_index] != 1) - continue; + if (ct_index == top_ct_index) continue; + if (constraint_to_num_non_integer[ct_index] != 1) continue; // Ignore non-equality here. const MPConstraintProto &ct = mp_model->constraint(top_ct_index); - if (ct.lower_bound() + tolerance < ct.upper_bound()) - continue; + if (ct.lower_bound() + tolerance < ct.upper_bound()) continue; const double multiplier = GetIntegralityMultiplier( *mp_model, var_scaling, var, ct_index, tolerance); @@ -347,12 +334,10 @@ std::vector DetectImpliedIntegers(bool log_info, int num_in_inequalities = 0; int num_to_be_handled = 0; for (int var = 0; var < num_variables; ++var) { - if (mp_model->variable(var).is_integer()) - continue; + if (mp_model->variable(var).is_integer()) continue; // This should be presolved and not happen. - if (var_to_constraints[var].empty()) - continue; + if (var_to_constraints[var].empty()) continue; bool ok = true; for (const int ct_index : var_to_constraints[var]) { @@ -361,8 +346,7 @@ std::vector DetectImpliedIntegers(bool log_info, break; } } - if (!ok) - continue; + if (!ok) continue; std::vector scaled_coeffs; for (const int ct_index : var_to_constraints[var]) { @@ -374,8 +358,7 @@ std::vector DetectImpliedIntegers(bool log_info, } scaled_coeffs.push_back(multiplier); } - if (!ok) - continue; + if (!ok) continue; // The situation is a bit tricky here, we have a bunch of coeffs c_i, and we // know that X * c_i can take integer value without changing the constraint @@ -400,13 +383,10 @@ std::vector DetectImpliedIntegers(bool log_info, continue; } - // Tricky, we also need the bound of the scaled variable to be integer. - for (const double bound : { - mp_model->variable(var).lower_bound(), - mp_model->variable(var).upper_bound() - }) { - if (!std::isfinite(bound)) - continue; + // Tricky, we also need the bound of the scaled variable to be integer. + for (const double bound : {mp_model->variable(var).lower_bound(), + mp_model->variable(var).upper_bound()}) { + if (!std::isfinite(bound)) continue; if (std::abs(std::round(bound * scaling) - bound * scaling) > tolerance * scaling) { ok = false; @@ -434,12 +414,12 @@ std::vector DetectImpliedIntegers(bool log_info, } const int num_integers = initial_num_integers + num_detected; - LOG_IF(INFO, log_info) - << "Num integers: " << num_integers << "/" << num_variables - << " (implied: " << num_detected - << " in_inequalities: " << num_in_inequalities - << " max_scaling: " << max_scaling << ")" - << (num_integers == num_variables ? " [IP] " : " [MIP] "); + LOG_IF(INFO, log_info) << "Num integers: " << num_integers << "/" + << num_variables << " (implied: " << num_detected + << " in_inequalities: " << num_in_inequalities + << " max_scaling: " << max_scaling << ")" + << (num_integers == num_variables ? " [IP] " + : " [MIP] "); ApplyVarScaling(var_scaling, mp_model); return var_scaling; @@ -459,8 +439,7 @@ struct ConstraintScaler { double max_scaling_factor = 0.0; double wanted_precision = 1e-6; - int64 scaling_target = int64 { 1 } - << 50; + int64 scaling_target = int64{1} << 50; std::vector var_indices; std::vector coefficients; std::vector lower_bounds; @@ -474,19 +453,17 @@ double FindFractionalScaling(const std::vector &coefficients, double multiplier = 1.0; for (const double coeff : coefficients) { multiplier *= - FindRationalFactor(coeff, /*limit=*/ 1e8, multiplier * tolerance); - if (multiplier == 0.0) - break; + FindRationalFactor(coeff, /*limit=*/1e8, multiplier * tolerance); + if (multiplier == 0.0) break; } return multiplier; } -} // namespace +} // namespace -ConstraintProto * -ConstraintScaler::AddConstraint(const MPModelProto &mp_model, - const MPConstraintProto &mp_constraint, - CpModelProto *cp_model) { +ConstraintProto *ConstraintScaler::AddConstraint( + const MPModelProto &mp_model, const MPConstraintProto &mp_constraint, + CpModelProto *cp_model) { if (mp_constraint.lower_bound() == -kInfinity && mp_constraint.upper_bound() == kInfinity) { return nullptr; @@ -507,12 +484,10 @@ ConstraintScaler::AddConstraint(const MPModelProto &mp_model, const auto &var_proto = cp_model->variables(mp_constraint.var_index(i)); const int64 lb = var_proto.domain(0); const int64 ub = var_proto.domain(var_proto.domain_size() - 1); - if (lb == 0 && ub == 0) - continue; + if (lb == 0 && ub == 0) continue; const double coeff = mp_constraint.coefficient(i); - if (coeff == 0.0) - continue; + if (coeff == 0.0) continue; var_indices.push_back(mp_constraint.var_index(i)); coefficients.push_back(coeff); @@ -539,8 +514,7 @@ ConstraintScaler::AddConstraint(const MPModelProto &mp_model, for (; x <= scaling_factor; x *= 2) { ComputeScalingErrors(coefficients, lower_bounds, upper_bounds, x, &relative_coeff_error, &scaled_sum_error); - if (scaled_sum_error < wanted_precision * x * ct_norm) - break; + if (scaled_sum_error < wanted_precision * x * ct_norm) break; } scaling_factor = x; @@ -592,7 +566,8 @@ ConstraintScaler::AddConstraint(const MPModelProto &mp_model, arg->add_domain(kint64min); } else { arg->add_domain(CeilRatio(IntegerValue(static_cast(scaled_lb)), - IntegerValue(gcd)).value()); + IntegerValue(gcd)) + .value()); } if (relax_bound) { @@ -603,13 +578,14 @@ ConstraintScaler::AddConstraint(const MPModelProto &mp_model, arg->add_domain(kint64max); } else { arg->add_domain(FloorRatio(IntegerValue(static_cast(scaled_ub)), - IntegerValue(gcd)).value()); + IntegerValue(gcd)) + .value()); } return constraint; } -} // namespace +} // namespace bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, const MPModelProto &mp_model, @@ -665,10 +641,8 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, continue; } - // Note that we must process the lower bound first. - for (const bool lower : { - true, false - }) { + // Note that we must process the lower bound first. + for (const bool lower : {true, false}) { const double bound = lower ? mp_var.lower_bound() : mp_var.upper_bound(); if (std::abs(bound) >= kMaxVariableBound) { ++num_truncated_bounds; @@ -696,16 +670,15 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, } } - LOG_IF(WARNING, num_truncated_bounds > 0) << num_truncated_bounds - << " bounds were truncated to " - << kMaxVariableBound << "."; + LOG_IF(WARNING, num_truncated_bounds > 0) + << num_truncated_bounds << " bounds were truncated to " + << kMaxVariableBound << "."; LOG_IF(WARNING, num_small_domains > 0) << num_small_domains << " continuous variable domain with fewer than " << kSmallDomainSize << " values."; ConstraintScaler scaler; - const int64 kScalingTarget = int64 { 1 } - << params.mip_max_activity_exponent(); + const int64 kScalingTarget = int64{1} << params.mip_max_activity_exponent(); scaler.wanted_precision = kWantedPrecision; scaler.scaling_target = kScalingTarget; @@ -716,65 +689,64 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, for (const MPGeneralConstraintProto &general_constraint : mp_model.general_constraint()) { switch (general_constraint.general_constraint_case()) { - case MPGeneralConstraintProto::kIndicatorConstraint: { - const auto &indicator_constraint = - general_constraint.indicator_constraint(); - const MPConstraintProto &mp_constraint = - indicator_constraint.constraint(); - ConstraintProto *ct = - scaler.AddConstraint(mp_model, mp_constraint, cp_model); - if (ct == nullptr) - continue; + case MPGeneralConstraintProto::kIndicatorConstraint: { + const auto &indicator_constraint = + general_constraint.indicator_constraint(); + const MPConstraintProto &mp_constraint = + indicator_constraint.constraint(); + ConstraintProto *ct = + scaler.AddConstraint(mp_model, mp_constraint, cp_model); + if (ct == nullptr) continue; - // Add the indicator. - const int var = indicator_constraint.var_index(); - const int value = indicator_constraint.var_value(); - ct->add_enforcement_literal(value == 1 ? var : NegatedRef(var)); - break; - } - case MPGeneralConstraintProto::kAndConstraint: { - const auto &and_constraint = general_constraint.and_constraint(); - const std::string &name = general_constraint.name(); - - ConstraintProto *ct_pos = cp_model->add_constraints(); - ct_pos->set_name(name.empty() ? "" : absl::StrCat(name, "_pos")); - ct_pos->add_enforcement_literal(and_constraint.resultant_var_index()); - *ct_pos->mutable_bool_and()->mutable_literals() = - and_constraint.var_index(); - - ConstraintProto *ct_neg = cp_model->add_constraints(); - ct_neg->set_name(name.empty() ? "" : absl::StrCat(name, "_neg")); - ct_neg->add_enforcement_literal( - NegatedRef(and_constraint.resultant_var_index())); - for (const int var_index : and_constraint.var_index()) { - ct_neg->mutable_bool_or()->add_literals(NegatedRef(var_index)); + // Add the indicator. + const int var = indicator_constraint.var_index(); + const int value = indicator_constraint.var_value(); + ct->add_enforcement_literal(value == 1 ? var : NegatedRef(var)); + break; } - break; - } - case MPGeneralConstraintProto::kOrConstraint: { - const auto &or_constraint = general_constraint.or_constraint(); - const std::string &name = general_constraint.name(); + case MPGeneralConstraintProto::kAndConstraint: { + const auto &and_constraint = general_constraint.and_constraint(); + const std::string &name = general_constraint.name(); - ConstraintProto *ct_pos = cp_model->add_constraints(); - ct_pos->set_name(name.empty() ? "" : absl::StrCat(name, "_pos")); - ct_pos->add_enforcement_literal(or_constraint.resultant_var_index()); - *ct_pos->mutable_bool_or()->mutable_literals() = - or_constraint.var_index(); + ConstraintProto *ct_pos = cp_model->add_constraints(); + ct_pos->set_name(name.empty() ? "" : absl::StrCat(name, "_pos")); + ct_pos->add_enforcement_literal(and_constraint.resultant_var_index()); + *ct_pos->mutable_bool_and()->mutable_literals() = + and_constraint.var_index(); - ConstraintProto *ct_neg = cp_model->add_constraints(); - ct_neg->set_name(name.empty() ? "" : absl::StrCat(name, "_neg")); - ct_neg->add_enforcement_literal( - NegatedRef(or_constraint.resultant_var_index())); - for (const int var_index : or_constraint.var_index()) { - ct_neg->mutable_bool_and()->add_literals(NegatedRef(var_index)); + ConstraintProto *ct_neg = cp_model->add_constraints(); + ct_neg->set_name(name.empty() ? "" : absl::StrCat(name, "_neg")); + ct_neg->add_enforcement_literal( + NegatedRef(and_constraint.resultant_var_index())); + for (const int var_index : and_constraint.var_index()) { + ct_neg->mutable_bool_or()->add_literals(NegatedRef(var_index)); + } + break; } - break; - } - default: - LOG(ERROR) << "Can't convert general constraints of type " - << general_constraint.general_constraint_case() - << " to CpModelProto."; - return false; + case MPGeneralConstraintProto::kOrConstraint: { + const auto &or_constraint = general_constraint.or_constraint(); + const std::string &name = general_constraint.name(); + + ConstraintProto *ct_pos = cp_model->add_constraints(); + ct_pos->set_name(name.empty() ? "" : absl::StrCat(name, "_pos")); + ct_pos->add_enforcement_literal(or_constraint.resultant_var_index()); + *ct_pos->mutable_bool_or()->mutable_literals() = + or_constraint.var_index(); + + ConstraintProto *ct_neg = cp_model->add_constraints(); + ct_neg->set_name(name.empty() ? "" : absl::StrCat(name, "_neg")); + ct_neg->add_enforcement_literal( + NegatedRef(or_constraint.resultant_var_index())); + for (const int var_index : or_constraint.var_index()) { + ct_neg->mutable_bool_and()->add_literals(NegatedRef(var_index)); + } + break; + } + default: + LOG(ERROR) << "Can't convert general constraints of type " + << general_constraint.general_constraint_case() + << " to CpModelProto."; + return false; } } @@ -788,8 +760,8 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, << (scaler.max_relative_rhs_error > params.mip_check_precision() ? " [Potentially IMPRECISE]" : ""); - LOG_IF(INFO, log_info) - << "Maximum constraint scaling factor: " << scaler.max_scaling_factor; + LOG_IF(INFO, log_info) << "Maximum constraint scaling factor: " + << scaler.max_scaling_factor; // Add the objective. std::vector var_indices; @@ -801,14 +773,12 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, double l1_norm = 0.0; for (int i = 0; i < num_variables; ++i) { const MPVariableProto &mp_var = mp_model.variable(i); - if (mp_var.objective_coefficient() == 0.0) - continue; + if (mp_var.objective_coefficient() == 0.0) continue; const auto &var_proto = cp_model->variables(i); const int64 lb = var_proto.domain(0); const int64 ub = var_proto.domain(var_proto.domain_size() - 1); - if (lb == 0 && ub == 0) - continue; + if (lb == 0 && ub == 0) continue; var_indices.push_back(i); coefficients.push_back(mp_var.objective_coefficient()); @@ -840,8 +810,7 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, for (; x <= scaling_factor; x *= 2) { ComputeScalingErrors(coefficients, lower_bounds, upper_bounds, x, &relative_coeff_error, &scaled_sum_error); - if (scaled_sum_error < kWantedPrecision * x) - break; + if (scaled_sum_error < kWantedPrecision * x) break; } scaling_factor = x; @@ -863,11 +832,10 @@ bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, << "objective coefficient relative error: " << relative_coeff_error << (relative_coeff_error > params.mip_check_precision() ? " [IMPRECISE]" : ""); - LOG_IF(INFO, log_info) - << "objective worst-case absolute error: " << scaled_sum_error / - scaling_factor; - LOG_IF(INFO, log_info) - << "objective scaling factor: " << scaling_factor / gcd; + LOG_IF(INFO, log_info) << "objective worst-case absolute error: " + << scaled_sum_error / scaling_factor; + LOG_IF(INFO, log_info) << "objective scaling factor: " + << scaling_factor / gcd; // Note that here we set the scaling factor for the inverse operation of // getting the "true" objective value from the scaled one. Hence the @@ -912,10 +880,8 @@ bool ConvertBinaryMPModelProtoToBooleanProblem(const MPModelProto &mp_model, const Fractional lb = mp_var.lower_bound(); const Fractional ub = mp_var.upper_bound(); - if (lb <= -1.0) - is_binary = false; - if (ub >= 2.0) - is_binary = false; + if (lb <= -1.0) is_binary = false; + if (ub >= 2.0) is_binary = false; if (is_binary) { // 4 cases. if (lb <= 0.0 && ub >= 1.0) { @@ -1046,8 +1012,9 @@ bool ConvertBinaryMPModelProtoToBooleanProblem(const MPModelProto &mp_model, objective->set_scaling_factor(1.0 / scaling_factor * gcd); for (int var_id = 0; var_id < num_variables; ++var_id) { const MPVariableProto &mp_var = mp_model.variable(var_id); - const int64 value = static_cast( - round(mp_var.objective_coefficient() * scaling_factor)) / gcd; + const int64 value = static_cast(round( + mp_var.objective_coefficient() * scaling_factor)) / + gcd; if (value != 0) { objective->add_literals(var_id + 1); objective->add_coefficients(value); @@ -1055,8 +1022,7 @@ bool ConvertBinaryMPModelProtoToBooleanProblem(const MPModelProto &mp_model, } // If the problem was a maximization one, we need to modify the objective. - if (mp_model.maximize()) - ChangeOptimizationDirection(problem); + if (mp_model.maximize()) ChangeOptimizationDirection(problem); // Test the precision of the conversion. const double kRelativeTolerance = 1e-8; @@ -1146,10 +1112,9 @@ int FixVariablesFromSat(const SatSolver &solver, glop::LinearProgram *lp) { return num_fixed_variables; } -bool -SolveLpAndUseSolutionForSatAssignmentPreference(const glop::LinearProgram &lp, - SatSolver *sat_solver, - double max_time_in_seconds) { +bool SolveLpAndUseSolutionForSatAssignmentPreference( + const glop::LinearProgram &lp, SatSolver *sat_solver, + double max_time_in_seconds) { glop::LPSolver solver; glop::GlopParameters glop_parameters; glop_parameters.set_max_time_in_seconds(max_time_in_seconds); @@ -1200,5 +1165,5 @@ bool SolveLpAndUseIntegerVariableToStartLNS(const glop::LinearProgram &lp, return true; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/lp_utils.h b/ortools/sat/lp_utils.h index d0d9ed6e32..1b4f5ac9bf 100644 --- a/ortools/sat/lp_utils.h +++ b/ortools/sat/lp_utils.h @@ -102,7 +102,7 @@ bool SolveLpAndUseSolutionForSatAssignmentPreference( bool SolveLpAndUseIntegerVariableToStartLNS(const glop::LinearProgram &lp, LinearBooleanProblem *problem); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_LP_UTILS_H_ +#endif // OR_TOOLS_SAT_LP_UTILS_H_ diff --git a/ortools/sat/model.h b/ortools/sat/model.h index 664b5e9920..2871c8083e 100644 --- a/ortools/sat/model.h +++ b/ortools/sat/model.h @@ -36,7 +36,7 @@ namespace sat { * constraints, watchers, solvers and provide a mecanism to wire them together. */ class Model { -public: + public: Model() {} ~Model() { @@ -77,10 +77,14 @@ public: const IntegerVariable i = model.Add(NewWeightedSum(weights, variables)); \endcode */ - template T Add(std::function f) { return f(this); } + template + T Add(std::function f) { + return f(this); + } /// Similar to Add() but this is const. - template T Get(std::function f) const { + template + T Get(std::function f) const { return f(*this); } @@ -98,7 +102,8 @@ public: * IMPORTANT: the Model* constructor functions shouldn't form a cycle between * each other, otherwise this will crash the program. */ - template T *GetOrCreate() { + template + T *GetOrCreate() { const size_t type_id = gtl::FastTypeId(); auto find = singletons_.find(type_id); if (find != singletons_.end()) { @@ -118,7 +123,8 @@ public: * * This returns a const version of the object. */ - template const T *Get() const { + template + const T *Get() const { return static_cast( gtl::FindWithDefault(singletons_, gtl::FastTypeId(), nullptr)); } @@ -126,7 +132,8 @@ public: /** * Same as Get(), but returns a mutable version of the object. */ - template T *Mutable() const { + template + T *Mutable() const { return static_cast( gtl::FindWithDefault(singletons_, gtl::FastTypeId(), nullptr)); } @@ -136,7 +143,8 @@ public: * * It will be destroyed when the model is. */ - template void TakeOwnership(T *t) { + template + void TakeOwnership(T *t) { cleanup_list_.emplace_back(new Delete(t)); } @@ -145,7 +153,8 @@ public: * T(Model* model) constructor if it exist or the T() constructor otherwise. * It is just a shortcut to new + TakeOwnership(). */ - template T *Create() { + template + T *Create() { T *new_t = MyNew(0); TakeOwnership(new_t); return new_t; @@ -156,7 +165,8 @@ public: * * It is an error to call this on an already registered class. */ - template void Register(T *non_owned_class) { + template + void Register(T *non_owned_class) { const size_t type_id = gtl::FastTypeId(); CHECK(!gtl::ContainsKey(singletons_, type_id)); singletons_[type_id] = non_owned_class; @@ -164,17 +174,20 @@ public: const std::string &Name() const { return name_; } -private: + private: // We want to call the constructor T(model*) if it exists or just T() if // it doesn't. For this we use some template "magic": // - The first MyNew() will only be defined if the type in decltype() exist. // - The second MyNew() will always be defined, but because of the ellipsis // it has lower priority that the first one. template - decltype(T(static_cast(nullptr))) * MyNew(int) { + decltype(T(static_cast(nullptr))) *MyNew(int) { return new T(this); } - template T *MyNew(...) { return new T(); } + template + T *MyNew(...) { + return new T(); + } const std::string name_; @@ -184,12 +197,13 @@ private: struct DeleteInterface { virtual ~DeleteInterface() = default; }; - template class Delete : public DeleteInterface { - public: + template + class Delete : public DeleteInterface { + public: explicit Delete(T *t) : to_delete_(t) {} ~Delete() override = default; - private: + private: std::unique_ptr to_delete_; }; @@ -203,7 +217,7 @@ private: DISALLOW_COPY_AND_ASSIGN(Model); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_MODEL_H_ +#endif // OR_TOOLS_SAT_MODEL_H_ diff --git a/ortools/sat/optimization.cc b/ortools/sat/optimization.cc index c0e47c4764..f19e8e3e0f 100644 --- a/ortools/sat/optimization.cc +++ b/ortools/sat/optimization.cc @@ -37,7 +37,7 @@ #if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP) #include "ortools/linear_solver/linear_solver.h" #include "ortools/linear_solver/linear_solver.pb.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ #include "ortools/base/random.h" #include "ortools/port/proto_utils.h" #include "ortools/sat/boolean_problem.h" @@ -56,7 +56,7 @@ namespace { // Used to log messages to stdout or to the normal logging framework according // to the given LogBehavior value. class Logger { -public: + public: explicit Logger(LogBehavior v) : use_stdout_(v == STDOUT_LOG) {} void Log(const std::string &message) { if (use_stdout_) { @@ -66,7 +66,7 @@ public: } } -private: + private: bool use_stdout_; }; @@ -133,7 +133,7 @@ void DeleteVectorIndices(const std::vector &indices, Vector *v) { // Reference: C Ansótegui, ML Bonet, J Levy, "Sat-based maxsat algorithms", // Artificial Intelligence, 2013 - Elsevier. class FuMalikSymmetryBreaker { -public: + public: FuMalikSymmetryBreaker() {} // Must be called before a new core is processed. @@ -181,8 +181,8 @@ public: info_by_assumption_index_[assumption_index]) { literal_by_core_[data.core_index].push_back(data.literal); } - info_by_assumption_index_[assumption_index] - .push_back(LiteralWithCoreIndex(b, literal_by_core_.size())); + info_by_assumption_index_[assumption_index].push_back( + LiteralWithCoreIndex(b, literal_by_core_.size())); return result; } @@ -202,23 +202,22 @@ public: void AddInfo(int assumption_index, Literal b) { CHECK_GE(assumption_index, info_by_assumption_index_.size()); info_by_assumption_index_.resize(assumption_index + 1); - info_by_assumption_index_[assumption_index] - .push_back(LiteralWithCoreIndex(b, literal_by_core_.size())); + info_by_assumption_index_[assumption_index].push_back( + LiteralWithCoreIndex(b, literal_by_core_.size())); } -private: + private: std::vector > info_by_assumption_index_; std::vector > literal_by_core_; DISALLOW_COPY_AND_ASSIGN(FuMalikSymmetryBreaker); }; -} // namespace +} // namespace void MinimizeCoreWithPropagation(SatSolver *solver, std::vector *core) { - if (solver->IsModelUnsat()) - return; + if (solver->IsModelUnsat()) return; std::set moved_last; std::vector candidate(core->begin(), core->end()); @@ -231,8 +230,7 @@ void MinimizeCoreWithPropagation(SatSolver *solver, // decision/progagation we need to perform. const int target_level = MoveOneUnprocessedLiteralLast( moved_last, solver->CurrentDecisionLevel(), &candidate); - if (target_level == -1) - break; + if (target_level == -1) break; solver->Backtrack(target_level); while (!solver->IsModelUnsat() && solver->CurrentDecisionLevel() < candidate.size()) { @@ -250,8 +248,7 @@ void MinimizeCoreWithPropagation(SatSolver *solver, solver->EnqueueDecisionAndBackjumpOnConflict(decision); } } - if (candidate.empty() || solver->IsModelUnsat()) - return; + if (candidate.empty() || solver->IsModelUnsat()) return; moved_last.insert(candidate.back().Index()); } @@ -334,8 +331,7 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, logger.Log(CnfObjectiveLine(problem, objective)); return SatSolver::FEASIBLE; } - if (result != SatSolver::ASSUMPTIONS_UNSAT) - return result; + if (result != SatSolver::ASSUMPTIONS_UNSAT) return result; // The interesting case: we have an unsat core. // @@ -354,8 +350,9 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, if (core.size() == 1) { // Find the index of the "objective" variable that need to be fixed in // its "costly" state. - const int index = std::find(assumptions.begin(), assumptions.end(), - core[0]) - assumptions.begin(); + const int index = + std::find(assumptions.begin(), assumptions.end(), core[0]) - + assumptions.begin(); CHECK_LT(index, assumptions.size()); // Fix it. We also fix all the associated blocking variables if any. @@ -363,8 +360,7 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, return SatSolver::INFEASIBLE; } for (Literal b : blocking_clauses[index]) { - if (!solver->AddUnitClause(b.Negated())) - return SatSolver::INFEASIBLE; + if (!solver->AddUnitClause(b.Negated())) return SatSolver::INFEASIBLE; } // Erase this entry from the current "objective" @@ -400,8 +396,9 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, // Since the assumptions appear in order in the core, we can find the // relevant "objective" variable efficiently with a simple linear scan // in the assumptions vector (done with index). - index = std::find(assumptions.begin() + index, assumptions.end(), - core[i]) - assumptions.begin(); + index = + std::find(assumptions.begin() + index, assumptions.end(), core[i]) - + assumptions.begin(); CHECK_LT(index, assumptions.size()); // The new blocking and assumption variables for this core entry. @@ -409,8 +406,7 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, Literal b(BooleanVariable(old_num_variables + core.size() + i), true); if (core.size() == 2) { b = Literal(BooleanVariable(old_num_variables + 2), true); - if (i == 1) - b = b.Negated(); + if (i == 1) b = b.Negated(); } // Symmetry breaking clauses. @@ -454,7 +450,7 @@ SatSolver::Status SolveWithFuMalik(LogBehavior log, // TODO(user): The algorithm does not really need the >= 1 side of this // constraint. Initial investigation shows that it doesn't really help, // but investigate more. - if (/* DISABLES CODE */(false)) { + if (/* DISABLES CODE */ (false)) { ok &= solver->AddProblemClause(at_least_one_constraint); } @@ -583,12 +579,10 @@ SatSolver::Status SolveWithWPM1(LogBehavior log, upper_bound = objective + objective_offset; } - if (stratified_lower_bound < old_lower_bound) - continue; + if (stratified_lower_bound < old_lower_bound) continue; return SatSolver::FEASIBLE; } - if (result != SatSolver::ASSUMPTIONS_UNSAT) - return result; + if (result != SatSolver::ASSUMPTIONS_UNSAT) return result; // The interesting case: we have an unsat core. // @@ -606,8 +600,9 @@ SatSolver::Status SolveWithWPM1(LogBehavior log, { int index = 0; for (int i = 0; i < core.size(); ++i) { - index = std::find(assumptions.begin() + index, assumptions.end(), - core[i]) - assumptions.begin(); + index = + std::find(assumptions.begin() + index, assumptions.end(), core[i]) - + assumptions.begin(); CHECK_LT(index, assumptions.size()); min_cost = std::min(min_cost, costs[index]); } @@ -631,8 +626,9 @@ SatSolver::Status SolveWithWPM1(LogBehavior log, if (core.size() == 1) { // Find the index of the "objective" variable that need to be fixed in // its "costly" state. - const int index = std::find(assumptions.begin(), assumptions.end(), - core[0]) - assumptions.begin(); + const int index = + std::find(assumptions.begin(), assumptions.end(), core[0]) - + assumptions.begin(); CHECK_LT(index, assumptions.size()); // Fix it. @@ -674,8 +670,9 @@ SatSolver::Status SolveWithWPM1(LogBehavior log, // Since the assumptions appear in order in the core, we can find the // relevant "objective" variable efficiently with a simple linear scan // in the assumptions vector (done with index). - index = std::find(assumptions.begin() + index, assumptions.end(), - core[i]) - assumptions.begin(); + index = + std::find(assumptions.begin() + index, assumptions.end(), core[i]) - + assumptions.begin(); CHECK_LT(index, assumptions.size()); // The new blocking and assumption variables for this core entry. @@ -683,8 +680,7 @@ SatSolver::Status SolveWithWPM1(LogBehavior log, Literal b(BooleanVariable(old_num_variables + core.size() + i), true); if (core.size() == 2) { b = Literal(BooleanVariable(old_num_variables + 2), true); - if (i == 1) - b = b.Negated(); + if (i == 1) b = b.Negated(); } // a false & b false => previous assumptions (which was false). @@ -793,24 +789,20 @@ SatSolver::Status SolveWithRandomParameters(LogBehavior log, solver->ResetDecisionHeuristic(); const bool use_obj = absl::Bernoulli(random, 1.0 / 4); - if (use_obj) - UseObjectiveForSatAssignmentPreference(problem, solver); + if (use_obj) UseObjectiveForSatAssignmentPreference(problem, solver); const SatSolver::Status result = solver->Solve(); if (result == SatSolver::INFEASIBLE) { // If the problem is INFEASIBLE after we over-constrained the objective, // then we found an optimal solution, otherwise, even the decision problem // is INFEASIBLE. - if (best == kCoefficientMax) - return SatSolver::INFEASIBLE; + if (best == kCoefficientMax) return SatSolver::INFEASIBLE; return SatSolver::FEASIBLE; } if (result == SatSolver::LIMIT_REACHED) { // We augment the number of conflict until we have one feasible solution. - if (best == kCoefficientMax) - ++max_number_of_conflicts; - if (time_limit.LimitReached()) - return SatSolver::LIMIT_REACHED; + if (best == kCoefficientMax) ++max_number_of_conflicts; + if (time_limit.LimitReached()) return SatSolver::LIMIT_REACHED; continue; } @@ -834,10 +826,10 @@ SatSolver::Status SolveWithRandomParameters(LogBehavior log, min_seen = std::min(min_seen, objective); max_seen = std::max(max_seen, objective); - logger.Log(absl::StrCat("c ", objective.value(), " [", min_seen.value(), - ", ", max_seen.value(), "] objective_preference: ", - use_obj ? "true" : "false", " ", - ProtobufShortDebugString(parameters))); + logger.Log(absl::StrCat( + "c ", objective.value(), " [", min_seen.value(), ", ", max_seen.value(), + "] objective_preference: ", use_obj ? "true" : "false", " ", + ProtobufShortDebugString(parameters))); } // Retore the initial parameter (with an updated time limit). @@ -875,8 +867,7 @@ SatSolver::Status SolveWithLinearScan(LogBehavior log, const SatSolver::Status result = solver->Solve(); CHECK_NE(result, SatSolver::ASSUMPTIONS_UNSAT); if (result == SatSolver::INFEASIBLE) { - if (objective == kCoefficientMax) - return SatSolver::INFEASIBLE; + if (objective == kCoefficientMax) return SatSolver::INFEASIBLE; return SatSolver::FEASIBLE; } if (result == SatSolver::LIMIT_REACHED) { @@ -894,10 +885,9 @@ SatSolver::Status SolveWithLinearScan(LogBehavior log, } } -SatSolver::Status -SolveWithCardinalityEncoding(LogBehavior log, - const LinearBooleanProblem &problem, - SatSolver *solver, std::vector *solution) { +SatSolver::Status SolveWithCardinalityEncoding( + LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, + std::vector *solution) { Logger logger(log); std::deque repository; @@ -909,8 +899,7 @@ SolveWithCardinalityEncoding(LogBehavior log, // This algorithm only work with weights of the same magnitude. CHECK(!nodes.empty()); const Coefficient reference = nodes.front()->weight(); - for (const EncodingNode *n : nodes) - CHECK_EQ(n->weight(), reference); + for (const EncodingNode *n : nodes) CHECK_EQ(n->weight(), reference); // Initialize the current objective. Coefficient objective = kCoefficientMax; @@ -922,9 +911,9 @@ SolveWithCardinalityEncoding(LogBehavior log, } // Print the number of variables with a non-zero cost. - logger.Log( - absl::StrFormat("c #weights:%u #vars:%d #constraints:%d", nodes.size(), - problem.num_variables(), problem.constraints_size())); + logger.Log(absl::StrFormat("c #weights:%u #vars:%d #constraints:%d", + nodes.size(), problem.num_variables(), + problem.constraints_size())); // Create the sorter network. solver->Backtrack(0); @@ -937,8 +926,7 @@ SolveWithCardinalityEncoding(LogBehavior log, // Over constrain the objective by fixing the variable index - 1 of the // root node to 0. const int index = offset.value() + objective.value(); - if (index == 0) - return SatSolver::FEASIBLE; + if (index == 0) return SatSolver::FEASIBLE; solver->Backtrack(0); if (!solver->AddUnitClause(root->literal(index - 1).Negated())) { return SatSolver::FEASIBLE; @@ -949,12 +937,10 @@ SolveWithCardinalityEncoding(LogBehavior log, const SatSolver::Status result = solver->Solve(); CHECK_NE(result, SatSolver::ASSUMPTIONS_UNSAT); if (result == SatSolver::INFEASIBLE) { - if (objective == kCoefficientMax) - return SatSolver::INFEASIBLE; + if (objective == kCoefficientMax) return SatSolver::INFEASIBLE; return SatSolver::FEASIBLE; } - if (result == SatSolver::LIMIT_REACHED) - return SatSolver::LIMIT_REACHED; + if (result == SatSolver::LIMIT_REACHED) return SatSolver::LIMIT_REACHED; // Extract the new best solution. CHECK_EQ(result, SatSolver::FEASIBLE); @@ -989,9 +975,9 @@ SatSolver::Status SolveWithCardinalityEncodingAndCore( } // Print the number of variables with a non-zero cost. - logger.Log( - absl::StrFormat("c #weights:%u #vars:%d #constraints:%d", nodes.size(), - problem.num_variables(), problem.constraints_size())); + logger.Log(absl::StrFormat("c #weights:%u #vars:%d #constraints:%d", + nodes.size(), problem.num_variables(), + problem.constraints_size())); // This is used by the "stratified" approach. Coefficient stratified_lower_bound(0); @@ -1009,8 +995,7 @@ SatSolver::Status SolveWithCardinalityEncodingAndCore( for (int iter = 0;; ++iter) { const std::vector assumptions = ReduceNodesAndExtractAssumptions( upper_bound, stratified_lower_bound, &lower_bound, &nodes, solver); - if (assumptions.empty()) - return SatSolver::FEASIBLE; + if (assumptions.empty()) return SatSolver::FEASIBLE; // Display the progress. const std::string gap_string = @@ -1043,17 +1028,14 @@ SatSolver::Status SolveWithCardinalityEncodingAndCore( // bound. Otherwise we have an optimal solution. stratified_lower_bound = MaxNodeWeightSmallerThan(nodes, stratified_lower_bound); - if (stratified_lower_bound > 0) - continue; + if (stratified_lower_bound > 0) continue; return SatSolver::FEASIBLE; } - if (result != SatSolver::ASSUMPTIONS_UNSAT) - return result; + if (result != SatSolver::ASSUMPTIONS_UNSAT) return result; // We have a new core. std::vector core = solver->GetLastIncompatibleDecisions(); - if (parameters.minimize_core()) - MinimizeCore(solver, &core); + if (parameters.minimize_core()) MinimizeCore(solver, &core); // Compute the min weight of all the nodes in the core. // The lower bound will be increased by that much. @@ -1083,8 +1065,7 @@ SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding( // Simple linear scan algorithm to find the optimal. while (true) { const SatSolver::Status result = SolveIntegerProblem(model); - if (result != SatSolver::FEASIBLE) - return result; + if (result != SatSolver::FEASIBLE) return result; // The objective is the current lower bound of the objective_var. const IntegerValue objective = integer_trail->LowerBound(objective_var); @@ -1100,10 +1081,8 @@ SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding( // Restrict the objective. sat_solver->Backtrack(0); if (!integer_trail->Enqueue( - IntegerLiteral::LowerOrEqual(objective_var, objective - 1), { - }, - { - })) { + IntegerLiteral::LowerOrEqual(objective_var, objective - 1), {}, + {})) { return SatSolver::INFEASIBLE; } } @@ -1154,57 +1133,48 @@ void RestrictObjectiveDomainWithBinarySearch( if (target < ub) { const Literal assumption = integer_encoder->GetOrCreateAssociatedLiteral( IntegerLiteral::LowerOrEqual(objective_var, target)); - result = ResetAndSolveIntegerProblem({ - assumption - }, - model); + result = ResetAndSolveIntegerProblem({assumption}, model); } else { - result = ResetAndSolveIntegerProblem({ - }, - model); + result = ResetAndSolveIntegerProblem({}, model); } switch (result) { - case SatSolver::INFEASIBLE: { - loop = false; - break; - } - case SatSolver::ASSUMPTIONS_UNSAT: { - // Update the objective lower bound. - sat_solver->Backtrack(0); - if (!integer_trail->Enqueue( - IntegerLiteral::GreaterOrEqual(objective_var, target + 1), { - }, - { - })) { + case SatSolver::INFEASIBLE: { loop = false; + break; } - break; - } - case SatSolver::FEASIBLE: { - // The objective is the current lower bound of the objective_var. - const IntegerValue objective = integer_trail->LowerBound(objective_var); - if (feasible_solution_observer != nullptr) { - feasible_solution_observer(); + case SatSolver::ASSUMPTIONS_UNSAT: { + // Update the objective lower bound. + sat_solver->Backtrack(0); + if (!integer_trail->Enqueue( + IntegerLiteral::GreaterOrEqual(objective_var, target + 1), {}, + {})) { + loop = false; + } + break; } + case SatSolver::FEASIBLE: { + // The objective is the current lower bound of the objective_var. + const IntegerValue objective = integer_trail->LowerBound(objective_var); + if (feasible_solution_observer != nullptr) { + feasible_solution_observer(); + } - // We have a solution, restrict the objective upper bound to only look - // for better ones now. - sat_solver->Backtrack(0); - if (!integer_trail->Enqueue( - IntegerLiteral::LowerOrEqual(objective_var, objective - 1), { - }, - { - })) { - loop = false; + // We have a solution, restrict the objective upper bound to only look + // for better ones now. + sat_solver->Backtrack(0); + if (!integer_trail->Enqueue( + IntegerLiteral::LowerOrEqual(objective_var, objective - 1), {}, + {})) { + loop = false; + } + break; + } + case SatSolver::LIMIT_REACHED: { + unknown_min = std::min(target, unknown_min); + unknown_max = std::max(target, unknown_max); + break; } - break; - } - case SatSolver::LIMIT_REACHED: { - unknown_min = std::min(target, unknown_min); - unknown_max = std::max(target, unknown_max); - break; - } } } @@ -1243,21 +1213,18 @@ SatSolver::Status FindCores(std::vector assumptions, SatSolver *sat_solver = model->GetOrCreate(); TimeLimit *limit = model->GetOrCreate(); do { - if (limit->LimitReached()) - return SatSolver::LIMIT_REACHED; + if (limit->LimitReached()) return SatSolver::LIMIT_REACHED; const SatSolver::Status result = ResetAndSolveIntegerProblem(assumptions, model); - if (result != SatSolver::ASSUMPTIONS_UNSAT) - return result; + if (result != SatSolver::ASSUMPTIONS_UNSAT) return result; std::vector core = sat_solver->GetLastIncompatibleDecisions(); if (sat_solver->parameters().minimize_core()) { MinimizeCoreWithPropagation(sat_solver, &core); } CHECK(!core.empty()); cores->push_back(core); - if (!sat_solver->parameters().find_multiple_cores()) - break; + if (!sat_solver->parameters().find_multiple_cores()) break; // Recover the original indices of the assumptions that are part of the // core. @@ -1288,8 +1255,7 @@ SatSolver::Status FindCores(std::vector assumptions, // current stratification threshold and see if we can find another core. int new_size = 0; for (int i = 0; i < assumptions.size(); ++i) { - if (assumption_weights[i] < stratified_threshold) - continue; + if (assumption_weights[i] < stratified_threshold) continue; assumptions[new_size] = assumptions[i]; assumption_weights[new_size] = assumption_weights[i]; ++new_size; @@ -1302,28 +1268,25 @@ SatSolver::Status FindCores(std::vector assumptions, // Slightly different algo than FindCores() which aim to extract more cores, but // not necessarily non-overlaping ones. -SatSolver::Status -FindMultipleCoresForMaxHs(std::vector assumptions, Model *model, - std::vector > *cores) { +SatSolver::Status FindMultipleCoresForMaxHs( + std::vector assumptions, Model *model, + std::vector > *cores) { cores->clear(); SatSolver *sat_solver = model->GetOrCreate(); TimeLimit *limit = model->GetOrCreate(); do { - if (limit->LimitReached()) - return SatSolver::LIMIT_REACHED; + if (limit->LimitReached()) return SatSolver::LIMIT_REACHED; const SatSolver::Status result = ResetAndSolveIntegerProblem(assumptions, model); - if (result != SatSolver::ASSUMPTIONS_UNSAT) - return result; + if (result != SatSolver::ASSUMPTIONS_UNSAT) return result; std::vector core = sat_solver->GetLastIncompatibleDecisions(); if (sat_solver->parameters().minimize_core()) { MinimizeCoreWithPropagation(sat_solver, &core); } CHECK(!core.empty()); cores->push_back(core); - if (!sat_solver->parameters().find_multiple_cores()) - break; + if (!sat_solver->parameters().find_multiple_cores()) break; // Pick a random literal from the core and remove it from the set of // assumptions. @@ -1342,7 +1305,7 @@ FindMultipleCoresForMaxHs(std::vector assumptions, Model *model, return SatSolver::ASSUMPTIONS_UNSAT; } -} // namespace +} // namespace CoreBasedOptimizer::CoreBasedOptimizer( IntegerVariable objective_var, @@ -1353,21 +1316,18 @@ CoreBasedOptimizer::CoreBasedOptimizer( sat_solver_(model->GetOrCreate()), time_limit_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()), - integer_encoder_(model->GetOrCreate()), model_(model), + integer_encoder_(model->GetOrCreate()), + model_(model), objective_var_(objective_var), feasible_solution_observer_(std::move(feasible_solution_observer)) { CHECK_EQ(variables.size(), coefficients.size()); for (int i = 0; i < variables.size(); ++i) { if (coefficients[i] > 0) { - terms_.push_back({ - variables[i], coefficients[i] - }); + terms_.push_back({variables[i], coefficients[i]}); } else if (coefficients[i] < 0) { - terms_.push_back({ - NegationOf(variables[i]), -coefficients[i] - }); + terms_.push_back({NegationOf(variables[i]), -coefficients[i]}); } else { - continue; // coefficients[i] == 0 + continue; // coefficients[i] == 0 } terms_.back().depth = 0; } @@ -1414,10 +1374,7 @@ bool CoreBasedOptimizer::ProcessSolution() { sat_solver_->Backtrack(0); sat_solver_->SetAssumptionLevel(0); return integer_trail_->Enqueue( - IntegerLiteral::LowerOrEqual(objective_var_, objective - 1), { - }, - { - }); + IntegerLiteral::LowerOrEqual(objective_var_, objective - 1), {}, {}); } bool CoreBasedOptimizer::PropagateObjectiveBounds() { @@ -1425,8 +1382,7 @@ bool CoreBasedOptimizer::PropagateObjectiveBounds() { bool some_bound_were_tightened = true; while (some_bound_were_tightened) { some_bound_were_tightened = false; - if (!sat_solver_->ResetToLevelZero()) - return false; + if (!sat_solver_->ResetToLevelZero()) return false; // Compute implied lb. IntegerValue implied_objective_lb(0); @@ -1440,10 +1396,7 @@ bool CoreBasedOptimizer::PropagateObjectiveBounds() { if (implied_objective_lb > integer_trail_->LowerBound(objective_var_)) { if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual( objective_var_, implied_objective_lb), - { - }, - { - })) { + {}, {})) { return false; } @@ -1460,12 +1413,10 @@ bool CoreBasedOptimizer::PropagateObjectiveBounds() { integer_trail_->UpperBound(objective_var_) - implied_objective_lb; for (const ObjectiveTerm &term : terms_) { - if (term.weight == 0) - continue; + if (term.weight == 0) continue; const IntegerValue var_lb = integer_trail_->LowerBound(term.var); const IntegerValue var_ub = integer_trail_->UpperBound(term.var); - if (var_lb == var_ub) - continue; + if (var_lb == var_ub) continue; // Hardening. This basically just propagate the implied upper bound on // term.var from the current best solution. Note that the gap is @@ -1478,10 +1429,7 @@ bool CoreBasedOptimizer::PropagateObjectiveBounds() { CHECK_LT(new_ub, var_ub); CHECK(!integer_trail_->IsCurrentlyIgnored(term.var)); if (!integer_trail_->Enqueue( - IntegerLiteral::LowerOrEqual(term.var, new_ub), { - }, - { - })) { + IntegerLiteral::LowerOrEqual(term.var, new_ub), {}, {})) { return false; } } @@ -1502,15 +1450,12 @@ bool CoreBasedOptimizer::PropagateObjectiveBounds() { void CoreBasedOptimizer::ComputeNextStratificationThreshold() { std::vector weights; for (ObjectiveTerm &term : terms_) { - if (term.weight >= stratification_threshold_) - continue; - if (term.weight == 0) - continue; + if (term.weight >= stratification_threshold_) continue; + if (term.weight == 0) continue; const IntegerValue var_lb = integer_trail_->LevelZeroLowerBound(term.var); const IntegerValue var_ub = integer_trail_->LevelZeroUpperBound(term.var); - if (var_lb == var_ub) - continue; + if (var_lb == var_ub) continue; weights.push_back(term.weight); } @@ -1538,8 +1483,7 @@ bool CoreBasedOptimizer::CoverOptimization() { // We currently skip the initial objective terms as there could be many // of them. TODO(user): provide an option to cover-optimize them? I // fear that this will slow down the solver too much though. - if (term.depth == 0) - continue; + if (term.depth == 0) continue; // Find out the true lower bound of var. This is called "cover // optimization" in some of the max-SAT literature. It can helps on some @@ -1552,8 +1496,7 @@ bool CoreBasedOptimizer::CoverOptimization() { // Note(user): this can happen in some corner case because each time we // find a solution, we constrain the objective to be smaller than it, so // it is possible that a previous best is now infeasible. - if (best <= integer_trail_->LowerBound(var)) - continue; + if (best <= integer_trail_->LowerBound(var)) continue; // Compute the global deterministic time for this core cover // optimization. @@ -1565,42 +1508,32 @@ bool CoreBasedOptimizer::CoverOptimization() { while (best > integer_trail_->LowerBound(var)) { const Literal assumption = integer_encoder_->GetOrCreateAssociatedLiteral( IntegerLiteral::LowerOrEqual(var, best - 1)); - result = ResetAndSolveIntegerProblem({ - assumption - }, - model_); - if (result != SatSolver::FEASIBLE) - break; + result = ResetAndSolveIntegerProblem({assumption}, model_); + if (result != SatSolver::FEASIBLE) break; best = integer_trail_->LowerBound(var); VLOG(1) << "cover_opt var:" << var << " domain:[" << integer_trail_->LevelZeroLowerBound(var) << "," << best << "]"; - if (!ProcessSolution()) - return false; - if (!sat_solver_->ResetToLevelZero()) - return false; + if (!ProcessSolution()) return false; + if (!sat_solver_->ResetToLevelZero()) return false; if (stop_ || time_limit_->GetElapsedDeterministicTime() > deterministic_limit) { break; } } - if (result == SatSolver::INFEASIBLE) - return false; + if (result == SatSolver::INFEASIBLE) return false; if (result == SatSolver::ASSUMPTIONS_UNSAT) { // TODO(user): If we improve the lower bound of var, we should check // if our global lower bound reached our current best solution in // order to abort early if the optimal is proved. - if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(var, best), { - }, - { - })) { + if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(var, best), + {}, {})) { return false; } } } - if (!PropagateObjectiveBounds()) - return false; + if (!PropagateObjectiveBounds()) return false; return true; } @@ -1616,18 +1549,15 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { while (true) { // TODO(user): This always resets the solver to level zero. // Because of that we don't resume a solve in "chunk" perfectly. Fix. - if (!PropagateObjectiveBounds()) - return SatSolver::INFEASIBLE; + if (!PropagateObjectiveBounds()) return SatSolver::INFEASIBLE; // Bulk cover optimization. // // TODO(user): If the search is aborted during this phase and we solve in // "chunk", we don't resume perfectly from where it was. Fix. if (parameters_->cover_optimization()) { - if (!CoverOptimization()) - return SatSolver::INFEASIBLE; - if (stop_) - return SatSolver::LIMIT_REACHED; + if (!CoverOptimization()) return SatSolver::INFEASIBLE; + if (stop_) return SatSolver::LIMIT_REACHED; } // We assumes all terms (modulo stratification) at their lower-bound. @@ -1640,8 +1570,7 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { const ObjectiveTerm term = terms_[i]; // TODO(user): These can be simply removed from the list. - if (term.weight == 0) - continue; + if (term.weight == 0) continue; // Skip fixed terms. // We still keep them around for a proper lower-bound computation. @@ -1705,8 +1634,9 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { ? 0 : static_cast(std::ceil( 100.0 * (ub - lb) / std::max(std::abs(ub), std::abs(lb)))); - VLOG(1) << absl::StrCat("unscaled_next_obj_range:[", lb, ",", ub, "]" - " gap:", + VLOG(1) << absl::StrCat("unscaled_next_obj_range:[", lb, ",", ub, + "]" + " gap:", gap, "%", " assumptions:", term_indices.size(), " strat:", stratification_threshold_.value(), " depth:", max_depth); @@ -1737,30 +1667,24 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { const SatSolver::Status result = FindCores(assumptions, assumption_weights, stratification_threshold_, model_, &cores); - if (result == SatSolver::INFEASIBLE) - return SatSolver::INFEASIBLE; + if (result == SatSolver::INFEASIBLE) return SatSolver::INFEASIBLE; if (result == SatSolver::FEASIBLE) { - if (!ProcessSolution()) - return SatSolver::INFEASIBLE; - if (stop_) - return SatSolver::LIMIT_REACHED; + if (!ProcessSolution()) return SatSolver::INFEASIBLE; + if (stop_) return SatSolver::LIMIT_REACHED; if (cores.empty()) { ComputeNextStratificationThreshold(); - if (stratification_threshold_ == 0) - return SatSolver::INFEASIBLE; + if (stratification_threshold_ == 0) return SatSolver::INFEASIBLE; continue; } } // Process the cores by creating new variables and transferring the minimum // weight of each core to it. - if (!sat_solver_->ResetToLevelZero()) - return SatSolver::INFEASIBLE; + if (!sat_solver_->ResetToLevelZero()) return SatSolver::INFEASIBLE; for (const std::vector &core : cores) { // This just increase the lower-bound of the corresponding node, which // should already be done by the solver. - if (core.size() == 1) - continue; + if (core.size() == 1) continue; // Compute the min weight of all the terms in the core. The lower bound // will be increased by that much because at least one assumption in the @@ -1789,21 +1713,18 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { new_var_lb += integer_trail_->LowerBound(terms_[index].var); new_var_ub += integer_trail_->UpperBound(terms_[index].var); } - if (ignore_this_core) - continue; + if (ignore_this_core) continue; VLOG(1) << absl::StrFormat( - "core:%u weight:[%d,%d] domain:[%d,%d] depth:%d", - core.size(), min_weight.value(), max_weight.value(), - new_var_lb.value(), new_var_ub.value(), new_depth); + "core:%u weight:[%d,%d] domain:[%d,%d] depth:%d", core.size(), + min_weight.value(), max_weight.value(), new_var_lb.value(), + new_var_ub.value(), new_depth); // We will "transfer" min_weight from all the variables of the core // to a new variable. const IntegerVariable new_var = integer_trail_->AddIntegerVariable(new_var_lb, new_var_ub); - terms_.push_back({ - new_var, min_weight, new_depth - }); + terms_.push_back({new_var, min_weight, new_depth}); terms_.back().cover_ub = new_var_ub; // Sum variables in the core <= new_var. @@ -1825,8 +1746,7 @@ SatSolver::Status CoreBasedOptimizer::Optimize() { // Abort if we reached the time limit. Note that we still add any cores we // found in case the solve is splitted in "chunk". - if (result == SatSolver::LIMIT_REACHED) - return result; + if (result == SatSolver::LIMIT_REACHED) return result; } } @@ -1856,8 +1776,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( objective += coefficients[i] * IntegerValue(model->Get(Value(variables[i]))); } - if (objective > integer_trail->UpperBound(objective_var)) - return true; + if (objective > integer_trail->UpperBound(objective_var)) return true; if (feasible_solution_observer != nullptr) { feasible_solution_observer(); @@ -1868,15 +1787,12 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( sat_solver->Backtrack(0); sat_solver->SetAssumptionLevel(0); if (!integer_trail->Enqueue( - IntegerLiteral::LowerOrEqual(objective_var, objective - 1), { - }, - { - })) { + IntegerLiteral::LowerOrEqual(objective_var, objective - 1), {}, + {})) { return false; } return true; - } - ; + }; // This is the "generalized" hitting set problem we will solve. Each time // we find a core, a new constraint will be added to this problem. @@ -1938,10 +1854,8 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( // Note(user): This is not needed for correctness, but it might cause // more propagation and is nice to have for reporting/logging purpose. if (!integer_trail->Enqueue( - IntegerLiteral::GreaterOrEqual(objective_var, mip_objective), { - }, - { - })) { + IntegerLiteral::GreaterOrEqual(objective_var, mip_objective), {}, + {})) { result = SatSolver::INFEASIBLE; break; } @@ -1954,8 +1868,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( for (int i = 0; i < num_variables_in_objective; ++i) { const IntegerValue hs_value( static_cast(response.variable_value(i))); - if (hs_value == integer_trail->UpperBound(variables[i])) - continue; + if (hs_value == integer_trail->UpperBound(variables[i])) continue; // Only consider the terms above the threshold. if (coefficients[i] < stratified_threshold) { @@ -1974,7 +1887,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( if (assumptions.empty() && next_stratified_threshold > 0) { CHECK_LT(next_stratified_threshold, stratified_threshold); stratified_threshold = next_stratified_threshold; - --iter; // "false" iteration, the lower bound does not increase. + --iter; // "false" iteration, the lower bound does not increase. continue; } @@ -1985,8 +1898,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( std::vector > cores; result = FindMultipleCoresForMaxHs(assumptions, model, &cores); if (result == SatSolver::FEASIBLE) { - if (!process_solution()) - return SatSolver::INFEASIBLE; + if (!process_solution()) return SatSolver::INFEASIBLE; if (parameters.stop_after_first_solution()) { return SatSolver::LIMIT_REACHED; } @@ -1994,9 +1906,8 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( // If not all assumptions were taken, continue with a lower stratified // bound. Otherwise we have an optimal solution. stratified_threshold = next_stratified_threshold; - if (stratified_threshold == 0) - break; - --iter; // "false" iteration, the lower bound does not increase. + if (stratified_threshold == 0) break; + --iter; // "false" iteration, the lower bound does not increase. continue; } } else if (result != SatSolver::ASSUMPTIONS_UNSAT) { @@ -2028,7 +1939,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( ct->add_coefficient(1.0); ct->set_lower_bound(ct->lower_bound() + lb); } else { - const std::pair key = { index, hs_value }; + const std::pair key = {index, hs_value}; if (!gtl::ContainsKey(created_var, key)) { const int new_var_index = hs_model.variable_size(); created_var[key] = new_var_index; @@ -2056,10 +1967,10 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( } return result; -#else // !__PORTABLE_PLATFORM__ && USE_SCIP +#else // !__PORTABLE_PLATFORM__ && USE_SCIP LOG(FATAL) << "Not supported."; -#endif // !__PORTABLE_PLATFORM__ && USE_SCIP +#endif // !__PORTABLE_PLATFORM__ && USE_SCIP } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/optimization.h b/ortools/sat/optimization.h index 0ee000bb64..e1f14fa811 100644 --- a/ortools/sat/optimization.h +++ b/ortools/sat/optimization.h @@ -41,10 +41,7 @@ void MinimizeCoreWithPropagation(SatSolver *solver, std::vector *core); // special output format, we use this to tell them whether or not to use the // default logging framework or simply stdout. Most users should just use // DEFAULT_LOG. -enum LogBehavior { - DEFAULT_LOG, - STDOUT_LOG -}; +enum LogBehavior { DEFAULT_LOG, STDOUT_LOG }; // All the Solve*() functions below reuse the SatSolver::Status with a slightly // different meaning: @@ -145,7 +142,7 @@ void RestrictObjectiveDomainWithBinarySearch( // just return the last solver status. In particular if it is INFEASIBLE but // feasible_solution_observer() was called, it means we are at OPTIMAL. class CoreBasedOptimizer { -public: + public: CoreBasedOptimizer(IntegerVariable objective_var, const std::vector &variables, const std::vector &coefficients, @@ -157,14 +154,14 @@ public: // some of the work already done, so it might just never find anything. SatSolver::Status Optimize(); -private: + private: CoreBasedOptimizer(const CoreBasedOptimizer &) = delete; CoreBasedOptimizer &operator=(const CoreBasedOptimizer &) = delete; struct ObjectiveTerm { IntegerVariable var; IntegerValue weight; - int depth; // Only for logging/debugging. + int depth; // Only for logging/debugging. IntegerValue old_var_lb; // An upper bound on the optimal solution if we were to optimize only this @@ -194,7 +191,7 @@ private: TimeLimit *time_limit_; IntegerTrail *integer_trail_; IntegerEncoder *integer_encoder_; - Model *model_; // TODO(user): remove this one. + Model *model_; // TODO(user): remove this one. IntegerVariable objective_var_; std::vector terms_; @@ -231,7 +228,7 @@ SatSolver::Status MinimizeWithHittingSetAndLazyEncoding( const ObjectiveDefinition &objective_definition, const std::function &feasible_solution_observer, Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_OPTIMIZATION_H_ +#endif // OR_TOOLS_SAT_OPTIMIZATION_H_ diff --git a/ortools/sat/pb_constraint.cc b/ortools/sat/pb_constraint.cc index d69d3daedc..704c9fbea2 100644 --- a/ortools/sat/pb_constraint.cc +++ b/ortools/sat/pb_constraint.cc @@ -35,12 +35,11 @@ bool CoeffComparator(const LiteralWithCoeff &a, const LiteralWithCoeff &b) { return a.coefficient < b.coefficient; } -} // namespace +} // namespace -bool -ComputeBooleanLinearExpressionCanonicalForm(std::vector *cst, - Coefficient *bound_shift, - Coefficient *max_value) { +bool ComputeBooleanLinearExpressionCanonicalForm( + std::vector *cst, Coefficient *bound_shift, + Coefficient *max_value) { // Note(user): For some reason, the IntType checking doesn't work here ?! that // is a bit worrying, but the code seems to behave correctly. *bound_shift = 0; @@ -53,8 +52,7 @@ ComputeBooleanLinearExpressionCanonicalForm(std::vector *cst, LiteralWithCoeff *representative = nullptr; for (int i = 0; i < cst->size(); ++i) { const LiteralWithCoeff current = (*cst)[i]; - if (current.coefficient == 0) - continue; + if (current.coefficient == 0) continue; if (representative != nullptr && current.literal.Variable() == representative->literal.Variable()) { if (current.literal == representative->literal) { @@ -67,8 +65,7 @@ ComputeBooleanLinearExpressionCanonicalForm(std::vector *cst, &(representative->coefficient))) { return false; } - if (!SafeAddInto(-current.coefficient, bound_shift)) - return false; + if (!SafeAddInto(-current.coefficient, bound_shift)) return false; } } else { if (representative != nullptr && representative->coefficient == 0) { @@ -89,13 +86,11 @@ ComputeBooleanLinearExpressionCanonicalForm(std::vector *cst, for (int i = 0; i < cst->size(); ++i) { const LiteralWithCoeff current = (*cst)[i]; if (current.coefficient < 0) { - if (!SafeAddInto(-current.coefficient, bound_shift)) - return false; + if (!SafeAddInto(-current.coefficient, bound_shift)) return false; (*cst)[i].coefficient = -current.coefficient; (*cst)[i].literal = current.literal.Negated(); } - if (!SafeAddInto((*cst)[i].coefficient, max_value)) - return false; + if (!SafeAddInto((*cst)[i].coefficient, max_value)) return false; } // Finally sort by increasing coefficients. @@ -104,10 +99,10 @@ ComputeBooleanLinearExpressionCanonicalForm(std::vector *cst, return true; } -bool -ApplyLiteralMapping(const gtl::ITIVector &mapping, - std::vector *cst, - Coefficient *bound_shift, Coefficient *max_value) { +bool ApplyLiteralMapping( + const gtl::ITIVector &mapping, + std::vector *cst, Coefficient *bound_shift, + Coefficient *max_value) { int index = 0; Coefficient shift_due_to_fixed_variables(0); for (const LiteralWithCoeff &entry : *cst) { @@ -132,18 +127,16 @@ ApplyLiteralMapping(const gtl::ITIVector &mapping, } const bool result = ComputeBooleanLinearExpressionCanonicalForm(cst, bound_shift, max_value); - if (!SafeAddInto(shift_due_to_fixed_variables, bound_shift)) - return false; + if (!SafeAddInto(shift_due_to_fixed_variables, bound_shift)) return false; return result; } // TODO(user): Also check for no duplicates literals + unit tests. -bool -BooleanLinearExpressionIsCanonical(const std::vector &cst) { +bool BooleanLinearExpressionIsCanonical( + const std::vector &cst) { Coefficient previous(1); for (LiteralWithCoeff term : cst) { - if (term.coefficient < previous) - return false; + if (term.coefficient < previous) return false; previous = term.coefficient; } return true; @@ -151,17 +144,15 @@ BooleanLinearExpressionIsCanonical(const std::vector &cst) { // TODO(user): Use more complex simplification like dividing by the gcd of // everyone and using less different coefficients if possible. -void -SimplifyCanonicalBooleanLinearConstraint(std::vector *cst, - Coefficient *rhs) { +void SimplifyCanonicalBooleanLinearConstraint( + std::vector *cst, Coefficient *rhs) { // Replace all coefficient >= rhs by rhs + 1 (these literal must actually be // false). Note that the linear sum of literals remains canonical. // // TODO(user): It is probably better to remove these literals and have other // constraint setting them to false from the symmetry finder perspective. for (LiteralWithCoeff &x : *cst) { - if (x.coefficient > *rhs) - x.coefficient = *rhs + 1; + if (x.coefficient > *rhs) x.coefficient = *rhs + 1; } } @@ -179,8 +170,7 @@ Coefficient ComputeCanonicalRhs(Coefficient upper_bound, return Coefficient(-1); } } - if (rhs < 0) - return Coefficient(-1); + if (rhs < 0) return Coefficient(-1); return std::min(max_value, rhs); } @@ -220,8 +210,7 @@ bool CanonicalBooleanLinearProblem::AddLinearConstraint( if (use_upper_bound) { const Coefficient rhs = ComputeCanonicalRhs(upper_bound, bound_shift, max_value); - if (!AddConstraint(*cst, max_value, rhs)) - return false; + if (!AddConstraint(*cst, max_value, rhs)) return false; } if (use_lower_bound) { // We transform the constraint into an upper-bounded one. @@ -230,8 +219,7 @@ bool CanonicalBooleanLinearProblem::AddLinearConstraint( } const Coefficient rhs = ComputeNegatedCanonicalRhs(lower_bound, bound_shift, max_value); - if (!AddConstraint(*cst, max_value, rhs)) - return false; + if (!AddConstraint(*cst, max_value, rhs)) return false; } return true; } @@ -239,10 +227,8 @@ bool CanonicalBooleanLinearProblem::AddLinearConstraint( bool CanonicalBooleanLinearProblem::AddConstraint( const std::vector &cst, Coefficient max_value, Coefficient rhs) { - if (rhs < 0) - return false; // Trivially unsatisfiable. - if (rhs >= max_value) - return true; // Trivially satisfiable. + if (rhs < 0) return false; // Trivially unsatisfiable. + if (rhs >= max_value) return true; // Trivially satisfiable. constraints_.emplace_back(cst.begin(), cst.end()); rhs_.push_back(rhs); SimplifyCanonicalBooleanLinearConstraint(&constraints_.back(), &rhs_.back()); @@ -290,8 +276,7 @@ void MutableUpperBoundedLinearConstraint::ReduceCoefficients() { std::string MutableUpperBoundedLinearConstraint::DebugString() { std::string result; for (BooleanVariable var : PossibleNonZeros()) { - if (!result.empty()) - result += " + "; + if (!result.empty()) result += " + "; result += absl::StrFormat("%d[%s]", GetCoefficient(var).value(), GetLiteral(var).DebugString()); } @@ -305,8 +290,7 @@ Coefficient MutableUpperBoundedLinearConstraint::ComputeSlackForTrailPrefix( const Trail &trail, int trail_index) const { Coefficient activity(0); for (BooleanVariable var : PossibleNonZeros()) { - if (GetCoefficient(var) == 0) - continue; + if (GetCoefficient(var) == 0) continue; if (trail.Assignment().LiteralIsTrue(GetLiteral(var)) && trail.Info(var).trail_index < trail_index) { activity += GetCoefficient(var); @@ -322,8 +306,7 @@ Coefficient MutableUpperBoundedLinearConstraint:: Coefficient removed_sum(0); const Coefficient bound = max_sum_ - rhs_; for (BooleanVariable var : PossibleNonZeros()) { - if (GetCoefficient(var) == 0) - continue; + if (GetCoefficient(var) == 0) continue; const Coefficient diff = GetCoefficient(var) - bound; if (trail.Assignment().LiteralIsTrue(GetLiteral(var)) && trail.Info(var).trail_index < trail_index) { @@ -361,15 +344,13 @@ void MutableUpperBoundedLinearConstraint::ReduceSlackTo( CHECK_LT(slack, coeff); // Nothing to do if the slack is already target. - if (slack == target) - return; + if (slack == target) return; // Applies the algorithm described in the .h const Coefficient diff = slack - target; rhs_ -= diff; for (BooleanVariable var : PossibleNonZeros()) { - if (GetCoefficient(var) == 0) - continue; + if (GetCoefficient(var) == 0) continue; if (trail.Assignment().LiteralIsTrue(GetLiteral(var)) && trail.Info(var).trail_index < trail_index) { continue; @@ -407,8 +388,10 @@ Coefficient MutableUpperBoundedLinearConstraint::ComputeMaxSum() const { UpperBoundedLinearConstraint::UpperBoundedLinearConstraint( const std::vector &cst) - : is_marked_for_deletion_(false), is_learned_(false), - first_reason_trail_index_(-1), activity_(0.0) { + : is_marked_for_deletion_(false), + is_learned_(false), + first_reason_trail_index_(-1), + activity_(0.0) { DCHECK(!cst.empty()); DCHECK(std::is_sorted(cst.begin(), cst.end(), CoeffComparator)); literals_.reserve(cst.size()); @@ -416,7 +399,7 @@ UpperBoundedLinearConstraint::UpperBoundedLinearConstraint( // Reserve the space for coeffs_ and starts_ (it is slightly more efficient). { int size = 0; - Coefficient prev(0); // Ignore initial zeros. + Coefficient prev(0); // Ignore initial zeros. for (LiteralWithCoeff term : cst) { if (term.coefficient != prev) { prev = term.coefficient; @@ -451,23 +434,19 @@ void UpperBoundedLinearConstraint::AddToConflict( for (Literal literal : literals_) { conflict->AddTerm(literal, coeffs_[coeff_index]); ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } conflict->AddToRhs(rhs_); } bool UpperBoundedLinearConstraint::HasIdenticalTerms( const std::vector &cst) { - if (cst.size() != literals_.size()) - return false; + if (cst.size() != literals_.size()) return false; int literal_index = 0; int coeff_index = 0; for (LiteralWithCoeff term : cst) { - if (literals_[literal_index] != term.literal) - return false; - if (coeffs_[coeff_index] != term.coefficient) - return false; + if (literals_[literal_index] != term.literal) return false; + if (coeffs_[coeff_index] != term.coefficient) return false; ++literal_index; if (literal_index == starts_[coeff_index + 1]) { ++coeff_index; @@ -507,13 +486,11 @@ bool UpperBoundedLinearConstraint::InitializeRhs( sum_at_previous_level[trail->Info(var).level + 1] += coeff; } ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } // The constraint is infeasible provided the current propagated trail. - if (slack < 0) - return false; + if (slack < 0) return false; // Cummulative sum. for (int i = 1; i < sum_at_previous_level.size(); ++i) { @@ -526,16 +503,15 @@ bool UpperBoundedLinearConstraint::InitializeRhs( int coeff_index = 0; for (Literal literal : literals_) { const BooleanVariable var = literal.Variable(); - const int level = - trail->Assignment().VariableIsAssigned(var) ? trail->Info(var).level - : last_level; + const int level = trail->Assignment().VariableIsAssigned(var) + ? trail->Info(var).level + : last_level; if (level > 0) { CHECK_LE(coeffs_[coeff_index], rhs_ - sum_at_previous_level[level]) << "var should have been propagated at an earlier level !"; } ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } // Initial propagation. @@ -553,21 +529,18 @@ bool UpperBoundedLinearConstraint::InitializeRhs( : true; } -bool -UpperBoundedLinearConstraint::Propagate(int trail_index, Coefficient *threshold, - Trail *trail, - PbConstraintsEnqueueHelper *helper) { +bool UpperBoundedLinearConstraint::Propagate( + int trail_index, Coefficient *threshold, Trail *trail, + PbConstraintsEnqueueHelper *helper) { DCHECK_LT(*threshold, 0); const Coefficient slack = GetSlackFromThreshold(*threshold); DCHECK_GE(slack, 0) << "The constraint is already a conflict!"; - while (index_ >= 0 && coeffs_[index_] > slack) - --index_; + while (index_ >= 0 && coeffs_[index_] > slack) --index_; // Check propagation. BooleanVariable first_propagated_variable(-1); for (int i = starts_[index_ + 1]; i < already_propagated_end_; ++i) { - if (trail->Assignment().LiteralIsFalse(literals_[i])) - continue; + if (trail->Assignment().LiteralIsFalse(literals_[i])) continue; if (trail->Assignment().LiteralIsTrue(literals_[i])) { if (trail->Info(literals_[i].Variable()).trail_index > trail_index) { // Conflict. @@ -646,8 +619,7 @@ void UpperBoundedLinearConstraint::FillReason( DCHECK_GE(propagated_variable_coefficient, 0); // In both cases, we can't minimize the reason further. - if (reason->size() <= 1 || coeffs_.size() == 1) - return; + if (reason->size() <= 1 || coeffs_.size() == 1) return; Coefficient limit = propagated_variable_coefficient - slack; DCHECK_GE(limit, 1); @@ -655,21 +627,17 @@ void UpperBoundedLinearConstraint::FillReason( // Remove literals with small coefficients from the reason as long as the // limit is still stricly positive. coeff_index = last_coeff_index; - if (coeffs_[coeff_index] >= limit) - return; + if (coeffs_[coeff_index] >= limit) return; for (int i = last_i; i < literals_.size(); ++i) { const Literal literal = literals_[i]; if (i == starts_[coeff_index + 1]) { ++coeff_index; - if (coeffs_[coeff_index] >= limit) - break; + if (coeffs_[coeff_index] >= limit) break; } - if (literal.Negated() != reason->back()) - continue; + if (literal.Negated() != reason->back()) continue; limit -= coeffs_[coeff_index]; reason->pop_back(); - if (coeffs_[coeff_index] >= limit) - break; + if (coeffs_[coeff_index] >= limit) break; } DCHECK(!reason->empty()); DCHECK_GE(limit, 1); @@ -687,8 +655,7 @@ Coefficient UpperBoundedLinearConstraint::ComputeCancelation( result += conflict.CancelationAmount(literal, coeffs_[coeff_index]); } ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } return result; } @@ -715,8 +682,7 @@ void UpperBoundedLinearConstraint::ResolvePBConflict( activity += coeffs_[coeff_index]; } ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } // Special case. @@ -835,8 +801,7 @@ void UpperBoundedLinearConstraint::ResolvePBConflict( } } ++literal_index; - if (literal_index == starts_[coeff_index + 1]) - ++coeff_index; + if (literal_index == starts_[coeff_index + 1]) ++coeff_index; } // And the rhs. @@ -846,8 +811,7 @@ void UpperBoundedLinearConstraint::ResolvePBConflict( void UpperBoundedLinearConstraint::Untrail(Coefficient *threshold, int trail_index) { const Coefficient slack = GetSlackFromThreshold(*threshold); - while (index_ + 1 < coeffs_.size() && coeffs_[index_ + 1] <= slack) - ++index_; + while (index_ + 1 < coeffs_.size() && coeffs_[index_ + 1] <= slack) ++index_; Update(slack, threshold); if (first_reason_trail_index_ >= trail_index) { first_reason_trail_index_ = -1; @@ -917,9 +881,8 @@ bool PbConstraints::AddConstraint(const std::vector &cst, return true; } -bool -PbConstraints::AddLearnedConstraint(const std::vector &cst, - Coefficient rhs, Trail *trail) { +bool PbConstraints::AddLearnedConstraint( + const std::vector &cst, Coefficient rhs, Trail *trail) { DeleteSomeLearnedConstraintIfNeeded(); const int old_num_constraints = constraints_.size(); const bool result = AddConstraint(cst, rhs, trail); @@ -971,8 +934,7 @@ bool PbConstraints::PropagateNext(Trail *trail) { bool PbConstraints::Propagate(Trail *trail) { const int old_index = trail->Index(); while (trail->Index() == old_index && propagation_trail_index_ < old_index) { - if (!PropagateNext(trail)) - return false; + if (!PropagateNext(trail)) return false; } return true; } @@ -995,8 +957,8 @@ void PbConstraints::Untrail(const Trail &trail, int trail_index) { } } for (ConstraintIndex cst_index : to_untrail_.PositionsSetAtLeastOnce()) { - constraints_[cst_index.value()] - ->Untrail(&(thresholds_[cst_index]), trail_index); + constraints_[cst_index.value()]->Untrail(&(thresholds_[cst_index]), + trail_index); } } @@ -1011,8 +973,8 @@ absl::Span PbConstraints::Reason(const Trail &trail, return *reason; } -UpperBoundedLinearConstraint * -PbConstraints::ReasonPbConstraint(int trail_index) const { +UpperBoundedLinearConstraint *PbConstraints::ReasonPbConstraint( + int trail_index) const { const PbConstraintsEnqueueHelper::ReasonInfo &reason_info = enqueue_helper_.reasons[trail_index]; return reason_info.pb_constraint; @@ -1027,7 +989,8 @@ void PbConstraints::ComputeNewLearnedConstraintLimit() { num_constraints + parameters_->pb_cleanup_increment(); num_learned_constraint_before_cleanup_ = static_cast(target_number_of_learned_constraint_ / - parameters_->pb_cleanup_ratio()) - num_constraints; + parameters_->pb_cleanup_ratio()) - + num_constraints; } void PbConstraints::DeleteSomeLearnedConstraintIfNeeded() { @@ -1037,8 +1000,7 @@ void PbConstraints::DeleteSomeLearnedConstraintIfNeeded() { return; } --num_learned_constraint_before_cleanup_; - if (num_learned_constraint_before_cleanup_ > 0) - return; + if (num_learned_constraint_before_cleanup_ > 0) return; SCOPED_TIME_STAT(&stats_); // Mark the constraint that needs to be deleted. @@ -1102,8 +1064,7 @@ void PbConstraints::DeleteSomeLearnedConstraintIfNeeded() { } void PbConstraints::BumpActivity(UpperBoundedLinearConstraint *constraint) { - if (!constraint->is_learned()) - return; + if (!constraint->is_learned()) return; const double max_activity = parameters_->max_clause_activity_value(); constraint->set_activity(constraint->activity() + constraint_activity_increment_); @@ -1170,5 +1131,5 @@ void PbConstraints::DeleteConstraintMarkedForDeletion() { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/pb_constraint.h b/ortools/sat/pb_constraint.h index e4a3f226a3..562e16cec4 100644 --- a/ortools/sat/pb_constraint.h +++ b/ortools/sat/pb_constraint.h @@ -42,8 +42,8 @@ DEFINE_INT_TYPE(Coefficient, int64); // IMPORTANT: We can't use numeric_limits::max() which will compile // but just returns zero!! -const Coefficient - kCoefficientMax(std::numeric_limits::max()); +const Coefficient kCoefficientMax( + std::numeric_limits::max()); // Represents a term in a pseudo-Boolean formula. struct LiteralWithCoeff { @@ -122,9 +122,8 @@ bool BooleanLinearExpressionIsCanonical( // Given a Boolean linear constraint in canonical form, simplify its // coefficients using simple heuristics. -void - SimplifyCanonicalBooleanLinearConstraint(std::vector *cst, - Coefficient *rhs); +void SimplifyCanonicalBooleanLinearConstraint( + std::vector *cst, Coefficient *rhs); // Holds a set of boolean linear constraints in canonical form: // - The constraint is a linear sum of LiteralWithCoeff <= rhs. @@ -140,7 +139,7 @@ void // this is not ideal for the symmetry computation since it leads to a lot of // symmetries of the associated graph that are not useful. class CanonicalBooleanLinearProblem { -public: + public: CanonicalBooleanLinearProblem() {} // Adds a new constraint to the problem. The bounds are inclusive. @@ -159,7 +158,7 @@ public: return constraints_[i]; } -private: + private: bool AddConstraint(const std::vector &cst, Coefficient max_value, Coefficient rhs); @@ -172,7 +171,7 @@ private: // Coefficient times a literal. This class allows efficient modification of the // constraint and is used during pseudo-Boolean resolution. class MutableUpperBoundedLinearConstraint { -public: + public: // This must be called before any other functions is used with an higher // variable index. void ClearAndResize(int num_variables); @@ -230,9 +229,8 @@ public: // or not. // // TODO(user): Ideally the slack should be maitainable incrementally. - Coefficient - ReduceCoefficientsAndComputeSlackForTrailPrefix(const Trail &trail, - int trail_index); + Coefficient ReduceCoefficientsAndComputeSlackForTrailPrefix( + const Trail &trail, int trail_index); // Relaxes the constraint so that: // - ComputeSlackForTrailPrefix(trail, trail_index) == target; @@ -298,8 +296,7 @@ public: Coefficient CancelationAmount(Literal literal, Coefficient coeff) const { DCHECK_GT(coeff, 0); const BooleanVariable var = literal.Variable(); - if (literal == GetLiteral(var)) - return Coefficient(0); + if (literal == GetLiteral(var)) return Coefficient(0); return std::min(coeff, AbsCoefficient(terms_[var])); } @@ -312,7 +309,7 @@ public: // Returns a string representation of the constraint. std::string DebugString(); -private: + private: Coefficient AbsCoefficient(Coefficient a) const { return a > 0 ? a : -a; } // Only used for DCHECK_EQ(max_sum_, ComputeMaxSum()); @@ -341,7 +338,7 @@ class UpperBoundedLinearConstraint; struct PbConstraintsEnqueueHelper { void Enqueue(Literal l, int source_trail_index, UpperBoundedLinearConstraint *ct, Trail *trail) { - reasons[trail->Index()] = { source_trail_index, ct }; + reasons[trail->Index()] = {source_trail_index, ct}; trail->Enqueue(l, propagator_id); } @@ -374,7 +371,7 @@ struct PbConstraintsEnqueueHelper { // even larger coefficients that are yet 'processed' must be false for the // constraint to be satisfiable. class UpperBoundedLinearConstraint { -public: + public: // Takes a pseudo-Boolean formula in canonical form. explicit UpperBoundedLinearConstraint( const std::vector &cst); @@ -451,9 +448,9 @@ public: // a trail index smaller than the given one. // // Note(user): Currently, this is only used in DCHECKs. - Coefficient - ComputeCancelation(const Trail &trail, int trail_index, - const MutableUpperBoundedLinearConstraint &conflict); + Coefficient ComputeCancelation( + const Trail &trail, int trail_index, + const MutableUpperBoundedLinearConstraint &conflict); // API to mark a constraint for deletion before actually deleting it. void MarkForDeletion() { is_marked_for_deletion_ = true; } @@ -478,7 +475,7 @@ public: // a Propagate() call. int already_propagated_end() const { return already_propagated_end_; } -private: + private: Coefficient GetSlackFromThreshold(Coefficient threshold) { return (index_ < 0) ? threshold : coeffs_[index_] + threshold; } @@ -516,14 +513,17 @@ private: // Class responsible for managing a set of pseudo-Boolean constraints and their // propagation. class PbConstraints : public SatPropagator { -public: + public: explicit PbConstraints(Model *model) - : SatPropagator("PbConstraints"), conflicting_constraint_index_(-1), + : SatPropagator("PbConstraints"), + conflicting_constraint_index_(-1), num_learned_constraint_before_cleanup_(0), constraint_activity_increment_(1.0), parameters_(model->GetOrCreate()), - stats_("PbConstraints"), num_constraint_lookups_(0), - num_inspected_constraint_literals_(0), num_threshold_updates_(0) { + stats_("PbConstraints"), + num_constraint_lookups_(0), + num_inspected_constraint_literals_(0), + num_threshold_updates_(0) { model->GetOrCreate()->RegisterPropagator(this); } ~PbConstraints() override { @@ -536,8 +536,8 @@ public: bool Propagate(Trail *trail) final; void Untrail(const Trail &trail, int trail_index) final; - absl::Span Reason(const Trail &trail, int trail_index) const - final; + absl::Span Reason(const Trail &trail, + int trail_index) const final; // Changes the number of variables. void Resize(int num_variables) { @@ -578,8 +578,7 @@ public: // the solver API assume only clause conflict. Find a cleaner way? void ClearConflictingConstraint() { conflicting_constraint_index_ = -1; } UpperBoundedLinearConstraint *ConflictingConstraint() { - if (conflicting_constraint_index_ == -1) - return nullptr; + if (conflicting_constraint_index_ == -1) return nullptr; return constraints_[conflicting_constraint_index_.value()].get(); } @@ -606,7 +605,7 @@ public: } int64 num_threshold_updates() const { return num_threshold_updates_; } -private: + private: bool PropagateNext(Trail *trail); // Same function as the clause related one is SatSolver(). @@ -628,8 +627,7 @@ private: // probably that the thresholds_ vector is a lot more efficient cache-wise. DEFINE_INT_TYPE(ConstraintIndex, int32); struct ConstraintIndexWithCoeff { - ConstraintIndexWithCoeff() { - } // Needed for vector.resize() + ConstraintIndexWithCoeff() {} // Needed for vector.resize() ConstraintIndexWithCoeff(bool n, ConstraintIndex i, Coefficient c) : need_untrail_inspection(n), index(i), coefficient(c) {} bool need_untrail_inspection; @@ -687,7 +685,7 @@ private: // TODO(user): With the new SAME_REASON_AS mechanism, this is more general so // move out of pb_constraint. class VariableWithSameReasonIdentifier { -public: + public: explicit VariableWithSameReasonIdentifier(const Trail &trail) : trail_(trail) {} @@ -703,20 +701,17 @@ public: // this function was called since the last Clear(). Note that if no variable // had the same reason, then var is returned. BooleanVariable FirstVariableWithSameReason(BooleanVariable var) { - if (seen_[var]) - return first_variable_[var]; + if (seen_[var]) return first_variable_[var]; const BooleanVariable reference_var = trail_.ReferenceVarWithSameReason(var); - if (reference_var == var) - return var; - if (seen_[reference_var]) - return first_variable_[reference_var]; + if (reference_var == var) return var; + if (seen_[reference_var]) return first_variable_[reference_var]; seen_.Set(reference_var); first_variable_[reference_var] = var; return var; } -private: + private: const Trail &trail_; gtl::ITIVector first_variable_; SparseBitset seen_; @@ -724,7 +719,7 @@ private: DISALLOW_COPY_AND_ASSIGN(VariableWithSameReasonIdentifier); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PB_CONSTRAINT_H_ +#endif // OR_TOOLS_SAT_PB_CONSTRAINT_H_ diff --git a/ortools/sat/precedences.cc b/ortools/sat/precedences.cc index 4758366cd0..bf64ef1d72 100644 --- a/ortools/sat/precedences.cc +++ b/ortools/sat/precedences.cc @@ -35,15 +35,14 @@ void AppendLowerBoundReasonIfValid(IntegerVariable var, } } -} // namespace +} // namespace bool PrecedencesPropagator::Propagate(Trail *trail) { return Propagate(); } bool PrecedencesPropagator::Propagate() { while (propagation_trail_index_ < trail_->Index()) { const Literal literal = (*trail_)[propagation_trail_index_++]; - if (literal.Index() >= literal_to_new_impacted_arcs_.size()) - continue; + if (literal.Index() >= literal_to_new_impacted_arcs_.size()) continue; // IMPORTANT: Because of the way Untrail() work, we need to add all the // potential arcs before we can abort. It is why we iterate twice here. @@ -59,24 +58,20 @@ bool PrecedencesPropagator::Propagate() { // modified_vars_. for (const ArcIndex arc_index : literal_to_new_impacted_arcs_[literal.Index()]) { - if (arc_counts_[arc_index] > 0) - continue; + if (arc_counts_[arc_index] > 0) continue; const ArcInfo &arc = arcs_[arc_index]; - if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) continue; const IntegerValue new_head_lb = integer_trail_->LowerBound(arc.tail_var) + ArcOffset(arc); if (new_head_lb > integer_trail_->LowerBound(arc.head_var)) { - if (!EnqueueAndCheck(arc, new_head_lb, trail_)) - return false; + if (!EnqueueAndCheck(arc, new_head_lb, trail_)) return false; } } } // Do the actual propagation of the IntegerVariable bounds. InitializeBFQueueWithModifiedNodes(); - if (!BellmanFordTarjan(trail_)) - return false; + if (!BellmanFordTarjan(trail_)) return false; // We can only test that no propagation is left if we didn't enqueue new // literal in the presence of optional variables. @@ -84,7 +79,8 @@ bool PrecedencesPropagator::Propagate() { // TODO(user): Because of our code to deal with InPropagationLoop(), this is // not always true. Find a cleaner way to DCHECK() while not failing in this // corner case. - if (/*DISABLES CODE*/(false) && propagation_trail_index_ == trail_->Index()) { + if (/*DISABLES CODE*/ (false) && + propagation_trail_index_ == trail_->Index()) { DCHECK(NoPropagationLeft(*trail_)); } @@ -99,13 +95,11 @@ bool PrecedencesPropagator::Propagate() { bool PrecedencesPropagator::PropagateOutgoingArcs(IntegerVariable var) { for (const ArcIndex arc_index : impacted_arcs_[var]) { const ArcInfo &arc = arcs_[arc_index]; - if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) continue; const IntegerValue new_head_lb = integer_trail_->LowerBound(arc.tail_var) + ArcOffset(arc); if (new_head_lb > integer_trail_->LowerBound(arc.head_var)) { - if (!EnqueueAndCheck(arc, new_head_lb, trail_)) - return false; + if (!EnqueueAndCheck(arc, new_head_lb, trail_)) return false; } } return true; @@ -120,8 +114,7 @@ void PrecedencesPropagator::Untrail(const Trail &trail, int trail_index) { } while (propagation_trail_index_ > trail_index) { const Literal literal = trail[--propagation_trail_index_]; - if (literal.Index() >= literal_to_new_impacted_arcs_.size()) - continue; + if (literal.Index() >= literal_to_new_impacted_arcs_.size()) continue; for (const ArcIndex arc_index : literal_to_new_impacted_arcs_[literal.Index()]) { if (arc_counts_[arc_index]++ == 0) { @@ -144,12 +137,10 @@ void PrecedencesPropagator::ComputePrecedences( for (int index = 0; index < vars.size(); ++index) { const IntegerVariable var = vars[index]; CHECK_NE(kNoIntegerVariable, var); - if (var >= impacted_arcs_.size()) - continue; + if (var >= impacted_arcs_.size()) continue; for (const ArcIndex arc_index : impacted_arcs_[var]) { const ArcInfo &arc = arcs_[arc_index]; - if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) continue; IntegerValue offset = arc.offset; if (arc.offset_var != kNoIntegerVariable) { @@ -160,26 +151,22 @@ void PrecedencesPropagator::ComputePrecedences( // often have relation of the form interval_start >= interval_end - // offset, and such relation are usually not useful. Revisit this in case // we see problems where we can propagate more without this test. - if (offset < 0) - continue; + if (offset < 0) continue; if (var_to_degree_[arc.head_var] == 0) { - tmp_sorted_vars_.push_back({ - arc.head_var, integer_trail_->LowerBound(arc.head_var) - }); + tmp_sorted_vars_.push_back( + {arc.head_var, integer_trail_->LowerBound(arc.head_var)}); } else { // This "seen" mechanism is needed because we may have multi-arc and we // don't want any duplicates in the "is_before" relation. Note that it // works because var_to_last_index_ is reset by the var_to_degree_ == 0 // case. - if (var_to_last_index_[arc.head_var] == index) - continue; + if (var_to_last_index_[arc.head_var] == index) continue; } var_to_last_index_[arc.head_var] = index; var_to_degree_[arc.head_var]++; - tmp_precedences_.push_back({ - index, arc.head_var, arc_index.value(), offset - }); + tmp_precedences_.push_back( + {index, arc.head_var, arc_index.value(), offset}); } } @@ -208,8 +195,7 @@ void PrecedencesPropagator::ComputePrecedences( } output->resize(start); for (const IntegerPrecedences &precedence : tmp_precedences_) { - if (var_to_degree_[precedence.var] < 0) - continue; + if (var_to_degree_[precedence.var] < 0) continue; (*output)[var_to_degree_[precedence.var]++] = precedence; } @@ -250,15 +236,13 @@ void PrecedencesPropagator::AdjustSizeFor(IntegerVariable i) { } } -void -PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, - IntegerValue offset, IntegerVariable offset_var, - absl::Span presence_literals) { +void PrecedencesPropagator::AddArc( + IntegerVariable tail, IntegerVariable head, IntegerValue offset, + IntegerVariable offset_var, absl::Span presence_literals) { DCHECK_EQ(trail_->CurrentDecisionLevel(), 0); AdjustSizeFor(tail); AdjustSizeFor(head); - if (offset_var != kNoIntegerVariable) - AdjustSizeFor(offset_var); + if (offset_var != kNoIntegerVariable) AdjustSizeFor(offset_var); // This arc is present iff all the literals here are true. absl::InlinedVector enforcement_literals; @@ -267,12 +251,12 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, enforcement_literals.push_back(l); } if (integer_trail_->IsOptional(tail)) { - enforcement_literals.push_back(integer_trail_->IsIgnoredLiteral(tail) - .Negated()); + enforcement_literals.push_back( + integer_trail_->IsIgnoredLiteral(tail).Negated()); } if (integer_trail_->IsOptional(head)) { - enforcement_literals.push_back(integer_trail_->IsIgnoredLiteral(head) - .Negated()); + enforcement_literals.push_back( + integer_trail_->IsIgnoredLiteral(head).Negated()); } if (offset_var != kNoIntegerVariable && integer_trail_->IsOptional(offset_var)) { @@ -283,9 +267,9 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, int new_size = 0; for (const Literal l : enforcement_literals) { if (trail_->Assignment().LiteralIsTrue(Literal(l))) { - continue; // At true, ignore this literal. + continue; // At true, ignore this literal. } else if (trail_->Assignment().LiteralIsFalse(Literal(l))) { - return; // At false, ignore completely this arc. + return; // At false, ignore completely this arc. } enforcement_literals[new_size++] = l; } @@ -315,9 +299,8 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, // Deal first with impacted_potential_arcs_/potential_arcs_. if (!enforcement_literals.empty()) { const OptionalArcIndex arc_index(potential_arcs_.size()); - potential_arcs_.push_back({ - tail, head, offset, offset_var, enforcement_literals - }); + potential_arcs_.push_back( + {tail, head, offset, offset_var, enforcement_literals}); impacted_potential_arcs_[tail].push_back(arc_index); impacted_potential_arcs_[NegationOf(head)].push_back(arc_index); if (offset_var != kNoIntegerVariable) { @@ -333,36 +316,20 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, }; std::vector to_add; if (offset_var == kNoIntegerVariable) { - // a + offset <= b and -b + offset <= -a - to_add.push_back({ - tail, head, kNoIntegerVariable - }); - to_add.push_back({ - NegationOf(head), NegationOf(tail), kNoIntegerVariable - }); + // a + offset <= b and -b + offset <= -a + to_add.push_back({tail, head, kNoIntegerVariable}); + to_add.push_back({NegationOf(head), NegationOf(tail), kNoIntegerVariable}); } else { - // tail (a) and offset_var (b) are symmetric, so we add: - // - a + b + offset <= c - to_add.push_back({ - tail, head, offset_var - }); - to_add.push_back({ - offset_var, head, tail - }); - // - a - c + offset <= -b - to_add.push_back({ - tail, NegationOf(offset_var), NegationOf(head) - }); - to_add.push_back({ - NegationOf(head), NegationOf(offset_var), tail - }); - // - b - c + offset <= -a - to_add.push_back({ - offset_var, NegationOf(tail), NegationOf(head) - }); - to_add.push_back({ - NegationOf(head), NegationOf(tail), offset_var - }); + // tail (a) and offset_var (b) are symmetric, so we add: + // - a + b + offset <= c + to_add.push_back({tail, head, offset_var}); + to_add.push_back({offset_var, head, tail}); + // - a - c + offset <= -b + to_add.push_back({tail, NegationOf(offset_var), NegationOf(head)}); + to_add.push_back({NegationOf(head), NegationOf(offset_var), tail}); + // - b - c + offset <= -a + to_add.push_back({offset_var, NegationOf(tail), NegationOf(head)}); + to_add.push_back({NegationOf(head), NegationOf(tail), offset_var}); } for (const InternalArc a : to_add) { // Since we add a new arc, we will need to consider its tail during the next @@ -384,9 +351,8 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, // If a.head_var is optional, we can potentially remove some literal from // enforcement_literals. const ArcIndex arc_index(arcs_.size()); - arcs_.push_back({ - a.tail_var, a.head_var, offset, a.offset_var, enforcement_literals - }); + arcs_.push_back( + {a.tail_var, a.head_var, offset, a.offset_var, enforcement_literals}); auto &presence_literals = arcs_.back().presence_literals; if (integer_trail_->IsOptional(a.head_var)) { // TODO(user): More generally, we can remove any literal that is implied @@ -395,8 +361,7 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, integer_trail_->IsIgnoredLiteral(a.head_var).Negated(); const auto it = std::find(presence_literals.begin(), presence_literals.end(), to_remove); - if (it != presence_literals.end()) - presence_literals.erase(it); + if (it != presence_literals.end()) presence_literals.erase(it); } if (presence_literals.empty()) { @@ -420,8 +385,7 @@ PrecedencesPropagator::AddArc(IntegerVariable tail, IntegerVariable head, // horizon. Find an even sparser algorithm? void PrecedencesPropagator::PropagateOptionalArcs(Trail *trail) { for (const IntegerVariable var : modified_vars_.PositionsSetAtLeastOnce()) { - if (var >= impacted_potential_arcs_.size()) - break; + if (var >= impacted_potential_arcs_.size()) break; // Note that we can currently check the same ArcInfo up to 3 times, one for // each of the arc variables: tail, NegationOf(head) and offset_var. @@ -435,10 +399,8 @@ void PrecedencesPropagator::PropagateOptionalArcs(Trail *trail) { to_propagate = l; } } - if (num_not_true != 1) - continue; - if (trail->Assignment().LiteralIsFalse(to_propagate)) - continue; + if (num_not_true != 1) continue; + if (trail->Assignment().LiteralIsFalse(to_propagate)) continue; // Test if this arc can be present or not. // Important arc.tail_var can be different from var here. @@ -454,8 +416,7 @@ void PrecedencesPropagator::PropagateOptionalArcs(Trail *trail) { &integer_reason_); literal_reason_.clear(); for (const Literal l : arc.presence_literals) { - if (l != to_propagate) - literal_reason_.push_back(l.Negated()); + if (l != to_propagate) literal_reason_.push_back(l.Negated()); } integer_trail_->EnqueueLiteral(to_propagate.Negated(), literal_reason_, integer_reason_); @@ -531,8 +492,7 @@ bool PrecedencesPropagator::NoPropagationLeft(const Trail &trail) const { for (IntegerVariable var(0); var < num_nodes; ++var) { for (const ArcIndex arc_index : impacted_arcs_[var]) { const ArcInfo &arc = arcs_[arc_index]; - if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) - continue; + if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) continue; if (integer_trail_->LowerBound(arc.tail_var) + ArcOffset(arc) > integer_trail_->LowerBound(arc.head_var)) { return false; @@ -547,15 +507,12 @@ void PrecedencesPropagator::InitializeBFQueueWithModifiedNodes() { // queue.size() is small or use SparseBitset. const int num_nodes = impacted_arcs_.size(); bf_in_queue_.resize(num_nodes, false); - for (const int node : bf_queue_) - bf_in_queue_[node] = false; + for (const int node : bf_queue_) bf_in_queue_[node] = false; bf_queue_.clear(); - DCHECK(std::none_of(bf_in_queue_.begin(), bf_in_queue_.end(), [](bool v) { - return v; - })); + DCHECK(std::none_of(bf_in_queue_.begin(), bf_in_queue_.end(), + [](bool v) { return v; })); for (const IntegerVariable var : modified_vars_.PositionsSetAtLeastOnce()) { - if (var >= num_nodes) - continue; + if (var >= num_nodes) continue; bf_queue_.push_back(var.value()); bf_in_queue_[var.value()] = true; } @@ -566,8 +523,7 @@ void PrecedencesPropagator::CleanUpMarkedArcsAndParents() { // modified_vars_. const int num_nodes = impacted_arcs_.size(); for (const IntegerVariable var : modified_vars_.PositionsSetAtLeastOnce()) { - if (var >= num_nodes) - continue; + if (var >= num_nodes) continue; const ArcIndex parent_arc_index = bf_parent_arc_of_[var.value()]; if (parent_arc_index != -1) { arcs_[parent_arc_index].is_marked = false; @@ -576,18 +532,13 @@ void PrecedencesPropagator::CleanUpMarkedArcsAndParents() { } } DCHECK(std::none_of(bf_parent_arc_of_.begin(), bf_parent_arc_of_.end(), - [](ArcIndex v) { - return v != -1; - })); + [](ArcIndex v) { return v != -1; })); DCHECK(std::none_of(bf_can_be_skipped_.begin(), bf_can_be_skipped_.end(), - [](bool v) { - return v; - })); + [](bool v) { return v; })); } -bool -PrecedencesPropagator::DisassembleSubtree(int source, int target, - std::vector *can_be_skipped) { +bool PrecedencesPropagator::DisassembleSubtree( + int source, int target, std::vector *can_be_skipped) { // Note that we explore a tree, so we can do it in any order, and the one // below seems to be the fastest. tmp_vector_.clear(); @@ -598,9 +549,8 @@ PrecedencesPropagator::DisassembleSubtree(int source, int target, for (const ArcIndex arc_index : impacted_arcs_[IntegerVariable(tail)]) { const ArcInfo &arc = arcs_[arc_index]; if (arc.is_marked) { - arc.is_marked = false; // mutable. - if (arc.head_var.value() == target) - return true; + arc.is_marked = false; // mutable. + if (arc.head_var.value() == target) return true; DCHECK(!(*can_be_skipped)[arc.head_var.value()]); (*can_be_skipped)[arc.head_var.value()] = true; tmp_vector_.push_back(arc.head_var.value()); @@ -631,8 +581,7 @@ void PrecedencesPropagator::AnalyzePositiveCycle( while (arc_on_cycle.size() <= num_nodes) { arc_on_cycle.push_back(arc_index); const ArcInfo &arc = arcs_[arc_index]; - if (arc.tail_var == first_arc_head) - break; + if (arc.tail_var == first_arc_head) break; arc_index = bf_parent_arc_of_[arc.tail_var.value()]; CHECK_NE(arc_index, ArcIndex(-1)); } @@ -676,9 +625,8 @@ bool PrecedencesPropagator::BellmanFordTarjan(Trail *trail) { // These vector are reset by CleanUpMarkedArcsAndParents() so resize is ok. bf_can_be_skipped_.resize(num_nodes, false); bf_parent_arc_of_.resize(num_nodes, ArcIndex(-1)); - const auto cleanup = ::absl::MakeCleanup([this]() { - CleanUpMarkedArcsAndParents(); - }); + const auto cleanup = + ::absl::MakeCleanup([this]() { CleanUpMarkedArcsAndParents(); }); // The queue initialization is done by InitializeBFQueueWithModifiedNodes(). while (!bf_queue_.empty()) { @@ -707,10 +655,8 @@ bool PrecedencesPropagator::BellmanFordTarjan(Trail *trail) { DCHECK_EQ(arc.tail_var, node); const IntegerValue candidate = tail_lb + ArcOffset(arc); if (candidate > integer_trail_->LowerBound(arc.head_var)) { - if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) - continue; - if (!EnqueueAndCheck(arc, candidate, trail)) - return false; + if (integer_trail_->IsCurrentlyIgnored(arc.head_var)) continue; + if (!EnqueueAndCheck(arc, candidate, trail)) return false; // This is the Tarjan contribution to Bellman-Ford. This code detect // positive cycle, and because it disassemble the subtree while doing @@ -736,8 +682,7 @@ bool PrecedencesPropagator::BellmanFordTarjan(Trail *trail) { } } for (const Literal l : must_be_all_true) { - if (trail_->Assignment().LiteralIsTrue(l)) - continue; + if (trail_->Assignment().LiteralIsTrue(l)) continue; integer_trail_->EnqueueLiteral(l, literal_reason_, integer_reason_); } @@ -787,34 +732,29 @@ bool PrecedencesPropagator::BellmanFordTarjan(Trail *trail) { int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraintsFromClause( const absl::Span clause, Model *model) { CHECK_EQ(model->GetOrCreate()->CurrentDecisionLevel(), 0); - if (clause.size() < 2) - return 0; + if (clause.size() < 2) return 0; // Collect all arcs impacted by this clause. std::vector infos; for (const Literal l : clause) { - if (l.Index() >= literal_to_new_impacted_arcs_.size()) - continue; + if (l.Index() >= literal_to_new_impacted_arcs_.size()) continue; for (const ArcIndex arc_index : literal_to_new_impacted_arcs_[l.Index()]) { const ArcInfo &arc = arcs_[arc_index]; - if (arc.presence_literals.size() != 1) - continue; + if (arc.presence_literals.size() != 1) continue; // TODO(user): Support variable offset. - if (arc.offset_var != kNoIntegerVariable) - continue; + if (arc.offset_var != kNoIntegerVariable) continue; infos.push_back(arc); } } - if (infos.size() <= 1) - return 0; + if (infos.size() <= 1) return 0; - // Stable sort by head_var so that for a same head_var, the entry are sorted - // by Literal as they appear in clause. + // Stable sort by head_var so that for a same head_var, the entry are sorted + // by Literal as they appear in clause. std::stable_sort(infos.begin(), infos.end(), - [](const ArcInfo & a, const ArcInfo & b) { - return a.head_var < b.head_var; - }); + [](const ArcInfo &a, const ArcInfo &b) { + return a.head_var < b.head_var; + }); // We process ArcInfo with the same head_var toghether. int num_added_constraints = 0; @@ -827,14 +767,12 @@ int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraintsFromClause( const absl::Span arcs(&infos[start], i - start); // Skip single arcs since it will already be fully propagated. - if (arcs.size() < 2) - continue; + if (arcs.size() < 2) continue; // Heuristic. Look for full or almost full clauses. We could add // GreaterThanAtLeastOneOf() with more enforcement literals. TODO(user): // experiments. - if (arcs.size() + 1 < clause.size()) - continue; + if (arcs.size() + 1 < clause.size()) continue; std::vector vars; std::vector offsets; @@ -863,14 +801,12 @@ int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraintsFromClause( // No point adding a constraint if there is not at least two different // literals in selectors. - if (enforcements.size() + 1 == clause.size()) - continue; + if (enforcements.size() + 1 == clause.size()) continue; ++num_added_constraints; model->Add(GreaterThanAtLeastOneOf(head_var, vars, offsets, selectors, enforcements)); - if (!solver->FinishPropagation()) - return num_added_constraints; + if (!solver->FinishPropagation()) return num_added_constraints; } return num_added_constraints; } @@ -886,12 +822,9 @@ int PrecedencesPropagator:: const ArcInfo &arc = arcs_[arc_index]; // Only keep arc that have a fixed offset and a single presence_literals. - if (arc.offset_var != kNoIntegerVariable) - continue; - if (arc.tail_var == arc.head_var) - continue; - if (arc.presence_literals.size() != 1) - continue; + if (arc.offset_var != kNoIntegerVariable) continue; + if (arc.tail_var == arc.head_var) continue; + if (arc.presence_literals.size() != 1) continue; if (arc.head_var >= incoming_arcs_.size()) { incoming_arcs_.resize(arc.head_var.value() + 1); @@ -901,27 +834,22 @@ int PrecedencesPropagator:: int num_added_constraints = 0; for (IntegerVariable target(0); target < incoming_arcs_.size(); ++target) { - if (incoming_arcs_[target].size() <= 1) - continue; - if (time_limit->LimitReached()) - return num_added_constraints; + if (incoming_arcs_[target].size() <= 1) continue; + if (time_limit->LimitReached()) return num_added_constraints; // Detect set of incoming arcs for which at least one must be present. // TODO(user): Find more than one disjoint set of incoming arcs. // TODO(user): call MinimizeCoreWithPropagation() on the clause. solver->Backtrack(0); - if (solver->IsModelUnsat()) - return num_added_constraints; + if (solver->IsModelUnsat()) return num_added_constraints; std::vector clause; for (const ArcIndex arc_index : incoming_arcs_[target]) { const Literal literal = arcs_[arc_index].presence_literals.front(); - if (solver->Assignment().LiteralIsFalse(literal)) - continue; + if (solver->Assignment().LiteralIsFalse(literal)) continue; const int old_level = solver->CurrentDecisionLevel(); solver->EnqueueDecisionAndBacktrackOnConflict(literal.Negated()); - if (solver->IsModelUnsat()) - return num_added_constraints; + if (solver->IsModelUnsat()) return num_added_constraints; const int new_level = solver->CurrentDecisionLevel(); if (new_level <= old_level) { clause = solver->GetLastIncompatibleDecisions(); @@ -953,8 +881,7 @@ int PrecedencesPropagator:: selectors.push_back(Literal(arcs_[a].presence_literals.front())); } model->Add(GreaterThanAtLeastOneOf(target, vars, offsets, selectors)); - if (!solver->FinishPropagation()) - return num_added_constraints; + if (!solver->FinishPropagation()) return num_added_constraints; } } @@ -983,10 +910,8 @@ int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraints(Model *model) { // - The automatic clause detection might be a better approach and it // could be combined with probing. for (const SatClause *clause : clauses->AllClausesInCreationOrder()) { - if (time_limit->LimitReached()) - return num_added_constraints; - if (solver->IsModelUnsat()) - return num_added_constraints; + if (time_limit->LimitReached()) return num_added_constraints; + if (solver->IsModelUnsat()) return num_added_constraints; num_added_constraints += AddGreaterThanAtLeastOneOfConstraintsFromClause( clause->AsSpan(), model); } @@ -1000,5 +925,5 @@ int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraints(Model *model) { return num_added_constraints; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/precedences.h b/ortools/sat/precedences.h index 3560d0d4b1..0aa9a4ce4a 100644 --- a/ortools/sat/precedences.h +++ b/ortools/sat/precedences.h @@ -109,10 +109,10 @@ class PrecedencesPropagator : public SatPropagator, PropagatorInterface { // // Important: For identical vars, the entry are sorted by index. struct IntegerPrecedences { - int index; // position in vars. - IntegerVariable var; // An IntegerVariable that is >= to vars[index]. - int arc_index; // Used by AddPrecedenceReason(). - IntegerValue offset; // we have: vars[index] + offset <= var + int index; // position in vars. + IntegerVariable var; // An IntegerVariable that is >= to vars[index]. + int arc_index; // Used by AddPrecedenceReason(). + IntegerValue offset; // we have: vars[index] + offset <= var }; void ComputePrecedences(const std::vector &vars, std::vector *output); @@ -153,7 +153,7 @@ class PrecedencesPropagator : public SatPropagator, PropagatorInterface { IntegerVariable head_var; IntegerValue offset; - IntegerVariable offset_var; // kNoIntegerVariable if none. + IntegerVariable offset_var; // kNoIntegerVariable if none. // This arc is "present" iff all these literals are true. absl::InlinedVector presence_literals; @@ -294,37 +294,30 @@ class PrecedencesPropagator : public SatPropagator, PropagatorInterface { inline void PrecedencesPropagator::AddPrecedence(IntegerVariable i1, IntegerVariable i2) { - AddArc(i1, i2, /*offset=*/ IntegerValue(0), - /*offset_var=*/ kNoIntegerVariable, { - }); + AddArc(i1, i2, /*offset=*/IntegerValue(0), + /*offset_var=*/kNoIntegerVariable, {}); } inline void PrecedencesPropagator::AddPrecedenceWithOffset( IntegerVariable i1, IntegerVariable i2, IntegerValue offset) { - AddArc(i1, i2, offset, /*offset_var=*/ kNoIntegerVariable, { - }); + AddArc(i1, i2, offset, /*offset_var=*/kNoIntegerVariable, {}); } inline void PrecedencesPropagator::AddConditionalPrecedence(IntegerVariable i1, IntegerVariable i2, Literal l) { - AddArc(i1, i2, /*offset=*/ IntegerValue(0), - /*offset_var=*/ kNoIntegerVariable, { - l - }); + AddArc(i1, i2, /*offset=*/IntegerValue(0), + /*offset_var=*/kNoIntegerVariable, {l}); } inline void PrecedencesPropagator::AddConditionalPrecedenceWithOffset( IntegerVariable i1, IntegerVariable i2, IntegerValue offset, Literal l) { - AddArc(i1, i2, offset, /*offset_var=*/ kNoIntegerVariable, { - l - }); + AddArc(i1, i2, offset, /*offset_var=*/kNoIntegerVariable, {l}); } inline void PrecedencesPropagator::AddPrecedenceWithVariableOffset( IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var) { - AddArc(i1, i2, /*offset=*/ IntegerValue(0), offset_var, { - }); + AddArc(i1, i2, /*offset=*/IntegerValue(0), offset_var, {}); } inline void PrecedencesPropagator::AddPrecedenceWithAllOptions( @@ -340,21 +333,19 @@ inline void PrecedencesPropagator::AddPrecedenceWithAllOptions( // a <= b. inline std::function LowerOrEqual(IntegerVariable a, IntegerVariable b) { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->AddPrecedence(a, b); - } - ; + }; } // a + offset <= b. inline std::function LowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64 offset) { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->AddPrecedenceWithOffset( a, b, IntegerValue(offset)); - } - ; + }; } // a + b <= ub. @@ -365,15 +356,14 @@ inline std::function Sum2LowerOrEqual(IntegerVariable a, } // l => (a + b <= ub). -inline std::function -ConditionalSum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64 ub, - const std::vector &enforcement_literals) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); +inline std::function ConditionalSum2LowerOrEqual( + IntegerVariable a, IntegerVariable b, int64 ub, + const std::vector &enforcement_literals) { + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); p->AddPrecedenceWithAllOptions(a, NegationOf(b), IntegerValue(-ub), kNoIntegerVariable, enforcement_literals); - } - ; + }; } // a + b + c <= ub. @@ -381,64 +371,57 @@ inline std::function Sum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64 ub) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); - p->AddPrecedenceWithAllOptions(a, NegationOf(c), IntegerValue(-ub), b, { - }); - } - ; + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); + p->AddPrecedenceWithAllOptions(a, NegationOf(c), IntegerValue(-ub), b, {}); + }; } // l => (a + b + c <= ub). -inline std::function -ConditionalSum3LowerOrEqual(IntegerVariable a, IntegerVariable b, - IntegerVariable c, int64 ub, - const std::vector &enforcement_literals) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); +inline std::function ConditionalSum3LowerOrEqual( + IntegerVariable a, IntegerVariable b, IntegerVariable c, int64 ub, + const std::vector &enforcement_literals) { + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); p->AddPrecedenceWithAllOptions(a, NegationOf(c), IntegerValue(-ub), b, enforcement_literals); - } - ; + }; } // a >= b. inline std::function GreaterOrEqual(IntegerVariable a, IntegerVariable b) { - return[ = ](Model * model) { + return [=](Model *model) { return model->GetOrCreate()->AddPrecedence(b, a); - } - ; + }; } // a == b. inline std::function Equality(IntegerVariable a, IntegerVariable b) { - return[ = ](Model * model) { model->Add(LowerOrEqual(a, b)); + return [=](Model *model) { + model->Add(LowerOrEqual(a, b)); model->Add(LowerOrEqual(b, a)); - } - ; + }; } // a + offset == b. inline std::function EqualityWithOffset(IntegerVariable a, IntegerVariable b, int64 offset) { - return[ = ](Model * model) { model->Add(LowerOrEqualWithOffset(a, b, offset)); + return [=](Model *model) { + model->Add(LowerOrEqualWithOffset(a, b, offset)); model->Add(LowerOrEqualWithOffset(b, a, -offset)); - } - ; + }; } // is_le => (a + offset <= b). -inline std::function -ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, - int64 offset, Literal is_le) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); +inline std::function ConditionalLowerOrEqualWithOffset( + IntegerVariable a, IntegerVariable b, int64 offset, Literal is_le) { + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); p->AddConditionalPrecedenceWithOffset(a, b, IntegerValue(offset), is_le); - } - ; + }; } // is_le => (a <= b). @@ -449,38 +432,34 @@ inline std::function ConditionalLowerOrEqual(IntegerVariable a, } // literals => (a <= b). -inline std::function -ConditionalLowerOrEqual(IntegerVariable a, IntegerVariable b, - absl::Span literals) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); +inline std::function ConditionalLowerOrEqual( + IntegerVariable a, IntegerVariable b, absl::Span literals) { + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); p->AddPrecedenceWithAllOptions(a, b, IntegerValue(0), /*offset_var*/ kNoIntegerVariable, literals); - } - ; + }; } // is_le <=> (a + offset <= b). -inline std::function -ReifiedLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, - int64 offset, Literal is_le) { - return[ = ](Model *model) { PrecedencesPropagator *p = - model->GetOrCreate(); +inline std::function ReifiedLowerOrEqualWithOffset( + IntegerVariable a, IntegerVariable b, int64 offset, Literal is_le) { + return [=](Model *model) { + PrecedencesPropagator *p = model->GetOrCreate(); p->AddConditionalPrecedenceWithOffset(a, b, IntegerValue(offset), is_le); // The negation of (a + offset <= b) is (a + offset > b) which can be // rewritten as (b + 1 - offset <= a). p->AddConditionalPrecedenceWithOffset(b, a, IntegerValue(1 - offset), is_le.Negated()); - } - ; + }; } // is_eq <=> (a == b). inline std::function ReifiedEquality(IntegerVariable a, IntegerVariable b, Literal is_eq) { - return[ = ](Model *model) { + return [=](Model *model) { // We creates two extra Boolean variables in this case. // // TODO(user): Avoid creating them if we already have some literal that @@ -488,14 +467,10 @@ inline std::function ReifiedEquality(IntegerVariable a, // a <= b, he would have called ReifiedLowerOrEqualWithOffset() directly. const Literal is_le = Literal(model->Add(NewBooleanVariable()), true); const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true); - model->Add(ReifiedBoolAnd({ - is_le, is_ge - }, - is_eq)); + model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq)); model->Add(ReifiedLowerOrEqualWithOffset(a, b, 0, is_le)); model->Add(ReifiedLowerOrEqualWithOffset(b, a, 0, is_ge)); - } - ; + }; } // is_eq <=> (a + offset == b). @@ -503,7 +478,7 @@ inline std::function ReifiedEqualityWithOffset(IntegerVariable a, IntegerVariable b, int64 offset, Literal is_eq) { - return[ = ](Model *model) { + return [=](Model *model) { // We creates two extra Boolean variables in this case. // // TODO(user): Avoid creating them if we already have some literal that @@ -511,30 +486,25 @@ inline std::function ReifiedEqualityWithOffset(IntegerVariable a, // a <= b, he would have called ReifiedLowerOrEqualWithOffset() directly. const Literal is_le = Literal(model->Add(NewBooleanVariable()), true); const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true); - model->Add(ReifiedBoolAnd({ - is_le, is_ge - }, - is_eq)); + model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq)); model->Add(ReifiedLowerOrEqualWithOffset(a, b, offset, is_le)); model->Add(ReifiedLowerOrEqualWithOffset(b, a, -offset, is_ge)); - } - ; + }; } // a != b. inline std::function NotEqual(IntegerVariable a, IntegerVariable b) { - return[ = ](Model *model) { + return [=](Model *model) { // We have two options (is_gt or is_lt) and one must be true. const Literal is_lt = Literal(model->Add(NewBooleanVariable()), true); const Literal is_gt = is_lt.Negated(); model->Add(ConditionalLowerOrEqualWithOffset(a, b, 1, is_lt)); model->Add(ConditionalLowerOrEqualWithOffset(b, a, 1, is_gt)); - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PRECEDENCES_H_ +#endif // OR_TOOLS_SAT_PRECEDENCES_H_ diff --git a/ortools/sat/presolve_context.cc b/ortools/sat/presolve_context.cc index af104235c9..992844d164 100644 --- a/ortools/sat/presolve_context.cc +++ b/ortools/sat/presolve_context.cc @@ -143,8 +143,8 @@ int64 PresolveContext::MaxOf(const LinearExpressionProto &expr) const { // Important: To be sure a variable can be removed, we need it to not be a // representative of both affine and equivalence relation. -bool -PresolveContext::VariableIsNotRepresentativeOfEquivalenceClass(int var) const { +bool PresolveContext::VariableIsNotRepresentativeOfEquivalenceClass( + int var) const { DCHECK(RefIsPositive(var)); if (affine_relations_.ClassSize(var) > 1 && affine_relations_.Get(var).representative == var) { @@ -162,8 +162,7 @@ PresolveContext::VariableIsNotRepresentativeOfEquivalenceClass(int var) const { // be the affine defining one. And in this case the code using this function // should do the proper stuff. bool PresolveContext::VariableIsUniqueAndRemovable(int ref) const { - if (!ConstraintVariableGraphIsUpToDate()) - return false; + if (!ConstraintVariableGraphIsUpToDate()) return false; const int var = PositiveRef(ref); return var_to_constraints_[var].size() == 1 && VariableIsNotRepresentativeOfEquivalenceClass(var) && @@ -172,8 +171,7 @@ bool PresolveContext::VariableIsUniqueAndRemovable(int ref) const { // Tricky: Same remark as for VariableIsUniqueAndRemovable(). bool PresolveContext::VariableWithCostIsUniqueAndRemovable(int ref) const { - if (!ConstraintVariableGraphIsUpToDate()) - return false; + if (!ConstraintVariableGraphIsUpToDate()) return false; const int var = PositiveRef(ref); return !keep_all_feasible_solutions && var_to_constraints_[var].contains(kObjectiveConstraint) && @@ -184,8 +182,7 @@ bool PresolveContext::VariableWithCostIsUniqueAndRemovable(int ref) const { // Here, even if the variable is equivalent to others, if its affine defining // constraints where removed, then it is not needed anymore. bool PresolveContext::VariableIsNotUsedAnymore(int ref) const { - if (!ConstraintVariableGraphIsUpToDate()) - return false; + if (!ConstraintVariableGraphIsUpToDate()) return false; return var_to_constraints_[PositiveRef(ref)].empty(); } @@ -198,10 +195,8 @@ void PresolveContext::MarkVariableAsRemoved(int ref) { // return false in the cases where it is used. bool PresolveContext::VariableWasRemoved(int ref) const { // It is okay to reuse removed fixed variable. - if (IsFixed(ref)) - return false; - if (!removed_variables_.contains(PositiveRef(ref))) - return false; + if (IsFixed(ref)) return false; + if (!removed_variables_.contains(PositiveRef(ref))) return false; if (!var_to_constraints_[PositiveRef(ref)].empty()) { const AffineRelation::Relation r = GetAffineRelation(PositiveRef(ref)); LOG(INFO) << "Variable " << PositiveRef(ref) @@ -209,17 +204,16 @@ bool PresolveContext::VariableWasRemoved(int ref) const { LOG(INFO) << "affine relation = " << r.coeff << " * X" << r.representative << " + " << r.offset; for (const int c : var_to_constraints_[PositiveRef(ref)]) { - LOG(INFO) - << "constraint #" << c << " : " - << (c >= 0 ? working_model->constraints(c).ShortDebugString() : ""); + LOG(INFO) << "constraint #" << c << " : " + << (c >= 0 ? working_model->constraints(c).ShortDebugString() + : ""); } } return true; } bool PresolveContext::VariableIsOnlyUsedInEncoding(int ref) const { - if (!ConstraintVariableGraphIsUpToDate()) - return false; + if (!ConstraintVariableGraphIsUpToDate()) return false; const int var = PositiveRef(ref); return var_to_num_linear1_[var] == var_to_constraints_[var].size(); } @@ -241,9 +235,8 @@ bool PresolveContext::DomainContains(int ref, int64 value) const { return domains[ref].Contains(value); } -ABSL_MUST_USE_RESULT bool -PresolveContext::IntersectDomainWith(int ref, const Domain &domain, - bool *domain_modified) { +ABSL_MUST_USE_RESULT bool PresolveContext::IntersectDomainWith( + int ref, const Domain &domain, bool *domain_modified) { DCHECK(!DomainIsEmpty(ref)); const int var = PositiveRef(ref); @@ -272,10 +265,10 @@ PresolveContext::IntersectDomainWith(int ref, const Domain &domain, // Propagate the domain of the representative right away. // Note that the recursive call should only by one level deep. const AffineRelation::Relation r = GetAffineRelation(var); - if (r.representative == var) - return true; + if (r.representative == var) return true; return IntersectDomainWith(r.representative, - DomainOf(var).AdditionWith(Domain(-r.offset)) + DomainOf(var) + .AdditionWith(Domain(-r.offset)) .InverseMultiplicationBy(r.coeff)); } @@ -318,23 +311,19 @@ void PresolveContext::AddVariableUsage(int c) { DCHECK(!VariableWasRemoved(v)); var_to_constraints_[v].insert(c); } - for (const int i : constraint_to_intervals_[c]) - interval_usage_[i]++; + for (const int i : constraint_to_intervals_[c]) interval_usage_[i]++; UpdateLinear1Usage(ct, c); } void PresolveContext::UpdateConstraintVariableUsage(int c) { - if (is_unsat) - return; + if (is_unsat) return; DCHECK_EQ(constraint_to_vars_.size(), working_model->constraints_size()); const ConstraintProto &ct = working_model->constraints(c); // We don't optimize the interval usage as this is not super frequent. - for (const int i : constraint_to_intervals_[c]) - interval_usage_[i]--; + for (const int i : constraint_to_intervals_[c]) interval_usage_[i]--; constraint_to_intervals_[c] = UsedIntervals(ct); - for (const int i : constraint_to_intervals_[c]) - interval_usage_[i]++; + for (const int i : constraint_to_intervals_[c]) interval_usage_[i]++; // For the variables, we avoid an erase() followed by an insert() for the // variables that didn't change. @@ -354,8 +343,7 @@ void PresolveContext::UpdateConstraintVariableUsage(int c) { var_to_constraints_[var].insert(c); } } - for (; i < old_size; ++i) - var_to_constraints_[old_usage[i]].erase(c); + for (; i < old_size; ++i) var_to_constraints_[old_usage[i]].erase(c); constraint_to_vars_[c] = tmp_new_usage_; UpdateLinear1Usage(ct, c); @@ -366,8 +354,7 @@ bool PresolveContext::ConstraintVariableGraphIsUpToDate() const { } void PresolveContext::UpdateNewConstraintsVariableUsage() { - if (is_unsat) - return; + if (is_unsat) return; const int old_size = constraint_to_vars_.size(); const int new_size = working_model->constraints_size(); CHECK_LE(old_size, new_size); @@ -382,8 +369,7 @@ void PresolveContext::UpdateNewConstraintsVariableUsage() { // TODO(user): Also test var_to_constraints_ !! bool PresolveContext::ConstraintVariableUsageIsConsistent() { - if (is_unsat) - return true; // We do not care in this case. + if (is_unsat) return true; // We do not care in this case. if (constraint_to_vars_.size() != working_model->constraints_size()) { LOG(INFO) << "Wrong constraint_to_vars size!"; return false; @@ -430,8 +416,7 @@ bool PresolveContext::AddRelation(int x, int y, int64 c, int64 o, AffineRelation *repo) { // When the coefficient is larger than one, then if later one variable becomes // Boolean, it must be the representative. - if (std::abs(c) != 1) - return repo->TryAdd(x, y, c, o); + if (std::abs(c) != 1) return repo->TryAdd(x, y, c, o); CHECK(!VariableWasRemoved(x)); CHECK(!VariableWasRemoved(y)); @@ -486,18 +471,19 @@ void PresolveContext::ExploitFixedDomain(int var) { bool PresolveContext::PropagateAffineRelation(int ref) { const int var = PositiveRef(ref); const AffineRelation::Relation r = GetAffineRelation(var); - if (r.representative == var) - return true; + if (r.representative == var) return true; // Propagate domains both ways. // var = coeff * rep + offset if (!IntersectDomainWith(r.representative, - DomainOf(var).AdditionWith(Domain(-r.offset)) + DomainOf(var) + .AdditionWith(Domain(-r.offset)) .InverseMultiplicationBy(r.coeff))) { return false; } - if (!IntersectDomainWith(var, DomainOf(r.representative).MultiplicationBy( - r.coeff).AdditionWith(Domain(r.offset)))) { + if (!IntersectDomainWith(var, DomainOf(r.representative) + .MultiplicationBy(r.coeff) + .AdditionWith(Domain(r.offset)))) { return false; } @@ -548,15 +534,12 @@ void PresolveContext::RemoveVariableFromAffineRelation(int var) { bool PresolveContext::StoreAffineRelation(int ref_x, int ref_y, int64 coeff, int64 offset) { CHECK_NE(coeff, 0); - if (is_unsat) - return false; + if (is_unsat) return false; // TODO(user): I am not 100% sure why, but sometimes the representative is // fixed but that is not propagated to ref_x or ref_y and this causes issues. - if (!PropagateAffineRelation(ref_x)) - return true; - if (!PropagateAffineRelation(ref_y)) - return true; + if (!PropagateAffineRelation(ref_x)) return true; + if (!PropagateAffineRelation(ref_y)) return true; if (IsFixed(ref_x)) { const int64 lhs = DomainOf(ref_x).Min() - offset; @@ -589,8 +572,7 @@ bool PresolveContext::StoreAffineRelation(int ref_x, int ref_y, int64 coeff, const int64 a = coeff * ry.coeff - rx.coeff; const int64 b = coeff * ry.offset + offset - rx.offset; if (a == 0) { - if (b != 0) - is_unsat = true; + if (b != 0) is_unsat = true; return true; } if (b % a != 0) { @@ -628,27 +610,21 @@ bool PresolveContext::StoreAffineRelation(int ref_x, int ref_y, int64 coeff, // Lets propagate again the new relation. We might as well do it as early // as possible and not all call site do it. - if (!PropagateAffineRelation(ref_x)) - return true; - if (!PropagateAffineRelation(ref_y)) - return true; + if (!PropagateAffineRelation(ref_x)) return true; + if (!PropagateAffineRelation(ref_y)) return true; // These maps should only contains representative, so only need to remap // either x or y. const int rep = GetAffineRelation(x).representative; - if (x != rep) - encoding_remap_queue_.push_back(x); - if (y != rep) - encoding_remap_queue_.push_back(y); + if (x != rep) encoding_remap_queue_.push_back(x); + if (y != rep) encoding_remap_queue_.push_back(y); // The domain didn't change, but this notification allows to re-process any // constraint containing these variables. Note that we do not need to // retrigger a propagation of the constraint containing a variable whose // representative didn't change. - if (x != rep) - modified_domains.Set(x); - if (y != rep) - modified_domains.Set(y); + if (x != rep) modified_domains.Set(x); + if (y != rep) modified_domains.Set(y); var_to_constraints_[x].insert(kAffineRelationConstraint); var_to_constraints_[y].insert(kAffineRelationConstraint); @@ -660,9 +636,7 @@ bool PresolveContext::StoreAffineRelation(int ref_x, int ref_y, int64 coeff, LOG(INFO) << "Cannot add relation " << DomainOf(ref_x) << " = " << coeff << " * " << DomainOf(ref_y) << " + " << offset << " because of incompatibilities with existing relation: "; - for (const int ref : { - ref_x, ref_y - }) { + for (const int ref : {ref_x, ref_y}) { const auto r = GetAffineRelation(ref); LOG(INFO) << DomainOf(ref) << " = " << r.coeff << " * " << DomainOf(r.representative) << " + " << r.offset; @@ -673,8 +647,7 @@ bool PresolveContext::StoreAffineRelation(int ref_x, int ref_y, int64 coeff, } void PresolveContext::StoreBooleanEqualityRelation(int ref_a, int ref_b) { - if (is_unsat) - return; + if (is_unsat) return; CHECK(!VariableWasRemoved(ref_a)); CHECK(!VariableWasRemoved(ref_b)); @@ -683,8 +656,7 @@ void PresolveContext::StoreBooleanEqualityRelation(int ref_a, int ref_b) { CHECK(CanBeUsedAsLiteral(ref_a)); CHECK(CanBeUsedAsLiteral(ref_b)); - if (ref_a == ref_b) - return; + if (ref_a == ref_b) return; if (ref_a == NegatedRef(ref_b)) { is_unsat = true; return; @@ -693,10 +665,10 @@ void PresolveContext::StoreBooleanEqualityRelation(int ref_a, int ref_b) { const int var_b = PositiveRef(ref_b); if (RefIsPositive(ref_a) == RefIsPositive(ref_b)) { // a = b - CHECK(StoreAffineRelation(var_a, var_b, /*coeff=*/ 1, /*offset=*/ 0)); + CHECK(StoreAffineRelation(var_a, var_b, /*coeff=*/1, /*offset=*/0)); } else { // a = 1 - b - CHECK(StoreAffineRelation(var_a, var_b, /*coeff=*/ -1, /*offset=*/ 1)); + CHECK(StoreAffineRelation(var_a, var_b, /*coeff=*/-1, /*offset=*/1)); } } @@ -717,8 +689,7 @@ bool PresolveContext::StoreAbsRelation(int target_ref, int ref) { bool PresolveContext::GetAbsRelation(int target_ref, int *ref) { auto it = abs_relations_.find(target_ref); - if (it == abs_relations_.end()) - return false; + if (it == abs_relations_.end()) return false; // Tricky: In some rare case the stored relation can refer to a deleted // variable, so we need to ignore it. @@ -777,8 +748,7 @@ AffineRelation::Relation PresolveContext::GetAffineRelation(int ref) const { AffineRelation::Relation r = affine_relations_.Get(PositiveRef(ref)); AffineRelation::Relation o = var_equiv_relations_.Get(r.representative); r.representative = o.representative; - if (o.coeff == -1) - r.coeff = -r.coeff; + if (o.coeff == -1) r.coeff = -r.coeff; if (!RefIsPositive(ref)) { r.coeff *= -1; r.offset *= -1; @@ -794,8 +764,7 @@ void PresolveContext::InitializeNewDomains() { is_unsat = true; return; } - if (IsFixed(i)) - ExploitFixedDomain(i); + if (IsFixed(i)) ExploitFixedDomain(i); } modified_domains.Resize(domains.size()); var_to_constraints_.resize(domains.size()); @@ -822,8 +791,7 @@ bool PresolveContext::RemapEncodingMaps() { for (const int var : encoding_remap_queue_) { CHECK(RefIsPositive(var)); const AffineRelation::Relation r = GetAffineRelation(var); - if (r.representative == var) - return true; + if (r.representative == var) return true; int num_remapping = 0; // Encoding. @@ -831,16 +799,13 @@ bool PresolveContext::RemapEncodingMaps() { const absl::flat_hash_map &var_map = encoding_[var]; for (const auto &entry : var_map) { const int lit = entry.second.Get(this); - if (removed_variables_.contains(PositiveRef(lit))) - continue; - if ((entry.first - r.offset) % r.coeff != 0) - continue; + if (removed_variables_.contains(PositiveRef(lit))) continue; + if ((entry.first - r.offset) % r.coeff != 0) continue; const int64 rep_value = (entry.first - r.offset) / r.coeff; ++num_remapping; InsertVarValueEncodingInternal(lit, r.representative, rep_value, - /*add_constraints=*/ false); - if (is_unsat) - return false; + /*add_constraints=*/false); + if (is_unsat) return false; } encoding_.erase(var); } @@ -850,16 +815,14 @@ bool PresolveContext::RemapEncodingMaps() { const absl::flat_hash_map > &var_map = eq_half_encoding_[var]; for (const auto &entry : var_map) { - if ((entry.first - r.offset) % r.coeff != 0) - continue; + if ((entry.first - r.offset) % r.coeff != 0) continue; const int64 rep_value = (entry.first - r.offset) / r.coeff; for (int literal : entry.second) { ++num_remapping; InsertHalfVarValueEncoding(GetLiteralRepresentative(literal), r.representative, rep_value, - /*imply_eq=*/ true); - if (is_unsat) - return false; + /*imply_eq=*/true); + if (is_unsat) return false; } } eq_half_encoding_.erase(var); @@ -870,16 +833,14 @@ bool PresolveContext::RemapEncodingMaps() { const absl::flat_hash_map > &var_map = neq_half_encoding_[var]; for (const auto &entry : var_map) { - if ((entry.first - r.offset) % r.coeff != 0) - continue; + if ((entry.first - r.offset) % r.coeff != 0) continue; const int64 rep_value = (entry.first - r.offset) / r.coeff; for (int literal : entry.second) { ++num_remapping; InsertHalfVarValueEncoding(GetLiteralRepresentative(literal), r.representative, rep_value, - /*imply_eq=*/ false); - if (is_unsat) - return false; + /*imply_eq=*/false); + if (is_unsat) return false; } } neq_half_encoding_.erase(var); @@ -900,8 +861,7 @@ void PresolveContext::CanonicalizeDomainOfSizeTwo(int var) { const int64 var_min = MinOf(var); const int64 var_max = MaxOf(var); - if (is_unsat) - return; + if (is_unsat) return; absl::flat_hash_map &var_map = encoding_[var]; @@ -934,13 +894,11 @@ void PresolveContext::CanonicalizeDomainOfSizeTwo(int var) { if (min_literal != NegatedRef(max_literal)) { UpdateRuleStats("variables with 2 values: merge encoding literals"); StoreBooleanEqualityRelation(min_literal, NegatedRef(max_literal)); - if (is_unsat) - return; + if (is_unsat) return; } min_literal = GetLiteralRepresentative(min_literal); max_literal = GetLiteralRepresentative(max_literal); - if (!IsFixed(min_literal)) - CHECK_EQ(min_literal, NegatedRef(max_literal)); + if (!IsFixed(min_literal)) CHECK_EQ(min_literal, NegatedRef(max_literal)); } else if (min_it != var_map.end() && max_it == var_map.end()) { UpdateRuleStats("variables with 2 values: register other encoding"); min_literal = min_it->second.Get(this); @@ -1033,16 +991,14 @@ void PresolveContext::InsertVarValueEncodingInternal(int literal, int var, bool PresolveContext::InsertHalfVarValueEncoding(int literal, int var, int64 value, bool imply_eq) { - if (is_unsat) - return false; + if (is_unsat) return false; CHECK(RefIsPositive(var)); // Creates the linking sets on demand. // Insert the enforcement literal in the half encoding map. auto &direct_set = imply_eq ? eq_half_encoding_[var][value] : neq_half_encoding_[var][value]; - if (!direct_set.insert(literal).second) - return false; // Already there. + if (!direct_set.insert(literal).second) return false; // Already there. VLOG(2) << "Collect lit(" << literal << ") implies var(" << var << (imply_eq ? ") == " : ") != ") << value; @@ -1053,13 +1009,12 @@ bool PresolveContext::InsertHalfVarValueEncoding(int literal, int var, auto &other_set = imply_eq ? neq_half_encoding_[var][value] : eq_half_encoding_[var][value]; for (const int other : other_set) { - if (GetLiteralRepresentative(other) != NegatedRef(literal)) - continue; + if (GetLiteralRepresentative(other) != NegatedRef(literal)) continue; UpdateRuleStats("variables: detect fully reified value encoding"); const int imply_eq_literal = imply_eq ? literal : NegatedRef(literal); InsertVarValueEncodingInternal(imply_eq_literal, var, value, - /*add_constraints=*/ false); + /*add_constraints=*/false); break; } @@ -1068,8 +1023,7 @@ bool PresolveContext::InsertHalfVarValueEncoding(int literal, int var, bool PresolveContext::CanonicalizeEncoding(int *ref, int64 *value) { const AffineRelation::Relation r = GetAffineRelation(*ref); - if ((*value - r.offset) % r.coeff != 0) - return false; + if ((*value - r.offset) % r.coeff != 0) return false; *ref = r.representative; *value = (*value - r.offset) / r.coeff; return true; @@ -1077,40 +1031,32 @@ bool PresolveContext::CanonicalizeEncoding(int *ref, int64 *value) { void PresolveContext::InsertVarValueEncoding(int literal, int ref, int64 value) { - if (!RemapEncodingMaps()) - return; - if (!CanonicalizeEncoding(&ref, &value)) - return; + if (!RemapEncodingMaps()) return; + if (!CanonicalizeEncoding(&ref, &value)) return; literal = GetLiteralRepresentative(literal); InsertVarValueEncodingInternal(literal, ref, value, - /*add_constraints=*/ true); + /*add_constraints=*/true); } bool PresolveContext::StoreLiteralImpliesVarEqValue(int literal, int var, int64 value) { - if (!RemapEncodingMaps()) - return false; - if (!CanonicalizeEncoding(&var, &value)) - return false; + if (!RemapEncodingMaps()) return false; + if (!CanonicalizeEncoding(&var, &value)) return false; literal = GetLiteralRepresentative(literal); - return InsertHalfVarValueEncoding(literal, var, value, /*imply_eq=*/ true); + return InsertHalfVarValueEncoding(literal, var, value, /*imply_eq=*/true); } bool PresolveContext::StoreLiteralImpliesVarNEqValue(int literal, int var, int64 value) { - if (!RemapEncodingMaps()) - return false; - if (!CanonicalizeEncoding(&var, &value)) - return false; + if (!RemapEncodingMaps()) return false; + if (!CanonicalizeEncoding(&var, &value)) return false; literal = GetLiteralRepresentative(literal); - return InsertHalfVarValueEncoding(literal, var, value, /*imply_eq=*/ false); + return InsertHalfVarValueEncoding(literal, var, value, /*imply_eq=*/false); } bool PresolveContext::HasVarValueEncoding(int ref, int64 value, int *literal) { - if (!RemapEncodingMaps()) - return false; - if (!CanonicalizeEncoding(&ref, &value)) - return false; + if (!RemapEncodingMaps()) return false; + if (!CanonicalizeEncoding(&ref, &value)) return false; const absl::flat_hash_map &var_map = encoding_[ref]; const auto it = var_map.find(value); if (it != var_map.end()) { @@ -1123,10 +1069,8 @@ bool PresolveContext::HasVarValueEncoding(int ref, int64 value, int *literal) { } int PresolveContext::GetOrCreateVarValueEncoding(int ref, int64 value) { - if (!RemapEncodingMaps()) - return GetOrCreateConstantVar(0); - if (!CanonicalizeEncoding(&ref, &value)) - return GetOrCreateConstantVar(0); + if (!RemapEncodingMaps()) return GetOrCreateConstantVar(0); + if (!CanonicalizeEncoding(&ref, &value)) return GetOrCreateConstantVar(0); // Positive after CanonicalizeEncoding(). const int var = ref; @@ -1205,8 +1149,7 @@ void PresolveContext::ReadObjectiveFromProto() { for (int i = 0; i < obj.vars_size(); ++i) { const int ref = obj.vars(i); int64 coeff = obj.coeffs(i); - if (!RefIsPositive(ref)) - coeff = -coeff; + if (!RefIsPositive(ref)) coeff = -coeff; int var = PositiveRef(ref); objective_map[var] += coeff; @@ -1237,8 +1180,7 @@ bool PresolveContext::CanonicalizeObjective() { for (const auto &entry : tmp_entries) { const int var = entry.first; const auto it = objective_map.find(var); - if (it == objective_map.end()) - continue; + if (it == objective_map.end()) continue; const int64 coeff = it->second; // If a variable only appear in objective, we can fix it! @@ -1268,8 +1210,7 @@ bool PresolveContext::CanonicalizeObjective() { } const AffineRelation::Relation r = GetAffineRelation(var); - if (r.representative == var) - continue; + if (r.representative == var) continue; objective_map.erase(var); var_to_constraints_[var].erase(kObjectiveConstraint); @@ -1313,7 +1254,7 @@ bool PresolveContext::CanonicalizeObjective() { // This is the new domain. // Note that the domain never include the offset. objective_domain = objective_domain.AdditionWith(Domain(-offset_change)) - .IntersectionWith(implied_domain); + .IntersectionWith(implied_domain); objective_domain = objective_domain.SimplifyUsingImpliedDomain(implied_domain); @@ -1330,14 +1271,15 @@ bool PresolveContext::CanonicalizeObjective() { objective_scaling_factor *= static_cast(gcd); } - if (objective_domain.IsEmpty()) - return false; + if (objective_domain.IsEmpty()) return false; // Detect if the objective domain do not limit the "optimal" objective value. // If this is true, then we can apply any reduction that reduce the objective // value without any issues. - objective_domain_is_constraining = !implied_domain.IntersectionWith(Domain( - kint64min, objective_domain.Max())).IsIncludedIn(objective_domain); + objective_domain_is_constraining = + !implied_domain + .IntersectionWith(Domain(kint64min, objective_domain.Max())) + .IsIncludedIn(objective_domain); return true; } @@ -1347,8 +1289,7 @@ void PresolveContext::SubstituteVariableInObjective( CHECK(equality.enforcement_literal().empty()); CHECK(RefIsPositive(var_in_equality)); - if (new_vars_in_objective != nullptr) - new_vars_in_objective->clear(); + if (new_vars_in_objective != nullptr) new_vars_in_objective->clear(); // We can only "easily" substitute if the objective coefficient is a multiple // of the one in the constraint. @@ -1365,8 +1306,7 @@ void PresolveContext::SubstituteVariableInObjective( var = NegatedRef(var); coeff = -coeff; } - if (var == var_in_equality) - continue; + if (var == var_in_equality) continue; int64 &map_ref = objective_map[var]; if (map_ref == 0 && new_vars_in_objective != nullptr) { @@ -1404,7 +1344,7 @@ void PresolveContext::SubstituteVariableInObjective( void PresolveContext::WriteObjectiveToProto() { if (objective_domain.IsEmpty()) { - return (void) NotifyThatModelIsUnsat(); + return (void)NotifyThatModelIsUnsat(); } // We need to sort the entries to be deterministic. @@ -1426,5 +1366,5 @@ void PresolveContext::WriteObjectiveToProto() { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/presolve_context.h b/ortools/sat/presolve_context.h index 1a0b31a922..39b04d7eb6 100644 --- a/ortools/sat/presolve_context.h +++ b/ortools/sat/presolve_context.h @@ -47,30 +47,30 @@ class PresolveContext; // literal that have already been removed, which will break invariants in a // bunch of places. class SavedLiteral { -public: + public: SavedLiteral() {} explicit SavedLiteral(int ref) : ref_(ref) {} int Get(PresolveContext *context) const; -private: + private: int ref_ = 0; }; // Same as SavedLiteral for variable. class SavedVariable { -public: + public: SavedVariable() {} explicit SavedVariable(int ref) : ref_(ref) {} int Get(PresolveContext *context) const; -private: + private: int ref_ = 0; }; // Wrap the CpModelProto we are presolving with extra data structure like the // in-memory domain of each variables and the constraint variable graph. class PresolveContext { -public: + public: explicit PresolveContext(CpModelProto *model, CpModelProto *mapping) : working_model(model), mapping_model(mapping) {} @@ -130,9 +130,8 @@ public: // Returns false if the new domain is empty. Sets 'domain_modified' (if // provided) to true iff the domain is modified otherwise does not change it. - ABSL_MUST_USE_RESULT bool IntersectDomainWith(int ref, const Domain &domain, - bool *domain_modified = - nullptr); + ABSL_MUST_USE_RESULT bool IntersectDomainWith( + int ref, const Domain &domain, bool *domain_modified = nullptr); // Returns false if the 'lit' doesn't have the desired value in the domain. ABSL_MUST_USE_RESULT bool SetLiteralToFalse(int lit); @@ -140,8 +139,8 @@ public: // This function always return false. It is just a way to make a little bit // more sure that we abort right away when infeasibility is detected. - ABSL_MUST_USE_RESULT bool NotifyThatModelIsUnsat(const std::string &message = - "") { + ABSL_MUST_USE_RESULT bool NotifyThatModelIsUnsat( + const std::string &message = "") { // TODO(user): Report any explanation for the client in a nicer way? VLOG(1) << "INFEASIBLE: " << message; DCHECK(!is_unsat); @@ -285,11 +284,10 @@ public: // If new_vars_in_objective is not nullptr, it will be filled with "new" // variables that where not in the objective before and are after // substitution. - void SubstituteVariableInObjective(int var_in_equality, - int64 coeff_in_equality, - const ConstraintProto &equality, - std::vector *new_vars_in_objective = - nullptr); + void SubstituteVariableInObjective( + int var_in_equality, int64 coeff_in_equality, + const ConstraintProto &equality, + std::vector *new_vars_in_objective = nullptr); // Objective getters. const Domain &ObjectiveDomain() const { return objective_domain; } @@ -379,7 +377,7 @@ public: // Advanced presolve. See this class comment. DomainDeductions deductions; -private: + private: // Helper to add an affine relation x = c.y + o to the given repository. bool AddRelation(int x, int y, int64 c, int64 o, AffineRelation *repo); @@ -486,7 +484,7 @@ private: absl::flat_hash_set removed_variables_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PRESOLVE_CONTEXT_H_ +#endif // OR_TOOLS_SAT_PRESOLVE_CONTEXT_H_ diff --git a/ortools/sat/presolve_util.cc b/ortools/sat/presolve_util.cc index b5b1e5d8b3..24eabdc7ee 100644 --- a/ortools/sat/presolve_util.cc +++ b/ortools/sat/presolve_util.cc @@ -29,10 +29,7 @@ void DomainDeductions::AddDeduction(int literal_ref, int var, Domain domain) { if (var >= tmp_num_occurrences_.size()) { tmp_num_occurrences_.resize(var + 1, 0); } - const auto insert = deductions_.insert({ - { index, var } - , domain - }); + const auto insert = deductions_.insert({{index, var}, domain}); if (insert.second) { // New element. something_changed_.Set(index); @@ -47,22 +44,20 @@ void DomainDeductions::AddDeduction(int literal_ref, int var, Domain domain) { } } -std::vector > -DomainDeductions::ProcessClause(absl::Span clause) { +std::vector > DomainDeductions::ProcessClause( + absl::Span clause) { std::vector > result; // We only need to process this clause if something changed since last time. bool abort = true; for (const int ref : clause) { const Index index = IndexFromLiteral(ref); - if (index >= something_changed_.size()) - return result; + if (index >= something_changed_.size()) return result; if (something_changed_[index]) { abort = false; } } - if (abort) - return result; + if (abort) return result; // Count for each variable, how many times it appears in the deductions lists. std::vector to_process; @@ -90,16 +85,13 @@ DomainDeductions::ProcessClause(absl::Span clause) { for (const int ref : clause) { const Index index = IndexFromLiteral(ref); for (int i = 0; i < to_process.size(); ++i) { - domains[i] = domains[i].UnionWith(gtl::FindOrDieNoPrint(deductions_, { - index, to_process[i] - })); + domains[i] = domains[i].UnionWith( + gtl::FindOrDieNoPrint(deductions_, {index, to_process[i]})); } } for (int i = 0; i < to_process.size(); ++i) { - result.push_back({ - to_process[i], std::move(domains[i]) - }); + result.push_back({to_process[i], std::move(domains[i])}); } return result; } @@ -128,9 +120,7 @@ int64 GetVarCoeffAndCopyOtherTerms(const int var, var_coeff = coeff; continue; } else { - terms->push_back({ - ref, coeff - }); + terms->push_back({ref, coeff}); } } CHECK(found); @@ -183,13 +173,11 @@ void AddTermsFromVarDefinition(const int var, const int64 var_coeff, if (ref == var) { continue; } else { - terms->push_back({ - ref, -coeff *var_coeff - }); + terms->push_back({ref, -coeff * var_coeff}); } } } -} // namespace +} // namespace void SubstituteVariable(int var, int64 var_coeff_in_definition, const ConstraintProto &definition, @@ -201,8 +189,7 @@ void SubstituteVariable(int var, int64 var_coeff_in_definition, std::vector > terms; int64 var_coeff = GetVarCoeffAndCopyOtherTerms(var, ct->linear(), &terms); - if (var_coeff_in_definition < 0) - var_coeff *= -1; + if (var_coeff_in_definition < 0) var_coeff *= -1; AddTermsFromVarDefinition(var, var_coeff, definition, &terms); @@ -219,5 +206,5 @@ void SubstituteVariable(int var, int64 var_coeff_in_definition, SortAndMergeTerms(&terms, ct->mutable_linear()); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/presolve_util.h b/ortools/sat/presolve_util.h index 6eac039591..40106e4ef2 100644 --- a/ortools/sat/presolve_util.h +++ b/ortools/sat/presolve_util.h @@ -44,7 +44,7 @@ namespace sat { // that with probing code? it might be costly to store all deduction done by // probing though, but I think this is what MIP solver do. class DomainDeductions { -public: + public: // Adds the fact that enforcement => var \in domain. // // Important: No need to store any deductions where the domain is a superset @@ -58,8 +58,8 @@ public: // TODO(user): We could probably be even more efficient. We could also // compute exactly what clauses need to be "waked up" as new deductions are // added. - std::vector > - ProcessClause(absl::Span clause); + std::vector > ProcessClause( + absl::Span clause); // Optimization. Any following ProcessClause() will be fast if no more // deduction touching that clause are added. @@ -70,7 +70,7 @@ public: // Returns the total number of "deductions" stored by this class. int NumDeductions() const { return deductions_.size(); } -private: + private: DEFINE_INT_TYPE(Index, int); Index IndexFromLiteral(int ref) { return Index(ref >= 0 ? 2 * ref : -2 * ref - 1); @@ -88,7 +88,7 @@ private: void SubstituteVariable(int var, int64 var_coeff_in_definition, const ConstraintProto &definition, ConstraintProto *ct); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PRESOLVE_UTIL_H_ +#endif // OR_TOOLS_SAT_PRESOLVE_UTIL_H_ diff --git a/ortools/sat/probing.cc b/ortools/sat/probing.cc index 15aa0294d8..860ed93d34 100644 --- a/ortools/sat/probing.cc +++ b/ortools/sat/probing.cc @@ -54,8 +54,7 @@ bool ProbeBooleanVariables(const double deterministic_time_limit, // Reset the solver in case it was already used. auto *sat_solver = model->GetOrCreate(); sat_solver->SetAssumptionLevel(0); - if (!sat_solver->RestoreSolverToAssumptionLevel()) - return false; + if (!sat_solver->RestoreSolverToAssumptionLevel()) return false; auto *time_limit = model->GetOrCreate(); const auto &assignment = sat_solver->LiteralTrail().Assignment(); @@ -109,21 +108,16 @@ bool ProbeBooleanVariables(const double deterministic_time_limit, ++num_probed; new_integer_bounds.clear(); propagated.SparseClearAll(); - for (const Literal decision : { - Literal(b, true), Literal(b, false) - }) { - if (assignment.LiteralIsAssigned(decision)) - continue; + for (const Literal decision : {Literal(b, true), Literal(b, false)}) { + if (assignment.LiteralIsAssigned(decision)) continue; CHECK_EQ(sat_solver->CurrentDecisionLevel(), 0); const int saved_index = trail.Index(); sat_solver->EnqueueDecisionAndBackjumpOnConflict(decision); sat_solver->AdvanceDeterministicTime(time_limit); - if (sat_solver->IsModelUnsat()) - return false; - if (sat_solver->CurrentDecisionLevel() == 0) - continue; + if (sat_solver->IsModelUnsat()) return false; + if (sat_solver->CurrentDecisionLevel() == 0) continue; if (integer_trail != nullptr) { implied_bounds->ProcessIntegerTrail(decision); @@ -145,55 +139,48 @@ bool ProbeBooleanVariables(const double deterministic_time_limit, // binary clause. This is becaue the BinaryImplicationGraph has the // highest priority of all propagators. if (trail.AssignmentType(l.Variable()) != id) { - new_binary_clauses.push_back({ - decision.Negated(), l - }); + new_binary_clauses.push_back({decision.Negated(), l}); } } // Fix variable and add new binary clauses. - if (!sat_solver->RestoreSolverToAssumptionLevel()) - return false; + if (!sat_solver->RestoreSolverToAssumptionLevel()) return false; for (const Literal l : to_fix_at_true) { sat_solver->AddUnitClause(l); } to_fix_at_true.clear(); - if (!sat_solver->FinishPropagation()) - return false; + if (!sat_solver->FinishPropagation()) return false; num_new_binary += new_binary_clauses.size(); for (auto binary : new_binary_clauses) { sat_solver->AddBinaryClause(binary.first, binary.second); } new_binary_clauses.clear(); - if (!sat_solver->FinishPropagation()) - return false; + if (!sat_solver->FinishPropagation()) return false; } - // We have at most two lower bounds for each variables (one for b==0 and - // one - // for b==1), so the min of the two is a valid level zero bound! More - // generally, the domain of a variable can be intersected with the union - // of the two propagated domains. This also allow to detect "holes". - // - // TODO(user): More generally, for any clauses (b or not(b) is one), we - // could probe all the literal inside, and for any integer variable, we - // can - // take the union of the propagated domain as a new domain. - // - // TODO(user): fix binary variable in the same way? It might not be as - // useful since probing on such variable will also fix it. But then we - // might - // abort probing early, so it might still be good. + // We have at most two lower bounds for each variables (one for b==0 and + // one + // for b==1), so the min of the two is a valid level zero bound! More + // generally, the domain of a variable can be intersected with the union + // of the two propagated domains. This also allow to detect "holes". + // + // TODO(user): More generally, for any clauses (b or not(b) is one), we + // could probe all the literal inside, and for any integer variable, we + // can + // take the union of the propagated domain as a new domain. + // + // TODO(user): fix binary variable in the same way? It might not be as + // useful since probing on such variable will also fix it. But then we + // might + // abort probing early, so it might still be good. std::sort(new_integer_bounds.begin(), new_integer_bounds.end(), - [](IntegerLiteral a, IntegerLiteral b) { - return a.var < b.var; - }); + [](IntegerLiteral a, IntegerLiteral b) { return a.var < b.var; }); // This is used for the hole detection. IntegerVariable prev_var = kNoIntegerVariable; IntegerValue lb_max = kMinIntegerValue; IntegerValue ub_min = kMaxIntegerValue; - new_integer_bounds.push_back(IntegerLiteral()); // Sentinel. + new_integer_bounds.push_back(IntegerLiteral()); // Sentinel. for (int i = 0; i < new_integer_bounds.size(); ++i) { const IntegerVariable var = new_integer_bounds[i].var; @@ -230,25 +217,20 @@ bool ProbeBooleanVariables(const double deterministic_time_limit, } // Bound tightening. - if (i == 0 || new_integer_bounds[i - 1].var != var) - continue; + if (i == 0 || new_integer_bounds[i - 1].var != var) continue; const IntegerValue new_bound = std::min(new_integer_bounds[i - 1].bound, new_integer_bounds[i].bound); if (new_bound > integer_trail->LowerBound(var)) { ++num_new_integer_bounds; if (!integer_trail->Enqueue( - IntegerLiteral::GreaterOrEqual(var, new_bound), { - }, - { - })) { + IntegerLiteral::GreaterOrEqual(var, new_bound), {}, {})) { return false; } } } // We might have updates some integer domain, lets propagate. - if (!sat_solver->FinishPropagation()) - return false; + if (!sat_solver->FinishPropagation()) return false; } // Display stats. @@ -285,8 +267,7 @@ bool LookForTrivialSatSolution(double deterministic_time_limit, Model *model, // Reset the solver in case it was already used. auto *sat_solver = model->GetOrCreate(); sat_solver->SetAssumptionLevel(0); - if (!sat_solver->RestoreSolverToAssumptionLevel()) - return false; + if (!sat_solver->RestoreSolverToAssumptionLevel()) return false; auto *time_limit = model->GetOrCreate(); const int initial_num_fixed = sat_solver->LiteralTrail().Index(); @@ -341,8 +322,7 @@ bool LookForTrivialSatSolution(double deterministic_time_limit, Model *model, sat_solver->SetParameters(initial_params); sat_solver->ResetDecisionHeuristic(); time_limit->AdvanceDeterministicTime(elapsed_dtime); - if (!sat_solver->RestoreSolverToAssumptionLevel()) - return false; + if (!sat_solver->RestoreSolverToAssumptionLevel()) return false; if (log_info) { const int num_fixed = sat_solver->LiteralTrail().Index(); @@ -366,17 +346,14 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { // Reset the solver in case it was already used. auto *sat_solver = model->GetOrCreate(); sat_solver->SetAssumptionLevel(0); - if (!sat_solver->RestoreSolverToAssumptionLevel()) - return false; + if (!sat_solver->RestoreSolverToAssumptionLevel()) return false; // When called from Inprocessing, the implication graph should already be a // DAG, so these two calls should return right away. But we do need them to // get the topological order if this is used in isolation. auto *implication_graph = model->GetOrCreate(); - if (!implication_graph->DetectEquivalences()) - return false; - if (!sat_solver->FinishPropagation()) - return false; + if (!implication_graph->DetectEquivalences()) return false; + if (!sat_solver->FinishPropagation()) return false; auto *time_limit = model->GetOrCreate(); const int initial_num_fixed = sat_solver->LiteralTrail().Index(); @@ -401,8 +378,8 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { // This is only needed when options.use_queue is true. struct SavedNextLiteral { - LiteralIndex literal_index; // kNoLiteralIndex if we need to backtrack. - int rank; // Cached position_in_order, we prefer lower positions. + LiteralIndex literal_index; // kNoLiteralIndex if we need to backtrack. + int rank; // Cached position_in_order, we prefer lower positions. bool operator<(const SavedNextLiteral &o) const { return rank < o.rank; } }; @@ -411,8 +388,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { // This is only needed when options use_queue is false; gtl::ITIVector starts; - if (!options.use_queue) - starts.resize(2 * num_variables, 0); + if (!options.use_queue) starts.resize(2 * num_variables, 0); // We delay fixing of already assigned literal once we go back to level // zero. @@ -447,34 +423,31 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { while (!time_limit->LimitReached() && time_limit->GetElapsedDeterministicTime() <= limit) { // We only enqueue literal at level zero if we don't use "tree look". - if (!options.use_tree_look) - sat_solver->Backtrack(0); + if (!options.use_tree_look) sat_solver->Backtrack(0); LiteralIndex next_decision = kNoLiteralIndex; if (options.use_queue && sat_solver->CurrentDecisionLevel() > 0) { // TODO(user): Instead of minimizing index in topo order (which might be // nice for binary extraction), we could try to maximize reusability in // some way. - const Literal prev_decision = sat_solver - ->Decisions()[sat_solver->CurrentDecisionLevel() - 1].literal; + const Literal prev_decision = + sat_solver->Decisions()[sat_solver->CurrentDecisionLevel() - 1] + .literal; const auto &list = implication_graph->Implications(prev_decision.Negated()); const int saved_queue_size = queue.size(); for (const Literal l : list) { const Literal candidate = l.Negated(); - if (processed[candidate.Index()]) - continue; - if (position_in_order[candidate.Index()] == -1) - continue; + if (processed[candidate.Index()]) continue; + if (position_in_order[candidate.Index()] == -1) continue; if (assignment.LiteralIsAssigned(candidate)) { if (assignment.LiteralIsFalse(candidate)) { to_fix.push_back(Literal(candidate.Negated())); } continue; } - queue.push_back({ - candidate.Index(), -position_in_order[candidate.Index()] - }); + queue.push_back( + {candidate.Index(), -position_in_order[candidate.Index()]}); } std::sort(queue.begin() + saved_queue_size, queue.end()); @@ -489,8 +462,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { continue; } const Literal candidate(index); - if (processed[candidate.Index()]) - continue; + if (processed[candidate.Index()]) continue; if (assignment.LiteralIsAssigned(candidate)) { if (assignment.LiteralIsFalse(candidate)) { to_fix.push_back(Literal(candidate.Negated())); @@ -511,23 +483,19 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { } } to_fix.clear(); - if (!sat_solver->FinishPropagation()) - return false; + if (!sat_solver->FinishPropagation()) return false; // Probe an unexplored node. for (; order_index < probing_order.size(); ++order_index) { const Literal candidate(probing_order[order_index]); - if (processed[candidate.Index()]) - continue; - if (assignment.LiteralIsAssigned(candidate)) - continue; + if (processed[candidate.Index()]) continue; + if (assignment.LiteralIsAssigned(candidate)) continue; next_decision = candidate.Index(); break; } // The pass is finished. - if (next_decision == kNoLiteralIndex) - break; + if (next_decision == kNoLiteralIndex) break; } else if (next_decision == kNoLiteralIndex) { const int level = sat_solver->CurrentDecisionLevel(); const Literal prev_decision = sat_solver->Decisions()[level - 1].literal; @@ -542,8 +510,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { for (int i = 0; i < list.size(); ++i, ++j) { j %= list.size(); const Literal candidate = Literal(list[j]).Negated(); - if (processed[candidate.Index()]) - continue; + if (processed[candidate.Index()]) continue; if (assignment.LiteralIsFalse(candidate)) { // candidate => previous => not(candidate), so we can fix it. to_fix.push_back(Literal(candidate.Negated())); @@ -551,8 +518,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { } // This shouldn't happen if extract_binary_clauses is false. // We have an equivalence. - if (assignment.LiteralIsTrue(candidate)) - continue; + if (assignment.LiteralIsTrue(candidate)) continue; next_decision = candidate.Index(); break; } @@ -566,17 +532,14 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { ++num_probed; processed.Set(next_decision); CHECK_NE(next_decision, kNoLiteralIndex); - queue.push_back({ - kNoLiteralIndex, 0 - }); // Backtrack marker. + queue.push_back({kNoLiteralIndex, 0}); // Backtrack marker. const int level = sat_solver->CurrentDecisionLevel(); const int first_new_trail_index = sat_solver->EnqueueDecisionAndBackjumpOnConflict( Literal(next_decision)); const int new_level = sat_solver->CurrentDecisionLevel(); sat_solver->AdvanceDeterministicTime(time_limit); - if (sat_solver->IsModelUnsat()) - return false; + if (sat_solver->IsModelUnsat()) return false; if (new_level <= level) { ++num_conflicts; @@ -588,8 +551,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { int queue_level = level + 1; while (queue_level > new_level) { CHECK(!queue.empty()); - if (queue.back().literal_index == kNoLiteralIndex) - --queue_level; + if (queue.back().literal_index == kNoLiteralIndex) --queue_level; queue.pop_back(); } } @@ -619,15 +581,13 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { // Inspect the newly propagated literals. Depending on the options, try to // extract binary clauses via hyper binary resolution and/or mark the // literals on the trail so that they do not need to be probed later. - if (new_level == 0) - continue; + if (new_level == 0) continue; const Literal last_decision = sat_solver->Decisions()[new_level - 1].literal; int num_new_subsumed = 0; for (int i = first_new_trail_index; i < trail.Index(); ++i) { const Literal l = trail[i]; - if (l == last_decision) - continue; + if (l == last_decision) continue; // If we can extract a binary clause that subsume the reason clause, we // do add the binary and remove the subsumed clause. @@ -652,10 +612,8 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { int test = 0; for (const Literal lit : clause_manager->ReasonClause(trail_index)->AsSpan()) { - if (lit == l) - ++test; - if (lit == last_decision.Negated()) - ++test; + if (lit == l) ++test; + if (lit == last_decision.Negated()) ++test; } CHECK_EQ(test, 2); clause_manager->LazyDetach(clause_manager->ReasonClause(trail_index)); @@ -707,8 +665,7 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { for (const auto &w : clause_manager->WatcherListOnFalse(last_decision.Negated())) { if (assignment.LiteralIsTrue(w.blocking_literal)) { - if (w.clause->empty()) - continue; + if (w.clause->empty()) continue; CHECK_NE(w.blocking_literal, last_decision.Negated()); // Add the binary clause if needed. Note that we change the reason @@ -748,15 +705,13 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { } } - if (!sat_solver->ResetToLevelZero()) - return false; + if (!sat_solver->ResetToLevelZero()) return false; for (const Literal literal : to_fix) { ++num_explicit_fix; sat_solver->AddUnitClause(literal); } to_fix.clear(); - if (!sat_solver->FinishPropagation()) - return false; + if (!sat_solver->FinishPropagation()) return false; // Display stats. const int num_fixed = sat_solver->LiteralTrail().Index(); @@ -777,5 +732,5 @@ bool FailedLiteralProbingRound(ProbingOptions options, Model *model) { return sat_solver->FinishPropagation(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/probing.h b/ortools/sat/probing.h index bc3859e5dd..ba66cf940c 100644 --- a/ortools/sat/probing.h +++ b/ortools/sat/probing.h @@ -148,8 +148,8 @@ struct ProbingOptions { std::string ToString() const { return absl::StrCat("deterministic_limit: ", deterministic_limit, " extract_binary_clauses: ", extract_binary_clauses, - " use_tree_look: ", use_tree_look, " use_queue: ", - use_queue); + " use_tree_look: ", use_tree_look, + " use_queue: ", use_queue); } }; @@ -175,7 +175,7 @@ struct ProbingOptions { // the implication graph. See the option comments for more details. bool FailedLiteralProbingRound(ProbingOptions options, Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PROBING_H_ +#endif // OR_TOOLS_SAT_PROBING_H_ diff --git a/ortools/sat/pseudo_costs.cc b/ortools/sat/pseudo_costs.cc index d302175773..69ac9f54fc 100644 --- a/ortools/sat/pseudo_costs.cc +++ b/ortools/sat/pseudo_costs.cc @@ -32,8 +32,7 @@ PseudoCosts::PseudoCosts(Model *model) } void PseudoCosts::InitializeCosts(double initial_value) { - if (pseudo_costs_initialized_) - return; + if (pseudo_costs_initialized_) return; VLOG(1) << "Initializing pseudo costs"; for (int i = 0; i < pseudo_costs_.size(); ++i) { pseudo_costs_[IntegerVariable(i)].Reset(initial_value); @@ -51,16 +50,14 @@ void PseudoCosts::UpdateCostForVar(IntegerVariable var, double new_cost) { pseudo_costs_[var].AddData(new_cost); } -void -PseudoCosts::UpdateCost(const std::vector &bound_changes, - const IntegerValue obj_bound_improvement) { +void PseudoCosts::UpdateCost( + const std::vector &bound_changes, + const IntegerValue obj_bound_improvement) { DCHECK_GE(obj_bound_improvement, 0); - if (obj_bound_improvement == IntegerValue(0)) - return; + if (obj_bound_improvement == IntegerValue(0)) return; for (const VariableBoundChange &decision : bound_changes) { - if (integer_trail_.IsCurrentlyIgnored(decision.var)) - continue; + if (integer_trail_.IsCurrentlyIgnored(decision.var)) continue; if (decision.lower_bound_change > IntegerValue(0)) { const double current_pseudo_cost = ToDouble(obj_bound_improvement) / @@ -82,8 +79,7 @@ PseudoCosts::UpdateCost(const std::vector &bound_changes, } IntegerVariable PseudoCosts::GetBestDecisionVar() { - if (!pseudo_costs_initialized_) - return kNoIntegerVariable; + if (!pseudo_costs_initialized_) return kNoIntegerVariable; const double epsilon = 1e-6; @@ -93,12 +89,10 @@ IntegerVariable PseudoCosts::GetBestDecisionVar() { for (IntegerVariable positive_var(0); positive_var < pseudo_costs_.size(); positive_var += 2) { const IntegerVariable negative_var = NegationOf(positive_var); - if (integer_trail_.IsCurrentlyIgnored(positive_var)) - continue; + if (integer_trail_.IsCurrentlyIgnored(positive_var)) continue; const IntegerValue lb = integer_trail_.LowerBound(positive_var); const IntegerValue ub = integer_trail_.UpperBound(positive_var); - if (lb >= ub) - continue; + if (lb >= ub) continue; if (GetRecordings(positive_var) + GetRecordings(negative_var) < parameters_.pseudo_cost_reliability_threshold()) { continue; @@ -123,20 +117,17 @@ IntegerVariable PseudoCosts::GetBestDecisionVar() { return chosen_var; } -std::vector -GetBoundChanges(LiteralIndex decision, Model *model) { +std::vector GetBoundChanges( + LiteralIndex decision, Model *model) { std::vector bound_changes; - if (decision == kNoLiteralIndex) - return bound_changes; + if (decision == kNoLiteralIndex) return bound_changes; auto *encoder = model->GetOrCreate(); auto *integer_trail = model->GetOrCreate(); // NOTE: We ignore negation of equality decisions. for (const IntegerLiteral l : encoder->GetAllIntegerLiterals(Literal(decision))) { - if (l.var == kNoIntegerVariable) - continue; - if (integer_trail->IsCurrentlyIgnored(l.var)) - continue; + if (l.var == kNoIntegerVariable) continue; + if (integer_trail->IsCurrentlyIgnored(l.var)) continue; PseudoCosts::VariableBoundChange var_bound_change; var_bound_change.var = l.var; var_bound_change.lower_bound_change = @@ -147,5 +138,5 @@ GetBoundChanges(LiteralIndex decision, Model *model) { return bound_changes; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/pseudo_costs.h b/ortools/sat/pseudo_costs.h index b36410d7ed..266f653a1a 100644 --- a/ortools/sat/pseudo_costs.h +++ b/ortools/sat/pseudo_costs.h @@ -25,7 +25,7 @@ namespace sat { // Pseudo cost of a variable is measured as average observed change in the // objective bounds per unit change in the variable bounds. class PseudoCosts { -public: + public: // Helper struct to get information relavant for pseudo costs from branching // decisions. struct VariableBoundChange { @@ -54,7 +54,7 @@ public: return pseudo_costs_[var].NumRecords(); } -private: + private: // Initializes the pseudo costs of all variables to given value. This method // doesn't change the number of recordings. void InitializeCosts(double initial_value); @@ -74,10 +74,10 @@ private: // Returns extracted information to update pseudo costs from the given // branching decision. -std::vector - GetBoundChanges(LiteralIndex decision, Model *model); +std::vector GetBoundChanges( + LiteralIndex decision, Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_PSEUDO_COSTS_H_ +#endif // OR_TOOLS_SAT_PSEUDO_COSTS_H_ diff --git a/ortools/sat/restart.cc b/ortools/sat/restart.cc index 62c73700a1..6239c09822 100644 --- a/ortools/sat/restart.cc +++ b/ortools/sat/restart.cc @@ -63,13 +63,13 @@ void RestartPolicy::Reset() { << string_value << "'."; continue; } -#else // __PORTABLE_PLATFORM__ +#else // __PORTABLE_PLATFORM__ if (!SatParameters::RestartAlgorithm_Parse(string_value, &tmp)) { LOG(WARNING) << "Couldn't parse the RestartAlgorithm name: '" << string_value << "'."; continue; } -#endif // !__PORTABLE_PLATFORM__ +#endif // !__PORTABLE_PLATFORM__ strategies_.push_back(tmp); } } @@ -81,35 +81,35 @@ void RestartPolicy::Reset() { bool RestartPolicy::ShouldRestart() { bool should_restart = false; switch (strategies_[strategy_counter_ % strategies_.size()]) { - case SatParameters::NO_RESTART: - break; - case SatParameters::LUBY_RESTART: - if (conflicts_until_next_restart_ == 0) { - luby_count_++; - should_restart = true; - } - break; - case SatParameters::DL_MOVING_AVERAGE_RESTART: - if (dl_running_average_.IsWindowFull() && - dl_running_average_.GlobalAverage() < - parameters_.restart_dl_average_ratio() * - dl_running_average_.WindowAverage()) { - should_restart = true; - } - break; - case SatParameters::LBD_MOVING_AVERAGE_RESTART: - if (lbd_running_average_.IsWindowFull() && - lbd_running_average_.GlobalAverage() < - parameters_.restart_lbd_average_ratio() * - lbd_running_average_.WindowAverage()) { - should_restart = true; - } - break; - case SatParameters::FIXED_RESTART: - if (conflicts_until_next_restart_ == 0) { - should_restart = true; - } - break; + case SatParameters::NO_RESTART: + break; + case SatParameters::LUBY_RESTART: + if (conflicts_until_next_restart_ == 0) { + luby_count_++; + should_restart = true; + } + break; + case SatParameters::DL_MOVING_AVERAGE_RESTART: + if (dl_running_average_.IsWindowFull() && + dl_running_average_.GlobalAverage() < + parameters_.restart_dl_average_ratio() * + dl_running_average_.WindowAverage()) { + should_restart = true; + } + break; + case SatParameters::LBD_MOVING_AVERAGE_RESTART: + if (lbd_running_average_.IsWindowFull() && + lbd_running_average_.GlobalAverage() < + parameters_.restart_lbd_average_ratio() * + lbd_running_average_.WindowAverage()) { + should_restart = true; + } + break; + case SatParameters::FIXED_RESTART: + if (conflicts_until_next_restart_ == 0) { + should_restart = true; + } + break; } if (should_restart) { num_restarts_++; @@ -189,5 +189,5 @@ std::string RestartPolicy::InfoString() const { return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/restart.h b/ortools/sat/restart.h index 2a52410128..1914143722 100644 --- a/ortools/sat/restart.h +++ b/ortools/sat/restart.h @@ -27,7 +27,7 @@ namespace sat { // Contain the logic to decide when to restart a SAT tree search. class RestartPolicy { -public: + public: explicit RestartPolicy(Model *model) : parameters_(*(model->GetOrCreate())), decision_policy_(model->GetOrCreate()) { @@ -54,7 +54,7 @@ public: // Returns a string with the current restart statistics. std::string InfoString() const; -private: + private: const SatParameters ¶meters_; SatDecisionPolicy *decision_policy_; @@ -95,7 +95,7 @@ inline int SUniv(int i) { return 1; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_RESTART_H_ +#endif // OR_TOOLS_SAT_RESTART_H_ diff --git a/ortools/sat/rins.cc b/ortools/sat/rins.cc index 073d79cfab..a539005155 100644 --- a/ortools/sat/rins.cc +++ b/ortools/sat/rins.cc @@ -24,8 +24,7 @@ namespace sat { void RecordLPRelaxationValues(Model *model) { auto *lp_solutions = model->Mutable(); - if (lp_solutions == nullptr) - return; + if (lp_solutions == nullptr) return; const LPVariables &lp_vars = *model->GetOrCreate(); std::vector relaxation_values( @@ -34,12 +33,10 @@ void RecordLPRelaxationValues(Model *model) { auto *integer_trail = model->GetOrCreate(); for (const LPVariable &lp_var : lp_vars.vars) { const IntegerVariable positive_var = lp_var.positive_var; - if (integer_trail->IsCurrentlyIgnored(positive_var)) - continue; + if (integer_trail->IsCurrentlyIgnored(positive_var)) continue; LinearProgrammingConstraint *lp = lp_var.lp; - if (lp == nullptr || !lp->HasSolution()) - continue; + if (lp == nullptr || !lp->HasSolution()) continue; relaxation_values[lp_var.model_var] = lp->GetSolutionValue(positive_var); } @@ -48,9 +45,8 @@ void RecordLPRelaxationValues(Model *model) { namespace { -std::vector -GetLPRelaxationValues(const SharedLPSolutionRepository *lp_solutions, - random_engine_t *random) { +std::vector GetLPRelaxationValues( + const SharedLPSolutionRepository *lp_solutions, random_engine_t *random) { std::vector relaxation_values; if (lp_solutions == nullptr || lp_solutions->NumSolutions() == 0) { @@ -98,7 +94,7 @@ std::vector GetIncompleteSolutionValues( return incomplete_solutions->GetNewSolution(); } -} // namespace +} // namespace RINSNeighborhood GetRINSNeighborhood( const SharedResponseManager *response_manager, @@ -131,8 +127,7 @@ RINSNeighborhood GetRINSNeighborhood( relaxation_values = GetGeneralRelaxationValues(relaxation_solutions, random); } - if (relaxation_values.empty()) - return rins_neighborhood; + if (relaxation_values.empty()) return rins_neighborhood; const double tolerance = 1e-6; const SharedSolutionRepository::Solution solution = @@ -159,22 +154,18 @@ RINSNeighborhood GetRINSNeighborhood( const int64 domain_ub = static_cast(std::ceil(relaxation_value - tolerance)); if (domain_lb == domain_ub) { - rins_neighborhood.fixed_vars.push_back({ - model_var, domain_lb - }); + rins_neighborhood.fixed_vars.push_back({model_var, domain_lb}); } else { - rins_neighborhood.reduced_domain_vars.push_back({ - model_var, { domain_lb, domain_ub } - }); + rins_neighborhood.reduced_domain_vars.push_back( + {model_var, {domain_lb, domain_ub}}); } } else { const IntegerValue best_solution_value = IntegerValue(solution.variable_values[model_var]); if (std::abs(best_solution_value.value() - relaxation_value) < 1e-4) { - rins_neighborhood.fixed_vars.push_back({ - model_var, best_solution_value.value() - }); + rins_neighborhood.fixed_vars.push_back( + {model_var, best_solution_value.value()}); } } } @@ -182,5 +173,5 @@ RINSNeighborhood GetRINSNeighborhood( return rins_neighborhood; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/rins.h b/ortools/sat/rins.h index d90070c834..d504796d0c 100644 --- a/ortools/sat/rins.h +++ b/ortools/sat/rins.h @@ -83,7 +83,7 @@ RINSNeighborhood GetRINSNeighborhood( // Adds the current LP solution to the pool. void RecordLPRelaxationValues(Model *model); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_RINS_H_ +#endif // OR_TOOLS_SAT_RINS_H_ diff --git a/ortools/sat/sat_base.h b/ortools/sat/sat_base.h index 58818154f5..19a4d01997 100644 --- a/ortools/sat/sat_base.h +++ b/ortools/sat/sat_base.h @@ -62,10 +62,10 @@ const LiteralIndex kFalseLiteralIndex(-3); // and for a 0-based variable index x, (x << 1) encode the variable x and the // same number XOR 1 encode its negation. class Literal { -public: + public: // Not explicit for tests so we can write: // vector literal = {+1, -3, +4, -9}; - Literal(int signed_value) // NOLINT + Literal(int signed_value) // NOLINT : index_(signed_value > 0 ? ((signed_value - 1) << 1) : ((-signed_value - 1) << 1) ^ 1) { CHECK_NE(signed_value, 0); @@ -100,7 +100,7 @@ public: return Index() < literal.Index(); } -private: + private: int index_; }; @@ -120,7 +120,7 @@ inline std::ostream &operator<<(std::ostream &os, // Holds the current variable assignment of the solver. // Each variable can be unassigned or be assigned to true or false. class VariablesAssignment { -public: + public: VariablesAssignment() {} explicit VariablesAssignment(int num_variables) { Resize(num_variables); } void Resize(int num_variables) { @@ -169,7 +169,7 @@ public: int NumberOfVariables() const { return assignment_.size().value() / 2; } -private: + private: // The encoding is as follows: // - assignment_.IsSet(literal.Index()) means literal is true. // - assignment_.IsSet(literal.Index() ^ 1]) means literal is false. @@ -231,7 +231,7 @@ struct AssignmentType { // This class is responsible for maintaining the assignment of each variable // and the information of each assignment. class Trail { -public: + public: explicit Trail(Model *model) : Trail() {} Trail() { @@ -282,8 +282,7 @@ public: // and this will return false otherwise this will enqueue the literal and // returns true. ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal) { - if (assignment_.LiteralIsTrue(true_literal)) - return true; + if (assignment_.LiteralIsTrue(true_literal)) return true; if (assignment_.LiteralIsFalse(true_literal)) { *MutableConflict() = reasons_repository_[Index()]; MutableConflict()->push_back(true_literal); @@ -389,14 +388,13 @@ public: std::string DebugString() { std::string result; for (int i = 0; i < current_info_.trail_index; ++i) { - if (!result.empty()) - result += " "; + if (!result.empty()) result += " "; result += trail_[i].DebugString(); } return result; } -private: + private: int64 num_untrailed_enqueues_ = 0; AssignmentInfo current_info_; VariablesAssignment assignment_; @@ -444,7 +442,7 @@ private: // Base class for all the SAT constraints. class SatPropagator { -public: + public: explicit SatPropagator(const std::string &name) : name_(name), propagator_id_(-1), propagation_trail_index_(0) {} virtual ~SatPropagator() {} @@ -502,12 +500,12 @@ public: return propagation_trail_index_ == trail.Index(); } -protected: + protected: const std::string name_; int propagator_id_; int propagation_trail_index_; -private: + private: DISALLOW_COPY_AND_ASSIGN(SatPropagator); }; @@ -515,8 +513,8 @@ private: // TODO(user): A few of these method should be moved in a .cc -inline bool -SatPropagator::PropagatePreconditionsAreSatisfied(const Trail &trail) const { +inline bool SatPropagator::PropagatePreconditionsAreSatisfied( + const Trail &trail) const { if (propagation_trail_index_ > trail.Index()) { LOG(INFO) << "Issue in '" << name_ << ":" << " propagation_trail_index_=" << propagation_trail_index_ @@ -558,8 +556,8 @@ inline void Trail::RegisterPropagator(SatPropagator *propagator) { propagators_.push_back(propagator); } -inline BooleanVariable -Trail::ReferenceVarWithSameReason(BooleanVariable var) const { +inline BooleanVariable Trail::ReferenceVarWithSameReason( + BooleanVariable var) const { DCHECK(Assignment().VariableIsAssigned(var)); // Note that we don't use AssignmentType() here. if (info_[var].type == AssignmentType::kSameReasonAs) { @@ -584,8 +582,7 @@ inline absl::Span Trail::Reason(BooleanVariable var) const { var = ReferenceVarWithSameReason(var); // Fast-track for cached reason. - if (info_[var].type == AssignmentType::kCachedReason) - return reasons_[var]; + if (info_[var].type == AssignmentType::kCachedReason) return reasons_[var]; const AssignmentInfo &info = info_[var]; if (info.type == AssignmentType::kUnitReason || @@ -601,7 +598,7 @@ inline absl::Span Trail::Reason(BooleanVariable var) const { return reasons_[var]; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SAT_BASE_H_ +#endif // OR_TOOLS_SAT_SAT_BASE_H_ diff --git a/ortools/sat/sat_decision.cc b/ortools/sat/sat_decision.cc index 18e17f06af..92ad3ac88f 100644 --- a/ortools/sat/sat_decision.cc +++ b/ortools/sat/sat_decision.cc @@ -40,16 +40,14 @@ void SatDecisionPolicy::IncreaseNumVariables(int num_variables) { target_polarity_.resize(num_variables); var_polarity_.resize(num_variables); - ResetInitialPolarity(/*from=*/ old_num_variables); + ResetInitialPolarity(/*from=*/old_num_variables); // Update the priority queue. Note that each addition is in O(1) because // the priority is 0.0. var_ordering_.Reserve(num_variables); if (var_ordering_is_initialized_) { for (BooleanVariable var(old_num_variables); var < num_variables; ++var) { - var_ordering_.Add({ - var, 0.0, activities_[var] - }); + var_ordering_.Add({var, 0.0, activities_[var]}); } } } @@ -57,9 +55,7 @@ void SatDecisionPolicy::IncreaseNumVariables(int num_variables) { void SatDecisionPolicy::BeforeConflict(int trail_index) { if (parameters_.use_erwa_heuristic()) { ++num_conflicts_; - num_conflicts_stack_.push_back({ - trail_.Index(), 1 - }); + num_conflicts_stack_.push_back({trail_.Index(), 1}); } if (trail_index > target_length_) { @@ -81,10 +77,8 @@ void SatDecisionPolicy::BeforeConflict(int trail_index) { } void SatDecisionPolicy::RephaseIfNeeded() { - if (parameters_.polarity_rephase_increment() <= 0) - return; - if (num_conflicts_until_rephase_ > 0) - return; + if (parameters_.polarity_rephase_increment() <= 0) return; + if (num_conflicts_until_rephase_ > 0) return; VLOG(1) << "End of polarity phase " << polarity_phase_ << " target_length: " << target_length_ @@ -102,30 +96,30 @@ void SatDecisionPolicy::RephaseIfNeeded() { // the default polarity, and this code is reached the first time with a // polarity_phase_ of 1. switch (polarity_phase_ % 8) { - case 0: - ResetInitialPolarity(/*from=*/ 0); - break; - case 1: - UseLongestAssignmentAsInitialPolarity(); - break; - case 2: - ResetInitialPolarity(/*from=*/ 0, /*inverted=*/ true); - break; - case 3: - UseLongestAssignmentAsInitialPolarity(); - break; - case 4: - RandomizeCurrentPolarity(); - break; - case 5: - UseLongestAssignmentAsInitialPolarity(); - break; - case 6: - FlipCurrentPolarity(); - break; - case 7: - UseLongestAssignmentAsInitialPolarity(); - break; + case 0: + ResetInitialPolarity(/*from=*/0); + break; + case 1: + UseLongestAssignmentAsInitialPolarity(); + break; + case 2: + ResetInitialPolarity(/*from=*/0, /*inverted=*/true); + break; + case 3: + UseLongestAssignmentAsInitialPolarity(); + break; + case 4: + RandomizeCurrentPolarity(); + break; + case 5: + UseLongestAssignmentAsInitialPolarity(); + break; + case 6: + FlipCurrentPolarity(); + break; + case 7: + UseLongestAssignmentAsInitialPolarity(); + break; } } @@ -140,7 +134,7 @@ void SatDecisionPolicy::ResetDecisionHeuristic() { polarity_phase_ = 0; num_conflicts_until_rephase_ = parameters_.polarity_rephase_increment(); - ResetInitialPolarity(/*from=*/ 0); + ResetInitialPolarity(/*from=*/0); has_target_polarity_.assign(num_variables, false); has_forced_polarity_.assign(num_variables, false); best_partial_assignment_.clear(); @@ -162,21 +156,21 @@ void SatDecisionPolicy::ResetInitialPolarity(int from, bool inverted) { const int num_variables = activities_.size(); for (BooleanVariable var(from); var < num_variables; ++var) { switch (parameters_.initial_polarity()) { - case SatParameters::POLARITY_TRUE: - var_polarity_[var] = inverted ? false : true; - break; - case SatParameters::POLARITY_FALSE: - var_polarity_[var] = inverted ? true : false; - break; - case SatParameters::POLARITY_RANDOM: - var_polarity_[var] = std::uniform_int_distribution(0, 1)(*random_); - break; - case SatParameters::POLARITY_WEIGHTED_SIGN: - var_polarity_[var] = weighted_sign_[var] > 0; - break; - case SatParameters::POLARITY_REVERSE_WEIGHTED_SIGN: - var_polarity_[var] = weighted_sign_[var] < 0; - break; + case SatParameters::POLARITY_TRUE: + var_polarity_[var] = inverted ? false : true; + break; + case SatParameters::POLARITY_FALSE: + var_polarity_[var] = inverted ? true : false; + break; + case SatParameters::POLARITY_RANDOM: + var_polarity_[var] = std::uniform_int_distribution(0, 1)(*random_); + break; + case SatParameters::POLARITY_WEIGHTED_SIGN: + var_polarity_[var] = weighted_sign_[var] > 0; + break; + case SatParameters::POLARITY_REVERSE_WEIGHTED_SIGN: + var_polarity_[var] = weighted_sign_[var] < 0; + break; } } } @@ -215,9 +209,8 @@ void SatDecisionPolicy::InitializeVariableOrdering() { for (BooleanVariable var(0); var < num_variables; ++var) { if (!trail_.Assignment().VariableIsAssigned(var)) { if (activities_[var] > 0.0) { - var_ordering_.Add({ - var, static_cast(tie_breakers_[var]), activities_[var] - }); + var_ordering_.Add( + {var, static_cast(tie_breakers_[var]), activities_[var]}); } else { variables.push_back(var); } @@ -231,21 +224,19 @@ void SatDecisionPolicy::InitializeVariableOrdering() { // // TODO(user): Experiment and come up with a good set of heuristics. switch (parameters_.preferred_variable_order()) { - case SatParameters::IN_ORDER: - break; - case SatParameters::IN_REVERSE_ORDER: - std::reverse(variables.begin(), variables.end()); - break; - case SatParameters::IN_RANDOM_ORDER: - std::shuffle(variables.begin(), variables.end(), *random_); - break; + case SatParameters::IN_ORDER: + break; + case SatParameters::IN_REVERSE_ORDER: + std::reverse(variables.begin(), variables.end()); + break; + case SatParameters::IN_RANDOM_ORDER: + std::shuffle(variables.begin(), variables.end(), *random_); + break; } // Add the variables without activity to the queue (in the default order) for (const BooleanVariable var : variables) { - var_ordering_.Add({ - var, static_cast(tie_breakers_[var]), 0.0 - }); + var_ordering_.Add({var, static_cast(tie_breakers_[var]), 0.0}); } // Finish the queue initialization. @@ -256,8 +247,7 @@ void SatDecisionPolicy::InitializeVariableOrdering() { void SatDecisionPolicy::SetAssignmentPreference(Literal literal, double weight) { - if (!parameters_.use_optimization_hints()) - return; + if (!parameters_.use_optimization_hints()) return; DCHECK_GE(weight, 0.0); DCHECK_LE(weight, 1.0); @@ -270,8 +260,8 @@ void SatDecisionPolicy::SetAssignmentPreference(Literal literal, var_ordering_is_initialized_ = false; } -std::vector > -SatDecisionPolicy::AllPreferences() const { +std::vector > SatDecisionPolicy::AllPreferences() + const { std::vector > prefs; for (BooleanVariable var(0); var < var_polarity_.size(); ++var) { // TODO(user): we currently assume that if the tie_breaker is zero then @@ -310,8 +300,7 @@ void SatDecisionPolicy::BumpVariableActivities( for (const Literal literal : literals) { const BooleanVariable var = literal.Variable(); const int level = trail_.Info(var).level; - if (level == 0) - continue; + if (level == 0) continue; activities_[var] += variable_activity_increment_; pq_need_update_for_var_at_trail_index_.Set(trail_.Info(var).trail_index); if (activities_[var] > max_activity_value) { @@ -355,8 +344,7 @@ Literal SatDecisionPolicy::NextBranch() { const double ratio = parameters_.random_branches_ratio(); auto zero_to_one = [this]() { return std::uniform_real_distribution()(*random_); - } - ; + }; if (ratio != 0.0 && zero_to_one() < ratio) { while (true) { // TODO(user): This may not be super efficient if almost all the @@ -364,8 +352,7 @@ Literal SatDecisionPolicy::NextBranch() { std::uniform_int_distribution index_dist(0, var_ordering_.Size() - 1); var = var_ordering_.QueueElement(index_dist(*random_)).var; - if (!trail_.Assignment().VariableIsAssigned(var)) - break; + if (!trail_.Assignment().VariableIsAssigned(var)) break; pq_need_update_for_var_at_trail_index_.Set(trail_.Info(var).trail_index); var_ordering_.Remove(var.value()); } @@ -387,8 +374,7 @@ Literal SatDecisionPolicy::NextBranch() { return Literal(var, std::uniform_int_distribution(0, 1)(*random_)); } - if (has_forced_polarity_[var]) - return Literal(var, forced_polarity_[var]); + if (has_forced_polarity_[var]) return Literal(var, forced_polarity_[var]); if (in_stable_phase_ && has_target_polarity_[var]) { return Literal(var, target_polarity_[var]); } @@ -396,10 +382,8 @@ Literal SatDecisionPolicy::NextBranch() { } void SatDecisionPolicy::PqInsertOrUpdate(BooleanVariable var) { - const WeightedVarQueueElement element { - var, static_cast(tie_breakers_[var]), activities_[var] - } - ; + const WeightedVarQueueElement element{ + var, static_cast(tie_breakers_[var]), activities_[var]}; if (var_ordering_.Contains(var.value())) { // Note that the new weight should always be higher than the old one. var_ordering_.IncreasePriority(element); @@ -452,22 +436,18 @@ void SatDecisionPolicy::Untrail(int target_trail_index) { new_rate = static_cast(num_bumps) / num_conflicts; } activities_[var] = alpha * new_rate + (1 - alpha) * activities_[var]; - if (var_ordering_is_initialized_) - PqInsertOrUpdate(var); + if (var_ordering_is_initialized_) PqInsertOrUpdate(var); } if (num_conflicts > 0) { if (!num_conflicts_stack_.empty() && num_conflicts_stack_.back().trail_index == trail_.Index()) { num_conflicts_stack_.back().count += num_conflicts; } else { - num_conflicts_stack_.push_back({ - trail_.Index(), num_conflicts - }); + num_conflicts_stack_.push_back({trail_.Index(), num_conflicts}); } } } else { - if (!var_ordering_is_initialized_) - return; + if (!var_ordering_is_initialized_) return; // Trail index of the next variable that will need a priority queue update. int to_update = pq_need_update_for_var_at_trail_index_.Top(); @@ -490,5 +470,5 @@ void SatDecisionPolicy::Untrail(int target_trail_index) { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/sat_decision.h b/ortools/sat/sat_decision.h index 1f9531854f..9d35755cd3 100644 --- a/ortools/sat/sat_decision.h +++ b/ortools/sat/sat_decision.h @@ -32,7 +32,7 @@ namespace sat { // Implement the SAT branching policy responsible for deciding the next Boolean // variable to branch on, and its polarity (true or false). class SatDecisionPolicy { -public: + public: explicit SatDecisionPolicy(Model *model); // Notifies that more variables are now present. Note that currently this may @@ -101,7 +101,7 @@ public: // Returns the vector of the current assignment preferences. std::vector > AllPreferences() const; -private: + private: // Computes an initial variable ordering. void InitializeVariableOrdering(); @@ -228,7 +228,7 @@ private: gtl::ITIVector weighted_sign_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SAT_DECISION_H_ +#endif // OR_TOOLS_SAT_SAT_DECISION_H_ diff --git a/ortools/sat/sat_inprocessing.cc b/ortools/sat/sat_inprocessing.cc index 4281b6af58..5493420e7b 100644 --- a/ortools/sat/sat_inprocessing.cc +++ b/ortools/sat/sat_inprocessing.cc @@ -36,9 +36,8 @@ void PostsolveClauses::AddClauseWithSpecialLiteral( CHECK(found); } -#define RETURN_IF_FALSE(f) \ - if (!(f)) \ - return false; +#define RETURN_IF_FALSE(f) \ + if (!(f)) return false; bool Inprocessing::PresolveLoop(SatPresolveOptions options) { WallTimer wall_timer; @@ -60,8 +59,7 @@ bool Inprocessing::PresolveLoop(SatPresolveOptions options) { while (!time_limit_->LimitReached() && time_limit_->GetElapsedDeterministicTime() <= stop_dtime) { CHECK_EQ(sat_solver_->CurrentDecisionLevel(), 0); - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; // This one is fast since only newly fixed variables are considered. implication_graph_->RemoveFixedVariables(); @@ -102,8 +100,7 @@ bool Inprocessing::PresolveLoop(SatPresolveOptions options) { const double saved_wtime = wall_timer.Get(); const double time_left = stop_dtime - time_limit_->GetElapsedDeterministicTime(); - if (time_left <= 0) - break; + if (time_left <= 0) break; ProbingOptions probing_options; probing_options.log_info = log_round_info; probing_options.deterministic_limit = time_left; @@ -121,8 +118,7 @@ bool Inprocessing::PresolveLoop(SatPresolveOptions options) { } // TODO(user): Maintain the total number of literals in the watched clauses. - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; LOG_IF(INFO, log_info) << "Presolve." @@ -150,15 +146,14 @@ bool Inprocessing::InprocessingRound() { const double start_dtime = time_limit_->GetElapsedDeterministicTime(); // Try to spend a given ratio of time in the inprocessing. - if (total_dtime_ > 0.1 * start_dtime) - return true; + if (total_dtime_ > 0.1 * start_dtime) return true; // We make sure we do not "pollute" the current saved polarities. We will // restore them at the end. // // TODO(user): We should probably also disable the variable/clauses activity // updates. - decision_policy_->MaybeEnablePhaseSaving(/*save_phase=*/ false); + decision_policy_->MaybeEnablePhaseSaving(/*save_phase=*/false); RETURN_IF_FALSE(DetectEquivalencesAndStamp(true, log_round_info)); RETURN_IF_FALSE(RemoveFixedAndEquivalentVariables(log_round_info)); @@ -182,7 +177,7 @@ bool Inprocessing::InprocessingRound() { // TODO(user): Add a small wrapper function to time this. RETURN_IF_FALSE(LevelZeroPropagate()); - sat_solver_->MinimizeSomeClauses(/*decisions_budget=*/ 1000); + sat_solver_->MinimizeSomeClauses(/*decisions_budget=*/1000); RETURN_IF_FALSE(LevelZeroPropagate()); RETURN_IF_FALSE(SubsumeAndStrenghtenRound(log_round_info)); @@ -204,7 +199,7 @@ bool Inprocessing::InprocessingRound() { << " wtime: " << wall_timer.Get() << " non-probing time: " << (wall_timer.Get() - probing_time); - decision_policy_->MaybeEnablePhaseSaving(/*save_phase=*/ true); + decision_policy_->MaybeEnablePhaseSaving(/*save_phase=*/true); return true; } @@ -231,28 +226,23 @@ bool Inprocessing::LevelZeroPropagate() { // since it needs a DAG and can detect extra failed literal. bool Inprocessing::DetectEquivalencesAndStamp(bool use_transitive_reduction, bool log_info) { - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; implication_graph_->RemoveFixedVariables(); if (!implication_graph_->IsDag()) { // TODO(user): consider doing the transitive reduction after each SCC. // It might be slow but we could try to make it more incremental to // compensate and it should allow further reduction. - if (!implication_graph_->DetectEquivalences(log_info)) - return false; - if (!LevelZeroPropagate()) - return false; + if (!implication_graph_->DetectEquivalences(log_info)) return false; + if (!LevelZeroPropagate()) return false; if (use_transitive_reduction) { if (!implication_graph_->ComputeTransitiveReduction(log_info)) { return false; } - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; } } - if (!stamping_simplifier_->ComputeStampsForNextRound(log_info)) - return false; + if (!stamping_simplifier_->ComputeStampsForNextRound(log_info)) return false; return LevelZeroPropagate(); } @@ -263,8 +253,7 @@ bool Inprocessing::RemoveFixedAndEquivalentVariables(bool log_info) { // but if we split this into two functions, we could rewrite clause at any // level. CHECK_EQ(sat_solver_->CurrentDecisionLevel(), 0); - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; // Test if some work is needed. // @@ -309,8 +298,7 @@ bool Inprocessing::RemoveFixedAndEquivalentVariables(bool log_info) { // TODO(user): we should output literal to the proof right away, // currently if we remove clauses before fixing literal the proof is // wrong. - if (!clause_manager_->InprocessingFixLiteral(l)) - return false; + if (!clause_manager_->InprocessingFixLiteral(l)) return false; clause_manager_->InprocessingRemoveClause(clause); num_removed_literals += clause->size(); removed = true; @@ -323,8 +311,7 @@ bool Inprocessing::RemoveFixedAndEquivalentVariables(bool log_info) { } num_inspected_literals += clause->size(); - if (removed || !need_rewrite) - continue; + if (removed || !need_rewrite) continue; num_inspected_literals += clause->size(); // Rewrite the clause. @@ -345,10 +332,8 @@ bool Inprocessing::RemoveFixedAndEquivalentVariables(bool log_info) { } // Restore marked. - for (const Literal l : new_clause) - marked[l.Index()] = false; - if (removed) - continue; + for (const Literal l : new_clause) marked[l.Index()] = false; + if (removed) continue; num_removed_literals += clause->size() - new_clause.size(); if (!clause_manager_->InprocessingRewriteClause(clause, new_clause)) { @@ -359,9 +344,9 @@ bool Inprocessing::RemoveFixedAndEquivalentVariables(bool log_info) { // TODO(user): find a way to auto-tune that after a run on borg... const double dtime = static_cast(num_inspected_literals) * 1e-8; time_limit_->AdvanceDeterministicTime(dtime); - LOG_IF(INFO, log_info) - << "Cleanup. num_removed_literals: " << num_removed_literals - << " dtime: " << dtime << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "Cleanup. num_removed_literals: " + << num_removed_literals << " dtime: " << dtime + << " wtime: " << wall_timer.Get(); return true; } @@ -395,9 +380,8 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { // TODO(user): probably faster without the size indirection. std::vector clauses = clause_manager_->AllClausesInCreationOrder(); - std::sort(clauses.begin(), clauses.end(), [](SatClause * a, SatClause * b) { - return a->size() < b->size(); - }); + std::sort(clauses.begin(), clauses.end(), + [](SatClause *a, SatClause *b) { return a->size() < b->size(); }); // Used to mark clause literals. const LiteralIndex num_literals(sat_solver_->NumVariables() * 2); @@ -438,9 +422,7 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { marked.SparseClearAll(); for (const Literal l : clause->AsSpan()) { marked.Set(l.Index()); - signature |= (uint64 { - 1 - } << (l.Variable().value() % 64)); + signature |= (uint64{1} << (l.Variable().value() % 64)); } // Look for clause that subsumes this one. Note that because we inspect @@ -452,8 +434,7 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { for (const Literal l : clause->AsSpan()) { num_inspected_signatures += one_watcher[l.Index()].size(); for (const int i : one_watcher[l.Index()]) { - if ((mask & signatures[i]) != 0) - continue; + if ((mask & signatures[i]) != 0) continue; bool subsumed = true; bool stengthen = true; @@ -482,24 +463,20 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { candidates_for_removal.push_back(Literal(to_remove)); } } - if (removed) - break; + if (removed) break; } - if (removed) - continue; + if (removed) continue; // For strengthenning we also need to check the negative watcher lists. for (const Literal l : clause->AsSpan()) { num_inspected_signatures += one_watcher[l.NegatedIndex()].size(); for (const int i : one_watcher[l.NegatedIndex()]) { - if ((mask & signatures[i]) != 0) - continue; + if ((mask & signatures[i]) != 0) continue; bool stengthen = true; num_inspected_literals += clauses[i]->size(); for (const Literal o : clauses[i]->AsSpan()) { - if (o == l.Negated()) - continue; + if (o == l.Negated()) continue; if (!marked[o.Index()]) { stengthen = false; break; @@ -525,8 +502,7 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { int new_size = 0; for (const Literal l : new_clause) { - if (l == candidates_for_removal[0]) - continue; + if (l == candidates_for_removal[0]) continue; new_clause[new_size++] = l; } CHECK_EQ(new_size + 1, new_clause.size()); @@ -536,15 +512,12 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { if (!clause_manager_->InprocessingRewriteClause(clause, new_clause)) { return false; } - if (clause->size() == 0) - continue; + if (clause->size() == 0) continue; // Recompute signature. signature = 0; for (const Literal l : clause->AsSpan()) { - signature |= (uint64 { - 1 - } << (l.Variable().value() % 64)); + signature |= (uint64{1} << (l.Variable().value() % 64)); } } @@ -583,17 +556,17 @@ bool Inprocessing::SubsumeAndStrenghtenRound(bool log_info) { } // We might have fixed variables, finish the propagation. - if (!LevelZeroPropagate()) - return false; + if (!LevelZeroPropagate()) return false; // TODO(user): tune the deterministic time. const double dtime = static_cast(num_inspected_signatures) * 1e-8 + static_cast(num_inspected_literals) * 5e-9; time_limit_->AdvanceDeterministicTime(dtime); - LOG_IF(INFO, log_info) - << "Subsume. num_removed_literals: " << num_removed_literals - << " num_subsumed: " << num_subsumed_clauses << " dtime: " << dtime - << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "Subsume. num_removed_literals: " + << num_removed_literals + << " num_subsumed: " << num_subsumed_clauses + << " dtime: " << dtime + << " wtime: " << wall_timer.Get(); return true; } @@ -606,35 +579,30 @@ bool StampingSimplifier::DoOneRound(bool log_info) { num_removed_literals_ = 0; num_fixed_ = 0; - if (implication_graph_->literal_size() == 0) - return true; - if (implication_graph_->num_implications() == 0) - return true; + if (implication_graph_->literal_size() == 0) return true; + if (implication_graph_->num_implications() == 0) return true; if (!stamps_are_already_computed_) { // We need a DAG so that we don't have cycle while we sample the tree. // TODO(user): We could probably deal with it if needed so that we don't // need to do equivalence detetion each time we want to run this. implication_graph_->RemoveFixedVariables(); - if (!implication_graph_->DetectEquivalences(log_info)) - return true; + if (!implication_graph_->DetectEquivalences(log_info)) return true; SampleTreeAndFillParent(); - if (!ComputeStamps()) - return false; + if (!ComputeStamps()) return false; } stamps_are_already_computed_ = false; - if (!ProcessClauses()) - return false; + if (!ProcessClauses()) return false; // Note that num_removed_literals_ do not count the literals of the subsumed // clauses. time_limit_->AdvanceDeterministicTime(dtime_); log_info |= VLOG_IS_ON(1); - LOG_IF(INFO, log_info) - << "Stamping. num_removed_literals: " << num_removed_literals_ - << " num_subsumed: " << num_subsumed_clauses_ - << " num_fixed: " << num_fixed_ << " dtime: " << dtime_ - << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "Stamping. num_removed_literals: " + << num_removed_literals_ + << " num_subsumed: " << num_subsumed_clauses_ + << " num_fixed: " << num_fixed_ << " dtime: " << dtime_ + << " wtime: " << wall_timer.Get(); return true; } @@ -644,17 +612,13 @@ bool StampingSimplifier::ComputeStampsForNextRound(bool log_info) { dtime_ = 0.0; num_fixed_ = 0; - if (implication_graph_->literal_size() == 0) - return true; - if (implication_graph_->num_implications() == 0) - return true; + if (implication_graph_->literal_size() == 0) return true; + if (implication_graph_->num_implications() == 0) return true; implication_graph_->RemoveFixedVariables(); - if (!implication_graph_->DetectEquivalences(log_info)) - return true; + if (!implication_graph_->DetectEquivalences(log_info)) return true; SampleTreeAndFillParent(); - if (!ComputeStamps()) - return false; + if (!ComputeStamps()) return false; stamps_are_already_computed_ = true; // TODO(user): compute some dtime, it is always zero currently. @@ -668,14 +632,12 @@ bool StampingSimplifier::ComputeStampsForNextRound(bool log_info) { void StampingSimplifier::SampleTreeAndFillParent() { const int size = implication_graph_->literal_size(); - CHECK(implication_graph_->IsDag()); // so we don't have cycle. + CHECK(implication_graph_->IsDag()); // so we don't have cycle. parents_.resize(size); for (LiteralIndex i(0); i < size; ++i) { - parents_[i] = i; // default. - if (implication_graph_->IsRedundant(Literal(i))) - continue; - if (assignment_.LiteralIsAssigned(Literal(i))) - continue; + parents_[i] = i; // default. + if (implication_graph_->IsRedundant(Literal(i))) continue; + if (assignment_.LiteralIsAssigned(Literal(i))) continue; // TODO(user): Better algo to not select redundant parent. // @@ -687,15 +649,14 @@ void StampingSimplifier::SampleTreeAndFillParent() { // them to the implication graph already). const auto &children_of_not_l = implication_graph_->DirectImplications(Literal(i).Negated()); - if (children_of_not_l.empty()) - continue; + if (children_of_not_l.empty()) continue; for (int num_tries = 0; num_tries < 10; ++num_tries) { - const Literal candidate = children_of_not_l[ - absl::Uniform(*random_, 0, children_of_not_l.size())].Negated(); - if (implication_graph_->IsRedundant(candidate)) - continue; - if (i == candidate.Index()) - continue; + const Literal candidate = + children_of_not_l[absl::Uniform(*random_, 0, + children_of_not_l.size())] + .Negated(); + if (implication_graph_->IsRedundant(candidate)) continue; + if (i == candidate.Index()) continue; // We found an interesting parent. parents_[i] = candidate.Index(); @@ -710,13 +671,12 @@ bool StampingSimplifier::ComputeStamps() { // Compute sizes. sizes_.assign(size, 0); for (LiteralIndex i(0); i < size; ++i) { - if (parents_[i] == i) - continue; // leaf. + if (parents_[i] == i) continue; // leaf. sizes_[parents_[i]]++; } // Compute starts in the children_ vector for each node. - starts_.resize(size + 1); // We use a sentinel. + starts_.resize(size + 1); // We use a sentinel. starts_[LiteralIndex(0)] = 0; for (LiteralIndex i(1); i <= size; ++i) { starts_[i] = starts_[i - 1] + sizes_[i - 1]; @@ -725,8 +685,7 @@ bool StampingSimplifier::ComputeStamps() { // Fill children. This messes up starts_. children_.resize(size); for (LiteralIndex i(0); i < size; ++i) { - if (parents_[i] == i) - continue; // leaf. + if (parents_[i] == i) continue; // leaf. children_[starts_[parents_[i]]++] = i; } @@ -748,8 +707,7 @@ bool StampingSimplifier::ComputeStamps() { last_stamps_.resize(size); marked_.assign(size, false); for (LiteralIndex i(0); i < size; ++i) { - if (parents_[i] != i) - continue; // Not a root. + if (parents_[i] != i) continue; // Not a root. DCHECK(!marked_[i]); const LiteralIndex tree_root = i; dfs_stack_.push_back(i); @@ -780,10 +738,10 @@ bool StampingSimplifier::ComputeStamps() { } } - const int end = starts_[top + 1]; // Ok with sentinel. + const int end = starts_[top + 1]; // Ok with sentinel. for (int j = starts_[top]; j < end; ++j) { - DCHECK_NE(top, children_[j]); // We removed leaf self-loop. - DCHECK(!marked_[children_[j]]); // This is a tree. + DCHECK_NE(top, children_[j]); // We removed leaf self-loop. + DCHECK(!marked_[children_[j]]); // This is a tree. dfs_stack_.push_back(children_[j]); } } @@ -794,9 +752,9 @@ bool StampingSimplifier::ComputeStamps() { bool StampingSimplifier::ProcessClauses() { struct Entry { - int i; // Index in the clause. - bool is_negated; // Correspond to clause[i] or clause[i].Negated(); - int start; // Note that all start stamps are different. + int i; // Index in the clause. + bool is_negated; // Correspond to clause[i] or clause[i].Negated(); + int start; // Note that all start stamps are different. int end; bool operator<(const Entry &o) const { return start < o.start; } }; @@ -807,8 +765,7 @@ bool StampingSimplifier::ProcessClauses() { clause_manager_->DetachAllClauses(); for (SatClause *clause : clause_manager_->AllClausesInCreationOrder()) { const auto span = clause->AsSpan(); - if (span.empty()) - continue; + if (span.empty()) continue; // Note that we might fix literal as we perform the loop here, so we do // need to deal with them. @@ -822,18 +779,13 @@ bool StampingSimplifier::ProcessClauses() { clause_manager_->InprocessingRemoveClause(clause); break; } - if (assignment_.LiteralIsFalse(span[i])) - continue; - entries.push_back({ - i, false, first_stamps_[span[i].Index()], last_stamps_[span[i].Index()] - }); - entries.push_back({ - i, true, first_stamps_[span[i].NegatedIndex()], - last_stamps_[span[i].NegatedIndex()] - }); + if (assignment_.LiteralIsFalse(span[i])) continue; + entries.push_back({i, false, first_stamps_[span[i].Index()], + last_stamps_[span[i].Index()]}); + entries.push_back({i, true, first_stamps_[span[i].NegatedIndex()], + last_stamps_[span[i].NegatedIndex()]}); } - if (clause->empty()) - continue; + if (clause->empty()) continue; // The sort should be dominant. if (!entries.empty()) { @@ -843,7 +795,7 @@ bool StampingSimplifier::ProcessClauses() { } Entry top_entry; - top_entry.end = -1; // Sentinel. + top_entry.end = -1; // Sentinel. to_remove.clear(); for (const Entry &e : entries) { if (e.end < top_entry.end) { @@ -865,8 +817,8 @@ bool StampingSimplifier::ProcessClauses() { } } else { // span[i] => not(span[i]) so span[i] false. - if (!clause_manager_->InprocessingFixLiteral(span[top_entry.i] - .Negated())) { + if (!clause_manager_->InprocessingFixLiteral( + span[top_entry.i].Negated())) { return false; } to_remove.push_back(top_entry.i); @@ -904,8 +856,7 @@ bool StampingSimplifier::ProcessClauses() { } } - if (clause->empty()) - continue; + if (clause->empty()) continue; // Strengthen the clause. if (!to_remove.empty() || entries.size() < span.size()) { @@ -922,8 +873,7 @@ bool StampingSimplifier::ProcessClauses() { clause_manager_->InprocessingRemoveClause(clause); continue; } - if (assignment_.LiteralIsFalse(span[i])) - continue; + if (assignment_.LiteralIsFalse(span[i])) continue; new_clause.push_back(span[i]); } num_removed_literals_ += span.size() - new_clause.size(); @@ -958,9 +908,9 @@ void BlockedClauseSimplifier::DoOneRound(bool log_info) { dtime_ += 1e-8 * num_inspected_literals_; time_limit_->AdvanceDeterministicTime(dtime_); log_info |= VLOG_IS_ON(1); - LOG_IF(INFO, log_info) - << "Blocked clause. num_blocked_clauses: " << num_blocked_clauses_ - << " dtime: " << dtime_ << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "Blocked clause. num_blocked_clauses: " + << num_blocked_clauses_ << " dtime: " << dtime_ + << " wtime: " << wall_timer.Get(); } void BlockedClauseSimplifier::InitializeForNewRound() { @@ -969,8 +919,7 @@ void BlockedClauseSimplifier::InitializeForNewRound() { clause_manager_->DetachAllClauses(); for (SatClause *c : clause_manager_->AllClausesInCreationOrder()) { // We ignore redundant clause. This shouldn't cause any validity issue. - if (clause_manager_->IsRemovable(c)) - continue; + if (clause_manager_->IsRemovable(c)) continue; clauses_.push_back(c); } @@ -984,9 +933,8 @@ void BlockedClauseSimplifier::InitializeForNewRound() { } marked_.resize(num_literals); - DCHECK(std::all_of(marked_.begin(), marked_.end(), [](bool b) { - return !b; - })); + DCHECK( + std::all_of(marked_.begin(), marked_.end(), [](bool b) { return !b; })); // TODO(user): because we don't create new clause here we can use a flat // vector for literal_to_clauses_. @@ -1001,10 +949,8 @@ void BlockedClauseSimplifier::InitializeForNewRound() { } void BlockedClauseSimplifier::ProcessLiteral(Literal current_literal) { - if (assignment_.LiteralIsAssigned(current_literal)) - return; - if (implication_graph_->IsRemoved(current_literal)) - return; + if (assignment_.LiteralIsAssigned(current_literal)) return; + if (implication_graph_->IsRemoved(current_literal)) return; // We want to check first that this clause will resolve to trivial clause with // all binary containing not(current_literal). So mark all literal l so that @@ -1022,8 +968,7 @@ void BlockedClauseSimplifier::ProcessLiteral(Literal current_literal) { const std::vector &implications = implication_graph_->DirectImplications(current_literal); for (const Literal l : implications) { - if (l == current_literal) - continue; + if (l == current_literal) continue; ++num_binary; marked_[l.Index()] = true; } @@ -1033,27 +978,23 @@ void BlockedClauseSimplifier::ProcessLiteral(Literal current_literal) { // clauses_to_process clauses that resolve trivially with that clause. std::vector clauses_to_process; for (const ClauseIndex i : literal_to_clauses_[current_literal.Index()]) { - if (clauses_[i]->empty()) - continue; + if (clauses_[i]->empty()) continue; // Blocked with respect to binary clause only? all marked binary should have // their negation in clause. // // TODO(user): Abort if size left is too small. if (num_binary > 0) { - if (clauses_[i]->size() <= num_binary) - continue; + if (clauses_[i]->size() <= num_binary) continue; int num_with_negation_marked = 0; for (const Literal l : clauses_[i]->AsSpan()) { - if (l == current_literal) - continue; + if (l == current_literal) continue; if (marked_[l.NegatedIndex()]) { ++num_with_negation_marked; } } num_inspected_literals_ += clauses_[i]->size(); - if (num_with_negation_marked < num_binary) - continue; + if (num_with_negation_marked < num_binary) continue; } clauses_to_process.push_back(i); } @@ -1098,26 +1039,22 @@ void BlockedClauseSimplifier::ProcessLiteral(Literal current_literal) { } // Note that this assume that the binary clauses have already been checked. -bool -BlockedClauseSimplifier::ClauseIsBlocked(Literal current_literal, - absl::Span clause) { +bool BlockedClauseSimplifier::ClauseIsBlocked( + Literal current_literal, absl::Span clause) { bool is_blocked = true; - for (const Literal l : clause) - marked_[l.Index()] = true; + for (const Literal l : clause) marked_[l.Index()] = true; // TODO(user): For faster reprocessing of the same literal, we should move // all clauses that are used in a non-blocked certificate first in the list. for (const ClauseIndex i : literal_to_clauses_[current_literal.NegatedIndex()]) { - if (clauses_[i]->empty()) - continue; + if (clauses_[i]->empty()) continue; bool some_marked = false; for (const Literal l : clauses_[i]->AsSpan()) { // TODO(user): we can be faster here by only updating it at the end? ++num_inspected_literals_; - if (l == current_literal.Negated()) - continue; + if (l == current_literal.Negated()) continue; if (marked_[l.NegatedIndex()]) { some_marked = true; break; @@ -1129,8 +1066,7 @@ BlockedClauseSimplifier::ClauseIsBlocked(Literal current_literal, } } - for (const Literal l : clause) - marked_[l.Index()] = false; + for (const Literal l : clause) marked_[l.Index()] = false; return is_blocked; } @@ -1153,8 +1089,7 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { // We ignore redundant clause. This shouldn't cause any validity issue. // TODO(user): but we shouldn't keep clauses containing removed literals. // It is still valid to do so, but it should be less efficient. - if (clause_manager_->IsRemovable(c)) - continue; + if (clause_manager_->IsRemovable(c)) continue; clauses_.push_back(c); } @@ -1179,17 +1114,14 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { in_need_to_be_updated_.resize(num_variables); queue_.Reserve(num_variables); for (BooleanVariable v(0); v < num_variables; ++v) { - if (assignment_.VariableIsAssigned(v)) - continue; - if (implication_graph_->IsRemoved(Literal(v, true))) - continue; + if (assignment_.VariableIsAssigned(v)) continue; + if (implication_graph_->IsRemoved(Literal(v, true))) continue; UpdatePriorityQueue(v); } marked_.resize(num_literals); - DCHECK(std::all_of(marked_.begin(), marked_.end(), [](bool b) { - return !b; - })); + DCHECK( + std::all_of(marked_.begin(), marked_.end(), [](bool b) { return !b; })); // TODO(user): add a local dtime limit for the corner case where this take too // much time. We can adapt the limit depending on how much we want to spend on @@ -1204,24 +1136,19 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { // TODO(user): we might also find new equivalent variable l => var => l // here, but for now we ignore those. bool is_unsat = false; - if (!Propagate()) - return false; + if (!Propagate()) return false; while (implication_graph_->FindFailedLiteralAroundVar(top, &is_unsat)) { - if (!Propagate()) - return false; + if (!Propagate()) return false; } - if (is_unsat) - return false; + if (is_unsat) return false; - if (!CrossProduct(top)) - return false; + if (!CrossProduct(top)) return false; for (const BooleanVariable v : need_to_be_updated_) { in_need_to_be_updated_[v] = false; // Currently we never re-add top if we just processed it. - if (v != top) - UpdatePriorityQueue(v); + if (v != top) UpdatePriorityQueue(v); } in_need_to_be_updated_.clear(); need_to_be_updated_.clear(); @@ -1232,8 +1159,7 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { // Remove all redundant clause containing a removed literal. This avoid to // re-introduce a removed literal via conflict learning. for (SatClause *c : clause_manager_->AllClausesInCreationOrder()) { - if (!clause_manager_->IsRemovable(c)) - continue; + if (!clause_manager_->IsRemovable(c)) continue; bool remove = false; for (const Literal l : c->AsSpan()) { if (implication_graph_->IsRemoved(l)) { @@ -1241,8 +1167,7 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { break; } } - if (remove) - clause_manager_->InprocessingRemoveClause(c); + if (remove) clause_manager_->InprocessingRemoveClause(c); } // Release some memory. @@ -1252,21 +1177,21 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) { dtime_ += 1e-8 * num_inspected_literals_; time_limit_->AdvanceDeterministicTime(dtime_); log_info |= VLOG_IS_ON(1); - LOG_IF(INFO, log_info) - << "BVE." - << " num_fixed: " << trail_->Index() - saved_trail_index - << " num_simplified_literals: " << num_simplifications_ - << " num_blocked_clauses_: " << num_blocked_clauses_ - << " num_eliminations: " << num_eliminated_variables_ - << " num_literals_diff: " << num_literals_diff_ - << " num_clause_diff: " << num_clauses_diff_ << " dtime: " << dtime_ - << " wtime: " << wall_timer.Get(); + LOG_IF(INFO, log_info) << "BVE." + << " num_fixed: " + << trail_->Index() - saved_trail_index + << " num_simplified_literals: " << num_simplifications_ + << " num_blocked_clauses_: " << num_blocked_clauses_ + << " num_eliminations: " << num_eliminated_variables_ + << " num_literals_diff: " << num_literals_diff_ + << " num_clause_diff: " << num_clauses_diff_ + << " dtime: " << dtime_ + << " wtime: " << wall_timer.Get(); return true; } -bool -BoundedVariableElimination::RemoveLiteralFromClause(Literal lit, - SatClause *sat_clause) { +bool BoundedVariableElimination::RemoveLiteralFromClause( + Literal lit, SatClause *sat_clause) { num_literals_diff_ -= sat_clause->size(); resolvant_.clear(); for (const Literal l : sat_clause->AsSpan()) { @@ -1286,8 +1211,7 @@ BoundedVariableElimination::RemoveLiteralFromClause(Literal lit, } if (sat_clause->empty()) { --num_clauses_diff_; - for (const Literal l : resolvant_) - literal_to_num_clauses_[l.Index()]--; + for (const Literal l : resolvant_) literal_to_num_clauses_[l.Index()]--; } else { num_literals_diff_ += sat_clause->size(); } @@ -1297,23 +1221,19 @@ BoundedVariableElimination::RemoveLiteralFromClause(Literal lit, bool BoundedVariableElimination::Propagate() { for (; propagation_index_ < trail_->Index(); ++propagation_index_) { // Make sure we always propagate the binary clauses first. - if (!implication_graph_->Propagate(trail_)) - return false; + if (!implication_graph_->Propagate(trail_)) return false; const Literal l = (*trail_)[propagation_index_]; for (const ClauseIndex index : literal_to_clauses_[l.Index()]) { - if (clauses_[index]->empty()) - continue; + if (clauses_[index]->empty()) continue; num_clauses_diff_--; num_literals_diff_ -= clauses_[index]->size(); clause_manager_->InprocessingRemoveClause(clauses_[index]); } literal_to_clauses_[l.Index()].clear(); for (const ClauseIndex index : literal_to_clauses_[l.NegatedIndex()]) { - if (clauses_[index]->empty()) - continue; - if (!RemoveLiteralFromClause(l.Negated(), clauses_[index])) - return false; + if (clauses_[index]->empty()) continue; + if (!RemoveLiteralFromClause(l.Negated(), clauses_[index])) return false; } literal_to_clauses_[l.NegatedIndex()].clear(); } @@ -1329,18 +1249,13 @@ int BoundedVariableElimination::NumClausesContaining(Literal l) { // TODO(user): Only enqueue variable that can be removed. void BoundedVariableElimination::UpdatePriorityQueue(BooleanVariable var) { - if (assignment_.VariableIsAssigned(var)) - return; + if (assignment_.VariableIsAssigned(var)) return; const int priority = -NumClausesContaining(Literal(var, true)) - NumClausesContaining(Literal(var, false)); if (queue_.Contains(var.value())) { - queue_.ChangePriority({ - var, priority - }); + queue_.ChangePriority({var, priority}); } else { - queue_.Add({ - var, priority - }); + queue_.Add({var, priority}); } } @@ -1366,8 +1281,7 @@ void BoundedVariableElimination::DeleteClause(SatClause *sat_clause) { void BoundedVariableElimination::DeleteAllClausesContaining(Literal literal) { for (const ClauseIndex i : literal_to_clauses_[literal.Index()]) { const auto clause = clauses_[i]->AsSpan(); - if (clause.empty()) - continue; + if (clause.empty()) continue; postsolve_->AddClauseWithSpecialLiteral(literal, clause); DeleteClause(clauses_[i]); } @@ -1376,8 +1290,7 @@ void BoundedVariableElimination::DeleteAllClausesContaining(Literal literal) { void BoundedVariableElimination::AddClause(absl::Span clause) { SatClause *pt = clause_manager_->InprocessingAddClause(clause); - if (pt == nullptr) - return; + if (pt == nullptr) return; num_clauses_diff_++; num_literals_diff_ += clause.size(); @@ -1404,14 +1317,11 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { for (int i = 0; i < clause_containing_lit.size(); ++i) { const ClauseIndex clause_index = clause_containing_lit[i]; const auto clause = clauses_[clause_index]->AsSpan(); - if (clause.empty()) - continue; + if (clause.empty()) continue; - if (!score_only) - resolvant_.clear(); + if (!score_only) resolvant_.clear(); for (const Literal l : clause) { - if (!score_only && l != lit) - resolvant_.push_back(l); + if (!score_only && l != lit) resolvant_.push_back(l); marked_[l.Index()] = true; } num_inspected_literals_ += clause.size() + implications.size(); @@ -1424,8 +1334,7 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { // Resolution with binary clauses. for (const Literal l : implications) { CHECK_NE(l, lit); - if (marked_[l.NegatedIndex()]) - continue; // trivial. + if (marked_[l.NegatedIndex()]) continue; // trivial. if (marked_[l.Index()]) { clause_can_be_simplified = true; break; @@ -1444,32 +1353,27 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { if (!with_binary_only && !clause_can_be_simplified) { auto &clause_containing_not_lit = literal_to_clauses_[lit.NegatedIndex()]; for (int j = 0; j < clause_containing_not_lit.size(); ++j) { - if (score_only && new_score_ > score_threshold_) - break; + if (score_only && new_score_ > score_threshold_) break; const ClauseIndex other_index = clause_containing_not_lit[j]; const auto other = clauses_[other_index]->AsSpan(); - if (other.empty()) - continue; + if (other.empty()) continue; bool trivial = false; int extra_size = 0; for (const Literal l : other) { // TODO(user): we can optimize this by updating it outside the loop. ++num_inspected_literals_; - if (l == lit.Negated()) - continue; + if (l == lit.Negated()) continue; if (marked_[l.NegatedIndex()]) { trivial = true; break; } if (!marked_[l.Index()]) { ++extra_size; - if (!score_only) - resolvant_.push_back(l); + if (!score_only) resolvant_.push_back(l); } } if (trivial) { - if (!score_only) - resolvant_.resize(resolvant_.size() - extra_size); + if (!score_only) resolvant_.resize(resolvant_.size() - extra_size); continue; } @@ -1496,7 +1400,7 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { std::swap(clause_containing_not_lit[j], clause_containing_not_lit.back()); clause_containing_not_lit.pop_back(); - --j; // Reprocess the new position. + --j; // Reprocess the new position. continue; } } @@ -1522,8 +1426,7 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { } // Note that we need to clear marked before aborting. - for (const Literal l : clause) - marked_[l.Index()] = false; + for (const Literal l : clause) marked_[l.Index()] = false; // In this case, we simplify and remove the clause from here. if (clause_can_be_simplified) { @@ -1533,15 +1436,13 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { new_score_ = saved_score; score_threshold_ -= clause_weight + clause.size(); - if (!RemoveLiteralFromClause(lit, clauses_[clause_index])) - return false; + if (!RemoveLiteralFromClause(lit, clauses_[clause_index])) return false; std::swap(clause_containing_lit[i], clause_containing_lit.back()); clause_containing_lit.pop_back(); - --i; // Reprocess the new position. + --i; // Reprocess the new position. } - if (score_only && new_score_ > score_threshold_) - return true; + if (score_only && new_score_ > score_threshold_) return true; // When this happen, then the clause is blocked (i.e. all its resolvant are // trivial). So even if we do not actually perform the variable elimination, @@ -1565,27 +1466,23 @@ bool BoundedVariableElimination::ResolveAllClauseContaining(Literal lit) { } bool BoundedVariableElimination::CrossProduct(BooleanVariable var) { - if (assignment_.VariableIsAssigned(var)) - return true; + if (assignment_.VariableIsAssigned(var)) return true; const Literal lit(var, true); const Literal not_lit(var, false); { const int s1 = NumClausesContaining(lit); const int s2 = NumClausesContaining(not_lit); - if (s1 == 0 && s2 == 0) - return true; + if (s1 == 0 && s2 == 0) return true; if (s1 > 0 && s2 == 0) { num_eliminated_variables_++; - if (!clause_manager_->InprocessingFixLiteral(lit)) - return false; + if (!clause_manager_->InprocessingFixLiteral(lit)) return false; DeleteAllClausesContaining(lit); return true; } if (s1 == 0 && s2 > 0) { num_eliminated_variables_++; - if (!clause_manager_->InprocessingFixLiteral(not_lit)) - return false; + if (!clause_manager_->InprocessingFixLiteral(not_lit)) return false; DeleteAllClausesContaining(not_lit); return true; } @@ -1621,13 +1518,11 @@ bool BoundedVariableElimination::CrossProduct(BooleanVariable var) { (clause_weight + 2); for (const ClauseIndex i : literal_to_clauses_[lit.Index()]) { const auto c = clauses_[i]->AsSpan(); - if (!c.empty()) - score += clause_weight + c.size(); + if (!c.empty()) score += clause_weight + c.size(); } for (const ClauseIndex i : literal_to_clauses_[not_lit.Index()]) { const auto c = clauses_[i]->AsSpan(); - if (!c.empty()) - score += clause_weight + c.size(); + if (!c.empty()) score += clause_weight + c.size(); } // Compute the new score after BVE. @@ -1641,29 +1536,26 @@ bool BoundedVariableElimination::CrossProduct(BooleanVariable var) { score_threshold_ = score; new_score_ = implication_graph_->NumImplicationOnVariableRemoval(var) * (clause_weight + 2); - if (new_score_ > score_threshold_) - return true; - if (!ResolveAllClauseContaining(not_lit)) { + if (new_score_ > score_threshold_) return true; + if (!ResolveAllClauseContaining(not_lit)) { return false; } - if (new_score_ > score_threshold_) - return true; - if (!ResolveAllClauseContaining(lit)) { + if (new_score_ > score_threshold_) return true; + if (!ResolveAllClauseContaining(lit)) { return false; } - if (new_score_ > score_threshold_) - return true; + if (new_score_ > score_threshold_) return true; // Perform BVE. if (new_score_ > 0) { - if (!ResolveAllClauseContaining(lit)) { + if (!ResolveAllClauseContaining(lit)) { return false; } - if (!ResolveAllClauseContaining(not_lit)) { + if (!ResolveAllClauseContaining(not_lit)) { return false; } } @@ -1675,5 +1567,5 @@ bool BoundedVariableElimination::CrossProduct(BooleanVariable var) { return true; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/sat_inprocessing.h b/ortools/sat/sat_inprocessing.h index 7b4ed6485c..b17d90e4e6 100644 --- a/ortools/sat/sat_inprocessing.h +++ b/ortools/sat/sat_inprocessing.h @@ -84,7 +84,7 @@ struct SatPresolveOptions { // InprocessingSolve() that lives outside SatSolver. Alternatively, we can // extract the propagation main loop and conflict analysis from SatSolver. class Inprocessing { -public: + public: explicit Inprocessing(Model *model) : assignment_(model->GetOrCreate()->Assignment()), implication_graph_(model->GetOrCreate()), @@ -130,7 +130,7 @@ public: // reductions that can be performed. Returns false if UNSAT. bool SubsumeAndStrenghtenRound(bool log_info); -private: + private: const VariablesAssignment &assignment_; BinaryImplicationGraph *implication_graph_; LiteralWatchers *clause_manager_; @@ -167,7 +167,7 @@ private: // Note that we randomize the spanning tree at each call. This can benefit by // having the implication graph be transitively reduced before. class StampingSimplifier { -public: + public: explicit StampingSimplifier(Model *model) : assignment_(model->GetOrCreate()->Assignment()), implication_graph_(model->GetOrCreate()), @@ -201,7 +201,7 @@ public: bool ProcessClauses(); -private: + private: const VariablesAssignment &assignment_; BinaryImplicationGraph *implication_graph_; LiteralWatchers *clause_manager_; @@ -246,7 +246,7 @@ private: // TODO(user): This requires that l only appear in clauses and not in the // integer part of CP-SAT. class BlockedClauseSimplifier { -public: + public: explicit BlockedClauseSimplifier(Model *model) : assignment_(model->GetOrCreate()->Assignment()), implication_graph_(model->GetOrCreate()), @@ -256,7 +256,7 @@ public: void DoOneRound(bool log_info); -private: + private: void InitializeForNewRound(); void ProcessLiteral(Literal current_literal); bool ClauseIsBlocked(Literal current_literal, @@ -288,7 +288,7 @@ private: }; class BoundedVariableElimination { -public: + public: explicit BoundedVariableElimination(Model *model) : parameters_(*model->GetOrCreate()), assignment_(model->GetOrCreate()->Assignment()), @@ -300,7 +300,7 @@ public: bool DoOneRound(bool log_info); -private: + private: int NumClausesContaining(Literal l); void UpdatePriorityQueue(BooleanVariable var); bool CrossProduct(BooleanVariable var); @@ -370,7 +370,7 @@ private: gtl::ITIVector literal_to_num_clauses_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SAT_INPROCESSING_H_ +#endif // OR_TOOLS_SAT_SAT_INPROCESSING_H_ diff --git a/ortools/sat/sat_solver.cc b/ortools/sat/sat_solver.cc index afe9e77486..64569d3bb8 100644 --- a/ortools/sat/sat_solver.cc +++ b/ortools/sat/sat_solver.cc @@ -44,14 +44,18 @@ SatSolver::SatSolver(Model *model) binary_implication_graph_(model->GetOrCreate()), clauses_propagator_(model->GetOrCreate()), pb_constraints_(model->GetOrCreate()), - track_binary_clauses_(false), trail_(model->GetOrCreate()), + track_binary_clauses_(false), + trail_(model->GetOrCreate()), time_limit_(model->GetOrCreate()), parameters_(model->GetOrCreate()), restart_(model->GetOrCreate()), decision_policy_(model->GetOrCreate()), - clause_activity_increment_(1.0), same_reason_identifier_(*trail_), - is_relevant_for_core_computation_(true), problem_is_pure_sat_(true), - drat_proof_handler_(nullptr), stats_("SatSolver") { + clause_activity_increment_(1.0), + same_reason_identifier_(*trail_), + is_relevant_for_core_computation_(true), + problem_is_pure_sat_(true), + drat_proof_handler_(nullptr), + stats_("SatSolver") { InitializePropagators(); } @@ -126,13 +130,10 @@ bool SatSolver::SetModelUnsat() { } bool SatSolver::AddClauseDuringSearch(absl::Span literals) { - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; const int index = trail_->Index(); - if (literals.empty()) - return SetModelUnsat(); - if (literals.size() == 1) - return AddUnitClause(literals[0]); + if (literals.empty()) return SetModelUnsat(); + if (literals.size() == 1) return AddUnitClause(literals[0]); if (literals.size() == 2) { const bool init = binary_implication_graph_->num_implications() == 0; if (!binary_implication_graph_->AddBinaryClauseDuringSearch(literals[0], @@ -154,31 +155,24 @@ bool SatSolver::AddClauseDuringSearch(absl::Span literals) { // Tricky: Even if nothing new is propagated, calling Propagate() might, via // the LP, deduce new things. This is problematic because some code assumes // that when we create newly associated literals, nothing else changes. - if (trail_->Index() == index) - return true; + if (trail_->Index() == index) return true; return FinishPropagation(); } bool SatSolver::AddUnitClause(Literal true_literal) { SCOPED_TIME_STAT(&stats_); CHECK_EQ(CurrentDecisionLevel(), 0); - if (model_is_unsat_) - return false; - if (trail_->Assignment().LiteralIsFalse(true_literal)) - return SetModelUnsat(); - if (trail_->Assignment().LiteralIsTrue(true_literal)) - return true; + if (model_is_unsat_) return false; + if (trail_->Assignment().LiteralIsFalse(true_literal)) return SetModelUnsat(); + if (trail_->Assignment().LiteralIsTrue(true_literal)) return true; if (drat_proof_handler_ != nullptr) { - // Note that we will output problem unit clauses twice, but that is a - // small - // price to pay for having a single variable fixing API. - drat_proof_handler_->AddClause({ - true_literal - }); + // Note that we will output problem unit clauses twice, but that is a + // small + // price to pay for having a single variable fixing API. + drat_proof_handler_->AddClause({true_literal}); } trail_->EnqueueWithUnitReason(true_literal); - if (!Propagate()) - return SetModelUnsat(); + if (!Propagate()) return SetModelUnsat(); return true; } @@ -188,8 +182,8 @@ bool SatSolver::AddBinaryClause(Literal a, Literal b) { tmp_pb_constraint_.push_back(LiteralWithCoeff(a, 1)); tmp_pb_constraint_.push_back(LiteralWithCoeff(b, 1)); return AddLinearConstraint( - /*use_lower_bound=*/ true, /*lower_bound=*/ Coefficient(1), - /*use_upper_bound=*/ false, /*upper_bound=*/ Coefficient(0), + /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1), + /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0), &tmp_pb_constraint_); } @@ -200,8 +194,8 @@ bool SatSolver::AddTernaryClause(Literal a, Literal b, Literal c) { tmp_pb_constraint_.push_back(LiteralWithCoeff(b, 1)); tmp_pb_constraint_.push_back(LiteralWithCoeff(c, 1)); return AddLinearConstraint( - /*use_lower_bound=*/ true, /*lower_bound=*/ Coefficient(1), - /*use_upper_bound=*/ false, /*upper_bound=*/ Coefficient(0), + /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1), + /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0), &tmp_pb_constraint_); } @@ -216,8 +210,8 @@ bool SatSolver::AddProblemClause(absl::Span literals) { tmp_pb_constraint_.push_back(LiteralWithCoeff(lit, 1)); } return AddLinearConstraint( - /*use_lower_bound=*/ true, /*lower_bound=*/ Coefficient(1), - /*use_upper_bound=*/ false, /*upper_bound=*/ Coefficient(0), + /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1), + /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0), &tmp_pb_constraint_); } @@ -230,11 +224,9 @@ bool SatSolver::AddProblemClauseInternal(absl::Span literals) { // simplifies the code. CHECK_GT(literals.size(), 0); if (literals.size() == 1) { - if (trail_->Assignment().LiteralIsFalse(literals[0])) - return false; - if (trail_->Assignment().LiteralIsTrue(literals[0])) - return true; - trail_->EnqueueWithUnitReason(literals[0]); // Not assigned. + if (trail_->Assignment().LiteralIsFalse(literals[0])) return false; + if (trail_->Assignment().LiteralIsTrue(literals[0])) return true; + trail_->EnqueueWithUnitReason(literals[0]); // Not assigned. return true; } @@ -248,20 +240,17 @@ bool SatSolver::AddProblemClauseInternal(absl::Span literals) { return true; } -bool -SatSolver::AddLinearConstraintInternal(const std::vector &cst, - Coefficient rhs, Coefficient max_value) { +bool SatSolver::AddLinearConstraintInternal( + const std::vector &cst, Coefficient rhs, + Coefficient max_value) { SCOPED_TIME_STAT(&stats_); DCHECK(BooleanLinearExpressionIsCanonical(cst)); - if (rhs < 0) - return SetModelUnsat(); // Unsatisfiable constraint. - if (rhs >= max_value) - return true; // Always satisfied constraint. + if (rhs < 0) return SetModelUnsat(); // Unsatisfiable constraint. + if (rhs >= max_value) return true; // Always satisfied constraint. // The case "rhs = 0" will just fix variables, so there is no need to // updates the weighted sign. - if (rhs > 0) - decision_policy_->UpdateWeightedSign(cst, rhs); + if (rhs > 0) decision_policy_->UpdateWeightedSign(cst, rhs); // Since the constraint is in canonical form, the coefficients are sorted. const Coefficient min_coeff = cst.front().coefficient; @@ -313,16 +302,14 @@ bool SatSolver::AddLinearConstraint(bool use_lower_bound, std::vector *cst) { SCOPED_TIME_STAT(&stats_); CHECK_EQ(CurrentDecisionLevel(), 0); - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; // This block removes assigned literals from the constraint. Coefficient fixed_variable_shift(0); { int index = 0; for (const LiteralWithCoeff &term : *cst) { - if (trail_->Assignment().LiteralIsFalse(term.literal)) - continue; + if (trail_->Assignment().LiteralIsFalse(term.literal)) continue; if (trail_->Assignment().LiteralIsTrue(term.literal)) { CHECK(SafeAddInto(-term.coefficient, &fixed_variable_shift)); continue; @@ -379,7 +366,7 @@ int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation( // ComputeBacktrackLevel() should have returned 0. CHECK_EQ(CurrentDecisionLevel(), 0); trail_->EnqueueWithUnitReason(literals[0]); - return /*lbd=*/ 1; + return /*lbd=*/1; } if (literals.size() == 2 && parameters_->treat_binary_clauses_separately()) { @@ -390,7 +377,7 @@ int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation( literals[1])); // In case this is the first binary clauses. InitializePropagators(); - return /*lbd=*/ 2; + return /*lbd=*/2; } CleanClauseDatabaseIfNeeded(); @@ -431,8 +418,8 @@ void SatSolver::AddLastPropagator(SatPropagator *propagator) { InitializePropagators(); } -UpperBoundedLinearConstraint * -SatSolver::ReasonPbConstraintOrNull(BooleanVariable var) const { +UpperBoundedLinearConstraint *SatSolver::ReasonPbConstraintOrNull( + BooleanVariable var) const { // It is important to deal properly with "SameReasonAs" variables here. var = trail_->ReferenceVarWithSameReason(var); const AssignmentInfo &info = trail_->Info(var); @@ -506,56 +493,48 @@ bool ClauseSubsumption(const std::vector &a, SatClause *b) { subset.end()); } -} // namespace +} // namespace int SatSolver::EnqueueDecisionAndBackjumpOnConflict(Literal true_literal) { SCOPED_TIME_STAT(&stats_); - if (model_is_unsat_) - return kUnsatTrailIndex; + if (model_is_unsat_) return kUnsatTrailIndex; CHECK(PropagationIsDone()); EnqueueNewDecision(true_literal); while (!PropagateAndStopAfterOneConflictResolution()) { - if (model_is_unsat_) - return kUnsatTrailIndex; + if (model_is_unsat_) return kUnsatTrailIndex; } CHECK(PropagationIsDone()); return last_decision_or_backtrack_trail_index_; } bool SatSolver::RestoreSolverToAssumptionLevel() { - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; if (CurrentDecisionLevel() > assumption_level_) { Backtrack(assumption_level_); return true; } - if (!FinishPropagation()) - return false; + if (!FinishPropagation()) return false; return ReapplyAssumptionsIfNeeded(); } bool SatSolver::FinishPropagation() { - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; while (!PropagateAndStopAfterOneConflictResolution()) { - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; } return true; } bool SatSolver::ResetToLevelZero() { - if (model_is_unsat_) - return false; + if (model_is_unsat_) return false; assumption_level_ = 0; Backtrack(0); return FinishPropagation(); } -bool -SatSolver::ResetWithGivenAssumptions(const std::vector &assumptions) { - if (!ResetToLevelZero()) - return false; +bool SatSolver::ResetWithGivenAssumptions( + const std::vector &assumptions) { + if (!ResetToLevelZero()) return false; // Assuming there is no duplicate in assumptions, but they can be a literal // and its negation (weird corner case), there will always be a conflict if we @@ -572,10 +551,8 @@ SatSolver::ResetWithGivenAssumptions(const std::vector &assumptions) { // Note that we do not count these as "branches" for a reporting purpose. bool SatSolver::ReapplyAssumptionsIfNeeded() { - if (model_is_unsat_) - return false; - if (CurrentDecisionLevel() >= assumption_level_) - return true; + if (model_is_unsat_) return false; + if (CurrentDecisionLevel() >= assumption_level_) return true; int unused = 0; const int64 old_num_branches = counters_.num_branches; @@ -588,8 +565,7 @@ bool SatSolver::ReapplyAssumptionsIfNeeded() { bool SatSolver::PropagateAndStopAfterOneConflictResolution() { SCOPED_TIME_STAT(&stats_); - if (Propagate()) - return true; + if (Propagate()) return true; ++counters_.num_failures; const int conflict_trail_index = trail_->Index(); @@ -603,8 +579,7 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { &subsumed_clauses_); // An empty conflict means that the problem is UNSAT. - if (learned_conflict_.empty()) - return SetModelUnsat(); + if (learned_conflict_.empty()) return SetModelUnsat(); DCHECK(IsConflictValid(learned_conflict_)); DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_)); @@ -682,8 +657,7 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { int pb_backjump_level; ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_, &pb_backjump_level); - if (pb_backjump_level == -1) - return SetModelUnsat(); + if (pb_backjump_level == -1) return SetModelUnsat(); // Convert the conflict into the vector form. std::vector cst; @@ -719,7 +693,7 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { // Continue with the normal clause flow, but use the PB conflict clause // if it has a lower backjump level. if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) { - subsumed_clauses_.clear(); // Because the conflict changes. + subsumed_clauses_.clear(); // Because the conflict changes. learned_conflict_.clear(); is_marked_.ClearAndResize(num_variables_); int max_level = 0; @@ -728,8 +702,7 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { DCHECK(Assignment().LiteralIsTrue(term.literal)); DCHECK_EQ(term.coefficient, 1); const int level = trail_->Info(term.literal.Variable()).level; - if (level == 0) - continue; + if (level == 0) continue; if (level > max_level) { max_level = level; max_index = learned_conflict_.size(); @@ -776,20 +749,20 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { // just uses the reason graph, this minimization can change the // clause LBD and even the backtracking level. switch (parameters_->binary_minimization_algorithm()) { - case SatParameters::NO_BINARY_MINIMIZATION: - ABSL_FALLTHROUGH_INTENDED; - case SatParameters::BINARY_MINIMIZATION_FIRST: - ABSL_FALLTHROUGH_INTENDED; - case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION: - break; - case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY: - binary_implication_graph_->MinimizeConflictWithReachability( - &learned_conflict_); - break; - case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION: - binary_implication_graph_->MinimizeConflictExperimental( - *trail_, &learned_conflict_); - break; + case SatParameters::NO_BINARY_MINIMIZATION: + ABSL_FALLTHROUGH_INTENDED; + case SatParameters::BINARY_MINIMIZATION_FIRST: + ABSL_FALLTHROUGH_INTENDED; + case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION: + break; + case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY: + binary_implication_graph_->MinimizeConflictWithReachability( + &learned_conflict_); + break; + case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION: + binary_implication_graph_->MinimizeConflictExperimental( + *trail_, &learned_conflict_); + break; } DCHECK(IsConflictValid(learned_conflict_)); } @@ -841,8 +814,8 @@ bool SatSolver::PropagateAndStopAfterOneConflictResolution() { return false; } -SatSolver::Status -SatSolver::ReapplyDecisionsUpTo(int max_level, int *first_propagation_index) { +SatSolver::Status SatSolver::ReapplyDecisionsUpTo( + int max_level, int *first_propagation_index) { SCOPED_TIME_STAT(&stats_); int decision_index = current_decision_level_; while (decision_index <= max_level) { @@ -865,8 +838,7 @@ SatSolver::ReapplyDecisionsUpTo(int max_level, int *first_propagation_index) { const int old_level = current_decision_level_; const int index = EnqueueDecisionAndBackjumpOnConflict(previous_decision); *first_propagation_index = std::min(*first_propagation_index, index); - if (index == kUnsatTrailIndex) - return INFEASIBLE; + if (index == kUnsatTrailIndex) return INFEASIBLE; if (current_decision_level_ <= old_level) { // A conflict occurred which backjumped to an earlier decision level. // We potentially backjumped over some valid decisions, so we need to @@ -889,8 +861,7 @@ int SatSolver::EnqueueDecisionAndBacktrackOnConflict(Literal true_literal) { SCOPED_TIME_STAT(&stats_); CHECK(PropagationIsDone()); - if (model_is_unsat_) - return kUnsatTrailIndex; + if (model_is_unsat_) return kUnsatTrailIndex; DCHECK_LT(CurrentDecisionLevel(), decisions_.size()); decisions_[CurrentDecisionLevel()].literal = true_literal; int first_propagation_index = trail_->Index(); @@ -902,8 +873,7 @@ bool SatSolver::EnqueueDecisionIfNotConflicting(Literal true_literal) { SCOPED_TIME_STAT(&stats_); CHECK(PropagationIsDone()); - if (model_is_unsat_) - return kUnsatTrailIndex; + if (model_is_unsat_) return kUnsatTrailIndex; const int current_level = CurrentDecisionLevel(); EnqueueNewDecision(true_literal); if (Propagate()) { @@ -925,8 +895,7 @@ void SatSolver::Backtrack(int target_level) { // that will cause some problems. Note that we could forbid a user to call // Backtrack() with the current level, but that is annoying when you just // want to reset the solver with Backtrack(0). - if (CurrentDecisionLevel() == target_level) - return; + if (CurrentDecisionLevel() == target_level) return; DCHECK_GE(target_level, 0); DCHECK_LE(target_level, CurrentDecisionLevel()); @@ -952,8 +921,7 @@ bool SatSolver::AddBinaryClauses(const std::vector &clauses) { } AddBinaryClauseInternal(c.a, c.b); } - if (!Propagate()) - return SetModelUnsat(); + if (!Propagate()) return SetModelUnsat(); return true; } @@ -970,13 +938,12 @@ namespace { int64 NextMultipleOf(int64 value, int64 interval) { return interval * (1 + value / interval); } -} // namespace +} // namespace SatSolver::Status SatSolver::ResetAndSolveWithGivenAssumptions( const std::vector &assumptions) { SCOPED_TIME_STAT(&stats_); - if (!ResetWithGivenAssumptions(assumptions)) - return UnsatStatus(); + if (!ResetWithGivenAssumptions(assumptions)) return UnsatStatus(); return SolveInternal(time_limit_); } @@ -1002,15 +969,13 @@ SatSolver::Status SatSolver::Solve() { return SolveInternal(time_limit_); } void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) { CHECK(Assignment().VariableIsAssigned(variable)); - if (trail_->Info(variable).level == 0) - return; + if (trail_->Info(variable).level == 0) return; int trail_index = trail_->Info(variable).trail_index; - std::vector is_marked(trail_index + 1, false); // move to local member. + std::vector is_marked(trail_index + 1, false); // move to local member. is_marked[trail_index] = true; int num = 1; for (; num > 0 && trail_index >= 0; --trail_index) { - if (!is_marked[trail_index]) - continue; + if (!is_marked[trail_index]) continue; is_marked[trail_index] = false; --num; @@ -1021,8 +986,7 @@ void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) { } for (const Literal l : trail_->Reason(var)) { const AssignmentInfo &info = trail_->Info(l.Variable()); - if (info.level == 0) - continue; + if (info.level == 0) continue; if (!is_marked[info.trail_index]) { is_marked[info.trail_index] = true; ++num; @@ -1047,8 +1011,7 @@ void SatSolver::TryToMinimizeClause(SatClause *clause) { // decision/progagation we need to perform. const int target_level = MoveOneUnprocessedLiteralLast( moved_last, CurrentDecisionLevel(), &candidate); - if (target_level == -1) - break; + if (target_level == -1) break; Backtrack(target_level); while (CurrentDecisionLevel() < candidate.size()) { const int level = CurrentDecisionLevel(); @@ -1098,8 +1061,7 @@ void SatSolver::TryToMinimizeClause(SatClause *clause) { Backtrack(0); return; } - if (model_is_unsat_) - return; + if (model_is_unsat_) return; } } if (candidate.empty()) { @@ -1111,8 +1073,7 @@ void SatSolver::TryToMinimizeClause(SatClause *clause) { // Returns if we don't have any minimization. Backtrack(0); - if (candidate.size() == clause->size()) - return; + if (candidate.size() == clause->size()) return; if (candidate.size() == 1) { if (drat_proof_handler_ != nullptr) { @@ -1152,8 +1113,7 @@ void SatSolver::TryToMinimizeClause(SatClause *clause) { SatSolver::Status SatSolver::SolveInternal(TimeLimit *time_limit) { SCOPED_TIME_STAT(&stats_); - if (model_is_unsat_) - return INFEASIBLE; + if (model_is_unsat_) return INFEASIBLE; // TODO(user): Because the counter are not reset to zero, this cause the // metrics / sec to be completely broken except when the solver is used @@ -1243,12 +1203,10 @@ SatSolver::Status SatSolver::SolveInternal(TimeLimit *time_limit) { if (!PropagateAndStopAfterOneConflictResolution()) { // A conflict occurred, continue the loop. - if (model_is_unsat_) - return StatusWithLog(INFEASIBLE); + if (model_is_unsat_) return StatusWithLog(INFEASIBLE); } else { // We need to reapply any assumptions that are not currently applied. - if (!ReapplyAssumptionsIfNeeded()) - return StatusWithLog(UnsatStatus()); + if (!ReapplyAssumptionsIfNeeded()) return StatusWithLog(UnsatStatus()); // At a leaf? if (trail_->Index() == num_variables_.value()) { @@ -1270,8 +1228,7 @@ SatSolver::Status SatSolver::SolveInternal(TimeLimit *time_limit) { // Corner case: the minimization above being based on propagation may // fix the remaining variables or prove UNSAT. - if (model_is_unsat_) - return StatusWithLog(INFEASIBLE); + if (model_is_unsat_) return StatusWithLog(INFEASIBLE); if (trail_->Index() == num_variables_.value()) { return StatusWithLog(FEASIBLE); } @@ -1294,8 +1251,7 @@ void SatSolver::MinimizeSomeClauses(int decisions_budget) { SatClause *to_minimize = clauses_propagator_->NextClauseToMinimize(); if (to_minimize != nullptr) { TryToMinimizeClause(to_minimize); - if (model_is_unsat_) - return; + if (model_is_unsat_) return; } else { if (to_minimize == nullptr) { VLOG(1) << "Minimized all clauses, restarting from first one."; @@ -1349,8 +1305,7 @@ std::vector SatSolver::GetLastIncompatibleDecisions() { while (trail_index >= 0 && !is_marked_[(*trail_)[trail_index].Variable()]) { --trail_index; } - if (trail_index < limit) - break; + if (trail_index < limit) break; const Literal marked_literal = (*trail_)[trail_index]; --trail_index; @@ -1362,8 +1317,7 @@ std::vector SatSolver::GetLastIncompatibleDecisions() { for (const Literal literal : trail_->Reason(marked_literal.Variable())) { const BooleanVariable var = literal.Variable(); const int level = DecisionLevel(var); - if (level > 0 && !is_marked_[var]) - is_marked_.Set(var); + if (level > 0 && !is_marked_[var]) is_marked_.Set(var); } } } @@ -1401,8 +1355,7 @@ void SatSolver::BumpClauseActivity(SatClause *clause) { // than the speed, this allows to limit as much as possible the activity // rescaling. auto it = clauses_propagator_->mutable_clauses_info()->find(clause); - if (it == clauses_propagator_->mutable_clauses_info()->end()) - return; + if (it == clauses_propagator_->mutable_clauses_info()->end()) return; // Check if the new clause LBD is below our threshold to keep this clause // indefinitely. Note that we use a +1 here because the LBD of a newly learned @@ -1415,20 +1368,20 @@ void SatSolver::BumpClauseActivity(SatClause *clause) { // Eventually protect this clause for the next cleanup phase. switch (parameters_->clause_cleanup_protection()) { - case SatParameters::PROTECTION_NONE: - break; - case SatParameters::PROTECTION_ALWAYS: - it->second.protected_during_next_cleanup = true; - break; - case SatParameters::PROTECTION_LBD: - // This one is similar to the one used by the Glucose SAT solver. - // - // TODO(user): why the +1? one reason may be that the LBD of a conflict - // decrease by 1 just afer the backjump... - if (new_lbd + 1 < it->second.lbd) { + case SatParameters::PROTECTION_NONE: + break; + case SatParameters::PROTECTION_ALWAYS: it->second.protected_during_next_cleanup = true; - it->second.lbd = new_lbd; - } + break; + case SatParameters::PROTECTION_LBD: + // This one is similar to the one used by the Glucose SAT solver. + // + // TODO(user): why the +1? one reason may be that the LBD of a conflict + // decrease by 1 just afer the backjump... + if (new_lbd + 1 < it->second.lbd) { + it->second.protected_during_next_cleanup = true; + it->second.lbd = new_lbd; + } } // Increase the activity. @@ -1453,13 +1406,11 @@ void SatSolver::UpdateClauseActivityIncrement() { bool SatSolver::IsConflictValid(const std::vector &literals) { SCOPED_TIME_STAT(&stats_); - if (literals.empty()) - return false; + if (literals.empty()) return false; const int highest_level = DecisionLevel(literals[0].Variable()); for (int i = 1; i < literals.size(); ++i) { const int level = DecisionLevel(literals[i].Variable()); - if (level <= 0 || level >= highest_level) - return false; + if (level <= 0 || level >= highest_level) return false; } return true; } @@ -1527,14 +1478,15 @@ std::string SatSolver::StatusString(Status status) const { absl::StrFormat( " num binary redundant implications: %d\n", binary_implication_graph_->num_redundant_implications()) + - absl::StrFormat(" num classic minimizations: %d" - " (literals removed: %d)\n", - counters_.num_minimizations, - counters_.num_literals_removed) + - absl::StrFormat(" num binary minimizations: %d" - " (literals removed: %d)\n", - binary_implication_graph_->num_minimization(), - binary_implication_graph_->num_literals_removed()) + + absl::StrFormat( + " num classic minimizations: %d" + " (literals removed: %d)\n", + counters_.num_minimizations, counters_.num_literals_removed) + + absl::StrFormat( + " num binary minimizations: %d" + " (literals removed: %d)\n", + binary_implication_graph_->num_minimization(), + binary_implication_graph_->num_literals_removed()) + absl::StrFormat(" num inspected clauses: %d\n", clauses_propagator_->num_inspected_clauses()) + absl::StrFormat(" num inspected clause_literals: %d\n", @@ -1583,10 +1535,8 @@ std::string SatSolver::RunningStatisticsString() const { } void SatSolver::ProcessNewlyFixedVariablesForDratProof() { - if (drat_proof_handler_ == nullptr) - return; - if (CurrentDecisionLevel() != 0) - return; + if (drat_proof_handler_ == nullptr) return; + if (CurrentDecisionLevel() != 0) return; // We need to output the literals that are fixed so we can remove all // clauses that contains them. Note that this doesn't seems to be needed @@ -1602,9 +1552,7 @@ void SatSolver::ProcessNewlyFixedVariablesForDratProof() { for (; drat_num_processed_fixed_variables_ < trail_->Index(); ++drat_num_processed_fixed_variables_) { temp = (*trail_)[drat_num_processed_fixed_variables_]; - drat_proof_handler_->AddClause({ - &temp, 1 - }); + drat_proof_handler_->AddClause({&temp, 1}); } } @@ -1620,8 +1568,7 @@ void SatSolver::ProcessNewlyFixedVariables() { // others. Note that none of the clause should be all false because we should // have detected a conflict before this is called. for (SatClause *clause : clauses_propagator_->AllClausesInCreationOrder()) { - if (!clause->IsAttached()) - continue; + if (!clause->IsAttached()) continue; const size_t old_size = clause->size(); if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->Assignment())) { @@ -1632,17 +1579,12 @@ void SatSolver::ProcessNewlyFixedVariables() { } const size_t new_size = clause->size(); - if (new_size == old_size) - continue; + if (new_size == old_size) continue; if (drat_proof_handler_ != nullptr) { CHECK_GT(new_size, 0); - drat_proof_handler_->AddClause({ - clause->begin(), new_size - }); - drat_proof_handler_->DeleteClause({ - clause->begin(), old_size - }); + drat_proof_handler_->AddClause({clause->begin(), new_size}); + drat_proof_handler_->DeleteClause({clause->begin(), old_size}); } if (new_size == 2 && parameters_->treat_binary_clauses_separately()) { @@ -1686,13 +1628,10 @@ bool SatSolver::Propagate() { const int old_index = trail_->Index(); for (SatPropagator *propagator : propagators_) { DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_)); - if (!propagator->Propagate(trail_)) - return false; - if (trail_->Index() > old_index) - break; + if (!propagator->Propagate(trail_)) return false; + if (trail_->Index() > old_index) break; } - if (trail_->Index() == old_index) - break; + if (trail_->Index() == old_index) break; } return true; } @@ -1726,8 +1665,7 @@ void SatSolver::InitializePropagators() { bool SatSolver::PropagationIsDone() const { for (SatPropagator *propagator : propagators_) { - if (!propagator->PropagationIsDone(*trail_)) - return false; + if (!propagator->PropagationIsDone(*trail_)) return false; } return true; } @@ -1753,18 +1691,18 @@ bool SatSolver::ResolvePBConflict(BooleanVariable var, // TODO(user): experiment and choose the "best" algo. const int algorithm = 1; switch (algorithm) { - case 1: - // We reduce the conflict slack to 0 before adding the clause. - // The advantage of this method is that the coefficients stay small. - conflict->ReduceSlackTo(*trail_, trail_index, *slack, Coefficient(0)); - break; - case 2: - // No reduction, we add the lower possible multiple. - multiplier = *slack + 1; - break; - default: - // No reduction, the multiple is chosen to cancel var. - multiplier = conflict->GetCoefficient(var); + case 1: + // We reduce the conflict slack to 0 before adding the clause. + // The advantage of this method is that the coefficients stay small. + conflict->ReduceSlackTo(*trail_, trail_index, *slack, Coefficient(0)); + break; + case 2: + // No reduction, we add the lower possible multiple. + multiplier = *slack + 1; + break; + default: + // No reduction, the multiple is chosen to cancel var. + multiplier = conflict->GetCoefficient(var); } Coefficient num_literals(1); @@ -1865,8 +1803,7 @@ void SatSolver::ComputeFirstUIPConflict( conflict->clear(); reason_used_to_infer_the_conflict->clear(); subsumed_clauses->clear(); - if (max_trail_index == -1) - return; + if (max_trail_index == -1) return; // max_trail_index is the maximum trail index appearing in the failing_clause // and its level (Which is almost always equals to the CurrentDecisionLevel(), @@ -1874,8 +1811,7 @@ void SatSolver::ComputeFirstUIPConflict( DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->FailingClause())); int trail_index = max_trail_index; const int highest_level = DecisionLevel((*trail_)[trail_index].Variable()); - if (highest_level == 0) - return; + if (highest_level == 0) return; // To find the 1-UIP conflict clause, we start by the failing_clause, and // expand each of its literal using the reason for this literal assignement to @@ -1902,8 +1838,7 @@ void SatSolver::ComputeFirstUIPConflict( for (const Literal literal : clause_to_expand) { const BooleanVariable var = literal.Variable(); const int level = DecisionLevel(var); - if (level > 0) - ++num_vars_at_positive_level_in_clause_to_expand; + if (level > 0) ++num_vars_at_positive_level_in_clause_to_expand; if (!is_marked_[var]) { is_marked_.Set(var); if (level == highest_level) { @@ -1982,8 +1917,7 @@ void SatSolver::ComputeUnionOfReasons(const std::vector &input, std::vector *literals) { tmp_mark_.ClearAndResize(num_variables_); literals->clear(); - for (const Literal l : input) - tmp_mark_.Set(l.Variable()); + for (const Literal l : input) tmp_mark_.Set(l.Variable()); for (const Literal l : input) { for (const Literal r : trail_->Reason(l.Variable())) { if (!tmp_mark_[r.Variable()]) { @@ -1992,10 +1926,8 @@ void SatSolver::ComputeUnionOfReasons(const std::vector &input, } } } - for (const Literal l : input) - tmp_mark_.Clear(l.Variable()); - for (const Literal l : *literals) - tmp_mark_.Clear(l.Variable()); + for (const Literal l : input) tmp_mark_.Clear(l.Variable()); + for (const Literal l : *literals) tmp_mark_.Clear(l.Variable()); } // TODO(user): Remove the literals assigned at level 0. @@ -2034,8 +1966,7 @@ void SatSolver::ComputePBConflict(int max_trail_index, // This can't happen at the beginning, but may happen later. // It means that even without var assigned, we still have a conflict. - if (slack < 0) - continue; + if (slack < 0) continue; // At this point, just removing the last assignment lift the conflict. // So we can abort if the true assignment before that is at a lower level @@ -2114,8 +2045,7 @@ void SatSolver::ComputePBConflict(int max_trail_index, Coefficient max_sum(0); for (BooleanVariable var : conflict->PossibleNonZeros()) { const Coefficient coeff = conflict->GetCoefficient(var); - if (coeff == 0) - continue; + if (coeff == 0) continue; max_sum += coeff; ++size; if (!trail_->Assignment().VariableIsAssigned(var) || @@ -2165,20 +2095,20 @@ void SatSolver::MinimizeConflict( const int old_size = conflict->size(); switch (parameters_->minimization_algorithm()) { - case SatParameters::NONE: - return; - case SatParameters::SIMPLE: { - MinimizeConflictSimple(conflict); - break; - } - case SatParameters::RECURSIVE: { - MinimizeConflictRecursively(conflict); - break; - } - case SatParameters::EXPERIMENTAL: { - MinimizeConflictExperimental(conflict); - break; - } + case SatParameters::NONE: + return; + case SatParameters::SIMPLE: { + MinimizeConflictSimple(conflict); + break; + } + case SatParameters::RECURSIVE: { + MinimizeConflictRecursively(conflict); + break; + } + case SatParameters::EXPERIMENTAL: { + MinimizeConflictExperimental(conflict); + break; + } } if (conflict->size() < old_size) { ++counters_.num_minimizations; @@ -2209,8 +2139,7 @@ void SatSolver::MinimizeConflictSimple(std::vector *conflict) { if (!reason.empty()) { can_be_removed = true; for (Literal literal : reason) { - if (DecisionLevel(literal.Variable()) == 0) - continue; + if (DecisionLevel(literal.Variable()) == 0) continue; if (!is_marked_[literal.Variable()]) { can_be_removed = false; break; @@ -2309,8 +2238,7 @@ bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) { DCHECK(is_marked_[variable]); const BooleanVariable v = same_reason_identifier_.FirstVariableWithSameReason(variable); - if (v != variable) - return !is_independent_[v]; + if (v != variable) return !is_independent_[v]; } // This function implement an iterative DFS from the given variable. It uses @@ -2331,8 +2259,7 @@ bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) { for (Literal literal : trail_->Reason(variable)) { const BooleanVariable var = literal.Variable(); DCHECK_NE(var, variable); - if (is_marked_[var]) - continue; + if (is_marked_[var]) continue; const int level = DecisionLevel(var); if (level == 0) { // Note that this is not needed if the solver is not configured to produce @@ -2379,8 +2306,7 @@ bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) { const BooleanVariable v = same_reason_identifier_.FirstVariableWithSameReason(current_var); if (v != current_var) { - if (is_independent_[v]) - break; + if (is_independent_[v]) break; DCHECK(is_marked_[v]); variable_to_process_.pop_back(); continue; @@ -2394,8 +2320,7 @@ bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) { const BooleanVariable var = literal.Variable(); DCHECK_NE(var, current_var); const int level = DecisionLevel(var); - if (level == 0 || is_marked_[var]) - continue; + if (level == 0 || is_marked_[var]) continue; if (trail_->Info(var).trail_index <= min_trail_index_per_level_[level] || is_independent_[var]) { abort_early = true; @@ -2403,8 +2328,7 @@ bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) { } variable_to_process_.push_back(var); } - if (abort_early) - break; + if (abort_early) break; } // All the variable left on the dfs_stack_ are independent. @@ -2432,7 +2356,7 @@ struct VariableWithLargerWeightFirst { (wv1.weight == wv2.weight && wv1.var < wv2.var)); } }; -} // namespace. +} // namespace. // This function allows a conflict variable to be replaced by another variable // not originally in the conflict. Greater reduction and backtracking can be @@ -2472,8 +2396,7 @@ void SatSolver::MinimizeConflictExperimental(std::vector *conflict) { // A nullptr reason means that this was a decision variable from the // previous levels. const absl::Span reason = trail_->Reason(var); - if (reason.empty()) - continue; + if (reason.empty()) continue; // Compute how many and which literals from the current reason do not appear // in the current conflict. Level 0 literals are ignored. @@ -2482,16 +2405,14 @@ void SatSolver::MinimizeConflictExperimental(std::vector *conflict) { const BooleanVariable reason_var = reason_literal.Variable(); // We ignore level 0 variables. - if (DecisionLevel(reason_var) == 0) - continue; + if (DecisionLevel(reason_var) == 0) continue; // We have a reason literal whose variable is not yet seen. // If there is more than one, break right away, we will not minimize the // current conflict with this variable. if (!is_marked_[reason_var]) { not_contained_literals.push_back(reason_literal); - if (not_contained_literals.size() > 1) - break; + if (not_contained_literals.size() > 1) break; } } if (not_contained_literals.empty()) { @@ -2527,8 +2448,7 @@ void SatSolver::MinimizeConflictExperimental(std::vector *conflict) { } void SatSolver::CleanClauseDatabaseIfNeeded() { - if (num_learned_clause_before_cleanup_ > 0) - return; + if (num_learned_clause_before_cleanup_ > 0) return; SCOPED_TIME_STAT(&stats_); // Creates a list of clauses that can be deleted. Note that only the clauses @@ -2537,8 +2457,7 @@ void SatSolver::CleanClauseDatabaseIfNeeded() { std::vector entries; auto &clauses_info = *(clauses_propagator_->mutable_clauses_info()); for (auto &entry : clauses_info) { - if (ClauseIsUsedAsReason(entry.first)) - continue; + if (ClauseIsUsedAsReason(entry.first)) continue; if (entry.second.protected_during_next_cleanup) { entry.second.protected_during_next_cleanup = false; continue; @@ -2548,23 +2467,23 @@ void SatSolver::CleanClauseDatabaseIfNeeded() { const int num_protected_clauses = clauses_info.size() - entries.size(); if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) { - // Order the clauses by decreasing LBD and then increasing activity. + // Order the clauses by decreasing LBD and then increasing activity. std::sort(entries.begin(), entries.end(), - [](const Entry & a, const Entry & b) { - if (a.second.lbd == b.second.lbd) { - return a.second.activity < b.second.activity; - } - return a.second.lbd > b.second.lbd; - }); + [](const Entry &a, const Entry &b) { + if (a.second.lbd == b.second.lbd) { + return a.second.activity < b.second.activity; + } + return a.second.lbd > b.second.lbd; + }); } else { - // Order the clauses by increasing activity and then decreasing LBD. + // Order the clauses by increasing activity and then decreasing LBD. std::sort(entries.begin(), entries.end(), - [](const Entry & a, const Entry & b) { - if (a.second.activity == b.second.activity) { - return a.second.lbd > b.second.lbd; - } - return a.second.activity < b.second.activity; - }); + [](const Entry &a, const Entry &b) { + if (a.second.activity == b.second.activity) { + return a.second.lbd > b.second.lbd; + } + return a.second.activity < b.second.activity; + }); } // The clause we want to keep are at the end of the vector. @@ -2578,8 +2497,7 @@ void SatSolver::CleanClauseDatabaseIfNeeded() { while (num_deleted_clauses > 0) { const ClauseInfo &a = entries[num_deleted_clauses].second; const ClauseInfo &b = entries[num_deleted_clauses - 1].second; - if (a.activity != b.activity || a.lbd != b.lbd) - break; + if (a.activity != b.activity || a.lbd != b.lbd) break; --num_deleted_clauses; ++num_kept_clauses; } @@ -2607,14 +2525,14 @@ void SatSolver::CleanClauseDatabaseIfNeeded() { std::string SatStatusString(SatSolver::Status status) { switch (status) { - case SatSolver::ASSUMPTIONS_UNSAT: - return "ASSUMPTIONS_UNSAT"; - case SatSolver::INFEASIBLE: - return "INFEASIBLE"; - case SatSolver::FEASIBLE: - return "FEASIBLE"; - case SatSolver::LIMIT_REACHED: - return "LIMIT_REACHED"; + case SatSolver::ASSUMPTIONS_UNSAT: + return "ASSUMPTIONS_UNSAT"; + case SatSolver::INFEASIBLE: + return "INFEASIBLE"; + case SatSolver::FEASIBLE: + return "FEASIBLE"; + case SatSolver::LIMIT_REACHED: + return "LIMIT_REACHED"; } // Fallback. We don't use "default:" so the compiler will return an error // if we forgot one enum case above. @@ -2653,5 +2571,5 @@ void MinimizeCore(SatSolver *solver, std::vector *core) { } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/sat_solver.h b/ortools/sat/sat_solver.h index 685a5f9f77..ad4955cb3f 100644 --- a/ortools/sat/sat_solver.h +++ b/ortools/sat/sat_solver.h @@ -317,11 +317,11 @@ class SatSolver { // - void AddClause(absl::Span clause); // // TODO(user): also copy the removable clauses? - template void ExtractClauses(Output *out) { + template + void ExtractClauses(Output *out) { CHECK(!IsModelUnsat()); Backtrack(0); - if (!FinishPropagation()) - return; + if (!FinishPropagation()) return; // It is important to process the newly fixed variables, so they are not // present in the clauses we export. @@ -486,8 +486,8 @@ class SatSolver { // constraint in question. This is used to bump the activity of the learned // clauses or pb constraints. SatClause *ReasonClauseOrNull(BooleanVariable var) const; - UpperBoundedLinearConstraint * - ReasonPbConstraintOrNull(BooleanVariable var) const; + UpperBoundedLinearConstraint *ReasonPbConstraintOrNull( + BooleanVariable var) const; // This does one step of a pseudo-Boolean resolution: // - The variable var has been assigned to l at a given trail_index. @@ -605,9 +605,9 @@ class SatSolver { // Precondidtion: is_marked_ should be set to true for all the variables of // the conflict. It can also contains false non-conflict variables that // are implied by the negation of the 1-UIP conflict literal. - void - MinimizeConflict(std::vector *conflict, - std::vector *reason_used_to_infer_the_conflict); + void MinimizeConflict( + std::vector *conflict, + std::vector *reason_used_to_infer_the_conflict); void MinimizeConflictExperimental(std::vector *conflict); void MinimizeConflictSimple(std::vector *conflict); void MinimizeConflictRecursively(std::vector *conflict); @@ -639,7 +639,8 @@ class SatSolver { // IMPORTANT: All the literals of the clause must be assigned, and the first // literal must be of the highest decision level. This will be the case for // all the reason clauses. - template int ComputeLbd(const LiteralList &literals); + template + int ComputeLbd(const LiteralList &literals); // Checks if we need to reduce the number of learned clauses and do // it if needed. Also updates the learned clause limit for the next cleanup. @@ -837,112 +838,109 @@ void MinimizeCore(SatSolver *solver, std::vector *core); // TODO(user): move them in another file, and unit-test them. // ============================================================================ -inline std::function -BooleanLinearConstraint(int64 lower_bound, int64 upper_bound, - std::vector *cst) { - return[ = ](Model * - model) { model->GetOrCreate()->AddLinearConstraint( - /*use_lower_bound=*/ true, Coefficient(lower_bound), - /*use_upper_bound=*/ true, Coefficient(upper_bound), cst); - } - ; +inline std::function BooleanLinearConstraint( + int64 lower_bound, int64 upper_bound, std::vector *cst) { + return [=](Model *model) { + model->GetOrCreate()->AddLinearConstraint( + /*use_lower_bound=*/true, Coefficient(lower_bound), + /*use_upper_bound=*/true, Coefficient(upper_bound), cst); + }; } -inline std::function -CardinalityConstraint(int64 lower_bound, int64 upper_bound, - const std::vector &literals) { - return[ = ](Model * model) { std::vector cst; +inline std::function CardinalityConstraint( + int64 lower_bound, int64 upper_bound, + const std::vector &literals) { + return [=](Model *model) { + std::vector cst; cst.reserve(literals.size()); for (int i = 0; i < literals.size(); ++i) { cst.emplace_back(literals[i], 1); } model->GetOrCreate()->AddLinearConstraint( - /*use_lower_bound=*/ true, Coefficient(lower_bound), - /*use_upper_bound=*/ true, Coefficient(upper_bound), &cst); - } - ; + /*use_lower_bound=*/true, Coefficient(lower_bound), + /*use_upper_bound=*/true, Coefficient(upper_bound), &cst); + }; } -inline std::function -ExactlyOneConstraint(const std::vector &literals) { - return[ = ](Model * model) { std::vector cst; +inline std::function ExactlyOneConstraint( + const std::vector &literals) { + return [=](Model *model) { + std::vector cst; cst.reserve(literals.size()); for (const Literal l : literals) { cst.emplace_back(l, Coefficient(1)); } - model->GetOrCreate() - ->AddLinearConstraint(/*use_lower_bound=*/ true, Coefficient(1), - /*use_upper_bound=*/ true, Coefficient(1), &cst); - } - ; + model->GetOrCreate()->AddLinearConstraint( + /*use_lower_bound=*/true, Coefficient(1), + /*use_upper_bound=*/true, Coefficient(1), &cst); + }; } -inline std::function -AtMostOneConstraint(const std::vector &literals) { - return[ = ](Model * model) { std::vector cst; +inline std::function AtMostOneConstraint( + const std::vector &literals) { + return [=](Model *model) { + std::vector cst; cst.reserve(literals.size()); for (const Literal l : literals) { cst.emplace_back(l, Coefficient(1)); } - model->GetOrCreate() - ->AddLinearConstraint(/*use_lower_bound=*/ false, Coefficient(0), - /*use_upper_bound=*/ true, Coefficient(1), &cst); - } - ; + model->GetOrCreate()->AddLinearConstraint( + /*use_lower_bound=*/false, Coefficient(0), + /*use_upper_bound=*/true, Coefficient(1), &cst); + }; } -inline std::function -ClauseConstraint(absl::Span literals) { - return[ = ](Model * model) { std::vector cst; +inline std::function ClauseConstraint( + absl::Span literals) { + return [=](Model *model) { + std::vector cst; cst.reserve(literals.size()); for (const Literal l : literals) { cst.emplace_back(l, Coefficient(1)); } - model->GetOrCreate() - ->AddLinearConstraint(/*use_lower_bound=*/ true, Coefficient(1), - /*use_upper_bound=*/ false, Coefficient(1), &cst); - } - ; + model->GetOrCreate()->AddLinearConstraint( + /*use_lower_bound=*/true, Coefficient(1), + /*use_upper_bound=*/false, Coefficient(1), &cst); + }; } // a => b. inline std::function Implication(Literal a, Literal b) { - return[ = ](Model * model) { + return [=](Model *model) { model->GetOrCreate()->AddBinaryClause(a.Negated(), b); - } - ; + }; } // a == b. inline std::function Equality(Literal a, Literal b) { - return[ = ](Model * model) { + return [=](Model *model) { model->GetOrCreate()->AddBinaryClause(a.Negated(), b); model->GetOrCreate()->AddBinaryClause(a, b.Negated()); - } - ; + }; } // r <=> (at least one literal is true). This is a reified clause. -inline std::function -ReifiedBoolOr(const std::vector &literals, Literal r) { - return[ = ](Model * model) { std::vector clause; +inline std::function ReifiedBoolOr( + const std::vector &literals, Literal r) { + return [=](Model *model) { + std::vector clause; for (const Literal l : literals) { - model->Add(Implication(l, r)); // l => r. + model->Add(Implication(l, r)); // l => r. clause.push_back(l); } // All false => r false. clause.push_back(r.Negated()); model->Add(ClauseConstraint(clause)); - } - ; + }; } // enforcement_literals => clause. -inline std::function -EnforcedClause(absl::Span enforcement_literals, - absl::Span clause) { - return[ = ](Model * model) { std::vector tmp; +inline std::function EnforcedClause( + absl::Span enforcement_literals, + absl::Span clause) { + return [=](Model *model) { + std::vector tmp; for (const Literal l : enforcement_literals) { tmp.push_back(l.Negated()); } @@ -950,56 +948,53 @@ EnforcedClause(absl::Span enforcement_literals, tmp.push_back(l); } model->Add(ClauseConstraint(tmp)); - } - ; + }; } // r <=> (all literals are true). // // Note(user): we could have called ReifiedBoolOr() with everything negated. -inline std::function -ReifiedBoolAnd(const std::vector &literals, Literal r) { - return[ = ](Model * model) { std::vector clause; +inline std::function ReifiedBoolAnd( + const std::vector &literals, Literal r) { + return [=](Model *model) { + std::vector clause; for (const Literal l : literals) { - model->Add(Implication(r, l)); // r => l. + model->Add(Implication(r, l)); // r => l. clause.push_back(l.Negated()); } // All true => r true. clause.push_back(r); model->Add(ClauseConstraint(clause)); - } - ; + }; } // r <=> (a <= b). inline std::function ReifiedBoolLe(Literal a, Literal b, Literal r) { - return [=](Model* model) { + return [=](Model *model) { // r <=> (a <= b) is the same as r <=> not(a=1 and b=0). // So r <=> a=0 OR b=1. - model->Add(ReifiedBoolOr( - { a.Negated(), b }, r)); - } - ; + model->Add(ReifiedBoolOr({a.Negated(), b}, r)); + }; } // This checks that the variable is fixed. inline std::function Value(Literal l) { - return[ = ](const Model &model) { const Trail *trail = model.Get(); + return [=](const Model &model) { + const Trail *trail = model.Get(); CHECK(trail->Assignment().VariableIsAssigned(l.Variable())); return trail->Assignment().LiteralIsTrue(l); - } - ; + }; } // This checks that the variable is fixed. inline std::function Value(BooleanVariable b) { - return[ = ](const Model &model) { const Trail *trail = model.Get(); + return [=](const Model &model) { + const Trail *trail = model.Get(); CHECK(trail->Assignment().VariableIsAssigned(b)); return trail->Assignment().LiteralIsTrue(Literal(b, true)); - } - ; + }; } // This can be used to enumerate all the solutions. After each SAT call to @@ -1007,8 +1002,8 @@ inline std::function Value(BooleanVariable b) { // so that the next call to Solve() will give a new solution or UNSAT is there // is no more new solutions. inline std::function ExcludeCurrentSolutionAndBacktrack() { - return[ = ](Model *model) { SatSolver *sat_solver = - model->GetOrCreate(); + return [=](Model *model) { + SatSolver *sat_solver = model->GetOrCreate(); // Note that we only exclude the current decisions, which is an efficient // way to not get the same SAT assignment. @@ -1016,13 +1011,12 @@ inline std::function ExcludeCurrentSolutionAndBacktrack() { std::vector clause_to_exclude_solution; clause_to_exclude_solution.reserve(current_level); for (int i = 0; i < current_level; ++i) { - clause_to_exclude_solution.push_back(sat_solver->Decisions()[i] - .literal.Negated()); + clause_to_exclude_solution.push_back( + sat_solver->Decisions()[i].literal.Negated()); } sat_solver->Backtrack(0); model->Add(ClauseConstraint(clause_to_exclude_solution)); - } - ; + }; } // Returns a string representation of a SatSolver::Status. @@ -1032,7 +1026,7 @@ inline std::ostream &operator<<(std::ostream &os, SatSolver::Status status) { return os; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SAT_SOLVER_H_ +#endif // OR_TOOLS_SAT_SAT_SOLVER_H_ diff --git a/ortools/sat/scheduling_constraints.cc b/ortools/sat/scheduling_constraints.cc index 7cf5b8a380..102f26f2d9 100644 --- a/ortools/sat/scheduling_constraints.cc +++ b/ortools/sat/scheduling_constraints.cc @@ -26,8 +26,11 @@ class SelectedMinPropagator : public PropagatorInterface { const std::vector &vars, const std::vector &selectors, Model *model) - : enforcement_literal_(enforcement_literal), target_(target), vars_(vars), - selectors_(selectors), trail_(model->GetOrCreate()), + : enforcement_literal_(enforcement_literal), + target_(target), + vars_(vars), + selectors_(selectors), + trail_(model->GetOrCreate()), integer_trail_(model->GetOrCreate()), precedences_(model->GetOrCreate()), true_literal_(model->GetOrCreate()->GetTrueLiteral()) {} @@ -57,21 +60,18 @@ bool SelectedMinPropagator::Propagate() { const auto add_var_non_selection_to_reason = [&](int i) { DCHECK(assignment.LiteralIsFalse(selectors_[i])); literal_reason_.push_back(selectors_[i]); - } - ; + }; const auto add_var_selection_to_reason = [&](int i) { DCHECK(assignment.LiteralIsTrue(selectors_[i])); literal_reason_.push_back(selectors_[i].Negated()); - } - ; + }; // Push the given integer literal if lit is true. Note that if lit is still // not assigned, we may still be able to deduce something. // TODO(user,user): Move this to integer_trail, and remove from here and // from scheduling helper. const auto push_bound = [&](Literal enforcement_lit, IntegerLiteral i_lit) { - if (assignment.LiteralIsFalse(enforcement_lit)) - return true; + if (assignment.LiteralIsFalse(enforcement_lit)) return true; if (integer_trail_->OptionalLiteralIndex(i_lit.var) != enforcement_lit.Index()) { if (assignment.LiteralIsTrue(enforcement_lit)) { @@ -96,8 +96,7 @@ bool SelectedMinPropagator::Propagate() { } return true; - } - ; + }; // Propagation. const int num_vars = vars_.size(); @@ -114,8 +113,7 @@ bool SelectedMinPropagator::Propagate() { int min_of_selected_maxes_index = -1; int first_selected = -1; for (int i = 0; i < num_vars; ++i) { - if (assignment.LiteralIsFalse(selectors_[i])) - continue; + if (assignment.LiteralIsFalse(selectors_[i])) continue; const IntegerVariable var = vars_[i]; const IntegerValue var_min = integer_trail_->LowerBound(var); @@ -196,8 +194,7 @@ bool SelectedMinPropagator::Propagate() { } // All propagations and checks belows rely of the presence of the target. - if (!assignment.LiteralIsTrue(enforcement_literal_)) - return true; + if (!assignment.LiteralIsTrue(enforcement_literal_)) return true; DCHECK_GE(integer_trail_->LowerBound(target_), min_of_mins); @@ -208,8 +205,7 @@ bool SelectedMinPropagator::Propagate() { DCHECK_GT(num_possible_vars + num_selected_vars, 1); return true; } - if (num_selected_vars != 1) - return true; + if (num_selected_vars != 1) return true; DCHECK_NE(first_selected, -1); DCHECK(assignment.LiteralIsTrue(selectors_[first_selected])); @@ -270,17 +266,16 @@ int SelectedMinPropagator::RegisterWith(GenericLiteralWatcher *watcher) { return id; } -std::function -EqualMinOfSelectedVariables(Literal enforcement_literal, IntegerVariable target, - const std::vector &vars, - const std::vector &selectors) { +std::function EqualMinOfSelectedVariables( + Literal enforcement_literal, IntegerVariable target, + const std::vector &vars, + const std::vector &selectors) { CHECK_EQ(vars.size(), selectors.size()); - return [=](Model* model) { + return [=](Model *model) { // If both a variable is selected and the enforcement literal is true, then // the var is always greater than the target. - for (int i = 0; - i < vars.size(); ++i) { - std::vector conditions = { enforcement_literal }; + for (int i = 0; i < vars.size(); ++i) { + std::vector conditions = {enforcement_literal}; conditions.push_back(selectors[i]); model->Add(ConditionalLowerOrEqual(target, vars[i], conditions)); } @@ -290,35 +285,30 @@ EqualMinOfSelectedVariables(Literal enforcement_literal, IntegerVariable target, enforcement_literal, target, vars, selectors, model); constraint->RegisterWith(model->GetOrCreate()); model->TakeOwnership(constraint); - } - ; + }; } -std::function -EqualMaxOfSelectedVariables(Literal enforcement_literal, IntegerVariable target, - const std::vector &vars, - const std::vector &selectors) { +std::function EqualMaxOfSelectedVariables( + Literal enforcement_literal, IntegerVariable target, + const std::vector &vars, + const std::vector &selectors) { CHECK_EQ(vars.size(), selectors.size()); - return[ = ](Model * model) { std::vector negations; + return [=](Model *model) { + std::vector negations; for (const IntegerVariable var : vars) { negations.push_back(NegationOf(var)); } model->Add(EqualMinOfSelectedVariables( enforcement_literal, NegationOf(target), negations, selectors)); - } - ; + }; } -std::function -SpanOfIntervals(IntervalVariable span, - const std::vector &intervals) { - return[ = ](Model *model) { SatSolver *sat_solver = - model->GetOrCreate(); +std::function SpanOfIntervals( + IntervalVariable span, const std::vector &intervals) { + return [=](Model *model) { + SatSolver *sat_solver = model->GetOrCreate(); SchedulingConstraintHelper task_helper(intervals, model); - SchedulingConstraintHelper target_helper({ - span - }, - model); + SchedulingConstraintHelper target_helper({span}, model); // If the target is absent, then all tasks are absent. if (target_helper.IsAbsent(0)) { @@ -346,8 +336,7 @@ SpanOfIntervals(IntervalVariable span, model->GetOrCreate()->GetTrueLiteral(); for (int t = 0; t < task_helper.NumTasks(); ++t) { - if (task_helper.IsAbsent(t)) - continue; + if (task_helper.IsAbsent(t)) continue; if (task_helper.IsOptional(t)) { const Literal task_lit = task_helper.PresenceLiteral(t); @@ -381,15 +370,14 @@ SpanOfIntervals(IntervalVariable span, target_helper.IsOptional(0) ? target_helper.PresenceLiteral(0) : model->GetOrCreate()->GetTrueLiteral(); - model->Add(EqualMinOfSelectedVariables( - enforcement_literal, target_helper.StartVars().front(), starts, - presence_literals)); - model->Add(EqualMaxOfSelectedVariables( - enforcement_literal, target_helper.EndVars().front(), ends, - presence_literals)); - } - ; + model->Add(EqualMinOfSelectedVariables(enforcement_literal, + target_helper.StartVars().front(), + starts, presence_literals)); + model->Add(EqualMaxOfSelectedVariables(enforcement_literal, + target_helper.EndVars().front(), + ends, presence_literals)); + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/scheduling_constraints.h b/ortools/sat/scheduling_constraints.h index 6a8dfef16e..e29a4ed989 100644 --- a/ortools/sat/scheduling_constraints.h +++ b/ortools/sat/scheduling_constraints.h @@ -35,22 +35,20 @@ namespace sat { // true. // // This constraint expects that enforcement_literal <==> bool_or(selectors). -std::function - EqualMinOfSelectedVariables(Literal enforcement_literal, - IntegerVariable target, - const std::vector &vars, - const std::vector &selectors); +std::function EqualMinOfSelectedVariables( + Literal enforcement_literal, IntegerVariable target, + const std::vector &vars, + const std::vector &selectors); // This propagator enforces that the target variable is equal to the max of the // selected variables. This equation only holds if the enforcement literal is // true. // // This constraint expects that enforcement_literal <==> bool_or(selectors).u -std::function - EqualMaxOfSelectedVariables(Literal enforcement_literal, - IntegerVariable target, - const std::vector &vars, - const std::vector &selectors); +std::function EqualMaxOfSelectedVariables( + Literal enforcement_literal, IntegerVariable target, + const std::vector &vars, + const std::vector &selectors); // This constraint enforces that the target interval is an exact cover of the // underlying intervals. @@ -63,10 +61,9 @@ std::function // is present. // - if the target interval is absent, all intervals are absent. // - If one interval is present, the target interval is present too. -std::function - SpanOfIntervals(IntervalVariable span, - const std::vector &intervals); -} // namespace sat -} // namespace operations_research +std::function SpanOfIntervals( + IntervalVariable span, const std::vector &intervals); +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SCHEDULING_CONSTRAINTS_H_ +#endif // OR_TOOLS_SAT_SCHEDULING_CONSTRAINTS_H_ diff --git a/ortools/sat/simplification.cc b/ortools/sat/simplification.cc index 98b0331345..a05f0e8087 100644 --- a/ortools/sat/simplification.cc +++ b/ortools/sat/simplification.cc @@ -125,8 +125,8 @@ void SatPostsolver::Postsolve(VariablesAssignment *assignment) const { assignment->Resize(initial_num_variables_); } -std::vector -SatPostsolver::ExtractAndPostsolveSolution(const SatSolver &solver) { +std::vector SatPostsolver::ExtractAndPostsolveSolution( + const SatSolver &solver) { std::vector solution(solver.NumVariables()); for (BooleanVariable var(0); var < solver.NumVariables(); ++var) { DCHECK(solver.Assignment().VariableIsAssigned(var)); @@ -136,8 +136,8 @@ SatPostsolver::ExtractAndPostsolveSolution(const SatSolver &solver) { return PostsolveSolution(solution); } -std::vector -SatPostsolver::PostsolveSolution(const std::vector &solution) { +std::vector SatPostsolver::PostsolveSolution( + const std::vector &solution) { for (BooleanVariable var(0); var < solution.size(); ++var) { DCHECK_LT(var, reverse_mapping_.size()); DCHECK_NE(reverse_mapping_[var], kNoBooleanVariable); @@ -155,11 +155,7 @@ SatPostsolver::PostsolveSolution(const std::vector &solution) { return postsolved_solution; } -void SatPresolver::AddBinaryClause(Literal a, Literal b) { - AddClause({ - a, b - }); -} +void SatPresolver::AddBinaryClause(Literal a, Literal b) { AddClause({a, b}); } void SatPresolver::AddClause(absl::Span clause) { DCHECK_GT(clause.size(), 0) << "Added an empty clause to the presolver"; @@ -174,8 +170,7 @@ void SatPresolver::AddClause(absl::Span clause) { for (int i = 0; i < clause_ref.size(); ++i) { const Literal old_literal = clause_ref[i]; clause_ref[i] = Literal(equiv_mapping_[clause_ref[i].Index()]); - if (old_literal != clause_ref[i]) - changed = true; + if (old_literal != clause_ref[i]) changed = true; } } std::sort(clause_ref.begin(), clause_ref.end()); @@ -205,7 +200,8 @@ void SatPresolver::AddClause(absl::Span clause) { const Literal max_literal = clause_ref.back(); const int required_size = std::max(max_literal.Index().value(), - max_literal.NegatedIndex().value()) + 1; + max_literal.NegatedIndex().value()) + + 1; if (required_size > literal_to_clauses_.size()) { literal_to_clauses_.resize(required_size); literal_to_clause_sizes_.resize(required_size); @@ -225,8 +221,7 @@ void SatPresolver::SetNumVariables(int num_variables) { } void SatPresolver::AddClauseInternal(std::vector *clause) { - if (drat_proof_handler_ != nullptr) - drat_proof_handler_->AddClause(*clause); + if (drat_proof_handler_ != nullptr) drat_proof_handler_->AddClause(*clause); DCHECK(std::is_sorted(clause->begin(), clause->end())); DCHECK_GT(clause->size(), 0) << "TODO(fdid): Unsat during presolve?"; @@ -246,8 +241,8 @@ void SatPresolver::AddClauseInternal(std::vector *clause) { DCHECK_EQ(signatures_.size(), clauses_.size()); } -gtl::ITIVector -SatPresolver::VariableMapping() const { +gtl::ITIVector SatPresolver::VariableMapping() + const { gtl::ITIVector result; BooleanVariable new_var(0); for (BooleanVariable var(0); var < NumVariables(); ++var) { @@ -276,8 +271,7 @@ void SatPresolver::LoadProblemIntoSatSolver(SatSolver *solver) { VariableMapping(); int new_size = 0; for (BooleanVariable index : mapping) { - if (index != kNoBooleanVariable) - ++new_size; + if (index != kNoBooleanVariable) ++new_size; } std::vector temp; @@ -288,8 +282,7 @@ void SatPresolver::LoadProblemIntoSatSolver(SatSolver *solver) { DCHECK_NE(mapping[l.Variable()], kNoBooleanVariable); temp.push_back(Literal(mapping[l.Variable()], l.IsPositive())); } - if (!temp.empty()) - solver->AddProblemClause(temp); + if (!temp.empty()) solver->AddProblemClause(temp); gtl::STLClearObject(&clause_ref); } } @@ -298,26 +291,24 @@ bool SatPresolver::ProcessAllClauses() { int num_skipped_checks = 0; const int kCheckFrequency = 1000; - // Because on large problem we don't have a budget to process all clauses, - // lets start by the smallest ones first. + // Because on large problem we don't have a budget to process all clauses, + // lets start by the smallest ones first. std::sort(clause_to_process_.begin(), clause_to_process_.end(), [this](ClauseIndex c1, ClauseIndex c2) { - return clauses_[c1].size() < clauses_[c2].size(); - }); + return clauses_[c1].size() < clauses_[c2].size(); + }); while (!clause_to_process_.empty()) { const ClauseIndex ci = clause_to_process_.front(); in_clause_to_process_[ci] = false; clause_to_process_.pop_front(); - if (!ProcessClauseToSimplifyOthers(ci)) - return false; + if (!ProcessClauseToSimplifyOthers(ci)) return false; if (++num_skipped_checks >= kCheckFrequency) { if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) { VLOG(1) << "Aborting ProcessAllClauses() because work limit has been " "reached"; return true; } - if (time_limit_ != nullptr && time_limit_->LimitReached()) - return true; + if (time_limit_ != nullptr && time_limit_->LimitReached()) return true; num_skipped_checks = 0; } } @@ -340,8 +331,7 @@ bool SatPresolver::Presolve(const std::vector &can_be_removed, if (log_info) { int64 num_removable = 0; for (const bool b : can_be_removed) { - if (b) - ++num_removable; + if (b) ++num_removable; } LOG(INFO) << "num removable Booleans: " << num_removable << " / " << can_be_removed.size(); @@ -351,46 +341,36 @@ bool SatPresolver::Presolve(const std::vector &can_be_removed, // TODO(user): When a clause is strengthened, add it to a queue so it can // be processed again? - if (!ProcessAllClauses()) - return false; - if (log_info) - DisplayStats(timer.Get()); + if (!ProcessAllClauses()) return false; + if (log_info) DisplayStats(timer.Get()); - if (time_limit_ != nullptr && time_limit_->LimitReached()) - return true; - if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) - return true; + if (time_limit_ != nullptr && time_limit_->LimitReached()) return true; + if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) return true; InitializePriorityQueue(); while (var_pq_.Size() > 0) { const BooleanVariable var = var_pq_.Top()->variable; var_pq_.Pop(); - if (!can_be_removed[var.value()]) - continue; + if (!can_be_removed[var.value()]) continue; if (CrossProduct(Literal(var, true))) { - if (!ProcessAllClauses()) - return false; + if (!ProcessAllClauses()) return false; } - if (time_limit_ != nullptr && time_limit_->LimitReached()) - return true; - if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) - return true; + if (time_limit_ != nullptr && time_limit_->LimitReached()) return true; + if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) return true; } - if (log_info) - DisplayStats(timer.Get()); + if (log_info) DisplayStats(timer.Get()); // We apply BVA after a pass of the other algorithms. if (parameters_.presolve_use_bva()) { PresolveWithBva(); - if (log_info) - DisplayStats(timer.Get()); + if (log_info) DisplayStats(timer.Get()); } return true; } void SatPresolver::PresolveWithBva() { - var_pq_elements_.clear(); // so we don't update it. + var_pq_elements_.clear(); // so we don't update it. InitializeBvaPriorityQueue(); while (bva_pq_.Size() > 0) { const LiteralIndex lit = bva_pq_.Top()->literal; @@ -403,13 +383,11 @@ void SatPresolver::PresolveWithBva() { void SatPresolver::SimpleBva(LiteralIndex l) { literal_to_p_size_.resize(literal_to_clauses_.size(), 0); DCHECK(std::all_of(literal_to_p_size_.begin(), literal_to_p_size_.end(), - [](int v) { - return v == 0; - })); + [](int v) { return v == 0; })); // We will try to add a literal to m_lit_ and take a subset of m_cls_ such // that |m_lit_| * |m_cls_| - |m_lit_| - |m_cls_| is maximized. - m_lit_ = { l }; + m_lit_ = {l}; m_cls_ = literal_to_clauses_[l]; int reduction = 0; @@ -420,25 +398,21 @@ void SatPresolver::SimpleBva(LiteralIndex l) { flattened_p_.clear(); for (const ClauseIndex c : m_cls_) { const std::vector &clause = clauses_[c]; - if (clause.empty()) - continue; // It has been deleted. + if (clause.empty()) continue; // It has been deleted. // Find a literal different from l that occur in the less number of // clauses. const LiteralIndex l_min = FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l)); - if (l_min == kNoLiteralIndex) - continue; + if (l_min == kNoLiteralIndex) continue; // Find all the clauses of the form "clause \ {l} + {l'}", for a literal // l' that is not in the clause. for (const ClauseIndex d : literal_to_clauses_[l_min]) { - if (clause.size() != clauses_[d].size()) - continue; + if (clause.size() != clauses_[d].size()) continue; const LiteralIndex l_diff = DifferAtGivenLiteral(clause, clauses_[d], Literal(l)); - if (l_diff == kNoLiteralIndex || m_lit_.count(l_diff) > 0) - continue; + if (l_diff == kNoLiteralIndex || m_lit_.count(l_diff) > 0) continue; if (l_diff == Literal(l).NegatedIndex()) { // Self-subsumbtion! // @@ -447,9 +421,7 @@ void SatPresolver::SimpleBva(LiteralIndex l) { VLOG(1) << "self-subsumbtion"; } - flattened_p_.push_back({ - l_diff, c - }); + flattened_p_.push_back({l_diff, c}); const int new_size = ++literal_to_p_size_[l_diff]; if (new_size > max_size) { lmax = l_diff; @@ -458,15 +430,13 @@ void SatPresolver::SimpleBva(LiteralIndex l) { } } - if (lmax == kNoLiteralIndex) - break; + if (lmax == kNoLiteralIndex) break; const int new_m_lit_size = m_lit_.size() + 1; const int new_m_cls_size = max_size; const int new_reduction = new_m_lit_size * new_m_cls_size - new_m_cls_size - new_m_lit_size; - if (new_reduction <= reduction) - break; + if (new_reduction <= reduction) break; DCHECK_NE(1, new_m_lit_size); DCHECK_NE(1, new_m_cls_size); @@ -481,22 +451,19 @@ void SatPresolver::SimpleBva(LiteralIndex l) { m_cls_.clear(); for (const auto entry : flattened_p_) { literal_to_p_size_[entry.first] = 0; - if (entry.first == lmax) - m_cls_.push_back(entry.second); + if (entry.first == lmax) m_cls_.push_back(entry.second); } flattened_p_.clear(); } // Make sure literal_to_p_size_ is all zero. - for (const auto entry : flattened_p_) - literal_to_p_size_[entry.first] = 0; + for (const auto entry : flattened_p_) literal_to_p_size_[entry.first] = 0; flattened_p_.clear(); // A strictly positive reduction means that applying the BVA transform will // reduce the overall number of clauses by that much. Here we can control // what kind of reduction we want to apply. - if (reduction <= parameters_.presolve_bva_threshold()) - return; + if (reduction <= parameters_.presolve_bva_threshold()) return; DCHECK_GT(m_lit_.size(), 1); // Create a new variable. @@ -510,10 +477,9 @@ void SatPresolver::SimpleBva(LiteralIndex l) { bva_pq_elements_[x_false.value()].literal = x_false; // Add the new clauses. - if (drat_proof_handler_ != nullptr) - drat_proof_handler_->AddOneVariable(); + if (drat_proof_handler_ != nullptr) drat_proof_handler_->AddOneVariable(); for (const LiteralIndex lit : m_lit_) { - tmp_new_clause_ = { Literal(lit), Literal(x_true) }; + tmp_new_clause_ = {Literal(lit), Literal(x_true)}; AddClauseInternal(&tmp_new_clause_); } for (const ClauseIndex ci : m_cls_) { @@ -545,11 +511,9 @@ void SatPresolver::SimpleBva(LiteralIndex l) { const LiteralIndex l_min = FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l)); for (const LiteralIndex lit : m_lit_) { - if (lit == l) - continue; + if (lit == l) continue; for (const ClauseIndex d : literal_to_clauses_[l_min]) { - if (clause.size() != clauses_[d].size()) - continue; + if (clause.size() != clauses_[d].size()) continue; const LiteralIndex l_diff = DifferAtGivenLiteral(clause, clauses_[d], Literal(l)); if (l_diff == lit) { @@ -574,9 +538,7 @@ void SatPresolver::SimpleBva(LiteralIndex l) { uint64 SatPresolver::ComputeSignatureOfClauseVariables(ClauseIndex ci) { uint64 signature = 0; for (const Literal l : clauses_[ci]) { - signature |= (uint64 { - 1 - } << (l.Variable().value() % 64)); + signature |= (uint64{1} << (l.Variable().value() % 64)); } DCHECK_EQ(signature == 0, clauses_[ci].empty()); return signature; @@ -619,8 +581,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthersUsingLiteral( continue; } else { DCHECK_NE(opposite_literal, lit.Index()); - if (clauses_[ci].empty()) - return false; // UNSAT. + if (clauses_[ci].empty()) return false; // UNSAT. if (drat_proof_handler_ != nullptr) { // TODO(user): remove the old clauses_[ci] afterwards. drat_proof_handler_->AddClause(clauses_[ci]); @@ -648,8 +609,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthersUsingLiteral( int new_index = 0; auto &occurrence_list_ref = literal_to_clauses_[lit.Index()]; for (const ClauseIndex ci : occurrence_list_ref) { - if (signatures_[ci] != 0) - occurrence_list_ref[new_index++] = ci; + if (signatures_[ci] != 0) occurrence_list_ref[new_index++] = ci; } occurrence_list_ref.resize(new_index); DCHECK_EQ(literal_to_clause_sizes_[lit.Index()], new_index); @@ -663,8 +623,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthersUsingLiteral( // of two sorted lists to get the simplified clauses. bool SatPresolver::ProcessClauseToSimplifyOthers(ClauseIndex clause_index) { const std::vector &clause = clauses_[clause_index]; - if (clause.empty()) - return true; + if (clause.empty()) return true; DCHECK(std::is_sorted(clause.begin(), clause.end())); LiteralIndex opposite_literal; @@ -692,8 +651,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthers(ClauseIndex clause_index) { for (const ClauseIndex ci : occurrence_list_ref) { const uint64 ci_signature = signatures_[ci]; DCHECK_EQ(ci_signature, ComputeSignatureOfClauseVariables(ci)); - if (ci_signature == 0) - continue; + if (ci_signature == 0) continue; // TODO(user): not super optimal since we could abort earlier if // opposite_literal is not the negation of shortest_list. Note that this @@ -703,8 +661,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthers(ClauseIndex clause_index) { SimplifyClause(clause, &clauses_[ci], &opposite_literal, &num_inspected_literals_)) { DCHECK_EQ(opposite_literal, lit.NegatedIndex()); - if (clauses_[ci].empty()) - return false; // UNSAT. + if (clauses_[ci].empty()) return false; // UNSAT. if (drat_proof_handler_ != nullptr) { // TODO(user): remove the old clauses_[ci] afterwards. drat_proof_handler_->AddClause(clauses_[ci]); @@ -734,8 +691,7 @@ bool SatPresolver::ProcessClauseToSimplifyOthers(ClauseIndex clause_index) { void SatPresolver::RemoveAndRegisterForPostsolveAllClauseContaining(Literal x) { for (ClauseIndex i : literal_to_clauses_[x.Index()]) { - if (!clauses_[i].empty()) - RemoveAndRegisterForPostsolve(i, x); + if (!clauses_[i].empty()) RemoveAndRegisterForPostsolve(i, x); } gtl::STLClearObject(&literal_to_clauses_[x.Index()]); literal_to_clause_sizes_[x.Index()] = 0; @@ -747,8 +703,7 @@ bool SatPresolver::CrossProduct(Literal x) { // Note that if s1 or s2 is equal to 0, this function will implicitely just // fix the variable x. - if (s1 == 0 && s2 == 0) - return false; + if (s1 == 0 && s2 == 0) return false; // Heuristic. Abort if the work required to decide if x should be removed // seems to big. @@ -771,26 +726,22 @@ bool SatPresolver::CrossProduct(Literal x) { } // For the BCE, we prefer s2 to be small. - if (s1 < s2) - x = x.Negated(); + if (s1 < s2) x = x.Negated(); // Test whether we should remove the x.Variable(). int size = 0; for (ClauseIndex i : literal_to_clauses_[x.Index()]) { - if (clauses_[i].empty()) - continue; + if (clauses_[i].empty()) continue; bool no_resolvant = true; for (ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) { - if (clauses_[j].empty()) - continue; + if (clauses_[j].empty()) continue; const int rs = ComputeResolvantSize(x, clauses_[i], clauses_[j]); if (rs >= 0) { no_resolvant = false; size += clause_weight + rs; // Abort early if the "size" become too big. - if (size > threshold) - return false; + if (size > threshold) return false; } } if (no_resolvant && parameters_.presolve_blocked_clause()) { @@ -815,11 +766,9 @@ bool SatPresolver::CrossProduct(Literal x) { // deletion. std::vector temp; for (ClauseIndex i : literal_to_clauses_[x.Index()]) { - if (clauses_[i].empty()) - continue; + if (clauses_[i].empty()) continue; for (ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) { - if (clauses_[j].empty()) - continue; + if (clauses_[j].empty()) continue; if (ComputeResolvant(x, clauses_[i], clauses_[j], &temp)) { AddClauseInternal(&temp); } @@ -878,8 +827,7 @@ LiteralIndex SatPresolver::FindLiteralWithShortestOccurrenceListExcluding( LiteralIndex result = kNoLiteralIndex; int num_occurrences = std::numeric_limits::max(); for (const Literal l : clause) { - if (l == to_exclude) - continue; + if (l == to_exclude) continue; if (literal_to_clause_sizes_[l.Index()] < num_occurrences) { result = l.Index(); num_occurrences = literal_to_clause_sizes_[l.Index()]; @@ -889,8 +837,7 @@ LiteralIndex SatPresolver::FindLiteralWithShortestOccurrenceListExcluding( } void SatPresolver::UpdatePriorityQueue(BooleanVariable var) { - if (var_pq_elements_.empty()) - return; // not initialized. + if (var_pq_elements_.empty()) return; // not initialized. PQElement *element = &var_pq_elements_[var]; element->weight = literal_to_clause_sizes_[Literal(var, true).Index()] + literal_to_clause_sizes_[Literal(var, false).Index()]; @@ -914,8 +861,7 @@ void SatPresolver::InitializePriorityQueue() { } void SatPresolver::UpdateBvaPriorityQueue(LiteralIndex lit) { - if (bva_pq_elements_.empty()) - return; // not initialized. + if (bva_pq_elements_.empty()) return; // not initialized. DCHECK_LT(lit, bva_pq_elements_.size()); BvaPqElement *element = &bva_pq_elements_[lit.value()]; element->weight = literal_to_clause_sizes_[lit]; @@ -925,14 +871,12 @@ void SatPresolver::UpdateBvaPriorityQueue(LiteralIndex lit) { } void SatPresolver::AddToBvaPriorityQueue(LiteralIndex lit) { - if (bva_pq_elements_.empty()) - return; // not initialized. + if (bva_pq_elements_.empty()) return; // not initialized. DCHECK_LT(lit, bva_pq_elements_.size()); BvaPqElement *element = &bva_pq_elements_[lit.value()]; element->weight = literal_to_clause_sizes_[lit]; DCHECK(!bva_pq_.Contains(element)); - if (element->weight > 2) - bva_pq_.Add(element); + if (element->weight > 2) bva_pq_.Add(element); } void SatPresolver::InitializeBvaPriorityQueue() { @@ -946,8 +890,7 @@ void SatPresolver::InitializeBvaPriorityQueue() { // If a literal occur only in two clauses, then there is no point calling // SimpleBva() on it. - if (element->weight > 2) - bva_pq_.Add(element); + if (element->weight > 2) bva_pq_.Add(element); } } @@ -957,8 +900,7 @@ void SatPresolver::DisplayStats(double elapsed_seconds) { int num_singleton_clauses = 0; for (const std::vector &c : clauses_) { if (!c.empty()) { - if (c.size() == 1) - ++num_singleton_clauses; + if (c.size() == 1) ++num_singleton_clauses; ++num_clauses; num_literals += c.size(); } @@ -969,8 +911,7 @@ void SatPresolver::DisplayStats(double elapsed_seconds) { for (BooleanVariable var(0); var < NumVariables(); ++var) { const int s1 = literal_to_clause_sizes_[Literal(var, true).Index()]; const int s2 = literal_to_clause_sizes_[Literal(var, false).Index()]; - if (s1 == 0 && s2 == 0) - continue; + if (s1 == 0 && s2 == 0) continue; ++num_vars; if (s1 == 0 || s2 == 0) { @@ -989,8 +930,7 @@ void SatPresolver::DisplayStats(double elapsed_seconds) { bool SimplifyClause(const std::vector &a, std::vector *b, LiteralIndex *opposite_literal, int64 *num_inspected_literals) { - if (b->size() < a.size()) - return false; + if (b->size() < a.size()) return false; DCHECK(std::is_sorted(a.begin(), a.end())); DCHECK(std::is_sorted(b->begin(), b->end())); if (num_inspected_literals != nullptr) { @@ -1009,25 +949,23 @@ bool SimplifyClause(const std::vector &a, std::vector *b, // in the while loop is not needed. int size_diff = b->size() - a.size(); while (ia != a.end() /* && ib != b->end() */) { - if (*ia == *ib) { // Same literal. + if (*ia == *ib) { // Same literal. ++ia; ++ib; - } else if (*ia == ib->Negated()) { // Opposite literal. + } else if (*ia == ib->Negated()) { // Opposite literal. ++num_diff; - if (num_diff > 1) - return false; // Too much difference. + if (num_diff > 1) return false; // Too much difference. to_remove = ib; ++ia; ++ib; } else if (*ia < *ib) { - return false; // A literal of a is not in b. - } else { // *ia > *ib + return false; // A literal of a is not in b. + } else { // *ia > *ib ++ib; // A literal of b is not in a, we can abort early by comparing the sizes // left. - if (--size_diff < 0) - return false; + if (--size_diff < 0) return false; } } if (num_diff == 1) { @@ -1046,30 +984,26 @@ LiteralIndex DifferAtGivenLiteral(const std::vector &a, std::vector::const_iterator ia = a.begin(); std::vector::const_iterator ib = b.begin(); while (ia != a.end() && ib != b.end()) { - if (*ia == *ib) { // Same literal. + if (*ia == *ib) { // Same literal. ++ia; ++ib; } else if (*ia < *ib) { // A literal of a is not in b, it must be l. // Note that this can only happen once. - if (*ia != l) - return kNoLiteralIndex; + if (*ia != l) return kNoLiteralIndex; ++ia; } else { // A literal of b is not in a, save it. // We abort if this happen twice. - if (result != kNoLiteralIndex) - return kNoLiteralIndex; + if (result != kNoLiteralIndex) return kNoLiteralIndex; result = (*ib).Index(); ++ib; } } // Check the corner case of the difference at the end. - if (ia != a.end() && *ia != l) - return kNoLiteralIndex; + if (ia != a.end() && *ia != l) return kNoLiteralIndex; if (ib != b.end()) { - if (result != kNoLiteralIndex) - return kNoLiteralIndex; + if (result != kNoLiteralIndex) return kNoLiteralIndex; result = (*ib).Index(); } return result; @@ -1090,15 +1024,14 @@ bool ComputeResolvant(Literal x, const std::vector &a, ++ia; ++ib; } else if (*ia == ib->Negated()) { - if (*ia != x) - return false; // Trivially true. + if (*ia != x) return false; // Trivially true. DCHECK_EQ(*ib, x.Negated()); ++ia; ++ib; } else if (*ia < *ib) { out->push_back(*ia); ++ia; - } else { // *ia > *ib + } else { // *ia > *ib out->push_back(*ib); ++ib; } @@ -1125,14 +1058,13 @@ int ComputeResolvantSize(Literal x, const std::vector &a, ++ia; ++ib; } else if (*ia == ib->Negated()) { - if (*ia != x) - return -1; // Trivially true. + if (*ia != x) return -1; // Trivially true. DCHECK_EQ(*ib, x.Negated()); ++ia; ++ib; } else if (*ia < *ib) { ++ia; - } else { // *ia > *ib + } else { // *ia > *ib ++ib; } } @@ -1148,10 +1080,11 @@ int ComputeResolvantSize(Literal x, const std::vector &a, // literals of a solver. Note that this can be expensive, hence the support // for a deterministic time limit. class PropagationGraph { -public: + public: PropagationGraph(double deterministic_time_limit, SatSolver *solver) - : solver_(solver), deterministic_time_limit(solver->deterministic_time() + - deterministic_time_limit) {} + : solver_(solver), + deterministic_time_limit(solver->deterministic_time() + + deterministic_time_limit) {} // Returns the set of node adjacent to the given one. // Interface needed by FindStronglyConnectedComponents(), note that it needs @@ -1184,7 +1117,7 @@ public: return scratchpad_; } -private: + private: mutable std::vector scratchpad_; SatSolver *const solver_; const double deterministic_time_limit; @@ -1221,8 +1154,7 @@ void ProbeAndFindEquivalentLiteral( MergingPartition partition(size); for (const std::vector &component : scc) { if (component.size() > 1) { - if (mapping->empty()) - mapping->resize(size, LiteralIndex(-1)); + if (mapping->empty()) mapping->resize(size, LiteralIndex(-1)); const Literal representative((LiteralIndex(component[0]))); for (int i = 1; i < component.size(); ++i) { const Literal l((LiteralIndex(component[i]))); @@ -1239,7 +1171,8 @@ void ProbeAndFindEquivalentLiteral( DCHECK_EQ(Literal(LiteralIndex(partition.GetRootAndCompressPath( representative.Index().value()))), Literal(LiteralIndex(partition.GetRootAndCompressPath( - representative.NegatedIndex().value()))).Negated()); + representative.NegatedIndex().value()))) + .Negated()); } } @@ -1259,14 +1192,12 @@ void ProbeAndFindEquivalentLiteral( const LiteralIndex rep(partition.GetRootAndCompressPath(i.value())); if (assignment.LiteralIsAssigned(Literal(i)) && !assignment.LiteralIsAssigned(Literal(rep))) { - const Literal true_lit = - assignment.LiteralIsTrue(Literal(i)) ? Literal(rep) - : Literal(rep).Negated(); + const Literal true_lit = assignment.LiteralIsTrue(Literal(i)) + ? Literal(rep) + : Literal(rep).Negated(); solver->AddUnitClause(true_lit); if (drat_proof_handler != nullptr) { - drat_proof_handler->AddClause({ - true_lit - }); + drat_proof_handler->AddClause({true_lit}); } } } @@ -1275,37 +1206,29 @@ void ProbeAndFindEquivalentLiteral( (*mapping)[i] = rep; if (assignment.LiteralIsAssigned(Literal(rep))) { if (!assignment.LiteralIsAssigned(Literal(i))) { - const Literal true_lit = - assignment.LiteralIsTrue(Literal(rep)) ? Literal(i) - : Literal(i).Negated(); + const Literal true_lit = assignment.LiteralIsTrue(Literal(rep)) + ? Literal(i) + : Literal(i).Negated(); solver->AddUnitClause(true_lit); if (drat_proof_handler != nullptr) { - drat_proof_handler->AddClause({ - true_lit - }); + drat_proof_handler->AddClause({true_lit}); } } } else if (assignment.LiteralIsAssigned(Literal(i))) { if (!assignment.LiteralIsAssigned(Literal(rep))) { - const Literal true_lit = - assignment.LiteralIsTrue(Literal(i)) ? Literal(rep) - : Literal(rep).Negated(); + const Literal true_lit = assignment.LiteralIsTrue(Literal(i)) + ? Literal(rep) + : Literal(rep).Negated(); solver->AddUnitClause(true_lit); if (drat_proof_handler != nullptr) { - drat_proof_handler->AddClause({ - true_lit - }); + drat_proof_handler->AddClause({true_lit}); } } } else if (rep != i) { ++num_equiv; - postsolver->Add(Literal(i), { - Literal(i), Literal(rep).Negated() - }); + postsolver->Add(Literal(i), {Literal(i), Literal(rep).Negated()}); if (drat_proof_handler != nullptr) { - drat_proof_handler->AddClause({ - Literal(i), Literal(rep).Negated() - }); + drat_proof_handler->AddClause({Literal(i), Literal(rep).Negated()}); } } } @@ -1313,11 +1236,11 @@ void ProbeAndFindEquivalentLiteral( const bool log_info = solver->parameters().log_search_progress() || VLOG_IS_ON(1); - LOG_IF(INFO, log_info) - << "Probing. fixed " << num_already_fixed_vars << " + " - << solver->LiteralTrail().Index() - num_already_fixed_vars << " equiv " - << num_equiv / 2 << " total " << solver->NumVariables() - << " wtime: " << timer.Get(); + LOG_IF(INFO, log_info) << "Probing. fixed " << num_already_fixed_vars << " + " + << solver->LiteralTrail().Index() - + num_already_fixed_vars + << " equiv " << num_equiv / 2 << " total " + << solver->NumVariables() << " wtime: " << timer.Get(); } SatSolver::Status SolveWithPresolve(std::unique_ptr *solver, @@ -1417,9 +1340,10 @@ SatSolver::Status SolveWithPresolve(std::unique_ptr *solver, // Tricky: the model local time limit is updated by the new functions, but // the old ones update time_limit directly. - time_limit->AdvanceDeterministicTime( - (*solver) - ->model()->GetOrCreate()->GetElapsedDeterministicTime()); + time_limit->AdvanceDeterministicTime((*solver) + ->model() + ->GetOrCreate() + ->GetElapsedDeterministicTime()); (*solver).reset(nullptr); std::vector can_be_removed(presolver.NumVariables(), true); @@ -1443,8 +1367,7 @@ SatSolver::Status SolveWithPresolve(std::unique_ptr *solver, presolver.LoadProblemIntoSatSolver((*solver).get()); // Stop if a fixed point has been reached. - if ((*solver)->NumVariables() == saved_num_variables) - break; + if ((*solver)->NumVariables() == saved_num_variables) break; } // Before solving, we use the new probing code that adds all new binary @@ -1463,8 +1386,9 @@ SatSolver::Status SolveWithPresolve(std::unique_ptr *solver, options.log_info = log_info; options.use_transitive_reduction = true; options.extract_binary_clauses_in_probing = true; - options.deterministic_time_limit = model->GetOrCreate() - ->presolve_probing_deterministic_time_limit(); + options.deterministic_time_limit = + model->GetOrCreate() + ->presolve_probing_deterministic_time_limit(); if (!model->GetOrCreate()->PresolveLoop(options)) { return SatSolver::INFEASIBLE; } @@ -1481,5 +1405,5 @@ SatSolver::Status SolveWithPresolve(std::unique_ptr *solver, return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/simplification.h b/ortools/sat/simplification.h index 0d44b870b1..02980c957b 100644 --- a/ortools/sat/simplification.h +++ b/ortools/sat/simplification.h @@ -45,7 +45,7 @@ namespace sat { // the end, this class will recover a solution of the initial problem from a // solution of the presolved problem. class SatPostsolver { -public: + public: explicit SatPostsolver(int num_variables); // The postsolver will process the Add() calls in reverse order. If the given @@ -99,7 +99,7 @@ public: return result; } -private: + private: Literal ApplyReverseMapping(Literal l); void Postsolve(VariablesAssignment *assignment) const; @@ -141,12 +141,13 @@ private: // only the clause part of a general Boolean problem by not removing variables // appearing in pseudo-Boolean constraints. class SatPresolver { -public: + public: // TODO(user): use IntType! typedef int32 ClauseIndex; explicit SatPresolver(SatPostsolver *postsolver) - : postsolver_(postsolver), num_trivial_clauses_(0), + : postsolver_(postsolver), + num_trivial_clauses_(0), drat_proof_handler_(nullptr) {} void SetParameters(const SatParameters ¶ms) { parameters_ = params; } @@ -222,7 +223,7 @@ public: drat_proof_handler_ = drat_proof_handler; } -private: + private: // Internal function used by ProcessClauseToSimplifyOthers(). bool ProcessClauseToSimplifyOthersUsingLiteral(ClauseIndex clause_index, Literal lit); @@ -245,8 +246,8 @@ private: // Finds the literal from the clause that occur the less in the clause // database. - Literal - FindLiteralWithShortestOccurrenceList(const std::vector &clause); + Literal FindLiteralWithShortestOccurrenceList( + const std::vector &clause); LiteralIndex FindLiteralWithShortestOccurrenceListExcluding( const std::vector &clause, Literal to_exclude); @@ -317,7 +318,7 @@ private: LiteralIndex literal; double weight; }; - std::deque bva_pq_elements_; // deque because we add variables. + std::deque bva_pq_elements_; // deque because we add variables. AdjustablePriorityQueue bva_pq_; // Temporary data for SimpleBva(). @@ -334,10 +335,10 @@ private: // The set of all clauses. // An empty clause means that it has been removed. - std::vector > clauses_; // Indexed by ClauseIndex + std::vector > clauses_; // Indexed by ClauseIndex // The cached value of ComputeSignatureOfClauseVariables() for each clause. - std::vector signatures_; // Indexed by ClauseIndex + std::vector signatures_; // Indexed by ClauseIndex int64 num_inspected_signatures_ = 0; int64 num_inspected_literals_ = 0; @@ -437,7 +438,7 @@ SatSolver::Status SolveWithPresolve( std::vector *solution /* only filled if SAT */, DratProofHandler *drat_proof_handler /* can be nullptr */); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SIMPLIFICATION_H_ +#endif // OR_TOOLS_SAT_SIMPLIFICATION_H_ diff --git a/ortools/sat/subsolver.cc b/ortools/sat/subsolver.cc index f94acde44e..b301eed8df 100644 --- a/ortools/sat/subsolver.cc +++ b/ortools/sat/subsolver.cc @@ -18,7 +18,7 @@ #if !defined(__PORTABLE_PLATFORM__) #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ namespace operations_research { namespace sat { @@ -41,28 +41,25 @@ int NextSubsolverToSchedule( } } } - if (best != -1) - VLOG(1) << "Scheduling " << subsolvers[best]->name(); + if (best != -1) VLOG(1) << "Scheduling " << subsolvers[best]->name(); return best; } -void -SynchronizeAll(const std::vector > &subsolvers) { - for (const auto &subsolver : subsolvers) - subsolver->Synchronize(); +void SynchronizeAll( + const std::vector > &subsolvers) { + for (const auto &subsolver : subsolvers) subsolver->Synchronize(); } -} // namespace +} // namespace -void -SequentialLoop(const std::vector > &subsolvers) { +void SequentialLoop( + const std::vector > &subsolvers) { int64 task_id = 0; std::vector num_generated_tasks(subsolvers.size(), 0); while (true) { SynchronizeAll(subsolvers); const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks); - if (best == -1) - break; + if (best == -1) break; num_generated_tasks[best]++; subsolvers[best]->GenerateTask(task_id++)(); } @@ -72,23 +69,23 @@ SequentialLoop(const std::vector > &subsolvers) { // On portable platform, we don't support multi-threading for now. -void -NonDeterministicLoop(const std::vector > &subsolvers, - int num_threads) { +void NonDeterministicLoop( + const std::vector > &subsolvers, + int num_threads) { SequentialLoop(subsolvers); } -void -DeterministicLoop(const std::vector > &subsolvers, - int num_threads, int batch_size) { +void DeterministicLoop( + const std::vector > &subsolvers, int num_threads, + int batch_size) { SequentialLoop(subsolvers); } -#else // __PORTABLE_PLATFORM__ +#else // __PORTABLE_PLATFORM__ -void -DeterministicLoop(const std::vector > &subsolvers, - int num_threads, int batch_size) { +void DeterministicLoop( + const std::vector > &subsolvers, int num_threads, + int batch_size) { CHECK_GT(num_threads, 0); CHECK_GT(batch_size, 0); if (batch_size == 1) { @@ -109,20 +106,18 @@ DeterministicLoop(const std::vector > &subsolvers, int num_in_batch = 0; for (int t = 0; t < batch_size; ++t) { const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks); - if (best == -1) - break; + if (best == -1) break; ++num_in_batch; num_generated_tasks[best]++; pool.Schedule(subsolvers[best]->GenerateTask(task_id++)); } - if (num_in_batch == 0) - break; + if (num_in_batch == 0) break; } } -void -NonDeterministicLoop(const std::vector > &subsolvers, - int num_threads) { +void NonDeterministicLoop( + const std::vector > &subsolvers, + int num_threads) { CHECK_GT(num_threads, 0); if (num_threads == 1) { return SequentialLoop(subsolvers); @@ -149,8 +144,7 @@ NonDeterministicLoop(const std::vector > &subsolvers, // The stopping condition is that we do not have anything else to generate // once all the task are done and synchronized. - if (num_scheduled_and_not_done == 0) - all_done = true; + if (num_scheduled_and_not_done == 0) all_done = true; // Wait if num_scheduled_and_not_done == num_threads. if (num_scheduled_and_not_done == num_threads) { @@ -161,8 +155,7 @@ NonDeterministicLoop(const std::vector > &subsolvers, SynchronizeAll(subsolvers); const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks); if (best == -1) { - if (all_done) - break; + if (all_done) break; // It is hard to know when new info will allows for more task to be // scheduled, so for now we just sleep for a bit. Note that in practice We @@ -194,7 +187,7 @@ NonDeterministicLoop(const std::vector > &subsolvers, } } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/subsolver.h b/ortools/sat/subsolver.h index f8b39f777e..ff08c05e58 100644 --- a/ortools/sat/subsolver.h +++ b/ortools/sat/subsolver.h @@ -28,7 +28,7 @@ #if !defined(__PORTABLE_PLATFORM__) #include "ortools/base/threadpool.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ namespace operations_research { namespace sat { @@ -39,7 +39,7 @@ namespace sat { // Note that currently only the main thread interact with subsolvers. Only the // tasks generated by GenerateTask() are executed in parallel in a threadpool. class SubSolver { -public: + public: explicit SubSolver(const std::string &name) : name_(name) {} virtual ~SubSolver() {} @@ -83,7 +83,7 @@ public: // Returns the name of this SubSolver. Used in logs. std::string name() const { return name_; } -protected: + protected: const std::string name_; double score_ = 0.0; double deterministic_time_ = 0.0; @@ -91,14 +91,14 @@ protected: // A simple wrapper to add a synchronization point in the list of subsolvers. class SynchronizationPoint : public SubSolver { -public: + public: explicit SynchronizationPoint(std::function f) : SubSolver(""), f_(std::move(f)) {} bool TaskIsAvailable() final { return false; } std::function GenerateTask(int64 task_id) final { return nullptr; } void Synchronize() final { f_(); } -private: + private: std::function f_; }; @@ -137,7 +137,7 @@ void DeterministicLoop( // higher batch size will not behave in the same way, even if num_threads=1. void SequentialLoop(const std::vector > &subsolvers); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SUBSOLVER_H_ +#endif // OR_TOOLS_SAT_SUBSOLVER_H_ diff --git a/ortools/sat/swig_helper.h b/ortools/sat/swig_helper.h index a1563265b5..0e5f8d2cfc 100644 --- a/ortools/sat/swig_helper.h +++ b/ortools/sat/swig_helper.h @@ -31,7 +31,7 @@ namespace sat { // Base class for SWIG director based on solution callbacks. // See http://www.swig.org/Doc3.0/SWIGDocumentation.html#CSharp_directors. class SolutionCallback { -public: + public: virtual ~SolutionCallback() {} virtual void OnSolutionCallback() const = 0; @@ -89,14 +89,14 @@ public: bool HasResponse() const { return has_response_; } -private: + private: mutable CpSolverResponse response_; mutable bool has_response_ = false; mutable std::atomic stopped_; }; class SatHelper { -public: + public: // The arguments of the functions defined below must follow these rules // to be wrapped by swig correctly: // 1) Their types must include the full operations_research::sat:: @@ -105,8 +105,8 @@ public: // file (see the python/ and java/ subdirectories). // 3) String variations of the parameters have been added for C# as // C# protobufs do not support proto2. - static operations_research::sat::CpSolverResponse - Solve(const operations_research::sat::CpModelProto &model_proto) { + static operations_research::sat::CpSolverResponse Solve( + const operations_research::sat::CpModelProto &model_proto) { FixFlagsAndEnvironmentForSwig(); return operations_research::sat::Solve(model_proto); } @@ -136,12 +136,10 @@ public: callback.ResetSharedBoolean(); Model model; model.Add(NewSatParameters(parameters)); - model.Add( - NewFeasibleSolutionObserver([&callback](const CpSolverResponse & r) { - return callback.Run(r); - })); - model.GetOrCreate() - ->RegisterExternalBooleanAsLimit(callback.stopped()); + model.Add(NewFeasibleSolutionObserver( + [&callback](const CpSolverResponse &r) { return callback.Run(r); })); + model.GetOrCreate()->RegisterExternalBooleanAsLimit( + callback.stopped()); return SolveCpModel(model_proto, &model); } @@ -154,19 +152,17 @@ public: callback.ResetSharedBoolean(); Model model; model.Add(NewSatParameters(parameters)); - model.Add( - NewFeasibleSolutionObserver([&callback](const CpSolverResponse & r) { - return callback.Run(r); - })); - model.GetOrCreate() - ->RegisterExternalBooleanAsLimit(callback.stopped()); + model.Add(NewFeasibleSolutionObserver( + [&callback](const CpSolverResponse &r) { return callback.Run(r); })); + model.GetOrCreate()->RegisterExternalBooleanAsLimit( + callback.stopped()); return SolveCpModel(model_proto, &model); } // Returns a string with some statistics on the given CpModelProto. - static std::string - ModelStats(const operations_research::sat::CpModelProto &model_proto) { + static std::string ModelStats( + const operations_research::sat::CpModelProto &model_proto) { return CpModelStats(model_proto); } @@ -177,8 +173,8 @@ public: } // Returns a non empty string explaining the issue if the model is not valid. - static std::string - ValidateModel(const operations_research::sat::CpModelProto &model_proto) { + static std::string ValidateModel( + const operations_research::sat::CpModelProto &model_proto) { return ValidateCpModel(model_proto); } @@ -189,14 +185,14 @@ public: } // Write the model proto to file. - static bool - WriteModelToFile(const operations_research::sat::CpModelProto &model_proto, - const std::string &filename) { + static bool WriteModelToFile( + const operations_research::sat::CpModelProto &model_proto, + const std::string &filename) { return file::SetTextProto(filename, model_proto, file::Defaults()).ok(); } }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SWIG_HELPER_H_ +#endif // OR_TOOLS_SAT_SWIG_HELPER_H_ diff --git a/ortools/sat/symmetry.cc b/ortools/sat/symmetry.cc index 60f0628e31..3bd5c5ca96 100644 --- a/ortools/sat/symmetry.cc +++ b/ortools/sat/symmetry.cc @@ -20,8 +20,10 @@ namespace operations_research { namespace sat { SymmetryPropagator::SymmetryPropagator() - : SatPropagator("SymmetryPropagator"), stats_("SymmetryPropagator"), - num_propagations_(0), num_conflicts_(0) {} + : SatPropagator("SymmetryPropagator"), + stats_("SymmetryPropagator"), + num_propagations_(0), + num_conflicts_(0) {} SymmetryPropagator::~SymmetryPropagator() { IF_STATS_ENABLED({ @@ -33,8 +35,7 @@ SymmetryPropagator::~SymmetryPropagator() { void SymmetryPropagator::AddSymmetry( std::unique_ptr permutation) { - if (permutation->NumCycles() == 0) - return; + if (permutation->NumCycles() == 0) return; SCOPED_TIME_STAT(&stats_); DCHECK_EQ(propagation_trail_index_, 0); if (permutation->Size() > images_.size()) { @@ -112,7 +113,7 @@ bool SymmetryPropagator::PropagateNext(Trail *trail) { if (trail->Index() >= reasons_.size()) { reasons_.resize(trail->Index() + 1); } - reasons_[trail->Index()] = { assignment_info.trail_index, p_index }; + reasons_[trail->Index()] = {assignment_info.trail_index, p_index}; trail->Enqueue(non_symmetric.image, propagator_id_); ++num_propagations_; } @@ -125,8 +126,7 @@ bool SymmetryPropagator::PropagateNext(Trail *trail) { bool SymmetryPropagator::Propagate(Trail *trail) { const int old_index = trail->Index(); while (trail->Index() == old_index && propagation_trail_index_ < old_index) { - if (!PropagateNext(trail)) - return false; + if (!PropagateNext(trail)) return false; } return true; } @@ -221,5 +221,5 @@ void SymmetryPropagator::Permute(int index, absl::Span input, } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/symmetry.h b/ortools/sat/symmetry.h index 545f221951..f1330e4deb 100644 --- a/ortools/sat/symmetry.h +++ b/ortools/sat/symmetry.h @@ -59,14 +59,14 @@ namespace sat { // TODO(user): Implement the optimizations mentioned in the paper? // TODO(user): Instrument and see if the code can be optimized. class SymmetryPropagator : public SatPropagator { -public: + public: SymmetryPropagator(); ~SymmetryPropagator() override; bool Propagate(Trail *trail) final; void Untrail(const Trail &trail, int trail_index) final; - absl::Span Reason(const Trail &trail, int trail_index) const - final; + absl::Span Reason(const Trail &trail, + int trail_index) const final; // Adds a new permutation to this symmetry propagator. The ownership is // transferred. This must be an integer permutation such that: @@ -95,7 +95,7 @@ public: void Permute(int index, absl::Span input, std::vector *output) const; -private: + private: // Propagates the literal at propagation_trail_index_ from the trail. bool PropagateNext(Trail *trail); @@ -156,7 +156,7 @@ private: DISALLOW_COPY_AND_ASSIGN(SymmetryPropagator); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SYMMETRY_H_ +#endif // OR_TOOLS_SAT_SYMMETRY_H_ diff --git a/ortools/sat/synchronization.cc b/ortools/sat/synchronization.cc index 94790588a8..6fc539e250 100644 --- a/ortools/sat/synchronization.cc +++ b/ortools/sat/synchronization.cc @@ -16,7 +16,7 @@ #if !defined(__PORTABLE_PLATFORM__) #include "ortools/base/file.h" #include "ortools/sat/cp_model_loader.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ #include "absl/container/flat_hash_set.h" #include "absl/random/random.h" @@ -46,13 +46,12 @@ void SharedRelaxationSolutionRepository::NewRelaxationSolution( const CpSolverResponse &response) { // Note that the Add() method already applies mutex lock. So we don't need it // here. - if (response.solution().empty()) - return; + if (response.solution().empty()) return; // Add this solution to the pool. SharedSolutionRepository::Solution solution; - solution.variable_values - .assign(response.solution().begin(), response.solution().end()); + solution.variable_values.assign(response.solution().begin(), + response.solution().end()); // For now we use the negated lower bound as the "internal objective" to // prefer solution with an higher bound. // @@ -63,10 +62,9 @@ void SharedRelaxationSolutionRepository::NewRelaxationSolution( Add(solution); } -void -SharedLPSolutionRepository::NewLPSolution(std::vector lp_solution) { - if (lp_solution.empty()) - return; +void SharedLPSolutionRepository::NewLPSolution( + std::vector lp_solution) { + if (lp_solution.empty()) return; // Add this solution to the pool. SharedSolutionRepository::Solution solution; @@ -86,8 +84,7 @@ bool SharedIncompleteSolutionManager::HasNewSolution() const { std::vector SharedIncompleteSolutionManager::GetNewSolution() { absl::MutexLock mutex_lock(&mutex_); std::vector solution; - if (solutions_.empty()) - return solution; + if (solutions_.empty()) return solution; solution = std::move(solutions_.back()); solutions_.pop_back(); @@ -107,9 +104,11 @@ SharedResponseManager::SharedResponseManager(bool log_updates, const WallTimer *wall_timer, SharedTimeLimit *shared_time_limit) : log_updates_(log_updates), - enumerate_all_solutions_(enumerate_all_solutions), model_proto_(*proto), - wall_timer_(*wall_timer), shared_time_limit_(shared_time_limit), - solutions_(/*num_solutions_to_keep=*/ 3) {} + enumerate_all_solutions_(enumerate_all_solutions), + model_proto_(*proto), + wall_timer_(*wall_timer), + shared_time_limit_(shared_time_limit), + solutions_(/*num_solutions_to_keep=*/3) {} namespace { @@ -130,12 +129,11 @@ void LogNewSatSolution(const std::string &event_or_solution_count, time_in_seconds, solution_info); } -} // namespace +} // namespace void SharedResponseManager::UpdatePrimalIntegral() { absl::MutexLock mutex_lock(&mutex_); - if (!model_proto_.has_objective()) - return; + if (!model_proto_.has_objective()) return; const double current_time = shared_time_limit_->GetElapsedDeterministicTime(); const double time_delta = current_time - last_primal_integral_time_stamp_; @@ -158,19 +156,15 @@ void SharedResponseManager::UpdatePrimalIntegral() { void SharedResponseManager::SetGapLimitsFromParameters( const SatParameters ¶meters) { absl::MutexLock mutex_lock(&mutex_); - if (!model_proto_.has_objective()) - return; + if (!model_proto_.has_objective()) return; absolute_gap_limit_ = parameters.absolute_gap_limit(); relative_gap_limit_ = parameters.relative_gap_limit(); } void SharedResponseManager::TestGapLimitsIfNeeded() { - if (absolute_gap_limit_ == 0 && relative_gap_limit_ == 0) - return; - if (best_solution_objective_value_ >= kMaxIntegerValue) - return; - if (inner_objective_lower_bound_ <= kMinIntegerValue) - return; + if (absolute_gap_limit_ == 0 && relative_gap_limit_ == 0) return; + if (best_solution_objective_value_ >= kMaxIntegerValue) return; + if (inner_objective_lower_bound_ <= kMinIntegerValue) return; const CpObjectiveProto &obj = model_proto_.objective(); const double user_best = @@ -179,8 +173,8 @@ void SharedResponseManager::TestGapLimitsIfNeeded() { ScaleObjectiveValue(obj, inner_objective_lower_bound_); const double gap = std::abs(user_best - user_bound); if (gap <= absolute_gap_limit_) { - LOG_IF(INFO, log_updates_) << "Absolute gap limit of " - << absolute_gap_limit_ << " reached."; + LOG_IF(INFO, log_updates_) + << "Absolute gap limit of " << absolute_gap_limit_ << " reached."; best_response_.set_status(CpSolverStatus::OPTIMAL); // Note(user): Some code path in single-thread assumes that the problem @@ -189,8 +183,8 @@ void SharedResponseManager::TestGapLimitsIfNeeded() { shared_time_limit_->Stop(); } if (gap / std::max(1.0, std::abs(user_best)) < relative_gap_limit_) { - LOG_IF(INFO, log_updates_) << "Relative gap limit of " - << relative_gap_limit_ << " reached."; + LOG_IF(INFO, log_updates_) + << "Relative gap limit of " << relative_gap_limit_ << " reached."; best_response_.set_status(CpSolverStatus::OPTIMAL); // Same as above. @@ -233,8 +227,7 @@ void SharedResponseManager::UpdateInnerObjectiveBounds( } else { best_response_.set_status(CpSolverStatus::INFEASIBLE); } - if (log_updates_) - LogNewSatSolution("Done", wall_timer_.Get(), worker_info); + if (log_updates_) LogNewSatSolution("Done", wall_timer_.Get(), worker_info); return; } if (log_updates_ && change) { @@ -249,8 +242,7 @@ void SharedResponseManager::UpdateInnerObjectiveBounds( LogNewSolution("Bound", wall_timer_.Get(), best, new_lb, new_ub, worker_info); } - if (change) - TestGapLimitsIfNeeded(); + if (change) TestGapLimitsIfNeeded(); } // Invariant: the status always start at UNKNOWN and can only evolve as follow: @@ -275,8 +267,7 @@ void SharedResponseManager::NotifyThatImprovingProblemIsInfeasible( CHECK_EQ(num_solutions_, 0); best_response_.set_status(CpSolverStatus::INFEASIBLE); } - if (log_updates_) - LogNewSatSolution("Done", wall_timer_.Get(), worker_info); + if (log_updates_) LogNewSatSolution("Done", wall_timer_.Get(), worker_info); } void SharedResponseManager::AddUnsatCore(const std::vector &core) { @@ -351,8 +342,7 @@ CpSolverResponse SharedResponseManager::GetResponse() { } void SharedResponseManager::FillObjectiveValuesInBestResponse() { - if (!model_proto_.has_objective()) - return; + if (!model_proto_.has_objective()) return; const CpObjectiveProto &obj = model_proto_.objective(); if (best_response_.status() == CpSolverStatus::INFEASIBLE) { @@ -390,15 +380,14 @@ void SharedResponseManager::NewSolution(const CpSolverResponse &response, // Add this solution to the pool, even if it is not improving. if (!response.solution().empty()) { SharedSolutionRepository::Solution solution; - solution.variable_values - .assign(response.solution().begin(), response.solution().end()); + solution.variable_values.assign(response.solution().begin(), + response.solution().end()); solution.rank = objective_value; solutions_.Add(solution); } // Ignore any non-strictly improving solution. - if (objective_value > inner_objective_upper_bound_) - return; + if (objective_value > inner_objective_upper_bound_) return; // Our inner_objective_lower_bound_ should be a globaly valid bound, until // the problem become infeasible (i.e the lb > ub) in which case the bound @@ -439,8 +428,8 @@ void SharedResponseManager::NewSolution(const CpSolverResponse &response, if (log_updates_) { std::string solution_info = response.solution_info(); if (model != nullptr) { - absl::StrAppend(&solution_info, " num_bool:", - model->Get()->NumVariables()); + absl::StrAppend(&solution_info, + " num_bool:", model->Get()->NumVariables()); } if (model_proto_.has_objective()) { @@ -480,15 +469,13 @@ void SharedResponseManager::NewSolution(const CpSolverResponse &response, LOG(INFO) << "Dumping solution to '" << file << "'."; CHECK_OK(file::SetTextProto(file, best_response_, file::Defaults())); } -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ } void SharedResponseManager::LoadDebugSolution(Model *model) { #if !defined(__PORTABLE_PLATFORM__) - if (absl::GetFlag(FLAGS_cp_model_load_debug_solution).empty()) - return; - if (model->Get() != nullptr) - return; // Already loaded. + if (absl::GetFlag(FLAGS_cp_model_load_debug_solution).empty()) return; + if (model->Get() != nullptr) return; // Already loaded. CpSolverResponse response; LOG(INFO) << "Reading solution from '" @@ -501,8 +488,7 @@ void SharedResponseManager::LoadDebugSolution(Model *model) { debug_solution.resize( model->GetOrCreate()->NumIntegerVariables().value()); for (int i = 0; i < response.solution().size(); ++i) { - if (!mapping.IsInteger(i)) - continue; + if (!mapping.IsInteger(i)) continue; const IntegerVariable var = mapping.Integer(i); debug_solution[var] = response.solution(i); debug_solution[NegationOf(var)] = -response.solution(i); @@ -511,15 +497,14 @@ void SharedResponseManager::LoadDebugSolution(Model *model) { // The objective variable is usually not part of the proto, but it is still // nice to have it, so we recompute it here. auto *objective_def = model->Get(); - if (objective_def == nullptr) - return; + if (objective_def == nullptr) return; const IntegerVariable objective_var = objective_def->objective_var; const int64 objective_value = ComputeInnerObjective(model_proto_.objective(), response); debug_solution[objective_var] = objective_value; debug_solution[NegationOf(objective_var)] = -objective_value; -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ } void SharedResponseManager::SetStatsFromModel(Model *model) { @@ -528,8 +513,7 @@ void SharedResponseManager::SetStatsFromModel(Model *model) { } void SharedResponseManager::SetStatsFromModelInternal(Model *model) { - if (model == nullptr) - return; + if (model == nullptr) return; auto *sat_solver = model->Get(); auto *integer_trail = model->Get(); best_response_.set_num_booleans(sat_solver->NumVariables()); @@ -551,7 +535,8 @@ bool SharedResponseManager::ProblemIsSolved() const { } SharedBoundsManager::SharedBoundsManager(const CpModelProto &model_proto) - : num_variables_(model_proto.variables_size()), model_proto_(model_proto), + : num_variables_(model_proto.variables_size()), + model_proto_(model_proto), lower_bounds_(num_variables_, kint64min), upper_bounds_(num_variables_, kint64max), synchronized_lower_bounds_(num_variables_, kint64min), @@ -577,8 +562,7 @@ void SharedBoundsManager::ReportPotentialNewBounds( absl::MutexLock mutex_lock(&mutex_); for (int i = 0; i < variables.size(); ++i) { const int var = variables[i]; - if (var >= num_variables_) - continue; + if (var >= num_variables_) continue; const int64 old_lb = lower_bounds_[var]; const int64 old_ub = upper_bounds_[var]; const int64 new_lb = new_lower_bounds[i]; @@ -586,8 +570,7 @@ void SharedBoundsManager::ReportPotentialNewBounds( const bool changed_lb = new_lb > old_lb; const bool changed_ub = new_ub < old_ub; CHECK_GE(var, 0); - if (!changed_lb && !changed_ub) - continue; + if (!changed_lb && !changed_ub) continue; if (changed_lb) { lower_bounds_[var] = new_lb; @@ -629,10 +612,9 @@ int SharedBoundsManager::RegisterNewId() { return id; } -void -SharedBoundsManager::GetChangedBounds(int id, std::vector *variables, - std::vector *new_lower_bounds, - std::vector *new_upper_bounds) { +void SharedBoundsManager::GetChangedBounds( + int id, std::vector *variables, std::vector *new_lower_bounds, + std::vector *new_upper_bounds) { variables->clear(); new_lower_bounds->clear(); new_upper_bounds->clear(); @@ -646,5 +628,5 @@ SharedBoundsManager::GetChangedBounds(int id, std::vector *variables, id_to_changed_variables_[id].ClearAll(); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/synchronization.h b/ortools/sat/synchronization.h index a5e6307324..7fade39398 100644 --- a/ortools/sat/synchronization.h +++ b/ortools/sat/synchronization.h @@ -39,8 +39,9 @@ namespace sat { // // TODO(user): Maybe add some criteria to only keep solution with an objective // really close to the best solution. -template class SharedSolutionRepository { -public: +template +class SharedSolutionRepository { + public: explicit SharedSolutionRepository(int num_solutions_to_keep) : num_solutions_to_keep_(num_solutions_to_keep) { CHECK_GE(num_solutions_to_keep_, 1); @@ -104,7 +105,7 @@ public: // Works in O(num_solutions_to_keep_). void Synchronize(); -protected: + protected: // Helper method for adding the solutions once the mutex is acquired. void AddInternal(const Solution &solution) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); @@ -124,7 +125,7 @@ protected: // LNS generators which in turn are used to generate some RINS neighborhood. class SharedRelaxationSolutionRepository : public SharedSolutionRepository { -public: + public: explicit SharedRelaxationSolutionRepository(int num_solutions_to_keep) : SharedSolutionRepository(num_solutions_to_keep) {} @@ -132,7 +133,7 @@ public: }; class SharedLPSolutionRepository : public SharedSolutionRepository { -public: + public: explicit SharedLPSolutionRepository(int num_solutions_to_keep) : SharedSolutionRepository(num_solutions_to_keep) {} @@ -148,13 +149,13 @@ public: // value for that variable. These solutions can not necessarily be completed to // complete feasible solutions. class SharedIncompleteSolutionManager { -public: + public: bool HasNewSolution() const; std::vector GetNewSolution(); void AddNewSolution(const std::vector &lp_solution); -private: + private: // New solutions are added and removed from the back. std::vector > solutions_; mutable absl::Mutex mutex_; @@ -163,7 +164,7 @@ private: // Manages the global best response kept by the solver. // All functions are thread-safe. class SharedResponseManager { -public: + public: // If log_updates is true, then all updates to the global "state" will be // logged. This class is responsible for our solver log progress. SharedResponseManager(bool log_updates, bool enumerate_all_solutions, @@ -284,7 +285,7 @@ public: dump_prefix_ = dump_prefix; } -private: + private: void TestGapLimitsIfNeeded() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void FillObjectiveValuesInBestResponse() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); @@ -330,7 +331,7 @@ private: // This class manages a pool of lower and upper bounds on a set of variables in // a parallel context. class SharedBoundsManager { -public: + public: explicit SharedBoundsManager(const CpModelProto &model_proto); // Reports a set of locally improved variable bounds to the shared bounds @@ -357,7 +358,7 @@ public: // state. void Synchronize(); -private: + private: const int num_variables_; const CpModelProto &model_proto_; @@ -440,13 +441,12 @@ void SharedSolutionRepository::Add(const Solution &solution) { } template -void -SharedSolutionRepository::AddInternal(const Solution &solution) { +void SharedSolutionRepository::AddInternal( + const Solution &solution) { int worse_solution_index = 0; for (int i = 0; i < new_solutions_.size(); ++i) { // Do not add identical solution. - if (new_solutions_[i] == solution) - return; + if (new_solutions_[i] == solution) return; if (new_solutions_[worse_solution_index] < new_solutions_[i]) { worse_solution_index = i; } @@ -476,7 +476,7 @@ void SharedSolutionRepository::Synchronize() { num_synchronization_++; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_SYNCHRONIZATION_H_ +#endif // OR_TOOLS_SAT_SYNCHRONIZATION_H_ diff --git a/ortools/sat/table.cc b/ortools/sat/table.cc index c7924cb31f..5930a64f00 100644 --- a/ortools/sat/table.cc +++ b/ortools/sat/table.cc @@ -52,11 +52,11 @@ absl::flat_hash_map GetEncoding(IntegerVariable var, // and the Literal of the column variable can be retrieved using the encoding // map. Thew tuples_with_any vector provides a list of line_literals that will // support any value. -void -ProcessOneColumn(const std::vector &line_literals, - const std::vector &values, - const absl::flat_hash_map &encoding, - const std::vector &tuples_with_any, Model *model) { +void ProcessOneColumn( + const std::vector &line_literals, + const std::vector &values, + const absl::flat_hash_map &encoding, + const std::vector &tuples_with_any, Model *model) { CHECK_EQ(line_literals.size(), values.size()); std::vector > pairs; @@ -66,9 +66,7 @@ ProcessOneColumn(const std::vector &line_literals, for (int i = 0; i < values.size(); ++i) { const IntegerValue v = values[i]; if (!encoding.contains(v)) { - model->Add(ClauseConstraint({ - line_literals[i].Negated() - })); + model->Add(ClauseConstraint({line_literals[i].Negated()})); } else { pairs.emplace_back(v, line_literals[i]); model->Add(Implication(line_literals[i], gtl::FindOrDie(encoding, v))); @@ -95,11 +93,11 @@ ProcessOneColumn(const std::vector &line_literals, } // Simpler encoding for table constraints with 2 variables. -void -AddSizeTwoTable(absl::Span vars, - const std::vector > &tuples, - const std::vector > &values_per_var, - Model *model) { +void AddSizeTwoTable( + absl::Span vars, + const std::vector > &tuples, + const std::vector > &values_per_var, + Model *model) { const int n = vars.size(); CHECK_EQ(n, 2); IntegerTrail *const integer_trail = model->GetOrCreate(); @@ -117,8 +115,7 @@ AddSizeTwoTable(absl::Span vars, } // One variable is fixed. Propagation is complete. - if (values_per_var[0].size() == 1 || values_per_var[1].size() == 1) - return; + if (values_per_var[0].size() == 1 || values_per_var[1].size() == 1) return; std::map > left_to_right; std::map > right_to_left; @@ -143,10 +140,9 @@ AddSizeTwoTable(absl::Span vars, std::vector clause; auto add_support_constraint = [model, &num_clause_added, &num_large_clause_added, &num_implications, - &clause](LiteralIndex lit, const std::vector & supports, + &clause](LiteralIndex lit, const std::vector &supports, int max_support_size) { - if (supports.size() == max_support_size) - return; + if (supports.size() == max_support_size) return; if (supports.size() == 1) { model->Add(Implication(Literal(lit), supports.front())); num_implications++; @@ -159,8 +155,7 @@ AddSizeTwoTable(absl::Span vars, num_large_clause_added++; } } - } - ; + }; for (const auto &it : left_to_right) { add_support_constraint(it.first, it.second, values_per_var[1].size()); @@ -201,8 +196,7 @@ void ExploreSubsetOfVariablesAndAddNegatedTables( } // Abort early. - if (max_num_prefix_tuples > 2 * tuples.size()) - break; + if (max_num_prefix_tuples > 2 * tuples.size()) break; absl::flat_hash_set > prefixes; bool skip = false; @@ -214,8 +208,7 @@ void ExploreSubsetOfVariablesAndAddNegatedTables( break; } } - if (skip) - continue; + if (skip) continue; const int num_prefix_tuples = prefixes.size(); std::vector > negated_tuples; @@ -245,7 +238,7 @@ void ExploreSubsetOfVariablesAndAddNegatedTables( } } -} // namespace +} // namespace // Makes a static decomposition of a table constraint into clauses. // This uses an auxiliary vector of Literals tuple_literals. @@ -364,8 +357,8 @@ void AddTableConstraint(absl::Span vars, absl::StrAppend(&message, ", num prefix tuples = ", num_prefix_tuples); } if (num_compressed_tuples != num_valid_tuples) { - absl::StrAppend(&message, ", compressed tuples = ", - num_compressed_tuples); + absl::StrAppend(&message, + ", compressed tuples = ", num_compressed_tuples); } VLOG(2) << message; } @@ -402,8 +395,7 @@ void AddTableConstraint(absl::Span vars, std::vector active_values; std::vector any_tuple_literals; for (int i = 0; i < n; ++i) { - if (values_per_var[i].size() == 1) - continue; + if (values_per_var[i].size() == 1) continue; active_tuple_literals.clear(); active_values.clear(); @@ -436,13 +428,11 @@ void AddTableConstraint(absl::Span vars, bool tuple_is_valid = true; for (int i = 0; i + 1 < n; ++i) { // Ignore fixed variables. - if (values_per_var[i].size() == 1) - continue; + if (values_per_var[i].size() == 1) continue; const int64 v = tuples[j][i]; // Ignored 'any' created during compression. - if (v == any_value) - continue; + if (v == any_value) continue; const IntegerValue value(v); if (!encodings[i].contains(value)) { @@ -451,13 +441,11 @@ void AddTableConstraint(absl::Span vars, } clause.push_back(gtl::FindOrDie(encodings[i], value).Negated()); } - if (!tuple_is_valid) - continue; + if (!tuple_is_valid) continue; // Add the target of the implication. const IntegerValue target_value = IntegerValue(tuples[j][n - 1]); - if (!encodings[n - 1].contains(target_value)) - continue; + if (!encodings[n - 1].contains(target_value)) continue; const Literal target_literal = gtl::FindOrDie(encodings[n - 1], target_value); clause.push_back(target_literal); @@ -478,8 +466,8 @@ void AddNegatedTableConstraint(absl::Span vars, while (index < tuples.size()) { bool remove = false; for (int i = 0; i < n; ++i) { - if (!integer_trail->InitialVariableDomain(vars[i]) - .Contains(tuples[index][i])) { + if (!integer_trail->InitialVariableDomain(vars[i]).Contains( + tuples[index][i])) { remove = true; break; } @@ -500,8 +488,8 @@ void AddNegatedTableConstraint(absl::Span vars, const int64 any_value = kint64min; std::vector domain_sizes; for (int i = 0; i < n; ++i) { - domain_sizes.push_back(integer_trail->InitialVariableDomain(vars[i]) - .Size()); + domain_sizes.push_back( + integer_trail->InitialVariableDomain(vars[i]).Size()); } CompressTuples(domain_sizes, any_value, &tuples); @@ -520,8 +508,7 @@ void AddNegatedTableConstraint(absl::Span vars, clause.clear(); for (int i = 0; i < n; ++i) { const int64 value = tuple[i]; - if (value == any_value) - continue; + if (value == any_value) continue; // If a literal associated to var == value exist, use it, otherwise // just use (and eventually create) the two literals var >= value + 1 @@ -550,22 +537,19 @@ void AddNegatedTableConstraint(absl::Span vars, } } } - if (add_tuple) - model->Add(ClauseConstraint(clause)); + if (add_tuple) model->Add(ClauseConstraint(clause)); } } -std::function -LiteralTableConstraint(const std::vector > &literal_tuples, - const std::vector &line_literals) { - return[ = ](Model * - model) { CHECK_EQ(literal_tuples.size(), line_literals.size()); +std::function LiteralTableConstraint( + const std::vector > &literal_tuples, + const std::vector &line_literals) { + return [=](Model *model) { + CHECK_EQ(literal_tuples.size(), line_literals.size()); const int num_tuples = line_literals.size(); - if (num_tuples == 0) - return; + if (num_tuples == 0) return; const int tuple_size = literal_tuples[0].size(); - if (tuple_size == 0) - return; + if (tuple_size == 0) return; for (int i = 1; i < num_tuples; ++i) { CHECK_EQ(tuple_size, literal_tuples[i].size()); } @@ -601,17 +585,15 @@ LiteralTableConstraint(const std::vector > &literal_tuples, clause.push_back(Literal(p.first).Negated()); model->Add(ClauseConstraint(clause)); } - } - ; + }; } -std::function -TransitionConstraint(const std::vector &vars, - const std::vector > &automaton, - int64 initial_state, - const std::vector &final_states) { - return[ = ](Model *model) { IntegerTrail *integer_trail = - model->GetOrCreate(); +std::function TransitionConstraint( + const std::vector &vars, + const std::vector > &automaton, int64 initial_state, + const std::vector &final_states) { + return [=](Model *model) { + IntegerTrail *integer_trail = model->GetOrCreate(); const int n = vars.size(); CHECK_GT(n, 0) << "No variables in TransitionConstraint()."; @@ -620,8 +602,7 @@ TransitionConstraint(const std::vector &vars, std::set > unique_transition_checker; for (const std::vector &transition : automaton) { CHECK_EQ(transition.size(), 3); - const std::pair p { transition[0], transition[1] } - ; + const std::pair p{transition[0], transition[1]}; CHECK(!gtl::ContainsKey(unique_transition_checker, p)) << "Duplicate outgoing transitions with value " << transition[1] << " from state " << transition[0] << "."; @@ -644,7 +625,7 @@ TransitionConstraint(const std::vector &vars, // Compute the set of reachable state at each time point. std::vector > reachable_states(n + 1); reachable_states[0].insert(initial_state); - reachable_states[n] = { final_states.begin(), final_states.end() }; + reachable_states[n] = {final_states.begin(), final_states.end()}; // Forward. // @@ -652,10 +633,8 @@ TransitionConstraint(const std::vector &vars, // all the possible transitions. for (int time = 0; time + 1 < n; ++time) { for (const std::vector &transition : automaton) { - if (!gtl::ContainsKey(reachable_states[time], transition[0])) - continue; - if (!gtl::ContainsKey(possible_values[time], transition[1])) - continue; + if (!gtl::ContainsKey(reachable_states[time], transition[0])) continue; + if (!gtl::ContainsKey(possible_values[time], transition[1])) continue; reachable_states[time + 1].insert(transition[2]); } } @@ -664,10 +643,8 @@ TransitionConstraint(const std::vector &vars, for (int time = n - 1; time > 0; --time) { std::set new_set; for (const std::vector &transition : automaton) { - if (!gtl::ContainsKey(reachable_states[time], transition[0])) - continue; - if (!gtl::ContainsKey(possible_values[time], transition[1])) - continue; + if (!gtl::ContainsKey(reachable_states[time], transition[0])) continue; + if (!gtl::ContainsKey(possible_values[time], transition[1])) continue; if (!gtl::ContainsKey(reachable_states[time + 1], transition[2])) continue; new_set.insert(transition[0]); @@ -692,10 +669,8 @@ TransitionConstraint(const std::vector &vars, std::vector transition_values; std::vector out_states; for (const std::vector &transition : automaton) { - if (!gtl::ContainsKey(reachable_states[time], transition[0])) - continue; - if (!gtl::ContainsKey(possible_values[time], transition[1])) - continue; + if (!gtl::ContainsKey(reachable_states[time], transition[0])) continue; + if (!gtl::ContainsKey(possible_values[time], transition[1])) continue; if (!gtl::ContainsKey(reachable_states[time + 1], transition[2])) continue; @@ -726,8 +701,7 @@ TransitionConstraint(const std::vector &vars, if (s.size() > 1) { std::vector values; values.reserve(s.size()); - for (IntegerValue v : s) - values.push_back(v.value()); + for (IntegerValue v : s) values.push_back(v.value()); integer_trail->UpdateInitialDomain(vars[time], Domain::FromValues(values)); model->Add(FullyEncodeVariable(vars[time])); @@ -765,25 +739,19 @@ TransitionConstraint(const std::vector &vars, // because it is already implicitely encoded since we have exactly one // transition value. if (!in_encoding.empty()) { - ProcessOneColumn(tuple_literals, in_states, in_encoding, { - }, - model); + ProcessOneColumn(tuple_literals, in_states, in_encoding, {}, model); } if (!encoding.empty()) { - ProcessOneColumn(tuple_literals, transition_values, encoding, { - }, + ProcessOneColumn(tuple_literals, transition_values, encoding, {}, model); } if (!out_encoding.empty()) { - ProcessOneColumn(tuple_literals, out_states, out_encoding, { - }, - model); + ProcessOneColumn(tuple_literals, out_states, out_encoding, {}, model); } in_encoding = out_encoding; } - } - ; + }; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/table.h b/ortools/sat/table.h index 85073271da..b22c40bb47 100644 --- a/ortools/sat/table.h +++ b/ortools/sat/table.h @@ -60,13 +60,12 @@ std::function LiteralTableConstraint( // // We CHECK that there is only one possible transition for a state/value pair. // See the test for some examples. -std::function - TransitionConstraint(const std::vector &vars, - const std::vector > &automaton, - int64 initial_state, - const std::vector &final_states); +std::function TransitionConstraint( + const std::vector &vars, + const std::vector > &automaton, int64 initial_state, + const std::vector &final_states); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_TABLE_H_ +#endif // OR_TOOLS_SAT_TABLE_H_ diff --git a/ortools/sat/theta_tree.cc b/ortools/sat/theta_tree.cc index 1ba6ed0666..f8d8300a81 100644 --- a/ortools/sat/theta_tree.cc +++ b/ortools/sat/theta_tree.cc @@ -27,13 +27,13 @@ ThetaLambdaTree::ThetaLambdaTree() {} template typename ThetaLambdaTree::TreeNode ThetaLambdaTree::ComposeTreeNodes(TreeNode left, TreeNode right) { - return { std::max(right.envelope, left.envelope + right.sum_of_energy_min), - std::max(right.envelope_opt, - right.sum_of_energy_min + - std::max(left.envelope_opt, - left.envelope + right.max_of_energy_delta)), - left.sum_of_energy_min + right.sum_of_energy_min, - std::max(right.max_of_energy_delta, left.max_of_energy_delta) }; + return {std::max(right.envelope, left.envelope + right.sum_of_energy_min), + std::max(right.envelope_opt, + right.sum_of_energy_min + + std::max(left.envelope_opt, + left.envelope + right.max_of_energy_delta)), + left.sum_of_energy_min + right.sum_of_energy_min, + std::max(right.max_of_energy_delta, left.max_of_energy_delta)}; } template @@ -48,13 +48,9 @@ void ThetaLambdaTree::Reset(int num_events) { num_leaves_ = std::max(2, num_events + (num_events & 1)); const int num_nodes = 2 * num_leaves_; - tree_.assign(num_nodes, TreeNode { - IntegerTypeMinimumValue(), - IntegerTypeMinimumValue(), IntegerType { - 0 - } - , IntegerType { 0 } - }); + tree_.assign(num_nodes, TreeNode{IntegerTypeMinimumValue(), + IntegerTypeMinimumValue(), + IntegerType{0}, IntegerType{0}}); // If num_leaves is not a power or two, the last depth of the tree will not be // full, and the array will look like: @@ -107,8 +103,8 @@ void ThetaLambdaTree::DelayedAddOrUpdateEvent( DCHECK_LE(0, energy_min); DCHECK_LE(energy_min, energy_max); const int node = GetLeafFromEvent(event); - tree_[node] = { initial_envelope + energy_min, initial_envelope + energy_max, - energy_min, energy_max - energy_min }; + tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max, + energy_min, energy_max - energy_min}; } template @@ -119,8 +115,8 @@ void ThetaLambdaTree::AddOrUpdateEvent( DCHECK_LE(0, energy_min); DCHECK_LE(energy_min, energy_max); const int node = GetLeafFromEvent(event); - tree_[node] = { initial_envelope + energy_min, initial_envelope + energy_max, - energy_min, energy_max - energy_min }; + tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max, + energy_min, energy_max - energy_min}; RefreshNode(node); } @@ -130,12 +126,8 @@ void ThetaLambdaTree::AddOrUpdateOptionalEvent( DCHECK(!leaf_nodes_have_delayed_operations_); DCHECK_LE(0, energy_max); const int node = GetLeafFromEvent(event); - tree_[node] = { IntegerTypeMinimumValue(), - initial_envelope_opt + energy_max, IntegerType - { 0 } - , energy_max -} -; + tree_[node] = {IntegerTypeMinimumValue(), + initial_envelope_opt + energy_max, IntegerType{0}, energy_max}; RefreshNode(node); } @@ -147,24 +139,17 @@ void ThetaLambdaTree::DelayedAddOrUpdateOptionalEvent( #endif DCHECK_LE(0, energy_max); const int node = GetLeafFromEvent(event); - tree_[node] = { IntegerTypeMinimumValue(), - initial_envelope_opt + energy_max, IntegerType - { 0 } - , energy_max -} -; + tree_[node] = {IntegerTypeMinimumValue(), + initial_envelope_opt + energy_max, IntegerType{0}, energy_max}; } template void ThetaLambdaTree::RemoveEvent(int event) { DCHECK(!leaf_nodes_have_delayed_operations_); const int node = GetLeafFromEvent(event); - tree_[node] = { IntegerTypeMinimumValue(), - IntegerTypeMinimumValue(), IntegerType - { 0 } - , IntegerType { 0 } -} -; + tree_[node] = {IntegerTypeMinimumValue(), + IntegerTypeMinimumValue(), IntegerType{0}, + IntegerType{0}}; RefreshNode(node); } @@ -174,12 +159,9 @@ void ThetaLambdaTree::DelayedRemoveEvent(int event) { leaf_nodes_have_delayed_operations_ = true; #endif const int node = GetLeafFromEvent(event); - tree_[node] = { IntegerTypeMinimumValue(), - IntegerTypeMinimumValue(), IntegerType - { 0 } - , IntegerType { 0 } -} -; + tree_[node] = {IntegerTypeMinimumValue(), + IntegerTypeMinimumValue(), IntegerType{0}, + IntegerType{0}}; } template @@ -223,8 +205,7 @@ IntegerType ThetaLambdaTree::GetEnvelopeOf(int event) const { IntegerType envelope = tree_[leaf].envelope; for (int node = leaf; node > 1; node >>= 1) { const int right = node | 1; - if (node != right) - envelope += tree_[right].sum_of_energy_min; + if (node != right) envelope += tree_[right].sum_of_energy_min; } return envelope; } @@ -303,7 +284,7 @@ void ThetaLambdaTree::GetLeavesWithOptionalEnvelopeGreaterThan( *available_energy = tree_[*optional_leaf].sum_of_energy_min + tree_[*optional_leaf].max_of_energy_delta - extra; return; - } else { // < tree_[left].envelope_opt + tree_[right].sum_of_energy_min + } else { // < tree_[left].envelope_opt + tree_[right].sum_of_energy_min target_envelope -= tree_[right].sum_of_energy_min; node = left; } @@ -319,5 +300,5 @@ void ThetaLambdaTree::GetLeavesWithOptionalEnvelopeGreaterThan( template class ThetaLambdaTree; template class ThetaLambdaTree; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/theta_tree.h b/ortools/sat/theta_tree.h index bfd9b3503d..ae6a62e3a4 100644 --- a/ortools/sat/theta_tree.h +++ b/ortools/sat/theta_tree.h @@ -94,12 +94,14 @@ template constexpr IntegerType IntegerTypeMinimumValue() { return std::numeric_limits::min(); } -template <> constexpr IntegerValue IntegerTypeMinimumValue() { +template <> +constexpr IntegerValue IntegerTypeMinimumValue() { return kMinIntegerValue; } -template class ThetaLambdaTree { -public: +template +class ThetaLambdaTree { + public: // Builds a reusable tree. Initialization is done with Reset(). ThetaLambdaTree(); @@ -196,7 +198,7 @@ public: return tree_[GetLeafFromEvent(event)].sum_of_energy_min; } -private: + private: struct TreeNode { IntegerType envelope; IntegerType envelope_opt; @@ -245,7 +247,7 @@ private: extern template class ThetaLambdaTree; extern template class ThetaLambdaTree; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_THETA_TREE_H_ +#endif // OR_TOOLS_SAT_THETA_TREE_H_ diff --git a/ortools/sat/timetable.cc b/ortools/sat/timetable.cc index 76d57d8a25..5e9328e423 100644 --- a/ortools/sat/timetable.cc +++ b/ortools/sat/timetable.cc @@ -27,8 +27,11 @@ namespace sat { TimeTablingPerTask::TimeTablingPerTask( const std::vector &demands, AffineExpression capacity, IntegerTrail *integer_trail, SchedulingConstraintHelper *helper) - : num_tasks_(helper->NumTasks()), demands_(demands), capacity_(capacity), - integer_trail_(integer_trail), helper_(helper) { + : num_tasks_(helper->NumTasks()), + demands_(demands), + capacity_(capacity), + integer_trail_(integer_trail), + helper_(helper) { // Each task may create at most two profile rectangles. Such pattern appear if // the profile is shaped like the Hanoi tower. The additional space is for // both extremities and the sentinels. @@ -73,23 +76,20 @@ bool TimeTablingPerTask::Propagate() { while (profile_changed_) { profile_changed_ = false; // This can fail if the profile exceeds the resource capacity. - if (!BuildProfile()) - return false; + if (!BuildProfile()) return false; // Update the minimum start times. - if (!SweepAllTasks(/*is_forward=*/ true)) - return false; + if (!SweepAllTasks(/*is_forward=*/true)) return false; // We reuse the same profile, but reversed, to update the maximum end times. ReverseProfile(); // Update the maximum end times (reversed problem). - if (!SweepAllTasks(/*is_forward=*/ false)) - return false; + if (!SweepAllTasks(/*is_forward=*/false)) return false; } return true; } bool TimeTablingPerTask::BuildProfile() { - helper_->SetTimeDirection(true); // forward + helper_->SetTimeDirection(true); // forward // Update the set of tasks that contribute to the profile. Tasks that were // contributing are still part of the profile so we only need to check the @@ -140,16 +140,14 @@ bool TimeTablingPerTask::BuildProfile() { // Process the starting compulsory parts. while (next_start >= 0 && by_decreasing_start_max[next_start].time == t) { const int task_index = by_decreasing_start_max[next_start].task_index; - if (IsInProfile(task_index)) - current_height += DemandMin(task_index); + if (IsInProfile(task_index)) current_height += DemandMin(task_index); --next_start; } // Process the ending compulsory parts. while (next_end < num_tasks_ && by_end_min[next_end].time == t) { const int task_index = by_end_min[next_end].task_index; - if (IsInProfile(task_index)) - current_height -= DemandMin(task_index); + if (IsInProfile(task_index)) current_height -= DemandMin(task_index); ++next_end; } @@ -176,7 +174,7 @@ bool TimeTablingPerTask::BuildProfile() { } void TimeTablingPerTask::ReverseProfile() { - helper_->SetTimeDirection(false); // backward + helper_->SetTimeDirection(false); // backward // We keep the sentinels inchanged. for (int i = 1; i + 1 < profile_.size(); ++i) { @@ -230,8 +228,7 @@ bool TimeTablingPerTask::SweepAllTasks(bool is_forward) { continue; } - if (!SweepTask(t)) - return false; + if (!SweepTask(t)) return false; } return true; @@ -251,9 +248,10 @@ bool TimeTablingPerTask::SweepTask(int task_id) { DCHECK(std::is_sorted(profile_.begin(), profile_.end())); int rec_id = std::upper_bound(profile_.begin(), profile_.end(), new_start_min, - [&](IntegerValue value, const ProfileRectangle & rect) { - return value < rect.start; - }) - profile_.begin(); + [&](IntegerValue value, const ProfileRectangle &rect) { + return value < rect.start; + }) - + profile_.begin(); --rec_id; // A profile rectangle is in conflict with the task if its height exceeds @@ -276,14 +274,13 @@ bool TimeTablingPerTask::SweepTask(int task_id) { IntegerValue limit = std::min(start_max, new_end_min); for (; profile_[rec_id].start < limit; ++rec_id) { // If the profile rectangle is not conflicting, go to the next rectangle. - if (profile_[rec_id].height <= conflict_height) - continue; + if (profile_[rec_id].height <= conflict_height) continue; conflict_found = true; // Compute the next minimum start and end times of task_id. The variables // are not updated yet. - new_start_min = profile_[rec_id + 1].start; // i.e. profile_[rec_id].end + new_start_min = profile_[rec_id + 1].start; // i.e. profile_[rec_id].end if (start_max < new_start_min) { if (IsInProfile(task_id)) { // Because the task is part of the profile, we cannot push it further. @@ -303,8 +300,7 @@ bool TimeTablingPerTask::SweepTask(int task_id) { } } - if (!conflict_found) - return true; + if (!conflict_found) return true; if (initial_start_min != new_start_min && !UpdateStartingTime(task_id, last_initial_conflict, new_start_min)) { @@ -335,16 +331,16 @@ bool TimeTablingPerTask::UpdateStartingTime(int task_id, IntegerValue left, AddProfileReason(left, right); if (capacity_.var != kNoIntegerVariable) { - helper_->MutableIntegerReason() - ->push_back(integer_trail_->UpperBoundAsLiteral(capacity_.var)); + helper_->MutableIntegerReason()->push_back( + integer_trail_->UpperBoundAsLiteral(capacity_.var)); } // State of the task to be pushed. helper_->AddEndMinReason(task_id, left + 1); helper_->AddSizeMinReason(task_id, IntegerValue(1)); if (demands_[task_id].var != kNoIntegerVariable) { - helper_->MutableIntegerReason() - ->push_back(integer_trail_->LowerBoundAsLiteral(demands_[task_id].var)); + helper_->MutableIntegerReason()->push_back( + integer_trail_->LowerBoundAsLiteral(demands_[task_id].var)); } // Explain the increase of the minimum start and end times. @@ -358,26 +354,23 @@ void TimeTablingPerTask::AddProfileReason(IntegerValue left, // Do not consider the task if it does not overlap for sure (left, right). const IntegerValue start_max = helper_->StartMax(t); - if (right <= start_max) - continue; + if (right <= start_max) continue; const IntegerValue end_min = helper_->EndMin(t); - if (end_min <= left) - continue; + if (end_min <= left) continue; helper_->AddPresenceReason(t); helper_->AddStartMaxReason(t, std::max(left, start_max)); helper_->AddEndMinReason(t, std::min(right, end_min)); if (demands_[t].var != kNoIntegerVariable) { - helper_->MutableIntegerReason() - ->push_back(integer_trail_->LowerBoundAsLiteral(demands_[t].var)); + helper_->MutableIntegerReason()->push_back( + integer_trail_->LowerBoundAsLiteral(demands_[t].var)); } } } bool TimeTablingPerTask::IncreaseCapacity(IntegerValue time, IntegerValue new_min) { - if (new_min <= CapacityMin()) - return true; + if (new_min <= CapacityMin()) return true; helper_->ClearReason(); AddProfileReason(time, time + 1); @@ -385,10 +378,10 @@ bool TimeTablingPerTask::IncreaseCapacity(IntegerValue time, return helper_->ReportConflict(); } - helper_->MutableIntegerReason() - ->push_back(integer_trail_->UpperBoundAsLiteral(capacity_.var)); + helper_->MutableIntegerReason()->push_back( + integer_trail_->UpperBoundAsLiteral(capacity_.var)); return helper_->PushIntegerLiteral(capacity_.GreaterOrEqual(new_min)); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/timetable.h b/ortools/sat/timetable.h index bf2820f157..8e3d8b4b75 100644 --- a/ortools/sat/timetable.h +++ b/ortools/sat/timetable.h @@ -27,7 +27,7 @@ namespace sat { // A strongly quadratic version of Time Tabling filtering. This propagator // is similar to the CumulativeTimeTable propagator of the constraint solver. class TimeTablingPerTask : public PropagatorInterface { -public: + public: TimeTablingPerTask(const std::vector &demands, AffineExpression capacity, IntegerTrail *integer_trail, SchedulingConstraintHelper *helper); @@ -36,7 +36,7 @@ public: void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // The rectangle will be ordered by start, and the end of each rectangle // will be equal to the start of the next one. struct ProfileRectangle { @@ -145,7 +145,7 @@ private: DISALLOW_COPY_AND_ASSIGN(TimeTablingPerTask); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_TIMETABLE_H_ +#endif // OR_TOOLS_SAT_TIMETABLE_H_ diff --git a/ortools/sat/timetable_edgefinding.cc b/ortools/sat/timetable_edgefinding.cc index a6c07931ee..a289adbbc9 100644 --- a/ortools/sat/timetable_edgefinding.cc +++ b/ortools/sat/timetable_edgefinding.cc @@ -30,8 +30,11 @@ namespace sat { TimeTableEdgeFinding::TimeTableEdgeFinding( const std::vector &demands, AffineExpression capacity, SchedulingConstraintHelper *helper, IntegerTrail *integer_trail) - : num_tasks_(helper->NumTasks()), demands_(demands), capacity_(capacity), - helper_(helper), integer_trail_(integer_trail) { + : num_tasks_(helper->NumTasks()), + demands_(demands), + capacity_(capacity), + helper_(helper), + integer_trail_(integer_trail) { // Edge finding structures. mandatory_energy_before_end_max_.resize(num_tasks_); mandatory_energy_before_start_min_.resize(num_tasks_); @@ -55,16 +58,13 @@ bool TimeTableEdgeFinding::Propagate() { const int64 old_timestamp = integer_trail_->num_enqueues(); helper_->SetTimeDirection(true); - if (!TimeTableEdgeFindingPass()) - return false; + if (!TimeTableEdgeFindingPass()) return false; helper_->SetTimeDirection(false); - if (!TimeTableEdgeFindingPass()) - return false; + if (!TimeTableEdgeFindingPass()) return false; // Stop if no propagation. - if (old_timestamp == integer_trail_->num_enqueues()) - break; + if (old_timestamp == integer_trail_->num_enqueues()) break; } return true; } @@ -77,8 +77,7 @@ void TimeTableEdgeFinding::BuildTimeTable() { for (const auto task_time : ::gtl::reversed_view(helper_->TaskByDecreasingStartMax())) { const int t = task_time.task_index; - if (!helper_->IsPresent(t)) - continue; + if (!helper_->IsPresent(t)) continue; if (task_time.time < helper_->EndMin(t)) { scp_.push_back(task_time); } @@ -87,8 +86,7 @@ void TimeTableEdgeFinding::BuildTimeTable() { // Build end of compulsory part events. for (const auto task_time : helper_->TaskByIncreasingEndMin()) { const int t = task_time.task_index; - if (!helper_->IsPresent(t)) - continue; + if (!helper_->IsPresent(t)) continue; if (helper_->StartMax(t) < task_time.time) { ecp_.push_back(task_time); } @@ -108,10 +106,10 @@ void TimeTableEdgeFinding::BuildTimeTable() { // be correct after the first iteration. IntegerValue previous_time = IntegerValue(0); - int index_scp = 0; // index of the next value in scp - int index_ecp = 0; // index of the next value in ecp - int index_smin = 0; // index of the next value in by_start_min_ - int index_emax = num_tasks_ - 1; // index of the next value in by_end_max_ + int index_scp = 0; // index of the next value in scp + int index_ecp = 0; // index of the next value in ecp + int index_smin = 0; // index of the next value in by_start_min_ + int index_emax = num_tasks_ - 1; // index of the next value in by_end_max_ while (index_emax >= 0) { // Next time point. @@ -186,14 +184,11 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { const int end_task = end_task_time.task_index; // TODO(user): consider optional tasks for additional propagation. - if (!helper_->IsPresent(end_task)) - continue; - if (energy_free_[end_task] == 0) - continue; + if (!helper_->IsPresent(end_task)) continue; + if (energy_free_[end_task] == 0) continue; // We only need to consider each time point once. - if (end_task_time.time == previous_end) - continue; + if (end_task_time.time == previous_end) continue; previous_end = end_task_time.time; // Energy of the free parts contained in the interval [begin, end). @@ -210,19 +205,16 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { const int begin_task = begin_task_time.task_index; // TODO(user): consider optional tasks for additional propagation. - if (!helper_->IsPresent(begin_task)) - continue; - if (energy_free_[begin_task] == 0) - continue; + if (!helper_->IsPresent(begin_task)) continue; + if (energy_free_[begin_task] == 0) continue; // The considered time window. Note that we use the "cached" values so // that our mandatory energy before computation is correct. - const IntegerValue begin = begin_task_time.time; // Start min. - const IntegerValue end = end_task_time.time; // End max. + const IntegerValue begin = begin_task_time.time; // Start min. + const IntegerValue end = end_task_time.time; // End max. // Not a valid time window. - if (end <= begin) - continue; + if (end <= begin) continue; // We consider two different cases: either the free part overlaps the // end of the interval (right) or it does not (inside). @@ -253,7 +245,8 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { // the free energy of this task that must be present in the window. const IntegerValue free_energy_in_window = std::max(IntegerValue(0), - size_free_[begin_task] - (end_max - end)) * demand_min; + size_free_[begin_task] - (end_max - end)) * + demand_min; if (extra_energy > extra_energy_required_by_max_task) { max_task = begin_task; @@ -272,8 +265,7 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { // interval are entirely contained in it. // TODO(user): check that we should not fail if the interval is // overloaded, i.e., available_energy < 0. - if (max_task == -1) - continue; + if (max_task == -1) continue; // Compute the amount of energy available to schedule max_task. const IntegerValue interval_energy = CapacityMax() * (end - begin); @@ -284,8 +276,7 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { interval_energy - energy_free_parts - energy_mandatory; // Enough energy to schedule max_task at its minimum start time. - if (extra_energy_required_by_max_task <= available_energy) - continue; + if (extra_energy_required_by_max_task <= available_energy) continue; // Compute the length of the mandatory subpart of max_task that should be // considered as available. @@ -303,8 +294,7 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() { // Push and explain only if the new start is bigger than the current one. if (helper_->StartMin(max_task) < new_start) { - if (!IncreaseStartMin(begin, end, max_task, new_start)) - return false; + if (!IncreaseStartMin(begin, end, max_task, new_start)) return false; } } } @@ -335,14 +325,10 @@ bool TimeTableEdgeFinding::IncreaseStartMin(IntegerValue begin, // Task contributing to the energy in the interval. for (int t = 0; t < num_tasks_; ++t) { - if (t == task_index) - continue; - if (!helper_->IsPresent(t)) - continue; - if (helper_->EndMax(t) <= begin) - continue; - if (helper_->StartMin(t) >= end) - continue; + if (t == task_index) continue; + if (!helper_->IsPresent(t)) continue; + if (helper_->EndMax(t) <= begin) continue; + if (helper_->StartMin(t) >= end) continue; if (demands_[t].var != kNoIntegerVariable) { mutable_reason->push_back( @@ -367,5 +353,5 @@ bool TimeTableEdgeFinding::IncreaseStartMin(IntegerValue begin, return helper_->IncreaseStartMin(task_index, new_start); } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/timetable_edgefinding.h b/ortools/sat/timetable_edgefinding.h index d8de3c8364..f2f3b24f52 100644 --- a/ortools/sat/timetable_edgefinding.h +++ b/ortools/sat/timetable_edgefinding.h @@ -59,7 +59,7 @@ namespace sat { // problem is unfeasible. A task thus cannot be scheduled at its minimum start // time if this would cause an overload in one of the task intervals. class TimeTableEdgeFinding : public PropagatorInterface { -public: + public: TimeTableEdgeFinding(const std::vector &demands, AffineExpression capacity, SchedulingConstraintHelper *helper, @@ -69,7 +69,7 @@ public: void RegisterWith(GenericLiteralWatcher *watcher); -private: + private: // Build the timetable and fills the mandatory_energy_before_start_min_ and // mandatory_energy_before_end_max_. // @@ -123,7 +123,7 @@ private: DISALLOW_COPY_AND_ASSIGN(TimeTableEdgeFinding); }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_TIMETABLE_EDGEFINDING_H_ +#endif // OR_TOOLS_SAT_TIMETABLE_EDGEFINDING_H_ diff --git a/ortools/sat/util.cc b/ortools/sat/util.cc index 11d6f9bf08..90ffa1dcbf 100644 --- a/ortools/sat/util.cc +++ b/ortools/sat/util.cc @@ -24,8 +24,7 @@ namespace sat { int MoveOneUnprocessedLiteralLast(const std::set &processed, int relevant_prefix_size, std::vector *literals) { - if (literals->empty()) - return -1; + if (literals->empty()) return -1; if (!gtl::ContainsKey(processed, literals->back().Index())) { return std::min(relevant_prefix_size, literals->size()); } @@ -47,19 +46,17 @@ int MoveOneUnprocessedLiteralLast(const std::set &processed, ++num_not_processed; target_prefix_size = i; } - if (num_not_processed >= num_processed) - break; + if (num_not_processed >= num_processed) break; } - if (num_not_processed == 0) - return -1; + if (num_not_processed == 0) return -1; target_prefix_size = std::min(target_prefix_size, relevant_prefix_size); - // Once a prefix size has been decided, it is always better to - // enqueue the literal already processed first. + // Once a prefix size has been decided, it is always better to + // enqueue the literal already processed first. std::stable_partition(literals->begin() + target_prefix_size, literals->end(), [&processed](Literal l) { - return gtl::ContainsKey(processed, l.Index()); - }); + return gtl::ContainsKey(processed, l.Index()); + }); return target_prefix_size; } @@ -114,8 +111,7 @@ double Percentile::GetPercentile(double percent) { void CompressTuples(absl::Span domain_sizes, int64 any_value, std::vector > *tuples) { - if (tuples->empty()) - return; + if (tuples->empty()) return; // Remove duplicates if any. gtl::STLSortAndRemoveDuplicates(tuples); @@ -126,23 +122,20 @@ void CompressTuples(absl::Span domain_sizes, int64 any_value, std::vector tuple_minus_var_i(num_vars - 1); for (int i = 0; i < num_vars; ++i) { const int domain_size = domain_sizes[i]; - if (domain_size == 1) - continue; + if (domain_size == 1) continue; absl::flat_hash_map, std::vector > masked_tuples_to_indices; for (int t = 0; t < tuples->size(); ++t) { int out = 0; for (int j = 0; j < num_vars; ++j) { - if (i == j) - continue; + if (i == j) continue; tuple_minus_var_i[out++] = (*tuples)[t][j]; } masked_tuples_to_indices[tuple_minus_var_i].push_back(t); } to_remove.clear(); for (const auto &it : masked_tuples_to_indices) { - if (it.second.size() != domain_size) - continue; + if (it.second.size() != domain_size) continue; (*tuples)[it.second.front()][i] = any_value; to_remove.insert(to_remove.end(), it.second.begin() + 1, it.second.end()); } @@ -154,5 +147,5 @@ void CompressTuples(absl::Span domain_sizes, int64 any_value, } } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/util.h b/ortools/sat/util.h index 89582deabd..590c95cdf1 100644 --- a/ortools/sat/util.h +++ b/ortools/sat/util.h @@ -24,7 +24,7 @@ #if !defined(__PORTABLE_PLATFORM__) #include "google/protobuf/descriptor.h" -#endif // __PORTABLE_PLATFORM__ +#endif // __PORTABLE_PLATFORM__ namespace operations_research { namespace sat { @@ -80,8 +80,9 @@ inline void RandomizeDecisionHeuristic(URBG *random, const google::protobuf::EnumDescriptor *order_d = SatParameters::VariableOrder_descriptor(); parameters->set_preferred_variable_order( - static_cast(order_d->value( - absl::Uniform(*random, 0, order_d->value_count()))->number())); + static_cast( + order_d->value(absl::Uniform(*random, 0, order_d->value_count())) + ->number())); // Random polarity initial value. const google::protobuf::EnumDescriptor *polarity_d = @@ -89,8 +90,8 @@ inline void RandomizeDecisionHeuristic(URBG *random, parameters->set_initial_polarity(static_cast( polarity_d->value(absl::Uniform(*random, 0, polarity_d->value_count())) ->number())); -#endif // __PORTABLE_PLATFORM__ - // Other random parameters. +#endif // __PORTABLE_PLATFORM__ + // Other random parameters. parameters->set_use_phase_saving(absl::Bernoulli(*random, 0.5)); parameters->set_random_polarity_ratio(absl::Bernoulli(*random, 0.5) ? 0.01 : 0.0); @@ -100,7 +101,7 @@ inline void RandomizeDecisionHeuristic(URBG *random, // Manages incremental averages. class IncrementalAverage { -public: + public: // Initializes the average with 'initial_average' and number of records to 0. explicit IncrementalAverage(double initial_average) : average_(initial_average) {} @@ -114,7 +115,7 @@ public: void AddData(double new_record); -private: + private: double average_ = 0.0; int64 num_records_ = 0; }; @@ -124,7 +125,7 @@ private: // + (1 - decaying_factor) * new_record. // where 0 < decaying_factor < 1. class ExponentialMovingAverage { -public: + public: explicit ExponentialMovingAverage(double decaying_factor) : decaying_factor_(decaying_factor) { DCHECK_GE(decaying_factor, 0.0); @@ -139,7 +140,7 @@ public: void AddData(double new_record); -private: + private: double average_ = 0.0; int64 num_records_ = 0; const double decaying_factor_; @@ -154,7 +155,7 @@ private: // the last). And otherwise we do a linear interpolation between the two element // around the asked percentile. class Percentile { -public: + public: explicit Percentile(int record_limit) : record_limit_(record_limit) {} void AddRecord(double record); @@ -165,7 +166,7 @@ public: // Note that this is not fast and runs in O(n log n) for n records. double GetPercentile(double percent); -private: + private: std::deque records_; const int record_limit_; }; @@ -180,7 +181,7 @@ private: void CompressTuples(absl::Span domain_sizes, int64 any_value, std::vector > *tuples); -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_UTIL_H_ +#endif // OR_TOOLS_SAT_UTIL_H_ diff --git a/ortools/sat/zero_half_cuts.cc b/ortools/sat/zero_half_cuts.cc index 04b748228d..e290de423c 100644 --- a/ortools/sat/zero_half_cuts.cc +++ b/ortools/sat/zero_half_cuts.cc @@ -48,8 +48,7 @@ void ZeroHalfCutHelper::ProcessVariables( void ZeroHalfCutHelper::AddBinaryRow(const CombinationOfRows &binary_row) { // No point pushing an all zero row with a zero rhs. - if (binary_row.cols.empty() && !binary_row.rhs_parity) - return; + if (binary_row.cols.empty() && !binary_row.rhs_parity) return; for (const int col : binary_row.cols) { col_to_rows_[col].push_back(rows_.size()); } @@ -60,8 +59,7 @@ void ZeroHalfCutHelper::AddOneConstraint( const glop::RowIndex row, const std::vector > &terms, IntegerValue lb, IntegerValue ub) { - if (terms.size() > kMaxInputConstraintSize) - return; + if (terms.size() > kMaxInputConstraintSize) return; double activity = 0.0; IntegerValue magnitude(0); @@ -73,8 +71,7 @@ void ZeroHalfCutHelper::AddOneConstraint( magnitude = std::max(magnitude, IntTypeAbs(term.second)); // Only consider odd coefficient. - if ((term.second.value() & 1) == 0) - continue; + if ((term.second.value() & 1) == 0) continue; // Ignore column in the binary matrix if its lp value is almost zero. if (shifted_lp_values_[col] > 1e-2) { @@ -88,8 +85,7 @@ void ZeroHalfCutHelper::AddOneConstraint( // We ignore constraint with large coefficient, since there is little chance // to cancel them and because of that the efficacity of a generated cut will // be limited. - if (magnitude > kMaxInputConstraintMagnitude) - return; + if (magnitude > kMaxInputConstraintMagnitude) return; // TODO(user): experiment with the best value. probably only tight rows are // best? and we could use the basis status rather than recomputing the @@ -99,25 +95,23 @@ void ZeroHalfCutHelper::AddOneConstraint( // that we should also remove duplicate in a generic way. const double tighteness_threshold = 1e-2; if (ToDouble(ub) - activity < tighteness_threshold) { - binary_row.multipliers = { { row, IntegerValue(1) } }; + binary_row.multipliers = {{row, IntegerValue(1)}}; binary_row.slack = ToDouble(ub) - activity; binary_row.rhs_parity = (ub.value() & 1) ^ rhs_adjust; AddBinaryRow(binary_row); } if (activity - ToDouble(lb) < tighteness_threshold) { - binary_row.multipliers = { { row, IntegerValue(-1) } }; + binary_row.multipliers = {{row, IntegerValue(-1)}}; binary_row.slack = activity - ToDouble(lb); binary_row.rhs_parity = (lb.value() & 1) ^ rhs_adjust; AddBinaryRow(binary_row); } } -void -ZeroHalfCutHelper::SymmetricDifference(std::function extra_condition, - const std::vector &a, - std::vector *b) { - for (const int v : *b) - tmp_marked_[v] = true; +void ZeroHalfCutHelper::SymmetricDifference( + std::function extra_condition, const std::vector &a, + std::vector *b) { + for (const int v : *b) tmp_marked_[v] = true; for (const int v : a) { if (tmp_marked_[v]) { tmp_marked_[v] = false; @@ -144,15 +138,13 @@ ZeroHalfCutHelper::SymmetricDifference(std::function extra_condition, void ZeroHalfCutHelper::ProcessSingletonColumns() { for (const int singleton_col : singleton_cols_) { - if (col_to_rows_[singleton_col].empty()) - continue; + if (col_to_rows_[singleton_col].empty()) continue; CHECK_EQ(col_to_rows_[singleton_col].size(), 1); const int row = col_to_rows_[singleton_col][0]; int new_size = 0; auto &mutable_cols = rows_[row].cols; for (const int col : mutable_cols) { - if (col == singleton_col) - continue; + if (col == singleton_col) continue; mutable_cols[new_size++] = col; } CHECK_LT(new_size, mutable_cols.size()); @@ -171,19 +163,15 @@ void ZeroHalfCutHelper::EliminateVarUsingRow(int eliminated_col, // First update the row representation of the matrix. tmp_marked_.resize(std::max(col_to_rows_.size(), rows_.size())); - DCHECK(std::all_of(tmp_marked_.begin(), tmp_marked_.end(), [](bool b) { - return !b; - })); + DCHECK(std::all_of(tmp_marked_.begin(), tmp_marked_.end(), + [](bool b) { return !b; })); int new_size = 0; for (const int other_row : col_to_rows_[eliminated_col]) { - if (other_row == eliminated_row) - continue; + if (other_row == eliminated_row) continue; col_to_rows_[eliminated_col][new_size++] = other_row; - SymmetricDifference([](int i) { - return true; - }, - rows_[eliminated_row].cols, &rows_[other_row].cols); + SymmetricDifference([](int i) { return true; }, rows_[eliminated_row].cols, + &rows_[other_row].cols); // Update slack & parity. rows_[other_row].rhs_parity ^= rows_[eliminated_row].rhs_parity; @@ -217,15 +205,12 @@ void ZeroHalfCutHelper::EliminateVarUsingRow(int eliminated_col, { int new_size = 0; for (const int other_col : rows_[eliminated_row].cols) { - if (other_col == eliminated_col) - continue; + if (other_col == eliminated_col) continue; const int old_size = col_to_rows_[other_col].size(); rows_[eliminated_row].cols[new_size++] = other_col; - SymmetricDifference([this](int i) { - return rows_[i].slack < kSlackThreshold; - }, - col_to_rows_[eliminated_col], - &col_to_rows_[other_col]); + SymmetricDifference( + [this](int i) { return rows_[i].slack < kSlackThreshold; }, + col_to_rows_[eliminated_col], &col_to_rows_[other_col]); if (old_size != 1 && col_to_rows_[other_col].size() == 1) { singleton_cols_.push_back(other_col); } @@ -245,14 +230,12 @@ ZeroHalfCutHelper::InterestingCandidates(ModelRandomGenerator *random) { // Initialize singleton_cols_. singleton_cols_.clear(); for (int col = 0; col < col_to_rows_.size(); ++col) { - if (col_to_rows_[col].size() == 1) - singleton_cols_.push_back(col); + if (col_to_rows_[col].size() == 1) singleton_cols_.push_back(col); } // Process rows by increasing size, but randomize if same size. std::vector to_process; - for (int row = 0; row < rows_.size(); ++row) - to_process.push_back(row); + for (int row = 0; row < rows_.size(); ++row) to_process.push_back(row); std::shuffle(to_process.begin(), to_process.end(), *random); std::stable_sort(to_process.begin(), to_process.end(), [this](int a, int b) { return rows_[a].cols.size() < rows_[b].cols.size(); @@ -261,12 +244,9 @@ ZeroHalfCutHelper::InterestingCandidates(ModelRandomGenerator *random) { for (const int row : to_process) { ProcessSingletonColumns(); - if (rows_[row].cols.empty()) - continue; - if (rows_[row].slack > 1e-6) - continue; - if (rows_[row].multipliers.size() > kMaxAggregationSize) - continue; + if (rows_[row].cols.empty()) continue; + if (rows_[row].slack > 1e-6) continue; + if (rows_[row].multipliers.size() > kMaxAggregationSize) continue; // Heuristic: eliminate the variable with highest shifted lp value. int eliminated_col = -1; @@ -277,8 +257,7 @@ ZeroHalfCutHelper::InterestingCandidates(ModelRandomGenerator *random) { eliminated_col = col; } } - if (eliminated_col == -1) - continue; + if (eliminated_col == -1) continue; EliminateVarUsingRow(eliminated_col, row); } @@ -294,5 +273,5 @@ ZeroHalfCutHelper::InterestingCandidates(ModelRandomGenerator *random) { return result; } -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research diff --git a/ortools/sat/zero_half_cuts.h b/ortools/sat/zero_half_cuts.h index fd2bb5ca39..d03ca9b7ca 100644 --- a/ortools/sat/zero_half_cuts.h +++ b/ortools/sat/zero_half_cuts.h @@ -36,7 +36,7 @@ namespace sat { // {0, 1/2}-Chvátal-Gomory Cuts", Arie M. C. A. Koster, Adrian Zymolka, Manuel // Kutschka. class ZeroHalfCutHelper { -public: + public: // Public API: ProcessVariables() must be called first and then constraints // can be added one by one. Finally GetZeroHalfInterestingCuts() will return a // set of good candidates. @@ -51,7 +51,7 @@ public: const std::vector > &terms, IntegerValue lb, IntegerValue ub); std::vector > > - InterestingCandidates(ModelRandomGenerator *random); + InterestingCandidates(ModelRandomGenerator *random); // Visible for testing. void Reset(int size); @@ -94,7 +94,7 @@ public: void SymmetricDifference(std::function extra_condition, const std::vector &a, std::vector *b); -private: + private: void ProcessSingletonColumns(); // As we combine rows, when the activity of a combination get too far away @@ -126,7 +126,7 @@ private: std::vector tmp_marked_; }; -} // namespace sat -} // namespace operations_research +} // namespace sat +} // namespace operations_research -#endif // OR_TOOLS_SAT_ZERO_HALF_CUTS_H_ +#endif // OR_TOOLS_SAT_ZERO_HALF_CUTS_H_ diff --git a/ortools/util/adaptative_parameter_value.h b/ortools/util/adaptative_parameter_value.h index 491b804dda..91f7679d31 100644 --- a/ortools/util/adaptative_parameter_value.h +++ b/ortools/util/adaptative_parameter_value.h @@ -35,7 +35,7 @@ namespace operations_research { // formula that converge way faster. It will also be nice to generalize the 0.5 // above to a target probability p. class AdaptiveParameterValue { -public: + public: // Initial value is in [0.0, 1.0], both 0.0 and 1.0 are valid. explicit AdaptiveParameterValue(double initial_value) : value_(initial_value) {} @@ -59,19 +59,17 @@ public: if (num_decreases == num_increases) { num_changes_ += num_decreases + num_increases; } else if (num_decreases < num_increases) { - for (int i = num_decreases; i < num_increases; ++i) - Increase(); + for (int i = num_decreases; i < num_increases; ++i) Increase(); num_changes_ += 2 * num_decreases; } else { - for (int i = num_increases; i < num_decreases; ++i) - Decrease(); + for (int i = num_increases; i < num_decreases; ++i) Decrease(); num_changes_ += 2 * num_increases; } } double value() const { return value_; } -private: + private: // We want to change the parameters more and more slowly. double IncreaseNumChangesAndGetFactor() { ++num_changes_; @@ -82,6 +80,6 @@ private: int64_t num_changes_ = 0; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_ADAPTATIVE_PARAMETER_VALUE_H_ +#endif // OR_TOOLS_UTIL_ADAPTATIVE_PARAMETER_VALUE_H_ diff --git a/ortools/util/affine_relation.h b/ortools/util/affine_relation.h index b2405ee430..4fd68650d9 100644 --- a/ortools/util/affine_relation.h +++ b/ortools/util/affine_relation.h @@ -34,7 +34,7 @@ namespace operations_research { // TODO(user): it might be possible to do something fancier and drop less // relations if all the affine relations are given before hand. class AffineRelation { -public: + public: AffineRelation() : num_relations_(0) {} // Returns the number of relations added to the class and not ignored. @@ -91,8 +91,7 @@ public: // this is called, then x should never be used anymore in any of the non const // calls of this class. void IgnoreFromClassSize(int x) { - if (x >= size_.size()) - return; // never seen here. + if (x >= size_.size()) return; // never seen here. CHECK_NE(size_[x], kSizeForRemovedEntry) << x; const int r = Get(x).representative; if (r != x) { @@ -106,17 +105,15 @@ public: // Returns the size of the class of x. int ClassSize(int x) const { - if (x >= representative_.size()) - return 1; + if (x >= representative_.size()) return 1; return size_[Get(x).representative]; } -private: + private: const int kSizeForRemovedEntry = 0; void IncreaseSizeOfMemberVectors(int new_size) { - if (new_size <= representative_.size()) - return; + if (new_size <= representative_.size()) return; for (int i = representative_.size(); i < new_size; ++i) { representative_.push_back(i); } @@ -181,8 +178,7 @@ inline bool AffineRelation::TryAdd(int x, int y, int64 coeff, int64 offset, CompressPath(y); const int rep_x = representative_[x]; const int rep_y = representative_[y]; - if (rep_x == rep_y) - return false; + if (rep_x == rep_y) return false; // TODO(user): It should be possible to optimize this code block a bit, for // instance depending on the magnitude of new_coeff vs coeff_x, we may already @@ -212,12 +208,11 @@ inline bool AffineRelation::TryAdd(int x, int y, int64 coeff, int64 offset, } inline AffineRelation::Relation AffineRelation::Get(int x) const { - if (x >= representative_.size() || representative_[x] == x) - return { x, 1, 0 }; + if (x >= representative_.size() || representative_[x] == x) return {x, 1, 0}; CompressPath(x); - return { representative_[x], coeff_[x], offset_[x] }; + return {representative_[x], coeff_[x], offset_[x]}; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_AFFINE_RELATION_H_ +#endif // OR_TOOLS_UTIL_AFFINE_RELATION_H_ diff --git a/ortools/util/bitset.cc b/ortools/util/bitset.cc index 82c27ea8e3..0d9b619cac 100644 --- a/ortools/util/bitset.cc +++ b/ortools/util/bitset.cc @@ -23,35 +23,35 @@ namespace operations_research { // ---------- Bit Operations ---------- -#define BIT_COUNT_RANGE(size, zero) \ - uint##size BitCountRange##size(const uint##size * const bits, \ - uint##size start, uint##size end) { \ - if (end - start > absl::GetFlag(FLAGS_bitset_small_bitset_count)) { \ - const int offset_start = BitOffset##size(start); \ - const int pos_start = BitPos##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_end = BitPos##size(end); \ - if (offset_end == offset_start) { \ - return BitCount##size(bits[offset_start] & \ - OneRange##size(pos_start, pos_end)); \ - } else { \ - uint##size bit_count = zero; \ - bit_count += \ - BitCount##size(bits[offset_start] & IntervalUp##size(pos_start)); \ - for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ - bit_count += BitCount##size(bits[offset]); \ - } \ - bit_count += \ - BitCount##size(bits[offset_end] & IntervalDown##size(pos_end)); \ - return bit_count; \ - } \ - } else { \ - uint##size bit_count = zero; \ - for (uint##size i = start; i <= end; ++i) { \ - bit_count += IsBitSet##size(bits, i); \ - } \ - return bit_count; \ - } \ +#define BIT_COUNT_RANGE(size, zero) \ + uint##size BitCountRange##size(const uint##size* const bits, \ + uint##size start, uint##size end) { \ + if (end - start > absl::GetFlag(FLAGS_bitset_small_bitset_count)) { \ + const int offset_start = BitOffset##size(start); \ + const int pos_start = BitPos##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_end = BitPos##size(end); \ + if (offset_end == offset_start) { \ + return BitCount##size(bits[offset_start] & \ + OneRange##size(pos_start, pos_end)); \ + } else { \ + uint##size bit_count = zero; \ + bit_count += \ + BitCount##size(bits[offset_start] & IntervalUp##size(pos_start)); \ + for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ + bit_count += BitCount##size(bits[offset]); \ + } \ + bit_count += \ + BitCount##size(bits[offset_end] & IntervalDown##size(pos_end)); \ + return bit_count; \ + } \ + } else { \ + uint##size bit_count = zero; \ + for (uint##size i = start; i <= end; ++i) { \ + bit_count += IsBitSet##size(bits, i); \ + } \ + return bit_count; \ + } \ } BIT_COUNT_RANGE(64, GG_ULONGLONG(0)) @@ -59,31 +59,31 @@ BIT_COUNT_RANGE(32, 0U) #undef BIT_COUNT_RANGE -#define IS_EMPTY_RANGE(size) \ - bool IsEmptyRange##size(const uint##size * const bits, uint##size start, \ - uint##size end) { \ - const int offset_start = BitOffset##size(start); \ - const int pos_start = BitPos##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_end = BitPos##size(end); \ - if (offset_end == offset_start) { \ - if (bits[offset_start] & OneRange##size(pos_start, pos_end)) { \ - return false; \ - } \ - } else { \ - if (bits[offset_start] & IntervalUp##size(pos_start)) { \ - return false; \ - } \ - for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ - if (bits[offset]) { \ - return false; \ - } \ - } \ - if (bits[offset_end] & IntervalDown##size(pos_end)) { \ - return false; \ - } \ - } \ - return true; \ +#define IS_EMPTY_RANGE(size) \ + bool IsEmptyRange##size(const uint##size* const bits, uint##size start, \ + uint##size end) { \ + const int offset_start = BitOffset##size(start); \ + const int pos_start = BitPos##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_end = BitPos##size(end); \ + if (offset_end == offset_start) { \ + if (bits[offset_start] & OneRange##size(pos_start, pos_end)) { \ + return false; \ + } \ + } else { \ + if (bits[offset_start] & IntervalUp##size(pos_start)) { \ + return false; \ + } \ + for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ + if (bits[offset]) { \ + return false; \ + } \ + } \ + if (bits[offset_end] & IntervalDown##size(pos_end)) { \ + return false; \ + } \ + } \ + return true; \ } IS_EMPTY_RANGE(64) @@ -91,49 +91,49 @@ IS_EMPTY_RANGE(32) #undef IS_EMPTY_RANGE -#define LEAST_SIGNIFCANT_BIT_POSITION(size) \ - int##size LeastSignificantBitPosition##size( \ - const uint##size * const bits, uint##size start, uint##size end) { \ - DCHECK_LE(start, end); \ - if (IsBitSet##size(bits, start)) { \ - return start; \ - } \ - const int offset_start = BitOffset##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_start = BitPos##size(start); \ - if (offset_start == offset_end) { \ - const int pos_end = BitPos##size(end); \ - const uint##size active_range = \ - bits[offset_start] & OneRange##size(pos_start, pos_end); \ - if (active_range) { \ - return BitShift##size(offset_start) + \ - LeastSignificantBitPosition##size(active_range); \ - } \ - return -1; \ - } else { \ - const uint##size start_mask = \ - bits[offset_start] & IntervalUp##size(pos_start); \ - if (start_mask) { \ - return BitShift##size(offset_start) + \ - LeastSignificantBitPosition##size(start_mask); \ - } else { \ - for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ - if (bits[offset]) { \ - return BitShift##size(offset) + \ - LeastSignificantBitPosition##size(bits[offset]); \ - } \ - } \ - const int pos_end = BitPos##size(end); \ - const uint##size active_range = \ - bits[offset_end] & IntervalDown##size(pos_end); \ - if (active_range) { \ - return BitShift##size(offset_end) + \ - LeastSignificantBitPosition##size(active_range); \ - } else { \ - return -1; \ - } \ - } \ - } \ +#define LEAST_SIGNIFCANT_BIT_POSITION(size) \ + int##size LeastSignificantBitPosition##size( \ + const uint##size* const bits, uint##size start, uint##size end) { \ + DCHECK_LE(start, end); \ + if (IsBitSet##size(bits, start)) { \ + return start; \ + } \ + const int offset_start = BitOffset##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_start = BitPos##size(start); \ + if (offset_start == offset_end) { \ + const int pos_end = BitPos##size(end); \ + const uint##size active_range = \ + bits[offset_start] & OneRange##size(pos_start, pos_end); \ + if (active_range) { \ + return BitShift##size(offset_start) + \ + LeastSignificantBitPosition##size(active_range); \ + } \ + return -1; \ + } else { \ + const uint##size start_mask = \ + bits[offset_start] & IntervalUp##size(pos_start); \ + if (start_mask) { \ + return BitShift##size(offset_start) + \ + LeastSignificantBitPosition##size(start_mask); \ + } else { \ + for (int offset = offset_start + 1; offset < offset_end; ++offset) { \ + if (bits[offset]) { \ + return BitShift##size(offset) + \ + LeastSignificantBitPosition##size(bits[offset]); \ + } \ + } \ + const int pos_end = BitPos##size(end); \ + const uint##size active_range = \ + bits[offset_end] & IntervalDown##size(pos_end); \ + if (active_range) { \ + return BitShift##size(offset_end) + \ + LeastSignificantBitPosition##size(active_range); \ + } else { \ + return -1; \ + } \ + } \ + } \ } LEAST_SIGNIFCANT_BIT_POSITION(64) @@ -141,50 +141,50 @@ LEAST_SIGNIFCANT_BIT_POSITION(32) #undef LEAST_SIGNIFCANT_BIT_POSITION -#define MOST_SIGNIFICANT_BIT_POSITION(size) \ - int##size MostSignificantBitPosition##size( \ - const uint##size * const bits, uint##size start, uint##size end) { \ - DCHECK_GE(end, start); \ - if (IsBitSet##size(bits, end)) { \ - return end; \ - } \ - const int offset_start = BitOffset##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_end = BitPos##size(end); \ - if (offset_start == offset_end) { \ - const int pos_start = BitPos##size(start); \ - const uint##size active_range = \ - bits[offset_start] & OneRange##size(pos_start, pos_end); \ - if (active_range) { \ - return BitShift##size(offset_end) + \ - MostSignificantBitPosition##size(active_range); \ - } else { \ - return -1; \ - } \ - } else { \ - const uint##size end_mask = \ - bits[offset_end] & IntervalDown##size(pos_end); \ - if (end_mask) { \ - return BitShift##size(offset_end) + \ - MostSignificantBitPosition##size(end_mask); \ - } else { \ - for (int offset = offset_end - 1; offset > offset_start; --offset) { \ - if (bits[offset]) { \ - return BitShift##size(offset) + \ - MostSignificantBitPosition##size(bits[offset]); \ - } \ - } \ - const int pos_start = BitPos##size(start); \ - const uint##size active_range = \ - bits[offset_start] & IntervalUp##size(pos_start); \ - if (active_range) { \ - return BitShift##size(offset_start) + \ - MostSignificantBitPosition##size(active_range); \ - } else { \ - return -1; \ - } \ - } \ - } \ +#define MOST_SIGNIFICANT_BIT_POSITION(size) \ + int##size MostSignificantBitPosition##size( \ + const uint##size* const bits, uint##size start, uint##size end) { \ + DCHECK_GE(end, start); \ + if (IsBitSet##size(bits, end)) { \ + return end; \ + } \ + const int offset_start = BitOffset##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_end = BitPos##size(end); \ + if (offset_start == offset_end) { \ + const int pos_start = BitPos##size(start); \ + const uint##size active_range = \ + bits[offset_start] & OneRange##size(pos_start, pos_end); \ + if (active_range) { \ + return BitShift##size(offset_end) + \ + MostSignificantBitPosition##size(active_range); \ + } else { \ + return -1; \ + } \ + } else { \ + const uint##size end_mask = \ + bits[offset_end] & IntervalDown##size(pos_end); \ + if (end_mask) { \ + return BitShift##size(offset_end) + \ + MostSignificantBitPosition##size(end_mask); \ + } else { \ + for (int offset = offset_end - 1; offset > offset_start; --offset) { \ + if (bits[offset]) { \ + return BitShift##size(offset) + \ + MostSignificantBitPosition##size(bits[offset]); \ + } \ + } \ + const int pos_start = BitPos##size(start); \ + const uint##size active_range = \ + bits[offset_start] & IntervalUp##size(pos_start); \ + if (active_range) { \ + return BitShift##size(offset_start) + \ + MostSignificantBitPosition##size(active_range); \ + } else { \ + return -1; \ + } \ + } \ + } \ } MOST_SIGNIFICANT_BIT_POSITION(64) @@ -192,30 +192,30 @@ MOST_SIGNIFICANT_BIT_POSITION(32) #undef MOST_SIGNIFICANT_BIT_POSITION -#define UNSAFE_LEAST_SIGNIFICANT_BIT_POSITION(size) \ - int##size UnsafeLeastSignificantBitPosition##size( \ - const uint##size * const bits, uint##size start, uint##size end) { \ - DCHECK_LE(start, end); \ - DCHECK(IsBitSet##size(bits, end)); \ - if (IsBitSet##size(bits, start)) { \ - return start; \ - } \ - const int offset_start = BitOffset##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_start = BitPos##size(start); \ - const uint##size start_mask = \ - bits[offset_start] & IntervalUp##size(pos_start); \ - if (start_mask) { \ - return BitShift##size(offset_start) + \ - LeastSignificantBitPosition##size(start_mask); \ - } \ - for (int offset = offset_start + 1; offset <= offset_end; ++offset) { \ - if (bits[offset]) { \ - return BitShift##size(offset) + \ - LeastSignificantBitPosition##size(bits[offset]); \ - } \ - } \ - return -1; \ +#define UNSAFE_LEAST_SIGNIFICANT_BIT_POSITION(size) \ + int##size UnsafeLeastSignificantBitPosition##size( \ + const uint##size* const bits, uint##size start, uint##size end) { \ + DCHECK_LE(start, end); \ + DCHECK(IsBitSet##size(bits, end)); \ + if (IsBitSet##size(bits, start)) { \ + return start; \ + } \ + const int offset_start = BitOffset##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_start = BitPos##size(start); \ + const uint##size start_mask = \ + bits[offset_start] & IntervalUp##size(pos_start); \ + if (start_mask) { \ + return BitShift##size(offset_start) + \ + LeastSignificantBitPosition##size(start_mask); \ + } \ + for (int offset = offset_start + 1; offset <= offset_end; ++offset) { \ + if (bits[offset]) { \ + return BitShift##size(offset) + \ + LeastSignificantBitPosition##size(bits[offset]); \ + } \ + } \ + return -1; \ } UNSAFE_LEAST_SIGNIFICANT_BIT_POSITION(64) @@ -223,30 +223,30 @@ UNSAFE_LEAST_SIGNIFICANT_BIT_POSITION(32) #undef UNSAFE_LEAST_SIGNIFICANT_BIT_POSITION -#define UNSAFE_MOST_SIGNIFICANT_BIT_POSITION(size) \ - int##size UnsafeMostSignificantBitPosition##size( \ - const uint##size * const bits, uint##size start, uint##size end) { \ - DCHECK_GE(end, start); \ - DCHECK(IsBitSet##size(bits, start)); \ - if (IsBitSet##size(bits, end)) { \ - return end; \ - } \ - const int offset_start = BitOffset##size(start); \ - const int offset_end = BitOffset##size(end); \ - const int pos_end = BitPos##size(end); \ - const uint##size end_mask = \ - bits[offset_end] & IntervalDown##size(pos_end); \ - if (end_mask) { \ - return BitShift##size(offset_end) + \ - MostSignificantBitPosition##size(end_mask); \ - } \ - for (int offset = offset_end - 1; offset >= offset_start; --offset) { \ - if (bits[offset]) { \ - return BitShift##size(offset) + \ - MostSignificantBitPosition##size(bits[offset]); \ - } \ - } \ - return -1; \ +#define UNSAFE_MOST_SIGNIFICANT_BIT_POSITION(size) \ + int##size UnsafeMostSignificantBitPosition##size( \ + const uint##size* const bits, uint##size start, uint##size end) { \ + DCHECK_GE(end, start); \ + DCHECK(IsBitSet##size(bits, start)); \ + if (IsBitSet##size(bits, end)) { \ + return end; \ + } \ + const int offset_start = BitOffset##size(start); \ + const int offset_end = BitOffset##size(end); \ + const int pos_end = BitPos##size(end); \ + const uint##size end_mask = \ + bits[offset_end] & IntervalDown##size(pos_end); \ + if (end_mask) { \ + return BitShift##size(offset_end) + \ + MostSignificantBitPosition##size(end_mask); \ + } \ + for (int offset = offset_end - 1; offset >= offset_start; --offset) { \ + if (bits[offset]) { \ + return BitShift##size(offset) + \ + MostSignificantBitPosition##size(bits[offset]); \ + } \ + } \ + return -1; \ } UNSAFE_MOST_SIGNIFICANT_BIT_POSITION(64) @@ -254,4 +254,4 @@ UNSAFE_MOST_SIGNIFICANT_BIT_POSITION(32) #undef UNSAFE_MOST_SIGNIFICANT_BIT_POSITION -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/bitset.h b/ortools/util/bitset.h index 69ac0cb192..7c254e85d6 100644 --- a/ortools/util/bitset.h +++ b/ortools/util/bitset.h @@ -67,9 +67,9 @@ inline uint32 LeastSignificantBitWord32(uint32 n) { return n & ~(n - 1); } // Discussion around lsb computation: // De Bruijn is almost as fast as the bsr/bsf-instruction-based intrinsics. // Both are always much faster than the Default algorithm. -#define USE_DEBRUIJN true // if true, use de Bruijn bit forward scanner. +#define USE_DEBRUIJN true // if true, use de Bruijn bit forward scanner. #if defined(__GNUC__) || defined(__llvm__) -#define USE_FAST_LEAST_SIGNIFICANT_BIT true // if true, use fast lsb. +#define USE_FAST_LEAST_SIGNIFICANT_BIT true // if true, use fast lsb. #endif #if defined(USE_FAST_LEAST_SIGNIFICANT_BIT) @@ -81,18 +81,17 @@ inline int LeastSignificantBitPosition64Fast(uint64 n) { inline int LeastSignificantBitPosition64DeBruijn(uint64 n) { static const uint64 kSeq = GG_ULONGLONG(0x0218a392dd5fb34f); static const int kTab[64] = { - // initialized by 'kTab[(kSeq << i) >> 58] = i - 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 52, 20, 58, 5, 17, 26, 56, 15, - 38, 29, 40, 10, 49, 53, 31, 21, 34, 59, 42, 63, 6, 12, 18, 24, 27, 51, 57, - 16, 55, 37, 39, 48, 30, 33, 41, 62, 11, 23, 50, 54, 36, 47, 32, 61, 22, 35, - 46, 60, 45, 44, 43, + // initialized by 'kTab[(kSeq << i) >> 58] = i + 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 52, 20, 58, + 5, 17, 26, 56, 15, 38, 29, 40, 10, 49, 53, 31, 21, 34, 59, 42, + 63, 6, 12, 18, 24, 27, 51, 57, 16, 55, 37, 39, 48, 30, 33, 41, + 62, 11, 23, 50, 54, 36, 47, 32, 61, 22, 35, 46, 60, 45, 44, 43, }; return kTab[((n & (~n + 1)) * kSeq) >> 58]; } inline int LeastSignificantBitPosition64Default(uint64 n) { - if (n == 0) - return 0; + if (n == 0) return 0; int pos = 63; if (n & 0x00000000FFFFFFFFLL) { pos -= 32; @@ -143,16 +142,16 @@ inline int LeastSignificantBitPosition32Fast(uint32 n) { #endif inline int LeastSignificantBitPosition32DeBruijn(uint32 n) { - static const uint32 kSeq = 0x077CB531U; // de Bruijn sequence - static const int kTab[32] = { // initialized by 'kTab[(kSeq << i) >> 27] = i - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, - 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + static const uint32 kSeq = 0x077CB531U; // de Bruijn sequence + static const int kTab[32] = {// initialized by 'kTab[(kSeq << i) >> 27] = i + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, + 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, + 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; return kTab[((n & (~n + 1)) * kSeq) >> 27]; } inline int LeastSignificantBitPosition32Default(uint32 n) { - if (n == 0) - return 0; + if (n == 0) return 0; int pos = 31; if (n & 0x0000FFFFL) { pos -= 16; @@ -409,12 +408,14 @@ inline uint64 TwoBitsFromPos64(uint64 pos) { // this by caching the current uint64 bucket in the Iterator and using // LeastSignificantBitPosition64() to iterate over the positions at 1 in this // bucket. -template class Bitset64 { -public: - Bitset64() : size_(), data_(), end_(*this, /*at_end=*/ true) {} +template +class Bitset64 { + public: + Bitset64() : size_(), data_(), end_(*this, /*at_end=*/true) {} explicit Bitset64(IndexType size) : size_(Value(size) > 0 ? size : IndexType(0)), - data_(BitLength64(Value(size_))), end_(*this, /*at_end=*/ true) {} + data_(BitLength64(Value(size_))), + end_(*this, /*at_end=*/true) {} // Returns how many bits this Bitset64 can hold. IndexType size() const { return size_; } @@ -516,13 +517,12 @@ public: template void SetContentFromBitset(const Bitset64 &other) { const int64 min_size = std::min(data_.size(), other.data_.size()); - if (min_size == 0) - return; + if (min_size == 0) return; const uint64 last_common_bucket = data_[min_size - 1]; memcpy(data_.data(), other.data_.data(), min_size * sizeof(uint64)); if (data_.size() >= other.data_.size()) { - const uint64 bitmask = - kAllBitsButLsb64 << BitPos64(other.Value(other.size() - 1)); + const uint64 bitmask = kAllBitsButLsb64 + << BitPos64(other.Value(other.size() - 1)); data_[min_size - 1] &= ~bitmask; data_[min_size - 1] |= (bitmask & last_common_bucket); } @@ -563,7 +563,7 @@ public: // IMPORTANT: Because the iterator "caches" the current uint64 bucket, this // will probably not do what you want if Bitset64 is modified while iterating. class Iterator { - public: + public: explicit Iterator(const Bitset64 &data_) : bitset_(data_), index_(0), base_index_(0), current_(0) { if (bitset_.data_.empty()) { @@ -621,7 +621,7 @@ public: IndexType operator*() const { return IndexType(index_); } void operator++() { Next(); } - private: + private: const Bitset64 &bitset_; int index_; int base_index_; @@ -663,7 +663,7 @@ public: return output; } -private: + private: // Returns the value of the index type. // This function is specialized below to work with IntType and int64. int64 Value(IndexType input) const; @@ -675,14 +675,15 @@ private: // Note that we cannot do the same for begin(). const Iterator end_; - template friend class Bitset64; + template + friend class Bitset64; DISALLOW_COPY_AND_ASSIGN(Bitset64); }; // Specialized version of Bitset64 that allows to query the last bit set more // efficiently. class BitQueue64 { -public: + public: BitQueue64() : size_(), top_(-1), data_() {} explicit BitQueue64(int size) : size_(size), top_(-1), data_(BitLength64(size), 0) {} @@ -741,7 +742,7 @@ public: MostSignificantBitPosition64(bucket)); } -private: + private: int size_; int top_; std::vector data_; @@ -754,21 +755,22 @@ inline int64 Bitset64::Value(IntType input) const { DCHECK_GE(input.value(), 0); return input.value(); } -template <> inline int64 Bitset64::Value(int64 input) const { +template <> +inline int64 Bitset64::Value(int64 input) const { DCHECK_GE(input, 0); return input; } // A simple utility class to set/unset integer in a range [0, size). // This is optimized for sparsity. -template class SparseBitset { -public: +template +class SparseBitset { + public: SparseBitset() {} explicit SparseBitset(IntegerType size) : bitset_(size) {} IntegerType size() const { return bitset_.size(); } void SparseClearAll() { - for (const IntegerType i : to_clear_) - bitset_.ClearBucket(i); + for (const IntegerType i : to_clear_) bitset_.ClearBucket(i); to_clear_.clear(); } void ClearAll() { @@ -822,18 +824,17 @@ public: // instance. This way, after the loop, a client can call this for efficiency. void NotifyAllClear() { if (DEBUG_MODE) { - for (IntegerType index : to_clear_) - CHECK(!bitset_[index]); + for (IntegerType index : to_clear_) CHECK(!bitset_[index]); } to_clear_.clear(); } -private: + private: Bitset64 bitset_; std::vector to_clear_; DISALLOW_COPY_AND_ASSIGN(SparseBitset); }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_BITSET_H_ +#endif // OR_TOOLS_UTIL_BITSET_H_ diff --git a/ortools/util/cached_log.cc b/ortools/util/cached_log.cc index 400b94d16f..9286f8e7af 100644 --- a/ortools/util/cached_log.cc +++ b/ortools/util/cached_log.cc @@ -29,7 +29,7 @@ double FastLog2(int64 input) { return log2(input); #endif } -} // namespace +} // namespace void CachedLog::Init(int size) { CHECK(cache_.empty()); @@ -49,4 +49,4 @@ double CachedLog::Log2(int64 input) const { } } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/cached_log.h b/ortools/util/cached_log.h index a8420c831a..d0dbe2014a 100644 --- a/ortools/util/cached_log.h +++ b/ortools/util/cached_log.h @@ -31,7 +31,7 @@ namespace operations_research { // - Sum of log on an array with callback. class CachedLog { -public: + public: CachedLog(); ~CachedLog(); @@ -41,10 +41,10 @@ public: // Returns the log2 of 'input'. double Log2(int64 input) const; -private: + private: std::vector cache_; DISALLOW_COPY_AND_ASSIGN(CachedLog); }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_CACHED_LOG_H_ +#endif // OR_TOOLS_UTIL_CACHED_LOG_H_ diff --git a/ortools/util/file_util.cc b/ortools/util/file_util.cc index dbbbff9675..dae1eda53c 100644 --- a/ortools/util/file_util.cc +++ b/ortools/util/file_util.cc @@ -85,31 +85,30 @@ bool WriteProtoToFile(absl::string_view filename, std::string output_string; google::protobuf::io::StringOutputStream stream(&output_string); switch (proto_write_format) { - case ProtoWriteFormat::kProtoBinary: - if (!proto.SerializeToZeroCopyStream(&stream)) { - LOG(WARNING) << "Serialize to stream failed."; - return false; - } - file_type_suffix = ".bin"; - break; - case ProtoWriteFormat::kProtoText: - if (!google::protobuf::TextFormat::PrintToString(proto, &output_string)) { - LOG(WARNING) << "Printing to string failed."; - return false; - } - break; + case ProtoWriteFormat::kProtoBinary: + if (!proto.SerializeToZeroCopyStream(&stream)) { + LOG(WARNING) << "Serialize to stream failed."; + return false; + } + file_type_suffix = ".bin"; + break; + case ProtoWriteFormat::kProtoText: + if (!google::protobuf::TextFormat::PrintToString(proto, &output_string)) { + LOG(WARNING) << "Printing to string failed."; + return false; + } + break; } std::string output_filename(filename); - if (append_extension_to_file_name) - output_filename += file_type_suffix; + if (append_extension_to_file_name) output_filename += file_type_suffix; VLOG(1) << "Writing " << output_string.size() << " bytes to " << output_filename; if (!file::SetContents(output_filename, output_string, file::Defaults()) - .ok()) { + .ok()) { LOG(WARNING) << "Writing to file failed."; return false; } return true; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/file_util.h b/ortools/util/file_util.h index 58bdae967b..45a259d042 100644 --- a/ortools/util/file_util.h +++ b/ortools/util/file_util.h @@ -44,9 +44,7 @@ Proto ReadFileToProtoOrDie(absl::string_view filename) { return proto; } -enum class ProtoWriteFormat { - kProtoText, kProtoBinary, kJson -}; +enum class ProtoWriteFormat { kProtoText, kProtoBinary, kJson }; // Writes a proto to a file. Supports the following formats: binary, text, JSON, // all of those optionally gzipped. Returns false on failure. @@ -95,7 +93,7 @@ std::vector ReadNumRecords(absl::string_view filename, return ReadNumRecords(file::OpenOrDie(filename, "r", file::Defaults()), expected_num_records); } -} // namespace internal +} // namespace internal // Reads all records in Proto format in 'file'. Silently does nothing if the // file is empty. Dies if the file doesn't exist or contains something else than @@ -104,14 +102,16 @@ template std::vector ReadAllRecordsOrDie(absl::string_view filename) { return internal::ReadNumRecords(filename, -1); } -template std::vector ReadAllRecordsOrDie(File *file) { +template +std::vector ReadAllRecordsOrDie(File *file) { return internal::ReadNumRecords(file, -1); } // Reads one record from file, which must be in RecordIO binary proto format. // Dies if the file can't be read, doesn't contain exactly one record, or // contains something else than the expected proto in RecordIO format. -template Proto ReadOneRecordOrDie(absl::string_view filename) { +template +Proto ReadOneRecordOrDie(absl::string_view filename) { Proto p; p.Swap(&internal::ReadNumRecords(filename, 1)[0]); return p; @@ -130,6 +130,6 @@ void WriteRecordsOrDie(absl::string_view filename, CHECK(writer.Close()); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_FILE_UTIL_H_ +#endif // OR_TOOLS_UTIL_FILE_UTIL_H_ diff --git a/ortools/util/fp_utils.cc b/ortools/util/fp_utils.cc index 07da1c8719..2130c322d0 100644 --- a/ortools/util/fp_utils.cc +++ b/ortools/util/fp_utils.cc @@ -22,12 +22,9 @@ namespace operations_research { namespace { void ReorderAndCapTerms(double *min, double *max) { - if (*min > *max) - std::swap(*min, *max); - if (*min > 0.0) - *min = 0.0; - if (*max < 0.0) - *max = 0.0; + if (*min > *max) std::swap(*min, *max); + if (*min > 0.0) *min = 0.0; + if (*max < 0.0) *max = 0.0; } template @@ -42,8 +39,7 @@ void ComputeScalingErrors(const std::vector &input, const int size = input.size(); for (int i = 0; i < size; ++i) { const double x = input[i]; - if (x == 0.0) - continue; + if (x == 0.0) continue; const double scaled = x * scaling_factor; if (scaled == 0.0) { @@ -74,8 +70,7 @@ void GetBestScalingOfDoublesToInt64(const std::vector &input, *scaling_factor = 0; // Abort in the "error" state if max_absolute_sum doesn't make sense. - if (max_absolute_sum < 0) - return; + if (max_absolute_sum < 0) return; // Our scaling scaling_factor will be 2^factor_exponent. // @@ -84,7 +79,7 @@ void GetBestScalingOfDoublesToInt64(const std::vector &input, // subsequent int64 -> double -> scaled back to int64 will loose no extra // information. int factor_exponent = 0; - uint64 sum_min = 0; // negated. + uint64 sum_min = 0; // negated. uint64 sum_max = 0; bool recompute_sum = false; bool is_first_value = true; @@ -97,13 +92,11 @@ void GetBestScalingOfDoublesToInt64(const std::vector &input, ReorderAndCapTerms(&min_term, &max_term); // If min_term or max_term is not finite, then abort in the "error" state. - if (!(min_term > -kInfinity && max_term < kInfinity)) - return; + if (!(min_term > -kInfinity && max_term < kInfinity)) return; // A value of zero can just be skipped (and needs to because the code below // doesn't handle it correctly). - if (min_term == 0.0 && max_term == 0.0) - continue; + if (min_term == 0.0 && max_term == 0.0) continue; // Compute the greatest candidate such that // round(fabs(c).2^candidate) <= max_absolute_sum. @@ -161,7 +154,7 @@ void GetBestScalingOfDoublesToInt64(const std::vector &input, *scaling_factor = ldexp(1.0, factor_exponent); } -} // namespace +} // namespace void ComputeScalingErrors(const std::vector &input, const std::vector &lb, @@ -187,17 +180,10 @@ void GetBestScalingOfDoublesToInt64(const std::vector &input, double *scaling_factor, double *max_relative_coeff_error) { double max_scaled_sum_error; - GetBestScalingOfDoublesToInt64(input, { - }, - { - }, - max_absolute_sum, scaling_factor); - ComputeScalingErrors(input, { - }, - { - }, - *scaling_factor, max_relative_coeff_error, - &max_scaled_sum_error); + GetBestScalingOfDoublesToInt64(input, {}, {}, max_absolute_sum, + scaling_factor); + ComputeScalingErrors(input, {}, {}, *scaling_factor, + max_relative_coeff_error, &max_scaled_sum_error); } int64 ComputeGcdOfRoundedDoubles(const std::vector &x, @@ -206,8 +192,7 @@ int64 ComputeGcdOfRoundedDoubles(const std::vector &x, for (int i = 0; i < x.size() && gcd != 1; ++i) { int64 value = std::abs(std::round(x[i] * scaling_factor)); DCHECK_GE(value, 0); - if (value == 0) - continue; + if (value == 0) continue; if (gcd == 0) { gcd = value; continue; @@ -223,4 +208,4 @@ int64 ComputeGcdOfRoundedDoubles(const std::vector &x, return gcd > 0 ? gcd : 1; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/fp_utils.h b/ortools/util/fp_utils.h index 9e8c87aa73..0e2cb8a0bc 100644 --- a/ortools/util/fp_utils.h +++ b/ortools/util/fp_utils.h @@ -23,9 +23,9 @@ #define OR_TOOLS_UTIL_FP_UTILS_H_ #if defined(_MSC_VER) -#pragma fenv_access(on) // NOLINT +#pragma fenv_access(on) // NOLINT #else -#include // NOLINT +#include // NOLINT #endif #ifdef __SSE__ @@ -58,11 +58,11 @@ namespace operations_research { // TODO(user): Make it work on msvc, currently calls to _controlfp crash. class ScopedFloatingPointEnv { -public: + public: ScopedFloatingPointEnv() { #if defined(_MSC_VER) // saved_control_ = _controlfp(0, 0); -#elif(defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) +#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) CHECK_EQ(0, fegetenv(&saved_fenv_)); #endif } @@ -78,7 +78,7 @@ public: void EnableExceptions(int excepts) { #if defined(_MSC_VER) // _controlfp(static_cast(excepts), _MCW_EM); -#elif(defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) && \ +#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) && \ !defined(__ANDROID__) CHECK_EQ(0, fegetenv(&fenv_)); excepts &= FE_ALL_EXCEPT; @@ -86,7 +86,7 @@ public: fenv_.__control &= ~excepts; #elif defined(__FreeBSD__) fenv_.__x87.__control &= ~excepts; -#else // Linux +#else // Linux fenv_.__control_word &= ~excepts; #endif fenv_.__mxcsr &= ~(excepts << 7); @@ -94,10 +94,10 @@ public: #endif } -private: + private: #if defined(_MSC_VER) // unsigned int saved_control_; -#elif(defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) +#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__) fenv_t fenv_; mutable fenv_t saved_fenv_; #endif @@ -151,8 +151,7 @@ bool AreWithinAbsoluteTolerance(FloatType x, FloatType y, // absolute or relative tolerance. template bool IsSmallerWithinTolerance(FloatType x, FloatType y, FloatType tolerance) { - if (IsPositiveOrNegativeInfinity(y)) - return x <= y; + if (IsPositiveOrNegativeInfinity(y)) return x <= y; return x <= y + tolerance * std::max(1.0, std::min(std::abs(x), std::abs(y))); } @@ -161,24 +160,23 @@ bool IsSmallerWithinTolerance(FloatType x, FloatType y, FloatType tolerance) { template inline bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance) { DCHECK_LE(0.0, tolerance); - if (IsPositiveOrNegativeInfinity(x)) - return false; + if (IsPositiveOrNegativeInfinity(x)) return false; return std::abs(x - std::round(x)) <= tolerance; } // Handy alternatives to EXPECT_NEAR(), using relative and absolute tolerance // instead of relative tolerance only, and with a proper support for infinity. // TODO(user): investigate moving this to ortools/base/ or some other place. -#define EXPECT_COMPARABLE(expected, obtained, epsilon) \ - EXPECT_TRUE(operations_research::AreWithinAbsoluteOrRelativeTolerances( \ - expected, obtained, epsilon, epsilon)) \ - << obtained << " != expected value " << expected \ +#define EXPECT_COMPARABLE(expected, obtained, epsilon) \ + EXPECT_TRUE(operations_research::AreWithinAbsoluteOrRelativeTolerances( \ + expected, obtained, epsilon, epsilon)) \ + << obtained << " != expected value " << expected \ << " within epsilon = " << epsilon; -#define EXPECT_NOTCOMPARABLE(expected, obtained, epsilon) \ - EXPECT_FALSE(operations_research::AreWithinAbsoluteOrRelativeTolerances( \ - expected, obtained, epsilon, epsilon)) \ - << obtained << " == expected value " << expected \ +#define EXPECT_NOTCOMPARABLE(expected, obtained, epsilon) \ + EXPECT_FALSE(operations_research::AreWithinAbsoluteOrRelativeTolerances( \ + expected, obtained, epsilon, epsilon)) \ + << obtained << " == expected value " << expected \ << " within epsilon = " << epsilon; // Given an array of doubles, this computes a positive scaling factor such that @@ -245,6 +243,6 @@ inline FloatType Interpolate(FloatType x, FloatType y, FloatType alpha) { return alpha * x + (1 - alpha) * y; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_FP_UTILS_H_ +#endif // OR_TOOLS_UTIL_FP_UTILS_H_ diff --git a/ortools/util/functions_swig_helpers.h b/ortools/util/functions_swig_helpers.h index 208d8378e2..a387e8e612 100644 --- a/ortools/util/functions_swig_helpers.h +++ b/ortools/util/functions_swig_helpers.h @@ -25,70 +25,70 @@ namespace operations_research { namespace swig_util { class LongToLong { -public: + public: virtual ~LongToLong() {} virtual int64 Run(int64) = 0; }; class LongLongToLong { -public: + public: virtual ~LongLongToLong() {} virtual int64 Run(int64, int64) = 0; }; class IntToLong { -public: + public: virtual ~IntToLong() {} virtual int64 Run(int) = 0; }; class IntIntToLong { -public: + public: virtual ~IntIntToLong() {} virtual int64 Run(int, int) = 0; }; class LongLongLongToLong { -public: + public: virtual ~LongLongLongToLong() {} virtual int64 Run(int64, int64, int64) = 0; }; class LongToBoolean { -public: + public: virtual ~LongToBoolean() {} virtual bool Run(int64) = 0; }; class VoidToString { -public: + public: virtual ~VoidToString() {} virtual std::string Run() = 0; }; class VoidToBoolean { -public: + public: virtual ~VoidToBoolean() {} virtual bool Run() = 0; }; class LongLongLongToBoolean { -public: + public: virtual ~LongLongLongToBoolean() {} virtual bool Run(int64 i, int64 j, int64 k) = 0; }; class LongToVoid { -public: + public: virtual ~LongToVoid() {} virtual void Run(int64 i) = 0; }; class VoidToVoid { -public: + public: virtual ~VoidToVoid() {} virtual void Run() = 0; }; -} // namespace swig_util -} // namespace operations_research -#endif // OR_TOOLS_UTIL_FUNCTIONS_SWIG_HELPERS_H_ +} // namespace swig_util +} // namespace operations_research +#endif // OR_TOOLS_UTIL_FUNCTIONS_SWIG_HELPERS_H_ diff --git a/ortools/util/functions_swig_test_helpers.h b/ortools/util/functions_swig_test_helpers.h index 57fc77aa20..4b49dc0a53 100644 --- a/ortools/util/functions_swig_test_helpers.h +++ b/ortools/util/functions_swig_test_helpers.h @@ -29,7 +29,7 @@ namespace operations_research { class FunctionSwigTestHelpers { -public: + public: static std::string NoOpVoidToString(std::function fun) { return fun(); } @@ -52,15 +52,14 @@ public: return fun(x, y); } - static int64 - NoOpInt64TripleToInt64(std::function fun, int64 x, - int64 y, int64 z) { + static int64 NoOpInt64TripleToInt64( + std::function fun, int64 x, int64 y, + int64 z) { return fun(x, y, z); } - static bool - NoOpInt64TripleToBool(std::function fun, int64 x, - int64 y, int64 z) { + static bool NoOpInt64TripleToBool( + std::function fun, int64 x, int64 y, int64 z) { return fun(x, y, z); } @@ -83,16 +82,16 @@ public: }; class DelayedFunctionSwigTestHelpers { -public: + public: explicit DelayedFunctionSwigTestHelpers( std::function fun) : fun_(fun) {} int64 NoOpInt64PairToInt64(int64 x, int64 y) { return fun_(x, y); } -private: + private: const std::function fun_; }; -} // namespace operations_research -#endif // OR_TOOLS_UTIL_FUNCTIONS_SWIG_TEST_HELPERS_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_FUNCTIONS_SWIG_TEST_HELPERS_H_ diff --git a/ortools/util/graph_export.cc b/ortools/util/graph_export.cc index 0cb6792726..d6e40fc754 100644 --- a/ortools/util/graph_export.cc +++ b/ortools/util/graph_export.cc @@ -27,7 +27,7 @@ GraphExporter::~GraphExporter() {} namespace { class GraphSyntax { -public: + public: virtual ~GraphSyntax() {} // Node in the right syntax. @@ -46,12 +46,12 @@ public: }; class DotSyntax : public GraphSyntax { -public: + public: ~DotSyntax() override {} std::string Node(const std::string &name, const std::string &label, - const std::string &shape, const std::string &color) - override { + const std::string &shape, + const std::string &color) override { return absl::StrFormat("%s [shape=%s label=\"%s\" color=%s]\n", name, shape, label, color); } @@ -72,39 +72,42 @@ public: }; class GmlSyntax : public GraphSyntax { -public: + public: ~GmlSyntax() override {} std::string Node(const std::string &name, const std::string &label, - const std::string &shape, const std::string &color) - override { - return absl::StrFormat(" node [\n" - " name \"%s\"\n" - " label \"%s\"\n" - " graphics [\n" - " type \"%s\"\n" - " fill \"%s\"\n" - " ]\n" - " ]\n", - name, label, shape, color); + const std::string &shape, + const std::string &color) override { + return absl::StrFormat( + " node [\n" + " name \"%s\"\n" + " label \"%s\"\n" + " graphics [\n" + " type \"%s\"\n" + " fill \"%s\"\n" + " ]\n" + " ]\n", + name, label, shape, color); } // Adds one link in the generated graph. std::string Link(const std::string &source, const std::string &destination, const std::string &label) override { - return absl::StrFormat(" edge [\n" - " label \"%s\"\n" - " source \"%s\"\n" - " target \"%s\"\n" - " ]\n", - label, source, destination); + return absl::StrFormat( + " edge [\n" + " label \"%s\"\n" + " source \"%s\"\n" + " target \"%s\"\n" + " ]\n", + label, source, destination); } // File header. std::string Header(const std::string &name) override { - return absl::StrFormat("graph [\n" - " name \"%s\"\n", - name); + return absl::StrFormat( + "graph [\n" + " name \"%s\"\n", + name); } // File footer. @@ -114,7 +117,7 @@ public: // Graph exporter that will write to a file with a given format. // Takes ownership of the GraphSyntax parameter. class FileGraphExporter : public GraphExporter { -public: + public: FileGraphExporter(File *const file, GraphSyntax *const syntax) : file_(file), syntax_(syntax) {} @@ -138,7 +141,7 @@ public: void WriteFooter() override { Append(syntax_->Footer()); } -private: + private: void Append(const std::string &str) { file::WriteString(file_, str, file::Defaults()).IgnoreError(); } @@ -146,25 +149,24 @@ private: File *const file_; std::unique_ptr syntax_; }; -} // namespace +} // namespace -GraphExporter * -GraphExporter::MakeFileExporter(File *const file, - GraphExporter::GraphFormat format) { +GraphExporter *GraphExporter::MakeFileExporter( + File *const file, GraphExporter::GraphFormat format) { GraphSyntax *syntax = nullptr; switch (format) { - case GraphExporter::DOT_FORMAT: { - syntax = new DotSyntax(); - break; - } - case GraphExporter::GML_FORMAT: { - syntax = new GmlSyntax(); - break; - } - default: - LOG(FATAL) << "Unknown graph format"; + case GraphExporter::DOT_FORMAT: { + syntax = new DotSyntax(); + break; + } + case GraphExporter::GML_FORMAT: { + syntax = new GmlSyntax(); + break; + } + default: + LOG(FATAL) << "Unknown graph format"; } CHECK(syntax != nullptr); return new FileGraphExporter(file, syntax); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/graph_export.h b/ortools/util/graph_export.h index 92749e777e..499f6ec2f9 100644 --- a/ortools/util/graph_export.h +++ b/ortools/util/graph_export.h @@ -26,7 +26,7 @@ namespace operations_research { // This class will allow the creation of a graph representation. // It supports different formats (see GraphFormat). class GraphExporter { -public: + public: // Supported graph formats. enum GraphFormat { DOT_FORMAT, @@ -55,6 +55,6 @@ public: static GraphExporter *MakeFileExporter(File *const file, GraphExporter::GraphFormat format); }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_GRAPH_EXPORT_H_ +#endif // OR_TOOLS_UTIL_GRAPH_EXPORT_H_ diff --git a/ortools/util/integer_pq.h b/ortools/util/integer_pq.h index 4b11a036b9..6caff56dc2 100644 --- a/ortools/util/integer_pq.h +++ b/ortools/util/integer_pq.h @@ -35,7 +35,7 @@ namespace operations_research { // memory and is in general slightly faster. template > class IntegerPriorityQueue { -public: + public: // Starts with an empty queue and reserve space for n elements. explicit IntegerPriorityQueue(int n = 0, Compare comp = Compare()) : size_(0), less_(comp) { @@ -80,8 +80,7 @@ public: DCHECK(!IsEmpty()); position_[Top().Index()] = 0; const int old_size = size_--; - if (old_size > 1) - SetAndDecreasePriority(1, heap_[old_size]); + if (old_size > 1) SetAndDecreasePriority(1, heap_[old_size]); } // Removes the element with given index from the queue. @@ -91,8 +90,7 @@ public: const int to_replace = position_[index]; position_[index] = 0; const int old_size = size_--; - if (to_replace == old_size) - return; + if (to_replace == old_size) return; const Element element = heap_[old_size]; if (less_(element, heap_[to_replace])) { SetAndDecreasePriority(to_replace, element); @@ -129,7 +127,7 @@ public: // This can be used to get a random element from the queue for instance. Element QueueElement(int i) const { return heap_[1 + i]; } -private: + private: // Puts the given element at heap index i. void Set(int i, Element element) { heap_[i] = element; @@ -145,11 +143,9 @@ private: const int left = i * 2; const int right = left + 1; if (right > size) { - if (left > size) - break; + if (left > size) break; const Element left_element = heap_[left]; - if (!less_(element, left_element)) - break; + if (!less_(element, left_element)) break; Set(i, left_element); i = left; break; @@ -157,13 +153,11 @@ private: const Element left_element = heap_[left]; const Element right_element = heap_[right]; if (less_(left_element, right_element)) { - if (!less_(element, right_element)) - break; + if (!less_(element, right_element)) break; Set(i, right_element); i = right; } else { - if (!less_(element, left_element)) - break; + if (!less_(element, left_element)) break; Set(i, left_element); i = left; } @@ -178,8 +172,7 @@ private: while (i > 1) { const int parent = i >> 1; const Element parent_element = heap_[parent]; - if (!less_(parent_element, element)) - break; + if (!less_(parent_element, element)) break; Set(i, parent_element); i = parent; } @@ -192,6 +185,6 @@ private: std::vector position_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_INTEGER_PQ_H_ +#endif // OR_TOOLS_UTIL_INTEGER_PQ_H_ diff --git a/ortools/util/lazy_mutable_copy.h b/ortools/util/lazy_mutable_copy.h index a5fb435b78..2b7a7724bc 100644 --- a/ortools/util/lazy_mutable_copy.h +++ b/ortools/util/lazy_mutable_copy.h @@ -41,12 +41,13 @@ namespace operations_research { // - copy: points to a mutable copy of the original and owns it. Owning the // copy means that the destructor will delete it, like std::unique_ptr<>. // This is what you get by calling get_mutable(). -template class LazyMutableCopy { -public: +template +class LazyMutableCopy { + public: // You always construct a LazyMutableCopy with a const reference to an object, // which must outlive this class (unless get_mutable() was called). - LazyMutableCopy(const T &obj) // NOLINT(google-explicit-constructor) - : original_ (&obj) {} + LazyMutableCopy(const T &obj) // NOLINT(google-explicit-constructor) + : original_(&obj) {} // You can move a LazyMutableCopy, much like a std::unique_ptr<> or a const*. // We simply rely on the default move constructors being available. @@ -64,11 +65,11 @@ public: // was copied). bool was_copied() const { return copy_ != nullptr; } -private: + private: const T *original_; std::unique_ptr copy_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_LAZY_MUTABLE_COPY_H_ +#endif // OR_TOOLS_UTIL_LAZY_MUTABLE_COPY_H_ diff --git a/ortools/util/monoid_operation_tree.h b/ortools/util/monoid_operation_tree.h index c865bb8e38..af62137dfe 100644 --- a/ortools/util/monoid_operation_tree.h +++ b/ortools/util/monoid_operation_tree.h @@ -52,8 +52,9 @@ namespace operations_research { // result is independent of the order of past numerical issues // * Maintain a product of identically sized square matrices, which is an // example of use with non-commutative operations. -template class MonoidOperationTree { -public: +template +class MonoidOperationTree { + public: // Constructs a MonoidOperationTree able to store 'size' operands. explicit MonoidOperationTree(int size); @@ -75,13 +76,14 @@ public: } // Dive down a branch of the operation tree, and then come back up. - template void DiveInTree(Diver *const diver) const { + template + void DiveInTree(Diver *const diver) const { DiveInTree(0, diver); } std::string DebugString() const; -private: + private: // Computes the index of the first leaf for the given size. static int ComputeLeafOffset(int size); @@ -108,7 +110,8 @@ private: return position - leaf_offset_; } - template void DiveInTree(int position, Diver *diver) const; + template + void DiveInTree(int position, Diver *diver) const; static int father(int pos) { return (pos - 1) >> 1; } static int left(int pos) { return (pos << 1) + 1; } @@ -137,7 +140,8 @@ private: // Implementation // --------------------------------------------------------------------- // -template int MonoidOperationTree::ComputeLeafOffset(int size) { +template +int MonoidOperationTree::ComputeLeafOffset(int size) { int smallest_pow_two_not_less_than_size = 1; while (smallest_pow_two_not_less_than_size < size) { smallest_pow_two_not_less_than_size <<= 1; @@ -151,22 +155,26 @@ int MonoidOperationTree::ComputeNumberOfNodes(int leaf_offset) { DCHECK_EQ(0, (leaf_offset) & (leaf_offset + 1)); const int num_leaves = leaf_offset + 1; const int num_nodes = leaf_offset + num_leaves; - DCHECK_GE(num_nodes, 3); // We need at least the root and its 2 children + DCHECK_GE(num_nodes, 3); // We need at least the root and its 2 children return num_nodes; } template MonoidOperationTree::MonoidOperationTree(int size) - : size_(size), leaf_offset_(ComputeLeafOffset(size)), - num_nodes_(ComputeNumberOfNodes(leaf_offset_)), nodes_(num_nodes_, T()), + : size_(size), + leaf_offset_(ComputeLeafOffset(size)), + num_nodes_(ComputeNumberOfNodes(leaf_offset_)), + nodes_(num_nodes_, T()), result_(&(nodes_[0])) {} -template void MonoidOperationTree::Clear() { +template +void MonoidOperationTree::Clear() { const int size = nodes_.size(); nodes_.assign(size, T()); } -template void MonoidOperationTree::Reset(int argument_index) { +template +void MonoidOperationTree::Reset(int argument_index) { Set(argument_index, T()); } @@ -178,7 +186,8 @@ void MonoidOperationTree::Set(int argument_index, const T &argument) { ComputeAbove(position); } -template void MonoidOperationTree::ComputeAbove(int position) { +template +void MonoidOperationTree::ComputeAbove(int position) { int pos = father(position); while (pos > 0) { Compute(pos); @@ -187,13 +196,15 @@ template void MonoidOperationTree::ComputeAbove(int position) { Compute(0); } -template void MonoidOperationTree::Compute(int position) { +template +void MonoidOperationTree::Compute(int position) { const T &left_child = nodes_[left(position)]; const T &right_child = nodes_[right(position)]; nodes_[position].Compute(left_child, right_child); } -template std::string MonoidOperationTree::DebugString() const { +template +std::string MonoidOperationTree::DebugString() const { std::string out; int layer = 0; for (int i = 0; i < num_nodes_; ++i) { @@ -235,6 +246,6 @@ void MonoidOperationTree::DiveInTree(int position, Diver *diver) const { } } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_MONOID_OPERATION_TREE_H_ +#endif // OR_TOOLS_UTIL_MONOID_OPERATION_TREE_H_ diff --git a/ortools/util/permutation.h b/ortools/util/permutation.h index ec8414a2fc..12a4f79217 100644 --- a/ortools/util/permutation.h +++ b/ortools/util/permutation.h @@ -90,8 +90,9 @@ namespace operations_research { // Abstract base class template defining the interface needed by // PermutationApplier to handle a single cycle of a permutation. -template class PermutationCycleHandler { -public: +template +class PermutationCycleHandler { + public: // Sets the internal temporary storage from the given index in the // underlying container(s). virtual void SetTempFromIndex(IndexType source) = 0; @@ -130,10 +131,10 @@ public: virtual ~PermutationCycleHandler() {} -protected: + protected: PermutationCycleHandler() {} -private: + private: DISALLOW_COPY_AND_ASSIGN(PermutationCycleHandler); }; @@ -144,12 +145,12 @@ private: // replace it by its ones-complement value. template class ArrayIndexCycleHandler : public PermutationCycleHandler { -public: + public: explicit ArrayIndexCycleHandler(DataType *data) : data_(data) {} void SetTempFromIndex(IndexType source) override { temp_ = data_[source]; } - void SetIndexFromIndex(IndexType source, IndexType destination) const - override { + void SetIndexFromIndex(IndexType source, + IndexType destination) const override { data_[destination] = data_[source]; } void SetIndexFromTemp(IndexType destination) const override { @@ -162,7 +163,7 @@ public: return permutation_element >= 0; } -private: + private: // Pointer to the base of the array of data to be permuted. DataType *data_; @@ -175,8 +176,9 @@ private: // Note that this template is not implemented in an especially // performance-sensitive way. In particular, it makes multiple virtual // method calls for each element of the permutation. -template class PermutationApplier { -public: +template +class PermutationApplier { + public: explicit PermutationApplier(PermutationCycleHandler *cycle_handler) : cycle_handler_(cycle_handler) {} @@ -206,10 +208,10 @@ public: } } -private: + private: PermutationCycleHandler *cycle_handler_; DISALLOW_COPY_AND_ASSIGN(PermutationApplier); }; -} // namespace operations_research -#endif // OR_TOOLS_UTIL_PERMUTATION_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_PERMUTATION_H_ diff --git a/ortools/util/piecewise_linear_function.cc b/ortools/util/piecewise_linear_function.cc index 352447a5b5..3ef5df4a9c 100644 --- a/ortools/util/piecewise_linear_function.cc +++ b/ortools/util/piecewise_linear_function.cc @@ -67,13 +67,11 @@ uint64 UnsignedCapAdd(uint64 left, uint64 right) { } uint64 UnsignedCapProd(uint64 left, uint64 right) { - if (right == 0) - return 0; - if (left > kuint64max / right) - return kuint64max; + if (right == 0) return 0; + if (left > kuint64max / right) return kuint64max; return left * right; } -} // namespace +} // namespace PiecewiseSegment::PiecewiseSegment(int64 point_x, int64 point_y, int64 slope, int64 other_point_x) @@ -258,11 +256,11 @@ void PiecewiseSegment::AddConstantToY(int64 constant) { } std::string PiecewiseSegment::DebugString() const { - std::string result = - absl::StrFormat("PiecewiseSegment()", - start_x_, Value(start_x_), end_x_, Value(end_x_), - reference_x_, reference_y_, slope_); + std::string result = absl::StrFormat( + "PiecewiseSegment()", + start_x_, Value(start_x_), end_x_, Value(end_x_), reference_x_, + reference_y_, slope_); return result; } @@ -270,7 +268,9 @@ const int PiecewiseLinearFunction::kNotFound = -1; PiecewiseLinearFunction::PiecewiseLinearFunction( std::vector segments) - : is_modified_(true), is_convex_(false), is_non_decreasing_(false), + : is_modified_(true), + is_convex_(false), + is_non_decreasing_(false), is_non_increasing_(false) { // Sort the segments in ascending order of start. std::sort(segments.begin(), segments.end(), PiecewiseSegment::SortComparator); @@ -304,10 +304,9 @@ PiecewiseLinearFunction *PiecewiseLinearFunction::CreatePiecewiseLinearFunction( return new PiecewiseLinearFunction(std::move(segments)); } -PiecewiseLinearFunction * -PiecewiseLinearFunction::CreateStepFunction(std::vector points_x, - std::vector points_y, - std::vector other_points_x) { +PiecewiseLinearFunction *PiecewiseLinearFunction::CreateStepFunction( + std::vector points_x, std::vector points_y, + std::vector other_points_x) { CHECK_EQ(points_x.size(), points_y.size()); CHECK_EQ(points_x.size(), other_points_x.size()); CHECK_GT(points_x.size(), 0); @@ -321,10 +320,9 @@ PiecewiseLinearFunction::CreateStepFunction(std::vector points_x, return new PiecewiseLinearFunction(std::move(segments)); } -PiecewiseLinearFunction * -PiecewiseLinearFunction::CreateFullDomainFunction(int64 initial_level, - std::vector points_x, - std::vector slopes) { +PiecewiseLinearFunction *PiecewiseLinearFunction::CreateFullDomainFunction( + int64 initial_level, std::vector points_x, + std::vector slopes) { CHECK_EQ(points_x.size(), slopes.size() - 1); CHECK_GT(points_x.size(), 0); @@ -350,33 +348,30 @@ PiecewiseLinearFunction *PiecewiseLinearFunction::CreateOneSegmentFunction( int64 point_x, int64 point_y, int64 slope, int64 other_point_x) { // Visual studio 2013: We cannot inline the vector in the // PiecewiseLinearFunction ctor. - std::vector segments = { PiecewiseSegment( - point_x, point_y, slope, other_point_x) }; - return new PiecewiseLinearFunction(std::move(segments)); -} - -PiecewiseLinearFunction * -PiecewiseLinearFunction::CreateRightRayFunction(int64 point_x, int64 point_y, - int64 slope) { - std::vector segments = { PiecewiseSegment( - point_x, point_y, slope, kint64max) }; - return new PiecewiseLinearFunction(std::move(segments)); -} - -PiecewiseLinearFunction * -PiecewiseLinearFunction::CreateLeftRayFunction(int64 point_x, int64 point_y, - int64 slope) { - std::vector segments = { PiecewiseSegment( - point_x, point_y, slope, kint64min) }; - return new PiecewiseLinearFunction(std::move(segments)); -} - -PiecewiseLinearFunction * -PiecewiseLinearFunction::CreateFixedChargeFunction(int64 slope, int64 value) { std::vector segments = { - PiecewiseSegment(0, 0, 0, kint64min), - PiecewiseSegment(0, value, slope, kint64max) - }; + PiecewiseSegment(point_x, point_y, slope, other_point_x)}; + return new PiecewiseLinearFunction(std::move(segments)); +} + +PiecewiseLinearFunction *PiecewiseLinearFunction::CreateRightRayFunction( + int64 point_x, int64 point_y, int64 slope) { + std::vector segments = { + PiecewiseSegment(point_x, point_y, slope, kint64max)}; + return new PiecewiseLinearFunction(std::move(segments)); +} + +PiecewiseLinearFunction *PiecewiseLinearFunction::CreateLeftRayFunction( + int64 point_x, int64 point_y, int64 slope) { + std::vector segments = { + PiecewiseSegment(point_x, point_y, slope, kint64min)}; + return new PiecewiseLinearFunction(std::move(segments)); +} + +PiecewiseLinearFunction *PiecewiseLinearFunction::CreateFixedChargeFunction( + int64 slope, int64 value) { + std::vector segments = { + PiecewiseSegment(0, 0, 0, kint64min), + PiecewiseSegment(0, value, slope, kint64max)}; CHECK_GE(slope, 0); CHECK_GE(value, 0); return new PiecewiseLinearFunction(std::move(segments)); @@ -385,9 +380,8 @@ PiecewiseLinearFunction::CreateFixedChargeFunction(int64 slope, int64 value) { PiecewiseLinearFunction *PiecewiseLinearFunction::CreateEarlyTardyFunction( int64 reference, int64 earliness_slope, int64 tardiness_slope) { std::vector segments = { - PiecewiseSegment(reference, 0, -earliness_slope, kint64min), - PiecewiseSegment(reference, 0, tardiness_slope, kint64max) - }; + PiecewiseSegment(reference, 0, -earliness_slope, kint64min), + PiecewiseSegment(reference, 0, tardiness_slope, kint64max)}; CHECK_GE(earliness_slope, 0); CHECK_GE(tardiness_slope, 0); return new PiecewiseLinearFunction(std::move(segments)); @@ -398,10 +392,9 @@ PiecewiseLinearFunction::CreateEarlyTardyFunctionWithSlack( int64 early_slack, int64 late_slack, int64 earliness_slope, int64 tardiness_slope) { std::vector segments = { - PiecewiseSegment(early_slack, 0, -earliness_slope, kint64min), - PiecewiseSegment(early_slack, 0, 0, late_slack), - PiecewiseSegment(late_slack, 0, tardiness_slope, kint64max) - }; + PiecewiseSegment(early_slack, 0, -earliness_slope, kint64min), + PiecewiseSegment(early_slack, 0, 0, late_slack), + PiecewiseSegment(late_slack, 0, tardiness_slope, kint64max)}; CHECK_GE(earliness_slope, 0); CHECK_GE(tardiness_slope, 0); @@ -541,11 +534,11 @@ std::pair ComputeXFromY(int64 start_x, int64 start_y, int64 slope, if ((delta_y >= 0 && slope >= 0) || (delta_y <= 0 && slope <= 0)) { const int64 delta_x_down = delta_x; const int64 delta_x_up = delta_y % slope == 0 ? delta_x : delta_x + 1; - return { delta_x_down + start_x, delta_x_up + start_x }; + return {delta_x_down + start_x, delta_x_up + start_x}; } else { const int64 delta_x_down = delta_y % slope == 0 ? delta_x : delta_x - 1; const int64 delta_x_up = -(-delta_y / slope); - return { delta_x_down + start_x, delta_x_up + start_x }; + return {delta_x_down + start_x, delta_x_up + start_x}; } } @@ -555,42 +548,42 @@ std::pair GetRangeInValueRange(int64 start_x, int64 end_x, int64 value_max) { if ((start_y > value_max && end_y > value_max) || (start_y < value_min && end_y < value_min)) { - return { kint64max, kint64min }; + return {kint64max, kint64min}; } - std::pair x_range_max = { kint64max, kint64min }; + std::pair x_range_max = {kint64max, kint64min}; if (start_y <= value_max && end_y <= value_max) { - x_range_max = { start_x, end_x }; + x_range_max = {start_x, end_x}; } else if (start_y <= value_max || end_y <= value_max) { const auto x = start_x == kint64min ? ComputeXFromY(end_x, end_y, slope, value_max) : ComputeXFromY(start_x, start_y, slope, value_max); if (end_y <= value_max) { - x_range_max = { x.second, end_x }; + x_range_max = {x.second, end_x}; } else { - x_range_max = { start_x, x.first }; + x_range_max = {start_x, x.first}; } } - std::pair x_range_min = { kint64max, kint64min }; + std::pair x_range_min = {kint64max, kint64min}; if (start_y >= value_min && end_y >= value_min) { - x_range_min = { start_x, end_x }; + x_range_min = {start_x, end_x}; } else if (start_y >= value_min || end_y >= value_min) { const auto x = start_x == kint64min ? ComputeXFromY(end_x, end_y, slope, value_min) : ComputeXFromY(start_x, start_y, slope, value_min); if (end_y >= value_min) { - x_range_min = { x.second, end_x }; + x_range_min = {x.second, end_x}; } else { - x_range_min = { start_x, x.first }; + x_range_min = {start_x, x.first}; } } if (x_range_min.first > x_range_max.second || x_range_max.first > x_range_min.second) { - return { kint64max, kint64min }; + return {kint64max, kint64min}; } - return { std::max(x_range_min.first, x_range_max.first), - std::min(x_range_min.second, x_range_max.second) }; + return {std::max(x_range_min.first, x_range_max.first), + std::min(x_range_min.second, x_range_max.second)}; } -} // namespace +} // namespace std::pair PiecewiseLinearFunction::GetSmallestRangeInValueRange( int64 range_start, int64 range_end, int64 value_min, @@ -601,7 +594,7 @@ std::pair PiecewiseLinearFunction::GetSmallestRangeInValueRange( int end_segment = -1; if (!FindSegmentIndicesFromRange(range_start, range_end, &start_segment, &end_segment)) { - return { reduced_range_start, reduced_range_end }; + return {reduced_range_start, reduced_range_end}; } for (int i = std::max(0, start_segment); i <= end_segment; ++i) { const auto &segment = segments_[i]; @@ -614,7 +607,7 @@ std::pair PiecewiseLinearFunction::GetSmallestRangeInValueRange( reduced_range_start = std::min(reduced_range_start, range.first); reduced_range_end = std::max(reduced_range_end, range.second); } - return { reduced_range_start, reduced_range_end }; + return {reduced_range_start, reduced_range_end}; } void PiecewiseLinearFunction::AddConstantToX(int64 constant) { @@ -632,22 +625,18 @@ void PiecewiseLinearFunction::AddConstantToY(int64 constant) { } void PiecewiseLinearFunction::Add(const PiecewiseLinearFunction &other) { - Operation(other, [](int64 a, int64 b) { - return CapAdd(a, b); - }); + Operation(other, [](int64 a, int64 b) { return CapAdd(a, b); }); } void PiecewiseLinearFunction::Subtract(const PiecewiseLinearFunction &other) { - Operation(other, [](int64 a, int64 b) { - return CapSub(a, b); - }); + Operation(other, [](int64 a, int64 b) { return CapSub(a, b); }); } std::vector PiecewiseLinearFunction::DecomposeToConvexFunctions() const { CHECK_GE(segments_.size(), 1); if (IsConvex()) { - return { new PiecewiseLinearFunction(segments_) }; + return {new PiecewiseLinearFunction(segments_)}; } std::vector convex_functions; @@ -782,8 +771,7 @@ bool PiecewiseLinearFunction::IsNonDecreasingInternal() const { for (const auto &segment : segments_) { const int64 start_y = segment.start_y(); const int64 end_y = segment.end_y(); - if (end_y < start_y || start_y < value) - return false; + if (end_y < start_y || start_y < value) return false; value = end_y; } return true; @@ -794,11 +782,10 @@ bool PiecewiseLinearFunction::IsNonIncreasingInternal() const { for (const auto &segment : segments_) { const int64 start_y = segment.start_y(); const int64 end_y = segment.end_y(); - if (end_y > start_y || start_y > value) - return false; + if (end_y > start_y || start_y > value) return false; value = end_y; } return true; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/piecewise_linear_function.h b/ortools/util/piecewise_linear_function.h index 57bf9573d3..4c8ec5bde7 100644 --- a/ortools/util/piecewise_linear_function.h +++ b/ortools/util/piecewise_linear_function.h @@ -36,7 +36,7 @@ namespace operations_research { // end point and the slope. // It is defined for x values between start_x and end_x. class PiecewiseSegment { -public: + public: PiecewiseSegment(int64 point_x, int64 point_y, int64 slope, int64 other_point_x); @@ -72,7 +72,7 @@ public: std::string DebugString() const; -private: + private: // Computes the value of the segment at point x, taking care of possible // overflows when the value x follow the x coordinate of the segment's // reference point. @@ -99,7 +99,7 @@ private: // In mathematics, a piecewise linear function is a function composed // of straight-line, non overlapping sections. class PiecewiseLinearFunction { -public: + public: static const int kNotFound; // This API provides a factory for creating different families of Piecewise @@ -124,19 +124,18 @@ public: // Builds a multiple-segment step function with continuous or non continuous // domain. The arguments have the same semantics with the generic builder of // the piecewise linear function. In the step function all the slopes are 0. - static PiecewiseLinearFunction * - CreateStepFunction(std::vector points_x, - std::vector points_y, - std::vector other_points_x); + static PiecewiseLinearFunction *CreateStepFunction( + std::vector points_x, std::vector points_y, + std::vector other_points_x); // Builds a multiple-segment piecewise linear function with domain from // from kint64min to kint64max with n points and n+1 slopes. Each slope // stops at the point with the corresponding index apart from the last one // which stops at kint64max. The first slope stops at the first point at // the level specified. - static PiecewiseLinearFunction * - CreateFullDomainFunction(int64 initial_level, std::vector points_x, - std::vector slopes); + static PiecewiseLinearFunction *CreateFullDomainFunction( + int64 initial_level, std::vector points_x, + std::vector slopes); // Builds a function consisting of one segment. static PiecewiseLinearFunction *CreateOneSegmentFunction(int64 point_x, @@ -168,9 +167,8 @@ public: // reference, the cost increases with the earliness slope and after the // referece, it increases with the tardiness slope. The absolute values of // the slopes are given. - static PiecewiseLinearFunction * - CreateEarlyTardyFunction(int64 reference, int64 earliness_slope, - int64 tardiness_slope); + static PiecewiseLinearFunction *CreateEarlyTardyFunction( + int64 reference, int64 earliness_slope, int64 tardiness_slope); // Builds an earliness-tardiness three-segment piecewise linear cost function // with a slack period around the due date. The early slack is the point @@ -178,10 +176,9 @@ public: // late slack is the point after which the cost increases with the late slope // specified. Between the early and the late slack point, the cost is zero. // The absolute values of the slopes are given. - static PiecewiseLinearFunction * - CreateEarlyTardyFunctionWithSlack(int64 early_slack, int64 late_slack, - int64 earliness_slope, - int64 tardiness_slope); + static PiecewiseLinearFunction *CreateEarlyTardyFunctionWithSlack( + int64 early_slack, int64 late_slack, int64 earliness_slope, + int64 tardiness_slope); // Returns if x is in the domain of the function. bool InDomain(int64 x) const; @@ -247,7 +244,7 @@ public: std::string DebugString() const; -private: + private: // Takes the sequence of segments, sorts them on increasing start and inserts // them in the piecewise linear function. explicit PiecewiseLinearFunction(std::vector segments); @@ -281,5 +278,5 @@ private: bool is_non_decreasing_; bool is_non_increasing_; }; -} // namespace operations_research -#endif // OR_TOOLS_UTIL_PIECEWISE_LINEAR_FUNCTION_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_PIECEWISE_LINEAR_FUNCTION_H_ diff --git a/ortools/util/proto_tools.cc b/ortools/util/proto_tools.cc index d2df960b34..c2a1872cbc 100644 --- a/ortools/util/proto_tools.cc +++ b/ortools/util/proto_tools.cc @@ -53,14 +53,13 @@ void WriteFullProtocolMessage(const google::protobuf::Message &message, } } } -} // namespace +} // namespace -std::string -FullProtocolMessageAsString(const google::protobuf::Message &message, - int indent_level) { +std::string FullProtocolMessageAsString( + const google::protobuf::Message &message, int indent_level) { std::string message_str; WriteFullProtocolMessage(message, indent_level, &message_str); return message_str; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/proto_tools.h b/ortools/util/proto_tools.h index ca02f55c2d..bbadde939a 100644 --- a/ortools/util/proto_tools.h +++ b/ortools/util/proto_tools.h @@ -31,15 +31,14 @@ namespace operations_research { template absl::StatusOr SafeProtoDownCast(google::protobuf::Message *proto); template -absl::StatusOr - SafeProtoConstDownCast(const google::protobuf::Message *proto); +absl::StatusOr SafeProtoConstDownCast( + const google::protobuf::Message *proto); // Prints a proto2 message as a string, it behaves like TextFormat::Print() // but also prints the default values of unset fields which is useful for // printing parameters. -std::string - FullProtocolMessageAsString(const google::protobuf::Message &message, - int indent_level); +std::string FullProtocolMessageAsString( + const google::protobuf::Message &message, int indent_level); // ============================================================================= // Implementation of function templates. @@ -58,8 +57,8 @@ absl::StatusOr SafeProtoDownCast(google::protobuf::Message *proto) { } template -absl::StatusOr -SafeProtoConstDownCast(const google::protobuf::Message *proto) { +absl::StatusOr SafeProtoConstDownCast( + const google::protobuf::Message *proto) { const google::protobuf::Descriptor *expected_descriptor = Proto::default_instance().GetDescriptor(); const google::protobuf::Descriptor *actual_descriptor = @@ -72,5 +71,5 @@ SafeProtoConstDownCast(const google::protobuf::Message *proto) { expected_descriptor->full_name(), actual_descriptor->full_name())); } -} // namespace operations_research -#endif // OR_TOOLS_UTIL_PROTO_TOOLS_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_PROTO_TOOLS_H_ diff --git a/ortools/util/random_engine.h b/ortools/util/random_engine.h index bd8123ad35..edd9e72b6b 100644 --- a/ortools/util/random_engine.h +++ b/ortools/util/random_engine.h @@ -22,6 +22,6 @@ namespace operations_research { using random_engine_t = std::mt19937; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_RANDOM_ENGINE_H_ +#endif // OR_TOOLS_UTIL_RANDOM_ENGINE_H_ diff --git a/ortools/util/range_minimum_query.h b/ortools/util/range_minimum_query.h index f3c2a0cdd9..23f76247fd 100644 --- a/ortools/util/range_minimum_query.h +++ b/ortools/util/range_minimum_query.h @@ -44,7 +44,7 @@ namespace operations_research { template > class RangeMinimumQuery { -public: + public: explicit RangeMinimumQuery(std::vector array); RangeMinimumQuery(std::vector array, Compare cmp); @@ -54,7 +54,7 @@ public: const std::vector &array() const; -private: + private: // cache_[k][i] = min(arr, i, i+2^k). std::vector > cache_; Compare cmp_; @@ -66,7 +66,7 @@ private: // GetMinimumIndexFromRange returns the index for which the minimum is attained. template > class RangeMinimumIndexQuery { -public: + public: explicit RangeMinimumIndexQuery(std::vector array); RangeMinimumIndexQuery(std::vector array, Compare cmp); @@ -77,7 +77,7 @@ public: // Returns the original array. const std::vector &array() const; -private: + private: // Returns a vector with values 0, 1, ... n - 1 for a given n. static std::vector CreateIndexVector(int n); struct IndexComparator { @@ -143,15 +143,12 @@ inline RangeMinimumIndexQuery::RangeMinimumIndexQuery( template RangeMinimumIndexQuery::RangeMinimumIndexQuery(std::vector array, Compare cmp) - : cmp_({ - std::move(array), std::move(cmp) -}), + : cmp_({std::move(array), std::move(cmp)}), rmq_(CreateIndexVector(cmp_.array.size()), cmp_) {} template -inline int -RangeMinimumIndexQuery::GetMinimumIndexFromRange(int from, - int to) const { +inline int RangeMinimumIndexQuery::GetMinimumIndexFromRange( + int from, int to) const { return rmq_.GetMinimumFromRange(from, to); } @@ -172,5 +169,5 @@ template inline const std::vector &RangeMinimumIndexQuery::array() const { return cmp_.array; } -} // namespace operations_research -#endif // OR_TOOLS_UTIL_RANGE_MINIMUM_QUERY_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_RANGE_MINIMUM_QUERY_H_ diff --git a/ortools/util/range_query_function.cc b/ortools/util/range_query_function.cc index 5c69169a55..9f953952f5 100644 --- a/ortools/util/range_query_function.cc +++ b/ortools/util/range_query_function.cc @@ -25,7 +25,7 @@ namespace { // This implementation basically calls the function as many times as needed for // each query. class LinearRangeIntToIntFunction : public RangeIntToIntFunction { -public: + public: explicit LinearRangeIntToIntFunction( std::function base_function) : base_function_(std::move(base_function)) {} @@ -53,23 +53,22 @@ public: } int64 RangeFirstInsideInterval(int64 range_begin, int64 range_end, - int64 interval_begin, int64 interval_end) const - override { + int64 interval_begin, + int64 interval_end) const override { // domain_start_ <= range_begin < range_end <= domain_start_+array().size() DCHECK_LT(range_begin, range_end); DCHECK_LT(interval_begin, interval_end); int64 i = range_begin; for (; i < range_end; ++i) { const int64 value = base_function_(i); - if (interval_begin <= value && value < interval_end) - break; + if (interval_begin <= value && value < interval_end) break; } return i; } int64 RangeLastInsideInterval(int64 range_begin, int64 range_end, - int64 interval_begin, int64 interval_end) const - override { + int64 interval_begin, + int64 interval_end) const override { // domain_start_ <= range_begin < range_end <= domain_start_+array().size() DCHECK_NE(range_begin, kint64max); DCHECK_LT(range_begin, range_end); @@ -77,13 +76,12 @@ public: int64 i = range_end - 1; for (; i >= range_begin; --i) { const int64 value = base_function_(i); - if (interval_begin <= value && value < interval_end) - break; + if (interval_begin <= value && value < interval_end) break; } return i; } -private: + private: std::function base_function_; DISALLOW_COPY_AND_ASSIGN(LinearRangeIntToIntFunction); @@ -104,7 +102,7 @@ std::vector FunctionToVector(const std::function &f, // 1. It caches the values returned by the function. // 2. It creates a data structure for quick answer to range queries. class CachedRangeIntToIntFunction : public RangeIntToIntFunction { -public: + public: CachedRangeIntToIntFunction(const std::function &base_function, int64 domain_start, int64 domain_end) : domain_start_(domain_start), @@ -133,8 +131,8 @@ public: to - domain_start_); } int64 RangeFirstInsideInterval(int64 range_begin, int64 range_end, - int64 interval_begin, int64 interval_end) const - override { + int64 interval_begin, + int64 interval_end) const override { // domain_start_ <= range_begin < range_end <= domain_start_+array().size() DCHECK_LE(domain_start_, range_begin); DCHECK_LT(range_begin, range_end); @@ -143,14 +141,13 @@ public: int64 i = range_begin; for (; i < range_end; ++i) { const int64 value = array()[i - domain_start_]; - if (interval_begin <= value && value < interval_end) - break; + if (interval_begin <= value && value < interval_end) break; } return i; } int64 RangeLastInsideInterval(int64 range_begin, int64 range_end, - int64 interval_begin, int64 interval_end) const - override { + int64 interval_begin, + int64 interval_end) const override { // domain_start_ <= range_begin < range_end <= domain_start_+array().size() DCHECK_LE(domain_start_, range_begin); DCHECK_LT(range_begin, range_end); @@ -159,13 +156,12 @@ public: int64 i = range_end - 1; for (; i >= range_begin; --i) { const int64 value = array()[i - domain_start_]; - if (interval_begin <= value && value < interval_end) - break; + if (interval_begin <= value && value < interval_end) break; } return i; } -private: + private: const std::vector &array() const { return rmq_min_.array(); } const int64 domain_start_; @@ -176,10 +172,11 @@ private: }; class CachedRangeMinMaxIndexFunction : public RangeMinMaxIndexFunction { -public: + public: CachedRangeMinMaxIndexFunction(const std::function &f, int64 domain_start, int64 domain_end) - : domain_start_(domain_start), domain_end_(domain_end), + : domain_start_(domain_start), + domain_end_(domain_end), index_rmq_min_(FunctionToVector(f, domain_start, domain_end)), index_rmq_max_(index_rmq_min_.array()) { CHECK_LT(domain_start, domain_end); @@ -189,18 +186,20 @@ public: DCHECK_LE(domain_start_, from); DCHECK_LT(from, to); DCHECK_LE(to, domain_end_); - return index_rmq_min_.GetMinimumIndexFromRange( - from - domain_start_, to - domain_start_) + domain_start_; + return index_rmq_min_.GetMinimumIndexFromRange(from - domain_start_, + to - domain_start_) + + domain_start_; } inline int64 RangeMaxArgument(int64 from, int64 to) const override { DCHECK_LE(domain_start_, from); DCHECK_LT(from, to); DCHECK_LE(to, domain_end_); - return index_rmq_max_.GetMinimumIndexFromRange( - from - domain_start_, to - domain_start_) + domain_start_; + return index_rmq_max_.GetMinimumIndexFromRange(from - domain_start_, + to - domain_start_) + + domain_start_; } -private: + private: const int64 domain_start_; const int64 domain_end_; const RangeMinimumIndexQuery > index_rmq_min_; @@ -208,21 +207,21 @@ private: DISALLOW_COPY_AND_ASSIGN(CachedRangeMinMaxIndexFunction); }; -} // namespace +} // namespace RangeIntToIntFunction *MakeBareIntToIntFunction(std::function f) { return new LinearRangeIntToIntFunction(std::move(f)); } -RangeIntToIntFunction * -MakeCachedIntToIntFunction(const std::function &f, - int64 domain_start, int64 domain_end) { +RangeIntToIntFunction *MakeCachedIntToIntFunction( + const std::function &f, int64 domain_start, + int64 domain_end) { return new CachedRangeIntToIntFunction(f, domain_start, domain_end); } -RangeMinMaxIndexFunction * -MakeCachedRangeMinMaxIndexFunction(const std::function &f, - int64 domain_start, int64 domain_end) { +RangeMinMaxIndexFunction *MakeCachedRangeMinMaxIndexFunction( + const std::function &f, int64 domain_start, + int64 domain_end) { return new CachedRangeMinMaxIndexFunction(f, domain_start, domain_end); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/range_query_function.h b/ortools/util/range_query_function.h index 2f10afb10b..52184f76b2 100644 --- a/ortools/util/range_query_function.h +++ b/ortools/util/range_query_function.h @@ -26,7 +26,7 @@ namespace operations_research { // RangeIntToIntFunction is an interface to int64->int64 functions supporting // fast answer to range queries about their domain/codomain. class RangeIntToIntFunction { -public: + public: virtual ~RangeIntToIntFunction() = default; // Suppose f is the abstract underlying function. @@ -56,7 +56,7 @@ public: // 2. For domain queries it returns an argument where the minimum/maximum is // attained, rather than the minimum/maximum value. class RangeMinMaxIndexFunction { -public: + public: virtual ~RangeMinMaxIndexFunction() = default; // Suppose f is the abstract underlying function. // Returns an x from [from, to), such that f(x) => f(y) for every y from @@ -73,14 +73,12 @@ RangeIntToIntFunction *MakeBareIntToIntFunction(std::function f); // It is assumed that f is defined over the interval [domain_start, domain_end). // The function scans f once and it is safe to destroy f and its closure after // MakeCachedIntToIntFunction returns. -RangeIntToIntFunction * - MakeCachedIntToIntFunction(const std::function &f, - int64 domain_start, int64 domain_end); +RangeIntToIntFunction *MakeCachedIntToIntFunction( + const std::function &f, int64 domain_start, int64 domain_end); // It is safe to destroy the first argument and its closure after // MakeCachedRangeMinMaxIndexFunction returns. -RangeMinMaxIndexFunction * - MakeCachedRangeMinMaxIndexFunction(const std::function &f, - int64 domain_start, int64 domain_end); -} // namespace operations_research +RangeMinMaxIndexFunction *MakeCachedRangeMinMaxIndexFunction( + const std::function &f, int64 domain_start, int64 domain_end); +} // namespace operations_research -#endif // OR_TOOLS_UTIL_RANGE_QUERY_FUNCTION_H_ +#endif // OR_TOOLS_UTIL_RANGE_QUERY_FUNCTION_H_ diff --git a/ortools/util/rational_approximation.cc b/ortools/util/rational_approximation.cc index 454bbaf321..a629985bc5 100644 --- a/ortools/util/rational_approximation.cc +++ b/ortools/util/rational_approximation.cc @@ -41,8 +41,7 @@ Fraction RationalApproximation(const double x, const double precision) { const int64 new_denominator = term * denominator + previous_denominator; // If there was an overflow, we prefer returning a not-so-good approximation // rather than something that is completely wrong. - if (new_numerator < 0 || new_denominator < 0) - break; + if (new_numerator < 0 || new_denominator < 0) break; previous_numerator = numerator; previous_denominator = denominator; numerator = new_numerator; @@ -56,4 +55,4 @@ Fraction RationalApproximation(const double x, const double precision) { } return Fraction((x < 0) ? -numerator : numerator, denominator); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/rational_approximation.h b/ortools/util/rational_approximation.h index 763ec5fdab..53c19342d7 100644 --- a/ortools/util/rational_approximation.h +++ b/ortools/util/rational_approximation.h @@ -32,5 +32,5 @@ typedef std::pair Fraction; // type parameters. Fraction RationalApproximation(const double x, const double precision); -} // namespace operations_research -#endif // OR_TOOLS_UTIL_RATIONAL_APPROXIMATION_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_RATIONAL_APPROXIMATION_H_ diff --git a/ortools/util/return_macros.h b/ortools/util/return_macros.h index 8da5359fc6..8b7b7f86df 100644 --- a/ortools/util/return_macros.h +++ b/ortools/util/return_macros.h @@ -17,16 +17,16 @@ // Macros to replace CHECK_NOTNULL() so we don't crash in production. // Logs a FATAL message in debug mode, and an ERROR message in production. // It is not perfect, but more robust than crashing right away. -#define RETURN_IF_NULL(x) \ - if (x == nullptr) { \ - LOG(DFATAL) << #x << " == NULL"; \ - return; \ +#define RETURN_IF_NULL(x) \ + if (x == nullptr) { \ + LOG(DFATAL) << #x << " == NULL"; \ + return; \ } -#define RETURN_VALUE_IF_NULL(x, v) \ - if (x == nullptr) { \ - LOG(DFATAL) << #x << " == NULL"; \ - return v; \ +#define RETURN_VALUE_IF_NULL(x, v) \ + if (x == nullptr) { \ + LOG(DFATAL) << #x << " == NULL"; \ + return v; \ } -#endif // OR_TOOLS_UTIL_RETURN_MACROS_H_ +#endif // OR_TOOLS_UTIL_RETURN_MACROS_H_ diff --git a/ortools/util/rev.h b/ortools/util/rev.h index 859d0ae7d5..3ca9483903 100644 --- a/ortools/util/rev.h +++ b/ortools/util/rev.h @@ -27,7 +27,7 @@ namespace operations_research { // Interface for reversible objects used to maintain them in sync with a tree // search organized by decision levels. class ReversibleInterface { -public: + public: ReversibleInterface() {} virtual ~ReversibleInterface() {} @@ -43,8 +43,9 @@ public: // A repository that maintains a set of reversible objects of type T. // This is meant to be used for small types that are efficient to copy, like // all the basic types, std::pair and things like this. -template class RevRepository : public ReversibleInterface { -public: +template +class RevRepository : public ReversibleInterface { + public: RevRepository() : stamp_(0) {} // This works in O(level_diff) on level increase. @@ -58,11 +59,8 @@ public: // for a given level. If a client cannot do that efficiently, it can use the // SaveStateWithStamp() function below. void SaveState(T *object) { - if (end_of_level_.empty()) - return; // Not useful for level zero. - stack_.push_back({ - object, *object - }); + if (end_of_level_.empty()) return; // Not useful for level zero. + stack_.push_back({object, *object}); } // Calls SaveState() if the given stamp is not the same as the current one. @@ -71,15 +69,14 @@ public: // process make sure that only one SaveValue() par level will ever be called, // so it is efficient to call this before each update to the object T. void SaveStateWithStamp(T *object, int64 *stamp) { - if (*stamp == stamp_) - return; + if (*stamp == stamp_) return; *stamp = stamp_; SaveState(object); } -private: + private: int64 stamp_; - std::vector end_of_level_; // In stack_. + std::vector end_of_level_; // In stack_. // TODO(user): If we ever see this in any cpu profile, consider using two // vectors for a better memory packing in case sizeof(T) is not sizeof(T*). @@ -89,7 +86,7 @@ private: // A basic reversible vector implementation. template class RevVector : public ReversibleInterface { -public: + public: const T &operator[](IndexType index) const { return vector_[index]; } // TODO(user): Maybe we could have also used the [] operator, but it is harder @@ -97,10 +94,7 @@ public: // the vector. And I had performance bug because of that. T &MutableRef(IndexType index) { // Save on the stack first. - if (!end_of_level_.empty()) - stack_.push_back({ - index, vector_[index] - }); + if (!end_of_level_.empty()) stack_.push_back({index, vector_[index]}); return vector_[index]; } @@ -117,40 +111,39 @@ public: void SetLevel(int level) final { DCHECK_GE(level, 0); - if (level == Level()) - return; + if (level == Level()) return; if (level < Level()) { const int index = end_of_level_[level]; - end_of_level_.resize(level); // Shrinks. + end_of_level_.resize(level); // Shrinks. for (int i = stack_.size() - 1; i >= index; --i) { vector_[stack_[i].first] = stack_[i].second; } stack_.resize(index); } else { - end_of_level_.resize(level, stack_.size()); // Grows. + end_of_level_.resize(level, stack_.size()); // Grows. } } -private: - std::vector end_of_level_; // In stack_. + private: + std::vector end_of_level_; // In stack_. std::vector > stack_; gtl::ITIVector vector_; }; -template void RevRepository::SetLevel(int level) { +template +void RevRepository::SetLevel(int level) { DCHECK_GE(level, 0); - if (level == Level()) - return; + if (level == Level()) return; ++stamp_; if (level < Level()) { const int index = end_of_level_[level]; - end_of_level_.resize(level); // Shrinks. + end_of_level_.resize(level); // Shrinks. for (int i = stack_.size() - 1; i >= index; --i) { *stack_[i].first = stack_[i].second; } stack_.resize(index); } else { - end_of_level_.resize(level, stack_.size()); // Grows. + end_of_level_.resize(level, stack_.size()); // Grows. } } @@ -158,8 +151,9 @@ template void RevRepository::SetLevel(int level) { // // This works on any class "Map" that supports: begin(), end(), find(), erase(), // insert(), key_type, value_type, mapped_type and const_iterator. -template class RevMap : ReversibleInterface { -public: +template +class RevMap : ReversibleInterface { + public: typedef typename Map::key_type key_type; typedef typename Map::mapped_type mapped_type; typedef typename Map::value_type value_type; @@ -180,7 +174,7 @@ public: } void EraseOrDie(key_type key); - void Set(key_type key, mapped_type value); // Adds or overwrites. + void Set(key_type key, mapped_type value); // Adds or overwrites. // Wrapper to the underlying const map functions. int size() const { return map_.size(); } @@ -189,7 +183,7 @@ public: const_iterator begin() const { return map_.begin(); } const_iterator end() const { return map_.end(); } -private: + private: Map map_; // The operation that needs to be performed to reverse one modification: @@ -208,19 +202,18 @@ private: std::vector first_op_index_of_next_level_; }; -template void RevMap::SetLevel(int level) { +template +void RevMap::SetLevel(int level) { DCHECK_GE(level, 0); if (level < Level()) { const int backtrack_level = first_op_index_of_next_level_[level]; - first_op_index_of_next_level_.resize(level); // Shrinks. + first_op_index_of_next_level_.resize(level); // Shrinks. while (operations_.size() > backtrack_level) { const UndoOperation &to_undo = operations_.back(); if (to_undo.is_deletion) { map_.erase(to_undo.key); } else { - map_.insert({ - to_undo.key, to_undo.value - }).first->second = to_undo.value; + map_.insert({to_undo.key, to_undo.value}).first->second = to_undo.value; } operations_.pop_back(); } @@ -228,36 +221,29 @@ template void RevMap::SetLevel(int level) { } // This is ok even if level == Level(). - first_op_index_of_next_level_.resize(level, operations_.size()); // Grows. + first_op_index_of_next_level_.resize(level, operations_.size()); // Grows. } -template void RevMap::EraseOrDie(key_type key) { +template +void RevMap::EraseOrDie(key_type key) { const auto iter = map_.find(key); - if (iter == map_.end()) - LOG(FATAL) << "key not present: '" << key << "'."; + if (iter == map_.end()) LOG(FATAL) << "key not present: '" << key << "'."; if (Level() > 0) { - operations_.push_back({ - false, key, iter->second - }); + operations_.push_back({false, key, iter->second}); } map_.erase(iter); } -template void RevMap::Set(key_type key, mapped_type value) { - auto insertion_result = map_.insert({ - key, value - }); +template +void RevMap::Set(key_type key, mapped_type value) { + auto insertion_result = map_.insert({key, value}); if (Level() > 0) { if (insertion_result.second) { - // It is an insertion. Undo = delete. - operations_.push_back({ - true, key - }); + // It is an insertion. Undo = delete. + operations_.push_back({true, key}); } else { - // It is a modification. Undo = change back to old value. - operations_.push_back({ - false, key, insertion_result.first->second - }); + // It is a modification. Undo = change back to old value. + operations_.push_back({false, key, insertion_result.first->second}); } } insertion_result.first->second = value; @@ -266,7 +252,7 @@ template void RevMap::Set(key_type key, mapped_type value) { // A basic backtrackable multi map that can only grow (except on backtrack). template class RevGrowingMultiMap : ReversibleInterface { -public: + public: void SetLevel(int level) final; // Adds a new value at the given key. @@ -275,7 +261,7 @@ public: // Returns the list of values for a given key (can be empty). const std::vector &Values(Key key) const; -private: + private: std::vector empty_values_; // TODO(user): use inlined vectors. Another datastructure that may be more @@ -293,7 +279,7 @@ void RevGrowingMultiMap::SetLevel(int level) { DCHECK_GE(level, 0); if (level < first_added_key_of_next_level_.size()) { const int backtrack_level = first_added_key_of_next_level_[level]; - first_added_key_of_next_level_.resize(level); // Shrinks. + first_added_key_of_next_level_.resize(level); // Shrinks. while (added_keys_.size() > backtrack_level) { auto it = map_.find(added_keys_.back()); if (it->second.size() > 1) { @@ -307,15 +293,14 @@ void RevGrowingMultiMap::SetLevel(int level) { } // This is ok even if level == Level(). - first_added_key_of_next_level_.resize(level, added_keys_.size()); // Grows. + first_added_key_of_next_level_.resize(level, added_keys_.size()); // Grows. } template -const std::vector & -RevGrowingMultiMap::Values(Key key) const { +const std::vector &RevGrowingMultiMap::Values( + Key key) const { const auto it = map_.find(key); - if (it != map_.end()) - return it->second; + if (it != map_.end()) return it->second; return empty_values_; } @@ -327,6 +312,6 @@ void RevGrowingMultiMap::Add(Key key, Value value) { map_[key].push_back(value); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_REV_H_ +#endif // OR_TOOLS_UTIL_REV_H_ diff --git a/ortools/util/running_stat.h b/ortools/util/running_stat.h index 2d6d7a6f13..17661904d1 100644 --- a/ortools/util/running_stat.h +++ b/ortools/util/running_stat.h @@ -24,7 +24,7 @@ namespace operations_research { // Simple class to compute the average over a fixed size window of an integer // stream. class RunningAverage { -public: + public: // Initialize the class with the maximum window size. // It must be positive (this is CHECKed). explicit RunningAverage(int window_size = 1); @@ -51,7 +51,7 @@ public: // Clears the current window. void ClearWindow(); -private: + private: int window_size_; int num_adds_; double global_sum_; @@ -63,8 +63,9 @@ private: // Simple class to compute efficiently the maximum over a fixed size window // of a numeric stream. This works in constant average amortized time. -template class RunningMax { -public: +template +class RunningMax { + public: // Takes the size of the running window. The size must be positive. explicit RunningMax(int window_size); @@ -75,7 +76,7 @@ public: // An element must have been added before calling this function. Number GetCurrentMax(); -private: + private: const int window_size_; // Values in the current window. @@ -93,7 +94,9 @@ private: // ################## Implementations below ##################### inline RunningAverage::RunningAverage(int window_size) - : window_size_(window_size), num_adds_(0), global_sum_(0.0), + : window_size_(window_size), + num_adds_(0), + global_sum_(0.0), local_sum_(0.0) { CHECK_GT(window_size_, 0); } @@ -140,7 +143,8 @@ RunningMax::RunningMax(int window_size) DCHECK_GT(window_size, 0); } -template void RunningMax::Add(Number value) { +template +void RunningMax::Add(Number value) { if (values_.size() < window_size_) { // Starting phase until values_ reaches its final size. // Note that last_index_ stays at 0 during this phase. @@ -178,11 +182,12 @@ template void RunningMax::Add(Number value) { } } -template Number RunningMax::GetCurrentMax() { +template +Number RunningMax::GetCurrentMax() { DCHECK(!values_.empty()); return values_[max_index_]; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_RUNNING_STAT_H_ +#endif // OR_TOOLS_UTIL_RUNNING_STAT_H_ diff --git a/ortools/util/saturated_arithmetic.h b/ortools/util/saturated_arithmetic.h index 92417b0d31..9b3b8c88e0 100644 --- a/ortools/util/saturated_arithmetic.h +++ b/ortools/util/saturated_arithmetic.h @@ -88,8 +88,7 @@ bool SafeAddInto(IntegerType a, IntegerType *b) { const int64 x = a.value(); const int64 y = b->value(); const int64 sum = TwosComplementAddition(x, y); - if (AddHadOverflow(x, y, sum)) - return false; + if (AddHadOverflow(x, y, sum)) return false; *b = sum; return true; } @@ -173,7 +172,7 @@ namespace cap_prod_util { inline uint64 uint_abs(int64 n) { return n < 0 ? ~static_cast(n) + 1 : static_cast(n); } -} // namespace cap_prod_util +} // namespace cap_prod_util // The generic algorithm computes a bound on the number of bits necessary to // store the result. For this it uses the position of the most significant bits @@ -190,15 +189,12 @@ inline int64 CapProdGeneric(int64 x, int64 y) { const int msb_sum = MostSignificantBitPosition64(a) + MostSignificantBitPosition64(b); const int kMaxBitIndexInInt64 = 63; - if (msb_sum <= kMaxBitIndexInInt64 - 2) - return x * y; + if (msb_sum <= kMaxBitIndexInInt64 - 2) return x * y; // Catch a == 0 or b == 0 now, as MostSignificantBitPosition64(0) == 0. // TODO(user): avoid this by writing function Log2(a) with Log2(0) == -1. - if (a == 0 || b == 0) - return 0; + if (a == 0 || b == 0) return 0; const int64 cap = CapWithSignOf(x ^ y); - if (msb_sum >= kMaxBitIndexInInt64) - return cap; + if (msb_sum >= kMaxBitIndexInInt64) return cap; // The corner case is when msb_sum == 62, i.e. at least 63 bits will be // needed to store the product. The following product will never overflow // on uint64, since msb_sum == 62. @@ -208,8 +204,7 @@ inline int64 CapProdGeneric(int64 x, int64 y) { // (cap < 0 && u_prod >= static_cast(kint64min)). // These can be optimized as follows (and if the condition is false, it is // safe to compute x * y. - if (u_prod >= static_cast(cap)) - return cap; + if (u_prod >= static_cast(cap)) return cap; const int64 abs_result = absl::bit_cast(u_prod); return cap < 0 ? -abs_result : abs_result; } @@ -246,6 +241,6 @@ inline int64 CapProd(int64 x, int64 y) { return CapProdGeneric(x, y); #endif } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_SATURATED_ARITHMETIC_H_ +#endif // OR_TOOLS_UTIL_SATURATED_ARITHMETIC_H_ diff --git a/ortools/util/sigint.cc b/ortools/util/sigint.cc index 91b99381bf..9303b49555 100644 --- a/ortools/util/sigint.cc +++ b/ortools/util/sigint.cc @@ -20,7 +20,7 @@ namespace operations_research { void SigintHandler::Register(const std::function &f) { - handler_ = [this, f]()->void { + handler_ = [this, f]() -> void { ++num_sigint_calls_; if (num_sigint_calls_ >= 3) { LOG(INFO) << "^C pressed " << num_sigint_calls_ @@ -29,10 +29,8 @@ void SigintHandler::Register(const std::function &f) { } LOG(INFO) << "^C pressed " << num_sigint_calls_ << " times. " << "Interrupting the solver. Press 3 times to force termination."; - if (num_sigint_calls_ == 1) - f(); - } - ; + if (num_sigint_calls_ == 1) f(); + }; signal(SIGINT, &ControlCHandler); } @@ -45,4 +43,4 @@ SigintHandler::~SigintHandler() { signal(SIGINT, SIG_DFL); } thread_local std::function SigintHandler::handler_; -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/sigint.h b/ortools/util/sigint.h index 438cf2e50b..8b5bcc10b1 100644 --- a/ortools/util/sigint.h +++ b/ortools/util/sigint.h @@ -19,7 +19,7 @@ namespace operations_research { class SigintHandler { -public: + public: SigintHandler() {} ~SigintHandler(); @@ -27,13 +27,13 @@ public: // times, kill the program. void Register(const std::function &f); -private: + private: static void ControlCHandler(int s); int num_sigint_calls_ = 0; thread_local static std::function handler_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_SIGINT_H_ +#endif // OR_TOOLS_UTIL_SIGINT_H_ diff --git a/ortools/util/sort.h b/ortools/util/sort.h index 31680f551a..594ceab445 100644 --- a/ortools/util/sort.h +++ b/ortools/util/sort.h @@ -44,12 +44,9 @@ using value_type_t = typename std::iterator_traits::value_type; // in Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne. template > > void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, - Compare comp = Compare { -}, - bool is_stable = false) { + Compare comp = Compare{}, bool is_stable = false) { // Ranges of at most one element are already sorted. - if (std::distance(begin, end) <= 1) - return; + if (std::distance(begin, end) <= 1) return; // Perform a single iteration of bubble-sort to place the smallest unsorted // element to its correct position. @@ -77,8 +74,7 @@ void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, } // Stop if insertion sort was able to sort the range. - if (it == end) - return; + if (it == end) return; if (is_stable) { std::stable_sort(last_sorted, end, comp); @@ -96,11 +92,9 @@ void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, // This algorithm is inspired by the ones recommended in Algorithms, 4th Edition // by Robert Sedgewick and Kevin Wayne. template > > -void InsertionSort(Iterator begin, Iterator end, Compare comp = Compare { -}) { +void InsertionSort(Iterator begin, Iterator end, Compare comp = Compare{}) { // Ranges of at most one element are already sorted. - if (std::distance(begin, end) <= 1) - return; + if (std::distance(begin, end) <= 1) return; // Perform a single iteration of bubble-sort to place the smallest unsorted // element to its correct position. @@ -132,8 +126,7 @@ void InsertionSort(Iterator begin, Iterator end, Compare comp = Compare { // This function performs well if the elements in the range [begin, end) are // almost sorted. template > > -void IncrementalSort(Iterator begin, Iterator end, Compare comp = Compare { -}, +void IncrementalSort(Iterator begin, Iterator end, Compare comp = Compare{}, bool is_stable = false) { const int size = std::distance(begin, end); if (size <= 32) { @@ -143,6 +136,6 @@ void IncrementalSort(Iterator begin, Iterator end, Compare comp = Compare { } } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_SORT_H_ +#endif // OR_TOOLS_UTIL_SORT_H_ diff --git a/ortools/util/sorted_interval_list.cc b/ortools/util/sorted_interval_list.cc index ed4e897e02..6faa2c41a9 100644 --- a/ortools/util/sorted_interval_list.cc +++ b/ortools/util/sorted_interval_list.cc @@ -30,16 +30,14 @@ namespace operations_research { std::string ClosedInterval::DebugString() const { - if (start == end) - return absl::StrFormat("[%d]", start); + if (start == end) return absl::StrFormat("[%d]", start); return absl::StrFormat("[%d,%d]", start, end); } -bool -IntervalsAreSortedAndNonAdjacent(absl::Span intervals) { +bool IntervalsAreSortedAndNonAdjacent( + absl::Span intervals) { for (int i = 1; i < intervals.size(); ++i) { - if (intervals[i - 1].start > intervals[i - 1].end) - return false; + if (intervals[i - 1].start > intervals[i - 1].end) return false; // First test make sure that intervals[i - 1].end + 1 will not overflow. if (intervals[i - 1].end >= intervals[i].start || intervals[i - 1].end + 1 >= intervals[i].start) { @@ -82,7 +80,7 @@ void UnionOfSortedIntervals(absl::InlinedVector *intervals) { DCHECK(IntervalsAreSortedAndNonAdjacent(*intervals)); } -} // namespace +} // namespace // TODO(user): Use MathUtil::CeilOfRatio / FloorOfRatio instead. int64 CeilRatio(int64 value, int64 positive_coeff) { @@ -112,10 +110,7 @@ std::ostream &operator<<(std::ostream &out, const Domain &domain) { return out << IntervalsAsString(domain); } -Domain::Domain(int64 value) - : intervals_({ - { value, value } -}) {} +Domain::Domain(int64 value) : intervals_({{value, value}}) {} // HACK(user): We spare significant time if we use an initializer here, because // InlineVector<1> is able to recognize the fast path or "exactly one element". @@ -130,14 +125,11 @@ inline ClosedInterval UncheckedClosedInterval(int64 s, int64 e) { i.end = e; return i; } -} // namespace +} // namespace Domain::Domain(int64 left, int64 right) - : intervals_({ - UncheckedClosedInterval(left, right) -}) { - if (left > right) - intervals_.clear(); + : intervals_({UncheckedClosedInterval(left, right)}) { + if (left > right) intervals_.clear(); } Domain Domain::AllValues() { return Domain(kint64min, kint64max); } @@ -147,9 +139,7 @@ Domain Domain::FromValues(std::vector values) { Domain result; for (const int64 v : values) { if (result.intervals_.empty() || v > result.intervals_.back().end + 1) { - result.intervals_.push_back({ - v, v - }); + result.intervals_.push_back({v, v}); } else { result.intervals_.back().end = v; } @@ -170,9 +160,7 @@ Domain Domain::FromFlatSpanOfIntervals(absl::Span flat_intervals) { Domain result; result.intervals_.reserve(flat_intervals.size() / 2); for (int i = 0; i < flat_intervals.size(); i += 2) { - result.intervals_.push_back({ - flat_intervals[i], flat_intervals[i + 1] - }); + result.intervals_.push_back({flat_intervals[i], flat_intervals[i + 1]}); } std::sort(result.intervals_.begin(), result.intervals_.end()); UnionOfSortedIntervals(&result.intervals_); @@ -183,19 +171,15 @@ Domain Domain::FromFlatIntervals(const std::vector &flat_intervals) { return FromFlatSpanOfIntervals(absl::MakeSpan(flat_intervals)); } -Domain -Domain::FromVectorIntervals(const std::vector > &intervals) { +Domain Domain::FromVectorIntervals( + const std::vector > &intervals) { Domain result; for (const std::vector &interval : intervals) { if (interval.size() == 1) { - result.intervals_.push_back({ - interval[0], interval[0] - }); + result.intervals_.push_back({interval[0], interval[0]}); } else { DCHECK_EQ(interval.size(), 2); - result.intervals_.push_back({ - interval[0], interval[1] - }); + result.intervals_.push_back({interval[0], interval[1]}); } } std::sort(result.intervals_.begin(), result.intervals_.end()); @@ -240,8 +224,7 @@ bool Domain::Contains(int64 value) const { // value. auto it = std::upper_bound(intervals_.begin(), intervals_.end(), ClosedInterval(value, value)); - if (it == intervals_.begin()) - return false; + if (it == intervals_.begin()) return false; --it; return value <= it->end; } @@ -253,10 +236,8 @@ bool Domain::IsIncludedIn(const Domain &domain) const { // Find the unique interval in others that contains interval if any. for (; i < others.size() && interval.end > others[i].end; ++i) { } - if (i == others.size()) - return false; - if (interval.start < others[i].start) - return false; + if (i == others.size()) return false; + if (interval.start < others[i].start) return false; } return true; } @@ -267,17 +248,12 @@ Domain Domain::Complement() const { result.intervals_.reserve(intervals_.size() + 1); for (const ClosedInterval &interval : intervals_) { if (interval.start != kint64min) { - result.intervals_.push_back({ - next_start, interval.start - 1 - }); + result.intervals_.push_back({next_start, interval.start - 1}); } - if (interval.end == kint64max) - return result; + if (interval.end == kint64max) return result; next_start = interval.end + 1; } - result.intervals_.push_back({ - next_start, kint64max - }); + result.intervals_.push_back({next_start, kint64max}); DCHECK(IntervalsAreSortedAndNonAdjacent(result.intervals_)); return result; } @@ -289,8 +265,7 @@ Domain Domain::Negation() const { } void Domain::NegateInPlace() { - if (intervals_.empty()) - return; + if (intervals_.empty()) return; std::reverse(intervals_.begin(), intervals_.end()); if (intervals_.back().end == kint64min) { // corner-case @@ -313,35 +288,27 @@ Domain Domain::IntersectionWith(const Domain &domain) const { if (a[i].end < b[j].start) { // Empty intersection. We advance past the first interval. ++i; - } else { // a[i].end >= b[j].start + } else { // a[i].end >= b[j].start // Non-empty intersection: push back the intersection of these two, and // advance past the first interval to finish. if (a[i].end <= b[j].end) { - result.intervals_.push_back({ - b[j].start, a[i].end - }); + result.intervals_.push_back({b[j].start, a[i].end}); ++i; - } else { // a[i].end > b[j].end. - result.intervals_.push_back({ - b[j].start, b[j].end - }); + } else { // a[i].end > b[j].end. + result.intervals_.push_back({b[j].start, b[j].end}); ++j; } } - } else { // a[i].start > b[i].start. - // We do the exact same thing as above, but swapping a and b. + } else { // a[i].start > b[i].start. + // We do the exact same thing as above, but swapping a and b. if (b[j].end < a[i].start) { ++j; - } else { // b[j].end >= a[i].start + } else { // b[j].end >= a[i].start if (b[j].end <= a[i].end) { - result.intervals_.push_back({ - a[i].start, b[j].end - }); + result.intervals_.push_back({a[i].start, b[j].end}); ++j; - } else { // a[i].end > b[j].end. - result.intervals_.push_back({ - a[i].start, a[i].end - }); + } else { // a[i].end > b[j].end. + result.intervals_.push_back({a[i].start, a[i].end}); ++i; } } @@ -370,9 +337,8 @@ Domain Domain::AdditionWith(const Domain &domain) const { result.intervals_.reserve(a.size() * b.size()); for (const ClosedInterval &i : a) { for (const ClosedInterval &j : b) { - result.intervals_.push_back({ - CapAdd(i.start, j.start), CapAdd(i.end, j.end) - }); + result.intervals_.push_back( + {CapAdd(i.start, j.start), CapAdd(i.end, j.end)}); } } @@ -393,16 +359,13 @@ Domain Domain::RelaxIfTooComplex() const { } Domain Domain::MultiplicationBy(int64 coeff, bool *exact) const { - if (exact != nullptr) - *exact = true; - if (intervals_.empty() || coeff == 0) - return {}; + if (exact != nullptr) *exact = true; + if (intervals_.empty() || coeff == 0) return {}; const int64 abs_coeff = std::abs(coeff); const int64 size_if_non_trivial = abs_coeff > 1 ? Size() : 0; if (size_if_non_trivial > kDomainComplexityLimit) { - if (exact != nullptr) - *exact = false; + if (exact != nullptr) *exact = false; return ContinuousMultiplicationBy(coeff); } @@ -413,16 +376,13 @@ Domain Domain::MultiplicationBy(int64 coeff, bool *exact) const { for (int v = i.start; v <= i.end; ++v) { // Because abs_coeff > 1, all new values are disjoint. const int64 new_value = CapProd(v, abs_coeff); - result.intervals_.push_back({ - new_value, new_value - }); + result.intervals_.push_back({new_value, new_value}); } } } else { result = *this; } - if (coeff < 0) - result.NegateInPlace(); + if (coeff < 0) result.NegateInPlace(); return result; } @@ -434,8 +394,7 @@ Domain Domain::ContinuousMultiplicationBy(int64 coeff) const { i.end = CapProd(i.end, abs_coeff); } UnionOfSortedIntervals(&result.intervals_); - if (coeff < 0) - result.NegateInPlace(); + if (coeff < 0) result.NegateInPlace(); return result; } @@ -448,12 +407,8 @@ Domain Domain::ContinuousMultiplicationBy(const Domain &domain) const { const int64 b = CapProd(i.end, j.end); const int64 c = CapProd(i.start, j.end); const int64 d = CapProd(i.end, j.start); - new_interval.start = std::min({ - a, b, c, d - }); - new_interval.end = std::max({ - a, b, c, d - }); + new_interval.start = std::min({a, b, c, d}); + new_interval.end = std::max({a, b, c, d}); result.intervals_.push_back(new_interval); } } @@ -471,8 +426,7 @@ Domain Domain::DivisionBy(int64 coeff) const { i.end = i.end / abs_coeff; } UnionOfSortedIntervals(&result.intervals_); - if (coeff < 0) - result.NegateInPlace(); + if (coeff < 0) result.NegateInPlace(); return result; } @@ -486,19 +440,17 @@ Domain Domain::InverseMultiplicationBy(const int64 coeff) const { for (const ClosedInterval &i : result.intervals_) { const int64 start = CeilRatio(i.start, abs_coeff); const int64 end = FloorRatio(i.end, abs_coeff); - if (start > end) - continue; + if (start > end) continue; if (new_size > 0 && start == result.intervals_[new_size - 1].end + 1) { result.intervals_[new_size - 1].end = end; } else { - result.intervals_[new_size++] = { start, end }; + result.intervals_[new_size++] = {start, end}; } } result.intervals_.resize(new_size); result.intervals_.shrink_to_fit(); DCHECK(IntervalsAreSortedAndNonAdjacent(result.intervals_)); - if (coeff < 0) - result.NegateInPlace(); + if (coeff < 0) result.NegateInPlace(); return result; } @@ -508,8 +460,7 @@ Domain Domain::InverseMultiplicationBy(const int64 coeff) const { // - Append to result [min, max] if these points exists. Domain Domain::SimplifyUsingImpliedDomain(const Domain &implied_domain) const { Domain result; - if (implied_domain.IsEmpty()) - return result; + if (implied_domain.IsEmpty()) return result; int i = 0; int64 min_point; @@ -521,9 +472,7 @@ Domain Domain::SimplifyUsingImpliedDomain(const Domain &implied_domain) const { // interval_: ...] [.... // implied : ...] [... i ...] if (started && implied_domain.intervals_[i].start < interval.start) { - result.intervals_.push_back({ - min_point, max_point - }); + result.intervals_.push_back({min_point, max_point}); started = false; } @@ -546,16 +495,12 @@ Domain Domain::SimplifyUsingImpliedDomain(const Domain &implied_domain) const { max_point = inter_max; } } - if (current.end > interval.end) - break; + if (current.end > interval.end) break; } - if (i == implied_domain.intervals_.size()) - break; + if (i == implied_domain.intervals_.size()) break; } if (started) { - result.intervals_.push_back({ - min_point, max_point - }); + result.intervals_.push_back({min_point, max_point}); } DCHECK(IntervalsAreSortedAndNonAdjacent(result.intervals_)); return result; @@ -577,14 +522,10 @@ bool Domain::operator<(const Domain &other) const { for (int i = 0; i < common_size; ++i) { const ClosedInterval &i1 = d1[i]; const ClosedInterval &i2 = d2[i]; - if (i1.start < i2.start) - return true; - if (i1.start > i2.start) - return false; - if (i1.end < i2.end) - return true; - if (i1.end > i2.end) - return false; + if (i1.start < i2.start) return true; + if (i1.start > i2.start) return false; + if (i1.end < i2.end) return true; + if (i1.end > i2.end) return false; } return d1.size() < d2.size(); } @@ -595,11 +536,9 @@ int64 SumOfKMinValueInDomain(const Domain &domain, int k) { int64 current_sum = 0.0; int current_index = 0; for (const ClosedInterval interval : domain) { - if (current_index >= k) - break; + if (current_index >= k) break; for (int v(interval.start); v <= interval.end; ++v) { - if (current_index >= k) - break; + if (current_index >= k) break; current_index++; current_sum += v; } @@ -637,8 +576,7 @@ SortedDisjointIntervalList::BuildComplementOnInterval(int64 start, int64 end) { for (auto it = FirstIntervalGreaterOrEqual(start); it != this->end(); ++it) { const ClosedInterval &interval = *it; const int64 next_end = CapSub(interval.start, 1); - if (next_end > end) - break; + if (next_end > end) break; if (next_start <= next_end) { interval_list.InsertInterval(next_start, next_end); } @@ -650,22 +588,17 @@ SortedDisjointIntervalList::BuildComplementOnInterval(int64 start, int64 end) { return interval_list; } -SortedDisjointIntervalList::Iterator -SortedDisjointIntervalList::InsertInterval(int64 start, int64 end) { +SortedDisjointIntervalList::Iterator SortedDisjointIntervalList::InsertInterval( + int64 start, int64 end) { // start > end could mean an empty interval, but we prefer to LOG(DFATAL) // anyway. Really, the user should never give us that. if (start > end) { - LOG(DFATAL) << "Invalid interval: " << ClosedInterval({ - start, end - }); + LOG(DFATAL) << "Invalid interval: " << ClosedInterval({start, end}); return intervals_.end(); } - auto result = intervals_.insert({ - start, end - }); - if (!result.second) - return result.first; // Duplicate: exit immediately. + auto result = intervals_.insert({start, end}); + if (!result.second) return result.first; // Duplicate: exit immediately. // TODO(user): tune the algorithm below if it proves to be a bottleneck. // For example, one could try to avoid an insertion if it's not needed @@ -677,15 +610,14 @@ SortedDisjointIntervalList::InsertInterval(int64 start, int64 end) { // merged with the current interval (possibly pointing to the current interval // itself, if no "earlier" interval should be merged). auto it1 = result.first; - if (start == kint64min) { // Catch underflows + if (start == kint64min) { // Catch underflows it1 = intervals_.begin(); } else { const int64 before_start = start - 1; while (it1 != intervals_.begin()) { auto prev_it = it1; --prev_it; - if (prev_it->end < before_start) - break; + if (prev_it->end < before_start) break; it1 = prev_it; } } @@ -707,8 +639,7 @@ SortedDisjointIntervalList::InsertInterval(int64 start, int64 end) { // and set *it3 to the merged interval. auto it3 = it2; it3--; - if (it1 == it3) - return it3; // Nothing was merged. + if (it1 == it3) return it3; // Nothing was merged. const int64 new_start = std::min(it1->start, start); const int64 new_end = std::max(it3->end, end); auto it = intervals_.erase(it1, it3); @@ -721,11 +652,9 @@ SortedDisjointIntervalList::InsertInterval(int64 start, int64 end) { return it; } -SortedDisjointIntervalList::Iterator -SortedDisjointIntervalList::GrowRightByOne(int64 value, int64 *newly_covered) { - auto it = intervals_.upper_bound({ - value, kint64max - }); +SortedDisjointIntervalList::Iterator SortedDisjointIntervalList::GrowRightByOne( + int64 value, int64 *newly_covered) { + auto it = intervals_.upper_bound({value, kint64max}); auto it_prev = it; // No interval containing or adjacent to "value" on the left (i.e. below). @@ -735,10 +664,8 @@ SortedDisjointIntervalList::GrowRightByOne(int64 value, int64 *newly_covered) { if (it == begin() || ((value != kint64min) && it_prev->end < value - 1)) { *newly_covered = value; if (it == end() || it->start != value + 1) { - // No interval adjacent to "value" on the right: insert a singleton. - return intervals_.insert(it, { - value, value - }); + // No interval adjacent to "value" on the right: insert a singleton. + return intervals_.insert(it, {value, value}); } else { // There is an interval adjacent to "value" on the right. Extend it by // one. Note that we already know that there won't be a merge with another @@ -771,13 +698,11 @@ template void SortedDisjointIntervalList::InsertAll(const std::vector &starts, const std::vector &ends) { CHECK_EQ(starts.size(), ends.size()); - for (int i = 0; i < starts.size(); ++i) - InsertInterval(starts[i], ends[i]); + for (int i = 0; i < starts.size(); ++i) InsertInterval(starts[i], ends[i]); } -void -SortedDisjointIntervalList::InsertIntervals(const std::vector &starts, - const std::vector &ends) { +void SortedDisjointIntervalList::InsertIntervals( + const std::vector &starts, const std::vector &ends) { InsertAll(starts, ends); } @@ -789,11 +714,8 @@ void SortedDisjointIntervalList::InsertIntervals(const std::vector &starts, SortedDisjointIntervalList::Iterator SortedDisjointIntervalList::FirstIntervalGreaterOrEqual(int64 value) const { - const auto it = intervals_.upper_bound({ - value, kint64max - }); - if (it == begin()) - return it; + const auto it = intervals_.upper_bound({value, kint64max}); + if (it == begin()) return it; auto it_prev = it; it_prev--; DCHECK_LE(it_prev->start, value); @@ -802,11 +724,8 @@ SortedDisjointIntervalList::FirstIntervalGreaterOrEqual(int64 value) const { SortedDisjointIntervalList::Iterator SortedDisjointIntervalList::LastIntervalLessOrEqual(int64 value) const { - const auto it = intervals_.upper_bound({ - value, kint64max - }); - if (it == begin()) - return end(); + const auto it = intervals_.upper_bound({value, kint64max}); + if (it == begin()) return end(); auto it_prev = it; it_prev--; return it_prev; @@ -820,4 +739,4 @@ std::string SortedDisjointIntervalList::DebugString() const { return str; } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/sorted_interval_list.h b/ortools/util/sorted_interval_list.h index bd4d6ee87a..159f51ee25 100644 --- a/ortools/util/sorted_interval_list.h +++ b/ortools/util/sorted_interval_list.h @@ -49,8 +49,8 @@ struct ClosedInterval { return start < other.start; } - int64 start = 0; // Inclusive. - int64 end = 0; // Inclusive. + int64 start = 0; // Inclusive. + int64 end = 0; // Inclusive. }; std::ostream &operator<<(std::ostream &out, const ClosedInterval &interval); @@ -79,7 +79,7 @@ bool IntervalsAreSortedAndNonAdjacent( * Note that all the functions are safe with respect to integer overflow. */ class Domain { -public: + public: /// By default, Domain will be empty. Domain() {} @@ -101,7 +101,7 @@ public: intervals_ = std::move(other.intervals_); return *this; } -#endif // !defined(SWIG) +#endif // !defined(SWIG) /// Constructor for the common case of a singleton domain. explicit Domain(int64 value); @@ -139,8 +139,8 @@ public: * building a Domain object from a list of intervals (long[][] in Java and * .NET, [[0, 2], [5, 5], [8, 10]] in python). */ - static Domain - FromVectorIntervals(const std::vector > &intervals); + static Domain FromVectorIntervals( + const std::vector > &intervals); /** * This method is available in Python, Java and .NET. It allows @@ -351,10 +351,10 @@ public: // TODO(user): remove, this makes a copy and is of a different type that our // internal InlinedVector() anyway. std::vector intervals() const { - return { intervals_.begin(), intervals_.end() }; + return {intervals_.begin(), intervals_.end()}; } -private: + private: // Same as Negation() but modify the current domain. void NegateInPlace(); @@ -387,7 +387,7 @@ int64 SumOfKMaxValueInDomain(const Domain &domain, int k); */ // TODO(user): Templatize the class on the type of the bounds. class SortedDisjointIntervalList { -public: + public: struct IntervalComparator { bool operator()(const ClosedInterval &a, const ClosedInterval &b) const { return a.start != b.start ? a.start < b.start : a.end < b.end; @@ -492,13 +492,13 @@ public: intervals_.swap(other.intervals_); } -private: + private: template void InsertAll(const std::vector &starts, const std::vector &ends); IntervalSet intervals_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_ +#endif // OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_ diff --git a/ortools/util/stats.cc b/ortools/util/stats.cc index c02c17fe10..a463810877 100644 --- a/ortools/util/stats.cc +++ b/ortools/util/stats.cc @@ -59,15 +59,14 @@ namespace { bool CompareStatPointers(const Stat *s1, const Stat *s2) { if (s1->Priority() == s2->Priority()) { - if (s1->Sum() == s2->Sum()) - return s1->Name() < s2->Name(); + if (s1->Sum() == s2->Sum()) return s1->Name() < s2->Name(); return (s1->Sum() > s2->Sum()); } else { return (s1->Priority() > s2->Priority()); } } -} // namespace +} // namespace std::string StatsGroup::StatString() const { // Computes the longest name of all the stats we want to display. @@ -75,30 +74,28 @@ std::string StatsGroup::StatString() const { int longest_name_size = 0; std::vector sorted_stats; for (int i = 0; i < stats_.size(); ++i) { - if (!stats_[i]->WorthPrinting()) - continue; + if (!stats_[i]->WorthPrinting()) continue; // We support UTF8 characters in the stat names. const int size = operations_research::utf8::UTF8StrLen(stats_[i]->Name()); longest_name_size = std::max(longest_name_size, size); sorted_stats.push_back(stats_[i]); } switch (print_order_) { - case SORT_BY_PRIORITY_THEN_VALUE: - std::sort(sorted_stats.begin(), sorted_stats.end(), CompareStatPointers); - break; - case SORT_BY_NAME: - std::sort(sorted_stats.begin(), sorted_stats.end(), - [](const Stat * s1, const Stat * s2)->bool { - return s1->Name() < s2->Name(); - }); - break; - default: - LOG(FATAL) << "Unknown print order: " << print_order_; + case SORT_BY_PRIORITY_THEN_VALUE: + std::sort(sorted_stats.begin(), sorted_stats.end(), CompareStatPointers); + break; + case SORT_BY_NAME: + std::sort(sorted_stats.begin(), sorted_stats.end(), + [](const Stat *s1, const Stat *s2) -> bool { + return s1->Name() < s2->Name(); + }); + break; + default: + LOG(FATAL) << "Unknown print order: " << print_order_; } // Do not display groups without print-worthy stats. - if (sorted_stats.empty()) - return ""; + if (sorted_stats.empty()) return ""; // Pretty-print all the stats. std::string result(name_ + " {\n"); @@ -124,12 +121,22 @@ TimeDistribution *StatsGroup::LookupOrCreateTimeDistribution(std::string name) { } DistributionStat::DistributionStat(const std::string &name) - : Stat(name), sum_(0.0), average_(0.0), sum_squares_from_average_(0.0), - min_(0.0), max_(0.0), num_(0) {} + : Stat(name), + sum_(0.0), + average_(0.0), + sum_squares_from_average_(0.0), + min_(0.0), + max_(0.0), + num_(0) {} DistributionStat::DistributionStat(const std::string &name, StatsGroup *group) - : Stat(name, group), sum_(0.0), average_(0.0), - sum_squares_from_average_(0.0), min_(0.0), max_(0.0), num_(0) {} + : Stat(name, group), + sum_(0.0), + average_(0.0), + sum_squares_from_average_(0.0), + min_(0.0), + max_(0.0), + num_(0) {} void DistributionStat::Reset() { sum_ = 0.0; @@ -161,8 +168,7 @@ void DistributionStat::AddToDistribution(double value) { double DistributionStat::Average() const { return average_; } double DistributionStat::StdDeviation() const { - if (num_ == 0) - return 0.0; + if (num_ == 0) return 0.0; return sqrt(sum_squares_from_average_ / num_); } @@ -176,16 +182,11 @@ std::string TimeDistribution::PrintCyclesAsTime(double cycles) { // This epsilon is just to avoid displaying 1000.00ms instead of 1.00s. double eps1 = 1 + 1e-3; double sec = CyclesToSeconds(cycles); - if (sec * eps1 >= 3600.0) - return absl::StrFormat("%.2fh", sec / 3600.0); - if (sec * eps1 >= 60.0) - return absl::StrFormat("%.2fm", sec / 60.0); - if (sec * eps1 >= 1.0) - return absl::StrFormat("%.2fs", sec); - if (sec * eps1 >= 1e-3) - return absl::StrFormat("%.2fms", sec * 1e3); - if (sec * eps1 >= 1e-6) - return absl::StrFormat("%.2fus", sec * 1e6); + if (sec * eps1 >= 3600.0) return absl::StrFormat("%.2fh", sec / 3600.0); + if (sec * eps1 >= 60.0) return absl::StrFormat("%.2fm", sec / 60.0); + if (sec * eps1 >= 1.0) return absl::StrFormat("%.2fs", sec); + if (sec * eps1 >= 1e-3) return absl::StrFormat("%.2fms", sec * 1e3); + if (sec * eps1 >= 1e-6) return absl::StrFormat("%.2fus", sec * 1e6); return absl::StrFormat("%.2fns", sec * 1e9); } @@ -247,6 +248,6 @@ EnabledScopedInstructionCounter::~EnabledScopedInstructionCounter() { time_limit_ != nullptr ? time_limit_->ReadInstructionCounter() : 0; LOG(INFO) << name_ << ", Instructions: " << ending_count_ - starting_count_; } -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/stats.h b/ortools/util/stats.h index d395745d82..04ad6ce1a4 100644 --- a/ortools/util/stats.h +++ b/ortools/util/stats.h @@ -75,7 +75,7 @@ #include "absl/strings/str_replace.h" #include "exegesis/exegesis/itineraries/perf_subsystem.h" #include "ortools/util/time_limit.h" -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM #include "ortools/base/macros.h" #include "ortools/base/timer.h" @@ -91,7 +91,7 @@ class TimeDistribution; // Base class for a statistic that can be pretty-printed. class Stat { -public: + public: explicit Stat(const std::string &name) : name_(name) {} // Also add this stat to the given group. @@ -123,13 +123,13 @@ public: // Reset this statistic to the same state as if it was newly created. virtual void Reset() = 0; -private: + private: const std::string name_; }; // Base class to print a nice summary of a group of statistics. class StatsGroup { -public: + public: enum PrintOrder { SORT_BY_PRIORITY_THEN_VALUE = 0, SORT_BY_NAME = 1, @@ -160,7 +160,7 @@ public: // Calls Reset() on all the statistics registered with this group. void Reset(); -private: + private: std::string name_; PrintOrder print_order_ = SORT_BY_PRIORITY_THEN_VALUE; std::vector stats_; @@ -173,7 +173,7 @@ private: // sequence of double. We provide a few sub-classes below that differ in the way // the values are added to the sequence and in the way the stats are printed. class DistributionStat : public Stat { -public: + public: explicit DistributionStat(const std::string &name); DistributionStat() : DistributionStat("") {} DistributionStat(const std::string &name, StatsGroup *group); @@ -200,7 +200,7 @@ public: // even more precise but a bit slower too. double StdDeviation() const; -protected: + protected: // Adds a value to this sequence and updates the stats. void AddToDistribution(double value); double sum_; @@ -219,7 +219,7 @@ protected: // because with the 53 bits of precision of a double, we will run into an issue // if the sum of times reaches 52 days for a 2GHz processor. class TimeDistribution : public DistributionStat { -public: + public: explicit TimeDistribution(const std::string &name) : DistributionStat(name), timer_() {} TimeDistribution() : TimeDistribution("") {} @@ -252,7 +252,7 @@ public: return cycles; } -private: + private: // Converts and prints a number of cycles in an human readable way using the // proper time unit depending on the value (ns, us, ms, s, m or h). static std::string PrintCyclesAsTime(double cycles); @@ -261,7 +261,7 @@ private: // Statistic on the distribution of a sequence of ratios, displayed as %. class RatioDistribution : public DistributionStat { -public: + public: explicit RatioDistribution(const std::string &name) : DistributionStat(name) {} RatioDistribution() : RatioDistribution("") {} @@ -273,7 +273,7 @@ public: // Statistic on the distribution of a sequence of doubles. class DoubleDistribution : public DistributionStat { -public: + public: explicit DoubleDistribution(const std::string &name) : DistributionStat(name) {} DoubleDistribution() : DoubleDistribution("") {} @@ -285,7 +285,7 @@ public: // Statistic on the distribution of a sequence of integers. class IntegerDistribution : public DistributionStat { -public: + public: explicit IntegerDistribution(const std::string &name) : DistributionStat(name) {} IntegerDistribution() : IntegerDistribution("") {} @@ -310,7 +310,7 @@ public: // * DisabledScopedTimeDistributionUpdater is used to implement // ScopedTimeDistributionUpdater when OR_STATS is not defined. class EnabledScopedTimeDistributionUpdater { -public: + public: // Note that this does not take ownership of the given stat. explicit EnabledScopedTimeDistributionUpdater(TimeDistribution *stat) : stat_(stat), also_update_(nullptr) { @@ -334,18 +334,18 @@ public: // } void AlsoUpdate(TimeDistribution *also_update) { also_update_ = also_update; } -private: + private: TimeDistribution *stat_; TimeDistribution *also_update_; DISALLOW_COPY_AND_ASSIGN(EnabledScopedTimeDistributionUpdater); }; class DisabledScopedTimeDistributionUpdater { -public: + public: explicit DisabledScopedTimeDistributionUpdater(TimeDistribution *stat) {} void AlsoUpdate(TimeDistribution *also_update) {} -private: + private: DISALLOW_COPY_AND_ASSIGN(DisabledScopedTimeDistributionUpdater); }; @@ -358,7 +358,7 @@ private: // sudo echo "1" > /proc/sys/kernel/perf_event_paranoid // sudo echo "0" > /proc/sys/kernel/kptr_restrict class EnabledScopedInstructionCounter { -public: + public: explicit EnabledScopedInstructionCounter(const std::string &name, TimeLimit *time_limit); EnabledScopedInstructionCounter(const EnabledScopedInstructionCounter &) = @@ -370,16 +370,16 @@ public: // Used only for testing. double ReadInstructionCount() { return ending_count_ - starting_count_; } -private: + private: TimeLimit *time_limit_; std::string name_; double starting_count_; double ending_count_; }; -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM class DisabledScopedInstructionCounter { -public: + public: explicit DisabledScopedInstructionCounter(const std::string &name) {} DisabledScopedInstructionCounter(const DisabledScopedInstructionCounter &) = delete; @@ -392,9 +392,9 @@ public: using ScopedTimeDistributionUpdater = EnabledScopedTimeDistributionUpdater; #ifdef HAS_PERF_SUBSYSTEM using ScopedInstructionCounter = EnabledScopedInstructionCounter; -#else // HAS_PERF_SUBSYSTEM +#else // HAS_PERF_SUBSYSTEM using ScopedInstructionCounter = DisabledScopedInstructionCounter; -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM // Simple macro to be used by a client that want to execute costly operations // only if OR_STATS is defined. @@ -407,27 +407,25 @@ using ScopedInstructionCounter = DisabledScopedInstructionCounter; // Note(user): This adds more extra overhead around the measured code compared // to defining your own TimeDistribution stat in your StatsGroup. About 80ns // per measurement compared to about 20ns (as of 2012-06, on my workstation). -#define SCOPED_TIME_STAT(stats) \ - operations_research::ScopedTimeDistributionUpdater scoped_time_stat( \ +#define SCOPED_TIME_STAT(stats) \ + operations_research::ScopedTimeDistributionUpdater scoped_time_stat( \ (stats)->LookupOrCreateTimeDistribution(__FUNCTION__)) #ifdef HAS_PERF_SUBSYSTEM -inline std::string -RemoveOperationsResearchAndGlop(const std::string &pretty_function) { - return strings::GlobalReplaceSubstrings(pretty_function, { - { "operations_research::", "" } - , { "glop::", "" } - }); +inline std::string RemoveOperationsResearchAndGlop( + const std::string &pretty_function) { + return strings::GlobalReplaceSubstrings( + pretty_function, {{"operations_research::", ""}, {"glop::", ""}}); } -#define SCOPED_INSTRUCTION_COUNT(time_limit) \ - operations_research::ScopedInstructionCounter scoped_instruction_count( \ +#define SCOPED_INSTRUCTION_COUNT(time_limit) \ + operations_research::ScopedInstructionCounter scoped_instruction_count( \ RemoveOperationsResearchAndGlop(__PRETTY_FUNCTION__), time_limit) -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM -#else // OR_STATS +#else // OR_STATS // If OR_STATS is not defined, we remove some instructions that may be time // consuming. @@ -438,8 +436,8 @@ using ScopedInstructionCounter = DisabledScopedInstructionCounter; #define SCOPED_TIME_STAT(stats) #define SCOPED_INSTRUCTION_COUNT(time_limit) -#endif // OR_STATS +#endif // OR_STATS -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_STATS_H_ +#endif // OR_TOOLS_UTIL_STATS_H_ diff --git a/ortools/util/string_array.h b/ortools/util/string_array.h index f54c071910..50aa4b6837 100644 --- a/ortools/util/string_array.h +++ b/ortools/util/string_array.h @@ -21,13 +21,12 @@ namespace operations_research { // ---------- Pretty Print Helpers ---------- // See the straightforward (and unique) usage of this macro below. -#define RETURN_STRINGIFIED_VECTOR(vector, separator, method) \ - std::string out; \ - for (int i = 0; i < vector.size(); ++i) { \ - if (i > 0) \ - out += separator; \ - out += vector[i] method; \ - } \ +#define RETURN_STRINGIFIED_VECTOR(vector, separator, method) \ + std::string out; \ + for (int i = 0; i < vector.size(); ++i) { \ + if (i > 0) out += separator; \ + out += vector[i] method; \ + } \ return out // Converts a vector into a string by calling the given method (or simply @@ -63,5 +62,5 @@ std::string JoinNameFieldPtr(const std::vector &v, #undef RETURN_STRINGIFIED_VECTOR -} // namespace operations_research -#endif // OR_TOOLS_UTIL_STRING_ARRAY_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_STRING_ARRAY_H_ diff --git a/ortools/util/testing_utils.h b/ortools/util/testing_utils.h index 121af38308..7e9c5a7206 100644 --- a/ortools/util/testing_utils.h +++ b/ortools/util/testing_utils.h @@ -18,6 +18,6 @@ namespace operations_research { inline bool ProbablyRunningInsideUnitTest() { running false; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_TESTING_UTILS_H_ +#endif // OR_TOOLS_UTIL_TESTING_UTILS_H_ diff --git a/ortools/util/time_limit.cc b/ortools/util/time_limit.cc index 8cd2daeb24..87ef6be095 100644 --- a/ortools/util/time_limit.cc +++ b/ortools/util/time_limit.cc @@ -30,8 +30,9 @@ const int TimeLimit::kHistorySize = 100; std::string TimeLimit::DebugString() const { std::string buffer = absl::StrCat( - "Time left: ", (GetTimeLeft()), "\nDeterministic time left: ", - (GetDeterministicTimeLeft()), "\nElapsed time: ", (GetElapsedTime()), + "Time left: ", (GetTimeLeft()), + "\nDeterministic time left: ", (GetDeterministicTimeLeft()), + "\nElapsed time: ", (GetElapsedTime()), "\nElapsed deterministic time: ", (GetElapsedDeterministicTime())); #ifndef NDEBUG for (const auto &counter : deterministic_counters_) { @@ -61,4 +62,4 @@ NestedTimeLimit::~NestedTimeLimit() { time_limit_.GetElapsedDeterministicTime()); } -} // namespace operations_research +} // namespace operations_research diff --git a/ortools/util/time_limit.h b/ortools/util/time_limit.h index a263b04359..a8abef8f8e 100644 --- a/ortools/util/time_limit.h +++ b/ortools/util/time_limit.h @@ -32,7 +32,7 @@ #include "ortools/util/running_stat.h" #ifdef HAS_PERF_SUBSYSTEM #include "exegesis/exegesis/itineraries/perf_subsystem.h" -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM /** * Enables changing the behavior of the TimeLimit class to use -b usertime @@ -104,8 +104,8 @@ namespace operations_research { // TODO(user): The expression "deterministic time" should be replaced with // "number of operations" to avoid confusion with "real" time. class TimeLimit { -public: - static const double kSafetyBufferSeconds; // See the .cc for the value. + public: + static const double kSafetyBufferSeconds; // See the .cc for the value. static const int kHistorySize; /** @@ -119,11 +119,10 @@ public: * * Use an infinite limit value to ignore a limit. */ - explicit TimeLimit(double limit_in_seconds, - double deterministic_limit = - std::numeric_limits::infinity(), - double instruction_limit = - std::numeric_limits::infinity()); + explicit TimeLimit( + double limit_in_seconds, + double deterministic_limit = std::numeric_limits::infinity(), + double instruction_limit = std::numeric_limits::infinity()); TimeLimit() : TimeLimit(std::numeric_limits::infinity()) {} TimeLimit(const TimeLimit &) = delete; @@ -143,8 +142,8 @@ public: /** * Creates a time limit object that puts limit only on the deterministic time. */ - static std::unique_ptr - FromDeterministicTime(double deterministic_limit) { + static std::unique_ptr FromDeterministicTime( + double deterministic_limit) { return absl::make_unique( std::numeric_limits::infinity(), deterministic_limit, std::numeric_limits::infinity()); @@ -158,8 +157,8 @@ public: */ // TODO(user): Support adding instruction count limit from parameters. template - static std::unique_ptr - FromParameters(const Parameters ¶meters) { + static std::unique_ptr FromParameters( + const Parameters ¶meters) { return absl::make_unique( parameters.max_time_in_seconds(), parameters.max_deterministic_time(), std::numeric_limits::infinity()); @@ -271,8 +270,8 @@ public: * * Note : The external_boolean_as_limit can be modified during solve. */ - void - RegisterExternalBooleanAsLimit(std::atomic *external_boolean_as_limit) { + void RegisterExternalBooleanAsLimit( + std::atomic *external_boolean_as_limit) { external_boolean_as_limit_ = external_boolean_as_limit; } @@ -296,7 +295,7 @@ public: */ std::string DebugString() const; -private: + private: void ResetTimers(double limit_in_seconds, double deterministic_limit, double instruction_limit); @@ -304,10 +303,10 @@ private: return "inst_retired:any_p:u"; } - mutable int64 start_ns_; // Not const! this is initialized after instruction - // counter initialization. + mutable int64 start_ns_; // Not const! this is initialized after instruction + // counter initialization. int64 last_ns_; - int64 limit_ns_; // Not const! See the code of LimitReached(). + int64 limit_ns_; // Not const! See the code of LimitReached(). const int64 safety_buffer_ns_; RunningMax running_max_; @@ -323,8 +322,8 @@ private: #ifdef HAS_PERF_SUBSYSTEM // PMU counter to help count the instructions. exegesis::PerfSubsystem perf_subsystem_; -#endif // HAS_PERF_SUBSYSTEM - // Given limit in terms of number of instructions. +#endif // HAS_PERF_SUBSYSTEM + // Given limit in terms of number of instructions. double instruction_limit_; #ifndef NDEBUG @@ -338,7 +337,7 @@ private: // Wrapper around TimeLimit to make it thread safe and add Stop() support. class SharedTimeLimit { -public: + public: explicit SharedTimeLimit(TimeLimit *time_limit) : time_limit_(time_limit), stopped_boolean_(false) { // We use the one already registered if present or ours otherwise. @@ -387,7 +386,7 @@ public: return time_limit_->GetElapsedDeterministicTime(); } -private: + private: mutable absl::Mutex mutex_; TimeLimit *time_limit_ ABSL_GUARDED_BY(mutex_); std::atomic stopped_boolean_ ABSL_GUARDED_BY(mutex_); @@ -425,7 +424,7 @@ private: * limit too. */ class NestedTimeLimit { -public: + public: /** * Creates the nested time limit. Note that 'base_time_limit' must remain * valid for the whole lifetime of the nested time limit object. @@ -446,9 +445,8 @@ public: * SatParameters. */ template - static std::unique_ptr - FromBaseTimeLimitAndParameters(TimeLimit *time_limit, - const Parameters ¶meters) { + static std::unique_ptr FromBaseTimeLimitAndParameters( + TimeLimit *time_limit, const Parameters ¶meters) { return absl::make_unique( time_limit, parameters.max_time_in_seconds(), parameters.max_deterministic_time()); @@ -462,7 +460,7 @@ public: */ TimeLimit *GetTimeLimit() { return &time_limit_; } -private: + private: TimeLimit *const base_time_limit_; TimeLimit time_limit_; @@ -474,7 +472,8 @@ private: inline TimeLimit::TimeLimit(double limit_in_seconds, double deterministic_limit, double instruction_limit) : safety_buffer_ns_(static_cast(kSafetyBufferSeconds * 1e9)), - running_max_(kHistorySize), external_boolean_as_limit_(nullptr) { + running_max_(kHistorySize), + external_boolean_as_limit_(nullptr) { ResetTimers(limit_in_seconds, deterministic_limit, instruction_limit); } @@ -495,7 +494,7 @@ inline void TimeLimit::ResetTimers(double limit_in_seconds, perf_subsystem_.AddEvent(GetInstructionRetiredEventName()); perf_subsystem_.StartCollecting(); } -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM start_ns_ = absl::GetCurrentTimeNanos(); last_ns_ = start_ns_; limit_ns_ = limit_in_seconds >= 1e-9 * (kint64max - start_ns_) @@ -511,8 +510,7 @@ inline void TimeLimit::ResetLimitFromParameters(const Parameters ¶meters) { } inline void TimeLimit::MergeWithGlobalTimeLimit(TimeLimit *other) { - if (other == nullptr) - return; + if (other == nullptr) return; ResetTimers( std::min(GetTimeLeft(), other->GetTimeLeft()), std::min(GetDeterministicTimeLeft(), other->GetDeterministicTimeLeft()), @@ -525,10 +523,10 @@ inline void TimeLimit::MergeWithGlobalTimeLimit(TimeLimit *other) { inline double TimeLimit::ReadInstructionCounter() { #ifdef HAS_PERF_SUBSYSTEM if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) { - return perf_subsystem_.ReadCounters() - .GetScaledOrDie(GetInstructionRetiredEventName()); + return perf_subsystem_.ReadCounters().GetScaledOrDie( + GetInstructionRetiredEventName()); } -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM return 0; } @@ -546,7 +544,7 @@ inline bool TimeLimit::LimitReached() { if (ReadInstructionCounter() >= instruction_limit_) { return true; } -#endif // HAS_PERF_SUBSYSTEM +#endif // HAS_PERF_SUBSYSTEM const int64 current_ns = absl::GetCurrentTimeNanos(); running_max_.Add(std::max(safety_buffer_ns_, current_ns - last_ns_)); @@ -571,11 +569,9 @@ inline bool TimeLimit::LimitReached() { } inline double TimeLimit::GetTimeLeft() const { - if (limit_ns_ == kint64max) - return std::numeric_limits::infinity(); + if (limit_ns_ == kint64max) return std::numeric_limits::infinity(); const int64 delta_ns = limit_ns_ - absl::GetCurrentTimeNanos(); - if (delta_ns < 0) - return 0.0; + if (delta_ns < 0) return 0.0; if (absl::GetFlag(FLAGS_time_limit_use_usertime)) { return std::max(limit_in_seconds_ - user_timer_.Get(), 0.0); } else { @@ -587,6 +583,6 @@ inline double TimeLimit::GetInstructionsLeft() { return std::max(instruction_limit_ - ReadInstructionCounter(), 0.0); } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_TIME_LIMIT_H_ +#endif // OR_TOOLS_UTIL_TIME_LIMIT_H_ diff --git a/ortools/util/tuple_set.h b/ortools/util/tuple_set.h index ab0557ad13..2d994ade93 100644 --- a/ortools/util/tuple_set.h +++ b/ortools/util/tuple_set.h @@ -47,11 +47,11 @@ namespace operations_research { // ----- Main IntTupleSet class ----- class IntTupleSet { -public: + public: // Creates an empty tuple set with a fixed length for all tuples. explicit IntTupleSet(int arity); // Copy constructor (it actually does a lazy copy, see toplevel comment). - IntTupleSet(const IntTupleSet &set); // NOLINT + IntTupleSet(const IntTupleSet &set); // NOLINT ~IntTupleSet(); // Clears data. @@ -93,27 +93,30 @@ public: // Returns a copy of the tuple set lexicographically sorted. IntTupleSet SortedLexicographically() const; -private: + private: // Class that holds the actual data of an IntTupleSet. It handles // the reference counters, etc. class Data { - public: + public: explicit Data(int arity); Data(const Data &data); ~Data(); void AddSharedOwner(); bool RemovedSharedOwner(); Data *CopyIfShared(); - template int Insert(const std::vector &tuple); - template bool Contains(const std::vector &candidate) const; - template int64 Fingerprint(const std::vector &tuple) const; + template + int Insert(const std::vector &tuple); + template + bool Contains(const std::vector &candidate) const; + template + int64 Fingerprint(const std::vector &tuple) const; int NumTuples() const; int64 Value(int index, int pos) const; int Arity() const; const int64 *RawData() const; void Clear(); - private: + private: const int arity_; int num_owners_; // Concatenation of all tuples ever added. @@ -146,7 +149,9 @@ private: inline IntTupleSet::Data::Data(int arity) : arity_(arity), num_owners_(0) {} inline IntTupleSet::Data::Data(const Data &data) - : arity_(data.arity_), num_owners_(0), flat_tuples_(data.flat_tuples_), + : arity_(data.arity_), + num_owners_(0), + flat_tuples_(data.flat_tuples_), tuple_fprint_to_index_(data.tuple_fprint_to_index_) {} inline IntTupleSet::Data::~Data() {} @@ -158,7 +163,7 @@ inline bool IntTupleSet::Data::RemovedSharedOwner() { } inline IntTupleSet::Data *IntTupleSet::Data::CopyIfShared() { - if (num_owners_ > 1) { // Copy on write. + if (num_owners_ > 1) { // Copy on write. Data *const new_data = new Data(*this); RemovedSharedOwner(); new_data->AddSharedOwner(); @@ -167,7 +172,8 @@ inline IntTupleSet::Data *IntTupleSet::Data::CopyIfShared() { return this; } -template int IntTupleSet::Data::Insert(const std::vector &tuple) { +template +int IntTupleSet::Data::Insert(const std::vector &tuple) { DCHECK(arity_ == 0 || flat_tuples_.size() % arity_ == 0); CHECK_EQ(arity_, tuple.size()); DCHECK_EQ(1, num_owners_); @@ -212,27 +218,27 @@ bool IntTupleSet::Data::Contains(const std::vector &candidate) const { template int64 IntTupleSet::Data::Fingerprint(const std::vector &tuple) const { switch (arity_) { - case 0: - return 0; - case 1: - return tuple[0]; - case 2: { - uint64 x = tuple[0]; - uint64 y = GG_ULONGLONG(0xe08c1d668b756f82); - uint64 z = tuple[1]; - mix(x, y, z); - return z; - } - default: { - uint64 x = tuple[0]; - uint64 y = GG_ULONGLONG(0xe08c1d668b756f82); - for (int i = 1; i < tuple.size(); ++i) { - uint64 z = tuple[i]; + case 0: + return 0; + case 1: + return tuple[0]; + case 2: { + uint64 x = tuple[0]; + uint64 y = GG_ULONGLONG(0xe08c1d668b756f82); + uint64 z = tuple[1]; mix(x, y, z); - x = z; + return z; + } + default: { + uint64 x = tuple[0]; + uint64 y = GG_ULONGLONG(0xe08c1d668b756f82); + for (int i = 1; i < tuple.size(); ++i) { + uint64 z = tuple[i]; + mix(x, y, z); + x = z; + } + return x; } - return x; - } } } @@ -322,16 +328,16 @@ inline bool IntTupleSet::Contains(const std::vector &tuple) const { return data_->Contains(tuple); } -inline void -IntTupleSet::InsertAll(const std::vector > &tuples) { +inline void IntTupleSet::InsertAll( + const std::vector > &tuples) { data_ = data_->CopyIfShared(); for (int i = 0; i < tuples.size(); ++i) { Insert(tuples[i]); } } -inline void -IntTupleSet::InsertAll(const std::vector > &tuples) { +inline void IntTupleSet::InsertAll( + const std::vector > &tuples) { data_ = data_->CopyIfShared(); for (int i = 0; i < tuples.size(); ++i) { Insert(tuples[i]); @@ -413,6 +419,6 @@ inline IntTupleSet IntTupleSet::SortedLexicographically() const { } return sorted; } -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_TUPLE_SET_H_ +#endif // OR_TOOLS_UTIL_TUPLE_SET_H_ diff --git a/ortools/util/vector_map.h b/ortools/util/vector_map.h index ba0449c9cc..e471cdb8e9 100644 --- a/ortools/util/vector_map.h +++ b/ortools/util/vector_map.h @@ -26,8 +26,9 @@ namespace operations_research { // This class stores a vector of distinct elements, as well as a map // from elements to index to find the index in the vector. // This is useful to store mapping between objects and indices. -template class VectorMap { -public: +template +class VectorMap { + public: // Adds an element if not already present, and returns its index in // the vector-map. int Add(const T &element) { @@ -107,10 +108,10 @@ public: return const_reverse_iterator(list_.data()); } -private: + private: std::vector list_; absl::flat_hash_map map_; }; -} // namespace operations_research -#endif // OR_TOOLS_UTIL_VECTOR_MAP_H_ +} // namespace operations_research +#endif // OR_TOOLS_UTIL_VECTOR_MAP_H_ diff --git a/ortools/util/vector_or_function.h b/ortools/util/vector_or_function.h index e13d5e5d37..8ea8a7481a 100644 --- a/ortools/util/vector_or_function.h +++ b/ortools/util/vector_or_function.h @@ -23,27 +23,28 @@ namespace operations_research { // Template to abstract the access to STL functions or vector values. -template class VectorOrFunction { -public: +template +class VectorOrFunction { + public: explicit VectorOrFunction(Evaluator evaluator) : evaluator_(std::move(evaluator)) {} void Reset(Evaluator evaluator) { evaluator_ = std::move(evaluator); } ScalarType operator()(int i) const { return evaluator_(i); } -private: + private: Evaluator evaluator_; }; // Specialization for vectors. template class VectorOrFunction > { -public: + public: explicit VectorOrFunction(std::vector values) : values_(std::move(values)) {} void Reset(std::vector values) { values_ = std::move(values); } ScalarType operator()(int i) const { return values_[i]; } -private: + private: std::vector values_; }; @@ -51,14 +52,14 @@ private: // values. template class MatrixOrFunction { -public: + public: explicit MatrixOrFunction(Evaluator evaluator) : evaluator_(std::move(evaluator)) {} void Reset(Evaluator evaluator) { evaluator_ = std::move(evaluator); } ScalarType operator()(int i, int j) const { return evaluator_(i, j); } bool Check() const { return true; } -private: + private: Evaluator evaluator_; }; @@ -66,7 +67,7 @@ private: template class MatrixOrFunction >, square> { -public: + public: explicit MatrixOrFunction(std::vector > matrix) : matrix_(std::move(matrix)) {} void Reset(std::vector > matrix) { @@ -76,8 +77,7 @@ public: // Returns true if the matrix is square or rectangular. // Intended to be used in a CHECK. bool Check() const { - if (matrix_.empty()) - return true; + if (matrix_.empty()) return true; const int size = square ? matrix_.size() : matrix_[0].size(); const char *msg = square ? "Matrix must be square." : "Matrix must be rectangular."; @@ -87,10 +87,10 @@ public: return true; } -private: + private: std::vector > matrix_; }; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_VECTOR_OR_FUNCTION_H_ +#endif // OR_TOOLS_UTIL_VECTOR_OR_FUNCTION_H_ diff --git a/ortools/util/zvector.h b/ortools/util/zvector.h index 81e2b28bce..da56d43cde 100644 --- a/ortools/util/zvector.h +++ b/ortools/util/zvector.h @@ -41,8 +41,9 @@ namespace operations_research { -template class ZVector { -public: +template +class ZVector { + public: ZVector() : base_(nullptr), min_index_(0), max_index_(-1), size_(0), storage_() {} @@ -137,7 +138,7 @@ public: } } -private: + private: // Pointer to the element indexed by zero in the array. T *base_; @@ -164,6 +165,6 @@ typedef ZVector UInt16ZVector; typedef ZVector UInt32ZVector; typedef ZVector UInt64ZVector; -} // namespace operations_research +} // namespace operations_research -#endif // OR_TOOLS_UTIL_ZVECTOR_H_ +#endif // OR_TOOLS_UTIL_ZVECTOR_H_