Files
ortools-clone/ortools/sat/combine_solutions.cc
Mizux Seiha 4f381f6d07 backport from main:
* bump abseil to 20250814
* bump protobuf to v32.0
* cmake: add ccache auto support
* backport flatzinc, math_opt and sat update
2025-09-16 16:25:04 +02:00

107 lines
4.0 KiB
C++

// 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/sat/combine_solutions.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "absl/log/check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "ortools/sat/cp_model_checker.h"
#include "ortools/sat/model.h"
#include "ortools/sat/synchronization.h"
namespace operations_research {
namespace sat {
bool TrySolution(const CpModelProto& model, absl::Span<const int64_t> solution,
absl::Span<const int64_t> new_solution,
absl::Span<const int64_t> base_solution,
std::vector<int64_t>* new_combined_solution) {
new_combined_solution->resize(new_solution.size());
for (int i = 0; i < new_solution.size(); ++i) {
if (new_solution[i] != base_solution[i]) {
// A value that changed that we patch.
(*new_combined_solution)[i] = new_solution[i];
} else {
(*new_combined_solution)[i] = solution[i];
}
}
return SolutionIsFeasible(model, *new_combined_solution);
}
std::optional<std::vector<int64_t>> FindCombinedSolution(
const CpModelProto& model, absl::Span<const int64_t> new_solution,
absl::Span<const int64_t> base_solution,
const SharedResponseManager* response_manager, std::string* solution_info) {
CHECK_EQ(new_solution.size(), base_solution.size());
const std::vector<
std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution>>
solutions =
response_manager->SolutionPool().BestSolutions().GetBestNSolutions(
10);
for (int sol_idx = 0; sol_idx < solutions.size(); ++sol_idx) {
std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution> s =
solutions[sol_idx];
DCHECK_EQ(s->variable_values.size(), new_solution.size());
if (s->variable_values == new_solution ||
s->variable_values == base_solution) {
continue;
}
std::vector<int64_t> new_combined_solution;
if (TrySolution(model, s->variable_values, new_solution, base_solution,
&new_combined_solution)) {
absl::StrAppend(solution_info, " [combined with: ",
std::string_view(solutions[sol_idx]->info).substr(0, 20),
"...]");
return new_combined_solution;
}
}
return std::nullopt;
}
PushedSolutionPointers PushAndMaybeCombineSolution(
SharedResponseManager* response_manager, const CpModelProto& model_proto,
absl::Span<const int64_t> new_solution, absl::string_view solution_info,
std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution>
base_solution) {
PushedSolutionPointers result = {nullptr, nullptr};
result.pushed_solution = response_manager->NewSolution(
new_solution, solution_info, nullptr,
base_solution == nullptr ? -1 : base_solution->source_id);
if (base_solution != nullptr) {
std::string combined_solution_info(solution_info);
std::optional<std::vector<int64_t>> combined_solution =
FindCombinedSolution(model_proto, new_solution,
base_solution->variable_values, response_manager,
&combined_solution_info);
if (combined_solution.has_value()) {
result.improved_solution = response_manager->NewSolution(
combined_solution.value(), combined_solution_info);
}
}
return result;
}
} // namespace sat
} // namespace operations_research