From a52d00b42b6fda041bab5bef842dff585abe057c Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Sun, 29 Dec 2024 19:21:42 +0100 Subject: [PATCH] fix examples --- examples/cpp/constraint_programming_cp.cc | 3 +- examples/cpp/dobble_ls.cc | 3 +- examples/cpp/flow_api.cc | 20 ++++++++----- examples/cpp/integer_programming.cc | 2 ++ examples/cpp/linear_assignment_api.cc | 16 +++++++---- examples/cpp/linear_programming.cc | 2 +- examples/cpp/max_flow.cc | 17 +++++++---- examples/cpp/min_cost_flow.cc | 25 ++++++++-------- examples/cpp/parse_dimacs_assignment.h | 35 +++++++++-------------- examples/cpp/pdlp_solve.cc | 2 +- examples/cpp/print_dimacs_assignment.h | 19 ++---------- examples/tests/issue260.py | 11 ------- 12 files changed, 71 insertions(+), 84 deletions(-) delete mode 100755 examples/tests/issue260.py diff --git a/examples/cpp/constraint_programming_cp.cc b/examples/cpp/constraint_programming_cp.cc index af3dc8c05b..c11cd27b8a 100644 --- a/examples/cpp/constraint_programming_cp.cc +++ b/examples/cpp/constraint_programming_cp.cc @@ -43,7 +43,8 @@ void RunConstraintProgrammingExample() { solver.NewSearch(db); while (solver.NextSolution()) { - LOG(INFO) << "Solution" << ": x = " << x->Value() << "; y = " << y->Value() + LOG(INFO) << "Solution" + << ": x = " << x->Value() << "; y = " << y->Value() << "; z = " << z->Value(); } solver.EndSearch(); diff --git a/examples/cpp/dobble_ls.cc b/examples/cpp/dobble_ls.cc index bbca214f15..3a0d78c022 100644 --- a/examples/cpp/dobble_ls.cc +++ b/examples/cpp/dobble_ls.cc @@ -38,6 +38,7 @@ #include "absl/random/random.h" #include "absl/strings/str_format.h" +#include "absl/types/span.h" #include "ortools/base/commandlineflags.h" #include "ortools/base/init_google.h" #include "ortools/base/map_util.h" @@ -549,7 +550,7 @@ class DobbleFilter : public IntVarLocalSearchFilter { // For each touched card, compare against all others to compute the // delta in term of cost. We use a bitset to avoid counting twice // between two cards appearing in the local search move. - int ComputeNewCost(const std::vector& touched_cards) { + int ComputeNewCost(absl::Span touched_cards) { ClearBitset(); int cost_delta = 0; for (int i = 0; i < touched_cards.size(); ++i) { diff --git a/examples/cpp/flow_api.cc b/examples/cpp/flow_api.cc index f646e016e2..75798dca35 100644 --- a/examples/cpp/flow_api.cc +++ b/examples/cpp/flow_api.cc @@ -15,12 +15,18 @@ #include "ortools/base/init_google.h" #include "ortools/base/logging.h" -#include "ortools/graph/ebert_graph.h" -#include "ortools/graph/max_flow.h" +#include "ortools/graph/generic_max_flow.h" +#include "ortools/graph/graph.h" #include "ortools/graph/min_cost_flow.h" namespace operations_research { +using Graph = ::util::ReverseArcListGraph<>; +using NodeIndex = Graph::NodeIndex; +using ArcIndex = Graph::ArcIndex; +using CostValue = GenericMinCostFlow::CostValue; +using FlowQuantity = GenericMinCostFlow::FlowQuantity; + // ----- Min Cost Flow ----- // Test on a 4x4 matrix. Example taken from @@ -34,8 +40,8 @@ void MinCostFlowOn4x4Matrix() { {125, 95, 90, 105}, {45, 110, 95, 115}}; const CostValue kExpectedCost = 275; - StarGraph graph(kNumSources + kNumTargets, kNumSources * kNumTargets); - MinCostFlow min_cost_flow(&graph); + Graph graph(kNumSources + kNumTargets, kNumSources * kNumTargets); + GenericMinCostFlow min_cost_flow(&graph); for (NodeIndex source = 0; source < kNumSources; ++source) { for (NodeIndex target = 0; target < kNumTargets; ++target) { ArcIndex arc = graph.AddArc(source, kNumSources + target); @@ -66,14 +72,14 @@ void MaxFeasibleFlow() { 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); + Graph graph(kNumNodes, kNumArcs); + GenericMaxFlow max_flow(&graph, 0, kNumNodes - 1); for (int i = 0; i < kNumArcs; ++i) { ArcIndex arc = graph.AddArc(kTail[i], kHead[i]); max_flow.SetArcCapacity(arc, kCapacity[i]); } CHECK(max_flow.Solve()); - CHECK_EQ(MaxFlow::OPTIMAL, max_flow.status()); + CHECK_EQ(MaxFlowStatusClass::OPTIMAL, max_flow.status()); FlowQuantity total_flow = max_flow.GetOptimalFlow(); CHECK_EQ(total_flow, kExpectedTotalFlow); for (int i = 0; i < kNumArcs; ++i) { diff --git a/examples/cpp/integer_programming.cc b/examples/cpp/integer_programming.cc index 33e98eae68..19bc51d511 100644 --- a/examples/cpp/integer_programming.cc +++ b/examples/cpp/integer_programming.cc @@ -16,6 +16,7 @@ #include #include +#include "absl/flags/flag.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" #include "ortools/base/init_google.h" @@ -88,6 +89,7 @@ void RunAllExamples() { RunIntegerProgrammingExample("GLPK"); RunIntegerProgrammingExample("CPLEX"); RunIntegerProgrammingExample("XPRESS"); + RunIntegerProgrammingExample("HIGHS"); } } // namespace operations_research diff --git a/examples/cpp/linear_assignment_api.cc b/examples/cpp/linear_assignment_api.cc index bf5204b136..d9e4dfce86 100644 --- a/examples/cpp/linear_assignment_api.cc +++ b/examples/cpp/linear_assignment_api.cc @@ -11,16 +11,22 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include "ortools/base/init_google.h" #include "ortools/base/logging.h" -#include "ortools/graph/ebert_graph.h" +#include "ortools/graph/graph.h" #include "ortools/graph/linear_assignment.h" namespace operations_research { +using NodeIndex = int32_t; +using ArcIndex = int32_t; +using CostValue = int64_t; +using Graph = ::util::ListGraph; + // Test assignment on a 4x4 matrix. Example taken from // http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1] // modified so the optimum solution is unique. @@ -34,8 +40,8 @@ void AssignmentOn4x4Matrix() { {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); - LinearSumAssignment assignment(graph, kNumSources); + Graph graph(kNumSources + kNumTargets, kNumSources * kNumTargets); + LinearSumAssignment assignment(graph, kNumSources); for (NodeIndex source = 0; source < kNumSources; ++source) { for (NodeIndex target = 0; target < kNumTargets; ++target) { ArcIndex arc = graph.AddArc(source, kNumSources + target); @@ -52,8 +58,8 @@ void AnotherAssignment() { 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 assignment(graph, kSize); + Graph graph(2 * kSize, kSize * kSize); + LinearSumAssignment assignment(graph, kSize); for (int i = 0; i < kSize; ++i) { CHECK_EQ(kSize, matrice[i].size()); for (int j = 0; j < kSize; ++j) { diff --git a/examples/cpp/linear_programming.cc b/examples/cpp/linear_programming.cc index 94639e3483..a4c8366d11 100644 --- a/examples/cpp/linear_programming.cc +++ b/examples/cpp/linear_programming.cc @@ -117,7 +117,7 @@ void RunAllExamples() { RunLinearProgrammingExample("GLPK_LP"); RunLinearProgrammingExample("XPRESS_LP"); RunLinearProgrammingExample("PDLP"); - RunLinearProgrammingExample("HIGHS"); + RunLinearProgrammingExample("HIGHS_LP"); } } // namespace operations_research diff --git a/examples/cpp/max_flow.cc b/examples/cpp/max_flow.cc index a99e9b4983..70a8db8e75 100644 --- a/examples/cpp/max_flow.cc +++ b/examples/cpp/max_flow.cc @@ -11,16 +11,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ortools/graph/max_flow.h" - #include #include #include "absl/flags/flag.h" #include "ortools/base/init_google.h" #include "ortools/base/logging.h" +#include "ortools/graph/generic_max_flow.h" +#include "ortools/graph/graph.h" namespace operations_research { + +using Graph = ::util::ReverseArcListGraph<>; +using NodeIndex = Graph::NodeIndex; +using ArcIndex = Graph::ArcIndex; +using MaxFlowT = GenericMaxFlow; +using FlowQuantity = MaxFlow::FlowQuantityT; + void SolveMaxFlow() { const int num_nodes = 5; // Add each arc @@ -30,8 +37,8 @@ void SolveMaxFlow() { 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}}; - StarGraph graph(num_nodes, arcs.size()); - MaxFlow max_flow(&graph, 0, num_nodes - 1); + Graph graph(num_nodes, arcs.size()); + MaxFlowT max_flow(&graph, 0, num_nodes - 1); for (const auto& it : arcs) { ArcIndex arc = graph.AddArc(it.first.first, it.first.second); max_flow.SetArcCapacity(arc, it.second); @@ -42,7 +49,7 @@ void SolveMaxFlow() { // Find the maximum flow between node 0 and node 4. max_flow.Solve(); - if (MaxFlow::OPTIMAL != max_flow.status()) { + if (MaxFlowStatusClass::OPTIMAL != max_flow.status()) { LOG(FATAL) << "Solving the max flow is not optimal!"; } FlowQuantity total_flow = max_flow.GetOptimalFlow(); diff --git a/examples/cpp/min_cost_flow.cc b/examples/cpp/min_cost_flow.cc index 7c4dbef571..7f0a068eaf 100644 --- a/examples/cpp/min_cost_flow.cc +++ b/examples/cpp/min_cost_flow.cc @@ -41,33 +41,32 @@ void SolveMinCostFlow() { {{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); + SimpleMinCostFlow min_cost_flow; for (const auto& it : arcs) { - ArcIndex arc = graph.AddArc(it.nodes.first, it.nodes.second); - min_cost_flow.SetArcCapacity(arc, it.capacity); - min_cost_flow.SetArcUnitCost(arc, it.unit_cost); + min_cost_flow.AddArcWithCapacityAndUnitCost(it.nodes.first, it.nodes.second, + it.capacity, it.unit_cost); } for (const auto& it : supplies) { min_cost_flow.SetNodeSupply(it.first, it.second); } - LOG(INFO) << "Solving min cost flow with: " << graph.num_nodes() - << " nodes, and " << graph.num_arcs() << " arcs."; + LOG(INFO) << "Solving min cost flow with: " << min_cost_flow.NumNodes() + << " nodes, and " << min_cost_flow.NumArcs() << " arcs."; // Find the maximum flow between node 0 and node 4. - min_cost_flow.Solve(); - if (MinCostFlow::OPTIMAL != min_cost_flow.status()) { + const auto status = min_cost_flow.Solve(); + if (status != SimpleMinCostFlow::OPTIMAL) { LOG(FATAL) << "Solving the max flow is not optimal!"; } - FlowQuantity total_flow_cost = min_cost_flow.GetOptimalCost(); + FlowQuantity total_flow_cost = min_cost_flow.OptimalCost(); LOG(INFO) << "Minimum cost flow: " << total_flow_cost; LOG(INFO) << ""; LOG(INFO) << "Arc : Flow / Capacity / Cost"; for (int i = 0; i < arcs.size(); ++i) { - LOG(INFO) << graph.Tail(i) << " -> " << graph.Head(i) << ": " - << min_cost_flow.Flow(i) << " / " << min_cost_flow.Capacity(i) - << " / " << min_cost_flow.UnitCost(i); + LOG(INFO) << min_cost_flow.Tail(i) << " -> " << min_cost_flow.Head(i) + << ": " << min_cost_flow.Flow(i) << " / " + << min_cost_flow.Capacity(i) << " / " + << min_cost_flow.UnitCost(i); } } } // namespace operations_research diff --git a/examples/cpp/parse_dimacs_assignment.h b/examples/cpp/parse_dimacs_assignment.h index f2ebab6091..cbd684a44d 100644 --- a/examples/cpp/parse_dimacs_assignment.h +++ b/examples/cpp/parse_dimacs_assignment.h @@ -30,25 +30,23 @@ #include "absl/flags/flag.h" #include "absl/log/check.h" #include "absl/strings/string_view.h" -#include "ortools/graph/ebert_graph.h" #include "ortools/graph/linear_assignment.h" #include "ortools/util/filelineiter.h" ABSL_FLAG(bool, assignment_maximize_cost, false, "Negate costs so a max-cost assignment is found."); -ABSL_FLAG(bool, assignment_optimize_layout, true, - "Optimize graph layout for speed."); namespace operations_research { -template -class LinearSumAssignment; - template class DimacsAssignmentParser { public: + using NodeIndex = GraphType::NodeIndex; + using ArcIndex = GraphType::ArcIndex; + using CostValue = LinearSumAssignment::CostValueT; + explicit DimacsAssignmentParser(absl::string_view filename) - : filename_(filename), graph_builder_(nullptr), assignment_(nullptr) {} + : filename_(filename), graph_(nullptr), assignment_(nullptr) {} // Reads an assignment problem description from the given file in // DIMACS format and returns a LinearSumAssignment object representing @@ -95,7 +93,7 @@ class DimacsAssignmentParser { ErrorTrackingState state_; - AnnotatedGraphBuildManager* graph_builder_; + std::unique_ptr graph_; LinearSumAssignment* assignment_; }; @@ -122,8 +120,7 @@ void DimacsAssignmentParser::ParseProblemLine( } state_.num_arcs = num_arcs; - graph_builder_ = new AnnotatedGraphBuildManager( - num_nodes, num_arcs, absl::GetFlag(FLAGS_assignment_optimize_layout)); + graph_ = std::make_unique(num_nodes, num_arcs); } template @@ -146,7 +143,7 @@ void DimacsAssignmentParser::ParseNodeLine(const std::string& line) { template void DimacsAssignmentParser::ParseArcLine(const std::string& line) { - if (graph_builder_ == nullptr) { + if (graph_ == nullptr) { state_.bad = true; state_.reason = "Problem specification line must precede any arc specification."; @@ -167,7 +164,7 @@ void DimacsAssignmentParser::ParseArcLine(const std::string& line) { state_.reason = "Syntax error in arc descriptor."; state_.bad_line.reset(new std::string(line)); } - ArcIndex arc = graph_builder_->AddArc(tail - 1, head - 1); + ArcIndex arc = graph_->AddArc(tail - 1, head - 1); assignment_->SetArcCost( arc, absl::GetFlag(FLAGS_assignment_maximize_cost) ? -cost : cost); } @@ -241,23 +238,17 @@ LinearSumAssignment* DimacsAssignmentParser::Parse( *error_message = *error_message + ": \"" + *state_.bad_line + "\""; return nullptr; } - if (graph_builder_ == nullptr) { + if (graph_ == nullptr) { *error_message = "empty graph description"; return nullptr; } - std::unique_ptr > cycle_handler( - assignment_->ArcAnnotationCycleHandler()); - GraphType* graph = graph_builder_->Graph(cycle_handler.get()); - if (graph == nullptr) { - *error_message = "unable to create compact static graph"; - return nullptr; - } - assignment_->SetGraph(graph); + graph_->Build(); + assignment_->SetGraph(graph_.get()); *error_message = ""; // Return a handle on the graph to the caller so the caller can free // the graph's memory, because the LinearSumAssignment object does // not take ownership of the graph and hence will not free it. - *graph_handle = graph; + *graph_handle = graph_.release(); return assignment_; } diff --git a/examples/cpp/pdlp_solve.cc b/examples/cpp/pdlp_solve.cc index 1a86d85eb9..fb4d052c92 100644 --- a/examples/cpp/pdlp_solve.cc +++ b/examples/cpp/pdlp_solve.cc @@ -112,7 +112,7 @@ void Solve(const std::string& input, absl::string_view params_str, absl::StrAppend( &sol_string, "=obj= ", RoundTripDoubleFormat(convergence_information->primal_objective()), - "\n"); + "\n"); for (int64_t i = 0; i < result.primal_solution.size(); ++i) { std::string name; if (qp.variable_names.has_value()) { diff --git a/examples/cpp/print_dimacs_assignment.h b/examples/cpp/print_dimacs_assignment.h index 4733eeb007..51fd178312 100644 --- a/examples/cpp/print_dimacs_assignment.h +++ b/examples/cpp/print_dimacs_assignment.h @@ -21,20 +21,16 @@ #include #include -#include "absl/status/status.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "ortools/base/file.h" #include "ortools/base/helpers.h" #include "ortools/base/logging.h" -#include "ortools/graph/ebert_graph.h" +#include "ortools/base/options.h" #include "ortools/graph/linear_assignment.h" namespace operations_research { -template -class LinearSumAssignment; - // Given a LinearSumAssignment object representing an assignment problem // description, outputs the problem in DIMACS format in the output file. // For a description of the format, see @@ -42,13 +38,6 @@ class LinearSumAssignment; template void PrintDimacsAssignmentProblem( const LinearSumAssignment& assignment, - const TailArrayManager& tail_array_manager, - absl::string_view output_filename); - -template -void PrintDimacsAssignmentProblem( - const LinearSumAssignment& assignment, - const TailArrayManager& tail_array_manager, absl::string_view output_filename) { File* output; CHECK_OK(file::Open(output_filename, "w", &output, file::Defaults())); @@ -64,11 +53,7 @@ void PrintDimacsAssignmentProblem( CHECK_OK(file::WriteString(output, output_line, file::Defaults())); } - tail_array_manager.BuildTailArrayFromAdjacencyListsIfForwardGraph(); - - for (typename GraphType::ArcIterator arc_it(assignment.Graph()); arc_it.Ok(); - arc_it.Next()) { - ArcIndex arc = arc_it.Index(); + for (const auto& arc : graph.AllForwardArcs()) { output_line = absl::StrFormat("a %d %d %d\n", graph.Tail(arc) + 1, graph.Head(arc) + 1, assignment.ArcCost(arc)); CHECK_OK(file::WriteString(output, output_line, file::Defaults())); diff --git a/examples/tests/issue260.py b/examples/tests/issue260.py deleted file mode 100755 index 7a78566873..0000000000 --- a/examples/tests/issue260.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python3 -#from ortools.constraint_solver import pywrapcp -from ortools.sat.python import cp_model - -model = cp_model.CpModel() -y = model.NewIntVar(0, 3, 'y') -y == None - -#solver = pywrapcp.Solver('my solver') -#x = solver.IntVar(0, 3, 'var_name') -#x == None