GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/normal_form.h Lines: 2 2 100.0 %
Date: 2021-05-22 Branches: 3 6 50.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Andres Noetzli, Mathias Preiner
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
 * Normal form datastructure for the theory of strings.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__STRINGS__NORMAL_FORM_H
19
#define CVC5__THEORY__STRINGS__NORMAL_FORM_H
20
21
#include <map>
22
#include <vector>
23
#include "expr/node.h"
24
25
namespace cvc5 {
26
namespace theory {
27
namespace strings {
28
29
/** normal forms
30
 *
31
 * Stores information regarding the "normal form" of terms t in the current
32
 * context. Normal forms can be associated with terms, or with string
33
 * equivalence classes. For the latter, the normal form of an equivalence class
34
 * exists if exactly one unique normal form is associated to a subset of its
35
 * terms.
36
 *
37
 * In the following we use example where assertions are:
38
 *   { x = y, y = z, y = u ++ v, u = u1 ++ u2 }
39
 * and equivalence class [x] = { x, y, z, u ++ v }, whose normal form is
40
 *   (u1, u2, v)
41
 */
42
1026041
class NormalForm
43
{
44
 public:
45
369767
  NormalForm() : d_isRev(false) {}
46
  /**
47
   * The "base" of the normal form. This is some term in the equivalence
48
   * class of t that the normal form is based on. This is an arbitrary term
49
   * which is used as the reference point for explanations. In the above
50
   * running example, let us assume the base of [x] is y.
51
   */
52
  Node d_base;
53
  /** the normal form, (u1, u2, v), in the above example */
54
  std::vector<Node> d_nf;
55
  /** is the normal form d_nf stored in reverse order? */
56
  bool d_isRev;
57
  /**
58
   * The explanation for the normal form, this is a set of literals such that
59
   *   d_exp => d_base = d_nf
60
   * In the above example, this is the set of equalities
61
   *   { y = u ++ v, u = u1 ++ u2 }
62
   * If u ++ v was chosen as the base, then the first literal could be omitted.
63
   */
64
  std::vector<Node> d_exp;
65
  /**
66
   * Map from literals in the vector d_exp to integers indicating indices in
67
   * d_nf for which that literal L is relevant for explaining d_base = d_nf.
68
   *
69
   * In particular:
70
   * - false maps to an (ideally maximal) index relative to the start of d_nf
71
   * such that L is required for explaining why d_base has a prefix that
72
   * includes the term at that index,
73
   * - true maps to an (ideally maximal) index relative to the end of d_nf
74
   * such that L is required for explaining why d_base has a suffix that
75
   * includes the term at that index.
76
   * We call these the forward and backwards dependency indices.
77
   *
78
   * In the above example:
79
   *   y = u ++ v   : false -> 0, true -> 0
80
   *   u = u1 ++ u2 : false -> 0, true -> 1
81
   * When explaining y = u1 ++ u2 ++ v, the equality y = u ++ v is required
82
   * for explaining any prefix/suffix of y and its normal form. More
83
   * interestingly, the equality u = u1 ++ u2 is not required for explaining
84
   * that v is a suffix of y, since its reverse index in this map is 1,
85
   * indicating that "u2" is the first position in u1 ++ u2 ++ v that it is
86
   * required for explaining.
87
   *
88
   * This information is used to minimize explanations when conflicts arise,
89
   * thereby strengthening conflict clauses and lemmas.
90
   *
91
   * For example, say u ++ v = y = x = u ++ w and w and v are distinct
92
   * constants, using this dependency information, we could construct a
93
   * conflict:
94
   *   x = y ^ y = u ++ v ^ x = u ++ w
95
   * that does not include u = u1 ++ u2, because the conflict only pertains
96
   * to the last position in the normal form of y.
97
   */
98
  std::map<Node, std::map<bool, unsigned> > d_expDep;
99
  /** initialize
100
   *
101
   * Initialize the normal form with base node base. If base is not the empty
102
   * string, then d_nf is set to the singleton list containing base, otherwise
103
   * d_nf is empty.
104
   */
105
  void init(Node base);
106
  /** reverse the content of normal form d_nf
107
   *
108
   * This operation is done in contexts where the normal form is being scanned
109
   * in reverse order.
110
   */
111
  void reverse();
112
  /** split constant
113
   *
114
   * Splits the constant in d_nf at index to constants c1 and c2.
115
   *
116
   * Notice this function depends on whether the normal form has been reversed
117
   * d_isRev, as this impacts how the dependency indices are updated.
118
   */
119
  void splitConstant(unsigned index, Node c1, Node c2);
120
  /** add to explanation
121
   *
122
   * This adds exp to the explanation vector d_exp with new forward and
123
   * backwards dependency indices new_val and new_rev_val.
124
   *
125
   * If exp already has dependencies, we update the forward dependency
126
   * index to the minimum of the previous value and the new value, and
127
   * similarly update the backwards dependency index to the maximum.
128
   */
129
  void addToExplanation(Node exp, unsigned new_val, unsigned new_rev_val);
130
  /** get explanation
131
   *
132
   * This gets the explanation for the prefix (resp. suffix) of the normal
133
   * form up to index when d_isRev is false (resp. true). In particular;
134
   *
135
   * If index is -1, then this method adds all literals in d_exp to curr_exp.
136
   *
137
   * If index>=0, this method adds all literals in d_exp to curr_exp whose
138
   * forward (resp. backwards) dependency index is less than index
139
   * when isRev is false (resp. true).
140
   */
141
  void getExplanation(int index, std::vector<Node>& curr_exp);
142
143
  /**
144
   * Collects the constant string starting at a given index, i.e. concatenates
145
   * all the consecutive constant strings. If the normal form is reverse order,
146
   * this function searches backwards but the result will be in the original
147
   * order.
148
   *
149
   * @param index The index to start at, updated to point to the first
150
   *              non-constant component of the normal form or set equal to the
151
   *              size of the normal form if the remainder is all constants
152
   * @return The combined string constants
153
   */
154
  Node collectConstantStringAt(size_t& index);
155
156
  /** get explanation for prefix equality
157
   *
158
   * This adds to curr_exp the reason why the prefix of nfi up to index index_i
159
   * is equivalent to the prefix of nfj up to index_j. The values of
160
   * nfi.d_isRev and nfj.d_isRev affect how dependency indices are updated
161
   * during this call.
162
   */
163
  static void getExplanationForPrefixEq(NormalForm& nfi,
164
                                        NormalForm& nfj,
165
                                        int index_i,
166
                                        int index_j,
167
                                        std::vector<Node>& curr_exp);
168
};
169
170
}  // namespace strings
171
}  // namespace theory
172
}  // namespace cvc5
173
174
#endif /* CVC5__THEORY__STRINGS__NORMAL_FORM_H */