GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
symrcm.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007-2017 Michael Weitzel
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 /*
24 An implementation of the Reverse Cuthill-McKee algorithm (symrcm)
25 
26 The implementation of this algorithm is based in the descriptions found in
27 
28 @INPROCEEDINGS{,
29  author = {E. Cuthill and J. McKee},
30  title = {Reducing the Bandwidth of Sparse Symmetric Matrices},
31  booktitle = {Proceedings of the 24th ACM National Conference},
32  publisher = {Brandon Press},
33  pages = {157 -- 172},
34  location = {New Jersey},
35  year = {1969}
36 }
37 
38 @BOOK{,
39  author = {Alan George and Joseph W. H. Liu},
40  title = {Computer Solution of Large Sparse Positive Definite Systems},
41  publisher = {Prentice Hall Series in Computational Mathematics},
42  ISBN = {0-13-165274-5},
43  year = {1981}
44 }
45 
46 The algorithm represents a heuristic approach to the NP-complete minimum
47 bandwidth problem.
48 
49 Written by Michael Weitzel <michael.weitzel@@uni-siegen.de>
50  <weitzel@@ldknet.org>
51 */
52 
53 #if defined (HAVE_CONFIG_H)
54 # include "config.h"
55 #endif
56 
57 #include "ov.h"
58 #include "defun-dld.h"
59 #include "error.h"
60 #include "errwarn.h"
61 #include "utils.h"
62 #include "oct-locbuf.h"
63 
64 #include "ov-re-mat.h"
65 #include "ov-re-sparse.h"
66 #include "ov-cx-sparse.h"
67 #include "oct-sparse.h"
68 
69 // A node struct for the Cuthill-McKee algorithm
70 struct CMK_Node
71 {
72  // the node's id (matrix row index)
74  // the node's degree
76  // minimal distance to the root of the spanning tree
78 };
79 
80 // A simple queue.
81 // Queues Q have a fixed maximum size N (rows,cols of the matrix) and are
82 // stored in an array. qh and qt point to queue head and tail.
83 
84 // Enqueue operation (adds a node "o" at the tail)
85 
86 inline static void
88 {
89  Q[qt] = o;
90  qt = (qt + 1) % (N + 1);
91 }
92 
93 // Dequeue operation (removes a node from the head)
94 
95 inline static CMK_Node
97 {
98  CMK_Node r = Q[qh];
99  qh = (qh + 1) % (N + 1);
100  return r;
101 }
102 
103 // Predicate (queue empty)
104 #define Q_empty(Q, N, qh, qt) ((qh) == (qt))
105 
106 // A simple, array-based binary heap (used as a priority queue for nodes)
107 
108 // the left descendant of entry i
109 #define LEFT(i) (((i) << 1) + 1) // = (2*(i)+1)
110 // the right descendant of entry i
111 #define RIGHT(i) (((i) << 1) + 2) // = (2*(i)+2)
112 // the parent of entry i
113 #define PARENT(i) (((i) - 1) >> 1) // = floor(((i)-1)/2)
114 
115 // Builds a min-heap (the root contains the smallest element). A is an array
116 // with the graph's nodes, i is a starting position, size is the length of A.
117 
118 static void
120 {
121  octave_idx_type j = i;
122  for (;;)
123  {
124  octave_idx_type l = LEFT(j);
125  octave_idx_type r = RIGHT(j);
126 
127  octave_idx_type smallest;
128  if (l < size && A[l].deg < A[j].deg)
129  smallest = l;
130  else
131  smallest = j;
132 
133  if (r < size && A[r].deg < A[smallest].deg)
134  smallest = r;
135 
136  if (smallest != j)
137  {
138  std::swap (A[j], A[smallest]);
139  j = smallest;
140  }
141  else
142  break;
143  }
144 }
145 
146 // Heap operation insert. Running time is O(log(n))
147 
148 static void
150 {
151  octave_idx_type i = h++;
152 
153  H[i] = o;
154 
155  if (i == 0)
156  return;
157  do
158  {
159  octave_idx_type p = PARENT(i);
160  if (H[i].deg < H[p].deg)
161  {
162  std::swap (H[i], H[p]);
163 
164  i = p;
165  }
166  else
167  break;
168  }
169  while (i > 0);
170 }
171 
172 // Heap operation remove-min. Removes the smalles element in O(1) and
173 // reorganizes the heap optionally in O(log(n))
174 
175 inline static CMK_Node
176 H_remove_min (CMK_Node *H, octave_idx_type& h, int reorg/*=1*/)
177 {
178  CMK_Node r = H[0];
179  H[0] = H[--h];
180  if (reorg)
181  H_heapify_min (H, 0, h);
182  return r;
183 }
184 
185 // Predicate (heap empty)
186 #define H_empty(H, h) ((h) == 0)
187 
188 // Helper function for the Cuthill-McKee algorithm. Tries to determine a
189 // pseudo-peripheral node of the graph as starting node.
190 
191 static octave_idx_type
193  const octave_idx_type *cidx, const octave_idx_type *ridx2,
194  const octave_idx_type *cidx2, octave_idx_type *D,
196 {
197  CMK_Node w;
198 
200  boolNDArray btmp (dim_vector (1, N), false);
201  bool *visit = btmp.fortran_vec ();
202 
203  octave_idx_type qh = 0;
204  octave_idx_type qt = 0;
205  CMK_Node x;
206  x.id = start;
207  x.deg = D[start];
208  x.dist = 0;
209  Q_enq (Q, N, qt, x);
210  visit[start] = true;
211 
212  // distance level
213  octave_idx_type level = 0;
214  // current largest "eccentricity"
215  octave_idx_type max_dist = 0;
216 
217  for (;;)
218  {
219  while (! Q_empty (Q, N, qh, qt))
220  {
221  CMK_Node v = Q_deq (Q, N, qh);
222 
223  if (v.dist > x.dist || (v.id != x.id && v.deg > x.deg))
224  x = v;
225 
226  octave_idx_type i = v.id;
227 
228  // add all unvisited neighbors to the queue
229  octave_idx_type j1 = cidx[i];
230  octave_idx_type j2 = cidx2[i];
231  while (j1 < cidx[i+1] || j2 < cidx2[i+1])
232  {
233  OCTAVE_QUIT;
234 
235  if (j1 == cidx[i+1])
236  {
237  octave_idx_type r2 = ridx2[j2++];
238  if (! visit[r2])
239  {
240  // the distance of node j is dist(i)+1
241  w.id = r2;
242  w.deg = D[r2];
243  w.dist = v.dist+1;
244  Q_enq (Q, N, qt, w);
245  visit[r2] = true;
246 
247  if (w.dist > level)
248  level = w.dist;
249  }
250  }
251  else if (j2 == cidx2[i+1])
252  {
253  octave_idx_type r1 = ridx[j1++];
254  if (! visit[r1])
255  {
256  // the distance of node j is dist(i)+1
257  w.id = r1;
258  w.deg = D[r1];
259  w.dist = v.dist+1;
260  Q_enq (Q, N, qt, w);
261  visit[r1] = true;
262 
263  if (w.dist > level)
264  level = w.dist;
265  }
266  }
267  else
268  {
269  octave_idx_type r1 = ridx[j1];
270  octave_idx_type r2 = ridx2[j2];
271  if (r1 <= r2)
272  {
273  if (! visit[r1])
274  {
275  w.id = r1;
276  w.deg = D[r1];
277  w.dist = v.dist+1;
278  Q_enq (Q, N, qt, w);
279  visit[r1] = true;
280 
281  if (w.dist > level)
282  level = w.dist;
283  }
284  j1++;
285  if (r1 == r2)
286  j2++;
287  }
288  else
289  {
290  if (! visit[r2])
291  {
292  w.id = r2;
293  w.deg = D[r2];
294  w.dist = v.dist+1;
295  Q_enq (Q, N, qt, w);
296  visit[r2] = true;
297 
298  if (w.dist > level)
299  level = w.dist;
300  }
301  j2++;
302  }
303  }
304  }
305  } // finish of BFS
306 
307  if (max_dist < x.dist)
308  {
309  max_dist = x.dist;
310 
311  for (octave_idx_type i = 0; i < N; i++)
312  visit[i] = false;
313 
314  visit[x.id] = true;
315  x.dist = 0;
316  qt = qh = 0;
317  Q_enq (Q, N, qt, x);
318  }
319  else
320  break;
321  }
322  return x.id;
323 }
324 
325 // Calculates the node's degrees. This means counting the nonzero elements
326 // in the symmetric matrix' rows. This works for non-symmetric matrices
327 // as well.
328 
329 static octave_idx_type
331  const octave_idx_type *cidx, octave_idx_type *D)
332 {
333  octave_idx_type max_deg = 0;
334 
335  for (octave_idx_type i = 0; i < N; i++)
336  D[i] = 0;
337 
338  for (octave_idx_type j = 0; j < N; j++)
339  {
340  for (octave_idx_type i = cidx[j]; i < cidx[j+1]; i++)
341  {
342  OCTAVE_QUIT;
343  octave_idx_type k = ridx[i];
344  // there is a nonzero element (k,j)
345  D[k]++;
346  if (D[k] > max_deg)
347  max_deg = D[k];
348  // if there is no element (j,k) there is one in
349  // the symmetric matrix:
350  if (k != j)
351  {
352  bool found = false;
353  for (octave_idx_type l = cidx[k]; l < cidx[k + 1]; l++)
354  {
355  OCTAVE_QUIT;
356 
357  if (ridx[l] == j)
358  {
359  found = true;
360  break;
361  }
362  else if (ridx[l] > j)
363  break;
364  }
365 
366  if (! found)
367  {
368  // A(j,k) == 0
369  D[j]++;
370  if (D[j] > max_deg)
371  max_deg = D[j];
372  }
373  }
374  }
375  }
376  return max_deg;
377 }
378 
379 // Transpose of the structure of a square sparse matrix
380 
381 static void
383  const octave_idx_type *cidx, octave_idx_type *ridx2,
384  octave_idx_type *cidx2)
385 {
386  octave_idx_type nz = cidx[N];
387 
389  for (octave_idx_type i = 0; i < N; i++)
390  w[i] = 0;
391  for (octave_idx_type i = 0; i < nz; i++)
392  w[ridx[i]]++;
393  nz = 0;
394  for (octave_idx_type i = 0; i < N; i++)
395  {
396  OCTAVE_QUIT;
397  cidx2[i] = nz;
398  nz += w[i];
399  w[i] = cidx2[i];
400  }
401  cidx2[N] = nz;
402  w[N] = nz;
403 
404  for (octave_idx_type j = 0; j < N; j++)
405  for (octave_idx_type k = cidx[j]; k < cidx[j + 1]; k++)
406  {
407  OCTAVE_QUIT;
408  octave_idx_type q = w[ridx[k]]++;
409  ridx2[q] = j;
410  }
411 }
412 
413 // An implementation of the Cuthill-McKee algorithm.
414 DEFUN_DLD (symrcm, args, ,
415  doc: /* -*- texinfo -*-
416 @deftypefn {} {@var{p} =} symrcm (@var{S})
417 Return the symmetric reverse @nospell{Cuthill-McKee} permutation of @var{S}.
418 
419 @var{p} is a permutation vector such that
420 @code{@var{S}(@var{p}, @var{p})} tends to have its diagonal elements closer
421 to the diagonal than @var{S}. This is a good preordering for LU or
422 Cholesky@tie{}factorization of matrices that come from ``long, skinny''
423 problems. It works for both symmetric and asymmetric @var{S}.
424 
425 The algorithm represents a heuristic approach to the NP-complete bandwidth
426 minimization problem. The implementation is based in the descriptions found
427 in
428 
429 @nospell{E. Cuthill, J. McKee}. @cite{Reducing the Bandwidth of Sparse
430 Symmetric Matrices}. Proceedings of the 24th ACM National Conference,
431 157--172 1969, Brandon Press, New Jersey.
432 
433 @nospell{A. George, J.W.H. Liu}. @cite{Computer Solution of Large Sparse
434 Positive Definite Systems}, Prentice Hall Series in Computational
435 Mathematics, ISBN 0-13-165274-5, 1981.
436 
437 @seealso{colperm, colamd, symamd}
438 @end deftypefn */)
439 {
440  if (args.length () != 1)
441  print_usage ();
442 
443  octave_value arg = args(0);
444 
445  // the parameter of the matrix is converted into a sparse matrix
446  //(if necessary)
447  octave_idx_type *cidx;
448  octave_idx_type *ridx;
449  SparseMatrix Ar;
451 
452  if (arg.is_real_type ())
453  {
454  Ar = arg.sparse_matrix_value ();
455  // Note cidx/ridx are const, so use xridx and xcidx...
456  cidx = Ar.xcidx ();
457  ridx = Ar.xridx ();
458  }
459  else
460  {
461  Ac = arg.sparse_complex_matrix_value ();
462  cidx = Ac.xcidx ();
463  ridx = Ac.xridx ();
464  }
465 
466  octave_idx_type nr = arg.rows ();
467  octave_idx_type nc = arg.columns ();
468 
469  if (nr != nc)
470  err_square_matrix_required ("symrcm", "S");
471 
472  if (nr == 0 && nc == 0)
473  return ovl (NDArray (dim_vector (1, 0)));
474 
475  // sizes of the heaps
476  octave_idx_type s = 0;
477 
478  // head- and tail-indices for the queue
479  octave_idx_type qt = 0;
480  octave_idx_type qh = 0;
481  CMK_Node v, w;
482  // dimension of the matrix
483  octave_idx_type N = nr;
484 
485  OCTAVE_LOCAL_BUFFER (octave_idx_type, cidx2, N + 1);
486  OCTAVE_LOCAL_BUFFER (octave_idx_type, ridx2, cidx[N]);
487  transpose (N, ridx, cidx, ridx2, cidx2);
488 
489  // the permutation vector
490  NDArray P (dim_vector (1, N));
491 
492  // compute the node degrees
494  octave_idx_type max_deg = calc_degrees (N, ridx, cidx, D);
495 
496  // if none of the nodes has a degree > 0 (a matrix of zeros)
497  // the return value corresponds to the identity permutation
498  if (max_deg == 0)
499  {
500  for (octave_idx_type i = 0; i < N; i++)
501  P(i) = i;
502 
503  return ovl (P);
504  }
505 
506  // a heap for the a node's neighbors. The number of neighbors is
507  // limited by the maximum degree max_deg:
508  OCTAVE_LOCAL_BUFFER (CMK_Node, S, max_deg);
509 
510  // a queue for the BFS. The array is always one element larger than
511  // the number of entries that are stored.
513 
514  // a counter (for building the permutation)
515  octave_idx_type c = -1;
516 
517  // upper bound for the bandwidth (=quality of solution)
518  // initialize the bandwidth of the graph with 0. B contains the
519  // the maximum of the theoretical lower limits of the subgraphs
520  // bandwidths.
521  octave_idx_type B = 0;
522 
523  // mark all nodes as unvisited; with the exception of the nodes
524  // that have degree==0 and build a CC of the graph.
525 
526  boolNDArray btmp (dim_vector (1, N), false);
527  bool *visit = btmp.fortran_vec ();
528 
529  do
530  {
531  // locate an unvisited starting node of the graph
533  for (i = 0; i < N; i++)
534  if (! visit[i])
535  break;
536 
537  // locate a probably better starting node
538  v.id = find_starting_node (N, ridx, cidx, ridx2, cidx2, D, i);
539 
540  // mark the node as visited and enqueue it (a starting node
541  // for the BFS). Since the node will be a root of a spanning
542  // tree, its dist is 0.
543  v.deg = D[v.id];
544  v.dist = 0;
545  visit[v.id] = true;
546  Q_enq (Q, N, qt, v);
547 
548  // lower bound for the bandwidth of a subgraph
549  // keep a "level" in the spanning tree (= min. distance to the
550  // root) for determining the bandwidth of the computed
551  // permutation P
552  octave_idx_type Bsub = 0;
553  // min. dist. to the root is 0
554  octave_idx_type level = 0;
555  // the root is the first/only node on level 0
556  octave_idx_type level_N = 1;
557 
558  while (! Q_empty (Q, N, qh, qt))
559  {
560  v = Q_deq (Q, N, qh);
561  i = v.id;
562 
563  c++;
564 
565  // for computing the inverse permutation P where
566  // A(inv(P),inv(P)) or P'*A*P is banded
567  // P(i) = c;
568 
569  // for computing permutation P where
570  // A(P(i),P(j)) or P*A*P' is banded
571  P(c) = i;
572 
573  // put all unvisited neighbors j of node i on the heap
574  s = 0;
575  octave_idx_type j1 = cidx[i];
576  octave_idx_type j2 = cidx2[i];
577 
578  OCTAVE_QUIT;
579  while (j1 < cidx[i+1] || j2 < cidx2[i+1])
580  {
581  OCTAVE_QUIT;
582  if (j1 == cidx[i+1])
583  {
584  octave_idx_type r2 = ridx2[j2++];
585  if (! visit[r2])
586  {
587  // the distance of node j is dist(i)+1
588  w.id = r2;
589  w.deg = D[r2];
590  w.dist = v.dist+1;
591  H_insert (S, s, w);
592  visit[r2] = true;
593  }
594  }
595  else if (j2 == cidx2[i+1])
596  {
597  octave_idx_type r1 = ridx[j1++];
598  if (! visit[r1])
599  {
600  w.id = r1;
601  w.deg = D[r1];
602  w.dist = v.dist+1;
603  H_insert (S, s, w);
604  visit[r1] = true;
605  }
606  }
607  else
608  {
609  octave_idx_type r1 = ridx[j1];
610  octave_idx_type r2 = ridx2[j2];
611  if (r1 <= r2)
612  {
613  if (! visit[r1])
614  {
615  w.id = r1;
616  w.deg = D[r1];
617  w.dist = v.dist+1;
618  H_insert (S, s, w);
619  visit[r1] = true;
620  }
621  j1++;
622  if (r1 == r2)
623  j2++;
624  }
625  else
626  {
627  if (! visit[r2])
628  {
629  w.id = r2;
630  w.deg = D[r2];
631  w.dist = v.dist+1;
632  H_insert (S, s, w);
633  visit[r2] = true;
634  }
635  j2++;
636  }
637  }
638  }
639 
640  // add the neighbors to the queue (sorted by node degree)
641  while (! H_empty (S, s))
642  {
643  OCTAVE_QUIT;
644 
645  // locate a neighbor of i with minimal degree in O(log(N))
646  v = H_remove_min (S, s, 1);
647 
648  // entered the BFS a new level?
649  if (v.dist > level)
650  {
651  // adjustment of bandwith:
652  // "[...] the minimum bandwidth that
653  // can be obtained [...] is the
654  // maximum number of nodes per level"
655  if (Bsub < level_N)
656  Bsub = level_N;
657 
658  level = v.dist;
659  // v is the first node on the new level
660  level_N = 1;
661  }
662  else
663  {
664  // there is no new level but another node on
665  // this level:
666  level_N++;
667  }
668 
669  // enqueue v in O(1)
670  Q_enq (Q, N, qt, v);
671  }
672 
673  // synchronize the bandwidth with level_N once again:
674  if (Bsub < level_N)
675  Bsub = level_N;
676  }
677  // finish of BFS. If there are still unvisited nodes in the graph
678  // then it is split into CCs. The computed bandwidth is the maximum
679  // of all subgraphs. Update:
680  if (Bsub > B)
681  B = Bsub;
682  }
683  // are there any nodes left?
684  while (c+1 < N);
685 
686  // compute the reverse-ordering
687  s = N / 2 - 1;
688  for (octave_idx_type i = 0, j = N - 1; i <= s; i++, j--)
689  std::swap (P.elem (i), P.elem (j));
690 
691  // increment all indices, since Octave is not C
692  return ovl (P+1);
693 }
octave_idx_type * xridx(void)
Definition: Sparse.h:536
static void Q_enq(CMK_Node *Q, octave_idx_type N, octave_idx_type &qt, const CMK_Node &o)
Definition: symrcm.cc:87
bool is_real_type(void) const
Definition: ov.h:667
static octave_idx_type calc_degrees(octave_idx_type N, const octave_idx_type *ridx, const octave_idx_type *cidx, octave_idx_type *D)
Definition: symrcm.cc:330
octave_idx_type rows(void) const
Definition: ov.h:489
static void H_insert(CMK_Node *H, octave_idx_type &h, const CMK_Node &o)
Definition: symrcm.cc:149
ar P
Definition: __luinc__.cc:49
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
for large enough k
Definition: lu.cc:606
static void transpose(octave_idx_type N, const octave_idx_type *ridx, const octave_idx_type *cidx, octave_idx_type *ridx2, octave_idx_type *cidx2)
Definition: symrcm.cc:382
octave_idx_type * xcidx(void)
Definition: Sparse.h:549
octave_idx_type deg
Definition: symrcm.cc:75
#define RIGHT(i)
Definition: symrcm.cc:111
T & elem(octave_idx_type n)
Definition: Array.h:482
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:112
s
Definition: file-io.cc:2682
octave_value arg
Definition: pr-output.cc:3440
static octave_idx_type find_starting_node(octave_idx_type N, const octave_idx_type *ridx, const octave_idx_type *cidx, const octave_idx_type *ridx2, const octave_idx_type *cidx2, octave_idx_type *D, octave_idx_type start)
Definition: symrcm.cc:192
OCTAVE_EXPORT octave_value_list search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:302
bool swap
Definition: load-save.cc:725
JNIEnv void * args
Definition: ov-java.cc:67
F77_RET_T const F77_INT F77_CMPLX const F77_INT F77_CMPLX * B
double h
Definition: graphics.cc:11205
octave_idx_type columns(void) const
Definition: ov.h:491
std::complex< double > w(std::complex< double > z, double relerr=0)
#define PARENT(i)
Definition: symrcm.cc:113
F77_RET_T const F77_INT & N
#define LEFT(i)
Definition: symrcm.cc:109
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:838
octave::sys::time start
Definition: graphics.cc:11731
octave_idx_type dist
Definition: symrcm.cc:77
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
#define Q_empty(Q, N, qh, qt)
Definition: symrcm.cc:104
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
static CMK_Node Q_deq(CMK_Node *Q, octave_idx_type N, octave_idx_type &qh)
Definition: symrcm.cc:96
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:45
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable or any other valid Octave code The number of return their size
Definition: input.cc:871
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834
const T * fortran_vec(void) const
Definition: Array.h:584
#define OCTAVE_QUIT
Definition: quit.h:212
octave_idx_type id
Definition: symrcm.cc:73
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
static CMK_Node H_remove_min(CMK_Node *H, octave_idx_type &h, int reorg)
Definition: symrcm.cc:176
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
#define H_empty(H, h)
Definition: symrcm.cc:186
F77_RET_T const F77_INT F77_CMPLX * A
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Q
static void H_heapify_min(CMK_Node *A, octave_idx_type i, octave_idx_type size)
Definition: symrcm.cc:119