GCC Code Coverage Report
Directory: . Exec Total Coverage
File: test/unit/theory/theory_bags_rewriter_white.cpp Lines: 478 478 100.0 %
Date: 2021-11-07 Branches: 1435 3442 41.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Aina Niemetz, Mudathir Mohamed, Andrew Reynolds
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
 * White box testing of bags rewriter
14
 */
15
16
#include "expr/dtype.h"
17
#include "expr/emptybag.h"
18
#include "test_smt.h"
19
#include "theory/bags/bags_rewriter.h"
20
#include "theory/strings/type_enumerator.h"
21
#include "util/rational.h"
22
#include "util/string.h"
23
24
namespace cvc5 {
25
26
using namespace theory;
27
using namespace kind;
28
using namespace theory::bags;
29
30
namespace test {
31
32
typedef expr::Attribute<Node, Node> attribute;
33
34
68
class TestTheoryWhiteBagsRewriter : public TestSmt
35
{
36
 protected:
37
34
  void SetUp() override
38
  {
39
34
    TestSmt::SetUp();
40
34
    d_rewriter.reset(new BagsRewriter(nullptr));
41
34
  }
42
43
18
  std::vector<Node> getNStrings(size_t n)
44
  {
45
18
    std::vector<Node> elements(n);
46
54
    for (size_t i = 0; i < n; i++)
47
    {
48
36
      elements[i] =
49
72
          d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
50
    }
51
18
    return elements;
52
  }
53
54
  std::unique_ptr<BagsRewriter> d_rewriter;
55
};
56
57
26
TEST_F(TestTheoryWhiteBagsRewriter, empty_bag_normal_form)
58
{
59
4
  Node emptybag = d_nodeManager->mkConst(EmptyBag(d_nodeManager->stringType()));
60
  // empty bags are in normal form
61
2
  ASSERT_TRUE(emptybag.isConst());
62
4
  RewriteResponse response = d_rewriter->postRewrite(emptybag);
63
2
  ASSERT_TRUE(emptybag == response.d_node && response.d_status == REWRITE_DONE);
64
}
65
66
26
TEST_F(TestTheoryWhiteBagsRewriter, bag_equality)
67
{
68
4
  std::vector<Node> elements = getNStrings(2);
69
4
  Node x = elements[0];
70
4
  Node y = elements[1];
71
4
  Node c = d_skolemManager->mkDummySkolem("c", d_nodeManager->integerType());
72
4
  Node d = d_skolemManager->mkDummySkolem("d", d_nodeManager->integerType());
73
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
74
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(), y, d);
75
2
  Node emptyBag = d_nodeManager->mkConst(
76
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
77
4
  Node emptyString = d_nodeManager->mkConst(String(""));
78
6
  Node constantBag = d_nodeManager->mkBag(d_nodeManager->stringType(),
79
                                          emptyString,
80
8
                                          d_nodeManager->mkConst(Rational(1)));
81
82
  // (= A A) = true where A is a bag
83
4
  Node n1 = A.eqNode(A);
84
4
  RewriteResponse response1 = d_rewriter->preRewrite(n1);
85
2
  ASSERT_TRUE(response1.d_node == d_nodeManager->mkConst(true)
86
2
              && response1.d_status == REWRITE_AGAIN_FULL);
87
88
  // (= A B) = false if A and B are different bag constants
89
4
  Node n2 = constantBag.eqNode(emptyBag);
90
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
91
2
  ASSERT_TRUE(response2.d_node == d_nodeManager->mkConst(false)
92
2
              && response2.d_status == REWRITE_AGAIN_FULL);
93
94
  // (= B A) = (= A B) if A < B and at least one of A or B is not a constant
95
4
  Node n3 = B.eqNode(A);
96
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
97
2
  ASSERT_TRUE(response3.d_node == A.eqNode(B)
98
2
              && response3.d_status == REWRITE_AGAIN_FULL);
99
100
  // (= A B) = (= A B) no rewrite
101
4
  Node n4 = A.eqNode(B);
102
4
  RewriteResponse response4 = d_rewriter->postRewrite(n4);
103
2
  ASSERT_TRUE(response4.d_node == n4 && response4.d_status == REWRITE_DONE);
104
}
105
106
26
TEST_F(TestTheoryWhiteBagsRewriter, mkBag_constant_element)
107
{
108
4
  std::vector<Node> elements = getNStrings(1);
109
6
  Node negative = d_nodeManager->mkBag(d_nodeManager->stringType(),
110
2
                                       elements[0],
111
10
                                       d_nodeManager->mkConst(Rational(-1)));
112
6
  Node zero = d_nodeManager->mkBag(d_nodeManager->stringType(),
113
2
                                   elements[0],
114
10
                                   d_nodeManager->mkConst(Rational(0)));
115
6
  Node positive = d_nodeManager->mkBag(d_nodeManager->stringType(),
116
2
                                       elements[0],
117
10
                                       d_nodeManager->mkConst(Rational(1)));
118
2
  Node emptybag = d_nodeManager->mkConst(
119
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
120
4
  RewriteResponse negativeResponse = d_rewriter->postRewrite(negative);
121
4
  RewriteResponse zeroResponse = d_rewriter->postRewrite(zero);
122
4
  RewriteResponse positiveResponse = d_rewriter->postRewrite(positive);
123
124
  // bags with non-positive multiplicity are rewritten as empty bags
125
2
  ASSERT_TRUE(negativeResponse.d_status == REWRITE_AGAIN_FULL
126
2
              && negativeResponse.d_node == emptybag);
127
2
  ASSERT_TRUE(zeroResponse.d_status == REWRITE_AGAIN_FULL
128
2
              && zeroResponse.d_node == emptybag);
129
130
  // no change for positive
131
2
  ASSERT_TRUE(positiveResponse.d_status == REWRITE_DONE
132
2
              && positive == positiveResponse.d_node);
133
}
134
135
26
TEST_F(TestTheoryWhiteBagsRewriter, mkBag_variable_element)
136
{
137
  Node skolem =
138
4
      d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
139
6
  Node variable = d_nodeManager->mkBag(d_nodeManager->stringType(),
140
                                       skolem,
141
8
                                       d_nodeManager->mkConst(Rational(-1)));
142
6
  Node negative = d_nodeManager->mkBag(d_nodeManager->stringType(),
143
                                       skolem,
144
8
                                       d_nodeManager->mkConst(Rational(-1)));
145
2
  Node zero = d_nodeManager->mkBag(
146
4
      d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(0)));
147
2
  Node positive = d_nodeManager->mkBag(
148
4
      d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(1)));
149
2
  Node emptybag = d_nodeManager->mkConst(
150
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
151
4
  RewriteResponse negativeResponse = d_rewriter->postRewrite(negative);
152
4
  RewriteResponse zeroResponse = d_rewriter->postRewrite(zero);
153
4
  RewriteResponse positiveResponse = d_rewriter->postRewrite(positive);
154
155
  // bags with non-positive multiplicity are rewritten as empty bags
156
2
  ASSERT_TRUE(negativeResponse.d_status == REWRITE_AGAIN_FULL
157
2
              && negativeResponse.d_node == emptybag);
158
2
  ASSERT_TRUE(zeroResponse.d_status == REWRITE_AGAIN_FULL
159
2
              && zeroResponse.d_node == emptybag);
160
161
  // no change for positive
162
2
  ASSERT_TRUE(positiveResponse.d_status == REWRITE_DONE
163
2
              && positive == positiveResponse.d_node);
164
}
165
166
26
TEST_F(TestTheoryWhiteBagsRewriter, bag_count)
167
{
168
4
  Node zero = d_nodeManager->mkConst(Rational(0));
169
4
  Node one = d_nodeManager->mkConst(Rational(1));
170
4
  Node three = d_nodeManager->mkConst(Rational(3));
171
  Node skolem =
172
4
      d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
173
2
  Node emptyBag = d_nodeManager->mkConst(
174
4
      EmptyBag(d_nodeManager->mkBagType(skolem.getType())));
175
176
  // (bag.count x emptybag) = 0
177
4
  Node n1 = d_nodeManager->mkNode(BAG_COUNT, skolem, emptyBag);
178
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
179
2
  ASSERT_TRUE(response1.d_status == REWRITE_AGAIN_FULL
180
2
              && response1.d_node == zero);
181
182
  // (bag.count x (mkBag x c) = (ite (>= c 1) c 0)
183
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), skolem, three);
184
4
  Node n2 = d_nodeManager->mkNode(BAG_COUNT, skolem, bag);
185
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
186
187
4
  Node geq = d_nodeManager->mkNode(GEQ, three, one);
188
4
  Node ite = d_nodeManager->mkNode(ITE, geq, three, zero);
189
2
  ASSERT_TRUE(response2.d_status == REWRITE_AGAIN_FULL
190
2
              && response2.d_node == ite);
191
}
192
193
26
TEST_F(TestTheoryWhiteBagsRewriter, duplicate_removal)
194
{
195
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
196
2
  Node bag = d_nodeManager->mkBag(
197
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(5)));
198
199
  // (duplicate_removal (mkBag x n)) = (mkBag x 1)
200
4
  Node n = d_nodeManager->mkNode(DUPLICATE_REMOVAL, bag);
201
4
  RewriteResponse response = d_rewriter->postRewrite(n);
202
2
  Node noDuplicate = d_nodeManager->mkBag(
203
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(1)));
204
2
  ASSERT_TRUE(response.d_node == noDuplicate
205
2
              && response.d_status == REWRITE_AGAIN_FULL);
206
}
207
208
26
TEST_F(TestTheoryWhiteBagsRewriter, union_max)
209
{
210
2
  int n = 3;
211
4
  std::vector<Node> elements = getNStrings(2);
212
2
  Node emptyBag = d_nodeManager->mkConst(
213
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
214
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
215
2
                                elements[0],
216
10
                                d_nodeManager->mkConst(Rational(n)));
217
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
218
2
                                elements[1],
219
10
                                d_nodeManager->mkConst(Rational(n + 1)));
220
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
221
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
222
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
223
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
224
225
  // (union_max A emptybag) = A
226
4
  Node unionMax1 = d_nodeManager->mkNode(UNION_MAX, A, emptyBag);
227
4
  RewriteResponse response1 = d_rewriter->postRewrite(unionMax1);
228
2
  ASSERT_TRUE(response1.d_node == A
229
2
              && response1.d_status == REWRITE_AGAIN_FULL);
230
231
  // (union_max emptybag A) = A
232
4
  Node unionMax2 = d_nodeManager->mkNode(UNION_MAX, emptyBag, A);
233
4
  RewriteResponse response2 = d_rewriter->postRewrite(unionMax2);
234
2
  ASSERT_TRUE(response2.d_node == A
235
2
              && response2.d_status == REWRITE_AGAIN_FULL);
236
237
  // (union_max A A) = A
238
4
  Node unionMax3 = d_nodeManager->mkNode(UNION_MAX, A, A);
239
4
  RewriteResponse response3 = d_rewriter->postRewrite(unionMax3);
240
2
  ASSERT_TRUE(response3.d_node == A
241
2
              && response3.d_status == REWRITE_AGAIN_FULL);
242
243
  // (union_max A (union_max A B)) = (union_max A B)
244
4
  Node unionMax4 = d_nodeManager->mkNode(UNION_MAX, A, unionMaxAB);
245
4
  RewriteResponse response4 = d_rewriter->postRewrite(unionMax4);
246
2
  ASSERT_TRUE(response4.d_node == unionMaxAB
247
2
              && response4.d_status == REWRITE_AGAIN_FULL);
248
249
  // (union_max A (union_max B A)) = (union_max B A)
250
4
  Node unionMax5 = d_nodeManager->mkNode(UNION_MAX, A, unionMaxBA);
251
4
  RewriteResponse response5 = d_rewriter->postRewrite(unionMax5);
252
2
  ASSERT_TRUE(response5.d_node == unionMaxBA
253
2
              && response4.d_status == REWRITE_AGAIN_FULL);
254
255
  // (union_max (union_max A B) A) = (union_max A B)
256
4
  Node unionMax6 = d_nodeManager->mkNode(UNION_MAX, unionMaxAB, A);
257
4
  RewriteResponse response6 = d_rewriter->postRewrite(unionMax6);
258
2
  ASSERT_TRUE(response6.d_node == unionMaxAB
259
2
              && response6.d_status == REWRITE_AGAIN_FULL);
260
261
  // (union_max (union_max B A) A) = (union_max B A)
262
4
  Node unionMax7 = d_nodeManager->mkNode(UNION_MAX, unionMaxBA, A);
263
4
  RewriteResponse response7 = d_rewriter->postRewrite(unionMax7);
264
2
  ASSERT_TRUE(response7.d_node == unionMaxBA
265
2
              && response7.d_status == REWRITE_AGAIN_FULL);
266
267
  // (union_max A (union_disjoint A B)) = (union_disjoint A B)
268
4
  Node unionMax8 = d_nodeManager->mkNode(UNION_MAX, A, unionDisjointAB);
269
4
  RewriteResponse response8 = d_rewriter->postRewrite(unionMax8);
270
2
  ASSERT_TRUE(response8.d_node == unionDisjointAB
271
2
              && response8.d_status == REWRITE_AGAIN_FULL);
272
273
  // (union_max A (union_disjoint B A)) = (union_disjoint B A)
274
4
  Node unionMax9 = d_nodeManager->mkNode(UNION_MAX, A, unionDisjointBA);
275
4
  RewriteResponse response9 = d_rewriter->postRewrite(unionMax9);
276
2
  ASSERT_TRUE(response9.d_node == unionDisjointBA
277
2
              && response9.d_status == REWRITE_AGAIN_FULL);
278
279
  // (union_max (union_disjoint A B) A) = (union_disjoint A B)
280
4
  Node unionMax10 = d_nodeManager->mkNode(UNION_MAX, unionDisjointAB, A);
281
4
  RewriteResponse response10 = d_rewriter->postRewrite(unionMax10);
282
2
  ASSERT_TRUE(response10.d_node == unionDisjointAB
283
2
              && response10.d_status == REWRITE_AGAIN_FULL);
284
285
  // (union_max (union_disjoint B A) A) = (union_disjoint B A)
286
4
  Node unionMax11 = d_nodeManager->mkNode(UNION_MAX, unionDisjointBA, A);
287
4
  RewriteResponse response11 = d_rewriter->postRewrite(unionMax11);
288
2
  ASSERT_TRUE(response11.d_node == unionDisjointBA
289
2
              && response11.d_status == REWRITE_AGAIN_FULL);
290
}
291
292
26
TEST_F(TestTheoryWhiteBagsRewriter, union_disjoint)
293
{
294
2
  int n = 3;
295
4
  std::vector<Node> elements = getNStrings(3);
296
2
  Node emptyBag = d_nodeManager->mkConst(
297
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
298
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
299
2
                                elements[0],
300
10
                                d_nodeManager->mkConst(Rational(n)));
301
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
302
2
                                elements[1],
303
10
                                d_nodeManager->mkConst(Rational(n + 1)));
304
6
  Node C = d_nodeManager->mkBag(d_nodeManager->stringType(),
305
2
                                elements[2],
306
10
                                d_nodeManager->mkConst(Rational(n + 2)));
307
308
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
309
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
310
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
311
4
  Node unionMaxAC = d_nodeManager->mkNode(UNION_MAX, A, C);
312
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
313
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
314
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
315
316
  // (union_disjoint A emptybag) = A
317
4
  Node unionDisjoint1 = d_nodeManager->mkNode(UNION_DISJOINT, A, emptyBag);
318
4
  RewriteResponse response1 = d_rewriter->postRewrite(unionDisjoint1);
319
2
  ASSERT_TRUE(response1.d_node == A
320
2
              && response1.d_status == REWRITE_AGAIN_FULL);
321
322
  // (union_disjoint emptybag A) = A
323
4
  Node unionDisjoint2 = d_nodeManager->mkNode(UNION_DISJOINT, emptyBag, A);
324
4
  RewriteResponse response2 = d_rewriter->postRewrite(unionDisjoint2);
325
2
  ASSERT_TRUE(response2.d_node == A
326
2
              && response2.d_status == REWRITE_AGAIN_FULL);
327
328
  // (union_disjoint (union_max A B) (intersection_min B A)) =
329
  //          (union_disjoint A B) // sum(a,b) = max(a,b) + min(a,b)
330
  Node unionDisjoint3 =
331
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxAB, intersectionBA);
332
4
  RewriteResponse response3 = d_rewriter->postRewrite(unionDisjoint3);
333
2
  ASSERT_TRUE(response3.d_node == unionDisjointAB
334
2
              && response3.d_status == REWRITE_AGAIN_FULL);
335
336
  // (union_disjoint (intersection_min B A)) (union_max A B) =
337
  //          (union_disjoint B A) // sum(a,b) = max(a,b) + min(a,b)
338
  Node unionDisjoint4 =
339
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxBA, intersectionBA);
340
4
  RewriteResponse response4 = d_rewriter->postRewrite(unionDisjoint4);
341
2
  ASSERT_TRUE(response4.d_node == unionDisjointBA
342
2
              && response4.d_status == REWRITE_AGAIN_FULL);
343
344
  // (union_disjoint (intersection_min B A)) (union_max A B) =
345
  //          (union_disjoint B A) // sum(a,b) = max(a,b) + min(a,b)
346
  Node unionDisjoint5 =
347
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxAC, intersectionAB);
348
4
  RewriteResponse response5 = d_rewriter->postRewrite(unionDisjoint5);
349
2
  ASSERT_TRUE(response5.d_node == unionDisjoint5
350
2
              && response5.d_status == REWRITE_DONE);
351
}
352
353
26
TEST_F(TestTheoryWhiteBagsRewriter, intersection_min)
354
{
355
2
  int n = 3;
356
4
  std::vector<Node> elements = getNStrings(2);
357
2
  Node emptyBag = d_nodeManager->mkConst(
358
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
359
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
360
2
                                elements[0],
361
10
                                d_nodeManager->mkConst(Rational(n)));
362
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
363
2
                                elements[1],
364
10
                                d_nodeManager->mkConst(Rational(n + 1)));
365
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
366
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
367
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
368
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
369
370
  // (intersection_min A emptybag) = emptyBag
371
4
  Node n1 = d_nodeManager->mkNode(INTERSECTION_MIN, A, emptyBag);
372
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
373
2
  ASSERT_TRUE(response1.d_node == emptyBag
374
2
              && response1.d_status == REWRITE_AGAIN_FULL);
375
376
  // (intersection_min emptybag A) = emptyBag
377
4
  Node n2 = d_nodeManager->mkNode(INTERSECTION_MIN, emptyBag, A);
378
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
379
2
  ASSERT_TRUE(response2.d_node == emptyBag
380
2
              && response2.d_status == REWRITE_AGAIN_FULL);
381
382
  // (intersection_min A A) = A
383
4
  Node n3 = d_nodeManager->mkNode(INTERSECTION_MIN, A, A);
384
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
385
2
  ASSERT_TRUE(response3.d_node == A
386
2
              && response3.d_status == REWRITE_AGAIN_FULL);
387
388
  // (intersection_min A (union_max A B) = A
389
4
  Node n4 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionMaxAB);
390
4
  RewriteResponse response4 = d_rewriter->postRewrite(n4);
391
2
  ASSERT_TRUE(response4.d_node == A
392
2
              && response4.d_status == REWRITE_AGAIN_FULL);
393
394
  // (intersection_min A (union_max B A) = A
395
4
  Node n5 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionMaxBA);
396
4
  RewriteResponse response5 = d_rewriter->postRewrite(n5);
397
2
  ASSERT_TRUE(response5.d_node == A
398
2
              && response4.d_status == REWRITE_AGAIN_FULL);
399
400
  // (intersection_min (union_max A B) A) = A
401
4
  Node n6 = d_nodeManager->mkNode(INTERSECTION_MIN, unionMaxAB, A);
402
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
403
2
  ASSERT_TRUE(response6.d_node == A
404
2
              && response6.d_status == REWRITE_AGAIN_FULL);
405
406
  // (intersection_min (union_max B A) A) = A
407
4
  Node n7 = d_nodeManager->mkNode(INTERSECTION_MIN, unionMaxBA, A);
408
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
409
2
  ASSERT_TRUE(response7.d_node == A
410
2
              && response7.d_status == REWRITE_AGAIN_FULL);
411
412
  // (intersection_min A (union_disjoint A B) = A
413
4
  Node n8 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionDisjointAB);
414
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
415
2
  ASSERT_TRUE(response8.d_node == A
416
2
              && response8.d_status == REWRITE_AGAIN_FULL);
417
418
  // (intersection_min A (union_disjoint B A) = A
419
4
  Node n9 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionDisjointBA);
420
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
421
2
  ASSERT_TRUE(response9.d_node == A
422
2
              && response9.d_status == REWRITE_AGAIN_FULL);
423
424
  // (intersection_min (union_disjoint A B) A) = A
425
4
  Node n10 = d_nodeManager->mkNode(INTERSECTION_MIN, unionDisjointAB, A);
426
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
427
2
  ASSERT_TRUE(response10.d_node == A
428
2
              && response10.d_status == REWRITE_AGAIN_FULL);
429
430
  // (intersection_min (union_disjoint B A) A) = A
431
4
  Node n11 = d_nodeManager->mkNode(INTERSECTION_MIN, unionDisjointBA, A);
432
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
433
2
  ASSERT_TRUE(response11.d_node == A
434
2
              && response11.d_status == REWRITE_AGAIN_FULL);
435
}
436
437
26
TEST_F(TestTheoryWhiteBagsRewriter, difference_subtract)
438
{
439
2
  int n = 3;
440
4
  std::vector<Node> elements = getNStrings(2);
441
2
  Node emptyBag = d_nodeManager->mkConst(
442
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
443
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
444
2
                                elements[0],
445
10
                                d_nodeManager->mkConst(Rational(n)));
446
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
447
2
                                elements[1],
448
10
                                d_nodeManager->mkConst(Rational(n + 1)));
449
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
450
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
451
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
452
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
453
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
454
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
455
456
  // (difference_subtract A emptybag) = A
457
4
  Node n1 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, emptyBag);
458
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
459
2
  ASSERT_TRUE(response1.d_node == A
460
2
              && response1.d_status == REWRITE_AGAIN_FULL);
461
462
  // (difference_subtract emptybag A) = emptyBag
463
4
  Node n2 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, emptyBag, A);
464
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
465
2
  ASSERT_TRUE(response2.d_node == emptyBag
466
2
              && response2.d_status == REWRITE_AGAIN_FULL);
467
468
  // (difference_subtract A A) = emptybag
469
4
  Node n3 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, A);
470
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
471
2
  ASSERT_TRUE(response3.d_node == emptyBag
472
2
              && response3.d_status == REWRITE_AGAIN_FULL);
473
474
  // (difference_subtract (union_disjoint A B) A) = B
475
4
  Node n4 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, unionDisjointAB, A);
476
4
  RewriteResponse response4 = d_rewriter->postRewrite(n4);
477
2
  ASSERT_TRUE(response4.d_node == B
478
2
              && response4.d_status == REWRITE_AGAIN_FULL);
479
480
  // (difference_subtract (union_disjoint B A) A) = B
481
4
  Node n5 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, unionDisjointBA, A);
482
4
  RewriteResponse response5 = d_rewriter->postRewrite(n5);
483
2
  ASSERT_TRUE(response5.d_node == B
484
2
              && response4.d_status == REWRITE_AGAIN_FULL);
485
486
  // (difference_subtract A (union_disjoint A B)) = emptybag
487
4
  Node n6 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionDisjointAB);
488
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
489
2
  ASSERT_TRUE(response6.d_node == emptyBag
490
2
              && response6.d_status == REWRITE_AGAIN_FULL);
491
492
  // (difference_subtract A (union_disjoint B A)) = emptybag
493
4
  Node n7 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionDisjointBA);
494
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
495
2
  ASSERT_TRUE(response7.d_node == emptyBag
496
2
              && response7.d_status == REWRITE_AGAIN_FULL);
497
498
  // (difference_subtract A (union_max A B)) = emptybag
499
4
  Node n8 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionMaxAB);
500
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
501
2
  ASSERT_TRUE(response8.d_node == emptyBag
502
2
              && response8.d_status == REWRITE_AGAIN_FULL);
503
504
  // (difference_subtract A (union_max B A)) = emptybag
505
4
  Node n9 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionMaxBA);
506
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
507
2
  ASSERT_TRUE(response9.d_node == emptyBag
508
2
              && response9.d_status == REWRITE_AGAIN_FULL);
509
510
  // (difference_subtract (intersection_min A B) A) = emptybag
511
4
  Node n10 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, intersectionAB, A);
512
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
513
2
  ASSERT_TRUE(response10.d_node == emptyBag
514
2
              && response10.d_status == REWRITE_AGAIN_FULL);
515
516
  // (difference_subtract (intersection_min B A) A) = emptybag
517
4
  Node n11 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, intersectionBA, A);
518
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
519
2
  ASSERT_TRUE(response11.d_node == emptyBag
520
2
              && response11.d_status == REWRITE_AGAIN_FULL);
521
}
522
523
26
TEST_F(TestTheoryWhiteBagsRewriter, difference_remove)
524
{
525
2
  int n = 3;
526
4
  std::vector<Node> elements = getNStrings(2);
527
2
  Node emptyBag = d_nodeManager->mkConst(
528
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
529
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
530
2
                                elements[0],
531
10
                                d_nodeManager->mkConst(Rational(n)));
532
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
533
2
                                elements[1],
534
10
                                d_nodeManager->mkConst(Rational(n + 1)));
535
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
536
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
537
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
538
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
539
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
540
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
541
542
  // (difference_remove A emptybag) = A
543
4
  Node n1 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, emptyBag);
544
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
545
2
  ASSERT_TRUE(response1.d_node == A
546
2
              && response1.d_status == REWRITE_AGAIN_FULL);
547
548
  // (difference_remove emptybag A) = emptyBag
549
4
  Node n2 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, emptyBag, A);
550
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
551
2
  ASSERT_TRUE(response2.d_node == emptyBag
552
2
              && response2.d_status == REWRITE_AGAIN_FULL);
553
554
  // (difference_remove A A) = emptybag
555
4
  Node n3 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, A);
556
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
557
2
  ASSERT_TRUE(response3.d_node == emptyBag
558
2
              && response3.d_status == REWRITE_AGAIN_FULL);
559
560
  // (difference_remove A (union_disjoint A B)) = emptybag
561
4
  Node n6 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionDisjointAB);
562
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
563
2
  ASSERT_TRUE(response6.d_node == emptyBag
564
2
              && response6.d_status == REWRITE_AGAIN_FULL);
565
566
  // (difference_remove A (union_disjoint B A)) = emptybag
567
4
  Node n7 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionDisjointBA);
568
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
569
2
  ASSERT_TRUE(response7.d_node == emptyBag
570
2
              && response7.d_status == REWRITE_AGAIN_FULL);
571
572
  // (difference_remove A (union_max A B)) = emptybag
573
4
  Node n8 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionMaxAB);
574
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
575
2
  ASSERT_TRUE(response8.d_node == emptyBag
576
2
              && response8.d_status == REWRITE_AGAIN_FULL);
577
578
  // (difference_remove A (union_max B A)) = emptybag
579
4
  Node n9 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionMaxBA);
580
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
581
2
  ASSERT_TRUE(response9.d_node == emptyBag
582
2
              && response9.d_status == REWRITE_AGAIN_FULL);
583
584
  // (difference_remove (intersection_min A B) A) = emptybag
585
4
  Node n10 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, intersectionAB, A);
586
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
587
2
  ASSERT_TRUE(response10.d_node == emptyBag
588
2
              && response10.d_status == REWRITE_AGAIN_FULL);
589
590
  // (difference_remove (intersection_min B A) A) = emptybag
591
4
  Node n11 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, intersectionBA, A);
592
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
593
2
  ASSERT_TRUE(response11.d_node == emptyBag
594
2
              && response11.d_status == REWRITE_AGAIN_FULL);
595
}
596
597
26
TEST_F(TestTheoryWhiteBagsRewriter, choose)
598
{
599
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
600
4
  Node c = d_nodeManager->mkConst(Rational(3));
601
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
602
603
  // (bag.choose (mkBag x c)) = x where c is a constant > 0
604
4
  Node n1 = d_nodeManager->mkNode(BAG_CHOOSE, bag);
605
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
606
2
  ASSERT_TRUE(response1.d_node == x
607
2
              && response1.d_status == REWRITE_AGAIN_FULL);
608
}
609
610
26
TEST_F(TestTheoryWhiteBagsRewriter, bag_card)
611
{
612
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
613
2
  Node emptyBag = d_nodeManager->mkConst(
614
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
615
4
  Node zero = d_nodeManager->mkConst(Rational(0));
616
4
  Node c = d_nodeManager->mkConst(Rational(3));
617
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
618
4
  std::vector<Node> elements = getNStrings(2);
619
6
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
620
2
                                elements[0],
621
10
                                d_nodeManager->mkConst(Rational(4)));
622
6
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
623
2
                                elements[1],
624
10
                                d_nodeManager->mkConst(Rational(5)));
625
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
626
627
  // TODO(projects#223): enable this test after implementing bags normal form
628
  //    // (bag.card emptybag) = 0
629
  //    Node n1 = d_nodeManager->mkNode(BAG_CARD, emptyBag);
630
  //    RewriteResponse response1 = d_rewriter->postRewrite(n1);
631
  //    ASSERT_TRUE(response1.d_node == zero && response1.d_status ==
632
  //    REWRITE_AGAIN_FULL);
633
634
  // (bag.card (mkBag x c)) = c where c is a constant > 0
635
4
  Node n2 = d_nodeManager->mkNode(BAG_CARD, bag);
636
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
637
2
  ASSERT_TRUE(response2.d_node == c
638
2
              && response2.d_status == REWRITE_AGAIN_FULL);
639
640
  // (bag.card (union-disjoint A B)) = (+ (bag.card A) (bag.card B))
641
4
  Node n3 = d_nodeManager->mkNode(BAG_CARD, unionDisjointAB);
642
4
  Node cardA = d_nodeManager->mkNode(BAG_CARD, A);
643
4
  Node cardB = d_nodeManager->mkNode(BAG_CARD, B);
644
4
  Node plus = d_nodeManager->mkNode(PLUS, cardA, cardB);
645
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
646
2
  ASSERT_TRUE(response3.d_node == plus
647
2
              && response3.d_status == REWRITE_AGAIN_FULL);
648
}
649
650
26
TEST_F(TestTheoryWhiteBagsRewriter, is_singleton)
651
{
652
2
  Node emptybag = d_nodeManager->mkConst(
653
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
654
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
655
4
  Node c = d_skolemManager->mkDummySkolem("c", d_nodeManager->integerType());
656
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
657
658
  // TODO(projects#223): complete this function
659
  // (bag.is_singleton emptybag) = false
660
  //    Node n1 = d_nodeManager->mkNode(BAG_IS_SINGLETON, emptybag);
661
  //    RewriteResponse response1 = d_rewriter->postRewrite(n1);
662
  //    ASSERT_TRUE(response1.d_node == d_nodeManager->mkConst(false)
663
  //              && response1.d_status == REWRITE_AGAIN_FULL);
664
665
  // (bag.is_singleton (mkBag x c) = (c == 1)
666
4
  Node n2 = d_nodeManager->mkNode(BAG_IS_SINGLETON, bag);
667
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
668
4
  Node one = d_nodeManager->mkConst(Rational(1));
669
4
  Node equal = c.eqNode(one);
670
2
  ASSERT_TRUE(response2.d_node == equal
671
2
              && response2.d_status == REWRITE_AGAIN_FULL);
672
}
673
674
26
TEST_F(TestTheoryWhiteBagsRewriter, from_set)
675
{
676
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
677
4
  Node singleton = d_nodeManager->mkSingleton(d_nodeManager->stringType(), x);
678
679
  // (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
680
4
  Node n = d_nodeManager->mkNode(BAG_FROM_SET, singleton);
681
4
  RewriteResponse response = d_rewriter->postRewrite(n);
682
4
  Node one = d_nodeManager->mkConst(Rational(1));
683
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, one);
684
2
  ASSERT_TRUE(response.d_node == bag
685
2
              && response.d_status == REWRITE_AGAIN_FULL);
686
}
687
688
26
TEST_F(TestTheoryWhiteBagsRewriter, to_set)
689
{
690
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
691
2
  Node bag = d_nodeManager->mkBag(
692
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(5)));
693
694
  // (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
695
4
  Node n = d_nodeManager->mkNode(BAG_TO_SET, bag);
696
4
  RewriteResponse response = d_rewriter->postRewrite(n);
697
4
  Node singleton = d_nodeManager->mkSingleton(d_nodeManager->stringType(), x);
698
2
  ASSERT_TRUE(response.d_node == singleton
699
2
              && response.d_status == REWRITE_AGAIN_FULL);
700
}
701
702
26
TEST_F(TestTheoryWhiteBagsRewriter, map)
703
{
704
  TypeNode bagStringType =
705
4
      d_nodeManager->mkBagType(d_nodeManager->stringType());
706
4
  Node emptybagString = d_nodeManager->mkConst(EmptyBag(bagStringType));
707
708
4
  Node empty = d_nodeManager->mkConst(String(""));
709
4
  Node xString = d_nodeManager->mkBoundVar("x", d_nodeManager->stringType());
710
4
  Node bound = d_nodeManager->mkNode(kind::BOUND_VAR_LIST, xString);
711
4
  Node lambda = d_nodeManager->mkNode(LAMBDA, bound, empty);
712
713
  // (bag.map (lambda ((x U))  t) emptybag) = emptybag
714
4
  Node n1 = d_nodeManager->mkNode(BAG_MAP, lambda, emptybagString);
715
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
716
2
  ASSERT_TRUE(response1.d_node == emptybagString
717
2
              && response1.d_status == REWRITE_AGAIN_FULL);
718
719
4
  std::vector<Node> elements = getNStrings(2);
720
4
  Node a = d_nodeManager->mkConst(String("a"));
721
4
  Node b = d_nodeManager->mkConst(String("b"));
722
2
  Node A = d_nodeManager->mkBag(
723
4
      d_nodeManager->stringType(), a, d_nodeManager->mkConst(Rational(3)));
724
2
  Node B = d_nodeManager->mkBag(
725
4
      d_nodeManager->stringType(), b, d_nodeManager->mkConst(Rational(4)));
726
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
727
728
2
  ASSERT_TRUE(unionDisjointAB.isConst());
729
730
  // (bag.map (lambda ((x Int)) "") (union_disjoint (bag "a" 3) (bag "b" 4))) =
731
  //   (bag "" 7))
732
4
  Node n2 = d_nodeManager->mkNode(BAG_MAP, lambda, unionDisjointAB);
733
734
4
  Node rewritten = Rewriter::rewrite(n2);
735
2
  Node bag = d_nodeManager->mkBag(
736
4
      d_nodeManager->stringType(), empty, d_nodeManager->mkConst(Rational(7)));
737
2
  ASSERT_TRUE(rewritten == bag);
738
}
739
740
}  // namespace test
741
54
}  // namespace cvc5