1 /********************* */
2 /*! \file sygus_abduct.cpp
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
12 ** \brief Implementation of sygus abduction utility, which
13 ** transforms an arbitrary input into an abduction problem.
16 #include "theory/quantifiers/sygus/sygus_abduct.h"
18 #include "expr/datatype.h"
19 #include "expr/dtype.h"
20 #include "expr/node_algorithm.h"
21 #include "expr/sygus_datatype.h"
22 #include "theory/datatypes/theory_datatypes_utils.h"
23 #include "theory/quantifiers/quantifiers_attributes.h"
24 #include "theory/quantifiers/quantifiers_rewriter.h"
25 #include "theory/quantifiers/sygus/sygus_grammar_cons.h"
26 #include "theory/quantifiers/term_util.h"
27 #include "theory/rewriter.h"
30 using namespace CVC4::kind
;
34 namespace quantifiers
{
36 SygusAbduct::SygusAbduct() {}
38 Node
SygusAbduct::mkAbductionConjecture(const std::string
& name
,
39 const std::vector
<Node
>& asserts
,
40 const std::vector
<Node
>& axioms
,
43 NodeManager
* nm
= NodeManager::currentNM();
44 std::unordered_set
<Node
, NodeHashFunction
> symset
;
45 for (size_t i
= 0, size
= asserts
.size(); i
< size
; i
++)
47 expr::getSymbols(asserts
[i
], symset
);
49 Trace("sygus-abduct-debug")
50 << "...finish, got " << symset
.size() << " symbols." << std::endl
;
52 Trace("sygus-abduct-debug") << "Setup symbols..." << std::endl
;
53 std::vector
<Node
> syms
;
54 std::vector
<Node
> vars
;
55 std::vector
<Node
> varlist
;
56 std::vector
<TypeNode
> varlistTypes
;
57 for (const Node
& s
: symset
)
59 TypeNode tn
= s
.getType();
60 if (tn
.isConstructor() || tn
.isSelector() || tn
.isTester())
62 // datatype symbols should be considered interpreted symbols here, not
63 // (higher-order) variables.
66 // Notice that we allow for non-first class (e.g. function) variables here.
67 // This is applicable to the case where we are doing get-abduct in a logic
71 Node var
= nm
->mkBoundVar(tn
);
74 Node vlv
= nm
->mkBoundVar(ss
.str(), tn
);
75 varlist
.push_back(vlv
);
76 varlistTypes
.push_back(tn
);
77 // set that this variable encodes the term s
78 SygusVarToTermAttribute sta
;
79 vlv
.setAttribute(sta
, s
);
81 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
83 Trace("sygus-abduct-debug") << "Make abduction predicate..." << std::endl
;
84 // make the abduction predicate to synthesize
85 TypeNode abdType
= varlistTypes
.empty() ? nm
->booleanType()
86 : nm
->mkPredicateType(varlistTypes
);
87 Node abd
= nm
->mkBoundVar(name
.c_str(), abdType
);
88 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
90 // the sygus variable list
92 // if provided, we will associate the provide sygus datatype type with the
93 // function-to-synthesize. However, we must convert it so that its
94 // free symbols are universally quantified.
95 if (!abdGType
.isNull())
97 Assert(abdGType
.isDatatype() && abdGType
.getDType().isSygus());
98 Trace("sygus-abduct-debug") << "Process abduction type:" << std::endl
;
99 Trace("sygus-abduct-debug") << abdGType
.getDType().getName() << std::endl
;
101 // substitute the free symbols of the grammar with variables corresponding
102 // to the formal argument list of the new sygus datatype type.
103 TypeNode abdGTypeS
= datatypes::utils::substituteAndGeneralizeSygusType(
104 abdGType
, syms
, varlist
);
106 Assert(abdGTypeS
.isDatatype() && abdGTypeS
.getDType().isSygus());
108 Trace("sygus-abduct-debug")
109 << "Make sygus grammar attribute..." << std::endl
;
110 Node sym
= nm
->mkBoundVar("sfproxy_abduct", abdGTypeS
);
111 // Set the sygus grammar attribute to indicate that abdGTypeS encodes the
113 theory::SygusSynthGrammarAttribute ssg
;
114 abd
.setAttribute(ssg
, sym
);
115 Trace("sygus-abduct-debug") << "Finished setting up grammar." << std::endl
;
117 // use the bound variable list from the new substituted grammar type
118 const DType
& agtsd
= abdGTypeS
.getDType();
119 abvl
= agtsd
.getSygusVarList();
120 Assert(!abvl
.isNull() && abvl
.getKind() == BOUND_VAR_LIST
);
124 // the bound variable list of the abduct-to-synthesize is determined by
125 // the variable list above
126 abvl
= nm
->mkNode(BOUND_VAR_LIST
, varlist
);
127 // We do not set a grammar type for abd (SygusSynthGrammarAttribute).
128 // Its grammar will be constructed internally in the default way
131 Trace("sygus-abduct-debug") << "Make abduction predicate app..." << std::endl
;
132 std::vector
<Node
> achildren
;
133 achildren
.push_back(abd
);
134 achildren
.insert(achildren
.end(), vars
.begin(), vars
.end());
135 Node abdApp
= vars
.empty() ? abd
: nm
->mkNode(APPLY_UF
, achildren
);
136 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
138 Trace("sygus-abduct-debug") << "Set attributes..." << std::endl
;
139 // set the sygus bound variable list
140 abd
.setAttribute(theory::SygusSynthFunVarListAttribute(), abvl
);
141 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
143 Trace("sygus-abduct-debug") << "Make conjecture body..." << std::endl
;
144 Node input
= asserts
.size() == 1 ? asserts
[0] : nm
->mkNode(AND
, asserts
);
145 input
= input
.substitute(syms
.begin(), syms
.end(), vars
.begin(), vars
.end());
146 // A(x) => ~input( x )
147 input
= nm
->mkNode(OR
, abdApp
.negate(), input
.negate());
148 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
150 Trace("sygus-abduct-debug") << "Make conjecture..." << std::endl
;
151 Node res
= input
.negate();
154 Node bvl
= nm
->mkNode(BOUND_VAR_LIST
, vars
);
155 // exists x. ~( A( x ) => ~input( x ) )
156 res
= nm
->mkNode(EXISTS
, bvl
, res
);
159 Node sygusVar
= nm
->mkSkolem("sygus", nm
->booleanType());
160 theory::SygusAttribute ca
;
161 sygusVar
.setAttribute(ca
, true);
162 Node instAttr
= nm
->mkNode(INST_ATTRIBUTE
, sygusVar
);
163 std::vector
<Node
> iplc
;
164 iplc
.push_back(instAttr
);
165 Node aconj
= axioms
.size() == 0
167 : (axioms
.size() == 1 ? axioms
[0] : nm
->mkNode(AND
, axioms
));
168 aconj
= aconj
.substitute(syms
.begin(), syms
.end(), vars
.begin(), vars
.end());
169 Trace("sygus-abduct") << "---> Assumptions: " << aconj
<< std::endl
;
170 Node sc
= nm
->mkNode(AND
, aconj
, abdApp
);
171 Node vbvl
= nm
->mkNode(BOUND_VAR_LIST
, vars
);
172 sc
= nm
->mkNode(EXISTS
, vbvl
, sc
);
173 Node sygusScVar
= nm
->mkSkolem("sygus_sc", nm
->booleanType());
174 sygusScVar
.setAttribute(theory::SygusSideConditionAttribute(), sc
);
175 instAttr
= nm
->mkNode(INST_ATTRIBUTE
, sygusScVar
);
176 // build in the side condition
177 // exists x. A( x ) ^ input_axioms( x )
178 // as an additional annotation on the sygus conjecture. In other words,
179 // the abducts A we procedure must be consistent with our axioms.
180 iplc
.push_back(instAttr
);
181 Node instAttrList
= nm
->mkNode(INST_PATTERN_LIST
, iplc
);
183 Node fbvl
= nm
->mkNode(BOUND_VAR_LIST
, abd
);
185 // forall A. exists x. ~( A( x ) => ~input( x ) )
186 res
= nm
->mkNode(FORALL
, fbvl
, res
, instAttrList
);
187 Trace("sygus-abduct-debug") << "...finish" << std::endl
;
189 res
= theory::Rewriter::rewrite(res
);
191 Trace("sygus-abduct") << "Generate: " << res
<< std::endl
;
196 } // namespace quantifiers
197 } // namespace theory