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++)
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++)
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())
726 return std::lexicographical_compare(this->m_nodes.begin(), this->m_nodes.end(), other.m_nodes.begin(), other.m_nodes.end());
731 return this->m_nodes.empty();
737 function.m_nodes.reserve(this->m_nodes.size());
739 for (
const auto& node : this->m_nodes)
741 function.m_nodes.emplace_back(node);
771 return ERR(
"Boolean function is empty");
796 return ERR(
"Boolean function is empty");
806 return ERR(
"Boolean function is empty");
826 return ERR(
"Boolean function is empty");
834 return this->m_nodes.back();
839 return this->m_nodes.size();
844 return this->m_nodes;
856 auto coverage = this->compute_node_coverage();
863 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.end() - 1}))};
868 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() +
index})),
872 auto index0 = this->
length() - coverage[this->
length() - 3] - coverage[this->
length() - 2] - 1;
873 auto index1 = this->
length() - coverage[this->
length() - 2] - 1;
875 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index0})),
876 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index0, this->m_nodes.begin() + index1})),
877 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index1, this->m_nodes.end() - 1}))};
881 assert(
false &&
"not implemented reached.");
889 auto variable_names = std::set<std::string>();
890 for (
const auto& node : this->m_nodes)
892 if (node.is_variable())
894 variable_names.insert(node.variable);
897 return variable_names;
904 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()));
915 return OK(
"(" + operands[0] +
" & " + operands[1] +
")");
917 return OK(
"(! " + operands[0] +
")");
919 return OK(
"(" + operands[0] +
" | " + operands[1] +
")");
921 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] +
" * " + operands[1] +
")");
930 return OK(
"(" + operands[0] +
" /s " + operands[1] +
")");
932 return OK(
"(" + operands[0] +
" / " + operands[1] +
")");
934 return OK(
"(" + operands[0] +
" \%s " + operands[1] +
")");
936 return OK(
"(" + operands[0] +
" \% " + operands[1] +
")");
939 return OK(
"(" + operands[0] +
" ++ " + operands[1] +
")");
941 return OK(
"Slice(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
943 return OK(
"Zext(" + operands[0] +
", " + operands[1] +
")");
945 return OK(
"Sext(" + operands[0] +
", " + operands[1] +
")");
948 return OK(
"(" + operands[0] +
" << " + operands[1] +
")");
950 return OK(
"(" + operands[0] +
" >> " + operands[1] +
")");
952 return OK(
"(" + operands[0] +
" >>a " + operands[1] +
")");
954 return OK(
"(" + operands[0] +
" <<r " + operands[1] +
")");
956 return OK(
"(" + operands[0] +
" >>r " + operands[1] +
")");
959 return OK(
"(" + operands[0] +
" == " + operands[1] +
")");
961 return OK(
"(" + operands[0] +
" <s " + operands[1] +
")");
963 return OK(
"(" + operands[0] +
" <=s " + operands[1] +
")");
965 return OK(
"(" + operands[0] +
" < " + operands[1] +
")");
967 return OK(
"(" + operands[0] +
" <= " + operands[1] +
")");
969 return OK(
"Ite(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
972 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.
type) +
"'");
976 Result<std::string> BooleanFunction::algebraic_printer(
const BooleanFunction::Node& node, std::vector<std::string>&& operands)
978 if (node.get_arity() != operands.size())
980 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()));
987 return OK(node.to_string());
990 return OK(
"CONST" + std::string(node.has_constant_value(0) ?
"0" :
"1"));
993 return OK(
"(" + operands[0] +
"*" + operands[1] +
")");
995 return OK(
"(! " + operands[0] +
")");
997 return OK(
"(" + operands[0] +
"+" + operands[1] +
")");
1000 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.type) +
"'");
1007 if (this->m_nodes.empty())
1013 std::vector<std::string> stack;
1014 for (
const auto& node : this->m_nodes)
1016 std::vector<std::string> operands;
1024 std::move(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end(), std::back_inserter(operands));
1025 stack.erase(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end());
1027 if (
auto res = printer(node, std::move(operands)); res.is_ok())
1029 stack.emplace_back(res.get());
1033 log_error(
"netlist",
"Cannot translate BooleanFunction::Node '{}' to a string: {}.", node.
to_string(), res.get_error().get());
1038 switch (stack.size())
1041 return stack.back();
1054 static const std::vector<std::tuple<ParserType, std::function<Result<std::vector<Token>>(
const std::string&)>>> parsers = {
1060 for (
const auto& [parser_type, parser] : parsers)
1062 std::string sanitized_expression = expression;
1065 if (parser_type == ParserType::LibertyNoSpace)
1067 sanitized_expression.erase(
1068 std::remove(sanitized_expression.begin(), sanitized_expression.end(),
' '),
1069 sanitized_expression.end()
1071 used_parser_type = ParserType::Liberty;
1074 auto tokens = parser(sanitized_expression);
1076 if (tokens.is_error())
1083 if (tokens.is_error())
1089 if (
function.is_error())
1095 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1104 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1111 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1116 auto function = this->
clone();
1117 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1131 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1132 if (node.has_variable_name(var_name))
1134 return repl.
clone();
1139 std::vector<BooleanFunction> stack;
1140 for (
const auto& node : this->m_nodes)
1142 std::vector<BooleanFunction> operands;
1143 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1144 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1146 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1149 switch (stack.size())
1152 return OK(stack.back());
1154 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1160 auto function = this->
clone();
1161 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1163 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1165 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1167 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1182 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1183 if (node.is_variable())
1185 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1187 return repl_it->second.
clone();
1193 std::vector<BooleanFunction> stack;
1194 for (
const auto& node : this->m_nodes)
1196 std::vector<BooleanFunction> operands;
1197 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1198 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1200 stack.emplace_back(substitute_variable(node, std::move(operands)));
1203 switch (stack.size())
1206 return OK(stack.back());
1208 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1215 if (this->m_nodes.empty())
1217 return OK(BooleanFunction::Value::X);
1221 if (this->
size() != 1)
1223 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");
1227 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1228 for (
const auto& [
name, value] : inputs)
1230 generic_inputs.emplace(
name, std::vector<Value>({value}));
1233 auto value = this->
evaluate(generic_inputs);
1237 return OK(value.get()[0]);
1240 return ERR(value.get_error());
1246 if (this->m_nodes.empty())
1248 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1254 for (
const auto& node : this->m_nodes)
1256 if (!node.is_variable())
1261 if (
const auto it = inputs.find(node.variable); it != inputs.end() && node.size != it->second.size())
1263 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the size of vairbale " + node.variable +
" with size " + std::to_string(node.size)
1264 +
" does not match the size of the provided input (" + std::to_string(it->second.size()) +
")");
1270 for (
const auto& [
name, value] : inputs)
1277 auto result = symbolic_execution.evaluate(*
this);
1280 if (
auto value = result.get(); value.is_constant())
1282 return OK(value.get_top_level_node().constant);
1284 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1286 return ERR(result.get_error());
1295 for (
const auto& node : this->m_nodes)
1297 if (node.is_variable() && node.size != 1)
1299 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");
1304 auto variables = ordered_variables;
1305 if (variables.empty())
1307 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1311 if (remove_unknown_variables)
1314 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(); }),
1320 if (this->m_nodes.empty())
1322 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1326 if (variables.size() > 10)
1328 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than 10 variables");
1331 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1334 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1336 std::unordered_map<std::string, std::vector<Value>>
input;
1338 for (
const auto& variable : variables)
1340 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1343 auto result = this->
evaluate(input);
1344 if (result.is_error())
1346 return ERR(result.get_error());
1348 auto output = result.get();
1355 return OK(truth_table);
1360 std::vector<std::string> inputs;
1362 if (ordered_inputs.empty())
1364 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1368 inputs = ordered_inputs;
1371 if (remove_unknown_inputs)
1373 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1379 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1381 const auto truth_table = res.get();
1383 std::stringstream str(
"");
1385 u32 num_inputs = inputs.size();
1386 u32 num_outputs = truth_table.size();
1389 std::vector<u32> in_widths;
1390 for (
const auto& var : inputs)
1392 in_widths.push_back(var.size());
1393 str <<
" " << var <<
" |";
1396 std::vector<u32> out_widths;
1397 if (function_name.empty())
1399 function_name =
"O";
1401 if (num_outputs == 1)
1403 str <<
"| " << function_name <<
" ";
1404 out_widths.push_back(function_name.size());
1408 for (
u32 i = 0; i < num_outputs; i++)
1410 std::string var = function_name +
"(" + std::to_string(i) +
")";
1411 str <<
"| " << var <<
" ";
1412 out_widths.push_back(var.size());
1418 for (
u32 i = 0; i < num_inputs; i++)
1420 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1422 for (
u32 i = 0; i < num_outputs; i++)
1424 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1429 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1431 for (
u32 j = 0; j < num_inputs; j++)
1433 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1436 for (
u32 k = 0; k < num_outputs; k++)
1438 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1442 return OK(str.str());
1453 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1454 if (node.get_arity() != p.size())
1456 return {
false, z3::expr(context)};
1462 return {
true, context.bv_val(node.index, node.size)};
1466 auto constant = context.bv_val(node.constant.front(), 1);
1467 for (
u32 i = 1; i < node.constant.size(); i++)
1469 const auto bit = node.constant.at(i);
1470 constant = z3::concat(context.bv_val(bit, 1), constant);
1472 return {
true, constant};
1475 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1477 return {
true, it->second};
1479 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1483 return {
true, p[0] & p[1]};
1485 return {
true, p[0] | p[1]};
1487 return {
true, ~p[0]};
1489 return {
true, p[0] ^ p[1]};
1491 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1493 return {
true, z3::concat(p[0], p[1])};
1495 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1498 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1499 return {
false, z3::expr(context)};
1503 std::vector<z3::expr> stack;
1504 for (
const auto& node : this->m_nodes)
1506 std::vector<z3::expr> operands;
1507 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1508 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1510 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1512 stack.emplace_back(reduction);
1516 return z3::expr(context);
1520 switch (stack.size())
1523 return stack.back();
1525 return z3::expr(context);
1536 for (
const auto& parameter : p)
1538 size += parameter.size();
1540 this->m_nodes.reserve(
size);
1542 for (
auto&& parameter : p)
1544 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1546 this->m_nodes.emplace_back(node);
1549 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1552 for (
const auto& node : this->m_nodes)
1554 s += node.to_string() +
" ";
1559 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1565 if (
auto coverage =
function.compute_node_coverage(); coverage.back() !=
function.
length())
1567 auto str =
function.to_string_in_reverse_polish_notation();
1568 return ERR(
"could not validate '" + str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1571 return OK(std::move(
function));
1574 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1576 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1583 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (
index < cov.size()) ? cov[
index] : -1; };
1594 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1596 auto arity = this->m_nodes[i].get_arity();
1605 auto x = get(coverage, i - 1);
1606 set(coverage, i,
x);
1610 auto x = get(coverage, i - 1);
1611 auto y = get(coverage, i - 1 -
x);
1612 set(coverage, i,
x,
y);
1616 auto x = get(coverage, i - 1);
1617 auto y = get(coverage, i - 1 -
x);
1618 auto z = get(coverage, i - 1 -
x -
y);
1619 set(coverage, i,
x,
y, z);
1630 return Node(_type, _size, {}, {}, {});
1655 return !(*
this == other);
1665 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1674 for (
const auto& value : this->constant)
1682 return std::to_string(this->index);
1684 return this->variable;
1744 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
1755 static const std::map<u16, u16> type2arity = {
1766 return type2arity.at(
type);
1771 return this->
type == _type;
1781 return this->
is_constant() && (this->constant == value);
1791 auto bv_value = std::vector<BooleanFunction::Value>({});
1792 bv_value.reserve(this->
size);
1793 for (
auto i = 0u; i < this->constant.size(); i++)
1795 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
1797 return this->constant == bv_value;
1804 return ERR(
"Node is not a constant");
1807 return OK(this->constant);
1814 return ERR(
"Node is not a constant");
1817 if (this->
size > 64)
1819 return ERR(
"Node constant has size > 64");
1822 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
1824 return ERR(
"Node constant is undefined or high-impedance");
1828 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
1844 return this->
is_index() && (this->index == value);
1851 return ERR(
"Node is not an index");
1854 return OK(this->index);
1864 return this->
is_variable() && (this->variable == value);
1871 return ERR(
"Node is not a variable");
1874 return OK(this->variable);
1879 return !this->is_operand();
1893 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
1894 :
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, T e)
std::string enum_to_string(T e)
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.