37 DCHECK(ct->table().vars().empty());
38 if (ct->table().exprs().empty()) {
39 CHECK(ct->table().values().empty());
43 if (ct->table().values().empty()) {
45 ct->mutable_table()->clear_exprs();
46 ct->mutable_table()->add_exprs()->set_offset(0);
50 const int num_exprs = ct->table().exprs_size();
51 const int num_tuples = ct->table().values_size() / num_exprs;
54 absl::flat_hash_map<int, int> var_to_position;
58 std::vector<std::optional<int>> position_mapping(num_exprs, std::nullopt);
59 int num_shared_vars = 0;
60 int num_fixed_exprs = 0;
61 for (
int i = 0;
i < num_exprs; ++
i) {
62 const LinearExpressionProto& expr = ct->table().exprs(
i);
68 const int var = expr.vars(0);
69 const auto [it, inserted] =
70 var_to_position.insert({var, var_to_position.size()});
73 position_mapping[
i] = it->second;
77 const int num_kept_exprs = num_exprs - num_shared_vars - num_fixed_exprs;
79 std::vector<std::vector<int64_t>> new_tuples;
80 new_tuples.reserve(num_tuples);
82 std::vector<int64_t> new_scaled_values;
83 new_scaled_values.reserve(num_kept_exprs);
85 for (
int t = 0; t < num_tuples; ++t) {
86 bool tuple_is_valid =
true;
87 new_scaled_values.clear();
89 for (
int e = 0; e < num_exprs; ++e) {
90 const int64_t value = ct->table().values(t * num_exprs + e);
91 const LinearExpressionProto& expr = ct->table().exprs(e);
94 tuple_is_valid =
false;
97 }
else if (position_mapping[e].has_value()) {
98 const int var_first_position = position_mapping[e].value();
99 const int64_t var_value = new_scaled_values[var_first_position];
101 if (value != forced_value) {
102 tuple_is_valid =
false;
107 tuple_is_valid =
false;
114 if (tuple_is_valid) {
115 DCHECK_EQ(new_scaled_values.size(), num_kept_exprs);
116 new_tuples.push_back(new_scaled_values);
121 for (
int e = 0; e < num_exprs; ++e) {
122 if (position_mapping[e].has_value())
continue;
123 if (context->
IsFixed(ct->table().exprs(e)))
continue;
124 DCHECK_EQ(ct->table().exprs(e).coeffs_size(), 1);
125 ct->mutable_table()->mutable_exprs(e)->set_offset(0);
126 ct->mutable_table()->mutable_exprs(e)->set_coeffs(0, 1);
129 if (num_kept_exprs < num_exprs) {
131 for (
int e = 0; e < num_exprs; ++e) {
132 if (position_mapping[e].has_value())
continue;
133 if (context->
IsFixed(ct->table().exprs(e)))
continue;
134 ct->mutable_table()->mutable_exprs()->SwapElements(index++, e);
136 CHECK_EQ(index, num_kept_exprs);
137 ct->mutable_table()->mutable_exprs()->DeleteSubrange(index,
143 if (new_tuples.size() < num_tuples) {
147 if (num_kept_exprs == 0) {
153 const bool all_tuples_invalid = new_tuples.empty();
154 const bool is_trivially_sat = all_tuples_invalid == ct->table().negated();
155 ct->mutable_table()->clear_exprs();
156 ct->mutable_table()->clear_values();
157 ct->mutable_table()->add_exprs()->set_offset(0);
158 ct->mutable_table()->set_negated(is_trivially_sat);
162 if (new_tuples.empty()) {
166 ct->mutable_table()->clear_exprs();
167 ct->mutable_table()->clear_values();
168 if (!ct->table().negated()) {
169 ct->mutable_table()->add_exprs()->set_offset(0);
171 ct->mutable_table()->set_negated(
false);
176 ct->mutable_table()->clear_values();
177 for (
const std::vector<int64_t>& tuple : new_tuples) {
178 ct->mutable_table()->mutable_values()->Add(tuple.begin(), tuple.end());
183 std::vector<std::vector<int64_t>>* tuples) {
184 if (tuples->empty())
return;
189 const int num_vars = (*tuples)[0].size();
191 std::vector<int> to_remove;
192 std::vector<int64_t> tuple_minus_var_i(num_vars - 1);
193 for (
int i = 0;
i < num_vars; ++
i) {
194 const int64_t domain_size = domain_sizes[
i];
195 if (domain_size == 1)
continue;
196 absl::flat_hash_map<std::vector<int64_t>, std::vector<int>>
197 masked_tuples_to_indices;
198 for (
int t = 0; t < tuples->size(); ++t) {
200 for (
int j = 0; j < num_vars; ++j) {
201 if (
i == j)
continue;
202 tuple_minus_var_i[out++] = (*tuples)[t][j];
204 masked_tuples_to_indices[tuple_minus_var_i].push_back(t);
207 for (
const auto& it : masked_tuples_to_indices) {
208 if (it.second.size() != domain_size)
continue;
210 to_remove.insert(to_remove.end(), it.second.begin() + 1, it.second.end());
212 std::sort(to_remove.begin(), to_remove.end(), std::greater<int>());
213 for (
const int t : to_remove) {
214 (*tuples)[t] = tuples->back();
322 absl::Span<const int64_t> domain_sizes,
323 std::vector<std::vector<int64_t>>* tuples) {
324 std::vector<absl::InlinedVector<int64_t, 2>> reversed_suffix;
325 std::vector<std::vector<absl::InlinedVector<int64_t, 2>>> output;
326 FullyCompressTuplesRecursive(domain_sizes, absl::MakeSpan(*tuples),
327 &reversed_suffix, &output);
336 std::vector<absl::flat_hash_set<int64_t>>* states,
337 std::vector<absl::flat_hash_set<int64_t>>* labels) {
338 const int n = proto.exprs_size();
339 const absl::flat_hash_set<int64_t> final_states(
340 {proto.final_states().begin(), proto.final_states().end()});
345 states->resize(n + 1);
346 (*states)[0].insert(proto.starting_state());
349 for (
int time = 0; time < n; ++time) {
350 for (
int t = 0; t < proto.transition_tail_size(); ++t) {
351 const int64_t tail = proto.transition_tail(t);
352 const int64_t label = proto.transition_label(t);
353 const int64_t head = proto.transition_head(t);
354 if (!(*states)[time].contains(tail))
continue;
356 if (time == n - 1 && !final_states.contains(head))
continue;
357 (*labels)[time].insert(label);
358 (*states)[time + 1].insert(head);
363 for (
int time = n - 1; time >= 0; --time) {
364 absl::flat_hash_set<int64_t> new_states;
365 absl::flat_hash_set<int64_t> new_labels;
366 for (
int t = 0; t < proto.transition_tail_size(); ++t) {
367 const int64_t tail = proto.transition_tail(t);
368 const int64_t label = proto.transition_label(t);
369 const int64_t head = proto.transition_head(t);
371 if (!(*states)[time].contains(tail))
continue;
372 if (!(*labels)[time].contains(label))
continue;
373 if (!(*states)[time + 1].contains(head))
continue;
374 new_labels.insert(label);
375 new_states.insert(tail);
377 (*labels)[time].swap(new_labels);
378 (*states)[time].swap(new_states);
void UpdateRuleStats(const std::string &name, int num_times=1)