Files
ortools-clone/ortools/math_opt/cpp/sparse_containers.cc
2022-05-19 17:23:02 +02:00

155 lines
5.6 KiB
C++

// Copyright 2010-2021 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/math_opt/cpp/sparse_containers.h"
namespace operations_research::math_opt {
namespace {
// SparseVectorProtoType should be SparseDoubleVector or SparseBasisStatusVector
template <typename SparseVectorProtoType>
absl::Status CheckSparseVectorProto(const SparseVectorProtoType& vec) {
RETURN_IF_ERROR(CheckIdsAndValuesSize(MakeView(vec)));
RETURN_IF_ERROR(CheckIdsRangeAndStrictlyIncreasing(vec.ids()));
return absl::OkStatus();
}
template <typename Key>
absl::StatusOr<IdMap<Key, BasisStatus>> BasisVectorFromProto(
const ModelStorage* const model,
const SparseBasisStatusVector& basis_proto) {
using IdType = typename Key::IdType;
absl::flat_hash_map<IdType, BasisStatus> raw_map;
raw_map.reserve(basis_proto.ids_size());
for (const auto& [id, basis_status_proto_int] : MakeView(basis_proto)) {
const auto basis_status_proto =
static_cast<BasisStatusProto>(basis_status_proto_int);
const std::optional<BasisStatus> basis_status =
EnumFromProto(basis_status_proto);
if (!basis_status.has_value()) {
return util::InvalidArgumentErrorBuilder()
<< "basis status not specified for id " << id;
}
raw_map[IdType(id)] = *basis_status;
}
return IdMap<Key, BasisStatus>(model, std::move(raw_map));
}
template <typename Key>
SparseDoubleVectorProto IdMapToProto(const IdMap<Key, double>& id_map) {
using IdType = typename Key::IdType;
SparseDoubleVectorProto result;
std::vector<std::pair<IdType, double>> sorted_entries(
id_map.raw_map().begin(), id_map.raw_map().end());
std::sort(sorted_entries.begin(), sorted_entries.end());
for (const auto& [id, val] : sorted_entries) {
result.add_ids(id.value());
result.add_values(val);
}
return result;
}
template <typename Key>
SparseBasisStatusVector BasisIdMapToProto(
const IdMap<Key, BasisStatus>& basis_map) {
using IdType = typename Key::IdType;
SparseBasisStatusVector result;
std::vector<std::pair<IdType, BasisStatus>> sorted_entries(
basis_map.raw_map().begin(), basis_map.raw_map().end());
std::sort(sorted_entries.begin(), sorted_entries.end());
for (const auto& [id, val] : sorted_entries) {
result.add_ids(id.value());
result.add_values(EnumToProto(val));
}
return result;
}
absl::Status VariableIdsExist(const ModelStorage* const model,
const absl::Span<const int64_t> ids) {
for (const int64_t id : ids) {
if (!model->has_variable(VariableId(id))) {
return util::InvalidArgumentErrorBuilder()
<< "no variable with id " << id << " exists";
}
}
return absl::OkStatus();
}
absl::Status LinearConstraintIdsExist(const ModelStorage* const model,
const absl::Span<const int64_t> ids) {
for (const int64_t id : ids) {
if (!model->has_linear_constraint(LinearConstraintId(id))) {
return util::InvalidArgumentErrorBuilder()
<< "no linear constraint with id " << id << " exists";
}
}
return absl::OkStatus();
}
} // namespace
absl::StatusOr<VariableMap<double>> VariableValuesFromProto(
const ModelStorage* const model,
const SparseDoubleVectorProto& vars_proto) {
RETURN_IF_ERROR(CheckSparseVectorProto(vars_proto));
RETURN_IF_ERROR(VariableIdsExist(model, vars_proto.ids()));
return VariableMap<double>(model, MakeView(vars_proto).as_map<VariableId>());
}
SparseDoubleVectorProto VariableValuesToProto(
const VariableMap<double>& variable_values) {
return IdMapToProto(variable_values);
}
absl::StatusOr<LinearConstraintMap<double>> LinearConstraintValuesFromProto(
const ModelStorage* const model,
const SparseDoubleVectorProto& lin_cons_proto) {
RETURN_IF_ERROR(CheckSparseVectorProto(lin_cons_proto));
RETURN_IF_ERROR(LinearConstraintIdsExist(model, lin_cons_proto.ids()));
return LinearConstraintMap<double>(
model, MakeView(lin_cons_proto).as_map<LinearConstraintId>());
}
SparseDoubleVectorProto LinearConstraintValuesToProto(
const LinearConstraintMap<double>& linear_constraint_values) {
return IdMapToProto(linear_constraint_values);
}
absl::StatusOr<VariableMap<BasisStatus>> VariableBasisFromProto(
const ModelStorage* const model,
const SparseBasisStatusVector& basis_proto) {
RETURN_IF_ERROR(CheckSparseVectorProto(basis_proto));
RETURN_IF_ERROR(VariableIdsExist(model, basis_proto.ids()));
return BasisVectorFromProto<Variable>(model, basis_proto);
}
SparseBasisStatusVector VariableBasisToProto(
const VariableMap<BasisStatus>& basis_values) {
return BasisIdMapToProto(basis_values);
}
absl::StatusOr<LinearConstraintMap<BasisStatus>> LinearConstraintBasisFromProto(
const ModelStorage* const model,
const SparseBasisStatusVector& basis_proto) {
RETURN_IF_ERROR(CheckSparseVectorProto(basis_proto));
RETURN_IF_ERROR(LinearConstraintIdsExist(model, basis_proto.ids()));
return BasisVectorFromProto<LinearConstraint>(model, basis_proto);
}
SparseBasisStatusVector LinearConstraintBasisToProto(
const LinearConstraintMap<BasisStatus>& basis_values) {
return BasisIdMapToProto(basis_values);
}
} // namespace operations_research::math_opt