// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Michael Murphy (Los Alamos National Laboratory)
// 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 <stdio.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/DBinGraph.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/UBinGraph.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/Matrix.h>
Matrix<double>
AdjacencyMatrix(const Graph *g)
{
	int i, neigh_rank, order = g->order();
	double eweight;
	Matrix<double> adj_matrix(order,order);  
	const SortedArray<Vertex*>& vertices = g->vertices();
	for (i=0; i<order; i++) {
		Set<Vertex*> neighs = vertices[i]->neighbors();                
		Iterator<Vertex*> get_neigh(&neighs);
		Vertex *n;
		while (get_neigh(n)) {
			neigh_rank = g->rank(n); 
			Edge *e = g->isEdge(vertices[i], n);
			getAttribute((GraphObject*)e, "weight", eweight);
			adj_matrix(i, neigh_rank) = eweight;
		}
	}
	return adj_matrix;
}

Matrix<double>
LaplacianMatrix(const Graph *g)
{
	Matrix<double> adjmat = AdjacencyMatrix(g);
	Vertex **v = g->vertexStart();
	int i, ord = g->order();
	for (i=0; i<ord; i++) {
		int deg = g->degree(v[i]);
		adjmat(i,i) = adjmat(i,i) - deg;
	}
	return adjmat;
}
	
// saves space if we are dealing with huge graphs
Matrix<double> 
UndirectedGraph2AdjacencyMatrix(const Graph* graph)
{
// might want to write, might want to delete
	static Matrix<double> m;
	return m;
}

MBinGraph
AdjacencyMatrix2Graph(const Matrix<int>& passed_matrix)
{
    int i, numVertices = passed_matrix.numRows();
    MBinGraph resultGraph;
    char s[10];  // temporary label string;
    // Create Vertices in the graph
    for (int j=0; j< numVertices; j++) {
        sprintf(s,"%d",j);
        resultGraph.addVertex(s);
    }
    // go through each element in the adjacency matrix, and add an edge if
    // something is there.
    Array<Vertex*> vertices = resultGraph.vertices();
    for (i=0; i < numVertices; i++) {
        for (int j=0; j<= i; j++) {
            if (passed_matrix(i,j)) {   // add the edge 
		Set<Vertex*> s;
		s.insert(vertices[i]);
		s.insert(vertices[j]);
                resultGraph.addEdge(s);
	    }
        }
    }
    return(resultGraph);
}

MBinGraph
AdjacencyMatrix2Graph(const Matrix<double>& passed_matrix)
{
    int i, numVertices = passed_matrix.numRows();
    MBinGraph resultGraph;
    char s[10];  // temporary label string;
    // Create Vertices in the graph
    for (int j=0; j< numVertices; j++) {
        sprintf(s,"%d",j);
        resultGraph.addVertex(s);
    }
    // go through each element in the adjacency matrix, and add an edge if
    // something is there.
    Array<Vertex*> vertices = resultGraph.vertices();
    for (i=0; i < numVertices; i++) {
        for (int j=0; j<= i; j++) {
            if (passed_matrix(i,j)) {   // add the edge 
		Set<Vertex*> s;
		s.insert(vertices[i]);
		s.insert(vertices[j]);
                Edge *e = resultGraph.addEdge(s);
		if (e)
			setAttribute((GraphObject*)e, "weight", 
					passed_matrix(i,j));
	    }
        }
    }
    return(resultGraph);
}

MBinGraph
AdjacencyMatrix2Digraph(const Matrix<int>& passed_matrix)
{
    int i, numVertices = passed_matrix.numRows();
    DBinGraph resultGraph;
    char s[10];  // temporary label string;
    // Create Vertices in the graph
    for (int j=0; j< numVertices; j++) {
        sprintf(s,"%d",j);
        resultGraph.addVertex(s);
    }
    // go through each element in the adjacency matrix, and add an edge if
    // something is there.
    Array<Vertex*> vertices = resultGraph.vertices();
    for (i=0; i < numVertices; i++) {
        for (int j=0; j< numVertices; j++) {
            if (passed_matrix(i,j)) {  // add the edge 
		Sequence<Vertex*> s;
		s.append(vertices[i]);
		s.append(vertices[j]);
                resultGraph.addEdge(s);
	    }
        }
    }
    MBinGraph resultGraph2 = resultGraph;
    return(resultGraph);
}

MBinGraph
AdjacencyMatrix2Digraph(const Matrix<double>& passed_matrix)
{
    int i, numVertices = passed_matrix.numRows();
    DBinGraph resultGraph;
    char s[10];  // temporary label string;
    // Create Vertices in the graph
    for (int j=0; j< numVertices; j++) {
        sprintf(s,"%d",j);
        resultGraph.addVertex(s);
    }
    // go through each element in the adjacency matrix, and add an edge if
    // something is there.
    Array<Vertex*> vertices = resultGraph.vertices();
    for (i=0; i < numVertices; i++) {
        for (int j=0; j< numVertices; j++) {
            if (passed_matrix(i,j)) {  // add the edge 
		Sequence<Vertex*> s;
		s.append(vertices[i]);
		s.append(vertices[j]);
                resultGraph.addEdge(s);
	    }
        }
    }
    MBinGraph resultGraph2 = resultGraph;
    return(resultGraph);
}
