9 #include "z3_utils/subgraph_function_generation.h"
10 #include "z3_utils/z3_utils.h"
17 namespace boolean_influence
21 const std::string probabilistic_function = R
"(
26 static unsigned long x=123456789, y=362436069, z=521288629;
29 unsigned long xorshf96(void) {
46 const int input_size = <INPUT_SIZE>;
48 void build_values(bool* values) {
49 for (int i = 0; i < input_size; i++) {
50 bool random_value = xorshf96() % 2;
51 values[i] = random_value;
57 int main(int argc, char *argv[]) {
58 unsigned long long b = strtoull(argv[1], 0, 10);
59 unsigned long long num = strtoull(argv[2], 0, 10);
60 unsigned long long count = 0;
62 bool values[input_size];
63 for (unsigned long long i = 0; i < num; i++) {
67 bool r1 = func(values);
70 bool r2 = func(values);
77 printf("%lld\n", count);
82 const std::string deterministic_function = R
"(
89 const int input_size = <INPUT_SIZE>;
91 void build_values(bool* values, unsigned long long val) {
92 for (int idx = 0; idx < input_size; idx++) {
93 values[idx] = (val >> idx) & 0x1;
99 int main(int argc, char *argv[]) {
100 unsigned long long b = strtoull(argv[1], 0, 10);
101 unsigned long long count = 0;
103 bool values[input_size];
104 for (unsigned long long i = 0; i < (1 << input_size); i++) {
105 build_values(values, i);
108 bool r1 = func(values);
111 bool r2 = func(values);
118 printf("%lld\n", count);
124 unsigned long xorshf96(
u64& x,
u64& y,
u64& z)
140 Result<std::unordered_map<std::string, double>> get_boolean_influence_internal(
const z3::expr& expr,
const u32 num_evaluations,
const bool deterministic)
142 const auto to_replacement_var = [](
const u32 var_idx) -> std::string {
return "var_" + std::to_string(var_idx); };
144 const auto extract_index = [](
const std::string& var) -> Result<u32> {
147 return ERR(
"variable " + var +
" does not start with prefix 'var_', so we cannot extract an index.");
152 return OK(
u32(std::stoul(var.substr(4))));
154 catch (
const std::invalid_argument& e)
156 return ERR(
"could not get index from string '" + var +
"': " + e.what());
158 catch (
const std::out_of_range& e)
160 return ERR(
"could not get index from string '" + var +
"': " + e.what());
164 const auto to_original_var = [extract_index](
const std::string& replacement_var,
const std::vector<std::string>& original_vars) -> Result<std::string> {
165 const auto var_idx_res = extract_index(replacement_var);
166 if (var_idx_res.is_error())
168 return ERR_APPEND(var_idx_res.get_error(),
"unable to reconstruct original variable from replacement variable" + replacement_var +
": failed to extract index.");
170 const auto var_idx = var_idx_res.get();
172 if (var_idx > original_vars.size())
174 return ERR(
"unable to reconstruct original variable from replacement variable" + replacement_var +
": extracted index " + std::to_string(var_idx)
175 +
" is bigger than the size of the original vars (" + std::to_string(original_vars.size()) +
").");
178 return OK(original_vars.at(var_idx));
181 std::unordered_map<std::string, double> influences;
185 std::vector<std::string> input_vars =
utils::to_vector(z3_utils::get_variable_names(expr));
187 if (input_vars.empty())
189 return OK(influences);
192 if (deterministic && input_vars.size() > 16)
194 return ERR(
"unable to generate Boolean influence: Cannot evaluate Boolean function deterministically for more than 16 variables but got " + std::to_string(input_vars.size()));
197 std::vector<std::string> replacement_vars;
199 z3::expr_vector from_vec(expr.ctx());
200 z3::expr_vector to_vec(expr.ctx());
202 for (
u32 var_idx = 0; var_idx < input_vars.size(); var_idx++)
204 replacement_vars.push_back(to_replacement_var(var_idx));
206 z3::expr
from = expr.ctx().bv_const(input_vars.at(var_idx).c_str(), 1);
207 z3::expr
to = expr.ctx().bv_const(to_replacement_var(var_idx).c_str(), 1);
209 from_vec.push_back(
from);
210 to_vec.push_back(
to);
213 auto replaced_e = expr;
214 replaced_e = replaced_e.substitute(from_vec, to_vec);
218 if (directory_res.is_error())
220 return ERR_APPEND(directory_res.get_error(),
"unable to generate Boolean influence: could not create temporary directory");
222 const std::filesystem::path directory = directory_res.get();
223 std::filesystem::create_directory(directory);
224 const std::filesystem::path file_path = directory /
"boolean_func.cpp";
226 std::string cpp_program = deterministic ? deterministic_function : probabilistic_function;
227 cpp_program =
utils::replace(cpp_program, std::string(
"<C_FUNCTION>"), z3_utils::to_cpp(replaced_e));
228 cpp_program =
utils::replace(cpp_program, std::string(
"<INPUT_SIZE>"), std::to_string(replacement_vars.size()));
231 std::ofstream ofs(file_path);
234 return ERR(
"unable to generate Boolean influence: could not open file " + file_path.string() +
".");
241 const std::string program_name = file_path.string().substr(0, file_path.string().size() - 4);
242 const std::string compile_command =
"g++ -o " + program_name +
" " + file_path.string() +
" -O3";
243 int res = system(compile_command.c_str());
247 for (
const auto& var : replacement_vars)
249 const auto idx_res = extract_index(var);
250 if (idx_res.is_error())
252 return ERR_APPEND(idx_res.get_error(),
"unable to generate Boolean influence: failed to extract index from variable " + var +
".");
254 const auto idx = idx_res.get();
256 const std::string num_evaluations_str = deterministic ?
"" : std::to_string(num_evaluations);
258 const std::string run_command = program_name +
" " + std::to_string(idx) +
" " + num_evaluations_str +
" 2>&1";
260 std::array<char, 128> buffer;
263 FILE* pipe = popen(run_command.c_str(),
"r");
266 return ERR(
"unable to generate Boolean influence: error during execution of compiled boolean program");
268 while (fgets(buffer.data(), 128, pipe) != NULL)
270 result += buffer.data();
275 const u32 count = std::stoi(result);
276 const u32 real_evaluations = deterministic ? (1 << input_vars.size()) : num_evaluations;
277 double cv = (double)(count) / (double)(real_evaluations);
279 const auto org_var_res = to_original_var(var, input_vars);
280 if (org_var_res.is_error())
282 return ERR_APPEND(org_var_res.get_error(),
"unable to generate Boolean influence: failed to reconstruct original variable from replacement variable " + var +
".");
284 const auto org_var = org_var_res.get();
286 influences.insert({org_var, cv});
294 return OK(influences);
297 Result<std::map<Net*, double>> get_boolean_influences_of_subcircuit_internal(
const std::vector<Gate*>& gates,
const Net* start_net,
const u32 num_evaluations,
const bool deterministic)
299 for (
const auto* gate : gates)
303 return ERR(
"unable to get Boolean influence for net " + start_net->get_name() +
" with ID " + std::to_string(start_net->get_id()) +
": sub circuit gates include gate "
304 + gate->get_name() +
" with ID " + std::to_string(gate->get_id()) +
" that is either not a combinational gate or is a VCC / GND gate.");
309 auto ctx = z3::context();
310 auto func = z3::expr(ctx);
314 const auto func_res = z3_utils::get_subgraph_z3_function(gates, start_net, ctx);
315 if (func_res.is_error())
318 "unable to get Boolean influence for net " + start_net->get_name() +
" with ID " + std::to_string(start_net->get_id())
319 +
": failed to build subgraph function");
321 func = func_res.get();
326 func = ctx.bv_const(BooleanFunctionNetDecorator(*start_net).get_boolean_variable_name().c_str(), 1);
330 const auto inf_res = get_boolean_influence_internal(func, num_evaluations, deterministic);
331 if (inf_res.is_error())
334 "unable to get Boolean influence for net " + start_net->get_name() +
" with ID " + std::to_string(start_net->get_id())
335 +
": failed to get boolean influence for net " + start_net->get_name() +
" with ID " + std::to_string(start_net->get_id()) +
".");
337 const std::unordered_map<std::string, double> var_names_to_inf = inf_res.get();
340 std::map<Net*, double> nets_to_inf;
342 Netlist* nl = start_net->get_netlist();
343 for (
const auto& [var_name,
inf] : var_names_to_inf)
346 if (net_res.is_error())
349 "unable to get Boolean influence for net " + start_net->get_name() +
" with ID " + std::to_string(start_net->get_id())
350 +
": failed to reconstruct net from variable " + var_name +
".");
352 const auto net = net_res.get();
354 nets_to_inf.insert({
net,
inf});
357 return OK(nets_to_inf);
360 Result<std::map<Net*, double>> get_boolean_influences_of_gate_internal(
const Gate* gate,
const u32 num_evaluations,
const bool deterministic)
364 return ERR(
"unable to get Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id()) +
": can only handle flip-flops but found gate type "
365 + gate->get_type()->get_name() +
".");
370 if (d_pins.size() != 1)
372 return ERR(
"unable to get Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id())
373 +
": can only handle flip-flops with exactly one data port, but found " + std::to_string(d_pins.size()) +
".");
375 const GatePin* data_pin = d_pins.front();
376 const Net* data_net = gate->get_fan_in_net(data_pin);
378 if (data_net ==
nullptr)
380 return ERR(
"unable to get Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id()) +
": failed to find net at data pin "
381 + data_pin->get_name());
385 const auto function_gates_res = NetlistTraversalDecorator(*(gate->get_netlist())).get_next_combinational_gates(data_net,
false);
386 if (function_gates_res.is_error())
388 return ERR_APPEND(function_gates_res.get_error(),
389 "unable to get Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id()) +
": failed to get combinational fan-in gates.");
394 const auto inf_res = get_boolean_influences_of_subcircuit_internal(function_gates, data_net, num_evaluations, deterministic);
395 if (inf_res.is_error())
398 "unable to get Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id()) +
": failed to get Boolean influence for data net "
399 + data_net->get_name() +
" with ID " + std::to_string(data_net->get_id()) +
".");
409 auto ctx = z3::context();
410 const auto z3_bf = z3_utils::from_bf(bf, ctx);
417 return get_boolean_influence_internal(expr, num_evaluations,
false);
422 auto ctx = z3::context();
423 const auto z3_bf = z3_utils::from_bf(bf, ctx);
430 return get_boolean_influence_internal(expr, 0,
true);
435 return get_boolean_influences_of_subcircuit_internal(gates, start_net, num_evaluations,
false);
440 return get_boolean_influences_of_gate_internal(gate, num_evaluations,
false);
445 return get_boolean_influences_of_subcircuit_internal(gates, start_net, 0,
true);
450 return get_boolean_influences_of_gate_internal(gate, 0,
true);
455 std::unordered_map<std::string, double> influences;
458 u64 x = 123456789, y = 362436069, z = 521288629;
460 for (
const auto& var : variables)
463 for (
unsigned long long i = 0; i < num_evaluations; i++)
465 std::unordered_map<std::string, BooleanFunction::Value> values;
467 for (
const auto& var_to_set : variables)
469 if (var == var_to_set)
474 BooleanFunction::Value random_value = (xorshf96(x, y, z) % 2) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO;
475 values.insert({var_to_set, random_value});
479 values[var] = BooleanFunction::Value::ONE;
480 const auto res_1 = bf.
evaluate(values);
481 if (res_1.is_error())
483 return ERR_APPEND(res_1.get_error(),
"unable to evaluate boolean function ");
487 values[var] = BooleanFunction::Value::ZERO;
488 const auto res_2 = bf.
evaluate(values);
489 if (res_2.is_error())
491 return ERR_APPEND(res_2.get_error(),
"unable to evaluate boolean function ");
494 const auto r1 = res_1.get();
495 const auto r2 = res_2.get();
502 double cv = (double)(count) / (double)(num_evaluations);
503 influences.insert({var, cv});
506 return OK(influences);
511 std::unordered_map<std::string, double> influences;
514 auto ctx = z3::context();
515 auto z3_bf = z3_utils::from_bf(bf, ctx);
517 u64 x = 123456789, y = 362436069, z = 521288629;
519 for (
const auto& var : variables)
521 const auto var_expr = ctx.bv_const(var.c_str(), 1);
524 for (
unsigned long long i = 0; i < num_evaluations; i++)
526 z3::expr_vector from_vec(ctx);
527 z3::expr_vector to_vec(ctx);
530 for (
const auto& var_to_set : variables)
532 if (var == var_to_set)
537 const auto var_to_set_expr = ctx.bv_const(var_to_set.c_str(), 1);
539 auto random_value = (xorshf96(x, y, z) % 2) ? ctx.bv_val(1, 1) : ctx.bv_val(0, 1);
541 from_vec.push_back(var_to_set_expr);
542 to_vec.push_back(random_value);
545 auto z3_bf_substitute = z3_bf.substitute(from_vec, to_vec).simplify();
547 z3::expr_vector from_vec_var(ctx);
548 z3::expr_vector to_vec_one(ctx);
549 z3::expr_vector to_vec_zero(ctx);
551 from_vec_var.push_back(var_expr);
552 to_vec_one.push_back(ctx.bv_val(1, 1));
553 to_vec_zero.push_back(ctx.bv_val(0, 1));
556 const auto res_1 = z3_bf_substitute.substitute(from_vec_var, to_vec_one).simplify();
557 if (!res_1.is_numeral())
559 std::cout << res_1 << std::endl;
560 return ERR(
"cannot determine boolean influence of variabel " + var +
": failed to simplify to a constant");
564 const auto res_2 = z3_bf_substitute.substitute(from_vec_var, to_vec_zero).simplify();
565 if (!res_2.is_numeral())
567 std::cout << res_2 << std::endl;
568 return ERR(
"cannot determine boolean influence of variabel " + var +
": failed to simplify to a constant");
571 const auto r1 = res_1.get_numeral_uint64();
572 const auto r2 = res_2.get_numeral_uint64();
579 double cv = (double)(count) / (double)(num_evaluations);
580 influences.insert({var, cv});
583 return OK(influences);
588 std::map<u32, Gate*> matrix_id_to_gate;
589 std::map<Gate*, u32> gate_to_matrix_id;
590 std::vector<std::vector<double>> matrix;
592 std::unordered_map<const Net*, std::set<Gate*>>* cache;
594 u32 matrix_gates = 0;
601 gate_to_matrix_id[gate] = matrix_gates;
602 matrix_id_to_gate[matrix_gates] = gate;
606 u32 status_counter = 0;
607 for (
const auto& [
id, gate] : matrix_id_to_gate)
609 if (status_counter % 100 == 0)
611 log_info(
"boolean_influence",
"status {}/{} processed", status_counter, matrix_id_to_gate.size());
614 std::vector<double> line_of_matrix;
616 std::set<u32> gates_to_add;
618 if (next_seq_gates.is_error())
621 "unable to generate ff dependency matrix: failed to generate Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id())
622 +
": failed to get next sequential gates.");
624 for (
const auto& pred_gate : next_seq_gates.get())
626 gates_to_add.insert(gate_to_matrix_id[pred_gate]);
628 std::map<Net*, double> boolean_influence_for_gate;
629 if (with_boolean_influence)
632 if (inf_res.is_error())
635 "unable to generate ff dependency matrix: failed to generate Boolean influence for gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id())
638 boolean_influence_for_gate = inf_res.get();
641 for (
u32 i = 0; i < matrix_gates; i++)
643 if (gates_to_add.find(i) != gates_to_add.end())
645 if (with_boolean_influence)
647 double influence = 0.0;
649 Gate* pred_ff = matrix_id_to_gate[i];
653 if (boolean_influence_for_gate.find(output_net) != boolean_influence_for_gate.end())
655 influence += boolean_influence_for_gate[output_net];
659 line_of_matrix.push_back(influence);
663 line_of_matrix.push_back(1.0);
668 line_of_matrix.push_back(0.0);
671 matrix.push_back(line_of_matrix);
674 return OK(std::make_pair(matrix_id_to_gate, matrix));
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable from
std::set< std::string > get_variable_names() const
Result< Value > evaluate(const std::unordered_map< std::string, Value > &inputs) const
Value
represents the type of the node
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
const std::vector< Net * > & get_fan_out_nets() const
const std::vector< Gate * > & get_gates() const
Result< std::set< Gate * > > get_next_sequential_gates(const Net *net, bool successors, const std::set< PinType > &forbidden_pins={}, std::unordered_map< const Net *, std::set< Gate * >> *cache=nullptr) const
#define log_info(channel,...)
#define ERR_APPEND(prev_error, message)
Result< std::map< Net *, double > > get_boolean_influences_of_subcircuit(const std::vector< Gate * > &gates, const Net *start_net, const u32 num_evaluations=32000)
Result< std::map< Net *, double > > get_boolean_influences_of_gate(const Gate *gate, const u32 num_evaluations=32000)
Result< std::unordered_map< std::string, double > > get_boolean_influence_with_z3_expr(const BooleanFunction &bf, const u32 num_evaluations)
Result< std::map< Net *, double > > get_boolean_influences_of_subcircuit_deterministic(const std::vector< Gate * > &gates, const Net *start_net)
Result< std::unordered_map< std::string, double > > get_boolean_influence_deterministic(const BooleanFunction &bf)
Result< std::unordered_map< std::string, double > > get_boolean_influence(const BooleanFunction &bf, const u32 num_evaluations=32000)
Result< std::map< Net *, double > > get_boolean_influences_of_gate_deterministic(const Gate *gate)
Result< std::pair< std::map< u32, Gate * >, std::vector< std::vector< double > > > > get_ff_dependency_matrix(const Netlist *netlist, bool with_boolean_influence)
Result< std::unordered_map< std::string, double > > get_boolean_influence_with_hal_boolean_function_class(const BooleanFunction &bf, const u32 num_evaluations)
void remove(std::filesystem::path file_path)
CORE_API T replace(const T &str, const T &search, const T &replace)
CORE_API bool starts_with(const T &s, const T &start)
Result< std::filesystem::path > get_unique_temp_directory(const std::string &prefix, const u32 max_attmeps)
CORE_API std::vector< T > to_vector(const Container< T, Args... > &container)