/** Number the vertices of the forest. */ void renumber_vertices() { size_t id=0; for (size_t i=0; i<levels.size(); ++i) { for (Vertices::const_iterator vi=levels[i].vertices.begin(); vi!=levels[i].vertices.end(); ++vi) (*vi)->id = id++; } }
/** Print the entire forest for debugging output. */ void print(std::ostream &o) const { for (size_t i=0; i<levels.size(); ++i) { if (levels[i].vertices.empty()) { o <<"partition forest level " <<i <<" is empty.\n"; } else { size_t nsets = levels[i].vertices.size(); size_t nfuncs = 0; for (Vertices::const_iterator vi=levels[i].vertices.begin(); vi!=levels[i].vertices.end(); ++vi) nfuncs += (*vi)->functions.size(); o <<"partition forest level " <<i <<" contains " <<nfuncs <<" function" <<(1==nfuncs?"":"s") <<" in " <<nsets <<" set" <<(1==nsets?"":"s") <<"\n"; o <<" the following input was used to generate " <<(1==nsets?"this set":"these sets") <<":\n"; o <<StringUtility::prefixLines(levels[i].inputs.toString(), " "); int setno = 1; for (Vertices::const_iterator vi=levels[i].vertices.begin(); vi!=levels[i].vertices.end(); ++vi, ++setno) { Vertex *vertex = *vi; const Functions &functions = vertex->functions; o <<" set #" <<setno <<" contains " <<vertex->functions.size() <<" function" <<(1==vertex->functions.size()?"":"s") <<":\n"; for (Functions::const_iterator fi=functions.begin(); fi!=functions.end(); ++fi) { SgAsmFunction *func = *fi; o <<" " <<StringUtility::addrToString(func->get_entry_va()) <<" <" <<func->get_name() <<">\n"; } o <<" whose output was: {"; for (OutputValues::const_iterator oi=vertex->outputs.begin(); oi!=vertex->outputs.end(); ++oi) o <<" " <<*oi; o <<" }\n"; } } } }
/** Dump the output sets to the DBMS. (FIXME: dumping SQL to a file instead; see dump())*/ void dump_outputsets(std::ostream &dbc) const { for (size_t i=0; i<levels.size(); ++i) { for (Vertices::const_iterator vi=levels[i].vertices.begin(); vi!=levels[i].vertices.end(); ++vi) { dbc <<"insert into outputsets (id) values (" <<(*vi)->id <<");\n"; for (OutputValues::const_iterator ni=(*vi)->outputs.begin(); ni!=(*vi)->outputs.end(); ++ni) dbc <<"insert into outputvalues (outputset_id, val) values (" <<(*vi)->id <<", " <<*ni <<");\n"; } } }
void printMe() { cout << "========================== UKS ==============================" << endl; cout << " --- Maxes --- " << endl << " "; for (int k = 0; k < maxes.size(); ++k) { cout << " " << maxes[k]; } cout << " --- Mins --- " << endl << " "; for (int k = 0; k < mins.size(); ++k) { cout << " " << mins[k]; } cout << " --- Range size --- " << endl << " "; for (int k = 0; k < range_size.size(); ++k) { cout << " " << range_size[k]; } cout << endl; cout << " ==== STATES ==== " << endl; for (int i = 0; i < states.size(); ++i) { TSStateProperty s = states[i]; cout << " State: " << s.ID << endl; cout << " - Levels: "; for (int k = 0; k < s.levels.size(); ++k) { cout << " " << s.levels[k]; } cout << endl; cout << " - Transitions: " << endl; for (int j = 0; j < s.transitions.size(); ++j) { TSTransitionProperty tr = s.transitions[j]; cout << " " << j << " Target: " << tr.target_ID << " step_size: " << tr.trans_const.step_size << " req_dir: " << tr.trans_const.req_dir << " comp_value: " << tr.trans_const.comp_value << endl; cout << " Targets: "; for (int k = 0; k < tr.trans_const.targets.size(); ++k) { cout << " " << tr.trans_const.targets[k]; } cout << endl; } } }
inline StateID getID(const Levels & levels) const { StateID result = 0; size_t factor = 1; for (size_t lvl_no = 0; lvl_no < levels.size(); lvl_no++) { result += (levels[lvl_no] - mins[lvl_no]) * factor; factor *= (range_size[lvl_no]); } return result; }
/** Returns the set of all leaf nodes in the forest. */ Vertices get_leaves() const { Vertices retval; for (size_t i=0; i<levels.size(); ++i) { const Vertices &vertices = vertices_at_level(i); for (Vertices::const_iterator vi=vertices.begin(); vi!=vertices.end(); ++vi) { if ((*vi)->children.empty()) retval.insert(*vi); } } return retval; }
StateID UnparametrizedStructure::computeID(const Levels & levels) const { StateID result = 0; size_t factor = 1; for (size_t lvl_no = 0; lvl_no < levels.size(); lvl_no++) { result += (levels[lvl_no] - get<0>(_bounds)[lvl_no]) * factor; factor *= (get<2>(_bounds)[lvl_no]); } return result; }
/** Dump inputsets to the DBMS. (FIXME: dumping SQL to a file instead; see dump()) */ void dump_inputsets(std::ostream &dbc) const { for (size_t i=0; i<levels.size(); ++i) { dbc <<"insert into inputsets (id) values(" <<i <<");\n"; const std::vector<uint64_t> &pointers = levels[i].inputs.get_pointers(); for (size_t j=0; j<pointers.size(); ++j) dbc <<"insert into inputvalues (inputset_id, vtype, pos, val)" <<" values (" <<i <<", 'P', " <<j <<", " <<pointers[j] <<");\n"; const std::vector<uint64_t> &integers = levels[i].inputs.get_integers(); for (size_t j=0; j<integers.size(); ++j) dbc <<"insert into inputvalues (inputset_id, vtype, pos, val)" <<" values (" <<i <<", 'N', " <<j <<", " <<integers[j] <<");\n"; } }
/** * Creates transitions from labelled edges of BA and passes them to the automaton structure. */ void addTransitions(AutomatonStructure & automaton, const StateID ID) const { const PropertyAutomaton::Edges & edges = property.getEdges(ID); // Transform each edge into transition and pass it to the automaton for (const PropertyAutomaton::Edge & edge : edges) { // Compute allowed values from string of constrains ConstraintParser * parser = new ConstraintParser(maxes.size(), *max_element(maxes.begin(), maxes.end())); parser->applyFormula(names, edge.cons.values); parser->addBoundaries(maxes, true); parser->addBoundaries(mins, false); automaton.addTransition(ID, { edge.target_ID, parser, edge.cons.transient, edge.cons.stable }); } }
/** Insert a function into a vertex of the forest, or create a new vertex. The (new) vertex into which the function was * inserted is either a child of @p parent or a root node. The @p outputs are used to select the vertex into which the * function is inserted (all functions of a particular vertex produced the same output when run with the same input). */ void insert(SgAsmFunction *func, OutputValues outputs, PartitionForest::Vertex *parent) { Vertices candidates = parent ? parent->children : vertices_at_level(0); assert(!contains(candidates, func)); for (Vertices::iterator vi=candidates.begin(); vi!=candidates.end(); ++vi) { Vertex *vertex = *vi; if (outputs.size()==vertex->outputs.size() && std::equal(outputs.begin(), outputs.end(), vertex->outputs.begin())) { vertex->functions.insert(func); return; } } size_t lno = parent ? parent->get_level() + 1 : 0; assert(lno<levels.size()); levels[lno].vertices.insert(new Vertex(parent, func, outputs)); }
/** Return the list of vertices at a given level of the forest. */ const Vertices& vertices_at_level(size_t level) const { assert(level<levels.size()); return levels[level].vertices; }
/** Create a new (empty) level. This is the level into which the next higher level's vertices will be partitioned. The * return value is the new level number. */ size_t new_level(const InputValues &inputs) { levels.push_back(Level(inputs)); return levels.size()-1; }
/** Returns the number of levels in the partition forest. Levels are numbered starting at zero. The return value is one * more than the maximum level that contains a vertex. */ size_t nlevels() const { return levels.size(); }