summaryrefslogtreecommitdiff
path: root/src/theory/bv/slice_manager.h
blob: 4fb11f1055781eab291f60bfd9b32a432df1caf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
/*
 * slice_manager.h
 *
 *  Created on: Feb 16, 2011
 *      Author: dejan
 */

#pragma once

#include "context/cdo.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/bv/equality_engine.h"
#include "theory/bv/cd_set_collection.h"

#include <map>
#include <set>
#include <vector>

namespace CVC4 {
namespace theory {
namespace bv {

/**
 * Representation of the slice points in tree.
 */
class slice_point
{
public:

  /** Number of bits we use for the index of the slice */
  static const size_t s_slice_index_bits = 31;
  /** Number of bits we use for the index of the slice_point in the slice memory (reference) */
  static const size_t s_slice_point_reference_bits = 32;
  /** The null reference (maximal number in the given bits) */
  static const size_t null = (1llu << s_slice_point_reference_bits) - 1;

  /** Type of the reference for the outside world */
  typedef size_t reference_type;

  /** Type of the value for the outside world */
  typedef size_t value_type;

private:

  /** The value of the slice point (bit index) */
  size_t d_value       : s_slice_index_bits;
  /** Is this the left child */
  size_t d_isLeftChild : 1;
  /** Reference to the left in the tree */
  size_t d_left        : s_slice_point_reference_bits;
  /** Reference to the right of the tree */
  size_t d_right       : s_slice_point_reference_bits;
  /** Reference to the parent */
  size_t d_parent      : s_slice_point_reference_bits;

public:

  slice_point(size_t value, size_t left, size_t right, size_t parent, bool isLeftChild)
  : d_value(value), d_isLeftChild(isLeftChild ? 1 : 0), d_left(left), d_right(right), d_parent(parent) {}

  bool isLeft() const  { return d_isLeftChild == 1; }
  bool isRight() const { return d_isLeftChild == 0; }

  bool hasLeft() const   { return d_left   != null; }
  bool hasRight() const  { return d_right  != null; }
  bool hasParent() const { return d_parent != null; }

  reference_type getLeft() const   { return d_left;   }
  reference_type getRight() const  { return d_right;  }
  reference_type getParent() const { return d_parent; }

  void removeLeft()  { Assert(d_left  != null); d_left = null;  }
  void removeRight() { Assert(d_right != null); d_right = null; }

  void setLeft(reference_type left)   { Assert(d_left  == null && left  != null); d_left  = left;  }
  void setRight(reference_type right) { Assert(d_right == null && right != null); d_right = right; }

  value_type getValue() const { return d_value; }
};

/**
 * Slice manager should keep the database of slices for the core theory leaf terms, for example
 *
 * term                           core leaf terms
 * ----------------------------------------------
 * (x + y)[31:0]                  x + y
 * a[10:0]@a[11:10]@(b + c)[1:0]  a, b, (b + c)
 * (a << 5)[10]                   (a << 5)
 *
 * If an (dis-)equality is added to the system, we refine the slicing in order to align the extracts, for example
 *
 * equality                       slicing
 * ----------------------------------------------
 * x = y                          x[32,0], y[32,0]
 * x@y = z                        x[32,0], y[32,0], z[64,32,0]
 * x@y = z, x[31:16] = y[15:0]    x[32,16,0], y[32,16,0], z[64,48,32,16,0]
 *
 * As a result of the slicing the slicing equalities are added to the equality engine, using the (associative)
 * concat function that is generated for the equality manager, for example
 *
 * equality                       added equalities
 * ----------------------------------------------
 * x = y                          none
 * x@y = z                        z = concat(z[63:32],z[31:0])
 * x@y = z, x[31:16] = y[15:0]    z = concat(z[63:32],z[31:0]),
 *                                z[63:32] = concat(z[63:48], z[47:32]),
 *                                z[31:0] = concat(z[31:16], z[15:0])
 *
 * In the last example, since concat is associative, the equality engine will know that z = concat(z[63:48], z[47:32],
 * z[31:16], z[15:0]).
 *
 */
template <class TheoryBitvector>
class SliceManager {

public:

  /** The references to backtrackable sets */
  typedef slice_point::reference_type set_reference;

  /** The set collection we'll be using */
  typedef context::BacktrackableSetCollection<std::vector<slice_point>, slice_point, set_reference> set_collection;

  /** The map type from nodes to their references */
  typedef context::CDMap<Node, set_reference, NodeHashFunction> slicing_map;

  /** The equality engine theory of bit-vectors is using */
  typedef typename TheoryBitvector::BvEqualityEngine EqualityEngine;

private:

  /** The theory of bitvectors */
  TheoryBitvector& d_theoryBitvector;

  /** The equality engine */
  EqualityEngine& d_equalityEngine;

  /** The collection of backtrackable sets */
  set_collection d_setCollection;

  /**
   * A map from base nodes to slice points. For each node, the slice points are
   * 0 = i_1 < i_2 < ... < i_n = size, and the slices are
   *            x[i_n-1:i_{n-1}]@x[i_{n-1}-1:i_{n-2}]@...@x[i_2-1:i_1]
   * Each time we add a slict t = t1@t2@...@tn of a term (or a slice), we also notify the equality engine with an
   * extra assertion. Since the equality engine is backtrackable, we will need to backtrack the slices accordingly.
   */
  slicing_map d_nodeSlicing;

public:

  SliceManager(TheoryBitvector& theoryBitvector, context::Context* context)
  : d_theoryBitvector(theoryBitvector),
    d_equalityEngine(theoryBitvector.getEqualityEngine()),
    d_setCollection(context),
    d_nodeSlicing(context)
  {
  }

  /**
   * Adds the equality (lhs = rhs) to the slice manager. The equality is first normalized according to the equality
   * manager, i.e. each base term is taken from the equality manager, replaced in, and then the whole concatenation
   * normalized and sliced wrt the current slicing. The method will not add the equalities to the equality manager,
   * but instead will slice the equality according to the current slicing in order to align all the slices.
   *
   * The terms that get sliced get sent to the theory engine as equalities, i.e if we slice x[10:0] into x[10:5]@x[4:0]
   * equality engine gets the assertion x[10:0] = concat(x[10:5], x[4:0]).
   *
   * input                                 output                            slicing
   * --------------------------------------------------------------------------------------------------------------
   * x@y = y@x                             x = y, y = x                      empty
   * x[31:0]@x[64:32] = x                  x = x[31:0]@x[63:32]              x:{64,32,0}
   * x@y = 0000@x@0000                     x = 0000@x[7:4], y = x[3:0]@0000  x:{8,4,0}
   *
   */
  inline bool solveEquality(TNode lhs, TNode rhs);

private:

  inline bool solveEquality(TNode lhs, TNode rhs, const std::set<TNode>& assumptions);

  /**
   * Slices up lhs and rhs and returns the slices in lhsSlices and rhsSlices. The slices are not atomic,
   * they are sliced in order to make one of lhs or rhs atomic, the other one can be a concatenation.
   */
  inline bool sliceAndSolve(std::vector<Node>& lhs, std::vector<Node>& rhs, const std::set<TNode>& assumptions);

  /**
   * Returns true if the term is already sliced wrt the current slicing. Note that, for example, even though
   * the slicing is empty, x[i:j] is considered sliced. Sliced means that there is no slice points between i and j.
   */
  inline bool isSliced(TNode node) const;

  /**
   * Slices the term wrt the current slicing. When done, isSliced returns true
   */
  inline bool slice(TNode node, std::vector<Node>& sliced);

  /**
   * Returns the base term in the core theory of the given term, i.e.
   * x            => x
   * x[i:j]       => x
   * (x + y)      => x+y
   * (x + y)[i:j] => x+y
   */
  static inline TNode baseTerm(TNode node);

  /**
   * Adds a new slice to the slice set of the given term.
   */
  inline bool addSlice(Node term, unsigned slicePoint);
};

template <class TheoryBitvector>
bool SliceManager<TheoryBitvector>::solveEquality(TNode lhs, TNode rhs) {
  std::set<TNode> assumptions;
  assumptions.insert(lhs.eqNode(rhs));
  bool ok = solveEquality(lhs, rhs, assumptions);
  return ok;
}

template <class TheoryBitvector>
bool SliceManager<TheoryBitvector>::solveEquality(TNode lhs, TNode rhs, const std::set<TNode>& assumptions) {

  BVDebug("slicing") << "SliceMagager::solveEquality(" << lhs << "," << rhs << "," << utils::setToString(assumptions) << ")" << push << std::endl;

  bool ok;

  // The concatenations on the left-hand side (reverse order, first is on top)
  std::vector<Node> lhsTerms;
  if (lhs.getKind() == kind::BITVECTOR_CONCAT) {
    for (int i = (int) lhs.getNumChildren() - 1; i >= 0; -- i) {
      lhsTerms.push_back(lhs[i]);
    }
  } else {
    lhsTerms.push_back(lhs);
  }

  // The concatenations on the right-hand side (reverse order, first is on top)
  std::vector<Node> rhsTerms;
  if (rhs.getKind() == kind::BITVECTOR_CONCAT) {
    for (int i = (int) rhs.getNumChildren() - 1; i >= 0; --i) {
      rhsTerms.push_back(rhs[i]);
    }
  } else {
    rhsTerms.push_back(rhs);
  }

  // Slice the individual terms to align them
  ok = sliceAndSolve(lhsTerms, rhsTerms, assumptions);

  BVDebug("slicing") << "SliceMagager::solveEquality(" << lhs << "," << rhs << "," << utils::setToString(assumptions) << ")" << pop << std::endl;

  return ok;
}


template <class TheoryBitvector>
bool SliceManager<TheoryBitvector>::sliceAndSolve(std::vector<Node>& lhs, std::vector<Node>& rhs, const std::set<TNode>& assumptions)
{

  BVDebug("slicing") << "SliceManager::sliceAndSolve()" << std::endl;

  // Go through the work-list, solve and align
  while (!lhs.empty()) {

    Assert(!rhs.empty());

    BVDebug("slicing") << "SliceManager::sliceAndSolve(): lhs " << utils::vectorToString(lhs) << std::endl;
    BVDebug("slicing") << "SliceManager::sliceAndSolve(): rhs " << utils::vectorToString(rhs) << std::endl;

    // The terms that we need to slice
    Node lhsTerm = lhs.back();
    Node rhsTerm = rhs.back();

    BVDebug("slicing") << "SliceManager::sliceAndSolve(): " << lhsTerm << " : " << rhsTerm << std::endl;

    // If the terms are not sliced wrt the current slicing, we have them sliced
    lhs.pop_back();
    if (!isSliced(lhsTerm)) {
      if (!slice(lhsTerm, lhs)) return false;
      BVDebug("slicing") << "SliceManager::sliceAndSolve(): lhs sliced" << std::endl;
      continue;
    }
    rhs.pop_back();
    if (!isSliced(rhsTerm)) {
      if (!slice(rhsTerm, rhs)) return false;
      // We also need to put lhs back
      lhs.push_back(lhsTerm);
      BVDebug("slicing") << "SliceManager::sliceAndSolve(): rhs sliced" << std::endl;
      continue;
    }

    BVDebug("slicing") << "SliceManager::sliceAndSolve(): both lhs and rhs sliced already" << std::endl;

    // The solving concatenation
    std::vector<Node> concatTerms;

    // If the slices are of the same size we do the additional work
    int sizeDifference = utils::getSize(lhsTerm) - utils::getSize(rhsTerm);

    // We slice constants immediately
    if (sizeDifference > 0 && lhsTerm.getKind() == kind::CONST_BITVECTOR) {
      Node low  = utils::mkConst(lhsTerm.getConst<BitVector>().extract(sizeDifference - 1, 0));
      Node high = utils::mkConst(lhsTerm.getConst<BitVector>().extract(utils::getSize(lhsTerm) - 1, sizeDifference));
      d_equalityEngine.addTerm(low); d_equalityEngine.addTerm(high);
      lhs.push_back(low);
      lhs.push_back(high);
      rhs.push_back(rhsTerm);
      continue;
    }
    if (sizeDifference < 0 && rhsTerm.getKind() == kind::CONST_BITVECTOR) {
      Node low  = utils::mkConst(rhsTerm.getConst<BitVector>().extract(-sizeDifference - 1, 0));
      Node high = utils::mkConst(rhsTerm.getConst<BitVector>().extract(utils::getSize(rhsTerm) - 1, -sizeDifference));
      d_equalityEngine.addTerm(low); d_equalityEngine.addTerm(high);
      rhs.push_back(low);
      rhs.push_back(high);
      lhs.push_back(lhsTerm);
      continue;
    }

    enum SolvingFor {
      SOLVING_FOR_LHS,
      SOLVING_FOR_RHS
    } solvingFor = sizeDifference < 0 || lhsTerm.getKind() == kind::CONST_BITVECTOR ? SOLVING_FOR_RHS : SOLVING_FOR_LHS;

    BVDebug("slicing") << "SliceManager::sliceAndSolve(): " << (solvingFor == SOLVING_FOR_LHS ? "solving for LHS" : "solving for RHS") << std::endl;

    // When we slice in order to align, we might have to reslice the one we are solving for
    bool reslice = false;

    switch (solvingFor) {
    case SOLVING_FOR_RHS: {
      concatTerms.push_back(lhsTerm);
      // Maybe we need to add more lhs to make them equal
      while (sizeDifference < 0 && !reslice) {
        Assert(lhs.size() > 0);
        // Get the next part for lhs
        lhsTerm = lhs.back();
        lhs.pop_back();
        // Slice if necessary
        if (!isSliced(lhsTerm)) {
          if (!slice(lhsTerm, lhs)) return false;
          continue;
        }
        // If we go above 0, we need to cut it
        if (sizeDifference + (int)utils::getSize(lhsTerm) > 0) {
          // Slice it so it fits
          addSlice(lhsTerm, (int)utils::getSize(lhsTerm) + sizeDifference);
          if (!slice(lhsTerm, lhs)) return false;
          if (!isSliced(rhsTerm)) {
            if (!slice(rhsTerm, rhs)) return false;
            while(!concatTerms.empty()) {
              lhs.push_back(concatTerms.back());
              concatTerms.pop_back();
            }
            reslice = true;
          }
          continue;
        }
        concatTerms.push_back(lhsTerm);
        sizeDifference += utils::getSize(lhsTerm);
      }
      break;
    }
    case SOLVING_FOR_LHS: {
      concatTerms.push_back(rhsTerm);
      // Maybe we need to add more rhs to make them equal
      while (sizeDifference > 0 && !reslice) {
        Assert(rhs.size() > 0);
        // Get the next part for lhs
        rhsTerm = rhs.back();
        rhs.pop_back();
        // Slice if necessary
        if (!isSliced(rhsTerm)) {
          if (!slice(rhsTerm, rhs)) return false;
          continue;
        }
        // If we go below 0, we need to cut it
        if (sizeDifference - (int)utils::getSize(rhsTerm) < 0) {
          // Slice it so it fits
          addSlice(rhsTerm, (int)utils::getSize(rhsTerm) - sizeDifference);
          if (!slice(rhsTerm, rhs)) return false;
	  if (!isSliced(lhsTerm)) {
            if (!slice(lhsTerm, lhs)) return false;
            while(!concatTerms.empty()) {
              rhs.push_back(concatTerms.back());
              concatTerms.pop_back();
            }
            reslice = true;
          }
          continue;
        }
        concatTerms.push_back(rhsTerm);
        sizeDifference -= utils::getSize(rhsTerm);
      }
      break;
    }
    }

    // If we need to reslice
    if (reslice) {
	continue;
    }

    Assert(sizeDifference == 0);

    Node concat = utils::mkConcat(concatTerms);
    BVDebug("slicing") << "SliceManager::sliceAndSolve(): concatenation " << concat << std::endl;

    // We have them equal size now. If the base term of the one we are solving is solved into a
    // non-trivial concatenation already, we have to normalize. A concatenation is non-trivial if
    // it is not a direct slicing, i.e it is a concat, and normalize(x) != x
    switch (solvingFor) {
    case SOLVING_FOR_LHS: {
      TNode lhsTermRepresentative = d_equalityEngine.getRepresentative(lhsTerm);
      if (lhsTermRepresentative != lhsTerm &&
          (lhsTermRepresentative.getKind() == kind::BITVECTOR_CONCAT || lhsTermRepresentative.getKind() == kind::CONST_BITVECTOR)) {
        // We need to normalize and solve the normalized equations
        std::vector<TNode> explanation;
        d_equalityEngine.getExplanation(lhsTerm, lhsTermRepresentative, explanation);
        std::set<TNode> additionalAssumptions(assumptions);
        utils::getConjuncts(explanation, additionalAssumptions);
        bool ok = solveEquality(lhsTermRepresentative, concat, additionalAssumptions);
        if (!ok) return false;
      } else {
        // We're fine, just add the equality
        BVDebug("slicing") << "SliceManager::sliceAndSolve(): adding " << lhsTerm << " = " << concat << " " << utils::setToString(assumptions) << std::endl;
        d_equalityEngine.addTerm(concat);
        bool ok = d_equalityEngine.addEquality(lhsTerm, concat, utils::mkConjunction(assumptions));
        if (!ok) return false;
      }
      break;
    }
    case SOLVING_FOR_RHS: {
      TNode rhsTermRepresentative = d_equalityEngine.getRepresentative(rhsTerm);
      if (rhsTermRepresentative != rhsTerm &&
          (rhsTermRepresentative.getKind() == kind::BITVECTOR_CONCAT || rhsTermRepresentative.getKind() == kind::CONST_BITVECTOR)) {
        // We need to normalize and solve the normalized equations
        std::vector<TNode> explanation;
        d_equalityEngine.getExplanation(rhsTerm, rhsTermRepresentative, explanation);
        std::set<TNode> additionalAssumptions(assumptions);
        utils::getConjuncts(explanation, additionalAssumptions);
        bool ok = solveEquality(rhsTermRepresentative, concat, additionalAssumptions);
        if (!ok) return false;
      } else {
        // We're fine, just add the equality
        BVDebug("slicing") << "SliceManager::sliceAndSolve(): adding " << rhsTerm << " = " << concat << utils::setToString(assumptions) << std::endl;
        d_equalityEngine.addTerm(concat);
        bool ok = d_equalityEngine.addEquality(rhsTerm, concat, utils::mkConjunction(assumptions));
        if (!ok) return false;
      }
      break;
    }
    }
  }

  return true;
}

template <class TheoryBitvector>
bool SliceManager<TheoryBitvector>::isSliced(TNode node) const {

  BVDebug("slicing") << "SliceManager::isSliced(" << node << ")" << std::endl;

  bool result = false;

  // Constants are always sliced
  if (node.getKind() == kind::CONST_BITVECTOR) {
    result = true;
  } else {
    // The indices of the beginning and end
    Kind nodeKind = node.getKind();
    unsigned high = nodeKind == kind::BITVECTOR_EXTRACT ? utils::getExtractHigh(node) : utils::getSize(node) - 1;
    unsigned low  = nodeKind == kind::BITVECTOR_EXTRACT ? utils::getExtractLow(node) : 0;

    // Get the base term
    TNode nodeBase = baseTerm(node);
    Assert(nodeBase.getKind() != kind::BITVECTOR_CONCAT);
    Assert(nodeBase.getKind() != kind::CONST_BITVECTOR);

    // Get the base term slice set
    slicing_map::const_iterator find = d_nodeSlicing.find(nodeBase);
    // If no slices, it's just a term, so we are done, UNLESS it's an extract
    if (find == d_nodeSlicing.end()) {
      result = nodeKind != kind::BITVECTOR_EXTRACT;
    } else {
      set_reference sliceSet = (*find).second;
      Assert(d_setCollection.size(sliceSet) >= 2);
      // The term is not sliced if one of the borders is not in the slice set or
      // there is a point between the borders      
      result = 
	d_setCollection.contains(sliceSet, low) && d_setCollection.contains(sliceSet, high + 1) &&
        (low == high || d_setCollection.count(sliceSet, low + 1, high) == 0);
    }
  }

  BVDebug("slicing") << "SliceManager::isSliced(" << node << ") => " << (result ? "true" : "false") << std::endl;
  return result;
}

template <class TheoryBitvector>
bool SliceManager<TheoryBitvector>::addSlice(Node node, unsigned slicePoint) {
  BVDebug("slicing") << "SliceMagager::addSlice(" << node << "," << slicePoint << ")" << std::endl;

  bool ok = true;

  int low  = node.getKind() == kind::BITVECTOR_EXTRACT ? utils::getExtractLow(node) : 0;
  int high = node.getKind() == kind::BITVECTOR_EXTRACT ? utils::getExtractHigh(node) + 1: utils::getSize(node);
  slicePoint += low;

  TNode nodeBase = baseTerm(node);

  Assert(nodeBase.getKind() != kind::CONST_BITVECTOR);

  set_reference sliceSet;
  slicing_map::iterator find = d_nodeSlicing.find(nodeBase);
  if (find == d_nodeSlicing.end()) {
    d_nodeSlicing[nodeBase] = sliceSet = d_setCollection.newSet(0);
    d_setCollection.insert(sliceSet, utils::getSize(nodeBase));
  } else {
    sliceSet = (*find).second;
  }

  Assert(d_setCollection.size(sliceSet) >= 2);

  // What are the points surrounding the new slice point
  int prev = d_setCollection.prev(sliceSet, slicePoint);
  int next = d_setCollection.next(sliceSet, slicePoint);

  // Add the slice to the set
  d_setCollection.insert(sliceSet, slicePoint);
  BVDebug("slicing") << "SliceMagager::addSlice(" << node << "," << slicePoint << "): current set " << d_setCollection.toString(sliceSet) << std::endl;

  // Add the terms and the equality to the equality engine
  Node t1 = utils::mkExtract(nodeBase, next - 1, slicePoint);
  Node t2 = utils::mkExtract(nodeBase, slicePoint - 1, prev);
  Node nodeSlice = (next == high && prev == low) ? node : utils::mkExtract(nodeBase, next - 1, prev);
  Node concat = utils::mkConcat(t1, t2);

  d_equalityEngine.addTerm(t1);
  d_equalityEngine.addTerm(t2);
  d_equalityEngine.addTerm(nodeSlice);
  d_equalityEngine.addTerm(concat);

  // We are free to add this slice, unless the slice has a representative that's already a concat
  TNode nodeSliceRepresentative = d_equalityEngine.getRepresentative(nodeSlice);
  if (nodeSliceRepresentative.getKind() != kind::BITVECTOR_CONCAT) {
    // Add the slice to the equality engine
    ok = d_equalityEngine.addEquality(nodeSlice, concat, utils::mkTrue());
  } else {
    // If the representative is a concat, we must solve it
    // There is no need do add nodeSlice = concat as we will solve the representative of nodeSlice
    std::set<TNode> assumptions;
    std::vector<TNode> equalities;
    d_equalityEngine.getExplanation(nodeSlice, nodeSliceRepresentative, equalities);
    utils::getConjuncts(equalities, assumptions);
    ok = solveEquality(nodeSliceRepresentative, concat, assumptions);
  }

  BVDebug("slicing") << "SliceMagager::addSlice(" << node << "," << slicePoint << ") => " << d_setCollection.toString(d_nodeSlicing[nodeBase]) << std::endl;

  return ok;
}

template <class TheoryBitvector>
inline bool SliceManager<TheoryBitvector>::slice(TNode node, std::vector<Node>& sliced) {

  BVDebug("slicing") << "SliceManager::slice(" << node << ")" << std::endl;

  Assert(!isSliced(node));

  // The indices of the beginning and (one past) end
  unsigned high = node.getKind() == kind::BITVECTOR_EXTRACT ? utils::getExtractHigh(node) + 1 : utils::getSize(node);
  unsigned low  = node.getKind() == kind::BITVECTOR_EXTRACT ? utils::getExtractLow(node) : 0;
  BVDebug("slicing") << "SliceManager::slice(" << node << "): low: " << low << std::endl;
  BVDebug("slicing") << "SliceManager::slice(" << node << "): high: " << high << std::endl;

  // Get the base term
  TNode nodeBase = baseTerm(node);
  Assert(nodeBase.getKind() != kind::BITVECTOR_CONCAT);
  Assert(nodeBase.getKind() != kind::CONST_BITVECTOR);

  // The nodes slice set
  set_reference nodeSliceSet;

  // Find the current one or construct it
  slicing_map::iterator findSliceSet = d_nodeSlicing.find(nodeBase);
  if (findSliceSet == d_nodeSlicing.end()) {
    d_nodeSlicing[nodeBase] = nodeSliceSet = d_setCollection.newSet(0);
    d_setCollection.insert(nodeSliceSet, utils::getSize(nodeBase));
  } else {
    nodeSliceSet = d_nodeSlicing[nodeBase];
  }

  Assert(d_setCollection.size(nodeSliceSet) >= 2);

  BVDebug("slicing") << "SliceManager::slice(" << node << "): current: " << d_setCollection.toString(nodeSliceSet) << std::endl;
  
  // Go through all the points i_0 <= low < i_1 < ... < i_{n-1} < high <= i_n from the slice set
  // and generate the slices [i_0:low-1][low:i_1-1] [i_1:i2] ... [i_{n-1}:high-1][high:i_n-1]. They are in reverse order,
  // as they should be
  
  // The high bound already in the slicing
  size_t i_n = high == utils::getSize(nodeBase) ? high: d_setCollection.next(nodeSliceSet, high - 1);
  BVDebug("slicing") << "SliceManager::slice(" << node << "): i_n: " << i_n << std::endl;  
  // Add the new point to the slice set (they might be there already)
  if (high < i_n) {
    if (!addSlice(nodeBase, high)) return false;
  }
  // The low bound already in the slicing (slicing might have changed after adding high)
  size_t i_0 = low == 0 ? 0 : d_setCollection.prev(nodeSliceSet, low + 1);
  BVDebug("slicing") << "SliceManager::slice(" << node << "): i_0: " << i_0 << std::endl;
  // Add the new points to the slice set (they might be there already)
  if (i_0 < low) {
    if (!addSlice(nodeBase, low)) return false;
  }

  // Get the slice points
  std::vector<size_t> slicePoints;
  if (low + 1 < high) {
    d_setCollection.getElements(nodeSliceSet, low + 1, high - 1, slicePoints);
  }

  // Construct the actuall slicing
  if (slicePoints.size() > 0) {
    BVDebug("slicing") << "SliceManager::slice(" << node << "): adding" << utils::mkExtract(nodeBase, slicePoints[0] - 1, low) << std::endl;
    sliced.push_back(utils::mkExtract(nodeBase, slicePoints[0] - 1, low));
    for (unsigned i = 1; i < slicePoints.size(); ++ i) {
      BVDebug("slicing") << "SliceManager::slice(" << node << "): adding" << utils::mkExtract(nodeBase, slicePoints[i] - 1, slicePoints[i-1])<< std::endl;
      sliced.push_back(utils::mkExtract(nodeBase, slicePoints[i] - 1, slicePoints[i-1]));
    }
    BVDebug("slicing") << "SliceManager::slice(" << node << "): adding" << utils::mkExtract(nodeBase, high-1, slicePoints.back()) << std::endl;
    sliced.push_back(utils::mkExtract(nodeBase, high-1, slicePoints.back()));
  } else {
    sliced.push_back(utils::mkExtract(nodeBase, high - 1, low));
  }
  
  return true;
}

template <class TheoryBitvector>
TNode SliceManager<TheoryBitvector>::baseTerm(TNode node) {
  if (node.getKind() == kind::BITVECTOR_EXTRACT) {
    Assert(node[0].getKind() != kind::BITVECTOR_EXTRACT);
    Assert(node[0].getKind() != kind::CONST_BITVECTOR);
    return node[0];
  } else {
    Assert(node.getKind() != kind::BITVECTOR_CONCAT);
    return node;
  }
}

} // Namespace bv
} // Namespace theory
} // Namespace CVC4
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback