GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quant_split.cpp Lines: 99 101 98.0 %
Date: 2021-08-20 Branches: 197 372 53.0 %

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
5418
QuantDSplit::QuantDSplit(QuantifiersState& qs,
31
                         QuantifiersInferenceManager& qim,
32
                         QuantifiersRegistry& qr,
33
5418
                         TermRegistry& tr)
34
5418
    : QuantifiersModule(qs, qim, qr, tr), d_added_split(qs.getUserContext())
35
{
36
5418
}
37
38
11327
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
21944
  QAttributes qa;
43
11327
  QuantAttributes::computeQuantAttributes(q, qa);
44
11327
  if (!qa.isStandard())
45
  {
46
710
    return;
47
  }
48
10617
  bool takeOwnership = false;
49
10617
  bool doSplit = false;
50
10617
  QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
51
10617
  Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl;
52
34178
  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
53
48930
    TypeNode tn = q[0][i].getType();
54
25369
    if( tn.isDatatype() ){
55
4626
      bool isFinite = d_qstate.isFiniteType(tn);
56
4626
      const DType& dt = tn.getDType();
57
4626
      if (dt.isRecursiveSingleton(tn))
58
      {
59
        Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl;
60
      }
61
      else
62
      {
63
4626
        if (options::quantDynamicSplit() == options::QuantDSplitMode::AGG)
64
        {
65
          // split if it is a finite datatype
66
          doSplit = isFinite;
67
        }
68
9252
        else if (options::quantDynamicSplit()
69
4626
                 == options::QuantDSplitMode::DEFAULT)
70
        {
71
4626
          if (!qbi.isFiniteBound(q, q[0][i]))
72
          {
73
4491
            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
898
              doSplit = true;
79
              // we additionally take ownership of this formula, in other words,
80
              // we mark it reduced.
81
898
              takeOwnership = true;
82
            }
83
3593
            else if (dt.getNumConstructors() == 1 && !dt.isCodatatype())
84
            {
85
              // split if only one constructor
86
910
              doSplit = true;
87
            }
88
          }
89
        }
90
4626
        if (doSplit)
91
        {
92
          // store the index to split
93
1808
          d_quant_to_reduce[q] = i;
94
3616
          Trace("quant-dsplit-debug")
95
3616
              << "Split at index " << i << " based on datatype " << dt.getName()
96
1808
              << std::endl;
97
1808
          break;
98
        }
99
5636
        Trace("quant-dsplit-debug")
100
2818
            << "Do not split based on datatype " << dt.getName() << std::endl;
101
      }
102
    }
103
  }
104
105
10617
  if (takeOwnership)
106
  {
107
898
    Trace("quant-dsplit-debug") << "Will take ownership." << std::endl;
108
898
    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
48070
bool QuantDSplit::needsCheck( Theory::Effort e ) {
119
48070
  return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty();
120
}
121
122
197
bool QuantDSplit::checkCompleteFor( Node q ) {
123
  // true if we split q
124
197
  return d_added_split.find( q )!=d_added_split.end();
125
}
126
127
/* Call during quantifier engine's check */
128
3457
void QuantDSplit::check(Theory::Effort e, QEffort quant_e)
129
{
130
  //add lemmas ASAP (they are a reduction)
131
3457
  if (quant_e != QEFFORT_CONFLICT)
132
  {
133
2295
    return;
134
  }
135
1162
  Trace("quant-dsplit") << "QuantDSplit::check" << std::endl;
136
1162
  NodeManager* nm = NodeManager::currentNM();
137
1162
  FirstOrderModel* m = d_treg.getModel();
138
2324
  std::vector<Node> lemmas;
139
28982
  for (std::map<Node, int>::iterator it = d_quant_to_reduce.begin();
140
28982
       it != d_quant_to_reduce.end();
141
       ++it)
142
  {
143
55640
    Node q = it->first;
144
27820
    Trace("quant-dsplit") << "- Split quantifier " << q << std::endl;
145
110747
    if (m->isQuantifierAsserted(q) && m->isQuantifierActive(q)
146
110747
        && d_added_split.find(q) == d_added_split.end())
147
    {
148
1800
      d_added_split.insert(q);
149
3600
      std::vector<Node> bvs;
150
7518
      for (unsigned i = 0, nvars = q[0].getNumChildren(); i < nvars; i++)
151
      {
152
5718
        if (static_cast<int>(i) != it->second)
153
        {
154
3918
          bvs.push_back(q[0][i]);
155
        }
156
      }
157
3600
      std::vector<Node> disj;
158
1800
      disj.push_back(q.negate());
159
3600
      TNode svar = q[0][it->second];
160
3600
      TypeNode tn = svar.getType();
161
1800
      Assert(tn.isDatatype());
162
3600
      std::vector<Node> cons;
163
1800
      const DType& dt = tn.getDType();
164
4265
      for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
165
      {
166
4930
        std::vector<Node> vars;
167
6055
        for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
168
        {
169
7180
          TypeNode tns = dt[j][k].getRangeType();
170
7180
          Node v = nm->mkBoundVar(tns);
171
3590
          vars.push_back(v);
172
        }
173
4930
        std::vector<Node> bvs_cmb;
174
2465
        bvs_cmb.insert(bvs_cmb.end(), bvs.begin(), bvs.end());
175
2465
        bvs_cmb.insert(bvs_cmb.end(), vars.begin(), vars.end());
176
2465
        vars.insert(vars.begin(), dt[j].getConstructor());
177
4930
        Node c = nm->mkNode(kind::APPLY_CONSTRUCTOR, vars);
178
4930
        TNode ct = c;
179
4930
        Node body = q[1].substitute(svar, ct);
180
2465
        if (!bvs_cmb.empty())
181
        {
182
4922
          Node bvl = nm->mkNode(kind::BOUND_VAR_LIST, bvs_cmb);
183
4922
          std::vector<Node> children;
184
2461
          children.push_back(bvl);
185
2461
          children.push_back(body);
186
2461
          if (q.getNumChildren() == 3)
187
          {
188
1782
            Node ipls = q[2].substitute(svar, ct);
189
891
            children.push_back(ipls);
190
          }
191
2461
          body = nm->mkNode(kind::FORALL, children);
192
        }
193
2465
        cons.push_back(body);
194
      }
195
3600
      Node conc = cons.size() == 1 ? cons[0] : nm->mkNode(kind::AND, cons);
196
1800
      disj.push_back(conc);
197
1800
      lemmas.push_back(disj.size() == 1 ? disj[0] : nm->mkNode(kind::OR, disj));
198
    }
199
  }
200
201
  // add lemmas to quantifiers engine
202
2962
  for (const Node& lem : lemmas)
203
  {
204
1800
    Trace("quant-dsplit") << "QuantDSplit lemma : " << lem << std::endl;
205
1800
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_DSPLIT);
206
  }
207
1162
  Trace("quant-dsplit") << "QuantDSplit::check finished" << std::endl;
208
}
209
210
}  // namespace quantifiers
211
}  // namespace theory
212
29358
}  // namespace cvc5