// file: $isip/class/dstr/BiGraph/BiGraph.h // version: $Id: BiGraph.h 10636 2007-01-26 22:18:09Z tm334 $ // // make sure definitions are only made once // #ifndef ISIP_BI_GRAPH #define ISIP_BI_GRAPH // isip include files // #ifndef ISIP_DOUBLE_LINKED_LIST #include #endif #ifndef ISIP_BI_COLOR_HASH #include #endif #ifndef ISIP_BOOLEAN #include #endif #ifndef ISIP_TRIPLE #include #endif #ifndef ISIP_PAIR #include #endif #ifndef ISIP_LONG #include #endif #ifndef ISIP_BIGRAPH_VERTEX #include #endif // forward class definitions: // we must define the BiGraphVertex class here first because the header files // might be short-circuited by the ifndef. // template class DiGraph; template class GraphVertex; template class GraphArc; template class BiColorHash; template class BiGraphVertex; // BiGraph: a generic directed-graph template class. it is implemented // with something close to an adjacency list, with data held on the // vertices. each vertex holds both a TObject* and a list of all // emanating arcs. a graph can be in either USER or SYSTEM allocated // mode, for a USER-allocated list the TObject data is never copied. // template class BiGraph : public DoubleLinkedList< BiGraphVertex > { //--------------------------------------------------------------------------- // // public constants // //--------------------------------------------------------------------------- public: // define the class name // static const String CLASS_NAME; //---------------------------------------- // // i/o related constants // //---------------------------------------- static const String DEF_PARAM; static const String PARAM_VERTICES; static const String PARAM_ARCS; static const String PARAM_WEIGHTED; static const String START_NAME; static const String TERM_NAME; //---------------------------------------- // // dummy objects for start and end vertices // //---------------------------------------- static const TObject START_OBJ; static const TObject TERM_OBJ; //---------------------------------------- // // indeces for start and end vertices // //---------------------------------------- static const int32 START_INDEX = -1; static const int32 TERM_INDEX = -2; //---------------------------------------- // // default values and arguments // //---------------------------------------- // default values // static const bool8 DEF_IS_WEIGHTED = true; // default arguments to methods // //---------------------------------------- // // error codes // //---------------------------------------- static const int32 ERR = 41200; static const int32 ERR_EPSCYC = 41201; static const int32 ERR_MULPAR = 41202; //--------------------------------------------------------------------------- // // protected data // //--------------------------------------------------------------------------- protected: // define the object used to hold graph topology in read and write // typedef Triple< Pair, Float, Boolean> TopoTriple; typedef HashTable< String, BiGraphVertex > ReadHash; // each graph has a dummy start vertex // BiGraphVertex* start_vertex_d; // each graph has a dummy terminal vertex // BiGraphVertex* term_vertex_d; // each graph has a hash table that associates a color with the // graph vertices that tell us if the vertex has been // visited. unless explicitely allocated via the makeBiColorHash // method this will be a null pointer and all color methods will // fail. // BiColorHash* chash_d; // is the graph weighted? // Boolean is_weighted_d; // the allocation mode // DstrBase::ALLOCATION alloc_d; // debugging parameters // static Integral::DEBUG debug_level_d; // define the memory manager // static MemoryManager mgr_d; //--------------------------------------------------------------------------- // // required public methods // //--------------------------------------------------------------------------- public: // static methods // diagnose method is moved outside the class header file and // defined in the BiGraphDiagnose.h in order to avoid issues // related to preprocessing of the diagnose code. // static const String& name(); // method: setDebug // static bool8 setDebug(Integral::DEBUG debug_level) { debug_level_d = debug_level; return true; } // other debug methods // bool8 debug(const unichar* message) const; // destructor // ~BiGraph(); // default constructor // BiGraph(DstrBase::ALLOCATION alloc = DstrBase::DEF_ALLOCATION); // copy constructor // BiGraph(const BiGraph& copy_graph); // assign methods: // having the same vertex appear in two different graphs is not allowed. // thus, memory is created for copied vertices even if the graph is in // user-allocating mode! // bool8 assign(const BiGraph& copy_graph); bool8 assign(const DiGraph& copy_graph); bool8 assign(DoubleLinkedList& data, DoubleLinkedList& arcs); // method: operator= // BiGraph& operator=(const BiGraph& arg) { assign(arg); return *this; } // equality method // bool8 eq(const BiGraph& compare_graph) const; // i/o methods // int32 sofSize() const; // method: read // bool8 read(Sof& sof, int32 tag) { return read(sof, tag, name()); } bool8 read(Sof& sof, int32 tag, const String& name); // method: write // bool8 write(Sof& sof, int32 tag) const { return write(sof, tag, name()); } bool8 write(Sof& sof, int32 tag, const String& name) const; bool8 readData(Sof& sof, const String& pname = DEF_PARAM, int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = false); bool8 writeData(Sof& sof, const String& pname = DEF_PARAM) const; bool8 readDataText(Sof& sof, const String& pname = DEF_PARAM, int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = false); bool8 readDataBinary(Sof& sof); bool8 writeDataText(Sof& sof, const String& pname, DoubleLinkedList& dlist, DoubleLinkedList& alist) const; bool8 writeDataBinary(Sof& sof, const String& pname, DoubleLinkedList& dlist, DoubleLinkedList& alist) const; // method: new // void* operator new(size_t size) { return mgr_d.get(); } // method: new[] // void* operator new[](size_t size) { return mgr_d.getBlock(size); } // method: delete // void operator delete(void* ptr) { mgr_d.release(ptr); } // method: delete[] // void operator delete[](void* ptr) { mgr_d.releaseBlock(ptr); } // method: setGrowSize // static bool8 setGrowSize(int32 grow_size) { return mgr_d.setGrow(grow_size); } // other memory management methods // bool8 clear(Integral::CMODE cmode = Integral::DEF_CMODE); //--------------------------------------------------------------------------- // // class-specific public methods: // graph manipulation methods // //--------------------------------------------------------------------------- // method: insertArc // bool8 insertArc(int32 start_index, int32 end_index, bool8 is_epsilon = BiGraphArc::DEF_EPSILON, float32 weight = BiGraphArc::DEF_WEIGHT) { return insertArc(getPosition(start_index), getPosition(this->end_vertex), is_epsilon, weight); } // other arc insertion methods // bool8 insertArc(BiGraphVertex* start_vertex, BiGraphVertex* end_vertex, bool8 is_epsilon = BiGraphArc::DEF_EPSILON, float32 weight = BiGraphArc::DEF_WEIGHT); // method: removeArc // bool8 removeArc(int32 start_index, int32 end_index) { return removeArc(getPosition(start_index), getPosition(this->end_vertex)); } // other arc removal methods // bool8 removeArc(BiGraphVertex* start_vertex, BiGraphVertex* end_vertex); // insert vertex methods // BiGraphVertex* insertVertex(TObject* arg); // remove vertex methods // bool8 removeVertex(); bool8 removeVertex(TObject*& arg); // item containment methods: // bool8 find(const TObject* obj); bool8 find(const BiGraphVertex* vertex); bool8 contains(const TObject* obj) const; bool8 contains(const BiGraphVertex* vertex) const; //--------------------------------------------------------------------------- // // class-specific public methods: // graph property methods // //--------------------------------------------------------------------------- // method: getStart // BiGraphVertex* getStart() const { return start_vertex_d; } // method: getTerm // BiGraphVertex* getTerm() const { return term_vertex_d; } // this method extracts the structure of the graph and places them // in two lists. the first list contains the vertices and the second // list contains the arcs between the vertices. // bool8 get(DoubleLinkedList& data, DoubleLinkedList& arcs) const; // method: isWeighted // bool8 isWeighted() const { return is_weighted_d; } // method: setWeighted // bool8 setWeighted(bool8 is_weighted = true) { is_weighted_d = is_weighted; return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // graph ordering methods // //--------------------------------------------------------------------------- // topological sort methods // bool8 topologicalSort(DoubleLinkedList& sorted_data, bool8 partial = false); // method: getColor // Integral::COLOR getColor(const BiGraphVertex* v) const { return chash_d->get(v); } // method: setColor // bool8 setColor(const BiGraphVertex* v, Integral::COLOR col) { return chash_d->set(v, col); } // method: releaseColorHash // bool8 releaseColorHash() { chash_d->clear(Integral::RESET); if (chash_d != (BiColorHash*)NULL) { delete chash_d; chash_d = (BiColorHash*)NULL; } return true; } // other color methods // bool8 invertColor(); bool8 makeColorHash(Integral::COLOR col = Integral::DEF_COLOR); bool8 setColor(Integral::COLOR col); bool8 isColor(Integral::COLOR col); bool8 replaceColor(Integral::COLOR old_col, Integral::COLOR new_col); // methods to do simple depth first search // bool8 dfsVisit(BiGraphVertex& vertex); //--------------------------------------------------------------------------- // // class-specific public methods: // graph allocation mode methods // //--------------------------------------------------------------------------- // method: getAllocationMode // DstrBase::ALLOCATION getAllocationMode() const { return alloc_d; } // method: setAllocationMode // bool8 setAllocationMode(DstrBase::ALLOCATION alloc) { alloc_d = alloc; return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // float64 linked list methods // //--------------------------------------------------------------------------- // the BiGraph class derives the DoubleLinkedList bases class which // is used as the primary underlying container class. to prevent the // user from circumventing the BiGraph's interface and interacting // directly with the DoubleLinkedList we use private inheritance. // we define here the methods of the DoubleLinkedList interface that // the user is permitted access to. // using DoubleLinkedList< BiGraphVertex >::length; using DoubleLinkedList< BiGraphVertex >::gotoFirst; using DoubleLinkedList< BiGraphVertex >::gotoNext; using DoubleLinkedList< BiGraphVertex >::gotoPrev; using DoubleLinkedList< BiGraphVertex >::getCurr; using DoubleLinkedList< BiGraphVertex >::getFirst; using DoubleLinkedList< BiGraphVertex >::getLast; using DoubleLinkedList< BiGraphVertex >::gotoMark; using DoubleLinkedList< BiGraphVertex >::setMark; using DoubleLinkedList< BiGraphVertex >::gotoPosition; using DoubleLinkedList< BiGraphVertex >::getPosition; //--------------------------------------------------------------------------- // // private methods // //--------------------------------------------------------------------------- private: // methods to split writeData: // the readData needed to be broken up // bool8 readVertexDataText(Sof& sof_a, SofParser& parser, ReadHash& hash) const; bool8 readArcDataText(Sof& sof_a, SofParser& parser, ReadHash& hash) const; // methods to split writeData: // the writeData needed to be broken up // bool8 writeVertexDataText(Sof& sof, DoubleLinkedList& dlist) const; bool8 writeArcDataText(Sof& sof, DoubleLinkedList& alist) const; // methods for topological sort: // topological sort needs some customized DFS routines // bool8 dfsVisitTS(DoubleLinkedList& output, BiGraphVertex& vertex); }; //----------------------------------------------------------------------------- // // we define non-integral constants at the end of class definition for // templates (for non-templates these are defined in the default constructor) // //----------------------------------------------------------------------------- // constants: required constants such as the class name // template const String BiGraph::CLASS_NAME(L"BiGraph"); // constants: i/o related constants // template const String BiGraph::DEF_PARAM(L""); template const String BiGraph::PARAM_VERTICES(L"vertices"); template const String BiGraph::PARAM_ARCS(L"arcs"); template const String BiGraph::PARAM_WEIGHTED(L"weighted"); // constants: define non-integral constants in the default constructor // template const String BiGraph::START_NAME(L"S"); template const String BiGraph::TERM_NAME(L"T"); template const TObject BiGraph::START_OBJ; template const TObject BiGraph::TERM_OBJ; // static instantiations: debug level and memory manager // template Integral::DEBUG BiGraph::debug_level_d = Integral::NONE; template MemoryManager BiGraph::mgr_d(sizeof(BiGraph), CLASS_NAME); // below are all the methods for the BiGraph template class // // --------------------------------------------------------------------- // // required static methods // //---------------------------------------------------------------------- // method: name // // arguments: none // // return: a static String& containing the class name // // this method returns the class name // template const String& BiGraph::name() { // create the static name string for this class and return it // static String cname(CLASS_NAME); cname.clear(Integral::RESET); cname.concat(CLASS_NAME); cname.concat(L"<"); cname.concat(TObject::name()); cname.concat(L">"); // return the name // return cname; } // --------------------------------------------------------------------- // // required debug methods // //---------------------------------------------------------------------- // method: debug // // arguments: // const unichar* message: (input) information message // // return: a bool8 value indicating status // // this method dumps the contents of an object to the console // template bool8 BiGraph::debug(const unichar* message_a) const { // build a debug string // String val; String output; output.debugStr(name(), message_a, L""); Console::put(output); Console::increaseIndention(); // dump the this pointer // val.assign(this); output.debugStr(name(), message_a, L"this", val); Console::put(output); // dump allocation mode // output.debugStr(name(), message_a, L"alloc_d", NameMap::ALLOCATION_MAP((int32)alloc_d)); Console::put(output); // dump is_weighted // val.assign(is_weighted_d); output.debugStr(name(), message_a, L"is_weighted_d", val); Console::put(output); // dump a pointer to the start vertex // val.assign(start_vertex_d); output.debugStr(name(), message_a, L"start_vertex_d", val); Console::put(output); // print the start vertex information // start_vertex_d->debug(L"start_vertex_d"); // call the parent debug method to debug the list of vertices itself // DoubleLinkedList< BiGraphVertex >::debug(L"vertices"); // dump a pointer to the terminal vertex // val.assign(term_vertex_d); output.debugStr(name(), message_a, L"term_vertex_d", val); Console::put(output); // print the terminal vertex information // term_vertex_d->debug(L"term_vertex_d"); // that's it for sub-items, decrease indentation // Console::decreaseIndention(); // exit gracefully // return true; } //------------------------------------------------------------------------ // // required destructor/constructor(s) // //----------------------------------------------------------------------- // method: destructor // // arguments: none // // return: none // // this is the default destructor for the BiGraph class // template BiGraph::~BiGraph() { // clear the BiGraph // BiGraph::clear(Integral::RESET); // delete the start and terminal vertices // delete start_vertex_d; start_vertex_d = (BiGraphVertex*)NULL; delete term_vertex_d; term_vertex_d = (BiGraphVertex*)NULL; // delete the color hash table // if (chash_d != (BiColorHash*)NULL) { delete chash_d; chash_d = (BiColorHash*)NULL; } } // method: default constructor // // arguments: // ALLOCATION alloc: (input) allocation mode for nodes // // return: none // // this is the default constructor for the BiGraph class // template BiGraph::BiGraph(DstrBase::ALLOCATION alloc_a) { // initialize internal data // is_weighted_d = DEF_IS_WEIGHTED; // set the allocation flag // alloc_d = alloc_a; // create and initialize the start and terminal vertices // start_vertex_d = new BiGraphVertex(); term_vertex_d = new BiGraphVertex(); start_vertex_d->setItem((TObject*)&START_OBJ); term_vertex_d->setItem((TObject*)&TERM_OBJ); start_vertex_d->setParentGraph(this); term_vertex_d->setParentGraph(this); // initialize the color hash table // chash_d = (BiColorHash*)NULL; // set the allocation mode of the parent class // DoubleLinkedList< BiGraphVertex >::setAllocationMode(DstrBase::USER); } // method: copy constructor // // arguments: // BiGraph& arg: (input) the graph to copy // // return: none // // this is the copy constructor for the BiGraph class. note that having the // same vertex appear in two different graphs is not allowed. thus, memory is // created for copied vertices even if the graph is in user-allocating // mode! // template BiGraph::BiGraph(const BiGraph& copy_graph_a) { // create and initialize the start and terminal vertices // start_vertex_d = new BiGraphVertex(); term_vertex_d = new BiGraphVertex(); start_vertex_d->setItem((TObject*)&START_OBJ); term_vertex_d->setItem((TObject*)&TERM_OBJ); start_vertex_d->setParentGraph(this); term_vertex_d->setParentGraph(this); // initialize the color hash table // chash_d = (BiColorHash*)NULL; // set the allocation mode of the parent class // DoubleLinkedList< BiGraphVertex >::setAllocationMode(DstrBase::USER); // intialize the allocation flag to default // alloc_d = DstrBase::DEF_ALLOCATION; // call the copy assign method // assign(copy_graph_a); } //------------------------------------------------------------------------- // // required assign methods // //------------------------------------------------------------------------- // method: assign // // arguments: // BiGraph& copy_graph: (input) the graph to copy // // return: a bool8 value indicating status // // this is the assign method for the BiGraph class. we can't just copy // the data over since the arcs make connections by pointer (and we // can't share vertices across two graphs), hence we must manually // insert every vertex and every arc. new vertices are created, but if // the graph is in USER mode the tobject is not copied. // template bool8 BiGraph::assign(const BiGraph& arg_a) { // first cleanup the list // if (!clear(Integral::RESET)) { return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__); } // copy the weighting flag. // is_weighted_d = arg_a.is_weighted_d; // copy the allocation flag // alloc_d = arg_a.alloc_d; // save the state of the input graph // const_cast& >(arg_a).setMark(); // we need to build a cross-referencing scheme to make sure we cover // all arcs and all nodes. the (+2) is for the start and terminal // vertices since they are NOT included in the list // int32 num_vertices = arg_a.length() + 2; BiGraphVertex* copy_sym_ptrs[num_vertices]; BiGraphVertex* this_sym_ptrs[num_vertices]; // set the start and terminal vertices // copy_sym_ptrs[0] = arg_a.getStart(); copy_sym_ptrs[num_vertices - 1] = arg_a.getTerm(); // loop through the list of vertices, and number them // const_cast& >(arg_a).gotoFirst(); for (int32 i = 1; i < num_vertices - 1; i++) { // get the current node in the graph and assign it to the array // copy_sym_ptrs[i] = const_cast* > (arg_a.getCurr()); // move to the next node in the graph // const_cast& >(arg_a).gotoNext(); } // before we assign the input graph we need to clear the current graph // this->clear(Integral::RESET); // set the start and terminal vertices // this_sym_ptrs[0] = getStart(); this_sym_ptrs[num_vertices - 1] = getTerm(); for (int32 i = 1; i < num_vertices - 1; i++) { // create a new graph vertex // this_sym_ptrs[i] = this->insertVertex(copy_sym_ptrs[i]->getItem()); } // now build the arclists for each node // for (int32 i = 0; i < num_vertices; i++) { // get the vertex in question // BiGraphVertex* tmp_copy_vert = copy_sym_ptrs[i]; // loop over the copy graph's arclist // bool8 arcs_remain = tmp_copy_vert->gotoFirstChild(); while (arcs_remain) { // setup temporary variables // int32 dest_index = -1; BiGraphArc* tmp_arc = tmp_copy_vert->getCurrChild(); BiGraphVertex* dest_vertex = tmp_arc->getVertex(); // find the destination vertex index // for (int32 j = 0; j < num_vertices; j++) { if (dest_vertex == copy_sym_ptrs[j]) { dest_index = j; break; } } if (dest_index == -1) { return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__); } // link the vertices in the new graph // insertArc(this_sym_ptrs[i], this_sym_ptrs[dest_index], tmp_arc->getEpsilon(), tmp_arc->getWeight()); // goto the next arc // arcs_remain = tmp_copy_vert->gotoNextChild(); } } // put the copy graph back in its original state // const_cast& >(arg_a).gotoMark(); // exit gracefully // return true; } // method: assign // // arguments: // DiGraph& copy_graph: (input) the graph to copy // // return: a bool8 value indicating status // // this is the assign method for the BiGraph class. we can't just copy // the data over since the arcs make connections by pointer (and we // can't share vertices across two graphs), hence we must manually // insert every vertex and every arc. new vertices are created, but if // the graph is in USER mode the tobject is not copied. // template bool8 BiGraph::assign(const DiGraph& arg_a) { // first cleanup the list // if (!clear(Integral::RESET)) { return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__); } // copy the weighting flag. // is_weighted_d = arg_a.isWeighted(); // copy the allocation flag // alloc_d = arg_a.getAllocationMode(); // save the state of the input graph // const_cast& >(arg_a).setMark(); // we need to build a cross-referencing scheme to make sure we cover // all arcs and all nodes. the (+2) is for the start and terminal // vertices since they are NOT included in the list // int32 num_vertices = arg_a.length() + 2; GraphVertex* copy_sym_ptrs[num_vertices]; BiGraphVertex* this_sym_ptrs[num_vertices]; // set the start and terminal vertices // copy_sym_ptrs[0] = arg_a.getStart(); copy_sym_ptrs[num_vertices - 1] = arg_a.getTerm(); // loop through the list of vertices, and number them // const_cast& >(arg_a).gotoFirst(); for (int32 i = 1; i < num_vertices - 1; i++) { // get the current node in the graph and assign it to the array // copy_sym_ptrs[i] = const_cast* > (arg_a.getCurr()); // move to the next node in the graph // const_cast& >(arg_a).gotoNext(); } // before we assign the input graph we need to clear the current graph // this->clear(Integral::RESET); // set the start and terminal vertices // this_sym_ptrs[0] = getStart(); this_sym_ptrs[num_vertices - 1] = getTerm(); for (int32 i = 1; i < num_vertices - 1; i++) { // create a new graph vertex // this_sym_ptrs[i] = this->insertVertex(copy_sym_ptrs[i]->getItem()); } // now build the arclists for each node // for (int32 i = 0; i < num_vertices; i++) { // get the vertex in question // GraphVertex* tmp_copy_vert = copy_sym_ptrs[i]; // loop over the copy graph's arclist // bool8 arcs_remain = tmp_copy_vert->gotoFirst(); while (arcs_remain) { // setup temporary variables // int32 dest_index = -1; GraphArc* tmp_arc = tmp_copy_vert->getCurr(); GraphVertex* dest_vertex = tmp_arc->getVertex(); // find the destination vertex index // for (int32 j = 0; j < num_vertices; j++) { if (dest_vertex == copy_sym_ptrs[j]) { dest_index = j; break; } } if (dest_index == -1) { return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__); } // link the vertices in the new graph // insertArc(this_sym_ptrs[i], this_sym_ptrs[dest_index], tmp_arc->getEpsilon(), tmp_arc->getWeight()); // goto the next arc // arcs_remain = tmp_copy_vert->gotoNext(); } } // put the copy graph back in its original state // const_cast& >(arg_a).gotoMark(); // exit gracefully // return true; } // method: assign // // arguments: // DoubleLinkedList& data: (input) list of vertex data elements // DoubleLinkedList arcs: (input) list of arcs between vertices // // return: a bool8 value indicating status // // this is a quick assign method for the BiGraph class. this method takes // a ordered list of data elements for the graph vertices and a list of // of arcs that connects the vertices in the graphs. // template bool8 BiGraph::assign(DoubleLinkedList& data_a, DoubleLinkedList& arcs_a) { // declare local variables // int32 src = 0; int32 dst = 0; float32 weight = 0.0; bool8 epsilon = false; // determine if we need to do any work // if (data_a.length() == 0) { return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__); } // before we assign we need to clear the current graph // this->clear(Integral::RESET); // create vertices for the input data // BiGraphVertex* vertices[data_a.length()]; for (int i = 0; i < data_a.length(); i++) { data_a.gotoPosition(i); vertices[i] = insertVertex(data_a.getCurr()); } // loop over all elements in the arc list // for (bool8 more = arcs_a.gotoFirst(); more; more = arcs_a.gotoNext()) { // define the source and destination objects // BiGraphVertex* src_vertex; BiGraphVertex* dst_vertex; // determine the parameters of the arc // weight = (float32)arcs_a.getCurr()->second(); epsilon = (bool8)arcs_a.getCurr()->third(); src = (int32)arcs_a.getCurr()->first().first(); dst = (int32)arcs_a.getCurr()->first().second(); // check if the source is the start vertex // if (src == START_INDEX) { src_vertex = getStart(); } // check if the source is the term vertex // else if (src == TERM_INDEX) { src_vertex = getTerm(); } else { src_vertex = vertices[src]; } // check if the destination is the term vertex // if (dst == TERM_INDEX) { dst_vertex = getTerm(); } // check if the destination is the start vertex // else if (dst == START_INDEX) { dst_vertex = getStart(); } else { dst_vertex = vertices[dst]; } // insert an arc from the source to the destination vertices // insertArc(src_vertex, dst_vertex, epsilon, weight); } // exit gracefully // return true; } //------------------------------------------------------------------------ // // required i/o methods // //------------------------------------------------------------------------ // method: sofSize // // arguments: none // // return: size of object as written to disk via the i/o methods // // this method determines the size of the object on disk. it has to // nearly go through as much trouble as writing the object to // determine the exact binary size. // template int32 BiGraph::sofSize() const { // declare lists to read the graph structure // DoubleLinkedList dlist(DstrBase::USER); DoubleLinkedList alist; // start with the length // int32 bytes = is_weighted_d.sofSize(); // get the structure of the graph // this->get(dlist, alist); // add the lengths of the lists // bytes += dlist.sofSize(); bytes += alist.sofSize(); // return the size // return bytes; } // method: read // // arguments: // Sof& sof: (input) sof file object // int32 tag: (input) sof object instance tag // const String& name: (input) sof object instance name // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file // template bool8 BiGraph::read(Sof& sof_a, int32 tag_a, const String& name_a) { // get the instance of the object from the Sof file // if (!sof_a.find(name_a, tag_a)) { return false; } // read the actual data from the sof file // if (!readData(sof_a)) { return false; } // exit gracefully // return true; } // method: write // // arguments: // Sof& sof: (input) sof file object // int32 tag: (input) sof object instance tag // const String& name: (input) sof object instance name // // return: a bool8 value indicating status // // this method has the object write itself to an Sof file // template bool8 BiGraph::write(Sof& sof_a, int32 tag_a, const String& name_a) const { // declare a temporary size variable // int32 obj_size = 0; // switch on ascii or binary mode // if (sof_a.isText()) { // set the size to be dynamic // obj_size = Sof::ANY_SIZE; } else { // the size of the binary data to write // obj_size = sofSize(); } // write the object into the sof file's index // if (!sof_a.put(name_a, tag_a, obj_size)) { return false; } // exit gracefully // return writeData(sof_a); } // method: readDataText // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // int32 size: (input) size of the object // bool8 param: (input) is the parameter specified? // bool8 nested: (input) is this nested? // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file. it assumes // that the Sof file is already positioned correctly. // template bool8 BiGraph::readDataText(Sof& sof_a, const String& pname_a, int32 size_a, bool8 param_a, bool8 nested_a) { // declare local variables // String index_str; // first cleanup the list // if (!clear(Integral::RESET)) { return Error::handle(name(), L"readDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // local variables // SofParser parser; parser.setDebug(debug_level_d); // are we nested? // if (nested_a) { parser.setNest(); } // load the parse // if (!parser.load(sof_a, size_a)) { return Error::handle(name(), L"readDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // read the two flags // if (!is_weighted_d.readData(sof_a, PARAM_WEIGHTED, parser.getEntry(sof_a, PARAM_WEIGHTED))) { return Error::handle(name(), L"readDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } if (debug_level_d >= Integral::ALL) { is_weighted_d.debug(L"is this weighted?"); } // create a hash table so that we can access the graph vertices // via their indeces i.e., their positions in the graph // ReadHash hash_table(DstrBase::USER); // read in the vertex data // if (!readVertexDataText(sof_a, parser, hash_table)) { return Error::handle(name(), L"readDataText", Error::ARG, __FILE__, __LINE__); } // read in the arc data // if (!readArcDataText(sof_a, parser, hash_table)) { return Error::handle(name(), L"readDataText", Error::ARG, __FILE__, __LINE__); } // exit gracefully // return true; } // method: readData // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // int32 size: (input) size of the object // bool8 param: (input) is the parameter specified? // bool8 nested: (input) is this nested? // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file. it assumes // that the Sof file is already positioned correctly. // template bool8 BiGraph::readData(Sof& sof_a, const String& pname_a, int32 size_a, bool8 param_a, bool8 nested_a) { // when we are reading text data // if (sof_a.isText()) { return readDataText(sof_a, pname_a, size_a, param_a, nested_a); } // when we are reading binary data // else { return readDataBinary(sof_a); } } // method: writeData // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // // return: a bool8 value indicating status // // this method writes the object to the Sof file. it assumes that the // Sof file is already positioned correctly. // template bool8 BiGraph::writeData(Sof& sof_a, const String& pname_a) const { // declare local variables and structures to read the graph // bool8 status = false; DoubleLinkedList dlist(DstrBase::USER); DoubleLinkedList alist; // read the current structure of the graph // this->get(dlist, alist); // when we are writing text data // if (sof_a.isText()) { status = writeDataText(sof_a, pname_a, dlist, alist); } // when we are writing binary data // else { status = writeDataBinary(sof_a, pname_a, dlist, alist); } // exit gracefully // return status; } // method: readDataBinary // // arguments: // Sof& sof: (input) sof file object // // return: a bool8 value indicating status // // this method has the object read itself from an Sof file. it assumes // that the Sof file is already positioned correctly. // template bool8 BiGraph::readDataBinary(Sof& sof_a) { // declare some lists to read the data from // DoubleLinkedList dlist; DoubleLinkedList alist; // first cleanup the list // if (!clear(Integral::RESET)) { return Error::handle(name(), L"readDataBinary", Error::ARG, __FILE__, __LINE__); } // read the list graph vertex elements // dlist.readData(sof_a); // read the list of graph arcs and weights // alist.readData(sof_a); // create a graph using the list of vertex elements and arcs // this->assign(dlist, alist); // exit gracefully // return true; } // method: writeDataText // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // DoubleLinkedList& dlist: (input) graph vertex elements // DoubleLinkedList& alist: (input) graph topology // // return: a bool8 value indicating status // // this method writes the object to the Sof file. it assumes that the // Sof file is already positioned correctly. // template bool8 BiGraph::writeDataText(Sof& sof_a, const String& pname_a, DoubleLinkedList& data_a, DoubleLinkedList& arcs_a) const { // write a start string if necessary // sof_a.writeLabelPrefix(pname_a); // first write the flags // is_weighted_d.writeData(sof_a, PARAM_WEIGHTED); // first write the vertices data (this includes subgraph indexing) // writeVertexDataText(sof_a, data_a); // now write the arcs // writeArcDataText(sof_a, arcs_a); // put an end string if necessary // sof_a.writeLabelSuffix(pname_a); // exit gracefully // return true; } // method: writeDataBinary // // arguments: // Sof& sof: (input) sof file object // const String& pname: (input) parameter name // DoubleLinkedList& dlist: (input) graph vertex elements // DoubleLinkedList& alist: (input) graph topology // // return: a bool8 value indicating status // // this method writes the object to the Sof file. it assumes that the // Sof file is already positioned correctly. // template bool8 BiGraph::writeDataBinary(Sof& sof_a, const String& pname_a, DoubleLinkedList& data_a, DoubleLinkedList& arcs_a) const { // write the graph vertex elements // data_a.writeData(sof_a, pname_a); // write the graph arcs and weights // arcs_a.writeData(sof_a, pname_a); // exit gracefully // return true; } //------------------------------------------------------------------------- // // required equality method // //------------------------------------------------------------------------- // method: eq // // arguments: // const BiGraph& graph: (input) the graph to compare // // return: bool8 value indicating test of equivalence // // this method compares two graph to see if they are equal. it can't // just call list-equality since all vertex pointers will be // different. // template bool8 BiGraph::eq(const BiGraph& graph_a) const { // create lists to extract the graph structures // DoubleLinkedList this_dlist; DoubleLinkedList this_alist; DoubleLinkedList input_dlist; DoubleLinkedList input_alist; // extract the structure of the current list // this->get(this_dlist, this_alist); // extract the structure of the input list // graph_a.get(input_dlist, input_alist); // compare the lists for quality // if (!this_dlist.eq(input_dlist)) { return false; } if (!this_alist.eq(input_alist)) { return false; } // we have reached this far so the graphs have to be equal // return true; } //------------------------------------------------------------------------- // // required clear methods // //------------------------------------------------------------------------- // method: clear // // arguments: // Integral::CMODE cmode_a: (input) clear mode // // return: a bool8 value indicating status // // this method clears the reference to the internal data. // template bool8 BiGraph::clear(Integral::CMODE cmode_a) { // for RETAIN mode, call clear on every object but do not change // topology. for FREE mode we also need to call clear(FREE) on all // TObjects, but we will also delete the topology below. // if ((cmode_a == Integral::RETAIN) || (cmode_a == Integral::FREE)) { for (bool8 more = gotoFirst(); more; more = gotoNext()) { ((TObject*)(getCurr()->getItem()))->clear(cmode_a); } } // for RETAIN mode we are done, make no changes to topology // if (cmode_a == Integral::RETAIN) { return true; } // remove all of the vertices from the start and term vertices // start_vertex_d->removeAllArcsChild(); term_vertex_d->removeAllArcsParent(); // when the graph is in SYSTEM-allocation mode we need to iterate over // all vertices in the graph and delete the objects // if ((getAllocationMode() == DstrBase::SYSTEM) || (cmode_a == Integral::FREE)) { for (bool8 more = gotoFirst(); more; more = gotoNext()) { // delete the TObject // delete getCurr()->getItem(); // set the pointer to null // ((BiGraphVertex*)getCurr())->setItem((TObject*)NULL); } } // clear the vertex list // DoubleLinkedList< BiGraphVertex >::setAllocationMode(DstrBase::SYSTEM); DoubleLinkedList< BiGraphVertex >::clear(Integral::RESET); DoubleLinkedList< BiGraphVertex >::setAllocationMode(DstrBase::USER); // exit gracefully // return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // insert/remove arc methods // //--------------------------------------------------------------------------- // method: insertArc // // arguments: // BiGraphVertex* start_vertex: (input) the start vertex // BiGraphVertex* end_vertex: (input) the ending vertex // bool8 is_epsilon: (input) is the arc an epsilon transition // float32 weight: (input) the weight on the arc (if any) // // return: a bool8 value indicating status // // this method inserts an arc between two vertices in the graph provided // that the two vertices are already present in the graph // template bool8 BiGraph::insertArc(BiGraphVertex* start_vertex_a, BiGraphVertex* end_vertex_a, bool8 is_epsilon_a, float32 weight_a) { // make sure neither vertex is NULL // if ((start_vertex_a == (BiGraphVertex*)NULL) || (end_vertex_a == (BiGraphVertex*)NULL)) { return Error::handle(name(), L"insertArc", Error::NULL_ARG, __FILE__, __LINE__); } // we don't allow connections between graphs so make sure the parent graph // for both vertices is either already this graph or is null // if (((start_vertex_a->getParentGraph() != (BiGraph*)NULL) && (start_vertex_a->getParentGraph() != this)) || ((end_vertex_a->getParentGraph() != (BiGraph*)NULL) && (end_vertex_a->getParentGraph() != this))) { return Error::handle(name(), L"insertArc", ERR_MULPAR, __FILE__, __LINE__); } // make sure that the start vertex and end vertex are already in the graph // if (start_vertex_a->getParentGraph() != this) { if ((start_vertex_a != start_vertex_d) && (start_vertex_a != term_vertex_d)) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } } if (end_vertex_a->getParentGraph() != this) { if ((end_vertex_a != start_vertex_d) && (end_vertex_a != term_vertex_d)) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } } // set the parent pointers regardless - this may be redundant but it is // probably no less efficient than putting an if statement around it // start_vertex_a->setParentGraph(this); end_vertex_a->setParentGraph(this); // add an arc from the start to the end in the child list // bool8 return_val = start_vertex_a->insertArcChild(end_vertex_a, weight_a, is_epsilon_a); // add an arc from the end to the start in the parent list // return_val &= end_vertex_a->insertArcParent(start_vertex_a, weight_a, is_epsilon_a); // exit gracefully // return return_val; } // method: removeArc // // arguments: // BiGraphVertex* start_vertex: (input) the start vertex // BiGraphVertex* end_vertex: (input) the ending vertex // // return: a bool8 value indicating status // // this method removes an arc between two vertices from the graph structure // template bool8 BiGraph::removeArc(BiGraphVertex* start_vertex_a, BiGraphVertex* end_vertex_a) { // make sure neither vertex is NULL // if ((start_vertex_a == (BiGraphVertex*)NULL) || (end_vertex_a == (BiGraphVertex*)NULL)) { return Error::handle(name(), L"removeArc", Error::NULL_ARG, __FILE__, __LINE__); } // we don't allow connections between graphs so make sure the parent graph // for both vertices is either already this graph or is null // if (((start_vertex_a->getParentGraph() != (BiGraph*)NULL) && (start_vertex_a->getParentGraph() != this)) || ((end_vertex_a->getParentGraph() != (BiGraph*)NULL) && (end_vertex_a->getParentGraph() != this))) { return Error::handle(name(), L"removeArc", ERR_MULPAR, __FILE__, __LINE__); } // make sure that the start vertex and end vertex are already in the graph // if (start_vertex_a->getParentGraph() != this) { if ((start_vertex_a != start_vertex_d) && (start_vertex_a != term_vertex_d)) { return Error::handle(name(), L"removeArc", Error::ARG, __FILE__, __LINE__); } } if (end_vertex_a->getParentGraph() != this) { if ((end_vertex_a != start_vertex_d) && (end_vertex_a != term_vertex_d)) { return Error::handle(name(), L"removeArc", Error::ARG, __FILE__, __LINE__); } } // remove the arc from the start to the end in the child list // bool8 return_val = start_vertex_a->removeArcChild(end_vertex_a); // remove the arc from the end to the start in the parent list // return_val &= end_vertex_a->removeArcParent(start_vertex_a); // exit gracefully // return return_val; } //--------------------------------------------------------------------------- // // class-specific public methods: // graph property methods // //--------------------------------------------------------------------------- // method: get // // arguments: // DoubleLinkedList& dlist: (input) graph vertex elements // DoubleLinkedList& alist: (input) graph topology // // return: a bool8 value indicating status // // this method reads the current graph structure into two lists and a // hash table. The first list contains all data elements in the graph // vertices and the second list contains information regarding the // graph arcs. // template bool8 BiGraph::get(DoubleLinkedList& data_a, DoubleLinkedList& arcs_a) const { // declare local variables and structures // Long index; Long src_pos; Long dst_pos; Float weight; Boolean epsilon(false); BiGraphArc* arc; BiGraphVertex* svert; BiGraphVertex* dvert; HashTable, Long> khash; // initialize the index // index = 0; // iterate over all vertices in the graph // for (bool8 more = const_cast* >(this)->gotoFirst(); more; more = const_cast* >(this)->gotoNext()) { // add the vertex to the dlist // data_a.insert((TObject*)(const_cast* > (this)->getCurr()->getItem())); // associate a unique number with the vertex // BiGVKey hashkey(this->getCurr()); khash.insert(hashkey, &index); // increment the vertex index // index = (int32)index + 1; } // iterate over all out going arcs from the start vertex // for (bool8 arcs = const_cast* > (start_vertex_d)->gotoFirstChild(); arcs; arcs = const_cast* > (start_vertex_d)->gotoNextChild()) { // retrieve the current arc // arc = start_vertex_d->getCurrChild(); // get the arc weight // weight = arc->getWeight(); // get the epsilon flag // epsilon = arc->getEpsilon(); // get the destination vertex // dvert = arc->getVertex(); // get the position of the source vertex // Long index(this->START_INDEX); src_pos = index; // get the position of the destination vertex // if (dvert == this->getStart()) { Long index(this->START_INDEX); dst_pos = index; } else if (dvert == this->getTerm()) { Long index(this->TERM_INDEX); dst_pos = index; } else { BiGVKey dst_key(dvert); dst_pos = *(khash.get(dst_key)); } // add the parameters to the alist // Pair pair(src_pos, dst_pos); TopoTriple triple(pair, weight, epsilon); arcs_a.insert(&triple); } // iterate over all vertices in the graph // for (bool8 more = const_cast* >(this)->gotoFirst(); more; more = const_cast* >(this)->gotoNext()) { // retrieve the current source vertex // svert = (BiGraphVertex*)const_cast* > (this)->getCurr(); // iterate over all out going arcs in the current vertex // for (bool8 arcs = svert->gotoFirstChild(); arcs; arcs = svert->gotoNextChild()) { // retrieve the current arc // arc = svert->getCurrChild(); // get the arc weight // weight = arc->getWeight(); // get the epsilon flag // epsilon = arc->getEpsilon(); // get the destination vertex // dvert = arc->getVertex(); // get the position of the source vertex // if (svert == this->getStart()) { Long index(this->START_INDEX); src_pos = index; } else if (svert == this->getTerm()) { Long index(this->TERM_INDEX); src_pos = index; } else { BiGVKey src_key(svert); src_pos = *(khash.get(src_key)); } // get the position of the destination vertex // if (dvert == this->getStart()) { Long index(this->START_INDEX); dst_pos = index; } else if (dvert == this->getTerm()) { Long index(this->TERM_INDEX); dst_pos = index; } else { BiGVKey dst_key(dvert); dst_pos = *(khash.get(dst_key)); } // add the parameters to the arcs_a // Pair pair(src_pos, dst_pos); TopoTriple triple(pair, weight, epsilon); arcs_a.insert(&triple); } } // iterate over all out going arcs from the destination vertex // for (bool8 arcs = term_vertex_d->gotoFirstChild(); arcs; arcs = term_vertex_d->gotoNextChild()) { // retrieve the current arc // arc = term_vertex_d->getCurrChild(); // get the arc weight // weight = arc->getWeight(); // get the epsilon flag // epsilon = arc->getEpsilon(); // get the destination vertex // dvert = arc->getVertex(); // get the position of the source vertex // Long index(this->TERM_INDEX); src_pos = index; // get the position of the destination vertex // if (dvert == this->getStart()) { Long index(this->START_INDEX); dst_pos = index; } else if (dvert == this->getTerm()) { Long index(this->TERM_INDEX); dst_pos = index; } else { BiGVKey dst_key(dvert); dst_pos = *(khash.get(dst_key)); } // add the parameters to the alist // Pair pair(src_pos, dst_pos); Triple, Float, Boolean> triple(pair, weight, epsilon); arcs_a.insert(&triple); } // exit gracefully // return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // insert/remove vertex methods // //--------------------------------------------------------------------------- // method: insertVertex // // arguments: // TObject* obj: (input) object to insert // // return: a BiGraphVertex* containing the objected to be added // // this method inserts a new object on the graph and return the created // vertex // template BiGraphVertex* BiGraph::insertVertex(TObject* obj_a) { // perform error checking // if (obj_a == (TObject*)NULL) { Error::handle(name(), L"insertVertex", Error::ARG, __FILE__, __LINE__); return (BiGraphVertex*)NULL; } // declare local variables and allocate a new BiGraphVertex object // TObject* new_obj = (TObject*)NULL; BiGraphVertex* v = new BiGraphVertex(); // when the graph is in SYSTEM mode make a copy of the object // if (getAllocationMode() == DstrBase::SYSTEM) { new_obj = new TObject(*obj_a); } // assign the object pointer when in USER mode // else { new_obj = obj_a; } // set the object on vertex // v->setItem(new_obj); // set the parent graph for the vertex // v->setParentGraph(this); // add vertex on the graph // DoubleLinkedList< BiGraphVertex >::insert(v); // exit gracefully // return v; } // method: removeVertex // // arguments: // // return: a BiGraphVertex* containing the objected to be added // // this method removes the current vertex from the graph // template bool8 BiGraph::removeVertex() { // declare local variables // BiGraphVertex* vertex; // make sure the current vertex is valid // if (this->getCurr() == (BiGraphVertex*)NULL) { return Error::handle(name(), L"removeVertex", Error::ARG, __FILE__, __LINE__); } // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*)this->getCurr(); // when in SYSTEM mode make a copy of the object data // if (getAllocationMode() == DstrBase::SYSTEM) { delete this_vertex->getItem(); } // save the current state so we can return to the node after we // search for other arcs. // this->setMark(); // if the start vertex points to the vertex we are about to delete // then remove the arc // BiGraphVertex* start_vertex = this->getStart(); for (bool8 morea = start_vertex->gotoFirstChild(); morea; morea = start_vertex->gotoNextChild()) { if (this_vertex == start_vertex->getCurrChild()->getVertex()) { start_vertex->removeArcChild(); } } for (bool8 morea = start_vertex->gotoFirstParent(); morea; morea = start_vertex->gotoNextParent()) { if (this_vertex == start_vertex->getCurrParent()->getVertex()) { start_vertex->removeArcParent(); } } // if the term vertex points to the vertex we are about to delete // then remove the arc // BiGraphVertex* term_vertex = this->getTerm(); for (bool8 morea = term_vertex->gotoFirstChild(); morea; morea = term_vertex->gotoNextChild()) { if (this_vertex == term_vertex->getCurrChild()->getVertex()) { term_vertex->removeArcChild(); } } for (bool8 morea = term_vertex->gotoFirstParent(); morea; morea = term_vertex->gotoNextParent()) { if (this_vertex == term_vertex->getCurrParent()->getVertex()) { term_vertex->removeArcParent(); } } // now search for all arcs comming into this vertex so they can be // removed. // for (bool8 moren = gotoFirst(); moren; moren = gotoNext()) { // retrieve the current vertex // vertex = (BiGraphVertex*)this->getCurr(); // iterate over all arcs in the current vertex // for (bool8 morea = vertex->gotoFirstChild(); morea; morea = vertex->gotoNextChild()) { // if the destination vertex is the same as the vertex we are // about to delete then remove the arc // if (this_vertex == vertex->getCurrChild()->getVertex()) { vertex->removeArcChild(); } } // iterate over all arcs in the current vertex // for (bool8 morea = vertex->gotoFirstParent(); morea; morea = vertex->gotoNextParent()) { // if the destination vertex is the same as the vertex we are // about to delete then remove the arc // if (this_vertex == vertex->getCurrParent()->getVertex()) { vertex->removeArcParent(); } } } // restore the previous state. this is the vertex we will actually // remove. // this->gotoMark(); // remove the object from the linked list // bool8 status = false; BiGraphVertex* graph_vertex; status = DoubleLinkedList< BiGraphVertex >::remove(graph_vertex); delete graph_vertex; return status; } // method: removeVertex // // arguments: // TObject* obj: (input) object to remove // // return: a BiGraphVertex* containing the objected to be added // // this method removes the current vertex from the graph and // outputs the objects contained in the deleted vertex // template bool8 BiGraph::removeVertex(TObject*& obj_a) { // make sure the current vertex is valid // if (this->getCurr() == (BiGraphVertex*)NULL) { return Error::handle(name(), L"removeVertex", Error::ARG, __FILE__, __LINE__); } // make sure memory is allocated if we are SYSTEM-allocated // if ((alloc_d == DstrBase::SYSTEM) && (obj_a == (TObject*)NULL)) { return (Error::handle(name(), L"removeVertex", Error::NULL_ARG, __FILE__, __LINE__)); } // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*)this->getCurr(); // when in SYSTEM mode make a copy of the object data // if (getAllocationMode() == DstrBase::SYSTEM) { obj_a->assign(*this_vertex->getItem()); delete this_vertex->getItem(); } // when in USER mode assign the object pointer // else { obj_a = this_vertex->getItem(); } // remove all outgoing arcs from the vertex // this_vertex->removeAllArcsChild(); // save the current state so we can return to the node after we // search for other arcs. // this->setMark(); // if the start vertex points to the vertex we are about to delete // then remove the arc // BiGraphVertex* start_vertex = this->getStart(); for (bool8 morea = start_vertex->gotoFirstChild(); morea; morea = start_vertex->gotoNextChild()) { if (this_vertex == start_vertex->getCurrChild()->getVertex()) { start_vertex->removeArcChild(); } } for (bool8 morea = start_vertex->gotoFirstParent(); morea; morea = start_vertex->gotoNextParent()) { if (this_vertex == start_vertex->getCurrParent()->getVertex()) { start_vertex->removeArcParent(); } } // if the term vertex points to the vertex we are about to delete // then remove the arc // BiGraphVertex* term_vertex = this->getTerm(); for (bool8 morea = term_vertex->gotoFirstChild(); morea; morea = term_vertex->gotoNextChild()) { if (this_vertex == term_vertex->getCurrChild()->getVertex()) { term_vertex->removeArcChild(); } } for (bool8 morea = term_vertex->gotoFirstParent(); morea; morea = term_vertex->gotoNextParent()) { if (this_vertex == term_vertex->getCurrParent()->getVertex()) { term_vertex->removeArcParent(); } } // now search for all arcs comming into this vertex so they can be // removed. // for (bool8 moren = gotoFirst(); moren; moren = gotoNext()) { // retrieve the current vertex // BiGraphVertex* vertex = (BiGraphVertex*)this->getCurr(); // iterate over all arcs in the current vertex // for (bool8 morea = vertex->gotoFirstChild(); morea; morea = vertex->gotoNextChild()) { // if the destination vertex is the same as the vertex we are // about to delete then remove the arc // if (this_vertex == vertex->getCurrChild()->getVertex()) { vertex->removeArcChild(); } } // iterate over all arcs in the current vertex // for (bool8 morea = vertex->gotoFirstParent(); morea; morea = vertex->gotoNextParent()) { // if the destination vertex is the same as the vertex we are // about to delete then remove the arc // if (this_vertex == vertex->getCurrParent()->getVertex()) { vertex->removeArcParent(); } } } // restore the previous state. this is the vertex we will actually // remove. // this->gotoMark(); // remove the object from the linked list // bool8 status = false; BiGraphVertex* graph_vertex; status = DoubleLinkedList< BiGraphVertex >::remove(graph_vertex); delete graph_vertex; return status; } // method: contains // // arguments: // TObject* obj: (input) the object to be found // // return: a bool8 value indicating status // // this method determines if the input object is in the list of vertices // template bool8 BiGraph::contains(const TObject* obj_a) const { // check if the input object is NULL // if (obj_a == (TObject*)NULL) { return Error::handle(name(), L"contains", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // const_cast* >(this)->setMark(); // temporary variables // bool8 obj_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!obj_found && more_nodes) { // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*) const_cast* >(this)->getCurr(); // get the object contained in the vertex // TObject* this_obj = this_vertex->getItem(); // compare the objects for equality // obj_found = obj_a->eq(*this_obj); if (!obj_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous position // const_cast* >(this)->gotoMark(); // return whether or not the object was found // return obj_found; } // method: contains // // arguments: // BiGraphVertex* vertex: (input) the vertex to be found // // return: a bool8 value indicating status // // this method determines if the input vertex is in the list of // vertices. note that we can't just call list contains since we only // want to compare pointers, not values. // template bool8 BiGraph::contains(const BiGraphVertex* vertex_a) const { // check if the input object is NULL // if (vertex_a == (BiGraphVertex*)NULL) { return Error::handle(name(), L"contains", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // const_cast* >(this)->setMark(); // temporary variables // bool8 vertex_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!vertex_found && more_nodes) { // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*) const_cast* >(this)->getCurr(); // compare the pointers for equality // if (this_vertex == vertex_a) { vertex_found = true; } if (!vertex_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous state // const_cast* >(this)->gotoMark(); // return whether or not the object was found // return vertex_found; } // method: find // // arguments: // TObject* obj: (input) the object to be found // // return: a bool8 value indicating status // // this method determines if the input object is in the list of vertices // and moves the list current pointer to the first occurance of the object // template bool8 BiGraph::find(const TObject* obj_a) { // check if the input object is NULL // if (obj_a == (TObject*)NULL) { return Error::handle(name(), L"find", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // this->setMark(); // temporary variables // bool8 obj_found = false; bool8 more_nodes = this->gotoFirst(); // search from the beginning for the item // while (!obj_found && more_nodes) { // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*)this->getCurr(); // get the object contained in the vertex // TObject* this_obj = this_vertex->getItem(); // compare the objects for equality // obj_found = obj_a->eq(*this_obj); if (!obj_found) { more_nodes = this->gotoNext(); } } if (!obj_found) { this->gotoMark(); } // return whether or not the object was found // return obj_found; } // method: find // // arguments: // BiGraphVertex* vertex: (input) the vertex to be found // // return: a bool8 value indicating status // // this method determines if the input vertex is in the list of // vertices. if found the vertex list is left pointing to the // vertex. note that we can't just call list contains since we only // want to compare pointers, not values. // template bool8 BiGraph::find(const BiGraphVertex* vertex_a) { // check if the input object is NULL // if (vertex_a == (BiGraphVertex*)NULL) { return Error::handle(name(), L"find", Error::NULL_ARG, __FILE__, __LINE__); } // save the current position // const_cast* >(this)->setMark(); // temporary variables // bool8 vertex_found = false; bool8 more_nodes = const_cast* >(this)->gotoFirst(); // search from the beginning for the item // while (!vertex_found && more_nodes) { // get the current vertex // BiGraphVertex* this_vertex = (BiGraphVertex*) const_cast* >(this)->getCurr(); // compare the pointers for equality // if (this_vertex == vertex_a) { vertex_found = true; } if (!vertex_found) { more_nodes = const_cast* >(this)->gotoNext(); } } // restore the previous state if the vertex was not found // if (!vertex_found) { const_cast* >(this)->gotoMark(); } // return whether or not the object was found // return vertex_found; } //--------------------------------------------------------------------------- // // class-specific public methods: // graph ordering methods // //--------------------------------------------------------------------------- // method: topologicalSort // // arguments: // DoubleLinkedList& output: (output) sorted list of data // bool8 partial: (input) sort only white nodes? // // return: a bool8 value indicating status // // this method performs a topological sort on the graph and returns // a sorted list of the data. the algorithm, "topological sort" using depth // first search, is taken from: // // T. Cormen, C. Leiserson, R. Rivest, "Exercise 23.4-1", // Introduction to Algorithms, MIT Press, Boston, Massachusetts, USA, // pp. 485, 1998. // // Modified to allow the graph to not be fully // initialized to WHITE upon initialization so partial graphs can be analyzed. // template bool8 BiGraph::topologicalSort(DoubleLinkedList& output_a, bool8 partial_a) { // make sure the color hash table is allocated // if (chash_d == (BiColorHash*)NULL) { Error::handle(name(), L"topologicalSort", Error::ARG, __FILE__, __LINE__); return false; } // if partial is true, then we assume that the color of all graph // nodes is already set as the user wants. this means that only // nodes that start out white will make it onto the output list. if // partial is false it performs a full search, hence it must // initialize all nodes to white. // if (!partial_a) { setColor(Integral::WHITE); } // run a depth first search that builds the list as it visits each // node. // for (bool8 more = gotoFirst(); more; more = gotoNext()) { BiGraphVertex* vertex = (BiGraphVertex*)getCurr(); if (getColor(vertex) == Integral::WHITE) { dfsVisitTS(output_a, *vertex); } } // exit gracefully // return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // graph color methods // //--------------------------------------------------------------------------- // method: invertColor // // arguments: none // // return: a bool8 value indicating status // // invert the color of all nodes. any black node will become white, // any non-black node will become black. this is useful for pruning // before topological sorts. // template bool8 BiGraph::invertColor() { // make sure the color hash table is allocated // if (chash_d == (BiColorHash*)NULL) { Error::handle(name(), L"invertColor", Error::ARG, __FILE__, __LINE__); return false; } // loop through all vertices // for (bool8 more_nodes = gotoFirst(); more_nodes; more_nodes = gotoNext()) { if (chash_d->get(getCurr()) == Integral::BLACK) { chash_d->set(getCurr(), Integral::WHITE); } else { chash_d->set(getCurr(), Integral::BLACK); } } // exit gracefully // return true; } // method: makeColorHash // // arguments: // Integral::COLOR col: (input) color to initialize the vertices // // return: a bool8 value indicating status // // this method creates a hash table of vertices and initializes all // vertices in the hash table to the given color // template bool8 BiGraph::makeColorHash(Integral::COLOR col_a) { // allocate memory to the color hash table // if (chash_d != (BiColorHash*)NULL) { Error::handle(name(), L"makeColorHash", Error::ARG, __FILE__, __LINE__); return false; } else { chash_d = new BiColorHash(); } // iterate over all vertices in the graph // for (bool8 more_nodes = gotoFirst(); more_nodes; more_nodes = gotoNext()) { chash_d->insert(getCurr(), col_a); } // add the start and term vertices // chash_d->insert(getStart(), col_a); chash_d->insert(getTerm(), col_a); // exit gracefully // return true; } // method: setColor // // arguments: // Integral::COLOR col: (input) color to initialize the vertices // // return: a bool8 value indicating status // // this method sets all vertices to a specified color // template bool8 BiGraph::setColor(Integral::COLOR col_a) { // make sure the color hash table is allocated // if (chash_d == (BiColorHash*)NULL) { Error::handle(name(), L"setColor", Error::ARG, __FILE__, __LINE__); return false; } // loop over all vertices // for (bool8 more_nodes = gotoFirst(); more_nodes; more_nodes = gotoNext()) { // set the color // chash_d->set(getCurr(), col_a); } // exit gracefully // return true; } // method: isColor // // arguments: // Integral::COLOR col: (input) color we match against // // return: a bool8 value indicating status // // are all nodes the specified color? // template bool8 BiGraph::isColor(Integral::COLOR col_a) { // make sure the color hash table is allocated // if (chash_d == (BiColorHash*)NULL) { Error::handle(name(), L"isColor", Error::ARG, __FILE__, __LINE__); return false; } // loop over all vertices // for (bool8 more = gotoFirst(); more; more = gotoNext()) { // get the color and compare // if (chash_d->get(getCurr()) != col_a) { return false; } } // exit gracefully // return true; } // method: replaceColor // // arguments: // BiGraphVertex::COLOR old_col: (input) old color to search for // BiGraphVertex::COLOR new_col: (input) new color to assign to // // return: a bool8 value indicating status // // change the color of all nodes that are currently old_col to new_col. // template bool8 BiGraph::replaceColor(Integral::COLOR old_col_a, Integral::COLOR new_col_a) { // make sure the color hash table is allocated // if (chash_d == (BiColorHash*)NULL) { Error::handle(name(), L"replaceColor", Error::ARG, __FILE__, __LINE__); return false; } // loop through all vertices // for (bool8 more = gotoFirst(); more; more = gotoNext()) { // if this node is old_color, set it to new_color // if (chash_d->get(getCurr()) == old_col_a) { chash_d->set(getCurr(), new_col_a); } } // exit gracefully // return true; } // method: dfsVisitTS // // arguments: // DoubleLinkedList& output: (output) sorted list of data // BiGraphVertex& v: (input) vertex to visit // // return: a bool8 value indicating status // // this method performs a topological sort on the graph and returns // a sorted list of the data. // template bool8 BiGraph::dfsVisitTS(DoubleLinkedList& output_a, BiGraphVertex& v_a) { // set the color of this vertex to gray // setColor(&v_a, Integral::GREY); // loop over all arcs starting from this node // for (bool8 more = v_a.gotoFirstChild(); more; more = v_a.gotoNextChild()) { // if this vertex is white, expand it // BiGraphVertex* vertex = v_a.getCurrChild()->getVertex(); if (getColor(vertex) == Integral::WHITE) { dfsVisitTS(output_a, *vertex); } } // since all arcs have been visited, set vertex to black // chash_d->set(&v_a, Integral::BLACK); // prepend the data to the output list // output_a.insertFirst(v_a.getItem()); // exit gracefully // return true; } // method: dfsVisit // // arguments: // BiGraphVertex& v: (input) vertex to visit // // return: a bool8 value indicating status // // "depth-first-search" taken from: // // T. Cormen, C. Leiserson, R. Rivest, "Exercise 23.4-1", // Introduction to Algorithms, MIT Press, Boston, Massachusetts, USA, // pp. 478, 1998. // // this method performs a depth-first-search visit for this node. it // leaves the graph with all nodes reachable from the starting node // colored black. // template bool8 BiGraph::dfsVisit(BiGraphVertex& v_a) { // set the color of this vertex to grey // setColor(&v_a, Integral::GREY); // loop over all arcs starting from this node // for (bool8 more = v_a.gotoFirst(); more; more = v_a.gotoNext()) { // if the node is white it has not been seen before, so // recursively call the dfsVisit method. // BiGraphVertex* vertex = v_a.getCurr()->getVertex(); if (chash_d->get(vertex) == Integral::WHITE) { dfsVisit(*vertex); } } // since all arcs have been visited, set vertex to black // chash_d->set(&v_a, Integral::BLACK); // exit gracefully // return true; } // method: readVertexDataText // // arguments: // Sof& sof: (input) sof file // SofParser parser: (input) sof parser // ReadHash hash_table: (input) mapping between vertex and index position // // return: a bool8 value indicating status // // write out the vertex data for this graph // template bool8 BiGraph::readVertexDataText(Sof& sof_a, SofParser& parser_a, ReadHash& hash_table_a) const { // declare local variables // String index_str; // the following is an example of the format used to write the // graph vertices to file in text mode. // // vertices = // {0, {\a}}, // {1, {\b}}, // {2, {\c}}, // {3, {\d}}, // {4, {\e}}, // {5, {\f}}, // {6, {\g}}; // // read the vertices // Long new_size((int32)0); // read the number of 'vertices' in the above example we have // seven vertices in the graph // new_size = parser_a.countTokens(PARAM_VERTICES); if (debug_level_d >= Integral::DETAILED) { new_size.debug(L"reading this many vertices"); } // insert the start vertex into the hash table // index_str.assign(START_INDEX); hash_table_a.insert(index_str, this->getStart()); // insert the term vertex into the hash table // index_str.assign(TERM_INDEX); hash_table_a.insert(index_str, this->getTerm()); // read the vertices one node at a time // for (int32 i = 0; i < new_size; i++) { // we need a sub-parser to read the vertices. // SofParser sub_parser; sub_parser.setNest(); sub_parser.setImplicitParam(); sub_parser.load(sof_a, parser_a.getEntry(sof_a, PARAM_VERTICES, i, 1)); // first read the index number // sub_parser.setNest(); sub_parser.setImplicitParam(); // read the number of tokens in the vertex entry i.e., in the // example above the entry: {0, {\a}}, has two tokens // int32 num_tok = sub_parser.countTokens(parser_a.implicitPname()); if (num_tok != 2) { return Error::handle(name(), L"readVertexDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // read the position of the vertex in the underlying list // container i.e., in the example above the entry: {0, {\a}}, // has a position of '0' in the list container class // if (!sub_parser.read(index_str, sof_a, sub_parser.getEntry(sof_a, parser_a.implicitPname(), 0, 1))) { return false; } if (debug_level_d >= Integral::ALL) { index_str.debug(L"read this index"); } sub_parser.setNest(); sub_parser.setImplicitParam(); // read the number of bytes of the vertex data element i.e., // in the example above we read the number of bytes of: '\a' // int32 vertex_len = sub_parser.getEntry(sof_a, parser_a.implicitPname(), 1, 1); // read the vertex data. note that we build the vertex by hand // instead of calling insertVertex since we always have to // allocate the memory. if we called insertVertex there might be // a wasted copy if the graph was in SYSTEM mode. // BiGraphVertex* v = new BiGraphVertex(); v->setParentGraph(const_cast* >(this)); TObject* data = new TObject; // read the vertex data element .i.e., in the example above // we read the character 'a' in: {0, {\a}}, // if (!data->readData(sof_a, DEF_PARAM, vertex_len, false, true)) { return Error::handle(name(), L"readVertexDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // set the data element of the vertex we created to the one // that we parsed from the text file // v->setItem(data); if (debug_level_d >= Integral::ALL) { v->debug(L"read this vertex"); } // add the vertex to the graph // const_cast* > (this)->DoubleLinkedList< BiGraphVertex >::insert(v); // place the vertex onto a HashTable for reference // hash_table_a.insert(index_str, v); } // exit gracefully // return true; } // method: readArcDataText // // arguments: // Sof& sof: (input) sof file // SofParser parser: (input) sof parser // ReadHash& hash_table: (input) mapping between vertex and index // // return: a bool8 value indicating status // // read in the arc data for this graph // template bool8 BiGraph::readArcDataText(Sof& sof_a, SofParser& parser_a, ReadHash& hash_table_a) const { // declare local variables // String index_str; // the following is an example of the format used to write the // graph arcs to file in text mode. where 'S' and 'T' denote // the start and term nodes and 'true' denotes a epsilon // transition between the vertices and '{0, 3, 0.7}' denotes // an arc from vertex '0' to vertex '3' with a weight of '0.7' // // arcs = // {S, 0, 0, true}, // {S, 1, 0, true}, // {S, 2, 0, true}, // {0, 3, 0.7}, // {0, 5, 0.8}, // {1, 3, 0.9}, // {2, 3, 3.7}, // {2, 6, 3.1}, // {3, 4, 1.2}, // {4, 5, 6.1}, // {4, 6, 1.7}, // {5, T, 0, true}, // {6, T, 0, true}; // // read the arcs // Long num_arcs((int32)0); // read the number of arcs entries i.e., in the example above we have // thirteen arc between vertices in the graph entries. // num_arcs = parser_a.countTokens(PARAM_ARCS); if (debug_level_d >= Integral::ALL) { num_arcs.debug(L"about to read this many arcs"); } // now read the arcs // for (int32 i = 0; i < num_arcs; i++) { // we need a sub-parser to read in the arc list. // SofParser sub_parser; sub_parser.setNest(); sub_parser.setImplicitParam(); sub_parser.load(sof_a, parser_a.getEntry(sof_a, PARAM_ARCS, i, 1)); // determine the number in the arc entry i.e., in the example above // we have the entries either three or four tokens i.e., // {0, 3, 0.7} or {S, 0, 0, true} // Byte ntokens; ntokens = sub_parser.countTokens(parser_a.implicitPname()); if (debug_level_d >= Integral::DETAILED) { ntokens.debug(L"reading this many tokens on this arc"); } // each arc can have 3 to 4 tokens: // 1) a source node index, // 2) a destination node index // 3) the weight (for a weighted graph) // 4) a flag for if this is an epsilon transition or not // if ((byte8)ntokens < 2) { if (debug_level_d >= Integral::ALL) { Console::put(L"not enough elements in arc list"); } return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // weighted graphs needs at least 3 tokens // if (isWeighted() && ((byte8)ntokens < 3)) { if (debug_level_d >= Integral::ALL) { Console::put(L"not enough elements in weighted arc list"); } return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // prepare to read the source and destination indices // sub_parser.setNest(); sub_parser.setImplicitParam(); String source; String dest; // first read the source index // if (!sub_parser.read(index_str, sof_a, sub_parser.getEntry(sof_a, parser_a.implicitPname(), 0, 1))) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // check if the source index is the start vertex // if (index_str.eq(START_NAME)) { if (!source.assign(START_INDEX)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } // check if the source index is the term vertex // else if (index_str.eq(TERM_NAME)) { if (!source.assign(TERM_INDEX)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } else { if (!source.assign(index_str)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } if (debug_level_d >= Integral::ALL) { source.debug(L"read this source node"); } // now read the destination index // String index_str; if (!sub_parser.read(index_str, sof_a, sub_parser.getEntry(sof_a, parser_a.implicitPname(), 1, 1))) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // check if the destination index is the start vertex // if (index_str.eq(START_NAME)) { if (!dest.assign(START_INDEX)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } // check if the destination index is the term vertex // else if (index_str.eq(TERM_NAME)) { if (!dest.assign(TERM_INDEX)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } else { if (!dest.assign(index_str)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } } if (debug_level_d >= Integral::ALL) { dest.debug(L"read this dest node"); } ntokens -= 2; Float weight(0.0); // if this is a weighted graph, the third token for each arc is the // weight // if (isWeighted()) { String weight_str; if (!sub_parser.read(weight_str, sof_a, sub_parser.getEntry(sof_a, parser_a.implicitPname(), 2, 1))) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } if (!weight.assign(weight_str)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } if (debug_level_d >= Integral::ALL) { weight.debug(L"read this weight"); } ntokens -= 1; } // if there are any tokens left, an epsilon flag must be specified // Boolean is_epsilon(false); if ((byte8)ntokens > 0) { String eps_str; if (!sub_parser.read(eps_str, sof_a, sub_parser.getEntry(sof_a, parser_a.implicitPname(), 3, 1))) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } if (!is_epsilon.assign(eps_str)) { return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } ntokens -= 1; } // check for leftover tokens: report error if found // if ((byte8)ntokens != 0) { Console::put(L"leftover tokens on arc"); return Error::handle(name(), L"readArcDataText", Error::READ, __FILE__, __LINE__, Error::WARNING); } // insert the arc from start to finish // if (isWeighted()) { // get the source and destination vertices // BiGraphVertex* src_vertex = hash_table_a.get(source); BiGraphVertex* dst_vertex = hash_table_a.get(dest); // make sure that the source and dest vertices are valid // if (src_vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"readArcDataText", Error::ARG, __FILE__, __LINE__); } if (dst_vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"readArcDataText", Error::ARG, __FILE__, __LINE__); } // insert an arc between the source and dest vertices // const_cast* >(this)->insertArc(src_vertex, dst_vertex, is_epsilon, weight); } else { // get the source and destination vertices // BiGraphVertex* src_vertex = hash_table_a.get(source); BiGraphVertex* dst_vertex = hash_table_a.get(dest); // make sure that the source and dest vertices are valid // if (src_vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"readArcDataText", Error::ARG, __FILE__, __LINE__); } if (dst_vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"readArcDataText", Error::ARG, __FILE__, __LINE__); } // insert an arc between the source and dest vertices // const_cast* >(this)->insertArc(src_vertex, dst_vertex, is_epsilon); } } // exit gracefully // return true; } // method: writeVertexDataText // // arguments: // Sof& sof: (input) sof file // DoubleLinkedList& dlist: (input) list of graph vertex elements // // return: a bool8 value indicating status // // write out the vertex data for this graph // template bool8 BiGraph::writeVertexDataText(Sof& sof_a, DoubleLinkedList& data_a) const { // declare local variables // bool8 more = false; // we need an empty string for the sub-parameter // String empty_str; String start_str; start_str.assign(SofParser::DEF_BLOCKSTART_CHAR); // L"{" String end_str; end_str.assign(SofParser::DEF_BLOCKSTOP_CHAR); // L"}" String delim0_str(end_str); delim0_str.concat(end_str); delim0_str.concat(SofParser::DEF_DELIMITER_CHAR); delim0_str.concat(SofParser::NEWLINE_CHAR); delim0_str.concat(L'\t'); delim0_str.concat(start_str); // L"}},\n\t" String vertex_beg; vertex_beg.assign(SofParser::DEF_BLOCKSTART_CHAR); // L"{" String vertex_end; vertex_end.assign(SofParser::DEF_BLOCKSTOP_CHAR); // L"}" String delim1_str; delim1_str.concat(SofParser::DEF_DELIMITER_CHAR); delim1_str.concat(SofParser::SPACE_CHAR); delim1_str.concat(start_str); // L", {" String term(end_str); term.concat(end_str); term.concat(SofParser::DEF_TERMINATOR_CHAR); term.concat(SofParser::NEWLINE_CHAR); // L"}};\n" // write a parameter name // String output(PARAM_VERTICES); output.concat(SofParser::SPACE_CHAR); output.concat(SofParser::DEF_ASSIGNMENT_CHAR); output.concat(SofParser::NEWLINE_CHAR); output.concat(L'\t'); sof_a.puts(output); // write the initial vertex start brace // output.assign(vertex_beg); sof_a.puts(output); // iterate over all vertices in the list and write them to file // for (more = const_cast& >(data_a).gotoFirst(); more; more = const_cast& >(data_a).gotoNext()) { // write the position of the vertex in the list // Long position(data_a.getPosition()); position.writeData(sof_a, String::getEmptyString()); // write the delimiter // output.assign(delim1_str); sof_a.puts(output); // retrieve the current vertex data element // TObject* curr_obj = const_cast& >(data_a).getCurr(); // write the vertex data elements // curr_obj->writeData(sof_a, String::getEmptyString()); // write the delimiter // TObject* last_obj = const_cast& >(data_a).getLast(); if (curr_obj == last_obj) { output.assign(term); sof_a.puts(output); } else { output.assign(delim0_str); sof_a.puts(output); } } // exit gracefully // return true; } // method: writeArcDataText // // arguments: // Sof& sof: (input) sof file // DoubleLinkedList& alist: (input) graph arcs and weights // // return: a bool8 value indicating status // // write out the arc data for this graph // template bool8 BiGraph::writeArcDataText(Sof& sof_a, DoubleLinkedList& arcs_a) const { // we need an empty string for the sub-parameter // String empty_str; String start_str; start_str.assign(SofParser::DEF_BLOCKSTART_CHAR); // L"{" String end_str; end_str.assign(SofParser::DEF_BLOCKSTOP_CHAR); // L"}" String start_vertex_str; start_vertex_str.assign(START_NAME); // L"S" String term_vertex_str; term_vertex_str.assign(TERM_NAME); // L"T" String delim0_str(end_str); delim0_str.concat(SofParser::DEF_DELIMITER_CHAR); delim0_str.concat(SofParser::NEWLINE_CHAR); delim0_str.concat(L'\t'); delim0_str.concat(start_str); // L"},\n\t" String arc_beg; arc_beg.assign(SofParser::DEF_BLOCKSTART_CHAR); // L"{" String arc_end; arc_end.assign(SofParser::DEF_BLOCKSTOP_CHAR); // L"}" String delim1_str; delim1_str.concat(SofParser::DEF_DELIMITER_CHAR); delim1_str.concat(SofParser::SPACE_CHAR); // L", " String term; term.assign(end_str); term.concat(SofParser::DEF_TERMINATOR_CHAR); term.concat(SofParser::NEWLINE_CHAR); // L"};\n" // write a parameter name // String output(PARAM_ARCS); output.concat(SofParser::SPACE_CHAR); output.concat(SofParser::DEF_ASSIGNMENT_CHAR); output.concat(SofParser::NEWLINE_CHAR); output.concat(L'\t'); sof_a.puts(output); // write the initial arc start brace // output.assign(arc_beg); sof_a.puts(output); // iterate over all vertices in the list and write them to file // for (bool8 more = const_cast& >(arcs_a).gotoFirst(); more; more = const_cast& >(arcs_a).gotoNext()) { // retrieve and write the source vertex position of the current arc // Long src_pos = arcs_a.getCurr()->first().first(); if (src_pos.eq(START_INDEX)) { output.assign(start_vertex_str); sof_a.puts(output); } else if (src_pos.eq(TERM_INDEX)) { output.assign(term_vertex_str); sof_a.puts(output); } else { src_pos.writeData(sof_a, String::getEmptyString()); } // write the parameter seperator // output.assign(delim1_str); sof_a.puts(output); // retrieve and write the destination vertex position of the current arc // Long dst_pos = arcs_a.getCurr()->first().second(); if (dst_pos.eq(START_INDEX)) { output.assign(start_vertex_str); sof_a.puts(output); } else if (dst_pos.eq(TERM_INDEX)) { output.assign(term_vertex_str); sof_a.puts(output); } else { dst_pos.writeData(sof_a, String::getEmptyString()); } // retrieve and write the weight of the current arc // if (this->isWeighted()) { output.assign(delim1_str); sof_a.puts(output); Float weight = arcs_a.getCurr()->second(); weight.writeData(sof_a, String::getEmptyString()); } // retrieve and write the epsilon flag of the current arc // Boolean epsilon = arcs_a.getCurr()->third(); if (epsilon.eq(true)) { output.assign(delim1_str); sof_a.puts(output); epsilon.writeData(sof_a, String::getEmptyString()); } // write the arc terminator // if (arcs_a.getLast() == arcs_a.getCurr()) { output.assign(term); sof_a.puts(output); } else { output.assign(delim0_str); sof_a.puts(output); } } // exit gracefully // return true; } // end of include file // #endif