148 : interpret_cnf_as_max_sat_(false),
149 wcnf_use_strong_slack_(wcnf_use_strong_slack) {}
160 bool Load(
const std::string& filename, LinearBooleanProblem* problem) {
162 problem->set_name(ExtractProblemName(filename));
164 return LoadInternal(filename, &wrapper);
166 bool Load(
const std::string& filename, CpModelProto* problem) {
168 problem->set_name(ExtractProblemName(filename));
170 return LoadInternal(filename, &wrapper);
174 template <
class Problem>
175 bool LoadInternal(
const std::string& filename, Problem* problem) {
177 objective_offset_ = 0;
178 positive_literal_to_weight_.clear();
180 end_marker_seen_ =
false;
182 num_skipped_soft_clauses_ = 0;
183 num_singleton_soft_clauses_ = 0;
184 num_added_clauses_ = 0;
185 num_slack_variables_ = 0;
189 actual_num_variables_ = 0;
194 ProcessNewLine(
line, problem);
196 if (num_lines == 0) {
197 LOG(FATAL) <<
"File '" << filename <<
"' is empty or can't be read.";
200 if (num_variables_ > 0 && num_variables_ != actual_num_variables_) {
201 LOG(ERROR) <<
"Wrong number of variables ! Expected:" << num_variables_
202 <<
" Seen:" << actual_num_variables_;
205 problem->SetSizeAndPostprocess(actual_num_variables_, num_slack_variables_);
208 if (!positive_literal_to_weight_.empty() ||
209 !slack_literal_to_weight_.empty()) {
210 for (
const std::pair<int, int64_t> p : positive_literal_to_weight_) {
212 problem->AddObjectiveTerm(p.first, p.second);
215 for (
const std::pair<int, int64_t> p : slack_literal_to_weight_) {
217 problem->AddObjectiveTerm(actual_num_variables_ + p.first, p.second);
220 problem->SetObjectiveOffset(objective_offset_);
225 const int total_seen = num_added_clauses_ + num_singleton_soft_clauses_ +
226 num_skipped_soft_clauses_;
227 if (num_clauses_ > 0 && num_clauses_ != total_seen) {
228 LOG(ERROR) <<
"Wrong number of clauses ! Expected:" << num_clauses_
229 <<
" Seen:" << total_seen;
236 static std::string ExtractProblemName(
const std::string& filename) {
237 const int found = filename.find_last_of(
'/');
238 const std::string problem_name =
239 found != std::string::npos ? filename.substr(found + 1) : filename;
243 void ProcessHeader(
const std::string&
line) {
244 static const char kWordDelimiters[] =
" ";
245 words_ = absl::StrSplit(
line, kWordDelimiters, absl::SkipEmpty());
247 CHECK_EQ(words_[0],
"p");
248 if (words_[1] ==
"cnf" || words_[1] ==
"wcnf") {
249 CHECK(absl::SimpleAtoi(words_[2], &num_variables_));
250 CHECK(absl::SimpleAtoi(words_[3], &num_clauses_));
251 if (words_[1] ==
"wcnf") {
254 if (words_.size() > 4) {
255 CHECK(absl::SimpleAtoi(words_[4], &hard_weight_));
259 LOG(FATAL) <<
"Unknown file type: " << words_[1];
263 template <
class Problem>
264 void ProcessNewLine(
const std::string&
line, Problem* problem) {
265 if (
line.empty() || end_marker_seen_)
return;
266 if (
line[0] ==
'c')
return;
267 if (
line[0] ==
'%') {
268 end_marker_seen_ =
true;
271 if (
line[0] ==
'p') {
277 if (num_variables_ == 0) {
281 static const char kWordDelimiters[] =
" ";
282 auto splitter = absl::StrSplit(
line, kWordDelimiters, absl::SkipEmpty());
286 (!is_wcnf_ && interpret_cnf_as_max_sat_) ? 1 : hard_weight_;
288 bool end_marker_seen =
false;
289 for (
const absl::string_view word : splitter) {
290 if (first && is_wcnf_) {
297 CHECK(absl::SimpleAtoi(word, &
weight));
302 ++num_skipped_soft_clauses_;
310 CHECK(absl::SimpleAtoi(word, &signed_value));
311 if (signed_value == 0) {
312 end_marker_seen =
true;
316 actual_num_variables_ = std::max(actual_num_variables_,
317 std::max(signed_value, -signed_value));
318 tmp_clause_.push_back(signed_value);
320 if (!end_marker_seen)
return;
322 if (
weight == hard_weight_) {
323 ++num_added_clauses_;
324 problem->AddConstraint(tmp_clause_);
326 if (tmp_clause_.size() == 1) {
331 ++num_singleton_soft_clauses_;
332 const int literal = -tmp_clause_[0];
337 objective_offset_ +=
weight;
342 const int slack_literal = ++num_slack_variables_;
344 slack_literal_to_weight_[slack_literal] +=
weight;
345 tmp_clause_.push_back(slack_literal);
347 ++num_added_clauses_;
348 problem->AddConstraint(tmp_clause_,
true);
350 if (wcnf_use_strong_slack_) {
353 for (
int i = 0;
i + 1 < tmp_clause_.size(); ++
i) {
354 problem->AddConstraint({-tmp_clause_[
i], -slack_literal},
362 bool interpret_cnf_as_max_sat_;
363 const bool wcnf_use_strong_slack_;
365 int num_clauses_ = 0;
366 int num_variables_ = 0;
367 int actual_num_variables_ = 0;
370 std::vector<absl::string_view> words_;
374 int64_t objective_offset_;
375 absl::btree_map<int, int64_t> positive_literal_to_weight_;
376 absl::btree_map<int, int64_t> slack_literal_to_weight_;
381 bool end_marker_seen_;
382 int64_t hard_weight_ = 0;
384 int num_slack_variables_;
385 int num_skipped_soft_clauses_;
386 int num_singleton_soft_clauses_;
387 int num_added_clauses_;
389 std::vector<int> tmp_clause_;