Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
fz.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
14// This is the skeleton for the official flatzinc interpreter. Much
15// of the functionalities are fixed (name of parameters, format of the
16// input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf
17
18#include <cstdlib>
19#include <cstring>
20#if defined(__GNUC__) // Linux or Mac OS X.
21#include <signal.h>
22#endif // __GNUC__
23
24#include <iostream>
25#include <ostream>
26#include <string>
27#include <vector>
28
29#include "absl/flags/flag.h"
30#include "absl/flags/parse.h"
31#include "absl/flags/usage.h"
32#include "absl/log/check.h"
33#include "absl/log/flags.h"
34#include "absl/log/initialize.h"
35#include "absl/log/log.h"
36#include "absl/strings/match.h"
37#include "absl/strings/str_split.h"
38#include "absl/strings/string_view.h"
39#include "absl/time/time.h"
40#include "google/protobuf/text_format.h"
42#include "ortools/base/path.h"
43#include "ortools/base/timer.h"
47#include "ortools/sat/model.h"
49
50constexpr bool kOrToolsMode = true;
51
52ABSL_FLAG(double, time_limit, 0, "time limit in seconds.");
53ABSL_FLAG(bool, search_all_solutions, false, "Search for all solutions.");
54ABSL_FLAG(bool, display_all_solutions, false,
55 "Display all improving solutions.");
56ABSL_FLAG(bool, free_search, !kOrToolsMode,
57 "If false, the solver must follow the defined search."
58 "If true, other search are allowed.");
59ABSL_FLAG(int, threads, 0, "Number of threads the solver will use.");
60ABSL_FLAG(bool, statistics, false, "Print solver statistics after search.");
61ABSL_FLAG(bool, read_from_stdin, false,
62 "Read the FlatZinc from stdin, not from a file.");
63ABSL_FLAG(int, fz_seed, 0, "Random seed");
64ABSL_FLAG(std::string, fz_model_name, "stdin",
65 "Define problem name when reading from stdin.");
66ABSL_FLAG(std::string, params, "", "SatParameters as a text proto.");
67ABSL_FLAG(bool, fz_logging, false,
68 "Print logging information from the flatzinc interpreter.");
69ABSL_FLAG(bool, ortools_mode, kOrToolsMode,
70 "Display solutions in the flatzinc format");
71ABSL_FLAG(bool, fz_check_all_solutions, DEBUG_MODE,
72 "Checks all solutions returned by the solver.");
73ABSL_FLAG(bool, ignore_redundant_constraints, false,
74 "Ignore redundant constraints.");
75ABSL_FLAG(bool, ignore_symmetry_breaking_constraints, false,
76 "Ignore symmetry breaking constraints.");
77
78namespace operations_research {
79namespace fz {
80
81std::vector<char*> FixAndParseParameters(int* argc, char*** argv) {
82 char all_param[] = "--search_all_solutions";
83 char print_solutions[] = "--display_all_solutions";
84 char free_param[] = "--free_search";
85 char threads_param[] = "--threads";
86 char logging_param[] = "--fz_logging";
87 char statistics_param[] = "--statistics";
88 char seed_param[] = "--fz_seed";
89 char time_param[] = "--time_limit";
90 bool use_time_param = false;
91 bool set_free_search = false;
92 for (int i = 1; i < *argc; ++i) {
93 if (strcmp((*argv)[i], "-a") == 0) {
94 (*argv)[i] = all_param;
95 }
96 if (strcmp((*argv)[i], "-i") == 0) {
97 (*argv)[i] = print_solutions;
98 }
99 if (strcmp((*argv)[i], "-f") == 0) {
100 (*argv)[i] = free_param;
101 set_free_search = true;
102 }
103 if (strcmp((*argv)[i], "-p") == 0) {
104 (*argv)[i] = threads_param;
105 }
106 if (strcmp((*argv)[i], "-l") == 0) {
107 (*argv)[i] = logging_param;
108 }
109 if (strcmp((*argv)[i], "-s") == 0) {
110 (*argv)[i] = statistics_param;
111 }
112 if (strcmp((*argv)[i], "-r") == 0) {
113 (*argv)[i] = seed_param;
114 }
115 if (strcmp((*argv)[i], "-t") == 0) {
116 (*argv)[i] = time_param;
117 use_time_param = true;
118 }
119 if (kOrToolsMode) {
120 if (strcmp((*argv)[i], "-v") == 0) {
121 (*argv)[i] = logging_param;
122 }
123 }
124 }
125 const char kUsage[] =
126 "Usage: see flags.\nThis program parses and solve a flatzinc problem.";
127
128 absl::SetProgramUsageMessage(kUsage);
129 const std::vector<char*> residual_flags =
130 absl::ParseCommandLine(*argc, *argv);
131 absl::InitializeLog();
132
133 // Fix time limit if -t was used.
134 if (use_time_param) {
135 absl::SetFlag(&FLAGS_time_limit, absl::GetFlag(FLAGS_time_limit) / 1000.0);
136 }
137
138 // Define the default number of workers to 1 if -f was used.
139 if (set_free_search && absl::GetFlag(FLAGS_threads) == 0) {
140 absl::SetFlag(&FLAGS_threads, 1);
141 }
142
143 return residual_flags;
144}
145
146Model ParseFlatzincModel(const std::string& input, bool input_is_filename,
147 SolverLogger* logger, absl::Duration* parse_duration) {
148 WallTimer timer;
149 timer.Start();
150
151 // Check the extension.
152 if (input_is_filename && !absl::EndsWith(input, ".fzn")) {
153 LOG(FATAL) << "Unrecognized flatzinc file: `" << input << "'";
154 }
155
156 // Read model.
157 const std::string problem_name = input_is_filename
158 ? std::string(file::Stem(input))
159 : absl::GetFlag(FLAGS_fz_model_name);
160 Model model(problem_name);
161 if (input_is_filename) {
162 CHECK(ParseFlatzincFile(input, &model));
163 } else {
164 CHECK(ParseFlatzincString(input, &model));
165 }
166
167 *parse_duration = timer.GetDuration();
168 SOLVER_LOG(logger, "File ", (input_is_filename ? input : "stdin"),
169 " parsed in ", absl::ToInt64Milliseconds(*parse_duration), " ms");
170
171 int num_redundant_constraints = 0;
172 int num_symmetry_breaking_constraints = 0;
173 for (Constraint* ct : model.constraints()) {
174 if (ct->is_redundant && absl::GetFlag(FLAGS_ignore_redundant_constraints)) {
175 ++num_redundant_constraints;
176 ct->MarkAsInactive();
177 }
178 if (ct->is_symmetric_breaking &&
179 absl::GetFlag(FLAGS_ignore_symmetry_breaking_constraints)) {
180 ++num_symmetry_breaking_constraints;
181 ct->MarkAsInactive();
182 }
183 }
184 if (num_redundant_constraints > 0) {
185 SOLVER_LOG(logger, " - ignored redundant constraints: ",
186 num_redundant_constraints);
187 }
188 if (num_symmetry_breaking_constraints > 0) {
189 SOLVER_LOG(logger, " - ignored symmetry breaking constraints: ",
190 num_symmetry_breaking_constraints);
191 }
192 SOLVER_LOG(logger, "");
193
194 // Print statistics.
195 ModelStatistics stats(model, logger);
196 stats.BuildStatistics();
197 stats.PrintStatistics();
198 return model;
199}
200
201void LogInFlatzincFormat(const std::string& multi_line_input) {
202 if (multi_line_input.empty()) {
203 std::cout << std::endl;
204 return;
205 }
206 const absl::string_view flatzinc_prefix =
207 absl::GetFlag(FLAGS_ortools_mode) ? "%% " : "";
208 const std::vector<absl::string_view> lines =
209 absl::StrSplit(multi_line_input, '\n');
210 for (const absl::string_view& line : lines) {
211 std::cout << flatzinc_prefix << line << std::endl;
212 }
213}
214
215} // namespace fz
216} // namespace operations_research
217
218int main(int argc, char** argv) {
219 // Flatzinc specifications require single dash parameters (-a, -f, -p).
220 // We need to fix parameters before parsing them.
221 const std::vector<char*> residual_flags =
223 // We allow piping model through stdin.
224 std::string input;
225 if (absl::GetFlag(FLAGS_read_from_stdin)) {
226 std::string currentLine;
227 while (std::getline(std::cin, currentLine)) {
228 input.append(currentLine);
229 input.append("\n");
230 }
231 } else {
232 if (residual_flags.empty()) {
233 LOG(ERROR) << "Usage: " << argv[0] << " <file>";
234 return EXIT_FAILURE;
235 }
236 input = residual_flags.back();
237 }
238
242 if (absl::GetFlag(FLAGS_ortools_mode)) {
243 logger->EnableLogging(absl::GetFlag(FLAGS_fz_logging));
244 // log_to_stdout is disabled later.
247 } else {
248 logger->EnableLogging(true);
249 logger->SetLogToStdOut(true);
250 }
251
252 absl::Duration parse_duration;
255 input, !absl::GetFlag(FLAGS_read_from_stdin), logger,
256 &parse_duration);
258
260 parameters.display_all_solutions = absl::GetFlag(FLAGS_display_all_solutions);
261 parameters.search_all_solutions = absl::GetFlag(FLAGS_search_all_solutions);
262 parameters.use_free_search = absl::GetFlag(FLAGS_free_search);
263 parameters.log_search_progress =
264 absl::GetFlag(FLAGS_fz_logging) || !absl::GetFlag(FLAGS_ortools_mode);
265 parameters.random_seed = absl::GetFlag(FLAGS_fz_seed);
266 parameters.display_statistics = absl::GetFlag(FLAGS_statistics);
267 parameters.number_of_threads = absl::GetFlag(FLAGS_threads);
268 parameters.max_time_in_seconds =
269 absl::GetFlag(FLAGS_time_limit) - absl::ToInt64Seconds(parse_duration);
270 parameters.ortools_mode = absl::GetFlag(FLAGS_ortools_mode);
271 parameters.check_all_solutions = absl::GetFlag(FLAGS_fz_check_all_solutions);
272
273 operations_research::SolverLogger solution_logger;
274 solution_logger.SetLogToStdOut(true);
275 solution_logger.EnableLogging(parameters.ortools_mode);
276
277 if (absl::GetFlag(FLAGS_time_limit) > 0 &&
278 parse_duration > absl::Seconds(absl::GetFlag(FLAGS_time_limit))) {
279 if (parameters.ortools_mode) {
280 SOLVER_LOG(&solution_logger, "%% TIMEOUT");
281 }
282 if (parameters.log_search_progress) {
283 SOLVER_LOG(logger, "CpSolverResponse summary:");
284 SOLVER_LOG(logger, "status: UNKNOWN");
285 }
286 return EXIT_SUCCESS;
287 }
288
290 CHECK(google::protobuf::TextFormat::ParseFromString(
291 absl::GetFlag(FLAGS_params), &flag_parameters))
292 << absl::GetFlag(FLAGS_params);
294 model, parameters, flag_parameters, &sat_model, &solution_logger);
295 return EXIT_SUCCESS;
296}
const bool DEBUG_MODE
Definition logging.h:35
absl::Duration GetDuration() const
Definition timer.h:47
void Start()
Definition timer.h:30
void EnableLogging(bool enable)
Definition logging.h:51
void SetLogToStdOut(bool enable)
Definition logging.h:57
void AddInfoLoggingCallback(std::function< void(const std::string &message)> callback)
Definition logging.cc:45
const std::vector< Constraint * > & constraints() const
Definition model.h:377
ABSL_FLAG(double, time_limit, 0, "time limit in seconds.")
int main(int argc, char **argv)
Definition fz.cc:218
constexpr bool kOrToolsMode
Definition fz.cc:50
absl::string_view Stem(absl::string_view path)
Definition path.cc:129
void LogInFlatzincFormat(const std::string &multi_line_input)
Definition fz.cc:201
Model ParseFlatzincModel(const std::string &input, bool input_is_filename, SolverLogger *logger, absl::Duration *parse_duration)
Definition fz.cc:146
bool ParseFlatzincString(const std::string &input, Model *model)
Definition parser.cc:67
bool ParseFlatzincFile(const std::string &filename, Model *model)
Definition parser.cc:42
std::vector< char * > FixAndParseParameters(int *argc, char ***argv)
Definition fz.cc:81
CpSolverResponse SolveFzWithCpModelProto(const fz::Model &fz_model, const fz::FlatzincSatParameters &p, const SatParameters &sat_params, Model *sat_model, SolverLogger *solution_logger)
void ProcessFloatingPointOVariablesAndObjective(fz::Model *fz_model)
OR-Tools root namespace.
static int input(yyscan_t yyscanner)
static const char kUsage[]
#define SOLVER_LOG(logger,...)
Definition logging.h:114