// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Patricia K. Fasel (Los Alamos Nat. Lab.), Jonathan Berry
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.
// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.
// Last File Update: 21-Feb-1998
// 
#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <strstream.h>
#include <LINK/basic/ElementOps.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/List.h>
#define EXTDEFS			// must define this to prevent multiple 
#include <LINK/graph/nauty.h>	// definitions of some nauty arrays
int	Graph::graph_count = 0;
//
// constructor for an abstract graph
//
Graph::Graph() :
		_cur_vertex_name(0),
		_cur_edge_name(0),
		_cur_subgraph_name(0),
		GraphObject(this)
{
    String new_name = new char[NAMESIZE];
    sprintf(new_name, "Graph%d", graph_count++);
    newAttribute(this, "graph_name", new_name);
    //newAttribute(this, "graph_name", new_name, LINK_DYNAMIC);
    // attributes of graph objects in this graph
    Graph* thisg = this;
    // this is first just to avoid innocuous error on resetAttribute()
    List<Vertex*>* vlist = new List<Vertex*>;
    new Attribute<List<Vertex*>*> (thisg, "x_supervertices", vlist);
    new Attribute<String>(thisg, "name", (char*)"");
    new Attribute<int>(thisg, "width", DEFAULT_WIDTH);
    new Attribute<int>(thisg, "size",  DEFAULT_SIZE);
    new Attribute<double>(thisg, "weight", DEFAULT_WEIGHT);
    new Attribute<double>(thisg, "x", DEFAULT_X);
    new Attribute<double>(thisg, "y", DEFAULT_Y);
    new Attribute<String>(thisg, "color", DEFAULT_COLOR);
    new Attribute<String>(thisg, "label", DEFAULT_LABEL);
    new Attribute<int>(thisg, "mark", DEFAULT_MARK);
    new Attribute<int>(thisg, "type", 0);
    new Attribute<int>(thisg, "starttime", DEFAULT_STARTTIME);
    new Attribute<int>(thisg, "finishtime", DEFAULT_FINISHTIME);
    new Attribute<int>(thisg, "back", DEFAULT_BACK);
    new Attribute<int>(thisg, "low", DEFAULT_LOW);
    new Attribute<int>(thisg, "partition", 0);
    new Attribute<int>(thisg, "locked", 0);
    new Attribute<double>(thisg, "distance", DEFAULT_DISTANCE);
    new Attribute<Vertex*>(thisg, "pred", (Vertex*)0);
    new Attribute<Vertex*>(thisg, "forefather", (Vertex*)0);
    // support for subgraph implementation
    // x_subgraph is used by supervertex to point to its subgraph
    // x_supervertex is used by subgraph to point to its supervertex
    // x_parent is used by supervertex and subgraph to point to graph above
    // x_supervertices is used by main graph to keep track of all subgraphs
    // x_open is used by each subgraph internally to keep state
    // open is used during save and load to indicate how subgraph should be done
    new Attribute<Graph*>(thisg, "x_subgraph", (Graph*) 0);
    new Attribute<Graph*>(thisg, "x_parent", thisg);
    new Attribute<Vertex*>(thisg, "x_supervertex", (Vertex*) 0);
    new Attribute<int>(thisg, "x_open", 1);
    new Attribute<int>(thisg, "open", 1);
}
Graph::Graph(const Graph &G, Flag clone, Flag reverse) 
      : _cur_vertex_name(0),
        _cur_edge_name(0),
        _cur_subgraph_name(0),
        GraphObject(G, clone)
{
    assert( ! GraphObject::_graphBeingConstructed );
    GraphObject::_graphBeingConstructed = this;
    GraphObject::_owner = this;		// And override what was set above
    //
    // Although the GraphObject constructor has already added the source
    // graph's attributes at this point, the job is not finished.  When 
    // Attribute objects are constructed without a Graph reference (as
    // they were just before this routine by the GraphObject constructor),
    // the _graph is not set.  The code below does what Attribute(g,n,v)
    // does.  The reason we can't simply tell GraphObject::GraphObject
    // to pass a Graph reference to the Attribute constructor is that
    // GraphObject must construct Vertices and Edges also. -JWB
    //
    Iterator<AttributeBase*> get_attr(&_attributes);
    AttributeBase *g_attr;
    while (get_attr(g_attr)) {
	char *n = g_attr->name();
	if (strncmp(n, "x_", 2) != 0)
		resetAttribute(this, n);
	g_attr->_graph = this;
    }
    String new_name = new char[NAMESIZE];	 // change the graph's name
    sprintf(new_name, "Graph%d", graph_count++);
    if (clone) 
	//setAttribute((GraphObject*) this, "graph_name",new_name,LINK_DYNAMIC);
	setAttribute((GraphObject*) this, "graph_name", new_name);
    else 
	//newAttribute(this, "graph_name", new_name, LINK_DYNAMIC);
	newAttribute(this, "graph_name", new_name);
    /*** to MHyperGraph::MHyperGraph
    void (Collection<Vertex*>::*pf)(Vertex*);
    if (reverse)
	pf = &Collection<Vertex*>::insert;
    else
	pf = &Collection<Vertex*>::append;
    ***/
    int i, n = G.order();
    Vertex *v, *old_v;
    Vertex** Gverts = G.vertexStart();
    for (i=0; i<n; i++) {
	v = new Vertex(*Gverts[i], CLONE);
	v->_owner = this;
	addVertex(v);
    }
    List<Vertex*>* xsvs;
    getAttribute((GraphObject*)&G, "x_supervertices", xsvs);
    if (xsvs && !xsvs->emptyQ()) {
    	warning("collapsed subgraphs not copied; save, "
		"then load to transfer subgraphs");
    }
    //Iterator<Vertex*> Sverts(xsvs);
    //Vertex *next_sv;
    //while (Sverts(next_sv)) {
    //	v = new Vertex(*next_sv, CLONE);
    //	v->_owner = this;
    //	addVertex(v);
    //}
    /*** to MHyperGraph::MHyperGraph
    int vert_index;
    Iterator<Edge*> Gedges(&G._edges);
    Collection<Vertex*> *edge_verts;
    Edge *edge, *old_e;
    String e_name;
    while (Gedges(old_e)) {
	edge = new Edge(*old_e, clone);
	edge->_owner = this;
	edge_verts = old_e->vertices()->newEmpty();
    	Iterator<Vertex*> old_edge_verts(old_e->vertices());
	while (old_edge_verts(v)) {
		vert_index = G._vertices.search(v);
		(edge_verts->*pf)(_vertices[vert_index]);
	}
	edge->_vertices = edge_verts;
	/////////////Edge* edge = new Edge(this, edge_verts, clone);
	Vertex* vertex;
	Iterator<Vertex*> get_evertex(edge_verts);
	while (get_evertex(vertex))
		vertex->addEdge(edge);
	_edges.insert(edge);
	e_name = makeEdgeName();
    }
    ****/
    List<Vertex*>* vlist = new List<Vertex*>;
    new Attribute<List<Vertex*>*> (this, "x_supervertices", vlist);
    new Attribute<Graph*>(this, "x_subgraph", (Graph*) 0);
    new Attribute<Graph*>(this, "x_parent", this);
    new Attribute<Vertex*>(this, "x_supervertex", (Vertex*) 0);
    new Attribute<int>(this, "x_open", 1);
    GraphObject::_graphBeingConstructed = 0;		// stop the stack
}
MSet<Edge*>
Graph::inducedEdges(Set<Vertex*> sub_verts) const 
{
    Vertex *v;
    Iterator<Vertex*> get_vertex(&sub_verts);
    while (get_vertex(v)) {				// can be improved
	MSet<Edge*> incident_edges = v->incidentEdges();
	Iterator<Edge*> get_incident_edge(&incident_edges);
	Edge *e;
	while (get_incident_edge(e))  {
	        double old_weight;
                getAttribute((GraphObject*) e, "weight", old_weight);
		setAttribute((GraphObject*)e, "mark", 0);
                getAttribute((GraphObject*) e, "weight", old_weight);
	}
    }
    MSet<Edge*> result;
    get_vertex.reset();
    while (get_vertex(v)) {				// can be improved
	MSet<Edge*> incident_edges = v->incidentEdges();
	Iterator<Edge*> get_incident_edge(&incident_edges);
	Edge *e;
	while (get_incident_edge(e)) {
		int mark;
	        double old_weight;
		getAttribute((GraphObject*)e, "mark", mark);	
		if (!mark) {
			MSet<Vertex*> intersection=sub_verts ^ *e->vertices();
			if (intersection.size() > 1) {
				result.insert(e);
				setAttribute((GraphObject*)e, "mark", 1);	
			}
		}
	}
    }
    return result;
}
Graph *
Graph::inducedSubgraph(Set<Vertex*> sub_verts, Flag clone=1) const
{
    // This should be the first time.
    //
    Graph *g = newEmpty(this);
    assert( ! GraphObject::_graphBeingConstructed );
    GraphObject::_graphBeingConstructed = g;
    g->_owner = g;	
    Iterator<AttributeBase*> get_attribute(&_attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute))
    {
        if ((strcmp(attribute->name(),"name")==0) ||
	    (clone && strncmp(attribute->name(), "x_", 2) != 0)) {
                g->addAttr(attribute->copy());
		char *n = attribute->name();
		attribute->_graph = g;
        }
    }
    List<Vertex*>* xsvs;
    getAttribute((GraphObject*)this, "x_supervertices", xsvs);
    if (xsvs && !xsvs->emptyQ()) {
    	warning("collapsed subgraphs not copied; save, "
		"then load to transfer subgraphs");
    }
    Vertex *v, *old_v;
    Vertex** verts = vertexStart();
    Iterator<Vertex*> get_sub_vert(&sub_verts);
    while (get_sub_vert(old_v)) {
	v = new Vertex(*old_v, clone);
	v->_owner = g;
	g->addVertex(v);
    }
    int vert_index;
    MSet<Edge*> induced_edges = inducedEdges(sub_verts);
    Iterator<Edge*> edges(&induced_edges);
    Collection<Vertex*> *edge_verts;
    Edge *e, *old_e;
    String e_name;
    while (edges(old_e)) {
	e_name = old_e->name();
	e = new Edge(*old_e, clone);
	e->_owner = g;
	edge_verts = old_e->vertices()->newEmpty();
    	Iterator<Vertex*> old_edge_verts(old_e->vertices());
	while (old_edge_verts(v)) {
	    Vertex *gv;
	    if (v && v->name() && (gv = g->findVertexByName(v->name())))
		edge_verts->append(g->findVertexByName(v->name()));
	}
	e->_vertices = edge_verts;
	Iterator<Vertex*> get_evertex(edge_verts);
	while (get_evertex(v))
		v->addEdge(e);
	g->addEdge(e);
	//setAttribute((GraphObject*) e, "name", 
	//	strcpy(new char[strlen(e_name)+1], e_name), LINK_DYNAMIC);
	setAttribute((GraphObject*) e, "name", 
		strcpy(new char[strlen(e_name)+1], e_name));
    }
    String new_name = new char[NAMESIZE];	 // change the graph's name
    sprintf(new_name, "Graph%d", graph_count++);
    if (clone) 
	//setAttribute((GraphObject*) g, "graph_name", new_name, LINK_DYNAMIC);
	setAttribute((GraphObject*) g, "graph_name", new_name);
    else 
	//newAttribute(g, "graph_name", new_name, LINK_DYNAMIC);
	newAttribute(g, "graph_name", new_name);
    GraphObject::_graphBeingConstructed = 0;
    List<Vertex*>* vlist = new List<Vertex*>;
    new Attribute<List<Vertex*>*> (g, "x_supervertices", vlist);
    new Attribute<Graph*>(g, "x_subgraph", (Graph*) 0);
    new Attribute<Graph*>(g, "x_parent", g);
    new Attribute<Vertex*>(g, "x_supervertex", (Vertex*) 0);
    new Attribute<int>(g, "x_open", 1);
    return g;
}
Graph *
Graph::edgeInducedSubgraph(Set<Edge*> sub_verts, Flag clone=1) const
{
    // This should be the first time.
    //
    Graph *g = newEmpty(this);
    warning("edgeInducedSubgraph(): not implemented yet");
    return g;
}
//
// destructor for an abstract graph
// at this point, the subgraphs have been opened by ~HyperGraph
// and the supervertices have already been removed
//
Graph::~Graph()
{
    // delete the attributes first, ~Attribute will call resetAttribute()
    // to remove all copies of attributes, which requires the vertices and
    // edges to still exist, also x_supervertices must be deleted last
    List<AttributeBase*> attributes = this->attributes();
    Iterator<AttributeBase*> get_attr(&attributes);
    AttributeBase* attribute;
    AttributeBase* x_super_attr;
    while (get_attr(attribute))
    	if (strcmp(attribute->name(), "x_supervertices") == 0)
    	    x_super_attr = attribute;
    	else {
    	    delete attribute;
    	}
    List<Vertex*>* super_vs;
    getAttribute((GraphObject*) this, "x_supervertices", super_vs);
    
    if (x_super_attr)
        delete x_super_attr;
    // Delete all vertices and edges
    for (int i=0; i < _vertices.size(); i++) {
	delete _vertices[i];
    }
    Edge *edge;
    Iterator<Edge*> get_edge(&_edges);
    while (get_edge(edge))
	delete edge;
    _vertices.clear();
    _edges.clear();
}
Bool Graph::isomorphicQ(const Graph *g) const
{
	if (!g)
		return FALSE;
	return isomorphicQ(*g);
}
Bool Graph::isomorphicQ(const Graph &g) const
{
	static Sequence<Vertex*> s;
	int this_order = order(), rflag;
	if ((this_order != g.order()) || (size() != g.size())) {
	   //cout << "violation: " << this_order << " " << g.order() << endl;
	   //cout << "violation: " << size() << " " << g.size() << endl;
		return FALSE;
	}
	int m = (this_order + WORDSIZE - 1) / WORDSIZE;
	graph *g1 = nautyGraph(this);
	graph *g2 = nautyGraph(&g);
	nvector labg1[MAXN], labg2[MAXN];
	graph *canong1 = canonicalNautyGraph(this, g1, labg1);
	graph *canong2 = canonicalNautyGraph(&g,   g2, labg2);
	int sr;
	if (testcanlab(g2, canong1, labg2, &sr, m, this_order)==0) 
		rflag = TRUE;
	else
		rflag = FALSE;
	delete g1;
	delete g2;
	delete canong1;
	delete canong2;
	return rflag;
}
Bool Graph::binaryQ() const
{
	switch (type()) {
		case MIXEDHYPERGRAPH:
		case UNDHYPERGRAPH:
		case DIRHYPERGRAPH:
		case M_MIXEDHYPERGRAPH:
		case M_UNDHYPERGRAPH:
		case M_DIRHYPERGRAPH:
			{ return FALSE; }
	}
	return TRUE;
}
Matrix<double>
Graph::adjacencyMatrix() const
{
	return AdjacencyMatrix(this);
}
Bool Graph::simpleQ() const
{
	switch (type()) {
		case M_MIXEDHYPERGRAPH:
		case M_UNDHYPERGRAPH:
		case M_DIRHYPERGRAPH:
		case M_MIXEDBINARYGRAPH:
		case M_UNDBINARYGRAPH:
		case M_DIRBINARYGRAPH:
			{ return FALSE; }
	}
	return TRUE;
}
Bool Graph::directedQ() const
{
	switch (type()) {
		case M_DIRHYPERGRAPH:
		case M_DIRBINARYGRAPH:
		case DIRHYPERGRAPH:
		case DIRBINARYGRAPH:
			{ return TRUE; }
	}
	return FALSE;
}
void Graph::addVertices(int n)  // 0..n-1 (or j..n+j-1 if j vertices already
{
    int i;
    for(i = 0; i < n; i++){
        addVertex(makeVertexName());
    }
}
void Graph::addVertex(Vertex* passed_vertex)
{
    if (_vertices.search(passed_vertex) == -1) {
    	_vertices.insert(passed_vertex);
    }
    /*else
	warning("Vertex cannot be inserted - already in Graph");*/
}
void Graph::deleteEdge(Collection<Vertex*>&vs)
{
	Edge *e = isEdge(vs);
	deleteEdge(e);
}
void Graph::deleteEdge(Vertex* v1, Vertex* v2)
{
	Sequence<Vertex*> vs; 
	vs.append(v1);
	vs.append(v2);
	deleteEdge(vs);
}
MSet<Edge*> 
Graph::addEdges(MSet<Set<Vertex*> > es)
{
	Iterator<Set<Vertex*> > get_edge(&es);
	Set<Vertex*> edge;
	while (get_edge(edge))
		addEdge(edge);
	return _edges;
}
MSet<Edge*> 
Graph::addEdges(MSet<Sequence<Vertex*> > es)
{
	Iterator<Sequence<Vertex*> > get_edge(&es);
	Sequence<Vertex*> edge;
	while (get_edge(edge))
		addEdge(edge);
	return _edges;
}
void
Graph::deleteEdges(MSet<Set<Vertex*> > es)
{
	Iterator<Set<Vertex*> > get_edge(&es);
	Set<Vertex*> edge;
	while (get_edge(edge))
		deleteEdge(edge);
}
void
Graph::deleteEdges(MSet<Sequence<Vertex*> > es)
{
	Iterator<Sequence<Vertex*> > get_edge(&es);
	Sequence<Vertex*> edge;
	while (get_edge(edge))
		deleteEdge(edge);
}
//
// create and add a vertex of the passed name to the graph
//
Vertex*
Graph::addVertex(String name)
{
    Vertex* vertex = new Vertex(this);
    String new_name = strcpy(new char[strlen(name)+1], name);
    //setAttribute((GraphObject*) vertex, "name", new_name, LINK_DYNAMIC);
    setAttribute((GraphObject*) vertex, "name", new_name);
    if (_vertices.search(vertex) == -1)
    	_vertices.insert(vertex);
    /*else 
	warning("Vertex cannot be inserted - already in Graph");*/
    return vertex;
}
//
// remove a vertex or edge from the stored array, don't delete or alter
//
void
Graph::removeVertex(Vertex* passed_vertex)
{
    _vertices.remove(passed_vertex);
}
void
Graph::removeEdge(Edge* passed_edge)
{
    _edges.remove(passed_edge);
}
// 
// locate a vertex of this graph by name, id or location
// must search recursively through the subgraphs of the supervertices
// 
Vertex* 
Graph::findVertexByName(String name) const
{
    // search actual vertices of the graph
    int low=0, high=_vertices.size()-1, mid, comp;
    while (low <= high) {
	mid = low + (int) (high-low)/2;
	if ((comp=compareVertexNames(_vertices[mid]->name(), name))==0)
		return _vertices[mid];
	else if (comp < 0)
		low = mid+1;
	else
		high = mid-1;
	Graph* subgraph;
	getAttribute((GraphObject*) _vertices[mid], "x_subgraph", subgraph);
	if (subgraph) {
	    Vertex* return_vertex = subgraph->findVertexByName(name);
	    if (return_vertex)
	        return return_vertex;
	}
    }
    return 0; 
}
Edge* 
Graph::findEdgeByName(String name) const
{
    Iterator<Edge*> get_edge(&_edges);
    Edge *e;
    while (get_edge(e)) {
	if (strcmp(e->name(), name)==0)
		return e;
    }
    return 0;
}
//
// locate the vertex which has the given edge as an incident edge
// this is used in the saving of subgraphs to match up edges with superverts
//
Vertex*
Graph::findVertexWithEdge(Edge* passed_edge) const
{
    cout << "fvwe: testing edge: " << *passed_edge << endl;
    cout << "in graph: " << *this << endl;
    for (int i = 0; i < _vertices.size(); i++) {
	int mark;
	getAttribute((GraphObject*) _vertices[i], "x_mark", mark);
	cout << "fvwe: testing: " << *_vertices[i] << endl;
	if (mark == 0) {
	    cout << "mark is 0" << endl;
	    Vertex* return_vertex;
	    Graph* subgraph;
	    getAttribute((GraphObject*) _vertices[i], "x_subgraph", subgraph);
	    if (subgraph) {
	    	cout << "it is a supervertex" << endl;
	        return_vertex = subgraph->findVertexWithEdge(passed_edge);
	        if (return_vertex != 0) {
	    	    cout << "found it's v: " << *return_vertex << endl;
	            return return_vertex;
		}
	    } else {
	    	cout << "it is NOT a supervertex" << endl;
	        Set<Edge*> inc_edges = _vertices[i]->incidentEdges();
	        Iterator<Edge*> get_edge(&inc_edges);
	        Edge* edge;
	        while (get_edge(edge)) {
		    cout << "incident edge: " << *edge << endl;
	            if (ElementOps<Edge*>::compareItems(edge, passed_edge)==0) {
		    	cout<<"it matches with this: " << *passed_edge<< endl;
		        return _vertices[i];
		    }
		}
	    }
	}
    }
    return 0;
}
//ostream& operator<<(ostream&, const Container<Vertex*>&);
//ostream& operator<<(ostream&, const Collection<Edge*>&);
ostream&
Graph::display(ostream& os)  const
{
        os << "{" << _vertices << "  ";
        os << _edges << "}";
	//os << _edges << "}" ;
	return os;
}
const SortedArray<Vertex*>&
Graph::vertices() const
{
	return _vertices;
}
// debugging only:
ostream&
Graph::displayAllGraphObjects(ostream& os)  const
{
	Vertex *v;
	Edge *e;
	Iterator<Vertex*> get_vert(&_vertices);
	Iterator<Edge*> get_edge(&_edges);
	os << "graph:" << endl;
	os << this << endl;
	os << "vertices:" << endl;
	while (get_vert(v))
		os << v << ": " << *v << endl;
	os << "edges:" << endl;
	while (get_edge(e))
		os << e << ": " << *e << endl;
		
	return os;
}
int Graph::operator==(const Graph& g) const
{
	if  ((_vertices == g._vertices) && (_edges == g._edges))
		return TRUE;
	return FALSE;
}
int Graph::operator<(const Graph& g) const
{
	if  ((_vertices < g._vertices) && (_edges < g._edges))
		return TRUE;
	return FALSE;
}
void
Graph::display(int indent) 
{
    char buf[BUFSIZE];
    sprintf(buf, "%*c", indent, ' ');
    cout << buf << "Graph: " << name() << endl;
    for (int i=0; i < _vertices.size(); i++) {
	Graph* subgraph;
	getAttribute((GraphObject*) _vertices[i], "x_subgraph", subgraph);
	cout << buf << "Vertex: " << _vertices[i] << endl;
	if (subgraph)
	    subgraph->display(indent+4);
    }
    Edge *edge;
    Iterator<Edge*> get_edge(&_edges);
    while (get_edge(edge)) {
        cout << buf <<  "Edge: ";
	ElementOps<Edge*>::displayItem(cout, edge);
	cout << endl;
    }
    // print all existing subgraphs belonging to this graph
    if (indent == 0) {
	List<Vertex*>* super_vs;
	getAttribute((GraphObject*) this, "x_supervertices", super_vs);
	Vertex* super_vertex;
	Iterator<Vertex*> get_super_v(super_vs);
	while (get_super_v(super_vertex)) {
	    Graph* subgraph;
	    int open;
	    Graph* parent;
 	    Vertex* superv;
	    getAttribute((GraphObject*) super_vertex, "x_subgraph", subgraph);
	    getAttribute((GraphObject*) super_vertex, "x_parent", parent);
	    getAttribute((GraphObject*) subgraph, "x_open", open);
	    getAttribute((GraphObject*) subgraph, "x_supervertex", superv);
	    cout << "Supervertex " << superv->name();
	    if (open)
		cout << " ,Subgraph is OPEN, ";
	    else
		cout << " ,Subgraph is CLOSED, ";
	    cout << "Parent is " << parent->name() << endl;
	    subgraph->display(cout);
	}
    }
}
// **********************************************************************
// Graph::isEdge(const Collection<Vertex*>&)
//
//	MHyperGraph::MHyperGraph has the job of constructing all copies
//      of graphs.  Since this constructor is called before the pertinent
//      graph constructor (e.g. DBinGraph::DBinGraph(...)), the graph
//      being constructed doesn't have an identity yet, and we can't
//      rely on directedQ() to tell us whether it will be a digraph or
//      not.  MHyperGraph::MHyperGraph calls this routine (isEdge(...))
//      to determine whether or not to insert edges into simple graphs.
//      the new_graph_type parameter is used to determine whether or
//      not to sort the vertices of an edge before checking if it's in
//      the graph.  For example, if we're constructing a simple, 
//      undirected graph, it already has the edge {0, 1}, and the next 
//      candidate edge is <1, 0>, then this edge would incorrectly be
//      judged not to be in the new graph.  It would then be inserted
//      as {0, 1}, a violation!  
// **********************************************************************
Edge*
Graph::isEdge(const Collection<Vertex*>& vset, int new_graph_type) const
{
	if (vset.emptyQ())
		return 0;
	MSet<Vertex*> sorted_verts;
	const Collection<Vertex*> *cp;
	if ((new_graph_type == UNDIRECTED) 
		 || (new_graph_type == MIXED)) { // MIXED is the default
		sorted_verts = vset;            // i.e. the value used
		cp = &sorted_verts;             // after the graph has
	} else                                  // been constructed.
		cp = &vset;
		
	Vertex* v1 = cp->first();
	//*********************************************************
	// v1 could conceivably belong to *another graph*
	// if so, find a vertex in *this graph* with the same name
	// for an example use, see animation in Kruskal.cpp
	//*********************************************************
	char *v1_graph_name, *this_graph_name;
	getAttribute((GraphObject*) v1, "graph_name", v1_graph_name);
	getAttribute((GraphObject*) this, "graph_name", this_graph_name);
	if (strcmp(this_graph_name, v1_graph_name) != 0)
		v1 = findVertexByName(v1->name());
        MSet<Edge*> v1_edges = v1->incidentEdges();
        Iterator<Edge*> get_edge(&v1_edges);
        Edge *e;
        while (get_edge(e)) {
		Collection<Vertex*>* everts = e->vertices();
		if (*everts == *cp) {
                        return e;
		}
	}
        return 0;
}
Edge*
Graph::isEdge(Vertex* v1, Vertex* v2) const
{
	if (!v1 || !v2)
		return 0;
	Sequence<Vertex*> s;
	s.append(v1);
	s.append(v2);
	if (directedQ())
		return isEdge(s, DIRECTED);
	else
		return isEdge(s);
}
Edge*
Graph::isEdge(Edge* e) const
{
	if (!e)
		return 0;
	Collection<Vertex*> *vs = e->vertices();
	return isEdge(*vs);
}
Bool
Graph::memberQ(Vertex* v) const
{
    for (int i=0; i<_vertices.size(); i++)
	if (ElementOps<Vertex*>::compareItems(_vertices[i],v)==0)
	    return TRUE;
    return FALSE;
}
Bool
Graph::memberQ(Edge* e) const
{
    Edge *edge;
    Iterator<Edge*> get_edge(&_edges);
    while (get_edge(edge))
	if (ElementOps<Edge*>::compareItems(edge, e)==0)
	    return TRUE;
    return FALSE;
}
//
// get the name from the attribute list
//
String
Graph::name() const
{
    Attribute<String>* attr = (Attribute<String>*) getAttr("graph_name");
    String name;
    if (attr)
        name = attr->value();
    else
        name = "";
    return name;
}
//
// is this graph or subgraph open
// need to recurse up the parent attribute, examining the open attribute
//
Bool
Graph::open()
{
    Graph* parent;
    int is_open;
    getAttribute((GraphObject*) this, "x_parent", parent);
    getAttribute((GraphObject*) this, "x_open", is_open);
    if (!is_open || parent == this)
	return is_open;
    else
	return parent->open();
}
//
// generate a new vertex name in the series
//
String
Graph::makeVertexName()
{
    static char name[NAMESIZE];
    sprintf(name, "%d", _cur_vertex_name++);
    return name;
}
String
Graph::makeEdgeName()
{
    static char name[NAMESIZE];
    sprintf(name, "e%d", _cur_edge_name++);
    return name;
}
String
Graph::makeSubgraphName()
{
    static char name[NAMESIZE];
    sprintf(name, "S%d", _cur_subgraph_name++);
    return name;
}
Vertex*
Graph::addSubgraph(const List<Vertex*>& vertices)
{
	return addSubgraph(this, vertices);
}
Vertex*
Graph::addSubgraph(const Set<Vertex*>& vertices)
{
	List<Vertex*> vlist;
	Iterator<Vertex*> get_vert(&vertices);
	Vertex *v;
	while (get_vert(v))
		vlist.append(v);
	return addSubgraph(this, vlist);
}
void Graph::collapseComponents(Set<Set<Vertex*> > vs)
{
	Iterator<Set<Vertex*> > next_piece(&vs);
	Set<Vertex*> piece;
	while (next_piece(piece))
		addSubgraph(piece);
}
void Graph::expandComponents()
{
	Vertex **vertices = vertexStart();
	int i, ord = order();
	for (i=0; i<ord; i++)
		dissolveSubgraph(vertices[i]);
}
Vertex* Graph::randomVertex() const
{
	int size = _vertices.size();
        if (size == 0)
                return 0;
        int rand_rank = Link_randomLong() % size;
        Vertex *rand_vertex = _vertices[rand_rank];
	return rand_vertex;
}
Sequence<Edge*> Graph::pathEdges(Sequence<Vertex*> vs)
{
	Iterator<Vertex*> get_vert(&vs);
	Sequence<Edge*> result;
	Vertex *v, *w;
	get_vert(v);
	while (get_vert(w)) {
		Edge *e = isEdge(v, w);
		if (e)
			result.append(e);
		v = w;
	}
	return result;
}
Sequence<Vertex*> Graph::pathVertices(Sequence<Edge*> es)
{
	Iterator<Edge*> get_edge(&es);
	Sequence<Vertex*> result;
	Vertex *last;
	Edge *e1, *e2;
	get_edge(e1);
	if (e1->size() != 2) 
		return result;
	get_edge(e2);
	if (e2->size() != 2) 
		return result;
	if (e1->type() == EDGEUND) {
		if (e2->type() == EDGEDIR) {
			if (e1->sourceVertex() == e2->sourceVertex()) {
				result.append(e1->sinkVertex());
				result.append(e1->sourceVertex());
			} else if (e1->sinkVertex() == e2->sourceVertex()) {
				result.append(e1->sourceVertex());
				result.append(e1->sinkVertex());
			} else
				return result;
		} else {
			if (e2->hasVertex(e1->sourceVertex())) {
				result.append(e1->sinkVertex());
				result.append(e1->sourceVertex());
			} else if (e2->hasVertex(e1->sinkVertex())) {
				result.append(e1->sourceVertex());
				result.append(e1->sinkVertex());
			} else
				return result;
		}
	} else {
		result.append(e1->sourceVertex());
		result.append(e1->sinkVertex());
	}
	do {
		if (e2->size() != 2) {
			result.clear();
			return result;
		}
		if (e2->sourceVertex() == result.last())
			result.append(e2->sinkVertex());
		else if ((e2->type() == EDGEUND) && 
			 (e2->sinkVertex() == result.last()))
			result.append(e2->sourceVertex());
		else {
			result.clear();
			return result;
		}
	} while (get_edge(e2));
	return result;
}
//
// Precondition:  "pred" attributes must be set (DFS or Dijkstra, etc)
//
Sequence<Edge*> Graph::treePath(Vertex *ancestor, Vertex *descendent)
{
	Sequence<Edge*> result;	
	if (!ancestor || !descendent)
		return result;
	Vertex *cur = descendent, *pred;
	int done=0;
	Edge *e;
	while ((cur != 0) && !done) {
		getAttribute((GraphObject*) cur, "pred", pred);
		if (!pred || ((e = isEdge(cur, pred)) == 0)) {
			result.clear();
			return result;
		}
		result.append(e);
		if (pred == ancestor)
			done = 1;
		cur = pred;
	}
	return result;
}
int Graph::maxDegree() const
{
        int i, temp, max=0, ord = order();
        Vertex **vertices=vertexStart();
 
        for (i=0; i<ord; i++) {
                temp = vertices[i]->incidentEdges().size();
                if (temp > max)
                        max = temp;
        }
        return max;
}
int Graph::minDegree() const
{
        int i, temp, max=0, ord = order();
        Vertex **vertices=vertexStart();
 
        for (i=0; i<ord; i++) {
                temp = vertices[i]->incidentEdges().size();
                if (temp > max)
                        max = temp;
        }
        return max;
}
		
			
		
