#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tabdelimfile.h"
#include "labellist.h"
#include "graphio.h"

#define COMMENT "#"
#define DEBUG 1

#ifndef min
	#define min(x, y)       ((x) < (y) ? (x) : (y))
#endif
#ifndef max
	#define max(x, y)       ((x) > (y) ? (x) : (y))
#endif

/* printMatrixLT?- functions that print a matrix in lower-triangular format
**                 assuming ? bytes for the underlying matrix data type
*/
static int printMatrixLT1(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int8_t *mat, int valbits, int8_t denom,
                          int8_t flag);
static int printMatrixLT2(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int16_t *mat, int valbits, int16_t denom,
                          int16_t flag);
static int printMatrixLT4(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int32_t *mat, int valbits, int32_t denom,
                          int32_t flag);
static int printMatrixLT8(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int64_t *mat, int valbits, int64_t denom,
                          int64_t flag);

/* printEdgeList?- functions that print an edge list assuming ? bytes for
**                 the underlying matrix data type
*/
static int printEdgeList1(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int8_t *mat, int valbits, int8_t denom,
                          int8_t flag);
static int printEdgeList2(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int16_t *mat, int valbits, int16_t denom,
                          int16_t flag);
static int printEdgeList4(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int32_t *mat, int valbits, int32_t denom,
                          int32_t flag);
static int printEdgeList8(FILE *out, double threshold, int absval, int prec,
                          unsigned int len, const char **labels,
                          const int64_t *mat, int valbits, int64_t denom,
                          int64_t flag);

/* getEdgeCount?- functions that determine the number of edges and vertices
**                in a graph based on the provided criteria and assuming
**                ? bytes for the underlying matrix data type
*/
static unsigned long getEdgeCount1(double threshold, int absval,
                                   const int8_t *mat, int valbits,
                                   int8_t denom, int8_t flag,
                                   unsigned int* len);
static unsigned long getEdgeCount2(double threshold, int absval,
                                   const int16_t *mat, int valbits,
                                   int16_t denom, int16_t flag,
                                   unsigned int* len);
static unsigned long getEdgeCount4(double threshold, int absval,
                                   const int32_t *mat, int valbits,
                                   int32_t denom, int32_t flag,
                                   unsigned int* len);
static unsigned long getEdgeCount8(double threshold, int absval,
                                   const int64_t *mat, int valbits,
                                   int64_t denom, int64_t flag,
                                   unsigned int* len);

/* readMatrixLT?- functions that read a matrix in lower-triangular format
**                from the provided file and storing the data in a matrix
**                with ? bytes for the underlying matrix data type
*/
static int readMatrixLT1(FILE *in, double threshold, int absval,
                         int valbits, int8_t denom, int8_t flag,
                         LabelList **labels, int8_t **mat, int *errLine,
                         const char **errStr);
static int readMatrixLT2(FILE *in, double threshold, int absval,
                         int valbits, int16_t denom, int16_t flag,
                         LabelList **labels, int16_t **mat, int *errLine,
                         const char **errStr);
static int readMatrixLT4(FILE *in, double threshold, int absval,
                         int valbits, int32_t denom, int32_t flag,
                         LabelList **labels, int32_t **mat, int *errLine,
                         const char **errStr);
static int readMatrixLT8(FILE *in, double threshold, int absval,
                         int valbits, int64_t denom, int64_t flag,
                         LabelList **labels, int64_t **mat, int *errLine,
                         const char **errStr);

/* readEdgeList?- functions that read a matrix in edgelist format from
**                the provided file and storing the data in a matrix with
**                ? bytes for the underlying matrix data type
*/
static int readEdgeList1(FILE *in, double threshold, int absval,
                         int valbits, int8_t denom, int8_t flag,
                         LabelList **labels, int8_t **mat, int *errLine,
                         const char **errStr);
static int readEdgeList2(FILE *in, double threshold, int absval,
                         int valbits, int16_t denom, int16_t flag,
                         LabelList **labels, int16_t **mat, int *errLine,
                         const char **errStr);
static int readEdgeList4(FILE *in, double threshold, int absval,
                         int valbits, int32_t denom, int32_t flag,
                         LabelList **labels, int32_t **mat, int *errLine,
                         const char **errStr);
static int readEdgeList8(FILE *in, double threshold, int absval,
                         int valbits, int64_t denom, int64_t flag,
                         LabelList **labels, int64_t **mat, int *errLine,
                         const char **errStr);

//Print lower triangle of the matrix
int printMatrixLT(FILE *out, double threshold, int absval, int prec,
                  int len, const char **labels, const void *mat,
                  int bbytes, int valbits, int64_t denom, int64_t flag) {
   switch(bbytes) {
      case 1:
         return printMatrixLT1(out, threshold, absval, prec, len, labels,
                               (int8_t *)mat, valbits, (int8_t)denom,
                               (int8_t)flag);
      case 2:
         return printMatrixLT2(out, threshold, absval, prec, len, labels,
                               (int16_t *)mat, valbits, (int16_t)denom,
                               (int16_t)flag);
      case 4:
         return printMatrixLT4(out, threshold, absval, prec, len, labels,
                               (int32_t *)mat, valbits, (int32_t)denom,
                               (int32_t)flag);
#if !defined WINDOWS && !defined WIN32
      case 8:
         return printMatrixLT8(out, threshold, absval, prec, len, labels,
                               (int64_t *)mat, valbits, (int64_t)denom,
                               (int64_t)flag);
#endif
      default:
         return -1;
   }
}

//Print an edgelist matrix matrix
int printEdgeList(FILE *out, double threshold, int absval, int prec,
                  int len, const char **labels, const void *mat,
                  int bbytes, int valbits, int64_t denom, int64_t flag) {
   switch(bbytes) {
      case 1:
         return printEdgeList1(out, threshold, absval, prec, len, labels,
                               (int8_t *)mat, valbits, (int8_t)denom,
                               (int8_t)flag);
      case 2:
         return printEdgeList2(out, threshold, absval, prec, len, labels,
                               (int16_t *)mat, valbits, (int16_t)denom,
                               (int16_t)flag);
      case 4:
         return printEdgeList4(out, threshold, absval, prec, len, labels,
                               (int32_t *)mat, valbits, (int32_t)denom,
                               (int32_t)flag);
#if !defined WINDOWS && !defined WIN32
      case 8:
         return printEdgeList8(out, threshold, absval, prec, len, labels,
                               (int64_t *)mat, valbits, (int64_t)denom,
                               (int64_t)flag);
#endif
      default:
         return -1;
   }
}

//Print a default unweighted edgelist matrix
int printDefaultUnweightedEdgeList(char* filename, int length, const void* mat, const char** labels) {
	FILE* fout;
	fout = fopen(filename,"w");
	if(fout==NULL) {
		printf("Error: can't open %s for writing.\n", filename);
		return 0;
	}
	else {
		return printEdgeList(fout,-3.0,0,4,length,labels,mat,sizeof(char),8*sizeof(char),1,0);
	}
}

//Print a default weighted edgelist matrix
int printDefaultWeightedEdgeList(char* filename, int length, const void *mat, const char** labels, double threshold) {
	FILE* fout;
	fout = fopen(filename,"w");
	if(fout==NULL) {
		printf("Error: can't open %s for writing.\n", filename);
		return 0;
	}
	else {
		return printEdgeList(fout,threshold,0,4,length,labels,mat,
			sizeof(short int),8*sizeof(short int),10000,INAN);
	}
}

//Count the number of edges in an edgelist matrix
unsigned long getEdgeCount(double threshold, int absval,
                           const void *mat, int bbytes, int valbits,
                           int64_t denom, int64_t flag, unsigned int* len) {
   switch(bbytes) {
      case 1:
         return getEdgeCount1(threshold, absval, (int8_t *)mat, valbits,
                              (int8_t)denom, (int8_t)flag, len);
      case 2:
         return getEdgeCount2(threshold, absval, (int16_t *)mat, valbits,
                              (int16_t)denom, (int16_t)flag, len);
      case 4:
         return getEdgeCount4(threshold, absval, (int32_t *)mat, valbits,
                              (int32_t)denom, (int32_t)flag, len);
#if !defined WINDOWS && !defined WIN32
      case 8:
         return getEdgeCount8(threshold, absval, (int64_t *)mat, valbits,
                              (int64_t)denom, (int64_t)flag, len);
#endif
      default:
         return 0;
   }
}

//Read the lower triangle of a matrix
int readMatrixLT(FILE *in, double threshold, int absval, int bbytes,
                 int valbits, int64_t denom, int64_t flag,
                 LabelList **labels, void **mat, int *errLine,
                 const char **errStr) {
   switch(bbytes) {
      case 1:
         return readMatrixLT1(in, threshold, absval, valbits,(int8_t)denom, 
                              (int8_t)flag, labels, (int8_t **)mat, errLine,
                              errStr);
      case 2:
         return readMatrixLT2(in, threshold, absval, valbits, (int16_t)denom,
                              (int16_t)flag, labels, (int16_t **)mat, errLine,
                              errStr);
      case 4:
         return readMatrixLT4(in, threshold, absval, valbits, (int32_t)denom,
                              (int32_t)flag, labels, (int32_t **)mat, errLine,
                              errStr);
#if !defined WINDOWS && !defined WIN32
      case 8:
         return readMatrixLT8(in, threshold, absval, valbits, (int64_t)denom,
                              (int64_t)flag, labels, (int64_t **)mat, errLine,
                              errStr);
#endif
      default:
         return -1;
   }
}

//Read an edgelist
int readEdgeList(FILE *in, double threshold, int absval, int bbytes,
                 int valbits, int64_t denom, int64_t flag,
                 LabelList **labels, void **mat, int *errLine,
                 const char **errStr) {
   switch(bbytes) {
      case 1:
         return readEdgeList1(in, threshold, absval, valbits,
                              (int8_t)denom, (int8_t)flag, labels,
                              (int8_t **)mat, errLine, errStr);
      case 2:
         return readEdgeList2(in, threshold, absval, valbits,
                              (int16_t)denom, (int16_t)flag, labels,
                              (int16_t **)mat, errLine, errStr);
      case 4:
         return readEdgeList4(in, threshold, absval, valbits,
                              (int32_t)denom, (int32_t)flag, labels,
                              (int32_t **)mat, errLine, errStr);
#if !defined WINDOWS && !defined WIN32
      case 8:
         return readEdgeList8(in, threshold, absval, valbits,
                              (int64_t)denom, (int64_t)flag, labels,
                              (int64_t **)mat, errLine, errStr);
#endif
      default:
         return -1;
   }
}

//Read a default unweighted edgelist matrix
int readDefaultUnweighted(char* filename, void** mat, LabelList **labels) {
	FILE* fin;
	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		return readEdgeList(fin,-3.0,1,sizeof(char),8*sizeof(char),
							1,0, labels, mat, NULL, NULL);
	}
}

//Read a default weighted edgelist matrix
int readDefaultWeighted(char* filename, void** mat,  LabelList **labels, double threshold) {
	FILE* fin;
	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		return readEdgeList(fin,threshold,1,sizeof(short int),8*sizeof(short int),
							10000,INAN, labels, mat, NULL, NULL);
	}
}

//Read a default weighted edgelist matrix
int readDefaultWeighted2D(char* filename, double threshold, int absVal, graph* g) {
	int numVerts, idx;
	void* tmpptr;
	FILE* fin;
	int errLine;
	char* errString;
	short int*** mat;
	mat=&(g->mat2d);

	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		if((*mat = (short int **)malloc(2*sizeof(short int *))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 (*mat)[0] = NULL;
		 numVerts = readEdgeList(fin, threshold, absVal, sizeof(short int),
						 sizeof(short int)*8, 10000, INAN,
						 &(g->edgeLabels), (void **)&((*mat)[1]), &errLine, (const char**)&errString);
		 if(numVerts < 0) {
            fprintf(stderr, "Error reading input matrix on line %d, %s\n",
                    errLine, errString);
			exit(1);
		 }
		 if(numVerts > 0) {
			tmpptr = (void *)realloc(*mat, numVerts*sizeof(short int *));
			if(tmpptr == NULL) {
			   perror("matrix allocation");
			   exit(1);
			}
			*mat = (short int **)tmpptr;
			for(idx = 2; idx < numVerts; idx++) {
			   (*mat)[idx] = (*mat)[idx-1] + idx-1;
			}
		 }
		 return numVerts;
	}
}

//Read a default weighted edgelist matrix from an LTM file
int readLTMDefaultWeighted2D(char* filename, double threshold, int absoluteValue, graph* g) {
	int numVerts, idx, i, numElems;
	float currentWeight;
	void* tmpptr;
	FILE* fin;
	short int*** mat;
	mat=&(g->mat2d);

	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		if((*mat = (short int **)malloc(2*sizeof(short int *))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 (*mat)[0] = NULL;
		 fscanf(fin,"%d",&numVerts);

		 numElems=numVerts*(numVerts+1)/2;
		 if(((*mat)[1] = (short int *)malloc( numElems*sizeof(short int))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 for(i=0;i<numElems;i++) {
			fscanf(fin,"%f ",&currentWeight);
			if(currentWeight!=INAN) {
				if(absoluteValue==1)
					if( (currentWeight>(threshold-(1e-6))) || ((-1*currentWeight)>(threshold-(1e-6))) )
						((*mat)[1])[i]=(short int)(DENOM_THRESH*currentWeight);
					else
						((*mat)[1])[i]=(short int)INAN;
				else
					if( currentWeight>(threshold-(1e-6)) )
						((*mat)[1])[i]=(short int)(DENOM_THRESH*currentWeight);
					else
						((*mat)[1])[i]=(short int)INAN;
			}
			else ((*mat)[1])[i]=(short int)INAN;
		 }

		 if(numVerts < 0) {
            fprintf(stderr, "Error reading input matrix.\n");
			exit(1);
		 }
		 if(numVerts > 0) {
			tmpptr = (void *)realloc(*mat, numVerts*sizeof(short int *));
			if(tmpptr == NULL) {
			   perror("matrix allocation");
			   exit(1);
			}
			*mat = (short int **)tmpptr;
			for(idx = 2; idx < numVerts; idx++) {
			   (*mat)[idx] = (*mat)[idx-1] + idx-1;
			}
		 }
		 
		 return numVerts;
	}
}

//Read a default weighted edgelist matrix
int readDefaultWeighted2D_deprecated(char* filename, short int*** mat, LabelList **labels, double threshold, int absVal) {
	int numVerts, idx;
	void* tmpptr;
	FILE* fin;
	int errLine;
	char* errString;

	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		exit(1);
	}
	else {
		if((*mat = (short int **)malloc(2*sizeof(short int *))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 (*mat)[0] = NULL;
		 numVerts = readEdgeList(fin, threshold, absVal, sizeof(short int),
						 sizeof(short int)*8, 10000, INAN,
						 labels, (void **)&((*mat)[1]), &errLine, (const char**)&errString);
		 if(numVerts < 0) {
            fprintf(stderr, "Error reading input matrix on line %d, %s\n",
                    errLine, errString);
			exit(1);
		 }
		 if(numVerts > 0) {
			tmpptr = (void *)realloc(*mat, numVerts*sizeof(short int *));
			if(tmpptr == NULL) {
			   perror("matrix allocation");
			   exit(1);
			}
			*mat = (short int **)tmpptr;
			for(idx = 2; idx < numVerts; idx++) {
			   (*mat)[idx] = (*mat)[idx-1] + idx-1;
			}
		 }
		 return numVerts;
	}
}

//Read a default weighted edgelist matrix from an LTM file
int readLTMDefaultWeighted2D_deprecated(char* filename, short int*** mat, double threshold, int absoluteValue) {
	int numVerts, idx, i, numElems;
	float currentWeight;
	void* tmpptr;
	FILE* fin;

	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		exit(1);
	}
	else {
		if((*mat = (short int **)malloc(2*sizeof(short int *))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 (*mat)[0] = NULL;
		 fscanf(fin,"%d",&numVerts);

		 numElems=numVerts*(numVerts+1)/2;
		 if(((*mat)[1] = (short int *)malloc( numElems*sizeof(short int))) == NULL) {
			perror("matrix allocation");
			exit(1);
		 }
		 for(i=0;i<numElems;i++) {
			fscanf(fin,"%f ",&currentWeight);
			((*mat)[1])[i]=(short int)(DENOM_THRESH*currentWeight);
		 }

		 if(numVerts < 0) {
            fprintf(stderr, "Error reading input matrix.\n");
			exit(1);
		 }
		 if(numVerts > 0) {
			tmpptr = (void *)realloc(*mat, numVerts*sizeof(short int *));
			if(tmpptr == NULL) {
			   perror("matrix allocation");
			   exit(1);
			}
			*mat = (short int **)tmpptr;
			for(idx = 2; idx < numVerts; idx++) {
			   (*mat)[idx] = (*mat)[idx-1] + idx-1;
			}
		 }
		 
		 return numVerts;
	}
}

// Normalize the given weights
void normalizeWeights(int numVerts, short int** data) {
	int i,j;
	short int min,max, minPos,maxPos, leastNeg,mostNeg;
	short int minPosRange = 0;
	short int maxPosRange = (int)DENOM_THRESH;
	short int minNegRange = 0;
	short int maxNegRange = -1*(int)DENOM_THRESH;

	//Find max and min for positive and negative weights
	maxPos=leastNeg = SHRT_MIN;
	minPos=mostNeg = SHRT_MAX;
	for(i=0;i<numVerts;i++) {
		for(j=0;j<i;j++) {
			if(data[i][j]!=INAN) {
				if(data[i][j]>=0) {
					if(maxPos<data[i][j]) maxPos=data[i][j];
					if(minPos>data[i][j]) minPos=data[i][j];
				} else {
					if(leastNeg<data[i][j]) leastNeg=data[i][j];
					if(mostNeg>data[i][j]) mostNeg=data[i][j];
				}
			}
		}
	}

	//Select the biggest difference from zero to maintain same ratio of strengths
	//  while keeping positive and negative separate
	if( (-1*leastNeg)<minPos) min=(-1*leastNeg);
	else min=minPos;
	if( (-1*mostNeg)>maxPos) max=(-1*mostNeg);
	else max=maxPos;
   if( max==min) min=0;

	//Normalize positive and negative weights using the same difference
	for(i=0;i<numVerts;i++) {
		for(j=0;j<i;j++) {
			if(data[i][j]!=INAN) {
				if(data[i][j]>=0) {
					data[i][j]=minPosRange+(maxPosRange-minPosRange)*(data[i][j]-min)/(max-min);
				} else {
					data[i][j]=minNegRange+(maxNegRange-minNegRange)*(data[i][j]-min)/(max-min);
				}
			}
		}
	}
	//Make sure values are in the expected vcbRange
	/*for(i=0;i<3*numVerts;i++) {
		if( (list[i]>maxRange) || (list[i]<minRange) )
			printf("Error: Normalization for element %d failed\n", i);*/
	printf("  Normalized %d vertices [%d,%d]\n",numVerts,min,max);
}

//Read graph vertex layout
/*int loadGVL(char* filename, short int** loc) {
	int i, numVerts;
	FILE* fin;
	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		fscanf(fin,"%d",&numVerts);
		(*loc)=(short int*)malloc(3*numVerts*sizeof(short int));
      if( (*loc)==NULL ) {
         perror("loadGVL(): loc"); return -1;
      }
		for(i=0;i<numVerts;i++) {
			fscanf(fin,"%d %d %d",&((*loc)[i*3+0]),&((*loc)[i*3+1]),&((*loc)[i*3+2]));
		}
	}
	return numVerts;
}*/

//Read graph vertex layout
int loadGVL(char* filename, short int** loc) {
	int i, numVerts;
	FILE* fin;
	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
		fscanf(fin,"%*[^\n]");
		fscanf(fin,"%*1[\n]");
		fscanf(fin,"%d\t%*d\n",&numVerts);
		(*loc)=(short int*)malloc(3*numVerts*sizeof(short int));
      if( (*loc)==NULL ) {
         perror("loadGVL(): loc"); return -1;
      }
      for(i=0;i<numVerts;i++) {
			fscanf(fin,"%*s\t%hd\t%hd\t%hd",&((*loc)[i*3]),&((*loc)[i*3+1]),&((*loc)[i*3+2]));
		}
		fclose(fin);
	}
	return numVerts;
}

// Find the lowest weight in a given graph file
int getLowestWeight(char* filename,float* threshold) {
	int numEdges, idx, i, format;
   float min,max;
   float* weights;
   char* extension;
	FILE* fin;

	fin = fopen(filename,"r");
	if(fin==NULL) {
		printf("Error: can't access %s.\n", filename);
		return -1;
	}
	else {
      extension=&(filename[strlen(filename)-4]);
      if(strcmp(extension,".wel")==0) {
         format=0;
      }
      else if (strcmp(extension,".ltm")==0) {
         format=1;
      }
      else {
    		printf("Unknown format: %s.\n", extension);
         return -1;
      }

      fscanf(fin,"%*d\t%d\n",&numEdges);
      weights=(float*)malloc(numEdges*sizeof(float));
      if(weights==NULL) {
         perror("initFromFileSmart(): weights");
         exit(1);
      }

      idx=0;
      if(format==0) {
         for(i=0;i<numEdges;i++) {
            fscanf(fin,"%*s\t%*s\t%f ",&(weights[idx]));
            if(weights[idx]!=INAN) idx++;

            //assume absolute value
            if(weights[idx-1]<0) weights[idx-1]*=-1.f;
         }
      }
      else if(format==1) {
         for(i=0;i<numEdges;i++) {
            fscanf(fin,"%f ",&(weights[idx]));
            if(weights[idx]!=INAN) idx++;

            //assume absolute value
            if(weights[idx-1]<0) weights[idx-1]*=-1.f;
         }
      }

      getMinMaxfv(numEdges,weights,&min,&max);
       *threshold = min;
      fclose(fin);
      return 0;
   }
}

#define MYTYPE     int8_t
#define MYUTYPE    uint8_t
#define MATRIXFUNC printMatrixLT1
#define ELISTFUNC  printEdgeList1
#define ECNTFUNC   getEdgeCount1
#define MATRIXREAD readMatrixLT1
#define ELISTREAD  readEdgeList1
#include "graphiofuncs.c"
#undef MATRIXFUNC
#undef ELISTFUNC
#undef ECNTFUNC
#undef MATRIXREAD
#undef ELISTREAD
#undef MYTYPE
#undef MYUTYPE

#define MYTYPE     int16_t
#define MYUTYPE    uint16_t
#define MATRIXFUNC printMatrixLT2
#define ELISTFUNC  printEdgeList2
#define ECNTFUNC   getEdgeCount2
#define MATRIXREAD readMatrixLT2
#define ELISTREAD  readEdgeList2
#include "graphiofuncs.c"
#undef MATRIXFUNC
#undef ELISTFUNC
#undef ECNTFUNC
#undef MATRIXREAD
#undef ELISTREAD
#undef MYTYPE
#undef MYUTYPE

#define MYTYPE     int32_t
#define MYUTYPE    uint32_t
#define MATRIXFUNC printMatrixLT4
#define ELISTFUNC  printEdgeList4
#define ECNTFUNC   getEdgeCount4
#define MATRIXREAD readMatrixLT4
#define ELISTREAD  readEdgeList4
#include "graphiofuncs.c"
#undef MATRIXFUNC
#undef ELISTFUNC
#undef ECNTFUNC
#undef MATRIXREAD
#undef ELISTREAD
#undef MYTYPE
#undef MYUTYPE

#if !defined WINDOWS && !defined WIN32
#  define MYTYPE     int64_t
#  define MYUTYPE    uint64_t
#  define MATRIXFUNC printMatrixLT8
#  define ELISTFUNC  printEdgeList8
#  define ECNTFUNC   getEdgeCount8
#  define MATRIXREAD readMatrixLT8
#  define ELISTREAD  readEdgeList8
#  include "graphiofuncs.c"
#  undef MATRIXFUNC
#  undef ELISTFUNC
#  undef ECNTFUNC
#  undef MATRIXREAD
#  undef ELISTREAD
#  undef MYTYPE
#  undef MYUTYPE
#endif
