1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 SRI International.
4 *
5 * Yices is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Yices is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Yices. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /***********************************************************
20 * EXTENSION OF THE EGRAPH TO DEAL WITH FUNCTION UPDATES *
21 **********************************************************/
22
23 /*
24 * Started 2012/09/14:
25 * - the array solver is currently implemented as a
26 * satellite of the egraph. This makes if hard to support
27 * new things such as lambda terms and type predicates.
28 * - new approach: get rid of fun_solver and implement
29 * instantiation of the update/extensionality axioms
30 * directly in the Egraph.
31 *
32 * To do this, we add to the egraph an optional new component
33 * called the update graph. Vertices in this graph are
34 * equivalence classes of function terms (extracted from the egraph)
35 * and edges correspond to update terms. If a = (update b t1 .. tn v)
36 * then there's an edge from Class(a) to Class(b) labeled by a.
37 * Also, there's an edge from Class(b) to Class(a). If two nodes
38 * are connected in the update graph, then they represent functions
39 * that differ by finitely many values.
40 *
41 */
42
43 #ifndef __UPDATE_GRAPH_H
44 #define __UPDATE_GRAPH_H
45
46 #include <assert.h>
47 #include <stdint.h>
48 #include <stdbool.h>
49
50 #include "solvers/egraph/egraph_types.h"
51 #include "utils/bitvectors.h"
52 #include "utils/ptr_partitions.h"
53
54
55 /*
56 * Tree/queue for visiting the graph from a source node
57 * - for each visited node, we store three things
58 * - the node id
59 * - the index of the previous triple on the path from source to the node
60 * - the incoming edge from the previous node
61 * - data[0 ... top-1] = the triples for each visited node
62 * - ptr = next node to process
63 * - top = next record
64 * - size = size of the data array
65 *
66 * We explore the graph breadth first:
67 * - triples in data[0 ... ptr - 1] correspond to nodes
68 * whose successors have been visited
69 * - triples in data[ptr ... top - 1] is a queue of nodes
70 * that are reachable but whose successors have not been
71 * explored yet.
72 *
73 * - let x be data[ptr].node
74 * - if edge u of x leads to node y, then we add
75 * a new record at the end of the queue
76 * data[top].node = y
77 * data[top].pre = ptr
78 * data[top].edge = u
79 */
80 typedef struct ugraph_visit_s {
81 int32_t node;
82 int32_t pre;
83 composite_t *edge;
84 } ugraph_visit_t;
85
86 typedef struct ugraph_queue_s {
87 uint32_t size;
88 uint32_t top;
89 uint32_t ptr;
90 ugraph_visit_t *data;
91 } ugraph_queue_t;
92
93 #define DEF_UGRAPH_QUEUE_SIZE 20
94 #define MAX_UGRAPH_QUEUE_SIZE (UINT32_MAX/sizeof(ugraph_visit_t))
95
96
97 /*
98 * Set of pairs [tag, type] for which there exists a lambda term.
99 * If a lambda term has type [tau_1 x ... x tau_n -> sigma]
100 * then we add the pair (tag, sigma) where tag is the lambda-tag for
101 * tau_1 x ... x tau_n.
102 *
103 * For now, we just store the pairs in an array (since there shouldn't
104 * be many pairs). We keep a pointer to the type table.
105 */
106 typedef struct lambda_pair_s {
107 int32_t tag;
108 type_t range;
109 } lambda_pair_t;
110
111 typedef struct lpair_set_s {
112 uint32_t size;
113 uint32_t nelems;
114 lambda_pair_t *data;
115 type_table_t *types;
116 } lpair_set_t;
117
118 #define DEF_LPAIR_SET_SIZE 10
119 #define MAX_LPAIR_SET_SIZE (UINT32_MAX/sizeof(lambda_pair_t))
120
121
122
123 /*
124 * Statistics
125 */
126 typedef struct ugraph_stats_s {
127 uint32_t num_update_props;
128 uint32_t num_lambda_props;
129 uint32_t num_update_conflicts;
130 uint32_t num_lambda_conflicts;
131 } ugraph_stats_t;
132
133
134
135
136 /*
137 * Graph:
138 * - for each node x, we keep:
139 * class[x] = the corresponding egraph
140 * edges[x] = vector of outgoing edges from that node
141 * tag[x] = the lambda tag (as defined in the egraph ltag_table)
142 * mark[x] = one bit: 1 means x has been visited
143 * - the set of edges is stored in a pointer vector (cf. pointer_vectors.h)
144 *
145 * For every class c, we store
146 * class2node[c] = -1 if c has no matching node in the graph
147 * = x is c is matched to node x (i.e., class[x] = c)
148 *
149 * For propagation:
150 * - queue = visited nodes
151 * - partition = to group composite terms that have equal arguments
152 * - lpair_set = types for the lambda terms
153 */
154 struct update_graph_s {
155 egraph_t *egraph; // pointer to the egraph
156
157 uint32_t size; // size of arrays class, edges, and tag
158 uint32_t nodes; // number of nodes
159 class_t *class; // class[i] = class of node i
160 void ***edges; // edges[i] = array of (void*) pointers
161 int32_t *tag; // tag[i] = lambda tag
162 byte_t *mark; // mark[i] = one bit
163
164 uint32_t nclasses; // size of array class2node
165 int32_t *class2node; // class2node[c] = node for class c (-1 if none)
166
167 ugraph_queue_t queue; // for exploration
168 ppart_t partition; // partition of apply terms
169 lpair_set_t lpair_set; // types of lambda terms
170
171 ugraph_stats_t stats;
172
173 ivector_t aux_vector;
174 ivector_t lemma_vector;
175 };
176
177
178 #define MAX_UGRAPH_SIZE (UINT32_MAX/sizeof(void **))
179 #define DEF_UGRAPH_SIZE 100
180
181 #define MAX_UGRAPH_NCLASSES (UINT32_MAX/sizeof(int32_t))
182 #define DEF_UGRAPH_NCLASSES 100
183
184
185
186 /*
187 * Initialize ugraph (to the empty graph)
188 */
189 extern void init_ugraph(update_graph_t *ugraph, egraph_t *egraph);
190
191
192 /*
193 * Reset to the empty graph
194 */
195 extern void reset_ugraph(update_graph_t *ugraph);
196
197
198 /*
199 * Delete ugraph:
200 * - free all internal structures
201 */
202 extern void delete_ugraph(update_graph_t *ugraph);
203
204
205 /*
206 * Build ugraph based on the current egraph partition
207 * - ugraph must be initialized and empty
208 * - one node is created for each egraph class that has function type
209 * - for each update term b = (update a ... ) that's in the congruence
210 * table (congruence root), we create two edges:
211 * a direct edge from node[class[a]] to node[class[b]]
212 * a reverse edge from node[class[b]] to node[class[a]]
213 */
214 extern void build_ugraph(update_graph_t *ugraph);
215
216
217 /*
218 * Propagate at the base level
219 * - make sure build_ugraph was called first
220 * - this searches for equalities implied by the update graph
221 * and adds them to the egraph (as axioms)
222 * - return the number of equalities found
223 */
224 extern uint32_t ugraph_base_propagate(update_graph_t *ugraph);
225
226
227
228
229
230 /*
231 * Marks
232 */
ugraph_node_is_marked(update_graph_t * ugraph,int32_t i)233 static inline bool ugraph_node_is_marked(update_graph_t *ugraph, int32_t i) {
234 assert(0 <= i && i < ugraph->nodes);
235 return tst_bit(ugraph->mark, i);
236 }
237
ugraph_node_is_unmarked(update_graph_t * ugraph,int32_t i)238 static inline bool ugraph_node_is_unmarked(update_graph_t *ugraph, int32_t i) {
239 assert(0 <= i && i < ugraph->nodes);
240 return ! tst_bit(ugraph->mark, i);
241 }
242
ugraph_mark_node(update_graph_t * ugraph,int32_t i)243 static inline void ugraph_mark_node(update_graph_t *ugraph, int32_t i) {
244 assert(0 <= i && i < ugraph->nodes);
245 set_bit(ugraph->mark, i);
246 }
247
clear_ugraph_node_mark(update_graph_t * ugraph,int32_t i)248 static inline void clear_ugraph_node_mark(update_graph_t *ugraph, int32_t i) {
249 assert(0 <= i && i < ugraph->nodes);
250 clr_bit(ugraph->mark, i);
251 }
252
253
254 #endif
255