1 /* glpnet02.c (permutations to block triangular form) */
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * This code is the result of translation of the Fortran subroutines
7 * MC13D and MC13E associated with the following paper:
9 * I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
10 * form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
12 * Use of ACM Algorithms is subject to the ACM Software Copyright and
13 * License Agreement. See <http://www.acm.org/publications/policies>.
15 * The translation was made by Andrew Makhorin <mao@gnu.org>.
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.
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.
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 ***********************************************************************/
33 /***********************************************************************
36 * mc13d - permutations to block triangular form
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[]);
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.
52 * n order of the matrix.
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.
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.
62 * lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
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
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.
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.
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
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.
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.
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.
101 * The routine mc13d returns num, the number of blocks found. */
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[])
106 int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
108 /* icnt is the number of nodes whose positions in final ordering
111 /* num is the number of blocks that have been found. */
114 /* Initialization of arrays. */
115 for (j = 1; j <= n; j++)
117 arp[j] = lenr[j] - 1;
119 for (isn = 1; isn <= n; isn++)
120 { /* Look for a starting node. */
121 if (numb[isn] != 0) continue;
123 /* ist is the number of nodes on the stack ... it is the stack
126 /* Put node iv at beginning of stack. */
127 lowl[iv] = numb[iv] = 1;
129 /* The body of this loop puts a new node on the stack or
131 for (dummy = 1; dummy <= nnm1; dummy++)
133 /* Have all edges leaving node iv been searched? */
135 { i2 = ip[iv] + lenr[iv] - 1;
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++)
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];
146 /* There are no more edges leaving node iv. */
149 /* Is node iv the root of a block? */
150 if (lowl[iv] < numb[iv]) goto L60;
151 /* Order nodes in a block. */
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++)
165 /* Are there any nodes left on the stack? */
166 if (ist != 0) goto L60;
167 /* Have all the nodes been ordered? */
170 L60: /* Backtrack to previous node on path. */
173 /* Update value of lowl[iv] if necessary. */
174 if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
176 L70: /* Put new node on the stack. */
177 arp[iv] = i2 - ii - 1;
180 lowl[iv] = numb[iv] = ++ist;
184 L100: /* Put permutation in the required form. */
185 for (i = 1; i <= n; i++)
190 /**********************************************************************/
195 void test(int n, int ipp);
198 { /* test program for routine mc13d */
214 void fa01bs(int max, int *nrand);
216 void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
218 void test(int n, int ipp)
219 { int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
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-"
225 for (j = 1; j <= n; j++)
226 { for (i = 1; i <= n; i++)
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 */
241 /* setup converts matrix a[i,j] to required sparsity-oriented
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");
251 for (i = 1; i <= n; i++)
252 { for (ij = 1; ij <= index; ij++)
260 for (j = 1; j <= n; j++)
261 { if (j == ib[jblock])
262 { hold[++index] = ' ';
267 hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
269 xprintf("%.*s\n", index, &hold[1]);
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]);
280 void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
282 for (i = 1; i <= n; i++)
285 for (i = 1; i <= n; i++)
287 for (j = 1; j <= n; j++)
297 double g = 1431655765.0;
300 { /* random number generator */
301 g = fmod(g * 9228907.0, 4294967296.0);
303 return g / 4294967296.0;
305 return 2.0 * g / 4294967296.0 - 1.0;
308 void fa01bs(int max, int *nrand)
309 { *nrand = (int)(fa01as(1) * (double)max) + 1;