Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
cp_model_solver_logging.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cctype>
17#include <string>
18#include <vector>
19
20#include "absl/strings/str_cat.h"
21#include "absl/strings/str_format.h"
22#include "absl/strings/string_view.h"
24#include "ortools/sat/util.h"
26
27namespace operations_research {
28namespace sat {
29
30namespace {
31std::string ExtractSubSolverName(const std::string& improvement_info) {
32 if (improvement_info.empty()) return "";
33
34 // We assume the subsolver name is always first.
35 for (int i = 0; i < improvement_info.size(); ++i) {
36 if (!std::isalnum(improvement_info[i]) && improvement_info[i] != '_') {
37 return improvement_info.substr(0, i);
38 }
39 }
40
41 return improvement_info;
42}
43
44std::string ProgressMessage(absl::string_view event_or_solution_count,
45 double time_in_seconds, double obj_best,
46 double obj_lb, double obj_ub,
47 absl::string_view solution_info) {
48 const std::string obj_next =
49 obj_lb <= obj_ub ? absl::StrFormat("next:[%.9g,%.9g]", obj_lb, obj_ub)
50 : "next:[]";
51 return absl::StrFormat("#%-5s %6.2fs best:%-5.9g %-15s %s",
52 event_or_solution_count, time_in_seconds, obj_best,
53 obj_next, solution_info);
54}
55
56std::string SatProgressMessage(absl::string_view event_or_solution_count,
57 double time_in_seconds,
58 absl::string_view solution_info) {
59 return absl::StrFormat("#%-5s %6.2fs %s", event_or_solution_count,
60 time_in_seconds, solution_info);
61}
62
63} // namespace
64
66 if (info.solved) {
67 SOLVER_LOG(logger_,
68 SatProgressMessage("Done", wall_timer_.Get(), info.change_info));
69 return;
70 }
71 if (info.new_best_solution) {
72 RegisterSolutionFound(info.change_info, num_solutions_);
73
74 num_solutions_++;
75 if (is_optimization_) {
76 RegisterSolutionFound(info.change_info, num_solutions_);
77 SOLVER_LOG(logger_,
78 ProgressMessage(
79 absl::StrCat(num_solutions_), wall_timer_.Get(),
82 return;
83 } else {
84 SOLVER_LOG(logger_,
85 SatProgressMessage(absl::StrCat(num_solutions_),
86 wall_timer_.Get(), info.change_info));
87 }
88 }
89 if (info.new_lower_bound || info.new_upper_bound) {
90 logger_->ThrottledLog(
91 bounds_logging_id_,
92 ProgressMessage("Bound", wall_timer_.Get(), info.best_objective_value,
95 RegisterObjectiveBoundImprovement(info.change_info);
96 }
97}
98
99void SolverProgressLogger::RegisterSolutionFound(
100 const std::string& improvement_info, int solution_number) {
101 if (improvement_info.empty()) return;
102 const std::string subsolver_name = ExtractSubSolverName(improvement_info);
103 primal_improvements_count_[subsolver_name]++;
104 primal_improvements_min_rank_.insert({subsolver_name, solution_number});
105 primal_improvements_max_rank_[subsolver_name] = solution_number;
106}
107
108void SolverProgressLogger::RegisterObjectiveBoundImprovement(
109 const std::string& improvement_info) {
110 if (improvement_info.empty() || improvement_info == "initial domain") return;
111 dual_improvements_count_[ExtractSubSolverName(improvement_info)]++;
112}
113
115 SolverLogger* logger) const {
116 if (!primal_improvements_count_.empty()) {
117 std::vector<std::vector<std::string>> table;
118 table.push_back(
119 {absl::StrCat("Solutions (", num_solutions_, ")"), "Num", "Rank"});
120 for (const auto& entry : primal_improvements_count_) {
121 auto it = primal_improvements_min_rank_.find(entry.first);
122 if (it == primal_improvements_min_rank_.end()) continue;
123 const int min_rank = it->second;
124 it = primal_improvements_max_rank_.find(entry.first);
125 if (it == primal_improvements_max_rank_.end()) continue;
126 const int max_rank = it->second;
127 table.push_back({FormatName(entry.first), FormatCounter(entry.second),
128 absl::StrCat("[", min_rank, ",", max_rank, "]")});
129 }
130 SOLVER_LOG(logger, FormatTable(table));
131 }
132 if (!dual_improvements_count_.empty()) {
133 std::vector<std::vector<std::string>> table;
134 table.push_back({"Objective bounds", "Num"});
135 for (const auto& entry : dual_improvements_count_) {
136 table.push_back({FormatName(entry.first), FormatCounter(entry.second)});
137 }
138 SOLVER_LOG(logger, FormatTable(table));
139 }
140}
141
142} // namespace sat
143} // namespace operations_research
void UpdateProgress(const SolverStatusChangeInfo &info)
void DisplayImprovementStatistics(SolverLogger *logger) const
std::string FormatName(absl::string_view name)
Definition util.h:342
std::string FormatTable(std::vector< std::vector< std::string > > &table, int spacing)
Definition util.cc:61
OR-Tools root namespace.
std::string FormatCounter(int64_t num)
Definition logging.cc:30
#define SOLVER_LOG(logger,...)
Definition logging.h:114