Files
ortools-clone/ortools/lp_data/sol_reader.cc
Laurent Perron c64f28f3bc fix includes
2024-01-12 16:30:47 +01:00

171 lines
5.7 KiB
C++

// Copyright 2010-2024 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/sol_reader.h"
#include <limits>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "ortools/base/numbers.h"
#include "ortools/base/status_macros.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/lp_data/lp_data.h"
#include "ortools/lp_data/lp_types.h"
#include "ortools/util/file_util.h"
namespace operations_research {
absl::StatusOr<glop::DenseRow> ParseSolFile(absl::string_view file_name,
const glop::LinearProgram& model) {
ASSIGN_OR_RETURN(std::string sol_file, ReadFileToString(file_name));
return ParseSolString(sol_file, model);
}
absl::StatusOr<MPSolutionResponse> ParseSolFile(absl::string_view file_name,
const MPModelProto& model) {
ASSIGN_OR_RETURN(std::string sol_file, ReadFileToString(file_name));
return ParseSolString(sol_file, model);
}
absl::StatusOr<glop::DenseRow> ParseSolString(
const std::string& solution, const glop::LinearProgram& model) {
constexpr double kInfinity = std::numeric_limits<double>::infinity();
absl::flat_hash_map<std::string, glop::ColIndex> var_index_by_name;
for (glop::ColIndex col(0); col < model.num_variables(); ++col) {
var_index_by_name[model.GetVariableName(col)] = col;
}
glop::ColIndex num_variables = model.num_variables();
glop::DenseRow dense_row(num_variables.value(), 0);
std::vector<std::string> lines =
absl::StrSplit(solution, '\n', absl::SkipEmpty());
for (const std::string& line : lines) {
std::vector<std::string> fields =
absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipEmpty());
// Remove the comments.
for (int i = 0; i < fields.size(); ++i) {
if (fields[i][0] == '#') {
fields.resize(i);
break;
}
}
if (fields.empty()) continue;
if (fields.size() == 1) {
return absl::InvalidArgumentError(
absl::StrCat("Found only one field on line '", line, "'."));
}
if (fields.size() > 2) {
return absl::InvalidArgumentError(
absl::StrCat("Found more than two fields on line '", line, "'."));
}
const std::string var_name = fields[0];
const double var_value =
strings::ParseLeadingDoubleValue(fields[1], kInfinity);
if (var_value == kInfinity) {
return absl::InvalidArgumentError(
absl::StrCat("Couldn't parse value on line '", line, "'."));
}
if (var_name == "=obj=") continue;
auto iter = var_index_by_name.find(var_name);
if (iter == var_index_by_name.end()) {
return absl::InvalidArgumentError(absl::StrCat(
"Couldn't find variable named '", var_name, "' in the model."));
}
dense_row[iter->second] = var_value;
}
return dense_row;
}
absl::StatusOr<MPSolutionResponse> ParseSolString(const std::string& solution,
const MPModelProto& model) {
constexpr double kInfinity = std::numeric_limits<double>::infinity();
absl::flat_hash_map<std::string, int> var_index_by_name;
for (int var_index = 0; var_index < model.variable_size(); ++var_index) {
if (model.variable(var_index).name().empty()) {
return absl::InvalidArgumentError("Found variable without name.");
}
var_index_by_name[model.variable(var_index).name()] = var_index;
}
MPSolutionResponse response;
std::vector<double> var_values(model.variable_size(), 0);
std::vector<std::string> lines =
absl::StrSplit(solution, '\n', absl::SkipEmpty());
for (const std::string& line : lines) {
std::vector<std::string> fields =
absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipEmpty());
// Remove the comments.
for (int i = 0; i < fields.size(); ++i) {
if (fields[i][0] == '#') {
fields.resize(i);
break;
}
}
if (fields.empty()) continue;
if (fields.size() == 1) {
return absl::InvalidArgumentError(
absl::StrCat("Found only one field on line '", line, "'."));
}
if (fields.size() > 2) {
return absl::InvalidArgumentError(
absl::StrCat("Found more than two fields on line '", line, "'."));
}
const std::string var_name = fields[0];
const double var_value =
strings::ParseLeadingDoubleValue(fields[1], kInfinity);
if (var_value == kInfinity) {
return absl::InvalidArgumentError(
absl::StrCat("Couldn't parse value on line '", line, "'."));
}
if (var_name == "=obj=") {
response.set_objective_value(var_value);
continue;
}
auto iter = var_index_by_name.find(var_name);
if (iter == var_index_by_name.end()) {
return absl::InvalidArgumentError(absl::StrCat(
"Couldn't find variable named '", var_name, "' in the model."));
}
var_values[iter->second] = var_value;
}
for (const double value : var_values) {
response.add_variable_value(value);
}
return response;
}
} // namespace operations_research