GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quant_split.cpp Lines: 99 101 98.0 %
Date: 2021-05-22 Branches: 199 382 52.1 %

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 dynamic quantifiers splitting.
14
 */
15
16
#include "theory/quantifiers/quant_split.h"
17
18
#include "expr/dtype.h"
19
#include "expr/dtype_cons.h"
20
#include "theory/quantifiers/term_database.h"
21
#include "theory/quantifiers/first_order_model.h"
22
#include "options/quantifiers_options.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace quantifiers {
29
30
5167
QuantDSplit::QuantDSplit(QuantifiersState& qs,
31
                         QuantifiersInferenceManager& qim,
32
                         QuantifiersRegistry& qr,
33
5167
                         TermRegistry& tr)
34
5167
    : QuantifiersModule(qs, qim, qr, tr), d_added_split(qs.getUserContext())
35
{
36
5167
}
37
38
12509
void QuantDSplit::checkOwnership(Node q)
39
{
40
  // If q is non-standard (marked as sygus, quantifier elimination, etc.), then
41
  // do no split it.
42
24319
  QAttributes qa;
43
12509
  QuantAttributes::computeQuantAttributes(q, qa);
44
12509
  if (!qa.isStandard())
45
  {
46
699
    return;
47
  }
48
11810
  bool takeOwnership = false;
49
11810
  bool doSplit = false;
50
11810
  QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
51
11810
  Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl;
52
37961
  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
53
54047
    TypeNode tn = q[0][i].getType();
54
27896
    if( tn.isDatatype() ){
55
4417
      bool isFinite = d_qstate.isFiniteType(tn);
56
4417
      const DType& dt = tn.getDType();
57
4417
      if (dt.isRecursiveSingleton(tn))
58
      {
59
        Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl;
60
      }
61
      else
62
      {
63
4417
        if (options::quantDynamicSplit() == options::QuantDSplitMode::AGG)
64
        {
65
          // split if it is a finite datatype
66
          doSplit = isFinite;
67
        }
68
8834
        else if (options::quantDynamicSplit()
69
4417
                 == options::QuantDSplitMode::DEFAULT)
70
        {
71
4417
          if (!qbi.isFiniteBound(q, q[0][i]))
72
          {
73
4310
            if (isFinite)
74
            {
75
              // split if goes from being unhandled -> handled by finite
76
              // instantiation. An example is datatypes with uninterpreted sort
77
              // fields which are "interpreted finite" but not "finite".
78
919
              doSplit = true;
79
              // we additionally take ownership of this formula, in other words,
80
              // we mark it reduced.
81
919
              takeOwnership = true;
82
            }
83
3391
            else if (dt.getNumConstructors() == 1 && !dt.isCodatatype())
84
            {
85
              // split if only one constructor
86
826
              doSplit = true;
87
            }
88
          }
89
        }
90
4417
        if (doSplit)
91
        {
92
          // store the index to split
93
1745
          d_quant_to_reduce[q] = i;
94
3490
          Trace("quant-dsplit-debug")
95
3490
              << "Split at index " << i << " based on datatype " << dt.getName()
96
1745
              << std::endl;
97
1745
          break;
98
        }
99
5344
        Trace("quant-dsplit-debug")
100
2672
            << "Do not split based on datatype " << dt.getName() << std::endl;
101
      }
102
    }
103
  }
104
105
11810
  if (takeOwnership)
106
  {
107
919
    Trace("quant-dsplit-debug") << "Will take ownership." << std::endl;
108
919
    d_qreg.setOwner(q, this);
109
  }
110
  // Notice we may not take ownership in some cases, meaning that both the
111
  // original quantified formula and the split one are generated. This may
112
  // increase our ability to answer "unsat", since quantifier instantiation
113
  // heuristics may be more effective for one or the other (see issues #993
114
  // and 3481).
115
}
116
117
/* whether this module needs to check this round */
118
65923
bool QuantDSplit::needsCheck( Theory::Effort e ) {
119
65923
  return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty();
120
}
121
122
240
bool QuantDSplit::checkCompleteFor( Node q ) {
123
  // true if we split q
124
240
  return d_added_split.find( q )!=d_added_split.end();
125
}
126
127
/* Call during quantifier engine's check */
128
1632
void QuantDSplit::check(Theory::Effort e, QEffort quant_e)
129
{
130
  //add lemmas ASAP (they are a reduction)
131
1632
  if (quant_e != QEFFORT_CONFLICT)
132
  {
133
1041
    return;
134
  }
135
591
  Trace("quant-dsplit") << "QuantDSplit::check" << std::endl;
136
591
  NodeManager* nm = NodeManager::currentNM();
137
591
  FirstOrderModel* m = d_treg.getModel();
138
1182
  std::vector<Node> lemmas;
139
25834
  for (std::map<Node, int>::iterator it = d_quant_to_reduce.begin();
140
25834
       it != d_quant_to_reduce.end();
141
       ++it)
142
  {
143
50486
    Node q = it->first;
144
25243
    Trace("quant-dsplit") << "- Split quantifier " << q << std::endl;
145
100755
    if (m->isQuantifierAsserted(q) && m->isQuantifierActive(q)
146
100755
        && d_added_split.find(q) == d_added_split.end())
147
    {
148
1737
      d_added_split.insert(q);
149
3474
      std::vector<Node> bvs;
150
7204
      for (unsigned i = 0, nvars = q[0].getNumChildren(); i < nvars; i++)
151
      {
152
5467
        if (static_cast<int>(i) != it->second)
153
        {
154
3730
          bvs.push_back(q[0][i]);
155
        }
156
      }
157
3474
      std::vector<Node> disj;
158
1737
      disj.push_back(q.negate());
159
3474
      TNode svar = q[0][it->second];
160
3474
      TypeNode tn = svar.getType();
161
1737
      Assert(tn.isDatatype());
162
3474
      std::vector<Node> cons;
163
1737
      const DType& dt = tn.getDType();
164
4157
      for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
165
      {
166
4840
        std::vector<Node> vars;
167
5884
        for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
168
        {
169
6928
          TypeNode tns = dt[j][k].getRangeType();
170
6928
          Node v = nm->mkBoundVar(tns);
171
3464
          vars.push_back(v);
172
        }
173
4840
        std::vector<Node> bvs_cmb;
174
2420
        bvs_cmb.insert(bvs_cmb.end(), bvs.begin(), bvs.end());
175
2420
        bvs_cmb.insert(bvs_cmb.end(), vars.begin(), vars.end());
176
2420
        vars.insert(vars.begin(), dt[j].getConstructor());
177
4840
        Node c = nm->mkNode(kind::APPLY_CONSTRUCTOR, vars);
178
4840
        TNode ct = c;
179
4840
        Node body = q[1].substitute(svar, ct);
180
2420
        if (!bvs_cmb.empty())
181
        {
182
4832
          Node bvl = nm->mkNode(kind::BOUND_VAR_LIST, bvs_cmb);
183
4832
          std::vector<Node> children;
184
2416
          children.push_back(bvl);
185
2416
          children.push_back(body);
186
2416
          if (q.getNumChildren() == 3)
187
          {
188
1724
            Node ipls = q[2].substitute(svar, ct);
189
862
            children.push_back(ipls);
190
          }
191
2416
          body = nm->mkNode(kind::FORALL, children);
192
        }
193
2420
        cons.push_back(body);
194
      }
195
3474
      Node conc = cons.size() == 1 ? cons[0] : nm->mkNode(kind::AND, cons);
196
1737
      disj.push_back(conc);
197
1737
      lemmas.push_back(disj.size() == 1 ? disj[0] : nm->mkNode(kind::OR, disj));
198
    }
199
  }
200
201
  // add lemmas to quantifiers engine
202
2328
  for (const Node& lem : lemmas)
203
  {
204
1737
    Trace("quant-dsplit") << "QuantDSplit lemma : " << lem << std::endl;
205
1737
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_DSPLIT);
206
  }
207
591
  Trace("quant-dsplit") << "QuantDSplit::check finished" << std::endl;
208
}
209
210
}  // namespace quantifiers
211
}  // namespace theory
212
28194
}  // namespace cvc5