amd_aat.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* ========================================================================= */
  2. /* === AMD_aat ============================================================= */
  3. /* ========================================================================= */
  4. /* ------------------------------------------------------------------------- */
  5. /* AMD, Copyright (c) Timothy A. Davis, */
  6. /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
  7. /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
  8. /* web: http://www.cise.ufl.edu/research/sparse/amd */
  9. /* ------------------------------------------------------------------------- */
  10. /* AMD_aat: compute the symmetry of the pattern of A, and count the number of
  11. * nonzeros each column of A+A' (excluding the diagonal). Assumes the input
  12. * matrix has no errors, with sorted columns and no duplicates
  13. * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
  14. * checked).
  15. */
  16. #include "amd_internal.h"
  17. GLOBAL size_t AMD_aat /* returns nz in A+A' */
  18. (
  19. Int n,
  20. const Int Ap [ ],
  21. const Int Ai [ ],
  22. Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/
  23. Int Tp [ ], /* workspace of size n */
  24. double Info [ ]
  25. )
  26. {
  27. Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
  28. double sym ;
  29. size_t nzaat ;
  30. #ifndef NDEBUG
  31. AMD_debug_init ("AMD AAT") ;
  32. for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
  33. ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
  34. #endif
  35. if (Info != (double *) NULL)
  36. {
  37. /* clear the Info array, if it exists */
  38. for (i = 0 ; i < AMD_INFO ; i++)
  39. {
  40. Info [i] = EMPTY ;
  41. }
  42. Info [AMD_STATUS] = AMD_OK ;
  43. }
  44. for (k = 0 ; k < n ; k++)
  45. {
  46. Len [k] = 0 ;
  47. }
  48. nzdiag = 0 ;
  49. nzboth = 0 ;
  50. nz = Ap [n] ;
  51. for (k = 0 ; k < n ; k++)
  52. {
  53. p1 = Ap [k] ;
  54. p2 = Ap [k+1] ;
  55. AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
  56. /* construct A+A' */
  57. for (p = p1 ; p < p2 ; )
  58. {
  59. /* scan the upper triangular part of A */
  60. j = Ai [p] ;
  61. if (j < k)
  62. {
  63. /* entry A (j,k) is in the strictly upper triangular part,
  64. * add both A (j,k) and A (k,j) to the matrix A+A' */
  65. Len [j]++ ;
  66. Len [k]++ ;
  67. AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
  68. p++ ;
  69. }
  70. else if (j == k)
  71. {
  72. /* skip the diagonal */
  73. p++ ;
  74. nzdiag++ ;
  75. break ;
  76. }
  77. else /* j > k */
  78. {
  79. /* first entry below the diagonal */
  80. break ;
  81. }
  82. /* scan lower triangular part of A, in column j until reaching
  83. * row k. Start where last scan left off. */
  84. ASSERT (Tp [j] != EMPTY) ;
  85. ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
  86. pj2 = Ap [j+1] ;
  87. for (pj = Tp [j] ; pj < pj2 ; )
  88. {
  89. i = Ai [pj] ;
  90. if (i < k)
  91. {
  92. /* A (i,j) is only in the lower part, not in upper.
  93. * add both A (i,j) and A (j,i) to the matrix A+A' */
  94. Len [i]++ ;
  95. Len [j]++ ;
  96. AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n",
  97. i,j, j,i)) ;
  98. pj++ ;
  99. }
  100. else if (i == k)
  101. {
  102. /* entry A (k,j) in lower part and A (j,k) in upper */
  103. pj++ ;
  104. nzboth++ ;
  105. break ;
  106. }
  107. else /* i > k */
  108. {
  109. /* consider this entry later, when k advances to i */
  110. break ;
  111. }
  112. }
  113. Tp [j] = pj ;
  114. }
  115. /* Tp [k] points to the entry just below the diagonal in column k */
  116. Tp [k] = p ;
  117. }
  118. /* clean up, for remaining mismatched entries */
  119. for (j = 0 ; j < n ; j++)
  120. {
  121. for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
  122. {
  123. i = Ai [pj] ;
  124. /* A (i,j) is only in the lower part, not in upper.
  125. * add both A (i,j) and A (j,i) to the matrix A+A' */
  126. Len [i]++ ;
  127. Len [j]++ ;
  128. AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n",
  129. i,j, j,i)) ;
  130. }
  131. }
  132. /* --------------------------------------------------------------------- */
  133. /* compute the symmetry of the nonzero pattern of A */
  134. /* --------------------------------------------------------------------- */
  135. /* Given a matrix A, the symmetry of A is:
  136. * B = tril (spones (A), -1) + triu (spones (A), 1) ;
  137. * sym = nnz (B & B') / nnz (B) ;
  138. * or 1 if nnz (B) is zero.
  139. */
  140. if (nz == nzdiag)
  141. {
  142. sym = 1 ;
  143. }
  144. else
  145. {
  146. sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
  147. }
  148. nzaat = 0 ;
  149. for (k = 0 ; k < n ; k++)
  150. {
  151. nzaat += Len [k] ;
  152. }
  153. AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
  154. (double) nzaat)) ;
  155. AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
  156. nzboth, nz, nzdiag, sym)) ;
  157. if (Info != (double *) NULL)
  158. {
  159. Info [AMD_STATUS] = AMD_OK ;
  160. Info [AMD_N] = n ;
  161. Info [AMD_NZ] = nz ;
  162. Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */
  163. Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */
  164. Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */
  165. }
  166. return (nzaat) ;
  167. }