GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/proof_node_algorithm.cpp Lines: 54 75 72.0 %
Date: 2021-05-22 Branches: 59 162 36.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa
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 proof node algorithm utilities.
14
 */
15
16
#include "expr/proof_node_algorithm.h"
17
18
#include "expr/proof_node.h"
19
20
namespace cvc5 {
21
namespace expr {
22
23
97270
void getFreeAssumptions(ProofNode* pn, std::vector<Node>& assump)
24
{
25
194540
  std::map<Node, std::vector<std::shared_ptr<ProofNode>>> amap;
26
  std::shared_ptr<ProofNode> spn = std::make_shared<ProofNode>(
27
194540
      pn->getRule(), pn->getChildren(), pn->getArguments());
28
97270
  getFreeAssumptionsMap(spn, amap);
29
97230
  for (const std::pair<const Node, std::vector<std::shared_ptr<ProofNode>>>& p :
30
97270
       amap)
31
  {
32
97230
    assump.push_back(p.first);
33
  }
34
97270
}
35
36
421778
void getFreeAssumptionsMap(
37
    std::shared_ptr<ProofNode> pn,
38
    std::map<Node, std::vector<std::shared_ptr<ProofNode>>>& amap)
39
{
40
  // proof should not be cyclic
41
  // visited set false after preorder traversal, true after postorder traversal
42
843556
  std::unordered_map<ProofNode*, bool> visited;
43
421778
  std::unordered_map<ProofNode*, bool>::iterator it;
44
843556
  std::vector<std::shared_ptr<ProofNode>> visit;
45
843556
  std::vector<std::shared_ptr<ProofNode>> traversing;
46
  // Maps a bound assumption to the number of bindings it is under
47
  // e.g. in (SCOPE (SCOPE (ASSUME x) (x y)) (y)), y would be mapped to 2 at
48
  // (ASSUME x), and x would be mapped to 1.
49
  //
50
  // This map is used to track which nodes are in scope while traversing the
51
  // DAG. The in-scope assumptions are keys in the map. They're removed when
52
  // their binding count drops to zero. Let's annotate the above example to
53
  // serve as an illustration:
54
  //
55
  //   (SCOPE0 (SCOPE1 (ASSUME x) (x y)) (y))
56
  //
57
  // This is how the map changes during the traversal:
58
  //   after  previsiting SCOPE0: { y: 1 }
59
  //   after  previsiting SCOPE1: { y: 2, x: 1 }
60
  //   at                 ASSUME: { y: 2, x: 1 } (so x is in scope!)
61
  //   after postvisiting SCOPE1: { y: 1 }
62
  //   after postvisiting SCOPE2: {}
63
  //
64
843556
  std::unordered_map<Node, uint32_t> scopeDepth;
65
843556
  std::shared_ptr<ProofNode> cur;
66
421778
  visit.push_back(pn);
67
16517427
  do
68
  {
69
16939205
    cur = visit.back();
70
16939205
    visit.pop_back();
71
16939205
    it = visited.find(cur.get());
72
16939205
    const std::vector<Node>& cargs = cur->getArguments();
73
16939205
    if (it == visited.end())
74
    {
75
9240082
      PfRule id = cur->getRule();
76
9240082
      if (id == PfRule::ASSUME)
77
      {
78
5476795
        visited[cur.get()] = true;
79
5476795
        Assert(cargs.size() == 1);
80
10953590
        Node f = cargs[0];
81
5476795
        if (!scopeDepth.count(f))
82
        {
83
4818383
          amap[f].push_back(cur);
84
        }
85
      }
86
      else
87
      {
88
3763287
        if (id == PfRule::SCOPE)
89
        {
90
          // mark that its arguments are bound in the current scope
91
810493
          for (const Node& a : cargs)
92
          {
93
659643
            scopeDepth[a] += 1;
94
          }
95
          // will need to unbind the variables below
96
        }
97
        // The following loop cannot be merged with the loop above because the
98
        // same subproof
99
3763287
        visited[cur.get()] = false;
100
3763287
        visit.push_back(cur);
101
3763287
        traversing.push_back(cur);
102
3763287
        const std::vector<std::shared_ptr<ProofNode>>& cs = cur->getChildren();
103
16517427
        for (const std::shared_ptr<ProofNode>& cp : cs)
104
        {
105
38262420
          if (std::find(traversing.begin(), traversing.end(), cp)
106
38262420
              != traversing.end())
107
          {
108
            Unhandled() << "getFreeAssumptionsMap: cyclic proof! (use "
109
                           "--proof-eager-checking)"
110
                        << std::endl;
111
          }
112
12754140
          visit.push_back(cp);
113
        }
114
      }
115
    }
116
7699123
    else if (!it->second)
117
    {
118
3763287
      Assert(!traversing.empty());
119
3763287
      traversing.pop_back();
120
3763287
      visited[cur.get()] = true;
121
3763287
      if (cur->getRule() == PfRule::SCOPE)
122
      {
123
        // unbind its assumptions
124
810493
        for (const Node& a : cargs)
125
        {
126
659643
          auto scopeCt = scopeDepth.find(a);
127
659643
          Assert(scopeCt != scopeDepth.end());
128
659643
          scopeCt->second -= 1;
129
659643
          if (scopeCt->second == 0)
130
          {
131
620357
            scopeDepth.erase(scopeCt);
132
          }
133
        }
134
      }
135
    }
136
16939205
  } while (!visit.empty());
137
421778
}
138
139
bool containsSubproof(ProofNode* pn, ProofNode* pnc)
140
{
141
  std::unordered_set<const ProofNode*> visited;
142
  return containsSubproof(pn, pnc, visited);
143
}
144
145
bool containsSubproof(ProofNode* pn,
146
                      ProofNode* pnc,
147
                      std::unordered_set<const ProofNode*>& visited)
148
{
149
  std::unordered_map<const ProofNode*, bool>::iterator it;
150
  std::vector<const ProofNode*> visit;
151
  visit.push_back(pn);
152
  const ProofNode* cur;
153
  while (!visit.empty())
154
  {
155
    cur = visit.back();
156
    visit.pop_back();
157
    if (visited.find(cur) == visited.end())
158
    {
159
      visited.insert(cur);
160
      if (cur == pnc)
161
      {
162
        return true;
163
      }
164
      const std::vector<std::shared_ptr<ProofNode>>& children =
165
          cur->getChildren();
166
      for (const std::shared_ptr<ProofNode>& cp : children)
167
      {
168
        visit.push_back(cp.get());
169
      }
170
    }
171
  }
172
  return false;
173
}
174
175
}  // namespace expr
176
28194
}  // namespace cvc5