Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
mps_reader_template.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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/container/inlined_vector.h"
19#include "absl/status/status.h"
20#include "absl/status/statusor.h"
21#include "absl/strings/ascii.h"
22#include "absl/strings/match.h"
23#include "absl/strings/string_view.h"
25
27namespace {
28
29// Starting positions of each of the fields for fixed format.
30static constexpr int kFieldStartPos[kNumMpsFields] = {1, 4, 14, 24, 39, 49};
31
32// Lengths of each of the fields for fixed format.
33static constexpr int kFieldLength[kNumMpsFields] = {2, 8, 8, 12, 8, 12};
34
35// Positions where there should be spaces for fixed format.
36static constexpr int kSpacePos[12] = {12, 13, 22, 23, 36, 37,
37 38, 47, 48, 61, 62, 63};
38
39} // namespace
40
41// static
42absl::StatusOr<MPSLineInfo> MPSLineInfo::Create(int64_t line_num,
43 bool free_form,
44 absl::string_view line) {
45 // Deal with windows end of line characters and trailing white space.
46 line = absl::StripTrailingAsciiWhitespace(line);
47 if (!free_form && absl::StrContains(line, '\t')) {
48 return absl::InvalidArgumentError("File contains tabs.");
49 }
50
51 MPSLineInfo line_info = MPSLineInfo(line_num, free_form, line);
52 if (!free_form && !line_info.IsFixedFormat()) {
53 return line_info.InvalidArgumentError("Line is not in fixed format.");
54 }
55 if (!line_info.IsCommentOrBlank()) {
56 RETURN_IF_ERROR(line_info.SplitLineIntoFields());
57 }
58 return line_info;
59}
60
61bool MPSLineInfo::IsFixedFormat() const {
62 if (IsCommentOrBlank()) {
63 return true;
64 }
65 if (IsNewSection()) {
66 absl::string_view first_word = GetFirstWord();
67 // Note: the name should also comply with the fixed format guidelines
68 // (maximum 8 characters) but in practice there are many problem files in
69 // the netlib archive that are in fixed format and have a long name. We
70 // choose to ignore these cases and treat them as fixed format anyway.
71 // Other than the NAME record, every new section label should be the only
72 // entry on the line.
73 return first_word == line_ || first_word == "NAME";
74 }
75 constexpr int kMaxLineSize =
76 kFieldStartPos[kNumMpsFields - 1] + kFieldLength[kNumMpsFields - 1];
77 // Note that `line_` already has been stripped of trailing white spaces.
78 const int line_size = line_.size();
79 if (line_size > kMaxLineSize) return false;
80 for (const int i : kSpacePos) {
81 if (i >= line_size) break;
82 if (line_[i] != ' ') return false;
83 }
84 return true;
85}
86
87absl::Status MPSLineInfo::SplitLineIntoFields() {
88 if (free_form_) {
89 absl::string_view remaining_line = absl::StripLeadingAsciiWhitespace(line_);
90 // Although using `fields_ = StrSplit(line, ByAnyChar(" \t))` is shorter to
91 // write, this explicit loop, and checking the `kNumMpsFields` is
92 // significantly faster.
93 while (!remaining_line.empty()) {
94 if (fields_.size() == kNumMpsFields) {
95 return InvalidArgumentError("Found too many fields.");
96 }
97 // find_first_of() returns npos for "not found". substr() interprets
98 // len==npos as end of string.
99 const int pos = remaining_line.find_first_of(" \t");
100 fields_.push_back(remaining_line.substr(0, pos));
101 if (pos == absl::string_view::npos) {
102 // substr() will throw an exception if the start is npos.
103 break;
104 }
105 remaining_line =
106 absl::StripLeadingAsciiWhitespace(remaining_line.substr(pos));
107 }
108 } else {
109 const int line_size = line_.size();
110 for (int i = 0; i < kNumMpsFields; ++i) {
111 if (kFieldStartPos[i] >= line_size) break;
112 fields_.push_back(absl::StripTrailingAsciiWhitespace(
113 line_.substr(kFieldStartPos[i], kFieldLength[i])));
114 }
115 }
116 return absl::OkStatus();
117}
118
119absl::string_view MPSLineInfo::GetFirstWord() const {
120 return line_.substr(0, line_.find(' '));
121}
122
123bool MPSLineInfo::IsCommentOrBlank() const {
124 // Trailing whitespace has already been trimmed, so a blank line has become
125 // empty.
126 return (line_.empty() || line_[0] == '*');
127}
128
129absl::Status MPSLineInfo::InvalidArgumentError(
130 absl::string_view error_message) const {
131 return AppendLineToError(absl::InvalidArgumentError(error_message));
132}
133
134absl::Status MPSLineInfo::AppendLineToError(const absl::Status& status) const {
136 << " Line " << line_num_ << ": \"" << line_ << "\".";
137}
138
139} // namespace operations_research::internal
#define RETURN_IF_ERROR(expr)
StatusBuilder & SetAppend()
absl::Status status
Definition g_gurobi.cc:44
End of the interface. Below is the implementation.
int line