14 #include <sys/resource.h>
22 inline BooleanFunction
23 get_function_of_gate(
const Gate*
const gate,
const std::string& output_pin,
const u32 time_index, std::map<std::tuple<u32, std::string, u32>, BooleanFunction>& cache)
25 if (
auto it = cache.find({gate->get_id(), output_pin, time_index}); it != cache.end())
30 BooleanFunction bf = gate->get_boolean_function(output_pin);
32 std::vector<std::string> input_vars =
utils::to_vector(bf.get_variable_names());
33 while (!input_vars.empty())
35 const std::string var = input_vars.back();
36 input_vars.pop_back();
38 const PinDirection pin_dir = gate->get_type()->get_pins([var](GatePin* p) {
return p->get_name() == var; }).front()->get_direction();
42 const Net*
const input_net = gate->get_fan_in_net(var);
43 if (input_net ==
nullptr)
46 log_warning(
"sequential_symbolic_execution",
"no net is connected to input pin '{}' of gate with ID {}, cannot replace pin name with net ID.", var, gate->get_id());
50 bf = bf.substitute(var,
"net_" + std::to_string(input_net->get_id()) +
"_" + std::to_string(time_index));
54 BooleanFunction bf_interal = gate->get_boolean_function(var);
55 if (bf_interal.is_empty())
58 "trying to replace {} in function {} for gate {} and pin {} but cannot find boolean fucntion.",
66 const std::vector<std::string> internal_input_vars =
utils::to_vector(bf_interal.get_variable_names());
67 input_vars.insert(input_vars.end(), internal_input_vars.begin(), internal_input_vars.end());
69 auto substituted = bf.substitute(var, bf_interal);
70 if (substituted.is_error())
72 log_error(
"sequential_symbolic_execution",
"{}", substituted.get_error().get());
73 return BooleanFunction();
75 bf = substituted.get();
79 cache.insert({{gate->get_id(), output_pin, time_index}, bf});
83 inline BooleanFunction
84 get_function_of_seq_gate(
const Gate*
const gate,
const std::string& output_pin,
const u32 time_index, std::map<std::tuple<u32, std::string, u32>, BooleanFunction>& cache)
86 if (
auto it = cache.find({gate->get_id(), output_pin, time_index}); it != cache.end())
91 auto state_pins = gate->get_type()->get_pins([](GatePin* p) {
return p->get_type() ==
PinType::state; });
93 if (state_pins.size() != 1)
95 log_error(
"iphone_tools",
"Found {} state pisn for gate {} of type {}. Can only handle one!", state_pins.size(), gate->get_id(), gate->get_type()->get_name());
98 auto state_pin = *(state_pins.begin());
100 auto internal_state_bf = gate->get_type()->get_boolean_function(state_pin);
101 if (!internal_state_bf.is_variable())
103 log_error(
"sequential_symbolic_execution",
"Internal state of ff type {} is not a single variable. Cannot handle!", gate->get_type()->get_name());
105 auto internal_state_name = *(internal_state_bf.get_variable_names().begin());
107 if (internal_state_bf.is_empty())
109 log_error(
"sequential_symbolic_execution",
"No booleanfunction for pin {} at gatetype {}!", output_pin, gate->get_type()->get_name());
114 auto bf = (ff_cfg->get_clock_function() & ff_cfg->get_next_state_function()) | (~ff_cfg->get_clock_function() & internal_state_bf);
116 if (
auto async_reset = ff_cfg->get_async_reset_function(); !async_reset.is_empty())
118 bf = bf & (~async_reset);
120 if (
auto async_set = ff_cfg->get_async_set_function(); !async_set.is_empty())
125 bf = bf.substitute(internal_state_name, state_pin->get_name());
133 if (gate->get_type()->get_pins([output_pin](GatePin* p) {
return p->get_name() == output_pin; }).front()->get_type() ==
PinType::neg_state)
138 for (
const auto& pin_name : bf.get_variable_names())
140 const auto pin = gate->get_type()->get_pins([pin_name](GatePin* p) {
return p->get_name() == pin_name; }).front();
141 const auto net = (pin->get_direction() ==
PinDirection::input) ? gate->get_fan_in_net(pin) : gate->get_fan_out_net(pin);
143 const u32 new_time_index = time_index - 1;
147 const std::string net_name =
"net_" + std::to_string(
net->get_id()) +
"_" + std::to_string(new_time_index);
148 bf = bf.substitute(pin_name, net_name);
152 cache.insert({{gate->get_id(), output_pin, time_index}, bf});
156 Result<z3::expr> get_function_of_net_z3_word_level_internal(Net*
net,
157 const u32 time_index,
158 const std::vector<bool>& subgraph_gates_byte_map,
159 const std::vector<std::map<u32, bool>>& known_inputs,
160 const std::map<PinGroup<ModulePin>*, BooleanFunction>& word_level_calculations,
161 std::map<std::tuple<u32, std::string, u32>, BooleanFunction>& gate_cache,
162 std::map<std::pair<u32, u32>, z3::expr>& net_cache,
163 const bool substitute_endpoints,
170 return ERR(
"nullptr given for target net");
172 else if (
net->get_num_of_sources() > 1)
174 return ERR(
"target net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
"has more than one source");
177 if (known_inputs.at(time_index).find(
net->get_id()) != known_inputs.at(time_index).end())
179 const auto known_value = known_inputs.at(time_index).at(
net->get_id()) ? 1 : 0;
180 const auto bf = ctx.bv_val(known_value, 1);
181 net_cache.insert({{
net->get_id(), time_index}, bf});
185 if (
const auto it = net_cache.find({net->get_id(), time_index}); it != net_cache.end())
187 return OK(it->second);
190 if (
net->is_global_input_net())
192 if (substitute_endpoints)
194 const auto pin =
net->get_netlist()->get_top_module()->get_pin_by_net(
net);
195 const auto [pin_group,
index] = pin->get_group();
196 const std::string
name = pin_group->get_name() +
"_" + std::to_string(time_index);
198 const auto bf = ctx.bv_const(
name.c_str(), pin_group->size()).extract(
index,
index);
199 net_cache.insert({{
net->get_id(), time_index}, bf});
203 const auto bf = ctx.bv_const((
"net_" + std::to_string(
net->get_id()) +
"_" + std::to_string(time_index)).c_str(), 1);
204 net_cache.insert({{
net->get_id(), time_index}, bf});
208 if (
net->get_num_of_sources() == 0)
212 const auto bf = ctx.bv_const((
"net_" + std::to_string(
net->get_id()) +
"_" + std::to_string(time_index)).c_str(), 1);
213 net_cache.insert({{
net->get_id(), time_index}, bf});
217 const Gate* src_gate =
net->get_sources()[0]->get_gate();
218 const std::string src_pin =
net->get_sources()[0]->get_pin()->get_name();
221 const auto all_src_modules = src_gate->get_modules(
nullptr,
true);
224 if ((!subgraph_gates_byte_map.at(src_gate->get_id())) || (has_sequential_src && (time_index == 0)))
226 if (substitute_endpoints)
229 for (
auto it = all_src_modules.rbegin(); it != all_src_modules.rend(); it++)
231 const auto src_mod = *it;
232 if (src_mod->is_output_net(
net))
234 const auto pin = src_mod->get_pin_by_net(
net);
235 const auto [pin_group,
index] = pin->get_group();
237 if (pin_group->size() > 1)
239 const std::string
name = src_mod->get_name() +
"_" + pin_group->get_name() +
"_" + std::to_string(time_index);
240 const auto bf = ctx.bv_const(
name.c_str(), pin_group->size()).extract(
index,
index);
241 net_cache.insert({{
net->get_id(), time_index}, bf});
248 const auto bf = ctx.bv_const((
"net_" + std::to_string(
net->get_id()) +
"_" + std::to_string(time_index)).c_str(), 1);
249 net_cache.insert({{
net->get_id(), time_index}, bf});
254 for (
auto it = all_src_modules.rbegin(); it != all_src_modules.rend(); it++)
256 const auto src_mod = *it;
257 if (src_mod->is_output_net(
net))
259 const auto pin = src_mod->get_pin_by_net(
net);
260 const auto [pin_group,
index] = pin->get_group();
262 if (
const auto it = word_level_calculations.find(pin_group); it != word_level_calculations.end())
264 const auto& wlc_operation = it->second;
267 std::map<std::string, BooleanFunction> known_signals;
268 for (
const auto& var_name : wlc_operation.get_variable_names())
270 if (var_name ==
"UNKNOWN_OPERATION")
276 if (var_net_res.is_error())
279 "cannot get function of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id())
280 +
": failed to extract index from word level computation variable");
282 const auto var_net = var_net_res.get();
284 if (
const auto it = known_inputs[time_index].find(var_net->get_id()); it != known_inputs[time_index].end())
290 const auto wlc_simplified = wlc_operation.substitute(known_signals).get().simplify_local();
292 std::map<std::string, z3::expr> operand_signals;
293 for (
const auto& var_name : wlc_simplified.get_variable_names())
295 if (var_name ==
"UNKNOWN_OPERATION")
302 if (
const auto it = net_cache.find({var_net->get_id(), time_index}); it != net_cache.end())
304 operand_signals.emplace(var_name, it->second);
308 return ERR(
"cannot get function of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
": failed to find net id "
309 + std::to_string(var_net->get_id()) +
" for time index " + std::to_string(time_index) +
" in net cache");
317 for (
u32 pin_idx = 0; pin_idx < pin_group->size(); pin_idx++)
319 const auto pin_net = pin_group->get_pins().at(pin_idx)->get_net();
324 z3::expr pin_e = bf_word_level_z3.extract(pin_idx, pin_idx);
327 net_cache.insert({{pin_net->get_id(), time_index}, pin_e});
336 if (has_sequential_src)
338 bf = get_function_of_seq_gate(src_gate, src_pin, time_index, gate_cache);
342 bf = get_function_of_gate(src_gate, src_pin, time_index, gate_cache);
346 for (
const auto& var : bf.get_variable_names())
349 const u32 var_net_id = std::stoi(
split.at(1));
350 const u32 var_time_index = std::stoi(
split.at(2));
352 if (known_inputs[var_time_index].find(var_net_id) != known_inputs[var_time_index].end())
354 BooleanFunction::Value known_value = known_inputs[var_time_index].at(var_net_id) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO;
357 bf = substitution.get();
361 log_error(
"sequential_symbolic_execution",
"{}", substitution.get_error().get());
369 bf = simplification.get();
373 log_error(
"sequential_symbolic_execution",
"{}", simplification.get_error().get());
376 std::map<std::string, z3::expr> var_name_to_function;
378 for (
const auto& var : bf.get_variable_names())
381 const u32 var_net_id = std::stoi(
split.at(1));
382 const u32 var_time_index = std::stoi(
split.at(2));
392 if (
const auto it = net_cache.find({var_net_id, var_time_index}); it != net_cache.end())
394 var_name_to_function.emplace(var, it->second);
398 return ERR(
"cannot get function of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
": failed to find net id " + std::to_string(var_net_id)
399 +
" for time index " + std::to_string(var_time_index) +
" in net cache");
407 if (simplify_res.is_error())
409 return ERR_APPEND(simplify_res.get_error(),
"cannot get function of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
": failed to simplify expression");
411 bf_z3 = simplify_res.get();
413 net_cache.insert({{
net->get_id(), time_index}, bf_z3});
417 Result<std::vector<std::pair<Net*, u32>>> get_net_inputs(Net*
net,
418 const u32 time_index,
419 const std::vector<bool>& subgraph_gates_byte_map,
420 const std::vector<std::map<u32, bool>>& known_inputs,
421 const std::map<PinGroup<ModulePin>*, BooleanFunction>& word_level_calculations,
422 std::map<std::tuple<u32, std::string, u32>, BooleanFunction>& gate_cache,
423 std::map<std::pair<u32, u32>, z3::expr>& net_cache)
427 std::vector<std::pair<Net*, u32>> indexed_net_inputs;
431 return ERR(
"nullptr given for target net");
433 else if (
net->get_num_of_sources() > 1)
435 return ERR(
"target net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
"has more than one source");
438 if (known_inputs.at(time_index).find(
net->get_id()) != known_inputs.at(time_index).end())
443 if (
const auto it = net_cache.find({net->get_id(), time_index}); it != net_cache.end())
448 if (
net->is_global_input_net())
453 if (
net->get_num_of_sources() == 0)
460 const Gate* src_gate =
net->get_sources()[0]->get_gate();
461 const std::string src_pin =
net->get_sources()[0]->get_pin()->get_name();
464 const auto all_src_modules = src_gate->get_modules(
nullptr,
true);
467 if ((!subgraph_gates_byte_map.at(src_gate->get_id())) || (has_sequential_src && (time_index == 0)))
473 for (
auto it = all_src_modules.rbegin(); it != all_src_modules.rend(); it++)
475 const auto src_mod = *it;
476 if (src_mod->is_output_net(
net))
478 const auto pin = src_mod->get_pin_by_net(
net);
479 const auto [pin_group,
index] = pin->get_group();
481 if (
const auto it = word_level_calculations.find(pin_group); it != word_level_calculations.end())
483 const auto& wlc_operation = it->second;
486 std::map<std::string, BooleanFunction> known_signals;
487 for (
const auto& var_name : wlc_operation.get_variable_names())
489 if (var_name ==
"UNKNOWN_OPERATION")
495 if (var_net_res.is_error())
498 "cannot get missing net inputs of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id())
499 +
": failed to extract index from word level computation variable");
501 const auto var_net = var_net_res.get();
503 if (
const auto it = known_inputs[time_index].find(var_net->get_id()); it != known_inputs[time_index].end())
509 const auto wlc_simplified = wlc_operation.substitute(known_signals).get().simplify_local();
511 for (
const auto& var_name : wlc_simplified.get_variable_names())
513 if (var_name ==
"UNKNOWN_OPERATION")
520 if (
const auto it = net_cache.find({var_net->get_id(), time_index}); it == net_cache.end())
522 indexed_net_inputs.push_back(std::pair<Net*, u32>{var_net, time_index});
526 return OK(indexed_net_inputs);
532 if (has_sequential_src)
534 bf = get_function_of_seq_gate(src_gate, src_pin, time_index, gate_cache);
538 bf = get_function_of_gate(src_gate, src_pin, time_index, gate_cache);
542 for (
const auto& var : bf.get_variable_names())
545 const u32 var_net_id = std::stoi(
split.at(1));
546 const u32 var_time_index = std::stoi(
split.at(2));
548 if (known_inputs[var_time_index].find(var_net_id) != known_inputs[var_time_index].end())
550 BooleanFunction::Value known_value = known_inputs[var_time_index].at(var_net_id) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO;
553 bf = substitution.get();
557 log_error(
"sequential_symbolic_execution",
"{}", substitution.get_error().get());
565 bf = simplification.get();
569 log_error(
"sequential_symbolic_execution",
"{}", simplification.get_error().get());
572 for (
const auto& var : bf.get_variable_names())
575 const u32 var_net_id = std::stoi(
split.at(1));
576 const u32 var_time_index = std::stoi(
split.at(2));
578 Net* var_net =
net->get_netlist()->get_net_by_id(var_net_id);
580 if (
const auto it = net_cache.find({var_net_id, var_time_index}); it == net_cache.end())
582 indexed_net_inputs.push_back({var_net, var_time_index});
586 return OK(indexed_net_inputs);
589 Result<z3::expr> get_function_of_net_z3_word_level(Net*
net,
590 const u32 time_index,
591 const std::vector<bool>& subgraph_gates_byte_map,
592 const std::vector<std::map<u32, bool>>& known_inputs,
593 const std::map<PinGroup<ModulePin>*, BooleanFunction>& word_level_calculations,
594 std::map<std::tuple<u32, std::string, u32>, BooleanFunction>& gate_cache,
595 std::map<std::pair<u32, u32>, z3::expr>& net_cache,
596 const bool substitute_endpoints,
599 std::vector<std::pair<Net*, u32>> stack = {std::pair<Net*, u32>{
net, time_index}};
600 std::set<std::pair<Net*, u32>> visited = {std::pair<Net*, u32>{
net, time_index}};
602 while (!stack.empty())
604 const auto [n, t] = stack.back();
605 const auto missing_inputs_res = get_net_inputs(n, t, subgraph_gates_byte_map, known_inputs, word_level_calculations, gate_cache, net_cache);
606 if (missing_inputs_res.is_error())
608 return ERR_APPEND(missing_inputs_res.get_error(),
609 "cannot get function of net " +
net->get_name() +
" with ID " + std::to_string(
net->get_id()) +
": failed to get missing input nets for net " + n->get_name()
610 +
" with ID " + std::to_string(n->get_id()) +
" at time index " + std::to_string(t));
613 const auto missing_inputs = missing_inputs_res.get();
615 if (!missing_inputs.empty())
617 const u32 before = stack.size();
618 for (
const auto& nt : missing_inputs)
620 if (visited.find(nt) == visited.end())
629 if (stack.size() == before)
631 for (
const auto& nt : missing_inputs)
642 get_function_of_net_z3_word_level_internal(n, t, subgraph_gates_byte_map, known_inputs, word_level_calculations, gate_cache, net_cache, substitute_endpoints, ctx);
643 if (bf_res.is_error())
648 if (stack.size() == 1)
656 return ERR(
"unreachable reached");
659 Result<z3::expr> subsitute_nets_with_pins(
const z3::expr& e,
const Netlist* nl,
const bool simplify)
663 z3::expr_vector from(e.ctx());
664 z3::expr_vector
to(e.ctx());
666 for (
const auto& vn : var_names)
669 if (vn.find(
"net_") != 0)
675 const u32 var_net_id = std::stoi(
split.at(1));
676 const u32 var_time_index = std::stoi(
split.at(2));
678 Net*
net = nl->get_net_by_id(var_net_id);
680 if (
net->is_global_input_net())
682 const auto pin = nl->get_top_module()->get_pin_by_net(
net);
683 const auto [pin_group,
index] = pin->get_group();
685 const std::string
name = pin_group->get_name() +
"_" + std::to_string(var_time_index);
686 const auto to_bf = e.ctx().bv_const(
name.c_str(), pin_group->size()).extract(
index,
index);
687 const auto from_bf = e.ctx().bv_const(vn.c_str(), 1);
699 if (
net->get_num_of_sources() != 1)
704 const Gate* src_gate =
net->get_sources()[0]->get_gate();
705 const std::string src_pin =
net->get_sources()[0]->get_pin()->get_name();
707 const auto all_src_modules = src_gate->get_modules(
nullptr,
true);
710 for (
auto it = all_src_modules.rbegin(); it != all_src_modules.rend(); it++)
712 const auto src_mod = *it;
713 if (src_mod->is_output_net(
net))
715 const auto pin = src_mod->get_pin_by_net(
net);
716 const auto [pin_group,
index] = pin->get_group();
718 if (pin_group->size() > 1)
720 const std::string
name = src_mod->get_name() +
"_" + pin_group->get_name() +
"_" + std::to_string(var_time_index);
721 const auto to_bf = e.ctx().bv_const(
name.c_str(), pin_group->size()).extract(
index,
index);
722 const auto from_bf = e.ctx().bv_const(vn.c_str(), 1);
734 auto res = e_cpy.substitute(from,
to);
739 if (simplify_res.is_error())
741 return ERR_APPEND(simplify_res.get_error(),
"cannot substitute endpoints for z3::expr: failed to simplify expression");
743 res = simplify_res.get();
752 const u32 time_index,
753 const std::vector<bool>& subgraph_gates_byte_map,
754 const std::vector<std::map<u32, bool>>& known_inputs,
756 const bool substitute_endpoints,
759 std::map<std::tuple<u32, std::string, u32>,
BooleanFunction> gate_cache;
760 std::map<std::pair<u32, u32>, z3::expr> net_cache;
762 auto bf_res = sse::get_function_of_net_z3_word_level(
net, time_index, subgraph_gates_byte_map, known_inputs, word_level_calculations, gate_cache, net_cache, substitute_endpoints, ctx);
768 const std::vector<u32>& time_indices,
769 const std::vector<bool>& subgraph_gates_byte_map,
770 const std::vector<std::map<u32, bool>>& known_inputs,
772 const bool substitute_endpoints,
775 std::map<std::tuple<u32, std::string, u32>,
BooleanFunction> gate_cache;
776 std::map<std::pair<u32, u32>, z3::expr> net_cache;
778 std::vector<z3::expr> result;
780 for (
u32 word_idx = 0; word_idx < words.size(); word_idx++)
782 const auto& nets = words.at(word_idx);
784 sse::get_function_of_net_z3_word_level(nets.front(), time_indices.at(word_idx), subgraph_gates_byte_map, known_inputs, word_level_calculations, gate_cache, net_cache,
false, ctx);
786 if (bf_res.is_error())
788 return ERR_APPEND(bf_res.get_error(),
"cannot get word value for word at index " + std::to_string(word_idx) +
": failed to build single net function");
791 z3::expr bf_word = bf_res.get();
792 for (
u32 bit_idx = 1; bit_idx < nets.size(); bit_idx++)
794 const auto bf_bit_res = sse::get_function_of_net_z3_word_level(
795 nets.at(bit_idx), time_indices.at(word_idx), subgraph_gates_byte_map, known_inputs, word_level_calculations, gate_cache, net_cache,
false, ctx);
796 if (bf_bit_res.is_error())
798 return ERR_APPEND(bf_res.get_error(),
"cannot get word value for word at index " + std::to_string(word_idx) +
": failed to build single net function");
801 bf_word = z3::concat(bf_bit_res.get(), bf_word);
804 if (substitute_endpoints)
806 const Netlist* nl = words.front().front()->get_netlist();
807 const auto substitute_res = subsitute_nets_with_pins(bf_word, nl,
true);
808 if (substitute_res.is_error())
810 return ERR_APPEND(substitute_res.get_error(),
"cannot get word value for word at index " + std::to_string(word_idx) +
": failed to substitute nets with pins");
812 bf_word = substitute_res.get();
817 if (simplify_res.is_error())
819 return ERR_APPEND(simplify_res.get_error(),
"cannot get word value for word at index " + std::to_string(word_idx) +
": failed to simplify expression");
821 bf_word = simplify_res.get();
823 result.push_back(bf_word);
830 const std::vector<u32>& time_indices,
831 const std::vector<bool>& subgraph_gates_byte_map,
832 const std::vector<std::map<u32, bool>>& known_inputs,
834 const bool substitute_endpoints,
837 std::map<std::tuple<u32, std::string, u32>,
BooleanFunction> gate_cache;
838 std::map<std::pair<u32, u32>, z3::expr> net_cache;
840 std::vector<std::vector<Net*>> word_nets;
842 for (
const auto& [_m, pg] : words)
844 std::vector<Net*> nets;
845 for (
const auto& pin : pg->get_pins())
847 nets.push_back(pin->get_net());
849 word_nets.push_back(nets);
852 return get_word_values_at_z3(word_nets, time_indices, subgraph_gates_byte_map, known_inputs, word_level_calculations, substitute_endpoints, ctx);
Value
represents the type of the node
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
#define log_error(channel,...)
#define log_warning(channel,...)
#define ERR_APPEND(prev_error, message)
Result< BooleanFunction > local_simplification(const BooleanFunction &function)
Result< z3::expr > get_value_at_z3(Net *net, const u32 time_index, const std::vector< bool > &subgraph_gates_byte_map, const std::vector< std::map< u32, bool >> &known_inputs, const std::map< PinGroup< ModulePin > *, BooleanFunction > &word_level_calculations, const bool substitute_endpoints, z3::context &ctx)
Get the Z3 expression representing the value of a net at a specific time index.
Result< std::vector< z3::expr > > get_word_values_at_z3(const std::vector< std::vector< Net * >> &words, const std::vector< u32 > &time_indices, const std::vector< bool > &subgraph_gates_byte_map, const std::vector< std::map< u32, bool >> &known_inputs, const std::map< PinGroup< ModulePin > *, BooleanFunction > &word_level_calculations, const bool substitute_endpoints, z3::context &ctx)
Get the Z3 expressions representing the values of multiple nets as words at specific time indices.
std::vector< T > to_vector(const Container< T, Args... > &container)
std::vector< T > split(const T &s, const char delim, bool obey_brackets=false)
std::set< std::string > get_variable_names(const z3::expr &e)
Extracts all variable names from a z3 expression.
Result< z3::expr > simplify_local(const z3::expr &e, std::unordered_map< u32, z3::expr > &cache, const bool check_correctness=false)
Applies hand-crafted simplification rules iteratively until no further simplifications can be made.
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Result< BooleanFunction > to_bf(const z3::expr &e)