GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/abduction_solver.cpp Lines: 86 101 85.1 %
Date: 2021-11-07 Branches: 162 414 39.1 %

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