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 <stdio.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <inttypes.h>
23 
24 #include "solvers/floyd_warshall/dl_vartable.h"
25 
26 #ifdef MINGW
27 
28 /*
29  * Need some version of random()
30  * rand() exists on mingw
31  */
random(void)32 static inline long int random(void) {
33   return rand();
34 }
35 
36 #endif
37 
38 
39 /*
40  * Print a monomial (copied from term_printer.c)
41  * - variables v is converted to vertex id i-1
42  */
print_monomial(int32_t v,rational_t * coeff,bool first)43 static void print_monomial(int32_t v, rational_t *coeff, bool first) {
44   bool negative;
45   bool abs_one;
46 
47   negative = q_is_neg(coeff);
48 
49   if (negative) {
50     if (first) {
51       printf("- ");
52     } else {
53       printf(" - ");
54     }
55     abs_one = q_is_minus_one(coeff);
56   } else {
57     if (! first) {
58       printf(" + ");
59     }
60     abs_one = q_is_one(coeff);
61   }
62 
63   if (v == const_idx) {
64     q_print_abs(stdout, coeff);
65   } else {
66     if (! abs_one) {
67       q_print_abs(stdout, coeff);
68       printf(" * ");
69     }
70     printf("x!%"PRId32, v-1);
71   }
72 }
73 
74 
75 /*
76  * Print monomial array a
77  * - n = number of monomials
78  */
print_polynomial(monomial_t * a,uint32_t n)79 static void print_polynomial(monomial_t *a, uint32_t n) {
80   uint32_t i;
81 
82   if (n == 0) {
83     printf("0");
84   } else {
85     for (i=0; i<n; i++) {
86       print_monomial(a[i].var, &a[i].coeff, i == 0);
87     }
88   }
89 }
90 
91 
92 /*
93  * Print the content of a poly_buffer b
94  */
print_poly_buffer(poly_buffer_t * b)95 static void print_poly_buffer(poly_buffer_t *b) {
96   print_polynomial(b->mono, b->nterms);
97 }
98 
99 
100 /*
101  * Print a triple
102  */
print_dl_triple(dl_triple_t * t)103 static void print_dl_triple(dl_triple_t *t) {
104   bool space;
105 
106   space = false;
107   if (t->target >= 0) {
108     printf("x!%"PRId32, t->target);
109     space = true;
110   }
111   if (t->source >= 0) {
112     if (space) printf(" ");
113     printf("- x!%"PRId32, t->source);
114   }
115 
116 
117   if (! space) {
118     q_print(stdout, &t->constant);
119   } else if (q_is_pos(&t->constant)) {
120     printf(" + ");
121     q_print(stdout, &t->constant);
122   } else if (q_is_neg(&t->constant)) {
123     printf(" - ");
124     q_print_abs(stdout, &t->constant);
125   }
126 }
127 
128 
129 /*
130  * Print table
131  */
print_dl_vartable(dl_vartable_t * table)132 static void print_dl_vartable(dl_vartable_t *table) {
133   uint32_t i, n;
134 
135   printf("DL vartable %p\n", table);
136   printf("  nvars = %"PRIu32"\n", table->nvars);
137   printf("  size = %"PRIu32"\n", table->size);
138   n = table->nvars;
139   if (n == 0) {
140     printf("  empty table\n");
141   } else {
142     printf("  content:\n");
143     for (i=0; i<n; i++) {
144       printf("    var[%"PRIu32"]: ", i);
145       print_dl_triple(dl_var_triple(table, i));
146       printf("\n");
147     }
148   }
149   printf("\n");
150 }
151 
152 
153 
154 /*
155  * Table of rationals for random tests
156  */
157 #define MAX_NUMERATOR (INT32_MAX>>1)
158 #define MIN_NUMERATOR (INT32_MIN>>1)
159 #define MAX_DENOMINATOR MAX_NUMERATOR
160 
161 static int32_t num[12] = {
162   1, 1, -1, 0, 120, -120, -120, 120, INT32_MAX, INT32_MIN, MIN_NUMERATOR, MAX_NUMERATOR
163 };
164 
165 static uint32_t den[12] = {
166   1, 10, 200, 72, 400, 999, INT32_MAX, MAX_DENOMINATOR, 1000, 120, 168, MAX_DENOMINATOR + 2
167 };
168 
169 
170 /*
171  * Assign a random rational to a
172  */
random_rational(rational_t * a)173 static void random_rational(rational_t *a) {
174   q_set_int32(a, num[random() % 12], den[random() %12]);
175 }
176 
177 /*
178  * Create a random index between 0 and n-1
179  */
random_vertex(uint32_t n)180 static int32_t random_vertex(uint32_t n) {
181   assert(n > 0);
182   return (int32_t) (random() % n);
183 }
184 
185 
186 /*
187  * Test hash consing: add a random triple in table
188  */
test_random_triple(dl_vartable_t * table)189 static void test_random_triple(dl_vartable_t *table) {
190   dl_triple_t *check;
191   dl_triple_t test;
192   int32_t x, y;
193 
194   test.target = random_vertex(6);
195   test.source = random_vertex(6);
196   q_init(&test.constant);
197   random_rational(&test.constant);
198   if (test.target == test.source) {
199     test.target = nil_vertex;
200     test.source = nil_vertex;
201   }
202 
203   printf("Test: add triple ");
204   print_dl_triple(&test);
205   printf("\n");
206   x = get_dl_var(table, &test);
207   printf(" ---> var = %"PRId32"\n", x);
208 
209   check = dl_var_triple(table, x);
210   if (check->target == test.target &&
211       check->source == test.source &&
212       q_eq(&check->constant, &test.constant)) {
213     printf("Checking descriptor: OK\n");
214   } else {
215     printf("BUG: invalid descriptor for var %"PRId32"\n", x);
216     fflush(stdout);
217     exit(1);
218   }
219 
220   y = get_dl_var(table, &test);
221   if (x == y) {
222     printf("Checking hash-consing: OK\n");
223   } else {
224     printf("BUG: hash-consing fails for var %"PRId32"\n", x);
225     fflush(stdout);
226     exit(1);
227   }
228 
229   printf("\n");
230   q_clear(&test.constant);
231 }
232 
233 
234 /*
235  * Test sum of triples for x and y
236  */
test_sum(dl_vartable_t * table,int32_t x,int32_t y,dl_triple_t * aux)237 static void test_sum(dl_vartable_t *table, int32_t x, int32_t y, dl_triple_t *aux) {
238   if (sum_dl_vars(table, x, y, aux)) {
239     printf("--> result = ");
240     print_dl_triple(aux);
241     printf("\n");
242   } else {
243     printf("--> result is not a triple\n");
244   }
245 }
246 
247 
248 /*
249  * Test difference of triples for x and y
250  */
test_diff(dl_vartable_t * table,int32_t x,int32_t y,dl_triple_t * aux)251 static void test_diff(dl_vartable_t *table, int32_t x, int32_t y, dl_triple_t *aux) {
252   if (diff_dl_vars(table, x, y, aux)) {
253     printf("--> result = ");
254     print_dl_triple(aux);
255     printf("\n");
256   } else {
257     printf("--> result is not a triple\n");
258   }
259 }
260 
261 
262 /*
263  * Test sum using a poly buffer
264  */
test_sum_buffer(dl_vartable_t * table,poly_buffer_t * buffer,int32_t x,int32_t y,dl_triple_t * aux)265 static void test_sum_buffer(dl_vartable_t *table, poly_buffer_t *buffer, int32_t x, int32_t y, dl_triple_t *aux) {
266   reset_poly_buffer(buffer);
267   add_dl_var_to_buffer(table, buffer, x);
268   add_dl_var_to_buffer(table, buffer, y);
269   normalize_poly_buffer(buffer);
270   printf("--> result = ");
271   print_poly_buffer(buffer);
272   printf("\n");
273   if (convert_poly_buffer_to_dl_triple(buffer, aux)) {
274     printf("--> convertible to triple: ");
275     print_dl_triple(aux);
276     printf("\n");
277   } else {
278     printf("--> not convertible to a triple\n");
279   }
280   if (rescale_poly_buffer_to_dl_triple(buffer, aux)) {
281     printf("--> convertible by rescaling to triple: ");
282     print_dl_triple(aux);
283     printf("\n");
284   } else {
285     printf("--> not convertible to a triple by rescaling\n");
286   }
287 }
288 
289 
test_diff_buffer(dl_vartable_t * table,poly_buffer_t * buffer,int32_t x,int32_t y,dl_triple_t * aux)290 static void test_diff_buffer(dl_vartable_t *table, poly_buffer_t *buffer, int32_t x, int32_t y, dl_triple_t *aux) {
291   reset_poly_buffer(buffer);
292   add_dl_var_to_buffer(table, buffer, x);
293   sub_dl_var_from_buffer(table, buffer, y);
294   normalize_poly_buffer(buffer);
295   printf("--> result = ");
296   print_poly_buffer(buffer);
297   printf("\n");
298   if (convert_poly_buffer_to_dl_triple(buffer, aux)) {
299     printf("--> convertible to triple: ");
300     print_dl_triple(aux);
301     printf("\n");
302   } else {
303     printf("--> not convertible to a triple\n");
304   }
305   if (rescale_poly_buffer_to_dl_triple(buffer, aux)) {
306     printf("--> convertible by rescaling to triple: ");
307     print_dl_triple(aux);
308     printf("\n");
309   } else {
310     printf("--> not convertible to a triple by rescaling\n");
311   }
312 }
313 
314 
315 
316 /*
317  * Test sum and difference of triples
318  */
test_add_diff(dl_vartable_t * table)319 static void test_add_diff(dl_vartable_t *table) {
320   uint32_t i, j, n;
321   dl_triple_t test;
322   dl_triple_t test2;
323   poly_buffer_t buffer;
324 
325   init_poly_buffer(&buffer);
326   q_init(&test.constant);
327   q_init(&test2.constant);
328 
329   n = table->nvars;
330   for (i=0; i<n; i++) {
331     for (j=0; j<n; j++) {
332       printf("Testing sum: var!%"PRIu32" + var!%"PRIu32":\n", i, j);
333       printf("--> var!%"PRIu32" : ", i);
334       print_dl_triple(dl_var_triple(table, i));
335       printf("\n");
336       printf("--> var!%"PRIu32" : ", j);
337       print_dl_triple(dl_var_triple(table, j));
338       printf("\n");
339       test_sum_buffer(table, &buffer, i, j, &test2);
340       test_sum(table, i, j, &test);
341       printf("\n");
342 
343       printf("Testing diff: var!%"PRIu32" - var!%"PRIu32":\n", i, j);
344       printf("--> var!%"PRIu32" : ", i);
345       print_dl_triple(dl_var_triple(table, i));
346       printf("\n");
347       printf("--> var!%"PRIu32" : ", j);
348       print_dl_triple(dl_var_triple(table, j));
349       printf("\n");
350       test_diff_buffer(table, &buffer, i, j, &test2);
351       test_diff(table, i, j, &test);
352       printf("\n");
353     }
354   }
355 
356   q_clear(&test.constant);
357   q_clear(&test2.constant);
358   delete_poly_buffer(&buffer);
359 }
360 
361 
362 
363 /*
364  * GLOBAL VARIABLE TABLE
365  */
366 static dl_vartable_t table;
367 
main(void)368 int main(void) {
369   uint32_t i;
370 
371   init_rationals();
372   init_dl_vartable(&table);
373   printf("Initial table\n");
374   print_dl_vartable(&table);
375 
376   for (i=0; i<10; i++) {
377     test_random_triple(&table);
378   }
379   printf("After 10 additions\n");
380   print_dl_vartable(&table);
381 
382   test_add_diff(&table);
383 
384   printf("Push\n");
385   dl_vartable_push(&table);
386 
387   for (i=0; i<10; i++) {
388     test_random_triple(&table);
389   }
390   printf("After 10 additions\n");
391   print_dl_vartable(&table);
392 
393   test_add_diff(&table);
394 
395   printf("Push\n");
396   dl_vartable_push(&table);
397 
398   printf("Pop\n");
399   dl_vartable_pop(&table);
400   print_dl_vartable(&table);
401 
402   printf("Pop\n");
403   dl_vartable_pop(&table);
404   print_dl_vartable(&table);
405 
406   printf("Reset\n");
407   reset_dl_vartable(&table);
408   print_dl_vartable(&table);
409 
410   printf("Push\n");
411   dl_vartable_push(&table);
412   for (i=0; i<100; i++) {
413     test_random_triple(&table);
414   }
415   printf("After 100 additions\n");
416   print_dl_vartable(&table);
417 
418   test_add_diff(&table);
419 
420   printf("Pop\n");
421   dl_vartable_pop(&table);
422   print_dl_vartable(&table);
423 
424   printf("Reset\n");
425   reset_dl_vartable(&table);
426   print_dl_vartable(&table);
427 
428   delete_dl_vartable(&table);
429   cleanup_rationals();
430 
431   return 0;
432 }
433