GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quant_split.cpp Lines: 100 102 98.0 %
Date: 2021-09-29 Branches: 201 392 51.3 %

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