src/glpnet02.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
     1 /* glpnet02.c (permutations to block triangular form) */
     2 
     3 /***********************************************************************
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
     5 *
     6 *  This code is the result of translation of the Fortran subroutines
     7 *  MC13D and MC13E associated with the following paper:
     8 *
     9 *  I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
    10 *  form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
    11 *
    12 *  Use of ACM Algorithms is subject to the ACM Software Copyright and
    13 *  License Agreement. See <http://www.acm.org/publications/policies>.
    14 *
    15 *  The translation was made by Andrew Makhorin <mao@gnu.org>.
    16 *
    17 *  GLPK is free software: you can redistribute it and/or modify it
    18 *  under the terms of the GNU General Public License as published by
    19 *  the Free Software Foundation, either version 3 of the License, or
    20 *  (at your option) any later version.
    21 *
    22 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
    23 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    24 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    25 *  License for more details.
    26 *
    27 *  You should have received a copy of the GNU General Public License
    28 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    29 ***********************************************************************/
    30 
    31 #include "glpnet.h"
    32 
    33 /***********************************************************************
    34 *  NAME
    35 *
    36 *  mc13d - permutations to block triangular form
    37 *
    38 *  SYNOPSIS
    39 *
    40 *  #include "glpnet.h"
    41 *  int mc13d(int n, const int icn[], const int ip[], const int lenr[],
    42 *     int ior[], int ib[], int lowl[], int numb[], int prev[]);
    43 *
    44 *  DESCRIPTION
    45 *
    46 *  Given the column numbers of the nonzeros in each row of the sparse
    47 *  matrix, the routine mc13d finds a symmetric permutation that makes
    48 *  the matrix block lower triangular.
    49 *
    50 *  INPUT PARAMETERS
    51 *
    52 *  n     order of the matrix.
    53 *
    54 *  icn   array containing the column indices of the non-zeros. Those
    55 *        belonging to a single row must be contiguous but the ordering
    56 *        of column indices within each row is unimportant and wasted
    57 *        space between rows is permitted.
    58 *
    59 *  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
    60 *        first column index of a non-zero in row i.
    61 *
    62 *  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
    63 *
    64 *  OUTPUT PARAMETERS
    65 *
    66 *  ior   ior[i], i = 1,2,...,n, gives the position on the original
    67 *        ordering of the row or column which is in position i in the
    68 *        permuted form.
    69 *
    70 *  ib    ib[i], i = 1,2,...,num, is the row number in the permuted
    71 *        matrix of the beginning of block i, 1 <= num <= n.
    72 *
    73 *  WORKING ARRAYS
    74 *
    75 *  arp   working array of length [1+n], where arp[0] is not used.
    76 *        arp[i] is one less than the number of unsearched edges leaving
    77 *        node i. At the end of the algorithm it is set to a permutation
    78 *        which puts the matrix in block lower triangular form.
    79 *
    80 *  ib    working array of length [1+n], where ib[0] is not used.
    81 *        ib[i] is the position in the ordering of the start of the ith
    82 *        block. ib[n+1-i] holds the node number of the ith node on the
    83 *        stack.
    84 *
    85 *  lowl  working array of length [1+n], where lowl[0] is not used.
    86 *        lowl[i] is the smallest stack position of any node to which a
    87 *        path from node i has been found. It is set to n+1 when node i
    88 *        is removed from the stack.
    89 *
    90 *  numb  working array of length [1+n], where numb[0] is not used.
    91 *        numb[i] is the position of node i in the stack if it is on it,
    92 *        is the permuted order of node i for those nodes whose final
    93 *        position has been found and is otherwise zero.
    94 *
    95 *  prev  working array of length [1+n], where prev[0] is not used.
    96 *        prev[i] is the node at the end of the path when node i was
    97 *        placed on the stack.
    98 *
    99 *  RETURNS
   100 *
   101 *  The routine mc13d returns num, the number of blocks found. */
   102 
   103 int mc13d(int n, const int icn[], const int ip[], const int lenr[],
   104       int ior[], int ib[], int lowl[], int numb[], int prev[])
   105 {     int *arp = ior;
   106       int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
   107          nnm1, num, stp;
   108       /* icnt is the number of nodes whose positions in final ordering
   109          have been found. */
   110       icnt = 0;
   111       /* num is the number of blocks that have been found. */
   112       num = 0;
   113       nnm1 = n + n - 1;
   114       /* Initialization of arrays. */
   115       for (j = 1; j <= n; j++)
   116       {  numb[j] = 0;
   117          arp[j] = lenr[j] - 1;
   118       }
   119       for (isn = 1; isn <= n; isn++)
   120       {  /* Look for a starting node. */
   121          if (numb[isn] != 0) continue;
   122          iv = isn;
   123          /* ist is the number of nodes on the stack ... it is the stack
   124             pointer. */
   125          ist = 1;
   126          /* Put node iv at beginning of stack. */
   127          lowl[iv] = numb[iv] = 1;
   128          ib[n] = iv;
   129          /* The body of this loop puts a new node on the stack or
   130             backtracks. */
   131          for (dummy = 1; dummy <= nnm1; dummy++)
   132          {  i1 = arp[iv];
   133             /* Have all edges leaving node iv been searched? */
   134             if (i1 >= 0)
   135             {  i2 = ip[iv] + lenr[iv] - 1;
   136                i1 = i2 - i1;
   137                /* Look at edges leaving node iv until one enters a new
   138                   node or all edges are exhausted. */
   139                for (ii = i1; ii <= i2; ii++)
   140                {  iw = icn[ii];
   141                   /* Has node iw been on stack already? */
   142                   if (numb[iw] == 0) goto L70;
   143                   /* Update value of lowl[iv] if necessary. */
   144                   if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
   145                }
   146                /* There are no more edges leaving node iv. */
   147                arp[iv] = -1;
   148             }
   149             /* Is node iv the root of a block? */
   150             if (lowl[iv] < numb[iv]) goto L60;
   151             /* Order nodes in a block. */
   152             num++;
   153             ist1 = n + 1 - ist;
   154             lcnt = icnt + 1;
   155             /* Peel block off the top of the stack starting at the top
   156                and working down to the root of the block. */
   157             for (stp = ist1; stp <= n; stp++)
   158             {  iw = ib[stp];
   159                lowl[iw] = n + 1;
   160                numb[iw] = ++icnt;
   161                if (iw == iv) break;
   162             }
   163             ist = n - stp;
   164             ib[num] = lcnt;
   165             /* Are there any nodes left on the stack? */
   166             if (ist != 0) goto L60;
   167             /* Have all the nodes been ordered? */
   168             if (icnt < n) break;
   169             goto L100;
   170 L60:        /* Backtrack to previous node on path. */
   171             iw = iv;
   172             iv = prev[iv];
   173             /* Update value of lowl[iv] if necessary. */
   174             if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
   175             continue;
   176 L70:        /* Put new node on the stack. */
   177             arp[iv] = i2 - ii - 1;
   178             prev[iw] = iv;
   179             iv = iw;
   180             lowl[iv] = numb[iv] = ++ist;
   181             ib[n+1-ist] = iv;
   182          }
   183       }
   184 L100: /* Put permutation in the required form. */
   185       for (i = 1; i <= n; i++)
   186          arp[numb[i]] = i;
   187       return num;
   188 }
   189 
   190 /**********************************************************************/
   191 
   192 #if 0
   193 #include "glplib.h"
   194 
   195 void test(int n, int ipp);
   196 
   197 int main(void)
   198 {     /* test program for routine mc13d */
   199       test( 1,   0);
   200       test( 2,   1);
   201       test( 2,   2);
   202       test( 3,   3);
   203       test( 4,   4);
   204       test( 5,  10);
   205       test(10,  10);
   206       test(10,  20);
   207       test(20,  20);
   208       test(20,  50);
   209       test(50,  50);
   210       test(50, 200);
   211       return 0;
   212 }
   213 
   214 void fa01bs(int max, int *nrand);
   215 
   216 void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
   217 
   218 void test(int n, int ipp)
   219 {     int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
   220          lenr[1+50];
   221       char a[1+50][1+50], hold[1+100];
   222       int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
   223       xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
   224          "zeros\n", n, ipp);
   225       for (j = 1; j <= n; j++)
   226       {  for (i = 1; i <= n; i++)
   227             a[i][j] = 0;
   228          a[j][j] = 1;
   229       }
   230       for (k9 = 1; k9 <= ipp; k9++)
   231       {  /* these statements should be replaced by calls to your
   232             favorite random number generator to place two pseudo-random
   233             numbers between 1 and n in the variables i and j */
   234          for (;;)
   235          {  fa01bs(n, &i);
   236             fa01bs(n, &j);
   237             if (!a[i][j]) break;
   238          }
   239          a[i][j] = 1;
   240       }
   241       /* setup converts matrix a[i,j] to required sparsity-oriented
   242          storage format */
   243       setup(n, a, ip, icn, lenr);
   244       num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
   245       /* output reordered matrix with blocking to improve clarity */
   246       xprintf("\nThe reordered matrix which has %d block%s is of the fo"
   247          "rm\n", num, num == 1 ? "" : "s");
   248       ib[num+1] = n + 1;
   249       index = 100;
   250       iblock = 1;
   251       for (i = 1; i <= n; i++)
   252       {  for (ij = 1; ij <= index; ij++)
   253             hold[ij] = ' ';
   254          if (i == ib[iblock])
   255          {  xprintf("\n");
   256             iblock++;
   257          }
   258          jblock = 1;
   259          index = 0;
   260          for (j = 1; j <= n; j++)
   261          {  if (j == ib[jblock])
   262             {  hold[++index] = ' ';
   263                jblock++;
   264             }
   265             ii = ior[i];
   266             jj = ior[j];
   267             hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
   268          }
   269          xprintf("%.*s\n", index, &hold[1]);
   270       }
   271       xprintf("\nThe starting point for each block is given by\n");
   272       for (i = 1; i <= num; i++)
   273       {  if ((i - 1) % 12 == 0) xprintf("\n");
   274          xprintf(" %4d", ib[i]);
   275       }
   276       xprintf("\n");
   277       return;
   278 }
   279 
   280 void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
   281 {     int i, j, ind;
   282       for (i = 1; i <= n; i++)
   283          lenr[i] = 0;
   284       ind = 1;
   285       for (i = 1; i <= n; i++)
   286       {  ip[i] = ind;
   287          for (j = 1; j <= n; j++)
   288          {  if (a[i][j])
   289             {  lenr[i]++;
   290                icn[ind++] = j;
   291             }
   292          }
   293       }
   294       return;
   295 }
   296 
   297 double g = 1431655765.0;
   298 
   299 double fa01as(int i)
   300 {     /* random number generator */
   301       g = fmod(g * 9228907.0, 4294967296.0);
   302       if (i >= 0)
   303          return g / 4294967296.0;
   304       else
   305          return 2.0 * g / 4294967296.0 - 1.0;
   306 }
   307 
   308 void fa01bs(int max, int *nrand)
   309 {     *nrand = (int)(fa01as(1) * (double)max) + 1;
   310       return;
   311 }
   312 #endif
   313 
   314 /* eof */