polish code
This commit is contained in:
@@ -348,6 +348,7 @@ cc_library(
|
||||
srcs = ["set_cover_reader.cc"],
|
||||
hdrs = ["set_cover_reader.h"],
|
||||
deps = [
|
||||
":set_cover_cc_proto",
|
||||
":set_cover_model",
|
||||
"//ortools/base:file",
|
||||
"//ortools/util:filelineiter",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
@@ -51,7 +52,7 @@ class HungarianOptimizer {
|
||||
private:
|
||||
typedef void (HungarianOptimizer::*Step)();
|
||||
|
||||
typedef enum { NONE, PRIME, STAR } Mark;
|
||||
typedef enum : uint8_t { 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
|
||||
|
||||
@@ -39,8 +39,18 @@ using ::operations_research::GuidedLocalSearch;
|
||||
using ::operations_research::GuidedTabuSearch;
|
||||
using ::operations_research::LazyElementDegreeSolutionGenerator;
|
||||
using ::operations_research::RandomSolutionGenerator;
|
||||
using ::operations_research::ReadBeasleySetCoverProblem;
|
||||
using ::operations_research::ReadRailSetCoverProblem;
|
||||
using ::operations_research::ReadFimiDat;
|
||||
using ::operations_research::ReadOrlibRail;
|
||||
using ::operations_research::ReadOrlibScp;
|
||||
using ::operations_research::ReadSetCoverProto;
|
||||
using ::operations_research::ReadSetCoverSolutionProto;
|
||||
using ::operations_research::ReadSetCoverSolutionText;
|
||||
using ::operations_research::WriteOrlibRail;
|
||||
using ::operations_research::WriteOrlibScp;
|
||||
using ::operations_research::WriteSetCoverProto;
|
||||
using ::operations_research::WriteSetCoverSolutionProto;
|
||||
using ::operations_research::WriteSetCoverSolutionText;
|
||||
|
||||
using ::operations_research::SetCoverDecision;
|
||||
using ::operations_research::SetCoverInvariant;
|
||||
using ::operations_research::SetCoverModel;
|
||||
@@ -550,8 +560,17 @@ PYBIND11_MODULE(set_cover, m) {
|
||||
});
|
||||
|
||||
// set_cover_reader.h
|
||||
m.def("read_beasly_set_cover_problem", &ReadBeasleySetCoverProblem);
|
||||
m.def("read_rail_set_cover_problem", &ReadRailSetCoverProblem);
|
||||
m.def("read_orlib_scp", &ReadOrlibScp);
|
||||
m.def("read_orlib_rail", &ReadOrlibRail);
|
||||
m.def("read_fimi_dat", &ReadFimiDat);
|
||||
m.def("read_set_cover_proto", &ReadSetCoverProto);
|
||||
m.def("write_orlib_scp", &WriteOrlibScp);
|
||||
m.def("write_orlib_rail", &WriteOrlibRail);
|
||||
m.def("write_set_cover_proto", &WriteSetCoverProto);
|
||||
m.def("write_set_cover_solution_text", &WriteSetCoverSolutionText);
|
||||
m.def("write_set_cover_solution_proto", &WriteSetCoverSolutionProto);
|
||||
m.def("read_set_cover_solution_text", &ReadSetCoverSolutionText);
|
||||
m.def("read_set_cover_solution_proto", &ReadSetCoverSolutionProto);
|
||||
|
||||
// set_cover_lagrangian.h
|
||||
// TODO(user): add support for SetCoverLagrangian.
|
||||
|
||||
@@ -16,12 +16,18 @@
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "ortools/algorithms/set_cover.pb.h"
|
||||
#include "ortools/algorithms/set_cover_model.h"
|
||||
#include "ortools/base/file.h"
|
||||
#include "ortools/base/helpers.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/options.h"
|
||||
#include "ortools/util/filelineiter.h"
|
||||
@@ -31,6 +37,8 @@ namespace operations_research {
|
||||
class SetCoverReader {
|
||||
public:
|
||||
explicit SetCoverReader(File* file);
|
||||
absl::string_view GetLine() { return line_; }
|
||||
void Advance() { ++line_iter_; }
|
||||
absl::string_view GetNextToken();
|
||||
double ParseNextDouble();
|
||||
int64_t ParseNextInteger();
|
||||
@@ -90,7 +98,8 @@ int64_t SetCoverReader::ParseNextInteger() {
|
||||
return value;
|
||||
}
|
||||
|
||||
SetCoverModel ReadBeasleySetCoverProblem(absl::string_view filename) {
|
||||
// This is a row-based format where the elements are 1-indexed.
|
||||
SetCoverModel ReadOrlibScp(absl::string_view filename) {
|
||||
SetCoverModel model;
|
||||
File* file(file::OpenOrDie(filename, "r", file::Defaults()));
|
||||
SetCoverReader reader(file);
|
||||
@@ -104,6 +113,7 @@ SetCoverModel ReadBeasleySetCoverProblem(absl::string_view filename) {
|
||||
for (ElementIndex element : ElementRange(num_rows)) {
|
||||
const RowEntryIndex row_size(reader.ParseNextInteger());
|
||||
for (RowEntryIndex entry(0); entry < row_size; ++entry) {
|
||||
// Correct the 1-indexing.
|
||||
const int subset(reader.ParseNextInteger() - 1);
|
||||
model.AddElementToSubset(element.value(), subset);
|
||||
}
|
||||
@@ -113,21 +123,23 @@ SetCoverModel ReadBeasleySetCoverProblem(absl::string_view filename) {
|
||||
return model;
|
||||
}
|
||||
|
||||
SetCoverModel ReadRailSetCoverProblem(absl::string_view filename) {
|
||||
// This is a column-based format where the elements are 1-indexed.
|
||||
SetCoverModel ReadOrlibRail(absl::string_view filename) {
|
||||
SetCoverModel model;
|
||||
File* file(file::OpenOrDie(filename, "r", file::Defaults()));
|
||||
SetCoverReader reader(file);
|
||||
const ElementIndex num_rows(reader.ParseNextInteger());
|
||||
const BaseInt num_cols(reader.ParseNextInteger());
|
||||
model.ReserveNumSubsets(num_cols);
|
||||
for (int i(0); i < num_cols; ++i) {
|
||||
for (int subset(0); subset < num_cols; ++subset) {
|
||||
const double cost(reader.ParseNextDouble());
|
||||
model.SetSubsetCost(i, cost);
|
||||
model.SetSubsetCost(subset, cost);
|
||||
const ColumnEntryIndex column_size(reader.ParseNextInteger());
|
||||
model.ReserveNumElementsInSubset(i, column_size.value());
|
||||
model.ReserveNumElementsInSubset(column_size.value(), subset);
|
||||
for (const ColumnEntryIndex _ : ColumnEntryRange(column_size)) {
|
||||
// Correct the 1-indexing.
|
||||
const ElementIndex element(reader.ParseNextInteger() - 1);
|
||||
model.AddElementToSubset(element.value(), i);
|
||||
model.AddElementToSubset(element.value(), subset);
|
||||
}
|
||||
}
|
||||
file->Close(file::Defaults()).IgnoreError();
|
||||
@@ -135,4 +147,197 @@ SetCoverModel ReadRailSetCoverProblem(absl::string_view filename) {
|
||||
return model;
|
||||
}
|
||||
|
||||
SetCoverModel ReadFimiDat(absl::string_view filename) {
|
||||
SetCoverModel model;
|
||||
for (const std::string& line : FileLines(filename)) {
|
||||
SubsetIndex subset(0);
|
||||
std::vector<std::string> elements = absl::StrSplit(line, ' ');
|
||||
if (elements.back().empty() || elements.back()[0] == '\0') {
|
||||
elements.pop_back();
|
||||
}
|
||||
model.AddEmptySubset(1);
|
||||
for (const std::string& number : elements) {
|
||||
BaseInt element;
|
||||
CHECK(absl::SimpleAtoi(number, &element));
|
||||
CHECK_GT(element, 0);
|
||||
// Correct the 1-indexing.
|
||||
model.AddElementToLastSubset(ElementIndex(element - 1));
|
||||
}
|
||||
++subset;
|
||||
}
|
||||
model.CreateSparseRowView();
|
||||
return model;
|
||||
}
|
||||
|
||||
SetCoverModel ReadSetCoverProto(absl::string_view filename, bool binary) {
|
||||
SetCoverModel model;
|
||||
SetCoverProto message;
|
||||
if (binary) {
|
||||
CHECK_OK(file::GetBinaryProto(filename, &message, file::Defaults()));
|
||||
} else {
|
||||
CHECK_OK(file::GetTextProto(filename, &message, file::Defaults()));
|
||||
}
|
||||
model.ImportModelFromProto(message);
|
||||
return model;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A class to write a line of text to a file.
|
||||
// The line is written in chunks of at most max_cols characters.
|
||||
class LineWriter {
|
||||
public:
|
||||
LineWriter(File* file, int max_cols)
|
||||
: num_cols_(0), max_cols_(max_cols), line_(), file_(file) {}
|
||||
~LineWriter() { Close(); }
|
||||
void Write(BaseInt value) {
|
||||
const std::string text = absl::StrCat(value, " ");
|
||||
const int text_size = text.size();
|
||||
if (num_cols_ + text_size > max_cols_) {
|
||||
CHECK_OK(file::WriteString(file_, absl::StrCat(line_, "\n"),
|
||||
file::Defaults()));
|
||||
line_.clear();
|
||||
} else {
|
||||
absl::StrAppend(&line_, text);
|
||||
num_cols_ += text_size;
|
||||
}
|
||||
}
|
||||
void Close() { CHECK_OK(file::WriteString(file_, line_, file::Defaults())); }
|
||||
|
||||
private:
|
||||
int num_cols_;
|
||||
int max_cols_;
|
||||
std::string line_;
|
||||
File* file_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void WriteOrlibScp(const SetCoverModel& model, absl::string_view filename) {
|
||||
const int kMaxCols = 80;
|
||||
File* file(file::OpenOrDie(filename, "w", file::Defaults()));
|
||||
CHECK_OK(file::WriteString(
|
||||
file, absl::StrCat(model.num_elements(), " ", model.num_subsets(), "\n"),
|
||||
file::Defaults()));
|
||||
LineWriter cost_writer(file, kMaxCols);
|
||||
for (const SubsetIndex subset : model.SubsetRange()) {
|
||||
cost_writer.Write(model.subset_costs()[subset]);
|
||||
}
|
||||
for (const ElementIndex element : model.ElementRange()) {
|
||||
CHECK_OK(file::WriteString(file,
|
||||
absl::StrCat(model.rows()[element].size(), "\n"),
|
||||
file::Defaults()));
|
||||
LineWriter row_writer(file, kMaxCols);
|
||||
for (const SubsetIndex subset : model.rows()[element]) {
|
||||
row_writer.Write(subset.value() + 1);
|
||||
}
|
||||
}
|
||||
file->Close(file::Defaults()).IgnoreError();
|
||||
}
|
||||
|
||||
// Beware the fact that elements written are converted to 1-indexed.
|
||||
void WriteOrlibRail(const SetCoverModel& model, absl::string_view filename) {
|
||||
const int kMaxCols = 80;
|
||||
File* file(file::OpenOrDie(filename, "w", file::Defaults()));
|
||||
CHECK_OK(file::WriteString(
|
||||
file, absl::StrCat(model.num_elements(), " ", model.num_subsets(), "\n"),
|
||||
file::Defaults()));
|
||||
for (const SubsetIndex subset : model.SubsetRange()) {
|
||||
CHECK_OK(
|
||||
file::WriteString(file,
|
||||
absl::StrCat(model.subset_costs()[subset], " ",
|
||||
model.columns()[subset].size(), "\n"),
|
||||
file::Defaults()));
|
||||
LineWriter writer(file, kMaxCols);
|
||||
for (const ElementIndex element : model.columns()[subset]) {
|
||||
writer.Write(element.value() + 1);
|
||||
}
|
||||
}
|
||||
file->Close(file::Defaults()).IgnoreError();
|
||||
}
|
||||
|
||||
void WriteSetCoverProto(const SetCoverModel& model, absl::string_view filename,
|
||||
bool binary) {
|
||||
const SetCoverProto message = model.ExportModelAsProto();
|
||||
if (binary) {
|
||||
CHECK_OK(file::SetBinaryProto(filename, message, file::Defaults()));
|
||||
} else {
|
||||
CHECK_OK(file::SetTextProto(filename, message, file::Defaults()));
|
||||
}
|
||||
}
|
||||
|
||||
SubsetBoolVector ReadSetCoverSolutionText(absl::string_view filename) {
|
||||
SubsetBoolVector solution;
|
||||
File* file(file::OpenOrDie(filename, "r", file::Defaults()));
|
||||
SetCoverReader reader(file);
|
||||
const BaseInt num_cols(reader.ParseNextInteger());
|
||||
solution.resize(num_cols, false);
|
||||
const BaseInt cardinality(reader.ParseNextInteger());
|
||||
for (int i = 0; i < cardinality; ++i) {
|
||||
// NOTE(user): The solution is 0-indexed.
|
||||
const SubsetIndex subset(reader.ParseNextInteger());
|
||||
solution[subset] = true;
|
||||
}
|
||||
file->Close(file::Defaults()).IgnoreError();
|
||||
return solution;
|
||||
}
|
||||
|
||||
SubsetBoolVector ReadSetCoverSolutionProto(absl::string_view filename,
|
||||
bool binary) {
|
||||
SubsetBoolVector solution;
|
||||
SetCoverSolutionResponse message;
|
||||
if (binary) {
|
||||
CHECK_OK(file::GetBinaryProto(filename, &message, file::Defaults()));
|
||||
} else {
|
||||
CHECK_OK(file::GetTextProto(filename, &message, file::Defaults()));
|
||||
}
|
||||
solution.resize(message.num_subsets(), false);
|
||||
// NOTE(user): The solution is 0-indexed.
|
||||
for (const BaseInt subset : message.subset()) {
|
||||
solution[SubsetIndex(subset)] = true;
|
||||
}
|
||||
return solution;
|
||||
}
|
||||
|
||||
void WriteSetCoverSolutionText(const SetCoverModel& model,
|
||||
const SubsetBoolVector& solution,
|
||||
absl::string_view filename) {
|
||||
File* file(file::OpenOrDie(filename, "w", file::Defaults()));
|
||||
BaseInt cardinality(0);
|
||||
Cost cost(0);
|
||||
for (SubsetIndex subset(0); subset.value() < solution.size(); ++subset) {
|
||||
if (solution[subset]) {
|
||||
++cardinality;
|
||||
cost += model.subset_costs()[subset];
|
||||
}
|
||||
}
|
||||
CHECK_OK(file::WriteString(
|
||||
file, absl::StrCat(solution.size(), " ", cardinality, " ", cost, "\n"),
|
||||
file::Defaults()));
|
||||
const int kMaxCols = 80;
|
||||
LineWriter writer(file, kMaxCols);
|
||||
for (BaseInt subset(0); subset < solution.size(); ++subset) {
|
||||
if (solution[SubsetIndex(subset)]) {
|
||||
writer.Write(subset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSetCoverSolutionProto(const SetCoverModel& model,
|
||||
const SubsetBoolVector& solution,
|
||||
absl::string_view filename, bool binary) {
|
||||
SetCoverSolutionResponse message;
|
||||
message.set_num_subsets(solution.size());
|
||||
Cost cost(0);
|
||||
for (SubsetIndex subset(0); subset.value() < solution.size(); ++subset) {
|
||||
if (solution[subset]) {
|
||||
message.add_subset(subset.value());
|
||||
cost += model.subset_costs()[subset];
|
||||
}
|
||||
}
|
||||
message.set_cost(cost);
|
||||
if (binary) {
|
||||
CHECK_OK(file::SetBinaryProto(filename, message, file::Defaults()));
|
||||
} else {
|
||||
CHECK_OK(file::SetTextProto(filename, message, file::Defaults()));
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -35,7 +35,9 @@ namespace operations_research {
|
||||
// for each column j, (j=1,...,n): the cost of the column c(j)
|
||||
// for each row i (i=1,...,m): the number of columns which cover
|
||||
// row i followed by a list of the columns which cover row i
|
||||
SetCoverModel ReadBeasleySetCoverProblem(absl::string_view filename);
|
||||
// The columns and rows are 1-indexed with this file format.
|
||||
// The translation to 0-indexing is done at read time.
|
||||
SetCoverModel ReadOrlibScp(absl::string_view filename);
|
||||
|
||||
// Reads a rail set cover problem and returns a SetCoverModel.
|
||||
// The format of these test problems is:
|
||||
@@ -43,7 +45,64 @@ SetCoverModel ReadBeasleySetCoverProblem(absl::string_view filename);
|
||||
// for each column j (j=1,...,n): the cost of the column, the
|
||||
// number of rows that it covers followed by a list of the rows
|
||||
// that it covers.
|
||||
SetCoverModel ReadRailSetCoverProblem(absl::string_view filename);
|
||||
// The columns and rows are 1-indexed with this file format.
|
||||
// The translation to 0-indexing is done at read time.
|
||||
SetCoverModel ReadOrlibRail(absl::string_view filename);
|
||||
|
||||
// Reads a file in the FIMI / .dat file format. FIMI stands for "Frequent
|
||||
// Itemset Mining Implementations".
|
||||
// The file is given column-by-column, with each column containing a space-
|
||||
// separated list of elements terminating with a newline. The elements are
|
||||
// 0-indexed.
|
||||
// The cost of each subset is 1.
|
||||
SetCoverModel ReadFimiDat(absl::string_view filename);
|
||||
|
||||
// Reads a set cover problem from a SetCoverProto.
|
||||
// The proto is either read from a binary (if binary is true) or a text file.
|
||||
SetCoverModel ReadSetCoverProto(absl::string_view filename, bool binary);
|
||||
|
||||
// Writers for the Beasley and Rail formats.
|
||||
// The translation of indices from 0 to 1-indexing is done at write time.
|
||||
void WriteOrlibScp(const SetCoverModel& model, absl::string_view filename);
|
||||
void WriteOrlibRail(const SetCoverModel& model, absl::string_view filename);
|
||||
|
||||
// Writes a set cover problem to a SetCoverProto.
|
||||
// The proto is either written to a binary (if binary is true) or a text file.
|
||||
// The model is modified (its columns are sorted) in-place when the proto is
|
||||
// generated.
|
||||
void WriteSetCoverProto(const SetCoverModel& model, absl::string_view filename,
|
||||
bool binary);
|
||||
|
||||
// Reads a set cover solution from a text file.
|
||||
// The format of the file is:
|
||||
// number of columns (n)
|
||||
// number of selected columns (k)
|
||||
// for each i (j=1,...,k): 1 if column[i] is selected, 0 otherwise.
|
||||
// The solution is 0-indexed.
|
||||
SubsetBoolVector ReadSetCoverSolutionText(absl::string_view filename);
|
||||
|
||||
// Reads a set cover solution from a SetCoverSolutionResponse proto.
|
||||
// The proto is either read from a binary (if binary is true) or a text file.
|
||||
// The solution is 0-indexed.
|
||||
SubsetBoolVector ReadSetCoverSolutionProto(absl::string_view filename,
|
||||
bool binary);
|
||||
|
||||
// Writes a set cover solution to a text file.
|
||||
// The format of the file is:
|
||||
// number of columns (n)
|
||||
// number of selected columns (k)
|
||||
// for each i (j=1,...,k): 1 if column[i] is selected, 0 otherwise.
|
||||
// The solution is 0-indexed.
|
||||
void WriteSetCoverSolutionText(const SetCoverModel& model,
|
||||
const SubsetBoolVector& solution,
|
||||
absl::string_view filename);
|
||||
|
||||
// Writes a set cover solution to a SetCoverSolutionResponse proto.
|
||||
// The proto is either written to a binary (if binary is true) or a text file.
|
||||
// The solution is 0-indexed.
|
||||
void WriteSetCoverSolutionProto(const SetCoverModel& model,
|
||||
const SubsetBoolVector& solution,
|
||||
absl::string_view filename, bool binary);
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ struct MatrixEntry {
|
||||
class SingletonUndo {
|
||||
public:
|
||||
// The type of a given operation.
|
||||
typedef enum {
|
||||
typedef enum : uint8_t {
|
||||
ZERO_COST_SINGLETON_COLUMN,
|
||||
SINGLETON_ROW,
|
||||
SINGLETON_COLUMN_IN_EQUALITY,
|
||||
@@ -662,7 +662,7 @@ class DoubletonFreeColumnPreprocessor final : public Preprocessor {
|
||||
void RecoverSolution(ProblemSolution* solution) const final;
|
||||
|
||||
private:
|
||||
enum RowChoice {
|
||||
enum RowChoice : int {
|
||||
DELETED = 0,
|
||||
MODIFIED = 1,
|
||||
// This is just a constant for the number of rows in a doubleton column.
|
||||
@@ -828,7 +828,7 @@ class DoubletonEqualityRowPreprocessor final : public Preprocessor {
|
||||
void RecoverSolution(ProblemSolution* solution) const final;
|
||||
|
||||
private:
|
||||
enum ColChoice {
|
||||
enum ColChoice : int {
|
||||
DELETED = 0,
|
||||
MODIFIED = 1,
|
||||
// For `for()` loops iterating over the ColChoice values and/or arrays.
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "ortools/base/helpers.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/options.h"
|
||||
@@ -179,7 +180,7 @@ class MPModelProtoExporter {
|
||||
// The sparse matrix must be passed as a vector of columns ('transpose').
|
||||
void AppendMpsColumns(
|
||||
bool integrality,
|
||||
const std::vector<std::vector<std::pair<int, double>>>& transpose,
|
||||
absl::Span<const std::vector<std::pair<int, double>>> transpose,
|
||||
std::string* output);
|
||||
|
||||
// Appends a line describing the bound of a variablenew-line if two columns
|
||||
@@ -722,7 +723,7 @@ void MPModelProtoExporter::AppendNewLineIfTwoColumns(std::string* output) {
|
||||
|
||||
void MPModelProtoExporter::AppendMpsColumns(
|
||||
bool integrality,
|
||||
const std::vector<std::vector<std::pair<int, double>>>& transpose,
|
||||
absl::Span<const std::vector<std::pair<int, double>>> transpose,
|
||||
std::string* output) {
|
||||
current_mps_column_ = 0;
|
||||
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
// Implements the minimum interface for a range-based for loop iterator.
|
||||
class FileLineIterator {
|
||||
public:
|
||||
enum {
|
||||
enum : int {
|
||||
DEFAULT = 0x0000,
|
||||
REMOVE_LINEFEED = DEFAULT,
|
||||
KEEP_LINEFEED = 0x0001, // Terminating \n in result.
|
||||
|
||||
Reference in New Issue
Block a user