GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/booleans/circuit_propagator.h Lines: 29 29 100.0 %
Date: 2021-05-22 Branches: 52 100 52.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Morgan Deters, Aina Niemetz, Gereon Kremer
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 non-clausal circuit propagator for Boolean simplification.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__BOOLEANS__CIRCUIT_PROPAGATOR_H
19
#define CVC5__THEORY__BOOLEANS__CIRCUIT_PROPAGATOR_H
20
21
#include <memory>
22
#include <unordered_map>
23
#include <vector>
24
25
#include "context/cdhashmap.h"
26
#include "context/cdhashset.h"
27
#include "context/cdo.h"
28
#include "context/context.h"
29
#include "expr/lazy_proof_chain.h"
30
#include "expr/node.h"
31
#include "theory/trust_node.h"
32
33
namespace cvc5 {
34
35
class ProofGenerator;
36
class ProofNode;
37
38
namespace theory {
39
40
class EagerProofGenerator;
41
42
namespace booleans {
43
44
/**
45
 * The main purpose of the CircuitPropagator class is to maintain the
46
 * state of the circuit for subsequent calls to propagate(), so that
47
 * the same fact is not output twice, so that the same edge in the
48
 * circuit isn't propagated twice, etc.
49
 */
50
10092
class CircuitPropagator
51
{
52
 public:
53
  /**
54
   * Value of a particular node
55
   */
56
  enum AssignmentStatus
57
  {
58
    /** Node is currently unassigned */
59
    UNASSIGNED = 0,
60
    /** Node is assigned to true */
61
    ASSIGNED_TO_TRUE,
62
    /** Node is assigned to false */
63
    ASSIGNED_TO_FALSE,
64
  };
65
66
  typedef std::unordered_map<Node, std::vector<Node>> BackEdgesMap;
67
68
  /**
69
   * Construct a new CircuitPropagator.
70
   */
71
  CircuitPropagator(bool enableForward = true, bool enableBackward = true);
72
73
  /** Get Node assignment in circuit.  Assert-fails if Node is unassigned. */
74
703631
  bool getAssignment(TNode n) const
75
  {
76
703631
    AssignmentMap::iterator i = d_state.find(n);
77
703631
    Assert(i != d_state.end() && (*i).second != UNASSIGNED);
78
703631
    return (*i).second == ASSIGNED_TO_TRUE;
79
  }
80
81
  // Use custom context to ensure propagator is reset after use
82
10277
  void initialize() { d_context.push(); }
83
84
20554
  void setNeedsFinish(bool value) { d_needsFinish = value; }
85
86
20369
  bool getNeedsFinish() { return d_needsFinish; }
87
88
21752
  std::vector<TrustNode>& getLearnedLiterals() { return d_learnedLiterals; }
89
90
  /** Finish the computation and pop the internal context */
91
  void finish();
92
93
  /** Assert for propagation */
94
  void assertTrue(TNode assertion);
95
96
  /**
97
   * Propagate through the asserted circuit propagator. New information
98
   * discovered by the propagator are put in the substitutions vector used in
99
   * construction.
100
   *
101
   * @return a trust node encapsulating the proof for a conflict as a lemma that
102
   * proves false, or the null trust node otherwise
103
   */
104
  TrustNode propagate() CVC5_WARN_UNUSED_RESULT;
105
106
  /**
107
   * Get the back edges of this circuit.
108
   */
109
8
  const BackEdgesMap& getBackEdges() const { return d_backEdges; }
110
111
  /** Invert a set value */
112
  static inline AssignmentStatus neg(AssignmentStatus value)
113
  {
114
    Assert(value != UNASSIGNED);
115
    if (value == ASSIGNED_TO_TRUE)
116
      return ASSIGNED_TO_FALSE;
117
    else
118
      return ASSIGNED_TO_TRUE;
119
  }
120
121
  /** True iff Node is assigned in circuit (either true or false). */
122
18196
  bool isAssigned(TNode n) const
123
  {
124
18196
    AssignmentMap::const_iterator i = d_state.find(n);
125
18196
    return i != d_state.end() && ((*i).second != UNASSIGNED);
126
  }
127
128
  /** True iff Node is assigned to the value. */
129
21520841
  bool isAssignedTo(TNode n, bool value) const
130
  {
131
21520841
    AssignmentMap::const_iterator i = d_state.find(n);
132
21520841
    if (i == d_state.end()) return false;
133
20392016
    if (value && ((*i).second == ASSIGNED_TO_TRUE)) return true;
134
838578
    if (!value && ((*i).second == ASSIGNED_TO_FALSE)) return true;
135
128032
    return false;
136
  }
137
  /**
138
   * Set proof node manager, context and parent proof generator.
139
   *
140
   * If parent is non-null, then it is responsible for the proofs provided
141
   * to this class.
142
   */
143
  void setProof(ProofNodeManager* pnm,
144
                context::Context* ctx,
145
                ProofGenerator* defParent);
146
147
 private:
148
  /** A context-notify object that clears out stale data. */
149
  template <class T>
150
30276
  class DataClearer : context::ContextNotifyObj
151
  {
152
   public:
153
30276
    DataClearer(context::Context* context, T& data)
154
30276
        : context::ContextNotifyObj(context), d_data(data)
155
    {
156
30276
    }
157
158
   protected:
159
30831
    void contextNotifyPop() override
160
    {
161
92493
      Trace("circuit-prop")
162
30831
          << "CircuitPropagator::DataClearer: clearing data "
163
61662
          << "(size was " << d_data.size() << ")" << std::endl;
164
30831
      d_data.clear();
165
30831
    }
166
167
   private:
168
    T& d_data;
169
  }; /* class DataClearer<T> */
170
171
  /**
172
   * Assignment status of each node.
173
   */
174
  typedef context::CDHashMap<TNode, AssignmentStatus> AssignmentMap;
175
176
  /**
177
   * Assign Node in circuit with the value and add it to the queue; note
178
   * conflicts.
179
   */
180
  void assignAndEnqueue(TNode n,
181
                        bool value,
182
                        std::shared_ptr<ProofNode> proof = nullptr);
183
184
  /**
185
   * Store a conflict for the case that we have derived both n and n.negate()
186
   * to be true.
187
   */
188
  void makeConflict(Node n);
189
190
  /**
191
   * Compute the map from nodes to the nodes that use it.
192
   */
193
  void computeBackEdges(TNode node);
194
195
  /**
196
   * Propagate new information forward in circuit to
197
   * the parents of "in".
198
   */
199
  void propagateForward(TNode child, bool assignment);
200
201
  /**
202
   * Propagate new information backward in circuit to
203
   * the children of "in".
204
   */
205
  void propagateBackward(TNode parent, bool assignment);
206
207
  /** Are proofs enabled? */
208
  bool isProofEnabled() const;
209
210
  context::Context d_context;
211
212
  /** The propagation queue */
213
  std::vector<TNode> d_propagationQueue;
214
215
  /**
216
   * We have a propagation queue "clearer" object for when the user
217
   * context pops.  Normally the propagation queue should be empty,
218
   * but this keeps us safe in case there's still some rubbish around
219
   * on the queue.
220
   */
221
  DataClearer<std::vector<TNode>> d_propagationQueueClearer;
222
223
  /** Are we in conflict? */
224
  context::CDO<TrustNode> d_conflict;
225
226
  /** Map of substitutions */
227
  std::vector<TrustNode> d_learnedLiterals;
228
229
  /**
230
   * Similar data clearer for learned literals.
231
   */
232
  DataClearer<std::vector<TrustNode>> d_learnedLiteralClearer;
233
234
  /**
235
   * Back edges from nodes to where they are used.
236
   */
237
  BackEdgesMap d_backEdges;
238
239
  /**
240
   * Similar data clearer for back edges.
241
   */
242
  DataClearer<BackEdgesMap> d_backEdgesClearer;
243
244
  /** Nodes that have been attached already (computed forward edges for) */
245
  // All the nodes we've visited so far
246
  context::CDHashSet<Node> d_seen;
247
248
  AssignmentMap d_state;
249
250
  /** Whether to perform forward propagation */
251
  const bool d_forwardPropagation;
252
253
  /** Whether to perform backward propagation */
254
  const bool d_backwardPropagation;
255
256
  /* Does the current state require a call to finish()? */
257
  bool d_needsFinish;
258
259
  /** Adds a new proof for f, or drops it if we already have a proof */
260
  void addProof(TNode f, std::shared_ptr<ProofNode> pf);
261
262
  /** A pointer to the proof manager */
263
  ProofNodeManager* d_pnm;
264
  /** Eager proof generator that actually stores the proofs */
265
  std::unique_ptr<EagerProofGenerator> d_epg;
266
  /** Connects the proofs to subproofs internally */
267
  std::unique_ptr<LazyCDProofChain> d_proofInternal;
268
  /** Connects the proofs to assumptions externally */
269
  std::unique_ptr<LazyCDProofChain> d_proofExternal;
270
}; /* class CircuitPropagator */
271
272
}  // namespace booleans
273
}  // namespace theory
274
}  // namespace cvc5
275
276
#endif /* CVC5__THEORY__BOOLEANS__CIRCUIT_PROPAGATOR_H */