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