GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quant_split.cpp Lines: 100 102 98.0 %
Date: 2021-09-07 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
5516
QuantDSplit::QuantDSplit(QuantifiersState& qs,
32
                         QuantifiersInferenceManager& qim,
33
                         QuantifiersRegistry& qr,
34
5516
                         TermRegistry& tr)
35
5516
    : QuantifiersModule(qs, qim, qr, tr), d_added_split(qs.getUserContext())
36
{
37
5516
}
38
39
11356
void QuantDSplit::checkOwnership(Node q)
40
{
41
  // If q is non-standard (marked as sygus, quantifier elimination, etc.), then
42
  // do no split it.
43
21992
  QAttributes qa;
44
11356
  QuantAttributes::computeQuantAttributes(q, qa);
45
11356
  if (!qa.isStandard())
46
  {
47
720
    return;
48
  }
49
10636
  bool takeOwnership = false;
50
10636
  bool doSplit = false;
51
10636
  QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
52
10636
  Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl;
53
34225
  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
54
48990
    TypeNode tn = q[0][i].getType();
55
25401
    if( tn.isDatatype() ){
56
4630
      bool isFinite = d_qstate.isFiniteType(tn);
57
4630
      const DType& dt = tn.getDType();
58
4630
      if (dt.isRecursiveSingleton(tn))
59
      {
60
        Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl;
61
      }
62
      else
63
      {
64
4630
        if (options::quantDynamicSplit() == options::QuantDSplitMode::AGG)
65
        {
66
          // split if it is a finite datatype
67
          doSplit = isFinite;
68
        }
69
9260
        else if (options::quantDynamicSplit()
70
4630
                 == options::QuantDSplitMode::DEFAULT)
71
        {
72
4630
          if (!qbi.isFiniteBound(q, q[0][i]))
73
          {
74
4495
            if (isFinite)
75
            {
76
              // split if goes from being unhandled -> handled by finite
77
              // instantiation. An example is datatypes with uninterpreted sort
78
              // fields which are "interpreted finite" but not "finite".
79
902
              doSplit = true;
80
              // we additionally take ownership of this formula, in other words,
81
              // we mark it reduced.
82
902
              takeOwnership = true;
83
            }
84
3593
            else if (dt.getNumConstructors() == 1 && !dt.isCodatatype())
85
            {
86
              // split if only one constructor
87
910
              doSplit = true;
88
            }
89
          }
90
        }
91
4630
        if (doSplit)
92
        {
93
          // store the index to split
94
1812
          d_quant_to_reduce[q] = i;
95
3624
          Trace("quant-dsplit-debug")
96
3624
              << "Split at index " << i << " based on datatype " << dt.getName()
97
1812
              << std::endl;
98
1812
          break;
99
        }
100
5636
        Trace("quant-dsplit-debug")
101
2818
            << "Do not split based on datatype " << dt.getName() << std::endl;
102
      }
103
    }
104
  }
105
106
10636
  if (takeOwnership)
107
  {
108
902
    Trace("quant-dsplit-debug") << "Will take ownership." << std::endl;
109
902
    d_qreg.setOwner(q, this);
110
  }
111
  // Notice we may not take ownership in some cases, meaning that both the
112
  // original quantified formula and the split one are generated. This may
113
  // increase our ability to answer "unsat", since quantifier instantiation
114
  // heuristics may be more effective for one or the other (see issues #993
115
  // and 3481).
116
}
117
118
/* whether this module needs to check this round */
119
48308
bool QuantDSplit::needsCheck( Theory::Effort e ) {
120
48308
  return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty();
121
}
122
123
200
bool QuantDSplit::checkCompleteFor( Node q ) {
124
  // true if we split q
125
200
  return d_added_split.find( q )!=d_added_split.end();
126
}
127
128
/* Call during quantifier engine's check */
129
2178
void QuantDSplit::check(Theory::Effort e, QEffort quant_e)
130
{
131
  //add lemmas ASAP (they are a reduction)
132
2178
  if (quant_e != QEFFORT_CONFLICT)
133
  {
134
1359
    return;
135
  }
136
819
  Trace("quant-dsplit") << "QuantDSplit::check" << std::endl;
137
819
  NodeManager* nm = NodeManager::currentNM();
138
819
  FirstOrderModel* m = d_treg.getModel();
139
1638
  std::vector<Node> lemmas;
140
28362
  for (std::map<Node, int>::iterator it = d_quant_to_reduce.begin();
141
28362
       it != d_quant_to_reduce.end();
142
       ++it)
143
  {
144
55086
    Node q = it->first;
145
27543
    Trace("quant-dsplit") << "- Split quantifier " << q << std::endl;
146
109989
    if (m->isQuantifierAsserted(q) && m->isQuantifierActive(q)
147
109989
        && d_added_split.find(q) == d_added_split.end())
148
    {
149
1804
      d_added_split.insert(q);
150
3608
      std::vector<Node> bvs;
151
7535
      for (unsigned i = 0, nvars = q[0].getNumChildren(); i < nvars; i++)
152
      {
153
5731
        if (static_cast<int>(i) != it->second)
154
        {
155
3927
          bvs.push_back(q[0][i]);
156
        }
157
      }
158
3608
      std::vector<Node> disj;
159
1804
      disj.push_back(q.negate());
160
3608
      TNode svar = q[0][it->second];
161
3608
      TypeNode tn = svar.getType();
162
1804
      Assert(tn.isDatatype());
163
3608
      std::vector<Node> cons;
164
1804
      const DType& dt = tn.getDType();
165
4273
      for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
166
      {
167
4938
        std::vector<Node> vars;
168
4938
        TypeNode dtjtn = dt[j].getSpecializedConstructorType(tn);
169
2469
        Assert(dtjtn.getNumChildren() == dt[j].getNumArgs() + 1);
170
6063
        for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
171
        {
172
7188
          TypeNode tns = dtjtn[k];
173
7188
          Node v = nm->mkBoundVar(tns);
174
3594
          vars.push_back(v);
175
        }
176
4938
        std::vector<Node> bvs_cmb;
177
2469
        bvs_cmb.insert(bvs_cmb.end(), bvs.begin(), bvs.end());
178
2469
        bvs_cmb.insert(bvs_cmb.end(), vars.begin(), vars.end());
179
4938
        Node c = datatypes::utils::mkApplyCons(tn, dt, j, vars);
180
4938
        TNode ct = c;
181
4938
        Node body = q[1].substitute(svar, ct);
182
2469
        if (!bvs_cmb.empty())
183
        {
184
4930
          Node bvl = nm->mkNode(kind::BOUND_VAR_LIST, bvs_cmb);
185
4930
          std::vector<Node> children;
186
2465
          children.push_back(bvl);
187
2465
          children.push_back(body);
188
2465
          if (q.getNumChildren() == 3)
189
          {
190
1764
            Node ipls = q[2].substitute(svar, ct);
191
882
            children.push_back(ipls);
192
          }
193
2465
          body = nm->mkNode(kind::FORALL, children);
194
        }
195
2469
        cons.push_back(body);
196
      }
197
3608
      Node conc = cons.size() == 1 ? cons[0] : nm->mkNode(kind::AND, cons);
198
1804
      disj.push_back(conc);
199
1804
      lemmas.push_back(disj.size() == 1 ? disj[0] : nm->mkNode(kind::OR, disj));
200
    }
201
  }
202
203
  // add lemmas to quantifiers engine
204
2623
  for (const Node& lem : lemmas)
205
  {
206
1804
    Trace("quant-dsplit") << "QuantDSplit lemma : " << lem << std::endl;
207
1804
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_DSPLIT);
208
  }
209
819
  Trace("quant-dsplit") << "QuantDSplit::check finished" << std::endl;
210
}
211
212
}  // namespace quantifiers
213
}  // namespace theory
214
29502
}  // namespace cvc5