GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_qe_preproc.cpp Lines: 82 83 98.8 %
Date: 2021-05-22 Branches: 178 376 47.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Morgan Deters
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
 * Sygus quantifier elimination preprocessor.
14
 */
15
16
#include "theory/quantifiers/sygus/sygus_qe_preproc.h"
17
18
#include "expr/node_algorithm.h"
19
#include "expr/skolem_manager.h"
20
#include "theory/quantifiers/single_inv_partition.h"
21
#include "theory/rewriter.h"
22
#include "theory/smt_engine_subsolver.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace quantifiers {
29
30
1529
SygusQePreproc::SygusQePreproc() {}
31
32
7
Node SygusQePreproc::preprocess(Node q)
33
{
34
14
  Node body = q[1];
35
7
  if (body.getKind() == NOT && body[0].getKind() == FORALL)
36
  {
37
5
    body = body[0][1];
38
  }
39
7
  NodeManager* nm = NodeManager::currentNM();
40
7
  SkolemManager* sm = nm->getSkolemManager();
41
14
  Trace("cegqi-qep") << "Compute single invocation for " << q << "..."
42
7
                     << std::endl;
43
14
  quantifiers::SingleInvocationPartition sip;
44
14
  std::vector<Node> funcs0;
45
7
  funcs0.insert(funcs0.end(), q[0].begin(), q[0].end());
46
7
  sip.init(funcs0, body);
47
7
  Trace("cegqi-qep") << "...finished, got:" << std::endl;
48
7
  sip.debugPrint("cegqi-qep");
49
50
7
  if (sip.isPurelySingleInvocation() || !sip.isNonGroundSingleInvocation())
51
  {
52
4
    return Node::null();
53
  }
54
  // create new smt engine to do quantifier elimination
55
6
  std::unique_ptr<SmtEngine> smt_qe;
56
3
  initializeSubsolver(smt_qe);
57
6
  Trace("cegqi-qep") << "Property is non-ground single invocation, run "
58
3
                        "QE to obtain single invocation."
59
3
                     << std::endl;
60
  // partition variables
61
6
  std::vector<Node> all_vars;
62
3
  sip.getAllVariables(all_vars);
63
6
  std::vector<Node> si_vars;
64
3
  sip.getSingleInvocationVariables(si_vars);
65
6
  std::vector<Node> qe_vars;
66
6
  std::vector<Node> nqe_vars;
67
74
  for (unsigned i = 0, size = all_vars.size(); i < size; i++)
68
  {
69
142
    Node v = all_vars[i];
70
71
    if (std::find(funcs0.begin(), funcs0.end(), v) != funcs0.end())
71
    {
72
65
      Trace("cegqi-qep") << "- fun var: " << v << std::endl;
73
    }
74
6
    else if (std::find(si_vars.begin(), si_vars.end(), v) == si_vars.end())
75
    {
76
3
      qe_vars.push_back(v);
77
3
      Trace("cegqi-qep") << "- qe var: " << v << std::endl;
78
    }
79
    else
80
    {
81
3
      nqe_vars.push_back(v);
82
3
      Trace("cegqi-qep") << "- non qe var: " << v << std::endl;
83
    }
84
  }
85
6
  std::vector<Node> orig;
86
6
  std::vector<Node> subs;
87
  // skolemize non-qe variables
88
6
  for (unsigned i = 0, size = nqe_vars.size(); i < size; i++)
89
  {
90
    Node k = sm->mkDummySkolem(
91
6
        "k", nqe_vars[i].getType(), "qe for non-ground single invocation");
92
3
    orig.push_back(nqe_vars[i]);
93
3
    subs.push_back(k);
94
6
    Trace("cegqi-qep") << "  subs : " << nqe_vars[i] << " -> " << k
95
3
                       << std::endl;
96
  }
97
6
  std::vector<Node> funcs1;
98
3
  sip.getFunctions(funcs1);
99
68
  for (unsigned i = 0, size = funcs1.size(); i < size; i++)
100
  {
101
130
    Node f = funcs1[i];
102
130
    Node fi = sip.getFunctionInvocationFor(f);
103
130
    Node fv = sip.getFirstOrderVariableForFunction(f);
104
65
    Assert(!fi.isNull());
105
65
    orig.push_back(fi);
106
    Node k = sm->mkDummySkolem(
107
130
        "k", fv.getType(), "qe for function in non-ground single invocation");
108
65
    subs.push_back(k);
109
65
    Trace("cegqi-qep") << "  subs : " << fi << " -> " << k << std::endl;
110
  }
111
6
  Node conj_se_ngsi = sip.getFullSpecification();
112
3
  Trace("cegqi-qep") << "Full specification is " << conj_se_ngsi << std::endl;
113
  Node conj_se_ngsi_subs = conj_se_ngsi.substitute(
114
6
      orig.begin(), orig.end(), subs.begin(), subs.end());
115
3
  Assert(!qe_vars.empty());
116
9
  conj_se_ngsi_subs = nm->mkNode(
117
12
      EXISTS, nm->mkNode(BOUND_VAR_LIST, qe_vars), conj_se_ngsi_subs.negate());
118
119
6
  Trace("cegqi-qep") << "Run quantifier elimination on " << conj_se_ngsi_subs
120
3
                     << std::endl;
121
6
  Node qeRes = smt_qe->getQuantifierElimination(conj_se_ngsi_subs, true, false);
122
3
  Trace("cegqi-qep") << "Result : " << qeRes << std::endl;
123
124
  // create single invocation conjecture, if QE was successful
125
3
  if (!expr::hasBoundVar(qeRes))
126
  {
127
3
    qeRes =
128
6
        qeRes.substitute(subs.begin(), subs.end(), orig.begin(), orig.end());
129
3
    if (!nqe_vars.empty())
130
    {
131
1
      qeRes = nm->mkNode(EXISTS, nm->mkNode(BOUND_VAR_LIST, nqe_vars), qeRes);
132
    }
133
3
    Assert(q.getNumChildren() == 3);
134
3
    qeRes = nm->mkNode(FORALL, q[0], qeRes, q[2]);
135
6
    Trace("cegqi-qep") << "Converted conjecture after QE : " << qeRes
136
3
                       << std::endl;
137
3
    qeRes = Rewriter::rewrite(qeRes);
138
6
    Node nq = qeRes;
139
    // must assert it is equivalent to the original
140
6
    Node lem = q.eqNode(nq);
141
6
    Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
142
3
                         << std::endl;
143
3
    return lem;
144
  }
145
  return Node::null();
146
}
147
148
}  // namespace quantifiers
149
}  // namespace theory
150
28194
}  // namespace cvc5