src/glpspm.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpspm.c */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glphbm.h"
alpar@1
    26
#include "glprgr.h"
alpar@1
    27
#include "glpspm.h"
alpar@1
    28
alpar@1
    29
/***********************************************************************
alpar@1
    30
*  NAME
alpar@1
    31
*
alpar@1
    32
*  spm_create_mat - create general sparse matrix
alpar@1
    33
*
alpar@1
    34
*  SYNOPSIS
alpar@1
    35
*
alpar@1
    36
*  #include "glpspm.h"
alpar@1
    37
*  SPM *spm_create_mat(int m, int n);
alpar@1
    38
*
alpar@1
    39
*  DESCRIPTION
alpar@1
    40
*
alpar@1
    41
*  The routine spm_create_mat creates a general sparse matrix having
alpar@1
    42
*  m rows and n columns. Being created the matrix is zero (empty), i.e.
alpar@1
    43
*  has no elements.
alpar@1
    44
*
alpar@1
    45
*  RETURNS
alpar@1
    46
*
alpar@1
    47
*  The routine returns a pointer to the matrix created. */
alpar@1
    48
alpar@1
    49
SPM *spm_create_mat(int m, int n)
alpar@1
    50
{     SPM *A;
alpar@1
    51
      xassert(0 <= m && m < INT_MAX);
alpar@1
    52
      xassert(0 <= n && n < INT_MAX);
alpar@1
    53
      A = xmalloc(sizeof(SPM));
alpar@1
    54
      A->m = m;
alpar@1
    55
      A->n = n;
alpar@1
    56
      if (m == 0 || n == 0)
alpar@1
    57
      {  A->pool = NULL;
alpar@1
    58
         A->row = NULL;
alpar@1
    59
         A->col = NULL;
alpar@1
    60
      }
alpar@1
    61
      else
alpar@1
    62
      {  int i, j;
alpar@1
    63
         A->pool = dmp_create_pool();
alpar@1
    64
         A->row = xcalloc(1+m, sizeof(SPME *));
alpar@1
    65
         for (i = 1; i <= m; i++) A->row[i] = NULL;
alpar@1
    66
         A->col = xcalloc(1+n, sizeof(SPME *));
alpar@1
    67
         for (j = 1; j <= n; j++) A->col[j] = NULL;
alpar@1
    68
      }
alpar@1
    69
      return A;
alpar@1
    70
}
alpar@1
    71
alpar@1
    72
/***********************************************************************
alpar@1
    73
*  NAME
alpar@1
    74
*
alpar@1
    75
*  spm_new_elem - add new element to sparse matrix
alpar@1
    76
*
alpar@1
    77
*  SYNOPSIS
alpar@1
    78
*
alpar@1
    79
*  #include "glpspm.h"
alpar@1
    80
*  SPME *spm_new_elem(SPM *A, int i, int j, double val);
alpar@1
    81
*
alpar@1
    82
*  DESCRIPTION
alpar@1
    83
*
alpar@1
    84
*  The routine spm_new_elem adds a new element to the specified sparse
alpar@1
    85
*  matrix. Parameters i, j, and val specify the row number, the column
alpar@1
    86
*  number, and a numerical value of the element, respectively.
alpar@1
    87
*
alpar@1
    88
*  RETURNS
alpar@1
    89
*
alpar@1
    90
*  The routine returns a pointer to the new element added. */
alpar@1
    91
alpar@1
    92
SPME *spm_new_elem(SPM *A, int i, int j, double val)
alpar@1
    93
{     SPME *e;
alpar@1
    94
      xassert(1 <= i && i <= A->m);
alpar@1
    95
      xassert(1 <= j && j <= A->n);
alpar@1
    96
      e = dmp_get_atom(A->pool, sizeof(SPME));
alpar@1
    97
      e->i = i;
alpar@1
    98
      e->j = j;
alpar@1
    99
      e->val = val;
alpar@1
   100
      e->r_prev = NULL;
alpar@1
   101
      e->r_next = A->row[i];
alpar@1
   102
      if (e->r_next != NULL) e->r_next->r_prev = e;
alpar@1
   103
      e->c_prev = NULL;
alpar@1
   104
      e->c_next = A->col[j];
alpar@1
   105
      if (e->c_next != NULL) e->c_next->c_prev = e;
alpar@1
   106
      A->row[i] = A->col[j] = e;
alpar@1
   107
      return e;
alpar@1
   108
}
alpar@1
   109
alpar@1
   110
/***********************************************************************
alpar@1
   111
*  NAME
alpar@1
   112
*
alpar@1
   113
*  spm_delete_mat - delete general sparse matrix
alpar@1
   114
*
alpar@1
   115
*  SYNOPSIS
alpar@1
   116
*
alpar@1
   117
*  #include "glpspm.h"
alpar@1
   118
*  void spm_delete_mat(SPM *A);
alpar@1
   119
*
alpar@1
   120
*  DESCRIPTION
alpar@1
   121
*
alpar@1
   122
*  The routine deletes the specified general sparse matrix freeing all
alpar@1
   123
*  the memory allocated to this object. */
alpar@1
   124
alpar@1
   125
void spm_delete_mat(SPM *A)
alpar@1
   126
{     /* delete sparse matrix */
alpar@1
   127
      if (A->pool != NULL) dmp_delete_pool(A->pool);
alpar@1
   128
      if (A->row != NULL) xfree(A->row);
alpar@1
   129
      if (A->col != NULL) xfree(A->col);
alpar@1
   130
      xfree(A);
alpar@1
   131
      return;
alpar@1
   132
}
alpar@1
   133
alpar@1
   134
/***********************************************************************
alpar@1
   135
*  NAME
alpar@1
   136
*
alpar@1
   137
*  spm_test_mat_e - create test sparse matrix of E(n,c) class
alpar@1
   138
*
alpar@1
   139
*  SYNOPSIS
alpar@1
   140
*
alpar@1
   141
*  #include "glpspm.h"
alpar@1
   142
*  SPM *spm_test_mat_e(int n, int c);
alpar@1
   143
*
alpar@1
   144
*  DESCRIPTION
alpar@1
   145
*
alpar@1
   146
*  The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
alpar@1
   147
*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
alpar@1
   148
*  Methods for Sparse Matrices. Springer-Verlag, 1983.
alpar@1
   149
*
alpar@1
   150
*  Matrix of E(n,c) class is a symmetric positive definite matrix of
alpar@1
   151
*  the order n. It has the number 4 on its main diagonal and the number
alpar@1
   152
*  -1 on its four co-diagonals, two of which are neighbour to the main
alpar@1
   153
*  diagonal and two others are shifted from the main diagonal on the
alpar@1
   154
*  distance c.
alpar@1
   155
*
alpar@1
   156
*  It is necessary that n >= 3 and 2 <= c <= n-1.
alpar@1
   157
*
alpar@1
   158
*  RETURNS
alpar@1
   159
*
alpar@1
   160
*  The routine returns a pointer to the matrix created. */
alpar@1
   161
alpar@1
   162
SPM *spm_test_mat_e(int n, int c)
alpar@1
   163
{     SPM *A;
alpar@1
   164
      int i;
alpar@1
   165
      xassert(n >= 3 && 2 <= c && c <= n-1);
alpar@1
   166
      A = spm_create_mat(n, n);
alpar@1
   167
      for (i = 1; i <= n; i++)
alpar@1
   168
         spm_new_elem(A, i, i, 4.0);
alpar@1
   169
      for (i = 1; i <= n-1; i++)
alpar@1
   170
      {  spm_new_elem(A, i, i+1, -1.0);
alpar@1
   171
         spm_new_elem(A, i+1, i, -1.0);
alpar@1
   172
      }
alpar@1
   173
      for (i = 1; i <= n-c; i++)
alpar@1
   174
      {  spm_new_elem(A, i, i+c, -1.0);
alpar@1
   175
         spm_new_elem(A, i+c, i, -1.0);
alpar@1
   176
      }
alpar@1
   177
      return A;
alpar@1
   178
}
alpar@1
   179
alpar@1
   180
/***********************************************************************
alpar@1
   181
*  NAME
alpar@1
   182
*
alpar@1
   183
*  spm_test_mat_d - create test sparse matrix of D(n,c) class
alpar@1
   184
*
alpar@1
   185
*  SYNOPSIS
alpar@1
   186
*
alpar@1
   187
*  #include "glpspm.h"
alpar@1
   188
*  SPM *spm_test_mat_d(int n, int c);
alpar@1
   189
*
alpar@1
   190
*  DESCRIPTION
alpar@1
   191
*
alpar@1
   192
*  The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
alpar@1
   193
*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
alpar@1
   194
*  Methods for Sparse Matrices. Springer-Verlag, 1983.
alpar@1
   195
*
alpar@1
   196
*  Matrix of D(n,c) class is a non-singular matrix of the order n. It
alpar@1
   197
*  has unity main diagonal, three co-diagonals above the main diagonal
alpar@1
   198
*  on the distance c, which are cyclically continued below the main
alpar@1
   199
*  diagonal, and a triangle block of the size 10x10 in the upper right
alpar@1
   200
*  corner.
alpar@1
   201
*
alpar@1
   202
*  It is necessary that n >= 14 and 1 <= c <= n-13.
alpar@1
   203
*
alpar@1
   204
*  RETURNS
alpar@1
   205
*
alpar@1
   206
*  The routine returns a pointer to the matrix created. */
alpar@1
   207
alpar@1
   208
SPM *spm_test_mat_d(int n, int c)
alpar@1
   209
{     SPM *A;
alpar@1
   210
      int i, j;
alpar@1
   211
      xassert(n >= 14 && 1 <= c && c <= n-13);
alpar@1
   212
      A = spm_create_mat(n, n);
alpar@1
   213
      for (i = 1; i <= n; i++)
alpar@1
   214
         spm_new_elem(A, i, i, 1.0);
alpar@1
   215
      for (i = 1; i <= n-c; i++)
alpar@1
   216
         spm_new_elem(A, i, i+c, (double)(i+1));
alpar@1
   217
      for (i = n-c+1; i <= n; i++)
alpar@1
   218
         spm_new_elem(A, i, i-n+c, (double)(i+1));
alpar@1
   219
      for (i = 1; i <= n-c-1; i++)
alpar@1
   220
         spm_new_elem(A, i, i+c+1, (double)(-i));
alpar@1
   221
      for (i = n-c; i <= n; i++)
alpar@1
   222
         spm_new_elem(A, i, i-n+c+1, (double)(-i));
alpar@1
   223
      for (i = 1; i <= n-c-2; i++)
alpar@1
   224
         spm_new_elem(A, i, i+c+2, 16.0);
alpar@1
   225
      for (i = n-c-1; i <= n; i++)
alpar@1
   226
         spm_new_elem(A, i, i-n+c+2, 16.0);
alpar@1
   227
      for (j = 1; j <= 10; j++)
alpar@1
   228
         for (i = 1; i <= 11-j; i++)
alpar@1
   229
            spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
alpar@1
   230
      return A;
alpar@1
   231
}
alpar@1
   232
alpar@1
   233
/***********************************************************************
alpar@1
   234
*  NAME
alpar@1
   235
*
alpar@1
   236
*  spm_show_mat - write sparse matrix pattern in BMP file format
alpar@1
   237
*
alpar@1
   238
*  SYNOPSIS
alpar@1
   239
*
alpar@1
   240
*  #include "glpspm.h"
alpar@1
   241
*  int spm_show_mat(const SPM *A, const char *fname);
alpar@1
   242
*
alpar@1
   243
*  DESCRIPTION
alpar@1
   244
*
alpar@1
   245
*  The routine spm_show_mat writes pattern of the specified sparse
alpar@1
   246
*  matrix in uncompressed BMP file format (Windows bitmap) to a binary
alpar@1
   247
*  file whose name is specified by the character string fname.
alpar@1
   248
*
alpar@1
   249
*  Each pixel corresponds to one matrix element. The pixel colors have
alpar@1
   250
*  the following meaning:
alpar@1
   251
*
alpar@1
   252
*  Black    structurally zero element
alpar@1
   253
*  White    positive element
alpar@1
   254
*  Cyan     negative element
alpar@1
   255
*  Green    zero element
alpar@1
   256
*  Red      duplicate element
alpar@1
   257
*
alpar@1
   258
*  RETURNS
alpar@1
   259
*
alpar@1
   260
*  If no error occured, the routine returns zero. Otherwise, it prints
alpar@1
   261
*  an appropriate error message and returns non-zero. */
alpar@1
   262
alpar@1
   263
int spm_show_mat(const SPM *A, const char *fname)
alpar@1
   264
{     int m = A->m;
alpar@1
   265
      int n = A->n;
alpar@1
   266
      int i, j, k, ret;
alpar@1
   267
      char *map;
alpar@1
   268
      xprintf("spm_show_mat: writing matrix pattern to `%s'...\n",
alpar@1
   269
         fname);
alpar@1
   270
      xassert(1 <= m && m <= 32767);
alpar@1
   271
      xassert(1 <= n && n <= 32767);
alpar@1
   272
      map = xmalloc(m * n);
alpar@1
   273
      memset(map, 0x08, m * n);
alpar@1
   274
      for (i = 1; i <= m; i++)
alpar@1
   275
      {  SPME *e;
alpar@1
   276
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   277
         {  j = e->j;
alpar@1
   278
            xassert(1 <= j && j <= n);
alpar@1
   279
            k = n * (i - 1) + (j - 1);
alpar@1
   280
            if (map[k] != 0x08)
alpar@1
   281
               map[k] = 0x0C;
alpar@1
   282
            else if (e->val > 0.0)
alpar@1
   283
               map[k] = 0x0F;
alpar@1
   284
            else if (e->val < 0.0)
alpar@1
   285
               map[k] = 0x0B;
alpar@1
   286
            else
alpar@1
   287
               map[k] = 0x0A;
alpar@1
   288
         }
alpar@1
   289
      }
alpar@1
   290
      ret = rgr_write_bmp16(fname, m, n, map);
alpar@1
   291
      xfree(map);
alpar@1
   292
      return ret;
alpar@1
   293
}
alpar@1
   294
alpar@1
   295
/***********************************************************************
alpar@1
   296
*  NAME
alpar@1
   297
*
alpar@1
   298
*  spm_read_hbm - read sparse matrix in Harwell-Boeing format
alpar@1
   299
*
alpar@1
   300
*  SYNOPSIS
alpar@1
   301
*
alpar@1
   302
*  #include "glpspm.h"
alpar@1
   303
*  SPM *spm_read_hbm(const char *fname);
alpar@1
   304
*
alpar@1
   305
*  DESCRIPTION
alpar@1
   306
*
alpar@1
   307
*  The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
alpar@1
   308
*  format from a text file whose name is the character string fname.
alpar@1
   309
*
alpar@1
   310
*  Detailed description of the Harwell-Boeing format recognised by this
alpar@1
   311
*  routine can be found in the following report:
alpar@1
   312
*
alpar@1
   313
*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
alpar@1
   314
*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
alpar@1
   315
*
alpar@1
   316
*  NOTE
alpar@1
   317
*
alpar@1
   318
*  The routine spm_read_hbm reads the matrix "as is", due to which zero
alpar@1
   319
*  and/or duplicate elements can appear in the matrix.
alpar@1
   320
*
alpar@1
   321
*  RETURNS
alpar@1
   322
*
alpar@1
   323
*  If no error occured, the routine returns a pointer to the matrix
alpar@1
   324
*  created. Otherwise, the routine prints an appropriate error message
alpar@1
   325
*  and returns NULL. */
alpar@1
   326
alpar@1
   327
SPM *spm_read_hbm(const char *fname)
alpar@1
   328
{     SPM *A = NULL;
alpar@1
   329
      HBM *hbm;
alpar@1
   330
      int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
alpar@1
   331
      double val, *values;
alpar@1
   332
      char *mxtype;
alpar@1
   333
      hbm = hbm_read_mat(fname);
alpar@1
   334
      if (hbm == NULL)
alpar@1
   335
      {  xprintf("spm_read_hbm: unable to read matrix\n");
alpar@1
   336
         goto fini;
alpar@1
   337
      }
alpar@1
   338
      mxtype = hbm->mxtype;
alpar@1
   339
      nrow = hbm->nrow;
alpar@1
   340
      ncol = hbm->ncol;
alpar@1
   341
      nnzero = hbm->nnzero;
alpar@1
   342
      colptr = hbm->colptr;
alpar@1
   343
      rowind = hbm->rowind;
alpar@1
   344
      values = hbm->values;
alpar@1
   345
      if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
alpar@1
   346
            strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
alpar@1
   347
            strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
alpar@1
   348
      {  xprintf("spm_read_hbm: matrix type `%s' not supported\n",
alpar@1
   349
            mxtype);
alpar@1
   350
         goto fini;
alpar@1
   351
      }
alpar@1
   352
      A = spm_create_mat(nrow, ncol);
alpar@1
   353
      if (mxtype[1] == 'S' || mxtype[1] == 'U')
alpar@1
   354
         xassert(nrow == ncol);
alpar@1
   355
      for (j = 1; j <= ncol; j++)
alpar@1
   356
      {  beg = colptr[j];
alpar@1
   357
         end = colptr[j+1];
alpar@1
   358
         xassert(1 <= beg && beg <= end && end <= nnzero + 1);
alpar@1
   359
         for (ptr = beg; ptr < end; ptr++)
alpar@1
   360
         {  i = rowind[ptr];
alpar@1
   361
            xassert(1 <= i && i <= nrow);
alpar@1
   362
            if (mxtype[0] == 'R')
alpar@1
   363
               val = values[ptr];
alpar@1
   364
            else
alpar@1
   365
               val = 1.0;
alpar@1
   366
            spm_new_elem(A, i, j, val);
alpar@1
   367
            if (mxtype[1] == 'S' && i != j)
alpar@1
   368
               spm_new_elem(A, j, i, val);
alpar@1
   369
         }
alpar@1
   370
      }
alpar@1
   371
fini: if (hbm != NULL) hbm_free_mat(hbm);
alpar@1
   372
      return A;
alpar@1
   373
}
alpar@1
   374
alpar@1
   375
/***********************************************************************
alpar@1
   376
*  NAME
alpar@1
   377
*
alpar@1
   378
*  spm_count_nnz - determine number of non-zeros in sparse matrix
alpar@1
   379
*
alpar@1
   380
*  SYNOPSIS
alpar@1
   381
*
alpar@1
   382
*  #include "glpspm.h"
alpar@1
   383
*  int spm_count_nnz(const SPM *A);
alpar@1
   384
*
alpar@1
   385
*  RETURNS
alpar@1
   386
*
alpar@1
   387
*  The routine spm_count_nnz returns the number of structural non-zero
alpar@1
   388
*  elements in the specified sparse matrix. */
alpar@1
   389
alpar@1
   390
int spm_count_nnz(const SPM *A)
alpar@1
   391
{     SPME *e;
alpar@1
   392
      int i, nnz = 0;
alpar@1
   393
      for (i = 1; i <= A->m; i++)
alpar@1
   394
         for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
alpar@1
   395
      return nnz;
alpar@1
   396
}
alpar@1
   397
alpar@1
   398
/***********************************************************************
alpar@1
   399
*  NAME
alpar@1
   400
*
alpar@1
   401
*  spm_drop_zeros - remove zero elements from sparse matrix
alpar@1
   402
*
alpar@1
   403
*  SYNOPSIS
alpar@1
   404
*
alpar@1
   405
*  #include "glpspm.h"
alpar@1
   406
*  int spm_drop_zeros(SPM *A, double eps);
alpar@1
   407
*
alpar@1
   408
*  DESCRIPTION
alpar@1
   409
*
alpar@1
   410
*  The routine spm_drop_zeros removes all elements from the specified
alpar@1
   411
*  sparse matrix, whose absolute value is less than eps.
alpar@1
   412
*
alpar@1
   413
*  If the parameter eps is 0, only zero elements are removed from the
alpar@1
   414
*  matrix.
alpar@1
   415
*
alpar@1
   416
*  RETURNS
alpar@1
   417
*
alpar@1
   418
*  The routine returns the number of elements removed. */
alpar@1
   419
alpar@1
   420
int spm_drop_zeros(SPM *A, double eps)
alpar@1
   421
{     SPME *e, *next;
alpar@1
   422
      int i, count = 0;
alpar@1
   423
      for (i = 1; i <= A->m; i++)
alpar@1
   424
      {  for (e = A->row[i]; e != NULL; e = next)
alpar@1
   425
         {  next = e->r_next;
alpar@1
   426
            if (e->val == 0.0 || fabs(e->val) < eps)
alpar@1
   427
            {  /* remove element from the row list */
alpar@1
   428
               if (e->r_prev == NULL)
alpar@1
   429
                  A->row[e->i] = e->r_next;
alpar@1
   430
               else
alpar@1
   431
                  e->r_prev->r_next = e->r_next;
alpar@1
   432
               if (e->r_next == NULL)
alpar@1
   433
                  ;
alpar@1
   434
               else
alpar@1
   435
                  e->r_next->r_prev = e->r_prev;
alpar@1
   436
               /* remove element from the column list */
alpar@1
   437
               if (e->c_prev == NULL)
alpar@1
   438
                  A->col[e->j] = e->c_next;
alpar@1
   439
               else
alpar@1
   440
                  e->c_prev->c_next = e->c_next;
alpar@1
   441
               if (e->c_next == NULL)
alpar@1
   442
                  ;
alpar@1
   443
               else
alpar@1
   444
                  e->c_next->c_prev = e->c_prev;
alpar@1
   445
               /* return element to the memory pool */
alpar@1
   446
               dmp_free_atom(A->pool, e, sizeof(SPME));
alpar@1
   447
               count++;
alpar@1
   448
            }
alpar@1
   449
         }
alpar@1
   450
      }
alpar@1
   451
      return count;
alpar@1
   452
}
alpar@1
   453
alpar@1
   454
/***********************************************************************
alpar@1
   455
*  NAME
alpar@1
   456
*
alpar@1
   457
*  spm_read_mat - read sparse matrix from text file
alpar@1
   458
*
alpar@1
   459
*  SYNOPSIS
alpar@1
   460
*
alpar@1
   461
*  #include "glpspm.h"
alpar@1
   462
*  SPM *spm_read_mat(const char *fname);
alpar@1
   463
*
alpar@1
   464
*  DESCRIPTION
alpar@1
   465
*
alpar@1
   466
*  The routine reads a sparse matrix from a text file whose name is
alpar@1
   467
*  specified by the parameter fname.
alpar@1
   468
*
alpar@1
   469
*  For the file format see description of the routine spm_write_mat.
alpar@1
   470
*
alpar@1
   471
*  RETURNS
alpar@1
   472
*
alpar@1
   473
*  On success the routine returns a pointer to the matrix created,
alpar@1
   474
*  otherwise NULL. */
alpar@1
   475
alpar@1
   476
#if 1
alpar@1
   477
SPM *spm_read_mat(const char *fname)
alpar@1
   478
{     xassert(fname != fname);
alpar@1
   479
      return NULL;
alpar@1
   480
}
alpar@1
   481
#else
alpar@1
   482
SPM *spm_read_mat(const char *fname)
alpar@1
   483
{     SPM *A = NULL;
alpar@1
   484
      PDS *pds;
alpar@1
   485
      jmp_buf jump;
alpar@1
   486
      int i, j, k, m, n, nnz, fail = 0;
alpar@1
   487
      double val;
alpar@1
   488
      xprintf("spm_read_mat: reading matrix from `%s'...\n", fname);
alpar@1
   489
      pds = pds_open_file(fname);
alpar@1
   490
      if (pds == NULL)
alpar@1
   491
      {  xprintf("spm_read_mat: unable to open `%s' - %s\n", fname,
alpar@1
   492
            strerror(errno));
alpar@1
   493
         fail = 1;
alpar@1
   494
         goto done;
alpar@1
   495
      }
alpar@1
   496
      if (setjmp(jump))
alpar@1
   497
      {  fail = 1;
alpar@1
   498
         goto done;
alpar@1
   499
      }
alpar@1
   500
      pds_set_jump(pds, jump);
alpar@1
   501
      /* number of rows, number of columns, number of non-zeros */
alpar@1
   502
      m = pds_scan_int(pds);
alpar@1
   503
      if (m < 0)
alpar@1
   504
         pds_error(pds, "invalid number of rows\n");
alpar@1
   505
      n = pds_scan_int(pds);
alpar@1
   506
      if (n < 0)
alpar@1
   507
         pds_error(pds, "invalid number of columns\n");
alpar@1
   508
      nnz = pds_scan_int(pds);
alpar@1
   509
      if (nnz < 0)
alpar@1
   510
         pds_error(pds, "invalid number of non-zeros\n");
alpar@1
   511
      /* create matrix */
alpar@1
   512
      xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
alpar@1
   513
         m, n, nnz);
alpar@1
   514
      A = spm_create_mat(m, n);
alpar@1
   515
      /* read matrix elements */
alpar@1
   516
      for (k = 1; k <= nnz; k++)
alpar@1
   517
      {  /* row index, column index, element value */
alpar@1
   518
         i = pds_scan_int(pds);
alpar@1
   519
         if (!(1 <= i && i <= m))
alpar@1
   520
            pds_error(pds, "row index out of range\n");
alpar@1
   521
         j = pds_scan_int(pds);
alpar@1
   522
         if (!(1 <= j && j <= n))
alpar@1
   523
            pds_error(pds, "column index out of range\n");
alpar@1
   524
         val = pds_scan_num(pds);
alpar@1
   525
         /* add new element to the matrix */
alpar@1
   526
         spm_new_elem(A, i, j, val);
alpar@1
   527
      }
alpar@1
   528
      xprintf("spm_read_mat: %d lines were read\n", pds->count);
alpar@1
   529
done: if (pds != NULL) pds_close_file(pds);
alpar@1
   530
      if (fail && A != NULL) spm_delete_mat(A), A = NULL;
alpar@1
   531
      return A;
alpar@1
   532
}
alpar@1
   533
#endif
alpar@1
   534
alpar@1
   535
/***********************************************************************
alpar@1
   536
*  NAME
alpar@1
   537
*
alpar@1
   538
*  spm_write_mat - write sparse matrix to text file
alpar@1
   539
*
alpar@1
   540
*  SYNOPSIS
alpar@1
   541
*
alpar@1
   542
*  #include "glpspm.h"
alpar@1
   543
*  int spm_write_mat(const SPM *A, const char *fname);
alpar@1
   544
*
alpar@1
   545
*  DESCRIPTION
alpar@1
   546
*
alpar@1
   547
*  The routine spm_write_mat writes the specified sparse matrix to a
alpar@1
   548
*  text file whose name is specified by the parameter fname. This file
alpar@1
   549
*  can be read back with the routine spm_read_mat.
alpar@1
   550
*
alpar@1
   551
*  RETURNS
alpar@1
   552
*
alpar@1
   553
*  On success the routine returns zero, otherwise non-zero.
alpar@1
   554
*
alpar@1
   555
*  FILE FORMAT
alpar@1
   556
*
alpar@1
   557
*  The file created by the routine spm_write_mat is a plain text file,
alpar@1
   558
*  which contains the following information:
alpar@1
   559
*
alpar@1
   560
*     m n nnz
alpar@1
   561
*     row[1] col[1] val[1]
alpar@1
   562
*     row[2] col[2] val[2]
alpar@1
   563
*     . . .
alpar@1
   564
*     row[nnz] col[nnz] val[nnz]
alpar@1
   565
*
alpar@1
   566
*  where:
alpar@1
   567
*  m is the number of rows;
alpar@1
   568
*  n is the number of columns;
alpar@1
   569
*  nnz is the number of non-zeros;
alpar@1
   570
*  row[k], k = 1,...,nnz, are row indices;
alpar@1
   571
*  col[k], k = 1,...,nnz, are column indices;
alpar@1
   572
*  val[k], k = 1,...,nnz, are element values. */
alpar@1
   573
alpar@1
   574
#if 1
alpar@1
   575
int spm_write_mat(const SPM *A, const char *fname)
alpar@1
   576
{     xassert(A != A);
alpar@1
   577
      xassert(fname != fname);
alpar@1
   578
      return 0;
alpar@1
   579
}
alpar@1
   580
#else
alpar@1
   581
int spm_write_mat(const SPM *A, const char *fname)
alpar@1
   582
{     FILE *fp;
alpar@1
   583
      int i, nnz, ret = 0;
alpar@1
   584
      xprintf("spm_write_mat: writing matrix to `%s'...\n", fname);
alpar@1
   585
      fp = fopen(fname, "w");
alpar@1
   586
      if (fp == NULL)
alpar@1
   587
      {  xprintf("spm_write_mat: unable to create `%s' - %s\n", fname,
alpar@1
   588
            strerror(errno));
alpar@1
   589
         ret = 1;
alpar@1
   590
         goto done;
alpar@1
   591
      }
alpar@1
   592
      /* number of rows, number of columns, number of non-zeros */
alpar@1
   593
      nnz = spm_count_nnz(A);
alpar@1
   594
      fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
alpar@1
   595
      /* walk through rows of the matrix */
alpar@1
   596
      for (i = 1; i <= A->m; i++)
alpar@1
   597
      {  SPME *e;
alpar@1
   598
         /* walk through elements of i-th row */
alpar@1
   599
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   600
         {  /* row index, column index, element value */
alpar@1
   601
            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
alpar@1
   602
         }
alpar@1
   603
      }
alpar@1
   604
      fflush(fp);
alpar@1
   605
      if (ferror(fp))
alpar@1
   606
      {  xprintf("spm_write_mat: writing error on `%s' - %s\n", fname,
alpar@1
   607
            strerror(errno));
alpar@1
   608
         ret = 1;
alpar@1
   609
         goto done;
alpar@1
   610
      }
alpar@1
   611
      xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
alpar@1
   612
done: if (fp != NULL) fclose(fp);
alpar@1
   613
      return ret;
alpar@1
   614
}
alpar@1
   615
#endif
alpar@1
   616
alpar@1
   617
/***********************************************************************
alpar@1
   618
*  NAME
alpar@1
   619
*
alpar@1
   620
*  spm_transpose - transpose sparse matrix
alpar@1
   621
*
alpar@1
   622
*  SYNOPSIS
alpar@1
   623
*
alpar@1
   624
*  #include "glpspm.h"
alpar@1
   625
*  SPM *spm_transpose(const SPM *A);
alpar@1
   626
*
alpar@1
   627
*  RETURNS
alpar@1
   628
*
alpar@1
   629
*  The routine computes and returns sparse matrix B, which is a matrix
alpar@1
   630
*  transposed to sparse matrix A. */
alpar@1
   631
alpar@1
   632
SPM *spm_transpose(const SPM *A)
alpar@1
   633
{     SPM *B;
alpar@1
   634
      int i;
alpar@1
   635
      B = spm_create_mat(A->n, A->m);
alpar@1
   636
      for (i = 1; i <= A->m; i++)
alpar@1
   637
      {  SPME *e;
alpar@1
   638
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   639
            spm_new_elem(B, e->j, i, e->val);
alpar@1
   640
      }
alpar@1
   641
      return B;
alpar@1
   642
}
alpar@1
   643
alpar@1
   644
SPM *spm_add_sym(const SPM *A, const SPM *B)
alpar@1
   645
{     /* add two sparse matrices (symbolic phase) */
alpar@1
   646
      SPM *C;
alpar@1
   647
      int i, j, *flag;
alpar@1
   648
      xassert(A->m == B->m);
alpar@1
   649
      xassert(A->n == B->n);
alpar@1
   650
      /* create resultant matrix */
alpar@1
   651
      C = spm_create_mat(A->m, A->n);
alpar@1
   652
      /* allocate and clear the flag array */
alpar@1
   653
      flag = xcalloc(1+C->n, sizeof(int));
alpar@1
   654
      for (j = 1; j <= C->n; j++)
alpar@1
   655
         flag[j] = 0;
alpar@1
   656
      /* compute pattern of C = A + B */
alpar@1
   657
      for (i = 1; i <= C->m; i++)
alpar@1
   658
      {  SPME *e;
alpar@1
   659
         /* at the beginning i-th row of C is empty */
alpar@1
   660
         /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
alpar@1
   661
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   662
         {  /* (note that i-th row of A may have duplicate elements) */
alpar@1
   663
            j = e->j;
alpar@1
   664
            if (!flag[j])
alpar@1
   665
            {  spm_new_elem(C, i, j, 0.0);
alpar@1
   666
               flag[j] = 1;
alpar@1
   667
            }
alpar@1
   668
         }
alpar@1
   669
         /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
alpar@1
   670
         for (e = B->row[i]; e != NULL; e = e->r_next)
alpar@1
   671
         {  /* (note that i-th row of B may have duplicate elements) */
alpar@1
   672
            j = e->j;
alpar@1
   673
            if (!flag[j])
alpar@1
   674
            {  spm_new_elem(C, i, j, 0.0);
alpar@1
   675
               flag[j] = 1;
alpar@1
   676
            }
alpar@1
   677
         }
alpar@1
   678
         /* reset the flag array */
alpar@1
   679
         for (e = C->row[i]; e != NULL; e = e->r_next)
alpar@1
   680
            flag[e->j] = 0;
alpar@1
   681
      }
alpar@1
   682
      /* check and deallocate the flag array */
alpar@1
   683
      for (j = 1; j <= C->n; j++)
alpar@1
   684
         xassert(!flag[j]);
alpar@1
   685
      xfree(flag);
alpar@1
   686
      return C;
alpar@1
   687
}
alpar@1
   688
alpar@1
   689
void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
alpar@1
   690
      const SPM *B)
alpar@1
   691
{     /* add two sparse matrices (numeric phase) */
alpar@1
   692
      int i, j;
alpar@1
   693
      double *work;
alpar@1
   694
      /* allocate and clear the working array */
alpar@1
   695
      work = xcalloc(1+C->n, sizeof(double));
alpar@1
   696
      for (j = 1; j <= C->n; j++)
alpar@1
   697
         work[j] = 0.0;
alpar@1
   698
      /* compute matrix C = alfa * A + beta * B */
alpar@1
   699
      for (i = 1; i <= C->n; i++)
alpar@1
   700
      {  SPME *e;
alpar@1
   701
         /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
alpar@1
   702
         /* (note that A and/or B may have duplicate elements) */
alpar@1
   703
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   704
            work[e->j] += alfa * e->val;
alpar@1
   705
         for (e = B->row[i]; e != NULL; e = e->r_next)
alpar@1
   706
            work[e->j] += beta * e->val;
alpar@1
   707
         /* (i-th row of C) := work, work := 0 */
alpar@1
   708
         for (e = C->row[i]; e != NULL; e = e->r_next)
alpar@1
   709
         {  j = e->j;
alpar@1
   710
            e->val = work[j];
alpar@1
   711
            work[j] = 0.0;
alpar@1
   712
         }
alpar@1
   713
      }
alpar@1
   714
      /* check and deallocate the working array */
alpar@1
   715
      for (j = 1; j <= C->n; j++)
alpar@1
   716
         xassert(work[j] == 0.0);
alpar@1
   717
      xfree(work);
alpar@1
   718
      return;
alpar@1
   719
}
alpar@1
   720
alpar@1
   721
SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
alpar@1
   722
{     /* add two sparse matrices (driver routine) */
alpar@1
   723
      SPM *C;
alpar@1
   724
      C = spm_add_sym(A, B);
alpar@1
   725
      spm_add_num(C, alfa, A, beta, B);
alpar@1
   726
      return C;
alpar@1
   727
}
alpar@1
   728
alpar@1
   729
SPM *spm_mul_sym(const SPM *A, const SPM *B)
alpar@1
   730
{     /* multiply two sparse matrices (symbolic phase) */
alpar@1
   731
      int i, j, k, *flag;
alpar@1
   732
      SPM *C;
alpar@1
   733
      xassert(A->n == B->m);
alpar@1
   734
      /* create resultant matrix */
alpar@1
   735
      C = spm_create_mat(A->m, B->n);
alpar@1
   736
      /* allocate and clear the flag array */
alpar@1
   737
      flag = xcalloc(1+C->n, sizeof(int));
alpar@1
   738
      for (j = 1; j <= C->n; j++)
alpar@1
   739
         flag[j] = 0;
alpar@1
   740
      /* compute pattern of C = A * B */
alpar@1
   741
      for (i = 1; i <= C->m; i++)
alpar@1
   742
      {  SPME *e, *ee;
alpar@1
   743
         /* compute pattern of i-th row of C */
alpar@1
   744
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   745
         {  k = e->j;
alpar@1
   746
            for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
alpar@1
   747
            {  j = ee->j;
alpar@1
   748
               /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
alpar@1
   749
               if (!flag[j])
alpar@1
   750
               {  /* c[i,j] does not exist, so create it */
alpar@1
   751
                  spm_new_elem(C, i, j, 0.0);
alpar@1
   752
                  flag[j] = 1;
alpar@1
   753
               }
alpar@1
   754
            }
alpar@1
   755
         }
alpar@1
   756
         /* reset the flag array */
alpar@1
   757
         for (e = C->row[i]; e != NULL; e = e->r_next)
alpar@1
   758
            flag[e->j] = 0;
alpar@1
   759
      }
alpar@1
   760
      /* check and deallocate the flag array */
alpar@1
   761
      for (j = 1; j <= C->n; j++)
alpar@1
   762
         xassert(!flag[j]);
alpar@1
   763
      xfree(flag);
alpar@1
   764
      return C;
alpar@1
   765
}
alpar@1
   766
alpar@1
   767
void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
alpar@1
   768
{     /* multiply two sparse matrices (numeric phase) */
alpar@1
   769
      int i, j;
alpar@1
   770
      double *work;
alpar@1
   771
      /* allocate and clear the working array */
alpar@1
   772
      work = xcalloc(1+A->n, sizeof(double));
alpar@1
   773
      for (j = 1; j <= A->n; j++)
alpar@1
   774
         work[j] = 0.0;
alpar@1
   775
      /* compute matrix C = A * B */
alpar@1
   776
      for (i = 1; i <= C->m; i++)
alpar@1
   777
      {  SPME *e, *ee;
alpar@1
   778
         double temp;
alpar@1
   779
         /* work := (i-th row of A) */
alpar@1
   780
         /* (note that A may have duplicate elements) */
alpar@1
   781
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   782
            work[e->j] += e->val;
alpar@1
   783
         /* compute i-th row of C */
alpar@1
   784
         for (e = C->row[i]; e != NULL; e = e->r_next)
alpar@1
   785
         {  j = e->j;
alpar@1
   786
            /* c[i,j] := work * (j-th column of B) */
alpar@1
   787
            temp = 0.0;
alpar@1
   788
            for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
alpar@1
   789
               temp += work[ee->i] * ee->val;
alpar@1
   790
            e->val = temp;
alpar@1
   791
         }
alpar@1
   792
         /* reset the working array */
alpar@1
   793
         for (e = A->row[i]; e != NULL; e = e->r_next)
alpar@1
   794
            work[e->j] = 0.0;
alpar@1
   795
      }
alpar@1
   796
      /* check and deallocate the working array */
alpar@1
   797
      for (j = 1; j <= A->n; j++)
alpar@1
   798
         xassert(work[j] == 0.0);
alpar@1
   799
      xfree(work);
alpar@1
   800
      return;
alpar@1
   801
}
alpar@1
   802
alpar@1
   803
SPM *spm_mul_mat(const SPM *A, const SPM *B)
alpar@1
   804
{     /* multiply two sparse matrices (driver routine) */
alpar@1
   805
      SPM *C;
alpar@1
   806
      C = spm_mul_sym(A, B);
alpar@1
   807
      spm_mul_num(C, A, B);
alpar@1
   808
      return C;
alpar@1
   809
}
alpar@1
   810
alpar@1
   811
PER *spm_create_per(int n)
alpar@1
   812
{     /* create permutation matrix */
alpar@1
   813
      PER *P;
alpar@1
   814
      int k;
alpar@1
   815
      xassert(n >= 0);
alpar@1
   816
      P = xmalloc(sizeof(PER));
alpar@1
   817
      P->n = n;
alpar@1
   818
      P->row = xcalloc(1+n, sizeof(int));
alpar@1
   819
      P->col = xcalloc(1+n, sizeof(int));
alpar@1
   820
      /* initially it is identity matrix */
alpar@1
   821
      for (k = 1; k <= n; k++)
alpar@1
   822
         P->row[k] = P->col[k] = k;
alpar@1
   823
      return P;
alpar@1
   824
}
alpar@1
   825
alpar@1
   826
void spm_check_per(PER *P)
alpar@1
   827
{     /* check permutation matrix for correctness */
alpar@1
   828
      int i, j;
alpar@1
   829
      xassert(P->n >= 0);
alpar@1
   830
      for (i = 1; i <= P->n; i++)
alpar@1
   831
      {  j = P->row[i];
alpar@1
   832
         xassert(1 <= j && j <= P->n);
alpar@1
   833
         xassert(P->col[j] == i);
alpar@1
   834
      }
alpar@1
   835
      return;
alpar@1
   836
}
alpar@1
   837
alpar@1
   838
void spm_delete_per(PER *P)
alpar@1
   839
{     /* delete permutation matrix */
alpar@1
   840
      xfree(P->row);
alpar@1
   841
      xfree(P->col);
alpar@1
   842
      xfree(P);
alpar@1
   843
      return;
alpar@1
   844
}
alpar@1
   845
alpar@1
   846
/* eof */