math_opt: export few cpp/ tests
This commit is contained in:
committed by
Corentin Le Molgat
parent
bb745da2c2
commit
a144ae4033
@@ -43,6 +43,17 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "basis_status_test",
|
||||
srcs = ["basis_status_test.cc"],
|
||||
deps = [
|
||||
":basis_status",
|
||||
":enums_testing",
|
||||
"//ortools/base:gmock",
|
||||
"//ortools/base:gmock_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "sparse_containers",
|
||||
srcs = ["sparse_containers.cc"],
|
||||
@@ -70,6 +81,21 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "sparse_containers_test",
|
||||
srcs = ["sparse_containers_test.cc"],
|
||||
deps = [
|
||||
":matchers",
|
||||
":math_opt",
|
||||
":sparse_containers",
|
||||
"//ortools/base:gmock",
|
||||
"//ortools/base:gmock_main",
|
||||
"//ortools/math_opt/constraints/quadratic:quadratic_constraint",
|
||||
"@abseil-cpp//absl/container:flat_hash_map",
|
||||
"@abseil-cpp//absl/status",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "model",
|
||||
srcs = ["model.cc"],
|
||||
@@ -457,6 +483,21 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "enums_testing",
|
||||
testonly = True,
|
||||
hdrs = ["enums_testing.h"],
|
||||
deps = [
|
||||
":enums",
|
||||
"//ortools/base:gmock",
|
||||
"//ortools/base:logging",
|
||||
"@abseil-cpp//absl/numeric:int128",
|
||||
"@abseil-cpp//absl/strings",
|
||||
],
|
||||
# Make sure the tests are included when using --dynamic_mode=off.
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "statistics",
|
||||
srcs = ["statistics.cc"],
|
||||
@@ -583,3 +624,14 @@ cc_library(
|
||||
hdrs = ["remote_streaming_mode.h"],
|
||||
deps = ["@abseil-cpp//absl/strings:string_view"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "remote_streaming_mode_test",
|
||||
srcs = ["remote_streaming_mode_test.cc"],
|
||||
deps = [
|
||||
":remote_streaming_mode",
|
||||
"//ortools/base:gmock_main",
|
||||
"@abseil-cpp//absl/flags:marshalling",
|
||||
"@abseil-cpp//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ set(NAME ${PROJECT_NAME}_math_opt_cpp)
|
||||
add_library(${NAME} OBJECT)
|
||||
|
||||
file(GLOB _SRCS "*.h" "*.cc")
|
||||
list(FILTER _SRCS EXCLUDE REGEX ".*_test.cc")
|
||||
list(FILTER _SRCS EXCLUDE REGEX "/matchers\\.")
|
||||
|
||||
target_sources(${NAME} PRIVATE ${_SRCS})
|
||||
|
||||
25
ortools/math_opt/cpp/basis_status_test.cc
Normal file
25
ortools/math_opt/cpp/basis_status_test.cc
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2010-2025 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/basis_status.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/math_opt/cpp/enums_testing.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
namespace {
|
||||
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(BasisStatus, EnumTest, BasisStatus);
|
||||
|
||||
}
|
||||
} // namespace operations_research::math_opt
|
||||
108
ortools/math_opt/cpp/enums_testing.h
Normal file
108
ortools/math_opt/cpp/enums_testing.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2010-2025 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.
|
||||
|
||||
// Typed tests for enums that use enums.h.
|
||||
#ifndef OR_TOOLS_MATH_OPT_CPP_ENUMS_TESTING_H_
|
||||
#define OR_TOOLS_MATH_OPT_CPP_ENUMS_TESTING_H_
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/numeric/int128.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/math_opt/cpp/enums.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
|
||||
// A type parameterized test suite for testing the correct implementation of
|
||||
// Enum<E> for a given enum.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// INSTANTIATE_TYPED_TEST_SUITE_P(<E>, EnumTest, <E>);
|
||||
//
|
||||
template <typename E>
|
||||
class EnumTest : public testing::Test {
|
||||
public:
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EnumTest);
|
||||
|
||||
TYPED_TEST_P(EnumTest, UnderlyingTypeFits) {
|
||||
// We could static_assert that but using a gUnit test works too.
|
||||
using underlying_type_limits =
|
||||
std::numeric_limits<std::underlying_type_t<TypeParam>>;
|
||||
using Proto = typename Enum<TypeParam>::Proto;
|
||||
CHECK_GE(EnumProto<Proto>::kMin, underlying_type_limits::min());
|
||||
CHECK_LE(EnumProto<Proto>::kMax, underlying_type_limits::max());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EnumTest, AllProtoValues) {
|
||||
using Proto = typename Enum<TypeParam>::Proto;
|
||||
|
||||
bool found_unspecified = false;
|
||||
std::vector<TypeParam> found_values;
|
||||
for (int i = EnumProto<Proto>::kMin; i <= EnumProto<Proto>::kMax; ++i) {
|
||||
if (!EnumProto<Proto>::kIsValid(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto proto_value = static_cast<Proto>(i);
|
||||
SCOPED_TRACE(proto_value);
|
||||
|
||||
const std::optional<TypeParam> cpp_enum = EnumFromProto(proto_value);
|
||||
if (proto_value == Enum<TypeParam>::kProtoUnspecifiedValue) {
|
||||
found_unspecified = true;
|
||||
ASSERT_FALSE(cpp_enum.has_value());
|
||||
} else {
|
||||
ASSERT_TRUE(cpp_enum.has_value());
|
||||
found_values.push_back(*cpp_enum);
|
||||
}
|
||||
|
||||
const Proto reconverted_proto_value = EnumToProto(cpp_enum);
|
||||
EXPECT_EQ(proto_value, reconverted_proto_value);
|
||||
}
|
||||
|
||||
// We should have found all C++ enum + nullopt when traversing all possible
|
||||
// Proto enums. And the AllValues() of C++ should not contain any additional
|
||||
// value.
|
||||
ASSERT_TRUE(found_unspecified);
|
||||
ASSERT_THAT(found_values, ::testing::UnorderedElementsAreArray(
|
||||
Enum<TypeParam>::AllValues()));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EnumTest, AllCppValuesString) {
|
||||
for (const TypeParam cpp_value : Enum<TypeParam>::AllValues()) {
|
||||
const auto cpp_underlying_value =
|
||||
static_cast<std::underlying_type_t<TypeParam>>(cpp_value);
|
||||
const std::optional<absl::string_view> opt_str_value =
|
||||
EnumToOptString(cpp_value);
|
||||
ASSERT_TRUE(opt_str_value.has_value())
|
||||
<< "cpp_value: " << cpp_underlying_value;
|
||||
EXPECT_THAT(EnumFromString<TypeParam>(*opt_str_value),
|
||||
::testing::Optional(cpp_value))
|
||||
<< "cpp_value: " << cpp_underlying_value;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EnumTest, UnderlyingTypeFits, AllProtoValues,
|
||||
AllCppValuesString);
|
||||
|
||||
} // namespace operations_research::math_opt
|
||||
|
||||
#endif // OR_TOOLS_MATH_OPT_CPP_ENUMS_TESTING_H_
|
||||
72
ortools/math_opt/cpp/remote_streaming_mode_test.cc
Normal file
72
ortools/math_opt/cpp/remote_streaming_mode_test.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2010-2025 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/remote_streaming_mode.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/flags/marshalling.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
// Tests that the AbslParseFlag() and AbslUnparseFlag() functions properly
|
||||
// roundtrips.
|
||||
class RemoteStreamingSolveModeRoundtripTest
|
||||
: public testing::TestWithParam<RemoteStreamingSolveMode> {};
|
||||
|
||||
TEST_P(RemoteStreamingSolveModeRoundtripTest, Roundtrip) {
|
||||
RemoteStreamingSolveMode output = RemoteStreamingSolveMode::kDefault;
|
||||
std::string error;
|
||||
EXPECT_TRUE(absl::ParseFlag(absl::UnparseFlag(GetParam()), &output, &error))
|
||||
<< "error: '" << absl::CEscape(error) << "'";
|
||||
EXPECT_EQ(output, GetParam());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All, RemoteStreamingSolveModeRoundtripTest,
|
||||
testing::Values(RemoteStreamingSolveMode::kDefault,
|
||||
RemoteStreamingSolveMode::kSubprocess,
|
||||
RemoteStreamingSolveMode::kInProcess),
|
||||
[](const testing::TestParamInfo<
|
||||
RemoteStreamingSolveModeRoundtripTest::ParamType>& info) {
|
||||
return AbslUnparseFlag(info.param);
|
||||
});
|
||||
|
||||
TEST(RemoteStreamingSolveModeTest, InvalidValue) {
|
||||
RemoteStreamingSolveMode output = RemoteStreamingSolveMode::kDefault;
|
||||
std::string error;
|
||||
EXPECT_FALSE(absl::ParseFlag("unknown", &output, &error))
|
||||
<< "output: " << output;
|
||||
EXPECT_THAT(error, HasSubstr("unknown value"));
|
||||
}
|
||||
|
||||
TEST(RemoteStreamingSolveModeTest, PrintToStdStream) {
|
||||
std::ostringstream oss;
|
||||
oss << RemoteStreamingSolveMode::kDefault;
|
||||
EXPECT_EQ(oss.str(), "default");
|
||||
}
|
||||
|
||||
TEST(RemoteStreamingSolveModeTest, PrintToAbsl) {
|
||||
EXPECT_EQ(absl::StrCat(RemoteStreamingSolveMode::kDefault), "default");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace operations_research::math_opt
|
||||
513
ortools/math_opt/cpp/sparse_containers_test.cc
Normal file
513
ortools/math_opt/cpp/sparse_containers_test.cc
Normal file
@@ -0,0 +1,513 @@
|
||||
// Copyright 2010-2025 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"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/math_opt/constraints/quadratic/quadratic_constraint.h"
|
||||
#include "ortools/math_opt/cpp/matchers.h"
|
||||
#include "ortools/math_opt/cpp/math_opt.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::Pair;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::testing::status::IsOkAndHolds;
|
||||
using ::testing::status::StatusIs;
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, Empty) {
|
||||
ModelStorage model;
|
||||
model.AddVariable("x");
|
||||
|
||||
const SparseDoubleVectorProto proto;
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, proto), IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, NonEmpty) {
|
||||
ModelStorage model;
|
||||
const VariableId x = model.AddVariable("x");
|
||||
model.AddVariable("y");
|
||||
const VariableId z = model.AddVariable("z");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(2);
|
||||
proto.add_values(3.0);
|
||||
proto.add_values(-2.0);
|
||||
|
||||
VariableMap<double> expected = {{Variable(&model, x), 3.0},
|
||||
{Variable(&model, z), -2.0}};
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(IsNear(expected, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, UnequalSize) {
|
||||
ModelStorage model;
|
||||
model.AddVariable("x");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, OutOfOrder) {
|
||||
ModelStorage model;
|
||||
model.AddVariable("x");
|
||||
model.AddVariable("y");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(1);
|
||||
proto.add_ids(0);
|
||||
proto.add_values(1.0);
|
||||
proto.add_values(1.0);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, NotInModel) {
|
||||
ModelStorage model;
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_values(1.0);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no variable with id")));
|
||||
}
|
||||
|
||||
TEST(DoubleVariableValuesFromProtoTest, SmallMap) {
|
||||
ModelStorage model;
|
||||
const VariableId x = model.AddVariable("x");
|
||||
model.AddVariable("y");
|
||||
const VariableId z = model.AddVariable("z");
|
||||
|
||||
const VariableMap<double> input = {{Variable(&model, x), 3.0},
|
||||
{Variable(&model, z), -2.0}};
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(&model, VariableValuesToProto(input)),
|
||||
IsOkAndHolds(IsNear(input, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(Int32VariableValuesFromProtoTest, UnequalSize) {
|
||||
Model model;
|
||||
model.AddVariable("x");
|
||||
|
||||
SparseInt32VectorProto proto;
|
||||
proto.add_ids(0);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(model.storage(), proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(Int32VariableValuesFromProtoTest, VariableDoesNotExist) {
|
||||
Model model;
|
||||
model.AddVariable("x");
|
||||
|
||||
SparseInt32VectorProto proto;
|
||||
proto.add_ids(1);
|
||||
proto.add_values(12);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(model.storage(), proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(Int32VariableValuesFromProtoTest, SmallMap) {
|
||||
Model model;
|
||||
const Variable x = model.AddVariable("x");
|
||||
model.AddVariable("y");
|
||||
const Variable z = model.AddVariable("z");
|
||||
|
||||
SparseInt32VectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(2);
|
||||
proto.add_values(12);
|
||||
proto.add_values(11);
|
||||
|
||||
EXPECT_THAT(VariableValuesFromProto(model.storage(), proto),
|
||||
IsOkAndHolds(UnorderedElementsAre(Pair(testing::Eq(x), 12),
|
||||
Pair(testing::Eq(z), 11))));
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesFromProtoTest, Empty) {
|
||||
ModelStorage model;
|
||||
EXPECT_THAT(AuxiliaryObjectiveValuesFromProto(
|
||||
&model, google::protobuf::Map<int64_t, double>()),
|
||||
IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesFromProtoTest, NonEmpty) {
|
||||
ModelStorage model;
|
||||
const Objective o =
|
||||
Objective::Auxiliary(&model, model.AddAuxiliaryObjective(2));
|
||||
|
||||
google::protobuf::Map<int64_t, double> proto;
|
||||
proto[o.id().value()] = 3.0;
|
||||
|
||||
EXPECT_THAT(AuxiliaryObjectiveValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(UnorderedElementsAre(Pair(o, 3.0))));
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesFromProtoTest, NotInModel) {
|
||||
ModelStorage model;
|
||||
|
||||
google::protobuf::Map<int64_t, double> proto;
|
||||
proto[0] = 3.0;
|
||||
|
||||
EXPECT_THAT(AuxiliaryObjectiveValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no auxiliary objective with id")));
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesToProtoTest, Empty) {
|
||||
EXPECT_THAT(AuxiliaryObjectiveValuesToProto({}), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesToProtoTest, NonEmpty) {
|
||||
ModelStorage model;
|
||||
const Objective o =
|
||||
Objective::Auxiliary(&model, model.AddAuxiliaryObjective(2));
|
||||
|
||||
const absl::flat_hash_map<Objective, double> input = {{o, 3.0}};
|
||||
|
||||
EXPECT_THAT(AuxiliaryObjectiveValuesToProto(input),
|
||||
UnorderedElementsAre(Pair(o.id().value(), 3.0)));
|
||||
}
|
||||
|
||||
TEST(AuxiliaryObjectiveValuesToProtoDeathTest, PrimaryObjectiveInMap) {
|
||||
ModelStorage model;
|
||||
const Objective o = Objective::Primary(&model);
|
||||
|
||||
const absl::flat_hash_map<Objective, double> input = {{o, 3.0}};
|
||||
EXPECT_DEATH(AuxiliaryObjectiveValuesToProto(input), "primary");
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesFromProtoTest, EmptySuccess) {
|
||||
ModelStorage model;
|
||||
model.AddLinearConstraint("c");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesFromProtoTest, NonEmptySuccess) {
|
||||
ModelStorage model;
|
||||
const LinearConstraintId c = model.AddLinearConstraint("c");
|
||||
model.AddLinearConstraint("d");
|
||||
const LinearConstraintId e = model.AddLinearConstraint("e");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(2);
|
||||
proto.add_values(3.0);
|
||||
proto.add_values(-2.0);
|
||||
|
||||
LinearConstraintMap<double> expected = {{LinearConstraint(&model, c), 3.0},
|
||||
{LinearConstraint(&model, e), -2.0}};
|
||||
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(IsNear(expected, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesFromProtoTest, UnequalSize) {
|
||||
ModelStorage model;
|
||||
model.AddLinearConstraint("c");
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesFromProtoTest, NotInModel) {
|
||||
ModelStorage model;
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_values(1.0);
|
||||
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no linear constraint with id")));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesToProtoTest, Empty) {
|
||||
ModelStorage model;
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(
|
||||
&model, LinearConstraintValuesToProto({})),
|
||||
IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintValuesToProtoTest, SmallMap) {
|
||||
ModelStorage model;
|
||||
const LinearConstraintId c = model.AddLinearConstraint("c");
|
||||
model.AddLinearConstraint("d");
|
||||
const LinearConstraintId e = model.AddLinearConstraint("e");
|
||||
|
||||
const LinearConstraintMap<double> input = {
|
||||
{LinearConstraint(&model, c), 3.0}, {LinearConstraint(&model, e), -2.0}};
|
||||
|
||||
EXPECT_THAT(LinearConstraintValuesFromProto(
|
||||
&model, LinearConstraintValuesToProto(input)),
|
||||
IsOkAndHolds(IsNear(input, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesFromProtoTest, EmptySuccess) {
|
||||
ModelStorage model;
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "c"});
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesFromProtoTest, NonEmptySuccess) {
|
||||
ModelStorage model;
|
||||
const QuadraticConstraintId c =
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "c"});
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "d"});
|
||||
const QuadraticConstraintId e =
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "e"});
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(2);
|
||||
proto.add_values(3.0);
|
||||
proto.add_values(-2.0);
|
||||
|
||||
absl::flat_hash_map<QuadraticConstraint, double> expected = {
|
||||
{QuadraticConstraint(&model, c), 3.0},
|
||||
{QuadraticConstraint(&model, e), -2.0}};
|
||||
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(&model, proto),
|
||||
IsOkAndHolds(IsNear(expected, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesFromProtoTest, UnequalSize) {
|
||||
ModelStorage model;
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "c"});
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesFromProtoTest, NotInModel) {
|
||||
ModelStorage model;
|
||||
|
||||
SparseDoubleVectorProto proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_values(1.0);
|
||||
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(&model, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no quadratic constraint with id")));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesToProtoTest, Empty) {
|
||||
ModelStorage model;
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(
|
||||
&model, QuadraticConstraintValuesToProto({})),
|
||||
IsOkAndHolds(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST(QuadraticConstraintValuesToProtoTest, SmallMap) {
|
||||
ModelStorage model;
|
||||
const QuadraticConstraintId c =
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "c"});
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "d"});
|
||||
const QuadraticConstraintId e =
|
||||
model.AddAtomicConstraint(QuadraticConstraintData{.name = "e"});
|
||||
|
||||
const absl::flat_hash_map<QuadraticConstraint, double> input = {
|
||||
{QuadraticConstraint(&model, c), 3.0},
|
||||
{QuadraticConstraint(&model, e), -2.0}};
|
||||
|
||||
EXPECT_THAT(QuadraticConstraintValuesFromProto(
|
||||
&model, QuadraticConstraintValuesToProto(input)),
|
||||
IsOkAndHolds(IsNear(input, /*tolerance=*/0.0)));
|
||||
}
|
||||
|
||||
TEST(VariableBasis, EmptyRoundTrip) {
|
||||
ModelStorage model;
|
||||
const VariableMap<BasisStatus> variable_basis;
|
||||
SparseBasisStatusVector proto;
|
||||
|
||||
// Test one way
|
||||
EXPECT_THAT(VariableBasisFromProto(&model, proto),
|
||||
IsOkAndHolds(variable_basis));
|
||||
// Test round trip
|
||||
EXPECT_THAT(
|
||||
VariableBasisFromProto(&model, VariableBasisToProto(variable_basis)),
|
||||
IsOkAndHolds(variable_basis));
|
||||
}
|
||||
|
||||
TEST(VariableBasis, RoundTrip) {
|
||||
ModelStorage model;
|
||||
const VariableId x = model.AddVariable("x");
|
||||
const VariableId y = model.AddVariable("y");
|
||||
|
||||
const VariableMap<BasisStatus> variable_basis = {
|
||||
{Variable(&model, x), BasisStatus::kAtUpperBound},
|
||||
{Variable(&model, y), BasisStatus::kFree}};
|
||||
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_UPPER_BOUND);
|
||||
proto.add_values(BASIS_STATUS_FREE);
|
||||
|
||||
// Test one way
|
||||
EXPECT_THAT(VariableBasisFromProto(&model, proto),
|
||||
IsOkAndHolds(variable_basis));
|
||||
// Test round trip
|
||||
EXPECT_THAT(
|
||||
VariableBasisFromProto(&model, VariableBasisToProto(variable_basis)),
|
||||
IsOkAndHolds(variable_basis));
|
||||
}
|
||||
|
||||
TEST(VariableBasisFromProto, UnequalSize) {
|
||||
ModelStorage storage;
|
||||
storage.AddVariable("x");
|
||||
storage.AddVariable("y");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_LOWER_BOUND);
|
||||
EXPECT_THAT(VariableBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(VariableBasisFromProto, VariableDoesNotExist) {
|
||||
ModelStorage storage;
|
||||
storage.AddVariable("x");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_LOWER_BOUND);
|
||||
proto.add_values(BASIS_STATUS_AT_UPPER_BOUND);
|
||||
EXPECT_THAT(VariableBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no variable with id")));
|
||||
}
|
||||
|
||||
TEST(VariableBasisFromProto, UnspecifiedStatus) {
|
||||
ModelStorage storage;
|
||||
storage.AddVariable("x");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_values(BASIS_STATUS_UNSPECIFIED);
|
||||
EXPECT_THAT(VariableBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("basis status not specified")));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintBasis, EmptyRoundTrip) {
|
||||
ModelStorage model;
|
||||
|
||||
const LinearConstraintMap<BasisStatus> linear_constraint_basis;
|
||||
|
||||
SparseBasisStatusVector proto;
|
||||
|
||||
// Test one way
|
||||
EXPECT_THAT(LinearConstraintBasisFromProto(&model, proto),
|
||||
IsOkAndHolds(linear_constraint_basis));
|
||||
// Test round trip
|
||||
EXPECT_THAT(
|
||||
LinearConstraintBasisFromProto(
|
||||
&model, LinearConstraintBasisToProto(linear_constraint_basis)),
|
||||
IsOkAndHolds(linear_constraint_basis));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintBasis, RoundTrip) {
|
||||
ModelStorage model;
|
||||
const LinearConstraintId c = model.AddLinearConstraint("c");
|
||||
const LinearConstraintId d = model.AddLinearConstraint("d");
|
||||
|
||||
const LinearConstraintMap<BasisStatus> linear_constraint_basis = {
|
||||
{LinearConstraint(&model, c), BasisStatus::kAtLowerBound},
|
||||
{LinearConstraint(&model, d), BasisStatus::kFixedValue}};
|
||||
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_LOWER_BOUND);
|
||||
proto.add_values(BASIS_STATUS_FIXED_VALUE);
|
||||
|
||||
// Test one way
|
||||
EXPECT_THAT(LinearConstraintBasisFromProto(&model, proto),
|
||||
IsOkAndHolds(linear_constraint_basis));
|
||||
// Test round trip
|
||||
EXPECT_THAT(
|
||||
LinearConstraintBasisFromProto(
|
||||
&model, LinearConstraintBasisToProto(linear_constraint_basis)),
|
||||
IsOkAndHolds(linear_constraint_basis));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintBasisFromProto, UnequalSize) {
|
||||
ModelStorage storage;
|
||||
storage.AddLinearConstraint("c");
|
||||
storage.AddLinearConstraint("d");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_LOWER_BOUND);
|
||||
EXPECT_THAT(LinearConstraintBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintBasisFromProto, LinearConstraintDoesNotExist) {
|
||||
ModelStorage storage;
|
||||
storage.AddLinearConstraint("c");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_ids(1);
|
||||
proto.add_values(BASIS_STATUS_AT_LOWER_BOUND);
|
||||
proto.add_values(BASIS_STATUS_AT_UPPER_BOUND);
|
||||
EXPECT_THAT(LinearConstraintBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("no linear constraint with id")));
|
||||
}
|
||||
|
||||
TEST(LinearConstraintBasisFromProto, UnspecifiedStatus) {
|
||||
ModelStorage storage;
|
||||
storage.AddLinearConstraint("c");
|
||||
SparseBasisStatusVector proto;
|
||||
proto.add_ids(0);
|
||||
proto.add_values(BASIS_STATUS_UNSPECIFIED);
|
||||
EXPECT_THAT(LinearConstraintBasisFromProto(&storage, proto),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("basis status not specified")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace operations_research::math_opt
|
||||
Reference in New Issue
Block a user