GCC Code Coverage Report
Directory: . Exec Total Coverage
File: test/unit/theory/theory_bags_rewriter_white.cpp Lines: 457 457 100.0 %
Date: 2021-09-07 Branches: 1427 3434 41.6 %

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
  Node emptyBag = d_nodeManager->mkConst(
76
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
77
4
  Node emptyString = d_nodeManager->mkConst(String(""));
78
4
  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
4
  Node negative = d_nodeManager->mkBag(d_nodeManager->stringType(),
110
2
                                       elements[0],
111
10
                                       d_nodeManager->mkConst(Rational(-1)));
112
4
  Node zero = d_nodeManager->mkBag(d_nodeManager->stringType(),
113
2
                                   elements[0],
114
10
                                   d_nodeManager->mkConst(Rational(0)));
115
4
  Node positive = d_nodeManager->mkBag(d_nodeManager->stringType(),
116
2
                                       elements[0],
117
10
                                       d_nodeManager->mkConst(Rational(1)));
118
  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
4
  Node variable = d_nodeManager->mkBag(d_nodeManager->stringType(),
140
                                       skolem,
141
8
                                       d_nodeManager->mkConst(Rational(-1)));
142
4
  Node negative = d_nodeManager->mkBag(d_nodeManager->stringType(),
143
                                       skolem,
144
8
                                       d_nodeManager->mkConst(Rational(-1)));
145
  Node zero = d_nodeManager->mkBag(
146
4
      d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(0)));
147
  Node positive = d_nodeManager->mkBag(
148
4
      d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(1)));
149
  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
2
  int n = 3;
169
  Node skolem =
170
4
      d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
171
  Node emptyBag = d_nodeManager->mkConst(
172
4
      EmptyBag(d_nodeManager->mkBagType(skolem.getType())));
173
  Node bag = d_nodeManager->mkBag(
174
4
      d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(n)));
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 == d_nodeManager->mkConst(Rational(0)));
181
182
  // (bag.count x (mkBag x c) = c where c > 0 is a constant
183
4
  Node n2 = d_nodeManager->mkNode(BAG_COUNT, skolem, bag);
184
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
185
2
  ASSERT_TRUE(response2.d_status == REWRITE_AGAIN_FULL
186
2
              && response2.d_node == d_nodeManager->mkConst(Rational(n)));
187
}
188
189
26
TEST_F(TestTheoryWhiteBagsRewriter, duplicate_removal)
190
{
191
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
192
  Node bag = d_nodeManager->mkBag(
193
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(5)));
194
195
  // (duplicate_removal (mkBag x n)) = (mkBag x 1)
196
4
  Node n = d_nodeManager->mkNode(DUPLICATE_REMOVAL, bag);
197
4
  RewriteResponse response = d_rewriter->postRewrite(n);
198
  Node noDuplicate = d_nodeManager->mkBag(
199
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(1)));
200
2
  ASSERT_TRUE(response.d_node == noDuplicate
201
2
              && response.d_status == REWRITE_AGAIN_FULL);
202
}
203
204
26
TEST_F(TestTheoryWhiteBagsRewriter, union_max)
205
{
206
2
  int n = 3;
207
4
  std::vector<Node> elements = getNStrings(2);
208
  Node emptyBag = d_nodeManager->mkConst(
209
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
210
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
211
2
                                elements[0],
212
10
                                d_nodeManager->mkConst(Rational(n)));
213
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
214
2
                                elements[1],
215
10
                                d_nodeManager->mkConst(Rational(n + 1)));
216
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
217
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
218
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
219
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
220
221
  // (union_max A emptybag) = A
222
4
  Node unionMax1 = d_nodeManager->mkNode(UNION_MAX, A, emptyBag);
223
4
  RewriteResponse response1 = d_rewriter->postRewrite(unionMax1);
224
2
  ASSERT_TRUE(response1.d_node == A
225
2
              && response1.d_status == REWRITE_AGAIN_FULL);
226
227
  // (union_max emptybag A) = A
228
4
  Node unionMax2 = d_nodeManager->mkNode(UNION_MAX, emptyBag, A);
229
4
  RewriteResponse response2 = d_rewriter->postRewrite(unionMax2);
230
2
  ASSERT_TRUE(response2.d_node == A
231
2
              && response2.d_status == REWRITE_AGAIN_FULL);
232
233
  // (union_max A A) = A
234
4
  Node unionMax3 = d_nodeManager->mkNode(UNION_MAX, A, A);
235
4
  RewriteResponse response3 = d_rewriter->postRewrite(unionMax3);
236
2
  ASSERT_TRUE(response3.d_node == A
237
2
              && response3.d_status == REWRITE_AGAIN_FULL);
238
239
  // (union_max A (union_max A B)) = (union_max A B)
240
4
  Node unionMax4 = d_nodeManager->mkNode(UNION_MAX, A, unionMaxAB);
241
4
  RewriteResponse response4 = d_rewriter->postRewrite(unionMax4);
242
2
  ASSERT_TRUE(response4.d_node == unionMaxAB
243
2
              && response4.d_status == REWRITE_AGAIN_FULL);
244
245
  // (union_max A (union_max B A)) = (union_max B A)
246
4
  Node unionMax5 = d_nodeManager->mkNode(UNION_MAX, A, unionMaxBA);
247
4
  RewriteResponse response5 = d_rewriter->postRewrite(unionMax5);
248
2
  ASSERT_TRUE(response5.d_node == unionMaxBA
249
2
              && response4.d_status == REWRITE_AGAIN_FULL);
250
251
  // (union_max (union_max A B) A) = (union_max A B)
252
4
  Node unionMax6 = d_nodeManager->mkNode(UNION_MAX, unionMaxAB, A);
253
4
  RewriteResponse response6 = d_rewriter->postRewrite(unionMax6);
254
2
  ASSERT_TRUE(response6.d_node == unionMaxAB
255
2
              && response6.d_status == REWRITE_AGAIN_FULL);
256
257
  // (union_max (union_max B A) A) = (union_max B A)
258
4
  Node unionMax7 = d_nodeManager->mkNode(UNION_MAX, unionMaxBA, A);
259
4
  RewriteResponse response7 = d_rewriter->postRewrite(unionMax7);
260
2
  ASSERT_TRUE(response7.d_node == unionMaxBA
261
2
              && response7.d_status == REWRITE_AGAIN_FULL);
262
263
  // (union_max A (union_disjoint A B)) = (union_disjoint A B)
264
4
  Node unionMax8 = d_nodeManager->mkNode(UNION_MAX, A, unionDisjointAB);
265
4
  RewriteResponse response8 = d_rewriter->postRewrite(unionMax8);
266
2
  ASSERT_TRUE(response8.d_node == unionDisjointAB
267
2
              && response8.d_status == REWRITE_AGAIN_FULL);
268
269
  // (union_max A (union_disjoint B A)) = (union_disjoint B A)
270
4
  Node unionMax9 = d_nodeManager->mkNode(UNION_MAX, A, unionDisjointBA);
271
4
  RewriteResponse response9 = d_rewriter->postRewrite(unionMax9);
272
2
  ASSERT_TRUE(response9.d_node == unionDisjointBA
273
2
              && response9.d_status == REWRITE_AGAIN_FULL);
274
275
  // (union_max (union_disjoint A B) A) = (union_disjoint A B)
276
4
  Node unionMax10 = d_nodeManager->mkNode(UNION_MAX, unionDisjointAB, A);
277
4
  RewriteResponse response10 = d_rewriter->postRewrite(unionMax10);
278
2
  ASSERT_TRUE(response10.d_node == unionDisjointAB
279
2
              && response10.d_status == REWRITE_AGAIN_FULL);
280
281
  // (union_max (union_disjoint B A) A) = (union_disjoint B A)
282
4
  Node unionMax11 = d_nodeManager->mkNode(UNION_MAX, unionDisjointBA, A);
283
4
  RewriteResponse response11 = d_rewriter->postRewrite(unionMax11);
284
2
  ASSERT_TRUE(response11.d_node == unionDisjointBA
285
2
              && response11.d_status == REWRITE_AGAIN_FULL);
286
}
287
288
26
TEST_F(TestTheoryWhiteBagsRewriter, union_disjoint)
289
{
290
2
  int n = 3;
291
4
  std::vector<Node> elements = getNStrings(3);
292
  Node emptyBag = d_nodeManager->mkConst(
293
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
294
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
295
2
                                elements[0],
296
10
                                d_nodeManager->mkConst(Rational(n)));
297
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
298
2
                                elements[1],
299
10
                                d_nodeManager->mkConst(Rational(n + 1)));
300
4
  Node C = d_nodeManager->mkBag(d_nodeManager->stringType(),
301
2
                                elements[2],
302
10
                                d_nodeManager->mkConst(Rational(n + 2)));
303
304
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
305
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
306
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
307
4
  Node unionMaxAC = d_nodeManager->mkNode(UNION_MAX, A, C);
308
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
309
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
310
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
311
312
  // (union_disjoint A emptybag) = A
313
4
  Node unionDisjoint1 = d_nodeManager->mkNode(UNION_DISJOINT, A, emptyBag);
314
4
  RewriteResponse response1 = d_rewriter->postRewrite(unionDisjoint1);
315
2
  ASSERT_TRUE(response1.d_node == A
316
2
              && response1.d_status == REWRITE_AGAIN_FULL);
317
318
  // (union_disjoint emptybag A) = A
319
4
  Node unionDisjoint2 = d_nodeManager->mkNode(UNION_DISJOINT, emptyBag, A);
320
4
  RewriteResponse response2 = d_rewriter->postRewrite(unionDisjoint2);
321
2
  ASSERT_TRUE(response2.d_node == A
322
2
              && response2.d_status == REWRITE_AGAIN_FULL);
323
324
  // (union_disjoint (union_max A B) (intersection_min B A)) =
325
  //          (union_disjoint A B) // sum(a,b) = max(a,b) + min(a,b)
326
  Node unionDisjoint3 =
327
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxAB, intersectionBA);
328
4
  RewriteResponse response3 = d_rewriter->postRewrite(unionDisjoint3);
329
2
  ASSERT_TRUE(response3.d_node == unionDisjointAB
330
2
              && response3.d_status == REWRITE_AGAIN_FULL);
331
332
  // (union_disjoint (intersection_min B A)) (union_max A B) =
333
  //          (union_disjoint B A) // sum(a,b) = max(a,b) + min(a,b)
334
  Node unionDisjoint4 =
335
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxBA, intersectionBA);
336
4
  RewriteResponse response4 = d_rewriter->postRewrite(unionDisjoint4);
337
2
  ASSERT_TRUE(response4.d_node == unionDisjointBA
338
2
              && response4.d_status == REWRITE_AGAIN_FULL);
339
340
  // (union_disjoint (intersection_min B A)) (union_max A B) =
341
  //          (union_disjoint B A) // sum(a,b) = max(a,b) + min(a,b)
342
  Node unionDisjoint5 =
343
4
      d_nodeManager->mkNode(UNION_DISJOINT, unionMaxAC, intersectionAB);
344
4
  RewriteResponse response5 = d_rewriter->postRewrite(unionDisjoint5);
345
2
  ASSERT_TRUE(response5.d_node == unionDisjoint5
346
2
              && response5.d_status == REWRITE_DONE);
347
}
348
349
26
TEST_F(TestTheoryWhiteBagsRewriter, intersection_min)
350
{
351
2
  int n = 3;
352
4
  std::vector<Node> elements = getNStrings(2);
353
  Node emptyBag = d_nodeManager->mkConst(
354
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
355
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
356
2
                                elements[0],
357
10
                                d_nodeManager->mkConst(Rational(n)));
358
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
359
2
                                elements[1],
360
10
                                d_nodeManager->mkConst(Rational(n + 1)));
361
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
362
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
363
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
364
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
365
366
  // (intersection_min A emptybag) = emptyBag
367
4
  Node n1 = d_nodeManager->mkNode(INTERSECTION_MIN, A, emptyBag);
368
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
369
2
  ASSERT_TRUE(response1.d_node == emptyBag
370
2
              && response1.d_status == REWRITE_AGAIN_FULL);
371
372
  // (intersection_min emptybag A) = emptyBag
373
4
  Node n2 = d_nodeManager->mkNode(INTERSECTION_MIN, emptyBag, A);
374
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
375
2
  ASSERT_TRUE(response2.d_node == emptyBag
376
2
              && response2.d_status == REWRITE_AGAIN_FULL);
377
378
  // (intersection_min A A) = A
379
4
  Node n3 = d_nodeManager->mkNode(INTERSECTION_MIN, A, A);
380
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
381
2
  ASSERT_TRUE(response3.d_node == A
382
2
              && response3.d_status == REWRITE_AGAIN_FULL);
383
384
  // (intersection_min A (union_max A B) = A
385
4
  Node n4 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionMaxAB);
386
4
  RewriteResponse response4 = d_rewriter->postRewrite(n4);
387
2
  ASSERT_TRUE(response4.d_node == A
388
2
              && response4.d_status == REWRITE_AGAIN_FULL);
389
390
  // (intersection_min A (union_max B A) = A
391
4
  Node n5 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionMaxBA);
392
4
  RewriteResponse response5 = d_rewriter->postRewrite(n5);
393
2
  ASSERT_TRUE(response5.d_node == A
394
2
              && response4.d_status == REWRITE_AGAIN_FULL);
395
396
  // (intersection_min (union_max A B) A) = A
397
4
  Node n6 = d_nodeManager->mkNode(INTERSECTION_MIN, unionMaxAB, A);
398
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
399
2
  ASSERT_TRUE(response6.d_node == A
400
2
              && response6.d_status == REWRITE_AGAIN_FULL);
401
402
  // (intersection_min (union_max B A) A) = A
403
4
  Node n7 = d_nodeManager->mkNode(INTERSECTION_MIN, unionMaxBA, A);
404
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
405
2
  ASSERT_TRUE(response7.d_node == A
406
2
              && response7.d_status == REWRITE_AGAIN_FULL);
407
408
  // (intersection_min A (union_disjoint A B) = A
409
4
  Node n8 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionDisjointAB);
410
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
411
2
  ASSERT_TRUE(response8.d_node == A
412
2
              && response8.d_status == REWRITE_AGAIN_FULL);
413
414
  // (intersection_min A (union_disjoint B A) = A
415
4
  Node n9 = d_nodeManager->mkNode(INTERSECTION_MIN, A, unionDisjointBA);
416
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
417
2
  ASSERT_TRUE(response9.d_node == A
418
2
              && response9.d_status == REWRITE_AGAIN_FULL);
419
420
  // (intersection_min (union_disjoint A B) A) = A
421
4
  Node n10 = d_nodeManager->mkNode(INTERSECTION_MIN, unionDisjointAB, A);
422
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
423
2
  ASSERT_TRUE(response10.d_node == A
424
2
              && response10.d_status == REWRITE_AGAIN_FULL);
425
426
  // (intersection_min (union_disjoint B A) A) = A
427
4
  Node n11 = d_nodeManager->mkNode(INTERSECTION_MIN, unionDisjointBA, A);
428
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
429
2
  ASSERT_TRUE(response11.d_node == A
430
2
              && response11.d_status == REWRITE_AGAIN_FULL);
431
}
432
433
26
TEST_F(TestTheoryWhiteBagsRewriter, difference_subtract)
434
{
435
2
  int n = 3;
436
4
  std::vector<Node> elements = getNStrings(2);
437
  Node emptyBag = d_nodeManager->mkConst(
438
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
439
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
440
2
                                elements[0],
441
10
                                d_nodeManager->mkConst(Rational(n)));
442
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
443
2
                                elements[1],
444
10
                                d_nodeManager->mkConst(Rational(n + 1)));
445
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
446
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
447
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
448
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
449
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
450
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
451
452
  // (difference_subtract A emptybag) = A
453
4
  Node n1 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, emptyBag);
454
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
455
2
  ASSERT_TRUE(response1.d_node == A
456
2
              && response1.d_status == REWRITE_AGAIN_FULL);
457
458
  // (difference_subtract emptybag A) = emptyBag
459
4
  Node n2 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, emptyBag, A);
460
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
461
2
  ASSERT_TRUE(response2.d_node == emptyBag
462
2
              && response2.d_status == REWRITE_AGAIN_FULL);
463
464
  // (difference_subtract A A) = emptybag
465
4
  Node n3 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, A);
466
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
467
2
  ASSERT_TRUE(response3.d_node == emptyBag
468
2
              && response3.d_status == REWRITE_AGAIN_FULL);
469
470
  // (difference_subtract (union_disjoint A B) A) = B
471
4
  Node n4 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, unionDisjointAB, A);
472
4
  RewriteResponse response4 = d_rewriter->postRewrite(n4);
473
2
  ASSERT_TRUE(response4.d_node == B
474
2
              && response4.d_status == REWRITE_AGAIN_FULL);
475
476
  // (difference_subtract (union_disjoint B A) A) = B
477
4
  Node n5 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, unionDisjointBA, A);
478
4
  RewriteResponse response5 = d_rewriter->postRewrite(n5);
479
2
  ASSERT_TRUE(response5.d_node == B
480
2
              && response4.d_status == REWRITE_AGAIN_FULL);
481
482
  // (difference_subtract A (union_disjoint A B)) = emptybag
483
4
  Node n6 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionDisjointAB);
484
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
485
2
  ASSERT_TRUE(response6.d_node == emptyBag
486
2
              && response6.d_status == REWRITE_AGAIN_FULL);
487
488
  // (difference_subtract A (union_disjoint B A)) = emptybag
489
4
  Node n7 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionDisjointBA);
490
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
491
2
  ASSERT_TRUE(response7.d_node == emptyBag
492
2
              && response7.d_status == REWRITE_AGAIN_FULL);
493
494
  // (difference_subtract A (union_max A B)) = emptybag
495
4
  Node n8 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionMaxAB);
496
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
497
2
  ASSERT_TRUE(response8.d_node == emptyBag
498
2
              && response8.d_status == REWRITE_AGAIN_FULL);
499
500
  // (difference_subtract A (union_max B A)) = emptybag
501
4
  Node n9 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, A, unionMaxBA);
502
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
503
2
  ASSERT_TRUE(response9.d_node == emptyBag
504
2
              && response9.d_status == REWRITE_AGAIN_FULL);
505
506
  // (difference_subtract (intersection_min A B) A) = emptybag
507
4
  Node n10 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, intersectionAB, A);
508
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
509
2
  ASSERT_TRUE(response10.d_node == emptyBag
510
2
              && response10.d_status == REWRITE_AGAIN_FULL);
511
512
  // (difference_subtract (intersection_min B A) A) = emptybag
513
4
  Node n11 = d_nodeManager->mkNode(DIFFERENCE_SUBTRACT, intersectionBA, A);
514
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
515
2
  ASSERT_TRUE(response11.d_node == emptyBag
516
2
              && response11.d_status == REWRITE_AGAIN_FULL);
517
}
518
519
26
TEST_F(TestTheoryWhiteBagsRewriter, difference_remove)
520
{
521
2
  int n = 3;
522
4
  std::vector<Node> elements = getNStrings(2);
523
  Node emptyBag = d_nodeManager->mkConst(
524
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
525
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
526
2
                                elements[0],
527
10
                                d_nodeManager->mkConst(Rational(n)));
528
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
529
2
                                elements[1],
530
10
                                d_nodeManager->mkConst(Rational(n + 1)));
531
4
  Node unionMaxAB = d_nodeManager->mkNode(UNION_MAX, A, B);
532
4
  Node unionMaxBA = d_nodeManager->mkNode(UNION_MAX, B, A);
533
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
534
4
  Node unionDisjointBA = d_nodeManager->mkNode(UNION_DISJOINT, B, A);
535
4
  Node intersectionAB = d_nodeManager->mkNode(INTERSECTION_MIN, A, B);
536
4
  Node intersectionBA = d_nodeManager->mkNode(INTERSECTION_MIN, B, A);
537
538
  // (difference_remove A emptybag) = A
539
4
  Node n1 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, emptyBag);
540
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
541
2
  ASSERT_TRUE(response1.d_node == A
542
2
              && response1.d_status == REWRITE_AGAIN_FULL);
543
544
  // (difference_remove emptybag A) = emptyBag
545
4
  Node n2 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, emptyBag, A);
546
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
547
2
  ASSERT_TRUE(response2.d_node == emptyBag
548
2
              && response2.d_status == REWRITE_AGAIN_FULL);
549
550
  // (difference_remove A A) = emptybag
551
4
  Node n3 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, A);
552
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
553
2
  ASSERT_TRUE(response3.d_node == emptyBag
554
2
              && response3.d_status == REWRITE_AGAIN_FULL);
555
556
  // (difference_remove A (union_disjoint A B)) = emptybag
557
4
  Node n6 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionDisjointAB);
558
4
  RewriteResponse response6 = d_rewriter->postRewrite(n6);
559
2
  ASSERT_TRUE(response6.d_node == emptyBag
560
2
              && response6.d_status == REWRITE_AGAIN_FULL);
561
562
  // (difference_remove A (union_disjoint B A)) = emptybag
563
4
  Node n7 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionDisjointBA);
564
4
  RewriteResponse response7 = d_rewriter->postRewrite(n7);
565
2
  ASSERT_TRUE(response7.d_node == emptyBag
566
2
              && response7.d_status == REWRITE_AGAIN_FULL);
567
568
  // (difference_remove A (union_max A B)) = emptybag
569
4
  Node n8 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionMaxAB);
570
4
  RewriteResponse response8 = d_rewriter->postRewrite(n8);
571
2
  ASSERT_TRUE(response8.d_node == emptyBag
572
2
              && response8.d_status == REWRITE_AGAIN_FULL);
573
574
  // (difference_remove A (union_max B A)) = emptybag
575
4
  Node n9 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, A, unionMaxBA);
576
4
  RewriteResponse response9 = d_rewriter->postRewrite(n9);
577
2
  ASSERT_TRUE(response9.d_node == emptyBag
578
2
              && response9.d_status == REWRITE_AGAIN_FULL);
579
580
  // (difference_remove (intersection_min A B) A) = emptybag
581
4
  Node n10 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, intersectionAB, A);
582
4
  RewriteResponse response10 = d_rewriter->postRewrite(n10);
583
2
  ASSERT_TRUE(response10.d_node == emptyBag
584
2
              && response10.d_status == REWRITE_AGAIN_FULL);
585
586
  // (difference_remove (intersection_min B A) A) = emptybag
587
4
  Node n11 = d_nodeManager->mkNode(DIFFERENCE_REMOVE, intersectionBA, A);
588
4
  RewriteResponse response11 = d_rewriter->postRewrite(n11);
589
2
  ASSERT_TRUE(response11.d_node == emptyBag
590
2
              && response11.d_status == REWRITE_AGAIN_FULL);
591
}
592
593
26
TEST_F(TestTheoryWhiteBagsRewriter, choose)
594
{
595
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
596
4
  Node c = d_nodeManager->mkConst(Rational(3));
597
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
598
599
  // (bag.choose (mkBag x c)) = x where c is a constant > 0
600
4
  Node n1 = d_nodeManager->mkNode(BAG_CHOOSE, bag);
601
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
602
2
  ASSERT_TRUE(response1.d_node == x
603
2
              && response1.d_status == REWRITE_AGAIN_FULL);
604
}
605
606
26
TEST_F(TestTheoryWhiteBagsRewriter, bag_card)
607
{
608
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
609
  Node emptyBag = d_nodeManager->mkConst(
610
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
611
4
  Node zero = d_nodeManager->mkConst(Rational(0));
612
4
  Node c = d_nodeManager->mkConst(Rational(3));
613
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
614
4
  std::vector<Node> elements = getNStrings(2);
615
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
616
2
                                elements[0],
617
10
                                d_nodeManager->mkConst(Rational(4)));
618
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
619
2
                                elements[1],
620
10
                                d_nodeManager->mkConst(Rational(5)));
621
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
622
623
  // TODO(projects#223): enable this test after implementing bags normal form
624
  //    // (bag.card emptybag) = 0
625
  //    Node n1 = d_nodeManager->mkNode(BAG_CARD, emptyBag);
626
  //    RewriteResponse response1 = d_rewriter->postRewrite(n1);
627
  //    ASSERT_TRUE(response1.d_node == zero && response1.d_status ==
628
  //    REWRITE_AGAIN_FULL);
629
630
  // (bag.card (mkBag x c)) = c where c is a constant > 0
631
4
  Node n2 = d_nodeManager->mkNode(BAG_CARD, bag);
632
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
633
2
  ASSERT_TRUE(response2.d_node == c
634
2
              && response2.d_status == REWRITE_AGAIN_FULL);
635
636
  // (bag.card (union-disjoint A B)) = (+ (bag.card A) (bag.card B))
637
4
  Node n3 = d_nodeManager->mkNode(BAG_CARD, unionDisjointAB);
638
4
  Node cardA = d_nodeManager->mkNode(BAG_CARD, A);
639
4
  Node cardB = d_nodeManager->mkNode(BAG_CARD, B);
640
4
  Node plus = d_nodeManager->mkNode(PLUS, cardA, cardB);
641
4
  RewriteResponse response3 = d_rewriter->postRewrite(n3);
642
2
  ASSERT_TRUE(response3.d_node == plus
643
2
              && response3.d_status == REWRITE_AGAIN_FULL);
644
}
645
646
26
TEST_F(TestTheoryWhiteBagsRewriter, is_singleton)
647
{
648
  Node emptybag = d_nodeManager->mkConst(
649
4
      EmptyBag(d_nodeManager->mkBagType(d_nodeManager->stringType())));
650
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
651
4
  Node c = d_skolemManager->mkDummySkolem("c", d_nodeManager->integerType());
652
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, c);
653
654
  // TODO(projects#223): complete this function
655
  // (bag.is_singleton emptybag) = false
656
  //    Node n1 = d_nodeManager->mkNode(BAG_IS_SINGLETON, emptybag);
657
  //    RewriteResponse response1 = d_rewriter->postRewrite(n1);
658
  //    ASSERT_TRUE(response1.d_node == d_nodeManager->mkConst(false)
659
  //              && response1.d_status == REWRITE_AGAIN_FULL);
660
661
  // (bag.is_singleton (mkBag x c) = (c == 1)
662
4
  Node n2 = d_nodeManager->mkNode(BAG_IS_SINGLETON, bag);
663
4
  RewriteResponse response2 = d_rewriter->postRewrite(n2);
664
4
  Node one = d_nodeManager->mkConst(Rational(1));
665
4
  Node equal = c.eqNode(one);
666
2
  ASSERT_TRUE(response2.d_node == equal
667
2
              && response2.d_status == REWRITE_AGAIN_FULL);
668
}
669
670
26
TEST_F(TestTheoryWhiteBagsRewriter, from_set)
671
{
672
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
673
4
  Node singleton = d_nodeManager->mkSingleton(d_nodeManager->stringType(), x);
674
675
  // (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
676
4
  Node n = d_nodeManager->mkNode(BAG_FROM_SET, singleton);
677
4
  RewriteResponse response = d_rewriter->postRewrite(n);
678
4
  Node one = d_nodeManager->mkConst(Rational(1));
679
4
  Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), x, one);
680
2
  ASSERT_TRUE(response.d_node == bag
681
2
              && response.d_status == REWRITE_AGAIN_FULL);
682
}
683
684
26
TEST_F(TestTheoryWhiteBagsRewriter, to_set)
685
{
686
4
  Node x = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType());
687
  Node bag = d_nodeManager->mkBag(
688
4
      d_nodeManager->stringType(), x, d_nodeManager->mkConst(Rational(5)));
689
690
  // (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
691
4
  Node n = d_nodeManager->mkNode(BAG_TO_SET, bag);
692
4
  RewriteResponse response = d_rewriter->postRewrite(n);
693
4
  Node singleton = d_nodeManager->mkSingleton(d_nodeManager->stringType(), x);
694
2
  ASSERT_TRUE(response.d_node == singleton
695
2
              && response.d_status == REWRITE_AGAIN_FULL);
696
}
697
698
26
TEST_F(TestTheoryWhiteBagsRewriter, map)
699
{
700
  TypeNode bagStringType =
701
4
      d_nodeManager->mkBagType(d_nodeManager->stringType());
702
4
  Node emptybagString = d_nodeManager->mkConst(EmptyBag(bagStringType));
703
704
4
  Node empty = d_nodeManager->mkConst(String(""));
705
4
  Node xString = d_nodeManager->mkBoundVar("x", d_nodeManager->stringType());
706
4
  Node bound = d_nodeManager->mkNode(kind::BOUND_VAR_LIST, xString);
707
4
  Node lambda = d_nodeManager->mkNode(LAMBDA, bound, empty);
708
709
  // (bag.map (lambda ((x U))  t) emptybag) = emptybag
710
4
  Node n1 = d_nodeManager->mkNode(BAG_MAP, lambda, emptybagString);
711
4
  RewriteResponse response1 = d_rewriter->postRewrite(n1);
712
2
  ASSERT_TRUE(response1.d_node == emptybagString
713
2
              && response1.d_status == REWRITE_AGAIN_FULL);
714
715
4
  std::vector<Node> elements = getNStrings(2);
716
4
  Node a = d_nodeManager->mkConst(String("a"));
717
4
  Node b = d_nodeManager->mkConst(String("b"));
718
4
  Node A = d_nodeManager->mkBag(d_nodeManager->stringType(),
719
                                a,
720
8
                                d_nodeManager->mkConst(Rational(3)));
721
4
  Node B = d_nodeManager->mkBag(d_nodeManager->stringType(),
722
                                b,
723
8
                                d_nodeManager->mkConst(Rational(4)));
724
4
  Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B);
725
726
2
  ASSERT_TRUE(unionDisjointAB.isConst());
727
728
  // (bag.map (lambda ((x Int)) "") (union_disjoint (bag "a" 3) (bag "b" 4))) =
729
  //   (bag "" 7))
730
4
  Node n2 = d_nodeManager->mkNode(BAG_MAP, lambda, unionDisjointAB);
731
732
4
  Node rewritten = Rewriter:: rewrite(n2);
733
  Node bag = d_nodeManager->mkBag(
734
4
      d_nodeManager->stringType(), empty, d_nodeManager->mkConst(Rational(7)));
735
2
  ASSERT_TRUE(rewritten == bag);
736
}
737
738
}  // namespace test
739
258066
}  // namespace cvc5