|
EpetraExt
Development
|
00001 //@HEADER 00002 // *********************************************************************** 00003 // 00004 // EpetraExt: Epetra Extended - Linear Algebra Services Package 00005 // Copyright (2011) Sandia Corporation 00006 // 00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00008 // the U.S. Government retains certain rights in this software. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 //@HEADER 00041 00042 #include <EpetraExt_BlockAdjacencyGraph.h> 00043 00044 #include <Epetra_CrsMatrix.h> 00045 #include <Epetra_CrsGraph.h> 00046 #include <Epetra_Map.h> 00047 #include <Epetra_Comm.h> 00048 00049 #include <math.h> 00050 #include <cstdlib> 00051 00052 namespace EpetraExt { 00053 00054 int compare_ints(const void *a, const void *b) 00055 { 00056 return(*((int *) a) - *((int *) b)); 00057 } 00058 00059 int ceil31log2(int n) 00060 { // Given 1 <= n < 2^31, find l such that 2^(l-1) < n <= 2^(l) 00061 int l=0, m = 1; 00062 while ((n > m) && (l < 31)) { 00063 m = 2*m; 00064 ++l; 00065 } 00066 return(l); 00067 } 00068 // Purpose: Compute the block connectivity graph of a matrix. 00069 // An nrr by nrr sparse matrix admits a (Dulmage-Mendelsohn) 00070 // permutation to block triangular form with nbrr blocks. 00071 // Abstractly, the block triangular form corresponds to a partition 00072 // of the set of integers {0,...,n-1} into nbrr disjoint sets. 00073 // The graph of the sparse matrix, with nrr vertices, may be compressed 00074 // into the graph of the blocks, a graph with nbrr vertices, that is 00075 // called here the block connectivity graph. 00076 // The partition of the rows and columns of B is represented by 00077 // r(0:nbrr), 0 = r(0) < r(1) < .. < r(nbrr) = nrr, 00078 // The graph (Mp,Mj) of the nbrr x nbrr matrix is represened by 00079 // a sparse matrix in sparse coordinate format. 00080 // Mp: row indices, dimension determined here (nzM). 00081 // Mj: column indices, dimension determined here (nzM). 00082 // The integer vector, weights, of block sizes (dimension nbrr) is also 00083 // computed here. 00084 // The case of nbrr proportional to nrr is critical. One must 00085 // efficiently look up the column indices of B in the partition. 00086 // This is done here using a binary search tree, so that the 00087 // look up cost is nzB*log2(nbrr). 00088 00089 template<typename int_type> 00090 Teuchos::RCP<Epetra_CrsGraph> BlockAdjacencyGraph::compute( Epetra_CrsGraph& B, int nbrr, std::vector<int>&r, std::vector<double>& weights, bool verbose) 00091 { 00092 // Check if the graph is on one processor. 00093 int myMatProc = -1, matProc = -1; 00094 int myPID = B.Comm().MyPID(); 00095 for (int proc=0; proc<B.Comm().NumProc(); proc++) 00096 { 00097 if (B.NumGlobalEntries64() == B.NumMyEntries()) 00098 myMatProc = myPID; 00099 } 00100 B.Comm().MaxAll( &myMatProc, &matProc, 1 ); 00101 00102 if( matProc == -1) 00103 { std::cout << "FAIL for Global! All CrsGraph entries must be on one processor!\n"; abort(); } 00104 00105 int i= 0, j = 0, k, l = 0, p, pm, q = -1, ns = 0; 00106 int tree_height; 00107 int error = -1; /* error detected, possibly a problem with the input */ 00108 (void) error; // silence "set but not used" warning 00109 int nrr; /* number of rows in B */ 00110 int nzM = 0; /* number of edges in graph */ 00111 int m = 0; /* maximum number of nonzeros in any block row of B */ 00112 int* colstack = 0; /* stack used to process each block row */ 00113 int* bstree = 0; /* binary search tree */ 00114 std::vector<int_type> Mi, Mj, Mnum(nbrr+1,0); 00115 nrr = B.NumMyRows(); 00116 if ( matProc == myPID ) 00117 { 00118 if ( verbose ) { std::printf(" Matrix Size = %d Number of Blocks = %d\n",nrr, nbrr); } 00119 } 00120 else 00121 { 00122 nrr = -1; /* Prevent processor from doing any computations */ 00123 } 00124 bstree = csr_bst(nbrr); /* 0 : nbrr-1 */ 00125 tree_height = ceil31log2(nbrr) + 1; 00126 error = -1; 00127 00128 l = 0; j = 0; m = 0; 00129 for( i = 0; i < nrr; i++ ){ 00130 if( i >= r[l+1] ){ 00131 ++l; /* new block row */ 00132 m = EPETRA_MAX(m,j) ; /* nonzeros in block row */ 00133 j = B.NumGlobalIndices(i); 00134 }else{ 00135 j += B.NumGlobalIndices(i); 00136 } 00137 } 00138 /* one more time for the final block */ 00139 m = EPETRA_MAX(m,j) ; /* nonzeros in block row */ 00140 00141 colstack = (int*) malloc( EPETRA_MAX(m,1) * sizeof(int) ); 00142 // The compressed graph is actually computed twice, 00143 // due to concerns about memory limitations. First, 00144 // without memory allocation, just nzM is computed. 00145 // Next Mj is allocated. Then, the second time, the 00146 // arrays are actually populated. 00147 nzM = 0; q = -1; l = 0; 00148 int * indices; 00149 int numEntries; 00150 for( i = 0; i <= nrr; i++ ){ 00151 if( i >= r[l+1] ){ 00152 if( q > 0 ) std::qsort(colstack,q+1,sizeof(int),compare_ints); /* sort stack */ 00153 if( q >= 0 ) ns = 1; /* l, colstack[0] M */ 00154 for( j=1; j<=q ; j++ ){ /* delete copies */ 00155 if( colstack[j] > colstack[j-1] ) ++ns; 00156 } 00157 nzM += ns; /*M->p[l+1] = M->p[l] + ns;*/ 00158 ++l; 00159 q = -1; 00160 } 00161 if( i < nrr ){ 00162 B.ExtractMyRowView( i, numEntries, indices ); 00163 for( k = 0; k < numEntries; k++){ 00164 j = indices[k]; ns = 0; p = 0; 00165 while( (r[bstree[p]] > j) || (j >= r[bstree[p]+1]) ){ 00166 if( r[bstree[p]] > j){ 00167 p = 2*p+1; 00168 }else{ 00169 if( r[bstree[p]+1] <= j) p = 2*p+2; 00170 } 00171 ++ns; 00172 if( p > nbrr || ns > tree_height ) { 00173 error = j; 00174 std::printf("error: p %d nbrr %d ns %d %d\n",p,nbrr,ns,j); break; 00175 } 00176 } 00177 colstack[++q] = bstree[p]; 00178 } 00179 //if( error >-1 ){ std::printf("%d\n",error); break; } 00180 // p > nbrr is a fatal error that is ignored 00181 } 00182 } 00183 00184 if ( matProc == myPID && verbose ) 00185 std::printf("nzM = %d \n", nzM ); 00186 Mi.resize( nzM ); 00187 Mj.resize( nzM ); 00188 q = -1; l = 0; pm = -1; 00189 for( i = 0; i <= nrr; i++ ){ 00190 if( i >= r[l+1] ){ 00191 if( q > 0 ) std::qsort(colstack,q+1,sizeof(colstack[0]),compare_ints); /* sort stack */ 00192 if( q >= 0 ){ 00193 Mi[++pm] = l; 00194 Mj[pm] = colstack[0]; 00195 } 00196 for( j=1; j<=q ; j++ ){ /* delete copies */ 00197 if( colstack[j] > colstack[j-1] ){ /* l, colstack[j] */ 00198 Mi[++pm] = l; 00199 Mj[pm] = colstack[j]; 00200 } 00201 } 00202 ++l; 00203 Mnum[l] = pm + 1; 00204 00205 /* sparse row format: M->p[l+1] = M->p[l] + ns; */ 00206 q = -1; 00207 } 00208 if( i < nrr ){ 00209 B.ExtractMyRowView( i, numEntries, indices ); 00210 for( k = 0; k < numEntries; k++){ 00211 j = indices[k]; ns = 0; p = 0; 00212 while( (r[bstree[p]] > j) || (j >= r[bstree[p]+1]) ){ 00213 if( r[bstree[p]] > j){ 00214 p = 2*p+1; 00215 }else{ 00216 if( r[bstree[p]+1] <= j) p = 2*p+2; 00217 } 00218 ++ns; 00219 } 00220 colstack[++q] = bstree[p]; 00221 } 00222 } 00223 } 00224 if ( bstree ) free ( bstree ); 00225 if ( colstack ) free( colstack ); 00226 00227 // Compute weights as number of rows in each block. 00228 weights.resize( nbrr ); 00229 for( l=0; l<nbrr; l++) weights[l] = r[l+1] - r[l]; 00230 00231 // Compute Epetra_CrsGraph and return 00232 Teuchos::RCP<Epetra_Map> newMap; 00233 if ( matProc == myPID ) 00234 newMap = Teuchos::rcp( new Epetra_Map(nbrr, nbrr, 0, B.Comm() ) ); 00235 else 00236 newMap = Teuchos::rcp( new Epetra_Map( nbrr, 0, 0, B.Comm() ) ); 00237 Teuchos::RCP<Epetra_CrsGraph> newGraph = Teuchos::rcp( new Epetra_CrsGraph( Copy, *newMap, 0 ) ); 00238 for( l=0; l<newGraph->NumMyRows(); l++) { 00239 newGraph->InsertGlobalIndices( l, Mnum[l+1]-Mnum[l], &Mj[Mnum[l]] ); 00240 } 00241 newGraph->FillComplete(); 00242 00243 return (newGraph); 00244 } 00245 00246 Teuchos::RCP<Epetra_CrsGraph> BlockAdjacencyGraph::compute( Epetra_CrsGraph& B, int nbrr, std::vector<int>&r, std::vector<double>& weights, bool verbose) { 00247 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES 00248 if(B.RowMap().GlobalIndicesInt()) { 00249 return compute<int>(B, nbrr, r, weights, verbose); 00250 } 00251 else 00252 #endif 00253 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES 00254 if(B.RowMap().GlobalIndicesLongLong()) { 00255 return compute<long long>(B, nbrr, r, weights, verbose); 00256 } 00257 else 00258 #endif 00259 throw "EpetraExt::BlockAdjacencyGraph::compute: GlobalIndices type unknown"; 00260 } 00261 00262 /* 00263 * bst(n) returns the complete binary tree, stored in an integer array of dimension n. 00264 * index i has children 2i+1 and 2i+2, root index 0. 00265 * A binary search of a sorted n-array: find array(k) 00266 * i=0; k = tree(i); 00267 * if < array( k ), i = 2i+1; 00268 * elif > array( k ), i = 2i+2; 00269 * otherwise exit 00270 */ 00271 int* BlockAdjacencyGraph::csr_bst( int n ) 00272 { 00273 int i, l=1, m, nstack = 0, nexp=0, os, *array, *stack; 00274 int max_nstack = 0; 00275 if( n == 0 ) return(NULL); 00276 while( l <= n ){ 00277 l = 2*l; 00278 ++nexp; 00279 } /* n < l = 2^nexp */ 00280 array = (int *) malloc( n * sizeof(int) ); 00281 stack = (int *) malloc(3*nexp * sizeof(int) ); 00282 stack[3*nstack] = 0; stack[3*nstack+1] = 0; stack[3*nstack+2] = n; 00283 ++nstack; 00284 /*if( debug ) std::printf("stack : %d %d %d\n", stack[0] , stack[1], stack[2] );*/ 00285 while( nstack > 0 ){ 00286 --nstack; 00287 i = stack[3*nstack]; os = stack[3*nstack+1]; m = stack[3*nstack+2]; 00288 array[i] = csr_bstrootindex(m) + os; /* 5 */ 00289 if( 2*i+2 < n){ /* right child 4 3 1 3 - 5 - 1 */ 00290 stack[3*nstack] = 2*i+2; stack[3*nstack+1] = array[i] + 1 ; stack[3*nstack+2] = m-array[i]-1+os; /* 6 10 -3 */ 00291 ++nstack; 00292 } 00293 if( 2*i+1 < n){ /* left child */ 00294 stack[3*nstack] = 2*i+1; stack[3*nstack+1] = os; stack[3*nstack+2] = array[i] - os; /* 5 4 5 */ 00295 ++nstack; 00296 } 00297 if( nstack > max_nstack ) max_nstack = nstack; 00298 } 00299 free( stack ); 00300 return(array); 00301 } 00302 00303 /* 00304 Given a complete binary search tree with n nodes, return 00305 the index of the root node. A nodeless tree, n=0, has no 00306 root node (-1). Nodes are indexed from 0 to n-1. 00307 */ 00308 int BlockAdjacencyGraph::csr_bstrootindex( int n ) 00309 { 00310 int l = 1, nexp = 0, i; 00311 if( n == 0) return(-1); 00312 while( l <= n ){ 00313 l = 2*l; 00314 ++nexp; 00315 } /* n < l = 2^nexp */ 00316 i = l/2 - 1; 00317 if(n<4) return(i); 00318 if (n-i < l/4) 00319 return( n - l/4 ); 00320 else 00321 return(i); 00322 } 00323 00324 } //namespace EpetraExt 00325
1.7.6.1