SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
FourierMotzkinQE.cpp
Go to the documentation of this file.
1 #include "FourierMotzkinQE.h"
2 #include "../util/EqualitySubstitution.h"
3 #include "eigen_helpers.h"
4 
5 
6 namespace smtrat::qe::fm {
7 
9  // gather quantified variables
10  std::vector<carl::Variable> elimination_vars;
11  for (const auto& [type, vars] : m_query) {
12  assert(type == QuantifierType::EXISTS); // Only support existential for now
13  elimination_vars.insert(elimination_vars.end(), vars.begin(), vars.end());
14  }
15  SMTRAT_STATISTICS_CALL(FMQEStatistics::get_instance().vars(elimination_vars.size()));
16 
17  // gather input constraints
18  FormulasT constraints;
19  if (m_formula.type() == carl::FormulaType::CONSTRAINT) constraints.push_back(m_formula);
20  else constraints = m_formula.subformulas();
21  SMTRAT_STATISTICS_CALL(FMQEStatistics::get_instance().input(constraints.size()));
22 
23  for (const auto& c : constraints) {
24  assert(c.type() == carl::FormulaType::CONSTRAINT);
25  assert(
26  c.constraint().relation() == carl::Relation::LEQ ||
27  c.constraint().relation() == carl::Relation::EQ // TODO: what about strict constraints?
28  );
29  }
30 
31 
32  // eliminate variables using equalities
33  qe::util::EquationSubstitution es(constraints, elimination_vars);
34  if (!es.apply()) {
35  SMTRAT_STATISTICS_CALL(FMQEStatistics::get_instance().elim_eq(elimination_vars.size()));
36  SMTRAT_STATISTICS_CALL(FMQEStatistics::get_instance().eq_conflict());
37  return FormulaT(carl::FormulaType::FALSE);
38  }
39  constraints = es.remaining_constraints();
40  elimination_vars = es.remaining_variables();
41  SMTRAT_LOG_DEBUG("smtrat.qe","Constraints after es: " << constraints);
42  SMTRAT_STATISTICS_CALL(FMQEStatistics::get_instance().elim_eq(elimination_vars.size()));
43 
44  if (elimination_vars.empty()) {
45  return FormulaT(carl::FormulaType::AND, constraints);
46  }
47 
48  // filter finished constraints from remaining constraints
49  FormulasT filtered;
50  for (const auto& c : constraints) {
51  auto vars = carl::variables(c).as_set();
52  if (std::any_of(elimination_vars.begin(),
53  elimination_vars.end(),
54  [&vars](const auto v){ return vars.contains(v); })
55  ) {
56  filtered.push_back(c);
57  } else m_finished.insert(c);
58  }
59  constraints = filtered;
60  SMTRAT_LOG_DEBUG("smtrat.qe","Constraints after filtering: " << constraints);
61 
62  // map from variables to indices
63  m_var_idx = qe::util::VariableIndex(elimination_vars);
64  m_var_idx.gather_variables(constraints);
65 
66  // gather elimination indices
67  std::vector<std::size_t> elim_cols;
68  for (std::size_t i = 0; i < elimination_vars.size(); ++i) {
69  elim_cols.push_back(i);
70  }
71 
72  // transform to matrix-vector representation
73  matrix_t m = matrix_t::Zero(constraints.size(), m_var_idx.size());
74  vector_t b = vector_t::Zero(constraints.size());
75 
76  for (std::size_t i = 0; i < constraints.size(); ++i) {
77  for (const auto& t : constraints[i].constraint().lhs()) {
78  if (t.is_constant()) b(i) = Rational(-1)*t.coeff();
79  else {
80  assert(t.is_single_variable());
81  m(i, m_var_idx.index(t.single_variable())) = t.coeff();
82  }
83  }
84  }
85 
86  auto [result_m, result_b] = eliminateCols(m, b, elim_cols);
87  // convert back
88  for (std::size_t i = 0, n_rows = result_m.rows(), n_cols = result_m.cols(); i < n_rows; ++i) {
89  Poly lhs = Poly(Rational(-1)*result_b(i));
90  for (std::size_t j = 0; j < n_cols; ++j) {
91  Rational& coeff = result_m(i,j);
92  if (!carl::is_zero(coeff)) {
93  lhs += coeff*Poly(m_var_idx.var(j));
94  }
95  }
96  m_finished.insert(FormulaT(lhs, carl::Relation::LEQ));
97  }
98 
100 }
101 
102 
103 std::pair<matrix_t, vector_t> FourierMotzkinQE::eliminateCol(const matrix_t& constraints,
104  const vector_t& constants,
105  std::size_t col,
106  bool conservative) {
107  std::vector<std::size_t> nbs, ubs, lbs;
108 
109  // initialize: detect upper and lower bounds
110  for (Eigen::Index row = 0; row < constraints.rows(); ++row) {
111  if (carl::is_zero(constraints(row, col))) nbs.push_back(row);
112  else if (carl::is_positive(constraints(row, col))) ubs.push_back(row);
113  else lbs.push_back(row);
114  }
115 
116  // initialize result
117  Eigen::Index n_new_constr = nbs.size() + (ubs.size() * lbs.size());
118  matrix_t newConstraints = matrix_t(n_new_constr, constraints.cols());
119  vector_t newConstants = vector_t(n_new_constr);
120 
121  // compute new constraints
122  std::vector<Eigen::Index> emptyRows;
123  Eigen::Index row = 0;
124  for (; row < nbs.size(); ++row) {
125  newConstraints.row(row) = constraints.row(nbs[row]);
126  newConstants.row(row) = constants.row(nbs[row]);
127  }
128 
129  for (; row < n_new_constr; ++row) {
130  std::size_t combinationIndex = row - nbs.size();
131  std::size_t lb_idx = combinationIndex / ubs.size();
132  std::size_t ub_idx = combinationIndex % ubs.size();
133  assert(lb_idx < lbs.size());
134  assert(ub_idx < ubs.size());
135  newConstraints.row(row) = (constraints(ubs[ub_idx], col) * constraints.row(lbs[lb_idx]))
136  - (constraints(lbs[lb_idx], col) * constraints.row(ubs[ub_idx]));
137  newConstants(row) = (constraints(ubs[ub_idx], col) * constants(lbs[lb_idx]))
138  - (constraints(lbs[lb_idx], col) * constants(ubs[ub_idx]));
139 
140  if (newConstraints.row(row).isZero()) emptyRows.push_back(row);
141  }
142 
143  assert(vector_t(newConstraints.col(col)) == vector_t::Zero(newConstants.rows()));
144 
145  // cleanup if demanded
146  if (!conservative) { newConstraints = removeCol(newConstraints, col); }
147 
148  // Optimizer<Number> opt(newConstraints, newConstants); TODO
149  // auto red = opt.redundantConstraints();
150  // newConstraints = removeRows(newConstraints, red);
151  // newConstants = removeRows(newConstants, red);
152  return std::make_pair(newConstraints, newConstants);
153 }
154 
155 std::pair<matrix_t, vector_t> FourierMotzkinQE::eliminateCols(const matrix_t &constraints,
156  const vector_t constants,
157  const std::vector<std::size_t> &cols,
158  bool conservative) {
159  auto resultConstraints = constraints;
160  auto resultConstants = constants;
161  auto dimensionsToEliminate = cols;
162  while (!dimensionsToEliminate.empty()) {
163  std::cout << "starting iteration\n";
164  std::tie(resultConstraints, resultConstants) =
165  eliminateCol(resultConstraints, resultConstants,
166  dimensionsToEliminate.front(), conservative);
167  // update the indices if the matrix and vector have changed dimensions
168  if (!conservative) {
169  // decrement this index, as one dimension before has been eliminated.
170  for (auto &idx: dimensionsToEliminate) {
171  if (idx > dimensionsToEliminate.front()) --idx;
172  }
173  }
174  dimensionsToEliminate.erase(std::begin(dimensionsToEliminate));
175  std::cout << "end iteration\n";
176 
177  }
178  return std::make_pair(resultConstraints, resultConstants);
179 }
180 
181 
182 
183 } // namespace smtrat::qe::fm
std::pair< matrix_t, vector_t > eliminateCols(const matrix_t &constraints, const vector_t constants, const std::vector< std::size_t > &cols, bool conservative=true)
std::pair< matrix_t, vector_t > eliminateCol(const matrix_t &constraints, const vector_t &constants, std::size_t col, bool conservative=true)
FormulaT m_formula
The quantifiers to eliminate.
qe::util::VariableIndex m_var_idx
The logical representation of the solution space.
std::vector< carl::Variable > remaining_variables()
Eigen::Matrix< Rational, Eigen::Dynamic, Eigen::Dynamic > matrix_t
Definition: eigen_helpers.h:10
Eigen::Matrix< Rational, Eigen::Dynamic, 1 > vector_t
Definition: eigen_helpers.h:9
matrix_t removeCol(const matrix_t &original, std::size_t colIndex)
Definition: eigen_helpers.h:90
QuantifierType type(const std::pair< QuantifierType, std::vector< carl::Variable >> &p)
Definition: QEQuery.h:39
std::vector< carl::Variable > vars(const std::pair< QuantifierType, std::vector< carl::Variable >> &p)
Definition: QEQuery.h:43
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::MultivariatePolynomial< Rational > Poly
Definition: types.h:25
carl::Formulas< Poly > FormulasT
Definition: types.h:39
mpq_class Rational
Definition: types.h:19
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35
#define SMTRAT_STATISTICS_CALL(function)
Definition: Statistics.h:23
std::size_t index(carl::Variable v) const
Definition: VariableIndex.h:28
carl::Variable var(std::size_t i) const
Definition: VariableIndex.h:33
void gather_variables(const FormulasT &fs)
Definition: VariableIndex.h:22