Google OR-Tools: ortools/sat/sat_cnf_reader.h Source File
47 problem_->set_num_variables(num_variables + num_slacks);
48 problem_->set_original_num_variables(num_variables);
49 for (const int c : to_postprocess_) {
50 auto* literals = problem_->mutable_constraints(c)->mutable_literals();
51 const int last_index = literals->size() - 1;
52 const int last = (*literals)[last_index];
61 void AddConstraint(absl::Span<const int> clause, bool last_is_slack = false) {
63 to_postprocess_.push_back(problem_->constraints().size());
75 CHECK_GE(literal, 0) << "Negative literal not supported.";
76 problem_->mutable_objective()->add_literals(literal);
95 for (int i = 0; i < num_variables + num_slacks; ++i) {
100 for (const int c : to_postprocess_) {
101 auto* literals = problem_->mutable_constraints(c)
104 const int last_index = literals->size() - 1;
105 const int last = (*literals)[last_index];
107 last >= 0 ? last + num_variables : last - num_variables;
115 void AddConstraint(absl::Span<const int> clause, bool last_is_slack = false) {
117 to_postprocess_.push_back(problem_->constraints().size());
118 auto* constraint = problem_->add_constraints()->mutable_bool_or();
119 constraint->mutable_literals()->Reserve(clause.size());
120 for (const int literal : clause) {
121 constraint->add_literals(LiteralToRef(literal));
126 CHECK_GE(literal, 0) << "Negative literal not supported.";
127 problem_->mutable_objective()->add_vars(LiteralToRef(literal));
161 problem->Clear();
162 problem->set_name(ExtractProblemName(filename));
167 problem->Clear();
168 problem->set_name(ExtractProblemName(filename));
175 bool LoadInternal(const std::string& filename, Problem* problem) {
178 positive_literal_to_weight_.clear();
182 num_skipped_soft_clauses_ = 0;
183 num_singleton_soft_clauses_ = 0;
189 actual_num_variables_ = 0;
192 for (const std::string& line : FileLines(filename)) {
194 ProcessNewLine(line, problem);
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());
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") {
255 CHECK(absl::SimpleAtoi(words_[4], &hard_weight_));
259 LOG(FATAL) << "Unknown file type: " << words_[1];
264 void ProcessNewLine(const std::string& line, Problem* problem) {
265 if (line.empty() || end_marker_seen_) return;
266 if (line[0] == 'c') return;
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) {
297 CHECK(absl::SimpleAtoi(word, &weight));
302 ++num_skipped_soft_clauses_;
310 CHECK(absl::SimpleAtoi(word, &signed_value));
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_) {
324 problem->AddConstraint(tmp_clause_);
326 if (tmp_clause_.size() == 1) {
331 ++num_singleton_soft_clauses_;
332 const int literal = -tmp_clause_[0];
334 positive_literal_to_weight_[literal] += weight;
336 positive_literal_to_weight_[-literal] -= weight;
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);
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_;
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_;
385 int num_skipped_soft_clauses_;
386 int num_singleton_soft_clauses_;