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

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