-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRCM.f90
311 lines (274 loc) · 9.07 KB
/
RCM.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
module mRCM
! By Kristoffer Andersen, Dec 2016
! Updated by Tue Boesen, August 2017
! These routines can be used to reorder a matrix.
! The only dependecies are to mSmat, mError, mArrays and mQuicksort
!
! The main routines are>
! RCMSort - performs a reverse Cuthill-McKee ordering of a matrix
! SymPerm - performs a symmetric permutation of a matrix: PAP^t
! HalfPermOnlyTranspose - by using permutation operations this
! routine finds the transpose of a matrix
use mSMat
implicit none
contains
subroutine RCMSort(ioA,oPerm)
! Kristoffer Andersen, Dec 2016
! this routine finds the reverse Cuthill-McKee ordering of matrix ioA
! and makes the symmetric permutation A = PAP^t
!
! IO
! IO - ioA - on input the unpermuted matrix
! on output the permuted matrix
! O - oPerm - the permuatation vector - this can ie be used for the vectors used together with the matrix
!
implicit none
type(Tsparsemat),intent(inout) :: ioA
integer,intent(out) :: oPerm(:)
! prog
call RCMOrdering(ioA,oPerm)
call symperm(ioA,oPerm)
end subroutine
subroutine RCMOrdering(iA,oRCMind,opStartIndex)
! Kristoffer Andersen, Dec 2016
! this routine finds the reverse Cuthill-McKee ordering for a
! symmetric sparse matrix iA.
! IO
! IO - iA - the unpermuted matrix
! O - RCMind - the permutation vector - this can ie be used for the vectors used together with the matrix
! I (optional) - opStartIndex - optional start index (default = 1)
!
use mArrays
use mQuickSort
implicit none
type(Tsparsemat),intent(inout) :: iA
integer,intent(out) :: oRCMind(:)
integer,intent(in),optional :: opStartIndex
!var
logical, allocatable :: inRCMind(:)
integer :: i,j,k,ni,ni1,nneighbours,jn,ad,itot,inArray,MinEle,n,MaxEle
integer,allocatable :: Neighbours(:),Adj(:),R(:),ele(:)
!prog
allocate(inRCMind(iA%NoRows))
allocate(Ele(iA%NoRows))
allocate(R(iA%NoRows))
inRCMInd(:) = .false. ! non sorted
MaxEle=-1
Ele=-1
do j=1,iA%NoRows
n=iA%RowIdxs(j+1)-iA%RowIdxs(j)
MaxEle=max(MaxEle,n)
Ele(j)=n
end do
allocate(Neighbours(MaxEle))
allocate(Adj(MaxEle))
R=-1
itot = 1
inArray = 0
do
if(itot.gt.iA%NoRows) exit ! termination
if(inArray.ge.iA%NoRows ) exit
if(R(itot).eq.-1) then
MinEle=999999
inArray=inArray+1
do j=1,iA%NoRows
if (inRCMInd(j)) then
cycle
end if
n=iA%RowIdxs(j+1)-iA%RowIdxs(j)
if (n.lt.MinEle) then
MinEle=n
R(itot)=j
end if
end do
end if
i = R(itot) !present index
inRCMInd(i) = .true. !Mark it
! get neighbours
ni = iA%Rowidxs(I)
ni1 = iA%Rowidxs(I+1)
Nneighbours = ni1-ni
Neighbours(1:Nneighbours) = ia%Colidxs(ni:(ni1-1))
! remove already present neighbours - this will also remove the self reference
jn = 1
do j = 1,Nneighbours
if(.not.inRCMInd(Neighbours(J))) then
Neighbours(Jn) = Neighbours(J)
jn = jn+1
endif
enddo
Nneighbours = jn-1
Adj(1:Nneighbours)=Ele(Neighbours(1:Nneighbours))
! sorting
call IntQSortC(adj(1:Nneighbours),Neighbours(1:Nneighbours)) ! we need a real type routine for this.
!Add new nodes to the queue
do j = 1,Nneighbours
inArray = inArray+1
R(inArray) = Neighbours(j) ! add neighbours
inRCMInd(Neighbours(J)) = .true. ! mark as included
enddo
itot = itot+1
enddo
! finally reverse the order
do i=1,(iA%NoRows)
oRCMind(i) = R(iA%NoRows-i+1)
enddo
return
! error messages
end subroutine RCMOrdering
subroutine halfperm(iA,oB,iPerm,opColCounts)
! by Kristoffer Andersen, Dec 2016
! this routine performs the operation B = (P*A)^t, where P is er
! permutation vector of A
! The out is sorted independent on the status of the input - nice feature!
!
! IO
! I iA - unpermuted matrix
! O oB - permuted and sorted matrix
! I iPerm - permutation vector
! I opColCounts (optional) - used to speed up repeated calls of the routine.
implicit none
!io
type(Tsparsemat),intent(in) :: iA
type(Tsparsemat),intent(out) :: oB
integer,intent(in) :: iPerm(:)
integer,intent(in),optional :: opColCounts(:)
!var
integer :: pi,i,j,jp,p,pm1,pm2,jpt
!prog
call SMatCreate(oB,ia%NoCols,iA%NoRows,'(PA)^T',.false.,iA%NoElements)
! create column structure in permuted matrix - the column count is unchanged by row permutations
if(present(opColCounts)) then ! when halfperm is called twice in symperm, one already knows this
oB%RowIdxs(1:iA%NoRows) = opColCounts(1:iA%NoRows)
else
oB%RowIdxs(:) = 0
do i=1,iA%NoRows
do j=iA%RowIDxs(i),iA%RowIdxs(i+1)-1
oB%RowIdxs(iA%ColIDxs(j)) = oB%RowIdxs(iA%ColIDxs(j))+1 ! find coumn counts
enddo
enddo
endif
! create column pointers
pm2 = 0
pm1 = 1
do i=3,iA%NoCols+3
p = pm1+ob%RowIdxs(i-2)
ob%RowIdxs(i-2) = pm2
pm2 =pm1
pm1 = p
enddo
! fill matrix
do i=1,iA%NoRows
pi = iPerm(i) ! get the permuted row
do jp=iA%RowIDxs(pi),iA%RowIdxs(pi+1)-1
j = iA%ColIdxs(jp)
jpt = oB%RowIdxs(j+1)
ob%ColIdxs(jpt) = i
oB%Vals(jpt) = iA%Vals(jp)
oB%RowIdxs(j+1) = jpt+1
enddo
enddo
oB%RowIdxs(1) = 1
oB%NoElements = iA%NoElements
return
! error messages
end subroutine halfperm
subroutine halfpermOnlyTranspose(iA,oB)
! by Kristoffer Andersen, Dec 2016
! this routine performs the operation B = A^t
! The out is sorted independent on the status of the input - nice feature!
!
! IO
! I iA - unpermuted matrix
! O oB - permuted and sorted matrix
!
implicit none
!io
type(Tsparsemat),intent(in) :: iA
type(Tsparsemat),intent(out) :: oB
!var
integer :: pi,i,j,jp,p,pm1,pm2,jpt
!prog
call SMatCreate(oB,ia%NoCols,iA%NoRows,'(A)^T',.false.,iA%NoElements)
! create column structure in permuted matrix - the column count is unchanged by row permutations
oB%RowIdxs(:) = 0
do i=1,iA%NoRows
do j=iA%RowIDxs(i),iA%RowIdxs(i+1)-1
oB%RowIdxs(iA%ColIDxs(j)) = oB%RowIdxs(iA%ColIDxs(j))+1 ! find coumn counts
enddo
enddo
! create column pointers
pm2 = 0
pm1 = 1
do i=3,iA%NoCols+3
p = pm1+ob%RowIdxs(i-2)
ob%RowIdxs(i-2) = pm2
pm2 =pm1
pm1 = p
enddo
! fill matrix
do i=1,iA%NoRows
pi = i ! get row
do jp=iA%RowIDxs(pi),iA%RowIdxs(pi+1)-1
j = iA%ColIdxs(jp)
jpt = oB%RowIdxs(j+1)
ob%ColIdxs(jpt) = i
oB%Vals(jpt) = iA%Vals(jp)
oB%RowIdxs(j+1) = jpt+1
enddo
enddo
oB%RowIdxs(1) = 1
oB%NoElements = iA%NoElements
return
! error messages
end subroutine halfpermOnlyTranspose
subroutine symperm(ioA,iPerm)
! by Kristoffer Andersen, Dec 2016
! performs the halfperm twice in order to get B = PAP^t = (P(PA)^t)^t
!
! IO
! IO ioA - in input: unpermuted matrix
! on output: permuted and sorted matrix
! I iPerm- permutation vector
implicit none
!io
type(Tsparsemat),intent(inout) :: ioA
integer,intent(in) :: iPerm(:)
!var
type(tsparsemat) :: temp
integer,allocatable :: ColCounts(:)
integer :: i,pi,N
!prog
call halfperm(ioA,temp,iPerm)
N = ioA%NoRows
allocate(ColCounts(N))
do i = 1,N
pi = iPerm(i)
ColCounts(i) = ioA%RowIdxs(pi+1)-ioA%RowIdxs(pi)
enddo
call halfperm(temp,ioA,iPerm,ColCounts)
return
end subroutine symperm
subroutine PermuteVector(ioV,iPerm)
! by Kristoffer Andersen, Dec 2016
! this routine permutes a vector according to iPerm
!
! IO
! IO ioV - in input: unpermuted vector
! on output: permuted vector
! I iPerm- permutation vector
real*8,intent(inout) :: ioV(:)
integer,intent(in) :: iPerm(:)
! var
real*8,allocatable :: temp(:)
integer :: i,N
!prog
N = ubound(ioV,1)
allocate(temp(N))
temp(1:N) = ioV(1:N)
do i=1,N
ioV(iPerm(i)) = temp(i)
enddo
return
end subroutine PermuteVector
end module mRCM