GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/relevant_domain.cpp Lines: 215 222 96.8 %
Date: 2021-05-22 Branches: 492 954 51.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Aina Niemetz
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
 * Implementation of relevant domain class.
14
 */
15
16
#include "theory/quantifiers/relevant_domain.h"
17
18
#include "expr/term_context.h"
19
#include "expr/term_context_stack.h"
20
#include "theory/arith/arith_msum.h"
21
#include "theory/quantifiers/first_order_model.h"
22
#include "theory/quantifiers/quantifiers_registry.h"
23
#include "theory/quantifiers/quantifiers_state.h"
24
#include "theory/quantifiers/term_database.h"
25
#include "theory/quantifiers/term_registry.h"
26
#include "theory/quantifiers/term_util.h"
27
28
using namespace cvc5::kind;
29
30
namespace cvc5 {
31
namespace theory {
32
namespace quantifiers {
33
34
13836
void RelevantDomain::RDomain::merge( RDomain * r ) {
35
13836
  Assert(!d_parent);
36
13836
  Assert(!r->d_parent);
37
13836
  d_parent = r;
38
14465
  for( unsigned i=0; i<d_terms.size(); i++ ){
39
629
    r->addTerm( d_terms[i] );
40
  }
41
13836
  d_terms.clear();
42
13836
}
43
44
21494
void RelevantDomain::RDomain::addTerm( Node t ) {
45
21494
  if( std::find( d_terms.begin(), d_terms.end(), t )==d_terms.end() ){
46
2881
    d_terms.push_back( t );
47
  }
48
21494
}
49
50
443150
RelevantDomain::RDomain * RelevantDomain::RDomain::getParent() {
51
443150
  if( !d_parent ){
52
223724
    return this;
53
  }else{
54
219426
    RDomain * p = d_parent->getParent();
55
219426
    d_parent = p;
56
219426
    return p;
57
  }
58
}
59
60
943
void RelevantDomain::RDomain::removeRedundantTerms(QuantifiersState& qs)
61
{
62
1886
  std::map< Node, Node > rterms;
63
3195
  for( unsigned i=0; i<d_terms.size(); i++ ){
64
4504
    Node r = d_terms[i];
65
2252
    if( !TermUtil::hasInstConstAttr( d_terms[i] ) ){
66
2252
      r = qs.getRepresentative(d_terms[i]);
67
    }
68
2252
    if( rterms.find( r )==rterms.end() ){
69
1926
      rterms[r] = d_terms[i];
70
    }
71
  }
72
943
  d_terms.clear();
73
2869
  for( std::map< Node, Node >::iterator it = rterms.begin(); it != rterms.end(); ++it ){
74
1926
    d_terms.push_back( it->second );
75
  }
76
943
}
77
78
83
RelevantDomain::RelevantDomain(QuantifiersState& qs,
79
                               QuantifiersRegistry& qr,
80
83
                               TermRegistry& tr)
81
83
    : d_qs(qs), d_qreg(qr), d_treg(tr)
82
{
83
83
  d_is_computed = false;
84
83
}
85
86
249
RelevantDomain::~RelevantDomain() {
87
809
  for( std::map< Node, std::map< int, RDomain * > >::iterator itr = d_rel_doms.begin(); itr != d_rel_doms.end(); ++itr ){
88
5858
    for( std::map< int, RDomain * >::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2 ){
89
5132
      RDomain * current = (*itr2).second;
90
5132
      Assert(current != NULL);
91
5132
      delete current;
92
    }
93
  }
94
166
}
95
96
208359
RelevantDomain::RDomain * RelevantDomain::getRDomain( Node n, int i, bool getParent ) {
97
208359
  if( d_rel_doms.find( n )==d_rel_doms.end() || d_rel_doms[n].find( i )==d_rel_doms[n].end() ){
98
5132
    d_rel_doms[n][i] = new RDomain;
99
5132
    d_rn_map[d_rel_doms[n][i]] = n;
100
5132
    d_ri_map[d_rel_doms[n][i]] = i;
101
  }
102
208359
  return getParent ? d_rel_doms[n][i]->getParent() : d_rel_doms[n][i];
103
}
104
105
1085
bool RelevantDomain::reset( Theory::Effort e ) {
106
1085
  d_is_computed = false;
107
1085
  return true;
108
}
109
110
3696
void RelevantDomain::registerQuantifier(Node q) {}
111
118
void RelevantDomain::compute(){
112
118
  if( !d_is_computed ){
113
118
    d_is_computed = true;
114
1612
    for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
115
11177
      for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
116
9683
        it2->second->reset();
117
      }
118
    }
119
118
    FirstOrderModel* fm = d_treg.getModel();
120
1638
    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
121
3040
      Node q = fm->getAssertedQuantifier( i );
122
3040
      Node icf = d_qreg.getInstConstantBody(q);
123
1520
      Trace("rel-dom-debug") << "compute relevant domain for " << icf << std::endl;
124
1520
      computeRelevantDomain(q);
125
    }
126
127
118
    Trace("rel-dom-debug") << "account for ground terms" << std::endl;
128
118
    TermDb* db = d_treg.getTermDatabase();
129
767
    for (unsigned k = 0; k < db->getNumOperators(); k++)
130
    {
131
1298
      Node op = db->getOperator(k);
132
649
      unsigned sz = db->getNumGroundTerms( op );
133
9519
      for( unsigned i=0; i<sz; i++ ){
134
17740
        Node n = db->getGroundTerm(op, i);
135
        //if it is a non-redundant term
136
8870
        if( db->isTermActive( n ) ){
137
24085
          for( unsigned j=0; j<n.getNumChildren(); j++ ){
138
18127
            RDomain * rf = getRDomain( op, j );
139
18127
            rf->addTerm( n[j] );
140
18127
            Trace("rel-dom-debug") << "...add ground term " << n[j] << " to rel dom " << op << "[" << j << "]" << std::endl;
141
          }
142
        }
143
      }
144
    }
145
    //print debug
146
2324
    for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
147
2206
      Trace("rel-dom") << "Relevant domain for " << it->first << " : " << std::endl;
148
16985
      for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
149
14779
        Trace("rel-dom") << "   " << it2->first << " : ";
150
14779
        RDomain * r = it2->second;
151
14779
        RDomain * rp = r->getParent();
152
14779
        if( r==rp ){
153
943
          r->removeRedundantTerms(d_qs);
154
2869
          for( unsigned i=0; i<r->d_terms.size(); i++ ){
155
1926
            Trace("rel-dom") << r->d_terms[i] << " ";
156
          }
157
        }else{
158
13836
          Trace("rel-dom") << "Dom( " << d_rn_map[rp] << ", " << d_ri_map[rp] << " ) ";
159
        }
160
14779
        Trace("rel-dom") << std::endl;
161
      }
162
    }
163
  }
164
118
}
165
166
1520
void RelevantDomain::computeRelevantDomain(Node q)
167
{
168
1520
  Assert(q.getKind() == FORALL);
169
3040
  Node n = d_qreg.getInstConstantBody(q);
170
  // we care about polarity in the traversal, so we use a polarity term context
171
3040
  PolarityTermContext tc;
172
3040
  TCtxStack ctx(&tc);
173
1520
  ctx.pushInitial(n);
174
  std::unordered_set<std::pair<Node, uint32_t>,
175
                     PairHashFunction<Node, uint32_t, std::hash<Node> > >
176
3040
      visited;
177
3040
  std::pair<Node, uint32_t> curr;
178
3040
  Node node;
179
  uint32_t nodeVal;
180
  std::unordered_set<
181
      std::pair<Node, uint32_t>,
182
1520
      PairHashFunction<Node, uint32_t, std::hash<Node> > >::const_iterator itc;
183
  bool hasPol, pol;
184
213798
  while (!ctx.empty())
185
  {
186
106139
    curr = ctx.getCurrent();
187
106139
    itc = visited.find(curr);
188
106139
    ctx.pop();
189
106139
    if (itc == visited.end())
190
    {
191
35675
      visited.insert(curr);
192
35675
      node = curr.first;
193
      // if not a quantified formula
194
35675
      if (!node.isClosure())
195
      {
196
35486
        nodeVal = curr.second;
197
        // get the polarity of the current term and process it
198
35486
        PolarityTermContext::getFlags(nodeVal, hasPol, pol);
199
35486
        computeRelevantDomainNode(q, node, hasPol, pol);
200
        // traverse the children
201
35486
        ctx.pushChildren(node, nodeVal);
202
      }
203
    }
204
  }
205
1520
}
206
207
35486
void RelevantDomain::computeRelevantDomainNode(Node q,
208
                                               Node n,
209
                                               bool hasPol,
210
                                               bool pol)
211
{
212
35486
  Trace("rel-dom-debug") << "Compute relevant domain " << n << "..." << std::endl;
213
70972
  Node op = d_treg.getTermDatabase()->getMatchOperator(n);
214
35486
  if (!op.isNull())
215
  {
216
92830
    for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
217
    {
218
81190
      RDomain * rf = getRDomain( op, i );
219
81190
      if( n[i].getKind()==ITE ){
220
        for( unsigned j=1; j<=2; j++ ){
221
          computeRelevantDomainOpCh( rf, n[i][j] );
222
        }
223
      }else{
224
81190
        computeRelevantDomainOpCh( rf, n[i] );
225
      }
226
    }
227
  }
228
229
35486
  if( ( ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) || n.getKind()==GEQ ) && TermUtil::hasInstConstAttr( n ) ){
230
    //compute the information for what this literal does
231
1240
    computeRelevantDomainLit( q, hasPol, pol, n );
232
1240
    if( d_rel_dom_lit[hasPol][pol][n].d_merge ){
233
157
      Assert(d_rel_dom_lit[hasPol][pol][n].d_rd[0] != NULL
234
             && d_rel_dom_lit[hasPol][pol][n].d_rd[1] != NULL);
235
157
      RDomain * rd1 = d_rel_dom_lit[hasPol][pol][n].d_rd[0]->getParent();
236
157
      RDomain * rd2 = d_rel_dom_lit[hasPol][pol][n].d_rd[1]->getParent();
237
157
      if( rd1!=rd2 ){
238
118
        rd1->merge( rd2 );
239
      }
240
    }else{
241
1083
      if( d_rel_dom_lit[hasPol][pol][n].d_rd[0]!=NULL ){
242
547
        RDomain * rd = d_rel_dom_lit[hasPol][pol][n].d_rd[0]->getParent();
243
1234
        for( unsigned i=0; i<d_rel_dom_lit[hasPol][pol][n].d_val.size(); i++ ){
244
687
          rd->addTerm( d_rel_dom_lit[hasPol][pol][n].d_val[i] );
245
        }
246
      }
247
    }
248
  }
249
35486
  Trace("rel-dom-debug") << "...finished Compute relevant domain " << n << std::endl;
250
35486
}
251
252
81190
void RelevantDomain::computeRelevantDomainOpCh( RDomain * rf, Node n ) {
253
81190
  if( n.getKind()==INST_CONSTANT ){
254
157356
    Node q = TermUtil::getInstConstAttr(n);
255
    //merge the RDomains
256
78678
    unsigned id = n.getAttribute(InstVarNumAttribute());
257
78678
    Assert(q[0][id].getType() == n.getType());
258
78678
    Trace("rel-dom-debug") << n << " is variable # " << id << " for " << q;
259
157356
    Trace("rel-dom-debug") << " with body : " << d_qreg.getInstConstantBody(q)
260
78678
                           << std::endl;
261
78678
    RDomain * rq = getRDomain( q, id );
262
78678
    if( rf!=rq ){
263
13718
      rq->merge( rf );
264
    }
265
2512
  }else if( !TermUtil::hasInstConstAttr( n ) ){
266
2051
    Trace("rel-dom-debug") << "...add ground term to rel dom " << n << std::endl;
267
    //term to add
268
2051
    rf->addTerm( n );
269
  }
270
81190
}
271
272
1240
void RelevantDomain::computeRelevantDomainLit( Node q, bool hasPol, bool pol, Node n ) {
273
1240
  if( d_rel_dom_lit[hasPol][pol].find( n )==d_rel_dom_lit[hasPol][pol].end() ){
274
416
    d_rel_dom_lit[hasPol][pol][n].d_merge = false;
275
416
    int varCount = 0;
276
416
    int varCh = -1;
277
1248
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
278
832
      if( n[i].getKind()==INST_CONSTANT ){
279
        // must get the quantified formula this belongs to, which may be
280
        // different from q
281
508
        Node qi = TermUtil::getInstConstAttr(n[i]);
282
254
        unsigned id = n[i].getAttribute(InstVarNumAttribute());
283
254
        d_rel_dom_lit[hasPol][pol][n].d_rd[i] = getRDomain(qi, id, false);
284
254
        varCount++;
285
254
        varCh = i;
286
      }else{
287
578
        d_rel_dom_lit[hasPol][pol][n].d_rd[i] = NULL;
288
      }
289
    }
290
291
832
    Node r_add;
292
416
    bool varLhs = true;
293
416
    if( varCount==2 ){
294
18
      d_rel_dom_lit[hasPol][pol][n].d_merge = true;
295
    }else{
296
398
      if( varCount==1 ){
297
218
        r_add = n[1-varCh];
298
218
        varLhs = (varCh==0);
299
218
        d_rel_dom_lit[hasPol][pol][n].d_rd[0] = d_rel_dom_lit[hasPol][pol][n].d_rd[varCh];
300
218
        d_rel_dom_lit[hasPol][pol][n].d_rd[1] = NULL;
301
      }else{
302
        //solve the inequality for one/two variables, if possible
303
180
        if( n[0].getType().isReal() ){
304
246
          std::map< Node, Node > msum;
305
123
          if (ArithMSum::getMonomialSumLit(n, msum))
306
          {
307
246
            Node var;
308
246
            Node var2;
309
123
            bool hasNonVar = false;
310
368
            for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
311
722
              if (!it->first.isNull() && it->first.getKind() == INST_CONSTANT
312
545
                  && TermUtil::getInstConstAttr(it->first) == q)
313
              {
314
55
                if( var.isNull() ){
315
33
                  var = it->first;
316
22
                }else if( var2.isNull() ){
317
22
                  var2 = it->first;
318
                }else{
319
                  hasNonVar = true;
320
                }
321
              }else{
322
190
                hasNonVar = true;
323
              }
324
            }
325
123
            if( !var.isNull() ){
326
33
              if( var2.isNull() ){
327
                //single variable solve
328
22
                Node veq_c;
329
22
                Node val;
330
                int ires =
331
11
                    ArithMSum::isolate(var, msum, veq_c, val, n.getKind());
332
11
                if( ires!=0 ){
333
11
                  if( veq_c.isNull() ){
334
3
                    r_add = val;
335
3
                    varLhs = (ires==1);
336
3
                    d_rel_dom_lit[hasPol][pol][n].d_rd[0] = getRDomain( q, var.getAttribute(InstVarNumAttribute()), false );
337
3
                    d_rel_dom_lit[hasPol][pol][n].d_rd[1] = NULL;
338
                  }
339
                }
340
22
              }else if( !hasNonVar ){
341
                //merge the domains
342
9
                d_rel_dom_lit[hasPol][pol][n].d_rd[0] = getRDomain( q, var.getAttribute(InstVarNumAttribute()), false );
343
9
                d_rel_dom_lit[hasPol][pol][n].d_rd[1] = getRDomain( q, var2.getAttribute(InstVarNumAttribute()), false );
344
9
                d_rel_dom_lit[hasPol][pol][n].d_merge = true;
345
              }
346
            }
347
          }
348
        }
349
      }
350
    }
351
416
    if( d_rel_dom_lit[hasPol][pol][n].d_merge ){
352
      //do not merge if constant negative polarity
353
27
      if( hasPol && !pol ){
354
        d_rel_dom_lit[hasPol][pol][n].d_merge = false;
355
      }
356
389
    }else if( !r_add.isNull() && !TermUtil::hasInstConstAttr( r_add ) ){
357
204
      Trace("rel-dom-debug") << "...add term " << r_add << ", pol = " << pol << ", kind = " << n.getKind() << std::endl;
358
      //the negative occurrence adds the term to the domain
359
204
      if( !hasPol || !pol ){
360
204
        d_rel_dom_lit[hasPol][pol][n].d_val.push_back( r_add );
361
      }
362
      //the positive occurence adds other terms
363
204
      if( ( !hasPol || pol ) && n[0].getType().isInteger() ){
364
136
        if( n.getKind()==EQUAL ){
365
          for( unsigned i=0; i<2; i++ ){
366
            d_rel_dom_lit[hasPol][pol][n].d_val.push_back(
367
                ArithMSum::offset(r_add, i == 0 ? 1 : -1));
368
          }
369
136
        }else if( n.getKind()==GEQ ){
370
272
          d_rel_dom_lit[hasPol][pol][n].d_val.push_back(
371
272
              ArithMSum::offset(r_add, varLhs ? 1 : -1));
372
        }
373
      }
374
    }else{
375
185
      d_rel_dom_lit[hasPol][pol][n].d_rd[0] = NULL;
376
185
      d_rel_dom_lit[hasPol][pol][n].d_rd[1] = NULL;
377
    }
378
  }
379
1240
}
380
381
}  // namespace quantifiers
382
}  // namespace theory
383
28194
}  // namespace cvc5