// Copyright 2010-2025 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ORTOOLS_SAT_CP_MODEL_COPY_H_ #define ORTOOLS_SAT_CP_MODEL_COPY_H_ #include #include #include #include #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/types/span.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/lrat_proof_handler.h" #include "ortools/sat/presolve_context.h" #include "ortools/sat/sat_base.h" #include "ortools/sat/sat_parameters.pb.h" #include "ortools/util/sorted_interval_list.h" namespace operations_research { namespace sat { // This helper class perform copy with simplification from a model and a // partial assignment to another model. The purpose is to minimize the size of // the copied model, as well as to reduce the pressure on the memory sub-system. // // It is currently used by the LNS part, but could be used with any other scheme // that generates partial assignments. class ModelCopy { public: explicit ModelCopy(PresolveContext* context, LratProofHandler* lrat_proof_handler = nullptr); // Copies all constraints from in_model to working model of the context. // // During the process, it will read variable domains from the context, and // simplify constraints to minimize the size of the copied model. // Thus it is important that the context->working_model already have the // variables part copied. // // It returns false iff the model is proven infeasible. // // It does not clear the constraints part of the working model of the context. // // Note(user): If first_copy is true, we will reorder the scheduling // constraint so that they only use reference to previously defined intervals. // This allow to be more efficient later in a few preprocessing steps. bool ImportAndSimplifyConstraints( const CpModelProto& in_model, bool first_copy = false, std::function active_constraints = nullptr); // Copy variables from the in_model to the working model. // It reads the 'ignore_names' parameters from the context, and keeps or // deletes names accordingly. void ImportVariablesAndMaybeIgnoreNames(const CpModelProto& in_model); // Setup new variables from a vector of domains. // Inactive variables will be fixed to their lower bound. void CreateVariablesFromDomains(absl::Span domains); // Advanced usage. When a model was copied, interval_mapping[i] will contain // for a copied interval with original index i, its new index. absl::Span InternalIntervalMapping() const { return interval_mapping_; } private: // Overwrites the out_model to be unsat. Returns false. // The arguments are used to log which constraint caused unsat. bool CreateUnsatModel(int c, const ConstraintProto& ct); // Returns false if the constraint is never enforced and can be skipped. bool PrepareEnforcementCopy(const ConstraintProto& ct); bool PrepareEnforcementCopyWithDup(const ConstraintProto& ct); void FinishEnforcementCopy(ConstraintProto* ct); // All these functions return false if the constraint is found infeasible. bool CopyBoolOr(const ConstraintProto& ct); bool CopyBoolOrWithDupSupport(const ConstraintProto& ct, ClauseId clause_id); bool FinishBoolOrCopy(ClauseId clause_id = kNoClauseId); bool CopyBoolAnd(const ConstraintProto& ct); bool CopyBoolAndWithDupSupport(const ConstraintProto& ct); bool CopyAtMostOne(const ConstraintProto& ct); bool CopyExactlyOne(const ConstraintProto& ct); bool CopyElement(const ConstraintProto& ct); bool CopyIntProd(const ConstraintProto& ct, bool ignore_names); bool CopyIntDiv(const ConstraintProto& ct, bool ignore_names); bool CopyIntMod(const ConstraintProto& ct, bool ignore_names); bool CopyLinear(const ConstraintProto& ct, bool canonicalize); bool CopyLinearExpression(const LinearExpressionProto& expr, LinearExpressionProto* dst, absl::Span enforcement_literals = {}); bool CopyAutomaton(const ConstraintProto& ct); bool CopyTable(const ConstraintProto& ct); bool CopyAllDiff(const ConstraintProto& ct); bool CopyLinMax(const ConstraintProto& ct); // If we "copy" an interval for a first time, we make sure to create the // linear constraint between the start, size and end. This allow to simplify // the input proto and client side code. If there are more than one // enforcement literals, we replace them with a new one, made equal to their // conjunction with two new constraints. bool CopyInterval(const ConstraintProto& ct, int c, bool ignore_names); bool AddLinearConstraintForInterval(const ConstraintProto& ct); int GetOrCreateVariableForConjunction(std::vector* literals); // These function remove unperformed intervals. Note that they requires // interval to appear before (validated) as they test unperformed by testing // if interval_mapping_ is empty. void CopyAndMapNoOverlap(const ConstraintProto& ct); void CopyAndMapNoOverlap2D(const ConstraintProto& ct); bool CopyAndMapCumulative(const ConstraintProto& ct); // Expands linear expressions with more than one variable in constraints which // internally only support affine expressions (such as all_diff, element, // interval, reservoir, table, etc). This creates new variables for each such // expression, and replaces the original expressions with the new variables in // the constraints. void ExpandNonAffineExpressions(); // Replaces the expression sum a_i * x_i + c with gcd * y + c, where y is a // new variable defined with an additional constraint y = sum a_i / gcd * x_i. void MaybeExpandNonAffineExpression(LinearExpressionProto* expr); void MaybeExpandNonAffineExpressions(LinearArgumentProto* linear_argument); ClauseId NextInferredClauseId(); PresolveContext* context_; LratProofHandler* lrat_proof_handler_; // Temp vectors. std::vector non_fixed_variables_; std::vector non_fixed_coefficients_; std::vector interval_mapping_; int starting_constraint_index_ = 0; std::vector temp_enforcement_literals_; absl::flat_hash_set temp_enforcement_literals_set_; std::vector temp_literals_; absl::flat_hash_set temp_literals_set_; ConstraintProto tmp_constraint_; // The unit clause IDs of the literals which are fixed to true. Only used if // lrat_proof_handler_ is not null. absl::flat_hash_map unit_clause_ids_; // Temp vectors used for LRAT. std::vector temp_clause_; std::vector temp_simplified_clause_; std::vector temp_clause_ids_; ClauseId next_inferred_clause_id_; // Map used in GetOrCreateVariableForConjunction() to avoid creating duplicate // variables for identical sets of literals. absl::flat_hash_map, int> boolean_product_encoding_; // Map used in ExpandNonAffineExpressions() to avoid creating duplicate // variables for the identical non affine expressions. absl::flat_hash_map>, int> non_affine_expression_to_new_var_; }; // Copy in_model to the model in the presolve context. // It performs on the fly simplification, and returns false if the // model is proved infeasible. If reads the parameters 'ignore_names' and keeps // or deletes variables and constraints names accordingly. // // This should only be called on the first copy of the user given model. // Note that this reorder all constraints that use intervals last. We loose the // user-defined order, but hopefully that should not matter too much. bool ImportModelWithBasicPresolveIntoContext( const CpModelProto& in_model, PresolveContext* context, LratProofHandler* lrat_proof_handler = nullptr); // Same as ImportModelWithBasicPresolveIntoContext() except that variable // domains are read from domains and constraint might be filtered. bool ImportModelAndDomainsWithBasicPresolveIntoContext( const CpModelProto& in_model, absl::Span domains, std::function active_constraints, PresolveContext* context, std::vector* interval_mapping); // Copies the non constraint, non variables part of the model. void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext( const CpModelProto& in_model, PresolveContext* context); } // namespace sat } // namespace operations_research #endif // ORTOOLS_SAT_CP_MODEL_COPY_H_