void Synth::model_to_aiger(const BDD &c_signal, const BDD &func) { /// Update AIGER spec with a definition of `c_signal` uint c_lit = aiger_by_cudd[c_signal.NodeReadIndex()]; string output_name = string(aiger_is_input(aiger_spec, c_lit)->name); // save the name before it is freed uint func_as_aiger_lit = walk(func.getNode()); aiger_redefine_input_as_and(aiger_spec, c_lit, func_as_aiger_lit, func_as_aiger_lit); if (print_full_model) aiger_add_output(aiger_spec, c_lit, output_name.c_str()); }
hmap<uint,BDD> Synth::extract_output_funcs() { /** The result vector respects the order of the controllable variables **/ L_INF("extract_output_funcs.."); cudd.FreeTree(); // ordering that worked for win region computation might not work here hmap<uint,BDD> model_by_cuddidx; vector<BDD> controls = get_controllable_vars_bdds(); while (!controls.empty()) { BDD c = controls.back(); controls.pop_back(); aiger_symbol *aiger_input = aiger_is_input(aiger_spec, aiger_by_cudd[c.NodeReadIndex()]); L_INF("getting output function for " << aiger_input->name); BDD c_arena; if (controls.size() > 0) { BDD cube = cudd.bddComputeCube(controls.data(), NULL, (int)controls.size()); c_arena = non_det_strategy.ExistAbstract(cube); } else { //no other signals left c_arena = non_det_strategy; } // Now we have: c_arena(t,u,c) = ∃c_others: nondet(t,u,c) // (i.e., c_arena talks about this particular c, about t and u) BDD c_can_be_true = c_arena.Cofactor(c); BDD c_can_be_false = c_arena.Cofactor(~c); BDD c_must_be_true = ~c_can_be_false & c_can_be_true; BDD c_must_be_false = c_can_be_false & ~c_can_be_true; // Note that we cannot use `c_must_be_true = ~c_can_be_false`, // since the negation can cause including tuples (t,i,o) that violate non_det_strategy. auto support_indices = cudd.SupportIndices(vector<BDD>({c_must_be_false, c_must_be_true})); for (auto const var_cudd_idx : support_indices) { auto v = cudd.ReadVars(var_cudd_idx); auto new_c_must_be_false = c_must_be_false.ExistAbstract(v); auto new_c_must_be_true = c_must_be_true.ExistAbstract(v); if ((new_c_must_be_false & new_c_must_be_true) == cudd.bddZero()) { c_must_be_false = new_c_must_be_false; c_must_be_true = new_c_must_be_true; } } // We use 'restrict' operation, but we could also just do: // c_model = care_set -> must_be_true // but this is (presumably) less efficient (in time? in size?). // (intuitively, because we always set c_model to 1 if !care_set, but we could set it to 0) // // The result of restrict operation satisfies: // on c_care_set: c_must_be_true <-> must_be_true.Restrict(c_care_set) BDD c_model = c_must_be_true.Restrict(c_must_be_true | c_must_be_false); model_by_cuddidx[c.NodeReadIndex()] = c_model; //killing node refs c_must_be_false = c_must_be_true = c_can_be_false = c_can_be_true = c_arena = cudd.bddZero(); //TODO: ak: strange -- the python version for the example amba_02_9n produces a smaller circuit (~5-10 times)! non_det_strategy = non_det_strategy.Compose(c_model, c.NodeReadIndex()); //non_det_strategy = non_det_strategy & ((c & c_model) | (~c & ~c_model)); } return model_by_cuddidx; }