Files
ortools-clone/ortools/lp_data/mps_reader.cc

182 lines
5.8 KiB
C++

// Copyright 2010-2018 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ortools/lp_data/mps_reader.h"
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "ortools/base/status.h"
//#include "ortools/base/status_builder.h"
namespace operations_research {
namespace glop {
const int MPSReader::kNumFields = 6;
const int MPSReader::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49};
const int MPSReader::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12};
const int MPSReader::kSpacePos[12] = {12, 13, 22, 23, 36, 37,
38, 47, 48, 61, 62, 63};
MPSReader::MPSReader()
: free_form_(true),
fields_(kNumFields),
section_(UNKNOWN_SECTION),
section_name_to_id_map_(),
row_name_to_id_map_(),
bound_name_to_id_map_(),
integer_type_names_set_(),
line_num_(0),
line_(),
in_integer_section_(false),
num_unconstrained_rows_(0) {
section_name_to_id_map_["*"] = COMMENT;
section_name_to_id_map_["NAME"] = NAME;
section_name_to_id_map_["ROWS"] = ROWS;
section_name_to_id_map_["LAZYCONS"] = LAZYCONS;
section_name_to_id_map_["COLUMNS"] = COLUMNS;
section_name_to_id_map_["RHS"] = RHS;
section_name_to_id_map_["RANGES"] = RANGES;
section_name_to_id_map_["BOUNDS"] = BOUNDS;
section_name_to_id_map_["INDICATORS"] = INDICATORS;
section_name_to_id_map_["ENDATA"] = ENDATA;
row_name_to_id_map_["E"] = EQUALITY;
row_name_to_id_map_["L"] = LESS_THAN;
row_name_to_id_map_["G"] = GREATER_THAN;
row_name_to_id_map_["N"] = NONE;
bound_name_to_id_map_["LO"] = LOWER_BOUND;
bound_name_to_id_map_["UP"] = UPPER_BOUND;
bound_name_to_id_map_["FX"] = FIXED_VARIABLE;
bound_name_to_id_map_["FR"] = FREE_VARIABLE;
bound_name_to_id_map_["MI"] = NEGATIVE;
bound_name_to_id_map_["PL"] = POSITIVE;
bound_name_to_id_map_["BV"] = BINARY;
bound_name_to_id_map_["LI"] = LOWER_BOUND;
bound_name_to_id_map_["UI"] = UPPER_BOUND;
integer_type_names_set_.insert("BV");
integer_type_names_set_.insert("LI");
integer_type_names_set_.insert("UI");
}
void MPSReader::Reset() {
fields_.resize(kNumFields);
line_num_ = 0;
in_integer_section_ = false;
num_unconstrained_rows_ = 0;
objective_name_.clear();
}
void MPSReader::DisplaySummary() {
if (num_unconstrained_rows_ > 0) {
VLOG(1) << "There are " << num_unconstrained_rows_ + 1
<< " unconstrained rows. The first of them (" << objective_name_
<< ") was used as the objective.";
}
}
bool MPSReader::IsFixedFormat() {
for (const int i : kSpacePos) {
if (i >= line_.length()) break;
if (line_[i] != ' ') return false;
}
return true;
}
util::Status MPSReader::SplitLineIntoFields() {
if (free_form_) {
fields_ = absl::StrSplit(line_, absl::ByAnyChar(" \t"), absl::SkipEmpty());
if (fields_.size() > kNumFields) {
return InvalidArgumentError("Found too many fields.");
}
} else {
// Note: the name should also comply with the fixed format guidelines
// (maximum 8 characters) but in practice there are many problem files in
// our netlib archive that are in fixed format and have a long name. We
// choose to ignore these cases and treat them as fixed format anyway.
if (section_ != NAME && !IsFixedFormat()) {
return InvalidArgumentError("Line is not in fixed format.");
}
const int length = line_.length();
for (int i = 0; i < kNumFields; ++i) {
if (kFieldStartPos[i] < length) {
fields_[i] = line_.substr(kFieldStartPos[i], kFieldLength[i]);
fields_[i].erase(fields_[i].find_last_not_of(" ") + 1);
} else {
fields_[i] = "";
}
}
}
return util::OkStatus();
}
std::string MPSReader::GetFirstWord() const {
if (line_[0] == ' ') {
return std::string("");
}
const int first_space_pos = line_.find(' ');
const std::string first_word = line_.substr(0, first_space_pos);
return first_word;
}
bool MPSReader::IsCommentOrBlank() const {
const char* line = line_.c_str();
if (*line == '*') {
return true;
}
for (; *line != '\0'; ++line) {
if (*line != ' ' && *line != '\t') {
return false;
}
}
return true;
}
util::StatusOr<double> MPSReader::GetDoubleFromString(const std::string& str) {
double result;
if (!absl::SimpleAtod(str, &result)) {
return InvalidArgumentError(
absl::StrCat("Failed to convert \"", str, "\" to double."));
}
if (std::isnan(result)) {
return InvalidArgumentError("Found NaN value.");
}
return result;
}
util::StatusOr<bool> MPSReader::GetBoolFromString(const std::string& str) {
int result;
if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
return InvalidArgumentError(
absl::StrCat("Failed to convert \"", str, "\" to bool."));
}
if (std::isnan(result)) {
return InvalidArgumentError("Found NaN value.");
}
return result;
}
util::Status MPSReader::ProcessSosSection() {
return InvalidArgumentError("Section SOS currently not supported.");
}
util::Status MPSReader::InvalidArgumentError(const std::string& error_message) {
return util::InvalidArgumentError(error_message);
}
// util::Status MPSReader::AppendLineToError(const util::Status& status) {
// return util::StatusBuilder(status, GTL_LOC).SetAppend()
// << " Line " << line_num_ << ": \"" << line_ << "\".";
// }
} // namespace glop
} // namespace operations_research