// file: $isip/class/dstr/GraphVertex/GraphVertex.h // version: $Id: GraphVertex.h 10636 2007-01-26 22:18:09Z tm334 $ // // make sure definitions are only made once // #ifndef ISIP_GRAPH_VERTEX #define ISIP_GRAPH_VERTEX // isip include files // #ifndef ISIP_SINGLE_LINKED_LIST #include #endif #ifndef ISIP_MEMORY_MANAGER #include #endif #ifndef ISIP_STRING #include #endif // forward class definitions: // we must define the Graph class and the GraphArc class here first because // the header files might be short-circuited by the ifndef. // template class DiGraph; template class GraphArc; // GraphVertex: a generic GraphVertex. the main purpose of a vertex is // to hold a list of arcs originating from the given vertex. // template class GraphVertex : public SingleLinkedList >, public Node { //--------------------------------------------------------------------------- // // public constants // //--------------------------------------------------------------------------- public: // define the class name // static const String CLASS_NAME; //---------------------------------------- // // i/o related constants // //---------------------------------------- static const String DEF_PARAM; //---------------------------------------- // // default values and arguments // //---------------------------------------- // default values // // default arguments to methods // //---------------------------------------- // // error codes // //---------------------------------------- static const int32 ERR = 41100; static const int32 ERR_NULLD = 41101; static const int32 ERR_NOPAR = 41102; //--------------------------------------------------------------------------- // // protected data // //--------------------------------------------------------------------------- protected: // what graph does this vertex belong to // DiGraph* parent_graph_d; // define the memory manager // static MemoryManager mgr_d; //--------------------------------------------------------------------------- // // required public methods // //--------------------------------------------------------------------------- public: // static methods // static const String& name(); // this class doesn't have a diagnose method, its functionality is // tested in Graph::diagnose // // debug methods: // setDebug is inherited from the SingleLinkedList template class // bool8 debug(const unichar* message) const; // method: destructor // ~GraphVertex() { removeAllArcs(); } // method: default constructor // GraphVertex() { parent_graph_d = (DiGraph*)NULL; SingleLinkedList< GraphArc >::setAllocationMode(DstrBase::USER); } // method: copy constructor // GraphVertex(const GraphVertex& arg) { parent_graph_d = (DiGraph*)NULL; SingleLinkedList< GraphArc >::setAllocationMode(DstrBase::USER); assign(arg); } // assign methods // bool8 assign(const GraphVertex& copy_vertex); // method: operator= // GraphVertex& operator=(const GraphVertex& arg) { assign(arg); return *this; } // i/o methods: // these methods are not needed since graph takes care of it's own I/O. // // method: eq // determines if the contents of the vertex are equivalent. // adjacency lists & weights are ignored. // bool8 eq(const GraphVertex& arg) const { return Node::eq(arg); } // 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: // parent graph manipulation methods // //--------------------------------------------------------------------------- // method: setParentGraph // bool8 setParentGraph(DiGraph* parent) { parent_graph_d = parent; return true; } // method: getParentGraph // DiGraph* getParentGraph() const { return parent_graph_d; } //--------------------------------------------------------------------------- // // class-specific public methods: // vertex manipulation methods // //--------------------------------------------------------------------------- // insert/remove a vertex to/from the adjacency list: // these methods assume that the user is taking care of updating the // parent graphs, end vertices, etc. // bool8 insertArc(GraphVertex* vertex, float64 weight = GraphArc::DEF_WEIGHT, bool8 is_epsilon = GraphArc::DEF_EPSILON); bool8 insertArc(GraphVertex* vertex, bool8 is_epsilon = GraphArc::DEF_EPSILON); bool8 insertArc(GraphVertex* vertex, GraphArc*& new_arc, float64 weight = GraphArc::DEF_WEIGHT, bool8 is_epsilon = GraphArc::DEF_EPSILON); bool8 insertArc(GraphVertex* vertex, GraphArc*& new_arc, bool8 is_epsilon = GraphArc::DEF_EPSILON); bool8 removeArc(GraphVertex* vertex); bool8 removeArc(); bool8 removeAllArcs(); // is this vertex adjacent? // bool8 isAdjacent(GraphVertex* vertex) const; // method: isStart // bool8 isStart() const { if (parent_graph_d == (DiGraph*)NULL) { return Error::handle(name(), L"isStart - undefined parent", Error::ARG, __FILE__, __LINE__); } return (this == parent_graph_d->getStart()); } // method: isTerm // bool8 isTerm() const { if (parent_graph_d == (DiGraph*)NULL) { return Error::handle(name(), L"isTerm - undefined parent", Error::ARG, __FILE__, __LINE__); } return (this == parent_graph_d->getTerm()); } //--------------------------------------------------------------------------- // // class-specific public methods: // vertex comparison methods // //--------------------------------------------------------------------------- // compares the siblings of the two vertices and arc weights to see if // the two vertices has a similar structure // bool8 compareVertices(const GraphVertex& compare_vertex_a) const; //--------------------------------------------------------------------------- // // private methods // //--------------------------------------------------------------------------- private: // friend class // template friend class GraphVertexDiagnose; }; // in order to allow graph to reference GraphVertex's constants, it // must be included after the class definition. // #ifndef ISIP_DI_GRAPH #include #endif #ifndef ISIP_GRAPH_ARC #include #endif //----------------------------------------------------------------------------- // // 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 GraphVertex::CLASS_NAME(L"GraphVertex"); template const String GraphVertex::DEF_PARAM(L"vertex"); // static instantiations: the memory manager // template MemoryManager GraphVertex::mgr_d(sizeof(GraphVertex), CLASS_NAME); // below are all the methods for the GraphVertex 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& GraphVertex::name() { // create the static name string for this class and return it // static String cname(CLASS_NAME); cname.clear(); 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 GraphVertex::debug(const unichar* message_a) const { // build a debug string // String output; String value; output.debugStr(name(), message_a, L""); Console::put(output); Console::increaseIndention(); // dump a pointer to the current vertex // value.assign(this); output.debugStr(name(), message_a, L"this", value); Console::put(output); // dump a pointer to the parent graph // value.assign(parent_graph_d); output.debugStr(name(), message_a, L"parent_graph_d", value); Console::put(output); // dump the internal item if it exists // Node::debug(L"item"); // call the parent debug method to debug the list itself // SingleLinkedList< GraphArc >::debug(L"arcs"); // that's it for sub-items, decrease indentation // Console::decreaseIndention(); // exit gracefully // return true; } //------------------------------------------------------------------------ // // required assign methods // //------------------------------------------------------------------------- // method: assign // // arguments: // const GraphVertex& arg: (input) the vertex to copy // // return: a bool8 value indicating status // // this method copies the contents of the input to this list // template bool8 GraphVertex::assign(const GraphVertex& arg_a) { // it may be necessary to clear this vertex // clear(); // call the parent assign method which handles the arc list elements // SingleLinkedList< GraphArc >::assign(arg_a); // call the Node assign method to assign the object // Node::assign(arg_a); // set the parent graph // setParentGraph(arg_a.parent_graph_d); // exit gracefully // return true; } //------------------------------------------------------------------------- // // required clear method // //------------------------------------------------------------------------- // 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 GraphVertex::clear(Integral::CMODE cmode_a) { // switch on cmode // if (cmode_a == Integral::RETAIN) { if (this->item_d != (TObject*)NULL) { this->item_d->clear(cmode_a); } } else if ((cmode_a == Integral::RESET) || (cmode_a == Integral::RELEASE)) { // clear the references to the data // this->item_d = (TObject*)NULL; // clear the reference to the parent graph // parent_graph_d = (DiGraph*)NULL; } else { // deallocate the allocated memory if necessary // if (this->item_d != (TObject*)NULL) { this->item_d->clear(Integral::FREE); delete this->item_d; this->item_d = (TObject*)NULL; } // clear the reference to the parent graph // parent_graph_d = (DiGraph*)NULL; } // clear the arc list // return removeAllArcs(); } //--------------------------------------------------------------------------- // // class-specific public methods: // vertex manipulation methods // //--------------------------------------------------------------------------- // method: insertArc // // arguments: // GraphVertex* vertex: (input) the vertex to connect to // float64 weight: (input) the weight on the generated arc // bool8 is_epsilon: (input) is this an epsilon transition? // // return: a bool8 value indicating status // // this method inserts a weighted arc connecting this vertex to the input // vertex. // template bool8 GraphVertex::insertArc(GraphVertex* vertex_a, float64 weight_a, bool8 is_epsilon_a) { // check that the input vertex is not null // if (vertex_a == (GraphVertex*)NULL) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } // create a new Arc // GraphArc* new_arc = new GraphArc(vertex_a, weight_a); new_arc->setEpsilon(is_epsilon_a); // insert the arc to the list // this->insert(new_arc); // exit gracefully // return true; } // method: insertArc // // arguments: // GraphVertex* vertex: (input) the vertex to connect to // bool8 is_epsilon: (input) is this an epsilon transition? // // return: a bool8 value indicating status // // this method inserts an arc connecting this vertex to the input // vertex. // template bool8 GraphVertex::insertArc(GraphVertex* vertex_a, bool8 is_epsilon_a) { // check that the input vertex is not null // if (vertex_a == (GraphVertex*)NULL) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } // create a new Arc // GraphArc* new_arc = new GraphArc(vertex_a); new_arc->setEpsilon(is_epsilon_a); // insert the arc to the list // this->insert(new_arc); // exit gracefully // return true; } // method: insertArc // // arguments: // GraphVertex* vertex: (input) the vertex to connect to // GraphArc*& new_arc: (output) new created arc // float64 weight: (input) the weight on the generated arc // bool8 is_epsilon: (input) is this an epsilon transition? // // return: a bool8 value indicating status // // this method inserts a weighted arc connecting this vertex to the input // vertex. // template bool8 GraphVertex::insertArc(GraphVertex* vertex_a, GraphArc*& new_arc_a, float64 weight_a, bool8 is_epsilon_a) { // check that the input vertex is not null // if (vertex_a == (GraphVertex*)NULL) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } // create a new Arc // new_arc_a = new GraphArc(vertex_a, weight_a); new_arc_a->setEpsilon(is_epsilon_a); // insert the arc to the list // this->insert(new_arc_a); // exit gracefully // return true; } // method: insertArc // // arguments: // GraphVertex* vertex: (input) the vertex to connect to // GraphArc*& new_arc: (output) new created arc // bool8 is_epsilon: (input) is this an epsilon transition? // // return: a bool8 value indicating status // // this method inserts an arc connecting this vertex to the input // vertex. // template bool8 GraphVertex::insertArc(GraphVertex* vertex_a, GraphArc*& new_arc_a, bool8 is_epsilon_a) { // check that the input vertex is not null // if (vertex_a == (GraphVertex*)NULL) { return Error::handle(name(), L"insertArc", Error::ARG, __FILE__, __LINE__); } // create a new Arc // new_arc_a = new GraphArc(vertex_a); new_arc_a->setEpsilon(is_epsilon_a); // insert the arc to the list // this->insert(new_arc_a); // exit gracefully // return true; } // method: removeArc // // arguments: // GraphVertex* vertex: (input) the vertex to unlink from // // return: a bool8 value indicating status // // this method unlinks this vertex from the input vertex. if the graph is // not directed, then an arc from the input vertex is removed as well // template bool8 GraphVertex::removeArc(GraphVertex* vertex_a) { // make sure the list is not empty // if (this->isEmpty()) { return false; } // find the input vertex in the adjacency list by looping over all arcs // SingleLinkedNode< GraphArc >* tmp_node = this->first_d; // declare temporary objects // GraphVertex* tmp_vert = (GraphVertex*) NULL; // loop over each element and look for the input vertex // bool8 vertex_found = false; while ((tmp_node != (SingleLinkedNode< GraphArc >*)NULL) && !vertex_found) { // get the vertex out of the arc // tmp_vert = tmp_node->getItem()->getVertex(); // check to see if the found vertex is the one we are looking for // if (tmp_vert == vertex_a) { vertex_found = true; } else { tmp_node = tmp_node->getNext(); } } // if we found the vertex then break the arcs, else return an error. // if (vertex_found) { // if the found vertex was at the current node position then remove the // node // if (this->curr_d == tmp_node) { // remove the arc from the graph // bool8 status = false; GraphArc* graph_arc; status = this->remove(graph_arc); delete graph_arc; if (!status) { return false; } } else { // put the current node pointer in place so we can call a // SingleLinkedList remove method // SingleLinkedNode< GraphArc >* tmp_curr = this->curr_d; this->curr_d = tmp_node; // remove the node // bool8 status = false; GraphArc* graph_arc; status = this->remove(graph_arc); delete graph_arc; if (!status) { return false; } // put the current pointer back in place // this->curr_d = tmp_curr; } } else { return false; } // exit gracefully // return true; } // method: removeArc // // arguments: none // // return: a bool8 value indicating status // // this method unlinks this vertex from the vertex linked by the current arc // in the list. if the graph is not directed, then an arc from the found // vertex is removed as well // template bool8 GraphVertex::removeArc() { // if the adjacency list is empty then return false // if (this->isEmpty()) { return false; } // remove this arc // bool8 status = false; GraphArc* graph_arc; status = this->remove(graph_arc); delete graph_arc; // exit gracefully // return status; } // method: removeAllArcs // // arguments: none // // return: a bool8 value indicating status // // this method removes all arcs extending from this vertex // template bool8 GraphVertex::removeAllArcs() { // declare a return value // bool8 return_val = true; // loop until no arcs remain // while (!this->isEmpty()) { // remove the forward link // bool8 status = false; GraphArc* graph_arc; status = this->remove(graph_arc); delete graph_arc; // exit gracefully // return_val &= status; } // exit gracefully // return return_val; } // method: isAdjacent // // arguments: // GraphVertex* vertex: (input) the vertex to find // // return: bool8 flag indicating whether or not the vertex was found // // this method finds the input vertex in the adjacency list for this // vertex // template bool8 GraphVertex::isAdjacent(GraphVertex* vertex_a) const { // make sure the list is not empty // if (this->isEmpty()) { return false; } // find the input vertex in the adjacency list by looping over all arcs // SingleLinkedNode< GraphArc >* tmp_node = this->first_d; // declare temporary objects // GraphVertex* tmp_vert = (GraphVertex*) NULL; // loop over each element and look for the input vertex // bool8 vertex_found = false; while ((tmp_node != (SingleLinkedNode< GraphArc >*)NULL) && !vertex_found) { // get the vertex out of the node // tmp_vert = tmp_node->getItem()->getVertex(); // check to see if the found vertex is the one we are looking for // if (tmp_vert == vertex_a) { vertex_found = true; } else { tmp_node = tmp_node->getNext(); } } // exit gracefully // return vertex_found; } //--------------------------------------------------------------------------- // // class-specific public methods: // vertex comparison methods // //--------------------------------------------------------------------------- // method: compareVertices // // arguments: // const GraphVertex& compare_vertex: (input) the vertex to compare // // return: bool8 value indicating test of equivalence // // this method compares two vertices for equivalent structure // template bool8 GraphVertex::compareVertices(const GraphVertex& vertex_a) const { // declare the output variable // bool8 arc_equal = false; // check for null items in either vertex // if (this->item_d == (TObject*)NULL) { if (vertex_a.item_d != (TObject*)NULL) { return false; } } else if (vertex_a.item_d == (TObject*)NULL) { return false; } // make sure that the vertices have the same number of arcs // if (this->length() != vertex_a.length()) { // if the lengths are different then the number of arcs in the // vertex are different // return false; } // save the current states // SingleLinkedNode< GraphArc >* temp_curr1 = this->curr_d; SingleLinkedNode< GraphArc >* temp_curr2 = vertex_a.curr_d; // iterate over all arcs contained in the current vertex // bool8 more_nodes = const_cast< GraphVertex* >(this)->gotoFirst(); while (more_nodes) { // get the current arc associated with the vertex // arc_equal = false; GraphArc* this_arc = const_cast< GraphVertex* > (this)->getCurr(); // iterate over all arcs associated with the input vertex // bool8 more_nodes1 = const_cast< GraphVertex& >(vertex_a).gotoFirst(); while (more_nodes1) { // get the current arc associated with the vertex // GraphArc* input_arc = const_cast< GraphVertex& > (vertex_a).getCurr(); // check if the arcs are similar // if (this_arc->eq(*input_arc)) { arc_equal = true; } // get the next arc in the vertex // more_nodes1 = const_cast< GraphVertex& >(vertex_a).gotoNext(); } // if none of the arcs in the input vector are similar exit // if (!arc_equal) { const_cast< GraphVertex* >(this)->curr_d = temp_curr1; const_cast< GraphVertex& >(vertex_a).curr_d = temp_curr2; return false; } // get the next arc in the vertex // more_nodes = const_cast< GraphVertex* >(this)->gotoNext(); } // reset the current pointer and return true // const_cast< GraphVertex* >(this)->curr_d = temp_curr1; const_cast< GraphVertex& >(vertex_a).curr_d = temp_curr2; return true; } // end of include file // #endif