From 3ccda66a0fc2c7a504f1f7aeca169e4ebe1d8f41 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Thu, 7 Nov 2019 13:22:44 +0100 Subject: [PATCH] remove fz-cp code; turn fz presolve to minimal by default; small improvements to sat --- makefiles/Makefile.archive.mk | 6 +- makefiles/Makefile.cpp.mk | 29 +- makefiles/Makefile.gen.mk | 9 +- ortools/flatzinc/constraints.cc | 3167 ----------------- ortools/flatzinc/constraints.h | 31 - ortools/flatzinc/flatzinc_constraints.cc | 928 ----- ortools/flatzinc/flatzinc_constraints.h | 73 - ortools/flatzinc/fz.cc | 2 +- ortools/flatzinc/{mznlib_sat => mznlib}/BUILD | 0 .../all_different_int.mzn | 0 .../{mznlib_cp => mznlib}/circuit.mzn | 0 .../{mznlib_cp => mznlib}/cumulative.mzn | 0 .../flatzinc/{mznlib_cp => mznlib}/diffn.mzn | 0 .../{mznlib_cp => mznlib}/diffn_nonstrict.mzn | 0 .../{mznlib_sat => mznlib}/inverse.mzn | 0 .../{mznlib_cp => mznlib}/maximum.mzn | 0 .../{mznlib_cp => mznlib}/maximum_int.mzn | 0 .../{mznlib_cp => mznlib}/minimum.mzn | 0 .../{mznlib_cp => mznlib}/minimum_int.mzn | 0 .../{mznlib_sat => mznlib}/network_flow.mzn | 0 .../{mznlib_sat => mznlib}/nostrings.mzn | 0 .../redefinitions-2.0.mzn | 0 .../{mznlib_cp => mznlib}/regular.mzn | 0 .../{mznlib_cp => mznlib}/subcircuit.mzn | 0 .../flatzinc/{mznlib_cp => mznlib}/table.mzn | 0 .../{mznlib_cp => mznlib}/table_bool.mzn | 0 .../{mznlib_cp => mznlib}/table_int.mzn | 0 .../mznlib_cp/alldifferent_except_0.mzn | 6 - ortools/flatzinc/mznlib_cp/among.mzn | 4 - ortools/flatzinc/mznlib_cp/arg_max_int.mzn | 2 - ortools/flatzinc/mznlib_cp/arg_min_int.mzn | 2 - ortools/flatzinc/mznlib_cp/at_most_int.mzn | 5 - ortools/flatzinc/mznlib_cp/count.mzn | 12 - ortools/flatzinc/mznlib_cp/count_eq.mzn | 14 - ortools/flatzinc/mznlib_cp/count_geq.mzn | 9 - ortools/flatzinc/mznlib_cp/count_gt.mzn | 9 - ortools/flatzinc/mznlib_cp/count_leq.mzn | 9 - ortools/flatzinc/mznlib_cp/count_lt.mzn | 8 - ortools/flatzinc/mznlib_cp/count_neq.mzn | 8 - ortools/flatzinc/mznlib_cp/count_reif.mzn | 12 - ortools/flatzinc/mznlib_cp/diffn_k.mzn | 9 - .../flatzinc/mznlib_cp/diffn_nonstrict_k.mzn | 9 - ortools/flatzinc/mznlib_cp/disjunctive.mzn | 3 - .../flatzinc/mznlib_cp/disjunctive_opt.mzn | 3 - .../flatzinc/mznlib_cp/disjunctive_strict.mzn | 2 - .../flatzinc/mznlib_cp/global_cardinality.mzn | 4 - .../mznlib_cp/global_cardinality_closed.mzn | 3 - .../mznlib_cp/global_cardinality_low_up.mzn | 4 - .../global_cardinality_low_up_closed.mzn | 4 - ortools/flatzinc/mznlib_cp/int_mod.mzn | 28 - ortools/flatzinc/mznlib_cp/inverse.mzn | 6 - ortools/flatzinc/mznlib_cp/lex_less_bool.mzn | 11 - ortools/flatzinc/mznlib_cp/lex_less_int.mzn | 8 - .../flatzinc/mznlib_cp/lex_lesseq_bool.mzn | 11 - ortools/flatzinc/mznlib_cp/lex_lesseq_int.mzn | 12 - ortools/flatzinc/mznlib_cp/nvalue.mzn | 4 - .../flatzinc/mznlib_cp/redefinitions-2.0.mzn | 29 - ortools/flatzinc/mznlib_cp/regular_nfa.mzn | 3 - ortools/flatzinc/mznlib_cp/sequence.mzn | 4 - ortools/flatzinc/mznlib_cp/sliding_sum.mzn | 6 - ortools/flatzinc/mznlib_cp/sort.mzn | 7 - .../mznlib_cp/symmetric_all_different.mzn | 2 - .../flatzinc/mznlib_sat/all_different_int.mzn | 1 - ortools/flatzinc/mznlib_sat/circuit.mzn | 12 - ortools/flatzinc/mznlib_sat/cumulative.mzn | 11 - ortools/flatzinc/mznlib_sat/diffn.mzn | 10 - .../flatzinc/mznlib_sat/diffn_nonstrict.mzn | 10 - ortools/flatzinc/mznlib_sat/maximum.mzn | 10 - ortools/flatzinc/mznlib_sat/maximum_int.mzn | 7 - ortools/flatzinc/mznlib_sat/minimum.mzn | 11 - ortools/flatzinc/mznlib_sat/minimum_int.mzn | 7 - ortools/flatzinc/mznlib_sat/regular.mzn | 9 - ortools/flatzinc/mznlib_sat/subcircuit.mzn | 12 - ortools/flatzinc/mznlib_sat/table.mzn | 13 - ortools/flatzinc/mznlib_sat/table_bool.mzn | 1 - ortools/flatzinc/mznlib_sat/table_int.mzn | 2 - ortools/flatzinc/presolve.cc | 33 +- ortools/flatzinc/presolve.h | 2 +- ortools/flatzinc/reporting.cc | 334 -- ortools/flatzinc/reporting.h | 201 -- ortools/flatzinc/sat_constraint.cc | 490 --- ortools/flatzinc/sat_constraint.h | 86 - ortools/flatzinc/solver.cc | 926 ----- ortools/flatzinc/solver.h | 151 - ortools/flatzinc/solver_data.cc | 109 - ortools/flatzinc/solver_data.h | 78 - ortools/flatzinc/solver_util.cc | 208 -- ortools/flatzinc/solver_util.h | 84 - ortools/linear_solver/model_exporter.cc | 6 + ortools/sat/cp_model_checker.cc | 14 + ortools/sat/cp_model_presolve.cc | 54 +- 91 files changed, 85 insertions(+), 7324 deletions(-) delete mode 100644 ortools/flatzinc/constraints.cc delete mode 100644 ortools/flatzinc/constraints.h delete mode 100644 ortools/flatzinc/flatzinc_constraints.cc delete mode 100644 ortools/flatzinc/flatzinc_constraints.h rename ortools/flatzinc/{mznlib_sat => mznlib}/BUILD (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/all_different_int.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/circuit.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/cumulative.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/diffn.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/diffn_nonstrict.mzn (100%) rename ortools/flatzinc/{mznlib_sat => mznlib}/inverse.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/maximum.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/maximum_int.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/minimum.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/minimum_int.mzn (100%) rename ortools/flatzinc/{mznlib_sat => mznlib}/network_flow.mzn (100%) rename ortools/flatzinc/{mznlib_sat => mznlib}/nostrings.mzn (100%) rename ortools/flatzinc/{mznlib_sat => mznlib}/redefinitions-2.0.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/regular.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/subcircuit.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/table.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/table_bool.mzn (100%) rename ortools/flatzinc/{mznlib_cp => mznlib}/table_int.mzn (100%) delete mode 100644 ortools/flatzinc/mznlib_cp/alldifferent_except_0.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/among.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/arg_max_int.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/arg_min_int.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/at_most_int.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_eq.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_geq.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_gt.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_leq.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_lt.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_neq.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/count_reif.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/diffn_k.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/diffn_nonstrict_k.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/disjunctive.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/disjunctive_opt.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/disjunctive_strict.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/global_cardinality.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/global_cardinality_closed.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/global_cardinality_low_up.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/global_cardinality_low_up_closed.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/int_mod.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/inverse.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/lex_less_bool.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/lex_less_int.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/lex_lesseq_bool.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/lex_lesseq_int.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/nvalue.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/redefinitions-2.0.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/regular_nfa.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/sequence.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/sliding_sum.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/sort.mzn delete mode 100644 ortools/flatzinc/mznlib_cp/symmetric_all_different.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/all_different_int.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/circuit.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/cumulative.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/diffn.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/diffn_nonstrict.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/maximum.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/maximum_int.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/minimum.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/minimum_int.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/regular.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/subcircuit.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/table.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/table_bool.mzn delete mode 100644 ortools/flatzinc/mznlib_sat/table_int.mzn delete mode 100644 ortools/flatzinc/reporting.cc delete mode 100644 ortools/flatzinc/reporting.h delete mode 100644 ortools/flatzinc/sat_constraint.cc delete mode 100644 ortools/flatzinc/sat_constraint.h delete mode 100644 ortools/flatzinc/solver.cc delete mode 100644 ortools/flatzinc/solver.h delete mode 100644 ortools/flatzinc/solver_data.cc delete mode 100644 ortools/flatzinc/solver_data.h delete mode 100644 ortools/flatzinc/solver_util.cc delete mode 100644 ortools/flatzinc/solver_util.h diff --git a/makefiles/Makefile.archive.mk b/makefiles/Makefile.archive.mk index d1f239488d..1b10caec67 100644 --- a/makefiles/Makefile.archive.mk +++ b/makefiles/Makefile.archive.mk @@ -121,10 +121,8 @@ $(FZ_INSTALL_DIR)$(ARCHIVE_EXT): fz | $(TEMP_FZ_DIR) $(COPY) $(BIN_DIR)$Sfz$E $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sbin$S$(FZ_EXE) $(COPY) $(BIN_DIR)$Sparser_main$E $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sbin$Sparser-or-tools$E -$(MKDIR_P) $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare - -$(MKDIR) $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc_cp - $(COPY) ortools$Sflatzinc$Smznlib_cp$S* $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc_cp - -$(MKDIR) $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc_sat - $(COPY) ortools$Sflatzinc$Smznlib_sat$S* $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc_sat + -$(MKDIR) $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc_ + $(COPY) ortools$Sflatzinc$Smznlib$S* $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sshare$Sminizinc -$(MKDIR_P) $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sexamples $(COPY) $(FZ_EX_PATH)$S* $(TEMP_FZ_DIR)$S$(FZ_INSTALL_DIR)$Sexamples ifeq ($(SYSTEM),win) diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk index 2013c67df1..decc5d4c3e 100755 --- a/makefiles/Makefile.cpp.mk +++ b/makefiles/Makefile.cpp.mk @@ -198,19 +198,12 @@ FLATZINC_LIBS = $(LIB_DIR)/$(LIB_PREFIX)fz.$L FLATZINC_PATH = $(subst /,$S,$(FLATZINC_LIBS)) FLATZINC_DEPS = \ $(SRC_DIR)/ortools/flatzinc/checker.h \ - $(SRC_DIR)/ortools/flatzinc/constraints.h \ $(SRC_DIR)/ortools/flatzinc/cp_model_fz_solver.h \ - $(SRC_DIR)/ortools/flatzinc/flatzinc_constraints.h \ $(SRC_DIR)/ortools/flatzinc/logging.h \ $(SRC_DIR)/ortools/flatzinc/model.h \ $(SRC_DIR)/ortools/flatzinc/parser.h \ $(SRC_DIR)/ortools/flatzinc/parser.tab.hh \ $(SRC_DIR)/ortools/flatzinc/presolve.h \ - $(SRC_DIR)/ortools/flatzinc/reporting.h \ - $(SRC_DIR)/ortools/flatzinc/sat_constraint.h \ - $(SRC_DIR)/ortools/flatzinc/solver_data.h \ - $(SRC_DIR)/ortools/flatzinc/solver.h \ - $(SRC_DIR)/ortools/flatzinc/solver_util.h \ $(CP_DEPS) \ $(SAT_DEPS) FLATZINC_LNK = $(PRE_LIB)fz$(POST_LIB) $(OR_TOOLS_LNK) @@ -220,23 +213,13 @@ endif FLATZINC_OBJS=\ $(OBJ_DIR)/flatzinc/checker.$O \ - $(OBJ_DIR)/flatzinc/constraints.$O \ $(OBJ_DIR)/flatzinc/cp_model_fz_solver.$O \ - $(OBJ_DIR)/flatzinc/flatzinc_constraints.$O \ $(OBJ_DIR)/flatzinc/logging.$O \ $(OBJ_DIR)/flatzinc/model.$O \ $(OBJ_DIR)/flatzinc/parser.$O \ $(OBJ_DIR)/flatzinc/parser.tab.$O \ $(OBJ_DIR)/flatzinc/parser.yy.$O \ - $(OBJ_DIR)/flatzinc/presolve.$O \ - $(OBJ_DIR)/flatzinc/reporting.$O \ - $(OBJ_DIR)/flatzinc/sat_constraint.$O \ - $(OBJ_DIR)/flatzinc/solver.$O \ - $(OBJ_DIR)/flatzinc/solver_data.$O \ - $(OBJ_DIR)/flatzinc/solver_util.$O - -FLATZINC_CC_TESTS = \ -boolean_test + $(OBJ_DIR)/flatzinc/presolve.$O fz_parser: #$(SRC_DIR)/ortools/flatzinc/parser.lex $(SRC_DIR)/ortools/flatzinc/parser.yy flex -o $(SRC_DIR)/ortools/flatzinc/parser.yy.cc $(SRC_DIR)/ortools/flatzinc/parser.lex @@ -253,17 +236,10 @@ $(FLATZINC_LIBS): $(OR_TOOLS_LIBS) $(FLATZINC_OBJS) | $(LIB_DIR) $(OR_TOOLS_LNK) \ $(OR_TOOLS_LDFLAGS) -$(OBJ_DIR)/boolean_test.$O: $(TEST_DIR)/boolean_test.cc $(FLATZINC_DEPS) | $(OBJ_DIR) - $(CCC) $(CFLAGS) -c $(TEST_PATH)$Sboolean_test.cc $(OBJ_OUT)$(OBJ_DIR)$Sboolean_test.$O - -$(BIN_DIR)/boolean_test$E: $(OBJ_DIR)/boolean_test.$O $(FLATZINC_LIBS) | $(BIN_DIR) - $(CCC) $(CFLAGS) $(OBJ_DIR)$Sboolean_test.$O $(FLATZINC_LNK) $(OR_TOOLS_LDFLAGS) $(EXE_OUT)$(BIN_DIR)$Sboolean_test$E - .PHONY: fz # Build Flatzinc binaries. fz: \ $(BIN_DIR)/fz$E \ - $(BIN_DIR)/parser_main$E \ - $(addsuffix $E, $(addprefix $(BIN_DIR)/, $(FLATZINC_CC_TESTS))) + $(BIN_DIR)/parser_main$E $(BIN_DIR)/fz$E: $(OBJ_DIR)/flatzinc/fz.$O $(FLATZINC_LIBS) $(OR_TOOLS_LIBS) | $(BIN_DIR) $(CCC) $(CFLAGS) $(OBJ_DIR)$Sflatzinc$Sfz.$O $(FLATZINC_LNK) $(OR_TOOLS_LDFLAGS) $(EXE_OUT)$(BIN_DIR)$Sfz$E @@ -426,7 +402,6 @@ check_cc_pimpl: \ .PHONY: test_cc_tests # Build and Run all C++ Tests (located in ortools/examples/tests) test_cc_tests: \ rcc_lp_test \ - rcc_boolean_test \ rcc_bug_fz1 \ rcc_cpp11_test \ rcc_forbidden_intervals_test \ diff --git a/makefiles/Makefile.gen.mk b/makefiles/Makefile.gen.mk index a54f75fa95..67731f1855 100644 --- a/makefiles/Makefile.gen.mk +++ b/makefiles/Makefile.gen.mk @@ -2045,7 +2045,7 @@ objs/sat/presolve_context.$O: ortools/sat/presolve_context.cc \ ortools/util/time_limit.h ortools/base/commandlineflags.h \ ortools/base/timer.h ortools/base/basictypes.h \ ortools/util/running_stat.h ortools/base/map_util.h \ - ortools/port/proto_utils.h | $(OBJ_DIR)/sat + ortools/base/mathutil.h ortools/port/proto_utils.h | $(OBJ_DIR)/sat $(CCC) $(CFLAGS) -c $(SRC_DIR)$Sortools$Ssat$Spresolve_context.cc $(OBJ_OUT)$(OBJ_DIR)$Ssat$Spresolve_context.$O objs/sat/presolve_util.$O: ortools/sat/presolve_util.cc \ @@ -2918,9 +2918,10 @@ objs/linear_solver/model_validator.$O: \ ortools/gen/ortools/linear_solver/linear_solver.pb.h \ ortools/gen/ortools/util/optional_boolean.pb.h \ ortools/util/lazy_mutable_copy.h ortools/base/accurate_sum.h \ - ortools/base/status.h ortools/base/logging.h \ - ortools/base/integral_types.h ortools/base/macros.h ortools/port/file.h \ - ortools/port/proto_utils.h ortools/util/fp_utils.h | $(OBJ_DIR)/linear_solver + ortools/base/commandlineflags.h ortools/base/status.h \ + ortools/base/logging.h ortools/base/integral_types.h \ + ortools/base/macros.h ortools/port/file.h ortools/port/proto_utils.h \ + ortools/util/fp_utils.h | $(OBJ_DIR)/linear_solver $(CCC) $(CFLAGS) -c $(SRC_DIR)$Sortools$Slinear_solver$Smodel_validator.cc $(OBJ_OUT)$(OBJ_DIR)$Slinear_solver$Smodel_validator.$O objs/linear_solver/sat_interface.$O: \ diff --git a/ortools/flatzinc/constraints.cc b/ortools/flatzinc/constraints.cc deleted file mode 100644 index bd44e1bf2a..0000000000 --- a/ortools/flatzinc/constraints.cc +++ /dev/null @@ -1,3167 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/constraints.h" - -#include - -#include "absl/container/flat_hash_set.h" -#include "ortools/base/hash.h" -#include "ortools/base/integral_types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/constraint_solver/constraint_solveri.h" -#include "ortools/flatzinc/flatzinc_constraints.h" -#include "ortools/flatzinc/logging.h" -#include "ortools/flatzinc/model.h" -#include "ortools/flatzinc/sat_constraint.h" -#include "ortools/flatzinc/solver_data.h" -#include "ortools/util/string_array.h" - -DECLARE_bool(fz_use_sat); - -// TODO(user): minizinc 2.0 support: arg_sort, geost -// TODO(user): Do we need to support knapsack and network_flow? -// TODO(user): Support alternative, span, disjunctive, cumulative with -// optional variables. - -namespace operations_research { -namespace { - -void AddConstraint(Solver* s, fz::Constraint* ct, Constraint* cte) { - FZVLOG << " - post " << cte->DebugString() << FZENDL; - s->AddConstraint(cte); -} - -void PostBooleanSumInRange(SatPropagator* sat, Solver* solver, - const std::vector& variables, - int64 range_min, int64 range_max) { - // TODO(user): Use sat_solver::AddLinearConstraint() - const int64 size = variables.size(); - range_min = std::max(int64{0}, range_min); - range_max = std::min(size, range_max); - int true_vars = 0; - std::vector alt; - for (int i = 0; i < size; ++i) { - if (!variables[i]->Bound()) { - alt.push_back(variables[i]); - } else if (variables[i]->Min() == 1) { - true_vars++; - } - } - const int possible_vars = alt.size(); - range_min -= true_vars; - range_max -= true_vars; - - if (range_max < 0 || range_min > possible_vars) { - Constraint* const ct = solver->MakeFalseConstraint(); - FZVLOG << " - posted " << ct->DebugString() << FZENDL; - solver->AddConstraint(ct); - } else if (range_min <= 0 && range_max >= possible_vars) { - FZVLOG << " - ignore true constraint" << FZENDL; - } else if (FLAGS_fz_use_sat && - AddSumInRange(sat, alt, range_min, range_max)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == 0 && range_max == 1 && - AddAtMostOne(sat, alt)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == 0 && range_max == size - 1 && - AddAtMostNMinusOne(sat, alt)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == 1 && range_max == 1 && - AddBoolOrArrayEqualTrue(sat, alt) && AddAtMostOne(sat, alt)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == 1 && range_max == possible_vars && - AddBoolOrArrayEqualTrue(sat, alt)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const ct = - MakeBooleanSumInRange(solver, alt, range_min, range_max); - FZVLOG << " - posted " << ct->DebugString() << FZENDL; - solver->AddConstraint(ct); - } -} - -void PostIsBooleanSumInRange(SatPropagator* sat, Solver* solver, - const std::vector& variables, - int64 range_min, int64 range_max, IntVar* target) { - const int64 size = variables.size(); - range_min = std::max(int64{0}, range_min); - range_max = std::min(size, range_max); - int true_vars = 0; - int possible_vars = 0; - for (int i = 0; i < size; ++i) { - if (variables[i]->Max() == 1) { - possible_vars++; - if (variables[i]->Min() == 1) { - true_vars++; - } - } - } - if (true_vars > range_max || possible_vars < range_min) { - target->SetValue(0); - FZVLOG << " - set target to 0" << FZENDL; - } else if (true_vars >= range_min && possible_vars <= range_max) { - target->SetValue(1); - FZVLOG << " - set target to 1" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == size && - AddBoolAndArrayEqVar(sat, variables, target)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_max == 0 && - AddBoolOrArrayEqVar(sat, variables, - solver->MakeDifference(1, target)->Var())) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && range_min == 1 && range_max == size && - AddBoolOrArrayEqVar(sat, variables, target)) { - FZVLOG << " - posted to sat" << FZENDL; - // TODO(user): Implement range_min == 0 and range_max = size - 1. - } else { - Constraint* const ct = MakeIsBooleanSumInRange(solver, variables, range_min, - range_max, target); - FZVLOG << " - posted " << ct->DebugString() << FZENDL; - solver->AddConstraint(ct); - } -} - -void PostIsBooleanSumDifferent(SatPropagator* sat, Solver* solver, - const std::vector& variables, - int64 value, IntVar* target) { - const int64 size = variables.size(); - if (value == 0) { - PostIsBooleanSumInRange(sat, solver, variables, 1, size, target); - } else if (value == size) { - PostIsBooleanSumInRange(sat, solver, variables, 0, size - 1, target); - } else { - Constraint* const ct = - solver->MakeIsDifferentCstCt(solver->MakeSum(variables), value, target); - FZVLOG << " - posted " << ct->DebugString() << FZENDL; - solver->AddConstraint(ct); - } -} - -void ExtractAllDifferentInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - Constraint* const constraint = s->MakeAllDifferent(vars, vars.size() < 100); - AddConstraint(s, ct, constraint); -} - -void ExtractAlldifferentExcept0(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - AddConstraint(s, ct, s->MakeAllDifferentExcept(vars, 0)); -} - -void ExtractAmong(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector tmp_sum; - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[1]); - for (IntVar* const var : tmp_vars) { - const fz::Argument& arg = ct->arguments[2]; - switch (arg.type) { - case fz::Argument::INT_VALUE: { - tmp_sum.push_back(solver->MakeIsEqualCstVar(var, arg.values[0])); - break; - } - case fz::Argument::INT_INTERVAL: { - if (var->Min() < arg.values[0] || var->Max() > arg.values[1]) { - tmp_sum.push_back( - solver->MakeIsBetweenVar(var, arg.values[0], arg.values[1])); - } - break; - } - case fz::Argument::INT_LIST: { - tmp_sum.push_back(solver->MakeIsMemberVar(var, arg.values)); - break; - } - default: { - LOG(FATAL) << "Invalid constraint " << ct->DebugString(); - } - } - } - if (ct->arguments[0].HasOneValue()) { - const int64 count = ct->arguments[0].Value(); - Constraint* const constraint = solver->MakeSumEquality(tmp_sum, count); - AddConstraint(solver, ct, constraint); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[0])->Var(); - Constraint* const constraint = solver->MakeSumEquality(tmp_sum, count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractAtMostInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const int64 max_count = ct->arguments[0].Value(); - const int64 value = ct->arguments[2].Value(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeAtMost(vars, value, max_count); - AddConstraint(solver, ct, constraint); -} - -void ExtractArrayBoolAnd(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector variables; - absl::flat_hash_set added; - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - for (IntVar* const to_add : tmp_vars) { - if (!gtl::ContainsKey(added, to_add) && to_add->Min() != 1) { - variables.push_back(to_add); - added.insert(to_add); - } - } - if (ct->target_variable != nullptr) { - IntExpr* const boolvar = solver->MakeMin(variables); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else if (ct->arguments[1].HasOneValue() && ct->arguments[1].Value() == 1) { - FZVLOG << " - forcing array_bool_and to 1" << FZENDL; - for (int i = 0; i < variables.size(); ++i) { - variables[i]->SetValue(1); - } - } else { - if (ct->arguments[1].HasOneValue()) { - if (ct->arguments[1].Value() == 0) { - if (FLAGS_fz_use_sat && - AddBoolAndArrayEqualFalse(data->Sat(), variables)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeSumLessOrEqual(variables, variables.size() - 1); - AddConstraint(solver, ct, constraint); - } - } else { - Constraint* const constraint = - solver->MakeSumEquality(variables, variables.size()); - AddConstraint(solver, ct, constraint); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[1])->Var(); - if (FLAGS_fz_use_sat && - AddBoolAndArrayEqVar(data->Sat(), variables, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeMinEquality(variables, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractArrayBoolOr(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector variables; - absl::flat_hash_set added; - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - for (IntVar* const to_add : tmp_vars) { - if (!gtl::ContainsKey(added, to_add) && to_add->Max() != 0) { - variables.push_back(to_add); - added.insert(to_add); - } - } - if (ct->target_variable != nullptr) { - IntExpr* const boolvar = solver->MakeMax(variables); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else if (ct->arguments[1].HasOneValue() && ct->arguments[1].Value() == 0) { - FZVLOG << " - forcing array_bool_or to 0" << FZENDL; - for (int i = 0; i < variables.size(); ++i) { - variables[i]->SetValue(0); - } - } else { - if (ct->arguments[1].HasOneValue()) { - if (ct->arguments[1].Value() == 1) { - if (FLAGS_fz_use_sat && - AddBoolOrArrayEqualTrue(data->Sat(), variables)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeSumGreaterOrEqual(variables, 1); - AddConstraint(solver, ct, constraint); - } - } else { - Constraint* const constraint = - solver->MakeSumEquality(variables, Zero()); - AddConstraint(solver, ct, constraint); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[1])->Var(); - if (FLAGS_fz_use_sat && - AddBoolOrArrayEqVar(data->Sat(), variables, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeMaxEquality(variables, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractArrayBoolXor(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - std::vector variables; - bool even = true; - for (IntVar* const var : tmp_vars) { - if (var->Max() == 1) { - if (var->Min() == 1) { - even = !even; - } else { - variables.push_back(var); - } - } - } - switch (variables.size()) { - case 0: { - Constraint* const constraint = - even ? solver->MakeFalseConstraint() : solver->MakeTrueConstraint(); - AddConstraint(solver, ct, constraint); - break; - } - case 1: { - Constraint* const constraint = - solver->MakeEquality(variables.front(), even); - AddConstraint(solver, ct, constraint); - break; - } - case 2: { - if (even) { - if (FLAGS_fz_use_sat && - AddBoolNot(data->Sat(), variables[0], variables[1])) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - PostBooleanSumInRange(data->Sat(), solver, variables, 1, 1); - } - } else { - if (FLAGS_fz_use_sat && - AddBoolEq(data->Sat(), variables[0], variables[1])) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - variables.push_back(solver->MakeIntConst(1)); - Constraint* const constraint = MakeBooleanSumOdd(solver, variables); - AddConstraint(solver, ct, constraint); - } - } - break; - } - default: { - if (!even) { - variables.push_back(solver->MakeIntConst(1)); - } - Constraint* const constraint = MakeBooleanSumOdd(solver, variables); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractArrayIntElement(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const index = data->GetOrCreateExpression(ct->arguments[0]); - const std::vector& values = ct->arguments[1].values; - const int64 imin = std::max(index->Min(), int64{1}); - const int64 imax = std::min(index->Max(), values.size()); - IntVar* const shifted_index = solver->MakeSum(index, -imin)->Var(); - const int64 size = imax - imin + 1; - std::vector coefficients(size); - for (int i = 0; i < size; ++i) { - coefficients[i] = values[i + imin - 1]; - } - if (ct->target_variable != nullptr) { - DCHECK_EQ(ct->arguments[2].Var(), ct->target_variable); - IntExpr* const target = solver->MakeElement(coefficients, shifted_index); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntVar* const target = - data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeElementEquality(coefficients, shifted_index, target); - AddConstraint(solver, ct, constraint); - } - } else { - CHECK_EQ(2, ct->arguments[0].variables.size()); - CHECK_EQ(5, ct->arguments.size()); - CHECK(ct->target_variable == nullptr); - IntVar* const index1 = data->Extract(ct->arguments[0].variables[0])->Var(); - IntVar* const index2 = data->Extract(ct->arguments[0].variables[1])->Var(); - const int64 coef1 = ct->arguments[3].values[0]; - const int64 coef2 = ct->arguments[3].values[1]; - const int64 offset = ct->arguments[4].values[0]; - const std::vector& values = ct->arguments[1].values; - std::unique_ptr domain1(index1->MakeDomainIterator(false)); - std::unique_ptr domain2(index2->MakeDomainIterator(false)); - IntTupleSet tuples(3); - for (domain1->Init(); domain1->Ok(); domain1->Next()) { - const int64 v1 = domain1->Value(); - for (domain2->Init(); domain2->Ok(); domain2->Next()) { - const int64 v2 = domain2->Value(); - const int64 index = v1 * coef1 + v2 * coef2 + offset - 1; - if (index >= 0 && index < values.size()) { - tuples.Insert3(v1, v2, values[index]); - } - } - } - std::vector variables; - variables.push_back(index1); - variables.push_back(index2); - IntVar* const target = data->GetOrCreateExpression(ct->arguments[2])->Var(); - variables.push_back(target); - Constraint* const constraint = - solver->MakeAllowedAssignments(variables, tuples); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractArrayIntElementNonShifted(fz::SolverData* data, - fz::Constraint* ct) { - CHECK_EQ(1, ct->arguments[0].variables.size()); - Solver* const solver = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntVar* const index = data->GetOrCreateExpression(ct->arguments[0])->Var(); - const std::vector& values = ct->arguments[1].values; - if (ct->target_variable != nullptr) { - DCHECK_EQ(ct->arguments[2].Var(), ct->target_variable); - IntExpr* const target = solver->MakeElement(values, index); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntVar* const target = - data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeElementEquality(values, index, target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractArrayVarIntElement(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const index = data->GetOrCreateExpression(ct->arguments[0]); - const int64 array_size = ct->arguments[1].variables.size(); - const int64 imin = std::max(index->Min(), int64{1}); - const int64 imax = std::min(index->Max(), array_size); - IntVar* const shifted_index = solver->MakeSum(index, -imin)->Var(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[1]); - const int64 size = imax - imin + 1; - std::vector var_array(size); - for (int i = 0; i < size; ++i) { - var_array[i] = vars[i + imin - 1]; - } - - if (ct->target_variable != nullptr) { - DCHECK_EQ(ct->arguments[2].Var(), ct->target_variable); - IntExpr* const target = solver->MakeElement(var_array, shifted_index); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - Constraint* constraint = nullptr; - if (ct->arguments[2].HasOneValue()) { - const int64 target = ct->arguments[2].Value(); - if (data->IsAllDifferent(ct->arguments[1].variables)) { - constraint = - solver->MakeIndexOfConstraint(var_array, shifted_index, target); - } else { - constraint = - solver->MakeElementEquality(var_array, shifted_index, target); - } - } else { - IntVar* const target = - data->GetOrCreateExpression(ct->arguments[2])->Var(); - constraint = - solver->MakeElementEquality(var_array, shifted_index, target); - } - AddConstraint(solver, ct, constraint); - } -} - -void ExtractBoolAnd(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeMin(left, right); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - if (FLAGS_fz_use_sat && AddBoolAndEqVar(data->Sat(), left, right, target)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeEquality(solver->MakeMin(left, right), target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractBoolClause(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector positive_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector negative_variables = - data->GetOrCreateVariableArray(ct->arguments[1]); - std::vector vars; - for (IntVar* const var : positive_variables) { - if (var->Bound() && var->Min() == 1) { // True constraint - AddConstraint(solver, ct, solver->MakeTrueConstraint()); - return; - } else if (!var->Bound()) { - vars.push_back(var); - } - } - for (IntVar* const var : negative_variables) { - if (var->Bound() && var->Max() == 0) { // True constraint - AddConstraint(solver, ct, solver->MakeTrueConstraint()); - return; - } else if (!var->Bound()) { - vars.push_back(solver->MakeDifference(1, var)->Var()); - } - } - if (FLAGS_fz_use_sat && AddBoolOrArrayEqualTrue(data->Sat(), vars)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = solver->MakeSumGreaterOrEqual(vars, 1); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractBoolNot(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->target_variable != nullptr) { - if (ct->target_variable == ct->arguments[1].Var()) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const target = solver->MakeDifference(1, left); - FZVLOG << " - creating " << ct->arguments[1].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = solver->MakeDifference(1, right); - FZVLOG << " - creating " << ct->arguments[0].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } - } else { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (FLAGS_fz_use_sat && AddBoolNot(data->Sat(), left, right)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeEquality(solver->MakeDifference(1, left), right); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractBoolOr(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeMax(left, right); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - if (FLAGS_fz_use_sat && AddBoolOrEqVar(data->Sat(), left, right, target)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeEquality(solver->MakeMax(left, right), target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractBoolXor(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntVar* const target = data->GetOrCreateExpression(ct->arguments[2])->Var(); - if (FLAGS_fz_use_sat && AddBoolIsNEqVar(data->Sat(), left, right, target)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeIsEqualCstCt(solver->MakeSum(left, right), 1, target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCircuit(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - const int size = tmp_vars.size(); - bool found_zero = false; - bool found_size = false; - for (IntVar* const var : tmp_vars) { - if (var->Min() == 0) { - found_zero = true; - } - if (var->Max() == size) { - found_size = true; - } - } - std::vector variables; - if (found_zero && !found_size) { // Variables values are 0 based. - variables = tmp_vars; - } else { // Variables values are 1 based. - variables.resize(size); - for (int i = 0; i < size; ++i) { - // Create variables. Account for 1-based array indexing. - variables[i] = solver->MakeSum(tmp_vars[i], -1)->Var(); - } - } - Constraint* const constraint = solver->MakeCircuit(variables); - AddConstraint(solver, ct, constraint); -} - -// Creates an [ct->arguments[0][i]->Var() == ct->arguments[1] for all i]. -// It is optimized for different cases: -// - ct->arguments[0] is constant and ct->arguments[1] has one value. -// - ct->arguments[1] has one value -// - generic case. -// This is used by all CreateCountXXX functions. -std::vector BuildCount(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector tmp_sum; - if (ct->arguments[0].variables.empty()) { - if (ct->arguments[1].HasOneValue()) { - const int64 value = ct->arguments[1].Value(); - for (const int64 v : ct->arguments[0].values) { - if (v == value) { - tmp_sum.push_back(solver->MakeIntConst(1)); - } - } - } else { - IntVar* const count_var = - data->GetOrCreateExpression(ct->arguments[1])->Var(); - tmp_sum.push_back( - solver->MakeIsMemberVar(count_var, ct->arguments[0].values)); - } - } else { - if (ct->arguments[1].HasOneValue()) { - const int64 value = ct->arguments[1].Value(); - for (fz::IntegerVariable* const fzvar : ct->arguments[0].variables) { - IntVar* const var = - solver->MakeIsEqualCstVar(data->Extract(fzvar), value); - if (var->Max() == 1) { - tmp_sum.push_back(var); - } - } - } else { - IntVar* const value = - data->GetOrCreateExpression(ct->arguments[1])->Var(); - for (fz::IntegerVariable* const fzvar : ct->arguments[0].variables) { - IntVar* const var = solver->MakeIsEqualVar(data->Extract(fzvar), value); - if (var->Max() == 1) { - tmp_sum.push_back(var); - } - } - } - } - return tmp_sum; -} - -void ExtractCountEq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, count, count); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = solver->MakeSumEquality(tmp_sum, count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountGeq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, count, tmp_sum.size()); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeGreaterOrEqual(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountGt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, count + 1, - tmp_sum.size()); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeGreater(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountLeq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->arguments[2].HasOneValue() && ct->arguments[1].HasOneValue()) { - // At most in disguise. - const int64 max_count = ct->arguments[2].Value(); - const int64 value = ct->arguments[1].Value(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - Constraint* const constraint = solver->MakeAtMost(vars, value, max_count); - AddConstraint(solver, ct, constraint); - } - - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, 0, count); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeLessOrEqual(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountLt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->arguments[2].HasOneValue() && ct->arguments[1].HasOneValue()) { - // At most in disguise. - const int64 max_count = ct->arguments[2].Value(); - const int64 value = ct->arguments[1].Value(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - Constraint* const constraint = - solver->MakeAtMost(vars, value, max_count - 1); - AddConstraint(solver, ct, constraint); - } - - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, 0, count - 1); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeLess(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountNeq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_sum = BuildCount(data, ct); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - if (count == 0) { - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, 1, tmp_sum.size()); - } else if (count == tmp_sum.size()) { - PostBooleanSumInRange(data->Sat(), solver, tmp_sum, 0, - tmp_sum.size() - 1); - } else { - Constraint* const constraint = - solver->MakeNonEquality(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeNonEquality(solver->MakeSum(tmp_sum), count); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractCountReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_sum = BuildCount(data, ct); - IntVar* const boolvar = data->GetOrCreateExpression(ct->arguments[3])->Var(); - if (ct->arguments[2].HasOneValue()) { - const int64 count = ct->arguments[2].Value(); - PostIsBooleanSumInRange(data->Sat(), solver, tmp_sum, count, count, - boolvar); - } else { - IntVar* const count = data->GetOrCreateExpression(ct->arguments[2])->Var(); - Constraint* const constraint = - solver->MakeIsEqualCt(solver->MakeSum(tmp_sum), count, boolvar); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractPerformedAndDemands(Solver* const solver, - const std::vector& vars, - std::vector* performed, - std::vector* demands) { - performed->clear(); - demands->clear(); - for (IntVar* const var : vars) { - if (var->Bound()) { - performed->push_back(solver->MakeIntConst(1)); - demands->push_back(var->Min()); - } else if (var->Max() == 1) { - performed->push_back(var); - demands->push_back(1); - } else { - IntExpr* sub = nullptr; - int64 coef = 1; - CHECK(solver->IsProduct(var, &sub, &coef)); - performed->push_back(sub->Var()); - demands->push_back(coef); - } - } -} - -// Recognize a demand of the form boolean_var * constant. -// In the context of cumulative, this can be interpreted as a task with fixed -// demand, and a performed variable 'boolean_var'. -bool IsHiddenPerformed(fz::SolverData* data, - const std::vector& fz_vars) { - for (fz::IntegerVariable* const fz_var : fz_vars) { - IntVar* const var = data->Extract(fz_var)->Var(); - if (var->Size() > 2 || (var->Size() == 2 && var->Min() != 0)) { - return false; - } - if (!var->Bound() && var->Max() != 1) { - IntExpr* sub = nullptr; - int64 coef = 1; - if (!data->solver()->IsProduct(var, &sub, &coef)) { - return false; - } - if (coef != var->Max()) { - return false; - } - CHECK_EQ(1, sub->Max()); - } - } - return true; -} - -void ExtractCumulative(fz::SolverData* data, fz::Constraint* ct) { - // This constraint has many possible translation into the CP library. - // First we parse the arguments. - Solver* const solver = data->solver(); - // Parse start variables. - const std::vector start_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - - // Parse durations. - std::vector fixed_durations; - std::vector variable_durations; - if (ct->arguments[1].type == fz::Argument::INT_LIST) { - fixed_durations = ct->arguments[1].values; - } else { - variable_durations = data->GetOrCreateVariableArray(ct->arguments[1]); - if (AreAllBound(variable_durations)) { - FillValues(variable_durations, &fixed_durations); - variable_durations.clear(); - } - } - - // Parse demands. - std::vector fixed_demands; - std::vector variable_demands; - if (ct->arguments[2].type == fz::Argument::INT_LIST) { - fixed_demands = ct->arguments[2].values; - } else { - variable_demands = data->GetOrCreateVariableArray(ct->arguments[2]); - if (AreAllBound(variable_demands)) { - FillValues(variable_demands, &fixed_demands); - variable_demands.clear(); - } - } - - // Parse capacity. - int64 fixed_capacity = 0; - IntVar* variable_capacity = nullptr; - if (ct->arguments[3].HasOneValue()) { - fixed_capacity = ct->arguments[3].Value(); - } else { - variable_capacity = data->GetOrCreateExpression(ct->arguments[3])->Var(); - } - - // Special case. We will not create the interval variables. - if (!fixed_durations.empty() && !fixed_demands.empty() && - AreAllOnes(fixed_durations) && variable_capacity == nullptr && - AreAllGreaterOrEqual(fixed_demands, fixed_capacity / 2 + 1)) { - // Hidden all different. - Constraint* const constraint = solver->MakeAllDifferent(start_variables); - AddConstraint(solver, ct, constraint); - return; - } - - // Special case. Durations are fixed, demands are boolean, capacity - // is one. We can transform the cumulative into a disjunctive with - // optional interval variables. - if (!fixed_durations.empty() && fixed_demands.empty() && - IsHiddenPerformed(data, ct->arguments[2].variables) && - variable_capacity == nullptr && fixed_capacity == 1) { - std::vector performed_variables; - ExtractPerformedAndDemands(solver, variable_demands, &performed_variables, - &fixed_demands); - std::vector intervals; - intervals.reserve(start_variables.size()); - for (int i = 0; i < start_variables.size(); ++i) { - if (fixed_demands[i] == 1) { - intervals.push_back(solver->MakeFixedDurationIntervalVar( - start_variables[i], fixed_durations[i], performed_variables[i], - start_variables[i]->name())); - } - } - if (intervals.size() > 1) { - Constraint* const constraint = - solver->MakeDisjunctiveConstraint(intervals, ""); - AddConstraint(solver, ct, constraint); - } - return; - } - - // Back to regular case. Let's create the interval variables. - Constraint* constraint = nullptr; - std::vector intervals; - if (!fixed_durations.empty()) { - for (int i = 0; i < start_variables.size(); ++i) { - IntervalVar* const interval = solver->MakeFixedDurationIntervalVar( - start_variables[i], fixed_durations[i], start_variables[i]->name()); - intervals.push_back(interval); - } - } else { - for (int i = 0; i < start_variables.size(); ++i) { - IntVar* const start = start_variables[i]; - IntVar* const duration = variable_durations[i]; - IntervalVar* const interval = - MakePerformedIntervalVar(solver, start, duration, start->name()); - intervals.push_back(interval); - } - } - - if (!fixed_demands.empty()) { - // Demands are fixed. - if (variable_capacity == nullptr) { - constraint = AreAllGreaterOrEqual(fixed_demands, fixed_capacity / 2 + 1) - ? solver->MakeDisjunctiveConstraint(intervals, "") - : solver->MakeCumulative(intervals, fixed_demands, - fixed_capacity, ""); - } else { - // Capacity is variable. - constraint = solver->MakeCumulative(intervals, fixed_demands, - variable_capacity, ""); - } - } else { - // Demands are variables. - if (variable_capacity == nullptr) { - // Capacity is fixed. - constraint = solver->MakeCumulative(intervals, variable_demands, - fixed_capacity, ""); - } else { - // Capacity is variable. - // Constraint* const constraint2 = MakeVariableCumulative( - // solver, start_variables, variable_durations, variable_demands, - // variable_capacity); - // AddConstraint(solver, ct, constraint2); - - constraint = solver->MakeCumulative(intervals, variable_demands, - variable_capacity, ""); - } - } - AddConstraint(solver, ct, constraint); -} - -void ExtractDiffn(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector x_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector y_variables = - data->GetOrCreateVariableArray(ct->arguments[1]); - if (ct->arguments[2].type == fz::Argument::INT_LIST && - ct->arguments[3].type == fz::Argument::INT_LIST) { - const std::vector& x_sizes = ct->arguments[2].values; - const std::vector& y_sizes = ct->arguments[3].values; - Constraint* const constraint = solver->MakeNonOverlappingBoxesConstraint( - x_variables, y_variables, x_sizes, y_sizes); - AddConstraint(solver, ct, constraint); - } else { - const std::vector x_sizes = - data->GetOrCreateVariableArray(ct->arguments[2]); - const std::vector y_sizes = - data->GetOrCreateVariableArray(ct->arguments[3]); - Constraint* const constraint = solver->MakeNonOverlappingBoxesConstraint( - x_variables, y_variables, x_sizes, y_sizes); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractDiffnK(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector flat_x = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector flat_dx = - data->GetOrCreateVariableArray(ct->arguments[1]); - const int num_boxes = ct->arguments[2].Value(); - const int num_dims = ct->arguments[3].Value(); - std::vector> x(num_boxes); - std::vector> dx(num_boxes); - int count = 0; - for (int b = 0; b < num_boxes; ++b) { - x[b].resize(num_dims); - dx[b].resize(num_dims); - for (int d = 0; d < num_dims; ++d) { - x[b][d] = flat_x[count]; - dx[b][d] = flat_dx[count]; - count++; - } - } - Constraint* const constraint = MakeKDiffn(solver, x, dx, true); - AddConstraint(solver, ct, constraint); -} - -void ExtractDiffnNonStrict(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector x_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector y_variables = - data->GetOrCreateVariableArray(ct->arguments[1]); - if (ct->arguments[2].type == fz::Argument::INT_LIST && - ct->arguments[3].type == fz::Argument::INT_LIST) { - const std::vector& x_sizes = ct->arguments[2].values; - const std::vector& y_sizes = ct->arguments[3].values; - Constraint* const constraint = - solver->MakeNonOverlappingNonStrictBoxesConstraint( - x_variables, y_variables, x_sizes, y_sizes); - AddConstraint(solver, ct, constraint); - } else { - const std::vector x_sizes = - data->GetOrCreateVariableArray(ct->arguments[2]); - const std::vector y_sizes = - data->GetOrCreateVariableArray(ct->arguments[3]); - Constraint* const constraint = - solver->MakeNonOverlappingNonStrictBoxesConstraint( - x_variables, y_variables, x_sizes, y_sizes); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractDiffnNonStrictK(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector flat_x = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector flat_dx = - data->GetOrCreateVariableArray(ct->arguments[1]); - const int num_boxes = ct->arguments[2].Value(); - const int num_dims = ct->arguments[3].Value(); - std::vector> x(num_boxes); - std::vector> dx(num_boxes); - int count = 0; - for (int b = 0; b < num_boxes; ++b) { - x[b].resize(num_dims); - dx[b].resize(num_dims); - for (int d = 0; d < num_dims; ++d) { - x[b][d] = flat_x[count]; - dx[b][d] = flat_dx[count]; - count++; - } - } - Constraint* const constraint = MakeKDiffn(solver, x, dx, false); - AddConstraint(solver, ct, constraint); -} - -void ExtractDisjunctive(fz::SolverData* data, fz::Constraint* ct) { - // This constraint has many possible translation into the CP library. - // First we parse the arguments. - Solver* const solver = data->solver(); - // Parse start variables. - const std::vector start_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - - // Parse durations. - std::vector fixed_durations; - std::vector variable_durations; - if (ct->arguments[1].type == fz::Argument::INT_LIST) { - fixed_durations = ct->arguments[1].values; - } else { - variable_durations = data->GetOrCreateVariableArray(ct->arguments[1]); - if (AreAllBound(variable_durations)) { - FillValues(variable_durations, &fixed_durations); - variable_durations.clear(); - } - } - - // Special case. We will not create the interval variables. - if (!fixed_durations.empty() && AreAllOnes(fixed_durations)) { - // Hidden all different. - Constraint* const constraint = solver->MakeAllDifferent(start_variables); - AddConstraint(solver, ct, constraint); - return; - } - - // Back to regular case. Let's create the interval variables. - std::vector intervals; - if (!fixed_durations.empty()) { - for (int i = 0; i < start_variables.size(); ++i) { - IntervalVar* const interval = solver->MakeFixedDurationIntervalVar( - start_variables[i], fixed_durations[i], start_variables[i]->name()); - intervals.push_back(interval); - } - } else { - for (int i = 0; i < start_variables.size(); ++i) { - IntVar* const start = start_variables[i]; - IntVar* const duration = variable_durations[i]; - IntervalVar* const interval = - MakePerformedIntervalVar(solver, start, duration, start->name()); - intervals.push_back(interval); - } - } - Constraint* const constraint = - solver->MakeDisjunctiveConstraint(intervals, ""); - AddConstraint(solver, ct, constraint); -} - -void ExtractDisjunctiveStrict(fz::SolverData* data, fz::Constraint* ct) { - // This constraint has many possible translation into the CP library. - // First we parse the arguments. - Solver* const solver = data->solver(); - // Parse start variables. - const std::vector start_variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - - // Parse durations. - std::vector fixed_durations; - std::vector variable_durations; - if (ct->arguments[1].type == fz::Argument::INT_LIST) { - fixed_durations = ct->arguments[1].values; - } else { - variable_durations = data->GetOrCreateVariableArray(ct->arguments[1]); - if (AreAllBound(variable_durations)) { - FillValues(variable_durations, &fixed_durations); - variable_durations.clear(); - } - } - - // Special case. We will not create the interval variables. - if (!fixed_durations.empty() && AreAllOnes(fixed_durations)) { - // Hidden all different. - Constraint* const constraint = solver->MakeAllDifferent(start_variables); - AddConstraint(solver, ct, constraint); - return; - } - - // Back to regular case. Let's create the interval variables. - std::vector intervals; - if (!fixed_durations.empty()) { - for (int i = 0; i < start_variables.size(); ++i) { - IntervalVar* const interval = solver->MakeFixedDurationIntervalVar( - start_variables[i], fixed_durations[i], start_variables[i]->name()); - intervals.push_back(interval); - } - } else { - for (int i = 0; i < start_variables.size(); ++i) { - IntVar* const start = start_variables[i]; - IntVar* const duration = variable_durations[i]; - IntervalVar* const interval = - MakePerformedIntervalVar(solver, start, duration, start->name()); - intervals.push_back(interval); - } - } - Constraint* const constraint = - solver->MakeStrictDisjunctiveConstraint(intervals, ""); - AddConstraint(solver, ct, constraint); -} - -void ExtractFalseConstraint(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - Constraint* const constraint = solver->MakeFalseConstraint(); - AddConstraint(solver, ct, constraint); -} - -void ExtractGlobalCardinality(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector values = ct->arguments[1].values; - std::vector variables; - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - for (IntVar* const var : tmp_vars) { - for (int v = 0; v < values.size(); ++v) { - if (var->Contains(values[v])) { - variables.push_back(var); - break; - } - } - } - const std::vector cards = - data->GetOrCreateVariableArray(ct->arguments[2]); - Constraint* const constraint = - solver->MakeDistribute(variables, values, cards); - AddConstraint(solver, ct, constraint); - Constraint* const constraint2 = - solver->MakeSumLessOrEqual(cards, variables.size()); - AddConstraint(solver, ct, constraint2); -} - -void ExtractGlobalCardinalityClosed(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector values = ct->arguments[1].values; - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - - const std::vector cards = - data->GetOrCreateVariableArray(ct->arguments[2]); - Constraint* const constraint = - solver->MakeDistribute(variables, values, cards); - AddConstraint(solver, ct, constraint); - for (IntVar* const var : variables) { - Constraint* const constraint2 = solver->MakeMemberCt(var, values); - AddConstraint(solver, ct, constraint2); - } - - Constraint* const constraint3 = - solver->MakeSumEquality(cards, variables.size()); - AddConstraint(solver, ct, constraint3); -} - -void ExtractGlobalCardinalityLowUp(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector values = ct->arguments[1].values; - std::vector variables; - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - for (IntVar* const var : tmp_vars) { - for (int v = 0; v < values.size(); ++v) { - if (var->Contains(values[v])) { - variables.push_back(var); - break; - } - } - } - const std::vector& low = ct->arguments[2].values; - const std::vector& up = ct->arguments[3].values; - Constraint* const constraint = - solver->MakeDistribute(variables, values, low, up); - AddConstraint(solver, ct, constraint); -} - -void ExtractGlobalCardinalityLowUpClosed(fz::SolverData* data, - fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector values = ct->arguments[1].values; - const std::vector& low = ct->arguments[2].values; - const std::vector& up = ct->arguments[3].values; - Constraint* const constraint = - solver->MakeDistribute(variables, values, low, up); - AddConstraint(solver, ct, constraint); - for (IntVar* const var : variables) { - Constraint* const constraint2 = solver->MakeMemberCt(var, values); - AddConstraint(solver, ct, constraint2); - } -} - -void ExtractGlobalCardinalityOld(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector cards = - data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeDistribute(variables, cards); - AddConstraint(solver, ct, constraint); -} - -void ExtractIntAbs(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeAbs(left); - FZVLOG << " - creating " << ct->arguments[1].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else if (ct->arguments[1].HasOneValue()) { - const int64 value = ct->arguments[1].Value(); - std::vector values(2); - values[0] = -value; - values[1] = value; - Constraint* const constraint = solver->MakeMemberCt(left, values); - AddConstraint(solver, ct, constraint); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[1]); - Constraint* const constraint = - solver->MakeAbsEquality(left->Var(), target->Var()); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntDiv(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->target_variable != nullptr) { - if (!ct->arguments[1].HasOneValue()) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = solver->MakeDiv(left, right); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - const int64 value = ct->arguments[1].Value(); - IntExpr* const target = solver->MakeDiv(left, value); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - if (!ct->arguments[1].HasOneValue()) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeDiv(left, right), target); - AddConstraint(solver, ct, constraint); - } else { - Constraint* const constraint = solver->MakeEquality( - solver->MakeDiv(left, ct->arguments[1].Value()), target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractIntEq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (FLAGS_fz_use_sat && AddBoolEq(data->Sat(), left, right)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - AddConstraint(s, ct, s->MakeEquality(left, right)); - } - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeEquality(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeEquality(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left != right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -void ExtractIntEqReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->target_variable != nullptr) { - CHECK_EQ(ct->target_variable, ct->arguments[2].Var()); - if (ct->arguments[1].HasOneValue()) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - const int64 value = ct->arguments[1].Value(); - IntVar* const boolvar = solver->MakeIsEqualCstVar(left, value); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else if (ct->arguments[0].HasOneValue()) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - const int64 value = ct->arguments[0].Value(); - IntVar* const boolvar = solver->MakeIsEqualCstVar(right, value); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntVar* tmp_var = nullptr; - bool tmp_neg = false; - bool success = false; - if (FLAGS_fz_use_sat && solver->IsBooleanVar(left, &tmp_var, &tmp_neg) && - solver->IsBooleanVar(right, &tmp_var, &tmp_neg)) { - // Try to post to sat. - IntVar* const boolvar = solver->MakeBoolVar(); - if (AddIntEqReif(data->Sat(), left, right, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - success = true; - } - } - if (!success) { - IntVar* const boolvar = solver->MakeIsEqualVar( - left, data->GetOrCreateExpression(ct->arguments[1])); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[2])->Var(); - if (ct->arguments[1].HasOneValue()) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - const int64 value = ct->arguments[1].Value(); - Constraint* const constraint = - solver->MakeIsEqualCstCt(left, value, boolvar); - AddConstraint(solver, ct, constraint); - } else if (ct->arguments[0].HasOneValue()) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - const int64 value = ct->arguments[0].Value(); - Constraint* const constraint = - solver->MakeIsEqualCstCt(right, value, boolvar); - AddConstraint(solver, ct, constraint); - } else { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = - data->GetOrCreateExpression(ct->arguments[1])->Var(); - if (FLAGS_fz_use_sat && AddIntEqReif(data->Sat(), left, right, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeIsEqualCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractIntGe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (FLAGS_fz_use_sat && AddBoolLe(data->Sat(), right, left)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - AddConstraint(s, ct, s->MakeGreaterOrEqual(left, right)); - } - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeGreaterOrEqual(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeLessOrEqual(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left < right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -#define EXTRACT_INT_XX_REIF(Op, Rev) \ - Solver* const solver = data->solver(); \ - if (ct->target_variable != nullptr) { \ - IntVar* boolvar = nullptr; \ - if (ct->arguments[0].HasOneValue()) { \ - const int64 left = ct->arguments[0].Value(); \ - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); \ - boolvar = solver->MakeIs##Rev##CstVar(right, left); \ - } else if (ct->arguments[1].HasOneValue()) { \ - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); \ - const int64 right = ct->arguments[1].Value(); \ - boolvar = solver->MakeIs##Op##CstVar(left, right); \ - } else { \ - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); \ - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); \ - boolvar = solver->MakeIs##Op##Var(left, right); \ - } \ - FZVLOG << " - creating " << ct->target_variable->DebugString() \ - << " := " << boolvar->DebugString() << FZENDL; \ - data->SetExtracted(ct->target_variable, boolvar); \ - } else { \ - IntVar* boolvar = nullptr; \ - Constraint* constraint = nullptr; \ - if (ct->arguments[0].HasOneValue()) { \ - const int64 left = ct->arguments[0].Value(); \ - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); \ - if (right->IsVar()) { \ - boolvar = solver->MakeIs##Rev##CstVar(right, left); \ - } else { \ - boolvar = data->GetOrCreateExpression(ct->arguments[2])->Var(); \ - constraint = solver->MakeIs##Rev##CstCt(right, left, boolvar); \ - } \ - } else if (ct->arguments[1].HasOneValue()) { \ - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); \ - const int64 right = ct->arguments[1].Value(); \ - if (left->IsVar()) { \ - boolvar = solver->MakeIs##Op##CstVar(left, right); \ - } else { \ - boolvar = data->GetOrCreateExpression(ct->arguments[2])->Var(); \ - constraint = solver->MakeIs##Op##CstCt(left, right, boolvar); \ - } \ - } else { \ - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); \ - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); \ - boolvar = data->GetOrCreateExpression(ct->arguments[2])->Var(); \ - constraint = solver->MakeIs##Op##Ct(left, right, boolvar); \ - } \ - if (constraint != nullptr) { \ - AddConstraint(solver, ct, constraint); \ - } else { \ - IntVar* const previous = \ - data->GetOrCreateExpression(ct->arguments[2])->Var(); \ - FZVLOG << " - creating and linking " << boolvar->DebugString() \ - << " to " << previous->DebugString() << FZENDL; \ - if (FLAGS_fz_use_sat && AddBoolEq(data->Sat(), boolvar, previous)) { \ - FZVLOG << " - posted to sat" << FZENDL; \ - } else { \ - Constraint* const constraint = \ - solver->MakeEquality(boolvar, previous); \ - AddConstraint(solver, ct, constraint); \ - } \ - } \ - } - -void ExtractIntGeReif(fz::SolverData* data, fz::Constraint* ct) { - EXTRACT_INT_XX_REIF(GreaterOrEqual, LessOrEqual) -} - -void ExtractIntGt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeGreater(left, right)); - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeGreater(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeLess(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left <= right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -void ExtractIntGtReif(fz::SolverData* data, fz::Constraint* ct) { - EXTRACT_INT_XX_REIF(Greater, Less); -} - -void ExtractIntLe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (FLAGS_fz_use_sat && AddBoolLe(data->Sat(), left, right)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - AddConstraint(s, ct, s->MakeLessOrEqual(left, right)); - } - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeLessOrEqual(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeGreaterOrEqual(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left > right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -void ExtractIntLeReif(fz::SolverData* data, fz::Constraint* ct) { - EXTRACT_INT_XX_REIF(LessOrEqual, GreaterOrEqual) -} - -void ExtractIntLt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeLess(left, right)); - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeLess(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeGreater(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left >= right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -void ExtractIntLtReif(fz::SolverData* data, fz::Constraint* ct) { - EXTRACT_INT_XX_REIF(Less, Greater) -} - -#undef EXTRACT_INT_XX_REIF - -void ParseShortIntLin(fz::SolverData* data, fz::Constraint* ct, IntExpr** left, - IntExpr** right) { - Solver* const solver = data->solver(); - const std::vector& fzvars = ct->arguments[1].variables; - const std::vector& coefficients = ct->arguments[0].values; - int64 rhs = ct->arguments[2].Value(); - const int size = ct->arguments[0].values.size(); - *left = nullptr; - *right = nullptr; - - if (fzvars.empty() && size != 0) { - // We have a constant array. - CHECK_EQ(ct->arguments[1].values.size(), size); - int64 result = 0; - for (int i = 0; i < size; ++i) { - result += coefficients[i] * ct->arguments[1].values[i]; - } - *left = solver->MakeIntConst(result); - *right = solver->MakeIntConst(rhs); - return; - } - - switch (size) { - case 0: { - *left = solver->MakeIntConst(0); - *right = solver->MakeIntConst(rhs); - break; - } - case 1: { - *left = solver->MakeProd(data->Extract(fzvars[0]), coefficients[0]); - *right = solver->MakeIntConst(rhs); - break; - } - case 2: { - IntExpr* const e1 = data->Extract(fzvars[0]); - IntExpr* const e2 = data->Extract(fzvars[1]); - const int64 c1 = coefficients[0]; - const int64 c2 = coefficients[1]; - if (c1 > 0) { - if (c2 > 0) { - *left = solver->MakeProd(e1, c1); - *right = solver->MakeDifference(rhs, solver->MakeProd(e2, c2)); - } else { - *left = solver->MakeProd(e1, c1); - *right = solver->MakeSum(solver->MakeProd(e2, -c2), rhs); - } - } else if (c2 > 0) { - *left = solver->MakeProd(e2, c2); - *right = solver->MakeSum(solver->MakeProd(e1, -c1), rhs); - } else { - *left = solver->MakeDifference(-rhs, solver->MakeProd(e2, -c2)); - *right = solver->MakeProd(e1, -c1); - } - break; - } - case 3: { - IntExpr* const e1 = data->Extract(fzvars[0]); - IntExpr* const e2 = data->Extract(fzvars[1]); - IntExpr* const e3 = data->Extract(fzvars[2]); - const int64 c1 = coefficients[0]; - const int64 c2 = coefficients[1]; - const int64 c3 = coefficients[2]; - if (c1 > 0 && c2 > 0 && c3 > 0) { - *left = - solver->MakeSum(solver->MakeProd(e1, c1), solver->MakeProd(e2, c2)); - *right = solver->MakeDifference(rhs, solver->MakeProd(e3, c3)); - - } else if (c1 < 0 && c2 > 0 && c3 > 0) { - *left = - solver->MakeSum(solver->MakeProd(e2, c2), solver->MakeProd(e3, c3)); - *right = solver->MakeSum(solver->MakeProd(e1, -c1), rhs); - } else if (c1 > 0 && c2 < 0 && c3 < 0) { - *left = solver->MakeSum(solver->MakeProd(e1, c1), -rhs); - *right = solver->MakeSum(solver->MakeProd(e2, -c2), - solver->MakeProd(e3, -c3)); - } else if (c1 > 0 && c2 < 0 && c3 > 0) { - *left = - solver->MakeSum(solver->MakeProd(e1, c1), solver->MakeProd(e3, c3)); - *right = solver->MakeSum(solver->MakeProd(e2, -c2), rhs); - } else if (c1 > 0 && c2 > 0 && c3 < 0) { - *left = - solver->MakeSum(solver->MakeProd(e1, c1), solver->MakeProd(e2, c2)); - *right = solver->MakeSum(solver->MakeProd(e3, -c3), rhs); - } else if (c1 < 0 && c2 < 0 && c3 > 0) { - *left = solver->MakeSum(solver->MakeProd(e3, c3), -rhs); - *right = solver->MakeSum(solver->MakeProd(e1, -c1), - solver->MakeProd(e2, -c2)); - } else if (c1 < 0 && c2 > 0 && c3 < 0) { - *left = solver->MakeSum(solver->MakeProd(e2, c2), -rhs); - *right = solver->MakeSum(solver->MakeProd(e1, -c1), - solver->MakeProd(e3, -c3)); - } else { - DCHECK_LE(c1, 0); - DCHECK_LE(c2, 0); - DCHECK_LE(c3, 0); - *left = solver->MakeDifference(-rhs, solver->MakeProd(e3, -c3)); - *right = solver->MakeSum(solver->MakeProd(e1, -c1), - solver->MakeProd(e2, -c2)); - } - break; - } - default: { - LOG(FATAL) << "Too many terms in " << ct->DebugString(); - } - } -} - -void ParseLongIntLin(fz::SolverData* data, fz::Constraint* ct, - std::vector* vars, std::vector* coeffs, - int64* rhs) { - CHECK(vars != nullptr); - CHECK(coeffs != nullptr); - CHECK(rhs != nullptr); - const std::vector& fzvars = ct->arguments[1].variables; - const std::vector& coefficients = ct->arguments[0].values; - *rhs = ct->arguments[2].values[0]; - const int size = fzvars.size(); - - for (int i = 0; i < size; ++i) { - const int64 coef = coefficients[i]; - IntVar* const var = data->Extract(fzvars[i])->Var(); - if (coef != 0 && (var->Min() != 0 || var->Max() != 0)) { - if (var->Bound()) { - (*rhs) -= var->Min() * coef; - } else { - coeffs->push_back(coef); - vars->push_back(var); - } - } - } -} - -bool AreAllExtractedAsVariables( - fz::SolverData* data, const std::vector& fz_vars) { - for (fz::IntegerVariable* const fz_var : fz_vars) { - IntExpr* const expr = data->Extract(fz_var); - if (!expr->IsVar()) { - return false; - } - } - return true; -} - -bool AreAllVariablesBoolean(fz::SolverData* data, fz::Constraint* ct) { - for (fz::IntegerVariable* const fz_var : ct->arguments[1].variables) { - IntVar* var = data->Extract(fz_var)->Var(); - if (var->Min() < 0 || var->Max() > 1) { - return false; - } - } - return true; -} - -bool ExtractLinAsShort(fz::SolverData* data, fz::Constraint* ct) { - const int size = ct->arguments[0].values.size(); - if (ct->arguments[1].variables.empty()) { - // Constant linear scalprods will be treated correctly by ParseShortLin. - return true; - } - switch (size) { - case 0: - return true; - case 1: - return true; - case 2: - case 3: { - if (AreAllOnes(ct->arguments[0].values) && - AreAllExtractedAsVariables(data, ct->arguments[1].variables) && - AreAllVariablesBoolean(data, ct)) { - return false; - } else { - return true; - } - } - default: { - return false; - } - } -} - -void ExtractIntLinEq(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector& fzvars = ct->arguments[1].variables; - const std::vector& coefficients = ct->arguments[0].values; - int64 rhs = ct->arguments[2].Value(); - const int size = ct->arguments[0].values.size(); - if (ct->target_variable != nullptr) { - if (size == 2) { - IntExpr* other = nullptr; - int64 other_coef = 0; - if (ct->target_variable == fzvars[0] && coefficients[0] == -1) { - other = data->Extract(fzvars[1]); - other_coef = coefficients[1]; - } else if (ct->target_variable == fzvars[1] && coefficients[1] == -1) { - other = data->Extract(fzvars[0]); - other_coef = coefficients[0]; - } else { - LOG(FATAL) << "Invalid constraint " << ct->DebugString(); - } - - IntExpr* const target = - solver->MakeSum(solver->MakeProd(other, other_coef), -rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - std::vector new_coefficients; - std::vector variables; - int64 constant = 0; - for (int i = 0; i < size; ++i) { - if (fzvars[i] == ct->target_variable) { - CHECK_EQ(-1, coefficients[i]); - } else if (fzvars[i]->domain.HasOneValue()) { - constant += coefficients[i] * fzvars[i]->domain.Min(); - } else { - const int64 coef = coefficients[i]; - IntVar* const var = data->Extract(fzvars[i])->Var(); - if (coef != 0 && (var->Min() != 0 || var->Max() != 0)) { - new_coefficients.push_back(coef); - variables.push_back(var); - } - } - } - IntExpr* const target = solver->MakeSum( - solver->MakeScalProd(variables, new_coefficients), constant - rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } - } else { - Constraint* constraint = nullptr; - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - constraint = solver->MakeEquality(left, right); - } else { - std::vector vars; - std::vector coeffs; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostBooleanSumInRange(data->Sat(), solver, vars, rhs, rhs); - return; - } else { - constraint = solver->MakeScalProdEquality(vars, coeffs, rhs); - } - } - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntLinEqReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - if (ct->target_variable != nullptr) { - IntVar* const boolvar = solver->MakeIsEqualVar(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - Constraint* const constraint = - solver->MakeIsEqualCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (ct->target_variable != nullptr) { - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - IntVar* const boolvar = solver->MakeBoolVar(); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - PostIsBooleanSumInRange(data->Sat(), solver, vars, rhs, rhs, boolvar); - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = - solver->MakeIsEqualCstVar(solver->MakeScalProd(vars, coeffs), rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostIsBooleanSumInRange(data->Sat(), solver, vars, rhs, rhs, boolvar); - } else { - Constraint* const constraint = solver->MakeIsEqualCstCt( - solver->MakeScalProd(vars, coeffs), rhs, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractIntLinGe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const int size = ct->arguments[0].values.size(); - if (ExtractLinAsShort(data, ct)) { - // Checks if it is not a hidden or. - if (ct->arguments[2].Value() == 1 && AreAllOnes(ct->arguments[0].values)) { - // Good candidate. - bool ok = true; - for (fz::IntegerVariable* const var : ct->arguments[1].variables) { - IntExpr* const expr = data->Extract(var); - if (expr->Min() < 0 || expr->Max() > 1 || !expr->IsVar()) { - ok = false; - break; - } - } - if (ok) { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - PostBooleanSumInRange(data->Sat(), solver, vars, rhs, size); - return; - } - } - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - AddConstraint(solver, ct, solver->MakeGreaterOrEqual(left, right)); - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostBooleanSumInRange(data->Sat(), solver, vars, rhs, size); - } else { - AddConstraint(solver, ct, - solver->MakeScalProdGreaterOrEqual(vars, coeffs, rhs)); - } - } -} - -void ExtractIntLinGeReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const int size = ct->arguments[0].values.size(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - if (ct->target_variable != nullptr) { - IntVar* const boolvar = solver->MakeIsGreaterOrEqualVar(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - Constraint* const constraint = - solver->MakeIsGreaterOrEqualCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (ct->target_variable != nullptr) { - if (AreAllBooleans(vars) && - (AreAllOnes(coeffs) || (rhs == 1 && AreAllPositive(coeffs)))) { - IntVar* const boolvar = solver->MakeBoolVar(); - PostIsBooleanSumInRange(data->Sat(), solver, vars, rhs, size, boolvar); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = solver->MakeIsGreaterOrEqualCstVar( - solver->MakeScalProd(vars, coeffs), rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostIsBooleanSumInRange(data->Sat(), solver, vars, rhs, size, boolvar); - } else { - Constraint* const constraint = solver->MakeIsGreaterOrEqualCstCt( - solver->MakeScalProd(vars, coeffs), rhs, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -bool PostHiddenClause(SatPropagator* const sat, - const std::vector& coeffs, - const std::vector& vars) { - std::vector others; - others.reserve(vars.size() - 1); - if (coeffs[0] != 1) { - return false; - } - for (int i = 1; i < coeffs.size(); ++i) { - if (coeffs[i] != -1) { - return false; - } - others.push_back(vars[i]); - } - return AddSumBoolArrayGreaterEqVar(sat, others, vars[0]); -} - -bool PostHiddenLeMax(SatPropagator* const sat, const std::vector& coeffs, - const std::vector& vars) { - std::vector others; - others.reserve(vars.size() - 1); - if (coeffs[0] > 1 - vars.size()) { - return false; - } - for (int i = 1; i < coeffs.size(); ++i) { - if (coeffs[i] != 1) { - return false; - } - others.push_back(vars[i]); - } - return AddMaxBoolArrayLessEqVar(sat, others, vars[0]); -} - -void ExtractIntLinLe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - AddConstraint(solver, ct, solver->MakeLessOrEqual(left, right)); - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostBooleanSumInRange(data->Sat(), solver, vars, 0, rhs); - } else if (FLAGS_fz_use_sat && AreAllBooleans(vars) && rhs == 0 && - PostHiddenClause(data->Sat(), coeffs, vars)) { - FZVLOG << " - posted to sat" << FZENDL; - } else if (FLAGS_fz_use_sat && AreAllBooleans(vars) && rhs == 0 && - PostHiddenLeMax(data->Sat(), coeffs, vars)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - AddConstraint(solver, ct, - solver->MakeScalProdLessOrEqual(vars, coeffs, rhs)); - } - } -} - -void ExtractIntLinLeReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - if (ct->target_variable != nullptr) { - IntVar* const boolvar = solver->MakeIsLessOrEqualVar(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - Constraint* const constraint = - solver->MakeIsLessOrEqualCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (ct->target_variable != nullptr) { - if (AreAllBooleans(vars) && - (AreAllOnes(coeffs) || (rhs == 0 && AreAllPositive(coeffs)))) { - IntVar* const boolvar = solver->MakeBoolVar(); - PostIsBooleanSumInRange(data->Sat(), solver, vars, 0, rhs, boolvar); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = solver->MakeIsLessOrEqualCstVar( - solver->MakeScalProd(vars, coeffs), rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostIsBooleanSumInRange(data->Sat(), solver, vars, 0, rhs, boolvar); - } else if (rhs == 0 && AreAllPositive(coeffs) && AreAllBooleans(vars)) { - // Special case. this is or(vars) = not(boolvar). - PostIsBooleanSumInRange(data->Sat(), solver, vars, 0, 0, boolvar); - } else if (rhs < 0 && AreAllPositive(coeffs) && - IsArrayInRange(vars, 0, kint64max)) { - // Trivial failure. - boolvar->SetValue(0); - FZVLOG << " - set target to 0" << FZENDL; - } else { - Constraint* const constraint = solver->MakeIsLessOrEqualCstCt( - solver->MakeScalProd(vars, coeffs), rhs, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractIntLinNe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - AddConstraint(solver, ct, solver->MakeNonEquality(left, right)); - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - AddConstraint( - solver, ct, - solver->MakeNonEquality(solver->MakeScalProd(vars, coeffs), rhs)); - } -} - -void ExtractIntLinNeReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ExtractLinAsShort(data, ct)) { - IntExpr* left = nullptr; - IntExpr* right = nullptr; - ParseShortIntLin(data, ct, &left, &right); - if (ct->target_variable != nullptr) { - IntVar* const boolvar = solver->MakeIsDifferentVar(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - Constraint* const constraint = - solver->MakeIsDifferentCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } else { - std::vector vars; - std::vector coeffs; - int64 rhs = 0; - ParseLongIntLin(data, ct, &vars, &coeffs, &rhs); - if (ct->target_variable != nullptr) { - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - IntVar* const boolvar = solver->MakeBoolVar(); - PostIsBooleanSumDifferent(data->Sat(), solver, vars, rhs, boolvar); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntVar* const boolvar = solver->MakeIsDifferentCstVar( - solver->MakeScalProd(vars, coeffs), rhs); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } else { - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[3])->Var(); - if (AreAllBooleans(vars) && AreAllOnes(coeffs)) { - PostIsBooleanSumDifferent(data->Sat(), solver, vars, rhs, boolvar); - } else { - Constraint* const constraint = solver->MakeIsDifferentCstCt( - solver->MakeScalProd(vars, coeffs), rhs, boolvar); - AddConstraint(solver, ct, constraint); - } - } - } -} - -void ExtractIntMax(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeMax(left, right); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeMax(left, right), target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntMin(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeMin(left, right); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeMin(left, right), target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntMinus(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeDifference(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeDifference(left, right), target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntMod(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->target_variable != nullptr) { - if (!ct->arguments[1].HasOneValue()) { - IntExpr* const mod = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = solver->MakeModulo(left, mod); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - const int64 mod = ct->arguments[1].Value(); - IntExpr* const target = solver->MakeModulo(left, mod); - FZVLOG << " - creating " << ct->arguments[2].DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } - } else if (ct->arguments[2].HasOneValue()) { - const int64 target = ct->arguments[2].Value(); - if (!ct->arguments[1].HasOneValue()) { - IntExpr* const mod = data->GetOrCreateExpression(ct->arguments[1]); - Constraint* const constraint = - MakeFixedModulo(solver, left->Var(), mod->Var(), target); - AddConstraint(solver, ct, constraint); - } else { - const int64 mod = ct->arguments[1].Value(); - Constraint* constraint = nullptr; - if (mod == 2) { - switch (target) { - case 0: { - constraint = MakeVariableEven(solver, left->Var()); - break; - } - case 1: { - constraint = MakeVariableOdd(solver, left->Var()); - break; - } - default: { - constraint = solver->MakeFalseConstraint(); - break; - } - } - } else { - constraint = - solver->MakeEquality(solver->MakeModulo(left, mod), target); - } - AddConstraint(solver, ct, constraint); - } - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - if (!ct->arguments[1].HasOneValue()) { - IntExpr* const mod = data->GetOrCreateExpression(ct->arguments[1]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeModulo(left, mod), target); - AddConstraint(solver, ct, constraint); - } else { - const int64 mod = ct->arguments[1].Value(); - Constraint* constraint = nullptr; - constraint = solver->MakeEquality(solver->MakeModulo(left, mod), target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractIntNe(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - if (ct->arguments[0].type == fz::Argument::INT_VAR_REF) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (FLAGS_fz_use_sat && AddBoolNot(data->Sat(), left, right)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - AddConstraint(s, ct, s->MakeNonEquality(left, right)); - } - } else { - const int64 right = ct->arguments[1].Value(); - AddConstraint(s, ct, s->MakeNonEquality(left, right)); - } - } else { - const int64 left = ct->arguments[0].Value(); - if (ct->arguments[1].type == fz::Argument::INT_VAR_REF) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - AddConstraint(s, ct, s->MakeNonEquality(right, left)); - } else { - const int64 right = ct->arguments[1].Value(); - if (left == right) { - AddConstraint(s, ct, s->MakeFalseConstraint()); - } - } - } -} - -void ExtractIntNeReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->target_variable != nullptr) { - CHECK_EQ(ct->target_variable, ct->arguments[2].Var()); - if (ct->arguments[1].HasOneValue()) { - IntVar* const boolvar = - solver->MakeIsDifferentCstVar(left, ct->arguments[1].Value()); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } else { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntVar* tmp_var = nullptr; - bool tmp_neg = false; - bool success = false; - if (FLAGS_fz_use_sat && solver->IsBooleanVar(left, &tmp_var, &tmp_neg) && - solver->IsBooleanVar(right, &tmp_var, &tmp_neg)) { - // Try to post to sat. - IntVar* const boolvar = solver->MakeBoolVar(); - if (AddIntNeReif(data->Sat(), left, right, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - success = true; - } - } - if (!success) { - IntVar* const boolvar = solver->MakeIsDifferentVar( - left, data->GetOrCreateExpression(ct->arguments[1])); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << boolvar->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, boolvar); - } - } - } else { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1])->Var(); - IntVar* const boolvar = - data->GetOrCreateExpression(ct->arguments[2])->Var(); - if (FLAGS_fz_use_sat && AddIntEqReif(data->Sat(), left, right, boolvar)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeIsDifferentCt(left, right, boolvar); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractIntNegate(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeOpposite(left); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeOpposite(left), target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntPlus(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (!ct->arguments[0].variables.empty() && - ct->target_variable == ct->arguments[0].variables[0]) { - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - IntExpr* const left = solver->MakeDifference(target, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << left->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, left); - } else if (!ct->arguments[1].variables.empty() && - ct->target_variable == ct->arguments[1].variables[0]) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - IntExpr* const right = solver->MakeDifference(target, left); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << right->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, right); - } else if (!ct->arguments[2].variables.empty() && - ct->target_variable == ct->arguments[2].variables[0]) { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = solver->MakeSum(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - Constraint* const constraint = - solver->MakeEquality(solver->MakeSum(left, right), target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractIntTimes(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const left = data->GetOrCreateExpression(ct->arguments[0]); - IntExpr* const right = data->GetOrCreateExpression(ct->arguments[1]); - if (ct->target_variable != nullptr) { - IntExpr* const target = solver->MakeProd(left, right); - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntExpr* const target = data->GetOrCreateExpression(ct->arguments[2]); - if (FLAGS_fz_use_sat && AddBoolAndEqVar(data->Sat(), left, right, target)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeEquality(solver->MakeProd(left, right), target); - AddConstraint(solver, ct, constraint); - } - } -} - -void ExtractInverse(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector left; - // Account for 1 based arrays. - left.push_back(solver->MakeIntConst(0)); - std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - left.insert(left.end(), tmp_vars.begin(), tmp_vars.end()); - - std::vector right; - // Account for 1 based arrays. - right.push_back(solver->MakeIntConst(0)); - tmp_vars = data->GetOrCreateVariableArray(ct->arguments[1]); - right.insert(right.end(), tmp_vars.begin(), tmp_vars.end()); - - Constraint* const constraint = - solver->MakeInversePermutationConstraint(left, right); - AddConstraint(solver, ct, constraint); -} - -void ExtractLexLessInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector left = data->GetOrCreateVariableArray(ct->arguments[0]); - std::vector right = data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeLexicalLess(left, right); - AddConstraint(solver, ct, constraint); -} - -void ExtractLexLesseqInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - std::vector left = data->GetOrCreateVariableArray(ct->arguments[0]); - std::vector right = data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeLexicalLessOrEqual(left, right); - AddConstraint(solver, ct, constraint); -} - -void ExtractMaximumArgInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - IntVar* const index = data->GetOrCreateExpression(ct->arguments[1])->Var(); - Constraint* const constraint = - solver->MakeIndexOfFirstMaxValueConstraint(index, variables); - AddConstraint(solver, ct, constraint); -} - -void ExtractMaximumInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntVar* const target = data->GetOrCreateExpression(ct->arguments[0])->Var(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeMaxEquality(variables, target); - AddConstraint(solver, ct, constraint); -} - -void ExtractMinimumArgInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - IntVar* const index = data->GetOrCreateExpression(ct->arguments[1])->Var(); - Constraint* const constraint = - solver->MakeIndexOfFirstMinValueConstraint(index, variables); - AddConstraint(solver, ct, constraint); -} - -void ExtractMinimumInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - if (ct->target_variable != nullptr && ct->arguments[1].variables.size() < 3) { - IntExpr* target = nullptr; - switch (ct->arguments[1].variables.size()) { - case 0: { - target = solver->MakeIntConst(0); - break; - } - case 1: { - target = data->Extract(ct->arguments[1].variables[0]); - break; - } - case 2: { - IntExpr* const e0 = data->Extract(ct->arguments[1].variables[0]); - IntExpr* const e1 = data->Extract(ct->arguments[1].variables[1]); - target = solver->MakeMin(e0, e1); - break; - } - default: { - target = - solver->MakeMin(data->GetOrCreateVariableArray(ct->arguments[1])); - break; - } - } - FZVLOG << " - creating " << ct->target_variable->DebugString() - << " := " << target->DebugString() << FZENDL; - data->SetExtracted(ct->target_variable, target); - } else { - IntVar* const target = data->GetOrCreateExpression(ct->arguments[0])->Var(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeMinEquality(variables, target); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractNvalue(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[1]); - - int64 lb = kint64max; - int64 ub = kint64min; - for (IntVar* const var : vars) { - lb = std::min(lb, var->Min()); - ub = std::max(ub, var->Max()); - } - - int csize = ub - lb + 1; - int64 always_true_cards = 0; - std::vector cards; - for (int b = 0; b < csize; ++b) { - const int value = lb + b; - std::vector contributors; - bool always_true = false; - for (IntVar* const var : vars) { - if (var->Contains(value)) { - if (var->Bound()) { - always_true = true; - break; - } else { - contributors.push_back(var->IsEqual(value)); - } - } - } - if (always_true) { - always_true_cards++; - } else if (contributors.size() == 1) { - cards.push_back(contributors.back()); - } else if (contributors.size() > 1) { - IntVar* const contribution = solver->MakeBoolVar(); - if (FLAGS_fz_use_sat && - AddBoolOrArrayEqVar(data->Sat(), contributors, contribution)) { - FZVLOG << " - posted to sat" << FZENDL; - } else { - Constraint* const constraint = - solver->MakeMaxEquality(contributors, contribution); - AddConstraint(solver, ct, constraint); - } - cards.push_back(contribution); - } - } - if (ct->arguments[0].HasOneValue()) { - const int64 card = ct->arguments[0].Value() - always_true_cards; - PostBooleanSumInRange(data->Sat(), solver, cards, card, card); - } else { - IntVar* const card = data->GetOrCreateExpression(ct->arguments[0])->Var(); - Constraint* const constraint = solver->MakeSumEquality( - cards, solver->MakeSum(card, -always_true_cards)->Var()); - AddConstraint(solver, ct, constraint); - } -} - -void ExtractRegular(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const int64 num_states = ct->arguments[1].Value(); - const int64 num_values = ct->arguments[2].Value(); - - const std::vector& array_transitions = ct->arguments[3].values; - IntTupleSet tuples(3); - int count = 0; - for (int64 q = 1; q <= num_states; ++q) { - for (int64 s = 1; s <= num_values; ++s) { - const int64 next = array_transitions[count++]; - if (next != 0) { - tuples.Insert3(q, s, next); - } - } - } - - const int64 initial_state = ct->arguments[4].Value(); - - std::vector final_states; - switch (ct->arguments[5].type) { - case fz::Argument::INT_VALUE: { - final_states.push_back(ct->arguments[5].values[0]); - break; - } - case fz::Argument::INT_INTERVAL: { - for (int v = ct->arguments[5].values[0]; v <= ct->arguments[5].values[1]; - ++v) { - final_states.push_back(v); - } - break; - } - case fz::Argument::INT_LIST: { - final_states = ct->arguments[5].values; - break; - } - default: { - LOG(FATAL) << "Wrong constraint " << ct->DebugString(); - } - } - Constraint* const constraint = solver->MakeTransitionConstraint( - variables, tuples, initial_state, final_states); - AddConstraint(solver, ct, constraint); -} - -void ExtractRegularNfa(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const int64 num_states = ct->arguments[1].Value(); - const int64 num_values = ct->arguments[2].Value(); - - const std::vector& array_transitions = ct->arguments[3].domains; - IntTupleSet tuples(3); - int count = 0; - for (int64 q = 1; q <= num_states; ++q) { - for (int64 s = 1; s <= num_values; ++s) { - const fz::Domain& next = array_transitions[count++]; - if (next.is_interval) { - for (int64 v = next.values[0]; v <= next.values[1]; ++v) { - if (v != 0) { - tuples.Insert3(q, s, v); - } - } - } else { - for (int64 v : next.values) { - if (v != 0) { - tuples.Insert3(q, s, v); - } - } - } - } - } - - const int64 initial_state = ct->arguments[4].Value(); - - std::vector final_states; - switch (ct->arguments[5].type) { - case fz::Argument::INT_VALUE: { - final_states.push_back(ct->arguments[5].values[0]); - break; - } - case fz::Argument::INT_INTERVAL: { - for (int v = ct->arguments[5].values[0]; v <= ct->arguments[5].values[1]; - ++v) { - final_states.push_back(v); - } - break; - } - case fz::Argument::INT_LIST: { - final_states = ct->arguments[5].values; - break; - } - default: { - LOG(FATAL) << "Wrong constraint " << ct->DebugString(); - } - } - Constraint* const constraint = solver->MakeTransitionConstraint( - variables, tuples, initial_state, final_states); - AddConstraint(solver, ct, constraint); -} - -void ExtractSetIn(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const expr = data->GetOrCreateExpression(ct->arguments[0]); - const fz::Argument& arg = ct->arguments[1]; - switch (arg.type) { - case fz::Argument::INT_VALUE: { - Constraint* const constraint = solver->MakeEquality(expr, arg.values[0]); - AddConstraint(solver, ct, constraint); - break; - } - case fz::Argument::INT_INTERVAL: { - if (expr->Min() < arg.values[0] || expr->Max() > arg.values[1]) { - Constraint* const constraint = - solver->MakeBetweenCt(expr, arg.values[0], arg.values[1]); - AddConstraint(solver, ct, constraint); - } - break; - } - case fz::Argument::INT_LIST: { - Constraint* const constraint = solver->MakeMemberCt(expr, arg.values); - AddConstraint(solver, ct, constraint); - break; - } - default: { - LOG(FATAL) << "Invalid constraint " << ct->DebugString(); - } - } -} - -void ExtractSetNotIn(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const expr = data->GetOrCreateExpression(ct->arguments[0]); - const fz::Argument& arg = ct->arguments[1]; - switch (arg.type) { - case fz::Argument::INT_VALUE: { - Constraint* const constraint = - solver->MakeNonEquality(expr, arg.values[0]); - AddConstraint(solver, ct, constraint); - break; - } - case fz::Argument::INT_INTERVAL: { - if (expr->Min() < arg.values[0] || expr->Max() > arg.values[1]) { - Constraint* const constraint = - solver->MakeNotBetweenCt(expr, arg.values[0], arg.values[1]); - AddConstraint(solver, ct, constraint); - } - break; - } - case fz::Argument::INT_LIST: { - Constraint* const constraint = solver->MakeNotMemberCt(expr, arg.values); - AddConstraint(solver, ct, constraint); - break; - } - default: { - LOG(FATAL) << "Invalid constraint " << ct->DebugString(); - } - } -} - -void ExtractSetInReif(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - IntExpr* const expr = data->GetOrCreateExpression(ct->arguments[0]); - IntVar* const target = data->GetOrCreateExpression(ct->arguments[2])->Var(); - const fz::Argument& arg = ct->arguments[1]; - switch (arg.type) { - case fz::Argument::INT_VALUE: { - Constraint* const constraint = - solver->MakeIsEqualCstCt(expr, arg.values[0], target); - AddConstraint(solver, ct, constraint); - break; - } - case fz::Argument::INT_INTERVAL: { - if (expr->Min() < arg.values[0] || expr->Max() > arg.values[1]) { - Constraint* const constraint = - solver->MakeIsBetweenCt(expr, arg.values[0], arg.values[1], target); - AddConstraint(solver, ct, constraint); - } else { - Constraint* const constraint = solver->MakeEquality(target, 1); - AddConstraint(solver, ct, constraint); - } - break; - } - case fz::Argument::INT_LIST: { - Constraint* const constraint = - solver->MakeIsMemberCt(expr, arg.values, target); - AddConstraint(solver, ct, constraint); - break; - } - default: { - LOG(FATAL) << "Invalid constraint " << ct->DebugString(); - } - } -} - -void ExtractSlidingSum(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const int64 low = ct->arguments[0].Value(); - const int64 up = ct->arguments[1].Value(); - const int64 seq = ct->arguments[2].Value(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[3]); - for (int i = 0; i < variables.size() - seq; ++i) { - std::vector tmp(seq); - for (int k = 0; k < seq; ++k) { - tmp[k] = variables[i + k]; - } - IntVar* const sum_var = solver->MakeSum(tmp)->Var(); - sum_var->SetRange(low, up); - } -} - -void ExtractSort(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector left = - data->GetOrCreateVariableArray(ct->arguments[0]); - const std::vector right = - data->GetOrCreateVariableArray(ct->arguments[1]); - Constraint* const constraint = solver->MakeSortingConstraint(left, right); - AddConstraint(solver, ct, constraint); -} - -void ExtractSubCircuit(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector tmp_vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - const int size = tmp_vars.size(); - bool found_zero = false; - bool found_size = false; - for (IntVar* const var : tmp_vars) { - if (var->Min() == 0) { - found_zero = true; - } - if (var->Max() == size) { - found_size = true; - } - } - std::vector variables; - if (found_zero && !found_size) { // Variables values are 0 based. - variables = tmp_vars; - } else { // Variables values are 1 based. - variables.resize(size); - for (int i = 0; i < size; ++i) { - // Create variables. Account for 1-based array indexing. - variables[i] = solver->MakeSum(tmp_vars[i], -1)->Var(); - } - } - Constraint* const constraint = solver->MakeSubCircuit(variables); - AddConstraint(solver, ct, constraint); -} - -void ExtractTableInt(fz::SolverData* data, fz::Constraint* ct) { - Solver* const solver = data->solver(); - const std::vector variables = - data->GetOrCreateVariableArray(ct->arguments[0]); - const int size = variables.size(); - IntTupleSet tuples(size); - const std::vector& t = ct->arguments[1].values; - const int t_size = t.size(); - DCHECK_EQ(0, t_size % size); - const int num_tuples = t_size / size; - std::vector one_tuple(size); - for (int tuple_index = 0; tuple_index < num_tuples; ++tuple_index) { - for (int var_index = 0; var_index < size; ++var_index) { - one_tuple[var_index] = t[tuple_index * size + var_index]; - } - tuples.Insert(one_tuple); - } - Constraint* const constraint = - solver->MakeAllowedAssignments(variables, tuples); - AddConstraint(solver, ct, constraint); -} - -void ExtractSymmetricAllDifferent(fz::SolverData* data, fz::Constraint* ct) { - Solver* const s = data->solver(); - const std::vector vars = - data->GetOrCreateVariableArray(ct->arguments[0]); - Constraint* const constraint = - s->MakeInversePermutationConstraint(vars, vars); - AddConstraint(s, ct, constraint); -} -} // namespace - -namespace fz { -void ExtractConstraint(SolverData* data, Constraint* ct) { - FZVLOG << "Extracting " << ct->DebugString() << std::endl; - const std::string& type = ct->type; - if (type == "all_different_int") { - ExtractAllDifferentInt(data, ct); - } else if (type == "alldifferent_except_0") { - ExtractAlldifferentExcept0(data, ct); - } else if (type == "among") { - ExtractAmong(data, ct); - } else if (type == "array_bool_and") { - ExtractArrayBoolAnd(data, ct); - } else if (type == "array_bool_element") { - ExtractArrayIntElement(data, ct); - } else if (type == "array_bool_or") { - ExtractArrayBoolOr(data, ct); - } else if (type == "array_bool_xor") { - ExtractArrayBoolXor(data, ct); - } else if (type == "array_int_element") { - ExtractArrayIntElement(data, ct); - } else if (type == "array_int_element_nonshifted") { - ExtractArrayIntElementNonShifted(data, ct); - } else if (type == "array_var_bool_element") { - ExtractArrayVarIntElement(data, ct); - } else if (type == "array_var_int_element") { - ExtractArrayVarIntElement(data, ct); - } else if (type == "at_most_int") { - ExtractAtMostInt(data, ct); - } else if (type == "bool_and") { - ExtractBoolAnd(data, ct); - } else if (type == "bool_clause") { - ExtractBoolClause(data, ct); - } else if (type == "bool_eq" || type == "bool2int") { - ExtractIntEq(data, ct); - } else if (type == "bool_eq_reif") { - ExtractIntEqReif(data, ct); - } else if (type == "bool_ge") { - ExtractIntGe(data, ct); - } else if (type == "bool_ge_reif") { - ExtractIntGeReif(data, ct); - } else if (type == "bool_gt") { - ExtractIntGt(data, ct); - } else if (type == "bool_gt_reif") { - ExtractIntGtReif(data, ct); - } else if (type == "bool_le") { - ExtractIntLe(data, ct); - } else if (type == "bool_le_reif") { - ExtractIntLeReif(data, ct); - } else if (type == "bool_left_imp") { - ExtractIntLe(data, ct); - } else if (type == "bool_lin_eq") { - ExtractIntLinEq(data, ct); - } else if (type == "bool_lin_le") { - ExtractIntLinLe(data, ct); - } else if (type == "bool_lt") { - ExtractIntLt(data, ct); - } else if (type == "bool_lt_reif") { - ExtractIntLtReif(data, ct); - } else if (type == "bool_ne") { - ExtractIntNe(data, ct); - } else if (type == "bool_ne_reif") { - ExtractIntNeReif(data, ct); - } else if (type == "bool_not") { - ExtractBoolNot(data, ct); - } else if (type == "bool_or") { - ExtractBoolOr(data, ct); - } else if (type == "bool_right_imp") { - ExtractIntGe(data, ct); - } else if (type == "bool_xor") { - ExtractBoolXor(data, ct); - } else if (type == "circuit") { - ExtractCircuit(data, ct); - } else if (type == "count_eq" || type == "count") { - ExtractCountEq(data, ct); - } else if (type == "count_geq") { - ExtractCountGeq(data, ct); - } else if (type == "count_gt") { - ExtractCountGt(data, ct); - } else if (type == "count_leq") { - ExtractCountLeq(data, ct); - } else if (type == "count_lt") { - ExtractCountLt(data, ct); - } else if (type == "count_neq") { - ExtractCountNeq(data, ct); - } else if (type == "count_reif") { - ExtractCountReif(data, ct); - } else if (type == "cumulative" || type == "var_cumulative" || - type == "variable_cumulative" || type == "fixed_cumulative") { - ExtractCumulative(data, ct); - } else if (type == "diffn") { - ExtractDiffn(data, ct); - } else if (type == "diffn_k_with_sizes") { - ExtractDiffnK(data, ct); - } else if (type == "diffn_nonstrict") { - ExtractDiffnNonStrict(data, ct); - } else if (type == "diffn_nonstrict_k_with_sizes") { - ExtractDiffnNonStrictK(data, ct); - } else if (type == "disjunctive") { - ExtractDisjunctive(data, ct); - } else if (type == "disjunctive_strict") { - ExtractDisjunctiveStrict(data, ct); - } else if (type == "false_constraint") { - ExtractFalseConstraint(data, ct); - } else if (type == "global_cardinality") { - ExtractGlobalCardinality(data, ct); - } else if (type == "global_cardinality_closed") { - ExtractGlobalCardinalityClosed(data, ct); - } else if (type == "global_cardinality_low_up") { - ExtractGlobalCardinalityLowUp(data, ct); - } else if (type == "global_cardinality_low_up_closed") { - ExtractGlobalCardinalityLowUpClosed(data, ct); - } else if (type == "global_cardinality_old") { - ExtractGlobalCardinalityOld(data, ct); - } else if (type == "int_abs") { - ExtractIntAbs(data, ct); - } else if (type == "int_div") { - ExtractIntDiv(data, ct); - } else if (type == "int_eq") { - ExtractIntEq(data, ct); - } else if (type == "int_eq_reif") { - ExtractIntEqReif(data, ct); - } else if (type == "int_ge") { - ExtractIntGe(data, ct); - } else if (type == "int_ge_reif") { - ExtractIntGeReif(data, ct); - } else if (type == "int_gt") { - ExtractIntGt(data, ct); - } else if (type == "int_gt_reif") { - ExtractIntGtReif(data, ct); - } else if (type == "int_le") { - ExtractIntLe(data, ct); - } else if (type == "int_le_reif") { - ExtractIntLeReif(data, ct); - } else if (type == "int_lin_eq") { - ExtractIntLinEq(data, ct); - } else if (type == "int_lin_eq_reif") { - ExtractIntLinEqReif(data, ct); - } else if (type == "int_lin_ge") { - ExtractIntLinGe(data, ct); - } else if (type == "int_lin_ge_reif") { - ExtractIntLinGeReif(data, ct); - } else if (type == "int_lin_le") { - ExtractIntLinLe(data, ct); - } else if (type == "int_lin_le_reif") { - ExtractIntLinLeReif(data, ct); - } else if (type == "int_lin_ne") { - ExtractIntLinNe(data, ct); - } else if (type == "int_lin_ne_reif") { - ExtractIntLinNeReif(data, ct); - } else if (type == "int_lt") { - ExtractIntLt(data, ct); - } else if (type == "int_lt_reif") { - ExtractIntLtReif(data, ct); - } else if (type == "int_max") { - ExtractIntMax(data, ct); - } else if (type == "int_min") { - ExtractIntMin(data, ct); - } else if (type == "int_minus") { - ExtractIntMinus(data, ct); - } else if (type == "int_mod") { - ExtractIntMod(data, ct); - } else if (type == "int_ne") { - ExtractIntNe(data, ct); - } else if (type == "int_ne_reif") { - ExtractIntNeReif(data, ct); - } else if (type == "int_negate") { - ExtractIntNegate(data, ct); - } else if (type == "int_plus") { - ExtractIntPlus(data, ct); - } else if (type == "int_times") { - ExtractIntTimes(data, ct); - } else if (type == "inverse") { - ExtractInverse(data, ct); - } else if (type == "lex_less_bool" || type == "lex_less_int") { - ExtractLexLessInt(data, ct); - } else if (type == "lex_lesseq_bool" || type == "lex_lesseq_int") { - ExtractLexLesseqInt(data, ct); - } else if (type == "maximum_arg_int") { - ExtractMaximumArgInt(data, ct); - } else if (type == "maximum_int" || type == "array_int_maximum") { - ExtractMaximumInt(data, ct); - } else if (type == "minimum_arg_int") { - ExtractMinimumArgInt(data, ct); - } else if (type == "minimum_int" || type == "array_int_minimum") { - ExtractMinimumInt(data, ct); - } else if (type == "nvalue") { - ExtractNvalue(data, ct); - } else if (type == "regular") { - ExtractRegular(data, ct); - } else if (type == "regular_nfa") { - ExtractRegularNfa(data, ct); - } else if (type == "set_in" || type == "int_in") { - ExtractSetIn(data, ct); - } else if (type == "set_not_in" || type == "int_not_in") { - ExtractSetNotIn(data, ct); - } else if (type == "set_in_reif") { - ExtractSetInReif(data, ct); - } else if (type == "sliding_sum") { - ExtractSlidingSum(data, ct); - } else if (type == "sort") { - ExtractSort(data, ct); - } else if (type == "subcircuit") { - ExtractSubCircuit(data, ct); - } else if (type == "symmetric_all_different") { - ExtractSymmetricAllDifferent(data, ct); - } else if (type == "table_bool" || type == "table_int") { - ExtractTableInt(data, ct); - } else if (type == "true_constraint") { - // Nothing to do. - } else { - LOG(FATAL) << "Unknown predicate: " << type; - } -} -} // namespace fz -} // namespace operations_research diff --git a/ortools/flatzinc/constraints.h b/ortools/flatzinc/constraints.h deleted file mode 100644 index 8b5c77137a..0000000000 --- a/ortools/flatzinc/constraints.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_CONSTRAINTS_H_ -#define OR_TOOLS_FLATZINC_CONSTRAINTS_H_ - -// This files provides all the extraction methods to transform flatzinc -// constraints into CP constraints. - -#include "ortools/flatzinc/model.h" -#include "ortools/flatzinc/solver_data.h" - -namespace operations_research { -namespace fz { - -void ExtractConstraint(SolverData* data, Constraint* ct); - -} // namespace fz -} // namespace operations_research - -#endif // OR_TOOLS_FLATZINC_CONSTRAINTS_H_ diff --git a/ortools/flatzinc/flatzinc_constraints.cc b/ortools/flatzinc/flatzinc_constraints.cc deleted file mode 100644 index a88cca04bb..0000000000 --- a/ortools/flatzinc/flatzinc_constraints.cc +++ /dev/null @@ -1,928 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/flatzinc_constraints.h" - -#include "absl/container/flat_hash_set.h" -#include "absl/strings/str_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/constraint_solver/constraint_solveri.h" -#include "ortools/flatzinc/logging.h" -#include "ortools/util/string_array.h" - -DECLARE_bool(cp_trace_search); -DECLARE_bool(cp_trace_propagation); - -namespace operations_research { -namespace { -class BooleanSumOdd : public Constraint { - public: - BooleanSumOdd(Solver* const s, const std::vector& vars) - : Constraint(s), - vars_(vars), - num_possible_true_vars_(0), - num_always_true_vars_(0) {} - - ~BooleanSumOdd() override {} - - void Post() override { - for (int i = 0; i < vars_.size(); ++i) { - if (!vars_[i]->Bound()) { - Demon* const u = MakeConstraintDemon1( - solver(), this, &BooleanSumOdd::Update, "Update", i); - vars_[i]->WhenBound(u); - } - } - } - - void InitialPropagate() override { - int num_always_true = 0; - int num_possible_true = 0; - int possible_true_index = -1; - for (int i = 0; i < vars_.size(); ++i) { - const IntVar* const var = vars_[i]; - if (var->Min() == 1) { - num_always_true++; - num_possible_true++; - } else if (var->Max() == 1) { - num_possible_true++; - possible_true_index = i; - } - } - if (num_always_true == num_possible_true && num_possible_true % 2 == 0) { - solver()->Fail(); - } else if (num_possible_true == num_always_true + 1) { - DCHECK_NE(-1, possible_true_index); - if (num_possible_true % 2 == 1) { - vars_[possible_true_index]->SetMin(1); - } else { - vars_[possible_true_index]->SetMax(0); - } - } - num_possible_true_vars_.SetValue(solver(), num_possible_true); - num_always_true_vars_.SetValue(solver(), num_always_true); - } - - void Update(int index) { - DCHECK(vars_[index]->Bound()); - const int64 value = vars_[index]->Min(); // Faster than Value(). - if (value == 0) { - num_possible_true_vars_.Decr(solver()); - } else { - DCHECK_EQ(1, value); - num_always_true_vars_.Incr(solver()); - } - if (num_always_true_vars_.Value() == num_possible_true_vars_.Value() && - num_possible_true_vars_.Value() % 2 == 0) { - solver()->Fail(); - } else if (num_possible_true_vars_.Value() == - num_always_true_vars_.Value() + 1) { - int possible_true_index = -1; - for (int i = 0; i < vars_.size(); ++i) { - if (!vars_[i]->Bound()) { - possible_true_index = i; - break; - } - } - if (possible_true_index != -1) { - if (num_possible_true_vars_.Value() % 2 == 1) { - vars_[possible_true_index]->SetMin(1); - } else { - vars_[possible_true_index]->SetMax(0); - } - } - } - } - - std::string DebugString() const override { - return absl::StrFormat("BooleanSumOdd([%s])", - JoinDebugStringPtr(vars_, ", ")); - } - - void Accept(ModelVisitor* const visitor) const override { - visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this); - visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, - vars_); - visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); - } - - private: - const std::vector vars_; - NumericalRev num_possible_true_vars_; - NumericalRev num_always_true_vars_; -}; - -class FixedModulo : public Constraint { - public: - FixedModulo(Solver* const s, IntVar* x, IntVar* const m, int64 r) - : Constraint(s), var_(x), mod_(m), residual_(r) {} - - ~FixedModulo() override {} - - void Post() override { - Demon* const d = solver()->MakeConstraintInitialPropagateCallback(this); - var_->WhenRange(d); - mod_->WhenBound(d); - } - - void InitialPropagate() override { - if (mod_->Bound()) { - const int64 d = std::abs(mod_->Min()); - if (d == 0) { - solver()->Fail(); - } else { - const int64 emin = var_->Min(); - const int64 emax = var_->Max(); - const int64 new_min = PosIntDivUp(emin - residual_, d) * d + residual_; - const int64 new_max = - PosIntDivDown(emax - residual_, d) * d + residual_; - var_->SetRange(new_min, new_max); - } - } - } - - std::string DebugString() const override { - return absl::StrFormat("(%s %% %s == %d)", var_->DebugString(), - mod_->DebugString(), residual_); - } - - private: - IntVar* const var_; - IntVar* const mod_; - const int64 residual_; -}; - -class VariableParity : public Constraint { - public: - VariableParity(Solver* const s, IntVar* const var, bool odd) - : Constraint(s), var_(var), odd_(odd) {} - - ~VariableParity() override {} - - void Post() override { - if (!var_->Bound()) { - Demon* const u = solver()->MakeConstraintInitialPropagateCallback(this); - var_->WhenRange(u); - } - } - - void InitialPropagate() override { - const int64 vmax = var_->Max(); - const int64 vmin = var_->Min(); - int64 new_vmax = vmax; - int64 new_vmin = vmin; - if (odd_) { - if (vmax % 2 == 0) { - new_vmax--; - } - if (vmin % 2 == 0) { - new_vmin++; - } - } else { - if (vmax % 2 == 1) { - new_vmax--; - } - if (vmin % 2 == 1) { - new_vmin++; - } - } - var_->SetRange(new_vmin, new_vmax); - } - - std::string DebugString() const override { - return absl::StrFormat("VarParity(%s, %d)", var_->DebugString(), odd_); - } - - void Accept(ModelVisitor* const visitor) const override { - visitor->BeginVisitConstraint("VarParity", this); - visitor->VisitIntegerExpressionArgument(ModelVisitor::kVariableArgument, - var_); - visitor->VisitIntegerArgument(ModelVisitor::kValuesArgument, odd_); - visitor->EndVisitConstraint("VarParity", this); - } - - private: - IntVar* const var_; - const bool odd_; -}; - -class IsBooleanSumInRange : public Constraint { - public: - IsBooleanSumInRange(Solver* const s, const std::vector& vars, - int64 range_min, int64 range_max, IntVar* const target) - : Constraint(s), - vars_(vars), - range_min_(range_min), - range_max_(range_max), - target_(target), - num_possible_true_vars_(0), - num_always_true_vars_(0) {} - - ~IsBooleanSumInRange() override {} - - void Post() override { - for (int i = 0; i < vars_.size(); ++i) { - if (!vars_[i]->Bound()) { - Demon* const u = MakeConstraintDemon1( - solver(), this, &IsBooleanSumInRange::Update, "Update", i); - vars_[i]->WhenBound(u); - } - } - if (!target_->Bound()) { - Demon* const u = MakeConstraintDemon0( - solver(), this, &IsBooleanSumInRange::UpdateTarget, "UpdateTarget"); - target_->WhenBound(u); - } - } - - void InitialPropagate() override { - int num_always_true = 0; - int num_possible_true = 0; - for (int i = 0; i < vars_.size(); ++i) { - const IntVar* const var = vars_[i]; - if (var->Min() == 1) { - num_always_true++; - num_possible_true++; - } else if (var->Max() == 1) { - num_possible_true++; - } - } - num_possible_true_vars_.SetValue(solver(), num_possible_true); - num_always_true_vars_.SetValue(solver(), num_always_true); - UpdateTarget(); - } - - void UpdateTarget() { - if (num_always_true_vars_.Value() > range_max_ || - num_possible_true_vars_.Value() < range_min_) { - inactive_.Switch(solver()); - target_->SetValue(0); - } else if (num_always_true_vars_.Value() >= range_min_ && - num_possible_true_vars_.Value() <= range_max_) { - inactive_.Switch(solver()); - target_->SetValue(1); - } else if (target_->Min() == 1) { - if (num_possible_true_vars_.Value() == range_min_) { - PushAllUnboundToOne(); - } else if (num_always_true_vars_.Value() == range_max_) { - PushAllUnboundToZero(); - } - } else if (target_->Max() == 0) { - if (num_possible_true_vars_.Value() == range_max_ + 1 && - num_always_true_vars_.Value() >= range_min_) { - PushAllUnboundToOne(); - } else if (num_always_true_vars_.Value() == range_min_ - 1 && - num_possible_true_vars_.Value() <= range_max_) { - PushAllUnboundToZero(); - } - } - } - - void Update(int index) { - if (!inactive_.Switched()) { - DCHECK(vars_[index]->Bound()); - const int64 value = vars_[index]->Min(); // Faster than Value(). - if (value == 0) { - num_possible_true_vars_.Decr(solver()); - } else { - DCHECK_EQ(1, value); - num_always_true_vars_.Incr(solver()); - } - UpdateTarget(); - } - } - - std::string DebugString() const override { - return absl::StrFormat("Sum([%s]) in [%d..%d] == %s", - JoinDebugStringPtr(vars_, ", "), range_min_, - range_max_, target_->DebugString()); - } - - void Accept(ModelVisitor* const visitor) const override { - visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this); - visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, - vars_); - visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); - } - - private: - void PushAllUnboundToZero() { - inactive_.Switch(solver()); - int true_vars = 0; - for (int i = 0; i < vars_.size(); ++i) { - if (vars_[i]->Min() == 0) { - vars_[i]->SetValue(0); - } else { - true_vars++; - } - } - target_->SetValue(true_vars >= range_min_ && true_vars <= range_max_); - } - - void PushAllUnboundToOne() { - inactive_.Switch(solver()); - int true_vars = 0; - for (int i = 0; i < vars_.size(); ++i) { - if (vars_[i]->Max() == 1) { - vars_[i]->SetValue(1); - true_vars++; - } - } - target_->SetValue(true_vars >= range_min_ && true_vars <= range_max_); - } - - const std::vector vars_; - const int64 range_min_; - const int64 range_max_; - IntVar* const target_; - NumericalRev num_possible_true_vars_; - NumericalRev num_always_true_vars_; - RevSwitch inactive_; -}; - -class BooleanSumInRange : public Constraint { - public: - BooleanSumInRange(Solver* const s, const std::vector& vars, - int64 range_min, int64 range_max) - : Constraint(s), - vars_(vars), - range_min_(range_min), - range_max_(range_max), - num_possible_true_vars_(0), - num_always_true_vars_(0) {} - - ~BooleanSumInRange() override {} - - void Post() override { - for (int i = 0; i < vars_.size(); ++i) { - if (!vars_[i]->Bound()) { - Demon* const u = MakeConstraintDemon1( - solver(), this, &BooleanSumInRange::Update, "Update", i); - vars_[i]->WhenBound(u); - } - } - } - - void InitialPropagate() override { - int num_always_true = 0; - int num_possible_true = 0; - int possible_true_index = -1; - for (int i = 0; i < vars_.size(); ++i) { - const IntVar* const var = vars_[i]; - if (var->Min() == 1) { - num_always_true++; - num_possible_true++; - } else if (var->Max() == 1) { - num_possible_true++; - possible_true_index = i; - } - } - num_possible_true_vars_.SetValue(solver(), num_possible_true); - num_always_true_vars_.SetValue(solver(), num_always_true); - Check(); - } - - void Check() { - if (num_always_true_vars_.Value() > range_max_ || - num_possible_true_vars_.Value() < range_min_) { - solver()->Fail(); - } else if (num_always_true_vars_.Value() >= range_min_ && - num_possible_true_vars_.Value() <= range_max_) { - // Inhibit. - } else { - if (num_possible_true_vars_.Value() == range_min_) { - PushAllUnboundToOne(); - } else if (num_always_true_vars_.Value() == range_max_) { - PushAllUnboundToZero(); - } - } - } - - void Update(int index) { - DCHECK(vars_[index]->Bound()); - const int64 value = vars_[index]->Min(); // Faster than Value(). - if (value == 0) { - num_possible_true_vars_.Decr(solver()); - } else { - DCHECK_EQ(1, value); - num_always_true_vars_.Incr(solver()); - } - Check(); - } - - std::string DebugString() const override { - return absl::StrFormat("Sum([%s]) in [%d..%d]", - JoinDebugStringPtr(vars_, ", "), range_min_, - range_max_); - } - - void Accept(ModelVisitor* const visitor) const override { - visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this); - visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, - vars_); - visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this); - } - - private: - void PushAllUnboundToZero() { - for (int i = 0; i < vars_.size(); ++i) { - if (vars_[i]->Min() == 0) { - vars_[i]->SetValue(0); - } else { - } - } - } - - void PushAllUnboundToOne() { - for (int i = 0; i < vars_.size(); ++i) { - if (vars_[i]->Max() == 1) { - vars_[i]->SetValue(1); - } - } - } - - const std::vector vars_; - const int64 range_min_; - const int64 range_max_; - NumericalRev num_possible_true_vars_; - NumericalRev num_always_true_vars_; -}; - -// ----- Variable duration interval var ----- - -class StartVarDurationVarPerformedIntervalVar : public IntervalVar { - public: - StartVarDurationVarPerformedIntervalVar(Solver* const s, IntVar* const var, - IntVar* const duration, - const std::string& name); - ~StartVarDurationVarPerformedIntervalVar() override {} - - int64 StartMin() const override; - int64 StartMax() const override; - void SetStartMin(int64 m) override; - void SetStartMax(int64 m) override; - void SetStartRange(int64 mi, int64 ma) override; - int64 OldStartMin() const override { return start_->OldMin(); } - int64 OldStartMax() const override { return start_->OldMax(); } - void WhenStartRange(Demon* const d) override { start_->WhenRange(d); } - void WhenStartBound(Demon* const d) override { start_->WhenBound(d); } - - int64 DurationMin() const override; - int64 DurationMax() const override; - void SetDurationMin(int64 m) override; - void SetDurationMax(int64 m) override; - void SetDurationRange(int64 mi, int64 ma) override; - int64 OldDurationMin() const override { return duration_->Min(); } - int64 OldDurationMax() const override { return duration_->Max(); } - void WhenDurationRange(Demon* const d) override { duration_->WhenRange(d); } - void WhenDurationBound(Demon* const d) override { duration_->WhenBound(d); } - - int64 EndMin() const override; - int64 EndMax() const override; - void SetEndMin(int64 m) override; - void SetEndMax(int64 m) override; - void SetEndRange(int64 mi, int64 ma) override; - int64 OldEndMin() const override { return end_->OldMin(); } - int64 OldEndMax() const override { return end_->OldMax(); } - void WhenEndRange(Demon* const d) override { end_->WhenRange(d); } - void WhenEndBound(Demon* const d) override { end_->WhenBound(d); } - - bool MustBePerformed() const override; - bool MayBePerformed() const override; - void SetPerformed(bool val) override; - bool WasPerformedBound() const override { return true; } - void WhenPerformedBound(Demon* const d) override {} - std::string DebugString() const override; - - IntExpr* StartExpr() override { return start_; } - IntExpr* DurationExpr() override { return duration_; } - IntExpr* EndExpr() override { return end_; } - IntExpr* PerformedExpr() override { return solver()->MakeIntConst(1); } - IntExpr* SafeStartExpr(int64 unperformed_value) override { - return StartExpr(); - } - IntExpr* SafeDurationExpr(int64 unperformed_value) override { - return DurationExpr(); - } - IntExpr* SafeEndExpr(int64 unperformed_value) override { return EndExpr(); } - - void Accept(ModelVisitor* const visitor) const override { - visitor->VisitIntervalVariable(this, "", 0, nullptr); - } - - private: - IntVar* const start_; - IntVar* const duration_; - IntVar* const end_; -}; - -// TODO(user): Take care of overflows. -StartVarDurationVarPerformedIntervalVar:: - StartVarDurationVarPerformedIntervalVar(Solver* const s, IntVar* const var, - IntVar* const duration, - const std::string& name) - : IntervalVar(s, name), - start_(var), - duration_(duration), - end_(s->MakeSum(var, duration)->Var()) {} - -int64 StartVarDurationVarPerformedIntervalVar::StartMin() const { - return start_->Min(); -} - -int64 StartVarDurationVarPerformedIntervalVar::StartMax() const { - return start_->Max(); -} - -void StartVarDurationVarPerformedIntervalVar::SetStartMin(int64 m) { - start_->SetMin(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetStartMax(int64 m) { - start_->SetMax(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetStartRange(int64 mi, - int64 ma) { - start_->SetRange(mi, ma); -} - -int64 StartVarDurationVarPerformedIntervalVar::DurationMin() const { - return duration_->Min(); -} - -int64 StartVarDurationVarPerformedIntervalVar::DurationMax() const { - return duration_->Max(); -} - -void StartVarDurationVarPerformedIntervalVar::SetDurationMin(int64 m) { - duration_->SetMin(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetDurationMax(int64 m) { - duration_->SetMax(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetDurationRange(int64 mi, - int64 ma) { - duration_->SetRange(mi, ma); -} - -int64 StartVarDurationVarPerformedIntervalVar::EndMin() const { - return end_->Min(); -} - -int64 StartVarDurationVarPerformedIntervalVar::EndMax() const { - return end_->Max(); -} - -void StartVarDurationVarPerformedIntervalVar::SetEndMin(int64 m) { - end_->SetMin(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetEndMax(int64 m) { - end_->SetMax(m); -} - -void StartVarDurationVarPerformedIntervalVar::SetEndRange(int64 mi, int64 ma) { - end_->SetRange(mi, ma); -} - -bool StartVarDurationVarPerformedIntervalVar::MustBePerformed() const { - return true; -} - -bool StartVarDurationVarPerformedIntervalVar::MayBePerformed() const { - return true; -} - -void StartVarDurationVarPerformedIntervalVar::SetPerformed(bool val) { - if (!val) { - solver()->Fail(); - } -} - -std::string StartVarDurationVarPerformedIntervalVar::DebugString() const { - std::string out; - const std::string& var_name = name(); - if (!var_name.empty()) { - out = var_name + "(start = "; - } else { - out = "IntervalVar(start = "; - } - absl::StrAppendFormat(&out, "%s, duration = %s, performed = true)", - start_->DebugString(), duration_->DebugString()); - return out; -} - -// k - Diffn - -class KDiffn : public Constraint { - public: - KDiffn(Solver* const solver, const std::vector>& x, - const std::vector>& dx, bool strict) - : Constraint(solver), - x_(x), - dx_(dx), - strict_(strict), - num_boxes_(x.size()), - num_dims_(x[0].size()), - fail_stamp_(0) {} - - ~KDiffn() override {} - - void Post() override { - Solver* const s = solver(); - for (int box = 0; box < num_boxes_; ++box) { - Demon* const demon = MakeConstraintDemon1( - s, this, &KDiffn::OnBoxRangeChange, "OnBoxRangeChange", box); - for (int dim = 0; dim < num_dims_; ++dim) { - x_[box][dim]->WhenRange(demon); - dx_[box][dim]->WhenRange(demon); - } - } - delayed_demon_ = MakeDelayedConstraintDemon0(s, this, &KDiffn::PropagateAll, - "PropagateAll"); - } - - void InitialPropagate() override { - // All sizes should be > 0. - for (int box = 0; box < num_boxes_; ++box) { - for (int dim = 0; dim < num_dims_; ++dim) { - dx_[box][dim]->SetMin(1); - } - } - - // Force propagation on all boxes. - to_propagate_.clear(); - for (int i = 0; i < num_boxes_; i++) { - to_propagate_.insert(i); - } - PropagateAll(); - } - - std::string DebugString() const override { return "KDiffn()"; } - - void Accept(ModelVisitor* const visitor) const override { - visitor->BeginVisitConstraint(ModelVisitor::kDisjunctive, this); - visitor->EndVisitConstraint(ModelVisitor::kDisjunctive, this); - } - - private: - void PropagateAll() { - for (const int box : to_propagate_) { - FillNeighbors(box); - FailWhenEnergyIsTooLarge(box); - PushOverlappingBoxes(box); - } - to_propagate_.clear(); - fail_stamp_ = solver()->fail_stamp(); - } - - void OnBoxRangeChange(int box) { - if (solver()->fail_stamp() > fail_stamp_ && !to_propagate_.empty()) { - // We have failed in the last propagation and the to_propagate_ - // was not cleared. - fail_stamp_ = solver()->fail_stamp(); - to_propagate_.clear(); - } - to_propagate_.insert(box); - EnqueueDelayedDemon(delayed_demon_); - } - - bool CanBoxesOverlap(int box1, int box2) const { - for (int dim = 0; dim < num_dims_; ++dim) { - if (AreBoxedDisjointInOneDimensionForSure(dim, box1, box2)) { - return false; - } - } - return true; - } - - bool AreBoxedDisjointInOneDimensionForSure(int dim, int i, int j) const { - return (x_[i][dim]->Min() >= x_[j][dim]->Max() + dx_[j][dim]->Max()) || - (x_[j][dim]->Min() >= x_[i][dim]->Max() + dx_[i][dim]->Max()) || - (!strict_ && (dx_[i][dim]->Min() == 0 || dx_[j][dim]->Min() == 0)); - } - - // Fill neighbors_ with all boxes that can overlap the given box. - void FillNeighbors(int box) { - // TODO(user): We could maintain a non reversible list of - // neighbors and clean it after each failure. - neighbors_.clear(); - for (int other = 0; other < num_boxes_; ++other) { - if (other != box && CanBoxesOverlap(other, box)) { - neighbors_.push_back(other); - } - } - } - - // Fails if the minimum area of the given box plus the area of its neighbors - // (that must already be computed in neighbors_) is greater than the area of a - // bounding box that necessarily contains all these boxes. - void FailWhenEnergyIsTooLarge(int box) { - std::vector starts(num_dims_); - std::vector ends(num_dims_); - - int64 box_volume = 1; - for (int dim = 0; dim < num_dims_; ++dim) { - starts[dim] = x_[box][dim]->Min(); - ends[dim] = x_[box][dim]->Max() + dx_[box][dim]->Max(); - box_volume *= dx_[box][dim]->Min(); - } - int64 sum_of_volumes = box_volume; - - // TODO(user): Is there a better order, maybe sort by distance - // with the current box. - for (int i = 0; i < neighbors_.size(); ++i) { - const int other = neighbors_[i]; - int64 other_volume = 1; - int64 bounding_volume = 1; - for (int dim = 0; dim < num_dims_; ++dim) { - IntVar* const x = x_[other][dim]; - IntVar* const dx = dx_[other][dim]; - starts[dim] = std::min(starts[dim], x->Min()); - ends[dim] = std::max(ends[dim], x->Max() + dx->Max()); - other_volume *= dx->Min(); - bounding_volume *= ends[dim] - starts[dim]; - } - // Update sum of volumes. - sum_of_volumes += other_volume; - if (sum_of_volumes > bounding_volume) { - solver()->Fail(); - } - } - } - - // Changes the domain of all the neighbors of a given box (that must - // already be computed in neighbors_) so that they can't overlap the - // mandatory part of the given box. - void PushOverlappingBoxes(int box) { - for (int i = 0; i < neighbors_.size(); ++i) { - TryPushOneBox(box, neighbors_[i]); - } - } - - // Changes the domain of the two given box by excluding the value that - // make them overlap for sure. Note that this function is symmetric in - // the sense that its argument can be swapped for the same result. - void TryPushOneBox(int b1, int b2) { - int b1_after_b2 = -1; - int b2_after_b1 = -1; - bool already_inserted = false; - for (int dim = 0; dim < num_dims_; ++dim) { - IntVar* const x1 = x_[b1][dim]; - IntVar* const x2 = x_[b2][dim]; - IntVar* const dx1 = dx_[b1][dim]; - IntVar* const dx2 = dx_[b2][dim]; - DCHECK(strict_ || dx1->Min() > 0); - DCHECK(strict_ || dx2->Min() > 0); - if (x1->Min() + dx1->Min() <= x2->Max()) { - if (already_inserted) { // Too much freedom degrees, we can exit. - return; - } else { - already_inserted = true; - } - b2_after_b1 = dim; - } - if (x2->Min() + dx2->Min() <= x1->Max()) { - if (already_inserted) { // Too much freedom degrees, we can exit. - return; - } else { - already_inserted = true; - } - b1_after_b2 = dim; - } - } - if (b1_after_b2 == -1 && b2_after_b1 == -1) { - // Stuck in an overlapping position. We can fail. - solver()->Fail(); - } - // We verify the exclusion. - CHECK((b2_after_b1 == -1 && b1_after_b2 != -1) || - (b1_after_b2 == -1 && b2_after_b1 != -1)); - - if (b1_after_b2 != -1) { - // We need to push b1 after b2, and restrict b2 to be before b1. - IntVar* const x1 = x_[b1][b1_after_b2]; - IntVar* const x2 = x_[b2][b1_after_b2]; - IntVar* const dx2 = dx_[b2][b1_after_b2]; - x1->SetMin(x2->Min() + dx2->Min()); - x2->SetMax(x1->Max() - dx2->Min()); - dx2->SetMax(x1->Max() - x2->Min()); - } - - if (b2_after_b1 != -1) { - // We need to push b2 after b1, and restrict b1 to be before b2. - IntVar* const x1 = x_[b1][b2_after_b1]; - IntVar* const x2 = x_[b2][b2_after_b1]; - IntVar* const dx1 = dx_[b1][b2_after_b1]; - x2->SetMin(x1->Min() + dx1->Min()); - x1->SetMax(x2->Max() - dx1->Min()); - dx1->SetMax(x2->Max() - x1->Min()); - } - } - - std::vector> x_; - std::vector> dx_; - const bool strict_; - const int64 num_boxes_; - const int64 num_dims_; - Demon* delayed_demon_; - absl::flat_hash_set to_propagate_; - std::vector neighbors_; - uint64 fail_stamp_; -}; -} // namespace - -Constraint* MakeIsBooleanSumInRange(Solver* const solver, - const std::vector& variables, - int64 range_min, int64 range_max, - IntVar* const target) { - return solver->RevAlloc( - new IsBooleanSumInRange(solver, variables, range_min, range_max, target)); -} - -Constraint* MakeBooleanSumInRange(Solver* const solver, - const std::vector& variables, - int64 range_min, int64 range_max) { - return solver->RevAlloc( - new BooleanSumInRange(solver, variables, range_min, range_max)); -} - -Constraint* MakeBooleanSumOdd(Solver* const solver, - const std::vector& variables) { - return solver->RevAlloc(new BooleanSumOdd(solver, variables)); -} - -Constraint* MakeStrongScalProdEquality(Solver* const solver, - const std::vector& variables, - const std::vector& coefficients, - int64 rhs) { - const bool trace = FLAGS_cp_trace_search; - const bool propag = FLAGS_cp_trace_propagation; - FLAGS_cp_trace_search = false; - FLAGS_cp_trace_propagation = false; - const int size = variables.size(); - IntTupleSet tuples(size); - Solver s("build"); - std::vector copy_vars(size); - for (int i = 0; i < size; ++i) { - copy_vars[i] = s.MakeIntVar(variables[i]->Min(), variables[i]->Max()); - } - s.AddConstraint(s.MakeScalProdEquality(copy_vars, coefficients, rhs)); - s.NewSearch(s.MakePhase(copy_vars, Solver::CHOOSE_FIRST_UNBOUND, - Solver::ASSIGN_MIN_VALUE)); - while (s.NextSolution()) { - std::vector one_tuple(size); - for (int i = 0; i < size; ++i) { - one_tuple[i] = copy_vars[i]->Value(); - } - tuples.Insert(one_tuple); - } - s.EndSearch(); - FLAGS_cp_trace_search = trace; - FLAGS_cp_trace_propagation = propag; - return solver->MakeAllowedAssignments(variables, tuples); -} - -Constraint* MakeVariableOdd(Solver* const s, IntVar* const var) { - return s->RevAlloc(new VariableParity(s, var, true)); -} - -Constraint* MakeVariableEven(Solver* const s, IntVar* const var) { - return s->RevAlloc(new VariableParity(s, var, false)); -} - -Constraint* MakeFixedModulo(Solver* const s, IntVar* const var, - IntVar* const mod, int64 residual) { - return s->RevAlloc(new FixedModulo(s, var, mod, residual)); -} - -IntervalVar* MakePerformedIntervalVar(Solver* const solver, IntVar* const start, - IntVar* const duration, - const std::string& n) { - CHECK(start != nullptr); - CHECK(duration != nullptr); - return solver->RegisterIntervalVar(solver->RevAlloc( - new StartVarDurationVarPerformedIntervalVar(solver, start, duration, n))); -} - -Constraint* MakeKDiffn(Solver* solver, - const std::vector>& x, - const std::vector>& dx, - bool strict) { - return solver->RevAlloc(new KDiffn(solver, x, dx, strict)); -} - -} // namespace operations_research diff --git a/ortools/flatzinc/flatzinc_constraints.h b/ortools/flatzinc/flatzinc_constraints.h deleted file mode 100644 index 476a42adce..0000000000 --- a/ortools/flatzinc/flatzinc_constraints.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_FLATZINC_CONSTRAINTS_H_ -#define OR_TOOLS_FLATZINC_FLATZINC_CONSTRAINTS_H_ - -// Additional constraints included in the minizinc specifications, but not -// general enough to be in the CP library. - -#include "ortools/constraint_solver/constraint_solver.h" - -namespace operations_research { - -// This function will precompute all valid combinations of variables values that -// satisfies Sum(variables[i] * coefficients[i]) == rhs, and it will create -// an AllowedAssignment constraint to enforce it. -Constraint* MakeStrongScalProdEquality(Solver* const solver, - const std::vector& variables, - const std::vector& coefficients, - int64 rhs); - -// Creates a constraints that represents: -// target == (sum(variables) in [range_min..range_max]). -Constraint* MakeIsBooleanSumInRange(Solver* const solver, - const std::vector& variables, - int64 range_min, int64 range_max, - IntVar* const target); - -// Creates the constraint sum(variables) in [range_min..range_max]. -Constraint* MakeBooleanSumInRange(Solver* const solver, - const std::vector& variables, - int64 range_min, int64 range_max); - -// Creates the constraint sum(variables) is odd. -Constraint* MakeBooleanSumOdd(Solver* const solver, - const std::vector& variables); - -// Creates a constraint var is odd. -Constraint* MakeVariableOdd(Solver* const s, IntVar* const var); - -// Creates a constraint var is even. -Constraint* MakeVariableEven(Solver* const s, IntVar* const var); - -// Creates a constraint var % mod == residual. -Constraint* MakeFixedModulo(Solver* const s, IntVar* const var, - IntVar* const mod, int64 residual); - -// Creates a performed interval variable with the given start and duration -// variables. -IntervalVar* MakePerformedIntervalVar(Solver* const solver, IntVar* const start, - IntVar* const duration, - const std::string& n); - -// Creates a n-dimensional constraints that enforces that k boxes (n dimension) -// do not overlap in space. -// The origin of box i is (x[i][0], ..., x[i][n - 1]). -// The dimension of the box i in dimension j is dx[i][j]. -Constraint* MakeKDiffn(Solver* solver, - const std::vector>& x, - const std::vector>& dx, - bool strict); -} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_FLATZINC_CONSTRAINTS_H_ diff --git a/ortools/flatzinc/fz.cc b/ortools/flatzinc/fz.cc index a04cac2b77..58db1239d9 100644 --- a/ortools/flatzinc/fz.cc +++ b/ortools/flatzinc/fz.cc @@ -42,7 +42,7 @@ DEFINE_bool(free_search, false, "If false, the solver must follow the defined search." "If true, other search are allowed."); DEFINE_int32(threads, 0, "Number of threads the solver will use."); -DEFINE_bool(presolve, true, "Presolve the model to simplify it."); +DEFINE_bool(presolve, false, "Presolve the model to simplify it."); DEFINE_bool(statistics, false, "Print solver statistics after search."); DEFINE_bool(read_from_stdin, false, "Read the FlatZinc from stdin, not from a file."); diff --git a/ortools/flatzinc/mznlib_sat/BUILD b/ortools/flatzinc/mznlib/BUILD similarity index 100% rename from ortools/flatzinc/mznlib_sat/BUILD rename to ortools/flatzinc/mznlib/BUILD diff --git a/ortools/flatzinc/mznlib_cp/all_different_int.mzn b/ortools/flatzinc/mznlib/all_different_int.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/all_different_int.mzn rename to ortools/flatzinc/mznlib/all_different_int.mzn diff --git a/ortools/flatzinc/mznlib_cp/circuit.mzn b/ortools/flatzinc/mznlib/circuit.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/circuit.mzn rename to ortools/flatzinc/mznlib/circuit.mzn diff --git a/ortools/flatzinc/mznlib_cp/cumulative.mzn b/ortools/flatzinc/mznlib/cumulative.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/cumulative.mzn rename to ortools/flatzinc/mznlib/cumulative.mzn diff --git a/ortools/flatzinc/mznlib_cp/diffn.mzn b/ortools/flatzinc/mznlib/diffn.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/diffn.mzn rename to ortools/flatzinc/mznlib/diffn.mzn diff --git a/ortools/flatzinc/mznlib_cp/diffn_nonstrict.mzn b/ortools/flatzinc/mznlib/diffn_nonstrict.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/diffn_nonstrict.mzn rename to ortools/flatzinc/mznlib/diffn_nonstrict.mzn diff --git a/ortools/flatzinc/mznlib_sat/inverse.mzn b/ortools/flatzinc/mznlib/inverse.mzn similarity index 100% rename from ortools/flatzinc/mznlib_sat/inverse.mzn rename to ortools/flatzinc/mznlib/inverse.mzn diff --git a/ortools/flatzinc/mznlib_cp/maximum.mzn b/ortools/flatzinc/mznlib/maximum.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/maximum.mzn rename to ortools/flatzinc/mznlib/maximum.mzn diff --git a/ortools/flatzinc/mznlib_cp/maximum_int.mzn b/ortools/flatzinc/mznlib/maximum_int.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/maximum_int.mzn rename to ortools/flatzinc/mznlib/maximum_int.mzn diff --git a/ortools/flatzinc/mznlib_cp/minimum.mzn b/ortools/flatzinc/mznlib/minimum.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/minimum.mzn rename to ortools/flatzinc/mznlib/minimum.mzn diff --git a/ortools/flatzinc/mznlib_cp/minimum_int.mzn b/ortools/flatzinc/mznlib/minimum_int.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/minimum_int.mzn rename to ortools/flatzinc/mznlib/minimum_int.mzn diff --git a/ortools/flatzinc/mznlib_sat/network_flow.mzn b/ortools/flatzinc/mznlib/network_flow.mzn similarity index 100% rename from ortools/flatzinc/mznlib_sat/network_flow.mzn rename to ortools/flatzinc/mznlib/network_flow.mzn diff --git a/ortools/flatzinc/mznlib_sat/nostrings.mzn b/ortools/flatzinc/mznlib/nostrings.mzn similarity index 100% rename from ortools/flatzinc/mznlib_sat/nostrings.mzn rename to ortools/flatzinc/mznlib/nostrings.mzn diff --git a/ortools/flatzinc/mznlib_sat/redefinitions-2.0.mzn b/ortools/flatzinc/mznlib/redefinitions-2.0.mzn similarity index 100% rename from ortools/flatzinc/mznlib_sat/redefinitions-2.0.mzn rename to ortools/flatzinc/mznlib/redefinitions-2.0.mzn diff --git a/ortools/flatzinc/mznlib_cp/regular.mzn b/ortools/flatzinc/mznlib/regular.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/regular.mzn rename to ortools/flatzinc/mznlib/regular.mzn diff --git a/ortools/flatzinc/mznlib_cp/subcircuit.mzn b/ortools/flatzinc/mznlib/subcircuit.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/subcircuit.mzn rename to ortools/flatzinc/mznlib/subcircuit.mzn diff --git a/ortools/flatzinc/mznlib_cp/table.mzn b/ortools/flatzinc/mznlib/table.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/table.mzn rename to ortools/flatzinc/mznlib/table.mzn diff --git a/ortools/flatzinc/mznlib_cp/table_bool.mzn b/ortools/flatzinc/mznlib/table_bool.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/table_bool.mzn rename to ortools/flatzinc/mznlib/table_bool.mzn diff --git a/ortools/flatzinc/mznlib_cp/table_int.mzn b/ortools/flatzinc/mznlib/table_int.mzn similarity index 100% rename from ortools/flatzinc/mznlib_cp/table_int.mzn rename to ortools/flatzinc/mznlib/table_int.mzn diff --git a/ortools/flatzinc/mznlib_cp/alldifferent_except_0.mzn b/ortools/flatzinc/mznlib_cp/alldifferent_except_0.mzn deleted file mode 100644 index 9422bbbe1d..0000000000 --- a/ortools/flatzinc/mznlib_cp/alldifferent_except_0.mzn +++ /dev/null @@ -1,6 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains the elements of the array 'vs' to be all different except those -% elements that are assigned the value 0. -%-----------------------------------------------------------------------------% - -predicate alldifferent_except_0(array[int] of var int: vs); diff --git a/ortools/flatzinc/mznlib_cp/among.mzn b/ortools/flatzinc/mznlib_cp/among.mzn deleted file mode 100644 index 442ddaec1a..0000000000 --- a/ortools/flatzinc/mznlib_cp/among.mzn +++ /dev/null @@ -1,4 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires exactly 'n' variables in 'x' to take one of the values in 'v'. -%-----------------------------------------------------------------------------% -predicate among(var int: n, array[int] of var int: x, set of int: v) ; diff --git a/ortools/flatzinc/mznlib_cp/arg_max_int.mzn b/ortools/flatzinc/mznlib_cp/arg_max_int.mzn deleted file mode 100644 index d9ee23a288..0000000000 --- a/ortools/flatzinc/mznlib_cp/arg_max_int.mzn +++ /dev/null @@ -1,2 +0,0 @@ -predicate maximum_arg_int(array[int] of var int: x, var int: i); - diff --git a/ortools/flatzinc/mznlib_cp/arg_min_int.mzn b/ortools/flatzinc/mznlib_cp/arg_min_int.mzn deleted file mode 100644 index c92f36c075..0000000000 --- a/ortools/flatzinc/mznlib_cp/arg_min_int.mzn +++ /dev/null @@ -1,2 +0,0 @@ -predicate minimum_arg_int(array[int] of var int: x, var int: i); - diff --git a/ortools/flatzinc/mznlib_cp/at_most_int.mzn b/ortools/flatzinc/mznlib_cp/at_most_int.mzn deleted file mode 100644 index 569c1d46bc..0000000000 --- a/ortools/flatzinc/mznlib_cp/at_most_int.mzn +++ /dev/null @@ -1,5 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires at most 'n' variables in 'x' to take the value 'v'. -%-----------------------------------------------------------------------------% - -predicate at_most_int(int: n, array[int] of var int: x, int: v); \ No newline at end of file diff --git a/ortools/flatzinc/mznlib_cp/count.mzn b/ortools/flatzinc/mznlib_cp/count.mzn deleted file mode 100644 index 893c9b8dce..0000000000 --- a/ortools/flatzinc/mznlib_cp/count.mzn +++ /dev/null @@ -1,12 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be the number of occurrences of 'y' in 'x'. -%-----------------------------------------------------------------------------% - -include "count_eq.mzn"; - -predicate count(array[int] of var int: x, var int: y, var int: c) = - count_eq(x, y, c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% - diff --git a/ortools/flatzinc/mznlib_cp/count_eq.mzn b/ortools/flatzinc/mznlib_cp/count_eq.mzn deleted file mode 100644 index 1bfec56517..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_eq.mzn +++ /dev/null @@ -1,14 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be the number of occurrences of 'y' in 'x'. -%-----------------------------------------------------------------------------% - -include "count_reif.mzn"; - -predicate count_eq_reif(array[int] of var int: x, var int: y, var int: c, - var bool: b) - = count_reif(x, y, c, b); - -predicate count_eq(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_geq.mzn b/ortools/flatzinc/mznlib_cp/count_geq.mzn deleted file mode 100644 index 75275a1fa6..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_geq.mzn +++ /dev/null @@ -1,9 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be greater or equal than or equal to the number of -% occurrences of % 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_geq(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_gt.mzn b/ortools/flatzinc/mznlib_cp/count_gt.mzn deleted file mode 100644 index f0aa4281da..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_gt.mzn +++ /dev/null @@ -1,9 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be greater to the number of occurrences of -% 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_gt(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_leq.mzn b/ortools/flatzinc/mznlib_cp/count_leq.mzn deleted file mode 100644 index cb7df58221..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_leq.mzn +++ /dev/null @@ -1,9 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be less than or equal to the number of occurrences of -% 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_leq(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_lt.mzn b/ortools/flatzinc/mznlib_cp/count_lt.mzn deleted file mode 100644 index 8ae935d6ed..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_lt.mzn +++ /dev/null @@ -1,8 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be less than to the number of occurrences of 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_lt(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_neq.mzn b/ortools/flatzinc/mznlib_cp/count_neq.mzn deleted file mode 100644 index 4e9d7c96ad..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_neq.mzn +++ /dev/null @@ -1,8 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'c' to be different to the number of occurrences of 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_neq(array[int] of var int: x, var int: y, var int: c); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/count_reif.mzn b/ortools/flatzinc/mznlib_cp/count_reif.mzn deleted file mode 100644 index 89de7bc815..0000000000 --- a/ortools/flatzinc/mznlib_cp/count_reif.mzn +++ /dev/null @@ -1,12 +0,0 @@ -%-----------------------------------------------------------------------------% -% Reified Constraint 'c' to be the number of occurrences of 'y' in 'x'. -%-----------------------------------------------------------------------------% - -predicate count_reif(array[int] of var int: x, - var int: y, - var int: c, - var bool: b); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% - diff --git a/ortools/flatzinc/mznlib_cp/diffn_k.mzn b/ortools/flatzinc/mznlib_cp/diffn_k.mzn deleted file mode 100644 index febed81f88..0000000000 --- a/ortools/flatzinc/mznlib_cp/diffn_k.mzn +++ /dev/null @@ -1,9 +0,0 @@ -predicate diffn_k(array[int,int] of var int: box_posn, - array[int,int] of var int: box_size) = - let { int: num_boxes = card(index_set_1of2(box_posn)); - int: num_dims = card(index_set_2of2(box_posn)) } in - diffn_k_with_sizes(box_posn, box_size, num_boxes, num_dims); - -predicate diffn_k_with_sizes(array[int,int] of var int: box_posn, - array[int,int] of var int: box_size, - int: num_boxes, int: num_dims); diff --git a/ortools/flatzinc/mznlib_cp/diffn_nonstrict_k.mzn b/ortools/flatzinc/mznlib_cp/diffn_nonstrict_k.mzn deleted file mode 100644 index a4d86278f5..0000000000 --- a/ortools/flatzinc/mznlib_cp/diffn_nonstrict_k.mzn +++ /dev/null @@ -1,9 +0,0 @@ -predicate diffn_nonstrict_k(array[int,int] of var int: box_posn, - array[int,int] of var int: box_size) = - let { int: num_boxes = card(index_set_1of2(box_posn)); - int: num_dims = card(index_set_2of2(box_posn)) } in - diffn_nonstrict_k_with_sizes(box_posn, box_size, num_boxes, num_dims); - -predicate diffn_nonstrict_k_with_sizes(array[int,int] of var int: box_posn, - array[int,int] of var int: box_size, - int: num_boxes, int: num_dims); diff --git a/ortools/flatzinc/mznlib_cp/disjunctive.mzn b/ortools/flatzinc/mznlib_cp/disjunctive.mzn deleted file mode 100644 index d0eea4cb39..0000000000 --- a/ortools/flatzinc/mznlib_cp/disjunctive.mzn +++ /dev/null @@ -1,3 +0,0 @@ -include "disjunctive_strict.mzn"; -predicate disjunctive(array[int] of var int: s, - array[int] of var int: d); diff --git a/ortools/flatzinc/mznlib_cp/disjunctive_opt.mzn b/ortools/flatzinc/mznlib_cp/disjunctive_opt.mzn deleted file mode 100644 index 8b1cb8006e..0000000000 --- a/ortools/flatzinc/mznlib_cp/disjunctive_opt.mzn +++ /dev/null @@ -1,3 +0,0 @@ -predicate disjunctive(array[int] of var opt int: s, - array[int] of var int: d); - diff --git a/ortools/flatzinc/mznlib_cp/disjunctive_strict.mzn b/ortools/flatzinc/mznlib_cp/disjunctive_strict.mzn deleted file mode 100644 index ae1f0f7b11..0000000000 --- a/ortools/flatzinc/mznlib_cp/disjunctive_strict.mzn +++ /dev/null @@ -1,2 +0,0 @@ -predicate disjunctive_strict(array[int] of var int: s, - array[int] of var int: d); diff --git a/ortools/flatzinc/mznlib_cp/global_cardinality.mzn b/ortools/flatzinc/mznlib_cp/global_cardinality.mzn deleted file mode 100644 index a19e7e3788..0000000000 --- a/ortools/flatzinc/mznlib_cp/global_cardinality.mzn +++ /dev/null @@ -1,4 +0,0 @@ -predicate global_cardinality(array[int] of var int: x, - array[int] of int: cover, - array[int] of var int: counts); - diff --git a/ortools/flatzinc/mznlib_cp/global_cardinality_closed.mzn b/ortools/flatzinc/mznlib_cp/global_cardinality_closed.mzn deleted file mode 100644 index 9ddc26ef2e..0000000000 --- a/ortools/flatzinc/mznlib_cp/global_cardinality_closed.mzn +++ /dev/null @@ -1,3 +0,0 @@ -predicate global_cardinality_closed(array[int] of var int: x, - array[int] of int: cover, - array[int] of var int: counts); diff --git a/ortools/flatzinc/mznlib_cp/global_cardinality_low_up.mzn b/ortools/flatzinc/mznlib_cp/global_cardinality_low_up.mzn deleted file mode 100644 index b8e428975e..0000000000 --- a/ortools/flatzinc/mznlib_cp/global_cardinality_low_up.mzn +++ /dev/null @@ -1,4 +0,0 @@ -predicate global_cardinality_low_up(array[int] of var int: x, - array[int] of int: cover, - array[int] of int: lbound, - array[int] of int: ubound); diff --git a/ortools/flatzinc/mznlib_cp/global_cardinality_low_up_closed.mzn b/ortools/flatzinc/mznlib_cp/global_cardinality_low_up_closed.mzn deleted file mode 100644 index c8d61910e1..0000000000 --- a/ortools/flatzinc/mznlib_cp/global_cardinality_low_up_closed.mzn +++ /dev/null @@ -1,4 +0,0 @@ -predicate global_cardinality_low_up_closed(array[int] of var int: x, - array[int] of int: cover, - array[int] of int: lbound, - array[int] of int: ubound); diff --git a/ortools/flatzinc/mznlib_cp/int_mod.mzn b/ortools/flatzinc/mznlib_cp/int_mod.mzn deleted file mode 100644 index 610aa2b5d9..0000000000 --- a/ortools/flatzinc/mznlib_cp/int_mod.mzn +++ /dev/null @@ -1,28 +0,0 @@ -predicate int_div_mod(var int: x, var int:y, var int:d, var int:r) = - y != 0 /\ - x == y * d + r /\ - x * r >= 0 /\ - -abs(y) < r /\ r < abs(y) /\ - min(lb(x),-ub(x)) <= d /\ d <= max(ub(x),-lb(x)) /\ - %% the next 5 lines are probably unnecessary for propagation solvers -% if lb(x) > 0 then -% 0 <= r /\ r < max(ub(y),-lb(y)) -% else if ub(x) < 0 then -% min(lb(y),-ub(y)) < r /\ r <= 0 -% else true endif endif /\ -% if lb(y) > 0 then -% lb(x) div lb(y) <= d /\ d <= ub(x) div lb(y) -% else if ub(y) < 0 then -% ub(x) div ub(y) <= d /\ d <= lb(x) div ub(y) -% else true endif endif; - - -predicate int_div(var int:x, var int:y, var int:d) = - let { var min(lb(y),-ub(y))+1 .. max(ub(y),-lb(y))-1: r } in - int_div_mod(x,y,d,r); - -predicate int_mud(var int:x, var int:y, var int:r) = - let { var min(lb(x),-ub(x)) .. max(ub(x),-lb(x)): d } in - int_div_mod(x,y,d,r); - -%%predicate int_mod(var int x, int y, var int r); diff --git a/ortools/flatzinc/mznlib_cp/inverse.mzn b/ortools/flatzinc/mznlib_cp/inverse.mzn deleted file mode 100644 index cf90acb690..0000000000 --- a/ortools/flatzinc/mznlib_cp/inverse.mzn +++ /dev/null @@ -1,6 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains two arrays of int variables, 'f' and 'invf', to represent -% inverse functions. All the values in each array must be within the index -% set of the other array. -%-----------------------------------------------------------------------------% -predicate inverse(array[int] of var int: f, array[int] of var int: invf); diff --git a/ortools/flatzinc/mznlib_cp/lex_less_bool.mzn b/ortools/flatzinc/mznlib_cp/lex_less_bool.mzn deleted file mode 100644 index 59506265e0..0000000000 --- a/ortools/flatzinc/mznlib_cp/lex_less_bool.mzn +++ /dev/null @@ -1,11 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the array 'x' is strictly lexicographically less than array 'y'. -% Compares them from first to last element, regardless of indices -%-----------------------------------------------------------------------------% - -predicate lex_less_bool(array[int] of var bool: x, array[int] of var bool: y); - -predicate lex_lt_bool(array[int] of var bool: x, array[int] of var bool: y) = - lex_less(x, y); - -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/lex_less_int.mzn b/ortools/flatzinc/mznlib_cp/lex_less_int.mzn deleted file mode 100644 index 80be34e97c..0000000000 --- a/ortools/flatzinc/mznlib_cp/lex_less_int.mzn +++ /dev/null @@ -1,8 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the array 'x' is strictly lexicographically less than array 'y'. -% Compares them from first to last element, regardless of indices -%-----------------------------------------------------------------------------% - -predicate lex_less_int(array[int] of var int: x, array[int] of var int: y); - -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/lex_lesseq_bool.mzn b/ortools/flatzinc/mznlib_cp/lex_lesseq_bool.mzn deleted file mode 100644 index fef3c2be55..0000000000 --- a/ortools/flatzinc/mznlib_cp/lex_lesseq_bool.mzn +++ /dev/null @@ -1,11 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the array 'x' is strictly lexicographically less than array 'y'. -% Compares them from first to last element, regardless of indices -%-----------------------------------------------------------------------------% - -predicate lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y); - -predicate lex_leq_bool(array[int] of var bool: x, array[int] of var bool: y) = - lex_lesseq_bool(x, y); - -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/lex_lesseq_int.mzn b/ortools/flatzinc/mznlib_cp/lex_lesseq_int.mzn deleted file mode 100644 index 5051e2e2c0..0000000000 --- a/ortools/flatzinc/mznlib_cp/lex_lesseq_int.mzn +++ /dev/null @@ -1,12 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the array 'x' is strictly lexicographically less than array 'y'. -% Compares them from first to last element, regardless of indices -%-----------------------------------------------------------------------------% - -predicate lex_lesseq_int(array[int] of var int: x, array[int] of var int: y); - -predicate lex_leq_int(array[int] of var int: x, - array[int] of var int: y) = - lex_lesseq_int(x, y); - -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_cp/nvalue.mzn b/ortools/flatzinc/mznlib_cp/nvalue.mzn deleted file mode 100644 index 5cb9f8e2be..0000000000 --- a/ortools/flatzinc/mznlib_cp/nvalue.mzn +++ /dev/null @@ -1,4 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the number of distinct values in 'x' is 'n'. -%-----------------------------------------------------------------------------% -predicate nvalue(var int: n, array[int] of var int: x); diff --git a/ortools/flatzinc/mznlib_cp/redefinitions-2.0.mzn b/ortools/flatzinc/mznlib_cp/redefinitions-2.0.mzn deleted file mode 100644 index af2c1aac24..0000000000 --- a/ortools/flatzinc/mznlib_cp/redefinitions-2.0.mzn +++ /dev/null @@ -1,29 +0,0 @@ -% This file contains redefinitions of standard builtins that can be overridden -% by solvers. - -predicate bool_clause_reif(array[int] of var bool: as, - array[int] of var bool: bs, - var bool: b) = - clause(as,bs++[b]) /\ - forall (i in index_set(as)) (as[i] -> b) /\ - forall (i in index_set(bs)) (bs[i] \/ b); - -predicate array_int_maximum(var int: m, array[int] of var int: x); -predicate array_int_minimum(var int: m, array[int] of var int: x); - -% Not supported -predicate array_float_maximum(var float: m, array[int] of var float: x); -predicate array_float_minimum(var float: m, array[int] of var float: x); - -% Define int_pow for CP solvers -% r = x ^ y -predicate int_pow( var int: x, var int: y, var int: r ) = - if is_fixed(y) /\ 2==fix(y) then r==x*x - elseif is_fixed(y) /\ 3==fix(y) then r==x*x*x - else - let { - array[ int, int ] of int: x2y = array2d( lb(x)..ub(x), lb(y)..ub(y), - [ pow( X, Y ) | X in lb(x)..ub(x), Y in lb(y)..ub(y) ] ) - } in - r == x2y[ x, y ] - endif; diff --git a/ortools/flatzinc/mznlib_cp/regular_nfa.mzn b/ortools/flatzinc/mznlib_cp/regular_nfa.mzn deleted file mode 100644 index 92a0166b08..0000000000 --- a/ortools/flatzinc/mznlib_cp/regular_nfa.mzn +++ /dev/null @@ -1,3 +0,0 @@ -predicate regular_nfa(array[int] of var int: x, int: Q, int: S, - array[int,int] of set of int: d, int: q0, set of int: F); - diff --git a/ortools/flatzinc/mznlib_cp/sequence.mzn b/ortools/flatzinc/mznlib_cp/sequence.mzn deleted file mode 100644 index 468a0919d6..0000000000 --- a/ortools/flatzinc/mznlib_cp/sequence.mzn +++ /dev/null @@ -1,4 +0,0 @@ -include "sliding_sum.mzn"; - -predicate sequence(array[int] of var int: x, int: k, int: lb, int: ub) = - sliding_sum(lb, ub, k, x); diff --git a/ortools/flatzinc/mznlib_cp/sliding_sum.mzn b/ortools/flatzinc/mznlib_cp/sliding_sum.mzn deleted file mode 100644 index aee10fc20e..0000000000 --- a/ortools/flatzinc/mznlib_cp/sliding_sum.mzn +++ /dev/null @@ -1,6 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that in each subsequence 'vs[i], ..., vs[i + seq - 1]' the sum of the -% values belongs to the interval ['low', 'up']. -%-----------------------------------------------------------------------------% - -predicate sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs); diff --git a/ortools/flatzinc/mznlib_cp/sort.mzn b/ortools/flatzinc/mznlib_cp/sort.mzn deleted file mode 100644 index bdbf7d52f9..0000000000 --- a/ortools/flatzinc/mznlib_cp/sort.mzn +++ /dev/null @@ -1,7 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that the multiset of values in 'x' are the same as the -% multiset of values in 'y' but 'y' is in sorted order. -%-----------------------------------------------------------------------------% -predicate sort(array[int] of var int: x, array[int] of var int: y); - - diff --git a/ortools/flatzinc/mznlib_cp/symmetric_all_different.mzn b/ortools/flatzinc/mznlib_cp/symmetric_all_different.mzn deleted file mode 100644 index abe7ed8a2b..0000000000 --- a/ortools/flatzinc/mznlib_cp/symmetric_all_different.mzn +++ /dev/null @@ -1,2 +0,0 @@ -predicate symmetric_all_different(array[int] of var int:x); - diff --git a/ortools/flatzinc/mznlib_sat/all_different_int.mzn b/ortools/flatzinc/mznlib_sat/all_different_int.mzn deleted file mode 100644 index 7781569082..0000000000 --- a/ortools/flatzinc/mznlib_sat/all_different_int.mzn +++ /dev/null @@ -1 +0,0 @@ -predicate all_different_int(array[int] of var int: x); diff --git a/ortools/flatzinc/mznlib_sat/circuit.mzn b/ortools/flatzinc/mznlib_sat/circuit.mzn deleted file mode 100644 index 2475a40b80..0000000000 --- a/ortools/flatzinc/mznlib_sat/circuit.mzn +++ /dev/null @@ -1,12 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains the elements of 'x' to define a circuit where 'x[i] = j' means -% that 'j' is the successor of 'i'. -%-----------------------------------------------------------------------------% - -predicate circuit(array[int] of var int: x); - -predicate circuit_reif(array[int] of var int: x, var bool: b) = - abort("Reified circuit/1 is not supported."); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_sat/cumulative.mzn b/ortools/flatzinc/mznlib_sat/cumulative.mzn deleted file mode 100644 index 6c25a16d65..0000000000 --- a/ortools/flatzinc/mznlib_sat/cumulative.mzn +++ /dev/null @@ -1,11 +0,0 @@ -%-----------------------------------------------------------------------------% -% Requires that a set of tasks given by start times 's', durations 'd', and -% resource requirements 'r', never require more than a global resource bound -% 'b' at any one time. -% Assumptions: -% - forall i, d[i] >= 0 and r[i] >= 0 -%-----------------------------------------------------------------------------% -predicate cumulative(array[int] of var int: s, - array[int] of var int: d, - array[int] of var int: r, - var int: b); diff --git a/ortools/flatzinc/mznlib_sat/diffn.mzn b/ortools/flatzinc/mznlib_sat/diffn.mzn deleted file mode 100644 index d572dc43e0..0000000000 --- a/ortools/flatzinc/mznlib_sat/diffn.mzn +++ /dev/null @@ -1,10 +0,0 @@ -%-----------------------------------------------------------------------------% -% diffn: constrains rectangles, given by their origins and sizes, to be -% non-overlapping -%-----------------------------------------------------------------------------% - -predicate diffn(array[int] of var int: x, - array[int] of var int: y, - array[int] of var int: dx, - array[int] of var int: dy); - diff --git a/ortools/flatzinc/mznlib_sat/diffn_nonstrict.mzn b/ortools/flatzinc/mznlib_sat/diffn_nonstrict.mzn deleted file mode 100644 index 1ccaa50a57..0000000000 --- a/ortools/flatzinc/mznlib_sat/diffn_nonstrict.mzn +++ /dev/null @@ -1,10 +0,0 @@ -%-----------------------------------------------------------------------------% -% diffn: constrains rectangles, given by their origins and sizes, to be -% non-overlapping -%-----------------------------------------------------------------------------% - -predicate diffn_nonstrict(array[int] of var int: x, - array[int] of var int: y, - array[int] of var int: dx, - array[int] of var int: dy); - diff --git a/ortools/flatzinc/mznlib_sat/maximum.mzn b/ortools/flatzinc/mznlib_sat/maximum.mzn deleted file mode 100644 index 3e73952edd..0000000000 --- a/ortools/flatzinc/mznlib_sat/maximum.mzn +++ /dev/null @@ -1,10 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'm' to be the maximum of the values in 'x'. -% Assumptions: |x| > 0. -%-----------------------------------------------------------------------------% - -include "maximum_int.mzn"; - -predicate maximum(var int: m, array[int] of var int: x) = - maximum_int(m, x); - diff --git a/ortools/flatzinc/mznlib_sat/maximum_int.mzn b/ortools/flatzinc/mznlib_sat/maximum_int.mzn deleted file mode 100644 index f3afab1480..0000000000 --- a/ortools/flatzinc/mznlib_sat/maximum_int.mzn +++ /dev/null @@ -1,7 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'm' to be the maximum of the values in 'x'. -% Assumptions: |x| > 0. -%-----------------------------------------------------------------------------% - -predicate maximum_int(var int: m, array[int] of var int: x); - diff --git a/ortools/flatzinc/mznlib_sat/minimum.mzn b/ortools/flatzinc/mznlib_sat/minimum.mzn deleted file mode 100644 index b410eae63e..0000000000 --- a/ortools/flatzinc/mznlib_sat/minimum.mzn +++ /dev/null @@ -1,11 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'm' to be the minimum of the values in 'x'. -% Assumptions: |x| > 0. -%-----------------------------------------------------------------------------% - -include "minimum_int.mzn"; - -predicate minimum(var int: m, array[int] of var int: x) = - minimum_int(m, x); - - diff --git a/ortools/flatzinc/mznlib_sat/minimum_int.mzn b/ortools/flatzinc/mznlib_sat/minimum_int.mzn deleted file mode 100644 index d2d128c2ae..0000000000 --- a/ortools/flatzinc/mznlib_sat/minimum_int.mzn +++ /dev/null @@ -1,7 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains 'm' to be the minimum of the values in 'x'. -% Assumptions: |x| > 0. -%-----------------------------------------------------------------------------% - -predicate minimum_int(var int: m, array[int] of var int: x); - diff --git a/ortools/flatzinc/mznlib_sat/regular.mzn b/ortools/flatzinc/mznlib_sat/regular.mzn deleted file mode 100644 index 22f64679f5..0000000000 --- a/ortools/flatzinc/mznlib_sat/regular.mzn +++ /dev/null @@ -1,9 +0,0 @@ -%-----------------------------------------------------------------------------% -% The sequence of values in array 'x' (which must all be in the range 1..S) -% is accepted by the DFA of 'Q' states with input 1..S and transition -% function 'd' (which maps (1..Q, 1..S) -> 0..Q)) and initial state 'q0' -% (which must be in 1..Q) and accepting states 'F' (which all must be in -% 1..Q). We reserve state 0 to be an always failing state. -%-----------------------------------------------------------------------------% -predicate regular(array[int] of var int: x, int: Q, int: S, - array[int,int] of int: d, int: q0, set of int: F); diff --git a/ortools/flatzinc/mznlib_sat/subcircuit.mzn b/ortools/flatzinc/mznlib_sat/subcircuit.mzn deleted file mode 100644 index f0f02a8db9..0000000000 --- a/ortools/flatzinc/mznlib_sat/subcircuit.mzn +++ /dev/null @@ -1,12 +0,0 @@ -%-----------------------------------------------------------------------------% -% Constrains the elements of 'x' to define a circuit where 'x[i] = j' means -% that 'j' is the successor of 'i'. -%-----------------------------------------------------------------------------% - -predicate subcircuit(array[int] of var int: x); - -predicate subcircuit_reif(array[int] of var int: x, var bool: b) = - abort("Reified circuit/1 is not supported."); - -%-----------------------------------------------------------------------------% -%-----------------------------------------------------------------------------% diff --git a/ortools/flatzinc/mznlib_sat/table.mzn b/ortools/flatzinc/mznlib_sat/table.mzn deleted file mode 100644 index 8be25add35..0000000000 --- a/ortools/flatzinc/mznlib_sat/table.mzn +++ /dev/null @@ -1,13 +0,0 @@ -%-----------------------------------------------------------------------------% -% A table constraint: table(x, t) represents the constraint x in t where we -% consider each row in t to be a tuple and t as a set of tuples. -%-----------------------------------------------------------------------------% - -include "table_bool.mzn"; -include "table_int.mzn"; - -predicate table(array[int] of var bool: x, array[int, int] of bool: t) = - table_bool(x, t); - -predicate table(array[int] of var int: x, array[int, int] of int: t) = - table_int(x, t); diff --git a/ortools/flatzinc/mznlib_sat/table_bool.mzn b/ortools/flatzinc/mznlib_sat/table_bool.mzn deleted file mode 100644 index 3ef1f2fd2f..0000000000 --- a/ortools/flatzinc/mznlib_sat/table_bool.mzn +++ /dev/null @@ -1 +0,0 @@ -predicate table_bool(array[int] of var bool: x, array[int, int] of bool: t); diff --git a/ortools/flatzinc/mznlib_sat/table_int.mzn b/ortools/flatzinc/mznlib_sat/table_int.mzn deleted file mode 100644 index d8eaeb0415..0000000000 --- a/ortools/flatzinc/mznlib_sat/table_int.mzn +++ /dev/null @@ -1,2 +0,0 @@ -predicate table_int(array[int] of var int: x, array[int, int] of int: t); - diff --git a/ortools/flatzinc/presolve.cc b/ortools/flatzinc/presolve.cc index c1a0439f0e..177c23092b 100644 --- a/ortools/flatzinc/presolve.cc +++ b/ortools/flatzinc/presolve.cc @@ -274,7 +274,7 @@ Presolver::RuleStatus Presolver::PresolveBool2Int(Constraint* ct, return CONSTRAINT_REWRITTEN; } else { // Rule 2. - AddVariableSubstition(ct->arguments[1].Var(), ct->arguments[0].Var()); + AddVariableSubstitution(ct->arguments[1].Var(), ct->arguments[0].Var()); return CONSTRAINT_ALWAYS_TRUE; } return NOT_CHANGED; @@ -333,7 +333,7 @@ Presolver::RuleStatus Presolver::PresolveIntEq(Constraint* ct, return CONSTRAINT_ALWAYS_TRUE; } else if (ct->arguments[1].IsVariable()) { // Rule 3. - AddVariableSubstition(ct->arguments[0].Var(), ct->arguments[1].Var()); + AddVariableSubstitution(ct->arguments[0].Var(), ct->arguments[1].Var()); return CONSTRAINT_ALWAYS_TRUE; } } else if (ct->arguments[0].HasOneValue()) { // Arg0 is an integer value. @@ -3388,10 +3388,6 @@ void Presolver::PresolveOneConstraint(int index, Constraint* ct) { } } -#undef CALL_TYPE -#undef CALL_PREFIX -#undef CALL_SUFFIX - // Stores all pairs of variables appearing in an int_ne(x, y) constraint. void Presolver::StoreDifference(Constraint* ct) { if (ct->arguments[2].Value() == 0 && ct->arguments[0].values.size() == 3) { @@ -3440,7 +3436,7 @@ void Presolver::MergeIntEqNe(Model* model) { } else { FZVLOG << "Merge " << ct->DebugString() << FZENDL; ct->MarkAsInactive(); - AddVariableSubstition(stored, boolvar); + AddVariableSubstitution(stored, boolvar); successful_rules_["MergeIntEqNe"]++; } } @@ -3468,7 +3464,7 @@ void Presolver::MergeIntEqNe(Model* model) { } else { FZVLOG << "Merge " << ct->DebugString() << FZENDL; ct->MarkAsInactive(); - AddVariableSubstition(stored, boolvar); + AddVariableSubstitution(stored, boolvar); successful_rules_["MergeIntEqNe"]++; } } @@ -3665,6 +3661,11 @@ bool Presolver::RunMinimal(Model* model) { return PresolveBool2Int(ct, log); }); changed = true; + } else if (ct->active && ct->type == "int_lin_eq") { + ApplyRule(index, ct, "PresolveStoreMapping", + [this](Constraint* ct, std::string* log) { + return PresolveStoreMapping(ct, log); + }); } } if (!var_representative_map_.empty()) { @@ -3674,6 +3675,14 @@ bool Presolver::RunMinimal(Model* model) { var_representative_vector_.clear(); } + for (int index = 0; index < model->constraints().size(); ++index) { + Constraint* const ct = constraint(index); + CALL_TYPE(index, ct, "array_int_element", PresolveSimplifyElement); + CALL_TYPE(index, ct, "array_bool_element", PresolveSimplifyElement); + CALL_TYPE(index, ct, "array_var_int_element", PresolveSimplifyExprElement); + CALL_TYPE(index, ct, "array_var_bool_element", PresolveSimplifyExprElement); + } + // Report presolve rules statistics. if (!successful_rules_.empty()) { for (const auto& rule : successful_rules_) { @@ -3688,6 +3697,10 @@ bool Presolver::RunMinimal(Model* model) { return changed; } +#undef CALL_TYPE +#undef CALL_PREFIX +#undef CALL_SUFFIX + bool Presolver::Run(Model* model) { // Check the validity of variable domains. for (const IntegerVariable* var : model->variables()) { @@ -3843,8 +3856,8 @@ bool Presolver::Run(Model* model) { // ----- Substitution support ----- -void Presolver::AddVariableSubstition(IntegerVariable* from, - IntegerVariable* to) { +void Presolver::AddVariableSubstitution(IntegerVariable* from, + IntegerVariable* to) { CHECK(from != nullptr); CHECK(to != nullptr); // Apply the substitutions, if any. diff --git a/ortools/flatzinc/presolve.h b/ortools/flatzinc/presolve.h index c866bdc3c8..13309f0399 100644 --- a/ortools/flatzinc/presolve.h +++ b/ortools/flatzinc/presolve.h @@ -204,7 +204,7 @@ class Presolver { // See http://en.wikipedia.org/wiki/Disjoint-set_data_structure. // Note that the equivalence is directed. We prefer to replace all instances // of 'from' with 'to', rather than the opposite. - void AddVariableSubstition(IntegerVariable* from, IntegerVariable* to); + void AddVariableSubstitution(IntegerVariable* from, IntegerVariable* to); IntegerVariable* FindRepresentativeOfVar(IntegerVariable* var); absl::flat_hash_map var_representative_map_; diff --git a/ortools/flatzinc/reporting.cc b/ortools/flatzinc/reporting.cc deleted file mode 100644 index 41876b66e9..0000000000 --- a/ortools/flatzinc/reporting.cc +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/reporting.h" - -#include // NOLINT -#include - -#include "absl/strings/str_format.h" -#include "absl/synchronization/mutex.h" -#include "ortools/base/integral_types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/constraint_solver/constraint_solveri.h" -#include "ortools/flatzinc/logging.h" - -namespace operations_research { -namespace fz { -MonoThreadReporting::MonoThreadReporting(bool print_all, int max_num_solutions) - : SearchReportingInterface(print_all, max_num_solutions), - best_objective_(0), - interrupted_(false) {} - -MonoThreadReporting::~MonoThreadReporting() {} - -void MonoThreadReporting::Init(int thread_id, const std::string& init_string) { - FZLOG << init_string << FZENDL; -} - -void MonoThreadReporting::OnSearchStart(int thread_id, Type type) { - if (type == MAXIMIZE) { - best_objective_ = kint64min; - } else if (type == MINIMIZE) { - best_objective_ = kint64max; - } -} - -void MonoThreadReporting::OnSatSolution(int thread_id, - const std::string& solution_string) { - if (NumSolutions() < MaxNumSolutions() || ShouldPrintAllSolutions()) { - Print(thread_id, solution_string); - } - IncrementSolutions(); -} - -void MonoThreadReporting::OnOptimizeSolution( - int thread_id, int64 value, const std::string& solution_string) { - best_objective_ = value; - if (ShouldPrintAllSolutions() || MaxNumSolutions() > 1) { - Print(thread_id, solution_string); - } else { - last_solution_ = solution_string; - } - IncrementSolutions(); -} - -void MonoThreadReporting::Log(int thread_id, - const std::string& final_output) const { - FZLOG << final_output << FZENDL; -} - -void MonoThreadReporting::Print(int thread_id, - const std::string& final_output) const { - std::cout << final_output << std::endl; -} - -bool MonoThreadReporting::ShouldFinish() const { return false; } - -void MonoThreadReporting::OnSearchEnd(int thread_id, bool interrupted) { - if (!last_solution_.empty()) { - Print(thread_id, last_solution_); - } - interrupted_ = interrupted; -} - -int64 MonoThreadReporting::BestSolution() const { return best_objective_; } - -OptimizeVar* MonoThreadReporting::CreateObjective(Solver* s, bool maximize, - IntVar* var, int64 step, - int thread_id) const { - return s->MakeOptimize(maximize, var, step); -} - -SearchLimit* MonoThreadReporting::CreateLimit(Solver* s, int thread_id) const { - return nullptr; -} - -bool MonoThreadReporting::Interrupted() const { return interrupted_; } - -// Silent subclass. -SilentMonoThreadReporting::SilentMonoThreadReporting(bool print_all, - int max_num_solutions) - : MonoThreadReporting(print_all, max_num_solutions) {} - -SilentMonoThreadReporting::~SilentMonoThreadReporting() {} - -void SilentMonoThreadReporting::Init(int thread_id, - const std::string& init_string) {} - -void SilentMonoThreadReporting::Log(int thread_id, - const std::string& final_output) const {} - -void SilentMonoThreadReporting::Print(int thread_id, - const std::string& final_output) const {} - -// ----- Helper classes for MultiThreadReporting ----- - -class MtOptimizeVar : public OptimizeVar { - public: - MtOptimizeVar(Solver* s, bool maximize, IntVar* v, int64 step, - const MultiThreadReporting* report, int thread_id, bool verbose) - : OptimizeVar(s, maximize, v, step), - report_(report), - thread_id_(thread_id), - verbose_(verbose) {} - - ~MtOptimizeVar() override {} - - void RefuteDecision(Decision* d) override { - const int64 polled_best = report_->BestSolution(); - if ((maximize_ && polled_best > best_) || - (!maximize_ && polled_best < best_)) { - if (verbose_) { - report_->Log( - thread_id_, - absl::StrFormat("Polling improved objective %d", polled_best)); - } - best_ = polled_best; - } - OptimizeVar::RefuteDecision(d); - } - - private: - const MultiThreadReporting* const report_; - const int thread_id_; - const bool verbose_; -}; - -class MtCustomLimit : public SearchLimit { - public: - MtCustomLimit(Solver* s, const MultiThreadReporting* report, int thread_id, - const bool verbose) - : SearchLimit(s), - report_(report), - thread_id_(thread_id), - verbose_(verbose) {} - - ~MtCustomLimit() override {} - - void Init() override {} - - bool Check() override { - const bool result = report_->ShouldFinish(); - if (result && verbose_) { - report_->Log(thread_id_, "terminating"); - } - return result; - } - - void Copy(const SearchLimit* limit) override {} - - // Not used in this context. - SearchLimit* MakeClone() const override { return nullptr; } - - private: - const MultiThreadReporting* const report_; - const int thread_id_; - const bool verbose_; -}; - -MultiThreadReporting::MultiThreadReporting(bool print_all, int num_solutions, - bool verbose) - : SearchReportingInterface(print_all, num_solutions), - verbose_(verbose), - type_(UNDEF), - last_thread_(-1), - best_objective_(0), - should_finish_(false), - interrupted_(false) {} - -MultiThreadReporting::~MultiThreadReporting() {} - -void MultiThreadReporting::Init(int thread_id, const std::string& init_string) { - absl::MutexLock lock(&mutex_); - if (thread_id == 0) { - FZLOG << init_string << FZENDL; - } - if (verbose_) { - LogNoLock(thread_id, "starting"); - } -} - -void MultiThreadReporting::OnSearchStart(int thread_id, Type type) { - absl::MutexLock lock(&mutex_); - if (type_ == UNDEF) { - type_ = type; - if (type_ == MAXIMIZE) { - best_objective_ = kint64min; - } else if (type_ == MINIMIZE) { - best_objective_ = kint64max; - } - } -} - -void MultiThreadReporting::OnSatSolution(int thread_id, - const std::string& solution_string) { - absl::MutexLock lock(&mutex_); - if (NumSolutions() < MaxNumSolutions() || ShouldPrintAllSolutions()) { - if (verbose_) { - LogNoLock(thread_id, "solution found"); - } - Print(thread_id, solution_string); - should_finish_ = true; - } - IncrementSolutions(); -} - -void MultiThreadReporting::OnOptimizeSolution( - int thread_id, int64 value, const std::string& solution_string) { - absl::MutexLock lock(&mutex_); - if (!should_finish_) { - switch (type_) { - case MINIMIZE: { - if (value < best_objective_) { - best_objective_ = value; - IncrementSolutions(); - if (verbose_) { - LogNoLock(thread_id, - absl::StrFormat("solution found with value %d", value)); - } - if (ShouldPrintAllSolutions() || MaxNumSolutions() > 1) { - Print(thread_id, solution_string); - } else { - last_solution_ = solution_string; - last_thread_ = thread_id; - } - } - break; - } - case MAXIMIZE: { - if (value > best_objective_) { - best_objective_ = value; - IncrementSolutions(); - if (verbose_) { - LogNoLock(thread_id, - absl::StrFormat("solution found with value %d", value)); - } - if (ShouldPrintAllSolutions() || MaxNumSolutions() > 1) { - Print(thread_id, solution_string); - } else { - last_solution_ = solution_string; - last_thread_ = thread_id; - } - } - break; - } - default: - LOG(ERROR) << "Should not be here"; - } - } -} - -void MultiThreadReporting::Log(int thread_id, - const std::string& message) const { - absl::MutexLock lock(&mutex_); - FZLOG << message << FZENDL; -} - -void MultiThreadReporting::Print(int thread_id, - const std::string& message) const { - std::cout << message << std::endl; -} -bool MultiThreadReporting::ShouldFinish() const { - absl::MutexLock lock(&mutex_); - return should_finish_; -} - -void MultiThreadReporting::OnSearchEnd(int thread_id, bool interrupted) { - absl::MutexLock lock(&mutex_); - if (verbose_) { - LogNoLock(thread_id, "exiting"); - } - if (!last_solution_.empty()) { - if (verbose_) { - LogNoLock(last_thread_, absl::StrFormat("solution found with value %d", - best_objective_)); - } - Print(thread_id, last_solution_); - last_solution_.clear(); - } - should_finish_ = true; - if (interrupted) { - interrupted_ = true; - } -} - -int64 MultiThreadReporting::BestSolution() const { - absl::MutexLock lock(&mutex_); - return best_objective_; -} - -OptimizeVar* MultiThreadReporting::CreateObjective(Solver* s, bool maximize, - IntVar* var, int64 step, - int thread_id) const { - return s->RevAlloc( - new MtOptimizeVar(s, maximize, var, step, this, thread_id, verbose_)); -} - -SearchLimit* MultiThreadReporting::CreateLimit(Solver* s, int thread_id) const { - return s->RevAlloc(new MtCustomLimit(s, this, thread_id, verbose_)); -} - -bool MultiThreadReporting::Interrupted() const { - absl::MutexLock lock(&mutex_); - return interrupted_; -} - -void MultiThreadReporting::LogNoLock(int thread_id, - const std::string& message) { - FZLOG << "%% thread " << thread_id << ": " << message << FZENDL; -} - -} // namespace fz -} // namespace operations_research diff --git a/ortools/flatzinc/reporting.h b/ortools/flatzinc/reporting.h deleted file mode 100644 index 2f24fcf895..0000000000 --- a/ortools/flatzinc/reporting.h +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_REPORTING_H_ -#define OR_TOOLS_FLATZINC_REPORTING_H_ - -#include - -#include "absl/synchronization/mutex.h" -#include "ortools/base/integral_types.h" -#include "ortools/constraint_solver/constraint_solver.h" - -namespace operations_research { -namespace fz { -// This class is used to abstract the interface to parallelism from -// the search code. It offers two sets of API: -// - Create specific search objects (Objective(), Limit()). -// - Report solution (SatSolution(), OptimizeSolution(), FinalOutput(), -// EndSearch(), BestSolution(), Interrupted(), -// Log(), Print()). -// -// There will be only one SearchReporting class shared among all the solver -// threads. -class SearchReportingInterface { - public: - enum Type { - UNDEF, - SATISFY, - MINIMIZE, - MAXIMIZE, - }; - - SearchReportingInterface(bool print_all, int max_num_solutions) - : print_all_solutions_(print_all), - num_solutions_(0), - max_num_solutions_(max_num_solutions) {} - - virtual ~SearchReportingInterface() {} - - // ----- Events on the search ----- - - // Initialize the interface for a given thread id. - // In sequential mode, the thread id is always -1. - // In parallel mode, it ranges from 0 to num_threads - 1. - virtual void Init(int thread_id, const std::string& init_string) = 0; - - // Callback on the start search event. - virtual void OnSearchStart(int thread_id, Type type) = 0; - - // Worker 'thread_id' notifies a new solution in a satisfaction - // problem. 'solution_string' is the solution to display if needed. - virtual void OnSatSolution(int thread_id, - const std::string& solution_string) = 0; - - // Worker 'thread_id' notifies a new solution in an optimization - // problem. 'solution_string' is the solution to display if needed. - virtual void OnOptimizeSolution(int thread_id, int64 value, - const std::string& solution_string) = 0; - - // Callback on the end search event. - virtual void OnSearchEnd(int thread_id, bool interrupted) = 0; - - // ----- Log methods ------ - - // Logs the message from the given thread. - virtual void Log(int thread_id, const std::string& message) const = 0; - // Prints message to std::cout and adds a std::endl at the end. - // The minizinc specifications indicates that solutions and search status - // must be printed to std::cout. - virtual void Print(int thread_id, const std::string& output) const = 0; - - // ----- Getters ----- - - // Checks if we should finish the search right away, for instance, - // in a satisfaction problem if a solution has already be found. - virtual bool ShouldFinish() const = 0; - - // Returns the value of the best solution found during search. - virtual int64 BestSolution() const = 0; - - // Returns true if the search was interrupted, usually by a time or - // solution limit. - virtual bool Interrupted() const = 0; - - // Returns the number of solutions found. - int NumSolutions() const { return num_solutions_; } - - // Returns the limit on the number of solutions to find. - int MaxNumSolutions() const { return max_num_solutions_; } - - // Indicates if we should print all solutions. - bool ShouldPrintAllSolutions() const { return print_all_solutions_; } - - // ----- Dedicated methods to create MT/Sequential specific objects ----- - -#if !defined(SWIG) - // Creates the objective used by the search. - // Each solver thread will get a different one. - virtual OptimizeVar* CreateObjective(Solver* s, bool maximize, IntVar* var, - int64 step, int thread_id) const = 0; - // Creates a dedicated search limit. - // Each solver thread will get a different one. - virtual SearchLimit* CreateLimit(Solver* s, int thread_id) const = 0; -#endif // SWIG - - protected: - // Increments the number of solutions found. - void IncrementSolutions() { num_solutions_++; } - - private: - const bool print_all_solutions_; - int num_solutions_; - const int max_num_solutions_; -}; - -class MonoThreadReporting : public SearchReportingInterface { - public: - MonoThreadReporting(bool print_all, int num_solutions); - ~MonoThreadReporting() override; - - void Init(int thread_id, const std::string& init_string) override; - void OnSearchStart(int thread_id, Type type) override; - void OnSatSolution(int thread_id, - const std::string& solution_string) override; - void OnOptimizeSolution(int thread_id, int64 value, - const std::string& solution_string) override; - void Log(int thread_id, const std::string& final_output) const override; - void Print(int thread_id, const std::string& final_output) const override; - bool ShouldFinish() const override; - void OnSearchEnd(int thread_id, bool interrupted) override; - int64 BestSolution() const override; -#if !defined(SWIG) - OptimizeVar* CreateObjective(Solver* s, bool maximize, IntVar* var, - int64 step, int thread_id) const override; - SearchLimit* CreateLimit(Solver* s, int thread_id) const override; -#endif // SWIG - bool Interrupted() const override; - - private: - std::string last_solution_; - int64 best_objective_; - bool interrupted_; -}; - -class SilentMonoThreadReporting : public MonoThreadReporting { - public: - SilentMonoThreadReporting(bool print_all, int num_solutions); - ~SilentMonoThreadReporting() override; - - void Init(int thread_id, const std::string& init_string) override; - void Log(int thread_id, const std::string& message) const override; - void Print(int thread_id, const std::string& final_output) const override; -}; - -#if !defined(SWIG) -class MultiThreadReporting : public SearchReportingInterface { - public: - MultiThreadReporting(bool print_all, int num_solutions, bool verbose); - ~MultiThreadReporting() override; - void Init(int thread_id, const std::string& init_string) override; - void OnSearchStart(int thread_id, Type type) override; - void OnSatSolution(int thread_id, - const std::string& solution_string) override; - void OnOptimizeSolution(int thread_id, int64 value, - const std::string& solution_string) override; - void Log(int thread_id, const std::string& message) const override; - void Print(int thread_id, const std::string& message) const override; - bool ShouldFinish() const override; - void OnSearchEnd(int thread_id, bool interrupted) override; - int64 BestSolution() const override; - OptimizeVar* CreateObjective(Solver* s, bool maximize, IntVar* var, - int64 step, int thread_id) const override; - SearchLimit* CreateLimit(Solver* s, int thread_id) const override; - bool Interrupted() const override; - - private: - void LogNoLock(int thread_id, const std::string& message); - - const bool verbose_; - mutable absl::Mutex mutex_; - Type type_ GUARDED_BY(mutex_); - std::string last_solution_ GUARDED_BY(mutex_); - int last_thread_ GUARDED_BY(mutex_); - int64 best_objective_ GUARDED_BY(mutex_); - bool should_finish_ GUARDED_BY(mutex_); - bool interrupted_ GUARDED_BY(mutex_); -}; -#endif // SWIG -} // namespace fz -} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_REPORTING_H_ diff --git a/ortools/flatzinc/sat_constraint.cc b/ortools/flatzinc/sat_constraint.cc deleted file mode 100644 index 24a726538f..0000000000 --- a/ortools/flatzinc/sat_constraint.cc +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/sat_constraint.h" - -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/strings/str_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/hash.h" -#include "ortools/base/int_type.h" -#include "ortools/base/int_type_indexed_vector.h" -#include "ortools/base/integral_types.h" -#include "ortools/base/logging.h" -#include "ortools/base/map_util.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/constraint_solver/constraint_solveri.h" -#include "ortools/flatzinc/logging.h" -#include "ortools/sat/pb_constraint.h" -#include "ortools/sat/sat_base.h" -#include "ortools/sat/sat_solver.h" - -// #define SAT_DEBUG -#if defined(SAT_DEBUG) -#define SATDLOG FZDLOG -#else -#define SATDLOG \ - if (false) FZDLOG -#endif - -namespace operations_research { -// Constraint that tight together boolean variables in the CP solver to sat -// variables and clauses. -class SatPropagator : public Constraint { - public: - explicit SatPropagator(Solver* solver) - : Constraint(solver), sat_decision_level_(0) {} - - ~SatPropagator() override {} - - bool ExpressionIsBoolean(IntExpr* expr) const { - IntVar* expr_var = nullptr; - bool expr_negated = false; - return solver()->IsBooleanVar(expr, &expr_var, &expr_negated); - } - - bool AllVariablesAreBoolean(const std::vector& vars) const { - for (int i = 0; i < vars.size(); ++i) { - if (!ExpressionIsBoolean(vars[i])) { - return false; - } - } - return true; - } - - // Converts a constraint solver literal to the SatSolver representation. - sat::Literal GetOrCreateLiteral(IntExpr* expr) { - IntVar* expr_var = nullptr; - bool expr_negated = false; - CHECK(solver()->IsBooleanVar(expr, &expr_var, &expr_negated)); - SATDLOG << " - SAT: Parse " << expr->DebugString() << " to " - << expr_var->DebugString() << "/" << expr_negated << FZENDL; - if (gtl::ContainsKey(indices_, expr_var)) { - return sat::Literal(indices_[expr_var], !expr_negated); - } - const sat::BooleanVariable var = sat_.NewBooleanVariable(); - vars_.push_back(expr_var); - indices_[expr_var] = var; - const sat::Literal literal(var, !expr_negated); - SATDLOG << " - created var = " << var.value() - << ", literal = " << literal.SignedValue() << FZENDL; - return literal; - } - - // Queries the sat solver for all newly assigned literals, and propagates - // the values to the CP variables. - void QueryAssignedSatLiterals(int from_index) { - const int to_index = sat_.LiteralTrail().Index(); - for (int index = from_index; index < to_index; ++index) { - const sat::Literal literal = sat_.LiteralTrail()[index]; - const sat::BooleanVariable var = literal.Variable(); - const bool assigned_bool = literal.IsPositive(); - SATDLOG << " - var " << var << " was assigned to " << assigned_bool - << " from literal " << literal.SignedValue() << FZENDL; - demons_[var.value()]->inhibit(solver()); - vars_[var.value()]->SetValue(assigned_bool); - } - } - - // This method is called during the processing of the CP solver queue when - // a boolean variable is bound. - void OnBooleanVariableFixed(int index) { - if (sat_decision_level_.Value() < sat_.CurrentDecisionLevel()) { - SATDLOG << "After failure, sat_decision_level = " - << sat_decision_level_.Value() - << ", sat decision level = " << sat_.CurrentDecisionLevel() - << FZENDL; - sat_.Backtrack(sat_decision_level_.Value()); - DCHECK_EQ(sat_decision_level_.Value(), sat_.CurrentDecisionLevel()); - } - const sat::BooleanVariable var = sat::BooleanVariable(index); - SATDLOG << "OnBooleanVariableFixed: " << vars_[index]->DebugString() - << " with sat variable " << var << FZENDL; - const bool new_value = vars_[index]->Value() != 0; - const sat::Literal literal(var, new_value); - if (sat_.Assignment().VariableIsAssigned(var)) { - if (sat_.Assignment().LiteralIsTrue(literal)) { - SATDLOG << " - literal = " << literal.SignedValue() - << " already processed" << FZENDL; - return; - } else { - SATDLOG << " - literal = " << literal.SignedValue() - << " assign opposite value" << FZENDL; - solver()->Fail(); - } - } - SATDLOG << " - enqueue literal = " << literal.SignedValue() << " at depth " - << sat_decision_level_.Value() << FZENDL; - const int trail_index = sat_.LiteralTrail().Index(); - if (!sat_.EnqueueDecisionIfNotConflicting(literal)) { - SATDLOG << " - failure detected, should backtrack" << FZENDL; - solver()->Fail(); - } else { - sat_decision_level_.SetValue(solver(), sat_.CurrentDecisionLevel()); - QueryAssignedSatLiterals(trail_index); - } - } - - void Post() override { - demons_.resize(vars_.size()); - for (int i = 0; i < vars_.size(); ++i) { - demons_[i] = MakeConstraintDemon1(solver(), this, - &SatPropagator::OnBooleanVariableFixed, - "OnBooleanVariableFixed", i); - vars_[i]->WhenDomain(demons_[i]); - } - } - - void InitialPropagate() override { - SATDLOG << "Initial propagation on sat solver" << FZENDL; - QueryAssignedSatLiterals(0); - - for (int i = 0; i < vars_.size(); ++i) { - IntVar* const var = vars_[i]; - if (var->Bound()) { - OnBooleanVariableFixed(i); - } - } - SATDLOG << " - done" << FZENDL; - } - - sat::SatSolver* sat() { return &sat_; } - - std::string DebugString() const override { - return absl::StrFormat("SatConstraint(%d variables)", sat_.NumVariables()); - } - - void Accept(ModelVisitor* visitor) const override { - VLOG(1) << "Should Not Be Visited"; - } - - private: - sat::SatSolver sat_; - std::vector vars_; - absl::flat_hash_map indices_; - std::vector bound_literals_; - NumericalRev sat_decision_level_; - std::vector demons_; - std::vector early_deductions_; -}; - -bool AddBoolEq(SatPropagator* sat, IntExpr* left, IntExpr* right) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - sat->sat()->AddBinaryClause(left_literal.Negated(), right_literal); - sat->sat()->AddBinaryClause(left_literal, right_literal.Negated()); - return true; -} - -bool AddBoolLe(SatPropagator* sat, IntExpr* left, IntExpr* right) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - sat->sat()->AddBinaryClause(left_literal.Negated(), right_literal); - return true; -} - -bool AddBoolNot(SatPropagator* sat, IntExpr* left, IntExpr* right) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - sat->sat()->AddBinaryClause(left_literal.Negated(), right_literal.Negated()); - sat->sat()->AddBinaryClause(left_literal, right_literal); - return true; -} - -bool AddBoolOrArrayEqVar(SatPropagator* sat, const std::vector& vars, - IntExpr* target) { - if (!sat->AllVariablesAreBoolean(vars) || !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - std::vector lits(vars.size() + 1); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]); - } - lits[vars.size()] = target_literal.Negated(); - sat->sat()->AddProblemClause(lits); - for (int i = 0; i < vars.size(); ++i) { - sat->sat()->AddBinaryClause(target_literal, - sat->GetOrCreateLiteral(vars[i]).Negated()); - } - return true; -} - -bool AddBoolAndArrayEqVar(SatPropagator* sat, const std::vector& vars, - IntExpr* target) { - if (!sat->AllVariablesAreBoolean(vars) || !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - std::vector lits(vars.size() + 1); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]).Negated(); - } - lits[vars.size()] = target_literal; - sat->sat()->AddProblemClause(lits); - for (int i = 0; i < vars.size(); ++i) { - sat->sat()->AddBinaryClause(target_literal.Negated(), - sat->GetOrCreateLiteral(vars[i])); - } - return true; -} - -bool AddSumBoolArrayGreaterEqVar(SatPropagator* sat, - const std::vector& vars, - IntExpr* target) { - if (!sat->AllVariablesAreBoolean(vars) || !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - std::vector lits(vars.size() + 1); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]); - } - lits[vars.size()] = target_literal.Negated(); - sat->sat()->AddProblemClause(lits); - return true; -} - -bool AddMaxBoolArrayLessEqVar(SatPropagator* sat, - const std::vector& vars, - IntExpr* target) { - if (!sat->AllVariablesAreBoolean(vars) || !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - for (int i = 0; i < vars.size(); ++i) { - const sat::Literal literal = sat->GetOrCreateLiteral(vars[i]).Negated(); - sat->sat()->AddBinaryClause(target_literal, literal); - } - return true; -} - -bool AddBoolOrEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal, right_literal, - target_literal.Negated()); - sat->sat()->AddBinaryClause(left_literal.Negated(), target_literal); - sat->sat()->AddBinaryClause(right_literal.Negated(), target_literal); - return true; -} - -bool AddBoolAndEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal.Negated(), - target_literal); - sat->sat()->AddBinaryClause(left_literal, target_literal.Negated()); - sat->sat()->AddBinaryClause(right_literal, target_literal.Negated()); - return true; -} - -bool AddBoolIsEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal, - target_literal.Negated()); - sat->sat()->AddTernaryClause(left_literal, right_literal.Negated(), - target_literal.Negated()); - sat->sat()->AddTernaryClause(left_literal, right_literal, target_literal); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal.Negated(), - target_literal); - return true; -} - -bool AddBoolIsNEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal, - target_literal); - sat->sat()->AddTernaryClause(left_literal, right_literal.Negated(), - target_literal); - sat->sat()->AddTernaryClause(left_literal, right_literal, - target_literal.Negated()); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal.Negated(), - target_literal.Negated()); - return true; -} - -bool AddBoolIsLeVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal, - target_literal.Negated()); - sat->sat()->AddBinaryClause(left_literal, target_literal); - sat->sat()->AddBinaryClause(right_literal.Negated(), target_literal); - return true; -} - -bool AddBoolOrArrayEqualTrue(SatPropagator* sat, - const std::vector& vars) { - if (!sat->AllVariablesAreBoolean(vars)) { - return false; - } - std::vector lits(vars.size()); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]); - } - sat->sat()->AddProblemClause(lits); - return true; -} - -bool AddBoolAndArrayEqualFalse(SatPropagator* sat, - const std::vector& vars) { - if (!sat->AllVariablesAreBoolean(vars)) { - return false; - } - std::vector lits(vars.size()); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]).Negated(); - } - sat->sat()->AddProblemClause(lits); - return true; -} - -bool AddAtMostOne(SatPropagator* sat, const std::vector& vars) { - if (!sat->AllVariablesAreBoolean(vars)) { - return false; - } - std::vector lits(vars.size()); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]).Negated(); - } - for (int i = 0; i < lits.size() - 1; ++i) { - for (int j = i + 1; j < lits.size(); ++j) { - sat->sat()->AddBinaryClause(lits[i], lits[j]); - } - } - return true; -} - -bool AddAtMostNMinusOne(SatPropagator* sat, const std::vector& vars) { - if (!sat->AllVariablesAreBoolean(vars)) { - return false; - } - std::vector lits(vars.size()); - for (int i = 0; i < vars.size(); ++i) { - lits[i] = sat->GetOrCreateLiteral(vars[i]).Negated(); - } - sat->sat()->AddProblemClause(lits); - return true; -} - -bool AddArrayXor(SatPropagator* sat, const std::vector& vars) { - if (!sat->AllVariablesAreBoolean(vars)) { - return false; - } - return false; -} - -bool AddIntEqReif(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal, right_literal, target_literal); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal.Negated(), - target_literal); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal, - target_literal.Negated()); - sat->sat()->AddTernaryClause(left_literal, right_literal.Negated(), - target_literal.Negated()); - return true; -} - -bool AddIntNeReif(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target) { - if (!sat->ExpressionIsBoolean(left) || !sat->ExpressionIsBoolean(right) || - !sat->ExpressionIsBoolean(target)) { - return false; - } - const sat::Literal left_literal = sat->GetOrCreateLiteral(left); - const sat::Literal right_literal = sat->GetOrCreateLiteral(right); - const sat::Literal target_literal = sat->GetOrCreateLiteral(target); - sat->sat()->AddTernaryClause(left_literal, right_literal.Negated(), - target_literal); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal, - target_literal); - sat->sat()->AddTernaryClause(left_literal.Negated(), right_literal.Negated(), - target_literal.Negated()); - sat->sat()->AddTernaryClause(left_literal, right_literal, - target_literal.Negated()); - return true; -} - -bool AddSumInRange(SatPropagator* sat, const std::vector& vars, - int64 range_min, int64 range_max) { - std::vector terms(vars.size()); - for (int i = 0; i < vars.size(); ++i) { - const sat::Literal lit = sat->GetOrCreateLiteral(vars[i]); - terms[i] = sat::LiteralWithCoeff(lit, 1); - } - sat->sat()->AddLinearConstraint(range_min > 0, sat::Coefficient(range_min), - range_max < vars.size(), - sat::Coefficient(range_max), &terms); - return true; -} - -SatPropagator* MakeSatPropagator(Solver* solver) { - return solver->RevAlloc(new SatPropagator(solver)); -} - -#undef SATDLOG -} // namespace operations_research diff --git a/ortools/flatzinc/sat_constraint.h b/ortools/flatzinc/sat_constraint.h deleted file mode 100644 index c658ed8df4..0000000000 --- a/ortools/flatzinc/sat_constraint.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_SAT_CONSTRAINT_H_ -#define OR_TOOLS_FLATZINC_SAT_CONSTRAINT_H_ - -#include "ortools/constraint_solver/constraint_solver.h" - -namespace operations_research { -class SatPropagator; - -// Creates a special instance of CP constraint that connects to a sat solver. -// Ownership of the constraint belongs to the CP solver. -SatPropagator* MakeSatPropagator(Solver* solver); - -// All the functions below add the constraint described by the function name to -// a SatPropagator. All the IntExpr or IntVar must refer to Boolean variables, -// if not the functions will return false. - -bool AddBoolEq(SatPropagator* sat, IntExpr* left, IntExpr* right); - -bool AddBoolLe(SatPropagator* sat, IntExpr* left, IntExpr* right); - -bool AddBoolNot(SatPropagator* sat, IntExpr* left, IntExpr* right); - -bool AddBoolAndArrayEqVar(SatPropagator* sat, const std::vector& vars, - IntExpr* target); - -bool AddBoolOrArrayEqVar(SatPropagator* sat, const std::vector& vars, - IntExpr* target); - -bool AddSumBoolArrayGreaterEqVar(SatPropagator* sat, - const std::vector& vars, - IntExpr* target); - -bool AddMaxBoolArrayLessEqVar(SatPropagator* sat, - const std::vector& vars, - IntExpr* target); - -bool AddBoolAndEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddBoolIsNEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddBoolIsLeVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddBoolOrEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddBoolIsEqVar(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddBoolOrArrayEqualTrue(SatPropagator* sat, - const std::vector& vars); - -bool AddBoolAndArrayEqualFalse(SatPropagator* sat, - const std::vector& vars); - -bool AddAtMostOne(SatPropagator* sat, const std::vector& vars); - -bool AddAtMostNMinusOne(SatPropagator* sat, const std::vector& vars); - -bool AddArrayXor(SatPropagator* sat, const std::vector& vars); - -bool AddIntEqReif(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); -bool AddIntNeReif(SatPropagator* sat, IntExpr* left, IntExpr* right, - IntExpr* target); - -bool AddSumInRange(SatPropagator* sat, const std::vector& vars, - int64 range_min, int64 range_max); - -} // namespace operations_research -#endif // OR_TOOLS_FLATZINC_SAT_CONSTRAINT_H_ diff --git a/ortools/flatzinc/solver.cc b/ortools/flatzinc/solver.cc deleted file mode 100644 index ad3fbf7321..0000000000 --- a/ortools/flatzinc/solver.cc +++ /dev/null @@ -1,926 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/solver.h" - -#include - -#include "absl/container/flat_hash_set.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "ortools/base/hash.h" -#include "ortools/base/integral_types.h" -#include "ortools/base/logging.h" -#include "ortools/base/map_util.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/flatzinc/checker.h" -#include "ortools/flatzinc/constraints.h" -#include "ortools/flatzinc/logging.h" -#include "ortools/flatzinc/model.h" -#include "ortools/flatzinc/sat_constraint.h" -#include "ortools/util/string_array.h" - -DEFINE_bool(fz_use_sat, true, "Use a sat solver for propagating on Booleans."); -DEFINE_bool(fz_check_solutions, true, "Check solutions"); - -namespace operations_research { - -// TODO(user): Proper API. -extern std::string DefaultPhaseStatString(DecisionBuilder* db); - -namespace fz { - -// ----- Parameters ----- -FlatzincParameters::FlatzincParameters() - : all_solutions(false), - free_search(false), - last_conflict(false), - ignore_annotations(false), - ignore_unknown(true), - logging(false), - statistics(false), - verbose_impact(false), - run_all_heuristics(false), - heuristic_period(100), - log_period(1000000), - luby_restart(0), - num_solutions(1), - random_seed(0), - threads(0), - thread_id(-1), - time_limit_in_ms(0), - search_type(MIN_SIZE), - store_all_solutions(false) {} - -// TODO(user): Investigate having the constants directly in the -// definition of the struct. This has to be tested with visual studio -// 2013 and 2015. - -// ----- Solver ----- - -int64 Solver::SolutionValue(IntegerVariable* var) const { - IntExpr* const result = gtl::FindPtrOrNull(data_.extracted_map(), var); - if (result != nullptr) { - if (result->IsVar()) { - return result->Var()->Value(); - } else { - int64 emin = 0; - int64 emax = 0; - result->Range(&emin, &emax); - CHECK_EQ(emin, emax) << "Expression " << result->DebugString() - << " is not fixed to a single value at a solution"; - return emin; - } - } else { - CHECK(var->domain.HasOneValue()); - return var->domain.values[0]; - } -} - -// The format is fixed in the flatzinc specification. -std::string Solver::SolutionString(const SolutionOutputSpecs& output) const { - if (output.variable != nullptr) { - const int64 value = SolutionValue(output.variable); - if (output.display_as_boolean) { - return absl::StrFormat("%s = %s;", output.name, - value == 1 ? "true" : "false"); - } else { - return absl::StrFormat("%s = %d;", output.name, value); - } - } else { - const int bound_size = output.bounds.size(); - std::string result = - absl::StrFormat("%s = array%dd(", output.name, bound_size); - for (int i = 0; i < bound_size; ++i) { - if (output.bounds[i].max_value != 0) { - result.append(absl::StrFormat("%d..%d, ", output.bounds[i].min_value, - output.bounds[i].max_value)); - } else { - result.append("{},"); - } - } - result.append("["); - for (int i = 0; i < output.flat_variables.size(); ++i) { - const int64 value = SolutionValue(output.flat_variables[i]); - if (output.display_as_boolean) { - result.append(value ? "true" : "false"); - } else { - absl::StrAppend(&result, value); - } - if (i != output.flat_variables.size() - 1) { - result.append(", "); - } - } - result.append("]);"); - return result; - } - return ""; -} - -void Solver::StoreSolution() { - stored_values_.resize(stored_values_.size() + 1); - for (const SolutionOutputSpecs& output : model_.output()) { - if (output.variable != nullptr) { - const int64 value = SolutionValue(output.variable); - stored_values_.back()[output.variable] = value; - } else { - for (IntegerVariable* const var : output.flat_variables) { - const int64 value = SolutionValue(var); - stored_values_.back()[var] = value; - } - } - } -} - -namespace { -struct ConstraintsWithRequiredVariables { - Constraint* ct; - int index; - absl::flat_hash_set required; - - ConstraintsWithRequiredVariables( - Constraint* cte, int i, - const absl::flat_hash_set& defined) - : ct(cte), index(i) { - // Collect required variables. - for (const Argument& arg : ct->arguments) { - for (IntegerVariable* const var : arg.variables) { - if (var != cte->target_variable && gtl::ContainsKey(defined, var)) { - required.insert(var); - } - } - } - } - - std::string DebugString() const { - return absl::StrFormat("Ctio(%s, %d, deps_size = %u)", ct->type, index, - required.size()); - } -}; - -int ComputeWeight(const ConstraintsWithRequiredVariables& c) { - return c.required.size() * 2 + (c.ct->target_variable == nullptr); -} - -// Comparator to sort constraints based on numbers of required -// elements and index. Reverse sorting to put elements to remove at the end. -struct ConstraintsWithRequiredVariablesComparator { - bool operator()(ConstraintsWithRequiredVariables* a, - ConstraintsWithRequiredVariables* b) const { - const int a_weight = ComputeWeight(*a); - const int b_weight = ComputeWeight(*b); - return a_weight > b_weight || (a_weight == b_weight && a->index > b->index); - } -}; -} // namespace - -bool Solver::Extract() { - // Create the sat solver. - if (FLAGS_fz_use_sat) { - FZLOG << " - Use sat" << FZENDL; - data_.CreateSatPropagatorAndAddToSolver(); - } - - statistics_.BuildStatistics(); - - // Extract the variable without defining constraint, and stores the other in - // defined_variables. - FZLOG << "Extract variables" << FZENDL; - int extracted_variables = 0; - int extracted_constants = 0; - int skipped_variables = 0; - absl::flat_hash_set defined_variables; - for (IntegerVariable* const var : model_.variables()) { - if (var->defining_constraint == nullptr && var->active) { - data_.Extract(var); - if (var->domain.HasOneValue()) { - extracted_constants++; - } else { - extracted_variables++; - } - } else { - FZVLOG << "Skip " << var->DebugString() << FZENDL; - if (var->defining_constraint != nullptr) { - FZVLOG << " - defined by " << var->defining_constraint->DebugString() - << FZENDL; - } - defined_variables.insert(var); - skipped_variables++; - } - } - FZLOG << " - " << extracted_variables << " variables created" << FZENDL; - FZLOG << " - " << extracted_constants << " constants created" << FZENDL; - FZLOG << " - " << skipped_variables << " variables skipped" << FZENDL; - - FZLOG << "Extract constraints" << FZENDL; - - // Sort constraints such that defined variables are created before the - // extraction of the constraints that use them. - // TODO(user): Look at our graph algorithms. - int index = 0; - std::vector to_sort; - std::vector sorted; - absl::flat_hash_map> - dependencies; - for (Constraint* ct : model_.constraints()) { - if (ct != nullptr && ct->active) { - ConstraintsWithRequiredVariables* const ctio = - new ConstraintsWithRequiredVariables(ct, index++, defined_variables); - to_sort.push_back(ctio); - for (IntegerVariable* const var : ctio->required) { - dependencies[var].push_back(ctio); - } - } - } - - // Sort a first time. - std::sort(to_sort.begin(), to_sort.end(), - ConstraintsWithRequiredVariablesComparator()); - - // Topological sort. - while (!to_sort.empty()) { - if (!to_sort.back()->required.empty()) { - // Sort again. - std::sort(to_sort.begin(), to_sort.end(), - ConstraintsWithRequiredVariablesComparator()); - } - ConstraintsWithRequiredVariables* const ctio = to_sort.back(); - if (!ctio->required.empty()) { - // Recovery. We pick the last constraint (min number of required - // variable) - // And we clean all of them (mark as non target). - std::vector required_vars(ctio->required.begin(), - ctio->required.end()); - for (IntegerVariable* const fz_var : required_vars) { - FZDLOG << " - clean " << fz_var->DebugString() << FZENDL; - if (fz_var->defining_constraint != nullptr) { - fz_var->defining_constraint->target_variable = nullptr; - fz_var->defining_constraint = nullptr; - } - for (ConstraintsWithRequiredVariables* const to_clean : - dependencies[fz_var]) { - to_clean->required.erase(fz_var); - } - } - continue; - } - to_sort.pop_back(); - FZDLOG << "Pop " << ctio->ct->DebugString() << FZENDL; - CHECK(ctio->required.empty()); - // TODO(user): Implement recovery mode. - sorted.push_back(ctio->ct); - IntegerVariable* const var = ctio->ct->target_variable; - if (var != nullptr && gtl::ContainsKey(dependencies, var)) { - FZDLOG << " - clean " << var->DebugString() << FZENDL; - for (ConstraintsWithRequiredVariables* const to_clean : - dependencies[var]) { - to_clean->required.erase(var); - } - } - delete ctio; - } - - // Start by identifying the all differents constraints. This does not process - // them yet. - for (Constraint* const ct : model_.constraints()) { - if (ct->type == "all_different_int") { - data_.StoreAllDifferent(ct->arguments[0].variables); - } - } - - // Then extract all constraints one by one. - for (Constraint* const ct : sorted) { - ExtractConstraint(&data_, ct); - } - - // Display some nice statistics. - FZLOG << " - " << sorted.size() << " constraints parsed" << FZENDL; - const int num_cp_constraints = solver_->constraints(); - if (num_cp_constraints <= 1) { - FZLOG << " - " << num_cp_constraints - << " constraint added to the CP solver" << FZENDL; - } else { - FZLOG << " - " << num_cp_constraints - << " constraints added to the CP solver" << FZENDL; - } - // TODO(user): Print the number of sat clauses/constraints. - - // Add domain constraints to created expressions. - int domain_constraints = 0; - for (IntegerVariable* const var : model_.variables()) { - if (var->defining_constraint != nullptr && var->active) { - const Domain& domain = var->domain; - if (!domain.is_interval && domain.values.size() == 2 && - domain.values[0] == 0 && domain.values[1] == 1) { - // Canonicalize domains: {0, 1} -> [0 ,, 1] - var->domain.is_interval = true; - } - IntExpr* const expr = data_.Extract(var); - if (expr->IsVar() && domain.is_interval && !domain.values.empty() && - (expr->Min() < domain.values[0] || expr->Max() > domain.values[1])) { - FZVLOG << "Intersect variable domain of " << expr->DebugString() - << " with" << domain.DebugString() << FZENDL; - expr->Var()->SetRange(domain.values[0], domain.values[1]); - } else if (expr->IsVar() && !domain.is_interval) { - FZVLOG << "Intersect variable domain of " << expr->DebugString() - << " with " << domain.DebugString() << FZENDL; - expr->Var()->SetValues(domain.values); - } else if (domain.is_interval && !domain.values.empty() && - (expr->Min() < domain.values[0] || - expr->Max() > domain.values[1])) { - FZVLOG << "Add domain constraint " << domain.DebugString() << " onto " - << expr->DebugString() << FZENDL; - solver_->AddConstraint(solver_->MakeBetweenCt( - expr->Var(), domain.values[0], domain.values[1])); - domain_constraints++; - } else if (!domain.is_interval) { - FZVLOG << "Add domain constraint " << domain.DebugString() << " onto " - << expr->DebugString() << FZENDL; - solver_->AddConstraint( - solver_->MakeMemberCt(expr->Var(), domain.values)); - domain_constraints++; - } - } - } - if (domain_constraints == 1) { - FZLOG << " - 1 domain constraint added" << FZENDL; - } else if (domain_constraints > 1) { - FZLOG << " - " << domain_constraints << " domain constraints added" - << FZENDL; - } - - return true; -} - -void Solver::ParseSearchAnnotations(bool ignore_unknown, - std::vector* defined, - std::vector* defined_variables, - std::vector* active_variables, - std::vector* defined_occurrences, - std::vector* active_occurrences) { - std::vector flat_annotations; - for (const Annotation& ann : model_.search_annotations()) { - FlattenAnnotations(ann, &flat_annotations); - } - - FZLOG << " - parsing search annotations" << FZENDL; - absl::flat_hash_set added; - for (const Annotation& ann : flat_annotations) { - FZLOG << " - parse " << ann.DebugString() << FZENDL; - if (ann.IsFunctionCallWithIdentifier("int_search")) { - const std::vector& args = ann.annotations; - const Annotation& vars = args[0]; - std::vector int_vars; - std::vector occurrences; - std::vector fz_vars; - vars.AppendAllIntegerVariables(&fz_vars); - for (IntegerVariable* const fz_var : fz_vars) { - IntVar* const to_add = data_.Extract(fz_var)->Var(); - const int occ = statistics_.NumVariableOccurrences(fz_var); - if (!gtl::ContainsKey(added, to_add) && !to_add->Bound()) { - added.insert(to_add); - int_vars.push_back(to_add); - occurrences.push_back(occ); - defined_variables->push_back(to_add); - defined_occurrences->push_back(occ); - } - } - const Annotation& choose = args[1]; - operations_research::Solver::IntVarStrategy str = - operations_research::Solver::CHOOSE_MIN_SIZE_LOWEST_MIN; - if (choose.id == "input_order") { - str = operations_research::Solver::CHOOSE_FIRST_UNBOUND; - } - if (choose.id == "first_fail") { - str = operations_research::Solver::CHOOSE_MIN_SIZE; - } - if (choose.id == "anti_first_fail") { - str = operations_research::Solver::CHOOSE_MAX_SIZE; - } - if (choose.id == "smallest") { - str = operations_research::Solver::CHOOSE_LOWEST_MIN; - } - if (choose.id == "largest") { - str = operations_research::Solver::CHOOSE_HIGHEST_MAX; - } - if (choose.id == "max_regret") { - str = operations_research::Solver::CHOOSE_MAX_REGRET_ON_MIN; - } - if (choose.id == "occurrence") { - SortVariableByDegree(occurrences, false, &int_vars); - str = operations_research::Solver::CHOOSE_FIRST_UNBOUND; - } - if (choose.id == "most_constrained") { - SortVariableByDegree(occurrences, false, &int_vars); - str = operations_research::Solver::CHOOSE_MIN_SIZE; - } - const Annotation& select = args[2]; - operations_research::Solver::IntValueStrategy vstr = - operations_research::Solver::ASSIGN_MIN_VALUE; - if (select.id == "indomain_max") { - vstr = operations_research::Solver::ASSIGN_MAX_VALUE; - } - if (select.id == "indomain_median" || select.id == "indomain_middle") { - vstr = operations_research::Solver::ASSIGN_CENTER_VALUE; - } - if (select.id == "indomain_random") { - vstr = operations_research::Solver::ASSIGN_RANDOM_VALUE; - } - if (select.id == "indomain_split") { - vstr = operations_research::Solver::SPLIT_LOWER_HALF; - } - if (select.id == "indomain_reverse_split") { - vstr = operations_research::Solver::SPLIT_UPPER_HALF; - } - DecisionBuilder* const db = solver_->MakePhase(int_vars, str, vstr); - defined->push_back(db); - } else if (ann.IsFunctionCallWithIdentifier("bool_search")) { - const std::vector& args = ann.annotations; - const Annotation& vars = args[0]; - std::vector bool_vars; - std::vector occurrences; - std::vector fz_vars; - vars.AppendAllIntegerVariables(&fz_vars); - for (IntegerVariable* const fz_var : fz_vars) { - IntVar* const to_add = data_.Extract(fz_var)->Var(); - const int occ = statistics_.NumVariableOccurrences(fz_var); - if (!gtl::ContainsKey(added, to_add) && !to_add->Bound()) { - added.insert(to_add); - bool_vars.push_back(to_add); - occurrences.push_back(occ); - defined_variables->push_back(to_add); - defined_occurrences->push_back(occ); - } - } - const Annotation& choose = args[1]; - operations_research::Solver::IntVarStrategy str = - operations_research::Solver::CHOOSE_FIRST_UNBOUND; - if (choose.id == "occurrence") { - SortVariableByDegree(occurrences, false, &bool_vars); - str = operations_research::Solver::CHOOSE_FIRST_UNBOUND; - } - const Annotation& select = args[2]; - operations_research::Solver::IntValueStrategy vstr = - operations_research::Solver::ASSIGN_MAX_VALUE; - if (select.id == "indomain_min") { - vstr = operations_research::Solver::ASSIGN_MIN_VALUE; - } - if (select.id == "indomain_random") { - vstr = operations_research::Solver::ASSIGN_RANDOM_VALUE; - } - if (!bool_vars.empty()) { - defined->push_back(solver_->MakePhase(bool_vars, str, vstr)); - } - } - } - - // Create the active_variables array, push smaller variables first. - for (IntVar* const var : active_variables_) { - if (!gtl::ContainsKey(added, var) && !var->Bound()) { - if (var->Size() < 0xFFFF) { - added.insert(var); - active_variables->push_back(var); - active_occurrences->push_back(extracted_occurrences_[var]); - } - } - } - for (IntVar* const var : active_variables_) { - if (!gtl::ContainsKey(added, var) && !var->Bound()) { - if (var->Size() >= 0xFFFF) { - added.insert(var); - active_variables->push_back(var); - active_occurrences->push_back(extracted_occurrences_[var]); - } - } - } - FZVLOG << "Active variables = [" - << JoinDebugStringPtr(*active_variables, ", ") << "]" << FZENDL; -} - -void Solver::CollectOutputVariables(std::vector* out) { - for (const SolutionOutputSpecs& output : model_.output()) { - if (output.variable != nullptr) { - if (!gtl::ContainsKey(implied_variables_, output.variable)) { - out->push_back(data_.Extract(output.variable)->Var()); - } - } - for (IntegerVariable* const var : output.flat_variables) { - if (var->defining_constraint == nullptr && - !gtl::ContainsKey(implied_variables_, var)) { - out->push_back(data_.Extract(var)->Var()); - } - } - } -} - -// Add completion goals to be robust to incomplete search specifications. -void Solver::AddCompletionDecisionBuilders( - const std::vector& defined_variables, - const std::vector& active_variables, SearchLimit* limit, - std::vector* builders) { - absl::flat_hash_set defined_set(defined_variables.begin(), - defined_variables.end()); - std::vector output_variables; - CollectOutputVariables(&output_variables); - std::vector secondary_vars; - for (IntVar* const var : active_variables) { - if (!gtl::ContainsKey(defined_set, var) && !var->Bound()) { - secondary_vars.push_back(var); - } - } - for (IntVar* const var : output_variables) { - if (!gtl::ContainsKey(defined_set, var) && !var->Bound()) { - secondary_vars.push_back(var); - } - } - if (!secondary_vars.empty()) { - builders->push_back(solver_->MakeSolveOnce( - solver_->MakePhase(secondary_vars, - operations_research::Solver::CHOOSE_FIRST_UNBOUND, - operations_research::Solver::ASSIGN_MIN_VALUE), - limit)); - } -} - -DecisionBuilder* Solver::CreateDecisionBuilders(const FlatzincParameters& p, - SearchLimit* limit) { - FZLOG << "Defining search" << (p.free_search ? " (free)" : " (fixed)") - << FZENDL; - // Fill builders_ with predefined search. - std::vector defined; - std::vector defined_variables; - std::vector defined_occurrences; - std::vector active_variables; - std::vector active_occurrences; - DecisionBuilder* obj_db = nullptr; - ParseSearchAnnotations(p.ignore_unknown, &defined, &defined_variables, - &active_variables, &defined_occurrences, - &active_occurrences); - - search_name_ = - defined.empty() ? "automatic" : (p.free_search ? "free" : "defined"); - - // We fill builders with information from search (flags, annotations). - std::vector builders; - if (!p.free_search && !defined.empty()) { - builders = defined; - default_phase_ = nullptr; - } else { - if (defined_variables.empty()) { - CHECK(defined.empty()); - defined_variables.swap(active_variables); - defined_occurrences.swap(active_occurrences); - } - DefaultPhaseParameters parameters; - DecisionBuilder* inner_builder = nullptr; - switch (p.search_type) { - case FlatzincParameters::DEFAULT: { - if (defined.empty()) { - SortVariableByDegree(defined_occurrences, true, &defined_variables); - inner_builder = solver_->MakePhase( - defined_variables, operations_research::Solver::CHOOSE_MIN_SIZE, - operations_research::Solver::ASSIGN_MIN_VALUE); - } else { - inner_builder = solver_->Compose(defined); - } - break; - } - case FlatzincParameters::IBS: { - break; - } - case FlatzincParameters::FIRST_UNBOUND: { - inner_builder = solver_->MakePhase( - defined_variables, - operations_research::Solver::CHOOSE_FIRST_UNBOUND, - operations_research::Solver::ASSIGN_MIN_VALUE); - break; - } - case FlatzincParameters::MIN_SIZE: { - inner_builder = solver_->MakePhase( - defined_variables, - operations_research::Solver::CHOOSE_MIN_SIZE_LOWEST_MIN, - operations_research::Solver::ASSIGN_MIN_VALUE); - break; - } - case FlatzincParameters::RANDOM_MIN: { - inner_builder = solver_->MakePhase( - defined_variables, operations_research::Solver::CHOOSE_RANDOM, - operations_research::Solver::ASSIGN_MIN_VALUE); - break; - } - case FlatzincParameters::RANDOM_MAX: { - inner_builder = solver_->MakePhase( - defined_variables, operations_research::Solver::CHOOSE_RANDOM, - operations_research::Solver::ASSIGN_MAX_VALUE); - } - } - parameters.use_last_conflict = p.last_conflict; - parameters.run_all_heuristics = p.run_all_heuristics; - parameters.heuristic_period = - model_.objective() != nullptr || - (!p.all_solutions && p.num_solutions == 1) - ? p.heuristic_period - : -1; - parameters.display_level = - p.logging ? (p.verbose_impact ? DefaultPhaseParameters::VERBOSE - : DefaultPhaseParameters::NORMAL) - : DefaultPhaseParameters::NONE; - parameters.var_selection_schema = - DefaultPhaseParameters::CHOOSE_MAX_SUM_IMPACT; - parameters.value_selection_schema = - DefaultPhaseParameters::SELECT_MIN_IMPACT; - parameters.random_seed = p.random_seed; - if (inner_builder == nullptr) { - CHECK_EQ(FlatzincParameters::IBS, p.search_type); - parameters.decision_builder = nullptr; - } else { - parameters.decision_builder = inner_builder; - } - default_phase_ = solver_->MakeDefaultPhase(defined_variables, parameters); - builders.push_back(default_phase_); - } - - // Add the objective decision builder. - if (obj_db != nullptr) { - builders.push_back(obj_db); - } else if (model_.objective() != nullptr) { - // The model contains an objective, but the obj_db was not built. - IntVar* const obj_var = data_.Extract(model_.objective())->Var(); - obj_db = solver_->MakePhase( - obj_var, operations_research::Solver::CHOOSE_FIRST_UNBOUND, - model_.maximize() ? operations_research::Solver::ASSIGN_MAX_VALUE - : operations_research::Solver::ASSIGN_MIN_VALUE); - builders.push_back(obj_db); - FZVLOG << " - adding objective decision builder = " - << obj_db->DebugString() << FZENDL; - } - // Add completion decision builders to be more robust. - AddCompletionDecisionBuilders(defined_variables, active_variables, limit, - &builders); - // Reporting - for (DecisionBuilder* const db : builders) { - FZVLOG << " - adding decision builder = " << db->DebugString() << FZENDL; - } - return solver_->Compose(builders); -} - -void Solver::SyncWithModel() { - for (Constraint* const ct : model_.constraints()) { - if (ct->active) { - MarkComputedVariables(ct, &implied_variables_); - } - } - - for (IntegerVariable* const fz_var : model_.variables()) { - if (!fz_var->active || fz_var->defining_constraint != nullptr || - gtl::ContainsKey(implied_variables_, fz_var)) { - continue; - } - IntExpr* const expr = data_.Extract(fz_var); - if (!expr->IsVar() || expr->Var()->Bound()) { - continue; - } - IntVar* const var = expr->Var(); - extracted_occurrences_[var] = statistics_.NumVariableOccurrences(fz_var); - active_variables_.push_back(var); - } - if (model_.objective() != nullptr) { - objective_var_ = data_.Extract(model_.objective())->Var(); - } -} - -void Solver::ReportInconsistentModel(const Model& model, FlatzincParameters p, - SearchReportingInterface* report) { - // Special mode. Print out failure status. - const std::string search_status = "=====UNSATISFIABLE====="; - report->Print(p.thread_id, search_status); - if (p.statistics) { - std::string solver_status = - "%% name, status, obj, solns, s_time, b_time, br, " - "fails, cts, demon, delayed, mem, search\n"; - absl::StrAppendFormat( - &solver_status, - "%%%% csv: %s, **unsat**, , 0, 0 ms, 0 ms, 0, 0, 0, 0, 0, %s, free", - model.name(), MemoryUsage()); - report->Print(p.thread_id, solver_status); - } -} - -void Solver::Solve(FlatzincParameters p, SearchReportingInterface* report) { - SyncWithModel(); - SearchLimit* const limit = p.time_limit_in_ms > 0 - ? solver_->MakeTimeLimit(p.time_limit_in_ms) - : nullptr; - - SearchLimit* const shadow = - limit == nullptr - ? nullptr - : solver_->MakeCustomLimit([limit]() { return limit->Check(); }); - DecisionBuilder* const db = CreateDecisionBuilders(p, shadow); - std::vector monitors; - if (model_.objective() != nullptr) { - objective_monitor_ = report->CreateObjective( - solver_, model_.maximize(), objective_var_, 1, p.thread_id); - SearchMonitor* const log = - p.logging ? solver_->RevAlloc( - new Log(solver_, objective_monitor_, p.log_period)) - : nullptr; - SearchLimit* const ctrl_c = solver_->RevAlloc(new Interrupt(solver_)); - monitors.push_back(log); - monitors.push_back(objective_monitor_); - monitors.push_back(ctrl_c); - report->OnSearchStart( - p.thread_id, model_.maximize() ? SearchReportingInterface::MAXIMIZE - : SearchReportingInterface::MINIMIZE); - } else { - SearchMonitor* const log = - p.logging ? solver_->RevAlloc(new Log(solver_, nullptr, p.log_period)) - : nullptr; - monitors.push_back(log); - report->OnSearchStart(p.thread_id, SearchReportingInterface::SATISFY); - } - // Custom limit in case of parallelism. - monitors.push_back(report->CreateLimit(solver_, p.thread_id)); - - if (limit != nullptr) { - FZLOG << " - adding a time limit of " << p.time_limit_in_ms << " ms" - << FZENDL; - } - monitors.push_back(limit); - - if (p.all_solutions && p.num_solutions == kint32max) { - FZLOG << " - searching for all solutions" << FZENDL; - } else if (p.all_solutions && p.num_solutions > 1) { - FZLOG << " - searching for " << p.num_solutions << " solutions" << FZENDL; - } else if (model_.objective() == nullptr || - (p.all_solutions && p.num_solutions == 1)) { - FZLOG << " - searching for the first solution" << FZENDL; - } else { - FZLOG << " - search for the best solution" << FZENDL; - } - - if (p.luby_restart > 0) { - FZLOG << " - using luby restart with a factor of " << p.luby_restart - << FZENDL; - monitors.push_back(solver_->MakeLubyRestart(p.luby_restart)); - } - if (p.last_conflict && p.free_search) { - FZLOG << " - using last conflict search hints" << FZENDL; - } - if (FLAGS_fz_check_solutions) { - FZLOG << " - using solution checker" << FZENDL; - } - - bool breaked = false; - std::string solution_string; - const int64 build_time = solver_->wall_time(); - solver_->NewSearch(db, monitors); - while (solver_->NextSolution()) { - if (FLAGS_fz_check_solutions) { - CHECK(CheckSolution( - model_, [this](IntegerVariable* v) { return SolutionValue(v); })); - } - if (!report->ShouldFinish()) { - solution_string.clear(); - if (!model_.output().empty()) { - for (const SolutionOutputSpecs& output : model_.output()) { - solution_string.append(SolutionString(output)); - solution_string.append("\n"); - } - if (p.store_all_solutions) { - StoreSolution(); - } - } - solution_string.append("----------"); - if (model_.objective() != nullptr) { - const int64 best = objective_monitor_->best(); - report->OnOptimizeSolution(p.thread_id, best, solution_string); - if ((p.num_solutions != 1 && - report->NumSolutions() >= p.num_solutions) || - (p.all_solutions && p.num_solutions == 1 && - report->NumSolutions() >= 1)) { - break; - } - } else { - report->OnSatSolution(p.thread_id, solution_string); - if (report->NumSolutions() >= p.num_solutions) { - break; - } - } - } - } - solver_->EndSearch(); - report->OnSearchEnd(p.thread_id, limit != nullptr ? limit->crossed() : false); - const int64 solve_time = solver_->wall_time() - build_time; - const int num_solutions = report->NumSolutions(); - bool proven = false; - bool timeout = false; - std::string search_status; - std::string solver_status; - if (p.thread_id <= 0) { - if (p.thread_id == 0) { - // Recompute the breaked variable. - if (model_.objective() == nullptr) { - breaked = report->NumSolutions() >= p.num_solutions; - } else { - breaked = - (p.num_solutions != 1 && num_solutions >= p.num_solutions) || - (p.all_solutions && p.num_solutions == 1 && num_solutions >= 1); - } - } - - if (report->Interrupted() || Interrupt::Interrupted()) { - search_status = "%% TIMEOUT"; - timeout = true; - } else if (!breaked && num_solutions == 0 && !report->Interrupted() && - !Interrupt::Interrupted()) { - search_status = "=====UNSATISFIABLE====="; - } else if (!breaked && !report->Interrupted() && - !Interrupt::Interrupted() && - (model_.objective() != nullptr || p.all_solutions)) { - search_status = "=========="; - proven = true; - } - solver_status.append(absl::StrFormat("%%%% total runtime: %d ms\n", - solve_time + build_time)); - solver_status.append( - absl::StrFormat("%%%% build time: %d ms\n", build_time)); - solver_status.append( - absl::StrFormat("%%%% solve time: %d ms\n", solve_time)); - solver_status.append( - absl::StrFormat("%%%% solutions: %d\n", num_solutions)); - solver_status.append(absl::StrFormat("%%%% constraints: %d\n", - solver_->constraints())); - solver_status.append(absl::StrFormat( - "%%%% normal propagations: %d\n", - solver_->demon_runs(operations_research::Solver::NORMAL_PRIORITY))); - solver_status.append(absl::StrFormat( - "%%%% delayed propagations: %d\n", - solver_->demon_runs(operations_research::Solver::DELAYED_PRIORITY))); - solver_status.append(absl::StrFormat("%%%% branches: %d\n", - solver_->branches())); - solver_status.append(absl::StrFormat("%%%% failures: %d\n", - solver_->failures())); - solver_status.append( - absl::StrFormat("%%%% memory: %s\n", MemoryUsage())); - const int64 best = report->BestSolution(); - if (model_.objective() != nullptr) { - if (!model_.maximize() && num_solutions > 0) { - solver_status.append( - absl::StrFormat("%%%% min objective: %d%s\n", best, - (proven ? " (proven)" : ""))); - } else if (num_solutions > 0) { - solver_status.append( - absl::StrFormat("%%%% max objective: %d%s\n", best, - (proven ? " (proven)" : ""))); - } - } - - if (default_phase_ != nullptr) { - const std::string default_search_stats = - DefaultPhaseStatString(default_phase_); - if (!default_search_stats.empty()) { - solver_status.append(absl::StrFormat("%%%% free search stats: %s\n", - default_search_stats)); - } - } - - const bool no_solutions = num_solutions == 0; - const std::string status_string = - (no_solutions ? (timeout ? "**timeout**" : "**unsat**") - : (model_.objective() == nullptr - ? "**sat**" - : (timeout ? "**feasible**" : "**proven**"))); - const std::string obj_string = - (model_.objective() != nullptr && !no_solutions ? absl::StrCat(best) - : ""); - solver_status.append( - "%% name, status, obj, solns, s_time, b_time, br, " - "fails, cts, demon, delayed, mem, search\n"); - solver_status.append(absl::StrFormat( - "%%%% csv: %s, %s, %s, %d, %d ms, %d ms, %d, %d, %d, %d, %d, %s, %s", - model_.name(), status_string, obj_string, num_solutions, solve_time, - build_time, solver_->branches(), solver_->failures(), - solver_->constraints(), - solver_->demon_runs(operations_research::Solver::NORMAL_PRIORITY), - solver_->demon_runs(operations_research::Solver::DELAYED_PRIORITY), - MemoryUsage(), search_name_)); - report->Print(p.thread_id, search_status); - if (p.statistics) { - report->Print(p.thread_id, solver_status); - } - } -} -} // namespace fz -} // namespace operations_research diff --git a/ortools/flatzinc/solver.h b/ortools/flatzinc/solver.h deleted file mode 100644 index 768cefb3d7..0000000000 --- a/ortools/flatzinc/solver.h +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_SOLVER_H_ -#define OR_TOOLS_FLATZINC_SOLVER_H_ - -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/flatzinc/model.h" -#include "ortools/flatzinc/reporting.h" -#include "ortools/flatzinc/solver_data.h" -#include "ortools/flatzinc/solver_util.h" - -namespace operations_research { -class SatPropagator; - -namespace fz { -// Search parameter for the flatzinc solver. -struct FlatzincParameters { - enum SearchType { - DEFAULT, - IBS, - FIRST_UNBOUND, - MIN_SIZE, - RANDOM_MIN, - RANDOM_MAX, - }; - - FlatzincParameters(); - - bool all_solutions; - bool free_search; - bool last_conflict; - bool ignore_annotations; - bool ignore_unknown; - bool logging; - bool statistics; - bool verbose_impact; - bool run_all_heuristics; - int heuristic_period; - int log_period; - int luby_restart; - int num_solutions; - int random_seed; - int threads; - int thread_id; - // TODO(user): Store time limit in seconds (double). - int64 time_limit_in_ms; - SearchType search_type; - bool store_all_solutions; -}; - -// The main class to search for a solution in a flatzinc model. It is -// responsible for parsing the search annotations, setting up the -// search state and performing the actual search. -class Solver { - public: - explicit Solver(const Model& model) - : model_(model), - statistics_(model), - data_(model.name()), - objective_var_(nullptr), - objective_monitor_(nullptr), - default_phase_(nullptr) { - solver_ = data_.solver(); - } - - // Searches for for solutions in the model passed at construction - // time. The exact search context (search for optimal solution, for - // n solutions, for the first solution) is specified in the - // parameters. - // The parallel context (sequential, multi-threaded) is encapsulated - // in the search reporting interface. - void Solve(FlatzincParameters p, SearchReportingInterface* report); - - // Extraction support. - bool Extract(); - - // String output for the minizinc interface. - std::string SolutionString(const SolutionOutputSpecs& output) const; - - // Query the value of the variable. This must be called during search, when - // a solution is found. - int64 SolutionValue(IntegerVariable* var) const; - - // Programmatic interface to read the solutions. - - // Returns the number of solutions stored. You need to set store_all_solution - // to true in the parameters, otherwise this method will always return 0. - int NumStoredSolutions() const { return stored_values_.size(); } - // Returns the stored value for the given variable in the solution_index'th - // stored solution. - // A variable is stored only if it appears in the output part of the model. - int64 StoredValue(int solution_index, IntegerVariable* var) { - CHECK_GE(solution_index, 0); - CHECK_LT(solution_index, stored_values_.size()); - CHECK(gtl::ContainsKey(stored_values_[solution_index], var)); - return stored_values_[solution_index][var]; - } - - static void ReportInconsistentModel(const Model& model, FlatzincParameters p, - SearchReportingInterface* report); - - private: - void StoreSolution(); - bool HasSearchAnnotations() const; - void ParseSearchAnnotations(bool ignore_unknown, - std::vector* defined, - std::vector* defined_variables, - std::vector* active_variables, - std::vector* defined_occurrences, - std::vector* active_occurrences); - void AddCompletionDecisionBuilders( - const std::vector& defined_variables, - const std::vector& active_variables, SearchLimit* limit, - std::vector* builders); - DecisionBuilder* CreateDecisionBuilders(const FlatzincParameters& p, - SearchLimit* limit); - void CollectOutputVariables(std::vector* output_variables); - void SyncWithModel(); - - const Model& model_; - ModelStatistics statistics_; - SolverData data_; - std::vector active_variables_; - absl::flat_hash_map extracted_occurrences_; - absl::flat_hash_set implied_variables_; - std::string search_name_; - IntVar* objective_var_; - OptimizeVar* objective_monitor_; - // Default Search Phase (to get stats). - DecisionBuilder* default_phase_; - // Stored solutions. - std::vector> stored_values_; - operations_research::Solver* solver_; -}; -} // namespace fz -} // namespace operations_research - -#endif // OR_TOOLS_FLATZINC_SOLVER_H_ diff --git a/ortools/flatzinc/solver_data.cc b/ortools/flatzinc/solver_data.cc deleted file mode 100644 index d5d2f5c551..0000000000 --- a/ortools/flatzinc/solver_data.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/solver_data.h" - -#include "ortools/flatzinc/logging.h" - -namespace operations_research { -namespace fz { - -IntExpr* SolverData::GetOrCreateExpression(const Argument& arg) { - switch (arg.type) { - case Argument::INT_VALUE: { - return solver_.MakeIntConst(arg.Value()); - } - case Argument::INT_VAR_REF: { - return Extract(arg.variables[0]); - } - default: { - LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable"; - return nullptr; - } - } -} - -std::vector SolverData::GetOrCreateVariableArray(const Argument& arg) { - std::vector result; - if (arg.type == Argument::INT_VAR_REF_ARRAY) { - result.resize(arg.variables.size()); - for (int i = 0; i < arg.variables.size(); ++i) { - result[i] = Extract(arg.variables[i])->Var(); - } - } else if (arg.type == Argument::INT_LIST) { - result.resize(arg.values.size()); - for (int i = 0; i < arg.values.size(); ++i) { - result[i] = solver_.MakeIntConst(arg.values[i]); - } - } else if (arg.type == Argument::VOID_ARGUMENT) { - // Nothing to do. - } else { - LOG(FATAL) << "Cannot extract " << arg.DebugString() - << " as a variable array"; - } - return result; -} - -IntExpr* SolverData::Extract(IntegerVariable* var) { - IntExpr* result = gtl::FindPtrOrNull(extracted_map_, var); - if (result != nullptr) { - return result; - } - if (var->domain.HasOneValue()) { - result = solver_.MakeIntConst(var->domain.values.back()); - } else if (var->domain.IsAllInt64()) { - result = solver_.MakeIntVar(kint32min, kint32max, var->name); - } else if (var->domain.is_interval) { - result = solver_.MakeIntVar(std::max(var->domain.Min(), kint32min), - std::min(var->domain.Max(), kint32max), - var->name); - } else { - result = solver_.MakeIntVar(var->domain.values, var->name); - } - FZVLOG << "Extract " << var->DebugString() << FZENDL; - FZVLOG << " - created " << result->DebugString() << FZENDL; - extracted_map_[var] = result; - return result; -} - -void SolverData::SetExtracted(IntegerVariable* fz_var, IntExpr* expr) { - CHECK(!gtl::ContainsKey(extracted_map_, fz_var)); - if (!expr->IsVar() && !fz_var->domain.is_interval) { - FZVLOG << " - lift to var" << FZENDL; - expr = expr->Var(); - } - extracted_map_[fz_var] = expr; -} - -void SolverData::StoreAllDifferent(std::vector diffs) { - if (!diffs.empty()) { - std::sort(diffs.begin(), diffs.end()); - FZVLOG << "Store AllDifferent info for [" << JoinDebugStringPtr(diffs, ", ") - << "]" << FZENDL; - alldiffs_.insert(diffs); - } -} - -bool SolverData::IsAllDifferent(std::vector diffs) const { - std::sort(diffs.begin(), diffs.end()); - return gtl::ContainsKey(alldiffs_, diffs); -} - -void SolverData::CreateSatPropagatorAndAddToSolver() { - CHECK(sat_ == nullptr); - sat_ = MakeSatPropagator(&solver_); - solver_.AddConstraint( - reinterpret_cast(sat_)); -} -} // namespace fz -} // namespace operations_research diff --git a/ortools/flatzinc/solver_data.h b/ortools/flatzinc/solver_data.h deleted file mode 100644 index 0854e5cdc3..0000000000 --- a/ortools/flatzinc/solver_data.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_SOLVER_DATA_H_ -#define OR_TOOLS_FLATZINC_SOLVER_DATA_H_ - -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/flatzinc/model.h" -#include "ortools/flatzinc/sat_constraint.h" - -namespace operations_research { -namespace fz { - -// Data structure to hold the mapping between flatzinc model objects and CP -// objects. -class SolverData { - public: - explicit SolverData(const std::string& name) : solver_(name), sat_(nullptr) {} - - // ----- Methods that deals with expressions and variables ----- - IntExpr* GetOrCreateExpression(const Argument& argument); - std::vector GetOrCreateVariableArray(const Argument& argument); - IntExpr* Extract(IntegerVariable* var); - void SetExtracted(IntegerVariable* var, IntExpr* expr); - const absl::flat_hash_map& extracted_map() const { - return extracted_map_; - } - - // ----- Methods that deals with AllDifferent information ----- - - // Stores the fact that the array of variable diffs appears in - // an AllDifferent constraints. - void StoreAllDifferent(std::vector diffs); - - // Queries whether the array diffs appears in an AllDifferent constraint. - // Currently, this performs exact matching, therefore a sub-array of an - // array of all-different variables will not match. - bool IsAllDifferent(std::vector diffs) const; - - // Returns the CP solver. - operations_research::Solver* solver() { return &solver_; } - - // Creates the sat propagator constraint and adds it to the solver. - void CreateSatPropagatorAndAddToSolver(); - // Returns the sat propagator constraint. - SatPropagator* Sat() const { - CHECK(sat_ != nullptr); - return sat_; - } - - private: - operations_research::Solver solver_; - SatPropagator* sat_; - absl::flat_hash_map extracted_map_; - - // Stores a set of sorted std::vector. - // TODO(user,user): If it become too slow, switch to an unordered_set, it - // isn't too hard to define the hash of a vector. - std::set> alldiffs_; -}; -} // namespace fz -} // namespace operations_research - -#endif // OR_TOOLS_FLATZINC_SOLVER_DATA_H_ diff --git a/ortools/flatzinc/solver_util.cc b/ortools/flatzinc/solver_util.cc deleted file mode 100644 index 18e1b99bd3..0000000000 --- a/ortools/flatzinc/solver_util.cc +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2010-2018 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/flatzinc/solver_util.h" - -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "ortools/flatzinc/logging.h" - -namespace operations_research { -namespace fz { - -void MarkComputedVariables(Constraint* ct, - absl::flat_hash_set* marked) { - const std::string& id = ct->type; - if (id == "global_cardinality") { - FZVLOG << " - marking " << ct->DebugString() << FZENDL; - for (IntegerVariable* const var : ct->arguments[2].variables) { - marked->insert(var); - } - } - - if (id == "array_var_int_element" && ct->target_variable == nullptr) { - FZVLOG << " - marking " << ct->DebugString() << FZENDL; - marked->insert(ct->arguments[2].Var()); - } - - if (id == "maximum_int" && ct->arguments[0].IsVariable() && - ct->target_variable == nullptr) { - marked->insert(ct->arguments[0].Var()); - } - - if (id == "minimum_int" && ct->arguments[0].IsVariable() && - ct->target_variable == nullptr) { - marked->insert(ct->arguments[0].Var()); - } - - if (id == "int_lin_eq" && ct->target_variable == nullptr) { - const std::vector& array_coefficients = ct->arguments[0].values; - const int size = array_coefficients.size(); - const std::vector& array_variables = - ct->arguments[1].variables; - bool todo = true; - if (size == 0) { - return; - } - if (array_coefficients[0] == -1) { - for (int i = 1; i < size; ++i) { - if (array_coefficients[i] < 0) { - todo = false; - break; - } - } - // Can mark the first one, this is a hidden sum. - if (todo) { - marked->insert(array_variables[0]); - FZVLOG << " - marking " << ct->DebugString() << ": " - << array_variables[0]->DebugString() << FZENDL; - return; - } - } - todo = true; - if (array_coefficients[0] == 1) { - for (int i = 1; i < size; ++i) { - if (array_coefficients[i] > 0) { - todo = false; - break; - } - } - if (todo) { - marked->insert(array_variables[0]); - FZVLOG << " - marking " << ct->DebugString() << ": " - << array_variables[0]->DebugString() << FZENDL; - return; - } - } - todo = true; - if (array_coefficients[size - 1] == 1) { - for (int i = 0; i < size - 1; ++i) { - if (array_coefficients[i] > 0) { - todo = false; - break; - } - } - if (todo) { - // Can mark the last one, this is a hidden sum. - marked->insert(array_variables[size - 1]); - FZVLOG << " - marking " << ct->DebugString() << ": " - << array_variables[size - 1]->DebugString() << FZENDL; - return; - } - } - todo = true; - if (array_coefficients[size - 1] == -1) { - for (int i = 0; i < size - 1; ++i) { - if (array_coefficients[i] < 0) { - todo = false; - break; - } - } - if (todo) { - // Can mark the last one, this is a hidden sum. - marked->insert(array_variables[size - 1]); - FZVLOG << " - marking " << ct->DebugString() << ": " - << array_variables[size - 1]->DebugString() << FZENDL; - return; - } - } - } -} - -Interrupt::Interrupt(operations_research::Solver* const solver) - : SearchLimit(solver) {} - -Interrupt::~Interrupt() {} - -bool Interrupt::Check() { return control_c_; } - -void Interrupt::Init() {} - -void Interrupt::Copy(const SearchLimit* const limit) {} - -SearchLimit* Interrupt::MakeClone() const { - return solver()->RevAlloc(new Interrupt(solver())); -} - -bool Interrupt::control_c_ = false; - -namespace { -// Comparison helpers. -struct VarDegreeIndexSize { - IntVar* v; - int d; - int i; - int b; - - VarDegreeIndexSize(IntVar* var, int degree, int index, uint64 size) - : v(var), d(degree), i(index), b(Bucket(size)) {} - - int Bucket(uint64 size) const { - if (size < 10) { - return 0; - } else if (size < 1000) { - return 1; - } else if (size < 100000) { - return 2; - } else { - return 3; - } - } - - bool operator<(const VarDegreeIndexSize& other) const { - return b < other.b || - (b == other.b && (d > other.d || (d == other.d && i < other.i))); - } -}; -} // namespace - -void SortVariableByDegree(const std::vector& occurrences, bool use_size, - std::vector* int_vars) { - std::vector to_sort; - for (int i = 0; i < int_vars->size(); ++i) { - IntVar* const var = (*int_vars)[i]; - const uint64 size = use_size ? var->Size() : 1; - to_sort.push_back(VarDegreeIndexSize(var, occurrences[i], i, size)); - } - std::sort(to_sort.begin(), to_sort.end()); - for (int i = 0; i < int_vars->size(); ++i) { - (*int_vars)[i] = to_sort[i].v; - } -} - -// Report memory usage in a nice way. -// TODO(user): Move to open source base directory. -std::string MemoryUsage() { - static const int64 kDisplayThreshold = 2; - static const int64 kKiloByte = 1024; - static const int64 kMegaByte = kKiloByte * kKiloByte; - static const int64 kGigaByte = kMegaByte * kKiloByte; - const int64 memory_usage = operations_research::Solver::MemoryUsage(); - if (memory_usage > kDisplayThreshold * kGigaByte) { - return absl::StrFormat("%.2f GB", memory_usage * 1.0 / kGigaByte); - } else if (memory_usage > kDisplayThreshold * kMegaByte) { - return absl::StrFormat("%.2f MB", memory_usage * 1.0 / kMegaByte); - } else if (memory_usage > kDisplayThreshold * kKiloByte) { - return absl::StrFormat("%2f KB", memory_usage * 1.0 / kKiloByte); - } else { - return absl::StrCat(memory_usage); - } -} - -void Interrupt::ControlCHandler(int s) { - FZLOG << "Ctrl-C caught" << FZENDL; - operations_research::fz::Interrupt::control_c_ = true; -} - -} // namespace fz -} // namespace operations_research diff --git a/ortools/flatzinc/solver_util.h b/ortools/flatzinc/solver_util.h deleted file mode 100644 index e3bc32f332..0000000000 --- a/ortools/flatzinc/solver_util.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2010-2018 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_FLATZINC_SOLVER_UTIL_H_ -#define OR_TOOLS_FLATZINC_SOLVER_UTIL_H_ - -#include "absl/container/flat_hash_set.h" -#include "ortools/constraint_solver/constraint_solver.h" -#include "ortools/constraint_solver/constraint_solveri.h" -#include "ortools/flatzinc/model.h" - -namespace operations_research { -namespace fz { - -// The Flatzinc SearchLog is just like a regular SearchLog, except -// that it uses stdout with a "%% " prefix instead of LOG(INFO). -class Log : public SearchLog { - public: - Log(operations_research::Solver* s, OptimizeVar* obj, int period) - : SearchLog(s, obj, nullptr, 1.0, 0.0, nullptr, period) {} - ~Log() override {} - - protected: - void OutputLine(const std::string& line) override { - std::cout << "%% " << line << std::endl; - } -}; - -// A custom search limit that checks the Control-C call. -class Interrupt : public SearchLimit { - public: - explicit Interrupt(operations_research::Solver* const solver); - - ~Interrupt() override; - - bool Check() override; - - void Init() override; - - void Copy(const SearchLimit* const limit) override; - - SearchLimit* MakeClone() const override; - - // Sets Interrupt::control_c_ to true - static void ControlCHandler(int s); - - static bool Interrupted() { return control_c_; } - - private: - static bool control_c_; -}; - -// Helper to sort variable for the automatic search. -// First it groups them in size bucket if use_size is true. -// (size < 10, < 1000, < 100000 and >= 100000). -// Then in each bucket, it sorts them by decreasing number of occurences. -void SortVariableByDegree(const std::vector& occurrences, bool use_size, - std::vector* int_vars); - -// Report memory usage in a nice way. -std::string MemoryUsage(); - -// This method tries to reduce the list of active variables when defining a -// search procedure with search annotations. In order to do so, it looks at -// constraints which semantics clearly defines output variables (x = sum(yi) -// for instances will mark x as computed). -// If this create cycles, they will be broken later during extraction. -void MarkComputedVariables(Constraint* ct, - absl::flat_hash_set* marked); - -} // namespace fz -} // namespace operations_research - -#endif // OR_TOOLS_FLATZINC_SOLVER_UTIL_H_ diff --git a/ortools/linear_solver/model_exporter.cc b/ortools/linear_solver/model_exporter.cc index 9072a8719f..c9162e292e 100644 --- a/ortools/linear_solver/model_exporter.cc +++ b/ortools/linear_solver/model_exporter.cc @@ -160,6 +160,9 @@ class MPModelProtoExporter { util::StatusOr ExportModelAsLpFormat( const MPModelProto& model, const MPModelExportOptions& options) { + if (model.general_constraint_size() > 0) { + return util::InvalidArgumentError("General constraints are not supported."); + } MPModelProtoExporter exporter(model); std::string output; if (!exporter.ExportModelAsLpFormat(options, &output)) { @@ -170,6 +173,9 @@ util::StatusOr ExportModelAsLpFormat( util::StatusOr ExportModelAsMpsFormat( const MPModelProto& model, const MPModelExportOptions& options) { + if (model.general_constraint_size() > 0) { + return util::InvalidArgumentError("General constraints are not supported."); + } MPModelProtoExporter exporter(model); std::string output; if (!exporter.ExportModelAsMpsFormat(options, &output)) { diff --git a/ortools/sat/cp_model_checker.cc b/ortools/sat/cp_model_checker.cc index 05f8a7c675..bedcbb8363 100644 --- a/ortools/sat/cp_model_checker.cc +++ b/ortools/sat/cp_model_checker.cc @@ -24,6 +24,7 @@ #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/port/proto_utils.h" +#include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_utils.h" #include "ortools/util/saturated_arithmetic.h" #include "ortools/util/sorted_interval_list.h" @@ -171,6 +172,18 @@ bool PossibleIntegerOverflow(const CpModelProto& model, return false; } +std::string ValidateIntervalConstraint(const CpModelProto& model, + const ConstraintProto& ct) { + const IntervalConstraintProto& arg = ct.interval(); + const IntegerVariableProto& size_var_proto = model.variables(arg.size()); + if (size_var_proto.domain(0) < 0) { + return absl::StrCat( + "Negative value in interval size domain: ", ProtobufDebugString(ct), + "size var: ", ProtobufDebugString(size_var_proto)); + } + return ""; +} + std::string ValidateLinearConstraint(const CpModelProto& model, const ConstraintProto& ct) { const LinearConstraintProto& arg = ct.linear(); @@ -363,6 +376,7 @@ std::string ValidateCpModel(const CpModelProto& model) { break; case ConstraintProto::ConstraintCase::kInterval: support_enforcement = true; + RETURN_IF_NOT_EMPTY(ValidateIntervalConstraint(model, ct)); break; case ConstraintProto::ConstraintCase::kCumulative: if (ct.cumulative().intervals_size() != diff --git a/ortools/sat/cp_model_presolve.cc b/ortools/sat/cp_model_presolve.cc index f45fd655e0..31c38c0bea 100644 --- a/ortools/sat/cp_model_presolve.cc +++ b/ortools/sat/cp_model_presolve.cc @@ -970,7 +970,8 @@ bool CpModelPresolver::RemoveSingletonInLinear(ConstraintProto* ct) { // // TODO(user): If the objective is a single variable, we can actually // "absorb" any factor into the objective scaling. - const int64 objective_coeff = gtl::FindOrDie(context_->ObjectiveMap(), var); + const int64 objective_coeff = + gtl::FindOrDie(context_->ObjectiveMap(), var); CHECK_NE(coeff, 0); if (objective_coeff % coeff != 0) continue; @@ -1317,7 +1318,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int c, ConstraintProto* ct) { const int size = context_->var_to_constraints[var].size() - (is_in_objective ? 1 : 0); const int64 obj_coeff = - is_in_objective ? gtl::FindOrDie(context_->ObjectiveMap(), var) : 0; + is_in_objective ? gtl::FindOrDie(context_->ObjectiveMap(), var) : 0; // We cannot fix anything if the domain of the objective is excluding // some objective values. @@ -1929,6 +1930,34 @@ bool CpModelPresolver::PresolveInterval(int c, ConstraintProto* ct) { const int start = ct->interval().start(); const int end = ct->interval().end(); const int size = ct->interval().size(); + + if (ct->enforcement_literal().empty()) { + bool changed = false; + const Domain start_domain = context_->DomainOf(start); + const Domain end_domain = context_->DomainOf(end); + const Domain size_domain = context_->DomainOf(size); + // Size can't be negative. + if (!context_->IntersectDomainWith(size, Domain(0, context_->MaxOf(size)), + &changed)) { + return false; + } + if (!context_->IntersectDomainWith( + end, start_domain.AdditionWith(size_domain), &changed)) { + return false; + } + if (!context_->IntersectDomainWith( + start, end_domain.AdditionWith(size_domain.Negation()), &changed)) { + return false; + } + if (!context_->IntersectDomainWith( + size, end_domain.AdditionWith(start_domain.Negation()), &changed)) { + return false; + } + if (changed) { + context_->UpdateRuleStats("interval: reduced domains"); + } + } + if (context_->interval_usage[c] == 0) { // Convert to linear. ConstraintProto* new_ct = context_->working_model->add_constraints(); @@ -1946,27 +1975,6 @@ bool CpModelPresolver::PresolveInterval(int c, ConstraintProto* ct) { return RemoveConstraint(ct); } - if (!ct->enforcement_literal().empty()) return false; - bool changed = false; - const Domain start_domain = context_->DomainOf(start); - const Domain end_domain = context_->DomainOf(end); - const Domain size_domain = context_->DomainOf(size); - if (!context_->IntersectDomainWith( - end, start_domain.AdditionWith(size_domain), &changed)) { - return false; - } - if (!context_->IntersectDomainWith( - start, end_domain.AdditionWith(size_domain.Negation()), &changed)) { - return false; - } - if (!context_->IntersectDomainWith( - size, end_domain.AdditionWith(start_domain.Negation()), &changed)) { - return false; - } - if (changed) { - context_->UpdateRuleStats("interval: reduced domains"); - } - // TODO(user): This currently has a side effect that both the interval and // a linear constraint are added to the presolved model. Fix. if (false && context_->IsFixed(size)) {