SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
PseudoBoolNormalizer.cpp
Go to the documentation of this file.
1 #include "PseudoBoolNormalizer.h"
2 
3 #include <utility>
4 
5 namespace smtrat {
6 
7  std::pair<std::optional<FormulaT>, ConstraintT> PseudoBoolNormalizer::normalize(const ConstraintT& constraint) {
8  bool hasPositiveCoeff = false;
9 
10  for (const auto& term : constraint.lhs()) {
11  if ( term.is_constant() ) continue;
12 
13  if (term.coeff() > Rational(0)) hasPositiveCoeff = true;
14  }
15 
16 
17  ConstraintT normalizedConstraint = constraint; // initially we assume that the input is normalized
18  std::optional<FormulaT> booleanPart = {};
19 
20  if (constraint.relation() == carl::Relation::LESS) {
21  normalizedConstraint = normalizeLessConstraint(normalizedConstraint);
22  }
23 
24  assert(constraint.relation() == carl::Relation::LEQ || constraint.relation() == carl::Relation::EQ);
25 
26  if (hasPositiveCoeff) {
27  std::pair<std::optional<FormulaT>, ConstraintT> processedPositiveConstr = removePositiveCoeff(normalizedConstraint);
28  booleanPart = processedPositiveConstr.first;
29  normalizedConstraint = processedPositiveConstr.second;
30  }
31 
32  if (trimmable(normalizedConstraint)) {
33  normalizedConstraint = trim(normalizedConstraint);
34  }
35 
36  normalizedConstraint = gcd(normalizedConstraint);
37 
38  return std::make_pair(booleanPart, normalizedConstraint);
39  }
40 
41  bool PseudoBoolNormalizer::trimmable(const ConstraintT& constraint) {
42  Rational constantPart = constraint.lhs().constant_part();
43 
44  for (const auto& term : constraint.lhs()) {
45  if ( term.is_constant() ) continue;
46 
47  if (carl::abs(term.coeff()) > constantPart && constantPart >= Rational(1)) return true;
48  }
49 
50  return false;
51  }
52 
54  Rational constant = constraint.lhs().constant_part();
55 
56  Poly result;
57  for (const auto& term : constraint.lhs()) {
58  if (term.is_constant()) continue;
59 
60  if (constant >= Rational(1) && term.coeff() < Rational(0) && carl::abs(term.coeff()) > constant) {
61  result -= constant*term.single_variable();
62  } else {
63  result += term;
64  }
65  }
66 
67  result += constant;
68 
69  return ConstraintT(result, carl::Relation::LEQ);
70 
71  }
72 
73  std::pair<std::optional<FormulaT>, ConstraintT> PseudoBoolNormalizer::removePositiveCoeff(const ConstraintT& constraint) {
74  Poly result;
75  FormulasT additionalBoolPart;
76 
77  for (const auto& term : constraint.lhs()) {
78  if (term.is_constant()) {
79  result += term.coeff();
80  continue;
81  }
82 
83  if (term.coeff() > Rational(0)) {
84  // substitute the variable by negative coefficient and the new variable
85  carl::Variable currentVariable = term.single_variable();
86  if (mVariablesCache.find(currentVariable) == mVariablesCache.end()) {
87  // we have not seen this variable before. Add new variable for substitution and add to booleanPart
88  mVariablesCache[currentVariable] = carl::fresh_boolean_variable();
89  Poly lhs; // b1 = 1 - b2 iff b1 + b2 - 1 = 0
90  lhs += currentVariable;
91  lhs += mVariablesCache[currentVariable];
92  lhs -= 1;
93  additionalBoolPart.push_back(FormulaT(ConstraintT(lhs, carl::Relation::EQ)));
94  }
95 
96  result -= term.coeff() * mVariablesCache[currentVariable];
97  result += term.coeff();
98  } else {
99  result += term;
100  }
101  }
102 
103  return std::make_pair(FormulaT(carl::FormulaType::AND, additionalBoolPart), ConstraintT(result, constraint.relation()));
104  }
105 
107  std::vector<Rational> coeffs;
108  Rational constant = constraint.lhs().constant_part();
109  for (const auto& term : constraint.lhs()) {
110  if (term.is_constant()) continue;
111 
112  coeffs.push_back(term.coeff());
113  }
114 
115  if (coeffs.size() == 0) {
116  return constraint;
117  }
118 
119  Rational gcd = coeffs[0];
120  for (size_t i = 0; i < coeffs.size(); i++) {
121  gcd = carl::gcd(coeffs[i], gcd);
122  }
123 
124  if (carl::is_one(gcd)) {
125  return constraint;
126  }
127 
128  return ConstraintT(((constraint.lhs() - constant) / gcd) + Poly(carl::floor(constant/gcd)), constraint.relation());
129  }
130 
132  assert(constraint.relation() == carl::Relation::LESS);
133 
134  // e.g. -x1 -x2 - 2 < 0 iff x1 + x2 < 2 iff x1 + x2 <= 1
135  // This means we need to add(!!) 1 to lhs
136  return ConstraintT(constraint.lhs() + Rational(1), carl::Relation::LEQ);
137  }
138 
139 }
std::pair< std::optional< FormulaT >, ConstraintT > normalize(const ConstraintT &constraint)
Modifies the constraint in-place and returns an additional boolean formula.
ConstraintT trim(const ConstraintT &constraint)
std::pair< std::optional< FormulaT >, ConstraintT > removePositiveCoeff(const ConstraintT &constraint)
ConstraintT normalizeLessConstraint(const ConstraintT &constraint)
bool trimmable(const ConstraintT &constraint)
ConstraintT gcd(const ConstraintT &constraint)
std::map< carl::Variable, carl::Variable > mVariablesCache
Numeric abs(const Numeric &_value)
Calculates the absolute value of the given Numeric.
Definition: Numeric.cpp:276
Numeric gcd(const Numeric &_valueA, const Numeric &_valueB)
Calculates the greatest common divisor of the two arguments.
Definition: Numeric.cpp:317
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