1 /********************* */
2 /*! \file theory_sets_rewriter.cpp
4 ** Original author: Kshitij Bansal
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2013-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
12 ** \brief Sets theory rewriter.
14 ** Sets theory rewriter.
17 #include "theory/sets/theory_sets_rewriter.h"
23 typedef std::set
<TNode
> Elements
;
24 typedef std::hash_map
<TNode
, Elements
, TNodeHashFunction
> SettermElementsMap
;
26 bool checkConstantMembership(TNode elementTerm
, TNode setTerm
)
28 // Assume from pre-rewrite constant sets look like the following:
29 // (union (setenum bla) (union (setenum bla) ... (union (setenum bla) (setenum bla) ) ... ))
31 if(setTerm
.getKind() == kind::EMPTYSET
) {
35 if(setTerm
.getKind() == kind::SET_SINGLETON
) {
36 return elementTerm
== setTerm
[0];
39 Assert(setTerm
.getKind() == kind::UNION
&& setTerm
[1].getKind() == kind::SET_SINGLETON
,
40 "kind was %d, term: %s", setTerm
.getKind(), setTerm
.toString().c_str());
42 return elementTerm
== setTerm
[1][0] || checkConstantMembership(elementTerm
, setTerm
[0]);
44 // switch(setTerm.getKind()) {
45 // case kind::EMPTYSET:
47 // case kind::SET_SINGLETON:
48 // return elementTerm == setTerm[0];
50 // return checkConstantMembership(elementTerm, setTerm[0]) ||
51 // checkConstantMembership(elementTerm, setTerm[1]);
52 // case kind::INTERSECTION:
53 // return checkConstantMembership(elementTerm, setTerm[0]) &&
54 // checkConstantMembership(elementTerm, setTerm[1]);
55 // case kind::SETMINUS:
56 // return checkConstantMembership(elementTerm, setTerm[0]) &&
57 // !checkConstantMembership(elementTerm, setTerm[1]);
64 RewriteResponse
TheorySetsRewriter::postRewrite(TNode node
) {
65 NodeManager
* nm
= NodeManager::currentNM();
66 Kind kind
= node
.getKind();
71 if(!node
[0].isConst() || !node
[1].isConst())
75 TNode S
= preRewrite(node
[1]).node
;
76 bool isMember
= checkConstantMembership(node
[0], S
);
77 return RewriteResponse(REWRITE_DONE
, nm
->mkConst(isMember
));
81 // rewrite (A subset-or-equal B) as (A union B = B)
84 return RewriteResponse(REWRITE_AGAIN_FULL
,
85 nm
->mkNode(kind::EQUAL
,
86 nm
->mkNode(kind::UNION
, A
, B
),
92 //rewrite: t = t with true (t term)
93 //rewrite: c = c' with c different from c' false (c, c' constants)
94 //otherwise: sort them
95 if(node
[0] == node
[1]) {
96 Trace("sets-postrewrite") << "Sets::postRewrite returning true" << std::endl
;
97 return RewriteResponse(REWRITE_DONE
, nm
->mkConst(true));
99 else if (node
[0].isConst() && node
[1].isConst()) {
100 Trace("sets-postrewrite") << "Sets::postRewrite returning false" << std::endl
;
101 return RewriteResponse(REWRITE_DONE
, nm
->mkConst(false));
103 else if (node
[0] > node
[1]) {
104 Node newNode
= nm
->mkNode(node
.getKind(), node
[1], node
[0]);
105 Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode
<< std::endl
;
106 return RewriteResponse(REWRITE_DONE
, newNode
);
111 case kind::SETMINUS
: {
112 if(node
[0] == node
[1]) {
113 Node newNode
= nm
->mkConst(EmptySet(nm
->toType(node
[0].getType())));
114 Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode
<< std::endl
;
115 return RewriteResponse(REWRITE_DONE
, newNode
);
116 } else if(node
[0].getKind() == kind::EMPTYSET
||
117 node
[1].getKind() == kind::EMPTYSET
) {
118 Trace("sets-postrewrite") << "Sets::postRewrite returning " << node
[0] << std::endl
;
119 return RewriteResponse(REWRITE_DONE
, node
[0]);
120 } else if (node
[0] > node
[1]) {
121 Node newNode
= nm
->mkNode(node
.getKind(), node
[1], node
[0]);
122 Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode
<< std::endl
;
123 return RewriteResponse(REWRITE_DONE
, newNode
);
128 case kind::INTERSECTION
: {
129 if(node
[0] == node
[1]) {
130 Trace("sets-postrewrite") << "Sets::postRewrite returning " << node
[0] << std::endl
;
131 return RewriteResponse(REWRITE_DONE
, node
[0]);
132 } else if(node
[0].getKind() == kind::EMPTYSET
) {
133 return RewriteResponse(REWRITE_DONE
, node
[0]);
134 } else if(node
[1].getKind() == kind::EMPTYSET
) {
135 return RewriteResponse(REWRITE_DONE
, node
[1]);
136 } else if (node
[0] > node
[1]) {
137 Node newNode
= nm
->mkNode(node
.getKind(), node
[1], node
[0]);
138 Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode
<< std::endl
;
139 return RewriteResponse(REWRITE_DONE
, newNode
);
145 if(node
[0] == node
[1]) {
146 Trace("sets-postrewrite") << "Sets::postRewrite returning " << node
[0] << std::endl
;
147 return RewriteResponse(REWRITE_DONE
, node
[0]);
148 } else if(node
[0].getKind() == kind::EMPTYSET
) {
149 return RewriteResponse(REWRITE_DONE
, node
[1]);
150 } else if(node
[1].getKind() == kind::EMPTYSET
) {
151 return RewriteResponse(REWRITE_DONE
, node
[0]);
152 } else if (node
[0] > node
[1]) {
153 Node newNode
= nm
->mkNode(node
.getKind(), node
[1], node
[0]);
154 Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode
<< std::endl
;
155 return RewriteResponse(REWRITE_DONE
, newNode
);
162 }//switch(node.getKind())
164 // This default implementation
165 return RewriteResponse(REWRITE_DONE
, node
);
168 const Elements
& collectConstantElements(TNode setterm
, SettermElementsMap
& settermElementsMap
) {
169 SettermElementsMap::const_iterator it
= settermElementsMap
.find(setterm
);
170 if(it
== settermElementsMap
.end() ) {
172 Kind k
= setterm
.getKind();
173 unsigned numChildren
= setterm
.getNumChildren();
175 if(numChildren
== 2) {
176 const Elements
& left
= collectConstantElements(setterm
[0], settermElementsMap
);
177 const Elements
& right
= collectConstantElements(setterm
[1], settermElementsMap
);
180 if(left
.size() >= right
.size()) {
181 cur
= left
; cur
.insert(right
.begin(), right
.end());
183 cur
= right
; cur
.insert(left
.begin(), left
.end());
186 case kind::INTERSECTION
:
187 std::set_intersection(left
.begin(), left
.end(), right
.begin(), right
.end(),
188 std::inserter(cur
, cur
.begin()) );
191 std::set_difference(left
.begin(), left
.end(), right
.begin(), right
.end(),
192 std::inserter(cur
, cur
.begin()) );
200 /* assign emptyset, which is default */
202 case kind::SET_SINGLETON
:
203 Assert(setterm
[0].isConst());
204 cur
.insert(setterm
[0]);
211 it
= settermElementsMap
.insert(SettermElementsMap::value_type(setterm
, cur
)).first
;
216 Node
elementsToNormalConstant(Elements elements
,
219 NodeManager
* nm
= NodeManager::currentNM();
221 if(elements
.size() == 0) {
222 return nm
->mkConst(EmptySet(nm
->toType(setType
)));
225 Elements::iterator it
= elements
.begin();
226 Node cur
= nm
->mkNode(kind::SET_SINGLETON
, *it
);
227 while( ++it
!= elements
.end() ) {
228 cur
= nm
->mkNode(kind::UNION
, cur
,
229 nm
->mkNode(kind::SET_SINGLETON
, *it
));
237 RewriteResponse
TheorySetsRewriter::preRewrite(TNode node
) {
238 NodeManager
* nm
= NodeManager::currentNM();
241 if(node
.getKind() == kind::EQUAL
&& node
[0] == node
[1])
242 return RewriteResponse(REWRITE_DONE
, nm
->mkConst(true));
243 // Further optimization, if constants but differing ones
245 if(node
.getType().isSet() && node
.isConst()) {
246 //rewrite set to normal form
247 SettermElementsMap setTermElementsMap
; // cache
248 const Elements
& elements
= collectConstantElements(node
, setTermElementsMap
);
249 return RewriteResponse(REWRITE_DONE
, elementsToNormalConstant(elements
, node
.getType()));
252 return RewriteResponse(REWRITE_DONE
, node
);
255 }/* CVC4::theory::sets namespace */
256 }/* CVC4::theory namespace */
257 }/* CVC4 namespace */