/*
 * mtrxmath.c
 *
 * Jeff Craig <luserjeff@linuxfreemail.com>
 *
 * Licensed under the GNU GPL
 */

#include "mtrxmath.h"

/* Displays usage options */
void display_options(void)
{
  fprintf(stderr,"Usage: mtrxmath [options] <file1> <file2>\n");
  fputs("\t-h or --help     \tDisplay this help.\n",stderr);
  fputs("\t-a or --add      \tPerform matrix addition.\n",stderr);
  fputs("\t-s or --subtract \tPerform matrix subtraction.\n",stderr);
  fputs("\t-m or --multiply \tPerform matrix multiplication.\n",stderr);
  fputs("\t-D or --determinant\t Find the determinant of a Matrix.\n",stderr);
  fputs("\t-d or --divide   \tPerform Matrix division.\n",stderr);
  fputs("\t-i or --invert   \tFind the Inverse of a Matrix.\n\n",stderr);
  fputs("\tThe file1 and file2 parts are optional, and can be used to specify\n",stderr);
  fputs("\tfiles to load the matrices from.  Must have one matrix per file\n",stderr);
  fputs("\tand you must load them in order \x28you can't load the second matrix\n",stderr);
  fputs("\tbut not the first\x29\n\n",stderr);
}

int main (int argc, char **argv)
{
  int optch,indlopts=0, cmdopt = 0;
  static char optstring[] = "asmDdhir";
  FILE* file = stdin;
  static struct option lopts[] = {
    { "help",        0, 0, 'h' },
    { "add",         0, 0, 'a' },
    { "subtract",    0, 0, 's' },
    { "multiply",    0, 0, 'm' },
    { "determinant", 0, 0, 'D' },
    { "divide",      0, 0, 'd' },
    { "invert",      0, 0, 'i' },
    { "reduce",      0, 0, 'r' },
    { 0,             0, 0,  0  }
  };
  MATRIX_PTR foo, bar, final;
  float det;

  while ( (optch = getopt_long(argc,argv,optstring,lopts,&indlopts)) != EOF ) 
    switch (optch) 
      {
      case 'a' :
	cmdopt = ADD;
	break;
      case 's' :
	cmdopt = SUBTRACT;
	break;
      case 'm' :
	cmdopt = MULTIPLY;
	break;
      case 'd' :
	cmdopt = DIVIDE;
	break;
      case 'D' :
	cmdopt = DETERMINANT;
	break;
      case 'i' :
	cmdopt = INVERT;
	break;
      case 'r' :
	cmdopt = REDUCE;
	break;
      case 'h' :
      case '?' :
	display_options();
	exit(1);
      }
  
  if(cmdopt == 0) { display_options(); exit(1); }

  if(argc < 3) {
    printf("First Matrix\n");
    foo = collect_matrix(stdin);
  }
  else {
    if ((file = fopen(argv[2],"r")) == NULL)
      die("Error opening file");
    foo = collect_matrix(file);
    fclose(file);
  }

  if (cmdopt==DETERMINANT) {
    det = determinant(foo);
    printf("Determinant = %f\n",det);
    exit(0);
  }
  if (cmdopt==INVERT) {
    final = inverse(foo);
    show_matrix(final);
    exit(0);
  } 
  if (cmdopt==REDUCE) {
    int x,y;
    printf("Where do you want to cut the matrix?");
    scanf("%i %i",&x,&y);
    final = reduce_matrix(x,y,foo);
    show_matrix(final);
    exit(0);
  }
  
  if(argc < 4) {
    printf("Second Matrix\n");
    bar = collect_matrix(stdin);
  }
  else {
    if ((file = fopen(argv[3],"r")) == NULL)
      die("Error opening file");
    bar = collect_matrix(file);
    fclose(file);
  }

  if(cmdopt==ADD) 
    final = matrix_add(foo,bar);
  if(cmdopt==SUBTRACT)
    final = matrix_sub(foo,bar);
  if(cmdopt==MULTIPLY)
    final = matrix_multiply(foo,bar);
  if(cmdopt==DIVIDE)
    final = matrix_divide(foo,bar);

  if (final==NULL) 
    die("No Solution");

  show_matrix(final);

  return(0);
}

/* 
 * This Code draws out a matrix of any size onto the console
 * limits the floating-point precision to 3 places past the
 * decimal
 */

void show_matrix(MATRIX_PTR show)
{
  int index, index2;

  for(index=0;index<show->rows;index++) {
    for(index2=0;index2<show->columns;index2++) {
      printf("%.3f\t",show->matrix[index][index2]);
    }
    printf("\n");
  }
}

/* 
 * This code takes keyboard input and places it into a matrix
 * I have gotten reports of problems with non-us character sets
 */

MATRIX_PTR collect_matrix(FILE* file)
{
  MATRIX_PTR input;
  unsigned int rows, columns;
  int index, index2;

  if ( file == stdin )
    printf("Rows: ");
  while((fscanf(file,"%u",&rows)!=1)) {
    fscanf(file,"%*s");
    if (file==stdin)
      printf("Invalid input. Rows: ");
  }
  
  if (file == stdin)
    printf("Columns: ");
  while((fscanf(file,"%u",&columns)!=1)) {
    fscanf(file,"%*s");
    if (file==stdin)
      printf("Invalid input. Columns: ");
  }
  
  input = alloc_matrix(rows, columns);
  
  for(index=0;index<input->rows;index++) {
    for(index2=0;index2<input->columns;index2++) {
      if (file == stdin)
	printf("Value for %i,%i: ",index,index2);
      while(fscanf(file,"%f",&input->matrix[index][index2])!=1) {
	fscanf(file,"%*s");
	if (file == stdin)
	  printf("Invalid input. Value for %i, %i: ",index,index2);
      }
    }
  }

  return(input);
}

/*
 * This code allocates a MATRIX structure
 */

MATRIX_PTR alloc_matrix(unsigned int rows, unsigned int columns)
{
  MATRIX_PTR m;
  int i;
  
  m = (MATRIX_PTR)malloc(sizeof(*m));
  if (m == NULL)
    die("MALLOC error");

  m->rows = rows;
  m->columns = columns;

  m->matrix = calloc(m->rows,sizeof(float*));
  if(m->matrix == NULL)
    die("MALLOC error");
  for(i=0;i<m->rows;i++) {
    m->matrix[i]=calloc(m->columns,sizeof(float));
    if(m->matrix[i] == NULL)
      die("MALLOC error");
  }
  return m;
}

/*
 * This function frees a MATRIX structure
 */
void free_matrix(MATRIX_PTR m)
{
  if (m) {
    if (m->matrix)
      free(m->matrix);
    free(m);
  }
}

void die(const char* msg) {
  printf("%s\n", msg);
  exit(1);
}
  


















syntax highlighted by Code2HTML, v. 0.9.1