GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_rewriter.cpp Lines: 327 344 95.1 %
Date: 2021-09-29 Branches: 921 1883 48.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Kshitij Bansal, Paul Meng
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
 * Sets theory rewriter.
14
 */
15
16
#include "theory/sets/theory_sets_rewriter.h"
17
18
#include "expr/attribute.h"
19
#include "expr/dtype_cons.h"
20
#include "options/sets_options.h"
21
#include "theory/sets/normal_form.h"
22
#include "theory/sets/rels_utils.h"
23
#include "util/rational.h"
24
25
using namespace cvc5::kind;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace sets {
30
31
1801
bool TheorySetsRewriter::checkConstantMembership(TNode elementTerm, TNode setTerm)
32
{
33
1801
  if(setTerm.getKind() == kind::EMPTYSET) {
34
57
    return false;
35
  }
36
37
1744
  if(setTerm.getKind() == kind::SINGLETON) {
38
584
    return elementTerm == setTerm[0];
39
  }
40
41
1160
  Assert(setTerm.getKind() == kind::UNION
42
         && setTerm[0].getKind() == kind::SINGLETON)
43
      << "kind was " << setTerm.getKind() << ", term: " << setTerm;
44
45
3480
  return elementTerm == setTerm[0][0]
46
3480
         || checkConstantMembership(elementTerm, setTerm[1]);
47
}
48
49
// static
50
49225
RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
51
49225
  NodeManager* nm = NodeManager::currentNM();
52
49225
  Kind kind = node.getKind();
53
49225
  Trace("sets-postrewrite") << "Process: " << node << std::endl;
54
55
49225
  if(node.isConst()) {
56
10224
    Trace("sets-rewrite-nf")
57
5112
        << "Sets::rewrite: no rewrite (constant) " << node << std::endl;
58
    // Dare you touch the const and mangle it to something else.
59
5112
    return RewriteResponse(REWRITE_DONE, node);
60
  }
61
62
44113
  switch(kind) {
63
64
17400
  case kind::MEMBER: {
65
17400
    if(node[0].isConst() && node[1].isConst()) {
66
      // both are constants
67
1778
      TNode S = preRewrite(node[1]).d_node;
68
889
      bool isMember = checkConstantMembership(node[0], S);
69
889
      return RewriteResponse(REWRITE_DONE, nm->mkConst(isMember));
70
16511
    }else if( node[1].getKind()==kind::EMPTYSET ){
71
170
      return RewriteResponse(REWRITE_DONE, nm->mkConst(false));
72
16341
    }else if( node[1].getKind()==kind::SINGLETON ){
73
1189
      return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode(kind::EQUAL, node[0], node[1][0] ) );
74
15152
    }else if( node[1].getKind()==kind::UNION || node[1].getKind()==kind::INTERSECTION || node[1].getKind()==kind::SETMINUS ){
75
4028
      std::vector< Node > children;
76
6042
      for( unsigned i=0; i<node[1].getNumChildren(); i++ ){
77
8056
        Node nc = nm->mkNode(kind::MEMBER, node[0], node[1][i] );
78
4028
        if( node[1].getKind()==kind::SETMINUS && i==1 ){
79
378
          nc = nc.negate();
80
        }
81
4028
        children.push_back( nc );
82
      }
83
2014
      return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode( node[1].getKind()==kind::UNION ? kind::OR : kind::AND, children ) );
84
    }
85
13138
    break;
86
  }//kind::MEMBER
87
88
  case kind::SUBSET: {
89
    Assert(false)
90
        << "TheorySets::postRrewrite(): Subset is handled in preRewrite.";
91
92
    // but in off-chance we do end up here, let us do our best
93
94
    // rewrite (A subset-or-equal B) as (A union B = B)
95
    TNode A = node[0];
96
    TNode B = node[1];
97
    return RewriteResponse(REWRITE_AGAIN_FULL,
98
                           nm->mkNode(kind::EQUAL,
99
                                      nm->mkNode(kind::UNION, A, B),
100
                                      B) );
101
  }//kind::SUBSET
102
103
15490
  case kind::EQUAL: {
104
    //rewrite: t = t with true (t term)
105
    //rewrite: c = c' with c different from c' false (c, c' constants)
106
    //otherwise: sort them
107
15490
    if(node[0] == node[1]) {
108
49
      Trace("sets-postrewrite") << "Sets::postRewrite returning true" << std::endl;
109
49
      return RewriteResponse(REWRITE_DONE, nm->mkConst(true));
110
    }
111
15441
    else if (node[0].isConst() && node[1].isConst()) {
112
151
      Trace("sets-postrewrite") << "Sets::postRewrite returning false" << std::endl;
113
151
      return RewriteResponse(REWRITE_DONE, nm->mkConst(false));
114
    }
115
15290
    else if (node[0] > node[1]) {
116
5850
      Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
117
2925
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
118
2925
      return RewriteResponse(REWRITE_DONE, newNode);
119
    }
120
12365
    break;
121
  }
122
123
976
  case kind::SETMINUS:
124
  {
125
976
    if (node[0] == node[1])
126
    {
127
58
      Node newNode = nm->mkConst(EmptySet(node[0].getType()));
128
58
      Trace("sets-postrewrite")
129
29
          << "Sets::postRewrite returning " << newNode << std::endl;
130
29
      return RewriteResponse(REWRITE_DONE, newNode);
131
    }
132
2841
    else if (node[0].getKind() == kind::EMPTYSET
133
2841
             || node[1].getKind() == kind::EMPTYSET)
134
    {
135
20
      Trace("sets-postrewrite")
136
10
          << "Sets::postRewrite returning " << node[0] << std::endl;
137
10
      return RewriteResponse(REWRITE_AGAIN, node[0]);
138
    }
139
937
    else if (node[1].getKind() == kind::SETMINUS && node[1][0] == node[0])
140
    {
141
      // (setminus A (setminus A B)) = (intersection A B)
142
6
      Node intersection = nm->mkNode(INTERSECTION, node[0], node[1][1]);
143
3
      return RewriteResponse(REWRITE_AGAIN, intersection);
144
    }
145
934
    else if (node[1].getKind() == kind::UNIVERSE_SET)
146
    {
147
      return RewriteResponse(
148
          REWRITE_AGAIN,
149
          NodeManager::currentNM()->mkConst(EmptySet(node[1].getType())));
150
    }
151
934
    else if (node[0].isConst() && node[1].isConst())
152
    {
153
146
      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
154
146
      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
155
146
      std::set<Node> newSet;
156
73
      std::set_difference(left.begin(),
157
                          left.end(),
158
                          right.begin(),
159
                          right.end(),
160
73
                          std::inserter(newSet, newSet.begin()));
161
146
      Node newNode = NormalForm::elementsToSet(newSet, node.getType());
162
73
      Assert(newNode.isConst());
163
146
      Trace("sets-postrewrite")
164
73
          << "Sets::postRewrite returning " << newNode << std::endl;
165
73
      return RewriteResponse(REWRITE_DONE, newNode);
166
    }
167
861
    break;
168
  }  // kind::SETMINUS
169
170
1243
  case kind::INTERSECTION: {
171
1243
    if(node[0] == node[1]) {
172
27
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
173
27
      return RewriteResponse(REWRITE_AGAIN, node[0]);
174
1216
    } else if(node[0].getKind() == kind::EMPTYSET || node[1].getKind() == kind::UNIVERSE_SET) {
175
10
      return RewriteResponse(REWRITE_AGAIN, node[0]);
176
1206
    } else if(node[1].getKind() == kind::EMPTYSET || node[0].getKind() == kind::UNIVERSE_SET) {
177
15
      return RewriteResponse(REWRITE_AGAIN, node[1]);
178
1191
    } else if(node[0].isConst() && node[1].isConst()) {
179
64
      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
180
64
      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
181
64
      std::set<Node> newSet;
182
32
      std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
183
32
                            std::inserter(newSet, newSet.begin()));
184
64
      Node newNode = NormalForm::elementsToSet(newSet, node.getType());
185
32
      Assert(newNode.isConst() && newNode.getType() == node.getType());
186
32
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
187
32
      return RewriteResponse(REWRITE_DONE, newNode);
188
    }
189
1159
    else if (node[0] > node[1])
190
    {
191
394
      Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
192
197
      return RewriteResponse(REWRITE_DONE, newNode);
193
    }
194
    // we don't merge non-constant intersections
195
962
    break;
196
  }//kind::INTERSECION
197
198
3401
  case kind::UNION: {
199
    // NOTE: case where it is CONST is taken care of at the top
200
3401
    if(node[0] == node[1]) {
201
40
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
202
40
      return RewriteResponse(REWRITE_AGAIN, node[0]);
203
3361
    } else if(node[0].getKind() == kind::EMPTYSET || node[1].getKind() == kind::UNIVERSE_SET) {
204
43
      return RewriteResponse(REWRITE_AGAIN, node[1]);
205
3318
    } else if(node[1].getKind() == kind::EMPTYSET || node[0].getKind() == kind::UNIVERSE_SET) {
206
25
      return RewriteResponse(REWRITE_AGAIN, node[0]);
207
3293
    } else if(node[0].isConst() && node[1].isConst()) {
208
740
      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
209
740
      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
210
740
      std::set<Node> newSet;
211
370
      std::set_union(left.begin(), left.end(), right.begin(), right.end(),
212
370
                          std::inserter(newSet, newSet.begin()));
213
740
      Node newNode = NormalForm::elementsToSet(newSet, node.getType());
214
370
      Assert(newNode.isConst());
215
740
      Trace("sets-rewrite")
216
370
          << "Sets::rewrite: UNION_CONSTANT_MERGE: " << newNode << std::endl;
217
370
      return RewriteResponse(REWRITE_DONE, newNode);
218
    }
219
2923
    else if (node[0] > node[1])
220
    {
221
826
      Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
222
413
      return RewriteResponse(REWRITE_DONE, newNode);
223
    }
224
    // we don't merge non-constant unions
225
2510
    break;
226
  }//kind::UNION
227
14
  case kind::COMPLEMENT:
228
  {
229
28
    Node univ = NodeManager::currentNM()->mkNullaryOperator(node[0].getType(),
230
42
                                                            kind::UNIVERSE_SET);
231
    return RewriteResponse(
232
        REWRITE_AGAIN,
233
14
        NodeManager::currentNM()->mkNode(kind::SETMINUS, univ, node[0]));
234
  }
235
2692
  case kind::CARD: {
236
2692
    if(node[0].isConst()) {
237
288
      std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]);
238
144
      return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(elements.size())));
239
2548
    }else if( node[0].getKind()==kind::SINGLETON ){
240
4
      return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(1)));
241
2544
    }else if( node[0].getKind()==kind::UNION ){
242
      Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
243
258
                   NodeManager::currentNM()->mkNode( kind::PLUS, NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ),
244
172
                                                                 NodeManager::currentNM()->mkNode( kind::CARD, node[0][1] ) ),
245
344
                   NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );
246
86
      return RewriteResponse(REWRITE_DONE, ret );
247
2458
    }else if( node[0].getKind()==kind::SETMINUS ){
248
      Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
249
664
                   NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ),
250
1328
                   NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );
251
332
      return RewriteResponse(REWRITE_DONE, ret );
252
    }
253
2126
    break;
254
  }
255
256
25
  case kind::CHOOSE:
257
  {
258
25
    if (node[0].getKind() == SINGLETON)
259
    {
260
      //(= (choose (singleton x)) x) is a tautology
261
      // we return x for (choose (singleton x))
262
5
      return RewriteResponse(REWRITE_AGAIN, node[0][0]);
263
    }
264
20
    break;
265
  }  // kind::CHOOSE
266
29
  case kind::IS_SINGLETON:
267
  {
268
29
    if (node[0].getKind() == SINGLETON)
269
    {
270
      //(= (is_singleton (singleton x)) is a tautology
271
      // we return true for (is_singleton (singleton x))
272
      return RewriteResponse(REWRITE_AGAIN,
273
5
                             NodeManager::currentNM()->mkConst(true));
274
    }
275
24
    break;
276
  } // kind::IS_SINGLETON
277
278
110
  case kind::TRANSPOSE: {
279
110
    if(node[0].getKind() == kind::TRANSPOSE) {
280
      return RewriteResponse(REWRITE_AGAIN, node[0][0]);
281
    }
282
283
110
    if(node[0].getKind() == kind::EMPTYSET) {
284
      return RewriteResponse(REWRITE_DONE,
285
                             nm->mkConst(EmptySet(node.getType())));
286
110
    } else if(node[0].isConst()) {
287
16
      std::set<Node> new_tuple_set;
288
16
      std::set<Node> tuple_set = NormalForm::getElementsFromNormalConstant(node[0]);
289
8
      std::set<Node>::iterator tuple_it = tuple_set.begin();
290
291
42
      while(tuple_it != tuple_set.end()) {
292
17
        new_tuple_set.insert(RelsUtils::reverseTuple(*tuple_it));
293
17
        ++tuple_it;
294
      }
295
16
      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
296
8
      Assert(new_node.isConst());
297
8
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
298
8
      return RewriteResponse(REWRITE_DONE, new_node);
299
300
    }
301
102
    if(node[0].getKind() != kind::TRANSPOSE) {
302
102
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
303
102
      return RewriteResponse(REWRITE_DONE, node);
304
    }
305
    break;
306
  }
307
308
53
  case kind::PRODUCT: {
309
53
    Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " <<  node << std::endl;
310
210
    if( node[0].getKind() == kind::EMPTYSET ||
311
157
        node[1].getKind() == kind::EMPTYSET) {
312
      return RewriteResponse(REWRITE_DONE,
313
1
                             nm->mkConst(EmptySet(node.getType())));
314
52
    } else if( node[0].isConst() && node[1].isConst() ) {
315
8
      Trace("sets-rels-postrewrite") << "Sets::postRewrite processing **** " <<  node << std::endl;
316
16
      std::set<Node> new_tuple_set;
317
16
      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
318
16
      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
319
8
      std::set<Node>::iterator left_it = left.begin();
320
8
      int left_len = (*left_it).getType().getTupleLength();
321
16
      TypeNode tn = node.getType().getSetElementType();
322
46
      while(left_it != left.end()) {
323
19
        Trace("rels-debug") << "Sets::postRewrite processing left_it = " <<  *left_it << std::endl;
324
38
        std::vector<Node> left_tuple;
325
19
        left_tuple.push_back(tn.getDType()[0].getConstructor());
326
54
        for(int i = 0; i < left_len; i++) {
327
35
          left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
328
        }
329
19
        std::set<Node>::iterator right_it = right.begin();
330
19
        int right_len = (*right_it).getType().getTupleLength();
331
137
        while(right_it != right.end()) {
332
59
          Trace("rels-debug") << "Sets::postRewrite processing right_it = " <<  *right_it << std::endl;
333
118
          std::vector<Node> right_tuple;
334
164
          for(int j = 0; j < right_len; j++) {
335
105
            right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
336
          }
337
118
          std::vector<Node> new_tuple;
338
59
          new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
339
59
          new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
340
118
          Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
341
59
          new_tuple_set.insert(composed_tuple);
342
59
          ++right_it;
343
        }
344
19
        ++left_it;
345
      }
346
16
      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
347
8
      Assert(new_node.isConst());
348
8
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
349
8
      return RewriteResponse(REWRITE_DONE, new_node);
350
    }
351
44
    break;
352
  }
353
354
322
  case kind::JOIN: {
355
1286
    if( node[0].getKind() == kind::EMPTYSET ||
356
964
        node[1].getKind() == kind::EMPTYSET) {
357
      return RewriteResponse(REWRITE_DONE,
358
3
                             nm->mkConst(EmptySet(node.getType())));
359
319
    } else if( node[0].isConst() && node[1].isConst() ) {
360
27
      Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " <<  node << std::endl;
361
54
      std::set<Node> new_tuple_set;
362
54
      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
363
54
      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
364
27
      std::set<Node>::iterator left_it = left.begin();
365
27
      int left_len = (*left_it).getType().getTupleLength();
366
54
      TypeNode tn = node.getType().getSetElementType();
367
129
      while(left_it != left.end()) {
368
102
        std::vector<Node> left_tuple;
369
51
        left_tuple.push_back(tn.getDType()[0].getConstructor());
370
99
        for(int i = 0; i < left_len - 1; i++) {
371
48
          left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
372
        }
373
51
        std::set<Node>::iterator right_it = right.begin();
374
51
        int right_len = (*right_it).getType().getTupleLength();
375
309
        while(right_it != right.end()) {
376
129
          if(RelsUtils::nthElementOfTuple(*left_it,left_len-1) == RelsUtils::nthElementOfTuple(*right_it,0)) {
377
74
            std::vector<Node> right_tuple;
378
76
            for(int j = 1; j < right_len; j++) {
379
39
              right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
380
            }
381
74
            std::vector<Node> new_tuple;
382
37
            new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
383
37
            new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
384
74
            Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
385
37
            new_tuple_set.insert(composed_tuple);
386
          }
387
129
          ++right_it;
388
        }
389
51
        ++left_it;
390
      }
391
54
      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
392
27
      Assert(new_node.isConst());
393
27
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
394
27
      return RewriteResponse(REWRITE_DONE, new_node);
395
    }
396
397
292
    break;
398
  }
399
400
53
  case kind::TCLOSURE: {
401
53
    if(node[0].getKind() == kind::EMPTYSET) {
402
      return RewriteResponse(REWRITE_DONE,
403
2
                             nm->mkConst(EmptySet(node.getType())));
404
51
    } else if (node[0].isConst()) {
405
14
      std::set<Node> rel_mems = NormalForm::getElementsFromNormalConstant(node[0]);
406
14
      std::set<Node> tc_rel_mems = RelsUtils::computeTC(rel_mems, node);
407
14
      Node new_node = NormalForm::elementsToSet(tc_rel_mems, node.getType());
408
7
      Assert(new_node.isConst());
409
7
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
410
7
      return RewriteResponse(REWRITE_DONE, new_node);
411
412
44
    } else if(node[0].getKind() == kind::TCLOSURE) {
413
      return RewriteResponse(REWRITE_AGAIN, node[0]);
414
44
    } else if(node[0].getKind() != kind::TCLOSURE) {
415
44
      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
416
44
      return RewriteResponse(REWRITE_DONE, node);
417
    }
418
    break;
419
  }
420
421
9
  case kind::IDEN: {
422
9
    if(node[0].getKind() == kind::EMPTYSET) {
423
      return RewriteResponse(REWRITE_DONE,
424
                             nm->mkConst(EmptySet(node.getType())));
425
9
    } else if (node[0].isConst()) {
426
2
      std::set<Node> iden_rel_mems;
427
2
      std::set<Node> rel_mems = NormalForm::getElementsFromNormalConstant(node[0]);
428
1
      std::set<Node>::iterator rel_mems_it = rel_mems.begin();
429
430
9
      while( rel_mems_it != rel_mems.end() ) {
431
8
        Node fst_mem = RelsUtils::nthElementOfTuple( *rel_mems_it, 0);
432
4
        iden_rel_mems.insert(RelsUtils::constructPair(node, fst_mem, fst_mem));
433
4
        ++rel_mems_it;
434
      }
435
436
2
      Node new_node = NormalForm::elementsToSet(iden_rel_mems, node.getType());
437
1
      Assert(new_node.isConst());
438
1
      Trace("rels-postrewrite") << "Rels::postRewrite returning " << new_node << std::endl;
439
1
      return RewriteResponse(REWRITE_DONE, new_node);
440
441
    } else {
442
8
      Trace("rels-postrewrite") << "Rels::postRewrite miss to handle term " << node << std::endl;
443
    }
444
8
    break;
445
  }
446
447
47
  case kind::JOIN_IMAGE: {
448
47
    unsigned int min_card = node[1].getConst<Rational>().getNumerator().getUnsignedInt();
449
47
    Trace("rels-postrewrite") << "Rels::postRewrite  " << node << " with min_card = " << min_card << std::endl;
450
451
47
    if( min_card == 0) {
452
2
      return RewriteResponse(REWRITE_DONE, nm->mkNullaryOperator( node.getType(), kind::UNIVERSE_SET ));
453
45
    } else if(node[0].getKind() == kind::EMPTYSET) {
454
      return RewriteResponse(REWRITE_DONE,
455
                             nm->mkConst(EmptySet(node.getType())));
456
45
    } else if (node[0].isConst()) {
457
14
      std::set<Node> has_checked;
458
14
      std::set<Node> join_img_mems;
459
14
      std::set<Node> rel_mems = NormalForm::getElementsFromNormalConstant(node[0]);
460
7
      std::set<Node>::iterator rel_mems_it = rel_mems.begin();
461
462
85
      while( rel_mems_it != rel_mems.end() ) {
463
63
        Node fst_mem = RelsUtils::nthElementOfTuple( *rel_mems_it, 0);
464
54
        if( has_checked.find( fst_mem ) != has_checked.end() ) {
465
15
          ++rel_mems_it;
466
15
          continue;
467
        }
468
24
        has_checked.insert( fst_mem );
469
48
        std::set<Node> existing_mems;
470
24
        std::set<Node>::iterator rel_mems_it_snd = rel_mems.begin();
471
308
        while( rel_mems_it_snd != rel_mems.end() ) {
472
284
          Node fst_mem_snd = RelsUtils::nthElementOfTuple( *rel_mems_it_snd, 0);
473
142
          if( fst_mem == fst_mem_snd ) {
474
39
            existing_mems.insert( RelsUtils::nthElementOfTuple( *rel_mems_it_snd, 1) );
475
          }
476
142
          ++rel_mems_it_snd;
477
        }
478
24
        if( existing_mems.size() >= min_card ) {
479
19
          const DType& dt = node.getType().getSetElementType().getDType();
480
19
          join_img_mems.insert(
481
38
              nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem));
482
        }
483
24
        ++rel_mems_it;
484
      }
485
14
      Node new_node = NormalForm::elementsToSet(join_img_mems, node.getType());
486
7
      Assert(new_node.isConst());
487
7
      Trace("rels-postrewrite") << "Rels::postRewrite returning " << new_node << std::endl;
488
7
      return RewriteResponse(REWRITE_DONE, new_node);
489
    } else {
490
38
      Trace("rels-postrewrite") << "Rels::postRewrite miss to handle term " << node << std::endl;
491
    }
492
38
    break;
493
  }
494
495
2249
  default:
496
2249
    break;
497
  }
498
499
34637
  return RewriteResponse(REWRITE_DONE, node);
500
}
501
502
503
// static
504
28694
RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
505
28694
  NodeManager* nm = NodeManager::currentNM();
506
28694
  Kind k = node.getKind();
507
28694
  if (k == kind::EQUAL)
508
  {
509
8433
    if(node[0] == node[1]) {
510
515
      return RewriteResponse(REWRITE_DONE, nm->mkConst(true));
511
    }
512
  }
513
20261
  else if (k == kind::INSERT)
514
  {
515
25
    size_t setNodeIndex =  node.getNumChildren()-1;
516
50
    TypeNode elementType = node[setNodeIndex].getType().getSetElementType();
517
50
    Node insertedElements = nm->mkSingleton(elementType, node[0]);
518
519
57
    for (size_t i = 1; i < setNodeIndex; ++i)
520
    {
521
64
      Node singleton = nm->mkSingleton(elementType, node[i]);
522
32
      insertedElements = nm->mkNode(kind::UNION, insertedElements, singleton);
523
    }
524
    return RewriteResponse(REWRITE_AGAIN,
525
50
                           nm->mkNode(kind::UNION,
526
                                      insertedElements,
527
25
                                      node[setNodeIndex]));
528
  }
529
20236
  else if (k == kind::SUBSET)
530
  {
531
    // rewrite (A subset-or-equal B) as (A union B = B)
532
    return RewriteResponse(REWRITE_AGAIN,
533
760
                           nm->mkNode(kind::EQUAL,
534
380
                                      nm->mkNode(kind::UNION, node[0], node[1]),
535
190
                                      node[1]) );
536
  }
537
538
  // could have an efficient normalizer for union here
539
540
27964
  return RewriteResponse(REWRITE_DONE, node);
541
}
542
543
}  // namespace sets
544
}  // namespace theory
545
22746
}  // namespace cvc5