/* glpmat2.c */

/*----------------------------------------------------------------------
-- Copyright (C) 2000, 2001, 2002 Andrew Makhorin <mao@mai2.rcnet.ru>,
--               Department for Applied Informatics, Moscow Aviation
--               Institute, Moscow, Russia. All rights reserved.
--
-- This file is a part of GLPK (GNU Linear Programming Kit).
--
-- GLPK is free software; you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2, or (at your option)
-- any later version.
--
-- GLPK is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-- License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with GLPK; see the file COPYING. If not, write to the Free
-- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
----------------------------------------------------------------------*/

#include <errno.h>
#include <float.h>
#include <stdio.h>
#include <string.h>
#include "glpimg.h"
#include "glpmat.h"
#include "glptext.h"

#define error print

/*----------------------------------------------------------------------
-- load_mat - read sparse matrix from text file using plain format.
--
-- *Synopsis*
--
-- #include "glpmat.h"
-- MAT *load_mat(char *fname);
--
-- *Description*
--
-- The load_mat routine reads a sparse matrix from the text file, whose
-- name is the character string fname, using plain format (this format
-- is described in comments to the routine save_mat; note that the order
-- of matrix elements may be arbitrary).
--
-- *Returns*
--
-- If the operation was successful, the load_mat routine returns a
-- pointer to the loaded matrix. Otherwise the routine returns NULL. */

MAT *load_mat(char *fname)
{     TEXT *text;
      MAT *A = NULL;
      int m, n, nz, i, j, k;
      double s, aij;
      print("load_mat: reading sparse matrix from `%s'...", fname);
      text = open_text(fname);
      if (text == NULL) goto fail;
      scan_token(text); if (text->err > 0) goto fail;
      if (!(text->token == T_NAME && strcmp(text->image, "MAT") == 0))
      {  error("%s:%d: missing marker `MAT'",
            text->file, text->line);
         goto fail;
      }
      scan_token(text); if (text->err > 0) goto fail;
      if (!(text->token == T_INT && text->t_int > 0))
      {  error("%s:%d: number of rows missing or invalid",
            text->file, text->line);
         goto fail;
      }
      m = text->t_int;
      scan_token(text); if (text->err > 0) goto fail;
      if (!(text->token == T_INT && text->t_int > 0))
      {  error("%s:%d: number of columns missing or invalid",
            text->file, text->line);
         goto fail;
      }
      n = text->t_int;
      scan_token(text); if (text->err > 0) goto fail;
      if (!(text->token == T_INT && text->t_int >= 0))
      {  error("%s:%d: number of non-zeros missing or invalid",
            text->file, text->line);
         goto fail;
      }
      nz = text->t_int;
      A = create_mat(m, n);
      for (k = 1; k <= nz; k++)
      {  scan_token(text); if (text->err > 0) goto fail;
         if (!(text->token == T_INT && 1 <= text->t_int &&
               text->t_int <= m))
         {  error("%s:%d: row number missing or invalid",
               text->file, text->line);
            goto fail;
         }
         i = text->t_int;
         scan_token(text); if (text->err > 0) goto fail;
         if (!(text->token == T_INT && 1 <= text->t_int &&
               text->t_int <= n))
         {  error("%s:%d: column number missing or invalid",
               text->file, text->line);
            goto fail;
         }
         j = text->t_int;
         scan_token(text); if (text->err > 0) goto fail;
         if (text->token == T_SPEC && text->image[0] == '+')
         {  s = +1.0;
            scan_token(text); if (text->err > 0) goto fail;
         }
         else if (text->token == T_SPEC && text->image[0] == '-')
         {  s = -1.0;
            scan_token(text); if (text->err > 0) goto fail;
         }
         else
            s = +1.0;
         if (!(text->token == T_INT || text->token == T_REAL))
         {  error("%s:%d: element value missing or invalid",
               text->file, text->line);
            goto fail;
         }
         aij = s * text->t_real;
         new_elem(A, i, j, aij);
      }
      scan_token(text); if (text->err > 0) goto fail;
      if (!(text->token == T_NAME && strcmp(text->image, "END") == 0))
      {  error("%s:%d: missing marker `END'",
            text->file, text->line);
         goto fail;
      }
      scan_token(text); if (text->err > 0) goto fail;
      if (text->token != T_EOF)
      {  error("%s:%d: extra symbols behind `END'",
            text->file, text->line);
         goto fail;
      }
      close_text(text);
      return A;
fail: if (text != NULL) close_text(text);
      if (A != NULL) delete_mat(A);
      return NULL;
}

/*----------------------------------------------------------------------
-- save_mat - write sparse matrix to text file using plain format.
--
-- *Synopsis*
--
-- #include "glpmat.h"
-- int save_mat(MAT *A, char *fname);
--
-- *Description*
--
-- The save_mat routine writes the sparse matrix A to the text file,
-- whose name is the character string fname, using the following plain
-- format:
--
--    MAT      \n
--    m n nz   \n
--    i j aij  \n    |
--    . . .          |-> nz lines
--    i j aij  \n    |
--    END      \n
--
-- where m is number of rows, n is number of columns, nz is number of
-- matrix elements, i is row number, j is column number, aij is value
-- of matrix elements. Total number of lines is nz+3.
--
-- The save_mat routine writes the matrix in row-wise manner. In order
-- that elements follow in the order of increasing column numbers the
-- sort_mat routine may be used before.
--
-- *Returns*
--
-- If the operation was successful, the save_mat routine returns zero.
-- Otherwise the routine returns non-zero. */

int save_mat(MAT *A, char *fname)
{     FILE *fp;
      int nz, i;
      print("save_mat: writing sparse matrix to `%s'...", fname);
      fp = fopen(fname, "w");
      if (fp == NULL)
      {  error("save_mat: unable to create `%s' - %s", fname,
            strerror(errno));
         goto fail;
      }
      fprintf(fp, "MAT\n");
      nz = count_nz(A, 0);
      fprintf(fp, "%d %d %d\n", A->m, A->n, nz);
      for (i = 1; i <= A->m; i++)
      {  ELEM *e;
         for (e = A->row[i]; e != NULL; e = e->row)
            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
      }
      fprintf(fp, "END\n");
      fflush(fp);
      if (ferror(fp))
      {  error("save_mat: writing error on `%s' - %s", fname,
            strerror(errno));
         goto fail;
      }
      fclose(fp);
      return 0;
fail: if (fp != NULL) fclose(fp);
      return 1;
}

/*----------------------------------------------------------------------
-- show_mat - output matrix pattern as raster image.
--
-- *Synopsis*
--
-- #include "glpmat.h"
-- int show_mat(MAT *A, int type, char *fname);
--
-- *Description*
--
-- The show_mat routine creates pattern of the matrix A in the form of
-- raster image and writes this image using default format to the file,
-- whose name is the character string fname.
--
-- The parameter type defines the type of the image.
--
-- If type is 0, the background is white, matrix elements are black.
--
-- If type is 1, the following colors are used:
--
-- gray:    there is no element in the position a[i,j] (background)
-- white:   a[i,j] > 0
-- cyan:    a[i,j] < 0
-- green:   a[i,j] = 0
-- red:     there are several elements in the position a[i,j].
--
-- In case of monochrome pattern the amount of memory is (m*n)/8 bytes,
-- and in case of color pattern the amount of memory is (m*n)/2 bytes,
-- where m and n are respectively number of rows and number of columns
-- of the matrix A.
--
-- *Returns*
--
-- If the operation completed successfully, the routine returns zero.
-- Otherwise the routine returns non-zero. */

int show_mat(MAT *A, int type, char *fname)
{     IMG *bmp;
      ELEM *e;
      int m = A->m, n = A->n, i, j, ret;
      print("show_mat: writing matrix pattern to `%s'...", fname);
      if (type == 0)
      {  /* monochrome pattern */
         bmp = create_img(IMG_2, n, m);
         for (i = 1; i <= m; i++)
         {  for (j = 1; j <= n; j++)
               set_imgval(bmp, j-1, i-1, IMG_WHITE);
            for (e = A->row[i]; e != NULL; e = e->row)
            {  j = e->j;
               set_imgval(bmp, j-1, i-1, IMG_BLACK);
            }
         }
         ret = save_img(bmp, fname);
         delete_img(bmp);
      }
      else if (type == 1)
      {  /* color pattern */
         bmp = create_img(IMG_16, n, m);
         for (i = 1; i <= m; i++)
         {  for (j = 1; j <= n; j++)
               set_imgval(bmp, j-1, i-1, IMG_DARKGRAY);
            for (e = A->row[i]; e != NULL; e = e->row)
            {  j = e->j;
               if (get_imgval(bmp, j-1, i-1) != IMG_DARKGRAY)
                  set_imgval(bmp, j-1, i-1, IMG_LIGHTRED);
               else if (e->val > 0.0)
                  set_imgval(bmp, j-1, i-1, IMG_WHITE);
               else if (e->val < 0.0)
                  set_imgval(bmp, j-1, i-1, IMG_LIGHTCYAN);
               else /* e->val == 0.0 */
                  set_imgval(bmp, j-1, i-1, IMG_LIGHTGREEN);
            }
         }
         ret = save_img(bmp, fname);
         delete_img(bmp);
      }
      else
         fault("show_mat: invalid image type");
      return ret;
}

/* eof */
