GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/printer/let_binding.h Lines: 1 1 100.0 %
Date: 2021-08-16 Branches: 0 0 0.0 %

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
 * A let binding.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__PRINTER__LET_BINDING_H
19
#define CVC5__PRINTER__LET_BINDING_H
20
21
#include <vector>
22
23
#include "context/cdhashmap.h"
24
#include "context/cdlist.h"
25
#include "expr/node.h"
26
27
namespace cvc5 {
28
29
/**
30
 * A flexible let binding class. This class provides functionalities for
31
 * printing letified terms. A simple use case is the following for Node n
32
 * and LetBinding lbind:
33
 * ```
34
 *   std::vector<Node> letList;
35
 *   lbind.letify(n, letList);
36
 * ```
37
 * Now, letList contains a list of subterms of n that should be letified based
38
 * on the threshold value passed to this class where a value n>0 indicates that
39
 * terms with n or more occurrences should be letified.
40
 *
41
 * The above is equivalent to:
42
 * ```
43
 *   std::vector<Node> letList;
44
 *   lbind.pushScope();
45
 *   lbind.process(n);
46
 *   lbind.letify(letList);
47
 * ```
48
 * In fact, multiple terms can be passed to calls to process, in which case the
49
 * counting is cumulative.
50
 *
51
 * All quantified formulas are treated as black boxes. This class can be used
52
 * to letify terms with quantifiers, where multiple calls to pushScope /
53
 * popScope can be used. In particular, consider:
54
 * ```
55
 *   std::vector<Node> letList1;
56
 *   lbind.letify(n1, letList1);
57
 *   std::vector<Node> letList2;
58
 *   lbind.letify(n2, letList2);
59
 *   ...
60
 *   lbind.popScope();
61
 *   lbind.popScope();
62
 * ```
63
 * In a typical use case, n2 is the body of a quantified formula that is a
64
 * subterm of n1. We have that letList2 is the list of subterms of n2 that
65
 * should be letified, assuming that we have already have let definitions
66
 * given by letList1.
67
 *
68
 * Internally, a let binding is a list and a map that can be printed as a let
69
 * expression. In particular, the list d_letList is ordered such that
70
 * d_letList[i] does not contain subterm d_letList[j] for j>i.
71
 * It is intended that d_letList contains only unique nodes. Each node
72
 * in d_letList is mapped to a unique identifier in d_letMap.
73
 *
74
 * Notice that this class will *not* use introduced let symbols when converting
75
 * the bodies of quantified formulas. Consider the formula:
76
 * (let ((Q (forall ((x Int)) (= x (+ a a))))) (and (= (+ a a) (+ a a)) Q Q))
77
 * where "let" above is from the user. When this is letified by this class,
78
 * note that (+ a a) occurs as a subterm of Q, however it is not seen until
79
 * after we have seen Q twice, since we traverse in reverse topological order.
80
 * Since we do not traverse underneath quantified formulas, this means that Q
81
 * may be marked as a term-to-letify before (+ a a), which leads to violation
82
 * of the above invariant concerning containment. Thus, when converting, if
83
 * a let symbol is introduced for (+ a a), we will not replace the occurence
84
 * of (+ a a) within Q. Instead, the user of this class is responsible for
85
 * letifying the bodies of quantified formulas independently.
86
 */
87
52797
class LetBinding
88
{
89
  using NodeList = context::CDList<Node>;
90
  using NodeIdMap = context::CDHashMap<Node, uint32_t>;
91
92
 public:
93
  LetBinding(uint32_t thresh = 2);
94
  /** Get threshold */
95
  uint32_t getThreshold() const;
96
  /**
97
   * This updates this let binding to consider the counts for node n.
98
   */
99
  void process(Node n);
100
  /**
101
   * This pushes a scope, computes the letification for n, adds the (new) terms
102
   * that must be letified in this context to letList.
103
   *
104
   * Notice that this method does not traverse inside of closures.
105
   *
106
   * @param n The node to letify
107
   * @param letList The list of terms that should be letified within n. This
108
   * list is ordered in such a way that letList[i] does not contain subterm
109
   * letList[j] for j>i.
110
   */
111
  void letify(Node n, std::vector<Node>& letList);
112
  /**
113
   * Same as above, without a node to letify.
114
   */
115
  void letify(std::vector<Node>& letList);
116
  /** Push scope */
117
  void pushScope();
118
  /** Pop scope for n, reverts the state change of the above method */
119
  void popScope();
120
  /**
121
   * @return the identifier for node n, or 0 if it does not have one.
122
   */
123
  uint32_t getId(Node n) const;
124
  /**
125
   * Convert n based on the state of the let binding. This replaces all
126
   * letified subterms of n with a fresh variable whose name prefix is the
127
   * given one.
128
   *
129
   * @param n The node to convert
130
   * @param prefix The prefix of variables to convert
131
   * @param letTop Whether we letify n itself
132
   * @return the converted node.
133
   */
134
  Node convert(Node n, const std::string& prefix, bool letTop = true) const;
135
136
 private:
137
  /**
138
   * Compute the count of sub nodes in n, store in d_count. Additionally,
139
   * store each node in the domain of d_count in an order in d_visitList
140
   * such that d_visitList[i] does not contain sub d_visitList[j] for j>i.
141
   */
142
  void updateCounts(Node n);
143
  /**
144
   * Convert a count to a let binding.
145
   */
146
  void convertCountToLet();
147
  /** The dag threshold */
148
  uint32_t d_thresh;
149
  /** An internal context */
150
  context::Context d_context;
151
  /** Visit list */
152
  NodeList d_visitList;
153
  /** Count */
154
  NodeIdMap d_count;
155
  /** The let list */
156
  NodeList d_letList;
157
  /** The let map */
158
  NodeIdMap d_letMap;
159
};
160
161
}  // namespace cvc5
162
163
#endif