GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quant_split.cpp Lines: 100 102 98.0 %
Date: 2021-09-18 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
5520
QuantDSplit::QuantDSplit(Env& env,
32
                         QuantifiersState& qs,
33
                         QuantifiersInferenceManager& qim,
34
                         QuantifiersRegistry& qr,
35
5520
                         TermRegistry& tr)
36
5520
    : QuantifiersModule(env, qs, qim, qr, tr), d_added_split(userContext())
37
{
38
5520
}
39
40
11390
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
22056
  QAttributes qa;
45
11390
  QuantAttributes::computeQuantAttributes(q, qa);
46
11390
  if (!qa.isStandard())
47
  {
48
724
    return;
49
  }
50
10666
  bool takeOwnership = false;
51
10666
  bool doSplit = false;
52
10666
  QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
53
10666
  Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl;
54
34296
  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
55
49072
    TypeNode tn = q[0][i].getType();
56
25442
    if( tn.isDatatype() ){
57
4627
      bool isFinite = d_qstate.isFiniteType(tn);
58
4627
      const DType& dt = tn.getDType();
59
4627
      if (dt.isRecursiveSingleton(tn))
60
      {
61
        Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl;
62
      }
63
      else
64
      {
65
4627
        if (options::quantDynamicSplit() == options::QuantDSplitMode::AGG)
66
        {
67
          // split if it is a finite datatype
68
          doSplit = isFinite;
69
        }
70
9254
        else if (options::quantDynamicSplit()
71
4627
                 == options::QuantDSplitMode::DEFAULT)
72
        {
73
4627
          if (!qbi.isFiniteBound(q, q[0][i]))
74
          {
75
4492
            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
902
              doSplit = true;
81
              // we additionally take ownership of this formula, in other words,
82
              // we mark it reduced.
83
902
              takeOwnership = true;
84
            }
85
3590
            else if (dt.getNumConstructors() == 1 && !dt.isCodatatype())
86
            {
87
              // split if only one constructor
88
910
              doSplit = true;
89
            }
90
          }
91
        }
92
4627
        if (doSplit)
93
        {
94
          // store the index to split
95
1812
          d_quant_to_reduce[q] = i;
96
3624
          Trace("quant-dsplit-debug")
97
3624
              << "Split at index " << i << " based on datatype " << dt.getName()
98
1812
              << std::endl;
99
1812
          break;
100
        }
101
5630
        Trace("quant-dsplit-debug")
102
2815
            << "Do not split based on datatype " << dt.getName() << std::endl;
103
      }
104
    }
105
  }
106
107
10666
  if (takeOwnership)
108
  {
109
902
    Trace("quant-dsplit-debug") << "Will take ownership." << std::endl;
110
902
    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
47303
bool QuantDSplit::needsCheck( Theory::Effort e ) {
121
47303
  return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty();
122
}
123
124
205
bool QuantDSplit::checkCompleteFor( Node q ) {
125
  // true if we split q
126
205
  return d_added_split.find( q )!=d_added_split.end();
127
}
128
129
/* Call during quantifier engine's check */
130
1602
void QuantDSplit::check(Theory::Effort e, QEffort quant_e)
131
{
132
  //add lemmas ASAP (they are a reduction)
133
1602
  if (quant_e != QEFFORT_CONFLICT)
134
  {
135
941
    return;
136
  }
137
661
  Trace("quant-dsplit") << "QuantDSplit::check" << std::endl;
138
661
  NodeManager* nm = NodeManager::currentNM();
139
661
  FirstOrderModel* m = d_treg.getModel();
140
1322
  std::vector<Node> lemmas;
141
28046
  for (std::map<Node, int>::iterator it = d_quant_to_reduce.begin();
142
28046
       it != d_quant_to_reduce.end();
143
       ++it)
144
  {
145
54770
    Node q = it->first;
146
27385
    Trace("quant-dsplit") << "- Split quantifier " << q << std::endl;
147
109515
    if (m->isQuantifierAsserted(q) && m->isQuantifierActive(q)
148
109515
        && d_added_split.find(q) == d_added_split.end())
149
    {
150
1804
      d_added_split.insert(q);
151
3608
      std::vector<Node> bvs;
152
7535
      for (unsigned i = 0, nvars = q[0].getNumChildren(); i < nvars; i++)
153
      {
154
5731
        if (static_cast<int>(i) != it->second)
155
        {
156
3927
          bvs.push_back(q[0][i]);
157
        }
158
      }
159
3608
      std::vector<Node> disj;
160
1804
      disj.push_back(q.negate());
161
3608
      TNode svar = q[0][it->second];
162
3608
      TypeNode tn = svar.getType();
163
1804
      Assert(tn.isDatatype());
164
3608
      std::vector<Node> cons;
165
1804
      const DType& dt = tn.getDType();
166
4273
      for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
167
      {
168
4938
        std::vector<Node> vars;
169
4938
        TypeNode dtjtn = dt[j].getSpecializedConstructorType(tn);
170
2469
        Assert(dtjtn.getNumChildren() == dt[j].getNumArgs() + 1);
171
6063
        for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
172
        {
173
7188
          TypeNode tns = dtjtn[k];
174
7188
          Node v = nm->mkBoundVar(tns);
175
3594
          vars.push_back(v);
176
        }
177
4938
        std::vector<Node> bvs_cmb;
178
2469
        bvs_cmb.insert(bvs_cmb.end(), bvs.begin(), bvs.end());
179
2469
        bvs_cmb.insert(bvs_cmb.end(), vars.begin(), vars.end());
180
4938
        Node c = datatypes::utils::mkApplyCons(tn, dt, j, vars);
181
4938
        TNode ct = c;
182
4938
        Node body = q[1].substitute(svar, ct);
183
2469
        if (!bvs_cmb.empty())
184
        {
185
4930
          Node bvl = nm->mkNode(kind::BOUND_VAR_LIST, bvs_cmb);
186
4930
          std::vector<Node> children;
187
2465
          children.push_back(bvl);
188
2465
          children.push_back(body);
189
2465
          if (q.getNumChildren() == 3)
190
          {
191
1764
            Node ipls = q[2].substitute(svar, ct);
192
882
            children.push_back(ipls);
193
          }
194
2465
          body = nm->mkNode(kind::FORALL, children);
195
        }
196
2469
        cons.push_back(body);
197
      }
198
3608
      Node conc = cons.size() == 1 ? cons[0] : nm->mkNode(kind::AND, cons);
199
1804
      disj.push_back(conc);
200
1804
      lemmas.push_back(disj.size() == 1 ? disj[0] : nm->mkNode(kind::OR, disj));
201
    }
202
  }
203
204
  // add lemmas to quantifiers engine
205
2465
  for (const Node& lem : lemmas)
206
  {
207
1804
    Trace("quant-dsplit") << "QuantDSplit lemma : " << lem << std::endl;
208
1804
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_DSPLIT);
209
  }
210
661
  Trace("quant-dsplit") << "QuantDSplit::check finished" << std::endl;
211
}
212
213
}  // namespace quantifiers
214
}  // namespace theory
215
29574
}  // namespace cvc5