GCC Code Coverage Report
Directory: . Exec Total Coverage
File: test/unit/theory/theory_bags_rewriter_white.cpp Lines: 433 433 100.0 %
Date: 2021-05-22 Branches: 1347 3250 41.4 %

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