25#include "absl/log/check.h"
26#include "absl/strings/numbers.h"
27#include "absl/strings/str_cat.h"
28#include "absl/strings/str_format.h"
29#include "absl/strings/str_split.h"
30#include "absl/strings/string_view.h"
31#include "ortools/algorithms/set_cover.pb.h"
49 size_t SkipBlanks(
size_t pos)
const;
50 size_t SkipNonBlanks(
size_t pos)
const;
52 absl::string_view line_;
65size_t SetCoverReader::SkipBlanks(
size_t pos)
const {
66 const size_t size = line_.size();
69 for (; pos < size && line_[pos] ==
' '; ++pos) {
72 for (; pos < size && std::isspace(line_[pos]); ++pos) {
77size_t SetCoverReader::SkipNonBlanks(
size_t pos)
const {
78 const size_t size = line_.size();
79 for (; pos < size && !std::isspace(line_[pos]); ++pos) {
85 const size_t size = line_.size();
86 start_pos_ = SkipBlanks(end_pos_);
87 if (start_pos_ >= size) {
90 start_pos_ = SkipBlanks(0);
92 end_pos_ = SkipNonBlanks(start_pos_);
93 return line_.substr(start_pos_, end_pos_ - start_pos_);
121 LOG_EVERY_N_SEC(INFO, 5)
122 << absl::StrFormat(
"Reading element %d (%.1f%%)", element.value(),
125 for (RowEntryIndex entry(0); entry < row_size; ++entry) {
131 LOG(INFO) <<
"Finished reading the model.";
145 for (
BaseInt subset(0); subset < num_cols; ++subset) {
146 LOG_EVERY_N_SEC(INFO, 5)
147 << absl::StrFormat(
"Reading subset %d (%.1f%%)", subset,
159 LOG(INFO) <<
"Finished reading the model.";
168 for (
const std::string& line :
FileLines(filename)) {
169 LOG_EVERY_N_SEC(INFO, 5)
170 << absl::StrFormat(
"Reading subset %d (%.1f%%)", subset,
172 std::vector<std::string> elements = absl::StrSplit(line,
' ');
173 if (elements.back().empty() || elements.back()[0] ==
'\0') {
177 for (
const std::string& number : elements) {
179 CHECK(absl::SimpleAtoi(number, &element));
180 CHECK_GT(element, 0);
186 LOG(INFO) <<
"Finished reading the model.";
193 SetCoverProto message;
212 : LineFormatter(
file,
std::numeric_limits<int64_t>::max()) {}
213 LineFormatter(File* file, int64_t max_cols)
214 : num_cols_(0), max_cols_(max_cols), line_(), file_(file) {}
215 ~LineFormatter() { CHECK(line_.empty()); }
217 void Append(absl::string_view text) {
218 const int text_size = text.size();
219 if (!text.empty() && text_size + num_cols_ > max_cols_) {
222 absl::StrAppend(&line_, text);
223 num_cols_ += text_size;
226 void Append(
BaseInt value) { Append(absl::StrCat(value,
" ")); }
228 void Append(
double value) { Append(absl::StrFormat(
"%.17g ", value)); }
247 LineFormatter formatter(
file);
250 formatter.FlushLine();
251 for (
const SubsetIndex subset : model.
SubsetRange()) {
254 formatter.FlushLine();
255 for (
const ElementIndex element : model.
ElementRange()) {
256 LOG_EVERY_N_SEC(INFO, 5)
257 << absl::StrFormat(
"Writing element %d (%.1f%%)", element.value(),
259 formatter.Append(absl::StrCat(model.
rows()[element].size(),
"\n"));
260 for (
const SubsetIndex subset : model.
rows()[element]) {
261 formatter.Append(subset.value() + 1);
263 formatter.FlushLine();
265 LOG(INFO) <<
"Finished writing the model.";
275 LineFormatter formatter(
file);
276 for (
const SubsetIndex subset : model.
SubsetRange()) {
277 LOG_EVERY_N_SEC(INFO, 5)
278 << absl::StrFormat(
"Writing subset %d (%.1f%%)", subset.value(),
281 formatter.Append(
static_cast<BaseInt>(model.
columns()[subset].size()));
282 for (
const ElementIndex element : model.
columns()[subset]) {
283 formatter.Append(element.value() + 1);
285 formatter.FlushLine();
287 LOG(INFO) <<
"Finished writing the model.";
308 for (
int i = 0; i < cardinality; ++i) {
320 SetCoverSolutionResponse message;
326 solution.resize(message.num_subsets(),
false);
328 for (
const BaseInt subset : message.subset()) {
329 solution[SubsetIndex(subset)] =
true;
336 absl::string_view filename) {
340 for (SubsetIndex subset(0); subset.value() <
solution.size(); ++subset) {
347 file, absl::StrCat(
solution.size(),
" ", cardinality,
" ", cost,
"\n"),
349 LineFormatter formatter(
file);
351 if (
solution[SubsetIndex(subset)]) {
352 formatter.Append(subset);
355 formatter.FlushLine();
361 absl::string_view filename,
bool binary) {
362 SetCoverSolutionResponse message;
363 message.set_num_subsets(
solution.size());
365 for (SubsetIndex subset(0); subset.value() <
solution.size(); ++subset) {
367 message.add_subset(subset.value());
371 message.set_cost(cost);
Implements the minimum interface for a range-based for loop iterator.
Main class for describing a weighted set-covering problem.
void ImportModelFromProto(const SetCoverProto &message)
Imports the model from a SetCoverProto.
void ReserveNumElementsInSubset(BaseInt num_elements, BaseInt subset)
Reserves num_elements rows in the column indexed by subset.
util_intops::StrongIntRange< ElementIndex > ElementRange() const
void AddElementToLastSubset(BaseInt element)
void AddEmptySubset(Cost cost)
const SparseRowView & rows() const
Row view of the set covering problem.
void ReserveNumSubsets(BaseInt num_subsets)
Reserves num_subsets columns in the model.
BaseInt num_elements() const
util_intops::StrongIntRange< SubsetIndex > SubsetRange() const
Access to the ranges of subsets and elements.
void AddElementToSubset(BaseInt element, BaseInt subset)
void SetSubsetCost(BaseInt subset, Cost cost)
const SubsetCostVector & subset_costs() const
Vector of costs for each subset.
void CreateSparseRowView()
SetCoverProto ExportModelAsProto() const
const SparseColumnView & columns() const
Column view of the set covering problem.
BaseInt num_subsets() const
int64_t ParseNextInteger()
absl::string_view GetNextToken()
SetCoverReader(File *file)
absl::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::Status WriteString(File *file, absl::string_view contents, Options options)
absl::Status GetTextProto(absl::string_view filename, google::protobuf::Message *proto, Options options)
absl::Status GetBinaryProto(const absl::string_view filename, google::protobuf::Message *proto, Options options)
File * OpenOrDie(absl::string_view filename, absl::string_view mode, Options options)
In SWIG mode, we don't want anything besides these top-level includes.
SetCoverModel ReadOrlibScp(absl::string_view filename)
This is a row-based format where the elements are 1-indexed.
void WriteSetCoverProto(const SetCoverModel &model, absl::string_view filename, bool binary)
SetCoverModel ReadSetCoverProto(absl::string_view filename, bool binary)
void WriteSetCoverSolutionProto(const SetCoverModel &model, const SubsetBoolVector &solution, absl::string_view filename, bool binary)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
util_intops::StrongIntRange< SubsetIndex > SubsetRange
SubsetBoolVector ReadSetCoverSolutionText(absl::string_view filename)
util_intops::StrongIntRange< ColumnEntryIndex > ColumnEntryRange
void WriteSetCoverSolutionText(const SetCoverModel &model, const SubsetBoolVector &solution, absl::string_view filename)
SetCoverModel ReadOrlibRail(absl::string_view filename)
This is a column-based format where the elements are 1-indexed.
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
void WriteOrlibScp(const SetCoverModel &model, absl::string_view filename)
void WriteOrlibRail(const SetCoverModel &model, absl::string_view filename)
Beware the fact that elements written are converted to 1-indexed.
SubsetBoolVector ReadSetCoverSolutionProto(absl::string_view filename, bool binary)
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.
util_intops::StrongIntRange< ElementIndex > ElementRange
SetCoverModel ReadFimiDat(absl::string_view filename)