11 #include <boost/spirit/home/x3.hpp>
19 {BooleanFunction::Value::ONE,
"1"},
20 {BooleanFunction::Value::X,
"X"},
21 {BooleanFunction::Value::Z,
"Z"}};
28 return std::string(
"0");
30 return std::string(
"1");
32 return std::string(
"X");
34 return std::string(
"Z");
37 return std::string(
"X");
42 static std::vector<char> char_map = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
45 static Result<std::string> to_bin(
const std::vector<BooleanFunction::Value>& value)
47 if (value.size() == 0)
49 return ERR(
"could not convert bit-vector to binary string: bit-vector is empty");
53 res.reserve(value.size());
57 res += enum_to_string<BooleanFunction::Value>(v);
63 static Result<std::string> to_oct(
const std::vector<BooleanFunction::Value>& value)
65 int bitsize = value.size();
68 return ERR(
"could not convert bit-vector to octal string: bit-vector is empty");
71 u8 first_bits = bitsize % 3;
80 res.reserve((bitsize + 2) / 3);
83 for (
u8 i = 0; i < first_bits; i++)
86 index = (index << 1) | v1;
89 mask = -((mask >> 1) & 0x1);
92 res += (char_map[index] & ~mask) | (
'X' & mask);
96 for (
int i = bitsize % 3; i < bitsize; i += 3)
102 index = (v1 << 2) | (v2 << 1) | v3;
103 mask = -(((v1 | v2 | v3) >> 1) & 0x1);
105 res += (char_map[index] & ~mask) | (
'X' & mask);
110 static Result<std::string> to_dec(
const std::vector<BooleanFunction::Value>& value)
112 int bitsize = value.size();
115 return ERR(
"could not convert bit-vector to decimal string: bit-vector is empty");
120 return ERR(
"could not convert bit-vector to decimal string: bit-vector has length " + std::to_string(bitsize) +
", but only up to 64 bits are supported for decimal conversion");
126 for (
auto it = value.rbegin(); it != value.rend(); it++)
135 return OK(std::string(
"X"));
137 return OK(std::to_string(tmp));
140 static Result<std::string> to_hex(
const std::vector<BooleanFunction::Value>& value)
142 int bitsize = value.size();
145 return ERR(
"could not convert bit-vector to hexadecimal string: bit-vector is empty");
148 u8 first_bits = bitsize & 0x3;
156 std::string res =
"";
157 res.reserve((bitsize + 3) / 4);
160 for (
u8 i = 0; i < first_bits; i++)
163 index = (index << 1) | v1;
166 mask = -((mask >> 1) & 0x1);
169 res += (char_map[index] & ~mask) | (
'X' & mask);
173 for (
int i = bitsize & 0x3; i < bitsize; i += 4)
180 index = ((v1 << 3) | (v2 << 2) | (v3 << 1) | v4) & 0xF;
181 mask = -(((v1 | v2 | v3 | v4) >> 1) & 0x1);
183 res += (char_map[index] & ~mask) | (
'X' & mask);
195 return to_bin(value);
197 return to_oct(value);
199 return to_dec(value);
201 return to_hex(value);
203 return ERR(
"could not convert bit-vector to string: invalid value '" + std::to_string(base) +
"' given for base");
209 if (value.size() > 64)
211 return ERR(
"cannot translate vector of values to u64 numeral: can only support vectors up to 64 bits and got vector of size " + std::to_string(value.size()) +
".");
215 for (
auto it = value.rbegin(); it != value.rend(); it++)
217 if ((*it != BooleanFunction::Value::ZERO) && (*it != BooleanFunction::Value::ONE))
219 return ERR(
"cannot translate vector of values to u64 numeral: found value other than ZERO or ONE: " +
BooleanFunction::to_string(*it) +
".");
240 if (
auto res = BooleanFunction::validate(
BooleanFunction(std::move(nodes))); res.is_error())
242 return ERR_APPEND(res.get_error(),
"could not build Boolean function from vector of nodes: failed to validate Boolean function");
267 auto values = std::vector<BooleanFunction::Value>();
268 values.reserve(
size);
269 for (
auto i = 0; i <
size; i++)
271 values.emplace_back(((value >> i) & 1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
284 if ((p0.size() != p1.size()) || (p0.size() !=
size))
286 return ERR(
"could not join Boolean functions using AND operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
287 +
", size = " + std::to_string(
size) +
")");
295 if ((p0.size() != p1.size()) || (p0.size() !=
size))
297 return ERR(
"could not join Boolean functions using OR operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
298 +
", size = " + std::to_string(
size) +
").");
306 if (p0.size() !=
size)
308 return ERR(
"could not invert Boolean function using NOT operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", size = " + std::to_string(
size) +
").");
316 if ((p0.size() != p1.size()) || (p0.size() !=
size))
318 return ERR(
"could not join Boolean functions using XOR operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
319 +
", size = " + std::to_string(
size) +
").");
327 if ((p0.size() != p1.size()) || (p0.size() !=
size))
329 return ERR(
"could not join Boolean functions using ADD operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
330 +
", size = " + std::to_string(
size) +
").");
338 if ((p0.size() != p1.size()) || (p0.size() !=
size))
340 return ERR(
"could not join Boolean functions using SUB operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
341 +
", size = " + std::to_string(
size) +
").");
349 if ((p0.size() != p1.size()) || (p0.size() !=
size))
351 return ERR(
"could not join Boolean functions using MUL operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
352 +
", size = " + std::to_string(
size) +
").");
360 if ((p0.size() != p1.size()) || (p0.size() !=
size))
362 return ERR(
"could not join Boolean functions using SDIV operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
363 +
", size = " + std::to_string(
size) +
").");
371 if ((p0.size() != p1.size()) || (p0.size() !=
size))
373 return ERR(
"could not join Boolean functions using UDIV operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
374 +
", size = " + std::to_string(
size) +
").");
382 if ((p0.size() != p1.size()) || (p0.size() !=
size))
384 return ERR(
"could not join Boolean functions using SREM operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
385 +
", size = " + std::to_string(
size) +
").");
393 if ((p0.size() != p1.size()) || (p0.size() !=
size))
395 return ERR(
"could not join Boolean functions using UREM operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
396 +
", size = " + std::to_string(
size) +
").");
404 if (!p1.is_index() || !p2.is_index())
406 return ERR(
"could not apply slice operation: function types do not match (p1 and p2 must be of type 'BooleanFunction::Index')");
408 if ((p0.size() != p1.size()) || (p1.size() != p2.size()))
410 return ERR(
"could not apply slice operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size()) +
", p2 = " + std::to_string(p2.size())
411 +
" - sizes must be equal)");
414 auto start = p1.get_index_value().get();
415 auto end = p2.get_index_value().get();
416 if ((start > end) || (start >= p0.size()) || (end >= p0.size()) || (end - start + 1) !=
size)
418 return ERR(
"could not apply SLICE operation: bit indices are not valid, p1 must be larger or equal than p1 and smaller than p0 (p0 = " + std::to_string(p0.size())
419 +
", p1 = " + std::to_string(start) +
", p2 = " + std::to_string(end) +
")");
427 if ((p0.size() + p1.size()) !=
size)
429 return ERR(
"could not apply CONCAT operation: function input widths do not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
430 +
"-bit, size = " + std::to_string(
size) +
").");
438 if (p0.size() >
size || p1.size() !=
size)
440 return ERR(
"could not apply ZEXT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
441 +
"-bit, size = " + std::to_string(
size) +
").");
444 if (!p1.has_index_value(
size))
446 return ERR(
"could not apply ZEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
454 if (p0.size() >
size || p1.size() !=
size)
456 return ERR(
"could not apply SEXT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
457 +
"-bit, size = " + std::to_string(
size) +
").");
460 if (!p1.has_index_value(
size))
462 return ERR(
"could not apply SEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
470 if (p0.size() !=
size || p1.size() !=
size)
472 return ERR(
"could not apply SHL operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
473 +
"-bit, size = " + std::to_string(
size) +
").");
478 return ERR(
"could not apply SHL operation: p1 is not an index.");
486 if (p0.size() !=
size || p1.size() !=
size)
488 return ERR(
"could not apply LSHR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
489 +
"-bit, size = " + std::to_string(
size) +
").");
494 return ERR(
"could not apply LSHR operation: p1 is not an index.");
502 if (p0.size() !=
size || p1.size() !=
size)
504 return ERR(
"could not apply ASHR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
505 +
"-bit, size = " + std::to_string(
size) +
").");
510 return ERR(
"could not apply ASHR operation: p1 is not an index.");
518 if (p0.size() !=
size || p1.size() !=
size)
520 return ERR(
"could not apply ROL operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
521 +
"-bit, size = " + std::to_string(
size) +
").");
526 return ERR(
"could not apply ROL operation: p1 is not an index.");
534 if (p0.size() !=
size || p1.size() !=
size)
536 return ERR(
"could not apply ROR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
537 +
"-bit, size = " + std::to_string(
size) +
").");
542 return ERR(
"could not apply ROR operation: p1 is not an index.");
550 if (p0.size() != p1.size() ||
size != 1)
552 return ERR(
"could not apply EQ operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
553 +
"-bit, size = " + std::to_string(
size) +
").");
561 if (p0.size() != p1.size() ||
size != 1)
563 return ERR(
"could not apply SLE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
564 +
"-bit, size = " + std::to_string(
size) +
").");
572 if (p0.size() != p1.size() ||
size != 1)
574 return ERR(
"could not apply SLT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
575 +
"-bit, size = " + std::to_string(
size) +
").");
583 if (p0.size() != p1.size() ||
size != 1)
585 return ERR(
"could not apply ULE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
586 +
"-bit, size = " + std::to_string(
size) +
").");
594 if (p0.size() != p1.size() ||
size != 1)
596 return ERR(
"could not apply ULT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
597 +
"-bit, size = " + std::to_string(
size) +
").");
605 if (p0.size() != 1 || p1.size() !=
size || p2.size() !=
size)
607 return ERR(
"could not apply ITE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
608 +
"-bit, p2 = " + std::to_string(p2.size()) +
"-bit, size = " + std::to_string(
size) +
").");
692 if (this->m_nodes.size() != other.m_nodes.size())
697 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
699 if (this->m_nodes[i] != other.m_nodes[i])
709 return !(*
this == other);
714 if (this->m_nodes.size() < other.m_nodes.size())
718 if (this->m_nodes.size() > other.m_nodes.size())
723 return this->to_string_in_reverse_polish_notation() < other.to_string_in_reverse_polish_notation();
728 return this->m_nodes.empty();
734 function.m_nodes.reserve(this->m_nodes.size());
736 for (
const auto& node : this->m_nodes)
738 function.m_nodes.emplace_back(node);
768 return ERR(
"Boolean function is empty");
793 return ERR(
"Boolean function is empty");
803 return ERR(
"Boolean function is empty");
823 return ERR(
"Boolean function is empty");
831 return this->m_nodes.back();
836 return this->m_nodes.size();
841 return this->m_nodes;
853 auto coverage = this->compute_node_coverage();
860 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.end() - 1}))};
863 auto index = this->
length() - coverage[this->
length() - 2] - 1;
865 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index})),
866 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index, this->m_nodes.end() - 1}))};
869 auto index0 = this->
length() - coverage[this->
length() - 3] - coverage[this->
length() - 2] - 1;
870 auto index1 = this->
length() - coverage[this->
length() - 2] - 1;
872 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index0})),
873 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index0, this->m_nodes.begin() + index1})),
874 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index1, this->m_nodes.end() - 1}))};
878 assert(
false &&
"not implemented reached.");
886 auto variable_names = std::set<std::string>();
887 for (
const auto& node : this->m_nodes)
889 if (node.is_variable())
891 variable_names.insert(node.variable);
894 return variable_names;
901 return ERR(
"could not print Boolean function: node arity of " + std::to_string(node.
get_arity()) +
" does not match number of operands of " + std::to_string(operands.size()));
912 return OK(
"(" + operands[0] +
" & " + operands[1] +
")");
914 return OK(
"(! " + operands[0] +
")");
916 return OK(
"(" + operands[0] +
" | " + operands[1] +
")");
918 return OK(
"(" + operands[0] +
" ^ " + operands[1] +
")");
921 return OK(
"(" + operands[0] +
" + " + operands[1] +
")");
923 return OK(
"(" + operands[0] +
" - " + operands[1] +
")");
925 return OK(
"(" + operands[0] +
" * " + operands[1] +
")");
927 return OK(
"(" + operands[0] +
" /s " + operands[1] +
")");
929 return OK(
"(" + operands[0] +
" / " + operands[1] +
")");
931 return OK(
"(" + operands[0] +
" \%s " + operands[1] +
")");
933 return OK(
"(" + operands[0] +
" \% " + operands[1] +
")");
936 return OK(
"(" + operands[0] +
" ++ " + operands[1] +
")");
938 return OK(
"Slice(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
940 return OK(
"Zext(" + operands[0] +
", " + operands[1] +
")");
942 return OK(
"Sext(" + operands[0] +
", " + operands[1] +
")");
945 return OK(
"(" + operands[0] +
" << " + operands[1] +
")");
947 return OK(
"(" + operands[0] +
" >> " + operands[1] +
")");
949 return OK(
"(" + operands[0] +
" >>a " + operands[1] +
")");
951 return OK(
"(" + operands[0] +
" <<r " + operands[1] +
")");
953 return OK(
"(" + operands[0] +
" >>r " + operands[1] +
")");
956 return OK(
"(" + operands[0] +
" == " + operands[1] +
")");
958 return OK(
"(" + operands[0] +
" <s " + operands[1] +
")");
960 return OK(
"(" + operands[0] +
" <=s " + operands[1] +
")");
962 return OK(
"(" + operands[0] +
" < " + operands[1] +
")");
964 return OK(
"(" + operands[0] +
" <= " + operands[1] +
")");
966 return OK(
"Ite(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
969 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.
type) +
"'");
973 Result<std::string> BooleanFunction::algebraic_printer(
const BooleanFunction::Node& node, std::vector<std::string>&& operands)
975 if (node.get_arity() != operands.size())
977 return ERR(
"could not print Boolean function: node arity of " + std::to_string(node.get_arity()) +
" does not match number of operands of " + std::to_string(operands.size()));
984 return OK(node.to_string());
987 return OK(
"CONST" + std::string(node.has_constant_value(0) ?
"0" :
"1"));
990 return OK(
"(" + operands[0] +
"*" + operands[1] +
")");
992 return OK(
"(! " + operands[0] +
")");
994 return OK(
"(" + operands[0] +
"+" + operands[1] +
")");
997 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.type) +
"'");
1004 if (this->m_nodes.empty())
1010 std::vector<std::string> stack;
1011 for (
const auto& node : this->m_nodes)
1013 std::vector<std::string> operands;
1021 std::move(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end(), std::back_inserter(operands));
1022 stack.erase(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end());
1024 if (
auto res = printer(node, std::move(operands)); res.is_ok())
1026 stack.emplace_back(res.get());
1030 log_error(
"netlist",
"Cannot translate BooleanFunction::Node '{}' to a string: {}.", node.
to_string(), res.get_error().get());
1035 switch (stack.size())
1038 return stack.back();
1051 static const std::vector<std::tuple<ParserType, std::function<Result<std::vector<Token>>(
const std::string&)>>> parsers = {
1056 for (
const auto& [parser_type,
parser] : parsers)
1058 auto tokens =
parser(expression);
1060 if (tokens.is_error())
1067 if (tokens.is_error())
1073 if (
function.is_error())
1079 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1088 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1095 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1100 auto function = this->
clone();
1101 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1115 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1116 if (node.has_variable_name(var_name))
1118 return repl.
clone();
1123 std::vector<BooleanFunction> stack;
1124 for (
const auto& node : this->m_nodes)
1126 std::vector<BooleanFunction> operands;
1127 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1128 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1130 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1133 switch (stack.size())
1136 return OK(stack.back());
1138 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1144 auto function = this->
clone();
1145 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1147 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1149 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1151 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1166 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1167 if (node.is_variable())
1169 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1171 return repl_it->second.
clone();
1177 std::vector<BooleanFunction> stack;
1178 for (
const auto& node : this->m_nodes)
1180 std::vector<BooleanFunction> operands;
1181 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1182 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1184 stack.emplace_back(substitute_variable(node, std::move(operands)));
1187 switch (stack.size())
1190 return OK(stack.back());
1192 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1199 if (this->m_nodes.empty())
1201 return OK(BooleanFunction::Value::X);
1205 if (this->
size() != 1)
1207 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': using single-bit evaluation on a Boolean function of size " + std::to_string(this->
size()) +
" is illegal");
1211 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1212 for (
const auto& [
name, value] : inputs)
1214 generic_inputs.emplace(
name, std::vector<Value>({value}));
1217 auto value = this->
evaluate(generic_inputs);
1221 return OK(value.get()[0]);
1224 return ERR(value.get_error());
1230 if (this->m_nodes.empty())
1232 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1236 for (
const auto& [
name, value] : inputs)
1238 for (
const auto& node : this->m_nodes)
1240 if (node.has_variable_name(
name) && node.size != value.size())
1243 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the number of variables (" + std::to_string(node.size)
1244 +
") does not match the number of provided inputs (" + std::to_string(value.size()) +
")");
1251 for (
const auto& [
name, value] : inputs)
1258 auto result = symbolic_execution.evaluate(*
this);
1261 if (
auto value = result.get(); value.is_constant())
1263 return OK(value.get_top_level_node().constant);
1265 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1267 return ERR(result.get_error());
1276 for (
const auto& node : this->m_nodes)
1278 if (node.is_variable() && node.size != 1)
1280 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate a truth-table for Boolean function with variables of > 1-bit");
1285 auto variables = ordered_variables;
1286 if (variables.empty())
1288 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1292 if (remove_unknown_variables)
1295 std::remove_if(variables.begin(), variables.end(), [&variable_names_in_function](
const auto& s) { return variable_names_in_function.find(s) == variable_names_in_function.end(); }),
1301 if (this->m_nodes.empty())
1303 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1307 if (variables.size() > 10)
1309 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than 10 variables");
1312 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1315 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1317 std::unordered_map<std::string, std::vector<Value>>
input;
1319 for (
const auto& variable : variables)
1321 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1324 auto result = this->
evaluate(input);
1325 if (result.is_error())
1327 return ERR(result.get_error());
1329 auto output = result.get();
1330 for (
auto index = 0u; index < truth_table.size(); index++)
1332 truth_table[index][value] =
output[index];
1336 return OK(truth_table);
1341 std::vector<std::string> inputs;
1343 if (ordered_inputs.empty())
1345 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1349 inputs = ordered_inputs;
1352 if (remove_unknown_inputs)
1354 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1360 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1362 const auto truth_table = res.get();
1364 std::stringstream
str(
"");
1366 u32 num_inputs = inputs.size();
1367 u32 num_outputs = truth_table.size();
1370 std::vector<u32> in_widths;
1371 for (
const auto& var : inputs)
1373 in_widths.push_back(var.size());
1374 str <<
" " << var <<
" |";
1377 std::vector<u32> out_widths;
1378 if (function_name.empty())
1380 function_name =
"O";
1382 if (num_outputs == 1)
1384 str <<
"| " << function_name <<
" ";
1385 out_widths.push_back(function_name.size());
1389 for (
u32 i = 0; i < num_outputs; i++)
1391 std::string var = function_name +
"(" + std::to_string(i) +
")";
1392 str <<
"| " << var <<
" ";
1393 out_widths.push_back(var.size());
1399 for (
u32 i = 0; i < num_inputs; i++)
1401 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1403 for (
u32 i = 0; i < num_outputs; i++)
1405 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1410 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1412 for (
u32 j = 0; j < num_inputs; j++)
1414 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1417 for (
u32 k = 0; k < num_outputs; k++)
1419 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1423 return OK(
str.str());
1434 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1435 if (node.get_arity() != p.size())
1437 return {
false, z3::expr(context)};
1443 return {
true, context.bv_val(node.index, node.size)};
1447 auto constant = context.bv_val(node.constant.front(), 1);
1448 for (
u32 i = 1; i < node.constant.size(); i++)
1450 const auto bit = node.constant.at(i);
1451 constant = z3::concat(context.bv_val(bit, 1), constant);
1453 return {
true, constant};
1456 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1458 return {
true, it->second};
1460 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1464 return {
true, p[0] & p[1]};
1466 return {
true, p[0] | p[1]};
1468 return {
true, ~p[0]};
1470 return {
true, p[0] ^ p[1]};
1472 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1474 return {
true, z3::concat(p[0], p[1])};
1476 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1479 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1480 return {
false, z3::expr(context)};
1484 std::vector<z3::expr> stack;
1485 for (
const auto& node : this->m_nodes)
1487 std::vector<z3::expr> operands;
1488 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1489 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1491 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1493 stack.emplace_back(reduction);
1497 return z3::expr(context);
1501 switch (stack.size())
1504 return stack.back();
1506 return z3::expr(context);
1517 for (
const auto& parameter : p)
1519 size += parameter.size();
1521 this->m_nodes.reserve(
size);
1523 for (
auto&& parameter : p)
1525 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1527 this->m_nodes.emplace_back(node);
1530 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1533 for (
const auto& node : this->m_nodes)
1535 s += node.to_string() +
" ";
1540 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1546 if (
auto coverage =
function.compute_node_coverage(); coverage.back() !=
function.
length())
1548 auto str =
function.to_string_in_reverse_polish_notation();
1549 return ERR(
"could not validate '" +
str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1552 return OK(std::move(
function));
1555 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1557 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1564 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (index < cov.size()) ? cov[index] : -1; };
1573 auto set = [](
auto& cov,
size_t index,
u32 x = 0,
u32 y = 0,
u32 z = 0) { cov[index] = ((x != (
u32)-1) && (y != (
u32)-1) && (z != (
u32)-1)) ? (x + y + z + 1) : (
u32)-1; };
1575 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1577 auto arity = this->m_nodes[i].get_arity();
1586 auto x = get(coverage, i - 1);
1587 set(coverage, i, x);
1591 auto x = get(coverage, i - 1);
1592 auto y = get(coverage, i - 1 - x);
1593 set(coverage, i, x, y);
1597 auto x = get(coverage, i - 1);
1598 auto y = get(coverage, i - 1 - x);
1599 auto z = get(coverage, i - 1 - x - y);
1600 set(coverage, i, x, y, z);
1611 return Node(_type, _size, {}, {}, {});
1636 return !(*
this == other);
1646 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1655 for (
const auto& value : this->constant)
1663 return std::to_string(this->index);
1665 return this->variable;
1725 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
1736 static const std::map<u16, u16> type2arity = {
1747 return type2arity.at(
type);
1752 return this->
type == _type;
1762 return this->
is_constant() && (this->constant == value);
1772 auto bv_value = std::vector<BooleanFunction::Value>({});
1773 bv_value.reserve(this->
size);
1774 for (
auto i = 0u; i < this->constant.size(); i++)
1776 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
1778 return this->constant == bv_value;
1785 return ERR(
"Node is not a constant");
1788 return OK(this->constant);
1795 return ERR(
"Node is not a constant");
1798 if (this->
size > 64)
1800 return ERR(
"Node constant has size > 64");
1803 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
1805 return ERR(
"Node constant is undefined or high-impedance");
1809 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
1825 return this->
is_index() && (this->index == value);
1832 return ERR(
"Node is not an index");
1835 return OK(this->index);
1845 return this->
is_variable() && (this->variable == value);
1852 return ERR(
"Node is not a variable");
1855 return OK(this->variable);
1860 return !this->is_operand();
1874 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
1875 :
type(_type),
size(_size), constant(_constant), index(_index), variable(_variable)
static Result< BooleanFunction > Slt(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_index_value(u16 index) const
BooleanFunction operator+(const BooleanFunction &other) const
static Result< BooleanFunction > Ite(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
BooleanFunction operator&(const BooleanFunction &other) const
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Var(const std::string &name, u16 size=1)
static Result< BooleanFunction > Xor(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool operator==(const BooleanFunction &other) const
Result< std::string > get_variable_name() const
BooleanFunction operator^(const BooleanFunction &other) const
const BooleanFunction::Node & get_top_level_node() const
static Result< BooleanFunction > Add(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
std::set< std::string > get_variable_names() const
static Result< BooleanFunction > Lshr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_constant_value(const std::vector< Value > &value) const
static Result< BooleanFunction > Zext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
Result< std::vector< Value > > get_constant_value() const
static Result< BooleanFunction > Mul(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_variable_name(const std::string &variable_name) const
static Result< BooleanFunction > Ule(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sub(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Udiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction operator~() const
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ult(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Index(u16 index, u16 size)
z3::expr to_z3(z3::context &context, const std::map< std::string, z3::expr > &var2expr={}) const
Result< std::vector< std::vector< Value > > > compute_truth_table(const std::vector< std::string > &ordered_variables={}, bool remove_unknown_variables=false) const
BooleanFunction & operator-=(const BooleanFunction &other)
Result< Value > evaluate(const std::unordered_map< std::string, Value > &inputs) const
static Result< BooleanFunction > Sle(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > build(std::vector< Node > &&nodes)
BooleanFunction operator|(const BooleanFunction &other) const
static Result< BooleanFunction > from_string(const std::string &expression)
static Result< BooleanFunction > Slice(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
const std::vector< BooleanFunction::Node > & get_nodes() const
BooleanFunction & operator*=(const BooleanFunction &other)
BooleanFunction simplify() const
BooleanFunction operator-(const BooleanFunction &other) const
Result< std::string > get_truth_table_as_string(const std::vector< std::string > &ordered_variables={}, std::string function_name="", bool remove_unknown_variables=false) const
bool operator<(const BooleanFunction &other) const
BooleanFunction & operator&=(const BooleanFunction &other)
BooleanFunction clone() const
Value
represents the type of the node
static Result< BooleanFunction > Or(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool operator!=(const BooleanFunction &other) const
static Result< BooleanFunction > Urem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator^=(const BooleanFunction &other)
static Result< BooleanFunction > Ror(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator+=(const BooleanFunction &other)
static Result< BooleanFunction > Sdiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator|=(const BooleanFunction &other)
static std::string to_string(Value value)
BooleanFunction simplify_local() const
static BooleanFunction Const(const BooleanFunction::Value &value)
BooleanFunction operator*(const BooleanFunction &other) const
static Result< BooleanFunction > Ashr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< u64 > to_u64(const std::vector< BooleanFunction::Value > &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
std::vector< BooleanFunction > get_parameters() const
Result< u16 > get_index_value() const
BooleanFunction substitute(const std::string &old_variable_name, const std::string &new_variable_name) const
static Result< BooleanFunction > Shl(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
Result< u64 > get_constant_value_u64() const
static Result< BooleanFunction > Rol(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Srem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
#define log_error(channel,...)
#define ERR_APPEND(prev_error, message)
Result< std::vector< Token > > parse_with_standard_grammar(const std::string &expression)
Result< std::vector< Token > > parse_with_liberty_grammar(const std::string &expression)
ParserType
ParserType refers to the parser identifier.
Result< BooleanFunction > translate(std::vector< Token > &&tokens, const std::string &expression)
Result< std::vector< Token > > reverse_polish_notation(std::vector< Token > &&tokens, const std::string &expression, const ParserType &parser)
Result< BooleanFunction > local_simplification(const BooleanFunction &function)
std::ostream & operator<<(std::ostream &os, BooleanFunction::Value v)
std::string enum_to_string(T e)
include set(SRCROOT ${CMAKE_CURRENT_SOURCE_DIR}/src) set(UIROOT $
std::vector< BooleanFunction::Value > constant
The (optional) constant value of the node.
u16 type
The type of the node.
bool is_operation() const
u16 size
The bit-size of the node.
static u16 get_arity_of_type(u16 type)
static Node Constant(const std::vector< BooleanFunction::Value > value)
bool has_index_value(u16 value) const
std::string variable
The (optional) variable name of the node.
bool has_variable_name(const std::string &variable_name) const
static Node Operation(u16 type, u16 size)
bool has_constant_value(const std::vector< Value > &value) const
bool is_commutative() const
std::string to_string() const
Result< std::vector< Value > > get_constant_value() const
static Node Index(u16 index, u16 size)
Result< u16 > get_index_value() const
bool operator!=(const Node &other) const
bool operator==(const Node &other) const
bool operator<(const Node &other) const
u16 index
The (optional) index value of the node.
static Node Variable(const std::string variable, u16 size)
Result< std::string > get_variable_name() const
Result< u64 > get_constant_value_u64() const
static constexpr u16 Constant
static constexpr u16 Srem
static constexpr u16 Udiv
static constexpr u16 Sdiv
static constexpr u16 Urem
static constexpr u16 Lshr
static constexpr u16 Sext
static constexpr u16 Ashr
static constexpr u16 Index
static constexpr u16 Concat
static constexpr u16 Slice
static constexpr u16 Zext
static constexpr u16 Variable
Token refers to a token identifier and accompanied data.