//====================================================== file = check.c =====
//=  Matrix checker for input matrix files for iter.c                       =
//=   - Checks validity of P and Q matrices                                 =
//===========================================================================
//=  Notes:                                                                 =
//=    1) Input from input file "in.dat" to stdin (see example below)       =
//=        * Note special format of input file, "-1" denotes end of         =
//=          column, "-999" denotes last entry, and "&" bounds comments     =
//=    2) Reads matrix Type ('P' or 'Q') as first input value and then      =
//=       reads matrix size (0...(size - 1)) as second input value.  No     =
//=       initial comment is allowed.                                       =
//=    3) Output is to stdout                                               =
//=    4) For a P matrix row sums should be 1.0 and for a Q matrix row      =
//=       sums should be 0.0                                                =
//=    5) For a P matrix there should be no negative values and for a Q     =
//=       matrix the diagonal value should be a negative sum of all         =
//=       row values                                                        =
//=-------------------------------------------------------------------------=
//= Example "in.dat" file:                                                  =
//=                                                                         =
//=   P 3                                                                   =
//=   & Example from Kleinrock, Volume 1, pages 31 - 33                     =
//=     ---------------- column #0    &                                     =
//=   1       0.25                                                          =
//=   2       0.25                                                          =
//=   -1      zero                                                          =
//=   & ---------------- column #1    &                                     =
//=   0       0.75                                                          =
//=   2       0.25                                                          =
//=   -1      zero                                                          =
//=   & ---------------- column #2    &                                     =
//=   0       0.25                                                          =
//=   1       0.75                                                          =
//=   2       0.50                                                          =
//=   -1      zero                                                          =
//=   & ---------------- END FLAG     &                                     =
//=   -999    zero                                                          =
//=-------------------------------------------------------------------------=
//= Example output (for above "in.dat"):                                    =
//=                                                                         =
//=   ------------------------------------------------- check.c -----       =
//=     P matrix with 3 rows                                                =
//=   ---------------------------------------------------------------       =
//=     Matrix is valid!                                                    =
//=   ---------------------------------------------------------------       =
//=-------------------------------------------------------------------------=
//=  Build: bcc32 check.c, cl check.c, gcc check.c                          =
//=-------------------------------------------------------------------------=
//=  Execute: check < in.dat                                                =
//=-------------------------------------------------------------------------=
//=  Author: Kenneth J. Christensen                                         =
//=          University of South Florida                                    =
//=          WWW: http://www.csee.usf.edu/~christen                         =
//=          Email: christen@csee.usf.edu                                   =
//=-------------------------------------------------------------------------=
//=  History: KJC (02/23/02) - Genesis                                      =
//=           KJC (05/19/05) - Now can have multiple sequential comments    =
//===========================================================================
//----- Include files -------------------------------------------------------
#include <stdio.h>                 // Needed for printf()
#include <stdlib.h>                // Needed for exit(), atoi(), and atof()
#include <string.h>                // Needed for strcmp()

//----- Defines -------------------------------------------------------------
#define P_TYPE           0         // P matrix type is 0
#define Q_TYPE           1         // Q matrix type is 1
#define MAX_SIZE      5000         // Max size of Q array (0...(MAX_SIZE - 1))

//===========================================================================
//=  Main program                                                           =
//===========================================================================
void main(void)
{
  int     matrix_type;             // Matrix is P_TYPE or Q_TYPE
  double  row_sum[MAX_SIZE];       // Row sums
  int     size;                    // Size of matrix  (0...(Size - 1))
  int     col_num;                 // Current column number
  int     row_num;                 // Current row number
  double  value;                   // Current row value
  char    instring[80];            // Input string variable
  int     i;                       // Loop counter

  // Output a banner
  printf("------------------------------------------------- check.c -----\n");

  // Read first entry, must be matrix type
  scanf("%s", instring);
  if ((instring[0] == 'P') || (instring[0] == 'p'))
  {
    matrix_type = P_TYPE;
    printf("  P matrix with ");
  }
  else if ((instring[0] == 'Q') || (instring[0] == 'q'))
  {
    matrix_type = Q_TYPE;
    printf("  Q matrix with ");
  }
  else
  {
    printf("  *** ERROR - Matrix type ('P' or 'Q') is not first entry \n");
    exit(1);
  }

  // Read second entry, must be matrix size
  scanf("%s", instring);
  size = atoi(instring);
  if ((size > 0) && (size < MAX_SIZE))
    printf("%d rows \n", size);
  else
  {
    printf("  *** ERROR - Matrix size is invalid (size = %d) \n", size);
    exit(1);
  }

  // Initialize column number to zero and all row sums to zero
  col_num = 0;
  for (i=0; i<size; i++)
    row_sum[i] = 0.0;

  // Read input file and compute row sums
  do
  {
    scanf("%s", instring);

    // This handles a comment (multiple comments are handled)
    if (strcmp(instring, "&") == 0)
    {
      while(1)
      {
        do
        {
          scanf("%s", instring);
        } while (strcmp(instring, "&") != 0);
        scanf("%s", instring);
        if (strcmp(instring, "&") != 0) break;
      }
    }

    // Input row number
    row_num = atoi(instring);

    // Handle end of column and end of file sentinel values
    if (row_num == -1)
    {
      col_num++;
      if (col_num >= MAX_SIZE)
      {
        printf("  *** ERROR - Matrix is larger than MAX_SIZE \n");
        exit(1);
      }
      continue;
    }
    if (row_num == -999) break;

    // Input value for this row number
    scanf("%s", instring);
    value = atof(instring);

    // Do a validity check on the value
    if (matrix_type == P_TYPE)
    {
      if (value < 0.0)
      {
        printf("  *** ERROR - Negative value in P matrix (row = %d) \n",
          row_num);
        exit(1);
      }
    }
    else if (matrix_type == Q_TYPE)
    {
      if ((col_num != row_num) && (value < 0.0))
      {
        printf("  *** ERROR - Invalid value in Q matrix (row = %d) \n",
          row_num);
        exit(1);
      }
      if ((col_num == row_num) && (value >= 0.0))
      {
        printf("  *** ERROR - Invalid value in Q matrix (row = %d) \n",
          row_num);
        exit(1);
      }
    }

    // Add value to row_sum
    row_sum[row_num] = row_sum[row_num] + value;

  } while (1);

  // Do a final validity check based on complete row sums
  if (matrix_type == P_TYPE)
  {
    for (i=0; i<size; i++)
      if (row_sum[i] != 1.0)
      {
        printf("  *** ERROR - Bad row in P matrix (row = %d) \n", i);
        exit(1);
      }
  }
  else if (matrix_type == Q_TYPE)
  {
    for (i=0; i<size; i++)
      if (row_sum[i] != 0.0)
      {
        printf("  *** ERROR - Bad row in Q matrix (row = %d) \n", i);
        exit(1);
      }
  }

  // Output success result
  printf("---------------------------------------------------------------\n");
  printf("  Matrix is valid! \n");
  printf("---------------------------------------------------------------\n");
}

