1 /********************* */
4 ** Original author: Morgan Deters
5 ** Major contributors: none
6 ** Minor contributors (to current version): Tim King, Kshitij Bansal
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-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 This is a "pickler" for expressions
14 ** This is a "pickler" for expressions. It produces a binary
15 ** serialization of an expression that can be converted back
16 ** into an expression in the same or another ExprManager.
23 #include "expr/pickler.h"
24 #include "expr/pickle_data.h"
25 #include "expr/expr.h"
26 #include "expr/node.h"
27 #include "expr/node_manager.h"
28 #include "expr/node_value.h"
29 #include "expr/expr_manager_scope.h"
30 #include "expr/variable_type_map.h"
31 #include "util/cvc4_assert.h"
32 #include "expr/kind.h"
33 #include "expr/metakind.h"
34 #include "util/output.h"
40 class PicklerPrivate
{
42 typedef std::stack
<Node
> NodeStack
;
49 NodeManager
* const d_nm
;
51 PicklerPrivate(Pickler
& pickler
, ExprManager
* em
) :
53 d_nm(NodeManager::fromExprManager(em
)) {
56 bool atDefaultState(){
57 return d_stack
.empty() && d_current
.empty();
60 /* Helper functions for toPickle */
61 void toCaseNode(TNode n
) throw(AssertionException
, PicklingException
);
62 void toCaseVariable(TNode n
) throw(AssertionException
, PicklingException
);
63 void toCaseConstant(TNode n
);
64 void toCaseOperator(TNode n
) throw(AssertionException
, PicklingException
);
65 void toCaseString(Kind k
, const std::string
& s
);
67 /* Helper functions for toPickle */
68 Node
fromCaseOperator(Kind k
, uint32_t nchildren
);
69 Node
fromCaseConstant(Kind k
, uint32_t nblocks
);
70 std::string
fromCaseString(uint32_t nblocks
);
71 Node
fromCaseVariable(Kind k
);
73 };/* class PicklerPrivate */
75 static Block
mkBlockBody4Chars(char a
, char b
, char c
, char d
) {
77 newBody
.d_body
.d_data
= (a
<< 24) | (b
<< 16) | (c
<< 8) | d
;
81 static char getCharBlockBody(BlockBody body
, int i
) {
82 Assert(0 <= i
&& i
<= 3);
85 case 0: return (body
.d_data
& 0xff000000) >> 24;
86 case 1: return (body
.d_data
& 0x00ff0000) >> 16;
87 case 2: return (body
.d_data
& 0x0000ff00) >> 8;
88 case 3: return (body
.d_data
& 0x000000ff);
95 static Block
mkBlockBody(unsigned data
) {
97 newBody
.d_body
.d_data
= data
;
101 static Block
mkOperatorHeader(Kind k
, unsigned numChildren
) {
103 newHeader
.d_headerOperator
.d_kind
= k
;
104 newHeader
.d_headerOperator
.d_nchildren
= numChildren
;
108 static Block
mkVariableHeader(Kind k
) {
110 newHeader
.d_header
.d_kind
= k
;
114 static Block
mkConstantHeader(Kind k
, unsigned numBlocks
) {
116 newHeader
.d_headerConstant
.d_kind
= k
;
117 newHeader
.d_headerConstant
.d_constblocks
= numBlocks
;
121 Pickler::Pickler(ExprManager
* em
) :
122 d_private(new PicklerPrivate(*this, em
)) {
125 Pickler::~Pickler() {
129 void Pickler::toPickle(Expr e
, Pickle
& p
)
130 throw(PicklingException
) {
131 Assert(NodeManager::fromExprManager(e
.getExprManager()) == d_private
->d_nm
);
132 Assert(d_private
->atDefaultState());
135 d_private
->d_current
.swap(*p
.d_data
);
136 d_private
->toCaseNode(e
.getTNode());
137 d_private
->d_current
.swap(*p
.d_data
);
138 }catch(PicklingException
& pe
){
139 d_private
->d_current
= PickleData();
140 Assert(d_private
->atDefaultState());
144 Assert(d_private
->atDefaultState());
147 void PicklerPrivate::toCaseNode(TNode n
)
148 throw(AssertionException
, PicklingException
) {
149 Debug("pickler") << "toCaseNode: " << n
<< std::endl
;
150 Kind k
= n
.getKind();
151 kind::MetaKind m
= metaKindOf(k
);
153 case kind::metakind::CONSTANT
:
156 case kind::metakind::VARIABLE
:
159 case kind::metakind::OPERATOR
:
160 case kind::metakind::PARAMETERIZED
:
168 void PicklerPrivate::toCaseOperator(TNode n
)
169 throw(AssertionException
, PicklingException
) {
170 Kind k
= n
.getKind();
171 kind::MetaKind m
= metaKindOf(k
);
172 Assert(m
== kind::metakind::PARAMETERIZED
|| m
== kind::metakind::OPERATOR
);
173 if(m
== kind::metakind::PARAMETERIZED
) {
174 toCaseNode(n
.getOperator());
176 for(TNode::iterator i
= n
.begin(), i_end
= n
.end(); i
!= i_end
; ++i
) {
179 d_current
<< mkOperatorHeader(k
, n
.getNumChildren());
182 void PicklerPrivate::toCaseVariable(TNode n
)
183 throw(AssertionException
, PicklingException
) {
184 Kind k
= n
.getKind();
185 Assert(metaKindOf(k
) == kind::metakind::VARIABLE
);
187 const NodeValue
* nv
= n
.d_nv
;
188 uint64_t asInt
= reinterpret_cast<uint64_t>(nv
);
189 uint64_t mapped
= d_pickler
.variableToMap(asInt
);
191 uint32_t firstHalf
= mapped
>> 32;
192 uint32_t secondHalf
= mapped
& 0xffffffff;
194 d_current
<< mkVariableHeader(k
);
195 d_current
<< mkBlockBody(firstHalf
);
196 d_current
<< mkBlockBody(secondHalf
);
200 void PicklerPrivate::toCaseConstant(TNode n
) {
201 Kind k
= n
.getKind();
202 Assert(metaKindOf(k
) == kind::metakind::CONSTANT
);
204 case kind::CONST_BOOLEAN
:
205 d_current
<< mkConstantHeader(k
, 1);
206 d_current
<< mkBlockBody(n
.getConst
<bool>());
208 case kind::CONST_RATIONAL
: {
209 std::string asString
;
210 Assert(k
== kind::CONST_RATIONAL
);
211 const Rational
& q
= n
.getConst
<Rational
>();
212 asString
= q
.toString(16);
213 toCaseString(k
, asString
);
216 case kind::BITVECTOR_EXTRACT_OP
: {
217 BitVectorExtract bve
= n
.getConst
<BitVectorExtract
>();
218 d_current
<< mkConstantHeader(k
, 2);
219 d_current
<< mkBlockBody(bve
.high
);
220 d_current
<< mkBlockBody(bve
.low
);
223 case kind::CONST_BITVECTOR
: {
224 // irritating: we incorporate the size of the string in with the
225 // size of this constant, so it appears as one big constant and
226 // doesn't confuse anybody
227 BitVector bv
= n
.getConst
<BitVector
>();
228 std::string asString
= bv
.getValue().toString(16);
229 d_current
<< mkConstantHeader(k
, 2 + asString
.size());
230 d_current
<< mkBlockBody(bv
.getSize());
231 toCaseString(k
, asString
);
234 case kind::BITVECTOR_SIGN_EXTEND_OP
: {
235 BitVectorSignExtend bvse
= n
.getConst
<BitVectorSignExtend
>();
236 d_current
<< mkConstantHeader(k
, 1);
237 d_current
<< mkBlockBody(bvse
.signExtendAmount
);
245 void PicklerPrivate::toCaseString(Kind k
, const std::string
& s
) {
246 d_current
<< mkConstantHeader(k
, s
.size());
248 unsigned size
= s
.size();
250 for(i
= 0; i
+ 4 <= size
; i
+= 4) {
251 d_current
<< mkBlockBody4Chars(s
[i
+ 0], s
[i
+ 1],s
[i
+ 2], s
[i
+ 3]);
255 case 1: d_current
<< mkBlockBody4Chars(s
[i
+ 0], '\0','\0', '\0'); break;
256 case 2: d_current
<< mkBlockBody4Chars(s
[i
+ 0], s
[i
+ 1], '\0', '\0'); break;
257 case 3: d_current
<< mkBlockBody4Chars(s
[i
+ 0], s
[i
+ 1],s
[i
+ 2], '\0'); break;
264 void Pickler::debugPickleTest(Expr e
) {
266 //ExprManager *em = e.getExprManager();
267 //Expr e1 = mkVar("x", makeType());
270 Pickler
pickler(e
.getExprManager());
273 pickler
.toPickle(e
, p
);
275 uint32_t size
= p
.d_data
->size();
276 std::string str
= p
.d_data
->toString();
278 Expr from
= pickler
.fromPickle(p
);
279 ExprManagerScope
ems(e
);
281 Debug("pickle") << "before: " << e
<< std::endl
;
282 Debug("pickle") << "after: " << from
.getNode() << std::endl
;
283 Debug("pickle") << "pickle: (oct) "<< size
<< " " << str
.length() << " " << str
<< std::endl
;
285 Assert(p
.d_data
->empty());
289 Expr
Pickler::fromPickle(Pickle
& p
) {
290 Assert(d_private
->atDefaultState());
292 d_private
->d_current
.swap(*p
.d_data
);
294 while(!d_private
->d_current
.empty()) {
295 Block front
= d_private
->d_current
.dequeue();
297 Kind k
= (Kind
)front
.d_header
.d_kind
;
298 kind::MetaKind m
= metaKindOf(k
);
300 Node result
= Node::null();
302 case kind::metakind::VARIABLE
:
303 result
= d_private
->fromCaseVariable(k
);
305 case kind::metakind::CONSTANT
:
306 result
= d_private
->fromCaseConstant(k
, front
.d_headerConstant
.d_constblocks
);
308 case kind::metakind::OPERATOR
:
309 case kind::metakind::PARAMETERIZED
:
310 result
= d_private
->fromCaseOperator(k
, front
.d_headerOperator
.d_nchildren
);
315 Assert(result
!= Node::null());
316 d_private
->d_stack
.push(result
);
319 Assert(d_private
->d_current
.empty());
320 Assert(d_private
->d_stack
.size() == 1);
321 Node res
= d_private
->d_stack
.top();
322 d_private
->d_stack
.pop();
324 Assert(d_private
->atDefaultState());
326 return d_private
->d_nm
->toExpr(res
);
329 Node
PicklerPrivate::fromCaseVariable(Kind k
) {
330 Assert(metaKindOf(k
) == kind::metakind::VARIABLE
);
332 Block firstHalf
= d_current
.dequeue();
333 Block secondHalf
= d_current
.dequeue();
335 uint64_t asInt
= firstHalf
.d_body
.d_data
;
337 asInt
= asInt
| (secondHalf
.d_body
.d_data
);
339 uint64_t mapped
= d_pickler
.variableFromMap(asInt
);
341 NodeValue
* nv
= reinterpret_cast<NodeValue
*>(mapped
);
342 Node
fromNodeValue(nv
);
344 Assert(fromNodeValue
.getKind() == k
);
346 return fromNodeValue
;
349 Node
PicklerPrivate::fromCaseConstant(Kind k
, uint32_t constblocks
) {
351 case kind::CONST_BOOLEAN
: {
352 Assert(constblocks
== 1);
353 Block val
= d_current
.dequeue();
355 bool b
= val
.d_body
.d_data
;
356 return d_nm
->mkConst
<bool>(b
);
358 case kind::CONST_RATIONAL
: {
359 std::string s
= fromCaseString(constblocks
);
361 return d_nm
->mkConst
<Rational
>(q
);
363 case kind::BITVECTOR_EXTRACT_OP
: {
364 Block high
= d_current
.dequeue();
365 Block low
= d_current
.dequeue();
366 BitVectorExtract
bve(high
.d_body
.d_data
, low
.d_body
.d_data
);
367 return d_nm
->mkConst
<BitVectorExtract
>(bve
);
369 case kind::CONST_BITVECTOR
: {
370 unsigned size
= d_current
.dequeue().d_body
.d_data
;
371 Block header CVC4_UNUSED
= d_current
.dequeue();
372 Assert(header
.d_headerConstant
.d_kind
== kind::CONST_BITVECTOR
);
373 Assert(header
.d_headerConstant
.d_constblocks
== constblocks
- 2);
374 Integer
value(fromCaseString(constblocks
- 2));
375 BitVector
bv(size
, value
);
376 return d_nm
->mkConst(bv
);
378 case kind::BITVECTOR_SIGN_EXTEND_OP
: {
379 Block signExtendAmount
= d_current
.dequeue();
380 BitVectorSignExtend
bvse(signExtendAmount
.d_body
.d_data
);
381 return d_nm
->mkConst
<BitVectorSignExtend
>(bvse
);
388 std::string
PicklerPrivate::fromCaseString(uint32_t size
) {
389 std::stringstream ss
;
391 for(i
= 0; i
+ 4 <= size
; i
+= 4) {
392 Block front
= d_current
.dequeue();
393 BlockBody body
= front
.d_body
;
395 ss
<< getCharBlockBody(body
,0)
396 << getCharBlockBody(body
,1)
397 << getCharBlockBody(body
,2)
398 << getCharBlockBody(body
,3);
400 Assert(i
== size
- (size
%4) );
402 Block front
= d_current
.dequeue();
403 BlockBody body
= front
.d_body
;
406 ss
<< getCharBlockBody(body
,0);
409 ss
<< getCharBlockBody(body
,0)
410 << getCharBlockBody(body
,1);
413 ss
<< getCharBlockBody(body
,0)
414 << getCharBlockBody(body
,1)
415 << getCharBlockBody(body
,2);
424 Node
PicklerPrivate::fromCaseOperator(Kind k
, uint32_t nchildren
) {
425 kind::MetaKind m
= metaKindOf(k
);
426 bool parameterized
= (m
== kind::metakind::PARAMETERIZED
);
427 uint32_t npops
= nchildren
+ (parameterized
? 1 : 0);
431 Assert(!d_stack
.empty());
432 Node top
= d_stack
.top();
438 NodeBuilder
<> nb(d_nm
, k
);
439 while(!aux
.empty()) {
440 Node top
= aux
.top();
449 d_data
= new PickleData();
452 // Just copying the pointer isn't right, we have to copy the
453 // underlying data. Otherwise user-level Pickles will delete the data
454 // twice! (once in each thread)
455 Pickle::Pickle(const Pickle
& p
) {
456 d_data
= new PickleData(*p
.d_data
);
459 Pickle
& Pickle::operator = (const Pickle
& other
) {
460 if (this != &other
) {
462 d_data
= new PickleData(*other
.d_data
);
472 uint64_t MapPickler::variableFromMap(uint64_t x
) const
474 VarMap::const_iterator i
= d_fromMap
.find(x
);
475 Assert(i
!= d_fromMap
.end());
479 }/* CVC4::expr::pickle namespace */
480 }/* CVC4::expr namespace */
481 }/* CVC4 namespace */