Beispiel #1
0
void _do_grouping(Cudd &cudd,
                  hmap<uint, vector<SetUint>> &groups_by_length,  // we modify its values
                  uint cur_group_length,
                  const VecUint& cur_order)
{
    L_INF("fixing groups of size " << cur_group_length << ". The number of groups = " << groups_by_length[cur_group_length].size());

    auto cur_groups = groups_by_length[cur_group_length];

    for (uint i = 0; i+cur_group_length < cur_order.size(); ++i) {
        SetUint candidate;
        for (uint j = 0; j < cur_group_length; ++j)
            candidate.insert(cur_order[i+j]);

        if (find(cur_groups.begin(), cur_groups.end(), candidate) != cur_groups.end()) {
            for (uint l = 2; l < cur_group_length; ++l) {
//                cout << "rm intersections " << string_set(candidate) << endl;
//                cout << "before: " << endl;
//                for (auto const v : groups_by_length[l])
//                    cout << string_set(v) << endl;
                remove_intersecting(candidate, groups_by_length[l]);  //remove from smaller groups
//                cout << "after: " << endl;
//                for (auto const v : groups_by_length[l])
//                    cout << string_set(v) << endl;
            }
            introduce_group_into_cudd(cudd, candidate);
        }
    }
}
Beispiel #2
0
void do_grouping(Cudd& cudd,
                 const vector<VecUint>& orders)
{
    L_INF("trying to group vars..");

    if (orders[0].size() < 5)  // window size is too big
        return;

    hmap<uint, vector<SetUint>> groups_by_length;
    groups_by_length[2] = get_group_candidates(orders, 2);
    groups_by_length[3] = get_group_candidates(orders, 3);
    groups_by_length[4] = get_group_candidates(orders, 4);
    groups_by_length[5] = get_group_candidates(orders, 5);

    L_INF("# of group candidates: of size 2 -- " << groups_by_length[2].size());
    for (auto const& g : groups_by_length[2]) {
        L_INF(string_set(g));
    }
    L_INF("# of group candidates: of size 3 -- " << groups_by_length[3].size());
    for (auto const& g : groups_by_length[3]) {
        L_INF(string_set(g));
    }
    L_INF("# of group candidates: of size 4 -- " << groups_by_length[4].size());
    L_INF("# of group candidates: of size 5 -- " << groups_by_length[5].size());

    auto cur_order = orders.back();    // we fix only groups present in the current order (because that is easier to implement)

    for (uint i = 5; i>=2; --i)  // decreasing order!
        if (!groups_by_length[i].empty())
            _do_grouping(cudd, groups_by_length, i, cur_order);
}
Beispiel #3
0
void Synth::compose_init_state_bdd() { // Initial state is 'all latches are zero'
    L_INF("compose_init_state_bdd..");

    init = cudd.bddOne();

    for (uint i = 0; i < aiger_spec->num_latches; i++) {
        BDD latch_var = get_bdd_for_sign_lit(aiger_spec->latches[i].lit);
        init = init & ~latch_var;
    }
}
Beispiel #4
0
BDD Synth::calc_win_region() {
    /** Calculate a winning region for the safety game: win = greatest_fix_point.X [not_error & pre_sys(X)]
        :return: BDD representing the winning region
    **/

    BDD new_ = cudd.bddOne();
    for (uint i = 1; ; ++i) {                                             L_INF("calc_win_region: iteration " << i << ": node count " << cudd.ReadNodeCount());
        BDD curr = new_;

        new_ = pre_sys(curr);

        if ((init & new_) == cudd.bddZero())
            return cudd.bddZero();

        if (new_ == curr)
            return new_;
    }
}
DdCiAdapter::DdCiAdapter( cDevice *dev, int ca_fd, int ci_fdw, int ci_fdr, cString &devNameCa, cString &devNameCi )
: device( dev )
, fd( ca_fd )
, caDevName( devNameCa )
, ciSend( *this, ci_fdw, devNameCi )
, ciRecv( *this, ci_fdr, devNameCi )
, camSlot( 0 )
{
	LOG_FUNCTION_ENTER;

	if (!dev) {
		L_ERROR_STR( "dev=NULL!" );
		return;
	}

	SetDescription( "DDCI adapter on device %d (%s)", device->DeviceNumber(), *caDevName );

	ca_caps_t Caps;
	if (ioctl( fd, CA_GET_CAP, &Caps ) == 0) {
		if ((Caps.slot_type & CA_CI_LINK) != 0) {
			int NumSlots = Caps.slot_num;
			if (NumSlots > 0) {
				for (int i = 0; i < NumSlots; i++) {
					if (!camSlot) {
						camSlot = new DdCiCamSlot( *this, ciSend );
					} else {
						L_ERR( "Currently only ONE CAM slot supported" );
					}
				}
				L_DBG( "DdCiAdapter(%s) for device %d created", *caDevName, device->DeviceNumber() );
				Start();
			} else
				L_ERR( "no CAM slots found on device %d", device->DeviceNumber() );
		} else
			L_INF( "device %d doesn't support CI link layer interface", device->DeviceNumber() );
	} else
		L_ERR( "can't get CA capabilities on device %d", device->DeviceNumber() );

	LOG_FUNCTION_EXIT;
}
Beispiel #6
0
BDD Synth::get_nondet_strategy() {
    /**
    Get non-deterministic strategy from the winning region.
    If the system outputs controllable values that satisfy this non-deterministic strategy,
    then the system wins.
    I.e., a non-deterministic strategy describes for each state all possible plausible output values
    (below is assuming W excludes error states)

        strategy(t,u,c) = ∃t' W(t) & T(t,i,c,t') & W(t')

    But since t' <-> bdd(t,i,o), (and since we use error=error(t,u,c)), we use:

        strategy(t,u,c) = ~error(t,u,c) & W(t) & W(t)[t <- bdd_next_t(t,u,c)]

    :return: non-deterministic strategy bdd
    :note: The strategy is non-deterministic -- determinization is done later.
    **/

    L_INF("get_nondet_strategy..");

    // TODO: do we need win_region?
    return ~error & win_region & win_region.VectorCompose(get_substitution());
}
Beispiel #7
0
bool Synth::run() {
    init_cudd(cudd);

    aiger_spec = aiger_init();
    const char *err = aiger_open_and_read_from_file(aiger_spec, aiger_file_name.c_str());
    MASSERT(err == NULL, err);
    Cleaner cleaner(aiger_spec);

    // main part
    L_INF("synthesize.. number of vars = " << aiger_spec->num_inputs + aiger_spec->num_latches);
//    grapher = new Grapher();                                        timer.sec_restart();
//    grapher->compute_deps(aiger_spec);                              L_INF("calculating deps graph took (sec): " << timer.sec_restart());

    //grapher.dump_dot();
    //print_set(grapher.deps[STRIP_LIT(aiger_spec->outputs[0].lit)], aiger_spec);

    // Create all variables. _tmp ensures that BDD have positive refs.
    vector<BDD> _tmp;
    for (uint i = 0; i < aiger_spec->num_inputs + aiger_spec->num_latches; ++i)
        _tmp.push_back(cudd.bddVar(i));

    for (uint i = 0; i < aiger_spec->num_inputs; ++i) {
        auto aiger_strip_lit = aiger_spec->inputs[i].lit;
        cudd_by_aiger[aiger_strip_lit] = i;
        aiger_by_cudd[i] = aiger_strip_lit;
    }
    for (uint i = 0; i < aiger_spec->num_latches; ++i) {
        auto aiger_strip_lit = aiger_spec->latches[i].lit;
        auto cudd_idx = i + aiger_spec->num_inputs;
        cudd_by_aiger[aiger_strip_lit] = cudd_idx;
        aiger_by_cudd[cudd_idx] = aiger_strip_lit;
    }

//    vector<int> permutation = compute_permutation(grapher, cudd, aiger_spec);
//    MASSERT(permutation.size() == (uint) cudd.ReadSize(), "");

    /*
    L_INF("frequencies of latches");
    for (uint i = 0; i < aiger_spec->num_latches; ++i) {
        auto lit = aiger_spec->latches[i].lit;
        cout << "latch lit " << lit << " : " << grapher.freq_map[lit] << endl;
    }
    L_INF("frequencies of inputs");
    for (uint i = 0; i < aiger_spec->num_inputs; ++i) {
        auto lit = aiger_spec->inputs[i].lit;
        cout << "input lit " << lit << " : " << grapher.freq_map[lit] << endl;
    }
    */

    /*
    vector<BDD> nodes;
    nodes.push_back(error);
    vector<string> names;
    vector<const char*> names_;

    names.push_back(string("weird0"));
    names_.push_back(names[0].data());

    for (uint i = 1; i < aiger_spec->num_latches + aiger_spec->num_inputs+1; ++i) {
        names.push_back(to_string(i));
        if (aiger_is_input(aiger_spec, i*2)) {
            auto s = aiger_is_input(aiger_spec, i*2);
            if (s->name)
                names.push_back(string(s->name));
            else
                names.push_back(to_string(i*2));
        }
        if (aiger_is_latch(aiger_spec, i*2)) {
            auto s = aiger_is_latch(aiger_spec, i*2);
            if (s->name)
                names.push_back(string(s->name));
            else
                names.push_back(to_string(i*2));
        }

        names_.push_back(names[i].data());

    }
    cudd.DumpDot(nodes, names_.data(), NULL);
    cout << cudd.OrderString() << endl;
    exit(0);
    */

    compose_init_state_bdd();
    timer.sec_restart();
    compose_transition_vector();
    L_INF("calc_trans_rel took (sec): " << timer.sec_restart());
    introduce_error_bdd();
    L_INF("introduce_error_bdd took (sec): " << timer.sec_restart());

//    cout << "before comput: nof_vars = " << cudd.ReadSize() << endl;
//    reachable = compute_reachable(aiger_spec, init, transition_func, error, cudd);
//    cout << "after comput: nof_vars = " << cudd.ReadSize() << endl;


    // no need for cache
    bdd_by_aiger_unlit.clear();

//                                               reorder_opt(cudd);
//                                               print_aiger_like_order(cudd);

    timer.sec_restart();
    win_region = calc_win_region();
    L_INF("calc_win_region took (sec): " << timer.sec_restart());

//                                               print_aiger_like_order(cudd);
//                                               Cudd_MakeTreeNode(cudd.getManager(), 5, 8, MTR_FIXED);

//                                               reorder_opt(cudd);
//                                               cout << "optimal order after calc_win_region" << endl;
//                                               print_aiger_like_order(cudd);
//                                                 cout << cudd.ReadNodeCount() << endl;

    if (win_region.IsZero()) {
        cout << "UNREALIZABLE" << endl;
        return 0;
    }

    cout << "REALIZABLE" << endl;

    non_det_strategy = get_nondet_strategy();

    //cleaning non-used bdds
    win_region = cudd.bddZero();
    transition_func.clear();
    init = cudd.bddZero();
    error = cudd.bddZero();
    //

    // TODO: set time limit on reordering? or even disable it if no time?
    hmap<uint, BDD> model_by_cuddidx = extract_output_funcs();                   L_INF("extract_output_funcs took (sec): " << timer.sec_restart());

    //cleaning non-used bdds
    non_det_strategy = cudd.bddZero();
    //

    auto elapsed_sec = time_limit_sec - timer.sec_from_origin();
    if (elapsed_sec > 100) {    // leave 100sec just in case
        auto spare_time_sec = elapsed_sec - 100;
        cudd.ResetStartTime();
        cudd.IncreaseTimeLimit((unsigned long) (spare_time_sec * 1000));
        cudd.ReduceHeap(CUDD_REORDER_SIFT_CONVERGE);
        cudd.UnsetTimeLimit();
        cudd.AutodynDisable();  // just in case -- cudd hangs on timeout
    }

    for (auto const it : model_by_cuddidx)
        model_to_aiger(cudd.ReadVars((int)it.first), it.second);
                                                                   L_INF("model_to_aiger took (sec): " << timer.sec_restart());
                                                                   L_INF("circuit size: " << (aiger_spec->num_ands + aiger_spec->num_latches));

    int res = 1;
    if (output_file_name == "stdout")
        res = aiger_write_to_file(aiger_spec, aiger_ascii_mode, stdout);
    else if (!output_file_name.empty()) {                                       L_INF("writing a model to " << output_file_name);
        res = aiger_open_and_write_to_file(aiger_spec, output_file_name.c_str());
    }

    MASSERT(res, "Could not write result file");

    return 1;
}
Beispiel #8
0
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;
}
Beispiel #9
0
void introduce_group_into_cudd(Cudd &cudd, const SetUint& group)
{
    L_INF("adding variable group to cudd: " << string_set(group));
    auto first_var_pos = get_var_of_min_order_position(cudd, group);
    cudd.MakeTreeNode(first_var_pos, (uint) group.size(), MTR_FIXED);
}
Beispiel #10
0
void Synth::compose_transition_vector() {
    L_INF("compose_transition_vector..");

    for (uint i = 0; i < aiger_spec->num_latches; ++i)
        transition_func[aiger_spec->latches[i].lit] = get_bdd_for_sign_lit(aiger_spec->latches[i].next);
}