/*
* This file is part of the Yices SMT Solver.
* Copyright (C) 2017 SRI International.
*
* Yices is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Yices is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Yices. If not, see .
*/
/*
* TEST BOOLEAN TABLE
*/
#include
#include
#include
#include "bool_vartable.h"
#include "smt_core_printer.h"
/*
* Display definition of variable x
*/
static void print_gate_desc(bgate_t *g) {
if (g->var[2] == null_bvar) {
printf("(gate p!%"PRId32" p!%"PRId32" [%02x])", g->var[0], g->var[1], (uint32_t) g->ttbl);
} else {
printf("(gate p!%"PRId32" p!%"PRId32" p!%"PRId32" [%02x])",
g->var[0], g->var[1], g->var[2], (uint32_t) g->ttbl);
}
}
static void print_or_desc(int32_t *d) {
int32_t n, i;
n = d[0];
printf("(or");
for (i=1; i<=n; i++) {
printf(" p!%"PRId32, d[i]);
}
printf(")");
}
static void show_var_def(bool_vartable_t *table, bvar_t x) {
assert(valid_boolvar(table, x));
printf("p!%"PRId32" := ", x);
switch (boolvar_tag(table, x)) {
case BCONST:
fputs("true", stdout);
break;
case BVAR:
printf("var");
break;
case BGATE:
print_gate_desc(boolvar_gate_desc(table, x));
break;
case BOR:
print_or_desc(boolvar_or_desc(table, x));
break;
}
}
static void show_bool_vartable(bool_vartable_t *table) {
uint32_t i, n;
printf("---- All variables ----\n");
n = table->nvars;
for (i=0; i= 0 && is_neg(l)) {
val ^= 1;
}
return val;
}
/*
* Evaluate gate g: return -1 if one of the variables is undefined
*/
static int32_t eval_bgate(bool_vartable_t *table, int8_t *v, uint32_t n, bgate_t *g) {
int32_t aux[3];
uint32_t i;
aux[0] = eval_var(table, v, n, g->var[0]);
aux[1] = eval_var(table, v, n, g->var[1]);
aux[2] = 0;
if (g->var[2] >= 0) {
aux[2] = eval_var(table, v, n, g->var[2]);
}
if (aux[0] < 0 || aux[1] < 0 || aux[2] < 0) {
return -1;
}
i = (aux[0] << 2) | (aux[1] << 1) | aux[2];
assert(0 <= i && i < 8);
return (g->ttbl >> i) & 0x01;
}
static int32_t eval_orgate(bool_vartable_t *table, int8_t *v, uint32_t n, int32_t *a) {
uint32_t i, p;
literal_t l;
int32_t val, aux;
p = a[0];
val = 0;
for (i=1; i<=p; i++) {
l = a[i];
aux = eval_lit(table, v, n, l);
if (aux == 1) return 1; // true
if (aux < 0) val = -1; // unknown
}
assert(val == 0 || val == -1);
return val;
}
/*
* Evaluate literal l
*/
static int32_t eval_literal(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l) {
bvar_t x;
int32_t val;
x = var_of(l);
val = -1;
if (x < n) {
val = v[x];
}
if (val < 0) {
switch (boolvar_tag(table, x)) {
case BCONST:
val = 1;
break;
case BVAR:
break;
case BGATE:
val = eval_bgate(table, v, n, boolvar_gate_desc(table, x));
break;
case BOR:
val = eval_orgate(table, v, n, boolvar_or_desc(table, x));
break;
default:
assert(false);
exit(1);
}
}
if (val >= 0 && is_neg(l)) {
val ^= 1; // flip
}
return val;
}
/*
* For cross-checking: evaluate primitive functions
*/
static int32_t eval_or2(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1, literal_t l2) {
int32_t val1, val2;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
if (val1 < 0 || val2 < 0) {
return -1; // to be consistent with eval_gate
}
return val1 | val2;
}
static int32_t eval_or3(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1,
literal_t l2, literal_t l3) {
int32_t val1, val2, val3;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
val3 = eval_lit(table, v, n, l3);
if (val1 < 0 || val2 < 0 || val3 < 0) {
return -1;
}
return val1 | val2 | val3;
}
static int32_t eval_xor2(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1, literal_t l2) {
int32_t val1, val2;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
if (val1 < 0 || val2 < 0) {
return -1; // to be consistent with eval_gate
}
return val1 ^ val2;
}
static int32_t eval_xor3(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1,
literal_t l2, literal_t l3) {
int32_t val1, val2, val3;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
val3 = eval_lit(table, v, n, l3);
if (val1 < 0 || val2 < 0 || val3 < 0) {
return -1;
}
return val1 ^ val2 ^ val3;
}
static int32_t eval_maj3(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1,
literal_t l2, literal_t l3) {
int32_t val1, val2, val3;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
val3 = eval_lit(table, v, n, l3);
if (val1 < 0 || val2 < 0 || val3 < 0) {
return -1;
}
return (val1 & val2) | (val1 & val3) | (val2 & val3);
}
static int32_t eval_ite(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1,
literal_t l2, literal_t l3) {
int32_t val1, val2, val3;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
val3 = eval_lit(table, v, n, l3);
if (val1 < 0 || val2 < 0 || val3 < 0) {
return -1;
}
return (val1 & val2) | ((!val1) & val3);
}
static int32_t eval_and2(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1, literal_t l2) {
int32_t val1, val2;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
if (val1 < 0 || val2 < 0) {
return -1; // to be consistent with eval_gate
}
return val1 & val2;
}
static int32_t eval_and3(bool_vartable_t *table, int8_t *v, uint32_t n, literal_t l1,
literal_t l2, literal_t l3) {
int32_t val1, val2, val3;
val1 = eval_lit(table, v, n, l1);
val2 = eval_lit(table, v, n, l2);
val3 = eval_lit(table, v, n, l3);
if (val1 < 0 || val2 < 0 || val3 < 0) {
return -1;
}
return val1 & val2 & val3;
}
/*
* Global array to store variable assignment
*/
#define MAX_VARS 100
static int8_t val[MAX_VARS];
static void reset_val(void) {
uint32_t i;
for (i=0; i= 0 && var_of(l) < MAX_VARS);
// ignore v if val[x] is already set
x = var_of(l);
if (val[x] < 0) {
v ^= is_neg(l); // flip if l is negative
val[x] = v;
}
}
/*
* Build assignment defined by l1, l2, and i
* - i must be between 0 and 3: bit 0 = value of l2, bit 1 = value of l1
* - special cases:
* if l1 = true or false: bit 1 is ignored
* if l2 = true or false: bit 0 is ignored
* if l1 = l2 or l1 = not(l2): bit 0 is ignored
*/
static void binary_assignment(literal_t l1, literal_t l2, uint32_t i) {
assert(0 <= i && i <= 3);
reset_val();
set_lit_val(l1, (i>>1) & 1);
set_lit_val(l2, i & 1);
}
/*
* same thing for l1, l2, l3, and i
* i must be between 0 and 7
*/
static void ternary_assignment(literal_t l1, literal_t l2, literal_t l3, uint32_t i) {
assert(0 <= i && i <= 7);
reset_val();
set_lit_val(l1, (i>>2) & 1);
set_lit_val(l2, (i>>1) & 1);
set_lit_val(l3, i & 1);
}
/*
* Check results
*/
// check l = (or l1 l2)
static void check_or2(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l) {
bvar_t x1, x2;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
if (x1 < MAX_VARS && x2 < MAX_VARS) {
for (i=0; i<4; i++) {
binary_assignment(l1, l2, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_or2(table, val, MAX_VARS, l1, l2);
if (check < 0 || check != v) {
printf("BUG: check_or2 failed\n");
exit(1);
}
}
}
}
// check l = (xor l1 l2)
static void check_xor2(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l) {
bvar_t x1, x2;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
if (x1 < MAX_VARS && x2 < MAX_VARS) {
for (i=0; i<4; i++) {
binary_assignment(l1, l2, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_xor2(table, val, MAX_VARS, l1, l2);
if (check < 0 || check != v) {
printf("BUG: check_xor2 failed\n");
exit(1);
}
}
}
}
// check l = (and l1 l2)
static void check_and2(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l) {
bvar_t x1, x2;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
if (x1 < MAX_VARS && x2 < MAX_VARS) {
for (i=0; i<4; i++) {
binary_assignment(l1, l2, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_and2(table, val, MAX_VARS, l1, l2);
if (check < 0 || check != v) {
printf("BUG: check_and2 failed\n");
exit(1);
}
}
}
}
// l = (or l1 l2 l3)
static void check_or3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3, literal_t l) {
bvar_t x1, x2, x3;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
x3 = var_of(l3);
if (x1 < MAX_VARS && x2 < MAX_VARS && x3 < MAX_VARS) {
for (i=0; i<8; i++) {
ternary_assignment(l1, l2, l3, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_or3(table, val, MAX_VARS, l1, l2, l3);
if (check < 0 || check != v) {
assert(false);
printf("BUG: check_or3 failed\n");
exit(1);
}
}
}
}
// l = (xor l1 l2 l3)
static void check_xor3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3, literal_t l) {
bvar_t x1, x2, x3;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
x3 = var_of(l3);
if (x1 < MAX_VARS && x2 < MAX_VARS && x3 < MAX_VARS) {
for (i=0; i<8; i++) {
ternary_assignment(l1, l2, l3, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_xor3(table, val, MAX_VARS, l1, l2, l3);
if (check < 0 || check != v) {
printf("BUG: check_xor3 failed\n");
exit(1);
}
}
}
}
// l = (or l1 l2 l3)
static void check_and3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3, literal_t l) {
bvar_t x1, x2, x3;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
x3 = var_of(l3);
if (x1 < MAX_VARS && x2 < MAX_VARS && x3 < MAX_VARS) {
for (i=0; i<8; i++) {
ternary_assignment(l1, l2, l3, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_and3(table, val, MAX_VARS, l1, l2, l3);
if (check < 0 || check != v) {
assert(false);
printf("BUG: check_and3 failed\n");
exit(1);
}
}
}
}
// l = (maj l1 l2 l3)
static void check_maj3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3, literal_t l) {
bvar_t x1, x2, x3;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
x3 = var_of(l3);
if (x1 < MAX_VARS && x2 < MAX_VARS && x3 < MAX_VARS) {
for (i=0; i<8; i++) {
ternary_assignment(l1, l2, l3, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_maj3(table, val, MAX_VARS, l1, l2, l3);
if (check < 0 || check != v) {
printf("BUG: check_maj3 failed\n");
exit(1);
}
}
}
}
// l = (ite l1 l2 l3)
static void check_ite(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3, literal_t l) {
bvar_t x1, x2, x3;
int32_t v, check;
uint32_t i;
x1 = var_of(l1);
x2 = var_of(l2);
x3 = var_of(l3);
if (x1 < MAX_VARS && x2 < MAX_VARS && x3 < MAX_VARS) {
for (i=0; i<8; i++) {
ternary_assignment(l1, l2, l3, i);
v = eval_literal(table, val, MAX_VARS, l);
check = eval_ite(table, val, MAX_VARS, l1, l2, l3);
if (check < 0 || check != v) {
printf("BUG: check_ite failed\n");
exit(1);
}
}
}
}
/*
* Test construction (or l1 l2)
*/
static void test_or2(bool_vartable_t *table, literal_t l1, literal_t l2) {
literal_t l, check, swap;
literal_t aux[2];
printf("test: (or ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(") --> ");
fflush(stdout);
l = make_or2(table, l1, l2);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_or2(table, l1, l2);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
swap = make_or2(table, l2, l1);
if (l != swap) {
printf("BUG: Symmetry failure\n");
exit(1);
}
aux[0] = l1;
aux[1] = l2;
check = make_or(table, 2, aux);
if (l != check) {
printf("BUG: mismatch between make_or and make_or2\n");
assert(false);
exit(1);
}
check_or2(table, l1, l2, l);
}
static void test_or3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3) {
literal_t l, check;
literal_t s1, s2, s3, s4, s5;
literal_t aux[3];
printf("test: (or ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(" ");
print_literal(stdout, l3);
printf(") --> ");
fflush(stdout);
l = make_or3(table, l1, l2, l3);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_or3(table, l1, l2, l3);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_or3(table, l1, l3, l2);
s2 = make_or3(table, l3, l1, l2);
s3 = make_or3(table, l2, l1, l3);
s4 = make_or3(table, l2, l3, l1);
s5 = make_or3(table, l3, l2, l1);
if (l != s1 || l != s2 || l != s3 || l != s4 || l != s5) {
printf("BUG: Symmetry failure\n");
exit(1);
}
aux[0] = l1;
aux[1] = l2;
aux[2] = l3;
check = make_or(table, 3, aux);
if (l != check) {
printf("BUG: mismatch between make_or and make_or3\n");
exit(1);
}
check_or3(table, l1, l2, l3, l);
}
/*
* Test construction (xor l1 l2)
*/
static void test_xor2(bool_vartable_t *table, literal_t l1, literal_t l2) {
literal_t l, check;
literal_t s1, s2, s3, s4;
literal_t aux[2];
printf("test: (xor ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(") --> ");
fflush(stdout);
l = make_xor2(table, l1, l2);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_xor2(table, l1, l2);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_xor2(table, l2, l1);
s2 = make_xor2(table, l1, not(l2));
s3 = make_xor2(table, not(l1), l2);
s4 = make_xor2(table, not(l1), not(l2));
if (l != s1 || l != not(s2) || l != not(s3) || l != s4) {
printf("BUG: in XOR2\n");
exit(1);
}
aux[0] = l1;
aux[1] = l2;
check = make_xor(table, 2, aux);
if (l != check) {
printf("BUG: mismatch between make_xor and make_xor2\n");
exit(1);
}
check_xor2(table, l1, l2, l);
}
static void test_xor3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3) {
literal_t l, check;
literal_t s1, s2, s3, s4, s5;
printf("test: (xor ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(" ");
print_literal(stdout, l3);
printf(") --> ");
fflush(stdout);
l = make_xor3(table, l1, l2, l3);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_xor3(table, l1, l2, l3);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_xor3(table, l1, l3, l2);
s2 = make_xor3(table, l1, l2, not(l3));
s3 = make_xor3(table, l1, not(l2), l3);
s4 = make_xor3(table, not(l1), l2, l3);
s5 = make_xor3(table, not(l1), not(l2), not(l3));
if (l != s1 || l != not(s2) || l != not(s3) || l != not(s4) || l != not(s5)) {
printf("BUG: in XOR3\n");
exit(1);
}
s2 = make_xor3(table, l1, not(l2), not(l3));
s3 = make_xor3(table, not(l1), not(l2), l3);
s4 = make_xor3(table, not(l1), l2, not(l3));
if (l != s2 || l != s3 || l != s4) {
printf("BUG in XOR3\n");
exit(1);
}
check_xor3(table, l1, l2, l3, l);
}
static void test_maj3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3) {
literal_t l, check;
literal_t s1, s2, s3, s4, s5;
printf("test: (maj ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(" ");
print_literal(stdout, l3);
printf(") --> ");
fflush(stdout);
l = make_maj3(table, l1, l2, l3);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_maj3(table, l1, l2, l3);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_maj3(table, l1, l3, l2);
s2 = make_maj3(table, l3, l1, l2);
s3 = make_maj3(table, l2, l1, l3);
s4 = make_maj3(table, l2, l3, l1);
s5 = make_maj3(table, l3, l2, l1);
if (l != s1 || l != s2 || l != s3 || l != s4 || l != s5) {
printf("BUG: Symmetry failure\n");
exit(1);
}
check_maj3(table, l1, l2, l3, l);
}
static void test_ite(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3) {
literal_t l, check;
literal_t s1, s2, s3;
printf("test: (ite ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(" ");
print_literal(stdout, l3);
printf(") --> ");
fflush(stdout);
l = make_ite(table, l1, l2, l3);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_ite(table, l1, l2, l3);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_ite(table, not(l1), l3, l2);
s2 = make_ite(table, l1, not(l2), not(l3));
s3 = make_ite(table, not(l1), not(l3), not(l2));
if (l != s1 || l != not(s2) || l != not(s3)) {
printf("BUG in ITE\n");
exit(1);
}
check_ite(table, l1, l2, l3, l);
}
static void test_and2(bool_vartable_t *table, literal_t l1, literal_t l2) {
literal_t l, check, swap;
literal_t aux[2];
printf("test: (and ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(") --> ");
fflush(stdout);
l = make_and2(table, l1, l2);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_and2(table, l1, l2);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
swap = make_and2(table, l2, l1);
if (l != swap) {
printf("BUG: Symmetry failure\n");
exit(1);
}
aux[0] = l1;
aux[1] = l2;
check = make_and(table, 2, aux);
if (l != check) {
printf("BUG: mismatch between make_and and make_and2\n");
assert(false);
exit(1);
}
check_and2(table, l1, l2, l);
}
static void test_and3(bool_vartable_t *table, literal_t l1, literal_t l2, literal_t l3) {
literal_t l, check;
literal_t s1, s2, s3, s4, s5;
literal_t aux[3];
printf("test: (or ");
print_literal(stdout, l1);
printf(" ");
print_literal(stdout, l2);
printf(" ");
print_literal(stdout, l3);
printf(") --> ");
fflush(stdout);
l = make_and3(table, l1, l2, l3);
print_literal(stdout, l);
printf("\n");
fflush(stdout);
check = make_and3(table, l1, l2, l3);
if (l != check) {
printf("BUG: Hash consing error\n");
exit(1);
}
s1 = make_and3(table, l1, l3, l2);
s2 = make_and3(table, l3, l1, l2);
s3 = make_and3(table, l2, l1, l3);
s4 = make_and3(table, l2, l3, l1);
s5 = make_and3(table, l3, l2, l1);
if (l != s1 || l != s2 || l != s3 || l != s4 || l != s5) {
printf("BUG: Symmetry failure\n");
exit(1);
}
aux[0] = l1;
aux[1] = l2;
aux[2] = l3;
check = make_and(table, 3, aux);
if (l != check) {
printf("BUG: mismatch between make_and and make_and3\n");
exit(1);
}
check_and3(table, l1, l2, l3, l);
}
/*
* Tests using variables in a[0 ..n-1]
*/
static void tests(bool_vartable_t *table, uint32_t n, bvar_t *a) {
uint32_t i, j, k;
bvar_t x, y, z;
for (i=0; i