GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_rels.cpp Lines: 734 782 93.9 %
Date: 2021-09-29 Branches: 1646 3247 50.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Paul Meng, Gereon Kremer
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
 * Extension to Sets theory.
14
 */
15
16
#include "theory/sets/theory_sets_rels.h"
17
18
#include "expr/skolem_manager.h"
19
#include "theory/sets/theory_sets.h"
20
#include "theory/sets/theory_sets_private.h"
21
#include "util/rational.h"
22
23
using namespace std;
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace sets {
29
30
typedef std::map< Node, std::vector< Node > >::iterator                                         MEM_IT;
31
typedef std::map< kind::Kind_t, std::vector< Node > >::iterator                                 KIND_TERM_IT;
32
typedef std::map<Node, std::unordered_set<Node> >::iterator TC_GRAPH_IT;
33
typedef std::map< Node, std::map< kind::Kind_t, std::vector< Node > > >::iterator               TERM_IT;
34
typedef std::map<Node, std::map<Node, std::unordered_set<Node> > >::iterator
35
    TC_IT;
36
37
6271
TheorySetsRels::TheorySetsRels(Env& env,
38
                               SolverState& s,
39
                               InferenceManager& im,
40
                               SkolemCache& skc,
41
6271
                               TermRegistry& treg)
42
    : EnvObj(env),
43
      d_state(s),
44
      d_im(im),
45
      d_skCache(skc),
46
      d_treg(treg),
47
6271
      d_shared_terms(userContext())
48
{
49
6271
  d_trueNode = NodeManager::currentNM()->mkConst(true);
50
6271
  d_falseNode = NodeManager::currentNM()->mkConst(false);
51
6271
}
52
53
12536
TheorySetsRels::~TheorySetsRels() {}
54
55
432
void TheorySetsRels::check(Theory::Effort level)
56
{
57
864
  Trace("rels") << "\n[sets-rels] ******************************* Start the "
58
432
                   "relational solver, effort = "
59
432
                << level << " *******************************\n"
60
432
                << std::endl;
61
432
  if (Theory::fullEffort(level))
62
  {
63
432
    collectRelsInfo();
64
432
    check();
65
432
    d_im.doPendingLemmas();
66
  }
67
432
  Assert(!d_im.hasPendingLemma());
68
864
  Trace("rels") << "\n[sets-rels] ******************************* Done with "
69
432
                   "the relational solver *******************************\n"
70
432
                << std::endl;
71
432
}
72
73
432
  void TheorySetsRels::check() {
74
432
    MEM_IT m_it = d_rReps_memberReps_cache.begin();
75
76
3760
    while(m_it != d_rReps_memberReps_cache.end()) {
77
3328
      Node rel_rep = m_it->first;
78
79
6261
      for(unsigned int i = 0; i < m_it->second.size(); i++) {
80
9194
        Node    mem     = d_rReps_memberReps_cache[rel_rep][i];
81
9194
        Node    exp     = d_rReps_memberReps_exp_cache[rel_rep][i];
82
        std::map<kind::Kind_t, std::vector<Node> >& kind_terms =
83
4597
            d_terms_cache[rel_rep];
84
85
4597
        if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) {
86
502
          std::vector<Node>& tp_terms = kind_terms[TRANSPOSE];
87
502
          if( tp_terms.size() > 0 ) {
88
502
            applyTransposeRule( tp_terms );
89
502
            applyTransposeRule( tp_terms[0], rel_rep, exp );
90
          }
91
        }
92
4597
        if( kind_terms.find(kind::JOIN) != kind_terms.end() ) {
93
525
          std::vector<Node>& join_terms = kind_terms[JOIN];
94
1160
          for( unsigned int j = 0; j < join_terms.size(); j++ ) {
95
635
            applyJoinRule( join_terms[j], rel_rep, exp );
96
          }
97
        }
98
4597
        if( kind_terms.find(kind::PRODUCT) != kind_terms.end() ) {
99
151
          std::vector<Node>& product_terms = kind_terms[PRODUCT];
100
302
          for( unsigned int j = 0; j < product_terms.size(); j++ ) {
101
151
            applyProductRule( product_terms[j], rel_rep, exp );
102
          }
103
        }
104
4597
        if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) {
105
186
          std::vector<Node>& tc_terms = kind_terms[TCLOSURE];
106
372
          for( unsigned int j = 0; j < tc_terms.size(); j++ ) {
107
186
            applyTCRule( mem, tc_terms[j], rel_rep, exp );
108
          }
109
        }
110
4597
        if( kind_terms.find(kind::JOIN_IMAGE) != kind_terms.end() ) {
111
122
          std::vector<Node>& join_image_terms = kind_terms[JOIN_IMAGE];
112
244
          for( unsigned int j = 0; j < join_image_terms.size(); j++ ) {
113
122
            applyJoinImageRule( mem, join_image_terms[j], exp );
114
          }
115
        }
116
4597
        if( kind_terms.find(kind::IDEN) != kind_terms.end() ) {
117
18
          std::vector<Node>& iden_terms = kind_terms[IDEN];
118
36
          for( unsigned int j = 0; j < iden_terms.size(); j++ ) {
119
18
            applyIdenRule( mem, iden_terms[j], exp );
120
          }
121
        }
122
      }
123
1664
      ++m_it;
124
    }
125
126
432
    TERM_IT t_it = d_terms_cache.begin();
127
4340
    while( t_it != d_terms_cache.end() ) {
128
1954
      if( d_rReps_memberReps_cache.find(t_it->first) == d_rReps_memberReps_cache.end() ) {
129
290
        Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl;
130
290
        KIND_TERM_IT k_t_it = t_it->second.begin();
131
132
870
        while( k_t_it != t_it->second.end() ) {
133
290
          if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) {
134
230
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
135
706
            while(term_it != k_t_it->second.end()) {
136
238
              computeMembersForBinOpRel( *term_it );
137
238
              ++term_it;
138
            }
139
60
          } else if( k_t_it->first == kind::TRANSPOSE ) {
140
46
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
141
138
            while( term_it != k_t_it->second.end() ) {
142
46
              computeMembersForUnaryOpRel( *term_it );
143
46
              ++term_it;
144
            }
145
14
          } else if ( k_t_it->first == kind::TCLOSURE ) {
146
9
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
147
27
            while( term_it != k_t_it->second.end() ) {
148
9
              buildTCGraphForRel( *term_it );
149
9
              ++term_it;
150
            }
151
5
          } else if( k_t_it->first == kind::JOIN_IMAGE ) {
152
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
153
            while( term_it != k_t_it->second.end() ) {
154
              computeMembersForJoinImageTerm( *term_it );
155
              ++term_it;
156
            }
157
5
          } else if( k_t_it->first == kind::IDEN ) {
158
5
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
159
15
            while( term_it != k_t_it->second.end() ) {
160
5
              computeMembersForIdenTerm( *term_it );
161
5
              ++term_it;
162
            }
163
          }
164
290
          ++k_t_it;
165
        }
166
      }
167
1954
      ++t_it;
168
    }
169
432
    doTCInference();
170
171
    // clean up
172
432
    d_tuple_reps.clear();
173
432
    d_rReps_memberReps_exp_cache.clear();
174
432
    d_terms_cache.clear();
175
432
    d_membership_trie.clear();
176
432
    d_rel_nodes.clear();
177
432
    d_rReps_memberReps_cache.clear();
178
432
    d_rRep_tcGraph.clear();
179
432
    d_tcr_tcGraph_exps.clear();
180
432
    d_tcr_tcGraph.clear();
181
432
  }
182
183
  /*
184
   * Populate relational terms data structure
185
   */
186
187
432
  void TheorySetsRels::collectRelsInfo() {
188
432
    Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
189
432
    eq::EqualityEngine* ee = d_state.getEqualityEngine();
190
432
    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
191
21580
    while( !eqcs_i.isFinished() ){
192
21148
      Node                      eqc_rep  = (*eqcs_i);
193
10574
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee);
194
195
21148
      TypeNode erType = eqc_rep.getType();
196
10574
      Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl;
197
198
57152
      while( !eqc_i.isFinished() ){
199
46578
        Node eqc_node = (*eqc_i);
200
201
23289
        Trace("rels-ee") << "  term : " << eqc_node << std::endl;
202
203
23289
        if (erType.isBoolean() && eqc_rep.isConst())
204
        {
205
          // collect membership info
206
10322
          if( eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) {
207
11878
            Node tup_rep = getRepresentative( eqc_node[0] );
208
11878
            Node rel_rep = getRepresentative( eqc_node[1] );
209
210
5939
            if( eqc_node[0].isVar() ){
211
475
              reduceTupleVar( eqc_node );
212
            }
213
214
5939
            bool is_true_eq = eqc_rep.getConst<bool>();
215
11878
            Node reason        = is_true_eq ? eqc_node : eqc_node.negate();
216
217
5939
            if( is_true_eq ) {
218
5352
              if( safelyAddToMap(d_rReps_memberReps_cache, rel_rep, tup_rep) ) {
219
4597
                d_rReps_memberReps_exp_cache[rel_rep].push_back(reason);
220
4597
                computeTupleReps(tup_rep);
221
4597
                d_membership_trie[rel_rep].addTerm(tup_rep, d_tuple_reps[tup_rep]);
222
              }
223
            }
224
          }
225
        // collect relational terms info
226
        }
227
12967
        else if (erType.isSet() && erType.getSetElementType().isTuple())
228
        {
229
9761
          if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN ||
230
5895
              eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE ||
231
6335
              eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) {
232
1606
            std::vector<Node> terms;
233
1606
            std::map< kind::Kind_t, std::vector<Node> >  rel_terms;
234
803
            TERM_IT terms_it = d_terms_cache.find(eqc_rep);
235
236
803
            if( terms_it == d_terms_cache.end() ) {
237
742
              terms.push_back(eqc_node);
238
742
              rel_terms[eqc_node.getKind()]      = terms;
239
742
              d_terms_cache[eqc_rep]             = rel_terms;
240
            } else {
241
61
              KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind());
242
243
61
              if( kind_term_it == terms_it->second.end() ) {
244
11
                terms.push_back(eqc_node);
245
11
                d_terms_cache[eqc_rep][eqc_node.getKind()] = terms;
246
              } else {
247
50
                kind_term_it->second.push_back(eqc_node);
248
              }
249
            }
250
          }
251
        // need to add all tuple elements as shared terms
252
        }
253
10345
        else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar())
254
        {
255
3606
          std::vector<TypeNode> tupleTypes = erType.getTupleTypes();
256
5394
          for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++)
257
          {
258
7182
            Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
259
3591
            if (!element.isConst())
260
            {
261
2831
              makeSharedTerm(element, tupleTypes[i]);
262
            }
263
          }
264
        }
265
23289
        ++eqc_i;
266
      }
267
10574
      ++eqcs_i;
268
    }
269
432
    Trace("rels-debug") << "[Theory::Rels] Done with collecting relational terms!" << std::endl;
270
432
  }
271
272
  /* JOIN-IMAGE UP  :   (x, x1) IS_IN R, ..., (x, xn) IS_IN R  (R JOIN_IMAGE n)
273
  *                     -------------------------------------------------------
274
  *                     x IS_IN (R JOIN_IMAGE n) || NOT DISTINCT(x1, ... , xn)
275
  *
276
  */
277
278
55
  void TheorySetsRels::computeMembersForJoinImageTerm( Node join_image_term ) {
279
55
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for JoinImage Term = " << join_image_term << std::endl;
280
55
    MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( getRepresentative( join_image_term[0] ) );
281
282
55
    if( rel_mem_it == d_rReps_memberReps_cache.end() ) {
283
      return;
284
    }
285
55
    NodeManager* nm = NodeManager::currentNM();
286
287
110
    Node join_image_rel = join_image_term[0];
288
110
    std::unordered_set<Node> hasChecked;
289
110
    Node join_image_rel_rep = getRepresentative( join_image_rel );
290
55
    std::vector< Node >::iterator mem_rep_it = (*rel_mem_it).second.begin();
291
55
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( join_image_rel_rep );
292
55
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
293
55
    unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt();
294
295
589
    while( mem_rep_it != (*rel_mem_it).second.end() ) {
296
339
      Node fst_mem_rep = RelsUtils::nthElementOfTuple( *mem_rep_it, 0 );
297
298
353
      if( hasChecked.find( fst_mem_rep ) != hasChecked.end() ) {
299
86
        ++mem_rep_it;
300
86
        ++mem_rep_exp_it;
301
86
        continue;
302
      }
303
181
      hasChecked.insert( fst_mem_rep );
304
305
      const DType& dt =
306
181
          join_image_term.getType().getSetElementType().getDType();
307
      Node new_membership = nm->mkNode(
308
          MEMBER,
309
362
          nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem_rep),
310
615
          join_image_term);
311
290
      if (d_state.isEntailed(new_membership, true))
312
      {
313
109
        ++mem_rep_it;
314
109
        ++mem_rep_exp_it;
315
109
        continue;
316
      }
317
318
144
      std::vector< Node > reasons;
319
144
      std::vector< Node > existing_members;
320
72
      std::vector< Node >::iterator mem_rep_exp_it_snd = (*rel_mem_exp_it).second.begin();
321
322
538
      while( mem_rep_exp_it_snd != (*rel_mem_exp_it).second.end() ) {
323
495
        Node fst_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 0 );
324
325
262
        if( areEqual( fst_mem_rep,  fst_element_snd_mem ) ) {
326
80
          bool notExist = true;
327
80
          std::vector< Node >::iterator existing_mem_it = existing_members.begin();
328
131
          Node snd_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 1 );
329
330
102
          while( existing_mem_it != existing_members.end() ) {
331
11
            if( areEqual( (*existing_mem_it), snd_element_snd_mem ) ) {
332
              notExist = false;
333
              break;
334
            }
335
11
            ++existing_mem_it;
336
          }
337
338
80
          if( notExist ) {
339
80
            existing_members.push_back( snd_element_snd_mem );
340
80
            reasons.push_back( *mem_rep_exp_it_snd );
341
80
            if( fst_mem_rep != fst_element_snd_mem ) {
342
4
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, fst_mem_rep, fst_element_snd_mem ) );
343
            }
344
80
            if( join_image_rel != (*mem_rep_exp_it_snd)[1] ) {
345
42
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it_snd)[1], join_image_rel ));
346
            }
347
80
            if( existing_members.size() == min_card ) {
348
29
              if( min_card >= 2) {
349
9
                new_membership = NodeManager::currentNM()->mkNode( kind::OR, new_membership, NodeManager::currentNM()->mkNode( kind::NOT, NodeManager::currentNM()->mkNode( kind::DISTINCT, existing_members ) ));
350
              }
351
29
              Assert(reasons.size() >= 1);
352
29
              sendInfer(
353
                  new_membership,
354
                  InferenceId::SETS_RELS_JOIN_IMAGE_UP,
355
58
                  reasons.size() > 1 ? nm->mkNode(AND, reasons) : reasons[0]);
356
29
              break;
357
            }
358
          }
359
        }
360
233
        ++mem_rep_exp_it_snd;
361
      }
362
72
      ++mem_rep_it;
363
72
      ++mem_rep_exp_it;
364
    }
365
55
    Trace("rels-debug") << "\n[Theory::Rels] *********** Done with computing members for JoinImage Term" << join_image_term << "*********** " << std::endl;
366
  }
367
368
  /* JOIN-IMAGE DOWN  : (x) IS_IN (R JOIN_IMAGE n)
369
   *                     -------------------------------------------------------
370
   *                     (x, x1) IS_IN R .... (x, xn) IS_IN R  DISTINCT(x1, ...
371
   * , xn)
372
   *
373
   */
374
122
  void TheorySetsRels::applyJoinImageRule( Node mem_rep, Node join_image_term, Node exp ) {
375
244
    Trace("rels-debug") << "\n[Theory::Rels] *********** applyJoinImageRule on " << join_image_term
376
122
                        << " with mem_rep = " << mem_rep  << " and exp = " << exp << std::endl;
377
122
    if( d_rel_nodes.find( join_image_term ) == d_rel_nodes.end() ) {
378
55
      computeMembersForJoinImageTerm( join_image_term );
379
55
      d_rel_nodes.insert( join_image_term );
380
    }
381
382
147
    Node join_image_rel = join_image_term[0];
383
147
    Node join_image_rel_rep = getRepresentative( join_image_rel );
384
122
    MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( join_image_rel_rep );
385
122
    unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt();
386
387
122
    if( rel_mem_it != d_rReps_memberReps_cache.end() ) {
388
122
      if( d_membership_trie.find( join_image_rel_rep ) != d_membership_trie.end() ) {
389
122
        computeTupleReps( mem_rep );
390
122
        if( d_membership_trie[join_image_rel_rep].findSuccessors(d_tuple_reps[mem_rep]).size() >= min_card ) {
391
97
          return;
392
        }
393
      }
394
    }
395
25
    NodeManager* nm = NodeManager::currentNM();
396
25
    SkolemManager* sm = nm->getSkolemManager();
397
50
    Node reason = exp;
398
50
    Node conclusion = d_trueNode;
399
50
    std::vector< Node > distinct_skolems;
400
50
    Node fst_mem_element = RelsUtils::nthElementOfTuple( exp[0], 0 );
401
402
25
    if( exp[1] != join_image_term ) {
403
4
      reason =
404
8
          nm->mkNode(AND, reason, nm->mkNode(EQUAL, exp[1], join_image_term));
405
    }
406
70
    for( unsigned int i = 0; i < min_card; i++ ) {
407
      Node skolem = sm->mkDummySkolem(
408
90
          "jig", join_image_rel.getType()[0].getTupleTypes()[0]);
409
45
      distinct_skolems.push_back( skolem );
410
45
      conclusion = nm->mkNode(
411
          AND,
412
          conclusion,
413
180
          nm->mkNode(
414
              MEMBER,
415
90
              RelsUtils::constructPair(join_image_rel, fst_mem_element, skolem),
416
              join_image_rel));
417
    }
418
25
    if( distinct_skolems.size() >= 2 ) {
419
19
      conclusion =
420
38
          nm->mkNode(AND, conclusion, nm->mkNode(DISTINCT, distinct_skolems));
421
    }
422
25
    sendInfer(conclusion, InferenceId::SETS_RELS_JOIN_IMAGE_DOWN, reason);
423
25
    Trace("rels-debug") << "\n[Theory::Rels] *********** Done with applyJoinImageRule ***********" << std::endl;
424
  }
425
426
  /* IDENTITY-DOWN  : (x, y) IS_IN IDEN(R)
427
  *               -------------------------------------------------------
428
  *                   x = y,  (x IS_IN R)
429
  *
430
  */
431
432
18
  void TheorySetsRels::applyIdenRule( Node mem_rep, Node iden_term, Node exp) {
433
36
    Trace("rels-debug") << "\n[Theory::Rels] *********** applyIdenRule on " << iden_term
434
18
                        << " with mem_rep = " << mem_rep  << " and exp = " << exp << std::endl;
435
18
    NodeManager* nm = NodeManager::currentNM();
436
18
    if( d_rel_nodes.find( iden_term ) == d_rel_nodes.end() ) {
437
5
      computeMembersForIdenTerm( iden_term );
438
5
      d_rel_nodes.insert( iden_term );
439
    }
440
36
    Node reason = exp;
441
36
    Node fst_mem = RelsUtils::nthElementOfTuple( exp[0], 0 );
442
36
    Node snd_mem = RelsUtils::nthElementOfTuple( exp[0], 1 );
443
18
    const DType& dt = iden_term[0].getType().getSetElementType().getDType();
444
    Node fact = nm->mkNode(
445
        MEMBER,
446
36
        nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem),
447
72
        iden_term[0]);
448
449
18
    if( exp[1] != iden_term ) {
450
2
      reason = NodeManager::currentNM()->mkNode( kind::AND, reason, NodeManager::currentNM()->mkNode( kind::EQUAL, exp[1], iden_term ) );
451
    }
452
18
    sendInfer(nm->mkNode(AND, fact, nm->mkNode(EQUAL, fst_mem, snd_mem)),
453
              InferenceId::SETS_RELS_IDENTITY_DOWN,
454
              reason);
455
18
    Trace("rels-debug") << "\n[Theory::Rels] *********** Done with applyIdenRule on " << iden_term << std::endl;
456
18
  }
457
458
  /* IDEN UP  : (x) IS_IN R        IDEN(R) IN T
459
  *             --------------------------------
460
  *                   (x, x) IS_IN IDEN(R)
461
  *
462
  */
463
464
10
  void TheorySetsRels::computeMembersForIdenTerm( Node iden_term ) {
465
10
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for Iden Term = " << iden_term << std::endl;
466
17
    Node iden_term_rel = iden_term[0];
467
17
    Node iden_term_rel_rep = getRepresentative( iden_term_rel );
468
469
10
    if( d_rReps_memberReps_cache.find( iden_term_rel_rep ) == d_rReps_memberReps_cache.end() ) {
470
3
      return;
471
    }
472
7
    NodeManager* nm = NodeManager::currentNM();
473
474
7
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( iden_term_rel_rep );
475
7
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
476
477
59
    while( mem_rep_exp_it != (*rel_mem_exp_it).second.end() ) {
478
52
      Node reason = *mem_rep_exp_it;
479
52
      Node fst_exp_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it)[0], 0 );
480
52
      Node new_mem = RelsUtils::constructPair( iden_term, fst_exp_mem, fst_exp_mem );
481
482
26
      if( (*mem_rep_exp_it)[1] != iden_term_rel ) {
483
        reason = NodeManager::currentNM()->mkNode( kind::AND, reason, NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it)[1], iden_term_rel ) );
484
      }
485
78
      sendInfer(
486
52
          nm->mkNode(MEMBER, new_mem, iden_term), InferenceId::SETS_RELS_IDENTITY_UP, reason);
487
26
      ++mem_rep_exp_it;
488
    }
489
7
    Trace("rels-debug") << "\n[Theory::Rels] *********** Done with computing members for Iden Term = " << iden_term << std::endl;
490
  }
491
492
493
  /*
494
   * Construct transitive closure graph for tc_rep based on the members of tc_r_rep
495
   */
496
497
  /*
498
   * TCLOSURE TCLOSURE(x) = x | x.x | x.x.x | ... (| is union)
499
   *
500
   * TCLOSURE-UP I:   (a, b) IS_IN x            TCLOSURE(x) in T
501
   *              ---------------------------------------------
502
   *                              (a, b) IS_IN TCLOSURE(x)
503
   *
504
   *
505
   *
506
   * TCLOSURE-UP II : (a, b) IS_IN TCLOSURE(x)  (b, c) IS_IN TCLOSURE(x)
507
   *              -----------------------------------------------------------
508
   *                            (a, c) IS_IN TCLOSURE(x)
509
   *
510
   */
511
186
  void TheorySetsRels::applyTCRule( Node mem_rep, Node tc_rel, Node tc_rel_rep, Node exp ) {
512
372
    Trace("rels-debug") << "[Theory::Rels] *********** Applying TCLOSURE rule on a tc term = " << tc_rel
513
186
                            << ", its representative = " << tc_rel_rep
514
186
                            << " with member rep = " << mem_rep << " and explanation = " << exp << std::endl;
515
186
    MEM_IT mem_it = d_rReps_memberReps_cache.find( tc_rel[0] );
516
517
552
    if( mem_it != d_rReps_memberReps_cache.end() && d_rel_nodes.find( tc_rel ) == d_rel_nodes.end()
518
446
        && d_rRep_tcGraph.find( getRepresentative( tc_rel[0] ) ) ==  d_rRep_tcGraph.end() ) {
519
74
      buildTCGraphForRel( tc_rel );
520
74
      d_rel_nodes.insert( tc_rel );
521
    }
522
523
    // mem_rep is a member of tc_rel[0] or mem_rep can be infered by TC_Graph of tc_rel[0], thus skip
524
186
    if( isTCReachable( mem_rep, tc_rel) ) {
525
346
      Trace("rels-debug") << "[Theory::Rels] mem_rep is a member of tc_rel[0] = " << tc_rel[0]
526
173
                              << " or can be infered by TC_Graph of tc_rel[0]! " << std::endl;
527
173
      return;
528
    }
529
13
    NodeManager* nm = NodeManager::currentNM();
530
531
    // add mem_rep to d_tcrRep_tcGraph
532
13
    TC_IT tc_it = d_tcr_tcGraph.find( tc_rel );
533
26
    Node mem_rep_fst = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 0 ) );
534
26
    Node mem_rep_snd = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 1 ) );
535
26
    Node mem_rep_tup = RelsUtils::constructPair( tc_rel, mem_rep_fst, mem_rep_snd );
536
537
13
    if( tc_it != d_tcr_tcGraph.end() ) {
538
7
      std::map< Node, std::map< Node, Node > >::iterator tc_exp_it = d_tcr_tcGraph_exps.find( tc_rel );
539
540
7
      TC_GRAPH_IT tc_graph_it = (tc_it->second).find( mem_rep_fst );
541
7
      Assert(tc_exp_it != d_tcr_tcGraph_exps.end());
542
7
      std::map< Node, Node >::iterator exp_map_it = (tc_exp_it->second).find( mem_rep_tup );
543
544
7
      if( exp_map_it == (tc_exp_it->second).end() ) {
545
7
        (tc_exp_it->second)[mem_rep_tup] = exp;
546
      }
547
548
7
      if( tc_graph_it != (tc_it->second).end() ) {
549
4
        (tc_graph_it->second).insert( mem_rep_snd );
550
      } else {
551
6
        std::unordered_set<Node> sets;
552
3
        sets.insert( mem_rep_snd );
553
3
        (tc_it->second)[mem_rep_fst] = sets;
554
      }
555
    } else {
556
12
      std::map< Node, Node > exp_map;
557
12
      std::unordered_set<Node> sets;
558
12
      std::map<Node, std::unordered_set<Node> > element_map;
559
6
      sets.insert( mem_rep_snd );
560
6
      element_map[mem_rep_fst] = sets;
561
6
      d_tcr_tcGraph[tc_rel] = element_map;
562
6
      exp_map[mem_rep_tup] = exp;
563
6
      d_tcr_tcGraph_exps[tc_rel] = exp_map;
564
    }
565
26
    Node fst_element = RelsUtils::nthElementOfTuple( exp[0], 0 );
566
26
    Node snd_element = RelsUtils::nthElementOfTuple( exp[0], 1 );
567
39
    Node sk_1 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
568
                                              exp[0],
569
                                              tc_rel[0],
570
                                              SkolemCache::SK_TCLOSURE_DOWN1,
571
52
                                              "stc1");
572
39
    Node sk_2 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
573
                                              exp[0],
574
                                              tc_rel[0],
575
                                              SkolemCache::SK_TCLOSURE_DOWN2,
576
52
                                              "stc2");
577
26
    Node mem_of_r = nm->mkNode(MEMBER, exp[0], tc_rel[0]);
578
26
    Node sk_eq = nm->mkNode(EQUAL, sk_1, sk_2);
579
26
    Node reason   = exp;
580
581
13
    if( tc_rel != exp[1] ) {
582
      reason = nm->mkNode(AND, reason, nm->mkNode(EQUAL, tc_rel, exp[1]));
583
    }
584
585
    Node conc = nm->mkNode(
586
        OR,
587
        mem_of_r,
588
78
        nm->mkNode(
589
            AND,
590
52
            nm->mkNode(MEMBER,
591
26
                       RelsUtils::constructPair(tc_rel, fst_element, sk_1),
592
                       tc_rel[0]),
593
52
            nm->mkNode(MEMBER,
594
26
                       RelsUtils::constructPair(tc_rel, sk_2, snd_element),
595
                       tc_rel[0]),
596
26
            nm->mkNode(OR,
597
                       sk_eq,
598
52
                       nm->mkNode(MEMBER,
599
26
                                  RelsUtils::constructPair(tc_rel, sk_1, sk_2),
600
26
                                  tc_rel))));
601
602
13
    sendInfer(conc, InferenceId::SETS_RELS_TCLOSURE_UP, reason);
603
  }
604
605
186
  bool TheorySetsRels::isTCReachable( Node mem_rep, Node tc_rel ) {
606
186
    MEM_IT mem_it = d_rReps_memberReps_cache.find( getRepresentative( tc_rel[0] ) );
607
608
186
    if( mem_it != d_rReps_memberReps_cache.end() && std::find( (mem_it->second).begin(), (mem_it->second).end(), mem_rep) != (mem_it->second).end() ) {
609
116
      return true;
610
    }
611
612
70
    TC_IT tc_it = d_rRep_tcGraph.find( getRepresentative(tc_rel[0]) );
613
70
    if( tc_it != d_rRep_tcGraph.end() ) {
614
64
      bool isReachable = false;
615
128
      std::unordered_set<Node> seen;
616
128
      isTCReachable( getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 0) ),
617
192
                     getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 1) ), seen, tc_it->second, isReachable );
618
64
      return isReachable;
619
    }
620
6
    return false;
621
  }
622
623
132
  void TheorySetsRels::isTCReachable(
624
      Node start,
625
      Node dest,
626
      std::unordered_set<Node>& hasSeen,
627
      std::map<Node, std::unordered_set<Node> >& tc_graph,
628
      bool& isReachable)
629
  {
630
132
    if(hasSeen.find(start) == hasSeen.end()) {
631
132
      hasSeen.insert(start);
632
    }
633
634
132
    TC_GRAPH_IT pair_set_it = tc_graph.find(start);
635
636
132
    if(pair_set_it != tc_graph.end()) {
637
120
      if(pair_set_it->second.find(dest) != pair_set_it->second.end()) {
638
57
        isReachable = true;
639
114
        return;
640
      } else {
641
63
        std::unordered_set<Node>::iterator set_it = pair_set_it->second.begin();
642
643
199
        while( set_it != pair_set_it->second.end() ) {
644
          // need to check if *set_it has been looked already
645
68
          if( hasSeen.find(*set_it) == hasSeen.end() ) {
646
68
            isTCReachable( *set_it, dest, hasSeen, tc_graph, isReachable );
647
          }
648
68
          ++set_it;
649
        }
650
      }
651
    }
652
  }
653
654
83
  void TheorySetsRels::buildTCGraphForRel( Node tc_rel ) {
655
166
    std::map< Node, Node > rel_tc_graph_exps;
656
166
    std::map<Node, std::unordered_set<Node> > rel_tc_graph;
657
658
166
    Node rel_rep = getRepresentative( tc_rel[0] );
659
166
    Node tc_rel_rep = getRepresentative( tc_rel );
660
166
    std::vector< Node > members = d_rReps_memberReps_cache[rel_rep];
661
166
    std::vector< Node > exps = d_rReps_memberReps_exp_cache[rel_rep];
662
663
231
    for( unsigned int i = 0; i < members.size(); i++ ) {
664
296
      Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 ));
665
296
      Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 ));
666
296
      Node tuple_rep = RelsUtils::constructPair( rel_rep, fst_element_rep, snd_element_rep );
667
      std::map<Node, std::unordered_set<Node> >::iterator rel_tc_graph_it =
668
148
          rel_tc_graph.find(fst_element_rep);
669
670
148
      if( rel_tc_graph_it == rel_tc_graph.end() ) {
671
262
        std::unordered_set<Node> snd_elements;
672
131
        snd_elements.insert( snd_element_rep );
673
131
        rel_tc_graph[fst_element_rep] = snd_elements;
674
131
        rel_tc_graph_exps[tuple_rep] = exps[i];
675
17
      } else if( (rel_tc_graph_it->second).find( snd_element_rep ) ==  (rel_tc_graph_it->second).end() ) {
676
17
        (rel_tc_graph_it->second).insert( snd_element_rep );
677
17
        rel_tc_graph_exps[tuple_rep] = exps[i];
678
      }
679
    }
680
681
83
    if( members.size() > 0 ) {
682
77
      d_rRep_tcGraph[rel_rep] = rel_tc_graph;
683
77
      d_tcr_tcGraph_exps[tc_rel] = rel_tc_graph_exps;
684
77
      d_tcr_tcGraph[tc_rel] = rel_tc_graph;
685
    }
686
83
  }
687
688
83
  void TheorySetsRels::doTCInference(
689
      std::map<Node, std::unordered_set<Node> > rel_tc_graph,
690
      std::map<Node, Node> rel_tc_graph_exps,
691
      Node tc_rel)
692
  {
693
83
    Trace("rels-debug") << "[Theory::Rels] ****** doTCInference !" << std::endl;
694
223
    for (TC_GRAPH_IT tc_graph_it = rel_tc_graph.begin();
695
223
         tc_graph_it != rel_tc_graph.end();
696
         ++tc_graph_it)
697
    {
698
161
      for (std::unordered_set<Node>::iterator snd_elements_it =
699
140
               tc_graph_it->second.begin();
700
301
           snd_elements_it != tc_graph_it->second.end();
701
           ++snd_elements_it)
702
      {
703
322
        std::vector< Node > reasons;
704
322
        std::unordered_set<Node> seen;
705
322
        Node tuple = RelsUtils::constructPair( tc_rel, getRepresentative( tc_graph_it->first ), getRepresentative( *snd_elements_it) );
706
161
        Assert(rel_tc_graph_exps.find(tuple) != rel_tc_graph_exps.end());
707
322
        Node exp   = rel_tc_graph_exps.find( tuple )->second;
708
709
161
        reasons.push_back( exp );
710
161
        seen.insert( tc_graph_it->first );
711
161
        doTCInference( tc_rel, reasons, rel_tc_graph, rel_tc_graph_exps, tc_graph_it->first, *snd_elements_it, seen);
712
      }
713
    }
714
83
    Trace("rels-debug") << "[Theory::Rels] ****** Done with doTCInference !" << std::endl;
715
83
  }
716
717
270
  void TheorySetsRels::doTCInference(
718
      Node tc_rel,
719
      std::vector<Node> reasons,
720
      std::map<Node, std::unordered_set<Node> >& tc_graph,
721
      std::map<Node, Node>& rel_tc_graph_exps,
722
      Node start_node_rep,
723
      Node cur_node_rep,
724
      std::unordered_set<Node>& seen)
725
  {
726
270
    NodeManager* nm = NodeManager::currentNM();
727
472
    Node tc_mem = RelsUtils::constructPair( tc_rel, RelsUtils::nthElementOfTuple((reasons.front())[0], 0), RelsUtils::nthElementOfTuple((reasons.back())[0], 1) );
728
472
    std::vector< Node > all_reasons( reasons );
729
730
408
    for( unsigned int i = 0 ; i < reasons.size()-1; i++ ) {
731
276
      Node fst_element_end = RelsUtils::nthElementOfTuple( reasons[i][0], 1 );
732
276
      Node snd_element_begin = RelsUtils::nthElementOfTuple( reasons[i+1][0], 0 );
733
138
      if( fst_element_end != snd_element_begin ) {
734
24
        all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, fst_element_end, snd_element_begin) );
735
      }
736
138
      if( tc_rel != reasons[i][1] && tc_rel[0] != reasons[i][1] ) {
737
        all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons[i][1]) );
738
      }
739
    }
740
270
    if( tc_rel != reasons.back()[1] && tc_rel[0] != reasons.back()[1] ) {
741
      all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons.back()[1]) );
742
    }
743
270
    if( all_reasons.size() > 1) {
744
109
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
745
                InferenceId::SETS_RELS_TCLOSURE_FWD,
746
218
                nm->mkNode(AND, all_reasons));
747
    } else {
748
161
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
749
                InferenceId::SETS_RELS_TCLOSURE_FWD,
750
161
                all_reasons.front());
751
    }
752
753
    // check if cur_node has been traversed or not
754
270
    if( seen.find( cur_node_rep ) != seen.end() ) {
755
68
      return;
756
    }
757
202
    seen.insert( cur_node_rep );
758
202
    TC_GRAPH_IT  cur_set = tc_graph.find( cur_node_rep );
759
202
    if( cur_set != tc_graph.end() ) {
760
194
      for (std::unordered_set<Node>::iterator set_it = cur_set->second.begin();
761
194
           set_it != cur_set->second.end();
762
           ++set_it)
763
      {
764
218
        Node new_pair = RelsUtils::constructPair( tc_rel, cur_node_rep, *set_it );
765
218
        std::vector< Node > new_reasons( reasons );
766
109
        new_reasons.push_back( rel_tc_graph_exps.find( new_pair )->second );
767
109
        doTCInference( tc_rel, new_reasons, tc_graph, rel_tc_graph_exps, start_node_rep, *set_it, seen );
768
      }
769
    }
770
  }
771
772
 /*  product-split rule:  (a, b) IS_IN (X PRODUCT Y)
773
  *                     ----------------------------------
774
  *                       a IS_IN X  && b IS_IN Y
775
  *
776
  *  product-compose rule: (a, b) IS_IN X    (c, d) IS_IN Y
777
  *                        ---------------------------------
778
  *                        (a, b, c, d) IS_IN (X PRODUCT Y)
779
  */
780
781
782
151
  void TheorySetsRels::applyProductRule( Node pt_rel, Node pt_rel_rep, Node exp ) {
783
302
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying PRODUCT rule on producted term = " << pt_rel
784
151
                            << ", its representative = " << pt_rel_rep
785
151
                            << " with explanation = " << exp << std::endl;
786
787
151
    if(d_rel_nodes.find( pt_rel ) == d_rel_nodes.end()) {
788
94
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply PRODUCT-COMPOSE rule on term: " << pt_rel
789
47
                          << " with explanation: " << exp << std::endl;
790
791
47
      computeMembersForBinOpRel( pt_rel );
792
47
      d_rel_nodes.insert( pt_rel );
793
    }
794
795
302
    Node mem = exp[0];
796
302
    std::vector<Node>   r1_element;
797
302
    std::vector<Node>   r2_element;
798
151
    const DType& dt1 = pt_rel[0].getType().getSetElementType().getDType();
799
151
    unsigned int s1_len  = pt_rel[0].getType().getSetElementType().getTupleLength();
800
151
    unsigned int tup_len = pt_rel.getType().getSetElementType().getTupleLength();
801
802
151
    r1_element.push_back(dt1[0].getConstructor());
803
804
151
    unsigned int i = 0;
805
655
    for(; i < s1_len; ++i) {
806
252
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
807
    }
808
151
    const DType& dt2 = pt_rel[1].getType().getSetElementType().getDType();
809
151
    r2_element.push_back(dt2[0].getConstructor());
810
655
    for(; i < tup_len; ++i) {
811
252
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
812
    }
813
302
    Node reason   = exp;
814
302
    Node mem1     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
815
302
    Node mem2     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
816
302
    Node fact_1   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, pt_rel[0]);
817
302
    Node fact_2   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, pt_rel[1]);
818
819
151
    if( pt_rel != exp[1] ) {
820
8
      reason = NodeManager::currentNM()->mkNode(kind::AND, exp, NodeManager::currentNM()->mkNode(kind::EQUAL, pt_rel, exp[1]));
821
    }
822
151
    sendInfer(fact_1, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
823
151
    sendInfer(fact_2, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
824
151
  }
825
826
  /* join-split rule:           (a, b) IS_IN (X JOIN Y)
827
   *                  --------------------------------------------
828
   *                  exists z | (a, z) IS_IN X  && (z, b) IS_IN Y
829
   *
830
   *
831
   * join-compose rule: (a, b) IS_IN X    (b, c) IS_IN Y  NOT (t, u) IS_IN (X JOIN Y)
832
   *                    -------------------------------------------------------------
833
   *                                      (a, c) IS_IN (X JOIN Y)
834
   */
835
836
635
  void TheorySetsRels::applyJoinRule( Node join_rel, Node join_rel_rep, Node exp ) {
837
1270
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying JOIN rule on joined term = " << join_rel
838
635
                            << ", its representative = " << join_rel_rep
839
635
                            << " with explanation = " << exp << std::endl;
840
635
    if(d_rel_nodes.find( join_rel ) == d_rel_nodes.end()) {
841
442
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply JOIN-COMPOSE rule on term: " << join_rel
842
221
                          << " with explanation: " << exp << std::endl;
843
844
221
      computeMembersForBinOpRel( join_rel );
845
221
      d_rel_nodes.insert( join_rel );
846
    }
847
848
759
    Node mem = exp[0];
849
759
    std::vector<Node> r1_element;
850
759
    std::vector<Node> r2_element;
851
759
    Node r1_rep = getRepresentative(join_rel[0]);
852
759
    Node r2_rep = getRepresentative(join_rel[1]);
853
759
    TypeNode     shared_type    = r2_rep.getType().getSetElementType().getTupleTypes()[0];
854
635
    Node shared_x = d_skCache.mkTypedSkolemCached(
855
759
        shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj");
856
635
    const DType& dt1 = join_rel[0].getType().getSetElementType().getDType();
857
635
    unsigned int s1_len         = join_rel[0].getType().getSetElementType().getTupleLength();
858
635
    unsigned int tup_len        = join_rel.getType().getSetElementType().getTupleLength();
859
860
635
    unsigned int i = 0;
861
635
    r1_element.push_back(dt1[0].getConstructor());
862
1881
    for(; i < s1_len-1; ++i) {
863
623
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
864
    }
865
635
    r1_element.push_back(shared_x);
866
635
    const DType& dt2 = join_rel[1].getType().getSetElementType().getDType();
867
635
    r2_element.push_back(dt2[0].getConstructor());
868
635
    r2_element.push_back(shared_x);
869
1937
    for(; i < tup_len; ++i) {
870
651
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
871
    }
872
759
    Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
873
759
    Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
874
875
635
    computeTupleReps(mem1);
876
635
    computeTupleReps(mem2);
877
878
759
    std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[mem1]);
879
880
726
    for(unsigned int j = 0; j < elements.size(); j++) {
881
693
      std::vector<Node> new_tup;
882
602
      new_tup.push_back(elements[j]);
883
602
      new_tup.insert(new_tup.end(), d_tuple_reps[mem2].begin()+1, d_tuple_reps[mem2].end());
884
602
      if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) {
885
511
        return;
886
      }
887
    }
888
248
    Node reason = exp;
889
124
    if( join_rel != exp[1] ) {
890
53
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, join_rel, exp[1]));
891
    }
892
248
    Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, join_rel[0]);
893
124
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_1, reason);
894
124
    fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]);
895
124
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_2, reason);
896
124
    makeSharedTerm(shared_x, shared_type);
897
  }
898
899
  /*
900
   * transpose-occur rule:    (a, b) IS_IN X   (TRANSPOSE X) in T
901
   *                         ---------------------------------------
902
   *                            (b, a) IS_IN (TRANSPOSE X)
903
   *
904
   * transpose-reverse rule:    (a, b) IS_IN (TRANSPOSE X)
905
   *                         ---------------------------------------
906
   *                            (b, a) IS_IN X
907
   *
908
   */
909
502
  void TheorySetsRels::applyTransposeRule( std::vector<Node> tp_terms ) {
910
502
    if( tp_terms.size() < 1) {
911
      return;
912
    }
913
502
    NodeManager* nm = NodeManager::currentNM();
914
502
    for( unsigned int i = 1; i < tp_terms.size(); i++ ) {
915
      Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE-Equal rule on transposed term = " << tp_terms[0] << " and " << tp_terms[i] << std::endl;
916
      sendInfer(nm->mkNode(EQUAL, tp_terms[0][0], tp_terms[i][0]),
917
                InferenceId::SETS_RELS_TRANSPOSE_EQ,
918
                nm->mkNode(EQUAL, tp_terms[0], tp_terms[i]));
919
    }
920
  }
921
922
502
  void TheorySetsRels::applyTransposeRule( Node tp_rel, Node tp_rel_rep, Node exp ) {
923
1004
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE rule on transposed term = " << tp_rel
924
502
                        << ", its representative = " << tp_rel_rep
925
502
                        << " with explanation = " << exp << std::endl;
926
502
    NodeManager* nm = NodeManager::currentNM();
927
928
502
    if(d_rel_nodes.find( tp_rel ) == d_rel_nodes.end()) {
929
194
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply TRANSPOSE-Compose rule on term: " << tp_rel
930
97
                          << " with explanation: " << exp << std::endl;
931
932
97
      computeMembersForUnaryOpRel( tp_rel );
933
97
      d_rel_nodes.insert( tp_rel );
934
    }
935
936
1004
    Node reason = exp;
937
1004
    Node reversed_mem = RelsUtils::reverseTuple( exp[0] );
938
939
502
    if( tp_rel != exp[1] ) {
940
57
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, tp_rel, exp[1]));
941
    }
942
502
    sendInfer(nm->mkNode(MEMBER, reversed_mem, tp_rel[0]),
943
              InferenceId::SETS_RELS_TRANSPOSE_REV,
944
              reason);
945
502
  }
946
947
432
  void TheorySetsRels::doTCInference() {
948
432
    Trace("rels-debug") << "[Theory::Rels] ****** Finalizing transitive closure inferences!" << std::endl;
949
432
    TC_IT tc_graph_it = d_tcr_tcGraph.begin();
950
598
    while( tc_graph_it != d_tcr_tcGraph.end() ) {
951
83
      Assert(d_tcr_tcGraph_exps.find(tc_graph_it->first)
952
             != d_tcr_tcGraph_exps.end());
953
83
      doTCInference( tc_graph_it->second, d_tcr_tcGraph_exps.find(tc_graph_it->first)->second, tc_graph_it->first );
954
83
      ++tc_graph_it;
955
    }
956
432
    Trace("rels-debug") << "[Theory::Rels] ****** Done with finalizing transitive closure inferences!" << std::endl;
957
432
  }
958
959
960
  // Bottom-up fashion to compute relations with more than 1 arity
961
681
  void TheorySetsRels::computeMembersForBinOpRel(Node rel) {
962
681
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForBinOpRel for relation  " << rel << std::endl;
963
964
681
    switch(rel[0].getKind()) {
965
106
      case kind::TRANSPOSE:
966
      case kind::TCLOSURE: {
967
106
        computeMembersForUnaryOpRel(rel[0]);
968
106
        break;
969
      }
970
100
      case kind::JOIN:
971
      case kind::PRODUCT: {
972
100
        computeMembersForBinOpRel(rel[0]);
973
100
        break;
974
      }
975
475
      default:
976
475
        break;
977
    }
978
681
    switch(rel[1].getKind()) {
979
      case kind::TRANSPOSE: {
980
        computeMembersForUnaryOpRel(rel[1]);
981
        break;
982
      }
983
10
      case kind::JOIN:
984
      case kind::PRODUCT: {
985
10
        computeMembersForBinOpRel(rel[1]);
986
10
        break;
987
      }
988
671
      default:
989
671
        break;
990
    }
991
1952
    if(d_rReps_memberReps_cache.find(getRepresentative(rel[0])) == d_rReps_memberReps_cache.end() ||
992
1271
       d_rReps_memberReps_cache.find(getRepresentative(rel[1])) == d_rReps_memberReps_cache.end()) {
993
131
      return;
994
    }
995
550
    composeMembersForRels(rel);
996
  }
997
998
  // Bottom-up fashion to compute unary relation
999
249
  void TheorySetsRels::computeMembersForUnaryOpRel(Node rel) {
1000
249
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForUnaryOpRel for relation  " << rel << std::endl;
1001
1002
249
    switch(rel[0].getKind()) {
1003
      case kind::TRANSPOSE:
1004
      case kind::TCLOSURE:
1005
        computeMembersForUnaryOpRel(rel[0]);
1006
        break;
1007
65
      case kind::JOIN:
1008
      case kind::PRODUCT:
1009
65
        computeMembersForBinOpRel(rel[0]);
1010
65
        break;
1011
184
      default:
1012
184
        break;
1013
    }
1014
1015
471
    Node rel0_rep  = getRepresentative(rel[0]);
1016
747
    if (d_rReps_memberReps_cache.find(rel0_rep)
1017
747
        == d_rReps_memberReps_cache.end())
1018
    {
1019
27
      return;
1020
    }
1021
222
    NodeManager* nm = NodeManager::currentNM();
1022
1023
444
    std::vector<Node>   members = d_rReps_memberReps_cache[rel0_rep];
1024
444
    std::vector<Node>   exps    = d_rReps_memberReps_exp_cache[rel0_rep];
1025
1026
222
    Assert(members.size() == exps.size());
1027
1028
2247
    for(unsigned int i = 0; i < members.size(); i++) {
1029
4050
      Node reason = exps[i];
1030
2025
      if( rel.getKind() == kind::TRANSPOSE) {
1031
2007
        if( rel[0] != exps[i][1] ) {
1032
69
          reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, rel[0], exps[i][1]));
1033
        }
1034
2007
        sendInfer(nm->mkNode(MEMBER, RelsUtils::reverseTuple(exps[i][0]), rel),
1035
                  InferenceId::SETS_RELS_TRANSPOSE_REV,
1036
                  reason);
1037
      }
1038
    }
1039
  }
1040
1041
  /*
1042
   * Explicitly compose the join or product relations of r1 and r2
1043
   * e.g. If (a, b) in X and (b, c) in Y, (a, c) in (X JOIN Y)
1044
   *
1045
   */
1046
550
  void TheorySetsRels::composeMembersForRels( Node rel ) {
1047
550
    Trace("rels-debug") << "[Theory::Rels] Start composing members for relation = " << rel << std::endl;
1048
1100
    Node r1 = rel[0];
1049
1100
    Node r2 = rel[1];
1050
1100
    Node r1_rep = getRepresentative( r1 );
1051
1100
    Node r2_rep = getRepresentative( r2 );
1052
1053
1650
    if(d_rReps_memberReps_cache.find( r1_rep ) == d_rReps_memberReps_cache.end() ||
1054
1100
       d_rReps_memberReps_cache.find( r2_rep ) == d_rReps_memberReps_cache.end() ) {
1055
      return;
1056
    }
1057
550
    NodeManager* nm = NodeManager::currentNM();
1058
1059
1100
    std::vector<Node> r1_rep_exps = d_rReps_memberReps_exp_cache[r1_rep];
1060
1100
    std::vector<Node> r2_rep_exps = d_rReps_memberReps_exp_cache[r2_rep];
1061
550
    unsigned int r1_tuple_len = r1.getType().getSetElementType().getTupleLength();
1062
550
    unsigned int r2_tuple_len = r2.getType().getSetElementType().getTupleLength();
1063
1064
2885
    for( unsigned int i = 0; i < r1_rep_exps.size(); i++ ) {
1065
95542
      for( unsigned int j = 0; j < r2_rep_exps.size(); j++ ) {
1066
186414
        std::vector<Node> tuple_elements;
1067
186414
        TypeNode tn = rel.getType().getSetElementType();
1068
186414
        Node r1_rmost = RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], r1_tuple_len-1 );
1069
186414
        Node r2_lmost = RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 );
1070
93207
        tuple_elements.push_back(tn.getDType()[0].getConstructor());
1071
1072
186414
        Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost
1073
93207
                            << " of type " << r1_rmost.getType() << std::endl;
1074
186414
        Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost
1075
93207
                            << " of type " << r2_lmost.getType() << std::endl;
1076
1077
186414
        if (rel.getKind() == kind::PRODUCT
1078
186414
            || (rel.getKind() == kind::JOIN && areEqual(r1_rmost, r2_lmost)))
1079
        {
1080
10076
          bool isProduct = rel.getKind() == kind::PRODUCT;
1081
10076
          unsigned int k = 0;
1082
10076
          unsigned int l = 1;
1083
1084
30076
          for( ; k < r1_tuple_len - 1; ++k ) {
1085
10000
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1086
          }
1087
10076
          if(isProduct) {
1088
237
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1089
237
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ) );
1090
          }
1091
30122
          for( ; l < r2_tuple_len; ++l ) {
1092
10023
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], l ) );
1093
          }
1094
1095
20152
          Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1096
20152
          Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, composed_tuple, rel);
1097
20152
          std::vector<Node> reasons;
1098
10076
          reasons.push_back( r1_rep_exps[i] );
1099
10076
          reasons.push_back( r2_rep_exps[j] );
1100
1101
10076
          if( r1 != r1_rep_exps[i][1] ) {
1102
35
            reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1, r1_rep_exps[i][1]) );
1103
          }
1104
10076
          if( r2 != r2_rep_exps[j][1] ) {
1105
16
            reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r2, r2_rep_exps[j][1]) );
1106
          }
1107
10076
          if( isProduct ) {
1108
237
            sendInfer(
1109
474
                fact, InferenceId::SETS_RELS_PRODUCE_COMPOSE, nm->mkNode(kind::AND, reasons));
1110
          } else {
1111
9839
            if( r1_rmost != r2_lmost ) {
1112
260
              reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1_rmost, r2_lmost) );
1113
            }
1114
9839
            sendInfer(
1115
19678
                fact, InferenceId::SETS_RELS_JOIN_COMPOSE, nm->mkNode(kind::AND, reasons));
1116
          }
1117
        }
1118
      }
1119
    }
1120
1121
  }
1122
1123
  void TheorySetsRels::processInference(Node conc, InferenceId id, Node exp)
1124
  {
1125
    Trace("sets-pinfer") << "Process inference: " << exp << " => " << conc
1126
                         << std::endl;
1127
    if (!d_state.isEntailed(exp, true))
1128
    {
1129
      Trace("sets-pinfer") << "  must assert as lemma" << std::endl;
1130
      // we wrap the spurious explanation into a splitting lemma
1131
      Node lem = NodeManager::currentNM()->mkNode(OR, exp.negate(), conc);
1132
      d_im.assertInference(lem, id, d_trueNode, 1);
1133
      return;
1134
    }
1135
    // try to assert it as a fact
1136
    d_im.assertInference(conc, id, exp);
1137
  }
1138
1139
252024
  bool TheorySetsRels::isRelationKind( Kind k ) {
1140
251820
    return k == TRANSPOSE || k == PRODUCT || k == JOIN || k == TCLOSURE
1141
503075
           || k == IDEN || k == JOIN_IMAGE;
1142
  }
1143
1144
24894
  Node TheorySetsRels::getRepresentative( Node t ) {
1145
24894
    return d_state.getRepresentative(t);
1146
  }
1147
1148
305504
  bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); }
1149
163162
  bool TheorySetsRels::areEqual( Node a, Node b ){
1150
163162
    Assert(a.getType() == b.getType());
1151
163162
    Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
1152
163162
    if(a == b) {
1153
10410
      return true;
1154
152752
    } else if( hasTerm( a ) && hasTerm( b ) ){
1155
152752
      return d_state.areEqual(a, b);
1156
    } else if(a.getType().isTuple()) {
1157
      bool equal = true;
1158
      for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) {
1159
        equal = equal && areEqual(RelsUtils::nthElementOfTuple(a, i), RelsUtils::nthElementOfTuple(b, i));
1160
      }
1161
      return equal;
1162
    } else if(!a.getType().isBoolean()){
1163
      // TODO(project##230): Find a safe type for the singleton operator
1164
      makeSharedTerm(a, a.getType());
1165
      makeSharedTerm(b, b.getType());
1166
    }
1167
    return false;
1168
  }
1169
1170
  /*
1171
   * Make sure duplicate members are not added in map
1172
   */
1173
5352
  bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
1174
5352
    std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep);
1175
5352
    if(mem_it == map.end()) {
1176
3328
      std::vector<Node> members;
1177
1664
      members.push_back(member);
1178
1664
      map[rel_rep] = members;
1179
1664
      return true;
1180
    } else {
1181
3688
      std::vector<Node>::iterator mems = mem_it->second.begin();
1182
142016
      while(mems != mem_it->second.end()) {
1183
69919
        if(areEqual(*mems, member)) {
1184
755
          return false;
1185
        }
1186
69164
        ++mems;
1187
      }
1188
2933
      map[rel_rep].push_back(member);
1189
2933
      return true;
1190
    }
1191
    return false;
1192
  }
1193
1194
3167
  void TheorySetsRels::makeSharedTerm(Node n, TypeNode t)
1195
  {
1196
3167
    if (d_shared_terms.find(n) != d_shared_terms.end())
1197
    {
1198
2818
      return;
1199
    }
1200
349
    Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl;
1201
    // force a proxy lemma to be sent for the singleton containing n
1202
698
    Node ss = NodeManager::currentNM()->mkSingleton(t, n);
1203
349
    d_treg.getProxy(ss);
1204
349
    d_shared_terms.insert(n);
1205
  }
1206
1207
  /*
1208
   * For each tuple n, we store a mapping between n and a list of its elements representatives
1209
   * in d_tuple_reps. This would later be used for applying JOIN operator.
1210
   */
1211
5989
  void TheorySetsRels::computeTupleReps( Node n ) {
1212
5989
    if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){
1213
11350
      for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){
1214
7616
        d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) );
1215
      }
1216
    }
1217
5989
  }
1218
1219
  /*
1220
   * Node n[0] is a tuple variable, reduce n[0] to a concrete representation,
1221
   * which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0].
1222
   */
1223
475
  void TheorySetsRels::reduceTupleVar(Node n) {
1224
475
    if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) {
1225
101
      Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl;
1226
202
      std::vector<Node> tuple_elements;
1227
101
      tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor());
1228
202
      std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes();
1229
313
      for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++)
1230
      {
1231
424
        Node element = RelsUtils::nthElementOfTuple(n[0], i);
1232
212
        makeSharedTerm(element, tupleTypes[i]);
1233
212
        tuple_elements.push_back(element);
1234
      }
1235
202
      Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1236
101
      tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]);
1237
202
      Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::EQUAL, n, tuple_reduct);
1238
101
      sendInfer(tuple_reduction_lemma, InferenceId::SETS_RELS_TUPLE_REDUCTION, d_trueNode);
1239
101
      d_symbolic_tuples.insert(n);
1240
    }
1241
475
  }
1242
1243
1230
  std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) {
1244
2460
    std::vector<Node>                           nodes;
1245
1230
    std::map< Node, TupleTrie >::iterator       it;
1246
1247
1230
    if( argIndex==(int)reps.size()-1 ){
1248
607
      if(reps[argIndex].getKind() == kind::SKOLEM) {
1249
529
        it = d_data.begin();
1250
5673
        while(it != d_data.end()) {
1251
2572
          nodes.push_back(it->first);
1252
2572
          ++it;
1253
        }
1254
      }
1255
607
      return nodes;
1256
    }else{
1257
623
      it = d_data.find( reps[argIndex] );
1258
623
      if( it==d_data.end() ){
1259
28
        return nodes;
1260
      }else{
1261
595
        return it->second.findTerms( reps, argIndex+1 );
1262
      }
1263
    }
1264
  }
1265
1266
221
  std::vector<Node> TupleTrie::findSuccessors( std::vector< Node >& reps, int argIndex ) {
1267
442
    std::vector<Node>   nodes;
1268
221
    std::map< Node, TupleTrie >::iterator it;
1269
1270
221
    if( argIndex==(int)reps.size() ){
1271
99
      it = d_data.begin();
1272
451
      while(it != d_data.end()) {
1273
176
        nodes.push_back(it->first);
1274
176
        ++it;
1275
      }
1276
99
      return nodes;
1277
    }else{
1278
122
      it = d_data.find( reps[argIndex] );
1279
122
      if( it==d_data.end() ){
1280
23
        return nodes;
1281
      }else{
1282
99
        return it->second.findSuccessors( reps, argIndex+1 );
1283
      }
1284
    }
1285
  }
1286
1287
1702
  Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) {
1288
1702
    if( argIndex==(int)reps.size() ){
1289
511
      if( d_data.empty() ){
1290
        return Node::null();
1291
      }else{
1292
511
        return d_data.begin()->first;
1293
      }
1294
    }else{
1295
1191
      std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] );
1296
1191
      if( it==d_data.end() ){
1297
91
        return Node::null();
1298
      }else{
1299
1100
        return it->second.existsTerm( reps, argIndex+1 );
1300
      }
1301
    }
1302
  }
1303
1304
13852
  bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){
1305
13852
    if( argIndex==(int)reps.size() ){
1306
4597
      if( d_data.empty() ){
1307
        //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
1308
4597
        d_data[n].clear();
1309
4597
        return true;
1310
      }else{
1311
        return false;
1312
      }
1313
    }else{
1314
9255
      return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
1315
    }
1316
  }
1317
1318
  void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) {
1319
    for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
1320
      for( unsigned i=0; i<depth; i++ ){ Debug(c) << "  "; }
1321
      Debug(c) << it->first << std::endl;
1322
      it->second.debugPrint( c, n, depth+1 );
1323
    }
1324
  }
1325
1326
13617
  void TheorySetsRels::sendInfer(Node fact, InferenceId id, Node reason)
1327
  {
1328
27234
    Trace("rels-lemma") << "Rels::lemma " << fact << " from " << reason
1329
13617
                        << " by " << id << std::endl;
1330
27234
    Node lemma = NodeManager::currentNM()->mkNode(IMPLIES, reason, fact);
1331
13617
    d_im.addPendingLemma(lemma, id);
1332
13617
  }
1333
}
1334
}
1335
22746
}  // namespace cvc5