11 #include <boost/spirit/home/x3.hpp>
20 {BooleanFunction::Value::ONE,
"1"},
21 {BooleanFunction::Value::X,
"X"},
22 {BooleanFunction::Value::Z,
"Z"}};
29 return std::string(
"0");
31 return std::string(
"1");
33 return std::string(
"X");
35 return std::string(
"Z");
38 return std::string(
"X");
43 static std::vector<char> char_map = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
46 static Result<std::string> to_bin(
const std::vector<BooleanFunction::Value>& value)
48 if (value.size() == 0)
50 return ERR(
"could not convert bit-vector to binary string: bit-vector is empty");
54 res.reserve(value.size());
58 res += enum_to_string<BooleanFunction::Value>(v);
64 static Result<std::string> to_oct(
const std::vector<BooleanFunction::Value>& value)
66 int bitsize = value.size();
69 return ERR(
"could not convert bit-vector to octal string: bit-vector is empty");
72 u8 first_bits = bitsize % 3;
81 res.reserve((bitsize + 2) / 3);
84 for (
u8 i = 0; i < first_bits; i++)
87 index = (index << 1) | v1;
90 mask = -((mask >> 1) & 0x1);
93 res += (char_map[index] & ~mask) | (
'X' & mask);
97 for (
int i = bitsize % 3; i < bitsize; i += 3)
103 index = (v1 << 2) | (v2 << 1) | v3;
104 mask = -(((v1 | v2 | v3) >> 1) & 0x1);
106 res += (char_map[index] & ~mask) | (
'X' & mask);
111 static Result<std::string> to_dec(
const std::vector<BooleanFunction::Value>& value)
113 int bitsize = value.size();
116 return ERR(
"could not convert bit-vector to decimal string: bit-vector is empty");
121 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");
127 for (
auto it = value.rbegin(); it != value.rend(); it++)
136 return OK(std::string(
"X"));
138 return OK(std::to_string(tmp));
141 static Result<std::string> to_hex(
const std::vector<BooleanFunction::Value>& value)
143 int bitsize = value.size();
146 return ERR(
"could not convert bit-vector to hexadecimal string: bit-vector is empty");
149 u8 first_bits = bitsize & 0x3;
157 std::string res =
"";
158 res.reserve((bitsize + 3) / 4);
161 for (
u8 i = 0; i < first_bits; i++)
164 index = (index << 1) | v1;
167 mask = -((mask >> 1) & 0x1);
170 res += (char_map[index] & ~mask) | (
'X' & mask);
174 for (
int i = bitsize & 0x3; i < bitsize; i += 4)
181 index = ((v1 << 3) | (v2 << 2) | (v3 << 1) | v4) & 0xF;
182 mask = -(((v1 | v2 | v3 | v4) >> 1) & 0x1);
184 res += (char_map[index] & ~mask) | (
'X' & mask);
196 return to_bin(value);
198 return to_oct(value);
200 return to_dec(value);
202 return to_hex(value);
204 return ERR(
"could not convert bit-vector to string: invalid value '" + std::to_string(base) +
"' given for base");
210 if (value.size() > 64)
212 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()) +
".");
216 for (
auto it = value.rbegin(); it != value.rend(); it++)
218 if ((*it != BooleanFunction::Value::ZERO) && (*it != BooleanFunction::Value::ONE))
220 return ERR(
"cannot translate vector of values to u64 numeral: found value other than ZERO or ONE: " +
BooleanFunction::to_string(*it) +
".");
241 if (
auto res = BooleanFunction::validate(
BooleanFunction(std::move(nodes))); res.is_error())
243 return ERR_APPEND(res.get_error(),
"could not build Boolean function from vector of nodes: failed to validate Boolean function");
268 auto values = std::vector<BooleanFunction::Value>();
269 values.reserve(
size);
270 for (
auto i = 0; i <
size; i++)
272 values.emplace_back(((value >> i) & 1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
285 if ((p0.size() != p1.size()) || (p0.size() !=
size))
287 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())
288 +
", size = " + std::to_string(
size) +
")");
296 if ((p0.size() != p1.size()) || (p0.size() !=
size))
298 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())
299 +
", size = " + std::to_string(
size) +
").");
307 if (p0.size() !=
size)
309 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) +
").");
317 if ((p0.size() != p1.size()) || (p0.size() !=
size))
319 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())
320 +
", size = " + std::to_string(
size) +
").");
328 if ((p0.size() != p1.size()) || (p0.size() !=
size))
330 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())
331 +
", size = " + std::to_string(
size) +
").");
339 if ((p0.size() != p1.size()) || (p0.size() !=
size))
341 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())
342 +
", size = " + std::to_string(
size) +
").");
350 if ((p0.size() != p1.size()) || (p0.size() !=
size))
352 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())
353 +
", size = " + std::to_string(
size) +
").");
361 if ((p0.size() != p1.size()) || (p0.size() !=
size))
363 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())
364 +
", size = " + std::to_string(
size) +
").");
372 if ((p0.size() != p1.size()) || (p0.size() !=
size))
374 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())
375 +
", size = " + std::to_string(
size) +
").");
383 if ((p0.size() != p1.size()) || (p0.size() !=
size))
385 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())
386 +
", size = " + std::to_string(
size) +
").");
394 if ((p0.size() != p1.size()) || (p0.size() !=
size))
396 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())
397 +
", size = " + std::to_string(
size) +
").");
405 if (!p1.is_index() || !p2.is_index())
407 return ERR(
"could not apply slice operation: function types do not match (p1 and p2 must be of type 'BooleanFunction::Index')");
409 if ((p0.size() != p1.size()) || (p1.size() != p2.size()))
411 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())
412 +
" - sizes must be equal)");
415 auto start = p1.get_index_value().get();
416 auto end = p2.get_index_value().get();
417 if ((start > end) || (start >= p0.size()) || (end >= p0.size()) || (end - start + 1) !=
size)
419 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())
420 +
", p1 = " + std::to_string(start) +
", p2 = " + std::to_string(end) +
")");
428 if ((p0.size() + p1.size()) !=
size)
430 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())
431 +
"-bit, size = " + std::to_string(
size) +
").");
439 if (p0.size() >
size || p1.size() !=
size)
441 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())
442 +
"-bit, size = " + std::to_string(
size) +
").");
445 if (!p1.has_index_value(
size))
447 return ERR(
"could not apply ZEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
455 if (p0.size() >
size || p1.size() !=
size)
457 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())
458 +
"-bit, size = " + std::to_string(
size) +
").");
461 if (!p1.has_index_value(
size))
463 return ERR(
"could not apply SEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
471 if (p0.size() !=
size || p1.size() !=
size)
473 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())
474 +
"-bit, size = " + std::to_string(
size) +
").");
479 return ERR(
"could not apply SHL operation: p1 is not an index.");
487 if (p0.size() !=
size || p1.size() !=
size)
489 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())
490 +
"-bit, size = " + std::to_string(
size) +
").");
495 return ERR(
"could not apply LSHR operation: p1 is not an index.");
503 if (p0.size() !=
size || p1.size() !=
size)
505 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())
506 +
"-bit, size = " + std::to_string(
size) +
").");
511 return ERR(
"could not apply ASHR operation: p1 is not an index.");
519 if (p0.size() !=
size || p1.size() !=
size)
521 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())
522 +
"-bit, size = " + std::to_string(
size) +
").");
527 return ERR(
"could not apply ROL operation: p1 is not an index.");
535 if (p0.size() !=
size || p1.size() !=
size)
537 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())
538 +
"-bit, size = " + std::to_string(
size) +
").");
543 return ERR(
"could not apply ROR operation: p1 is not an index.");
551 if (p0.size() != p1.size() ||
size != 1)
553 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())
554 +
"-bit, size = " + std::to_string(
size) +
").");
562 if (p0.size() != p1.size() ||
size != 1)
564 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())
565 +
"-bit, size = " + std::to_string(
size) +
").");
573 if (p0.size() != p1.size() ||
size != 1)
575 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())
576 +
"-bit, size = " + std::to_string(
size) +
").");
584 if (p0.size() != p1.size() ||
size != 1)
586 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())
587 +
"-bit, size = " + std::to_string(
size) +
").");
595 if (p0.size() != p1.size() ||
size != 1)
597 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())
598 +
"-bit, size = " + std::to_string(
size) +
").");
606 if (p0.size() != 1 || p1.size() !=
size || p2.size() !=
size)
608 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())
609 +
"-bit, p2 = " + std::to_string(p2.size()) +
"-bit, size = " + std::to_string(
size) +
").");
693 if (this->m_nodes.size() != other.m_nodes.size())
698 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
700 if (this->m_nodes[i] != other.m_nodes[i])
710 return !(*
this == other);
715 if (this->m_nodes.size() < other.m_nodes.size())
719 if (this->m_nodes.size() > other.m_nodes.size())
724 return this->to_string_in_reverse_polish_notation() < other.to_string_in_reverse_polish_notation();
729 return this->m_nodes.empty();
735 function.m_nodes.reserve(this->m_nodes.size());
737 for (
const auto& node : this->m_nodes)
739 function.m_nodes.emplace_back(node);
769 return ERR(
"Boolean function is empty");
794 return ERR(
"Boolean function is empty");
804 return ERR(
"Boolean function is empty");
824 return ERR(
"Boolean function is empty");
832 return this->m_nodes.back();
837 return this->m_nodes.size();
842 return this->m_nodes;
854 auto coverage = this->compute_node_coverage();
861 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.end() - 1}))};
864 auto index = this->
length() - coverage[this->
length() - 2] - 1;
866 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index})),
867 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index, this->m_nodes.end() - 1}))};
870 auto index0 = this->
length() - coverage[this->
length() - 3] - coverage[this->
length() - 2] - 1;
871 auto index1 = this->
length() - coverage[this->
length() - 2] - 1;
873 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index0})),
874 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index0, this->m_nodes.begin() + index1})),
875 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index1, this->m_nodes.end() - 1}))};
879 assert(
false &&
"not implemented reached.");
887 auto variable_names = std::set<std::string>();
888 for (
const auto& node : this->m_nodes)
890 if (node.is_variable())
892 variable_names.insert(node.variable);
895 return variable_names;
902 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()));
913 return OK(
"(" + operands[0] +
" & " + operands[1] +
")");
915 return OK(
"(! " + operands[0] +
")");
917 return OK(
"(" + operands[0] +
" | " + operands[1] +
")");
919 return OK(
"(" + operands[0] +
" ^ " + operands[1] +
")");
922 return OK(
"(" + operands[0] +
" + " + operands[1] +
")");
924 return OK(
"(" + operands[0] +
" - " + operands[1] +
")");
926 return OK(
"(" + operands[0] +
" * " + operands[1] +
")");
928 return OK(
"(" + operands[0] +
" /s " + operands[1] +
")");
930 return OK(
"(" + operands[0] +
" / " + operands[1] +
")");
932 return OK(
"(" + operands[0] +
" \%s " + operands[1] +
")");
934 return OK(
"(" + operands[0] +
" \% " + operands[1] +
")");
937 return OK(
"(" + operands[0] +
" ++ " + operands[1] +
")");
939 return OK(
"Slice(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
941 return OK(
"Zext(" + operands[0] +
", " + operands[1] +
")");
943 return OK(
"Sext(" + operands[0] +
", " + operands[1] +
")");
946 return OK(
"(" + operands[0] +
" << " + operands[1] +
")");
948 return OK(
"(" + operands[0] +
" >> " + operands[1] +
")");
950 return OK(
"(" + operands[0] +
" >>a " + operands[1] +
")");
952 return OK(
"(" + operands[0] +
" <<r " + operands[1] +
")");
954 return OK(
"(" + operands[0] +
" >>r " + operands[1] +
")");
957 return OK(
"(" + operands[0] +
" == " + operands[1] +
")");
959 return OK(
"(" + operands[0] +
" <s " + operands[1] +
")");
961 return OK(
"(" + operands[0] +
" <=s " + operands[1] +
")");
963 return OK(
"(" + operands[0] +
" < " + operands[1] +
")");
965 return OK(
"(" + operands[0] +
" <= " + operands[1] +
")");
967 return OK(
"Ite(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
970 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.
type) +
"'");
974 Result<std::string> BooleanFunction::algebraic_printer(
const BooleanFunction::Node& node, std::vector<std::string>&& operands)
976 if (node.get_arity() != operands.size())
978 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()));
985 return OK(node.to_string());
988 return OK(
"CONST" + std::string(node.has_constant_value(0) ?
"0" :
"1"));
991 return OK(
"(" + operands[0] +
"*" + operands[1] +
")");
993 return OK(
"(! " + operands[0] +
")");
995 return OK(
"(" + operands[0] +
"+" + operands[1] +
")");
998 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.type) +
"'");
1005 if (this->m_nodes.empty())
1011 std::vector<std::string> stack;
1012 for (
const auto& node : this->m_nodes)
1014 std::vector<std::string> operands;
1022 std::move(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end(), std::back_inserter(operands));
1023 stack.erase(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end());
1025 if (
auto res = printer(node, std::move(operands)); res.is_ok())
1027 stack.emplace_back(res.get());
1031 log_error(
"netlist",
"Cannot translate BooleanFunction::Node '{}' to a string: {}.", node.
to_string(), res.get_error().get());
1036 switch (stack.size())
1039 return stack.back();
1052 static const std::vector<std::tuple<ParserType, std::function<Result<std::vector<Token>>(
const std::string&)>>> parsers = {
1057 for (
const auto& [parser_type,
parser] : parsers)
1059 auto tokens =
parser(expression);
1061 if (tokens.is_error())
1068 if (tokens.is_error())
1074 if (
function.is_error())
1080 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1089 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1096 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1101 auto function = this->
clone();
1102 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1116 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1117 if (node.has_variable_name(var_name))
1119 return repl.
clone();
1124 std::vector<BooleanFunction> stack;
1125 for (
const auto& node : this->m_nodes)
1127 std::vector<BooleanFunction> operands;
1128 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1129 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1131 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1134 switch (stack.size())
1137 return OK(stack.back());
1139 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1145 auto function = this->
clone();
1146 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1148 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1150 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1152 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1167 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1168 if (node.is_variable())
1170 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1172 return repl_it->second.
clone();
1178 std::vector<BooleanFunction> stack;
1179 for (
const auto& node : this->m_nodes)
1181 std::vector<BooleanFunction> operands;
1182 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1183 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1185 stack.emplace_back(substitute_variable(node, std::move(operands)));
1188 switch (stack.size())
1191 return OK(stack.back());
1193 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1200 if (this->m_nodes.empty())
1202 return OK(BooleanFunction::Value::X);
1206 if (this->
size() != 1)
1208 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");
1212 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1213 for (
const auto& [
name, value] : inputs)
1215 generic_inputs.emplace(
name, std::vector<Value>({value}));
1218 auto value = this->
evaluate(generic_inputs);
1222 return OK(value.get()[0]);
1225 return ERR(value.get_error());
1231 if (this->m_nodes.empty())
1233 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1237 for (
const auto& [
name, value] : inputs)
1239 for (
const auto& node : this->m_nodes)
1241 if (node.has_variable_name(
name) && node.size != value.size())
1244 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the number of variables (" + std::to_string(node.size)
1245 +
") does not match the number of provided inputs (" + std::to_string(value.size()) +
")");
1252 for (
const auto& [
name, value] : inputs)
1259 auto result = symbolic_execution.evaluate(*
this);
1262 if (
auto value = result.get(); value.is_constant())
1264 return OK(value.get_top_level_node().constant);
1266 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1268 return ERR(result.get_error());
1277 for (
const auto& node : this->m_nodes)
1279 if (node.is_variable() && node.size != 1)
1281 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");
1286 auto variables = ordered_variables;
1287 if (variables.empty())
1289 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1293 if (remove_unknown_variables)
1296 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(); }),
1302 if (this->m_nodes.empty())
1304 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1308 if (variables.size() > 10)
1310 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than 10 variables");
1313 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1316 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1318 std::unordered_map<std::string, std::vector<Value>>
input;
1320 for (
const auto& variable : variables)
1322 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1325 auto result = this->
evaluate(input);
1326 if (result.is_error())
1328 return ERR(result.get_error());
1330 auto output = result.get();
1331 for (
auto index = 0u; index < truth_table.size(); index++)
1333 truth_table[index][value] =
output[index];
1337 return OK(truth_table);
1342 std::vector<std::string> inputs;
1344 if (ordered_inputs.empty())
1346 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1350 inputs = ordered_inputs;
1353 if (remove_unknown_inputs)
1355 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1361 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1363 const auto truth_table = res.get();
1365 std::stringstream
str(
"");
1367 u32 num_inputs = inputs.size();
1368 u32 num_outputs = truth_table.size();
1371 std::vector<u32> in_widths;
1372 for (
const auto& var : inputs)
1374 in_widths.push_back(var.size());
1375 str <<
" " << var <<
" |";
1378 std::vector<u32> out_widths;
1379 if (function_name.empty())
1381 function_name =
"O";
1383 if (num_outputs == 1)
1385 str <<
"| " << function_name <<
" ";
1386 out_widths.push_back(function_name.size());
1390 for (
u32 i = 0; i < num_outputs; i++)
1392 std::string var = function_name +
"(" + std::to_string(i) +
")";
1393 str <<
"| " << var <<
" ";
1394 out_widths.push_back(var.size());
1400 for (
u32 i = 0; i < num_inputs; i++)
1402 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1404 for (
u32 i = 0; i < num_outputs; i++)
1406 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1411 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1413 for (
u32 j = 0; j < num_inputs; j++)
1415 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1418 for (
u32 k = 0; k < num_outputs; k++)
1420 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1424 return OK(
str.str());
1435 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1436 if (node.get_arity() != p.size())
1438 return {
false, z3::expr(context)};
1444 return {
true, context.bv_val(node.index, node.size)};
1448 auto constant = context.bv_val(node.constant.front(), 1);
1449 for (
u32 i = 1; i < node.constant.size(); i++)
1451 const auto bit = node.constant.at(i);
1452 constant = z3::concat(context.bv_val(bit, 1), constant);
1454 return {
true, constant};
1457 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1459 return {
true, it->second};
1461 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1465 return {
true, p[0] & p[1]};
1467 return {
true, p[0] | p[1]};
1469 return {
true, ~p[0]};
1471 return {
true, p[0] ^ p[1]};
1473 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1475 return {
true, z3::concat(p[0], p[1])};
1477 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1480 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1481 return {
false, z3::expr(context)};
1485 std::vector<z3::expr> stack;
1486 for (
const auto& node : this->m_nodes)
1488 std::vector<z3::expr> operands;
1489 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1490 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1492 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1494 stack.emplace_back(reduction);
1498 return z3::expr(context);
1502 switch (stack.size())
1505 return stack.back();
1507 return z3::expr(context);
1518 for (
const auto& parameter : p)
1520 size += parameter.size();
1522 this->m_nodes.reserve(
size);
1524 for (
auto&& parameter : p)
1526 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1528 this->m_nodes.emplace_back(node);
1531 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1534 for (
const auto& node : this->m_nodes)
1536 s += node.to_string() +
" ";
1541 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1547 if (
auto coverage =
function.compute_node_coverage(); coverage.back() !=
function.
length())
1549 auto str =
function.to_string_in_reverse_polish_notation();
1550 return ERR(
"could not validate '" +
str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1553 return OK(std::move(
function));
1556 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1558 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1565 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (index < cov.size()) ? cov[index] : -1; };
1574 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; };
1576 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1578 auto arity = this->m_nodes[i].get_arity();
1587 auto x = get(coverage, i - 1);
1588 set(coverage, i, x);
1592 auto x = get(coverage, i - 1);
1593 auto y = get(coverage, i - 1 - x);
1594 set(coverage, i, x, y);
1598 auto x = get(coverage, i - 1);
1599 auto y = get(coverage, i - 1 - x);
1600 auto z = get(coverage, i - 1 - x - y);
1601 set(coverage, i, x, y, z);
1612 return Node(_type, _size, {}, {}, {});
1637 return !(*
this == other);
1647 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1656 for (
const auto& value : this->constant)
1664 return std::to_string(this->index);
1666 return this->variable;
1726 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
1737 static const std::map<u16, u16> type2arity = {
1748 return type2arity.at(
type);
1753 return this->
type == _type;
1763 return this->
is_constant() && (this->constant == value);
1773 auto bv_value = std::vector<BooleanFunction::Value>({});
1774 bv_value.reserve(this->
size);
1775 for (
auto i = 0u; i < this->constant.size(); i++)
1777 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
1779 return this->constant == bv_value;
1786 return ERR(
"Node is not a constant");
1789 return OK(this->constant);
1796 return ERR(
"Node is not a constant");
1799 if (this->
size > 64)
1801 return ERR(
"Node constant has size > 64");
1804 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
1806 return ERR(
"Node constant is undefined or high-impedance");
1810 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
1826 return this->
is_index() && (this->index == value);
1833 return ERR(
"Node is not an index");
1836 return OK(this->index);
1846 return this->
is_variable() && (this->variable == value);
1853 return ERR(
"Node is not a variable");
1856 return OK(this->variable);
1861 return !this->is_operand();
1875 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
1876 :
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.