GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/quant_elim_solver.cpp Lines: 54 59 91.5 %
Date: 2021-09-07 Branches: 130 306 42.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Aina Niemetz
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * The solver for quantifier elimination queries.
14
 */
15
16
#include "smt/quant_elim_solver.h"
17
18
#include "base/modal_exception.h"
19
#include "expr/skolem_manager.h"
20
#include "expr/subs.h"
21
#include "smt/smt_solver.h"
22
#include "theory/quantifiers/cegqi/nested_qe.h"
23
#include "theory/quantifiers/extended_rewrite.h"
24
#include "theory/quantifiers_engine.h"
25
#include "theory/rewriter.h"
26
#include "theory/theory_engine.h"
27
#include "util/string.h"
28
29
using namespace cvc5::theory;
30
using namespace cvc5::kind;
31
32
namespace cvc5 {
33
namespace smt {
34
35
13182
QuantElimSolver::QuantElimSolver(Env& env, SmtSolver& sms)
36
13182
    : d_env(env), d_smtSolver(sms)
37
{
38
13182
}
39
40
10542
QuantElimSolver::~QuantElimSolver() {}
41
42
30
Node QuantElimSolver::getQuantifierElimination(Assertions& as,
43
                                               Node q,
44
                                               bool doFull,
45
                                               bool isInternalSubsolver)
46
{
47
30
  Trace("smt-qe") << "QuantElimSolver: get qe : " << q << std::endl;
48
30
  if (q.getKind() != EXISTS && q.getKind() != FORALL)
49
  {
50
    throw ModalException(
51
        "Expecting a quantified formula as argument to get-qe.");
52
  }
53
30
  NodeManager* nm = NodeManager::currentNM();
54
  // ensure the body is rewritten
55
30
  q = nm->mkNode(q.getKind(), q[0], Rewriter::rewrite(q[1]));
56
  // do nested quantifier elimination if necessary
57
30
  q = quantifiers::NestedQe::doNestedQe(d_env, q, true);
58
60
  Trace("smt-qe") << "QuantElimSolver: after nested quantifier elimination : "
59
30
                  << q << std::endl;
60
  // tag the quantified formula with the quant-elim attribute
61
60
  TypeNode t = nm->booleanType();
62
30
  TheoryEngine* te = d_smtSolver.getTheoryEngine();
63
30
  Assert(te != nullptr);
64
  Node keyword =
65
60
      nm->mkConst(String(doFull ? "quant-elim" : "quant-elim-partial"));
66
60
  Node n_attr = nm->mkNode(INST_ATTRIBUTE, keyword);
67
30
  n_attr = nm->mkNode(INST_PATTERN_LIST, n_attr);
68
60
  std::vector<Node> children;
69
30
  children.push_back(q[0]);
70
30
  children.push_back(q.getKind() == EXISTS ? q[1] : q[1].negate());
71
30
  children.push_back(n_attr);
72
60
  Node ne = nm->mkNode(EXISTS, children);
73
60
  Trace("smt-qe-debug") << "Query for quantifier elimination : " << ne
74
30
                        << std::endl;
75
30
  Assert(ne.getNumChildren() == 3);
76
  // We consider this to be an entailment check, which also avoids incorrect
77
  // status reporting (see SmtEngineState::d_expectedStatus).
78
60
  Result r = d_smtSolver.checkSatisfiability(as, std::vector<Node>{ne}, true);
79
30
  Trace("smt-qe") << "Query returned " << r << std::endl;
80
30
  if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
81
  {
82
21
    if (r.asSatisfiabilityResult().isSat() != Result::SAT && doFull)
83
    {
84
      Notice()
85
          << "While performing quantifier elimination, unexpected result : "
86
          << r << " for query.";
87
      // failed, return original
88
      return q;
89
    }
90
21
    QuantifiersEngine* qe = te->getQuantifiersEngine();
91
    // must use original quantified formula to compute QE, which ensures that
92
    // e.g. term formula removal is not run on the body. Notice that we assume
93
    // that the (single) quantified formula is preprocessed, rewritten
94
    // version of the input quantified formula q.
95
42
    std::vector<Node> inst_qs;
96
21
    qe->getInstantiatedQuantifiedFormulas(inst_qs);
97
21
    Assert(inst_qs.size() <= 1);
98
42
    Node ret;
99
21
    if (inst_qs.size() == 1)
100
    {
101
32
      Node topq = inst_qs[0];
102
16
      Assert(topq.getKind() == FORALL);
103
32
      Trace("smt-qe") << "Get qe based on preprocessed quantified formula "
104
16
                      << topq << std::endl;
105
32
      std::vector<Node> insts;
106
16
      qe->getInstantiations(topq, insts);
107
      // note we do not convert to witness form here, since we could be
108
      // an internal subsolver (SmtEngine::isInternalSubsolver).
109
16
      ret = nm->mkAnd(insts);
110
16
      Trace("smt-qe") << "QuantElimSolver returned : " << ret << std::endl;
111
16
      if (q.getKind() == EXISTS)
112
      {
113
13
        ret = Rewriter::rewrite(ret.negate());
114
      }
115
    }
116
    else
117
    {
118
5
      ret = nm->mkConst(q.getKind() != EXISTS);
119
    }
120
    // do extended rewrite to minimize the size of the formula aggressively
121
42
    theory::quantifiers::ExtendedRewriter extr(true);
122
21
    ret = extr.extendedRewrite(ret);
123
    // if we are not an internal subsolver, convert to witness form, since
124
    // internally generated skolems should not escape
125
21
    if (!isInternalSubsolver)
126
    {
127
12
      ret = SkolemManager::getOriginalForm(ret);
128
    }
129
21
    return ret;
130
  }
131
  // otherwise, just true/false
132
9
  return nm->mkConst(q.getKind() == EXISTS);
133
}
134
135
}  // namespace smt
136
29502
}  // namespace cvc5