20#include "absl/algorithm/container.h"
21#include "absl/log/check.h"
22#include "absl/log/log.h"
23#include "absl/types/span.h"
35 stats_(
"SymmetryPropagator"),
41 LOG(INFO) << stats_.StatString();
42 LOG(INFO) <<
"num propagations by symmetry: " << num_propagations_;
43 LOG(INFO) <<
"num conflicts by symmetry: " << num_conflicts_;
48 std::unique_ptr<SparsePermutation> permutation) {
49 if (permutation->NumCycles() == 0)
return;
52 if (permutation->Size() > images_.size()) {
53 images_.resize(permutation->Size());
55 for (
int c = 0; c < permutation->NumCycles(); ++c) {
56 int e = permutation->LastElementInCycle(c);
57 for (
const int image : permutation->Cycle(c)) {
58 DCHECK_GE(LiteralIndex(e), 0);
59 DCHECK_LE(LiteralIndex(e), images_.size());
60 const int permutation_index = permutations_.size();
61 images_[LiteralIndex(e)].push_back(
62 ImageInfo(permutation_index,
Literal(LiteralIndex(image))));
66 permutation_trails_.push_back(std::vector<AssignedLiteralInfo>());
67 permutation_trails_.back().reserve(permutation->Support().size());
68 permutations_.emplace_back(permutation.release());
71bool SymmetryPropagator::PropagateNext(
Trail* trail) {
74 if (true_literal.
Index() < images_.size()) {
75 const std::vector<ImageInfo>& images = images_[true_literal.
Index()];
76 for (
int image_index = 0; image_index < images.size(); ++image_index) {
77 const int p_index = images[image_index].permutation_index;
81 std::vector<AssignedLiteralInfo>* p_trail =
82 &(permutation_trails_[p_index]);
83 if (Enqueue(*trail, true_literal, images[image_index].image, p_trail)) {
89 const AssignedLiteralInfo& non_symmetric =
90 (*p_trail)[p_trail->back().first_non_symmetric_info_index_so_far];
94 const BooleanVariable non_symmetric_var =
95 non_symmetric.literal.Variable();
96 const AssignmentInfo& assignment_info = trail->
Info(non_symmetric_var);
101 const absl::Span<const Literal> initial_reason =
102 trail->
Reason(non_symmetric.literal.Variable());
103 if (absl::c_any_of(initial_reason, [
this](Literal literal) {
104 return literal.Index() >= num_literals_with_knonw_symmetry_;
115 Permute(p_index, initial_reason, conflict);
116 conflict->push_back(non_symmetric.image);
117 for (Literal literal : *conflict) {
122 for (; image_index >= 0; --image_index) {
123 permutation_trails_[images[image_index].permutation_index].pop_back();
128 if (trail->
Index() >= reasons_.size()) {
129 reasons_.resize(trail->
Index() + 1);
131 reasons_[trail->
Index()] = {assignment_info.trail_index, p_index};
142 const int old_index = trail->
Index();
144 if (!PropagateNext(trail))
return false;
154 if (true_literal.
Index() < images_.size()) {
155 for (ImageInfo& info : images_[true_literal.
Index()]) {
156 permutation_trails_[info.permutation_index].pop_back();
163 const Trail& trail,
int trail_index, int64_t )
const {
165 const ReasonInfo& reason_info = reasons_[trail_index];
167 Permute(reason_info.symmetry_index,
168 trail.
Reason(trail[reason_info.source_trail_index].Variable()),
173bool SymmetryPropagator::Enqueue(
const Trail& trail,
Literal literal,
175 std::vector<AssignedLiteralInfo>* p_trail) {
184 p_trail->push_back(AssignedLiteralInfo(
188 : p_trail->back().first_non_symmetric_info_index_so_far));
189 int* index = &(p_trail->back().first_non_symmetric_info_index_so_far);
192 while (*index < p_trail->size() &&
197 literal_trail_index) {
204 return *index == p_trail->size();
208 std::vector<Literal>* output)
const {
213 DCHECK_LT(index, permutations_.size());
215 if (permutation.
Size() > tmp_literal_mapping_.size()) {
216 tmp_literal_mapping_.resize(permutation.
Size());
217 for (LiteralIndex
i(0);
i < tmp_literal_mapping_.size(); ++
i) {
221 for (
int c = 0; c < permutation.
NumCycles(); ++c) {
223 for (
const int image : permutation.
Cycle(c)) {
224 tmp_literal_mapping_[LiteralIndex(e)] =
Literal(LiteralIndex(image));
232 if (literal.
Index() < tmp_literal_mapping_.size()) {
233 output->push_back(tmp_literal_mapping_[literal.
Index()]);
235 output->push_back(literal);
240 for (
const int e : permutation.
Support()) {
241 tmp_literal_mapping_[LiteralIndex(e)] =
Literal(LiteralIndex(e));
const std::vector< int > & Support() const
Iterator Cycle(int i) const
int LastElementInCycle(int i) const
LiteralIndex Index() const
BooleanVariable Variable() const
SatPropagator(const std::string &name)
int propagation_trail_index_
void AddSymmetry(std::unique_ptr< SparsePermutation > permutation)
void Untrail(const Trail &trail, int trail_index) final
bool Propagate(Trail *trail) final
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
~SymmetryPropagator() override
void Permute(int index, absl::Span< const Literal > input, std::vector< Literal > *output) const
std::vector< Literal > * MutableConflict()
int AssignmentType(BooleanVariable var) const
void Enqueue(Literal true_literal, int propagator_id)
absl::Span< const Literal > Reason(BooleanVariable var, int64_t conflict_id=-1) const
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
const VariablesAssignment & Assignment() const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
static int input(yyscan_t yyscanner)
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static constexpr int kSearchDecision