GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_abduct.cpp Lines: 85 86 98.8 %
Date: 2021-09-18 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
16
Node SygusAbduct::mkAbductionConjecture(const std::string& name,
43
                                        const std::vector<Node>& asserts,
44
                                        const std::vector<Node>& axioms,
45
                                        TypeNode abdGType)
46
{
47
16
  NodeManager* nm = NodeManager::currentNM();
48
16
  SkolemManager* sm = nm->getSkolemManager();
49
32
  std::unordered_set<Node> symset;
50
106
  for (size_t i = 0, size = asserts.size(); i < size; i++)
51
  {
52
90
    expr::getSymbols(asserts[i], symset);
53
  }
54
32
  Trace("sygus-abduct-debug")
55
16
      << "...finish, got " << symset.size() << " symbols." << std::endl;
56
57
16
  Trace("sygus-abduct-debug") << "Setup symbols..." << std::endl;
58
32
  std::vector<Node> syms;
59
32
  std::vector<Node> vars;
60
32
  std::vector<Node> varlist;
61
32
  std::vector<TypeNode> varlistTypes;
62
91
  for (const Node& s : symset)
63
  {
64
146
    TypeNode tn = s.getType();
65
75
    if (tn.isConstructor() || tn.isSelector() || tn.isTester())
66
    {
67
      // datatype symbols should be considered interpreted symbols here, not
68
      // (higher-order) variables.
69
4
      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
142
    std::stringstream ss;
75
71
    ss << s;
76
142
    Node var = nm->mkBoundVar(tn);
77
71
    syms.push_back(s);
78
71
    vars.push_back(var);
79
142
    Node vlv = nm->mkBoundVar(ss.str(), tn);
80
71
    varlist.push_back(vlv);
81
71
    varlistTypes.push_back(tn);
82
    // set that this variable encodes the term s
83
    SygusVarToTermAttribute sta;
84
71
    vlv.setAttribute(sta, s);
85
  }
86
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
87
88
16
  Trace("sygus-abduct-debug") << "Make abduction predicate..." << std::endl;
89
  // make the abduction predicate to synthesize
90
16
  TypeNode abdType = varlistTypes.empty() ? nm->booleanType()
91
32
                                          : nm->mkPredicateType(varlistTypes);
92
32
  Node abd = nm->mkBoundVar(name.c_str(), abdType);
93
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
94
95
  // the sygus variable list
96
32
  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
16
  if (!abdGType.isNull())
101
  {
102
6
    Assert(abdGType.isDatatype() && abdGType.getDType().isSygus());
103
6
    Trace("sygus-abduct-debug") << "Process abduction type:" << std::endl;
104
6
    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
12
        abdGType, syms, varlist);
110
111
6
    Assert(abdGTypeS.isDatatype() && abdGTypeS.getDType().isSygus());
112
113
12
    Trace("sygus-abduct-debug")
114
6
        << "Make sygus grammar attribute..." << std::endl;
115
12
    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
6
    abd.setAttribute(ssg, sym);
120
6
    Trace("sygus-abduct-debug") << "Finished setting up grammar." << std::endl;
121
122
    // use the bound variable list from the new substituted grammar type
123
6
    const DType& agtsd = abdGTypeS.getDType();
124
6
    abvl = agtsd.getSygusVarList();
125
6
    Assert(!abvl.isNull() && abvl.getKind() == BOUND_VAR_LIST);
126
  }
127
10
  else if (!varlist.empty())
128
  {
129
    // the bound variable list of the abduct-to-synthesize is determined by
130
    // the variable list above
131
9
    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
16
  Trace("sygus-abduct-debug") << "Make abduction predicate app..." << std::endl;
137
32
  std::vector<Node> achildren;
138
16
  achildren.push_back(abd);
139
16
  achildren.insert(achildren.end(), vars.begin(), vars.end());
140
32
  Node abdApp = vars.empty() ? abd : nm->mkNode(APPLY_UF, achildren);
141
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
142
143
16
  Trace("sygus-abduct-debug") << "Set attributes..." << std::endl;
144
  // set the sygus bound variable list
145
16
  abd.setAttribute(theory::SygusSynthFunVarListAttribute(), abvl);
146
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
147
148
16
  Trace("sygus-abduct-debug") << "Make conjecture body..." << std::endl;
149
32
  Node input = asserts.size() == 1 ? asserts[0] : nm->mkNode(AND, asserts);
150
16
  input = input.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
151
  // A(x) => ~input( x )
152
16
  input = nm->mkNode(OR, abdApp.negate(), input.negate());
153
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
154
155
16
  Trace("sygus-abduct-debug") << "Make conjecture..." << std::endl;
156
16
  Node res = input.negate();
157
16
  if (!vars.empty())
158
  {
159
30
    Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
160
    // exists x. ~( A( x ) => ~input( x ) )
161
15
    res = nm->mkNode(EXISTS, bvl, res);
162
  }
163
  // sygus attribute
164
16
  Node aconj = axioms.size() == 0
165
                   ? nm->mkConst(true)
166
32
                   : (axioms.size() == 1 ? axioms[0] : nm->mkNode(AND, axioms));
167
16
  aconj = aconj.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
168
16
  Trace("sygus-abduct") << "---> Assumptions: " << aconj << std::endl;
169
32
  Node sc = nm->mkNode(AND, aconj, abdApp);
170
16
  if (!vars.empty())
171
  {
172
30
    Node vbvl = nm->mkNode(BOUND_VAR_LIST, vars);
173
15
    sc = nm->mkNode(EXISTS, vbvl, sc);
174
  }
175
32
  Node sygusScVar = sm->mkDummySkolem("sygus_sc", nm->booleanType());
176
16
  sygusScVar.setAttribute(theory::SygusSideConditionAttribute(), sc);
177
32
  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
16
  res = SygusUtils::mkSygusConjecture({abd}, res, {instAttr});
185
16
  Trace("sygus-abduct-debug") << "...finish" << std::endl;
186
187
16
  res = theory::Rewriter::rewrite(res);
188
189
16
  Trace("sygus-abduct") << "Generate: " << res << std::endl;
190
191
32
  return res;
192
}
193
194
}  // namespace quantifiers
195
}  // namespace theory
196
29574
}  // namespace cvc5