GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_abduct.cpp Lines: 85 86 98.8 %
Date: 2021-11-07 Branches: 221 448 49.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, 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
 * Implementation of sygus abduction utility, which transforms an arbitrary
14
 * input into an abduction problem.
15
 */
16
17
#include "theory/quantifiers/sygus/sygus_abduct.h"
18
19
#include <sstream>
20
21
#include "expr/dtype.h"
22
#include "expr/node_algorithm.h"
23
#include "expr/skolem_manager.h"
24
#include "expr/sygus_datatype.h"
25
#include "theory/datatypes/sygus_datatype_utils.h"
26
#include "theory/quantifiers/quantifiers_attributes.h"
27
#include "theory/quantifiers/quantifiers_rewriter.h"
28
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
29
#include "theory/quantifiers/sygus/sygus_utils.h"
30
#include "theory/quantifiers/term_util.h"
31
#include "theory/rewriter.h"
32
33
using namespace std;
34
using namespace cvc5::kind;
35
36
namespace cvc5 {
37
namespace theory {
38
namespace quantifiers {
39
40
SygusAbduct::SygusAbduct() {}
41
42
42
Node SygusAbduct::mkAbductionConjecture(const std::string& name,
43
                                        const std::vector<Node>& asserts,
44
                                        const std::vector<Node>& axioms,
45
                                        TypeNode abdGType)
46
{
47
42
  NodeManager* nm = NodeManager::currentNM();
48
42
  SkolemManager* sm = nm->getSkolemManager();
49
84
  std::unordered_set<Node> symset;
50
240
  for (size_t i = 0, size = asserts.size(); i < size; i++)
51
  {
52
198
    expr::getSymbols(asserts[i], symset);
53
  }
54
84
  Trace("sygus-abduct-debug")
55
42
      << "...finish, got " << symset.size() << " symbols." << std::endl;
56
57
42
  Trace("sygus-abduct-debug") << "Setup symbols..." << std::endl;
58
84
  std::vector<Node> syms;
59
84
  std::vector<Node> vars;
60
84
  std::vector<Node> varlist;
61
84
  std::vector<TypeNode> varlistTypes;
62
206
  for (const Node& s : symset)
63
  {
64
320
    TypeNode tn = s.getType();
65
164
    if (tn.isConstructor() || tn.isSelector() || tn.isTester())
66
    {
67
      // datatype symbols should be considered interpreted symbols here, not
68
      // (higher-order) variables.
69
8
      continue;
70
    }
71
    // Notice that we allow for non-first class (e.g. function) variables here.
72
    // This is applicable to the case where we are doing get-abduct in a logic
73
    // with UF.
74
312
    std::stringstream ss;
75
156
    ss << s;
76
312
    Node var = nm->mkBoundVar(tn);
77
156
    syms.push_back(s);
78
156
    vars.push_back(var);
79
312
    Node vlv = nm->mkBoundVar(ss.str(), tn);
80
156
    varlist.push_back(vlv);
81
156
    varlistTypes.push_back(tn);
82
    // set that this variable encodes the term s
83
    SygusVarToTermAttribute sta;
84
156
    vlv.setAttribute(sta, s);
85
  }
86
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
87
88
42
  Trace("sygus-abduct-debug") << "Make abduction predicate..." << std::endl;
89
  // make the abduction predicate to synthesize
90
42
  TypeNode abdType = varlistTypes.empty() ? nm->booleanType()
91
84
                                          : nm->mkPredicateType(varlistTypes);
92
84
  Node abd = nm->mkBoundVar(name.c_str(), abdType);
93
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
94
95
  // the sygus variable list
96
84
  Node abvl;
97
  // if provided, we will associate the provide sygus datatype type with the
98
  // function-to-synthesize. However, we must convert it so that its
99
  // free symbols are universally quantified.
100
42
  if (!abdGType.isNull())
101
  {
102
10
    Assert(abdGType.isDatatype() && abdGType.getDType().isSygus());
103
10
    Trace("sygus-abduct-debug") << "Process abduction type:" << std::endl;
104
10
    Trace("sygus-abduct-debug") << abdGType.getDType().getName() << std::endl;
105
106
    // substitute the free symbols of the grammar with variables corresponding
107
    // to the formal argument list of the new sygus datatype type.
108
    TypeNode abdGTypeS = datatypes::utils::substituteAndGeneralizeSygusType(
109
20
        abdGType, syms, varlist);
110
111
10
    Assert(abdGTypeS.isDatatype() && abdGTypeS.getDType().isSygus());
112
113
20
    Trace("sygus-abduct-debug")
114
10
        << "Make sygus grammar attribute..." << std::endl;
115
20
    Node sym = nm->mkBoundVar("sfproxy_abduct", abdGTypeS);
116
    // Set the sygus grammar attribute to indicate that abdGTypeS encodes the
117
    // grammar for abd.
118
    theory::SygusSynthGrammarAttribute ssg;
119
10
    abd.setAttribute(ssg, sym);
120
10
    Trace("sygus-abduct-debug") << "Finished setting up grammar." << std::endl;
121
122
    // use the bound variable list from the new substituted grammar type
123
10
    const DType& agtsd = abdGTypeS.getDType();
124
10
    abvl = agtsd.getSygusVarList();
125
10
    Assert(!abvl.isNull() && abvl.getKind() == BOUND_VAR_LIST);
126
  }
127
32
  else if (!varlist.empty())
128
  {
129
    // the bound variable list of the abduct-to-synthesize is determined by
130
    // the variable list above
131
24
    abvl = nm->mkNode(BOUND_VAR_LIST, varlist);
132
    // We do not set a grammar type for abd (SygusSynthGrammarAttribute).
133
    // Its grammar will be constructed internally in the default way
134
  }
135
136
42
  Trace("sygus-abduct-debug") << "Make abduction predicate app..." << std::endl;
137
84
  std::vector<Node> achildren;
138
42
  achildren.push_back(abd);
139
42
  achildren.insert(achildren.end(), vars.begin(), vars.end());
140
84
  Node abdApp = vars.empty() ? abd : nm->mkNode(APPLY_UF, achildren);
141
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
142
143
42
  Trace("sygus-abduct-debug") << "Set attributes..." << std::endl;
144
  // set the sygus bound variable list
145
42
  abd.setAttribute(theory::SygusSynthFunVarListAttribute(), abvl);
146
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
147
148
42
  Trace("sygus-abduct-debug") << "Make conjecture body..." << std::endl;
149
84
  Node input = asserts.size() == 1 ? asserts[0] : nm->mkNode(AND, asserts);
150
42
  input = input.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
151
  // A(x) => ~input( x )
152
42
  input = nm->mkNode(OR, abdApp.negate(), input.negate());
153
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
154
155
42
  Trace("sygus-abduct-debug") << "Make conjecture..." << std::endl;
156
42
  Node res = input.negate();
157
42
  if (!vars.empty())
158
  {
159
68
    Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
160
    // exists x. ~( A( x ) => ~input( x ) )
161
34
    res = nm->mkNode(EXISTS, bvl, res);
162
  }
163
  // sygus attribute
164
42
  Node aconj = axioms.size() == 0
165
                   ? nm->mkConst(true)
166
84
                   : (axioms.size() == 1 ? axioms[0] : nm->mkNode(AND, axioms));
167
42
  aconj = aconj.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
168
42
  Trace("sygus-abduct") << "---> Assumptions: " << aconj << std::endl;
169
84
  Node sc = nm->mkNode(AND, aconj, abdApp);
170
42
  if (!vars.empty())
171
  {
172
68
    Node vbvl = nm->mkNode(BOUND_VAR_LIST, vars);
173
34
    sc = nm->mkNode(EXISTS, vbvl, sc);
174
  }
175
84
  Node sygusScVar = sm->mkDummySkolem("sygus_sc", nm->booleanType());
176
42
  sygusScVar.setAttribute(theory::SygusSideConditionAttribute(), sc);
177
84
  Node instAttr = nm->mkNode(INST_ATTRIBUTE, sygusScVar);
178
  // build in the side condition
179
  //   exists x. A( x ) ^ input_axioms( x )
180
  // as an additional annotation on the sygus conjecture. In other words,
181
  // the abducts A we procedure must be consistent with our axioms.
182
183
  // forall A. exists x. ~( A( x ) => ~input( x ) )
184
42
  res = SygusUtils::mkSygusConjecture({abd}, res, {instAttr});
185
42
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
186
187
42
  res = theory::Rewriter::rewrite(res);
188
189
42
  Trace("sygus-abduct") << "Generate: " << res << std::endl;
190
191
84
  return res;
192
}
193
194
}  // namespace quantifiers
195
}  // namespace theory
196
31137
}  // namespace cvc5