GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/abduction_solver.cpp Lines: 83 99 83.8 %
Date: 2021-08-16 Branches: 163 418 39.0 %

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