SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
MixedSignEncoder.cpp
Go to the documentation of this file.
1 #include "MixedSignEncoder.h"
2 
3 namespace smtrat {
4  std::optional<FormulaT> MixedSignEncoder::doEncode(const ConstraintT& constraint) {
5  // first partition into positive and negative terms
6  std::vector<TermT> positiveTerms;
7  std::vector<TermT> negativeTerms;
8 
9  for (const auto& term : constraint.lhs()) {
10  if (term.is_constant()) continue;
11 
12  if (term.coeff() > 0) {
13  positiveTerms.push_back(term);
14  } else {
15  negativeTerms.push_back(term);
16  }
17  }
18 
19  Poly lhs;
20  Poly rhs;
21  for (const auto& term : positiveTerms) {
22  lhs += term;
23  }
24 
25  for (const auto& term : negativeTerms) {
26  rhs -= term;
27  }
28 
29  if (constraint.relation() == carl::Relation::LEQ) { // we assume mixed signs
30  // x1 + x2 - x3 - x4 - 1 <= 0 iff x1 + x2 -1 <= x3 + x4
31  // lhsValues -1, 0, 1
32  // rhs Value 0, 1, 2
33  // x1 + x2 - 1 >= -1 impl. x3 + x4 >= - 1
34  // x1 + x2 - 1 >= 0 impl x3 + x4 >= 0
35  // x1 + x2 - 1 >= 1 impl x3 + x4 >= 1
36 
37  // now we can express the constraint as sum of positive terms <= negative sum of negative terms - constantPart
38  // this holds iff
39  // take all possible subsetsums of our new lhs. For each of these sums b_i we construct
40  // encode(lhs + constant >= b_i) implies encode(rhs >= b_i)
41 
42  std::vector<Rational> subsetsums = calculateSubsetsums(positiveTerms);
43  FormulasT conjunction;
44  for (const auto& sum : subsetsums) {
45  ConstraintT lhsImplication(lhs - sum, carl::Relation::GEQ); // poly lhs + constantPart >= bi
46  ConstraintT rhsImplication(rhs - sum - constraint.lhs().constant_part(), carl::Relation::GEQ); // rhs >= bi
47 
48 
49  FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication));
50  FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication));
51 
52  conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenLhsEncoding, chosenRhsEncoding));
53  }
54 
55  return FormulaT(carl::FormulaType::AND, conjunction);
56  }
57 
58  if (constraint.relation() == carl::Relation::EQ) {
59  // x1 + x2 - x3 - x4 - 1= 0 iff x1 + x2 -1 = x3 + x4
60  // positiveSums: -1, 0, 1
61  // negativeSums: 0, 1, 2
62 
63  // x3 + x4 = 0 impl. x1 + x2 -1 = 0
64  // x3 + x4 = 1 impl. x1 + x2 -1 = 1
65  // x3 + x4 = 2 impl. x1 + x2 -1 = 2
66  // x1 + x2 -1 = -1 impl. x3 + x4 = -1
67  // x1 + x2 -1 = 0 impl. x3 + x4 = 0
68  // x1 + x2 -1 = 1 impl. x3 + x4 = 1
69 
70  std::vector<Rational> subsetsumsPositive = calculateSubsetsums(positiveTerms);
71  std::vector<Rational> subsetsumsNegative = calculateSubsetsums(negativeTerms);
72  FormulasT conjunction;
73  for (const auto& sum : subsetsumsPositive) {
74  ConstraintT lhsImplication(lhs - sum, carl::Relation::EQ);
75  ConstraintT rhsImplication(rhs - sum - constraint.lhs().constant_part(), carl::Relation::EQ);
76 
77  FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication));
78  FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication));
79 
80  conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenLhsEncoding, chosenRhsEncoding));
81  }
82 
83  for (const auto& sum : subsetsumsNegative) {
84  ConstraintT lhsImplication(lhs - constraint.lhs().constant_part() - sum, carl::Relation::EQ);
85  ConstraintT rhsImplication(rhs - sum, carl::Relation::EQ);
86 
87  FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication));
88  FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication));
89 
90  conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenRhsEncoding, chosenLhsEncoding));
91  }
92 
93  return FormulaT(carl::FormulaType::AND, conjunction);
94  }
95 
96  return {};
97  }
98 
99  bool MixedSignEncoder::canEncode(const ConstraintT& constraint) {
100  bool positiveSign = false;
101  bool negativeSign = false;
102 
103  for (const auto& term: constraint.lhs()) {
104  if (term.is_constant()) continue;
105 
106  if (term.coeff() > 0) {
107  positiveSign = true;
108  }
109 
110  if (term.coeff() < 0) {
111  negativeSign = true;
112  }
113  }
114 
115  return positiveSign && negativeSign;
116  }
117 
119  if (!canEncode(constraint)) return PseudoBoolEncoder::encodingSize(constraint);
120 
121  std::vector<TermT> positiveTerms;
122  std::vector<TermT> negativeTerms;
123  for (const auto& term: constraint.lhs()) {
124  if (term.is_constant()) continue;
125 
126  if (term.coeff() > 0) {
127  positiveTerms.push_back(term);
128  } else {
129  negativeTerms.push_back(term);
130  }
131  }
132 
133  std::set<Rational> sums;
134  for (Rational r : calculateSubsetsums(positiveTerms)) {
135  sums.insert(r);
136  }
137 
138  for (Rational r : calculateSubsetsums(negativeTerms)) {
139  sums.insert(r);
140  }
141 
142  return sums.size();
143  }
144 
145  std::vector<Rational> MixedSignEncoder::calculateSubsetsums(const std::vector<TermT>& terms) {
146  // start with a set in order to filter duplicates easily
147  std::set<Rational> sums;
148 
149  calculateSubsetsums(terms, 0, sums);
150 
151  return std::vector<Rational>(sums.begin(), sums.end());
152  }
153 
154  void MixedSignEncoder::calculateSubsetsums(const std::vector<TermT>& terms, size_t leftIndex, std::set<Rational>& result, Rational sum) {
155  if (leftIndex >= terms.size()) {
156  result.insert(sum);
157  return;
158  }
159 
160  calculateSubsetsums(terms, leftIndex + 1, result, sum + terms[leftIndex].coeff());
161  calculateSubsetsums(terms, leftIndex + 1, result, sum);
162  }
163 
164 
166  FormulaT chosenEncoding;
167  bool hasEncoded = false;
168 
169  if (mShortFormulaEncoder.canEncode(constraint)) {
170  std::optional<FormulaT> shortEncoding = mShortFormulaEncoder.encode(constraint);
171  if (shortEncoding) {
172  chosenEncoding = *shortEncoding;
173  hasEncoded = true;
174  }
175  } else if (mCardinalityEncoder.canEncode(constraint)) {
176  std::optional<FormulaT> cardinalityEncoding = mCardinalityEncoder.encode(constraint);
177  if (cardinalityEncoding) {
178  chosenEncoding = *cardinalityEncoding;
179  hasEncoded = true;
180  }
181  } else if (mLongFormulaEncoder.canEncode(constraint)) {
182  std::optional<FormulaT> longEncoding = mLongFormulaEncoder.encode(constraint);
183  if (longEncoding) {
184  chosenEncoding = *longEncoding;
185  hasEncoded = true;
186  }
187  }
188 
189  if (!hasEncoded) {
190  chosenEncoding = FormulaT(constraint);
191  }
192 
193  return chosenEncoding;
194  }
195 
196 }
bool canEncode(const ConstraintT &constraint)
bool canEncode(const ConstraintT &constraint)
CardinalityEncoder mCardinalityEncoder
std::optional< FormulaT > doEncode(const ConstraintT &constraint)
Rational encodingSize(const ConstraintT &constraint)
PseudoBoolNormalizer mNormalizer
FormulaT findSubEncoding(const ConstraintT &constraint)
ShortFormulaEncoder mShortFormulaEncoder
std::vector< Rational > calculateSubsetsums(const std::vector< TermT > &terms)
bool canEncode(const ConstraintT &constraint)
LongFormulaEncoder mLongFormulaEncoder
virtual Rational encodingSize(const ConstraintT &constraint)
std::optional< FormulaT > encode(const ConstraintT &constraint)
Encodes an arbitrary constraint.
ConstraintT trim(const ConstraintT &constraint)
bool canEncode(const ConstraintT &constraint)
Class to create the formulas for axioms.
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::MultivariatePolynomial< Rational > Poly
Definition: types.h:25
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
carl::Formulas< Poly > FormulasT
Definition: types.h:39
mpq_class Rational
Definition: types.h:19