Mercurial > octave-nkf
comparison src/DLD-FUNCTIONS/symrcm.cc @ 11586:12df7854fa7c
strip trailing whitespace from source files
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 20 Jan 2011 17:24:59 -0500 |
parents | 01f703952eff |
children | 72c96de7a403 |
comparison
equal
deleted
inserted
replaced
11585:1473d0cf86d2 | 11586:12df7854fa7c |
---|---|
81 // Queues Q have a fixed maximum size N (rows,cols of the matrix) and are | 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. | 82 // stored in an array. qh and qt point to queue head and tail. |
83 | 83 |
84 // Enqueue operation (adds a node "o" at the tail) | 84 // Enqueue operation (adds a node "o" at the tail) |
85 | 85 |
86 inline static void | 86 inline static void |
87 Q_enq (CMK_Node *Q, octave_idx_type N, octave_idx_type& qt, const CMK_Node& o) | 87 Q_enq (CMK_Node *Q, octave_idx_type N, octave_idx_type& qt, const CMK_Node& o) |
88 { | 88 { |
89 Q[qt] = o; | 89 Q[qt] = o; |
90 qt = (qt + 1) % (N + 1); | 90 qt = (qt + 1) % (N + 1); |
91 } | 91 } |
92 | 92 |
93 // Dequeue operation (removes a node from the head) | 93 // Dequeue operation (removes a node from the head) |
94 | 94 |
95 inline static CMK_Node | 95 inline static CMK_Node |
96 Q_deq (CMK_Node * Q, octave_idx_type N, octave_idx_type& qh) | 96 Q_deq (CMK_Node * Q, octave_idx_type N, octave_idx_type& qh) |
97 { | 97 { |
98 CMK_Node r = Q[qh]; | 98 CMK_Node r = Q[qh]; |
99 qh = (qh + 1) % (N + 1); | 99 qh = (qh + 1) % (N + 1); |
100 return r; | 100 return r; |
113 #define PARENT(i) (((i) - 1) >> 1) // = floor(((i)-1)/2) | 113 #define PARENT(i) (((i) - 1) >> 1) // = floor(((i)-1)/2) |
114 | 114 |
115 // Builds a min-heap (the root contains the smallest element). A is an array | 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. | 116 // with the graph's nodes, i is a starting position, size is the length of A. |
117 | 117 |
118 static void | 118 static void |
119 H_heapify_min (CMK_Node *A, octave_idx_type i, octave_idx_type size) | 119 H_heapify_min (CMK_Node *A, octave_idx_type i, octave_idx_type size) |
120 { | 120 { |
121 octave_idx_type j = i; | 121 octave_idx_type j = i; |
122 for (;;) | 122 for (;;) |
123 { | 123 { |
138 CMK_Node tmp = A[j]; | 138 CMK_Node tmp = A[j]; |
139 A[j] = A[smallest]; | 139 A[j] = A[smallest]; |
140 A[smallest] = tmp; | 140 A[smallest] = tmp; |
141 j = smallest; | 141 j = smallest; |
142 } | 142 } |
143 else | 143 else |
144 break; | 144 break; |
145 } | 145 } |
146 } | 146 } |
147 | 147 |
148 // Heap operation insert. Running time is O(log(n)) | 148 // Heap operation insert. Running time is O(log(n)) |
149 | 149 |
150 static void | 150 static void |
151 H_insert (CMK_Node *H, octave_idx_type& h, const CMK_Node& o) | 151 H_insert (CMK_Node *H, octave_idx_type& h, const CMK_Node& o) |
152 { | 152 { |
153 octave_idx_type i = h++; | 153 octave_idx_type i = h++; |
154 | 154 |
155 H[i] = o; | 155 H[i] = o; |
156 | 156 |
157 if (i == 0) | 157 if (i == 0) |
158 return; | 158 return; |
159 do | 159 do |
160 { | 160 { |
161 octave_idx_type p = PARENT(i); | 161 octave_idx_type p = PARENT(i); |
162 if (H[i].deg < H[p].deg) | 162 if (H[i].deg < H[p].deg) |
165 H[i] = H[p]; | 165 H[i] = H[p]; |
166 H[p] = tmp; | 166 H[p] = tmp; |
167 | 167 |
168 i = p; | 168 i = p; |
169 } | 169 } |
170 else | 170 else |
171 break; | 171 break; |
172 } | 172 } |
173 while (i > 0); | 173 while (i > 0); |
174 } | 174 } |
175 | 175 |
176 // Heap operation remove-min. Removes the smalles element in O(1) and | 176 // Heap operation remove-min. Removes the smalles element in O(1) and |
177 // reorganizes the heap optionally in O(log(n)) | 177 // reorganizes the heap optionally in O(log(n)) |
178 | 178 |
179 inline static CMK_Node | 179 inline static CMK_Node |
180 H_remove_min (CMK_Node *H, octave_idx_type& h, int reorg/*=1*/) | 180 H_remove_min (CMK_Node *H, octave_idx_type& h, int reorg/*=1*/) |
181 { | 181 { |
182 CMK_Node r = H[0]; | 182 CMK_Node r = H[0]; |
183 H[0] = H[--h]; | 183 H[0] = H[--h]; |
184 if (reorg) | 184 if (reorg) |
185 H_heapify_min(H, 0, h); | 185 H_heapify_min(H, 0, h); |
186 return r; | 186 return r; |
187 } | 187 } |
188 | 188 |
189 // Predicate (heap empty) | 189 // Predicate (heap empty) |
190 #define H_empty(H, h) ((h) == 0) | 190 #define H_empty(H, h) ((h) == 0) |
191 | 191 |
192 // Helper function for the Cuthill-McKee algorithm. Tries to determine a | 192 // Helper function for the Cuthill-McKee algorithm. Tries to determine a |
193 // pseudo-peripheral node of the graph as starting node. | 193 // pseudo-peripheral node of the graph as starting node. |
194 | 194 |
195 static octave_idx_type | 195 static octave_idx_type |
196 find_starting_node (octave_idx_type N, const octave_idx_type *ridx, | 196 find_starting_node (octave_idx_type N, const octave_idx_type *ridx, |
197 const octave_idx_type *cidx, const octave_idx_type *ridx2, | 197 const octave_idx_type *cidx, const octave_idx_type *ridx2, |
198 const octave_idx_type *cidx2, octave_idx_type *D, | 198 const octave_idx_type *cidx2, octave_idx_type *D, |
199 octave_idx_type start) | 199 octave_idx_type start) |
200 { | 200 { |
201 CMK_Node w; | 201 CMK_Node w; |
202 | 202 |
203 OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); | 203 OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); |
325 } | 325 } |
326 return x.id; | 326 return x.id; |
327 } | 327 } |
328 | 328 |
329 // Calculates the node's degrees. This means counting the non-zero elements | 329 // Calculates the node's degrees. This means counting the non-zero elements |
330 // in the symmetric matrix' rows. This works for non-symmetric matrices | 330 // in the symmetric matrix' rows. This works for non-symmetric matrices |
331 // as well. | 331 // as well. |
332 | 332 |
333 static octave_idx_type | 333 static octave_idx_type |
334 calc_degrees (octave_idx_type N, const octave_idx_type *ridx, | 334 calc_degrees (octave_idx_type N, const octave_idx_type *ridx, |
335 const octave_idx_type *cidx, octave_idx_type *D) | 335 const octave_idx_type *cidx, octave_idx_type *D) |
336 { | 336 { |
337 octave_idx_type max_deg = 0; | 337 octave_idx_type max_deg = 0; |
338 | 338 |
339 for (octave_idx_type i = 0; i < N; i++) | 339 for (octave_idx_type i = 0; i < N; i++) |
340 D[i] = 0; | 340 D[i] = 0; |
341 | 341 |
342 for (octave_idx_type j = 0; j < N; j++) | 342 for (octave_idx_type j = 0; j < N; j++) |
343 { | 343 { |
344 for (octave_idx_type i = cidx[j]; i < cidx[j+1]; i++) | 344 for (octave_idx_type i = cidx[j]; i < cidx[j+1]; i++) |
345 { | 345 { |
346 OCTAVE_QUIT; | 346 OCTAVE_QUIT; |
347 octave_idx_type k = ridx[i]; | 347 octave_idx_type k = ridx[i]; |
348 // there is a non-zero element (k,j) | 348 // there is a non-zero element (k,j) |
349 D[k]++; | 349 D[k]++; |
350 if (D[k] > max_deg) | 350 if (D[k] > max_deg) |
351 max_deg = D[k]; | 351 max_deg = D[k]; |
352 // if there is no element (j,k) there is one in | 352 // if there is no element (j,k) there is one in |
353 // the symmetric matrix: | 353 // the symmetric matrix: |
354 if (k != j) | 354 if (k != j) |
355 { | 355 { |
369 | 369 |
370 if (! found) | 370 if (! found) |
371 { | 371 { |
372 // A(j,k) == 0 | 372 // A(j,k) == 0 |
373 D[j]++; | 373 D[j]++; |
374 if (D[j] > max_deg) | 374 if (D[j] > max_deg) |
375 max_deg = D[j]; | 375 max_deg = D[j]; |
376 } | 376 } |
377 } | 377 } |
378 } | 378 } |
379 } | 379 } |
381 } | 381 } |
382 | 382 |
383 // Transpose of the structure of a square sparse matrix | 383 // Transpose of the structure of a square sparse matrix |
384 | 384 |
385 static void | 385 static void |
386 transpose (octave_idx_type N, const octave_idx_type *ridx, | 386 transpose (octave_idx_type N, const octave_idx_type *ridx, |
387 const octave_idx_type *cidx, octave_idx_type *ridx2, | 387 const octave_idx_type *cidx, octave_idx_type *ridx2, |
388 octave_idx_type *cidx2) | 388 octave_idx_type *cidx2) |
389 { | 389 { |
390 octave_idx_type nz = cidx[N]; | 390 octave_idx_type nz = cidx[N]; |
391 | 391 |
392 OCTAVE_LOCAL_BUFFER (octave_idx_type, w, N + 1); | 392 OCTAVE_LOCAL_BUFFER (octave_idx_type, w, N + 1); |
449 return retval; | 449 return retval; |
450 } | 450 } |
451 | 451 |
452 octave_value arg = args(0); | 452 octave_value arg = args(0); |
453 | 453 |
454 // the parameter of the matrix is converted into a sparse matrix | 454 // the parameter of the matrix is converted into a sparse matrix |
455 //(if necessary) | 455 //(if necessary) |
456 octave_idx_type *cidx; | 456 octave_idx_type *cidx; |
457 octave_idx_type *ridx; | 457 octave_idx_type *ridx; |
458 SparseMatrix Ar; | 458 SparseMatrix Ar; |
459 SparseComplexMatrix Ac; | 459 SparseComplexMatrix Ac; |
509 | 509 |
510 // if none of the nodes has a degree > 0 (a matrix of zeros) | 510 // if none of the nodes has a degree > 0 (a matrix of zeros) |
511 // the return value corresponds to the identity permutation | 511 // the return value corresponds to the identity permutation |
512 if (max_deg == 0) | 512 if (max_deg == 0) |
513 { | 513 { |
514 for (octave_idx_type i = 0; i < N; i++) | 514 for (octave_idx_type i = 0; i < N; i++) |
515 P(i) = i; | 515 P(i) = i; |
516 return octave_value (P); | 516 return octave_value (P); |
517 } | 517 } |
518 | 518 |
519 // a heap for the a node's neighbors. The number of neighbors is | 519 // a heap for the a node's neighbors. The number of neighbors is |
533 // bandwidths. | 533 // bandwidths. |
534 octave_idx_type B = 0; | 534 octave_idx_type B = 0; |
535 | 535 |
536 // mark all nodes as unvisited; with the exception of the nodes | 536 // mark all nodes as unvisited; with the exception of the nodes |
537 // that have degree==0 and build a CC of the graph. | 537 // that have degree==0 and build a CC of the graph. |
538 | 538 |
539 boolNDArray btmp (dim_vector (1, N), false); | 539 boolNDArray btmp (dim_vector (1, N), false); |
540 bool *visit = btmp.fortran_vec (); | 540 bool *visit = btmp.fortran_vec (); |
541 | 541 |
542 do | 542 do |
543 { | 543 { |
544 // locate an unvisited starting node of the graph | 544 // locate an unvisited starting node of the graph |
545 octave_idx_type i; | 545 octave_idx_type i; |
546 for (i = 0; i < N; i++) | 546 for (i = 0; i < N; i++) |
547 if (! visit[i]) | 547 if (! visit[i]) |
548 break; | 548 break; |
549 | 549 |
550 // locate a probably better starting node | 550 // locate a probably better starting node |
551 v.id = find_starting_node (N, ridx, cidx, ridx2, cidx2, D, i); | 551 v.id = find_starting_node (N, ridx, cidx, ridx2, cidx2, D, i); |
552 | 552 |
553 // mark the node as visited and enqueue it (a starting node | 553 // mark the node as visited and enqueue it (a starting node |
554 // for the BFS). Since the node will be a root of a spanning | 554 // for the BFS). Since the node will be a root of a spanning |
555 // tree, its dist is 0. | 555 // tree, its dist is 0. |
556 v.deg = D[v.id]; | 556 v.deg = D[v.id]; |
557 v.dist = 0; | 557 v.dist = 0; |
565 octave_idx_type Bsub = 0; | 565 octave_idx_type Bsub = 0; |
566 // min. dist. to the root is 0 | 566 // min. dist. to the root is 0 |
567 octave_idx_type level = 0; | 567 octave_idx_type level = 0; |
568 // the root is the first/only node on level 0 | 568 // the root is the first/only node on level 0 |
569 octave_idx_type level_N = 1; | 569 octave_idx_type level_N = 1; |
570 | 570 |
571 while (! Q_empty (Q, N, qh, qt)) | 571 while (! Q_empty (Q, N, qh, qt)) |
572 { | 572 { |
573 v = Q_deq (Q, N, qh); | 573 v = Q_deq (Q, N, qh); |
574 i = v.id; | 574 i = v.id; |
575 | 575 |
576 c++; | 576 c++; |
577 | 577 |
578 // for computing the inverse permutation P where | 578 // for computing the inverse permutation P where |
579 // A(inv(P),inv(P)) or P'*A*P is banded | 579 // A(inv(P),inv(P)) or P'*A*P is banded |
580 // P(i) = c; | 580 // P(i) = c; |
581 | 581 |
582 // for computing permutation P where | 582 // for computing permutation P where |
583 // A(P(i),P(j)) or P*A*P' is banded | 583 // A(P(i),P(j)) or P*A*P' is banded |
584 P(c) = i; | 584 P(c) = i; |
585 | 585 |
586 // put all unvisited neighbors j of node i on the heap | 586 // put all unvisited neighbors j of node i on the heap |
655 { | 655 { |
656 OCTAVE_QUIT; | 656 OCTAVE_QUIT; |
657 | 657 |
658 // locate a neighbor of i with minimal degree in O(log(N)) | 658 // locate a neighbor of i with minimal degree in O(log(N)) |
659 v = H_remove_min(S, s, 1); | 659 v = H_remove_min(S, s, 1); |
660 | 660 |
661 // entered the BFS a new level? | 661 // entered the BFS a new level? |
662 if (v.dist > level) | 662 if (v.dist > level) |
663 { | 663 { |
664 // adjustment of bandwith: | 664 // adjustment of bandwith: |
665 // "[...] the minimum bandwidth that | 665 // "[...] the minimum bandwidth that |
666 // can be obtained [...] is the | 666 // can be obtained [...] is the |
667 // maximum number of nodes per level" | 667 // maximum number of nodes per level" |
668 if (Bsub < level_N) | 668 if (Bsub < level_N) |
669 Bsub = level_N; | 669 Bsub = level_N; |
670 | 670 |
671 level = v.dist; | 671 level = v.dist; |
672 // v is the first node on the new level | 672 // v is the first node on the new level |
673 level_N = 1; | 673 level_N = 1; |
674 } | 674 } |
675 else | 675 else |
676 { | 676 { |
677 // there is no new level but another node on | 677 // there is no new level but another node on |
678 // this level: | 678 // this level: |
679 level_N++; | 679 level_N++; |
680 } | 680 } |
681 | 681 |
682 // enqueue v in O(1) | 682 // enqueue v in O(1) |
683 Q_enq (Q, N, qt, v); | 683 Q_enq (Q, N, qt, v); |
684 } | 684 } |
685 | 685 |
686 // synchronize the bandwidth with level_N once again: | 686 // synchronize the bandwidth with level_N once again: |
687 if (Bsub < level_N) | 687 if (Bsub < level_N) |
688 Bsub = level_N; | 688 Bsub = level_N; |
689 } | 689 } |
690 // finish of BFS. If there are still unvisited nodes in the graph | 690 // finish of BFS. If there are still unvisited nodes in the graph |