//Brandon S. Parker
//April 18, 2003    
//generator.cc     
//=========================
//**************************************************************
//*               Graph Adj. Matrix Generator:                 *
//*                                                            *
//* Source file: generator.cc   Vers. 1.0                      *
//*                                                            *
//* Input: command line arguments 	                       *
//*                                                            *
//* Output: console and ASCII file                             *
//*                                                            *
//* Compile with: g++ -o generator generator.cc                *
//*                                                            *
//* Objective: Provide complete graphs for analysis            *
//*                                                            *
//* License: GPL - http://www.gnu.org/copyleft/gpl.html        *
//*                                                            *
//* For more information, see http://www.brandonparker.net     *
//*                                                            *
//* Author:                                                    *
//*  Brandon S. Parker                                         *
//*  (c) 2003 by Brandon S. Parker                             *
//*                                                            *
//**************************************************************

#include <iostream.h>
#include <stdio.h>
#include <fstream.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>


#define VERSION "1.0"
#define COPYRIGHT "(c)2003 Brandon Parker"

#define INFINITE 65535
#define MAXDIM 60000

//***Prototypes:
int CmdParse(int argv, char *argc[], char filename[], bool *QUIET, int *TYPE, int *MAX_W, int *n);
double getNOWTime();
double getCPUTime();

//************
//*** MAIN ***
//************

int main(int argv, char *argc[])
{

//*** Definitions:

srand((unsigned int)getCPUTime()); //*** seed randomize with currect time for uniqueness

char filename[88]; //*** Output filename
strcpy(filename, "AdjMatrix.mtx");

bool QUIET = false; //*** true = print to file, false = print to STDOUT only
int TYPE = 1; 	    //*** graph type: (1) Sparse, (2) Dense, (3) Mid/Random (4) Complete
int MAX_W = 60000; //*** Max weight allowed in the graph. Set to '1' for unweighted
int n = 25; //*** number of graph nodes/ matrix dimension
CmdParse(argv, argc, filename, &QUIET, &TYPE, &MAX_W, &n);
ofstream FILE(filename); //*** ASCII output file



if (!QUIET) FILE<<n<<endl;
cout<<endl<<"Size = "<<n<<endl;

unsigned int AdjMatrix[n][n]; //*** The Adjacency Matrix to be output
for (int i = 0; i < n; i++)
	for (int j = 0; j < n; j++)
		AdjMatrix[i][j] = 0;

//*** create a minimum edge connected graph (sparse)
//*** (See proof in footnote #1)
for (int i = 1; i < n; i++) 
       AdjMatrix[int(rand()%i)][i] = rand()%MAX_W + 1;

switch(TYPE)
	{ // *** Place at least one edge per node
	  // Note: above is the insurance of a connected graph... so the following cases are already connected:
	case 1: //Sparse where Edges << n(n-1)/2
		for(int i,j,k = 0; k <= (n); k++)
                        {
                        i = int(rand()%(n-1) + 1);
                        j = int(rand()%i);
                        AdjMatrix[j][i] = rand()%MAX_W + 1;
                        }

		break;
	case 2: // Dense  where Edges >> n(n-1)/2
		for(int i,j,k = 0; k <= (4 * n * n / 5); k++)
			{
			i = int(rand()%(n-1) + 1);
			j = int(rand()%i);
			AdjMatrix[j][i] = rand()%MAX_W + 1;
			}		
		break;
	case 3: // Mid/Random where Edges ~= n(n-1)/2
		for(int i,j,k = 0; k <= (n * n / 2); k++)
                        {
                        i = int(rand()%(n-1) + 1);
                        j = int(rand()%i);
                        AdjMatrix[j][i] = rand()%MAX_W + 1;
                        }
		break;
	case 4: // Complete where Edges = n
	default:
		 for (int i = 1; i < n; i++)
		    for (int j = 0; j < i; j++)
                        AdjMatrix[j][i] = rand()%MAX_W + 1;
	}

//*** Print it out.
for (int i = 0; i < n; i++)
	{
	for (int j = 0; j < n; j++)
		{
		if (!QUIET) FILE<<AdjMatrix[i][j]<<" ";
		}
	if (!QUIET) FILE<<endl;
	}
cout<<"Finished "<<filename<<"."<<endl;
FILE.close();
return 1;
}

//***************************************
//***		Sub-Routines	     * **
//***************************************



int CmdParse(int argv, char *argc[], char filename[], bool *QUIET, int *TYPE, int *MAX_W, int *n)
{
if (argv < 2)
	{
	cout<<endl<<"Usage: "<<argc[0]<<" <dimensions> [<filename>]"<<endl<<endl;
	exit(1);
	}
for (int i =  0; i < argv; i++)
	{
	if (argc[i][0] == '-')
		switch(argc[i][1])
		{
		  case 'f':
			if((argv > (i+1)) && (argc[i+1][0] != '-'))
				strcpy(filename, argc[i+1]);
			break;
		  case 'v': 
			cout<<endl<<argc[0]<<" Vers. "<<VERSION<<endl<<COPYRIGHT<<endl<<endl;
		  case 'q':
			*QUIET = true;
			break;
		  case 's':
			*TYPE = 1;
			break;
		  case 'd':
			*TYPE = 2;	
			break;
		  case 'r': 
			*TYPE = 3;
			break;
		  case 'c':
			*TYPE = 4;	
			break;
		  case 'w':
			*MAX_W = 1;
			break; 
		  case '?':
		  case 'h':
		  default:
			cout<<endl<<"Usage: "<<argc[0]<<" <dimensions> [-f <filename>] [-vhq]"<<endl;
			cout<<"Version: "<<VERSION<<" "<<COPYRIGHT<<endl<<endl;
			cout<<"  -c	Create a Complete graph."<<endl;
			cout<<"  -d	Create a Dense graph."<<endl;
			cout<<"  -f	Specify filename to write adjacency matrix to."<<endl;
			cout<<"  -h 	Display usage information."<<endl;
			cout<<"  -r	Create a random graph, (Sparse < graph < Dense)."<<endl;
			cout<<"  -s	Create a Sparse graph."<<endl;
			cout<<"  -q 	Print Adjacency Matrix to STDOUT only."<<endl;
			cout<<"  -w	Create an Unweighted graph."<<endl;
			cout<<"  -v 	Displays version information."<<endl;
			cout<<endl<<" Note: Maximum dimension for matrix is "<<MAXDIM<<"."<<endl; 
			cout<<" Output is a randomly generated, weighted (unless the -w flag is used)"<<endl;
			cout<<" adjacency matrix for a graph in ASCII format."<<endl<<endl;

		}
	else if ((i > 0) && (argc[i-1][1] != 'f'))
		 *n = atoi(argc[i]); 
	}
return 1;
}

//************************************************

double getCPUTime()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_usec;
}

//************************************************

double getNOWTime() {
  struct timeval tv;
   gettimeofday(&tv, NULL);
   return tv.tv_sec*1e+06 + tv.tv_usec;
   }

//***************************************
//***              Foot-Notes         ***
//***************************************
//
// ----------------------------------------------------
// 1.) Proof of Connected minimum edge graph algorithm:
// ----------------------------------------------------
// Proof by induction:
// LET:
//	a.) G be a graph of n nodes
//	b.) M[n][n] be the Adjacency Matrix for G.
//	
// Note:
//	a.) For any i such that 0<i<n  M[i][i] is Infinity
//	b.) For any i,j such that 0<i,j<n  M[i][j] = M[j][i]
//		As such, any M[i][j>i] can be disregarded as the
//		contained value is a duplicate.
//
// Algorithm:
//	For each i = 1 to n
//	  choose a value of j such that 0<j<i
//	  Assign a connection and weight to M[i][j]	   
// Proof:
//
// (1) Let n = 2
//	The only edge possible is M[1][0], and a weight and connection
//	is placed at that location by the algorithm. Therefore, the
//	resulting graph is the minimum edge connected graph.
//
// (2) Let n = n + 1;
//	The new node must connect to one of the previous n nodes,
//	and therefore is connected to the rest of the graph maintaining
//	the minimum edge conneceted graph 
//     
// (3) Therefore, by induction, any G of size n will be a connected,
// 	minimum edge graph following the algorithm.
//


