SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
TotalizerEncoder.cpp
Go to the documentation of this file.
1 #include"TotalizerEncoder.h"
2 
3 namespace smtrat {
4  std::optional<FormulaT> TotalizerEncoder::doEncode(const ConstraintT& constraint) {
5  assert(canEncode(constraint) && "Input must be <=-cardinality constraint.");
6 
7  auto treeIt = mTreeCache.find(constraint.variables().as_set());
8  if (treeIt == mTreeCache.end()) {
9  TotalizerTree* tree = new TotalizerTree(constraint.variables().as_set());
10  mTreeCache.insert(std::map<carl::Variables, TotalizerTree*>::value_type(constraint.variables().as_set(), tree));
11  mSumPropagationFormulaCache.insert(std::map<carl::Variables, FormulaT>::value_type(constraint.variables().as_set(), encodeSumPropagation(*tree)));
12  }
13 
14  TotalizerTree* tree = mTreeCache[constraint.variables().as_set()];
15 
16  // traverse non-leaf nodes and construct formula
17  FormulaT sumPropagation = mSumPropagationFormulaCache[constraint.variables().as_set()];
18  FormulaT cardinalityRestriction = encodeCardinalityRestriction(*tree, carl::abs(constraint.lhs().constant_part()));
19 
20  return FormulaT(carl::FormulaType::AND, sumPropagation, cardinalityRestriction);
21  }
22 
24  if (tree.isLeaf()) return FormulaT(carl::FormulaType::TRUE);
25 
26  // build sums for current non-leaf
27  std::vector<carl::Variable> leftVars = tree.left().variables();
28  std::vector<carl::Variable> rightVars = tree.right().variables();
29 
30  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Having rootVars = " << tree.variables() << ", leftVars = " << leftVars << ", rightVars = " << rightVars);
31 
32  FormulasT encoding;
33  for (size_t alpha = 0; alpha <= leftVars.size(); alpha++) {
34  for (size_t beta = 0; beta <= rightVars.size(); beta++) {
35  size_t sigma = alpha + beta;
36  FormulaT leftNode;
37  FormulaT rightNode;
38  FormulaT rootNode;
39 
40  if (alpha != 0) {
41  leftNode = !FormulaT(leftVars[alpha - 1]);
42  }
43 
44  if (beta != 0) {
45  rightNode = !FormulaT(rightVars[beta - 1]);
46  }
47 
48  if (sigma == 0) {
49  rootNode = FormulaT(carl::FormulaType::TRUE);
50  } else {
51  rootNode = FormulaT(tree.variables().at(sigma - 1));
52  }
53 
54  FormulaT nodeSum = FormulaT(carl::FormulaType::OR, leftNode, rightNode, rootNode);
55  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Adding for alpha =" << alpha << ", beta = " << beta << ", sigma = " << sigma << ": " << nodeSum);
56  encoding.push_back(nodeSum);
57  }
58  }
59 
60  encoding.push_back(encodeSumPropagation(tree.left()));
61  encoding.push_back(encodeSumPropagation(tree.right()));
62 
63  return FormulaT(carl::FormulaType::AND, encoding);
64 
65  }
66 
68  std::vector<carl::Variable> vars = root.variables();
69 
70  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Restricting to " << constantPart << ": " << vars);
71 
72  FormulasT encoding;
73  for (size_t i = vars.size() - 1; i >= 0; i--) {
74  if (Rational(i) < constantPart) break; // abort when we reach constantPart var
75  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Forcing variable " << vars[i] << " at index " << i << " to false");
76  encoding.push_back(!FormulaT(vars[i]));
77 
78  if (i == 0) break; // underflow protection
79  }
80 
81  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Those literals are added to assure cardinality: " << encoding);
82  return FormulaT(carl::FormulaType::AND, encoding);
83  }
84 
85  bool TotalizerEncoder::canEncode(const ConstraintT& constraint) {
86  bool encodable = true;
87  bool allCoeffPositive = true;
88  bool allCoeffNegative = true;
89 
90  for (const auto& it : constraint.lhs()) {
91  if (it.is_constant()) continue;
92 
93  encodable = encodable && (it.coeff() == 1 || it.coeff() == -1);
94  if (it.coeff() < 0) allCoeffPositive = false;
95  if (it.coeff() > 0) allCoeffNegative = false;
96  }
97 
98  encodable = encodable && allCoeffNegative != allCoeffPositive;
99  encodable = encodable && constraint.relation() == carl::Relation::LEQ;
100 
101  return encodable;
102  }
103 
105  std::size_t nVars = constraint.variables().size();
106 
107  return carl::log(Rational(nVars)) * nVars;
108  }
109 
110  TotalizerTree::TotalizerTree(const std::set<carl::Variable>& variables) {
111  if (variables.size() == 1) {
112  // just keep the variable
113  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Adding leaf " << *(variables.begin()) );
114  mNodeVariables.push_back(*(variables.begin()));
115  return;
116  }
117 
118  // create size() many new variables save it to this node
119  for (size_t i = 0; i < variables.size(); i++) {
120  mNodeVariables.push_back(carl::fresh_boolean_variable());
121  }
122 
123  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Partitioning node variables " << mNodeVariables);
124 
125  // partition variables
126  std::set<carl::Variable> leftVariables;
127  std::set<carl::Variable> rightVariables;
128 
129  std::vector<carl::Variable> varVector(variables.begin(), variables.end());
130  int i = -1;
131  auto separator = std::partition(varVector.begin(), varVector.end(), [&](const carl::Variable&){
132  i++;
133  return i % 2 == 0;
134  });
135 
136  for (auto it = varVector.begin(); it != separator; it++) {
137  rightVariables.insert(*it);
138  }
139 
140  for (auto it = separator; it != varVector.end(); it++) {
141  leftVariables.insert(*it);
142  }
143 
144  assert(leftVariables.size() != 0);
145  assert(rightVariables.size() != 0);
146 
147  // create children recursively
148  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Adding child left " << leftVariables);
149  SMTRAT_LOG_TRACE("smtrat.pbpp.total", "Adding child right " << rightVariables);
150  mLeft = new TotalizerTree(leftVariables);
151  mRight = new TotalizerTree(rightVariables);
152 
153  }
154 
156  for (const auto& it : mTreeCache) {
157  delete it.second;
158  }
159  }
160 }
161 
std::optional< FormulaT > doEncode(const ConstraintT &constraint)
Rational encodingSize(const ConstraintT &constraint)
FormulaT encodeCardinalityRestriction(TotalizerTree &tree, Rational constantPart)
std::map< carl::Variables, FormulaT > mSumPropagationFormulaCache
FormulaT encodeSumPropagation(TotalizerTree &tree)
std::map< carl::Variables, TotalizerTree * > mTreeCache
bool canEncode(const ConstraintT &constraint)
std::vector< carl::Variable > mNodeVariables
TotalizerTree * mLeft
TotalizerTree * mRight
TotalizerTree & left()
std::vector< carl::Variable > variables()
TotalizerTree & right()
TotalizerTree(const std::set< carl::Variable > &variables)
void log(const FormulaDB &db, const FormulaID id)
Numeric abs(const Numeric &_value)
Calculates the absolute value of the given Numeric.
Definition: Numeric.cpp:276
std::vector< carl::Variable > vars(const std::pair< QuantifierType, std::vector< carl::Variable >> &p)
Definition: QEQuery.h:43
Class to create the formulas for axioms.
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
carl::Formulas< Poly > FormulasT
Definition: types.h:39
mpq_class Rational
Definition: types.h:19
#define SMTRAT_LOG_TRACE(channel, msg)
Definition: logging.h:36