1c this file contains the following user-callable routines: 2c 3c 4c routine iddp_aid computes the ID, to a specified precision, 5c of an arbitrary matrix. This routine is randomized. 6c 7c routine idd_estrank estimates the numerical rank, 8c to a specified precision, of an arbitrary matrix. 9c This routine is randomized. 10c 11c 12ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 13c 14c 15c 16c 17 subroutine iddp_aid(eps,m,n,a,work,krank,list,proj) 18c 19c computes the ID of the matrix a, i.e., lists in list 20c the indices of krank columns of a such that 21c 22c a(j,list(k)) = a(j,list(k)) 23c 24c for all j = 1, ..., m; k = 1, ..., krank, and 25c 26c krank 27c a(j,list(k)) = Sigma a(j,list(l)) * proj(l,k-krank) (*) 28c l=1 29c 30c + epsilon(j,k-krank) 31c 32c for all j = 1, ..., m; k = krank+1, ..., n, 33c 34c for some matrix epsilon dimensioned epsilon(m,n-krank) 35c such that the greatest singular value of epsilon 36c <= the greatest singular value of a * eps. 37c 38c input: 39c eps -- precision to which the ID is to be computed 40c m -- first dimension of a 41c n -- second dimension of a 42c a -- matrix to be decomposed; the present routine does not 43c alter a 44c work -- initialization array that has been constructed 45c by routine idd_frmi 46c 47c output: 48c krank -- numerical rank of a to precision eps 49c list -- indices of the columns in the ID 50c proj -- matrix of coefficients needed to interpolate 51c from the selected columns to the other columns 52c in the original matrix being ID'd; 53c proj doubles as a work array in the present routine, so 54c proj must be at least n*(2*n2+1)+n2+1 real*8 elements 55c long, where n2 is the greatest integer less than 56c or equal to m, such that n2 is a positive integer 57c power of two. 58c 59c _N.B._: The algorithm used by this routine is randomized. 60c proj must be at least n*(2*n2+1)+n2+1 real*8 elements 61c long, where n2 is the greatest integer less than 62c or equal to m, such that n2 is a positive integer 63c power of two. 64c 65c reference: 66c Halko, Martinsson, Tropp, "Finding structure with randomness: 67c probabilistic algorithms for constructing approximate 68c matrix decompositions," SIAM Review, 53 (2): 217-288, 69c 2011. 70c 71 implicit none 72 integer m,n,list(n),krank,kranki,n2 73 real*8 eps,a(m,n),proj(*),work(17*m+70) 74c 75c 76c Allocate memory in proj. 77c 78 n2 = work(2) 79c 80c 81c Find the rank of a. 82c 83 call idd_estrank(eps,m,n,a,work,kranki,proj) 84c 85c 86 if(kranki .eq. 0) call iddp_aid0(eps,m,n,a,krank,list,proj, 87 1 proj(m*n+1)) 88c 89 if(kranki .ne. 0) call iddp_aid1(eps,n2,n,kranki,proj, 90 1 krank,list,proj(n2*n+1)) 91c 92c 93 return 94 end 95c 96c 97c 98c 99 subroutine iddp_aid0(eps,m,n,a,krank,list,proj,rnorms) 100c 101c uses routine iddp_id to ID a without modifying its entries 102c (in contrast to the usual behavior of iddp_id). 103c 104c input: 105c eps -- precision of the decomposition to be constructed 106c m -- first dimension of a 107c n -- second dimension of a 108c 109c output: 110c krank -- numerical rank of the ID 111c list -- indices of the columns in the ID 112c proj -- matrix of coefficients needed to interpolate 113c from the selected columns to the other columns in a; 114c proj doubles as a work array in the present routine, so 115c must be at least m*n real*8 elements long 116c 117c work: 118c rnorms -- must be at least n real*8 elements long 119c 120c _N.B._: proj must be at least m*n real*8 elements long 121c 122 implicit none 123 integer m,n,krank,list(n),j,k 124 real*8 eps,a(m,n),proj(m,n),rnorms(n) 125c 126c 127c Copy a into proj. 128c 129 do k = 1,n 130 do j = 1,m 131 proj(j,k) = a(j,k) 132 enddo ! j 133 enddo ! k 134c 135c 136c ID proj. 137c 138 call iddp_id(eps,m,n,proj,krank,list,rnorms) 139c 140c 141 return 142 end 143c 144c 145c 146c 147 subroutine iddp_aid1(eps,n2,n,kranki,proj,krank,list,rnorms) 148c 149c IDs the uppermost kranki x n block of the n2 x n matrix 150c input as proj. 151c 152c input: 153c eps -- precision of the decomposition to be constructed 154c n2 -- first dimension of proj as input 155c n -- second dimension of proj as input 156c kranki -- number of rows to extract from proj 157c proj -- matrix containing the kranki x n block to be ID'd 158c 159c output: 160c proj -- matrix of coefficients needed to interpolate 161c from the selected columns to the other columns 162c in the original matrix being ID'd 163c krank -- numerical rank of the ID 164c list -- indices of the columns in the ID 165c 166c work: 167c rnorms -- must be at least n real*8 elements long 168c 169 implicit none 170 integer n,n2,kranki,krank,list(n),j,k 171 real*8 eps,proj(n2*n),rnorms(n) 172c 173c 174c Move the uppermost kranki x n block of the n2 x n matrix proj 175c to the beginning of proj. 176c 177 do k = 1,n 178 do j = 1,kranki 179 proj(j+kranki*(k-1)) = proj(j+n2*(k-1)) 180 enddo ! j 181 enddo ! k 182c 183c 184c ID proj. 185c 186 call iddp_id(eps,kranki,n,proj,krank,list,rnorms) 187c 188c 189 return 190 end 191c 192c 193c 194c 195 subroutine idd_estrank(eps,m,n,a,w,krank,ra) 196c 197c estimates the numerical rank krank of an m x n matrix a 198c to precision eps. This routine applies n2 random vectors 199c to a, obtaining ra, where n2 is the greatest integer 200c less than or equal to m such that n2 is a positive integer 201c power of two. krank is typically about 8 higher than 202c the actual numerical rank. 203c 204c input: 205c eps -- precision defining the numerical rank 206c m -- first dimension of a 207c n -- second dimension of a 208c a -- matrix whose rank is to be estimated 209c w -- initialization array that has been constructed 210c by routine idd_frmi 211c 212c output: 213c krank -- estimate of the numerical rank of a; 214c this routine returns krank = 0 when the actual 215c numerical rank is nearly full (that is, 216c greater than n - 8 or n2 - 8) 217c ra -- product of an n2 x m random matrix and the m x n matrix 218c a, where n2 is the greatest integer less than or equal 219c to m such that n2 is a positive integer power of two; 220c ra doubles as a work array in the present routine, and so 221c must be at least n*n2+(n+1)*(n2+1) real*8 elements long 222c 223c _N.B._: ra must be at least n*n2+(n2+1)*(n+1) real*8 224c elements long for use in the present routine 225c (here, n2 is the greatest integer less than or equal 226c to m, such that n2 is a positive integer power of two). 227c This routine returns krank = 0 when the actual 228c numerical rank is nearly full. 229c 230 implicit none 231 integer m,n,krank,n2,irat,lrat,iscal,lscal,ira,lra,lra2 232 real*8 eps,a(m,n),ra(*),w(17*m+70) 233c 234c 235c Extract from the array w initialized by routine idd_frmi 236c the greatest integer less than or equal to m that is 237c a positive integer power of two. 238c 239 n2 = w(2) 240c 241c 242c Allocate memory in ra. 243c 244 lra = 0 245c 246 ira = lra+1 247 lra2 = n2*n 248 lra = lra+lra2 249c 250 irat = lra+1 251 lrat = n*(n2+1) 252 lra = lra+lrat 253c 254 iscal = lra+1 255 lscal = n2+1 256 lra = lra+lscal 257c 258 call idd_estrank0(eps,m,n,a,w,n2,krank,ra(ira),ra(irat), 259 1 ra(iscal)) 260c 261c 262 return 263 end 264c 265c 266c 267c 268 subroutine idd_estrank0(eps,m,n,a,w,n2,krank,ra,rat,scal) 269c 270c routine idd_estrank serves as a memory wrapper 271c for the present routine. (Please see routine idd_estrank 272c for further documentation.) 273c 274 implicit none 275 integer m,n,n2,krank,ifrescal,k,nulls,j 276 real*8 a(m,n),ra(n2,n),scal(n2+1),eps,residual, 277 1 w(17*m+70),rat(n,n2+1),ss,ssmax 278c 279c 280c Apply the random matrix to every column of a, obtaining ra. 281c 282 do k = 1,n 283 call idd_frm(m,n2,w,a(1,k),ra(1,k)) 284 enddo ! k 285c 286c 287c Compute the sum of squares of the entries in each column of ra 288c and the maximum of all such sums. 289c 290 ssmax = 0 291c 292 do k = 1,n 293c 294 ss = 0 295 do j = 1,m 296 ss = ss+a(j,k)**2 297 enddo ! j 298c 299 if(ss .gt. ssmax) ssmax = ss 300c 301 enddo ! k 302c 303c 304c Transpose ra to obtain rat. 305c 306 call idd_atransposer(n2,n,ra,rat) 307c 308c 309 krank = 0 310 nulls = 0 311c 312c 313c Loop until nulls = 7, krank+nulls = n2, or krank+nulls = n. 314c 315 1000 continue 316c 317c 318 if(krank .gt. 0) then 319c 320c Apply the previous Householder transformations 321c to rat(:,krank+1). 322c 323 ifrescal = 0 324c 325 do k = 1,krank 326 call idd_houseapp(n-k+1,rat(1,k),rat(k,krank+1), 327 1 ifrescal,scal(k),rat(k,krank+1)) 328 enddo ! k 329c 330 endif ! krank .gt. 0 331c 332c 333c Compute the Householder vector associated 334c with rat(krank+1:*,krank+1). 335c 336 call idd_house(n-krank,rat(krank+1,krank+1), 337 1 residual,rat(1,krank+1),scal(krank+1)) 338 residual = abs(residual) 339c 340c 341 krank = krank+1 342 if(residual .le. eps*sqrt(ssmax)) nulls = nulls+1 343c 344c 345 if(nulls .lt. 7 .and. krank+nulls .lt. n2 346 1 .and. krank+nulls .lt. n) 347 2 goto 1000 348c 349c 350 if(nulls .lt. 7) krank = 0 351c 352c 353 return 354 end 355c 356c 357c 358c 359 subroutine idd_atransposer(m,n,a,at) 360c 361c transposes a to obtain at. 362c 363c input: 364c m -- first dimension of a, and second dimension of at 365c n -- second dimension of a, and first dimension of at 366c a -- matrix to be transposed 367c 368c output: 369c at -- transpose of a 370c 371 implicit none 372 integer m,n,j,k 373 real*8 a(m,n),at(n,m) 374c 375c 376 do k = 1,n 377 do j = 1,m 378c 379 at(k,j) = a(j,k) 380c 381 enddo ! j 382 enddo ! k 383c 384c 385 return 386 end 387