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 #include "mcsat/trail.h"
20 #include "io/term_printer.h"
21 #include "io/yices_pp.h"
22 
trail_construct(mcsat_trail_t * trail,const variable_db_t * var_db)23 void trail_construct(mcsat_trail_t* trail, const variable_db_t* var_db) {
24   trail->var_db = var_db;
25   init_ivector(&trail->elements, 0);
26   init_ivector(&trail->to_repropagate, 0);
27   init_ivector(&trail->level_sizes, 0);
28   trail->decision_level = 0;
29   trail->decision_level_base = 0;
30   mcsat_model_construct(&trail->model);
31   init_ivector(&trail->type, 0);
32   init_ivector(&trail->level, 0);
33   init_ivector(&trail->index, 0);
34   init_ivector(&trail->id, 0);
35   init_ivector(&trail->unassigned, 0);
36   trail->inconsistent = false;
37 }
38 
trail_destruct(mcsat_trail_t * trail)39 void trail_destruct(mcsat_trail_t* trail) {
40   trail->var_db = NULL;
41   delete_ivector(&trail->elements);
42   delete_ivector(&trail->to_repropagate);
43   delete_ivector(&trail->level_sizes);
44   trail->decision_level = 0;
45   mcsat_model_destruct(&trail->model);
46   delete_ivector(&trail->type);
47   delete_ivector(&trail->level);
48   delete_ivector(&trail->index);
49   delete_ivector(&trail->id);
50   delete_ivector(&trail->unassigned);
51 }
52 
trail_new_variable_notify(mcsat_trail_t * trail,variable_t x)53 void trail_new_variable_notify(mcsat_trail_t* trail, variable_t x) {
54   // Notify the model
55   mcsat_model_new_variable_notify(&trail->model, x);
56   // Resize variable info
57   while (trail->type.size <= x) {
58     ivector_push(&trail->type, UNASSIGNED);
59     ivector_push(&trail->level, -1);
60     ivector_push(&trail->index, -1);
61     ivector_push(&trail->id, -1);
62   }
63 }
64 
trail_print(const mcsat_trail_t * trail,FILE * out)65 void trail_print(const mcsat_trail_t* trail, FILE* out) {
66   uint32_t i;
67   variable_t var;
68   assignment_type_t var_type;
69 
70   fprintf(out, "[\n");
71   for (i = 0; i < trail->elements.size; ++ i) {
72     if (i) {
73       fprintf(out, ", ");
74     }
75     var = trail->elements.data[i];
76     var_type = trail_get_assignment_type(trail, var);
77 
78     if (var_type == DECISION) {
79       fprintf(out, "\n");
80     } else if (i > 0) {
81       variable_t prev_var = trail->elements.data[i-1];
82       uint32_t l = trail_get_level(trail, prev_var);
83       uint32_t l_end = trail_get_level(trail, var);
84       for (; l < l_end; ++ l) {
85         fprintf(out, "\n ----------- PUSH -------------- \n");
86       }
87     }
88 
89     variable_db_print_variable(trail->var_db, var, out);
90 
91     switch (var_type) {
92     case DECISION:
93       fprintf(out, " *= ");
94       break;
95     case PROPAGATION:
96       fprintf(out, " == ");
97       break;
98     default:
99       assert(false);
100     }
101     mcsat_value_print(trail->model.values + var, out);
102   }
103   fprintf(out, "\n]\n");
104 }
105 
106 static inline
trail_new_decision(mcsat_trail_t * trail)107 void trail_new_decision(mcsat_trail_t* trail) {
108   assert(trail_is_consistent(trail));
109   trail->decision_level ++;
110   ivector_push(&trail->level_sizes, trail->elements.size);
111 }
112 
trail_new_base_level(mcsat_trail_t * trail)113 void trail_new_base_level(mcsat_trail_t* trail) {
114   assert(trail->decision_level == trail->decision_level_base);
115   trail_new_decision(trail);
116   trail->decision_level_base = trail->decision_level;
117 }
118 
trail_pop_base_level(mcsat_trail_t * trail)119 uint32_t trail_pop_base_level(mcsat_trail_t* trail) {
120   assert(trail->decision_level == trail->decision_level_base);
121   assert(trail->decision_level_base > 0);
122   trail->decision_level_base --;
123   return trail->decision_level_base;
124 }
125 
126 static inline
trail_undo_decision(mcsat_trail_t * trail)127 void trail_undo_decision(mcsat_trail_t* trail) {
128   trail->decision_level --;
129   ivector_pop(&trail->level_sizes);
130 }
131 
132 static inline
trail_set_value(mcsat_trail_t * trail,variable_t x,const mcsat_value_t * value,uint32_t id,assignment_type_t type,uint32_t level)133 void trail_set_value(mcsat_trail_t* trail, variable_t x, const mcsat_value_t* value, uint32_t id, assignment_type_t type, uint32_t level) {
134   assert(trail->index.data[x] == -1);
135   assert(trail->type.data[x] == UNASSIGNED);
136   assert(trail->level.data[x] == -1);
137   assert(trail->id.data[x] == -1);
138   assert((type == DECISION && level == trail->decision_level) || (type == PROPAGATION && level <= trail->decision_level));
139 
140   // Remember the index
141   trail->index.data[x] = trail->elements.size;
142   // Set the type
143   trail->type.data[x] = type;
144   // Set the level
145   trail->level.data[x] = level;
146   // Set the id of the decision
147   trail->id.data[x] = id;
148 
149   // Set the value
150   assert(value->type != VALUE_BOOLEAN || variable_db_is_boolean(trail->var_db, x));
151   mcsat_model_set_value(&trail->model, x, value);
152 }
153 
154 static inline
trail_undo_value(mcsat_trail_t * trail,variable_t x)155 void trail_undo_value(mcsat_trail_t* trail, variable_t x) {
156   trail->type.data[x] = UNASSIGNED;
157   trail->index.data[x] = -1;
158   trail->level.data[x] = -1;
159   trail->id.data[x] = -1;
160   ivector_push(&trail->unassigned, x);
161 }
162 
trail_add_decision(mcsat_trail_t * trail,variable_t x,const mcsat_value_t * value,uint32_t id)163 void trail_add_decision(mcsat_trail_t* trail, variable_t x, const mcsat_value_t* value, uint32_t id) {
164   assert(x >= 0);
165   assert(!trail_has_value(trail, x));
166 
167   // Mark new decision
168   trail_new_decision(trail);
169   // Set the value
170   trail_set_value(trail, x, value, id, DECISION, trail->decision_level);
171   // Push the element
172   ivector_push(&trail->elements, x);
173 }
174 
trail_pop_decision(mcsat_trail_t * trail)175 void trail_pop_decision(mcsat_trail_t* trail) {
176   variable_t x;
177   // Undo the value with the addition of decision unmark
178   x = ivector_last(&trail->elements);
179   trail_undo_value(trail, x);
180   // Don't unset value, keep for caching: mcsat_model_unset_value(&trail->model, x);
181   trail_undo_decision(trail);
182   ivector_pop(&trail->elements);
183   // Also, we're back into consistent
184   trail->inconsistent = false;
185   // Repropagate
186   while (trail->to_repropagate.size > 0) {
187     x = ivector_last(&trail->to_repropagate);
188     ivector_pop(&trail->to_repropagate);
189     trail->index.data[x] = trail->elements.size;
190     ivector_push(&trail->elements, x);
191   }
192 }
193 
trail_add_propagation(mcsat_trail_t * trail,variable_t x,const mcsat_value_t * value,uint32_t id,uint32_t level)194 void trail_add_propagation(mcsat_trail_t* trail, variable_t x, const mcsat_value_t* value, uint32_t id, uint32_t level) {
195   assert(x >= 0);
196   assert(!trail_has_value(trail, x));
197   assert(level >= trail->decision_level_base);
198   // Set the value
199   trail_set_value(trail, x, value, id, PROPAGATION, level);
200   // Push the element
201   ivector_push(&trail->elements, x);
202 }
203 
204 
trail_pop_propagation(mcsat_trail_t * trail)205 void trail_pop_propagation(mcsat_trail_t* trail) {
206   variable_t x;
207   uint32_t x_level;
208   // Undo the value with the addition of decision unmark
209   x = ivector_last(&trail->elements);
210   x_level = trail_get_level(trail, x);
211   if (x_level == trail->decision_level) {
212     trail_undo_value(trail, x);
213     // Don't unset model value, keep for caching: mcsat_model_unset_value(&trail->model, x);
214   } else {
215     // Propagations at lower levels, remember and re-propagate during on pop-decision
216     assert(x_level < trail->decision_level);
217     ivector_push(&trail->to_repropagate, x);
218   }
219   ivector_pop(&trail->elements);
220 }
221 
trail_pop(mcsat_trail_t * trail)222 void trail_pop(mcsat_trail_t* trail) {
223   assert(trail->decision_level >= trail->decision_level_base);
224   assert(trail->level_sizes.size > 0);
225   uint32_t target_size = ivector_last(&trail->level_sizes);
226   while (trail->elements.size > target_size && trail_get_assignment_type(trail, trail_back(trail)) != DECISION) {
227     trail_pop_propagation(trail);
228   };
229   if (trail->elements.size > target_size) {
230     trail_pop_decision(trail);
231   } else {
232     // Fake push, no decision, so we just undo
233     trail_undo_decision(trail);
234     // Also, we're back into consistent
235     trail->inconsistent = false;
236   }
237 }
238 
trail_gc_mark(mcsat_trail_t * trail,gc_info_t * gc_vars)239 void trail_gc_mark(mcsat_trail_t* trail, gc_info_t* gc_vars) {
240 
241   uint32_t i;
242   variable_t var;
243 
244   assert(trail->to_repropagate.size == 0);
245   assert(trail->unassigned.size == 0);
246   assert(trail->decision_level == trail->decision_level_base);
247 
248   for (i = 0; i < trail->elements.size; ++ i) {
249     var = trail->elements.data[i];
250     assert(variable_db_is_variable(trail->var_db, var, true));
251     gc_info_mark(gc_vars, var);
252   }
253 }
254 
trail_gc_sweep(mcsat_trail_t * trail,const gc_info_t * gc_vars)255 void trail_gc_sweep(mcsat_trail_t* trail, const gc_info_t* gc_vars) {
256   variable_t var;
257 
258   assert(gc_vars->is_id);
259 
260   // Remove from the model cache, otherwise the cache might contain wrongly
261   // typed variables
262   for (var = 0; var < trail->model.size; ++ var) {
263     if (var != variable_null && gc_info_get_reloc(gc_vars, var) == variable_null) {
264       assert(!trail_has_value(trail, var));
265       if (mcsat_model_has_value(&trail->model, var)) {
266         mcsat_model_unset_value(&trail->model, var);
267       }
268       assert(!trail_has_value(trail, var));
269     }
270   }
271 }
272