// 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_2D_TRY_EDGE_PROPAGATOR_H_ #define ORTOOLS_SAT_2D_TRY_EDGE_PROPAGATOR_H_ #include #include #include #include #include "ortools/sat/diffn_util.h" #include "ortools/sat/integer.h" #include "ortools/sat/integer_base.h" #include "ortools/sat/model.h" #include "ortools/sat/no_overlap_2d_helper.h" #include "ortools/sat/synchronization.h" #include "ortools/sat/util.h" #include "ortools/util/bitset.h" namespace operations_research { namespace sat { // Propagator that for each boxes participating in a no_overlap_2d constraint // try to find the leftmost valid position that is compatible with all the // other boxes. If none is found, it will propagate a conflict. Otherwise, if // it is different from the current x_min, it will propagate the new x_min. void CreateAndRegisterTryEdgePropagator(NoOverlap2DConstraintHelper* helper, Model* model, GenericLiteralWatcher* watcher, int priority); // Exposed for testing. class TryEdgeRectanglePropagator : public PropagatorInterface { public: TryEdgeRectanglePropagator(bool x_is_forward_after_swap, bool y_is_forward_after_swap, bool swap_x_and_y, NoOverlap2DConstraintHelper* helper, Model* model) : helper_(*helper), shared_stats_(model->GetOrCreate()), x_is_forward_after_swap_(x_is_forward_after_swap), y_is_forward_after_swap_(y_is_forward_after_swap), swap_x_and_y_(swap_x_and_y) {} ~TryEdgeRectanglePropagator() override; bool Propagate() final; int RegisterWith(GenericLiteralWatcher* watcher); protected: // placed_boxes_ is a list that is only meaningful for indices for which // is_in_cache_[box_index] is true. After applying this condition, // placed_boxes_ contains a list of boxes placed at their current x_min and // that does not overlap with the mandatory region of any other box in // placed_boxes_. In other words, there is no point on looking for any // propagation for this heuristic between boxes that are already in // placed_boxes_. std::vector placed_boxes_; std::vector is_in_cache_; std::vector mandatory_regions_; std::vector active_box_ranges_; std::vector is_active_; Bitset64 has_mandatory_region_; std::vector changed_item_; std::vector changed_mandatory_; virtual bool ExplainAndPropagate( const std::vector>>& found_propagations); // This function assumes that a propagation is found and the box with index // `box_index` cannot be placed to the left of new_x_min. It returns a list of // indices of boxes that defines a subproblem where the propagation is still // valid, including `box_index` itself. std::vector GetMinimumProblemWithPropagation(int box_index, IntegerValue new_x_min); private: void PopulateActiveBoxRanges(); NoOverlap2DConstraintHelper& helper_; SharedStatistics* shared_stats_; bool x_is_forward_after_swap_; bool y_is_forward_after_swap_; bool swap_x_and_y_; std::vector cached_y_hint_; std::vector potential_x_positions_; std::vector potential_y_positions_; int64_t num_conflicts_ = 0; int64_t num_propagations_ = 0; int64_t num_calls_ = 0; CompactVectorVector conflicts_per_x_and_y_; bool CanPlace(int box_index, const std::pair& position, CompactVectorVector* with_conflicts = nullptr) const; TryEdgeRectanglePropagator(const TryEdgeRectanglePropagator&) = delete; TryEdgeRectanglePropagator& operator=(const TryEdgeRectanglePropagator&) = delete; }; } // namespace sat } // namespace operations_research #endif // ORTOOLS_SAT_2D_TRY_EDGE_PROPAGATOR_H_