Files
ortools-clone/examples/cpp/sat_runner.cc

460 lines
17 KiB
C++
Raw Normal View History

2021-04-02 10:08:51 +02:00
// Copyright 2010-2021 Google LLC
2013-12-12 14:43:04 +00:00
// 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 <cstdint>
#include <cstdlib>
#include <memory>
2013-12-12 14:43:04 +00:00
#include <string>
#include <utility>
2013-12-12 14:43:04 +00:00
#include <vector>
#include "absl/flags/flag.h"
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
#include "absl/memory/memory.h"
2022-02-25 09:47:52 +01:00
#include "absl/random/random.h"
2020-09-23 11:45:03 +02:00
#include "absl/status/status.h"
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
2022-02-25 09:47:52 +01:00
#include "absl/strings/string_view.h"
2018-06-08 16:40:43 +02:00
#include "examples/cpp/opb_reader.h"
#include "examples/cpp/sat_cnf_reader.h"
#include "google/protobuf/text_format.h"
#include "ortools/algorithms/sparse_permutation.h"
#include "ortools/base/file.h"
2022-02-25 09:47:52 +01:00
#include "ortools/base/init_google.h"
#include "ortools/base/logging.h"
2022-02-25 09:47:52 +01:00
#include "ortools/base/logging_flags.h"
#include "ortools/base/timer.h"
2022-02-25 09:47:52 +01:00
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/lp_data/lp_data.h"
#include "ortools/lp_data/mps_reader.h"
#include "ortools/lp_data/proto_utils.h"
#include "ortools/sat/boolean_problem.h"
#include "ortools/sat/boolean_problem.pb.h"
2017-06-29 11:59:21 +02:00
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/sat/lp_utils.h"
#include "ortools/sat/model.h"
#include "ortools/sat/optimization.h"
#include "ortools/sat/pb_constraint.h"
#include "ortools/sat/sat_base.h"
#include "ortools/sat/sat_parameters.pb.h"
#include "ortools/sat/sat_solver.h"
#include "ortools/sat/simplification.h"
#include "ortools/sat/symmetry.h"
2017-06-29 11:59:21 +02:00
#include "ortools/util/file_util.h"
2022-02-25 09:47:52 +01:00
#include "ortools/util/logging.h"
#include "ortools/util/strong_integers.h"
#include "ortools/util/time_limit.h"
2013-12-12 14:43:04 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(
std::string, input, "",
2013-12-12 14:43:04 +00:00
"Required: input file of the problem to solve. Many format are supported:"
".cnf (sat, max-sat, weighted max-sat), .opb (pseudo-boolean sat/optim) "
"and by default the LinearBooleanProblem proto (binary or text).");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(
std::string, output, "",
2013-12-12 14:43:04 +00:00
"If non-empty, write the input problem as a LinearBooleanProblem proto to "
"this file. By default it uses the binary format except if the file "
"extension is '.txt'. If the problem is SAT, a satisfiable assignment is "
"also written to the file.");
2013-12-12 14:43:04 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, output_cnf_solution, false,
"If true and the problem was solved to optimality, this output "
"the solution to stdout in cnf form.\n");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(std::string, params, "",
"Parameters for the sat solver in a text format of the "
"SatParameters proto, example: --params=use_conflicts:true.");
2013-12-12 14:43:04 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, strict_validity, false,
"If true, stop if the given input is invalid (duplicate literals, "
"out of range, zero cofficients, etc.)");
2014-11-07 14:31:18 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(
std::string, lower_bound, "",
2013-12-12 14:43:04 +00:00
"If not empty, look for a solution with an objective value >= this bound.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(
std::string, upper_bound, "",
2013-12-12 14:43:04 +00:00
"If not empty, look for a solution with an objective value <= this bound.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, fu_malik, false,
"If true, search the optimal solution with the Fu & Malik algo.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, wpm1, false,
"If true, search the optimal solution with the WPM1 algo.");
2014-06-11 20:48:53 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, qmaxsat, false,
"If true, search the optimal solution with a linear scan and "
" the cardinality encoding used in qmaxsat.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, core_enc, false,
"If true, search the optimal solution with the core-based "
"cardinality encoding algo.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, linear_scan, false,
"If true, search the optimal solution with the linear scan algo.");
2013-12-12 14:43:04 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(int, randomize, 500,
"If positive, solve that many times the problem with a random "
"decision heuristic before trying to optimize it.");
2014-05-21 12:56:57 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, use_symmetry, false,
"If true, find and exploit the eventual symmetries "
"of the problem.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, presolve, true,
"Only work on pure SAT problem. If true, presolve the problem.");
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, probing, false, "If true, presolve the problem using probing.");
2014-11-07 14:31:18 +00:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, use_cp_model, true,
"Whether to interpret everything as a CpModelProto or "
"to read by default a CpModelProto.");
2017-06-29 11:59:21 +02:00
2020-10-23 11:50:14 +02:00
ABSL_FLAG(bool, reduce_memory_usage, false,
"If true, do not keep a copy of the original problem in memory."
"This reduce the memory usage, but disable the solution cheking at "
"the end.");
2013-12-12 14:43:04 +00:00
namespace operations_research {
namespace sat {
namespace {
2014-11-07 14:31:18 +00:00
// Returns a trivial best bound. The best bound corresponds to the lower bound
// (resp. upper bound) in case of a minimization (resp. maximization) problem.
2020-10-29 14:25:39 +01:00
double GetScaledTrivialBestBound(const LinearBooleanProblem& problem) {
2014-11-07 14:31:18 +00:00
Coefficient best_bound(0);
2020-10-29 14:25:39 +01:00
const LinearObjective& objective = problem.objective();
for (const int64_t value : objective.coefficients()) {
2020-10-22 23:36:58 +02:00
if (value < 0) best_bound += Coefficient(value);
2014-11-07 14:31:18 +00:00
}
return AddOffsetAndScaleObjectiveValue(problem, best_bound);
2014-04-04 09:46:49 +00:00
}
2020-10-29 14:25:39 +01:00
bool LoadBooleanProblem(const std::string& filename,
LinearBooleanProblem* problem, CpModelProto* cp_model) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
if (absl::EndsWith(filename, ".opb") ||
absl::EndsWith(filename, ".opb.bz2")) {
2014-05-15 09:21:11 +00:00
OpbReader reader;
if (!reader.Load(filename, problem)) {
LOG(FATAL) << "Cannot load file '" << filename << "'.";
}
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
} else if (absl::EndsWith(filename, ".cnf") ||
absl::EndsWith(filename, ".cnf.gz") ||
absl::EndsWith(filename, ".wcnf") ||
absl::EndsWith(filename, ".wcnf.gz")) {
2014-05-15 09:21:11 +00:00
SatCnfReader reader;
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_qmaxsat) ||
absl::GetFlag(FLAGS_core_enc)) {
reader.InterpretCnfAsMaxSat(true);
}
if (absl::GetFlag(FLAGS_use_cp_model)) {
if (!reader.Load(filename, cp_model)) {
LOG(FATAL) << "Cannot load file '" << filename << "'.";
}
} else {
if (!reader.Load(filename, problem)) {
LOG(FATAL) << "Cannot load file '" << filename << "'.";
}
2014-05-15 09:21:11 +00:00
}
} else if (absl::GetFlag(FLAGS_use_cp_model)) {
2017-06-29 11:59:21 +02:00
LOG(INFO) << "Reading a CpModelProto.";
*cp_model = ReadFileToProtoOrDie<CpModelProto>(filename);
2014-05-15 09:21:11 +00:00
} else {
2017-06-29 11:59:21 +02:00
LOG(INFO) << "Reading a LinearBooleanProblem.";
*problem = ReadFileToProtoOrDie<LinearBooleanProblem>(filename);
2014-05-15 09:21:11 +00:00
}
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
return true;
2014-05-15 09:21:11 +00:00
}
2020-10-29 14:25:39 +01:00
std::string SolutionString(const LinearBooleanProblem& problem,
const std::vector<bool>& assignment) {
2014-05-15 09:21:11 +00:00
std::string output;
BooleanVariable limit(problem.original_num_variables());
for (BooleanVariable index(0); index < limit; ++index) {
2020-10-22 23:36:58 +02:00
if (index > 0) output += " ";
absl::StrAppend(&output,
Literal(index, assignment[index.value()]).SignedValue());
2014-05-15 09:21:11 +00:00
}
return output;
}
2013-12-12 14:43:04 +00:00
// To benefit from the operations_research namespace, we put all the main() code
// here.
int Run() {
2014-06-11 20:48:53 +00:00
SatParameters parameters;
if (absl::GetFlag(FLAGS_input).empty()) {
2013-12-12 14:43:04 +00:00
LOG(FATAL) << "Please supply a data file with --input=";
}
// Parse the --params flag.
2021-01-15 09:47:18 +01:00
parameters.set_log_search_progress(true);
if (!absl::GetFlag(FLAGS_params).empty()) {
CHECK(google::protobuf::TextFormat::MergeFromString(
absl::GetFlag(FLAGS_params), &parameters))
<< absl::GetFlag(FLAGS_params);
2013-12-12 14:43:04 +00:00
}
2013-12-12 14:43:04 +00:00
// Initialize the solver.
std::unique_ptr<SatSolver> solver(new SatSolver());
solver->SetParameters(parameters);
2013-12-12 14:43:04 +00:00
// Read the problem.
LinearBooleanProblem problem;
2017-06-29 11:59:21 +02:00
CpModelProto cp_model;
if (!LoadBooleanProblem(absl::GetFlag(FLAGS_input), &problem, &cp_model)) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
CpSolverResponse response;
response.set_status(CpSolverStatus::MODEL_INVALID);
return EXIT_SUCCESS;
}
2021-12-13 10:45:53 +01:00
if (!absl::GetFlag(FLAGS_use_cp_model)) {
LOG(INFO) << "Converting to CpModelProto ...";
cp_model = BooleanProblemToCpModelproto(problem);
}
2017-06-29 11:59:21 +02:00
// TODO(user): clean this hack. Ideally LinearBooleanProblem should be
// completely replaced by the more general CpModelProto.
2021-12-13 10:45:53 +01:00
if (absl::GetFlag(FLAGS_use_cp_model)) {
2020-10-22 23:36:58 +02:00
problem.Clear(); // We no longer need it, release memory.
2017-06-29 11:59:21 +02:00
Model model;
model.Add(NewSatParameters(parameters));
2017-06-29 11:59:21 +02:00
const CpSolverResponse response = SolveCpModel(cp_model, &model);
if (!absl::GetFlag(FLAGS_output).empty()) {
if (absl::EndsWith(absl::GetFlag(FLAGS_output), "txt")) {
CHECK_OK(file::SetTextProto(absl::GetFlag(FLAGS_output), response,
file::Defaults()));
} else {
CHECK_OK(file::SetBinaryProto(absl::GetFlag(FLAGS_output), response,
file::Defaults()));
}
}
// The SAT competition requires a particular exit code and since we don't
// really use it for any other purpose, we comply.
if (response.status() == CpSolverStatus::OPTIMAL) return 10;
2020-10-22 23:36:58 +02:00
if (response.status() == CpSolverStatus::FEASIBLE) return 10;
if (response.status() == CpSolverStatus::INFEASIBLE) return 20;
2018-11-07 09:52:37 +01:00
return EXIT_SUCCESS;
2017-06-29 11:59:21 +02:00
}
if (absl::GetFlag(FLAGS_strict_validity)) {
2020-05-06 18:35:18 +02:00
const absl::Status status = ValidateBooleanProblem(problem);
2014-11-07 14:31:18 +00:00
if (!status.ok()) {
2020-05-06 18:35:18 +02:00
LOG(ERROR) << "Invalid Boolean problem: " << status.message();
2014-11-07 14:31:18 +00:00
return EXIT_FAILURE;
}
}
2013-12-12 14:43:04 +00:00
// Count the time from there.
WallTimer wall_timer;
UserTimer user_timer;
wall_timer.Start();
user_timer.Start();
2014-11-07 14:31:18 +00:00
double scaled_best_bound = GetScaledTrivialBestBound(problem);
// Probing.
SatPostsolver probing_postsolver(problem.num_variables());
LinearBooleanProblem original_problem;
if (absl::GetFlag(FLAGS_probing)) {
2014-11-07 14:31:18 +00:00
// TODO(user): This is nice for testing, but consumes memory.
original_problem = problem;
ProbeAndSimplifyProblem(&probing_postsolver, &problem);
}
2013-12-12 14:43:04 +00:00
// Load the problem into the solver.
if (absl::GetFlag(FLAGS_reduce_memory_usage)) {
if (!LoadAndConsumeBooleanProblem(&problem, solver.get())) {
LOG(INFO) << "UNSAT when loading the problem.";
}
} else {
if (!LoadBooleanProblem(problem, solver.get())) {
LOG(INFO) << "UNSAT when loading the problem.";
}
2013-12-12 14:43:04 +00:00
}
2020-10-29 14:25:39 +01:00
auto strtoint64 = [](const std::string& word) {
2021-04-02 14:58:16 +02:00
int64_t value = 0;
2020-10-22 23:36:58 +02:00
if (!word.empty()) CHECK(absl::SimpleAtoi(word, &value));
return value;
2020-10-22 23:36:58 +02:00
};
if (!AddObjectiveConstraint(
problem, !absl::GetFlag(FLAGS_lower_bound).empty(),
Coefficient(strtoint64(absl::GetFlag(FLAGS_lower_bound))),
!absl::GetFlag(FLAGS_upper_bound).empty(),
Coefficient(strtoint64(absl::GetFlag(FLAGS_upper_bound))),
solver.get())) {
LOG(INFO) << "UNSAT when setting the objective constraint.";
2013-12-12 14:43:04 +00:00
}
// Symmetries!
//
// TODO(user): To make this compatible with presolve, we just need to run
// it after the presolve step.
if (absl::GetFlag(FLAGS_use_symmetry)) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
CHECK(!absl::GetFlag(FLAGS_presolve)) << "incompatible";
LOG(INFO) << "Finding symmetries of the problem.";
std::vector<std::unique_ptr<SparsePermutation>> generators;
FindLinearBooleanProblemSymmetries(problem, &generators);
2016-01-26 13:58:53 +01:00
std::unique_ptr<SymmetryPropagator> propagator(new SymmetryPropagator);
for (int i = 0; i < generators.size(); ++i) {
propagator->AddSymmetry(std::move(generators[i]));
}
2017-06-29 11:59:21 +02:00
solver->AddPropagator(propagator.get());
solver->TakePropagatorOwnership(std::move(propagator));
}
// Optimize?
std::vector<bool> solution;
2014-06-11 20:48:53 +00:00
SatSolver::Status result = SatSolver::LIMIT_REACHED;
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_qmaxsat) ||
absl::GetFlag(FLAGS_core_enc)) {
if (absl::GetFlag(FLAGS_randomize) > 0 &&
(absl::GetFlag(FLAGS_linear_scan) || absl::GetFlag(FLAGS_qmaxsat))) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
absl::BitGen bitgen;
2020-10-22 23:36:58 +02:00
result = SolveWithRandomParameters(STDOUT_LOG, problem,
absl::GetFlag(FLAGS_randomize), bitgen,
2020-10-22 23:36:58 +02:00
solver.get(), &solution);
2014-06-11 20:48:53 +00:00
}
if (result == SatSolver::LIMIT_REACHED) {
if (absl::GetFlag(FLAGS_qmaxsat)) {
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
solver = absl::make_unique<SatSolver>();
solver->SetParameters(parameters);
CHECK(LoadBooleanProblem(problem, solver.get()));
result = SolveWithCardinalityEncoding(STDOUT_LOG, problem, solver.get(),
&solution);
} else if (absl::GetFlag(FLAGS_core_enc)) {
result = SolveWithCardinalityEncodingAndCore(STDOUT_LOG, problem,
solver.get(), &solution);
} else if (absl::GetFlag(FLAGS_fu_malik)) {
result = SolveWithFuMalik(STDOUT_LOG, problem, solver.get(), &solution);
} else if (absl::GetFlag(FLAGS_wpm1)) {
result = SolveWithWPM1(STDOUT_LOG, problem, solver.get(), &solution);
} else if (absl::GetFlag(FLAGS_linear_scan)) {
result =
SolveWithLinearScan(STDOUT_LOG, problem, solver.get(), &solution);
}
}
} else {
// Only solve the decision version.
parameters.set_log_search_progress(true);
solver->SetParameters(parameters);
if (absl::GetFlag(FLAGS_presolve)) {
std::unique_ptr<TimeLimit> time_limit =
TimeLimit::FromParameters(parameters);
SolverLogger logger;
result = SolveWithPresolve(&solver, time_limit.get(), &solution,
/*drat_proof_handler=*/nullptr, &logger);
if (result == SatSolver::FEASIBLE) {
2014-11-07 14:31:18 +00:00
CHECK(IsAssignmentValid(problem, solution));
}
} else {
result = solver->Solve();
if (result == SatSolver::FEASIBLE) {
ExtractAssignment(problem, *solver, &solution);
CHECK(IsAssignmentValid(problem, solution));
}
2013-12-12 14:43:04 +00:00
}
}
// Print the solution status.
if (result == SatSolver::FEASIBLE) {
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_core_enc)) {
absl::PrintF("s OPTIMUM FOUND\n");
2014-11-07 14:31:18 +00:00
CHECK(!solution.empty());
const Coefficient objective = ComputeObjectiveValue(problem, solution);
scaled_best_bound = AddOffsetAndScaleObjectiveValue(problem, objective);
// Postsolve.
if (absl::GetFlag(FLAGS_probing)) {
2014-11-07 14:31:18 +00:00
solution = probing_postsolver.PostsolveSolution(solution);
problem = original_problem;
}
} else {
absl::PrintF("s SATISFIABLE\n");
}
// Check and output the solution.
CHECK(IsAssignmentValid(problem, solution));
if (absl::GetFlag(FLAGS_output_cnf_solution)) {
absl::PrintF("v %s\n", SolutionString(problem, solution));
2013-12-12 14:43:04 +00:00
}
if (!absl::GetFlag(FLAGS_output).empty()) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
if (result == SatSolver::FEASIBLE) {
StoreAssignment(solver->Assignment(), problem.mutable_assignment());
}
if (absl::EndsWith(absl::GetFlag(FLAGS_output), ".txt")) {
CHECK_OK(file::SetTextProto(absl::GetFlag(FLAGS_output), problem,
file::Defaults()));
} else {
CHECK_OK(file::SetBinaryProto(absl::GetFlag(FLAGS_output), problem,
file::Defaults()));
}
}
}
if (result == SatSolver::INFEASIBLE) {
absl::PrintF("s UNSATISFIABLE\n");
}
2016-12-09 14:15:01 +01:00
// Print status.
absl::PrintF("c status: %s\n", SatStatusString(result));
2016-12-09 14:15:01 +01:00
// Print objective value.
if (solution.empty()) {
absl::PrintF("c objective: na\n");
absl::PrintF("c best bound: na\n");
} else {
const Coefficient objective = ComputeObjectiveValue(problem, solution);
absl::PrintF("c objective: %.16g\n",
AddOffsetAndScaleObjectiveValue(problem, objective));
absl::PrintF("c best bound: %.16g\n", scaled_best_bound);
2013-12-12 14:43:04 +00:00
}
// Print final statistics.
absl::PrintF("c booleans: %d\n", solver->NumVariables());
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
absl::PrintF("c conflicts: %d\n", solver->num_failures());
absl::PrintF("c branches: %d\n", solver->num_branches());
absl::PrintF("c propagations: %d\n", solver->num_propagations());
absl::PrintF("c walltime: %f\n", wall_timer.Get());
absl::PrintF("c usertime: %f\n", user_timer.Get());
absl::PrintF("c deterministic_time: %f\n", solver->deterministic_time());
2018-11-07 09:52:37 +01:00
return EXIT_SUCCESS;
2013-12-12 14:43:04 +00:00
}
2020-10-22 23:36:58 +02:00
} // namespace
} // namespace sat
} // namespace operations_research
2013-12-12 14:43:04 +00:00
static const char kUsage[] =
"Usage: see flags.\n"
"This program solves a given Boolean linear problem.";
2013-12-12 14:43:04 +00:00
2020-10-29 14:25:39 +01:00
int main(int argc, char** argv) {
// By default, we want to show how the solver progress. Note that this needs
// to be set before InitGoogle() which has the nice side-effect of allowing
// the user to override it.
2022-02-25 09:47:52 +01:00
InitGoogle(kUsage, &argc, &argv, /*remove_flags=*/true);
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
absl::SetFlag(&FLAGS_alsologtostderr, true);
return operations_research::sat::Run();
2013-12-12 14:43:04 +00:00
}