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