Octopus
sort.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2021 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
24module sort_oct_m
25 use debug_oct_m
26 use global_oct_m
27
28 implicit none
29
30 private
31 public :: &
32 sort, &
34
35 interface robust_sort_by_abs
36 procedure irobust_sort_by_abs, drobust_sort_by_abs
37 end interface robust_sort_by_abs
38
39 ! ------------------------------------------------------------------------------
61 interface sort
62 module procedure dsort, isort, lsort
63 module procedure dshellsort1, zshellsort1, ishellsort1
64 module procedure dshellsort2, zshellsort2, ishellsort2
65 end interface sort
66
68 interface
69 subroutine dsort1(size, array)
70 use, intrinsic :: iso_fortran_env
71 implicit none
72 integer, intent(in) :: size
73 real(real64), intent(inout) :: array(*)
74 end subroutine dsort1
75
76 subroutine dsort2(size, array, indices)
77 use, intrinsic :: iso_fortran_env
78 implicit none
79 integer, intent(in) :: size
80 real(real64), intent(inout) :: array(*)
81 integer, intent(out) :: indices(*)
82 end subroutine dsort2
83
84 subroutine isort1(size, array)
85 implicit none
86 integer, intent(in) :: size
87 integer, intent(inout) :: array(*)
88 end subroutine isort1
89
90 subroutine isort2(size, array, indices)
91 implicit none
92 integer, intent(in) :: size
93 integer, intent(inout) :: array(*)
94 integer, intent(out) :: indices(*)
95 end subroutine isort2
96
97 subroutine lsort1(size, array)
98 use, intrinsic :: iso_fortran_env
99 implicit none
100 integer, intent(in) :: size
101 integer(int64), intent(inout) :: array(*)
102 end subroutine lsort1
103
104 subroutine lsort2(size, array, indices)
105 use, intrinsic :: iso_fortran_env
106 implicit none
107 integer, intent(in) :: size
108 integer(int64), intent(inout) :: array(*)
109 integer, intent(out) :: indices(*)
110 end subroutine lsort2
111 end interface
112
113contains
114
115 ! ---------------------------------------------------------
116 subroutine dsort(a, ind)
117 real(real64), intent(inout) :: a(:)
118 integer, optional, intent(out) :: ind(:)
120 push_sub(dsort)
121
122 if (size(a) > 0) then
123
124 if (.not. present(ind)) then
125 call dsort1(size(a), a)
126 else
127 call dsort2(size(a), a, ind)
128 end if
129
130 end if
131
132 pop_sub(dsort)
133 end subroutine dsort
134
135
136 ! ---------------------------------------------------------
138 subroutine isort(a, ind)
139 integer, intent(inout) :: a(:)
140 integer, optional, intent(out) :: ind(:)
141
142 push_sub(isort)
143
144 if (size(a) > 0) then
145
146 if (.not. present(ind)) then
147 call isort1(size(a), a)
148 else
149 call isort2(size(a), a, ind)
150 end if
151
152 end if
153
154 pop_sub(isort)
155 end subroutine isort
157 ! ---------------------------------------------------------
159 subroutine lsort(a, ind)
160 integer(int64), intent(inout) :: a(:)
161 integer, optional, intent(out) :: ind(:)
162
163 push_sub(lsort)
165 if (size(a) > 0) then
166
167 if (.not. present(ind)) then
168 call lsort1(size(a), a)
169 else
170 call lsort2(size(a), a, ind)
171 end if
172
173 end if
174
175 pop_sub(lsort)
176 end subroutine lsort
177
178
180 pure logical function iless_idx(i, j, off, kabs, ksgn) result(less)
181 integer, intent(in) :: i, j
182 integer, intent(in) :: off(:, :) ! (ndim, n)
183 real(int64), intent(in) :: kabs(:)
184 integer, intent(in) :: ksgn(:)
186 integer :: d, ndim
187
188 if (are_different(kabs(i), kabs(j))) then
189 less = kabs(i) < kabs(j)
190 return
191 end if
193 if (ksgn(i) /= ksgn(j)) then
194 less = ksgn(i) < ksgn(j) ! 0 before 1
195 return
196 end if
197
198 ndim = size(off, 1)
199 do d = 1, ndim
200 if (off(d,i) /= off(d,j)) then
201 less = off(d,i) < off(d,j)
202 return
203 end if
204 end do
205
206 less = i < j ! final stability (should not matter if offsets are unique)
207 end function iless_idx
208
210 pure logical function dless_idx(i, j, off, kabs, ksgn) result(less)
211 integer, intent(in) :: i, j
212 real(int64), intent(in) :: off(:, :) ! (ndim, n)
213 real(int64), intent(in) :: kabs(:)
214 integer, intent(in) :: ksgn(:)
215
216 integer :: d, ndim
217
218 if (are_different(kabs(i), kabs(j))) then
219 less = kabs(i) < kabs(j)
220 return
221 end if
222
223 if (ksgn(i) /= ksgn(j)) then
224 less = ksgn(i) < ksgn(j) ! 0 before 1
225 return
226 end if
227
228 ndim = size(off, 1)
229 do d = 1, ndim
230 if (are_different(off(d,i), off(d,j))) then
231 less = off(d,i) < off(d,j)
232 return
233 end if
234 end do
235
236 less = i < j ! final stability (should not matter if offsets are unique)
237 end function dless_idx
238
239 logical pure function are_different(x, y)
240 real(real64), intent(in) :: x,y
241 are_different = abs(x - y) > abs(y) * 1.0e-14_real64 + 1.0e-14_real64
242 end function are_different
243
245 recursive subroutine imergesort_perm(perm, tmp, l, r, off, kabs, ksgn)
246 integer, intent(inout) :: perm(:), tmp(:)
247 integer, intent(in) :: l, r
248 integer, intent(in) :: off(:, :)
249 real(real64), intent(in) :: kabs(:)
250 integer, intent(in) :: ksgn(:)
251
252 integer :: m, i, j, k
253
254 if (r <= l) return
255 m = (l + r) / 2
256
257 call imergesort_perm(perm, tmp, l, m, off, kabs, ksgn)
258 call imergesort_perm(perm, tmp, m+1, r, off, kabs, ksgn)
259
260 i = l; j = m+1; k = l
261 do while (i <= m .and. j <= r)
262 if (iless_idx(perm(i), perm(j), off, kabs, ksgn)) then
263 tmp(k) = perm(i); i = i+1
264 else
265 tmp(k) = perm(j); j = j+1
266 end if
267 k = k+1
268 end do
269 do while (i <= m); tmp(k) = perm(i); i=i+1; k=k+1; end do
270 do while (j <= r); tmp(k) = perm(j); j=j+1; k=k+1; end do
271
272 perm(l:r) = tmp(l:r)
273 end subroutine imergesort_perm
274
276 recursive subroutine dmergesort_perm(perm, tmp, l, r, off, kabs, ksgn)
277 integer, intent(inout) :: perm(:), tmp(:)
278 integer, intent(in) :: l, r
279 real(real64), intent(in) :: off(:, :)
280 real(real64), intent(in) :: kabs(:)
281 integer, intent(in) :: ksgn(:)
282
283 integer :: m, i, j, k
284
285 if (r <= l) return
286 m = (l + r) / 2
287
288 call dmergesort_perm(perm, tmp, l, m, off, kabs, ksgn)
289 call dmergesort_perm(perm, tmp, m+1, r, off, kabs, ksgn)
290
291 i = l; j = m+1; k = l
292 do while (i <= m .and. j <= r)
293 if (dless_idx(perm(i), perm(j), off, kabs, ksgn)) then
294 tmp(k) = perm(i); i = i+1
295 else
296 tmp(k) = perm(j); j = j+1
297 end if
298 k = k+1
299 end do
300 do while (i <= m); tmp(k) = perm(i); i=i+1; k=k+1; end do
301 do while (j <= r); tmp(k) = perm(j); j=j+1; k=k+1; end do
302
303 perm(l:r) = tmp(l:r)
304 end subroutine dmergesort_perm
306
312 subroutine irobust_sort_by_abs(v, off, perm, negative_first)
313 real(real64), intent(in) :: v(:)
314 integer, intent(in) :: off(:, :) ! (ndim, n)
315 integer, intent(out) :: perm(size(v))
316 logical, intent(in), optional :: negative_first
317
318 integer :: n, i
319 logical :: neg_first
320 integer, allocatable :: tmp(:)
321 real(real64), allocatable :: kabs(:)
322 integer, allocatable :: ksgn(:)
323
324 push_sub(irobust_sort_by_abs)
325
326 n = size(v)
327 assert(size(off, dim=2) == n)
328
329 neg_first = optional_default(negative_first, .true.)
330
331 allocate(tmp(n), kabs(n), ksgn(n))
332
333 do i = 1, n
334 perm(i) = i
335 kabs(i) = abs(v(i))
336
337 if (neg_first) then
338 ksgn(i) = merge(0, 1, v(i) < 0.0_real64) ! neg (0) then pos (1)
339 else
340 ksgn(i) = merge(0, 1, v(i) >= 0.0_real64) ! pos (0) then neg (1)
341 end if
342 end do
343
344 call imergesort_perm(perm, tmp, 1, n, off, kabs, ksgn)
345
346 deallocate(tmp, kabs, ksgn)
347 pop_sub(irobust_sort_by_abs)
348 end subroutine irobust_sort_by_abs
349
350 subroutine drobust_sort_by_abs(v, off, perm, negative_first)
351 real(real64), intent(in) :: v(:)
352 real(real64), intent(in) :: off(:, :) ! (ndim, n)
353 integer, intent(out) :: perm(size(v))
354 logical, intent(in), optional :: negative_first
355
356 integer :: n, i
357 logical :: neg_first
358 integer, allocatable :: tmp(:)
359 real(real64), allocatable :: kabs(:)
360 integer, allocatable :: ksgn(:)
361
362 push_sub(drobust_sort_by_abs)
363
364 n = size(v)
365 assert(size(off, dim=2) == n)
366
367 neg_first = optional_default(negative_first, .true.)
368
369 allocate(tmp(n), kabs(n), ksgn(n))
370
371 do i = 1, n
372 perm(i) = i
373 kabs(i) = abs(v(i))
374
375 if (neg_first) then
376 ksgn(i) = merge(0, 1, v(i) < 0.0_real64) ! neg (0) then pos (1)
377 else
378 ksgn(i) = merge(0, 1, v(i) >= 0.0_real64) ! pos (0) then neg (1)
379 end if
380 end do
381
382 call dmergesort_perm(perm, tmp, 1, n, off, kabs, ksgn)
383
384 deallocate(tmp, kabs, ksgn)
385 pop_sub(drobust_sort_by_abs)
386 end subroutine drobust_sort_by_abs
387
388
389#include "undef.F90"
390#include "complex.F90"
391#include "sort_inc.F90"
392
393#include "undef.F90"
394#include "real.F90"
395#include "sort_inc.F90"
396
397#include "undef.F90"
398#include "integer.F90"
399#include "sort_inc.F90"
400
401end module sort_oct_m
402
403!! Local Variables:
404!! mode: f90
405!! coding: utf-8
406!! End:
from sort_low.cc
Definition: sort.F90:164
This is the common interface to a sorting routine. It performs the shell algorithm,...
Definition: sort.F90:156
This module is intended to contain "only mathematical" functions and procedures.
Definition: sort.F90:119
subroutine ishellsort2(a, x)
Definition: sort.F90:931
subroutine drobust_sort_by_abs(v, off, perm, negative_first)
Definition: sort.F90:446
recursive subroutine dmergesort_perm(perm, tmp, l, r, off, kabs, ksgn)
Perform the permutations for the sorting.
Definition: sort.F90:372
subroutine dsort(a, ind)
Definition: sort.F90:212
subroutine dshellsort1(a, x)
Definition: sort.F90:719
subroutine zshellsort2(a, x)
Definition: sort.F90:599
subroutine isort(a, ind)
Shell sort for integer arrays.
Definition: sort.F90:234
subroutine irobust_sort_by_abs(v, off, perm, negative_first)
Robbust sorting of floating point numbers by absolute values.
Definition: sort.F90:408
subroutine ishellsort1(a, x)
Definition: sort.F90:885
subroutine dshellsort2(a, x)
Definition: sort.F90:765
logical pure function are_different(x, y)
Definition: sort.F90:335
pure logical function dless_idx(i, j, off, kabs, ksgn)
Sorting criterium for the robust sorting below.
Definition: sort.F90:306
subroutine lsort(a, ind)
Shell sort for integer(int64) arrays.
Definition: sort.F90:255
subroutine zshellsort1(a, x)
Definition: sort.F90:553
recursive subroutine imergesort_perm(perm, tmp, l, r, off, kabs, ksgn)
Perform the permutations for the sorting.
Definition: sort.F90:341
pure logical function iless_idx(i, j, off, kabs, ksgn)
Sorting criterium for the robust sorting below.
Definition: sort.F90:276
int true(void)