GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/abduction_solver.cpp Lines: 83 99 83.8 %
Date: 2021-05-22 Branches: 166 444 37.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Mathias Preiner
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 abduction queries.
14
 */
15
16
#include "smt/abduction_solver.h"
17
18
#include <sstream>
19
20
#include "base/modal_exception.h"
21
#include "options/smt_options.h"
22
#include "smt/env.h"
23
#include "smt/smt_engine.h"
24
#include "theory/quantifiers/quantifiers_attributes.h"
25
#include "theory/quantifiers/sygus/sygus_abduct.h"
26
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
27
#include "theory/smt_engine_subsolver.h"
28
#include "theory/trust_substitutions.h"
29
30
using namespace cvc5::theory;
31
32
namespace cvc5 {
33
namespace smt {
34
35
322
AbductionSolver::AbductionSolver(SmtEngine* parent) : d_parent(parent) {}
36
37
322
AbductionSolver::~AbductionSolver() {}
38
15
bool AbductionSolver::getAbduct(const Node& goal,
39
                                const TypeNode& grammarType,
40
                                Node& abd)
41
{
42
24772
  if (!options::produceAbducts())
43
  {
44
    const char* msg = "Cannot get abduct when produce-abducts options is off.";
45
    throw ModalException(msg);
46
  }
47
15
  Trace("sygus-abduct") << "SmtEngine::getAbduct: goal " << goal << std::endl;
48
30
  std::vector<Node> axioms = d_parent->getExpandedAssertions();
49
30
  std::vector<Node> asserts(axioms.begin(), axioms.end());
50
  // must expand definitions
51
30
  Node conjn = d_parent->getEnv().getTopLevelSubstitutions().apply(goal);
52
  // now negate
53
15
  conjn = conjn.negate();
54
15
  d_abdConj = conjn;
55
15
  asserts.push_back(conjn);
56
30
  std::string name("A");
57
  Node aconj = quantifiers::SygusAbduct::mkAbductionConjecture(
58
30
      name, asserts, axioms, grammarType);
59
  // should be a quantified conjecture with one function-to-synthesize
60
15
  Assert(aconj.getKind() == kind::FORALL && aconj[0].getNumChildren() == 1);
61
  // remember the abduct-to-synthesize
62
15
  d_sssf = aconj[0][0];
63
30
  Trace("sygus-abduct") << "SmtEngine::getAbduct: made conjecture : " << aconj
64
15
                        << ", solving for " << d_sssf << std::endl;
65
  // we generate a new smt engine to do the abduction query
66
15
  initializeSubsolver(d_subsolver);
67
  // get the logic
68
30
  LogicInfo l = d_subsolver->getLogicInfo().getUnlockedCopy();
69
  // enable everything needed for sygus
70
15
  l.enableSygus();
71
15
  d_subsolver->setLogic(l);
72
  // assert the abduction query
73
15
  d_subsolver->assertFormula(aconj);
74
28
  return getAbductInternal(abd);
75
}
76
77
bool AbductionSolver::getAbduct(const Node& goal, Node& abd)
78
{
79
  TypeNode grammarType;
80
  return getAbduct(goal, grammarType, abd);
81
}
82
83
15
bool AbductionSolver::getAbductInternal(Node& abd)
84
{
85
  // should have initialized the subsolver by now
86
15
  Assert(d_subsolver != nullptr);
87
15
  Trace("sygus-abduct") << "  SmtEngine::getAbduct check sat..." << std::endl;
88
28
  Result r = d_subsolver->checkSat();
89
13
  Trace("sygus-abduct") << "  SmtEngine::getAbduct result: " << r << std::endl;
90
13
  if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
91
  {
92
    // get the synthesis solution
93
26
    std::map<Node, Node> sols;
94
13
    d_subsolver->getSynthSolutions(sols);
95
13
    Assert(sols.size() == 1);
96
13
    std::map<Node, Node>::iterator its = sols.find(d_sssf);
97
13
    if (its != sols.end())
98
    {
99
26
      Trace("sygus-abduct")
100
13
          << "SmtEngine::getAbduct: solution is " << its->second << std::endl;
101
13
      abd = its->second;
102
13
      if (abd.getKind() == kind::LAMBDA)
103
      {
104
13
        abd = abd[1];
105
      }
106
      // get the grammar type for the abduct
107
26
      Node agdtbv = d_sssf.getAttribute(SygusSynthFunVarListAttribute());
108
13
      Assert(!agdtbv.isNull());
109
13
      Assert(agdtbv.getKind() == kind::BOUND_VAR_LIST);
110
      // convert back to original
111
      // must replace formal arguments of abd with the free variables in the
112
      // input problem that they correspond to.
113
26
      std::vector<Node> vars;
114
26
      std::vector<Node> syms;
115
      SygusVarToTermAttribute sta;
116
76
      for (const Node& bv : agdtbv)
117
      {
118
63
        vars.push_back(bv);
119
63
        syms.push_back(bv.hasAttribute(sta) ? bv.getAttribute(sta) : bv);
120
      }
121
13
      abd = abd.substitute(vars.begin(), vars.end(), syms.begin(), syms.end());
122
123
      // if check abducts option is set, we check the correctness
124
38
      if (options::checkAbducts())
125
      {
126
9
        checkAbduct(abd);
127
      }
128
13
      return true;
129
    }
130
    Trace("sygus-abduct") << "SmtEngine::getAbduct: could not find solution!"
131
                          << std::endl;
132
    throw RecoverableModalException("Could not find solution for get-abduct.");
133
  }
134
  return false;
135
}
136
137
9
void AbductionSolver::checkAbduct(Node a)
138
{
139
9
  Assert(a.getType().isBoolean());
140
18
  Trace("check-abduct") << "SmtEngine::checkAbduct: get expanded assertions"
141
9
                        << std::endl;
142
143
18
  std::vector<Node> asserts = d_parent->getExpandedAssertions();
144
9
  asserts.push_back(a);
145
146
  // two checks: first, consistent with assertions, second, implies negated goal
147
  // is unsatisfiable.
148
27
  for (unsigned j = 0; j < 2; j++)
149
  {
150
36
    Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
151
18
                          << ": make new SMT engine" << std::endl;
152
    // Start new SMT engine to check solution
153
36
    std::unique_ptr<SmtEngine> abdChecker;
154
18
    initializeSubsolver(abdChecker);
155
36
    Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
156
18
                          << ": asserting formulas" << std::endl;
157
173
    for (const Node& e : asserts)
158
    {
159
155
      abdChecker->assertFormula(e);
160
    }
161
36
    Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
162
18
                          << ": check the assertions" << std::endl;
163
36
    Result r = abdChecker->checkSat();
164
36
    Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
165
18
                          << ": result is " << r << std::endl;
166
36
    std::stringstream serr;
167
18
    bool isError = false;
168
18
    if (j == 0)
169
    {
170
9
      if (r.asSatisfiabilityResult().isSat() != Result::SAT)
171
      {
172
        isError = true;
173
        serr << "SmtEngine::checkAbduct(): produced solution cannot be shown "
174
                "to be consisconsistenttent with assertions, result was "
175
             << r;
176
      }
177
18
      Trace("check-abduct")
178
9
          << "SmtEngine::checkAbduct: goal is " << d_abdConj << std::endl;
179
      // add the goal to the set of assertions
180
9
      Assert(!d_abdConj.isNull());
181
9
      asserts.push_back(d_abdConj);
182
    }
183
    else
184
    {
185
9
      if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
186
      {
187
        isError = true;
188
        serr << "SmtEngine::checkAbduct(): negated goal cannot be shown "
189
                "unsatisfiable with produced solution, result was "
190
             << r;
191
      }
192
    }
193
    // did we get an unexpected result?
194
18
    if (isError)
195
    {
196
      InternalError() << serr.str();
197
    }
198
  }
199
9
}
200
201
}  // namespace smt
202
52973
}  // namespace cvc5