Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
opb_reader.h
Go to the documentation of this file.
1// Copyright 2010-2025 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
14#ifndef OR_TOOLS_SAT_OPB_READER_H_
15#define OR_TOOLS_SAT_OPB_READER_H_
16
17#include <algorithm>
18#include <cstdint>
19#include <string>
20#include <vector>
21
22#include "absl/log/check.h"
23#include "absl/strings/numbers.h"
24#include "absl/strings/str_split.h"
26#include "ortools/sat/boolean_problem.pb.h"
28
29namespace operations_research {
30namespace sat {
31
32// This class loads a file in pbo file format into a LinearBooleanProblem.
33// The format is described here:
34// http://www.cril.univ-artois.fr/PB12/format.pdf
35class OpbReader {
36 public:
37 OpbReader() = default;
38 // This type is neither copyable nor movable.
39 OpbReader(const OpbReader&) = delete;
40 OpbReader& operator=(const OpbReader&) = delete;
41
42 // Loads the given opb filename into the given problem.
43 bool Load(const std::string& filename, LinearBooleanProblem* problem) {
44 problem->Clear();
45 problem->set_name(ExtractProblemName(filename));
46
47 num_variables_ = 0;
48 int num_lines = 0;
49 for (const std::string& line : FileLines(filename)) {
50 ++num_lines;
51 ProcessNewLine(problem, line);
52 }
53 if (num_lines == 0) {
54 LOG(FATAL) << "File '" << filename << "' is empty or can't be read.";
55 }
56 problem->set_num_variables(num_variables_);
57 return true;
58 }
59
60 private:
61 // Since the problem name is not stored in the cnf format, we infer it from
62 // the file name.
63 static std::string ExtractProblemName(const std::string& filename) {
64 const int found = filename.find_last_of('/');
65 const std::string problem_name =
66 found != std::string::npos ? filename.substr(found + 1) : filename;
67 return problem_name;
68 }
69
70 void ProcessNewLine(LinearBooleanProblem* problem, const std::string& line) {
71 const std::vector<std::string> words =
72 absl::StrSplit(line, absl::ByAnyChar(" ;"), absl::SkipEmpty());
73 if (words.empty() || words[0].empty() || words[0][0] == '*') {
74 return;
75 }
76
77 if (words[0] == "min:") {
78 LinearObjective* objective = problem->mutable_objective();
79 for (int i = 1; i < words.size(); ++i) {
80 const std::string& word = words[i];
81 if (word.empty() || word[0] == ';') continue;
82 if (word[0] == 'x') {
83 int literal;
84 CHECK(absl::SimpleAtoi(word.substr(1), &literal));
85 num_variables_ = std::max(num_variables_, literal);
86 objective->add_literals(literal);
87 } else {
88 int64_t value;
89 CHECK(absl::SimpleAtoi(word, &value));
90 objective->add_coefficients(value);
91 }
92 }
93 if (objective->literals_size() != objective->coefficients_size()) {
94 LOG(INFO) << "words.size() = " << words.size();
95 LOG(FATAL) << "Failed to parse objective:\n " << line;
96 }
97 return;
98 }
99 LinearBooleanConstraint* constraint = problem->add_constraints();
100 for (int i = 0; i < words.size(); ++i) {
101 const std::string& word = words[i];
102 CHECK(!word.empty());
103 if (word == ">=") {
104 CHECK_LT(i + 1, words.size());
105 int64_t value;
106 CHECK(absl::SimpleAtoi(words[i + 1], &value));
107 constraint->set_lower_bound(value);
108 break;
109 } else if (word == "=") {
110 CHECK_LT(i + 1, words.size());
111 int64_t value;
112 CHECK(absl::SimpleAtoi(words[i + 1], &value));
113 constraint->set_upper_bound(value);
114 constraint->set_lower_bound(value);
115 break;
116 } else {
117 if (word[0] == 'x') {
118 int literal;
119 CHECK(absl::SimpleAtoi(word.substr(1), &literal));
120 num_variables_ = std::max(num_variables_, literal);
121 constraint->add_literals(literal);
122 } else {
123 int64_t value;
124 CHECK(absl::SimpleAtoi(words[i], &value));
125 constraint->add_coefficients(value);
126 }
127 }
128 }
129 if (constraint->literals_size() != constraint->coefficients_size()) {
130 LOG(FATAL) << "Failed to parse constraint:\n " << line;
131 }
132 }
133
134 int num_variables_;
135};
136
137} // namespace sat
138} // namespace operations_research
139
140#endif // OR_TOOLS_SAT_OPB_READER_H_
bool Load(const std::string &filename, LinearBooleanProblem *problem)
Loads the given opb filename into the given problem.
Definition opb_reader.h:43
OpbReader(const OpbReader &)=delete
This type is neither copyable nor movable.
OpbReader & operator=(const OpbReader &)=delete
In SWIG mode, we don't want anything besides these top-level includes.