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);
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;
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;
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);
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();
417 return get_boolean_influence_internal(expr, num_evaluations,
false);
422 auto ctx = z3::context();
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();
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));
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)
T replace(const T &str, const T &search, const T &replace)
Result< std::filesystem::path > get_unique_temp_directory(const std::string &prefix="", const u32 max_attempts=5)
bool starts_with(const T &s, const T &start)
std::vector< T > to_vector(const Container< T, Args... > &container)
std::set< std::string > get_variable_names(const z3::expr &e)
Extracts all variable names from a z3 expression.
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Result< z3::expr > get_subgraph_z3_function(const std::vector< Gate * > &subgraph_gates, const Net *subgraph_output, z3::context &ctx)
Get the z3 expression representation of a combined Boolean function of a subgraph of combinational ga...
std::string to_cpp(const z3::expr &e)