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 = {
1058 for (
const auto& [parser_type,
parser] : parsers)
1060 std::string sanitized_expression = expression;
1063 if (parser_type == ParserType::LibertyNoSpace)
1065 sanitized_expression.erase(
1066 std::remove(sanitized_expression.begin(), sanitized_expression.end(),
' '),
1067 sanitized_expression.end()
1069 used_parser_type = ParserType::Liberty;
1072 auto tokens =
parser(sanitized_expression);
1074 if (tokens.is_error())
1081 if (tokens.is_error())
1087 if (
function.is_error())
1093 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1102 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1109 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1114 auto function = this->
clone();
1115 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1129 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1130 if (node.has_variable_name(var_name))
1132 return repl.
clone();
1137 std::vector<BooleanFunction> stack;
1138 for (
const auto& node : this->m_nodes)
1140 std::vector<BooleanFunction> operands;
1141 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1142 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1144 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1147 switch (stack.size())
1150 return OK(stack.back());
1152 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1158 auto function = this->
clone();
1159 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1161 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1163 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1165 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1180 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1181 if (node.is_variable())
1183 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1185 return repl_it->second.
clone();
1191 std::vector<BooleanFunction> stack;
1192 for (
const auto& node : this->m_nodes)
1194 std::vector<BooleanFunction> operands;
1195 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1196 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1198 stack.emplace_back(substitute_variable(node, std::move(operands)));
1201 switch (stack.size())
1204 return OK(stack.back());
1206 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1213 if (this->m_nodes.empty())
1215 return OK(BooleanFunction::Value::X);
1219 if (this->
size() != 1)
1221 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");
1225 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1226 for (
const auto& [
name, value] : inputs)
1228 generic_inputs.emplace(
name, std::vector<Value>({value}));
1231 auto value = this->
evaluate(generic_inputs);
1235 return OK(value.get()[0]);
1238 return ERR(value.get_error());
1244 if (this->m_nodes.empty())
1246 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1250 for (
const auto& [
name, value] : inputs)
1252 for (
const auto& node : this->m_nodes)
1254 if (node.has_variable_name(
name) && node.size != value.size())
1256 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the size of vairbale " +
name +
" with size " + std::to_string(node.size)
1257 +
" does not match the size of the provided input (" + std::to_string(value.size()) +
")");
1264 for (
const auto& [
name, value] : inputs)
1271 auto result = symbolic_execution.evaluate(*
this);
1274 if (
auto value = result.get(); value.is_constant())
1276 return OK(value.get_top_level_node().constant);
1278 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1280 return ERR(result.get_error());
1289 for (
const auto& node : this->m_nodes)
1291 if (node.is_variable() && node.size != 1)
1293 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");
1298 auto variables = ordered_variables;
1299 if (variables.empty())
1301 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1305 if (remove_unknown_variables)
1308 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(); }),
1314 if (this->m_nodes.empty())
1316 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1320 if (variables.size() > 10)
1322 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than 10 variables");
1325 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1328 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1330 std::unordered_map<std::string, std::vector<Value>>
input;
1332 for (
const auto& variable : variables)
1334 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1337 auto result = this->
evaluate(input);
1338 if (result.is_error())
1340 return ERR(result.get_error());
1342 auto output = result.get();
1343 for (
auto index = 0u; index < truth_table.size(); index++)
1345 truth_table[index][value] =
output[index];
1349 return OK(truth_table);
1354 std::vector<std::string> inputs;
1356 if (ordered_inputs.empty())
1358 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1362 inputs = ordered_inputs;
1365 if (remove_unknown_inputs)
1367 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1373 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1375 const auto truth_table = res.get();
1377 std::stringstream
str(
"");
1379 u32 num_inputs = inputs.size();
1380 u32 num_outputs = truth_table.size();
1383 std::vector<u32> in_widths;
1384 for (
const auto& var : inputs)
1386 in_widths.push_back(var.size());
1387 str <<
" " << var <<
" |";
1390 std::vector<u32> out_widths;
1391 if (function_name.empty())
1393 function_name =
"O";
1395 if (num_outputs == 1)
1397 str <<
"| " << function_name <<
" ";
1398 out_widths.push_back(function_name.size());
1402 for (
u32 i = 0; i < num_outputs; i++)
1404 std::string var = function_name +
"(" + std::to_string(i) +
")";
1405 str <<
"| " << var <<
" ";
1406 out_widths.push_back(var.size());
1412 for (
u32 i = 0; i < num_inputs; i++)
1414 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1416 for (
u32 i = 0; i < num_outputs; i++)
1418 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1423 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1425 for (
u32 j = 0; j < num_inputs; j++)
1427 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1430 for (
u32 k = 0; k < num_outputs; k++)
1432 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1436 return OK(
str.str());
1447 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1448 if (node.get_arity() != p.size())
1450 return {
false, z3::expr(context)};
1456 return {
true, context.bv_val(node.index, node.size)};
1460 auto constant = context.bv_val(node.constant.front(), 1);
1461 for (
u32 i = 1; i < node.constant.size(); i++)
1463 const auto bit = node.constant.at(i);
1464 constant = z3::concat(context.bv_val(bit, 1), constant);
1466 return {
true, constant};
1469 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1471 return {
true, it->second};
1473 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1477 return {
true, p[0] & p[1]};
1479 return {
true, p[0] | p[1]};
1481 return {
true, ~p[0]};
1483 return {
true, p[0] ^ p[1]};
1485 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1487 return {
true, z3::concat(p[0], p[1])};
1489 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1492 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1493 return {
false, z3::expr(context)};
1497 std::vector<z3::expr> stack;
1498 for (
const auto& node : this->m_nodes)
1500 std::vector<z3::expr> operands;
1501 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1502 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1504 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1506 stack.emplace_back(reduction);
1510 return z3::expr(context);
1514 switch (stack.size())
1517 return stack.back();
1519 return z3::expr(context);
1530 for (
const auto& parameter : p)
1532 size += parameter.size();
1534 this->m_nodes.reserve(
size);
1536 for (
auto&& parameter : p)
1538 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1540 this->m_nodes.emplace_back(node);
1543 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1546 for (
const auto& node : this->m_nodes)
1548 s += node.to_string() +
" ";
1553 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1559 if (
auto coverage =
function.compute_node_coverage(); coverage.back() !=
function.
length())
1561 auto str =
function.to_string_in_reverse_polish_notation();
1562 return ERR(
"could not validate '" +
str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1565 return OK(std::move(
function));
1568 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1570 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1577 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (index < cov.size()) ? cov[index] : -1; };
1586 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; };
1588 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1590 auto arity = this->m_nodes[i].get_arity();
1599 auto x = get(coverage, i - 1);
1600 set(coverage, i, x);
1604 auto x = get(coverage, i - 1);
1605 auto y = get(coverage, i - 1 - x);
1606 set(coverage, i, x, y);
1610 auto x = get(coverage, i - 1);
1611 auto y = get(coverage, i - 1 - x);
1612 auto z = get(coverage, i - 1 - x - y);
1613 set(coverage, i, x, y, z);
1624 return Node(_type, _size, {}, {}, {});
1649 return !(*
this == other);
1659 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1668 for (
const auto& value : this->constant)
1676 return std::to_string(this->index);
1678 return this->variable;
1738 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
1749 static const std::map<u16, u16> type2arity = {
1760 return type2arity.at(
type);
1765 return this->
type == _type;
1775 return this->
is_constant() && (this->constant == value);
1785 auto bv_value = std::vector<BooleanFunction::Value>({});
1786 bv_value.reserve(this->
size);
1787 for (
auto i = 0u; i < this->constant.size(); i++)
1789 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
1791 return this->constant == bv_value;
1798 return ERR(
"Node is not a constant");
1801 return OK(this->constant);
1808 return ERR(
"Node is not a constant");
1811 if (this->
size > 64)
1813 return ERR(
"Node constant has size > 64");
1816 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
1818 return ERR(
"Node constant is undefined or high-impedance");
1822 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
1838 return this->
is_index() && (this->index == value);
1845 return ERR(
"Node is not an index");
1848 return OK(this->index);
1858 return this->
is_variable() && (this->variable == value);
1865 return ERR(
"Node is not a variable");
1868 return OK(this->variable);
1873 return !this->is_operand();
1887 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
1888 :
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)
void remove(std::filesystem::path file_path)
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.