SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
VariableOrdering.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <carl-arith/core/Variable.h>
4 #include <carl-formula/formula/Formula.h>
5 #include <carl-formula/formula/functions/Variables.h>
6 #include <smtrat-common/types.h>
7 
8 #include "types.h"
9 
11 
13 
14 /**
15  * @brief Possible heuristics for variable ordering.
16  */
26 };
27 
28 inline std::string get_name(VariableOrderingHeuristics ordering) {
29  switch (ordering) {
31  return "GreedyMaxUnivariate";
32  case FeatureBased:
33  return "FeatureBased";
34  case FeatureBasedZ3:
35  return "FeatureBasedZ3";
36  case FeatureBasedBrown:
37  return "FeatureBasedBrown";
39  return "FeatureBasedTriangular";
41  return "FeatureBasedLexicographic";
43  return "FeatureBasedPickering";
44  case EarliestSplitting:
45  return "EarliestSplitting";
46  default:
47  return "";
48  }
49 }
50 
51 namespace impl {
52 
53 using carl::operator<<;
54 
55 /**
56  * @brief Calculates a variable ordering based on the given quantifier blocks and the given formula.
57  * @tparam vo The variable ordering heuristic to use.
58  * @param quantifiers The quantifier blocks (Variables in a block can be exchanged, blocks can not be exchanged)
59  * @param formula Formula to calculate the variable ordering for.
60  * @return Variable ordering.
61  * @details The variable ordering is calculated as follows:
62  * 1. Calculate the variable ordering for the formula as if there were no quantifiers. This is done by calling mcsat::calculate_variable_order<vo>(constraints). In code this is called the unblocked variable ordering
63  * 2. Sort the variables in the unblocked variable ordering by the quantifier block they are in. The order of the quantifier blocks is the same as in the vector quantifiers. Use a stable sort such that the order of the variables in a quantifier block is not changed.
64  * 3. Return the resulting vector.
65  */
66 template<mcsat::VariableOrdering vo>
67 inline std::vector<carl::Variable> variable_ordering(const carl::QuantifierPrefix& quantifiers, const FormulaT& formula) {
68  boost::container::flat_map<carl::Variable, size_t> quantifier_block_index;
69  for (auto v : formula.variables()) {
70  if (std::find_if(quantifiers.begin(), quantifiers.end(), [v](const auto& e) { return e.second == v; }) == quantifiers.end()) {
71  quantifier_block_index[v] = 0;
72  }
73  }
74  std::size_t i = 0;
75  if (!quantifier_block_index.empty()) i++;
76  carl::Quantifier last = carl::Quantifier::FREE;
77  for (const auto& e : quantifiers) {
78  assert(e.first != carl::Quantifier::FREE);
79  if (last != e.first && last != carl::Quantifier::FREE) i++;
80  quantifier_block_index[e.second] = i;
81  }
82 
83 
84  //1. Calculate the unblocked variable ordering
85  std::vector<ConstraintT> constraints;
86  carl::arithmetic_constraints(formula, constraints);
87  std::vector<carl::Variable> result = mcsat::calculate_variable_order<vo>(constraints);
88  SMTRAT_LOG_DEBUG("smtrat.covering_ng", "Unblocked variable order: " << result);
89 
90  //2. Sort the variables in the unblocked variable ordering by the quantifier block they are in.
91  std::stable_sort(result.begin(), result.end(), [&quantifier_block_index](const auto& lhs, const auto& rhs) {
92  return quantifier_block_index.at(lhs) < quantifier_block_index.at(rhs);
93  });
94 
95  SMTRAT_LOG_DEBUG("smtrat.covering_ng", "Resulting variable order: " << result);
96  return result;
97 }
98 
99 /**
100  * @brief Calculates a variable ordering based on the given quantifier blocks and the given formula. Heuristic such that the formula can be split as early as possible
101  * @param quantifiers The quantifier blocks (Variables in a block can be exchanged, blocks can not be exchanged)
102  * @param base_formula Formula to calculate the variable ordering for.
103  * @return Variable ordering.
104  * @details The variable ordering is calculated as follows:
105  * 1. Identify the first opportunity to split the formula. This is the first time that the formula is not an atom and not a negation of an atom. If there is no such opportunity, return some other variable ordering.
106  * 2. For each pairwise combination of subformulas, calculate the set of shared variables
107  * 3. Iterate over the quantifier blocks and for each block, sort the variables by the number of occurrences in the sets of shared variables and the size of the smallest set of shared variables in which the variable occurs.
108  * If the heuristic is inconclusive, sort the remaining variables of this block by some other variable ordering
109  * 4. Return the resulting vector.
110  */
111 inline std::vector<carl::Variable> sort_earliest_splitting(const carl::QuantifierPrefix& prefix, const FormulaT& base_formula) {
112  //Check if the formula can be split at all -> if not return some other variable ordering
113  //subformulas will otherwise contain the subformulas of tge formula the first time it can potentially be split
114  std::vector<FormulaT> subformulas;
115  FormulaT formula = base_formula;
116  while (subformulas.empty()) {
117  if (formula.is_atom()) {
118  // No splitting possible at all -> return some other variable ordering
119  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedBrown>(prefix, base_formula);
120  }
121  if (formula.type() == carl::FormulaType::NOT) {
122  formula = formula.subformula();
123  } else {
124  assert(formula.is_nary());
125  subformulas = formula.subformulas();
126  }
127  }
128 
129  std::vector<boost::container::flat_set<carl::Variable>> quantifiers;
130  quantifiers.emplace_back();
131  for (auto v : base_formula.variables()) {
132  if (std::find_if(prefix.begin(), prefix.end(), [v](const auto& e) { return e.second == v; }) == prefix.end()) {
133  quantifiers.back().insert(v);
134  }
135  }
136  if (quantifiers.back().empty()) quantifiers.pop_back();
137  carl::Quantifier last = carl::Quantifier::FREE;
138  for (const auto& e : prefix) {
139  assert(e.first != carl::Quantifier::FREE);
140  if (last != e.first && last != carl::Quantifier::FREE) quantifiers.emplace_back();
141  quantifiers.back().insert(e.second);
142  }
143 
144  //For each pairwise combination of subformulas, calculate the set of shared variables
145  std::vector<carl::Variables> shared_subformula_variables;
146  for (size_t i = 0; i < subformulas.size() - 1; i++) {
147  for (size_t j = i + 1; j < subformulas.size(); j++) {
148  auto& lhs = subformulas[i].variables();
149  auto& rhs = subformulas[j].variables();
150  carl::Variables shared;
151  std::set_intersection(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::inserter(shared, shared.begin()));
152  shared_subformula_variables.push_back(shared);
153  }
154  }
155 
156  //Helper function to delete a variable from all sets of shared variables
157  auto deleteVariable = [&shared_subformula_variables](const carl::Variable& var) -> void {
158  for (auto& shared : shared_subformula_variables) {
159  shared.erase(var);
160  }
161  //delete empty sets
162  shared_subformula_variables.erase(std::remove_if(shared_subformula_variables.begin(), shared_subformula_variables.end(), [](const auto& set) { return set.empty(); }), shared_subformula_variables.end());
163  };
164 
165  // Helper function to return a pair of number of occurrences and size of smallest set of shared variables in which this variable occurs
166  auto getInfo = [&shared_subformula_variables](const carl::Variable& var) -> std::pair<size_t, size_t> {
167  size_t num_occurrences = 0;
168  size_t min_shared_size = std::numeric_limits<size_t>::max();
169  for (const auto& shared : shared_subformula_variables) {
170  if (shared.find(var) != shared.end()) {
171  num_occurrences++;
172  min_shared_size = std::min(min_shared_size, shared.size());
173  }
174  }
175  return std::make_pair(num_occurrences, min_shared_size);
176  };
177 
178  // resulting variable ordering
179  std::vector<carl::Variable> result;
180 
181  //Used in case that the heuristic is inconclusive
182  std::vector<ConstraintT> constraints;
183  carl::arithmetic_constraints(formula, constraints);
184  auto unblocked_sorting = mcsat::variableordering::greedy_max_univariate(constraints);
185 
186  for (const auto& block : quantifiers) {
187  auto block_variables = block;
188  while(!block_variables.empty()) {
189  std::map<carl::Variable, std::pair<size_t, size_t>> variables_by_info;
190  for (const auto& var : block_variables) {
191  auto info = getInfo(var);
192  variables_by_info[var] = info;
193  }
194  SMTRAT_LOG_DEBUG("smtrat.covering_ng", "Variables by info: " << variables_by_info)
195  // iterate over the keys
196  std::pair<size_t, size_t> max_info = std::make_pair(std::numeric_limits<size_t>::min(), std::numeric_limits<size_t>::max());
197  carl::Variable max_var = carl::Variable::NO_VARIABLE;
198  for (const auto& [var, info] : variables_by_info) {
199  if (info.first > max_info.first) {
200  max_info = info;
201  max_var = var;
202  } else if (info.first == max_info.first) {
203  if (info.second < max_info.second) {
204  max_info = info;
205  max_var = var;
206  }
207  }
208  }
209  SMTRAT_LOG_DEBUG("smtrat.covering_ng", "Max var: " << max_var << " with info " << max_info)
210  if(max_var == carl::Variable::NO_VARIABLE){
211  //Sort the remaining variables of this block by some other variable ordering
212  for(const auto& var : unblocked_sorting){
213  if(block_variables.contains(var)){
214  result.push_back(var);
215  deleteVariable(var);
216  block_variables.erase(var);
217  }
218  }
219  break;
220  }
221  //add the variable to the result
222  result.push_back(max_var);
223  //delete the variable from all sets of shared variables and remove it from the current quantifier block
224  deleteVariable(max_var);
225  block_variables.erase(max_var);
226  }
227  }
228 
229  SMTRAT_LOG_DEBUG("smtrat.covering_ng", "Resulting variable order: " << result);
230 
231  assert(result.size() == formula.variables().size());
232 
233  return result;
234 
235 } // namespace impl
236 
237 } // namespace impl
238 
239 template<VariableOrderingHeuristics vo>
240 inline std::vector<carl::Variable> get_variable_ordering(const carl::QuantifierPrefix& quantifiers, const FormulaT& formula) {
241  switch (vo) {
242  case GreedyMaxUnivariate:
243  return impl::variable_ordering<mcsat::VariableOrdering::GreedyMaxUnivariate>(quantifiers, formula);
244  case FeatureBased:
245  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBased>(quantifiers, formula);
246  case FeatureBasedZ3:
247  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedZ3>(quantifiers, formula);
248  case FeatureBasedBrown:
249  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedBrown>(quantifiers, formula);
251  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedTriangular>(quantifiers, formula);
253  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedLexicographic>(quantifiers, formula);
255  return impl::variable_ordering<mcsat::VariableOrdering::FeatureBasedPickering>(quantifiers, formula);
256  case EarliestSplitting:
257  return impl::sort_earliest_splitting(quantifiers, formula);
258  }
259 }
260 
261 } // namespace smtrat::covering_ng::variables
int var(Lit p)
Definition: SolverTypes.h:64
std::vector< carl::Variable > variable_ordering(const carl::QuantifierPrefix &quantifiers, const FormulaT &formula)
Calculates a variable ordering based on the given quantifier blocks and the given formula.
std::vector< carl::Variable > sort_earliest_splitting(const carl::QuantifierPrefix &prefix, const FormulaT &base_formula)
Calculates a variable ordering based on the given quantifier blocks and the given formula.
std::vector< carl::Variable > get_variable_ordering(const carl::QuantifierPrefix &quantifiers, const FormulaT &formula)
VariableOrderingHeuristics
Possible heuristics for variable ordering.
std::string get_name(VariableOrderingHeuristics ordering)
std::vector< T > prefix(const std::vector< T > vars, std::size_t prefixSize)
Definition: utils.h:349
double num_occurrences(const Constraints &constraints, carl::Variable v)
std::vector< carl::Variable > greedy_max_univariate(const Constraints &c)
carl::Formula< Poly > FormulaT
Definition: types.h:37
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35