GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_rels.cpp Lines: 738 778 94.9 %
Date: 2021-11-06 Branches: 1659 3185 52.1 %

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
15272
TheorySetsRels::TheorySetsRels(Env& env,
38
                               SolverState& s,
39
                               InferenceManager& im,
40
                               SkolemCache& skc,
41
15272
                               TermRegistry& treg)
42
    : EnvObj(env),
43
      d_state(s),
44
      d_im(im),
45
      d_skCache(skc),
46
      d_treg(treg),
47
15272
      d_shared_terms(userContext())
48
{
49
15272
  d_trueNode = NodeManager::currentNM()->mkConst(true);
50
15272
  d_falseNode = NodeManager::currentNM()->mkConst(false);
51
15272
}
52
53
30534
TheorySetsRels::~TheorySetsRels() {}
54
55
809
void TheorySetsRels::check(Theory::Effort level)
56
{
57
1618
  Trace("rels") << "\n[sets-rels] ******************************* Start the "
58
809
                   "relational solver, effort = "
59
809
                << level << " *******************************\n"
60
809
                << std::endl;
61
809
  if (Theory::fullEffort(level))
62
  {
63
809
    collectRelsInfo();
64
809
    check();
65
809
    d_im.doPendingLemmas();
66
  }
67
809
  Assert(!d_im.hasPendingLemma());
68
1618
  Trace("rels") << "\n[sets-rels] ******************************* Done with "
69
809
                   "the relational solver *******************************\n"
70
809
                << std::endl;
71
809
}
72
73
809
  void TheorySetsRels::check() {
74
809
    MEM_IT m_it = d_rReps_memberReps_cache.begin();
75
76
6515
    while(m_it != d_rReps_memberReps_cache.end()) {
77
5706
      Node rel_rep = m_it->first;
78
79
12219
      for(unsigned int i = 0; i < m_it->second.size(); i++) {
80
18732
        Node    mem     = d_rReps_memberReps_cache[rel_rep][i];
81
18732
        Node    exp     = d_rReps_memberReps_exp_cache[rel_rep][i];
82
        std::map<kind::Kind_t, std::vector<Node> >& kind_terms =
83
9366
            d_terms_cache[rel_rep];
84
85
9366
        if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) {
86
1349
          std::vector<Node>& tp_terms = kind_terms[TRANSPOSE];
87
1349
          if( tp_terms.size() > 0 ) {
88
1349
            applyTransposeRule( tp_terms );
89
1349
            applyTransposeRule( tp_terms[0], rel_rep, exp );
90
          }
91
        }
92
9366
        if( kind_terms.find(kind::JOIN) != kind_terms.end() ) {
93
1251
          std::vector<Node>& join_terms = kind_terms[JOIN];
94
2794
          for( unsigned int j = 0; j < join_terms.size(); j++ ) {
95
1543
            applyJoinRule( join_terms[j], rel_rep, exp );
96
          }
97
        }
98
9366
        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
9366
        if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) {
105
276
          std::vector<Node>& tc_terms = kind_terms[TCLOSURE];
106
552
          for( unsigned int j = 0; j < tc_terms.size(); j++ ) {
107
276
            applyTCRule( mem, tc_terms[j], rel_rep, exp );
108
          }
109
        }
110
9366
        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
9366
        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
2853
      ++m_it;
124
    }
125
126
809
    TERM_IT t_it = d_terms_cache.begin();
127
7995
    while( t_it != d_terms_cache.end() ) {
128
      // check the terms in this equivalence class for e.g. upwards closure
129
      // (computeMembersForBinOpRel / computeMembersForUnaryOpRel). This is
130
      // done regardless of whether we have initialized
131
      // d_rReps_memberReps_cache for this equivalence class.
132
7186
      Trace("rels-debug")
133
3593
          << "[sets-rels] Check equivalence class: "
134
3593
          << t_it->first << std::endl;
135
3593
      KIND_TERM_IT k_t_it = t_it->second.begin();
136
137
6625
      while (k_t_it != t_it->second.end())
138
      {
139
3032
        Trace("rels-debug") << "[sets-rels] Check " << k_t_it->second.size()
140
1516
                            << " terms of kind " << k_t_it->first << std::endl;
141
1516
        std::vector<Node>::iterator term_it = k_t_it->second.begin();
142
1516
        if (k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT)
143
        {
144
2921
          while (term_it != k_t_it->second.end())
145
          {
146
1015
            computeMembersForBinOpRel(*term_it);
147
1015
            ++term_it;
148
          }
149
        }
150
625
        else if (k_t_it->first == kind::TRANSPOSE)
151
        {
152
1140
          while (term_it != k_t_it->second.end())
153
          {
154
380
            computeMembersForUnaryOpRel(*term_it);
155
380
            ++term_it;
156
          }
157
        }
158
245
        else if (k_t_it->first == kind::TCLOSURE)
159
        {
160
474
          while (term_it != k_t_it->second.end())
161
          {
162
158
            buildTCGraphForRel(*term_it);
163
158
            ++term_it;
164
          }
165
        }
166
87
        else if (k_t_it->first == kind::JOIN_IMAGE)
167
        {
168
213
          while (term_it != k_t_it->second.end())
169
          {
170
71
            computeMembersForJoinImageTerm(*term_it);
171
71
            ++term_it;
172
          }
173
        }
174
16
        else if (k_t_it->first == kind::IDEN)
175
        {
176
48
          while (term_it != k_t_it->second.end())
177
          {
178
16
            computeMembersForIdenTerm(*term_it);
179
16
            ++term_it;
180
          }
181
        }
182
1516
        ++k_t_it;
183
      }
184
3593
      ++t_it;
185
    }
186
809
    doTCInference();
187
188
    // clean up
189
809
    d_tuple_reps.clear();
190
809
    d_rReps_memberReps_exp_cache.clear();
191
809
    d_terms_cache.clear();
192
809
    d_membership_trie.clear();
193
809
    d_rel_nodes.clear();
194
809
    d_rReps_memberReps_cache.clear();
195
809
    d_rRep_tcGraph.clear();
196
809
    d_tcr_tcGraph_exps.clear();
197
809
    d_tcr_tcGraph.clear();
198
809
  }
199
200
  /*
201
   * Populate relational terms data structure
202
   */
203
204
809
  void TheorySetsRels::collectRelsInfo() {
205
809
    Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
206
809
    eq::EqualityEngine* ee = d_state.getEqualityEngine();
207
809
    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
208
47615
    while( !eqcs_i.isFinished() ){
209
46806
      Node                      eqc_rep  = (*eqcs_i);
210
23403
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee);
211
212
46806
      TypeNode erType = eqc_rep.getType();
213
23403
      Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl;
214
215
147137
      while( !eqc_i.isFinished() ){
216
123734
        Node eqc_node = (*eqc_i);
217
218
61867
        Trace("rels-ee") << "  term : " << eqc_node << std::endl;
219
220
61867
        if (erType.isBoolean() && eqc_rep.isConst())
221
        {
222
          // collect membership info
223
25654
          if( eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) {
224
28446
            Node tup_rep = getRepresentative( eqc_node[0] );
225
28446
            Node rel_rep = getRepresentative( eqc_node[1] );
226
227
14223
            if( eqc_node[0].isVar() ){
228
1880
              reduceTupleVar( eqc_node );
229
            }
230
231
14223
            bool is_true_eq = eqc_rep.getConst<bool>();
232
28446
            Node reason        = is_true_eq ? eqc_node : eqc_node.negate();
233
234
14223
            if( is_true_eq ) {
235
13054
              if( safelyAddToMap(d_rReps_memberReps_cache, rel_rep, tup_rep) ) {
236
9366
                d_rReps_memberReps_exp_cache[rel_rep].push_back(reason);
237
9366
                computeTupleReps(tup_rep);
238
9366
                d_membership_trie[rel_rep].addTerm(tup_rep, d_tuple_reps[tup_rep]);
239
              }
240
            }
241
          }
242
        // collect relational terms info
243
        }
244
36213
        else if (erType.isSet() && erType.getSetElementType().isTuple())
245
        {
246
17886
          if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN ||
247
10426
              eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE ||
248
11499
              eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) {
249
1640
            d_terms_cache[eqc_rep][eqc_node.getKind()].push_back(eqc_node);
250
          }
251
        // need to add all tuple elements as shared terms
252
        }
253
31321
        else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar())
254
        {
255
12188
          std::vector<TypeNode> tupleTypes = erType.getTupleTypes();
256
18407
          for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++)
257
          {
258
24626
            Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
259
12313
            if (!element.isConst())
260
            {
261
10901
              makeSharedTerm(element, tupleTypes[i]);
262
            }
263
          }
264
        }
265
61867
        ++eqc_i;
266
      }
267
23403
      ++eqcs_i;
268
    }
269
809
    Trace("rels-debug") << "[Theory::Rels] Done with collecting relational terms!" << std::endl;
270
809
  }
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
140
  void TheorySetsRels::computeMembersForJoinImageTerm( Node join_image_term ) {
279
140
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for JoinImage Term = " << join_image_term << std::endl;
280
140
    MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( getRepresentative( join_image_term[0] ) );
281
282
140
    if( rel_mem_it == d_rReps_memberReps_cache.end() ) {
283
      return;
284
    }
285
140
    NodeManager* nm = NodeManager::currentNM();
286
287
280
    Node join_image_rel = join_image_term[0];
288
280
    std::unordered_set<Node> hasChecked;
289
280
    Node join_image_rel_rep = getRepresentative( join_image_rel );
290
140
    std::vector< Node >::iterator mem_rep_it = (*rel_mem_it).second.begin();
291
140
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( join_image_rel_rep );
292
140
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
293
140
    unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt();
294
295
1432
    while( mem_rep_it != (*rel_mem_it).second.end() ) {
296
856
      Node fst_mem_rep = RelsUtils::nthElementOfTuple( *mem_rep_it, 0 );
297
298
854
      if( hasChecked.find( fst_mem_rep ) != hasChecked.end() ) {
299
208
        ++mem_rep_it;
300
208
        ++mem_rep_exp_it;
301
208
        continue;
302
      }
303
438
      hasChecked.insert( fst_mem_rep );
304
305
      const DType& dt =
306
438
          join_image_term.getType().getSetElementType().getDType();
307
      Node new_membership = nm->mkNode(
308
          MEMBER,
309
876
          nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem_rep),
310
1524
          join_image_term);
311
666
      if (d_state.isEntailed(new_membership, true))
312
      {
313
228
        ++mem_rep_it;
314
228
        ++mem_rep_exp_it;
315
228
        continue;
316
      }
317
318
420
      std::vector< Node > reasons;
319
420
      std::vector< Node > existing_members;
320
210
      std::vector< Node >::iterator mem_rep_exp_it_snd = (*rel_mem_exp_it).second.begin();
321
322
1628
      while( mem_rep_exp_it_snd != (*rel_mem_exp_it).second.end() ) {
323
1493
        Node fst_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 0 );
324
325
784
        if( areEqual( fst_mem_rep,  fst_element_snd_mem ) ) {
326
233
          bool notExist = true;
327
233
          std::vector< Node >::iterator existing_mem_it = existing_members.begin();
328
391
          Node snd_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 1 );
329
330
315
          while( existing_mem_it != existing_members.end() ) {
331
41
            if( areEqual( (*existing_mem_it), snd_element_snd_mem ) ) {
332
              notExist = false;
333
              break;
334
            }
335
41
            ++existing_mem_it;
336
          }
337
338
233
          if( notExist ) {
339
233
            existing_members.push_back( snd_element_snd_mem );
340
233
            reasons.push_back( *mem_rep_exp_it_snd );
341
233
            if( fst_mem_rep != fst_element_snd_mem ) {
342
11
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, fst_mem_rep, fst_element_snd_mem ) );
343
            }
344
233
            if( join_image_rel != (*mem_rep_exp_it_snd)[1] ) {
345
140
              reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it_snd)[1], join_image_rel ));
346
            }
347
233
            if( existing_members.size() == min_card ) {
348
75
              if( min_card >= 2) {
349
31
                new_membership = NodeManager::currentNM()->mkNode( kind::OR, new_membership, NodeManager::currentNM()->mkNode( kind::NOT, NodeManager::currentNM()->mkNode( kind::DISTINCT, existing_members ) ));
350
              }
351
75
              Assert(reasons.size() >= 1);
352
75
              sendInfer(
353
                  new_membership,
354
                  InferenceId::SETS_RELS_JOIN_IMAGE_UP,
355
150
                  reasons.size() > 1 ? nm->mkNode(AND, reasons) : reasons[0]);
356
75
              break;
357
            }
358
          }
359
        }
360
709
        ++mem_rep_exp_it_snd;
361
      }
362
210
      ++mem_rep_it;
363
210
      ++mem_rep_exp_it;
364
    }
365
140
    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
24
  void TheorySetsRels::computeMembersForIdenTerm( Node iden_term ) {
465
24
    Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for Iden Term = " << iden_term << std::endl;
466
38
    Node iden_term_rel = iden_term[0];
467
38
    Node iden_term_rel_rep = getRepresentative( iden_term_rel );
468
469
24
    if( d_rReps_memberReps_cache.find( iden_term_rel_rep ) == d_rReps_memberReps_cache.end() ) {
470
10
      return;
471
    }
472
14
    NodeManager* nm = NodeManager::currentNM();
473
474
14
    MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( iden_term_rel_rep );
475
14
    std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin();
476
477
108
    while( mem_rep_exp_it != (*rel_mem_exp_it).second.end() ) {
478
94
      Node reason = *mem_rep_exp_it;
479
94
      Node fst_exp_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it)[0], 0 );
480
94
      Node new_mem = RelsUtils::constructPair( iden_term, fst_exp_mem, fst_exp_mem );
481
482
47
      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
141
      sendInfer(
486
94
          nm->mkNode(MEMBER, new_mem, iden_term), InferenceId::SETS_RELS_IDENTITY_UP, reason);
487
47
      ++mem_rep_exp_it;
488
    }
489
14
    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
276
  void TheorySetsRels::applyTCRule( Node mem_rep, Node tc_rel, Node tc_rel_rep, Node exp ) {
512
552
    Trace("rels-debug") << "[Theory::Rels] *********** Applying TCLOSURE rule on a tc term = " << tc_rel
513
276
                            << ", its representative = " << tc_rel_rep
514
276
                            << " with member rep = " << mem_rep << " and explanation = " << exp << std::endl;
515
276
    MEM_IT mem_it = d_rReps_memberReps_cache.find( tc_rel[0] );
516
517
818
    if( mem_it != d_rReps_memberReps_cache.end() && d_rel_nodes.find( tc_rel ) == d_rel_nodes.end()
518
653
        && d_rRep_tcGraph.find( getRepresentative( tc_rel[0] ) ) ==  d_rRep_tcGraph.end() ) {
519
101
      buildTCGraphForRel( tc_rel );
520
101
      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
276
    if( isTCReachable( mem_rep, tc_rel) ) {
525
506
      Trace("rels-debug") << "[Theory::Rels] mem_rep is a member of tc_rel[0] = " << tc_rel[0]
526
253
                              << " or can be infered by TC_Graph of tc_rel[0]! " << std::endl;
527
253
      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
13
      std::map< Node, std::map< Node, Node > >::iterator tc_exp_it = d_tcr_tcGraph_exps.find( tc_rel );
539
540
13
      TC_GRAPH_IT tc_graph_it = (tc_it->second).find( mem_rep_fst );
541
13
      Assert(tc_exp_it != d_tcr_tcGraph_exps.end());
542
13
      std::map< Node, Node >::iterator exp_map_it = (tc_exp_it->second).find( mem_rep_tup );
543
544
13
      if( exp_map_it == (tc_exp_it->second).end() ) {
545
13
        (tc_exp_it->second)[mem_rep_tup] = exp;
546
      }
547
548
13
      if( tc_graph_it != (tc_it->second).end() ) {
549
8
        (tc_graph_it->second).insert( mem_rep_snd );
550
      } else {
551
10
        std::unordered_set<Node> sets;
552
5
        sets.insert( mem_rep_snd );
553
5
        (tc_it->second)[mem_rep_fst] = sets;
554
      }
555
    } else {
556
20
      std::map< Node, Node > exp_map;
557
20
      std::unordered_set<Node> sets;
558
20
      std::map<Node, std::unordered_set<Node> > element_map;
559
10
      sets.insert( mem_rep_snd );
560
10
      element_map[mem_rep_fst] = sets;
561
10
      d_tcr_tcGraph[tc_rel] = element_map;
562
10
      exp_map[mem_rep_tup] = exp;
563
10
      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
5
      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
276
  bool TheorySetsRels::isTCReachable( Node mem_rep, Node tc_rel ) {
606
276
    MEM_IT mem_it = d_rReps_memberReps_cache.find( getRepresentative( tc_rel[0] ) );
607
608
276
    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
168
      return true;
610
    }
611
612
108
    TC_IT tc_it = d_rRep_tcGraph.find( getRepresentative(tc_rel[0]) );
613
108
    if( tc_it != d_rRep_tcGraph.end() ) {
614
98
      bool isReachable = false;
615
196
      std::unordered_set<Node> seen;
616
196
      isTCReachable( getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 0) ),
617
294
                     getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 1) ), seen, tc_it->second, isReachable );
618
98
      return isReachable;
619
    }
620
10
    return false;
621
  }
622
623
210
  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
210
    if(hasSeen.find(start) == hasSeen.end()) {
631
210
      hasSeen.insert(start);
632
    }
633
634
210
    TC_GRAPH_IT pair_set_it = tc_graph.find(start);
635
636
210
    if(pair_set_it != tc_graph.end()) {
637
184
      if(pair_set_it->second.find(dest) != pair_set_it->second.end()) {
638
85
        isReachable = true;
639
170
        return;
640
      } else {
641
99
        std::unordered_set<Node>::iterator set_it = pair_set_it->second.begin();
642
643
323
        while( set_it != pair_set_it->second.end() ) {
644
          // need to check if *set_it has been looked already
645
112
          if( hasSeen.find(*set_it) == hasSeen.end() ) {
646
112
            isTCReachable( *set_it, dest, hasSeen, tc_graph, isReachable );
647
          }
648
112
          ++set_it;
649
        }
650
      }
651
    }
652
  }
653
654
259
  void TheorySetsRels::buildTCGraphForRel( Node tc_rel ) {
655
518
    std::map< Node, Node > rel_tc_graph_exps;
656
518
    std::map<Node, std::unordered_set<Node> > rel_tc_graph;
657
658
518
    Node rel_rep = getRepresentative( tc_rel[0] );
659
518
    Node tc_rel_rep = getRepresentative( tc_rel );
660
259
    const std::vector<Node>& members = d_rReps_memberReps_cache[rel_rep];
661
259
    const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel_rep];
662
663
734
    for (size_t i = 0, msize = members.size(); i < msize; i++)
664
    {
665
950
      Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 ));
666
950
      Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 ));
667
950
      Node tuple_rep = RelsUtils::constructPair( rel_rep, fst_element_rep, snd_element_rep );
668
      std::map<Node, std::unordered_set<Node> >::iterator rel_tc_graph_it =
669
475
          rel_tc_graph.find(fst_element_rep);
670
671
475
      if( rel_tc_graph_it == rel_tc_graph.end() ) {
672
818
        std::unordered_set<Node> snd_elements;
673
409
        snd_elements.insert( snd_element_rep );
674
409
        rel_tc_graph[fst_element_rep] = snd_elements;
675
409
        rel_tc_graph_exps[tuple_rep] = exps[i];
676
66
      } else if( (rel_tc_graph_it->second).find( snd_element_rep ) ==  (rel_tc_graph_it->second).end() ) {
677
66
        (rel_tc_graph_it->second).insert( snd_element_rep );
678
66
        rel_tc_graph_exps[tuple_rep] = exps[i];
679
      }
680
    }
681
682
259
    if( members.size() > 0 ) {
683
216
      d_rRep_tcGraph[rel_rep] = rel_tc_graph;
684
216
      d_tcr_tcGraph_exps[tc_rel] = rel_tc_graph_exps;
685
216
      d_tcr_tcGraph[tc_rel] = rel_tc_graph;
686
    }
687
259
  }
688
689
125
  void TheorySetsRels::doTCInference(
690
      std::map<Node, std::unordered_set<Node> > rel_tc_graph,
691
      std::map<Node, Node> rel_tc_graph_exps,
692
      Node tc_rel)
693
  {
694
125
    Trace("rels-debug") << "[Theory::Rels] ****** doTCInference !" << std::endl;
695
350
    for (TC_GRAPH_IT tc_graph_it = rel_tc_graph.begin();
696
350
         tc_graph_it != rel_tc_graph.end();
697
         ++tc_graph_it)
698
    {
699
264
      for (std::unordered_set<Node>::iterator snd_elements_it =
700
225
               tc_graph_it->second.begin();
701
489
           snd_elements_it != tc_graph_it->second.end();
702
           ++snd_elements_it)
703
      {
704
528
        std::vector< Node > reasons;
705
528
        std::unordered_set<Node> seen;
706
528
        Node tuple = RelsUtils::constructPair( tc_rel, getRepresentative( tc_graph_it->first ), getRepresentative( *snd_elements_it) );
707
264
        Assert(rel_tc_graph_exps.find(tuple) != rel_tc_graph_exps.end());
708
528
        Node exp   = rel_tc_graph_exps.find( tuple )->second;
709
710
264
        reasons.push_back( exp );
711
264
        seen.insert( tc_graph_it->first );
712
264
        doTCInference( tc_rel, reasons, rel_tc_graph, rel_tc_graph_exps, tc_graph_it->first, *snd_elements_it, seen);
713
      }
714
    }
715
125
    Trace("rels-debug") << "[Theory::Rels] ****** Done with doTCInference !" << std::endl;
716
125
  }
717
718
492
  void TheorySetsRels::doTCInference(
719
      Node tc_rel,
720
      std::vector<Node> reasons,
721
      std::map<Node, std::unordered_set<Node> >& tc_graph,
722
      std::map<Node, Node>& rel_tc_graph_exps,
723
      Node start_node_rep,
724
      Node cur_node_rep,
725
      std::unordered_set<Node>& seen)
726
  {
727
492
    NodeManager* nm = NodeManager::currentNM();
728
868
    Node tc_mem = RelsUtils::constructPair( tc_rel, RelsUtils::nthElementOfTuple((reasons.front())[0], 0), RelsUtils::nthElementOfTuple((reasons.back())[0], 1) );
729
868
    std::vector< Node > all_reasons( reasons );
730
731
821
    for( unsigned int i = 0 ; i < reasons.size()-1; i++ ) {
732
658
      Node fst_element_end = RelsUtils::nthElementOfTuple( reasons[i][0], 1 );
733
658
      Node snd_element_begin = RelsUtils::nthElementOfTuple( reasons[i+1][0], 0 );
734
329
      if( fst_element_end != snd_element_begin ) {
735
48
        all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, fst_element_end, snd_element_begin) );
736
      }
737
329
      if( tc_rel != reasons[i][1] && tc_rel[0] != reasons[i][1] ) {
738
8
        all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons[i][1]) );
739
      }
740
    }
741
492
    if( tc_rel != reasons.back()[1] && tc_rel[0] != reasons.back()[1] ) {
742
8
      all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons.back()[1]) );
743
    }
744
492
    if( all_reasons.size() > 1) {
745
236
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
746
                InferenceId::SETS_RELS_TCLOSURE_FWD,
747
472
                nm->mkNode(AND, all_reasons));
748
    } else {
749
256
      sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel),
750
                InferenceId::SETS_RELS_TCLOSURE_FWD,
751
256
                all_reasons.front());
752
    }
753
754
    // check if cur_node has been traversed or not
755
492
    if( seen.find( cur_node_rep ) != seen.end() ) {
756
116
      return;
757
    }
758
376
    seen.insert( cur_node_rep );
759
376
    TC_GRAPH_IT  cur_set = tc_graph.find( cur_node_rep );
760
376
    if( cur_set != tc_graph.end() ) {
761
397
      for (std::unordered_set<Node>::iterator set_it = cur_set->second.begin();
762
397
           set_it != cur_set->second.end();
763
           ++set_it)
764
      {
765
456
        Node new_pair = RelsUtils::constructPair( tc_rel, cur_node_rep, *set_it );
766
456
        std::vector< Node > new_reasons( reasons );
767
228
        new_reasons.push_back( rel_tc_graph_exps.find( new_pair )->second );
768
228
        doTCInference( tc_rel, new_reasons, tc_graph, rel_tc_graph_exps, start_node_rep, *set_it, seen );
769
      }
770
    }
771
  }
772
773
 /*  product-split rule:  (a, b) IS_IN (X PRODUCT Y)
774
  *                     ----------------------------------
775
  *                       a IS_IN X  && b IS_IN Y
776
  *
777
  *  product-compose rule: (a, b) IS_IN X    (c, d) IS_IN Y
778
  *                        ---------------------------------
779
  *                        (a, b, c, d) IS_IN (X PRODUCT Y)
780
  */
781
782
783
169
  void TheorySetsRels::applyProductRule( Node pt_rel, Node pt_rel_rep, Node exp ) {
784
338
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying PRODUCT rule on producted term = " << pt_rel
785
169
                            << ", its representative = " << pt_rel_rep
786
169
                            << " with explanation = " << exp << std::endl;
787
788
169
    if(d_rel_nodes.find( pt_rel ) == d_rel_nodes.end()) {
789
114
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply PRODUCT-COMPOSE rule on term: " << pt_rel
790
57
                          << " with explanation: " << exp << std::endl;
791
792
57
      computeMembersForBinOpRel( pt_rel );
793
57
      d_rel_nodes.insert( pt_rel );
794
    }
795
796
338
    Node mem = exp[0];
797
338
    std::vector<Node>   r1_element;
798
338
    std::vector<Node>   r2_element;
799
169
    const DType& dt1 = pt_rel[0].getType().getSetElementType().getDType();
800
169
    unsigned int s1_len  = pt_rel[0].getType().getSetElementType().getTupleLength();
801
169
    unsigned int tup_len = pt_rel.getType().getSetElementType().getTupleLength();
802
803
169
    r1_element.push_back(dt1[0].getConstructor());
804
805
169
    unsigned int i = 0;
806
743
    for(; i < s1_len; ++i) {
807
287
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
808
    }
809
169
    const DType& dt2 = pt_rel[1].getType().getSetElementType().getDType();
810
169
    r2_element.push_back(dt2[0].getConstructor());
811
743
    for(; i < tup_len; ++i) {
812
287
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
813
    }
814
338
    Node reason   = exp;
815
338
    Node mem1     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
816
338
    Node mem2     = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
817
338
    Node fact_1   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, pt_rel[0]);
818
338
    Node fact_2   = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, pt_rel[1]);
819
820
169
    if( pt_rel != exp[1] ) {
821
12
      reason = NodeManager::currentNM()->mkNode(kind::AND, exp, NodeManager::currentNM()->mkNode(kind::EQUAL, pt_rel, exp[1]));
822
    }
823
169
    sendInfer(fact_1, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
824
169
    sendInfer(fact_2, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason);
825
169
  }
826
827
  /* join-split rule:           (a, b) IS_IN (X JOIN Y)
828
   *                  --------------------------------------------
829
   *                  exists z | (a, z) IS_IN X  && (z, b) IS_IN Y
830
   *
831
   *
832
   * join-compose rule: (a, b) IS_IN X    (b, c) IS_IN Y  NOT (t, u) IS_IN (X JOIN Y)
833
   *                    -------------------------------------------------------------
834
   *                                      (a, c) IS_IN (X JOIN Y)
835
   */
836
837
1543
  void TheorySetsRels::applyJoinRule( Node join_rel, Node join_rel_rep, Node exp ) {
838
3086
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying JOIN rule on joined term = " << join_rel
839
1543
                            << ", its representative = " << join_rel_rep
840
1543
                            << " with explanation = " << exp << std::endl;
841
1543
    if(d_rel_nodes.find( join_rel ) == d_rel_nodes.end()) {
842
832
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply JOIN-COMPOSE rule on term: " << join_rel
843
416
                          << " with explanation: " << exp << std::endl;
844
845
416
      computeMembersForBinOpRel( join_rel );
846
416
      d_rel_nodes.insert( join_rel );
847
    }
848
849
1830
    Node mem = exp[0];
850
1830
    std::vector<Node> r1_element;
851
1830
    std::vector<Node> r2_element;
852
1830
    Node r1_rep = getRepresentative(join_rel[0]);
853
1830
    Node r2_rep = getRepresentative(join_rel[1]);
854
1830
    TypeNode     shared_type    = r2_rep.getType().getSetElementType().getTupleTypes()[0];
855
1543
    Node shared_x = d_skCache.mkTypedSkolemCached(
856
1830
        shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj");
857
1543
    const DType& dt1 = join_rel[0].getType().getSetElementType().getDType();
858
1543
    unsigned int s1_len         = join_rel[0].getType().getSetElementType().getTupleLength();
859
1543
    unsigned int tup_len        = join_rel.getType().getSetElementType().getTupleLength();
860
861
1543
    unsigned int i = 0;
862
1543
    r1_element.push_back(dt1[0].getConstructor());
863
4581
    for(; i < s1_len-1; ++i) {
864
1519
      r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
865
    }
866
1543
    r1_element.push_back(shared_x);
867
1543
    const DType& dt2 = join_rel[1].getType().getSetElementType().getDType();
868
1543
    r2_element.push_back(dt2[0].getConstructor());
869
1543
    r2_element.push_back(shared_x);
870
4685
    for(; i < tup_len; ++i) {
871
1571
      r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i));
872
    }
873
1830
    Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
874
1830
    Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
875
876
1543
    computeTupleReps(mem1);
877
1543
    computeTupleReps(mem2);
878
879
1830
    std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[mem1]);
880
881
1768
    for(unsigned int j = 0; j < elements.size(); j++) {
882
1706
      std::vector<Node> new_tup;
883
1481
      new_tup.push_back(elements[j]);
884
1481
      new_tup.insert(new_tup.end(), d_tuple_reps[mem2].begin()+1, d_tuple_reps[mem2].end());
885
1481
      if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) {
886
1256
        return;
887
      }
888
    }
889
574
    Node reason = exp;
890
287
    if( join_rel != exp[1] ) {
891
159
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, join_rel, exp[1]));
892
    }
893
574
    Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, join_rel[0]);
894
287
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_1, reason);
895
287
    fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]);
896
287
    sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_2, reason);
897
287
    makeSharedTerm(shared_x, shared_type);
898
  }
899
900
  /*
901
   * transpose-occur rule:    (a, b) IS_IN X   (TRANSPOSE X) in T
902
   *                         ---------------------------------------
903
   *                            (b, a) IS_IN (TRANSPOSE X)
904
   *
905
   * transpose-reverse rule:    (a, b) IS_IN (TRANSPOSE X)
906
   *                         ---------------------------------------
907
   *                            (b, a) IS_IN X
908
   *
909
   */
910
1349
  void TheorySetsRels::applyTransposeRule( std::vector<Node> tp_terms ) {
911
1349
    if( tp_terms.size() < 1) {
912
      return;
913
    }
914
1349
    NodeManager* nm = NodeManager::currentNM();
915
1349
    for( unsigned int i = 1; i < tp_terms.size(); i++ ) {
916
      Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE-Equal rule on transposed term = " << tp_terms[0] << " and " << tp_terms[i] << std::endl;
917
      sendInfer(nm->mkNode(EQUAL, tp_terms[0][0], tp_terms[i][0]),
918
                InferenceId::SETS_RELS_TRANSPOSE_EQ,
919
                nm->mkNode(EQUAL, tp_terms[0], tp_terms[i]));
920
    }
921
  }
922
923
1349
  void TheorySetsRels::applyTransposeRule( Node tp_rel, Node tp_rel_rep, Node exp ) {
924
2698
    Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE rule on transposed term = " << tp_rel
925
1349
                        << ", its representative = " << tp_rel_rep
926
1349
                        << " with explanation = " << exp << std::endl;
927
1349
    NodeManager* nm = NodeManager::currentNM();
928
929
1349
    if(d_rel_nodes.find( tp_rel ) == d_rel_nodes.end()) {
930
394
      Trace("rels-debug") <<  "\n[Theory::Rels] Apply TRANSPOSE-Compose rule on term: " << tp_rel
931
197
                          << " with explanation: " << exp << std::endl;
932
933
197
      computeMembersForUnaryOpRel( tp_rel );
934
197
      d_rel_nodes.insert( tp_rel );
935
    }
936
937
2698
    Node reason = exp;
938
2698
    Node reversed_mem = RelsUtils::reverseTuple( exp[0] );
939
940
1349
    if( tp_rel != exp[1] ) {
941
155
      reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, tp_rel, exp[1]));
942
    }
943
1349
    sendInfer(nm->mkNode(MEMBER, reversed_mem, tp_rel[0]),
944
              InferenceId::SETS_RELS_TRANSPOSE_REV,
945
              reason);
946
1349
  }
947
948
809
  void TheorySetsRels::doTCInference() {
949
809
    Trace("rels-debug") << "[Theory::Rels] ****** Finalizing transitive closure inferences!" << std::endl;
950
809
    TC_IT tc_graph_it = d_tcr_tcGraph.begin();
951
1059
    while( tc_graph_it != d_tcr_tcGraph.end() ) {
952
125
      Assert(d_tcr_tcGraph_exps.find(tc_graph_it->first)
953
             != d_tcr_tcGraph_exps.end());
954
125
      doTCInference( tc_graph_it->second, d_tcr_tcGraph_exps.find(tc_graph_it->first)->second, tc_graph_it->first );
955
125
      ++tc_graph_it;
956
    }
957
809
    Trace("rels-debug") << "[Theory::Rels] ****** Done with finalizing transitive closure inferences!" << std::endl;
958
809
  }
959
960
961
  // Bottom-up fashion to compute relations with more than 1 arity
962
2022
  void TheorySetsRels::computeMembersForBinOpRel(Node rel) {
963
2022
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForBinOpRel for relation  " << rel << std::endl;
964
965
2022
    switch(rel[0].getKind()) {
966
288
      case kind::TRANSPOSE:
967
      case kind::TCLOSURE: {
968
288
        computeMembersForUnaryOpRel(rel[0]);
969
288
        break;
970
      }
971
280
      case kind::JOIN:
972
      case kind::PRODUCT: {
973
280
        computeMembersForBinOpRel(rel[0]);
974
280
        break;
975
      }
976
1454
      default:
977
1454
        break;
978
    }
979
2022
    switch(rel[1].getKind()) {
980
26
      case kind::TRANSPOSE: {
981
26
        computeMembersForUnaryOpRel(rel[1]);
982
26
        break;
983
      }
984
16
      case kind::JOIN:
985
      case kind::PRODUCT: {
986
16
        computeMembersForBinOpRel(rel[1]);
987
16
        break;
988
      }
989
1980
      default:
990
1980
        break;
991
    }
992
2022
    composeMembersForRels(rel);
993
2022
  }
994
995
  // Bottom-up fashion to compute unary relation
996
891
  void TheorySetsRels::computeMembersForUnaryOpRel(Node rel) {
997
891
    Trace("rels-debug") << "\n[Theory::Rels] computeMembersForUnaryOpRel for relation  " << rel << std::endl;
998
999
891
    switch(rel[0].getKind()) {
1000
      case kind::TRANSPOSE:
1001
      case kind::TCLOSURE:
1002
        computeMembersForUnaryOpRel(rel[0]);
1003
        break;
1004
238
      case kind::JOIN:
1005
      case kind::PRODUCT:
1006
238
        computeMembersForBinOpRel(rel[0]);
1007
238
        break;
1008
653
      default:
1009
653
        break;
1010
    }
1011
1012
1672
    Node rel0_rep  = getRepresentative(rel[0]);
1013
2673
    if (d_rReps_memberReps_cache.find(rel0_rep)
1014
2673
        == d_rReps_memberReps_cache.end())
1015
    {
1016
110
      return;
1017
    }
1018
781
    NodeManager* nm = NodeManager::currentNM();
1019
1020
781
    const std::vector<Node>& members = d_rReps_memberReps_cache[rel0_rep];
1021
781
    const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel0_rep];
1022
1023
781
    Assert(members.size() == exps.size());
1024
1025
781
    if (rel.getKind() == kind::TRANSPOSE)
1026
    {
1027
8457
      for (size_t i = 0, msize = members.size(); i < msize; i++)
1028
      {
1029
15388
        Node reason = exps[i];
1030
7694
        if( rel[0] != exps[i][1] ) {
1031
414
          reason = nm->mkNode(
1032
828
              kind::AND, reason, nm->mkNode(kind::EQUAL, rel[0], exps[i][1]));
1033
        }
1034
7694
        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. For example,
1043
   * consider the case that (a, b) in r1, (c, d) in r2.
1044
   *
1045
   * For JOIN, we have three cases:
1046
   *   if b = c, we infer (a, d) in (join r1 r2)
1047
   *   else, we mark b and c as shared terms; their equality will be split in
1048
   *         theory combination if necessary.
1049
   *
1050
   * For PRODUCT, we infer (a, b, c, d) in (product r1 r2).
1051
   */
1052
2022
  void TheorySetsRels::composeMembersForRels( Node rel ) {
1053
2022
    Trace("rels-debug") << "[Theory::Rels] Start composing members for relation = " << rel << std::endl;
1054
3698
    Node r1 = rel[0];
1055
3698
    Node r2 = rel[1];
1056
3698
    Node r1_rep = getRepresentative( r1 );
1057
3698
    Node r2_rep = getRepresentative( r2 );
1058
1059
5839
    if(d_rReps_memberReps_cache.find( r1_rep ) == d_rReps_memberReps_cache.end() ||
1060
3817
       d_rReps_memberReps_cache.find( r2_rep ) == d_rReps_memberReps_cache.end() ) {
1061
346
      return;
1062
    }
1063
1676
    NodeManager* nm = NodeManager::currentNM();
1064
1065
3352
    std::vector<Node> r1_rep_exps = d_rReps_memberReps_exp_cache[r1_rep];
1066
3352
    std::vector<Node> r2_rep_exps = d_rReps_memberReps_exp_cache[r2_rep];
1067
1676
    size_t r1_tuple_len = r1.getType().getSetElementType().getTupleLength();
1068
1676
    size_t r2_tuple_len = r2.getType().getSetElementType().getTupleLength();
1069
1070
1676
    Kind rk = rel.getKind();
1071
3352
    TypeNode tn = rel.getType().getSetElementType();
1072
9586
    for( unsigned int i = 0; i < r1_rep_exps.size(); i++ ) {
1073
349239
      for( unsigned int j = 0; j < r2_rep_exps.size(); j++ ) {
1074
378087
        std::vector<Node> tuple_elements;
1075
341329
        tuple_elements.push_back(tn.getDType()[0].getConstructor());
1076
378087
        std::vector<Node> reasons;
1077
341329
        if (rk == kind::JOIN)
1078
        {
1079
          Node r1_rmost =
1080
376837
              RelsUtils::nthElementOfTuple(r1_rep_exps[i][0], r1_tuple_len - 1);
1081
376837
          Node r2_lmost = RelsUtils::nthElementOfTuple(r2_rep_exps[j][0], 0);
1082
          // Since we require notification r1_rmost and r2_lmost are equal,
1083
          // they must be shared terms of theory of sets. Hence, we make the
1084
          // following calls to makeSharedTerm to ensure this is the case.
1085
340704
          makeSharedTerm(r1_rmost, r1_rmost.getType());
1086
340704
          makeSharedTerm(r2_lmost, r2_lmost.getType());
1087
1088
681408
          Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost
1089
340704
                              << " of type " << r1_rmost.getType() << std::endl;
1090
681408
          Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost
1091
340704
                              << " of type " << r2_lmost.getType() << std::endl;
1092
340704
          if (!areEqual(r1_rmost, r2_lmost))
1093
          {
1094
1095
304571
            continue;
1096
          }
1097
36133
          else if (r1_rmost != r2_lmost)
1098
          {
1099
10205
            Trace("rels-debug") << "...equal" << std::endl;
1100
10205
            reasons.push_back(nm->mkNode(kind::EQUAL, r1_rmost, r2_lmost));
1101
          }
1102
        }
1103
1104
36758
        if (rk == kind::PRODUCT || rk == kind::JOIN)
1105
        {
1106
36758
          bool isProduct = rk == kind::PRODUCT;
1107
36758
          unsigned int k = 0;
1108
36758
          unsigned int l = 1;
1109
1110
109950
          for( ; k < r1_tuple_len - 1; ++k ) {
1111
36596
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1112
          }
1113
36758
          if(isProduct) {
1114
625
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) );
1115
625
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ) );
1116
          }
1117
110102
          for( ; l < r2_tuple_len; ++l ) {
1118
36672
            tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], l ) );
1119
          }
1120
1121
          Node composed_tuple =
1122
73516
              nm->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1123
73516
          Node fact = nm->mkNode(kind::MEMBER, composed_tuple, rel);
1124
36758
          reasons.push_back( r1_rep_exps[i] );
1125
36758
          reasons.push_back( r2_rep_exps[j] );
1126
1127
36758
          if( r1 != r1_rep_exps[i][1] ) {
1128
211
            reasons.push_back(nm->mkNode(kind::EQUAL, r1, r1_rep_exps[i][1]));
1129
          }
1130
36758
          if( r2 != r2_rep_exps[j][1] ) {
1131
151
            reasons.push_back(nm->mkNode(kind::EQUAL, r2, r2_rep_exps[j][1]));
1132
          }
1133
36758
          if( isProduct ) {
1134
625
            sendInfer(
1135
1250
                fact, InferenceId::SETS_RELS_PRODUCE_COMPOSE, nm->mkNode(kind::AND, reasons));
1136
          } else {
1137
36133
            sendInfer(
1138
72266
                fact, InferenceId::SETS_RELS_JOIN_COMPOSE, nm->mkNode(kind::AND, reasons));
1139
          }
1140
        }
1141
      }
1142
    }
1143
1144
  }
1145
1146
  void TheorySetsRels::processInference(Node conc, InferenceId id, Node exp)
1147
  {
1148
    Trace("sets-pinfer") << "Process inference: " << exp << " => " << conc
1149
                         << std::endl;
1150
    if (!d_state.isEntailed(exp, true))
1151
    {
1152
      Trace("sets-pinfer") << "  must assert as lemma" << std::endl;
1153
      // we wrap the spurious explanation into a splitting lemma
1154
      Node lem = NodeManager::currentNM()->mkNode(OR, exp.negate(), conc);
1155
      d_im.assertInference(lem, id, d_trueNode, 1);
1156
      return;
1157
    }
1158
    // try to assert it as a fact
1159
    d_im.assertInference(conc, id, exp);
1160
  }
1161
1162
1300704
  bool TheorySetsRels::isRelationKind( Kind k ) {
1163
1300208
    return k == TRANSPOSE || k == PRODUCT || k == JOIN || k == TCLOSURE
1164
2599238
           || k == IDEN || k == JOIN_IMAGE;
1165
  }
1166
1167
55339
  Node TheorySetsRels::getRepresentative( Node t ) {
1168
55339
    return d_state.getRepresentative(t);
1169
  }
1170
1171
1270802
  bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); }
1172
665239
  bool TheorySetsRels::areEqual( Node a, Node b ){
1173
665239
    Assert(a.getType() == b.getType());
1174
665239
    Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
1175
665239
    if(a == b) {
1176
29838
      return true;
1177
635401
    } else if( hasTerm( a ) && hasTerm( b ) ){
1178
635401
      return d_state.areEqual(a, b);
1179
    }
1180
    TypeNode atn = a.getType();
1181
    if (atn.isTuple())
1182
    {
1183
      size_t tlen = atn.getTupleLength();
1184
      for (size_t i = 0; i < tlen; i++)
1185
      {
1186
        if (!areEqual(RelsUtils::nthElementOfTuple(a, i),
1187
                      RelsUtils::nthElementOfTuple(b, i)))
1188
        {
1189
          return false;
1190
        }
1191
      }
1192
      return true;
1193
    }
1194
    else if (!atn.isBoolean())
1195
    {
1196
      // TODO(project##230): Find a safe type for the singleton operator
1197
      makeSharedTerm(a, atn);
1198
      makeSharedTerm(b, b.getType());
1199
    }
1200
    return false;
1201
  }
1202
1203
  /*
1204
   * Make sure duplicate members are not added in map
1205
   */
1206
13054
  bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
1207
13054
    std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep);
1208
13054
    if(mem_it == map.end()) {
1209
5706
      std::vector<Node> members;
1210
2853
      members.push_back(member);
1211
2853
      map[rel_rep] = members;
1212
2853
      return true;
1213
    } else {
1214
10201
      std::vector<Node>::iterator mems = mem_it->second.begin();
1215
650245
      while(mems != mem_it->second.end()) {
1216
323710
        if(areEqual(*mems, member)) {
1217
3688
          return false;
1218
        }
1219
320022
        ++mems;
1220
      }
1221
6513
      map[rel_rep].push_back(member);
1222
6513
      return true;
1223
    }
1224
    return false;
1225
  }
1226
1227
693782
  void TheorySetsRels::makeSharedTerm(Node n, TypeNode t)
1228
  {
1229
693782
    if (d_shared_terms.find(n) != d_shared_terms.end())
1230
    {
1231
692136
      return;
1232
    }
1233
1646
    Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl;
1234
    // force a proxy lemma to be sent for the singleton containing n
1235
3292
    Node ss = NodeManager::currentNM()->mkSingleton(t, n);
1236
1646
    d_treg.getProxy(ss);
1237
1646
    d_shared_terms.insert(n);
1238
  }
1239
1240
  /*
1241
   * For each tuple n, we store a mapping between n and a list of its elements representatives
1242
   * in d_tuple_reps. This would later be used for applying JOIN operator.
1243
   */
1244
12591
  void TheorySetsRels::computeTupleReps( Node n ) {
1245
12591
    if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){
1246
23446
      for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){
1247
15706
        d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) );
1248
      }
1249
    }
1250
12591
  }
1251
1252
  /*
1253
   * Node n[0] is a tuple variable, reduce n[0] to a concrete representation,
1254
   * which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0].
1255
   */
1256
1880
  void TheorySetsRels::reduceTupleVar(Node n) {
1257
1880
    if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) {
1258
583
      Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl;
1259
1166
      std::vector<Node> tuple_elements;
1260
583
      tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor());
1261
1166
      std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes();
1262
1769
      for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++)
1263
      {
1264
2372
        Node element = RelsUtils::nthElementOfTuple(n[0], i);
1265
1186
        makeSharedTerm(element, tupleTypes[i]);
1266
1186
        tuple_elements.push_back(element);
1267
      }
1268
1166
      Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
1269
583
      tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]);
1270
1166
      Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::EQUAL, n, tuple_reduct);
1271
583
      sendInfer(tuple_reduction_lemma, InferenceId::SETS_RELS_TUPLE_REDUCTION, d_trueNode);
1272
583
      d_symbolic_tuples.insert(n);
1273
    }
1274
1880
  }
1275
1276
2974
  std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) {
1277
5948
    std::vector<Node>                           nodes;
1278
2974
    std::map< Node, TupleTrie >::iterator       it;
1279
1280
2974
    if( argIndex==(int)reps.size()-1 ){
1281
1455
      if(reps[argIndex].getKind() == kind::SKOLEM) {
1282
1306
        it = d_data.begin();
1283
15948
        while(it != d_data.end()) {
1284
7321
          nodes.push_back(it->first);
1285
7321
          ++it;
1286
        }
1287
      }
1288
1455
      return nodes;
1289
    }else{
1290
1519
      it = d_data.find( reps[argIndex] );
1291
1519
      if( it==d_data.end() ){
1292
88
        return nodes;
1293
      }else{
1294
1431
        return it->second.findTerms( reps, argIndex+1 );
1295
      }
1296
    }
1297
  }
1298
1299
243
  std::vector<Node> TupleTrie::findSuccessors( std::vector< Node >& reps, int argIndex ) {
1300
486
    std::vector<Node>   nodes;
1301
243
    std::map< Node, TupleTrie >::iterator it;
1302
1303
243
    if( argIndex==(int)reps.size() ){
1304
104
      it = d_data.begin();
1305
476
      while(it != d_data.end()) {
1306
186
        nodes.push_back(it->first);
1307
186
        ++it;
1308
      }
1309
104
      return nodes;
1310
    }else{
1311
139
      it = d_data.find( reps[argIndex] );
1312
139
      if( it==d_data.end() ){
1313
35
        return nodes;
1314
      }else{
1315
104
        return it->second.findSuccessors( reps, argIndex+1 );
1316
      }
1317
    }
1318
  }
1319
1320
4191
  Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) {
1321
4191
    if( argIndex==(int)reps.size() ){
1322
1256
      if( d_data.empty() ){
1323
        return Node::null();
1324
      }else{
1325
1256
        return d_data.begin()->first;
1326
      }
1327
    }else{
1328
2935
      std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] );
1329
2935
      if( it==d_data.end() ){
1330
225
        return Node::null();
1331
      }else{
1332
2710
        return it->second.existsTerm( reps, argIndex+1 );
1333
      }
1334
    }
1335
  }
1336
1337
28219
  bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){
1338
28219
    if( argIndex==(int)reps.size() ){
1339
9366
      if( d_data.empty() ){
1340
        //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
1341
9366
        d_data[n].clear();
1342
9366
        return true;
1343
      }else{
1344
        return false;
1345
      }
1346
    }else{
1347
18853
      return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
1348
    }
1349
  }
1350
1351
  void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) {
1352
    for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
1353
      for( unsigned i=0; i<depth; i++ ){ Debug(c) << "  "; }
1354
      Debug(c) << it->first << std::endl;
1355
      it->second.debugPrint( c, n, depth+1 );
1356
    }
1357
  }
1358
1359
47993
  void TheorySetsRels::sendInfer(Node fact, InferenceId id, Node reason)
1360
  {
1361
95986
    Trace("rels-lemma") << "Rels::lemma " << fact << " from " << reason
1362
47993
                        << " by " << id << std::endl;
1363
95986
    Node lemma = NodeManager::currentNM()->mkNode(IMPLIES, reason, fact);
1364
47993
    d_im.addPendingLemma(lemma, id);
1365
47993
  }
1366
}
1367
}
1368
31137
}  // namespace cvc5