OR-Tools  9.0
set_covering_parser.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
15 
16 #include <cstdint>
17 
18 #include "absl/strings/numbers.h"
19 #include "absl/strings/str_split.h"
21 
22 namespace operations_research {
23 namespace scp {
24 
25 ScpParser::ScpParser() : section_(INIT), line_(0), remaining_(0), current_(0) {}
26 
27 bool ScpParser::LoadProblem(const std::string& filename, Format format,
28  ScpData* data) {
29  section_ = INIT;
30  line_ = 0;
31  remaining_ = 0;
32  current_ = 0;
33 
34  for (const std::string& line : FileLines(filename)) {
35  ProcessLine(line, format, data);
36  if (section_ == ERROR) return false;
37  }
38  return section_ == END;
39 }
40 
41 void ScpParser::ProcessLine(const std::string& line, Format format,
42  ScpData* data) {
43  line_++;
44  const std::vector<std::string> words =
45  absl::StrSplit(line, absl::ByAnyChar(" :\t\r"), absl::SkipEmpty());
46  switch (section_) {
47  case INIT: {
48  if (words.size() != 2) {
49  LogError(line, "Problem reading the size of the problem");
50  return;
51  }
52  const int num_rows = strtoint32(words[0]);
53  const int num_columns = strtoint32(words[1]);
54  data->SetProblemSize(num_rows, num_columns);
55  current_ = 0;
56  switch (format) {
57  case SCP_FORMAT: {
58  section_ = COSTS;
59  break;
60  }
61  case RAILROAD_FORMAT: {
62  section_ = COLUMN;
63  break;
64  }
65  case TRIPLET_FORMAT: {
66  section_ = COLUMN;
67  break;
68  }
69  case SPP_FORMAT: {
70  section_ = COLUMN;
71  data->set_is_set_partitioning(true);
72  break;
73  }
74  }
75  break;
76  }
77  case COSTS: {
78  const int num_items = words.size();
79  if (current_ + num_items > data->num_columns()) {
80  LogError(line, "Too many cost items");
81  return;
82  }
83  for (int i = 0; i < num_items; ++i) {
84  data->SetColumnCost(current_++, strtoint32(words[i]));
85  }
86  if (current_ == data->num_columns()) {
87  section_ = NUM_COLUMNS_IN_ROW;
88  current_ = 0;
89  }
90  break;
91  }
92  case COLUMN: {
93  switch (format) {
94  case SCP_FORMAT: {
95  LogError(line, "Wrong state in the loader");
96  return;
97  }
98  case RAILROAD_FORMAT:
99  ABSL_FALLTHROUGH_INTENDED;
100  case SPP_FORMAT: {
101  if (words.size() < 2) {
102  LogError(line, "Column declaration too short");
103  return;
104  }
105  const int cost = strtoint32(words[0]);
106  data->SetColumnCost(current_, cost);
107  const int num_items = strtoint32(words[1]);
108  if (words.size() != 2 + num_items) {
109  LogError(line, "Mistatch in column declaration");
110  return;
111  }
112  for (int i = 0; i < num_items; ++i) {
113  const int row = strtoint32(words[i + 2]) - 1; // 1 based.
114  data->AddRowInColumn(row, current_);
115  }
116  current_++;
117  if (current_ == data->num_columns()) {
118  section_ = format == RAILROAD_FORMAT ? END : NUM_NON_ZEROS;
119  }
120  break;
121  }
122  case TRIPLET_FORMAT: {
123  if (words.size() != 3) {
124  LogError(line, "Column declaration does not contain 3 rows");
125  break;
126  }
127  data->SetColumnCost(current_, 1);
128  for (int i = 0; i < 3; ++i) {
129  const int row = strtoint32(words[i]) - 1; // 1 based.
130  data->AddRowInColumn(row, current_);
131  }
132  current_++;
133  if (current_ == data->num_columns()) {
134  section_ = END;
135  }
136  break;
137  }
138  }
139  break;
140  }
141  case NUM_COLUMNS_IN_ROW: {
142  if (words.size() != 1) {
143  LogError(line, "The header of a column should be one number");
144  return;
145  }
146  remaining_ = strtoint32(words[0]);
147  section_ = ROW;
148  break;
149  }
150  case ROW: {
151  const int num_items = words.size();
152  if (num_items > remaining_) {
153  LogError(line, "Too many columns in a row declaration");
154  return;
155  }
156  for (const std::string& w : words) {
157  remaining_--;
158  const int column = strtoint32(w) - 1; // 1 based.
159  data->AddRowInColumn(current_, column);
160  }
161  if (remaining_ == 0) {
162  current_++;
163  if (current_ == data->num_rows()) {
164  section_ = END;
165  } else {
166  section_ = NUM_COLUMNS_IN_ROW;
167  }
168  }
169  break;
170  }
171  case NUM_NON_ZEROS: {
172  if (words.size() != 1) {
173  LogError(line, "The header of a column should be one number");
174  return;
175  }
176  section_ = END;
177  break;
178  }
179  case END: {
180  break;
181  }
182  case ERROR: {
183  break;
184  }
185  }
186 }
187 
188 void ScpParser::LogError(const std::string& line, const std::string& message) {
189  LOG(ERROR) << "Error on line " << line_ << ": " << message << "(" << line
190  << ")";
191  section_ = ERROR;
192 }
193 
194 int ScpParser::strtoint32(const std::string& word) {
195  int result;
196  CHECK(absl::SimpleAtoi(word, &result));
197  return result;
198 }
199 
200 int64_t ScpParser::strtoint64(const std::string& word) {
201  int64_t result;
202  CHECK(absl::SimpleAtoi(word, &result));
203  return result;
204 }
205 
206 } // namespace scp
207 } // namespace operations_research
#define CHECK(condition)
Definition: base/logging.h:498
#define LOG(severity)
Definition: base/logging.h:423
void SetProblemSize(int num_rows, int num_columns)
void SetColumnCost(int column_id, int cost)
void AddRowInColumn(int row, int column)
bool LoadProblem(const std::string &filename, Format format, ScpData *data)
RowIndex row
Definition: markowitz.cc:182
Collection of objects used to extend the Constraint Solver library.
int64_t cost
int64_t current_
Definition: search.cc:2968
std::string message
Definition: trace.cc:398