GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_rels.cpp Lines: 740 782 94.6 %
Date: 2021-09-15 Branches: 1669 3247 51.4 %

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
9942
TheorySetsRels::TheorySetsRels(Env& env,
38
                               SolverState& s,
39
                               InferenceManager& im,
40
                               SkolemCache& skc,
41
9942
                               TermRegistry& treg)
42
    : EnvObj(env),
43
      d_state(s),
44
      d_im(im),
45
      d_skCache(skc),
46
      d_treg(treg),
47
9942
      d_shared_terms(userContext())
48
{
49
9942
  d_trueNode = NodeManager::currentNM()->mkConst(true);
50
9942
  d_falseNode = NodeManager::currentNM()->mkConst(false);
51
9942
}
52
53
19878
TheorySetsRels::~TheorySetsRels() {}
54
55
769
void TheorySetsRels::check(Theory::Effort level)
56
{
57
1538
  Trace("rels") << "\n[sets-rels] ******************************* Start the "
58
769
                   "relational solver, effort = "
59
769
                << level << " *******************************\n"
60
769
                << std::endl;
61
769
  if (Theory::fullEffort(level))
62
  {
63
769
    collectRelsInfo();
64
769
    check();
65
769
    d_im.doPendingLemmas();
66
  }
67
769
  Assert(!d_im.hasPendingLemma());
68
1538
  Trace("rels") << "\n[sets-rels] ******************************* Done with "
69
769
                   "the relational solver *******************************\n"
70
769
                << std::endl;
71
769
}
72
73
769
  void TheorySetsRels::check() {
74
769
    MEM_IT m_it = d_rReps_memberReps_cache.begin();
75
76
6329
    while(m_it != d_rReps_memberReps_cache.end()) {
77
5560
      Node rel_rep = m_it->first;
78
79
12070
      for(unsigned int i = 0; i < m_it->second.size(); i++) {
80
18580
        Node    mem     = d_rReps_memberReps_cache[rel_rep][i];
81
18580
        Node    exp     = d_rReps_memberReps_exp_cache[rel_rep][i];
82
        std::map<kind::Kind_t, std::vector<Node> >& kind_terms =
83
9290
            d_terms_cache[rel_rep];
84
85
9290
        if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) {
86
1337
          std::vector<Node>& tp_terms = kind_terms[TRANSPOSE];
87
1337
          if( tp_terms.size() > 0 ) {
88
1337
            applyTransposeRule( tp_terms );
89
1337
            applyTransposeRule( tp_terms[0], rel_rep, exp );
90
          }
91
        }
92
9290
        if( kind_terms.find(kind::JOIN) != kind_terms.end() ) {
93
1242
          std::vector<Node>& join_terms = kind_terms[JOIN];
94
2740
          for( unsigned int j = 0; j < join_terms.size(); j++ ) {
95
1498
            applyJoinRule( join_terms[j], rel_rep, exp );
96
          }
97
        }
98
9290
        if( kind_terms.find(kind::PRODUCT) != kind_terms.end() ) {
99
169
          std::vector<Node>& product_terms = kind_terms[PRODUCT];
100
338
          for( unsigned int j = 0; j < product_terms.size(); j++ ) {
101
169
            applyProductRule( product_terms[j], rel_rep, exp );
102
          }
103
        }
104
9290
        if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) {
105
266
          std::vector<Node>& tc_terms = kind_terms[TCLOSURE];
106
532
          for( unsigned int j = 0; j < tc_terms.size(); j++ ) {
107
266
            applyTCRule( mem, tc_terms[j], rel_rep, exp );
108
          }
109
        }
110
9290
        if( kind_terms.find(kind::JOIN_IMAGE) != kind_terms.end() ) {
111
139
          std::vector<Node>& join_image_terms = kind_terms[JOIN_IMAGE];
112
278
          for( unsigned int j = 0; j < join_image_terms.size(); j++ ) {
113
139
            applyJoinImageRule( mem, join_image_terms[j], exp );
114
          }
115
        }
116
9290
        if( kind_terms.find(kind::IDEN) != kind_terms.end() ) {
117
23
          std::vector<Node>& iden_terms = kind_terms[IDEN];
118
46
          for( unsigned int j = 0; j < iden_terms.size(); j++ ) {
119
23
            applyIdenRule( mem, iden_terms[j], exp );
120
          }
121
        }
122
      }
123
2780
      ++m_it;
124
    }
125
126
769
    TERM_IT t_it = d_terms_cache.begin();
127
7695
    while( t_it != d_terms_cache.end() ) {
128
3463
      if( d_rReps_memberReps_cache.find(t_it->first) == d_rReps_memberReps_cache.end() ) {
129
683
        Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl;
130
683
        KIND_TERM_IT k_t_it = t_it->second.begin();
131
132
2049
        while( k_t_it != t_it->second.end() ) {
133
683
          if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) {
134
477
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
135
1447
            while(term_it != k_t_it->second.end()) {
136
485
              computeMembersForBinOpRel( *term_it );
137
485
              ++term_it;
138
            }
139
206
          } else if( k_t_it->first == kind::TRANSPOSE ) {
140
171
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
141
513
            while( term_it != k_t_it->second.end() ) {
142
171
              computeMembersForUnaryOpRel( *term_it );
143
171
              ++term_it;
144
            }
145
35
          } else if ( k_t_it->first == kind::TCLOSURE ) {
146
25
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
147
75
            while( term_it != k_t_it->second.end() ) {
148
25
              buildTCGraphForRel( *term_it );
149
25
              ++term_it;
150
            }
151
10
          } else if( k_t_it->first == kind::JOIN_IMAGE ) {
152
2
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
153
6
            while( term_it != k_t_it->second.end() ) {
154
2
              computeMembersForJoinImageTerm( *term_it );
155
2
              ++term_it;
156
            }
157
8
          } else if( k_t_it->first == kind::IDEN ) {
158
8
            std::vector<Node>::iterator term_it = k_t_it->second.begin();
159
24
            while( term_it != k_t_it->second.end() ) {
160
8
              computeMembersForIdenTerm( *term_it );
161
8
              ++term_it;
162
            }
163
          }
164
683
          ++k_t_it;
165
        }
166
      }
167
3463
      ++t_it;
168
    }
169
769
    doTCInference();
170
171
    // clean up
172
769
    d_tuple_reps.clear();
173
769
    d_rReps_memberReps_exp_cache.clear();
174
769
    d_terms_cache.clear();
175
769
    d_membership_trie.clear();
176
769
    d_rel_nodes.clear();
177
769
    d_rReps_memberReps_cache.clear();
178
769
    d_rRep_tcGraph.clear();
179
769
    d_tcr_tcGraph_exps.clear();
180
769
    d_tcr_tcGraph.clear();
181
769
  }
182
183
  /*
184
   * Populate relational terms data structure
185
   */
186
187
769
  void TheorySetsRels::collectRelsInfo() {
188
769
    Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
189
769
    eq::EqualityEngine* ee = d_state.getEqualityEngine();
190
769
    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
191
45429
    while( !eqcs_i.isFinished() ){
192
44660
      Node                      eqc_rep  = (*eqcs_i);
193
22330
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee);
194
195
44660
      TypeNode erType = eqc_rep.getType();
196
22330
      Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl;
197
198
138658
      while( !eqc_i.isFinished() ){
199
116328
        Node eqc_node = (*eqc_i);
200
201
58164
        Trace("rels-ee") << "  term : " << eqc_node << std::endl;
202
203
58164
        if (erType.isBoolean() && eqc_rep.isConst())
204
        {
205
          // collect membership info
206
24080
          if( eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) {
207
28168
            Node tup_rep = getRepresentative( eqc_node[0] );
208
28168
            Node rel_rep = getRepresentative( eqc_node[1] );
209
210
14084
            if( eqc_node[0].isVar() ){
211
1882
              reduceTupleVar( eqc_node );
212
            }
213
214
14084
            bool is_true_eq = eqc_rep.getConst<bool>();
215
28168
            Node reason        = is_true_eq ? eqc_node : eqc_node.negate();
216
217
14084
            if( is_true_eq ) {
218
12949
              if( safelyAddToMap(d_rReps_memberReps_cache, rel_rep, tup_rep) ) {
219
9290
                d_rReps_memberReps_exp_cache[rel_rep].push_back(reason);
220
9290
                computeTupleReps(tup_rep);
221
9290
                d_membership_trie[rel_rep].addTerm(tup_rep, d_tuple_reps[tup_rep]);
222
              }
223
            }
224
          }
225
        // collect relational terms info
226
        }
227
34084
        else if (erType.isSet() && erType.getSetElementType().isTuple())
228
        {
229
16938
          if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN ||
230
9936
              eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE ||
231
10951
              eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) {
232
3036
            std::vector<Node> terms;
233
3036
            std::map< kind::Kind_t, std::vector<Node> >  rel_terms;
234
1518
            TERM_IT terms_it = d_terms_cache.find(eqc_rep);
235
236
1518
            if( terms_it == d_terms_cache.end() ) {
237
1400
              terms.push_back(eqc_node);
238
1400
              rel_terms[eqc_node.getKind()]      = terms;
239
1400
              d_terms_cache[eqc_rep]             = rel_terms;
240
            } else {
241
118
              KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind());
242
243
118
              if( kind_term_it == terms_it->second.end() ) {
244
38
                terms.push_back(eqc_node);
245
38
                d_terms_cache[eqc_rep][eqc_node.getKind()] = terms;
246
              } else {
247
80
                kind_term_it->second.push_back(eqc_node);
248
              }
249
            }
250
          }
251
        // need to add all tuple elements as shared terms
252
        }
253
29456
        else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar())
254
        {
255
11792
          std::vector<TypeNode> tupleTypes = erType.getTupleTypes();
256
17813
          for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++)
257
          {
258
23834
            Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
259
11917
            if (!element.isConst())
260
            {
261
10557
              makeSharedTerm(element, tupleTypes[i]);
262
            }
263
          }
264
        }
265
58164
        ++eqc_i;
266
      }
267
22330
      ++eqcs_i;
268
    }
269
769
    Trace("rels-debug") << "[Theory::Rels] Done with collecting relational terms!" << std::endl;
270
769
  }
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
71
  void TheorySetsRels::computeMembersForJoinImageTerm( Node join_image_term ) {
279
71
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for JoinImage Term = " << join_image_term << std::endl;
280
71
    MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( getRepresentative( join_image_term[0] ) );
281
282
71
    if( rel_mem_it == d_rReps_memberReps_cache.end() ) {
283
      return;
284
    }
285
71
    NodeManager* nm = NodeManager::currentNM();
286
287
142
    Node join_image_rel = join_image_term[0];
288
142
    std::unordered_set<Node> hasChecked;
289
142
    Node join_image_rel_rep = getRepresentative( join_image_rel );
290
71
    std::vector< Node >::iterator mem_rep_it = (*rel_mem_it).second.begin();
291
71
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( join_image_rel_rep );
292
71
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
293
71
    unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt();
294
295
721
    while( mem_rep_it != (*rel_mem_it).second.end() ) {
296
431
      Node fst_mem_rep = RelsUtils::nthElementOfTuple( *mem_rep_it, 0 );
297
298
430
      if( hasChecked.find( fst_mem_rep ) != hasChecked.end() ) {
299
105
        ++mem_rep_it;
300
105
        ++mem_rep_exp_it;
301
105
        continue;
302
      }
303
220
      hasChecked.insert( fst_mem_rep );
304
305
      const DType& dt =
306
220
          join_image_term.getType().getSetElementType().getDType();
307
      Node new_membership = nm->mkNode(
308
          MEMBER,
309
440
          nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem_rep),
310
766
          join_image_term);
311
334
      if (d_state.isEntailed(new_membership, true))
312
      {
313
114
        ++mem_rep_it;
314
114
        ++mem_rep_exp_it;
315
114
        continue;
316
      }
317
318
212
      std::vector< Node > reasons;
319
212
      std::vector< Node > existing_members;
320
106
      std::vector< Node >::iterator mem_rep_exp_it_snd = (*rel_mem_exp_it).second.begin();
321
322
818
      while( mem_rep_exp_it_snd != (*rel_mem_exp_it).second.end() ) {
323
750
        Node fst_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 0 );
324
325
394
        if( areEqual( fst_mem_rep,  fst_element_snd_mem ) ) {
326
118
          bool notExist = true;
327
118
          std::vector< Node >::iterator existing_mem_it = existing_members.begin();
328
198
          Node snd_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 1 );
329
330
160
          while( existing_mem_it != existing_members.end() ) {
331
21
            if( areEqual( (*existing_mem_it), snd_element_snd_mem ) ) {
332
              notExist = false;
333
              break;
334
            }
335
21
            ++existing_mem_it;
336
          }
337
338
118
          if( notExist ) {
339
118
            existing_members.push_back( snd_element_snd_mem );
340
118
            reasons.push_back( *mem_rep_exp_it_snd );
341
118
            if( fst_mem_rep != fst_element_snd_mem ) {
342
6
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, fst_mem_rep, fst_element_snd_mem ) );
343
            }
344
118
            if( join_image_rel != (*mem_rep_exp_it_snd)[1] ) {
345
70
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it_snd)[1], join_image_rel ));
346
            }
347
118
            if( existing_members.size() == min_card ) {
348
38
              if( min_card >= 2) {
349
16
                new_membership = NodeManager::currentNM()->mkNode( kind::OR, new_membership, NodeManager::currentNM()->mkNode( kind::NOT, NodeManager::currentNM()->mkNode( kind::DISTINCT, existing_members ) ));
350
              }
351
38
              Assert(reasons.size() >= 1);
352
38
              sendInfer(
353
                  new_membership,
354
                  InferenceId::SETS_RELS_JOIN_IMAGE_UP,
355
76
                  reasons.size() > 1 ? nm->mkNode(AND, reasons) : reasons[0]);
356
38
              break;
357
            }
358
          }
359
        }
360
356
        ++mem_rep_exp_it_snd;
361
      }
362
106
      ++mem_rep_it;
363
106
      ++mem_rep_exp_it;
364
    }
365
71
    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
139
  void TheorySetsRels::applyJoinImageRule( Node mem_rep, Node join_image_term, Node exp ) {
375
278
    Trace("rels-debug") << "\n[Theory::Rels] *********** applyJoinImageRule on " << join_image_term
376
139
                        << " with mem_rep = " << mem_rep  << " and exp = " << exp << std::endl;
377
139
    if( d_rel_nodes.find( join_image_term ) == d_rel_nodes.end() ) {
378
69
      computeMembersForJoinImageTerm( join_image_term );
379
69
      d_rel_nodes.insert( join_image_term );
380
    }
381
382
176
    Node join_image_rel = join_image_term[0];
383
176
    Node join_image_rel_rep = getRepresentative( join_image_rel );
384
139
    MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( join_image_rel_rep );
385
139
    unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt();
386
387
139
    if( rel_mem_it != d_rReps_memberReps_cache.end() ) {
388
139
      if( d_membership_trie.find( join_image_rel_rep ) != d_membership_trie.end() ) {
389
139
        computeTupleReps( mem_rep );
390
139
        if( d_membership_trie[join_image_rel_rep].findSuccessors(d_tuple_reps[mem_rep]).size() >= min_card ) {
391
102
          return;
392
        }
393
      }
394
    }
395
37
    NodeManager* nm = NodeManager::currentNM();
396
37
    SkolemManager* sm = nm->getSkolemManager();
397
74
    Node reason = exp;
398
74
    Node conclusion = d_trueNode;
399
74
    std::vector< Node > distinct_skolems;
400
74
    Node fst_mem_element = RelsUtils::nthElementOfTuple( exp[0], 0 );
401
402
37
    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
108
    for( unsigned int i = 0; i < min_card; i++ ) {
407
      Node skolem = sm->mkDummySkolem(
408
142
          "jig", join_image_rel.getType()[0].getTupleTypes()[0]);
409
71
      distinct_skolems.push_back( skolem );
410
71
      conclusion = nm->mkNode(
411
          AND,
412
          conclusion,
413
284
          nm->mkNode(
414
              MEMBER,
415
142
              RelsUtils::constructPair(join_image_rel, fst_mem_element, skolem),
416
              join_image_rel));
417
    }
418
37
    if( distinct_skolems.size() >= 2 ) {
419
31
      conclusion =
420
62
          nm->mkNode(AND, conclusion, nm->mkNode(DISTINCT, distinct_skolems));
421
    }
422
37
    sendInfer(conclusion, InferenceId::SETS_RELS_JOIN_IMAGE_DOWN, reason);
423
37
    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
23
  void TheorySetsRels::applyIdenRule( Node mem_rep, Node iden_term, Node exp) {
433
46
    Trace("rels-debug") << "\n[Theory::Rels] *********** applyIdenRule on " << iden_term
434
23
                        << " with mem_rep = " << mem_rep  << " and exp = " << exp << std::endl;
435
23
    NodeManager* nm = NodeManager::currentNM();
436
23
    if( d_rel_nodes.find( iden_term ) == d_rel_nodes.end() ) {
437
8
      computeMembersForIdenTerm( iden_term );
438
8
      d_rel_nodes.insert( iden_term );
439
    }
440
46
    Node reason = exp;
441
46
    Node fst_mem = RelsUtils::nthElementOfTuple( exp[0], 0 );
442
46
    Node snd_mem = RelsUtils::nthElementOfTuple( exp[0], 1 );
443
23
    const DType& dt = iden_term[0].getType().getSetElementType().getDType();
444
    Node fact = nm->mkNode(
445
        MEMBER,
446
46
        nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem),
447
92
        iden_term[0]);
448
449
23
    if( exp[1] != iden_term ) {
450
7
      reason = NodeManager::currentNM()->mkNode( kind::AND, reason, NodeManager::currentNM()->mkNode( kind::EQUAL, exp[1], iden_term ) );
451
    }
452
23
    sendInfer(nm->mkNode(AND, fact, nm->mkNode(EQUAL, fst_mem, snd_mem)),
453
              InferenceId::SETS_RELS_IDENTITY_DOWN,
454
              reason);
455
23
    Trace("rels-debug") << "\n[Theory::Rels] *********** Done with applyIdenRule on " << iden_term << std::endl;
456
23
  }
457
458
  /* IDEN UP  : (x) IS_IN R        IDEN(R) IN T
459
  *             --------------------------------
460
  *                   (x, x) IS_IN IDEN(R)
461
  *
462
  */
463
464
16
  void TheorySetsRels::computeMembersForIdenTerm( Node iden_term ) {
465
16
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for Iden Term = " << iden_term << std::endl;
466
26
    Node iden_term_rel = iden_term[0];
467
26
    Node iden_term_rel_rep = getRepresentative( iden_term_rel );
468
469
16
    if( d_rReps_memberReps_cache.find( iden_term_rel_rep ) == d_rReps_memberReps_cache.end() ) {
470
6
      return;
471
    }
472
10
    NodeManager* nm = NodeManager::currentNM();
473
474
10
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( iden_term_rel_rep );
475
10
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
476
477
72
    while( mem_rep_exp_it != (*rel_mem_exp_it).second.end() ) {
478
62
      Node reason = *mem_rep_exp_it;
479
62
      Node fst_exp_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it)[0], 0 );
480
62
      Node new_mem = RelsUtils::constructPair( iden_term, fst_exp_mem, fst_exp_mem );
481
482
31
      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
93
      sendInfer(
486
62
          nm->mkNode(MEMBER, new_mem, iden_term), InferenceId::SETS_RELS_IDENTITY_UP, reason);
487
31
      ++mem_rep_exp_it;
488
    }
489
10
    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
266
  void TheorySetsRels::applyTCRule( Node mem_rep, Node tc_rel, Node tc_rel_rep, Node exp ) {
512
532
    Trace("rels-debug") << "[Theory::Rels] *********** Applying TCLOSURE rule on a tc term = " << tc_rel
513
266
                            << ", its representative = " << tc_rel_rep
514
266
                            << " with member rep = " << mem_rep << " and explanation = " << exp << std::endl;
515
266
    MEM_IT mem_it = d_rReps_memberReps_cache.find( tc_rel[0] );
516
517
790
    if( mem_it != d_rReps_memberReps_cache.end() && d_rel_nodes.find( tc_rel ) == d_rel_nodes.end()
518
625
        && d_rRep_tcGraph.find( getRepresentative( tc_rel[0] ) ) ==  d_rRep_tcGraph.end() ) {
519
93
      buildTCGraphForRel( tc_rel );
520
93
      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
266
    if( isTCReachable( mem_rep, tc_rel) ) {
525
486
      Trace("rels-debug") << "[Theory::Rels] mem_rep is a member of tc_rel[0] = " << tc_rel[0]
526
243
                              << " or can be infered by TC_Graph of tc_rel[0]! " << std::endl;
527
243
      return;
528
    }
529
23
    NodeManager* nm = NodeManager::currentNM();
530
531
    // add mem_rep to d_tcrRep_tcGraph
532
23
    TC_IT tc_it = d_tcr_tcGraph.find( tc_rel );
533
46
    Node mem_rep_fst = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 0 ) );
534
46
    Node mem_rep_snd = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 1 ) );
535
46
    Node mem_rep_tup = RelsUtils::constructPair( tc_rel, mem_rep_fst, mem_rep_snd );
536
537
23
    if( tc_it != d_tcr_tcGraph.end() ) {
538
15
      std::map< Node, std::map< Node, Node > >::iterator tc_exp_it = d_tcr_tcGraph_exps.find( tc_rel );
539
540
15
      TC_GRAPH_IT tc_graph_it = (tc_it->second).find( mem_rep_fst );
541
15
      Assert(tc_exp_it != d_tcr_tcGraph_exps.end());
542
15
      std::map< Node, Node >::iterator exp_map_it = (tc_exp_it->second).find( mem_rep_tup );
543
544
15
      if( exp_map_it == (tc_exp_it->second).end() ) {
545
15
        (tc_exp_it->second)[mem_rep_tup] = exp;
546
      }
547
548
15
      if( tc_graph_it != (tc_it->second).end() ) {
549
8
        (tc_graph_it->second).insert( mem_rep_snd );
550
      } else {
551
14
        std::unordered_set<Node> sets;
552
7
        sets.insert( mem_rep_snd );
553
7
        (tc_it->second)[mem_rep_fst] = sets;
554
      }
555
    } else {
556
16
      std::map< Node, Node > exp_map;
557
16
      std::unordered_set<Node> sets;
558
16
      std::map<Node, std::unordered_set<Node> > element_map;
559
8
      sets.insert( mem_rep_snd );
560
8
      element_map[mem_rep_fst] = sets;
561
8
      d_tcr_tcGraph[tc_rel] = element_map;
562
8
      exp_map[mem_rep_tup] = exp;
563
8
      d_tcr_tcGraph_exps[tc_rel] = exp_map;
564
    }
565
46
    Node fst_element = RelsUtils::nthElementOfTuple( exp[0], 0 );
566
46
    Node snd_element = RelsUtils::nthElementOfTuple( exp[0], 1 );
567
69
    Node sk_1 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
568
                                              exp[0],
569
                                              tc_rel[0],
570
                                              SkolemCache::SK_TCLOSURE_DOWN1,
571
92
                                              "stc1");
572
69
    Node sk_2 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
573
                                              exp[0],
574
                                              tc_rel[0],
575
                                              SkolemCache::SK_TCLOSURE_DOWN2,
576
92
                                              "stc2");
577
46
    Node mem_of_r = nm->mkNode(MEMBER, exp[0], tc_rel[0]);
578
46
    Node sk_eq = nm->mkNode(EQUAL, sk_1, sk_2);
579
46
    Node reason   = exp;
580
581
23
    if( tc_rel != exp[1] ) {
582
3
      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
138
        nm->mkNode(
589
            AND,
590
92
            nm->mkNode(MEMBER,
591
46
                       RelsUtils::constructPair(tc_rel, fst_element, sk_1),
592
                       tc_rel[0]),
593
92
            nm->mkNode(MEMBER,
594
46
                       RelsUtils::constructPair(tc_rel, sk_2, snd_element),
595
                       tc_rel[0]),
596
46
            nm->mkNode(OR,
597
                       sk_eq,
598
92
                       nm->mkNode(MEMBER,
599
46
                                  RelsUtils::constructPair(tc_rel, sk_1, sk_2),
600
46
                                  tc_rel))));
601
602
23
    sendInfer(conc, InferenceId::SETS_RELS_TCLOSURE_UP, reason);
603
  }
604
605
266
  bool TheorySetsRels::isTCReachable( Node mem_rep, Node tc_rel ) {
606
266
    MEM_IT mem_it = d_rReps_memberReps_cache.find( getRepresentative( tc_rel[0] ) );
607
608
266
    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
154
      return true;
610
    }
611
612
112
    TC_IT tc_it = d_rRep_tcGraph.find( getRepresentative(tc_rel[0]) );
613
112
    if( tc_it != d_rRep_tcGraph.end() ) {
614
104
      bool isReachable = false;
615
208
      std::unordered_set<Node> seen;
616
208
      isTCReachable( getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 0) ),
617
312
                     getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 1) ), seen, tc_it->second, isReachable );
618
104
      return isReachable;
619
    }
620
8
    return false;
621
  }
622
623
220
  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
220
    if(hasSeen.find(start) == hasSeen.end()) {
631
220
      hasSeen.insert(start);
632
    }
633
634
220
    TC_GRAPH_IT pair_set_it = tc_graph.find(start);
635
636
220
    if(pair_set_it != tc_graph.end()) {
637
192
      if(pair_set_it->second.find(dest) != pair_set_it->second.end()) {
638
89
        isReachable = true;
639
178
        return;
640
      } else {
641
103
        std::unordered_set<Node>::iterator set_it = pair_set_it->second.begin();
642
643
335
        while( set_it != pair_set_it->second.end() ) {
644
          // need to check if *set_it has been looked already
645
116
          if( hasSeen.find(*set_it) == hasSeen.end() ) {
646
116
            isTCReachable( *set_it, dest, hasSeen, tc_graph, isReachable );
647
          }
648
116
          ++set_it;
649
        }
650
      }
651
    }
652
  }
653
654
118
  void TheorySetsRels::buildTCGraphForRel( Node tc_rel ) {
655
236
    std::map< Node, Node > rel_tc_graph_exps;
656
236
    std::map<Node, std::unordered_set<Node> > rel_tc_graph;
657
658
236
    Node rel_rep = getRepresentative( tc_rel[0] );
659
236
    Node tc_rel_rep = getRepresentative( tc_rel );
660
236
    std::vector< Node > members = d_rReps_memberReps_cache[rel_rep];
661
236
    std::vector< Node > exps = d_rReps_memberReps_exp_cache[rel_rep];
662
663
355
    for( unsigned int i = 0; i < members.size(); i++ ) {
664
474
      Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 ));
665
474
      Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 ));
666
474
      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
237
          rel_tc_graph.find(fst_element_rep);
669
670
237
      if( rel_tc_graph_it == rel_tc_graph.end() ) {
671
400
        std::unordered_set<Node> snd_elements;
672
200
        snd_elements.insert( snd_element_rep );
673
200
        rel_tc_graph[fst_element_rep] = snd_elements;
674
200
        rel_tc_graph_exps[tuple_rep] = exps[i];
675
37
      } else if( (rel_tc_graph_it->second).find( snd_element_rep ) ==  (rel_tc_graph_it->second).end() ) {
676
37
        (rel_tc_graph_it->second).insert( snd_element_rep );
677
37
        rel_tc_graph_exps[tuple_rep] = exps[i];
678
      }
679
    }
680
681
118
    if( members.size() > 0 ) {
682
105
      d_rRep_tcGraph[rel_rep] = rel_tc_graph;
683
105
      d_tcr_tcGraph_exps[tc_rel] = rel_tc_graph_exps;
684
105
      d_tcr_tcGraph[tc_rel] = rel_tc_graph;
685
    }
686
118
  }
687
688
113
  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
113
    Trace("rels-debug") << "[Theory::Rels] ****** doTCInference !" << std::endl;
694
328
    for (TC_GRAPH_IT tc_graph_it = rel_tc_graph.begin();
695
328
         tc_graph_it != rel_tc_graph.end();
696
         ++tc_graph_it)
697
    {
698
260
      for (std::unordered_set<Node>::iterator snd_elements_it =
699
215
               tc_graph_it->second.begin();
700
475
           snd_elements_it != tc_graph_it->second.end();
701
           ++snd_elements_it)
702
      {
703
520
        std::vector< Node > reasons;
704
520
        std::unordered_set<Node> seen;
705
520
        Node tuple = RelsUtils::constructPair( tc_rel, getRepresentative( tc_graph_it->first ), getRepresentative( *snd_elements_it) );
706
260
        Assert(rel_tc_graph_exps.find(tuple) != rel_tc_graph_exps.end());
707
520
        Node exp   = rel_tc_graph_exps.find( tuple )->second;
708
709
260
        reasons.push_back( exp );
710
260
        seen.insert( tc_graph_it->first );
711
260
        doTCInference( tc_rel, reasons, rel_tc_graph, rel_tc_graph_exps, tc_graph_it->first, *snd_elements_it, seen);
712
      }
713
    }
714
113
    Trace("rels-debug") << "[Theory::Rels] ****** Done with doTCInference !" << std::endl;
715
113
  }
716
717
491
  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
491
    NodeManager* nm = NodeManager::currentNM();
727
888
    Node tc_mem = RelsUtils::constructPair( tc_rel, RelsUtils::nthElementOfTuple((reasons.front())[0], 0), RelsUtils::nthElementOfTuple((reasons.back())[0], 1) );
728
888
    std::vector< Node > all_reasons( reasons );
729
730
814
    for( unsigned int i = 0 ; i < reasons.size()-1; i++ ) {
731
646
      Node fst_element_end = RelsUtils::nthElementOfTuple( reasons[i][0], 1 );
732
646
      Node snd_element_begin = RelsUtils::nthElementOfTuple( reasons[i+1][0], 0 );
733
323
      if( fst_element_end != snd_element_begin ) {
734
28
        all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, fst_element_end, snd_element_begin) );
735
      }
736
323
      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
491
    if( tc_rel != reasons.back()[1] && tc_rel[0] != reasons.back()[1] ) {
741
8
      all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons.back()[1]) );
742
    }
743
491
    if( all_reasons.size() > 1) {
744
234
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
745
                InferenceId::SETS_RELS_TCLOSURE_FWD,
746
468
                nm->mkNode(AND, all_reasons));
747
    } else {
748
257
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
749
                InferenceId::SETS_RELS_TCLOSURE_FWD,
750
257
                all_reasons.front());
751
    }
752
753
    // check if cur_node has been traversed or not
754
491
    if( seen.find( cur_node_rep ) != seen.end() ) {
755
94
      return;
756
    }
757
397
    seen.insert( cur_node_rep );
758
397
    TC_GRAPH_IT  cur_set = tc_graph.find( cur_node_rep );
759
397
    if( cur_set != tc_graph.end() ) {
760
388
      for (std::unordered_set<Node>::iterator set_it = cur_set->second.begin();
761
388
           set_it != cur_set->second.end();
762
           ++set_it)
763
      {
764
462
        Node new_pair = RelsUtils::constructPair( tc_rel, cur_node_rep, *set_it );
765
462
        std::vector< Node > new_reasons( reasons );
766
231
        new_reasons.push_back( rel_tc_graph_exps.find( new_pair )->second );
767
231
        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
169
  void TheorySetsRels::applyProductRule( Node pt_rel, Node pt_rel_rep, Node exp ) {
783
338
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying PRODUCT rule on producted term = " << pt_rel
784
169
                            << ", its representative = " << pt_rel_rep
785
169
                            << " with explanation = " << exp << std::endl;
786
787
169
    if(d_rel_nodes.find( pt_rel ) == d_rel_nodes.end()) {
788
114
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply PRODUCT-COMPOSE rule on term: " << pt_rel
789
57
                          << " with explanation: " << exp << std::endl;
790
791
57
      computeMembersForBinOpRel( pt_rel );
792
57
      d_rel_nodes.insert( pt_rel );
793
    }
794
795
338
    Node mem = exp[0];
796
338
    std::vector<Node>   r1_element;
797
338
    std::vector<Node>   r2_element;
798
169
    const DType& dt1 = pt_rel[0].getType().getSetElementType().getDType();
799
169
    unsigned int s1_len  = pt_rel[0].getType().getSetElementType().getTupleLength();
800
169
    unsigned int tup_len = pt_rel.getType().getSetElementType().getTupleLength();
801
802
169
    r1_element.push_back(dt1[0].getConstructor());
803
804
169
    unsigned int i = 0;
805
743
    for(; i < s1_len; ++i) {
806
287
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
807
    }
808
169
    const DType& dt2 = pt_rel[1].getType().getSetElementType().getDType();
809
169
    r2_element.push_back(dt2[0].getConstructor());
810
743
    for(; i < tup_len; ++i) {
811
287
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
812
    }
813
338
    Node reason   = exp;
814
338
    Node mem1     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
815
338
    Node mem2     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
816
338
    Node fact_1   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, pt_rel[0]);
817
338
    Node fact_2   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, pt_rel[1]);
818
819
169
    if( pt_rel != exp[1] ) {
820
12
      reason = NodeManager::currentNM()->mkNode(kind::AND, exp, NodeManager::currentNM()->mkNode(kind::EQUAL, pt_rel, exp[1]));
821
    }
822
169
    sendInfer(fact_1, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
823
169
    sendInfer(fact_2, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
824
169
  }
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
1498
  void TheorySetsRels::applyJoinRule( Node join_rel, Node join_rel_rep, Node exp ) {
837
2996
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying JOIN rule on joined term = " << join_rel
838
1498
                            << ", its representative = " << join_rel_rep
839
1498
                            << " with explanation = " << exp << std::endl;
840
1498
    if(d_rel_nodes.find( join_rel ) == d_rel_nodes.end()) {
841
802
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply JOIN-COMPOSE rule on term: " << join_rel
842
401
                          << " with explanation: " << exp << std::endl;
843
844
401
      computeMembersForBinOpRel( join_rel );
845
401
      d_rel_nodes.insert( join_rel );
846
    }
847
848
1751
    Node mem = exp[0];
849
1751
    std::vector<Node> r1_element;
850
1751
    std::vector<Node> r2_element;
851
1751
    Node r1_rep = getRepresentative(join_rel[0]);
852
1751
    Node r2_rep = getRepresentative(join_rel[1]);
853
1751
    TypeNode     shared_type    = r2_rep.getType().getSetElementType().getTupleTypes()[0];
854
1498
    Node shared_x = d_skCache.mkTypedSkolemCached(
855
1751
        shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj");
856
1498
    const DType& dt1 = join_rel[0].getType().getSetElementType().getDType();
857
1498
    unsigned int s1_len         = join_rel[0].getType().getSetElementType().getTupleLength();
858
1498
    unsigned int tup_len        = join_rel.getType().getSetElementType().getTupleLength();
859
860
1498
    unsigned int i = 0;
861
1498
    r1_element.push_back(dt1[0].getConstructor());
862
4446
    for(; i < s1_len-1; ++i) {
863
1474
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
864
    }
865
1498
    r1_element.push_back(shared_x);
866
1498
    const DType& dt2 = join_rel[1].getType().getSetElementType().getDType();
867
1498
    r2_element.push_back(dt2[0].getConstructor());
868
1498
    r2_element.push_back(shared_x);
869
4550
    for(; i < tup_len; ++i) {
870
1526
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
871
    }
872
1751
    Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
873
1751
    Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
874
875
1498
    computeTupleReps(mem1);
876
1498
    computeTupleReps(mem2);
877
878
1751
    std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[mem1]);
879
880
1715
    for(unsigned int j = 0; j < elements.size(); j++) {
881
1679
      std::vector<Node> new_tup;
882
1462
      new_tup.push_back(elements[j]);
883
1462
      new_tup.insert(new_tup.end(), d_tuple_reps[mem2].begin()+1, d_tuple_reps[mem2].end());
884
1462
      if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) {
885
1245
        return;
886
      }
887
    }
888
506
    Node reason = exp;
889
253
    if( join_rel != exp[1] ) {
890
129
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, join_rel, exp[1]));
891
    }
892
506
    Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, join_rel[0]);
893
253
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_1, reason);
894
253
    fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]);
895
253
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_2, reason);
896
253
    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
1337
  void TheorySetsRels::applyTransposeRule( std::vector<Node> tp_terms ) {
910
1337
    if( tp_terms.size() < 1) {
911
      return;
912
    }
913
1337
    NodeManager* nm = NodeManager::currentNM();
914
1337
    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
1337
  void TheorySetsRels::applyTransposeRule( Node tp_rel, Node tp_rel_rep, Node exp ) {
923
2674
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE rule on transposed term = " << tp_rel
924
1337
                        << ", its representative = " << tp_rel_rep
925
1337
                        << " with explanation = " << exp << std::endl;
926
1337
    NodeManager* nm = NodeManager::currentNM();
927
928
1337
    if(d_rel_nodes.find( tp_rel ) == d_rel_nodes.end()) {
929
382
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply TRANSPOSE-Compose rule on term: " << tp_rel
930
191
                          << " with explanation: " << exp << std::endl;
931
932
191
      computeMembersForUnaryOpRel( tp_rel );
933
191
      d_rel_nodes.insert( tp_rel );
934
    }
935
936
2674
    Node reason = exp;
937
2674
    Node reversed_mem = RelsUtils::reverseTuple( exp[0] );
938
939
1337
    if( tp_rel != exp[1] ) {
940
155
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, tp_rel, exp[1]));
941
    }
942
1337
    sendInfer(nm->mkNode(MEMBER, reversed_mem, tp_rel[0]),
943
              InferenceId::SETS_RELS_TRANSPOSE_REV,
944
              reason);
945
1337
  }
946
947
769
  void TheorySetsRels::doTCInference() {
948
769
    Trace("rels-debug") << "[Theory::Rels] ****** Finalizing transitive closure inferences!" << std::endl;
949
769
    TC_IT tc_graph_it = d_tcr_tcGraph.begin();
950
995
    while( tc_graph_it != d_tcr_tcGraph.end() ) {
951
113
      Assert(d_tcr_tcGraph_exps.find(tc_graph_it->first)
952
             != d_tcr_tcGraph_exps.end());
953
113
      doTCInference( tc_graph_it->second, d_tcr_tcGraph_exps.find(tc_graph_it->first)->second, tc_graph_it->first );
954
113
      ++tc_graph_it;
955
    }
956
769
    Trace("rels-debug") << "[Theory::Rels] ****** Done with finalizing transitive closure inferences!" << std::endl;
957
769
  }
958
959
960
  // Bottom-up fashion to compute relations with more than 1 arity
961
1289
  void TheorySetsRels::computeMembersForBinOpRel(Node rel) {
962
1289
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForBinOpRel for relation  " << rel << std::endl;
963
964
1289
    switch(rel[0].getKind()) {
965
220
      case kind::TRANSPOSE:
966
      case kind::TCLOSURE: {
967
220
        computeMembersForUnaryOpRel(rel[0]);
968
220
        break;
969
      }
970
210
      case kind::JOIN:
971
      case kind::PRODUCT: {
972
210
        computeMembersForBinOpRel(rel[0]);
973
210
        break;
974
      }
975
859
      default:
976
859
        break;
977
    }
978
1289
    switch(rel[1].getKind()) {
979
      case kind::TRANSPOSE: {
980
        computeMembersForUnaryOpRel(rel[1]);
981
        break;
982
      }
983
16
      case kind::JOIN:
984
      case kind::PRODUCT: {
985
16
        computeMembersForBinOpRel(rel[1]);
986
16
        break;
987
      }
988
1273
      default:
989
1273
        break;
990
    }
991
3669
    if(d_rReps_memberReps_cache.find(getRepresentative(rel[0])) == d_rReps_memberReps_cache.end() ||
992
2380
       d_rReps_memberReps_cache.find(getRepresentative(rel[1])) == d_rReps_memberReps_cache.end()) {
993
259
      return;
994
    }
995
1030
    composeMembersForRels(rel);
996
  }
997
998
  // Bottom-up fashion to compute unary relation
999
582
  void TheorySetsRels::computeMembersForUnaryOpRel(Node rel) {
1000
582
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForUnaryOpRel for relation  " << rel << std::endl;
1001
1002
582
    switch(rel[0].getKind()) {
1003
      case kind::TRANSPOSE:
1004
      case kind::TCLOSURE:
1005
        computeMembersForUnaryOpRel(rel[0]);
1006
        break;
1007
120
      case kind::JOIN:
1008
      case kind::PRODUCT:
1009
120
        computeMembersForBinOpRel(rel[0]);
1010
120
        break;
1011
462
      default:
1012
462
        break;
1013
    }
1014
1015
1067
    Node rel0_rep  = getRepresentative(rel[0]);
1016
1746
    if (d_rReps_memberReps_cache.find(rel0_rep)
1017
1746
        == d_rReps_memberReps_cache.end())
1018
    {
1019
97
      return;
1020
    }
1021
485
    NodeManager* nm = NodeManager::currentNM();
1022
1023
970
    std::vector<Node>   members = d_rReps_memberReps_cache[rel0_rep];
1024
970
    std::vector<Node>   exps    = d_rReps_memberReps_exp_cache[rel0_rep];
1025
1026
485
    Assert(members.size() == exps.size());
1027
1028
5777
    for(unsigned int i = 0; i < members.size(); i++) {
1029
10584
      Node reason = exps[i];
1030
5292
      if( rel.getKind() == kind::TRANSPOSE) {
1031
5269
        if( rel[0] != exps[i][1] ) {
1032
214
          reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, rel[0], exps[i][1]));
1033
        }
1034
5269
        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
1030
  void TheorySetsRels::composeMembersForRels( Node rel ) {
1047
1030
    Trace("rels-debug") << "[Theory::Rels] Start composing members for relation = " << rel << std::endl;
1048
2060
    Node r1 = rel[0];
1049
2060
    Node r2 = rel[1];
1050
2060
    Node r1_rep = getRepresentative( r1 );
1051
2060
    Node r2_rep = getRepresentative( r2 );
1052
1053
3090
    if(d_rReps_memberReps_cache.find( r1_rep ) == d_rReps_memberReps_cache.end() ||
1054
2060
       d_rReps_memberReps_cache.find( r2_rep ) == d_rReps_memberReps_cache.end() ) {
1055
      return;
1056
    }
1057
1030
    NodeManager* nm = NodeManager::currentNM();
1058
1059
2060
    std::vector<Node> r1_rep_exps = d_rReps_memberReps_exp_cache[r1_rep];
1060
2060
    std::vector<Node> r2_rep_exps = d_rReps_memberReps_exp_cache[r2_rep];
1061
1030
    unsigned int r1_tuple_len = r1.getType().getSetElementType().getTupleLength();
1062
1030
    unsigned int r2_tuple_len = r2.getType().getSetElementType().getTupleLength();
1063
1064
6414
    for( unsigned int i = 0; i < r1_rep_exps.size(); i++ ) {
1065
252085
      for( unsigned int j = 0; j < r2_rep_exps.size(); j++ ) {
1066
493402
        std::vector<Node> tuple_elements;
1067
493402
        TypeNode tn = rel.getType().getSetElementType();
1068
493402
        Node r1_rmost = RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], r1_tuple_len-1 );
1069
493402
        Node r2_lmost = RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 );
1070
246701
        tuple_elements.push_back(tn.getDType()[0].getConstructor());
1071
1072
493402
        Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost
1073
246701
                            << " of type " << r1_rmost.getType() << std::endl;
1074
493402
        Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost
1075
246701
                            << " of type " << r2_lmost.getType() << std::endl;
1076
1077
493402
        if (rel.getKind() == kind::PRODUCT
1078
493402
            || (rel.getKind() == kind::JOIN && areEqual(r1_rmost, r2_lmost)))
1079
        {
1080
26097
          bool isProduct = rel.getKind() == kind::PRODUCT;
1081
26097
          unsigned int k = 0;
1082
26097
          unsigned int l = 1;
1083
1084
78137
          for( ; k < r1_tuple_len - 1; ++k ) {
1085
26020
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1086
          }
1087
26097
          if(isProduct) {
1088
348
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1089
348
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ) );
1090
          }
1091
78225
          for( ; l < r2_tuple_len; ++l ) {
1092
26064
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], l ) );
1093
          }
1094
1095
52194
          Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1096
52194
          Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, composed_tuple, rel);
1097
52194
          std::vector<Node> reasons;
1098
26097
          reasons.push_back( r1_rep_exps[i] );
1099
26097
          reasons.push_back( r2_rep_exps[j] );
1100
1101
26097
          if( r1 != r1_rep_exps[i][1] ) {
1102
73
            reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1, r1_rep_exps[i][1]) );
1103
          }
1104
26097
          if( r2 != r2_rep_exps[j][1] ) {
1105
51
            reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r2, r2_rep_exps[j][1]) );
1106
          }
1107
26097
          if( isProduct ) {
1108
348
            sendInfer(
1109
696
                fact, InferenceId::SETS_RELS_PRODUCE_COMPOSE, nm->mkNode(kind::AND, reasons));
1110
          } else {
1111
25749
            if( r1_rmost != r2_lmost ) {
1112
6623
              reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1_rmost, r2_lmost) );
1113
            }
1114
25749
            sendInfer(
1115
51498
                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
521073
  bool TheorySetsRels::isRelationKind( Kind k ) {
1140
520597
    return k == TRANSPOSE || k == PRODUCT || k == JOIN || k == TCLOSURE
1141
1040082
           || k == IDEN || k == JOIN_IMAGE;
1142
  }
1143
1144
53852
  Node TheorySetsRels::getRepresentative( Node t ) {
1145
53852
    return d_state.getRepresentative(t);
1146
  }
1147
1148
1095138
  bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); }
1149
570466
  bool TheorySetsRels::areEqual( Node a, Node b ){
1150
570466
    Assert(a.getType() == b.getType());
1151
570466
    Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
1152
570466
    if(a == b) {
1153
22897
      return true;
1154
547569
    } else if( hasTerm( a ) && hasTerm( b ) ){
1155
547569
      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
12949
  bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
1174
12949
    std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep);
1175
12949
    if(mem_it == map.end()) {
1176
5560
      std::vector<Node> members;
1177
2780
      members.push_back(member);
1178
2780
      map[rel_rep] = members;
1179
2780
      return true;
1180
    } else {
1181
10169
      std::vector<Node>::iterator mems = mem_it->second.begin();
1182
650247
      while(mems != mem_it->second.end()) {
1183
323698
        if(areEqual(*mems, member)) {
1184
3659
          return false;
1185
        }
1186
320039
        ++mems;
1187
      }
1188
6510
      map[rel_rep].push_back(member);
1189
6510
      return true;
1190
    }
1191
    return false;
1192
  }
1193
1194
12008
  void TheorySetsRels::makeSharedTerm(Node n, TypeNode t)
1195
  {
1196
12008
    if (d_shared_terms.find(n) != d_shared_terms.end())
1197
    {
1198
10648
      return;
1199
    }
1200
1360
    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
2720
    Node ss = NodeManager::currentNM()->mkSingleton(t, n);
1203
1360
    d_treg.getProxy(ss);
1204
1360
    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
12425
  void TheorySetsRels::computeTupleReps( Node n ) {
1212
12425
    if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){
1213
23008
      for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){
1214
15414
        d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) );
1215
      }
1216
    }
1217
12425
  }
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
1882
  void TheorySetsRels::reduceTupleVar(Node n) {
1224
1882
    if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) {
1225
589
      Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl;
1226
1178
      std::vector<Node> tuple_elements;
1227
589
      tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor());
1228
1178
      std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes();
1229
1787
      for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++)
1230
      {
1231
2396
        Node element = RelsUtils::nthElementOfTuple(n[0], i);
1232
1198
        makeSharedTerm(element, tupleTypes[i]);
1233
1198
        tuple_elements.push_back(element);
1234
      }
1235
1178
      Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1236
589
      tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]);
1237
1178
      Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::EQUAL, n, tuple_reduct);
1238
589
      sendInfer(tuple_reduction_lemma, InferenceId::SETS_RELS_TUPLE_REDUCTION, d_trueNode);
1239
589
      d_symbolic_tuples.insert(n);
1240
    }
1241
1882
  }
1242
1243
2898
  std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) {
1244
5796
    std::vector<Node>                           nodes;
1245
2898
    std::map< Node, TupleTrie >::iterator       it;
1246
1247
2898
    if( argIndex==(int)reps.size()-1 ){
1248
1424
      if(reps[argIndex].getKind() == kind::SKOLEM) {
1249
1287
        it = d_data.begin();
1250
15891
        while(it != d_data.end()) {
1251
7302
          nodes.push_back(it->first);
1252
7302
          ++it;
1253
        }
1254
      }
1255
1424
      return nodes;
1256
    }else{
1257
1474
      it = d_data.find( reps[argIndex] );
1258
1474
      if( it==d_data.end() ){
1259
74
        return nodes;
1260
      }else{
1261
1400
        return it->second.findTerms( reps, argIndex+1 );
1262
      }
1263
    }
1264
  }
1265
1266
243
  std::vector<Node> TupleTrie::findSuccessors( std::vector< Node >& reps, int argIndex ) {
1267
486
    std::vector<Node>   nodes;
1268
243
    std::map< Node, TupleTrie >::iterator it;
1269
1270
243
    if( argIndex==(int)reps.size() ){
1271
104
      it = d_data.begin();
1272
476
      while(it != d_data.end()) {
1273
186
        nodes.push_back(it->first);
1274
186
        ++it;
1275
      }
1276
104
      return nodes;
1277
    }else{
1278
139
      it = d_data.find( reps[argIndex] );
1279
139
      if( it==d_data.end() ){
1280
35
        return nodes;
1281
      }else{
1282
104
        return it->second.findSuccessors( reps, argIndex+1 );
1283
      }
1284
    }
1285
  }
1286
1287
4146
  Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) {
1288
4146
    if( argIndex==(int)reps.size() ){
1289
1245
      if( d_data.empty() ){
1290
        return Node::null();
1291
      }else{
1292
1245
        return d_data.begin()->first;
1293
      }
1294
    }else{
1295
2901
      std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] );
1296
2901
      if( it==d_data.end() ){
1297
217
        return Node::null();
1298
      }else{
1299
2684
        return it->second.existsTerm( reps, argIndex+1 );
1300
      }
1301
    }
1302
  }
1303
1304
27991
  bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){
1305
27991
    if( argIndex==(int)reps.size() ){
1306
9290
      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
9290
        d_data[n].clear();
1309
9290
        return true;
1310
      }else{
1311
        return false;
1312
      }
1313
    }else{
1314
18701
      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
34779
  void TheorySetsRels::sendInfer(Node fact, InferenceId id, Node reason)
1327
  {
1328
69558
    Trace("rels-lemma") << "Rels::lemma " << fact << " from " << reason
1329
34779
                        << " by " << id << std::endl;
1330
69558
    Node lemma = NodeManager::currentNM()->mkNode(IMPLIES, reason, fact);
1331
34779
    d_im.addPendingLemma(lemma, id);
1332
34779
  }
1333
}
1334
}
1335
29577
}  // namespace cvc5