1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli |
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 |
|
* Arithmetic entailment computation for string terms. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__STRINGS__ARITH_ENTAIL_H |
19 |
|
#define CVC5__THEORY__STRINGS__ARITH_ENTAIL_H |
20 |
|
|
21 |
|
#include <vector> |
22 |
|
|
23 |
|
#include "expr/node.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace theory { |
27 |
|
|
28 |
|
class Rewriter; |
29 |
|
|
30 |
|
namespace strings { |
31 |
|
|
32 |
|
/** |
33 |
|
* Techniques for computing arithmetic entailment for string terms. This |
34 |
|
* is an implementation of the techniques from Reynolds et al, "High Level |
35 |
|
* Abstractions for Simplifying Extended String Constraints in SMT", CAV 2019. |
36 |
|
*/ |
37 |
33177 |
class ArithEntail |
38 |
|
{ |
39 |
|
public: |
40 |
|
ArithEntail(Rewriter* r); |
41 |
|
/** |
42 |
|
* Returns the rewritten form a term, intended (although not enforced) to be |
43 |
|
* an arithmetic term. |
44 |
|
*/ |
45 |
|
Node rewrite(Node a); |
46 |
|
/** check arithmetic entailment equal |
47 |
|
* Returns true if it is always the case that a = b. |
48 |
|
*/ |
49 |
|
bool checkEq(Node a, Node b); |
50 |
|
/** check arithmetic entailment |
51 |
|
* Returns true if it is always the case that a >= b, |
52 |
|
* and a>b if strict is true. |
53 |
|
*/ |
54 |
|
bool check(Node a, Node b, bool strict = false); |
55 |
|
/** check arithmetic entailment |
56 |
|
* Returns true if it is always the case that a >= 0. |
57 |
|
*/ |
58 |
|
bool check(Node a, bool strict = false); |
59 |
|
/** check arithmetic entailment with approximations |
60 |
|
* |
61 |
|
* Returns true if it is always the case that a >= 0. We expect that a is in |
62 |
|
* rewritten form. |
63 |
|
* |
64 |
|
* This function uses "approximation" techniques that under-approximate |
65 |
|
* the value of a for the purposes of showing the entailment holds. For |
66 |
|
* example, given: |
67 |
|
* len( x ) - len( substr( y, 0, len( x ) ) ) |
68 |
|
* Since we know that len( substr( y, 0, len( x ) ) ) <= len( x ), the above |
69 |
|
* term can be under-approximated as len( x ) - len( x ) = 0, which is >= 0, |
70 |
|
* and thus the entailment len( x ) - len( substr( y, 0, len( x ) ) ) >= 0 |
71 |
|
* holds. |
72 |
|
*/ |
73 |
|
bool checkApprox(Node a); |
74 |
|
|
75 |
|
/** |
76 |
|
* Checks whether assumption |= a >= 0 (if strict is false) or |
77 |
|
* assumption |= a > 0 (if strict is true), where assumption is an equality |
78 |
|
* assumption. The assumption must be in rewritten form. |
79 |
|
* |
80 |
|
* Example: |
81 |
|
* |
82 |
|
* checkWithEqAssumption(x + (str.len y) = 0, -x, false) = true |
83 |
|
* |
84 |
|
* Because: x = -(str.len y), so -x >= 0 --> (str.len y) >= 0 --> true |
85 |
|
*/ |
86 |
|
bool checkWithEqAssumption(Node assumption, Node a, bool strict = false); |
87 |
|
|
88 |
|
/** |
89 |
|
* Checks whether assumption |= a >= b (if strict is false) or |
90 |
|
* assumption |= a > b (if strict is true). The function returns true if it |
91 |
|
* can be shown that the entailment holds and false otherwise. Assumption |
92 |
|
* must be in rewritten form. Assumption may be an equality or an inequality. |
93 |
|
* |
94 |
|
* Example: |
95 |
|
* |
96 |
|
* checkWithAssumption(x + (str.len y) = 0, 0, x, false) = true |
97 |
|
* |
98 |
|
* Because: x = -(str.len y), so 0 >= x --> 0 >= -(str.len y) --> true |
99 |
|
* |
100 |
|
* Since this method rewrites on rewriting and may introduce new variables |
101 |
|
* (slack variables for inequalities), it should *not* be called from the |
102 |
|
* main rewriter of strings, or non-termination can occur. |
103 |
|
*/ |
104 |
|
bool checkWithAssumption(Node assumption, |
105 |
|
Node a, |
106 |
|
Node b, |
107 |
|
bool strict = false); |
108 |
|
|
109 |
|
/** |
110 |
|
* Checks whether assumptions |= a >= b (if strict is false) or |
111 |
|
* assumptions |= a > b (if strict is true). The function returns true if it |
112 |
|
* can be shown that the entailment holds and false otherwise. Assumptions |
113 |
|
* must be in rewritten form. Assumptions may be an equalities or an |
114 |
|
* inequalities. |
115 |
|
* |
116 |
|
* Example: |
117 |
|
* |
118 |
|
* checkWithAssumptions([x + (str.len y) = 0], 0, x, false) = true |
119 |
|
* |
120 |
|
* Because: x = -(str.len y), so 0 >= x --> 0 >= -(str.len y) --> true |
121 |
|
* |
122 |
|
* Since this method rewrites on rewriting and may introduce new variables |
123 |
|
* (slack variables for inequalities), it should *not* be called from the |
124 |
|
* main rewriter of strings, or non-termination can occur. |
125 |
|
*/ |
126 |
|
bool checkWithAssumptions(std::vector<Node> assumptions, |
127 |
|
Node a, |
128 |
|
Node b, |
129 |
|
bool strict = false); |
130 |
|
|
131 |
|
/** get arithmetic lower bound |
132 |
|
* If this function returns a non-null Node ret, |
133 |
|
* then ret is a rational constant and |
134 |
|
* we know that n >= ret always if isLower is true, |
135 |
|
* or n <= ret if isLower is false. |
136 |
|
* |
137 |
|
* Notice the following invariant. |
138 |
|
* If getConstantArithBound(a, true) = ret where ret is non-null, then for |
139 |
|
* strict = { true, false } : |
140 |
|
* ret >= strict ? 1 : 0 |
141 |
|
* if and only if |
142 |
|
* check( a, strict ) = true. |
143 |
|
*/ |
144 |
|
Node getConstantBound(Node a, bool isLower = true); |
145 |
|
|
146 |
|
/** |
147 |
|
* get constant bound on the length of s. |
148 |
|
*/ |
149 |
|
Node getConstantBoundLength(Node s, bool isLower = true); |
150 |
|
/** |
151 |
|
* Given an inequality y1 + ... + yn >= x, removes operands yi s.t. the |
152 |
|
* original inequality still holds. Returns true if the original inequality |
153 |
|
* holds and false otherwise. The list of ys is modified to contain a subset |
154 |
|
* of the original ys. |
155 |
|
* |
156 |
|
* Example: |
157 |
|
* |
158 |
|
* inferZerosInSumGeq( (str.len x), [ (str.len x), (str.len y), 1 ], [] ) |
159 |
|
* --> returns true with ys = [ (str.len x) ] and zeroYs = [ (str.len y), 1 ] |
160 |
|
* (can be used to rewrite the inequality to false) |
161 |
|
* |
162 |
|
* inferZerosInSumGeq( (str.len x), [ (str.len y) ], [] ) |
163 |
|
* --> returns false because it is not possible to show |
164 |
|
* str.len(y) >= str.len(x) |
165 |
|
*/ |
166 |
|
bool inferZerosInSumGeq(Node x, |
167 |
|
std::vector<Node>& ys, |
168 |
|
std::vector<Node>& zeroYs); |
169 |
|
|
170 |
|
private: |
171 |
|
/** check entail arithmetic internal |
172 |
|
* Returns true if we can show a >= 0 always. |
173 |
|
* a is in rewritten form. |
174 |
|
*/ |
175 |
|
bool checkInternal(Node a); |
176 |
|
/** Get arithmetic approximations |
177 |
|
* |
178 |
|
* This gets the (set of) arithmetic approximations for term a and stores |
179 |
|
* them in approx. If isOverApprox is true, these are over-approximations |
180 |
|
* for the value of a, otherwise, they are underapproximations. For example, |
181 |
|
* an over-approximation for len( substr( y, n, m ) ) is m; an |
182 |
|
* under-approximation for indexof( x, y, n ) is -1. |
183 |
|
* |
184 |
|
* Notice that this function is not generally recursive (although it may make |
185 |
|
* a small bounded of recursive calls). Instead, it returns the shape |
186 |
|
* of the approximations for a. For example, an under-approximation |
187 |
|
* for the term len( replace( substr( x, 0, n ), y, z ) ) returned by this |
188 |
|
* function might be len( substr( x, 0, n ) ) - len( y ), where we don't |
189 |
|
* consider (recursively) the approximations for len( substr( x, 0, n ) ). |
190 |
|
*/ |
191 |
|
void getArithApproximations(Node a, |
192 |
|
std::vector<Node>& approx, |
193 |
|
bool isOverApprox = false); |
194 |
|
/** Set bound cache */ |
195 |
|
void setConstantBoundCache(Node n, Node ret, bool isLower); |
196 |
|
/** Get bound cache */ |
197 |
|
Node getConstantBoundCache(Node n, bool isLower); |
198 |
|
/** The underlying rewriter */ |
199 |
|
Rewriter* d_rr; |
200 |
|
/** Constant zero */ |
201 |
|
Node d_zero; |
202 |
|
}; |
203 |
|
|
204 |
|
} // namespace strings |
205 |
|
} // namespace theory |
206 |
|
} // namespace cvc5 |
207 |
|
|
208 |
|
#endif |