backport sat fuzztest from main

This commit is contained in:
Corentin Le Molgat
2024-11-20 15:10:09 +01:00
parent 019ff0b73b
commit 5a20b0296e
34 changed files with 12353 additions and 9 deletions

View File

@@ -9,14 +9,15 @@ OR_TOOLS_VERSION = "9.12.0"
module(
name = "or-tools",
repo_name = "com_google_ortools",
version = OR_TOOLS_VERSION,
repo_name = "com_google_ortools",
)
bazel_dep(name = "abseil-cpp", version = "20240722.0", repo_name = "com_google_absl")
bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "contrib_rules_jvm", version = "0.27.0")
bazel_dep(name = "eigen", version = "3.4.0.bcr.1")
bazel_dep(name = "fuzztest", version = "20241028.0", repo_name = "com_google_fuzztest")
bazel_dep(name = "gazelle", version = "0.39.1", repo_name = "bazel_gazelle")
bazel_dep(name = "glpk", version = "5.0.bcr.1")
bazel_dep(name = "google_benchmark", version = "1.8.5", repo_name = "com_google_benchmark")
@@ -42,8 +43,8 @@ bazel_dep(name = "zlib", version = "1.3.1.bcr.3")
git_override(
module_name = "pybind11_abseil",
commit = "70f8b693b3b70573ca785ef62d9f48054f45d786",
patches = ["//patches:pybind11_abseil.patch"],
patch_strip = 1,
patches = ["//patches:pybind11_abseil.patch"],
remote = "https://github.com/pybind/pybind11_abseil.git",
)
@@ -57,14 +58,15 @@ SUPPORTED_PYTHON_VERSIONS = [
DEFAULT_PYTHON = "3.11"
python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency=True)
python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True)
[
python.toolchain(
ignore_root_user_error = True, # needed for CI
python_version = version,
is_default = version == DEFAULT_PYTHON,
)
for version in SUPPORTED_PYTHON_VERSIONS
python.toolchain(
ignore_root_user_error = True, # needed for CI
is_default = version == DEFAULT_PYTHON,
python_version = version,
)
for version in SUPPORTED_PYTHON_VERSIONS
]
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")

View File

@@ -215,6 +215,19 @@ cc_library(
],
)
cc_library(
name = "fuzztest",
testonly = 1,
hdrs = ["fuzztest.h"],
deps = [
"@com_google_absl//absl/log:check",
"@com_google_fuzztest//fuzztest",
"@com_google_fuzztest//fuzztest:googletest_fixture_adapter",
"@com_google_fuzztest//fuzztest:init_fuzztest",
"@com_google_protobuf//:protobuf",
],
)
cc_library(
name = "status_matchers",
hdrs = ["status_matchers.h"],

55
ortools/base/fuzztest.h Normal file
View File

@@ -0,0 +1,55 @@
// 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.
#ifndef OR_TOOLS_BASE_FUZZTEST_H_
#define OR_TOOLS_BASE_FUZZTEST_H_
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include "fuzztest/domain.h"
#include "fuzztest/fuzztest.h"
#include "fuzztest/googletest_fixture_adapter.h"
#include "fuzztest/init_fuzztest.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
#include "ortools/base/logging.h"
namespace fuzztest {
// Reads protos from directory and returns a vector usable by the .WithSeeds()
// function to aid in fuzz test migrations. `is_text_format` should be true iff
// the protos are in text format.
template <class ProtoType>
std::vector<std::tuple<ProtoType>> ReadFilesFromDirectory(
std::string_view dir) {
std::vector<std::tuple<ProtoType>> corpus;
for (std::tuple<std::string>& proto_tuple : ReadFilesFromDirectory(dir)) {
std::string text_proto = std::get<0>(proto_tuple);
ProtoType proto;
bool was_parsed =
google::protobuf::TextFormat::ParseFromString(text_proto, &proto);
if (was_parsed) {
corpus.push_back(std::make_tuple(proto));
}
}
return corpus;
}
} // namespace fuzztest
#endif // OR_TOOLS_BASE_FUZZTEST_H_

View File

@@ -3743,6 +3743,22 @@ cc_test(
],
)
cc_test(
name = "cp_model_solver_fuzz",
size = "large",
srcs = ["cp_model_solver_fuzz.cc"],
data = glob(["fuzz_testdata/*"]),
deps = [
":cp_model_cc_proto",
":cp_model_solver",
"//ortools/base:fuzztest",
"//ortools/base:path",
"@bazel_tools//tools/cpp/runfiles",
"@com_google_absl//absl/log:check",
"@com_google_fuzztest//fuzztest:fuzztest_gtest_main",
],
)
cc_test(
name = "flaky_models_test",
size = "small",

View File

@@ -13,6 +13,7 @@
file(GLOB _SRCS "*.h" "*.cc")
list(FILTER _SRCS EXCLUDE REGEX ".*/.*_test.cc")
list(FILTER _SRCS EXCLUDE REGEX ".*/.*_fuzz.cc")
list(REMOVE_ITEM _SRCS
${CMAKE_CURRENT_SOURCE_DIR}/opb_reader.h
${CMAKE_CURRENT_SOURCE_DIR}/sat_cnf_reader.h

View File

@@ -0,0 +1,69 @@
// 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 <string>
#include "absl/log/check.h"
#include "gtest/gtest.h" // IWYU pragma: keep
#include "ortools/base/fuzztest.h"
#include "ortools/base/path.h" // IWYU pragma: keep
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "tools/cpp/runfiles/runfiles.h"
namespace operations_research::sat {
namespace {
std::string GetTestDataDir() {
return file::JoinPathRespectAbsolute(::testing::SrcDir(),
"_main/ortools/sat/fuzz_testdata");
}
void Solve(const CpModelProto& proto) {
const CpSolverResponse response =
operations_research::sat::SolveWithParameters(proto,
"max_time_in_seconds: 4.0");
const CpSolverResponse response_no_presolve =
operations_research::sat::SolveWithParameters(
proto, "max_time_in_seconds:4.0,cp_model_presolve:false");
CHECK_EQ(response.status() == CpSolverStatus::MODEL_INVALID,
response_no_presolve.status() == CpSolverStatus::MODEL_INVALID)
<< "Model being invalid should not depend on presolve";
if (response.status() == CpSolverStatus::MODEL_INVALID) {
return;
}
if (response.status() == CpSolverStatus::UNKNOWN ||
response_no_presolve.status() == CpSolverStatus::UNKNOWN) {
return;
}
CHECK_EQ(response.status() == CpSolverStatus::INFEASIBLE,
response_no_presolve.status() == CpSolverStatus::INFEASIBLE)
<< "Presolve should not change feasibility";
}
// Fuzzing repeats solve() 100 times, and timeout after 600s.
// With a time limit of 4s, we should be fine.
FUZZ_TEST(CpModelProtoFuzzer, Solve)
.WithDomains(/*proto:*/ fuzztest::Arbitrary<CpModelProto>())
.WithSeeds([]() {
return fuzztest::ReadFilesFromDirectory<CpModelProto>(GetTestDataDir());
});
} // namespace
} // namespace operations_research::sat

View File

@@ -0,0 +1,38 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 5
}
variables {
domain: 0
domain: 5
}
variables {
domain: 2
domain: 8
}
constraints {
linear {
vars: 0
vars: 1
vars: 2
coeffs: 1
coeffs: 1
coeffs: -1
domain: 0
domain: 0
}
}
objective {
vars: 2
scaling_factor: 1
coeffs: 1
}
solution_hint {
vars: 0
vars: 1
values: 4
values: 5
}

View File

@@ -0,0 +1,70 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 2
domain: 0
domain: 8
}
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: 2
domain: 20
}
}
constraints {
linear {
vars: 2
vars: 3
coeffs: 1
coeffs: 2
domain: 0
domain: 6
}
}
constraints {
linear {
vars: 2
vars: 3
coeffs: 1
coeffs: 1
domain: 2
domain: 20
}
}
objective {
vars: -1
vars: -2
vars: -3
vars: -4
scaling_factor: -1
coeffs: 1
coeffs: 2
coeffs: 3
coeffs: 4
}

View File

@@ -0,0 +1,27 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 4
}
variables {
domain: 1
domain: 4
}
variables {
domain: 1
domain: 4
}
variables {
domain: 1
domain: 4
}
constraints {
all_diff {
exprs {
vars: [0, 1, 2, 3]
coeffs: [1, 1, 1, 1]
}
}
}

View File

@@ -0,0 +1,21 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 5
}
variables {
domain: 0
domain: 5
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: 6
domain: 6
}
}

View File

@@ -0,0 +1,15 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 2
}
variables {
domain: 0
domain: 2
}
variables {
domain: 0
domain: 2
}

View File

@@ -0,0 +1,34 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 5
}
variables {
domain: 0
domain: 5
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: 2
domain: 8
}
}
objective {
vars: 0
vars: 1
scaling_factor: 1
coeffs: 1
coeffs: 1
}
solution_hint {
vars: 0
vars: 1
values: 2
values: 3
}

View File

@@ -0,0 +1,5 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
}

View File

@@ -0,0 +1,31 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 4
}
variables {
domain: 0
domain: 4
}
constraints {
enforcement_literal: 0
enforcement_literal: 1
linear {
vars: 2
vars: 3
coeffs: 1
coeffs: -1
domain: 0
domain: 0
}
}

View File

@@ -0,0 +1,21 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 10
}
variables {
domain: 0
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: 4
domain: 5
}
}

View File

@@ -0,0 +1,27 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 2
coeffs: 1
domain: 10
domain: 10
}
}
objective {
vars: 1
coeffs: 1
domain: 8
domain: 10
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 4
}
variables {
domain: 2
domain: 2
}
variables {
domain: 0
domain: 4
}
variables {
domain: 1
domain: 4
}
variables {
domain: 2
domain: 2
}
variables {
domain: 0
domain: 4
}
variables {
domain: 3
domain: 3
}
variables {
domain: 4
domain: 4
}
variables {
domain: 6
domain: 6
}
constraints {
interval {
end { vars: 2 coeffs: 1 }
size { vars: 2 coeffs: 1 }
}
}
constraints {
interval {
start { vars: 3 coeffs: 1 }
end { vars: 5 coeffs: 1 }
size { vars: 4 coeffs: 1 }
}
}
constraints {
cumulative {
capacity { vars: 8 coeffs: 1 }
intervals: 0
intervals: 1
demands: { vars: 6 coeffs: 1 }
demands: { vars: 7 coeffs: 1 }
}
}

View File

@@ -0,0 +1,46 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 0
domain: 6
}
variables {
domain: 3
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 3
domain: 6
}
constraints {
interval {
end {vars: 2 coeffs: 1 }
size { vars: 1 coeffs: 1 }
}
}
constraints {
interval {
start { vars: 3 coeffs: 1 }
end {vars: 5 coeffs: 1 }
size {vars: 4 coeffs: 1 }
}
}
constraints {
no_overlap {
intervals: 0
intervals: 1
}
}

View File

@@ -0,0 +1,28 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: -10
domain: 10
}
variables {
domain: -10
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: -100
domain: 100
}
}
objective {
vars: 0
vars: 1
scaling_factor: -1
coeffs: -1
coeffs: -2
}

View File

@@ -0,0 +1,83 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 0
domain: 6
}
variables {
domain: 0
domain: 1
}
variables {
domain: 2
domain: 6
}
variables {
domain: 2
domain: 2
}
variables {
domain: 2
domain: 6
}
variables {
domain: 3
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 3
domain: 6
}
constraints {
enforcement_literal: 0
interval {
start { vars: 1 coeffs: 1 }
end { vars: 3 coeffs: 1 }
size { vars: 2 offset: 2 }
}
}
constraints {
enforcement_literal: 4
interval {
start { vars: 5 coeffs: 1 }
end { vars: 7 coeffs: 1 }
size { vars: 6 coeffs: 1 }
}
}
constraints {
interval {
start { vars: 8 coeffs: 1 }
end { vars: 10 coeffs: 1 }
size { vars: 9 coeffs: 1 }
}
}
constraints {
no_overlap {
intervals: 0
intervals: 1
intervals: 2
}
}
constraints {
bool_xor {
literals: 0
literals: 4
}
}

View File

@@ -0,0 +1,83 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 0
domain: 6
}
variables {
domain: 0
domain: 1
}
variables {
domain: 2
domain: 6
}
variables {
domain: 2
domain: 2
}
variables {
domain: 2
domain: 6
}
variables {
domain: 3
domain: 6
}
variables {
domain: 3
domain: 3
}
variables {
domain: 3
domain: 6
}
constraints {
enforcement_literal: 0
interval {
start { vars: 1 coeffs: 1 }
end { vars: 3 coeffs: 1 }
size { vars: 2 coeffs: 1 }
}
}
constraints {
enforcement_literal: 4
interval {
start { vars: 5 coeffs: 1 }
end { vars: 7 coeffs: 1 }
size { vars: 6 coeffs: 1 }
}
}
constraints {
interval {
start { vars: 8 coeffs: 1 }
end { vars: 10 coeffs: 1 }
size { vars: 9 coeffs: 1 }
}
}
constraints {
no_overlap {
intervals: 0
intervals: 1
intervals: 2
}
}
constraints {
bool_and {
literals: 0
literals: 4
}
}

View File

@@ -0,0 +1,50 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 1
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 2
domain: 0
domain: 8
}
}
constraints {
linear {
vars: 2
vars: 3
coeffs: 1
coeffs: 2
domain: 0
domain: 6
}
}
objective {
vars: -1
vars: -2
vars: -3
vars: -4
scaling_factor: -1
coeffs: 1
coeffs: 2
coeffs: 3
coeffs: 4
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
name: "x"
domain: 0
domain: 10
}
variables {
name: "y"
domain: 0
domain: 10
}
constraints {
linear {
vars: 1
vars: 0
coeffs: 1
coeffs: 1
domain: 10
domain: 10
}
}
solution_hint {
vars: 0
values: -1
}

View File

@@ -0,0 +1,39 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
objective {
vars: 0
vars: 1
vars: 2
vars: 3
coeffs: 1
coeffs: 2
coeffs: 3
coeffs: 4
}
solution_hint {
vars: 0
vars: 1
vars: 2
vars: 3
values: 1
values: 0
values: 0
values: 1
}

View File

@@ -0,0 +1,39 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
variables {
domain: 0
domain: 1
}
objective {
vars: 0
vars: 1
vars: 2
vars: 3
coeffs: -1
coeffs: 2
coeffs: 3
coeffs: -4
}
solution_hint {
vars: 0
vars: 1
vars: 2
vars: 3
values: 1
values: 0
values: 0
values: 1
}

View File

@@ -0,0 +1,19 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 4
}
variables {
domain: 1
domain: 1
}
variables {
domain: 3
domain: 3
}
variables {
domain: 1
domain: 4
}

View File

@@ -0,0 +1,27 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 0
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
vars: 2
coeffs: 1
coeffs: 2
coeffs: 3
domain: 0
domain: 7
}
}

View File

@@ -0,0 +1,27 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 10
}
variables {
domain: 1
domain: 10
}
variables {
domain: 0
domain: 10
}
constraints {
linear {
vars: 0
vars: 1
vars: 2
coeffs: 1
coeffs: 2
coeffs: 3
domain: 80
domain: 87
}
}

View File

@@ -0,0 +1,42 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: -10
domain: 10
}
variables {
domain: -10
domain: 10
}
variables {
domain: -4611686018427387903
domain: 4611686018427387903
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: -4611686018427387903
domain: 4611686018427387903
}
}
constraints {
linear {
vars: 0
vars: 1
vars: 2
coeffs: 1
coeffs: 2
coeffs: -1
domain: 0
domain: 0
}
}
objective {
vars: -3
scaling_factor: -1
coeffs: 1
}

View File

@@ -0,0 +1,11 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 1
domain: 1
}
objective {
vars: 0
coeffs: 1
}

View File

@@ -0,0 +1,21 @@
# proto-file: ortools/sat/cp_model.proto
# proto-message: operations_research.sat.CpModelProto
variables {
domain: 0
domain: 0
}
variables {
domain: 1
domain: 1
}
constraints {
linear {
vars: 0
vars: 1
coeffs: 1
coeffs: 1
domain: 0
domain: 0
}
}