GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/decision/justification_strategy.h Lines: 1 1 100.0 %
Date: 2021-08-17 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
 * Implementation of the justification SAT decision strategy
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__DECISION__JUSTIFICATION_STRATEGY_H
19
#define CVC5__DECISION__JUSTIFICATION_STRATEGY_H
20
21
#include "context/cdinsert_hashmap.h"
22
#include "context/cdo.h"
23
#include "decision/assertion_list.h"
24
#include "decision/decision_engine.h"
25
#include "decision/justify_info.h"
26
#include "decision/justify_stack.h"
27
#include "decision/justify_stats.h"
28
#include "expr/node.h"
29
#include "options/decision_options.h"
30
#include "prop/cnf_stream.h"
31
#include "prop/sat_solver.h"
32
#include "prop/sat_solver_types.h"
33
34
namespace cvc5 {
35
36
namespace prop {
37
class SkolemDefManager;
38
}
39
40
namespace decision {
41
42
/**
43
 * An implementation of justification SAT decision heuristic. This class
44
 * is given access to the set of input formulas, and chooses next decisions
45
 * based on the structure of the input formula.
46
 *
47
 * Notice that the SAT solver still propagates values for literals in the
48
 * normal way based on BCP when using this SAT decision heuristic. This means
49
 * that values for literals can be assigned between calls to get next
50
 * decision. Thus, this module has access to the SAT solver for the purpose
51
 * of looking up values already assigned to literals.
52
 *
53
 * One novel feature of this module is that it maintains a SAT-context-dependent
54
 * stack corresponding to the current path in the input formula we are trying
55
 * to satisfy. This means that computing the next decision does not require
56
 * traversing the current assertion.
57
 *
58
 * As an example, say our input formulas are:
59
 *   (or (and A B) C D), (or E F)
60
 * where A, B, C, D, E, F are theory literals. Moreover, say we are in a
61
 * state where the SAT solver has initially assigned values:
62
 *   { A -> false, E -> true }
63
 * Given a call to getNext, this module will analyze what is the next
64
 * literal that would contribute towards making the input formulas evaluate to
65
 * true. Assuming it works on assertions and terms left-to-right, it will
66
 * perform the following reasoning:
67
 * - The desired value of (or (and A B) C D) is true
68
 *   - The desired value of (and A B) is true
69
 *     - The desired value of A is true,
70
 *       ...The value of A was assigned false
71
 *     ...The value of (and A B) is false
72
 *   - Moving to the next literal, the desired value of C is true
73
 *     ...The value of C is unassigned, return C as a decision.
74
 * After deciding C, assuming no backtracking occurs, we end up in a state
75
 * where we have assigned:
76
 *   { A -> false, E -> true, C -> true }
77
 * In the next call to getNext, this module will proceed, keeping the stack
78
 * from the previous call:
79
 *     ... The value of C is true
80
 *   ... The value of (or (and A B) C D) is true
81
 * - Moving to the next assertion, the desired value of (or E F) is true
82
 *   - The desired value of E is true
83
 *     ... The value of E is (already) assigned true
84
 *   ... the value of (or E F) is true.
85
 * - The are no further assertions.
86
 * Hence it will return the null SAT decision literal, indicating that no
87
 * further decisions are necessary to satisfy the input assertions.
88
 *
89
 * This class has special handling of "skolem definitions", which arise when
90
 * lemmas are introduced that correspond to the behavior of skolems. As an
91
 * example, say our input, prior to preprocessing, is:
92
 *   (or (P (ite A 1 2)) Q)
93
 * where P is an uninterpreted predicate of type Int -> Bool. After
94
 * preprocessing, in particular term formula removal which replaces term-level
95
 * ITE terms with fresh skolems, we get this set of assertions:
96
 *   (or (P k) Q), (ite A (= k 1) (= k 2))
97
 * The second assertion is the skolem definition for k. Conceptually, this
98
 * lemma is only relevant if we have asserted a literal that contains k.
99
 * This module thus maintains two separate assertion lists, one for
100
 * input assertions, and one for skolem definitions. The latter is populated
101
 * only as skolems appear in assertions. In this example, we have initially:
102
 *   input assertions = { (or (P k) Q) }
103
 *   relevant skolem definitions =  {}
104
 *   SAT context = {}
105
 * Say this module returns (P k) as a decision. When this is asserted to
106
 * the theory engine, a call to notifyAsserted is made with (P k). The
107
 * skolem definition manager will recognize that (P k) contains k and hence
108
 * its skolem definition is activated, giving us this state:
109
 *   input assertions = { (or (P k) Q) }
110
 *   relevant skolem definitions =  { (ite A (= k 1) (= k 2)) }
111
 *   SAT context = { (P k) }
112
 * We then proceed by satisfying (ite A (= k 1) (= k 2)), e.g. by returning
113
 * A as a decision for getNext.
114
 *
115
 * Notice that the above policy allows us to ignore certain skolem definitions
116
 * entirely. For example, if Q were to have been asserted instead of (P k),
117
 * then (ite A (= k 1) (= k 2)) would not be added as a relevant skolem
118
 * definition, and Q alone would have sufficed to show the input formula
119
 * was satisfied.
120
 */
121
15476
class JustificationStrategy : public DecisionEngine
122
{
123
 public:
124
  /** Constructor */
125
  JustificationStrategy(context::Context* c,
126
                        context::UserContext* u,
127
                        prop::SkolemDefManager* skdm,
128
                        ResourceManager* rm);
129
130
  /** Presolve, called at the beginning of each check-sat call */
131
  void presolve() override;
132
133
  /**
134
   * Gets the next decision based on the current assertion to satisfy. This
135
   * returns undefSatLiteral if there are no more assertions. In this case,
136
   * all relevant input assertions are already propositionally satisfied by
137
   * the current assignment.
138
   *
139
   * @param stopSearch Set to true if we can stop the search
140
   * @return The next SAT literal to decide on.
141
   */
142
  prop::SatLiteral getNextInternal(bool& stopSearch) override;
143
144
  /**
145
   * Are we finished assigning values to literals?
146
   *
147
   * @return true if and only if all relevant input assertions are already
148
   * propositionally satisfied by the current assignment.
149
   */
150
  bool isDone() override;
151
152
  /**
153
   * Notify this class that assertion is an (input) assertion, not corresponding
154
   * to a skolem definition.
155
   */
156
  void addAssertion(TNode assertion) override;
157
  /**
158
   * Notify this class that lem is the skolem definition for skolem, which is
159
   * a part of the current assertions.
160
   */
161
  void addSkolemDefinition(TNode lem, TNode skolem) override;
162
  /**
163
   * Notify this class that literal n has been asserted. This is triggered when
164
   * n is sent to TheoryEngine. This activates skolem definitions for skolems
165
   * k that occur in n.
166
   */
167
  void notifyAsserted(TNode n) override;
168
169
 private:
170
  /**
171
   * Helper method to insert assertions in `toProcess` to `d_assertions` or
172
   * `d_skolemAssertions` based on `useSkolemList`.
173
   */
174
  void insertToAssertionList(std::vector<TNode>& toProcess, bool useSkolemList);
175
  /**
176
   * Refresh current assertion. This ensures that d_stack has a current
177
   * assertion to satisfy. If it does not already have one, we take the next
178
   * assertion from the list of input assertions, or from the relevant
179
   * skolem definitions based on the JutificationSkolemMode mode.
180
   *
181
   * @return true if we successfully initialized d_stack with the next
182
   * assertion to satisfy.
183
   */
184
  bool refreshCurrentAssertion();
185
  /**
186
   * Implements the above function for the case where d_stack must get a new
187
   * assertion to satisfy.
188
   *
189
   * @param useSkolemList If this is true, we pull the next assertion from
190
   * the list of relevant skolem definitions.
191
   * @return true if we successfully initialized d_stack with the next
192
   * assertion to satisfy.
193
   */
194
  bool refreshCurrentAssertionFromList(bool useSkolemList);
195
  /**
196
   * Let n be the node referenced by ji.
197
   *
198
   * This method is called either when we have yet to process any children of n,
199
   * or we just determined that the last child we processed of n had value
200
   * lastChildVal.
201
   *
202
   * Note that knowing which child of n we processed last is the value of
203
   * ji->d_childIndex.
204
   *
205
   * @param ji The justify node to process
206
   * @param lastChildVal The value determined for the last child of the node of
207
   * ji.
208
   * @return Either (1) the justify node corresponding to the next child of n to
209
   * consider adding to the stack, and its desired polarity, or
210
   * (2) a null justify node and updates lastChildVal to the value of n.
211
   */
212
  JustifyNode getNextJustifyNode(JustifyInfo* ji, prop::SatValue& lastChildVal);
213
  /**
214
   * Returns the value TRUE/FALSE for n, or UNKNOWN otherwise.
215
   *
216
   * We return a value for n only if we have justified its values based on its
217
   * children. For example, we return UNKNOWN for n of the form (and A B) if
218
   * A and B have UNKNOWN value, even if the SAT solver has assigned a value for
219
   * (internal) node n. If n itself is a theory literal, we lookup its value
220
   * in the SAT solver if it is not already cached.
221
   */
222
  prop::SatValue lookupValue(TNode n);
223
  /** Is n a theory literal? */
224
  static bool isTheoryLiteral(TNode n);
225
  /** Is n a theory atom? */
226
  static bool isTheoryAtom(TNode n);
227
  /** Pointer to the skolem definition manager */
228
  prop::SkolemDefManager* d_skdm;
229
  /** The assertions, which are user-context dependent. */
230
  AssertionList d_assertions;
231
  /** The skolem assertions */
232
  AssertionList d_skolemAssertions;
233
234
  /** Mapping from non-negated nodes to their SAT value */
235
  context::CDInsertHashMap<Node, prop::SatValue> d_justified;
236
  /** A justify stack */
237
  JustifyStack d_stack;
238
  /** The last decision literal */
239
  context::CDO<TNode> d_lastDecisionLit;
240
  //------------------------------------ activity
241
  /** Current assertion we are checking for status (context-independent) */
242
  Node d_currUnderStatus;
243
  /** Whether we have added a decision while considering d_currUnderStatus */
244
  bool d_currStatusDec;
245
  //------------------------------------ options
246
  /** using relevancy order */
247
  bool d_useRlvOrder;
248
  /** using stop only */
249
  bool d_decisionStopOnly;
250
  /** skolem mode */
251
  options::JutificationSkolemMode d_jhSkMode;
252
  /** skolem relevancy mode */
253
  options::JutificationSkolemRlvMode d_jhSkRlvMode;
254
  /** The statistics */
255
  JustifyStatistics d_stats;
256
};
257
258
}  // namespace decision
259
}  // namespace cvc5
260
261
#endif /* CVC5__DECISION__JUSTIFICATION_STRATEGY_H */