GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_preprocess.cpp Lines: 71 130 54.6 %
Date: 2021-09-17 Branches: 168 632 26.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds
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
 * Preprocessor for the theory of quantifiers.
14
 */
15
16
#include "theory/quantifiers/quantifiers_preprocess.h"
17
18
#include "expr/node_algorithm.h"
19
#include "options/quantifiers_options.h"
20
#include "theory/quantifiers/quant_util.h"
21
#include "theory/quantifiers/quantifiers_rewriter.h"
22
#include "theory/quantifiers/skolemize.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace quantifiers {
29
30
18168
QuantifiersPreprocess::QuantifiersPreprocess(Env& env) : EnvObj(env) {}
31
32
Node QuantifiersPreprocess::computePrenexAgg(
33
    Node n, std::map<Node, Node>& visited) const
34
{
35
  std::map<Node, Node>::iterator itv = visited.find(n);
36
  if (itv != visited.end())
37
  {
38
    return itv->second;
39
  }
40
  if (!expr::hasClosure(n))
41
  {
42
    // trivial
43
    return n;
44
  }
45
  NodeManager* nm = NodeManager::currentNM();
46
  Node ret = n;
47
  if (n.getKind() == NOT)
48
  {
49
    ret = computePrenexAgg(n[0], visited).negate();
50
  }
51
  else if (n.getKind() == FORALL)
52
  {
53
    std::vector<Node> children;
54
    children.push_back(computePrenexAgg(n[1], visited));
55
    std::vector<Node> args;
56
    args.insert(args.end(), n[0].begin(), n[0].end());
57
    // for each child, strip top level quant
58
    for (unsigned i = 0; i < children.size(); i++)
59
    {
60
      if (children[i].getKind() == FORALL)
61
      {
62
        args.insert(args.end(), children[i][0].begin(), children[i][0].end());
63
        children[i] = children[i][1];
64
      }
65
    }
66
    // keep the pattern
67
    std::vector<Node> iplc;
68
    if (n.getNumChildren() == 3)
69
    {
70
      iplc.insert(iplc.end(), n[2].begin(), n[2].end());
71
    }
72
    Node nb = nm->mkOr(children);
73
    ret = QuantifiersRewriter::mkForall(args, nb, iplc, true);
74
  }
75
  else
76
  {
77
    std::unordered_set<Node> argsSet;
78
    std::unordered_set<Node> nargsSet;
79
    Node q;
80
    QuantifiersRewriter qrew(options());
81
    Node nn = qrew.computePrenex(q, n, argsSet, nargsSet, true, true);
82
    Assert(n != nn || argsSet.empty());
83
    Assert(n != nn || nargsSet.empty());
84
    if (n != nn)
85
    {
86
      Node nnn = computePrenexAgg(nn, visited);
87
      // merge prenex
88
      if (nnn.getKind() == FORALL)
89
      {
90
        argsSet.insert(nnn[0].begin(), nnn[0].end());
91
        nnn = nnn[1];
92
        // pos polarity variables are inner
93
        if (!argsSet.empty())
94
        {
95
          nnn = QuantifiersRewriter::mkForall(
96
              {argsSet.begin(), argsSet.end()}, nnn, true);
97
        }
98
        argsSet.clear();
99
      }
100
      else if (nnn.getKind() == NOT && nnn[0].getKind() == FORALL)
101
      {
102
        nargsSet.insert(nnn[0][0].begin(), nnn[0][0].end());
103
        nnn = nnn[0][1].negate();
104
      }
105
      if (!nargsSet.empty())
106
      {
107
        nnn = QuantifiersRewriter::mkForall(
108
                  {nargsSet.begin(), nargsSet.end()}, nnn.negate(), true)
109
                  .negate();
110
      }
111
      if (!argsSet.empty())
112
      {
113
        nnn = QuantifiersRewriter::mkForall(
114
            {argsSet.begin(), argsSet.end()}, nnn, true);
115
      }
116
      ret = nnn;
117
    }
118
  }
119
  visited[n] = ret;
120
  return ret;
121
}
122
123
632
Node QuantifiersPreprocess::preSkolemizeQuantifiers(
124
    Node n,
125
    bool polarity,
126
    std::vector<TNode>& fvs,
127
    std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>&
128
        visited) const
129
{
130
1264
  std::pair<Node, bool> key(n, polarity);
131
  std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>::
132
632
      iterator it = visited.find(key);
133
632
  if (it != visited.end())
134
  {
135
12
    return it->second;
136
  }
137
620
  NodeManager* nm = NodeManager::currentNM();
138
1240
  Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size()
139
620
                  << std::endl;
140
620
  if (n.getKind() == FORALL)
141
  {
142
324
    Node ret = n;
143
162
    if (n.getNumChildren() == 3)
144
    {
145
      // Do not pre-skolemize quantified formulas with three children.
146
      // This includes non-standard quantified formulas
147
      // like recursive function definitions, or sygus conjectures, and
148
      // quantified formulas with triggers.
149
    }
150
74
    else if (polarity)
151
    {
152
112
      if (options().quantifiers.preSkolemQuant
153
56
          && options().quantifiers.preSkolemQuantNested)
154
      {
155
84
        std::vector<Node> children;
156
42
        children.push_back(n[0]);
157
        // add children to current scope
158
84
        std::vector<TNode> fvss;
159
42
        fvss.insert(fvss.end(), fvs.begin(), fvs.end());
160
42
        fvss.insert(fvss.end(), n[0].begin(), n[0].end());
161
        // process body in a new context
162
        std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>
163
84
            visitedSub;
164
84
        Node pbody = preSkolemizeQuantifiers(n[1], polarity, fvss, visitedSub);
165
42
        children.push_back(pbody);
166
        // return processed quantifier
167
42
        ret = nm->mkNode(FORALL, children);
168
      }
169
    }
170
    else
171
    {
172
      // will skolemize current, process body
173
36
      Node nn = preSkolemizeQuantifiers(n[1], polarity, fvs, visited);
174
36
      std::vector<Node> sk;
175
36
      Node sub;
176
36
      std::vector<unsigned> sub_vars;
177
      // return skolemized body
178
18
      ret = Skolemize::mkSkolemizedBody(n, nn, fvs, sk, sub, sub_vars);
179
    }
180
162
    visited[key] = ret;
181
162
    return ret;
182
  }
183
  // check if it contains a quantifier as a subterm
184
  // if so, we may preprocess this node
185
458
  if (!expr::hasClosure(n))
186
  {
187
366
    visited[key] = n;
188
366
    return n;
189
  }
190
92
  Kind k = n.getKind();
191
184
  Node ret = n;
192
92
  Assert(n.getType().isBoolean());
193
92
  if (k == ITE || (k == EQUAL && n[0].getType().isBoolean()))
194
  {
195
10
    if (options().quantifiers.preSkolemQuantAgg)
196
    {
197
20
      Node nn;
198
      // must remove structure
199
10
      if (k == ITE)
200
      {
201
        nn = nm->mkNode(AND,
202
                        nm->mkNode(OR, n[0].notNode(), n[1]),
203
                        nm->mkNode(OR, n[0], n[2]));
204
      }
205
10
      else if (k == EQUAL)
206
      {
207
30
        nn = nm->mkNode(AND,
208
20
                        nm->mkNode(OR, n[0].notNode(), n[1]),
209
20
                        nm->mkNode(OR, n[0], n[1].notNode()));
210
      }
211
10
      ret = preSkolemizeQuantifiers(nn, polarity, fvs, visited);
212
    }
213
  }
214
82
  else if (k == AND || k == OR || k == NOT || k == IMPLIES)
215
  {
216
160
    std::vector<Node> children;
217
206
    for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
218
    {
219
      bool newHasPol;
220
      bool newPol;
221
126
      QuantPhaseReq::getPolarity(n, i, true, polarity, newHasPol, newPol);
222
126
      Assert(newHasPol);
223
126
      children.push_back(preSkolemizeQuantifiers(n[i], newPol, fvs, visited));
224
    }
225
80
    ret = nm->mkNode(k, children);
226
  }
227
92
  visited[key] = ret;
228
92
  return ret;
229
}
230
231
97464
TrustNode QuantifiersPreprocess::preprocess(Node n, bool isInst) const
232
{
233
194928
  Node prev = n;
234
97464
  if (options().quantifiers.preSkolemQuant)
235
  {
236
494
    if (!isInst || !options().quantifiers.preSkolemQuantNested)
237
    {
238
872
      Trace("quantifiers-preprocess-debug")
239
436
          << "Pre-skolemize " << n << "..." << std::endl;
240
      // apply pre-skolemization to existential quantifiers
241
872
      std::vector<TNode> fvs;
242
      std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>
243
872
          visited;
244
436
      n = preSkolemizeQuantifiers(prev, true, fvs, visited);
245
    }
246
  }
247
  // pull all quantifiers globally
248
97464
  if (options().quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
249
  {
250
    Trace("quantifiers-prenex") << "Prenexing : " << n << std::endl;
251
    std::map<Node, Node> visited;
252
    n = computePrenexAgg(n, visited);
253
    n = rewrite(n);
254
    Trace("quantifiers-prenex") << "Prenexing returned : " << n << std::endl;
255
  }
256
97464
  if (n != prev)
257
  {
258
16
    Trace("quantifiers-preprocess") << "Preprocess " << prev << std::endl;
259
16
    Trace("quantifiers-preprocess") << "..returned " << n << std::endl;
260
16
    return TrustNode::mkTrustRewrite(prev, n, nullptr);
261
  }
262
97448
  return TrustNode::null();
263
}
264
265
}  // namespace quantifiers
266
}  // namespace theory
267
29577
}  // namespace cvc5