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())
1243 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the size of vairbale " +
name +
" with size " + std::to_string(node.size)
1244 +
" does not match the size of the provided input (" + 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.