GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bv/abstraction.cpp Lines: 165 626 26.4 %
Date: 2021-05-22 Branches: 270 2750 9.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Liana Hadarean, Aina Niemetz, Mathias Preiner
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
 * [[ Add lengthier description here ]]
14
 * \todo document this file
15
 */
16
#include "theory/bv/abstraction.h"
17
18
#include "expr/skolem_manager.h"
19
#include "options/bv_options.h"
20
#include "printer/printer.h"
21
#include "smt/dump.h"
22
#include "smt/smt_engine.h"
23
#include "smt/smt_engine_scope.h"
24
#include "smt/smt_statistics_registry.h"
25
#include "theory/bv/theory_bv_utils.h"
26
#include "theory/rewriter.h"
27
28
using namespace cvc5;
29
using namespace cvc5::theory;
30
using namespace cvc5::theory::bv;
31
using namespace cvc5::context;
32
33
using namespace std;
34
using namespace cvc5::theory::bv::utils;
35
36
4
bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions,
37
                                         std::vector<Node>& new_assertions)
38
{
39
4
  Debug("bv-abstraction") << "AbstractionModule::applyAbstraction\n";
40
41
8
  TimerStat::CodeTimer abstractionTimer(d_statistics.d_abstractionTime);
42
43
8
  TNodeSet seen;
44
14
  for (unsigned i = 0; i < assertions.size(); ++i)
45
  {
46
10
    if (assertions[i].getKind() == kind::OR)
47
    {
48
22
      for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j)
49
      {
50
16
        if (!isConjunctionOfAtoms(assertions[i][j], seen))
51
        {
52
4
          continue;
53
        }
54
24
        Node signature = computeSignature(assertions[i][j]);
55
12
        storeSignature(signature, assertions[i][j]);
56
12
        Debug("bv-abstraction") << "   assertion: " << assertions[i][j] << "\n";
57
12
        Debug("bv-abstraction") << "   signature: " << signature << "\n";
58
      }
59
    }
60
  }
61
4
  finalizeSignatures();
62
63
14
  for (unsigned i = 0; i < assertions.size(); ++i)
64
  {
65
20
    if (assertions[i].getKind() == kind::OR
66
20
        && assertions[i][0].getKind() == kind::AND)
67
    {
68
4
      std::vector<Node> new_children;
69
6
      for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j)
70
      {
71
4
        if (hasSignature(assertions[i][j]))
72
        {
73
          new_children.push_back(abstractSignatures(assertions[i][j]));
74
        }
75
        else
76
        {
77
4
          new_children.push_back(assertions[i][j]);
78
        }
79
      }
80
2
      new_assertions.push_back(utils::mkOr(new_children));
81
    }
82
    else
83
    {
84
      // assertions that are not changed
85
8
      new_assertions.push_back(assertions[i]);
86
    }
87
  }
88
89
8
  if (options::skolemizeArguments())
90
  {
91
    skolemizeArguments(new_assertions);
92
  }
93
94
  // if we are using the eager solver reverse the abstraction
95
4
  if (options::bitblastMode() == options::BitblastMode::EAGER)
96
  {
97
2
    if (d_funcToSignature.size() == 0)
98
    {
99
      // we did not change anything
100
2
      return false;
101
    }
102
    NodeNodeMap seen_rev;
103
    for (unsigned i = 0; i < new_assertions.size(); ++i)
104
    {
105
      new_assertions[i] = reverseAbstraction(new_assertions[i], seen_rev);
106
    }
107
    // we undo the abstraction functions so the logic is QF_BV still
108
    return true;
109
  }
110
111
  // return true if we have created new function symbols for the problem
112
2
  return d_funcToSignature.size() != 0;
113
}
114
115
20
bool AbstractionModule::isConjunctionOfAtoms(TNode node, TNodeSet& seen)
116
{
117
20
  if (seen.find(node)!= seen.end())
118
    return true;
119
120
20
  if (!node.getType().isBitVector() && node.getKind() != kind::AND)
121
  {
122
16
    return utils::isBVPredicate(node);
123
  }
124
125
4
  if (node.getNumChildren() == 0)
126
    return true;
127
128
4
  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
129
4
    if (!isConjunctionOfAtoms(node[i], seen))
130
    {
131
4
      return false;
132
    }
133
  }
134
  seen.insert(node);
135
  return true;
136
}
137
138
139
Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) {
140
141
  if (seen.find(assertion) != seen.end())
142
    return seen[assertion];
143
144
  if (isAbstraction(assertion)) {
145
    Node interp =  getInterpretation(assertion);
146
    seen[assertion] = interp;
147
    Assert(interp.getType() == assertion.getType());
148
    return interp;
149
  }
150
151
  if (assertion.getNumChildren() == 0) {
152
    seen[assertion] = assertion;
153
    return assertion;
154
  }
155
156
  NodeBuilder result(assertion.getKind());
157
  if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) {
158
    result << assertion.getOperator();
159
  }
160
161
  for (unsigned i = 0; i < assertion.getNumChildren(); ++i) {
162
    result << reverseAbstraction(assertion[i], seen);
163
  }
164
  Node res = result;
165
  seen[assertion] = res;
166
  return res;
167
}
168
169
void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions)
170
{
171
  NodeManager* nm = NodeManager::currentNM();
172
  for (unsigned i = 0; i < assertions.size(); ++i)
173
  {
174
    TNode assertion = assertions[i];
175
    if (assertion.getKind() != kind::OR) continue;
176
177
    bool is_skolemizable = true;
178
    for (unsigned k = 0; k < assertion.getNumChildren(); ++k)
179
    {
180
      if (assertion[k].getKind() != kind::EQUAL
181
          || assertion[k][0].getKind() != kind::APPLY_UF
182
          || assertion[k][1].getKind() != kind::CONST_BITVECTOR
183
          || assertion[k][1].getConst<BitVector>() != BitVector(1, 1u))
184
      {
185
        is_skolemizable = false;
186
        break;
187
      }
188
    }
189
190
    if (!is_skolemizable) continue;
191
192
    ArgsTable assertion_table;
193
194
    // collect function symbols and their arguments
195
    for (unsigned j = 0; j < assertion.getNumChildren(); ++j)
196
    {
197
      TNode current = assertion[j];
198
      Assert(current.getKind() == kind::EQUAL
199
             && current[0].getKind() == kind::APPLY_UF);
200
      TNode func = current[0];
201
      ArgsVec args;
202
      for (unsigned k = 0; k < func.getNumChildren(); ++k)
203
      {
204
        args.push_back(func[k]);
205
      }
206
      assertion_table.addEntry(func.getOperator(), args);
207
    }
208
209
    NodeBuilder assertion_builder(kind::OR);
210
    // construct skolemized assertion
211
    for (ArgsTable::iterator it = assertion_table.begin();
212
         it != assertion_table.end();
213
         ++it)
214
    {
215
      // for each function symbol
216
      ++(d_statistics.d_numArgsSkolemized);
217
      TNode func = it->first;
218
      ArgsTableEntry& args = it->second;
219
      NodeBuilder skolem_func(kind::APPLY_UF);
220
      skolem_func << func;
221
      std::vector<Node> skolem_args;
222
223
      for (unsigned j = 0; j < args.getArity(); ++j)
224
      {
225
        bool all_same = true;
226
        for (unsigned k = 1; k < args.getNumEntries(); ++k)
227
        {
228
          if (args.getEntry(k)[j] != args.getEntry(0)[j]) all_same = false;
229
        }
230
        Node new_arg = all_same
231
                           ? (Node)args.getEntry(0)[j]
232
                           : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
233
        skolem_args.push_back(new_arg);
234
        skolem_func << new_arg;
235
      }
236
237
      Node skolem_func_eq1 =
238
          nm->mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
239
240
      // enumerate arguments assignments
241
      std::vector<Node> or_assignments;
242
      for (const ArgsVec& av : args)
243
      // for (ArgsTableEntry::iterator it = args.begin(); it != args.end();
244
      // ++it)
245
      {
246
        NodeBuilder arg_assignment(kind::AND);
247
        // ArgsVec& args = *it;
248
        for (unsigned k = 0; k < av.size(); ++k)
249
        {
250
          Node eq = nm->mkNode(kind::EQUAL, av[k], skolem_args[k]);
251
          arg_assignment << eq;
252
        }
253
        or_assignments.push_back(arg_assignment);
254
      }
255
256
      Node new_func_def =
257
        utils::mkAnd(skolem_func_eq1, utils::mkOr(or_assignments));
258
      assertion_builder << new_func_def;
259
    }
260
    Node new_assertion = assertion_builder;
261
    Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments "
262
                                << assertions[i] << " => \n";
263
    Debug("bv-abstraction-dbg") << "    " << new_assertion;
264
    assertions[i] = new_assertion;
265
  }
266
}
267
268
12
void AbstractionModule::storeSignature(Node signature, TNode assertion) {
269
12
  if(d_signatures.find(signature) == d_signatures.end()) {
270
4
    d_signatures[signature] = 0;
271
  }
272
12
  d_signatures[signature] = d_signatures[signature] + 1;
273
12
  d_assertionToSignature[assertion] = signature;
274
12
}
275
276
12
Node AbstractionModule::computeSignature(TNode node) {
277
12
  resetSignatureIndex();
278
24
  NodeNodeMap cache;
279
12
  Node sig = computeSignatureRec(node, cache);
280
24
  return sig;
281
}
282
283
36
Node AbstractionModule::getSignatureSkolem(TNode node)
284
{
285
36
  Assert(node.getMetaKind() == kind::metakind::VARIABLE);
286
36
  NodeManager* nm = NodeManager::currentNM();
287
36
  SkolemManager* sm = nm->getSkolemManager();
288
36
  unsigned bitwidth = utils::getSize(node);
289
36
  if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end())
290
  {
291
2
    d_signatureSkolems[bitwidth] = vector<Node>();
292
  }
293
294
36
  vector<Node>& skolems = d_signatureSkolems[bitwidth];
295
  // get the index of bv variables of this size
296
36
  unsigned index = getBitwidthIndex(bitwidth);
297
36
  Assert(skolems.size() + 1 >= index);
298
36
  if (skolems.size() == index)
299
  {
300
12
    ostringstream os;
301
6
    os << "sig_" << bitwidth << "_" << index;
302
18
    skolems.push_back(sm->mkDummySkolem(os.str(),
303
12
                                        nm->mkBitVectorType(bitwidth),
304
                                        "skolem for computing signatures"));
305
  }
306
36
  ++(d_signatureIndices[bitwidth]);
307
36
  return skolems[index];
308
}
309
310
36
unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) {
311
36
  if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) {
312
2
    d_signatureIndices[bitwidth] = 0;
313
  }
314
36
  return d_signatureIndices[bitwidth];
315
}
316
317
12
void AbstractionModule::resetSignatureIndex() {
318
22
  for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) {
319
10
    it->second = 0;
320
  }
321
12
}
322
323
4
bool AbstractionModule::hasSignature(Node node) {
324
4
  return d_assertionToSignature.find(node) != d_assertionToSignature.end();
325
}
326
327
Node AbstractionModule::getGeneralizedSignature(Node node) {
328
  NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
329
  Assert(it != d_assertionToSignature.end());
330
  Node generalized_signature = getGeneralization(it->second);
331
  return generalized_signature;
332
}
333
334
114
Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
335
114
  if (cache.find(node) != cache.end()) {
336
    return cache.find(node)->second;
337
  }
338
339
114
  if (node.getNumChildren() == 0) {
340
60
    if (node.getKind() == kind::CONST_BITVECTOR)
341
24
      return node;
342
343
72
    Node sig = getSignatureSkolem(node);
344
36
    cache[node] = sig;
345
36
    return sig;
346
  }
347
348
108
  NodeBuilder builder(node.getKind());
349
54
  if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
350
12
    builder << node.getOperator();
351
  }
352
156
  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
353
204
    Node converted = computeSignatureRec(node[i], cache);
354
102
    builder << converted;
355
  }
356
108
  Node result = builder;
357
54
  cache[node] = result;
358
54
  return result;
359
}
360
361
/**
362
 * Returns 0, if the two are equal,
363
 * 1 if s is a generalization of t
364
 * 2 if t is a generalization of s
365
 * -1 if the two cannot be unified
366
 *
367
 * @param s
368
 * @param t
369
 *
370
 * @return
371
 */
372
4
int AbstractionModule::comparePatterns(TNode s, TNode t) {
373
4
  if (s.getKind() == kind::SKOLEM &&
374
      t.getKind() == kind::SKOLEM) {
375
    return 0;
376
  }
377
378
4
  if (s.getKind() == kind::CONST_BITVECTOR &&
379
      t.getKind() == kind::CONST_BITVECTOR) {
380
    if (s == t) {
381
      return 0;
382
    } else {
383
      return -1;
384
    }
385
  }
386
387
4
  if (s.getKind() == kind::SKOLEM &&
388
      t.getKind() == kind::CONST_BITVECTOR) {
389
    return 1;
390
  }
391
392
4
  if (s.getKind() == kind::CONST_BITVECTOR &&
393
      t.getKind() == kind::SKOLEM) {
394
    return 2;
395
  }
396
397
6
  if (s.getNumChildren() != t.getNumChildren() ||
398
2
      s.getKind() != t.getKind())
399
2
    return -1;
400
401
2
  int unify = 0;
402
2
  for (unsigned i = 0; i < s.getNumChildren(); ++i) {
403
2
    int unify_i = comparePatterns(s[i], t[i]);
404
2
    if (unify_i < 0)
405
2
      return -1;
406
    if (unify == 0) {
407
      unify = unify_i;
408
    } else if (unify != unify_i && unify_i != 0) {
409
      return -1;
410
    }
411
  }
412
  return unify;
413
}
414
415
16
TNode AbstractionModule::getGeneralization(TNode term) {
416
16
  NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
417
  // if not in the map we add it
418
16
  if (it == d_sigToGeneralization.end()) {
419
4
    d_sigToGeneralization[term] = term;
420
4
    return term;
421
  }
422
  // doesn't have a generalization
423
12
  if (it->second == term)
424
12
    return term;
425
426
  TNode generalization = getGeneralization(it->second);
427
  Assert(generalization != term);
428
  d_sigToGeneralization[term] = generalization;
429
  return generalization;
430
}
431
432
void AbstractionModule::storeGeneralization(TNode s, TNode t) {
433
  Assert(s == getGeneralization(s));
434
  Assert(t == getGeneralization(t));
435
  d_sigToGeneralization[s] = t;
436
}
437
438
4
void AbstractionModule::finalizeSignatures()
439
{
440
4
  NodeManager* nm = NodeManager::currentNM();
441
4
  SkolemManager* sm = nm->getSkolemManager();
442
8
  Debug("bv-abstraction")
443
4
      << "AbstractionModule::finalizeSignatures num signatures = "
444
4
      << d_signatures.size() << "\n";
445
8
  TNodeSet new_signatures;
446
447
  // "unify" signatures
448
8
  for (SignatureMap::const_iterator ss = d_signatures.begin();
449
8
       ss != d_signatures.end();
450
       ++ss)
451
  {
452
10
    for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt)
453
    {
454
10
      TNode t = getGeneralization(tt->first);
455
10
      TNode s = getGeneralization(ss->first);
456
457
6
      if (t != s)
458
      {
459
2
        int status = comparePatterns(s, t);
460
2
        Assert(status);
461
2
        if (status < 0) continue;
462
        if (status == 1)
463
        {
464
          storeGeneralization(t, s);
465
        }
466
        else
467
        {
468
          storeGeneralization(s, t);
469
        }
470
      }
471
    }
472
  }
473
  // keep only most general signatures
474
8
  for (SignatureMap::iterator it = d_signatures.begin();
475
8
       it != d_signatures.end();)
476
  {
477
8
    TNode sig = it->first;
478
8
    TNode gen = getGeneralization(sig);
479
4
    if (sig != gen)
480
    {
481
      Assert(d_signatures.find(gen) != d_signatures.end());
482
      // update the count
483
      d_signatures[gen] += d_signatures[sig];
484
      d_signatures.erase(it++);
485
    }
486
    else
487
    {
488
4
      ++it;
489
    }
490
  }
491
492
  // remove signatures that are not frequent enough
493
8
  for (SignatureMap::iterator it = d_signatures.begin();
494
8
       it != d_signatures.end();)
495
  {
496
4
    if (it->second <= 7)
497
    {
498
4
      d_signatures.erase(it++);
499
    }
500
    else
501
    {
502
      ++it;
503
    }
504
  }
505
506
4
  for (SignatureMap::const_iterator it = d_signatures.begin();
507
4
       it != d_signatures.end();
508
       ++it)
509
  {
510
    TNode signature = it->first;
511
    // we already processed this signature
512
    Assert(d_signatureToFunc.find(signature) == d_signatureToFunc.end());
513
514
    Debug("bv-abstraction") << "Processing signature " << signature << " count "
515
                            << it->second << "\n";
516
    std::vector<TypeNode> arg_types;
517
    TNodeSet seen;
518
    collectArgumentTypes(signature, arg_types, seen);
519
    Assert(signature.getType().isBoolean());
520
    // make function return a bitvector of size 1
521
    // Node bv_function = nm->mkNode(kind::ITE, signature, utils::mkConst(1,
522
    // 1u), utils::mkConst(1, 0u));
523
    TypeNode range = nm->mkBitVectorType(1);
524
525
    TypeNode abs_type = nm->mkFunctionType(arg_types, range);
526
    Node abs_func = sm->mkDummySkolem(
527
        "abs_$$", abs_type, "abstraction function for bv theory");
528
    Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n";
529
530
    // NOTE: signature expression type is BOOLEAN
531
    d_signatureToFunc[signature] = abs_func;
532
    d_funcToSignature[abs_func] = signature;
533
  }
534
535
8
  Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted "
536
4
                          << d_signatureToFunc.size() << " signatures. \n";
537
4
}
538
539
void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) {
540
  if (seen.find(sig) != seen.end())
541
    return;
542
543
  if (sig.getKind() == kind::SKOLEM) {
544
    types.push_back(sig.getType());
545
    seen.insert(sig);
546
    return;
547
  }
548
549
  for (unsigned i = 0; i < sig.getNumChildren(); ++i) {
550
    collectArgumentTypes(sig[i], types, seen);
551
    seen.insert(sig);
552
  }
553
}
554
555
void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) {
556
  if (seen.find(node)!= seen.end())
557
    return;
558
559
  if (node.getMetaKind() == kind::metakind::VARIABLE
560
      || node.getKind() == kind::CONST_BITVECTOR)
561
  {
562
    // a constant in the node can either map to an argument of the abstraction
563
    // or can be hard-coded and part of the abstraction
564
    if (signature.getKind() == kind::SKOLEM) {
565
      args.push_back(node);
566
      seen.insert(node);
567
    } else {
568
      Assert(signature.getKind() == kind::CONST_BITVECTOR);
569
    }
570
    //
571
    return;
572
  }
573
  Assert(node.getKind() == signature.getKind()
574
         && node.getNumChildren() == signature.getNumChildren());
575
576
  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
577
    collectArguments(node[i], signature[i], args, seen);
578
    seen.insert(node);
579
  }
580
}
581
582
Node AbstractionModule::abstractSignatures(TNode assertion)
583
{
584
  Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "
585
                          << assertion << "\n";
586
  NodeManager* nm = NodeManager::currentNM();
587
  // assume the assertion has been fully abstracted
588
  Node signature = getGeneralizedSignature(assertion);
589
590
  Debug("bv-abstraction") << "   with sig " << signature << "\n";
591
  NodeNodeMap::iterator it = d_signatureToFunc.find(signature);
592
  if (it != d_signatureToFunc.end())
593
  {
594
    std::vector<Node> args;
595
    TNode func = it->second;
596
    // pushing the function symbol
597
    args.push_back(func);
598
    TNodeSet seen;
599
    collectArguments(assertion, signature, args, seen);
600
    std::vector<TNode> real_args;
601
    for (unsigned i = 1; i < args.size(); ++i)
602
    {
603
      real_args.push_back(args[i]);
604
    }
605
    d_argsTable.addEntry(func, real_args);
606
    Node result = nm->mkNode(
607
        kind::EQUAL,
608
        nm->mkNode(kind::APPLY_UF, args), utils::mkConst(1, 1u));
609
    Debug("bv-abstraction") << "=>   " << result << "\n";
610
    Assert(result.getType() == assertion.getType());
611
    return result;
612
  }
613
  return assertion;
614
}
615
616
12
bool AbstractionModule::isAbstraction(TNode node) {
617
12
  if (node.getKind() != kind::EQUAL)
618
    return false;
619
36
  if ((node[0].getKind() != kind::CONST_BITVECTOR ||
620
84
       node[1].getKind() != kind::APPLY_UF) &&
621
36
      (node[1].getKind() != kind::CONST_BITVECTOR ||
622
12
       node[0].getKind() != kind::APPLY_UF))
623
12
    return false;
624
625
  TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
626
  TNode func = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
627
  Assert(constant.getKind() == kind::CONST_BITVECTOR
628
         && func.getKind() == kind::APPLY_UF);
629
  if (utils::getSize(constant) != 1)
630
    return false;
631
  if (constant != utils::mkConst(1, 1u))
632
    return false;
633
634
  TNode func_symbol = func.getOperator();
635
  if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end())
636
    return false;
637
638
  return true;
639
}
640
641
Node AbstractionModule::getInterpretation(TNode node) {
642
  Assert(isAbstraction(node));
643
  TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
644
  TNode apply = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
645
  Assert(constant.getKind() == kind::CONST_BITVECTOR
646
         && apply.getKind() == kind::APPLY_UF);
647
648
  Node func = apply.getOperator();
649
  Assert(d_funcToSignature.find(func) != d_funcToSignature.end());
650
651
  Node sig = d_funcToSignature[func];
652
653
  // substitute arguments in signature
654
  TNodeTNodeMap seen;
655
  unsigned index = 0;
656
  Node result = substituteArguments(sig, apply, index, seen);
657
  Assert(result.getType().isBoolean());
658
  Assert(index == apply.getNumChildren());
659
  // Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n";
660
  // Debug("bv-abstraction") << "    => " << result << "\n";
661
  return result;
662
}
663
664
Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) {
665
  if (seen.find(signature) != seen.end()) {
666
    return seen[signature];
667
  }
668
669
  if (signature.getKind() == kind::SKOLEM) {
670
    // return corresponding argument and increment counter
671
    seen[signature] = apply[index];
672
    return apply[index++];
673
  }
674
675
  if (signature.getNumChildren() == 0) {
676
    Assert(signature.getMetaKind() != kind::metakind::VARIABLE);
677
    seen[signature] = signature;
678
    return signature;
679
  }
680
681
  NodeBuilder builder(signature.getKind());
682
  if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) {
683
    builder << signature.getOperator();
684
  }
685
686
  for (unsigned i = 0; i < signature.getNumChildren(); ++i) {
687
    Node child = substituteArguments(signature[i], apply, index, seen);
688
    builder << child;
689
  }
690
691
  Node result = builder;
692
  seen[signature]= result;
693
694
  return result;
695
}
696
697
Node AbstractionModule::simplifyConflict(TNode conflict) {
698
  Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
699
  if (conflict.getKind() != kind::AND)
700
    return conflict;
701
702
  std::vector<Node> conjuncts;
703
  for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
704
    conjuncts.push_back(conflict[i]);
705
706
  theory::SubstitutionMap subst(new context::Context());
707
  for (unsigned i = 0; i < conjuncts.size(); ++i) {
708
    TNode conjunct = conjuncts[i];
709
    // substitute s -> t
710
    Node s, t;
711
712
    if (conjunct.getKind() == kind::EQUAL) {
713
      if (conjunct[0].getMetaKind() == kind::metakind::VARIABLE &&
714
          conjunct[1].getKind() == kind::CONST_BITVECTOR) {
715
        s = conjunct[0];
716
        t = conjunct[1];
717
      }
718
      else if (conjunct[1].getMetaKind() == kind::metakind::VARIABLE &&
719
               conjunct[0].getKind() == kind::CONST_BITVECTOR) {
720
        s = conjunct[1];
721
        t = conjunct[0];
722
      } else {
723
        continue;
724
      }
725
726
      Assert(!subst.hasSubstitution(s));
727
      Assert(!t.isNull() && !s.isNull() && s != t);
728
      subst.addSubstitution(s, t);
729
730
      for (unsigned k = 0; k < conjuncts.size(); k++) {
731
        conjuncts[k] = subst.apply(conjuncts[k]);
732
      }
733
    }
734
  }
735
  Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts));
736
737
  Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
738
  Debug("bv-abstraction") << "   => " << new_conflict <<"\n";
739
740
  return new_conflict;
741
}
742
743
void DebugPrintInstantiations(
744
    const std::vector<std::vector<ArgsVec> >& instantiations,
745
    const std::vector<TNode>& functions)
746
{
747
  // print header
748
  Debug("bv-abstraction-dbg") <<"[ ";
749
  for (unsigned i = 0; i < functions.size(); ++i) {
750
    for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) {
751
      Debug("bv-abstraction-dgb") << functions[i][j] <<" ";
752
    }
753
    Debug("bv-abstraction-dgb") << " || ";
754
  }
755
  Debug("bv-abstraction-dbg") <<"]\n";
756
757
  for (unsigned i = 0; i < instantiations.size(); ++i) {
758
    Debug("bv-abstraction-dbg") <<"[";
759
    const std::vector<ArgsVec>& inst = instantiations[i];
760
    for (unsigned j = 0; j < inst.size(); ++j) {
761
      for (unsigned k = 0; k < inst[j].size(); ++k) {
762
        Debug("bv-abstraction-dbg") << inst[j][k] << " ";
763
      }
764
      Debug("bv-abstraction-dbg") << " || ";
765
    }
766
    Debug("bv-abstraction-dbg") <<"]\n";
767
  }
768
}
769
770
void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) {
771
  Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
772
  std::vector<TNode> functions;
773
774
  // collect abstract functions
775
  if (conflict.getKind() != kind::AND) {
776
    if (isAbstraction(conflict)) {
777
      Assert(conflict[0].getKind() == kind::APPLY_UF);
778
      functions.push_back(conflict[0]);
779
    }
780
  } else {
781
    for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
782
      TNode conjunct = conflict[i];
783
      if (isAbstraction(conjunct)) {
784
        Assert(conjunct[0].getKind() == kind::APPLY_UF);
785
        functions.push_back(conjunct[0]);
786
      }
787
    }
788
  }
789
790
  // if (functions.size() >= 3) {
791
  //   // dump conflict
792
  //   NodeNodeMap seen;
793
  //   Node reversed = reverseAbstraction(conflict, seen);
794
  //   std::cout << "CONFLICT " << reversed << "\n";
795
  // }
796
797
798
  if (functions.size() == 0 || functions.size() > options::bvNumFunc()) {
799
    return;
800
  }
801
802
803
  // Skolemize function arguments to avoid confusion in pattern matching
804
  SubstitutionMap skolem_subst(new context::Context());
805
  SubstitutionMap reverse_skolem(new context::Context());
806
  makeFreshSkolems(conflict, skolem_subst, reverse_skolem);
807
808
  Node skolemized_conflict = skolem_subst.apply(conflict);
809
  for (unsigned i = 0; i < functions.size(); ++i) {
810
    functions[i] = skolem_subst.apply(functions[i]);
811
  }
812
813
  conflict = skolem_subst.apply(conflict);
814
815
  LemmaInstantiatior inst(functions, d_argsTable, conflict);
816
  std::vector<Node> new_lemmas;
817
  inst.generateInstantiations(new_lemmas);
818
  for (unsigned i = 0; i < new_lemmas.size(); ++i) {
819
    TNode lemma = reverse_skolem.apply(new_lemmas[i]);
820
    if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) {
821
      lemmas.push_back(lemma);
822
      Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
823
      storeLemma(lemma);
824
    }
825
  }
826
}
827
828
int AbstractionModule::LemmaInstantiatior::next(int val, int index) {
829
  if (val < d_maxMatch[index]  - 1)
830
    return val + 1;
831
  return -1;
832
}
833
834
/**
835
 * Assumes the stack without top is consistent, and checks that the
836
 * full stack is consistent
837
 *
838
 * @param stack
839
 *
840
 * @return
841
 */
842
bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) {
843
  if (stack.empty())
844
    return true;
845
846
  unsigned current = stack.size() - 1;
847
  TNode func = d_functions[current];
848
  ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator());
849
  ArgsVec& args = matches.getEntry(stack[current]);
850
  Assert(args.size() == func.getNumChildren());
851
  for (unsigned k = 0; k < args.size(); ++k) {
852
    TNode s = func[k];
853
    TNode t = args[k];
854
855
    TNode s0 = s;
856
    while (d_subst.hasSubstitution(s0)) {
857
      s0 = d_subst.getSubstitution(s0);
858
    }
859
860
    TNode t0 = t;
861
    while (d_subst.hasSubstitution(t0)) {
862
      t0 = d_subst.getSubstitution(t0);
863
    }
864
865
    if (s0.isConst() && t0.isConst()) {
866
      if (s0 != t0)
867
        return false; // fail
868
      else
869
        continue;
870
    }
871
872
    if(s0.getMetaKind() == kind::metakind::VARIABLE &&
873
       t0.isConst()) {
874
      d_subst.addSubstitution(s0, t0);
875
      continue;
876
    }
877
878
    if (s0.isConst() &&
879
        t0.getMetaKind() == kind::metakind::VARIABLE) {
880
      d_subst.addSubstitution(t0, s0);
881
      continue;
882
    }
883
884
    Assert(s0.getMetaKind() == kind::metakind::VARIABLE
885
           && t0.getMetaKind() == kind::metakind::VARIABLE);
886
887
    if (s0 != t0) {
888
      d_subst.addSubstitution(s0, t0);
889
    }
890
  }
891
  return true;
892
}
893
894
bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
895
  return stack.size() == d_functions.size();
896
}
897
898
void AbstractionModule::LemmaInstantiatior::mkLemma() {
899
  Node lemma = d_subst.apply(d_conflict);
900
  // Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n";
901
  d_lemmas.push_back(lemma);
902
}
903
904
void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
905
  if (!isConsistent(stack))
906
    return;
907
908
  if (accept(stack)) {
909
    mkLemma();
910
    return;
911
  }
912
913
  int x = 0;
914
  while (x != -1) {
915
    d_ctx->push();
916
    stack.push_back(x);
917
    backtrack(stack);
918
919
    d_ctx->pop();
920
    stack.pop_back();
921
    x = next(x, stack.size());
922
  }
923
}
924
925
926
void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) {
927
  Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
928
929
  std::vector<int> stack;
930
  backtrack(stack);
931
  Assert(d_ctx->getLevel() == 0);
932
  Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
933
  lemmas.swap(d_lemmas);
934
}
935
936
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
937
  if (map.hasSubstitution(node)) {
938
    return;
939
  }
940
  if (node.getMetaKind() == kind::metakind::VARIABLE) {
941
    Node skolem = utils::mkVar(utils::getSize(node));
942
    map.addSubstitution(node, skolem);
943
    reverse_map.addSubstitution(skolem, node);
944
    return;
945
  }
946
  if (node.isConst())
947
    return;
948
949
  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
950
    makeFreshSkolems(node[i], map, reverse_map);
951
  }
952
}
953
954
void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
955
  Assert(fresh_args.size() == 0);
956
  Assert(func.getKind() == kind::APPLY_UF);
957
  TNodeNodeMap d_map;
958
  for (unsigned i = 0; i < func.getNumChildren(); ++i) {
959
    TNode arg = func[i];
960
    if (arg.isConst()) {
961
      fresh_args.push_back(arg);
962
      continue;
963
    }
964
    Assert(arg.getMetaKind() == kind::metakind::VARIABLE);
965
    TNodeNodeMap::iterator it = d_map.find(arg);
966
    if (it != d_map.end()) {
967
      fresh_args.push_back(it->second);
968
    } else {
969
      Node skolem = utils::mkVar(utils::getSize(arg));
970
      d_map[arg] = skolem;
971
      fresh_args.push_back(skolem);
972
    }
973
  }
974
  Assert(fresh_args.size() == func.getNumChildren());
975
}
976
977
Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict) {
978
  Assert(ss.size() == tt.size());
979
980
  Debug("bv-abstraction-dbg") << "AbstractionModule::tryMatching conflict = " << conflict << "\n";
981
  if (Debug.isOn("bv-abstraction-dbg")) {
982
    Debug("bv-abstraction-dbg") << "  Match: ";
983
    for (unsigned i = 0; i < ss.size(); ++i) {
984
      Debug("bv-abstraction-dbg") << ss[i] <<" ";
985
986
    }
987
    Debug("bv-abstraction-dbg") << "\n  To: ";
988
    for (unsigned i = 0; i < tt.size(); ++i) {
989
      Debug("bv-abstraction-dbg") << tt[i] <<" ";
990
    }
991
    Debug("bv-abstraction-dbg") <<"\n";
992
  }
993
994
995
  SubstitutionMap subst(new context::Context());
996
997
  for (unsigned i = 0; i < ss.size(); ++i) {
998
    TNode s = ss[i];
999
    TNode t = tt[i];
1000
1001
    TNode s0 = subst.hasSubstitution(s) ? subst.getSubstitution(s) : s;
1002
    TNode t0 = subst.hasSubstitution(t) ? subst.getSubstitution(t) : t;
1003
1004
    if (s0.isConst() && t0.isConst()) {
1005
      if (s0 != t0)
1006
        return Node(); // fail
1007
      else
1008
        continue;
1009
    }
1010
1011
    if(s0.getMetaKind() == kind::metakind::VARIABLE &&
1012
       t0.isConst()) {
1013
      subst.addSubstitution(s0, t0);
1014
      continue;
1015
    }
1016
1017
    if (s0.isConst() &&
1018
        t0.getMetaKind() == kind::metakind::VARIABLE) {
1019
      subst.addSubstitution(t0, s0);
1020
      continue;
1021
    }
1022
1023
    Assert(s0.getMetaKind() == kind::metakind::VARIABLE
1024
           && t0.getMetaKind() == kind::metakind::VARIABLE);
1025
1026
    Assert(s0 != t0);
1027
    subst.addSubstitution(s0, t0);
1028
  }
1029
1030
  Node res = subst.apply(conflict);
1031
  Debug("bv-abstraction-dbg") << "  Lemma: " << res <<"\n";
1032
  return res;
1033
}
1034
1035
void AbstractionModule::storeLemma(TNode lemma) {
1036
  d_addedLemmas.insert(lemma);
1037
  if (lemma.getKind() == kind::AND) {
1038
    for (unsigned i = 0; i < lemma.getNumChildren(); i++) {
1039
      TNode atom = lemma[i];
1040
      atom = atom.getKind() == kind::NOT ? atom[0] : atom;
1041
      Assert(atom.getKind() != kind::NOT);
1042
      Assert(utils::isBVPredicate(atom));
1043
      d_lemmaAtoms.insert(atom);
1044
    }
1045
  } else {
1046
    lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma;
1047
    Assert(utils::isBVPredicate(lemma));
1048
    d_lemmaAtoms.insert(lemma);
1049
  }
1050
}
1051
1052
1053
16
bool AbstractionModule::isLemmaAtom(TNode node) const {
1054
16
  Assert(node.getType().isBoolean());
1055
16
  node = node.getKind() == kind::NOT? node[0] : node;
1056
1057
32
  return d_inputAtoms.find(node) == d_inputAtoms.end() &&
1058
32
    d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
1059
}
1060
1061
12
void AbstractionModule::addInputAtom(TNode atom) {
1062
12
  if (options::bitblastMode() == options::BitblastMode::LAZY)
1063
  {
1064
12
    d_inputAtoms.insert(atom);
1065
  }
1066
12
}
1067
1068
void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) {
1069
  Assert(args.size() == d_arity);
1070
  d_data.push_back(args);
1071
}
1072
1073
void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) {
1074
  if (d_data.find(signature) == d_data.end()) {
1075
    d_data[signature] = ArgsTableEntry(args.size());
1076
  }
1077
  ArgsTableEntry& entry = d_data[signature];
1078
  entry.addArguments(args);
1079
}
1080
1081
1082
bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const {
1083
  return d_data.find(signature) != d_data.end();
1084
}
1085
1086
AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) {
1087
  Assert(hasEntry(signature));
1088
  return d_data.find(signature)->second;
1089
}
1090
1091
9444
AbstractionModule::Statistics::Statistics(
1092
9444
    const std::string& name, const NodeNodeMap& functionsAbstracted)
1093
    : d_numFunctionsAbstracted(
1094
9444
        smtStatisticsRegistry().registerSize<NodeNodeMap>(
1095
18888
            name + "NumFunctionsAbstracted", functionsAbstracted)),
1096
      d_numArgsSkolemized(
1097
18888
          smtStatisticsRegistry().registerInt(name + "NumArgsSkolemized")),
1098
      d_abstractionTime(
1099
28332
          smtStatisticsRegistry().registerTimer(name + "AbstractionTime"))
1100
{
1101
37639
}