/* * coingenerator.cc * * Created on: 30.10.2010 * Author: Milan Krivanek */ #if GEN_COIN #include using namespace std; namespace divine { namespace generator { int Coin::count = 0; Coin::Coin() : por(false), coin_system(NULL) { id = count++; #ifdef VERBOSE std::cout << id << ": Empty constructor" << std::endl; #endif #ifdef LCA lca = NULL; restrict = NULL; only = NULL; empty_label_set = NULL; #endif } Coin::Coin(const Coin & other) : Common(other), file(other.file), por(other.por), coin_system(NULL), original_slack(other.original_slack) { id = count++; #ifdef VERBOSE std::cout << "Creating instance " << id << " as a copy of " << other.id << std::endl; #endif #ifdef LCA lca = NULL; restrict = NULL; only = NULL; empty_label_set = NULL; #endif } Coin::~Coin() { #ifdef VERBOSE std::cout << "Deleting instance " << id << " initialized with " << file << std::endl; #endif if (coin_system) { delete coin_system; } for (unsigned i = 0; i < tree_nodes.size(); i++) { delete tree_nodes[i]; } tree_nodes.clear(); #ifdef LCA if(lca != NULL) { for (int i = 0; i < system_primitive_components.size(); i++) { free(lca[i]); } free(lca); lca = NULL; } if(restrict != NULL && only != NULL) { for(int i = 0; i < automata_size; i++) { for(int j = 0; j <= i; j++) { if(restrict[i][j] != NULL && restrict[i][j] != empty_label_set) { delete restrict[i][j]; } if(only[i][j] != NULL && only[i][j] != empty_label_set) { delete only[i][j]; } } free(restrict[i]); free(only[i]); } free(restrict); free(only); } if(empty_label_set != NULL) { delete empty_label_set; } #endif } coin_system_t * Coin::getCoinSystem() { if (!coin_system) { coin_system = new coin_system_t; if (!file.empty()) { #ifdef VERBOSE std::cout << id << ": Parse" << std::endl; #endif the_coin_system = coin_system; yyin = fopen(file.c_str(), "r"); if (!yyin) { throw std::runtime_error("Error reading input model."); } yyparse(); // build the coin system fclose(yyin); init(); } } return coin_system; } void Coin::initPOR() { #ifdef VERBOSE std::cout << id << ": Init POR" << std::endl; #endif por = true; } void Coin::read(std::string path, std::vector< std::string >, Coin *) { #ifdef VERBOSE std::cout << id << ": Read '" << path << "'" << std::endl; #endif file = path; getCoinSystem(); } Coin & Coin::operator=(const Coin &other) { #ifdef VERBOSE std::cout << "Assignment: " << id << " := " << other.id << std::endl; #endif Common::operator=(other); file = other.file; original_slack = other.original_slack; if (coin_system != NULL) { delete coin_system; coin_system = NULL; } getCoinSystem(); // FIXME, we force read here to keep parsing from happening in // multiple threads at once, no matter the mutex... return *this; } int Coin::setSlack(int s) { #ifdef VERBOSE std::cout << id << ": setSlack() " << s << std::endl; #endif original_slack = s; return Common::setSlack(por ? s + sizeof(Extension) : s); } inline size_t Coin::getSize(unsigned int number_of_states) { if (number_of_states < 256) { return 1; } else if (number_of_states < 65536) { return 2; } else if (number_of_states < 16777216) { return 3; } else { return 4; } } std::string Coin::showNode(Node compressed_state) { std::stringstream stream; State state(pool(), compressed_state, this->slack()); vector v = state.getValues(); //primitive stream << '['; int n = 0; for(int i = 0; i < automata_size; i++) { aut_t * tmpa = automata->get(i); if(tmpa->is_prim()) { if(n > 0) { stream << ", "; } int sid = v[n]; string name = tmpa->states[sid]->name; stream << name; n++; } } if(property) { if(n > 0) { stream << ", "; } int sid = v[n]; string name = property->prop_states[sid]->name; stream << name; n++; } stream << ']'; return stream.str(); } std::string Coin::showTransition( Node, Node, Label ) { return ""; } void Coin::packPrimitiveStates(vector & packed_state, vector & unpacked_state) { int j = 0; for(int i = 0; i < automata_size; i++) { if(automata->get(i)->is_primitive) { packed_state[j] = unpacked_state[i]; j++; } } if(property) { packed_state[j] = unpacked_state[prop_aut_id]; } } void Coin::unpackPrimitiveStates(vector & packed_state, vector & unpacked_state) { int j = 0; for(int i = 0; i < automata_size; i++) { if(automata->get(i)->is_primitive) { unpacked_state[i] = packed_state[j]; j++; } } if(property) { unpacked_state[prop_aut_id] = packed_state[j]; } } void Coin::init() { #ifdef VERBOSE std::cout << id << ": Init, original slack: " << original_slack << std::endl; #endif ASSERT(coin_system); automata = coin_system->get_automata_list(); property = coin_system->property; system_aut_id = coin_system->system_aut_id; automata_size = automata->size(); packed_state_size = 0; state_size = automata_size + (property ? 1 : 0); prop_aut_id = property ? state_size - 1 : -1; state_vector.resize(state_size); next_state_vector.resize(state_size); vector metrics; for (int i = 0; i < automata_size; i++) { aut_t * tmp = automata->get(i); if (tmp->is_prim()) { state_vector[i] = tmp->init_state; metrics.push_back(getSize(tmp->states.size())); packed_state_size++; } else { // previously -1, but we work with unsigned int; // 255 for easier debugging state_vector[i] = 255; } } if (property) { state_vector[prop_aut_id] = property->init_state; metrics.push_back(getSize(property->prop_states.size())); packed_state_size++; } metrics.resize(packed_state_size); primitive_states.resize(packed_state_size); // fixed size state metrics - 1 byte per index State::metrics = StateMetrics(packed_state_size, metrics); #ifdef LCA initSystemPrimitiveComponents(); #ifdef VERBOSE std::cout << id << ": Initialized sys. prim. comp. " << std::endl; #endif initLCA(); #ifdef VERBOSE std::cout << id << ": Initialized LCAs." << std::endl; #endif initRestrictSets(); #ifdef VERBOSE std::cout << id << ": Initialized restrict sets." << std::endl; #endif #endif if (por) { coin_system->precompute(); for(unsigned i = 0; i < tree_nodes.size(); i++) { delete tree_nodes[i]; } tree_nodes.clear(); for(int i = 0; i < automata_size; i++) { tree_nodes.push_back(new tree_node_t()); } } } vector Coin::getSuccTransitions(int aid) { vector result; aut_t * tmpa = automata->get(aid); if (!tmpa->is_primitive) { // composite vector input; vector output; for (vector::iterator i = tmpa->composed_of.begin(); i != tmpa->composed_of.end(); i++) { vector tmp_succs = getSuccTransitions(*i); for (vector::iterator iter = tmp_succs.begin(); iter != tmp_succs.end(); iter++) { bool inr = ( tmpa->restrictions.find(iter->label) == tmpa->restrictions.end() ); // inr == not found in restriction list // if not found and list is restrictL // or if found and list is onlyL // then add if (tmpa->is_restrict == inr) { result.push_back(*iter); } if (iter->label.isInput()) { input.push_back(*iter); } else if (iter->label.isOutput()) { output.push_back(*iter); } } } for (vector::iterator inp = input.begin(); inp != input.end(); inp++) { int inp_act_id = inp->label.act_id; for (vector::iterator outp = output.begin(); outp != output.end(); outp++) { if (inp_act_id == outp->label.act_id // same action //the topmost automata the transitions belong to are different && inp->top_aut_id != outp->top_aut_id) { label_t newlabel; newlabel.fromc_id = outp->label.fromc_id; newlabel.toc_id = inp->label.toc_id; newlabel.act_id = inp_act_id; bool inr = ( tmpa->restrictions.find(newlabel) == tmpa->restrictions.end() ); if (inr == tmpa->is_restrict) { sometrans newtrans; newtrans.prop = false; newtrans.single = false; newtrans.aut_id = inp->aut_id; newtrans.state_id = inp->state_id; newtrans.label = newlabel; newtrans.aut_id2 = outp->aut_id; newtrans.state_id2 = outp->state_id; result.push_back(newtrans); } } } } } else { // primitive int sid = state_vector[aid]; coin_state_t * stmp = tmpa->states.get(sid); for (vector::iterator i = stmp->outtrans.begin(); i != stmp->outtrans.end(); i++) { sometrans strn; strn.prop = false; strn.single = true; strn.aut_id = aid; // strn.trans = *i; strn.state_id = (*i)->tostate_id; strn.label = (*i)->label; result.push_back(strn); } } //set the topmost automaton the transitions belong to //to the current aid; do it here not to affect previous computation for (vector::iterator i = result.begin(); i != result.end(); i++) { i->top_aut_id = aid; } return result; } vector * Coin::combineWithProp(vector * system_trans) { vector * trans = new vector ; set enabled_labels; for (vector::iterator j = system_trans->begin(); j != system_trans->end(); j++) { enabled_labels.insert((*j)->get_label()); } prop_state * ps = property->prop_states.get( state_vector[state_size - 1]); for (vector::iterator i = ps->outtrans.begin(); i != ps->outtrans.end(); i++) { prop_trans_t * pt = *i; if (!common_elem(enabled_labels, pt->guard_false) && subset(pt->guard_true, enabled_labels)) { // all guards are met for (vector::iterator j = system_trans->begin(); j != system_trans->end(); j++) { transition_t * st = *j; if (pt->any_label != // any_label XOR j_label in labels (pt->labels.find(st->get_label()) != pt->labels.end())) { transition_t * at; if (st->is_sync()) { at = new sync_transition_with_property_t( *(dynamic_cast (st)), pt->tostate_id); } else { at = new transition_with_property_t(*st, pt->tostate_id); } trans->push_back(at); } } } } return trans; } vector * Coin::getEnabledTrans(Node compressed_state) { State state(pool(), compressed_state, this->slack()); primitive_states = state.getValues(); unpackPrimitiveStates(primitive_states, state_vector); vector * enabled_trans = new vector; //compute successors-> vector transitions; #ifdef LCA transitions = getSuccTransitionsLCA(); #else transitions = getSuccTransitions(system_aut_id); #endif vector::iterator i; for (i = transitions.begin(); i != transitions.end(); i++) { transition_t * t; if (i->single) { t = new transition_t(i->aut_id, i->state_id, i->label); } else { t = new sync_transition_t(i->aut_id, i->state_id, i->aut_id2, i->state_id2, i->label); } enabled_trans->push_back(t); } return enabled_trans; } void Coin::setInComposition(int i) { aut_t * automaton = (*automata)[i]; tree_node_t * node = tree_nodes[i]; node->in_composition = true; for (vector::iterator j = automaton->composed_of.begin(); j != automaton->composed_of.end(); j++) { setInComposition(*j); } } inline void Coin::setCandidateFlags(int aid) { // reset the flags for (int j = 0; j < automata_size; j++) { tree_nodes[j]->in_composition = false; } setInComposition(aid); } bool Coin::checkC1(int aid) { // reset the flags and set them for the subtree of aid setCandidateFlags(aid); // now: ample set candidates are in_composition bit_set_t * candidate_input = new bit_set_t(coin_system->act_count); bit_set_t * candidate_output = new bit_set_t(coin_system->act_count); bit_set_t * other_input = new bit_set_t(coin_system->act_count); bit_set_t * other_output = new bit_set_t(coin_system->act_count); // step 1: gather candidate actions for (int j = 0; j < automata_size; j++) { aut_t * aut = automata->get(j); tree_node_t * node = tree_nodes[j]; if (aut->is_primitive && node->in_composition) { coin_state_t * cst = aut->states[state_vector[j]]; candidate_input -> union_with(cst->input_act); candidate_output-> union_with(cst->output_act); } if (aut->is_primitive && !node->in_composition) { other_input -> union_with(aut->all_input_act); other_output -> union_with(aut->all_output_act); } } // step 2: check if no communication between candidates and other // would be possible bool result = !candidate_input->common_element(other_output) && !candidate_output->common_element(other_input); delete candidate_input; delete candidate_output; delete other_input; delete other_output; return result; } void Coin::setC0C2(const vector * enabled_trans) { // clear the values for (int i = 0; i < automata_size; i++) { tree_node_t * n = tree_nodes[i]; n->c2 = true; n->nonempty_succs = false; } // process simple automata affected by enabled_trans for (vector::const_iterator i = enabled_trans->begin(); i != enabled_trans->end(); i++) { transition_t * t = *i; int a1_id = t->get_automaton(); int a2_id = -1; aut_t * automaton = automata->get(a1_id); aut_t * automaton2 = NULL; tree_node_t * node1 = tree_nodes[a1_id]; tree_node_t * node2 = NULL; if (t->is_sync()) { a2_id = t->get_automaton2(); automaton2 = automata->get(a2_id); node2 = tree_nodes[a2_id]; } // check C0 node1->nonempty_succs = true; if (node2) { node2->nonempty_succs = true; } // check C2 // * check interesting label (Act') if (coin_system->int_Act.find(t->get_label()) != coin_system->int_Act.end()) { node1->c2 = false; if (node2) { node2->c2 = false; } continue; // no further checks needed } // * check Ap' visibility if (automaton->is_Ap_visible_trans(state_vector[a1_id], t->get_to_state()) || (automaton2 && automaton2->is_Ap_visible_trans( state_vector[a2_id], t->get_to_state2()))) { node1->c2 = false; if (node2) { node2->c2 = false; } continue; // no further checks needed } } // now set c2 and nonempty_succs for composite automata for (int i = 0; i < automata_size; i++) { aut_t * aut = automata->get(i); if (!aut->is_primitive) { tree_node_t * parent_node = tree_nodes[i]; bool tmp_c2 = true; bool tmp_nonempty_succs = false; vector::iterator end = aut->composed_of.end(); for (vector::iterator j = aut->composed_of.begin(); j != end; j++) { int child_id = *j; tree_node_t * child_node = tree_nodes[child_id]; tmp_c2 = tmp_c2 && child_node->c2; tmp_nonempty_succs = tmp_nonempty_succs || child_node->nonempty_succs; } parent_node->c2 = tmp_c2; parent_node->nonempty_succs = tmp_nonempty_succs; } } } int Coin::findAmpleSet(vector * enabled_trans) { aut_t * automaton; tree_node_t * node; int i; vector::iterator j; // This passes through enabled_trans and sets c2 and nonempty_succs // accordingly setC0C2(enabled_trans); // First iteration through simple automata for (i = 0; i < automata_size; i++) { automaton = automata->get(i); node = tree_nodes[i]; if (automaton->is_primitive && node->nonempty_succs && node->c2 && checkC1(i)) { return i; } } // Second iteration through composite automata for (i = 0; i < automata_size; i++) { automaton = automata->get(i); node = tree_nodes[i]; if (i != system_aut_id && !automaton->is_primitive && node->nonempty_succs && node->c2 && checkC1(i)) { return i; } } return system_aut_id; } #ifdef LCA void Coin::markSystemComponents(int id) { aut_t *a = automata->get(id); a->is_system_component = true; for(vector::iterator it = a->composed_of.begin(); it != a->composed_of.end(); it++) { markSystemComponents(*it); } } void Coin::initSystemPrimitiveComponents() { markSystemComponents(system_aut_id); system_primitive_components.clear(); for (int i = 0; i < automata_size; i++) { aut_t * a = automata->get(i); if (a->is_primitive && a->is_system_component) { system_primitive_components.push_back(i); } } /* TODO for (int i = 0; i < automata_size; i++) { aut_t * a = automata->get(i); if (!a->is_system_component) { std::cout << "Deleting unused automaton " << a->aut_name << std::endl; delete a; } } */ system_primitive_components.resize(system_primitive_components.size()); } int Coin::computeLCA(int i, int j) { aut_t * a1 = automata->get(i); aut_t * a2 = automata->get(j); aut_t * ancestor = NULL; for(aut_t * current = a1; current != NULL; current = current->parent) { current->visited = true; } for(aut_t * current = a2; current != NULL; current = current->parent) { if(current->visited) { ancestor = current; break; } } //cleanup! for(aut_t * current = a1; current != NULL; current = current->parent) { current->visited = false; } ASSERT(ancestor != NULL); return automata->find_id(ancestor->aut_name); } void Coin::initLCA() { lca = (int**) malloc(system_primitive_components.size() * sizeof(int*)); for (int i = 0; i < system_primitive_components.size(); i++) { lca[i] = (int*) malloc(i * sizeof(int)); for(int j = 0; j < i; j++) { lca[i][j] = computeLCA(system_primitive_components[i], system_primitive_components[j]); } } } int Coin::getLCA(int i, int j) { if(i == j) { std::cerr << "The automata must be different." << std::endl; } int x = std::max(i, j); // first coordinate contains all primitive comp. int y = std::min(i, j); // second coordinate contains only previous ones return lca[x][y]; } label_set * Coin::computeRestrictSet(int lower, int upper) { label_set * const result = new label_set(); aut_t * current = automata->get(lower); aut_t * last = automata->get(upper); do { #ifndef NDEBUG if (current == NULL) { fprintf(stderr, "Error - current is NULL\n"); } #endif //TODO chci tady uz ten prvni automat??? if (current->is_restrict) { for (set::iterator it = current->restrictions.begin(); it != current->restrictions.end(); it++) { result->insert(*it); } } current = current->parent; } while (current != last && current != NULL); return result; } label_set * Coin::computeOnlySet(int lower, int upper) { label_set * result = empty_label_set; aut_t * current = automata->get(lower); aut_t * last = automata->get(upper); do { #ifndef NDEBUG if (current == NULL) { fprintf(stderr, "Error - current is NULL\n"); } #endif //process just nonempty only-sets if (!current->is_restrict && !current->restrictions.empty()) { if (result == empty_label_set) { result = new label_set(); for (set::iterator it = current->restrictions.begin(); it != current->restrictions.end(); it++) { result->insert(*it); } } else { for (label_set::iterator it = result->begin(); it != result->end(); /* empty */) { if (current->restrictions.count(*it) <= 0) { it = result->erase(it); } else { ++it; } } } } current = current->parent; } while (current != last && current != NULL); return result; } void Coin::initRestrictSets() { empty_label_set = new label_set(); restrict = (label_set ***) malloc(automata_size * sizeof(label_set **)); only = (label_set ***) malloc(automata_size * sizeof(label_set **)); for(int i = 0; i < automata_size; i++) { restrict[i] = (label_set **) malloc((i+1) * sizeof(label_set *)); only[i] = (label_set **) malloc((i+1) * sizeof(label_set *)); for(int j = 0; j <= i; j++) { restrict[i][j] = NULL; only[i][j] = NULL; } } for(int i = 0; i < system_primitive_components.size(); i++) { int a1 = system_primitive_components[i]; if(restrict[system_aut_id][a1] == NULL) { restrict[system_aut_id][a1] = computeRestrictSet(a1, system_aut_id); only[system_aut_id][a1] = computeOnlySet(a1, system_aut_id); } for(int j = 0; j < i; j++) { int a2 = system_primitive_components[j]; int lca = getLCA(i, j); if(restrict[lca][a1] == NULL) { restrict[lca][a1] = computeRestrictSet(a1, lca); only[lca][a1] = computeOnlySet(a1, lca); } if(restrict[lca][a2] == NULL) { restrict[lca][a2] = computeRestrictSet(a2, lca); only[lca][a2] = computeOnlySet(a2, lca); } if(restrict[system_aut_id][lca] == NULL) { restrict[system_aut_id][lca] = computeRestrictSet(lca, system_aut_id); only[system_aut_id][lca] = computeOnlySet(lca, system_aut_id); } } } } label_set * Coin::getRestrictSet(int lower, int upper) { int x = std::max(lower, upper); int y = std::min(lower, upper); return restrict[x][y]; } label_set * Coin::getOnlySet(int lower, int upper) { int x = std::max(lower, upper); int y = std::min(lower, upper); return only[x][y]; } bool Coin::isLabelAllowed(const label_t& l, int from, int to, bool incl) { label_set * r = getRestrictSet(from, to); ASSERT(r); if(r->count(l) > 0) { return false; } label_set * o = getOnlySet(from, to); ASSERT(o); if(o != empty_label_set && o->count(l) <= 0) { return false; } if(incl) { aut_t * last = automata->get(to); bool found = last->restrictions.count(l) > 0; if(last->is_restrict == found) { return false; } } return true; } vector Coin::getSuccTransitionsLCA() { //TODO store pointers only? vector result; int a1, a2, s1, s2; vector *v1, *v2; vector::iterator v1it, v1end, v2it, v2end; int N = system_primitive_components.size(); for (int i = 0; i < N; i++) { a1 = system_primitive_components[i]; s1 = state_vector[a1]; //internal v1 = &(automata->get(a1)->states[s1]->internal_trans); for (v1it = v1->begin(), v1end = v1->end(); v1it != v1end; v1it++) { //printf("Internal: %d\n", it->second->tostate_id); trans_t * t = *v1it; if (isLabelAllowed(t->label, a1, system_aut_id, true)) { sometrans strn; strn.prop = false; strn.single = true; strn.aut_id = a1; strn.state_id = t->tostate_id; strn.label = t->label; result.push_back(strn); } } //external - input v2 = &(automata->get(a1)->states[s1]->input_trans); for (v2it = v2->begin(), v2end = v2->end(); v2it != v2end; v2it++) { //printf("Input: from state %d\n", it->second->tostate_id); trans_t * t = *v2it; if (isLabelAllowed(t->label, a1, system_aut_id, true)) { sometrans strn; strn.prop = false; strn.single = true; strn.aut_id = a1; strn.state_id = t->tostate_id; strn.label = t->label; result.push_back(strn); } } //external - output v1 = &(automata->get(a1)->states[s1]->output_trans); for (v1it = v1->begin(), v1end = v1->end(); v1it != v1end; v1it++) { //printf("Output: to state %d\n", it->second->tostate_id); trans_t * send = *v1it; if (isLabelAllowed(send->label, a1, system_aut_id, true)) { sometrans strn; strn.prop = false; strn.single = true; strn.aut_id = a1; strn.state_id = send->tostate_id; strn.label = send->label; result.push_back(strn); } //sync int act_id = send->label.act_id; for (int j = 0; j < N; j++) { //iterate through all the other automata if (j != i) { a2 = system_primitive_components[j]; int lca = getLCA(i, j); if (!isLabelAllowed(send->label, a1, lca, false)) { continue; } s2 = state_vector[a2]; v2 = &(automata->get(a2)->states[s2]->input_trans); //TODO Maybe we could check if the input and output transitions are enabled earlier, //also the order of the checks may be optimized - e.g. source transitions first for (v2it = v2->begin(), v2end = v2->end(); v2it != v2end; v2it++) { trans_t * recv = *v2it; // receiver transition if(recv->label.act_id == act_id) { //same action if (!isLabelAllowed(recv->label, a2, lca, false)) { continue; } label_t sync_label; //create new label sync_label.act_id = act_id; //with the same action sync_label.fromc_id = send->label.fromc_id; //sender component from the sender transition sync_label.toc_id = recv->label.toc_id; //receiver component from the receiver transition if (!isLabelAllowed(sync_label, lca, system_aut_id, true)) { continue; } sometrans sync; sync.prop = false; sync.single = false; //sync transition sync.aut_id = a1; //sending automaton sync.aut_id2 = a2; //receiving automaton sync.state_id = send->tostate_id; //sender moves to state_id sync.state_id2 = recv->tostate_id; //receiver moves to state_id2 sync.label = sync_label; //assign the newly created label result.push_back(sync); } } } } } } return result; } #endif } // namespace generator } // namespace divine #endif