fix examples

This commit is contained in:
Laurent Perron
2024-12-29 19:21:42 +01:00
parent 6be2ba21e9
commit a52d00b42b
12 changed files with 71 additions and 84 deletions

View File

@@ -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();

View File

@@ -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<int>& touched_cards) {
int ComputeNewCost(absl::Span<const int> touched_cards) {
ClearBitset();
int cost_delta = 0;
for (int i = 0; i < touched_cards.size(); ++i) {

View File

@@ -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<Graph>::CostValue;
using FlowQuantity = GenericMinCostFlow<Graph>::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<Graph> 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<Graph> 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) {

View File

@@ -16,6 +16,7 @@
#include <string>
#include <vector>
#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

View File

@@ -11,16 +11,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <cstdlib>
#include <vector>
#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<NodeIndex, ArcIndex>;
// 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<ForwardStarGraph> assignment(graph, kNumSources);
Graph graph(kNumSources + kNumTargets, kNumSources * kNumTargets);
LinearSumAssignment<Graph, CostValue> 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<std::vector<int>> matrice(
{{8, 7, 9, 9}, {5, 2, 7, 8}, {6, 1, 4, 9}, {2, 3, 2, 6}});
const int kSize = matrice.size();
ForwardStarGraph graph(2 * kSize, kSize * kSize);
LinearSumAssignment<ForwardStarGraph> assignment(graph, kSize);
Graph graph(2 * kSize, kSize * kSize);
LinearSumAssignment<Graph, CostValue> assignment(graph, kSize);
for (int i = 0; i < kSize; ++i) {
CHECK_EQ(kSize, matrice[i].size());
for (int j = 0; j < kSize; ++j) {

View File

@@ -117,7 +117,7 @@ void RunAllExamples() {
RunLinearProgrammingExample("GLPK_LP");
RunLinearProgrammingExample("XPRESS_LP");
RunLinearProgrammingExample("PDLP");
RunLinearProgrammingExample("HIGHS");
RunLinearProgrammingExample("HIGHS_LP");
}
} // namespace operations_research

View File

@@ -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 <utility>
#include <vector>
#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<Graph>;
using FlowQuantity = MaxFlow::FlowQuantityT;
void SolveMaxFlow() {
const int num_nodes = 5;
// Add each arc
@@ -30,8 +37,8 @@ void SolveMaxFlow() {
std::vector<std::pair<std::pair<NodeIndex, NodeIndex>, FlowQuantity> > arcs =
{{{0, 1}, 20}, {{0, 2}, 30}, {{0, 3}, 10}, {{1, 2}, 40}, {{1, 4}, 30},
{{2, 3}, 10}, {{2, 4}, 20}, {{3, 2}, 5}, {{3, 4}, 20}};
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();

View File

@@ -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

View File

@@ -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 <typename GraphType>
class LinearSumAssignment;
template <typename GraphType>
class DimacsAssignmentParser {
public:
using NodeIndex = GraphType::NodeIndex;
using ArcIndex = GraphType::ArcIndex;
using CostValue = LinearSumAssignment<GraphType>::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<GraphType>* graph_builder_;
std::unique_ptr<GraphType> graph_;
LinearSumAssignment<GraphType>* assignment_;
};
@@ -122,8 +120,7 @@ void DimacsAssignmentParser<GraphType>::ParseProblemLine(
}
state_.num_arcs = num_arcs;
graph_builder_ = new AnnotatedGraphBuildManager<GraphType>(
num_nodes, num_arcs, absl::GetFlag(FLAGS_assignment_optimize_layout));
graph_ = std::make_unique<GraphType>(num_nodes, num_arcs);
}
template <typename GraphType>
@@ -146,7 +143,7 @@ void DimacsAssignmentParser<GraphType>::ParseNodeLine(const std::string& line) {
template <typename GraphType>
void DimacsAssignmentParser<GraphType>::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<GraphType>::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<GraphType>* DimacsAssignmentParser<GraphType>::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<PermutationCycleHandler<ArcIndex> > 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_;
}

View File

@@ -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()) {

View File

@@ -21,20 +21,16 @@
#include <cstdio>
#include <string>
#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 <typename GraphType>
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 <typename GraphType>
void PrintDimacsAssignmentProblem(
const LinearSumAssignment<GraphType>& assignment,
const TailArrayManager<GraphType>& tail_array_manager,
absl::string_view output_filename);
template <typename GraphType>
void PrintDimacsAssignmentProblem(
const LinearSumAssignment<GraphType>& assignment,
const TailArrayManager<GraphType>& 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()));

View File

@@ -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