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