GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/witness_form.cpp Lines: 45 64 70.3 %
Date: 2021-11-07 Branches: 81 296 27.4 %

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
 * The module for managing witness form conversion in proofs.
14
 */
15
16
#include "smt/witness_form.h"
17
18
#include "expr/skolem_manager.h"
19
#include "smt/env.h"
20
#include "theory/rewriter.h"
21
22
namespace cvc5 {
23
namespace smt {
24
25
7989
WitnessFormGenerator::WitnessFormGenerator(Env& env)
26
7989
    : d_rewriter(env.getRewriter()),
27
      d_tcpg(env.getProofNodeManager(),
28
             nullptr,
29
             TConvPolicy::FIXPOINT,
30
             TConvCachePolicy::NEVER,
31
             "WfGenerator::TConvProofGenerator",
32
             nullptr,
33
             true),
34
      d_wintroPf(env.getProofNodeManager(),
35
                 nullptr,
36
                 nullptr,
37
                 "WfGenerator::LazyCDProof"),
38
      d_pskPf(
39
15978
          env.getProofNodeManager(), nullptr, "WfGenerator::PurifySkolemProof")
40
{
41
7989
}
42
43
8830
std::shared_ptr<ProofNode> WitnessFormGenerator::getProofFor(Node eq)
44
{
45
8830
  if (eq.getKind() != kind::EQUAL)
46
  {
47
    // expecting an equality
48
    return nullptr;
49
  }
50
17660
  Node lhs = eq[0];
51
17660
  Node rhs = convertToWitnessForm(eq[0]);
52
8830
  if (rhs != eq[1])
53
  {
54
    // expecting witness form
55
    return nullptr;
56
  }
57
17660
  std::shared_ptr<ProofNode> pn = d_tcpg.getProofFor(eq);
58
8830
  Assert(pn != nullptr);
59
8830
  return pn;
60
}
61
62
std::string WitnessFormGenerator::identify() const
63
{
64
  return "WitnessFormGenerator";
65
}
66
67
8830
Node WitnessFormGenerator::convertToWitnessForm(Node t)
68
{
69
8830
  Node tw = SkolemManager::getOriginalForm(t);
70
8830
  if (t == tw)
71
  {
72
    // trivial case
73
    return tw;
74
  }
75
8830
  std::unordered_set<TNode>::iterator it;
76
17660
  std::vector<TNode> visit;
77
17660
  TNode cur;
78
17660
  TNode curw;
79
8830
  visit.push_back(t);
80
62949
  do
81
  {
82
71779
    cur = visit.back();
83
71779
    visit.pop_back();
84
71779
    it = d_visited.find(cur);
85
71779
    if (it == d_visited.end())
86
    {
87
29617
      d_visited.insert(cur);
88
29617
      curw = SkolemManager::getOriginalForm(cur);
89
      // if its witness form is different
90
29617
      if (cur != curw)
91
      {
92
21174
        if (cur.isVar())
93
        {
94
7168
          Node eq = cur.eqNode(curw);
95
          // equality between a variable and its original form
96
3584
          d_eqs.insert(eq);
97
          // ------- SKOLEM_INTRO
98
          // k = t
99
3584
          d_wintroPf.addStep(eq, PfRule::SKOLEM_INTRO, {}, {cur});
100
3584
          d_tcpg.addRewriteStep(
101
              cur, curw, &d_wintroPf, true, PfRule::ASSUME, true);
102
        }
103
        else
104
        {
105
          // A term whose witness form is different from itself, recurse.
106
          // It should be the case that cur has children, since the witness
107
          // form of constants are themselves.
108
17590
          Assert(cur.getNumChildren() > 0);
109
17590
          if (cur.hasOperator())
110
          {
111
17590
            visit.push_back(cur.getOperator());
112
          }
113
17590
          visit.insert(visit.end(), cur.begin(), cur.end());
114
        }
115
      }
116
    }
117
71779
  } while (!visit.empty());
118
8830
  return tw;
119
}
120
121
36327
bool WitnessFormGenerator::requiresWitnessFormTransform(Node t, Node s) const
122
{
123
36327
  return d_rewriter->rewrite(t) != d_rewriter->rewrite(s);
124
}
125
126
8066
bool WitnessFormGenerator::requiresWitnessFormIntro(Node t) const
127
{
128
16132
  Node tr = d_rewriter->rewrite(t);
129
16132
  return !tr.isConst() || !tr.getConst<bool>();
130
}
131
132
const std::unordered_set<Node>& WitnessFormGenerator::getWitnessFormEqs() const
133
{
134
  return d_eqs;
135
}
136
137
ProofGenerator* WitnessFormGenerator::convertExistsInternal(Node exists)
138
{
139
  Assert(exists.getKind() == kind::EXISTS);
140
  if (exists[0].getNumChildren() == 1 && exists[1].getKind() == kind::EQUAL
141
      && exists[1][0] == exists[0][0])
142
  {
143
    Node tpurified = exists[1][1];
144
    Trace("witness-form") << "convertExistsInternal: infer purification "
145
                          << exists << " for " << tpurified << std::endl;
146
    // ------ REFL
147
    // t = t
148
    // ---------------- EXISTS_INTRO
149
    // exists x. x = t
150
    // The concluded existential is then used to construct the witness term
151
    // via witness intro.
152
    Node teq = tpurified.eqNode(tpurified);
153
    d_pskPf.addStep(teq, PfRule::REFL, {}, {tpurified});
154
    d_pskPf.addStep(exists, PfRule::EXISTS_INTRO, {teq}, {exists});
155
    return &d_pskPf;
156
  }
157
  return nullptr;
158
}
159
160
}  // namespace smt
161
31137
}  // namespace cvc5