diff --git a/src/stdlib_sorting.fypp b/src/stdlib_sorting.fypp index f1139e9b2..9658021fe 100644 --- a/src/stdlib_sorting.fypp +++ b/src/stdlib_sorting.fypp @@ -336,24 +336,26 @@ module stdlib_sorting !! non-decreasing data. #:for k1, t1 in IRS_KINDS_TYPES - module subroutine ${k1}$_ord_sort( array, work ) + module subroutine ${k1}$_ord_sort( array, work, reverse ) !! Version: experimental !! !! `${k1}$_ord_sort( array )` sorts the input `ARRAY` of type `${t1}$` !! using a hybrid sort based on the `'Rust" sort` algorithm found in `slice.rs` ${t1}$, intent(inout) :: array(0:) ${t1}$, intent(out), optional :: work(0:) + logical, intent(in), optional :: reverse end subroutine ${k1}$_ord_sort #:endfor - module subroutine char_ord_sort( array, work ) + module subroutine char_ord_sort( array, work, reverse ) !! Version: experimental !! !! `char_ord_sort( array )` sorts the input `ARRAY` of type `CHARACTER(*)` !! using a hybrid sort based on the `'Rust" sort` algorithm found in `slice.rs` character(len=*), intent(inout) :: array(0:) character(len=len(array)), intent(out), optional :: work(0:) + logical, intent(in), optional :: reverse end subroutine char_ord_sort end interface ord_sort @@ -365,7 +367,7 @@ module stdlib_sorting !! on the `introsort` of David Musser. #:for k1, t1 in IRS_KINDS_TYPES - pure module subroutine ${k1}$_sort( array ) + pure module subroutine ${k1}$_sort( array, reverse ) !! Version: experimental !! !! `${k1}$_sort( array )` sorts the input `ARRAY` of type `${t1}$` @@ -373,12 +375,13 @@ module stdlib_sorting !! The algorithm is of order O(N Ln(N)) for all inputs. !! Because it relies on `quicksort`, the coefficient of the O(N Ln(N)) !! behavior is small for random data compared to other sorting algorithms. - ${t1}$, intent(inout) :: array(0:) + ${t1}$, intent(inout) :: array(0:) + logical, intent(in), optional :: reverse end subroutine ${k1}$_sort #:endfor - pure module subroutine char_sort( array ) + pure module subroutine char_sort( array, reverse ) !! Version: experimental !! !! `char_sort( array )` sorts the input `ARRAY` of type `CHARACTER(*)` @@ -387,6 +390,7 @@ module stdlib_sorting !! Because it relies on `quicksort`, the coefficient of the O(N Ln(N)) !! behavior is small for random data compared to other sorting algorithms. character(len=*), intent(inout) :: array(0:) + logical, intent(in), optional :: reverse end subroutine char_sort end interface sort diff --git a/src/stdlib_sorting_ord_sort.fypp b/src/stdlib_sorting_ord_sort.fypp index 065b2a3c8..d43162320 100644 --- a/src/stdlib_sorting_ord_sort.fypp +++ b/src/stdlib_sorting_ord_sort.fypp @@ -1,6 +1,11 @@ #:include "common.fypp" #:set IRS_KINDS_TYPES = INT_KINDS_TYPES + REAL_KINDS_TYPES + STRING_KINDS_TYPES +#:set SIGN_NAME = ["increase", "decrease"] +#:set SIGN_TYPE = [">", "<"] +#:set SIGN_OPP_TYPE = ["<", ">"] +#:set SIGN_NAME_TYPE = list(zip(SIGN_NAME, SIGN_TYPE, SIGN_OPP_TYPE)) + !! Licensing: !! !! This file is subjec† both to the Fortran Standard Library license, and @@ -57,8 +62,29 @@ submodule(stdlib_sorting) stdlib_sorting_ord_sort contains #:for k1, t1 in IRS_KINDS_TYPES + module subroutine ${k1}$_ord_sort( array, work, reverse ) + ${t1}$, intent(inout) :: array(0:) + ${t1}$, intent(out), optional :: work(0:) + logical, intent(in), optional :: reverse + + logical :: reverse_ + + reverse_ = .false. + if(present(reverse)) reverse_ = reverse + + if (reverse_) then + call ${k1}$_decrease_ord_sort(array, work) + else + call ${k1}$_increase_ord_sort(array, work) + endif - module subroutine ${k1}$_ord_sort( array, work ) + end subroutine ${k1}$_ord_sort +#:endfor + +#:for sname, signt, signoppt in SIGN_NAME_TYPE +#:for k1, t1 in IRS_KINDS_TYPES + + subroutine ${k1}$_${sname}$_ord_sort( array, work ) ! A translation to Fortran 2008, of the `"Rust" sort` algorithm found in ! `slice.rs` ! https://github.com/rust-lang/rust/blob/90eb44a5897c39e3dff9c7e48e3973671dcd9496/src/liballoc/slice.rs#L2159 @@ -92,7 +118,7 @@ contains ! Allocate a buffer to use as scratch memory. array_size = size( array, kind=int_size ) allocate( buf(0:array_size/2-1), stat=stat ) - if ( stat /= 0 ) error stop "${k1}$_ord_sort: Allocation of buffer failed." + if ( stat /= 0 ) error stop "${k1}$_${sname}$_ord_sort: Allocation of buffer failed." call merge_sort( array, buf ) end if @@ -129,7 +155,7 @@ contains do j=1, size(array, kind=int_size)-1 key = array(j) i = j - 1 - do while( i >= 0 .and. array(i) > key ) + do while( i >= 0 .and. array(i) ${signt}$ key ) array(i+1) = array(i) i = i - 1 end do @@ -204,7 +230,7 @@ contains tmp = array(0) find_hole: do i=1, size(array, kind=int_size)-1 - if ( array(i) >= tmp ) exit find_hole + if ( array(i) ${signt}$= tmp ) exit find_hole array(i-1) = array(i) end do find_hole array(i-1) = tmp @@ -263,16 +289,16 @@ contains start = finish if ( start > 0 ) then start = start - 1 - if ( array(start+1) < array(start) ) then + if ( array(start+1) ${signoppt}$ array(start) ) then Descending: do while ( start > 0 ) - if ( array(start) >= array(start-1) ) & + if ( array(start) ${signt}$= array(start-1) ) & exit Descending start = start - 1 end do Descending call reverse_segment( array(start:finish) ) else Ascending: do while( start > 0 ) - if ( array(start) < array(start-1) ) exit Ascending + if ( array(start) ${signoppt}$ array(start-1) ) exit Ascending start = start - 1 end do Ascending end if @@ -338,7 +364,7 @@ contains i = 0 j = mid merge_lower: do k = 0, array_len-1 - if ( buf(i) <= array(j) ) then + if ( buf(i) ${signoppt}$= array(j) ) then array(k) = buf(i) i = i + 1 if ( i >= mid ) exit merge_lower @@ -356,7 +382,7 @@ contains i = mid - 1 j = array_len - mid -1 merge_upper: do k = array_len-1, 0, -1 - if ( buf(j) >= array(i) ) then + if ( buf(j) ${signt}$= array(i) ) then array(k) = buf(j) j = j - 1 if ( j < 0 ) exit merge_upper @@ -392,12 +418,32 @@ contains end subroutine reverse_segment - end subroutine ${k1}$_ord_sort + end subroutine ${k1}$_${sname}$_ord_sort #:endfor +#:endfor + + module subroutine char_ord_sort( array, work, reverse ) + character(len=*), intent(inout) :: array(0:) + character(len=len(array)), intent(out), optional :: work(0:) + logical, intent(in), optional :: reverse + + logical :: reverse_ + + reverse_ = .false. + if(present(reverse)) reverse_ = reverse + if (reverse_) then + call char_decrease_ord_sort(array, work) + else + call char_increase_ord_sort(array, work) + endif + + end subroutine char_ord_sort - module subroutine char_ord_sort( array, work ) + +#:for sname, signt, signoppt in SIGN_NAME_TYPE + subroutine char_${sname}$_ord_sort( array, work ) ! A translation to Fortran 2008, of the `"Rust" sort` algorithm found in ! `slice.rs` ! https://github.com/rust-lang/rust/blob/90eb44a5897c39e3dff9c7e48e3973671dcd9496/src/liballoc/slice.rs#L2159 @@ -432,7 +478,7 @@ contains array_size = size( array, kind=int_size ) allocate( character(len=len(array)) :: buf(0:array_size/2-1), & stat=stat ) - if ( stat /= 0 ) error stop "${k1}$_ord_sort: Allocation of buffer failed." + if ( stat /= 0 ) error stop "${k1}$_${sname}$_ord_sort: Allocation of buffer failed." call merge_sort( array, buf ) end if @@ -469,7 +515,7 @@ contains do j=1, size(array, kind=int_size)-1 key = array(j) i = j - 1 - do while( i >= 0 .and. array(i) > key ) + do while( i >= 0 .and. array(i) ${signt}$ key ) array(i+1) = array(i) i = i - 1 end do @@ -544,7 +590,7 @@ contains tmp = array(0) find_hole: do i=1, size(array, kind=int_size)-1 - if ( array(i) >= tmp ) exit find_hole + if ( array(i) ${signt}$= tmp ) exit find_hole array(i-1) = array(i) end do find_hole array(i-1) = tmp @@ -603,16 +649,16 @@ contains start = finish if ( start > 0 ) then start = start - 1 - if ( array(start+1) < array(start) ) then + if ( array(start+1) ${signoppt}$ array(start) ) then Descending: do while ( start > 0 ) - if ( array(start) >= array(start-1) ) & + if ( array(start) ${signt}$= array(start-1) ) & exit Descending start = start - 1 end do Descending call reverse_segment( array(start:finish) ) else Ascending: do while( start > 0 ) - if ( array(start) < array(start-1) ) exit Ascending + if ( array(start) ${signoppt}$ array(start-1) ) exit Ascending start = start - 1 end do Ascending end if @@ -678,7 +724,7 @@ contains i = 0 j = mid merge_lower: do k = 0, array_len-1 - if ( buf(i) <= array(j) ) then + if ( buf(i) ${signoppt}$= array(j) ) then array(k) = buf(i) i = i + 1 if ( i >= mid ) exit merge_lower @@ -696,7 +742,7 @@ contains i = mid - 1 j = array_len - mid -1 merge_upper: do k = array_len-1, 0, -1 - if ( buf(j) >= array(i) ) then + if ( buf(j) ${signt}$= array(i) ) then array(k) = buf(j) j = j - 1 if ( j < 0 ) exit merge_upper @@ -732,7 +778,8 @@ contains end subroutine reverse_segment - end subroutine char_ord_sort + end subroutine char_${sname}$_ord_sort +#:endfor end submodule stdlib_sorting_ord_sort diff --git a/src/stdlib_sorting_sort.fypp b/src/stdlib_sorting_sort.fypp index 244165c69..8d042ad18 100644 --- a/src/stdlib_sorting_sort.fypp +++ b/src/stdlib_sorting_sort.fypp @@ -1,6 +1,11 @@ #:include "common.fypp" #:set IRS_KINDS_TYPES = INT_KINDS_TYPES + REAL_KINDS_TYPES + STRING_KINDS_TYPES +#:set SIGN_NAME = ["increase", "decrease"] +#:set SIGN_TYPE = [">", "<"] +#:set SIGN_OPP_TYPE = ["<", ">"] +#:set SIGN_NAME_TYPE = list(zip(SIGN_NAME, SIGN_TYPE, SIGN_OPP_TYPE)) + !! Licensing: !! !! This file is subjec† both to the Fortran Standard Library license, and @@ -60,10 +65,28 @@ submodule(stdlib_sorting) stdlib_sorting_sort contains +#:for k1, t1 in IRS_KINDS_TYPES + pure module subroutine ${k1}$_sort( array, reverse ) + ${t1}$, intent(inout) :: array(0:) + logical, intent(in), optional :: reverse + + logical :: reverse_ + + reverse_ = .false. + if(present(reverse)) reverse_ = reverse + if(reverse_)then + call ${k1}$_decrease_sort(array) + else + call ${k1}$_increase_sort(array) + endif + end subroutine ${k1}$_sort +#:endfor + +#:for sname, signt, signoppt in SIGN_NAME_TYPE #:for k1, t1 in IRS_KINDS_TYPES - pure module subroutine ${k1}$_sort( array ) + pure subroutine ${k1}$_${sname}$_sort( array ) ! `${k1}$_sort( array )` sorts the input `ARRAY` of type `${t1}$` ! using a hybrid sort based on the `introsort` of David Musser. As with ! `introsort`, `${k1}$_sort( array )` is an unstable hybrid comparison @@ -126,12 +149,12 @@ contains u = array( 0 ) v = array( size(array, kind=int_size)/2-1 ) w = array( size(array, kind=int_size)-1 ) - if ( (u > v) .neqv. (u > w) ) then + if ( (u ${signt}$ v) .neqv. (u ${signt}$ w) ) then x = u y = array(0) array(0) = array( size( array, kind=int_size ) - 1 ) array( size( array, kind=int_size ) - 1 ) = y - else if ( (v < u) .neqv. (v < w) ) then + else if ( (v ${signoppt}$ u) .neqv. (v ${signoppt}$ w) ) then x = v y = array(size( array, kind=int_size )/2-1) array( size( array, kind=int_size )/2-1 ) = & @@ -143,7 +166,7 @@ contains ! Partition the array. i = -1_int_size do j = 0_int_size, size(array, kind=int_size)-2 - if ( array(j) <= x ) then + if ( array(j) ${signoppt}$= x ) then i = i + 1 y = array(i) array(i) = array(j) @@ -168,7 +191,7 @@ contains key = array(j) i = j - 1 do while( i >= 0 ) - if ( array(i) <= key ) exit + if ( array(i) ${signoppt}$= key ) exit array(i+1) = array(i) i = i - 1 end do @@ -212,10 +235,10 @@ contains l = 2_int_size * i + 1_int_size r = l + 1_int_size if ( l < heap_size ) then - if ( array(l) > array(largest) ) largest = l + if ( array(l) ${signt}$ array(largest) ) largest = l end if if ( r < heap_size ) then - if ( array(r) > array(largest) ) largest = r + if ( array(r) ${signt}$ array(largest) ) largest = r end if if ( largest /= i ) then y = array(i) @@ -226,14 +249,32 @@ contains end subroutine max_heapify - end subroutine ${k1}$_sort + end subroutine ${k1}$_${sname}$_sort #:endfor +#:endfor + + pure module subroutine char_sort( array, reverse ) + character(len=*), intent(inout) :: array(0:) + logical, intent(in), optional :: reverse + logical :: reverse_ + reverse_ = .false. + if(present(reverse)) reverse_ = reverse + + if(reverse_)then + call char_decrease_sort(array) + else + call char_increase_sort(array) + endif + end subroutine char_sort - pure module subroutine char_sort( array ) + + +#:for sname, signt, signoppt in SIGN_NAME_TYPE + pure subroutine char_${sname}$_sort( array ) ! `char_sort( array )` sorts the input `ARRAY` of type `CHARACTER(*)` ! using a hybrid sort based on the `introsort` of David Musser. As with ! `introsort`, `char_sort( array )` is an unstable hybrid comparison @@ -296,12 +337,12 @@ contains u = array( 0 ) v = array( size(array, kind=int_size)/2-1 ) w = array( size(array, kind=int_size)-1 ) - if ( (u > v) .neqv. (u > w) ) then + if ( (u ${signt}$ v) .neqv. (u ${signt}$ w) ) then x = u y = array(0) array(0) = array( size( array, kind=int_size ) - 1 ) array( size( array, kind=int_size ) - 1 ) = y - else if ( (v < u) .neqv. (v < w) ) then + else if ( (v ${signoppt}$ u) .neqv. (v ${signoppt}$ w) ) then x = v y = array(size( array, kind=int_size )/2-1) array( size( array, kind=int_size )/2-1 ) = & @@ -313,7 +354,7 @@ contains ! Partition the array. i = -1_int_size do j = 0_int_size, size(array, kind=int_size)-2 - if ( array(j) <= x ) then + if ( array(j) ${signoppt}$= x ) then i = i + 1 y = array(i) array(i) = array(j) @@ -338,7 +379,7 @@ contains key = array(j) i = j - 1 do while( i >= 0 ) - if ( array(i) <= key ) exit + if ( array(i) ${signoppt}$= key ) exit array(i+1) = array(i) i = i - 1 end do @@ -382,10 +423,10 @@ contains l = 2_int_size * i + 1_int_size r = l + 1_int_size if ( l < heap_size ) then - if ( array(l) > array(largest) ) largest = l + if ( array(l) ${signt}$ array(largest) ) largest = l end if if ( r < heap_size ) then - if ( array(r) > array(largest) ) largest = r + if ( array(r) ${signt}$ array(largest) ) largest = r end if if ( largest /= i ) then y = array(i) @@ -396,6 +437,7 @@ contains end subroutine max_heapify - end subroutine char_sort + end subroutine char_${sname}$_sort +#:endfor end submodule stdlib_sorting_sort diff --git a/src/tests/sorting/test_sorting.f90 b/src/tests/sorting/test_sorting.f90 index 4025aef42..3ce0aae52 100644 --- a/src/tests/sorting/test_sorting.f90 +++ b/src/tests/sorting/test_sorting.f90 @@ -4,8 +4,9 @@ program test_sorting compiler_version use stdlib_kinds, only: int32, int64, dp, sp use stdlib_sorting - use stdlib_string_type, only: string_type, assignment(=), operator(>), & + use stdlib_string_type, only: string_type, assignment(=), operator(>), operator(<), & write(formatted) + use stdlib_error, only: check implicit none @@ -48,6 +49,7 @@ program test_sorting integer :: lun character(len=4) :: char_temp type(string_type) :: string_temp + logical :: ltest, ldummy ! Create the test arrays identical(:) = 10 @@ -149,50 +151,72 @@ program test_sorting '--|-----------|")' ) ! test the sorting routines on the test arrays - call test_int_ord_sorts( ) + ltest = .true. - call test_char_ord_sorts( ) + call test_int_ord_sorts( ldummy ); ltest = (ltest .and. ldummy) - call test_string_ord_sorts( ) + call test_char_ord_sorts(ldummy ); ltest = (ltest .and. ldummy) - call test_int_sorts( ) + call test_string_ord_sorts( ldummy ); ltest = (ltest .and. ldummy) - call test_char_sorts( ) + call test_int_sorts( ldummy ); ltest = (ltest .and. ldummy) - call test_string_sorts( ) + call test_char_sorts( ldummy ); ltest = (ltest .and. ldummy) - call test_int_sort_indexes( ) + call test_string_sorts( ldummy ); ltest = (ltest .and. ldummy) - call test_char_sort_indexes( ) + call test_int_sort_indexes( ldummy ); ltest = (ltest .and. ldummy) - call test_string_sort_indexes( ) + call test_char_sort_indexes( ldummy ); ltest = (ltest .and. ldummy) + + call test_string_sort_indexes( ldummy ); ltest = (ltest .and. ldummy) -contains - subroutine test_int_ord_sorts( ) + call check(ltest) + +contains - call test_int_ord_sort( blocks, "Blocks" ) - call test_int_ord_sort( decrease, "Decreasing" ) - call test_int_ord_sort( identical, "Identical" ) - call test_int_ord_sort( increase, "Increasing" ) - call test_int_ord_sort( rand1, "Random dense" ) - call test_int_ord_sort( rand2, "Random order" ) - call test_int_ord_sort( rand0, "Random sparse" ) - call test_int_ord_sort( rand3, "Random 3" ) - call test_int_ord_sort( rand10, "Random 10" ) + subroutine test_int_ord_sorts( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. + + call test_int_ord_sort( blocks, "Blocks", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( decrease, "Decreasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( identical, "Identical", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( increase, "Increasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( rand1, "Random dense", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( rand2, "Random order", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( rand0, "Random sparse", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( rand3, "Random 3", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_ord_sort( rand10, "Random 10", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_int_ord_sorts - subroutine test_int_ord_sort( a, a_name ) + subroutine test_int_ord_sort( a, a_name, ltest ) integer(int32), intent(in) :: a(:) - character(*), intent(in) :: a_name + character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat dummy = a @@ -204,6 +228,7 @@ subroutine test_int_ord_sort( a, a_name ) tdiff = tdiff/repeat call verify_sort( dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "ORD_SORT did not sort " // a_name // "." write(*,*) 'i = ', i @@ -213,25 +238,57 @@ subroutine test_int_ord_sort( a, a_name ) 'a12, " |", F10.5, " |" )' ) & test_size, a_name, "Ord_Sort", tdiff/rate + !reverse + dummy = a + call ord_sort( dummy, work, reverse = .true.) + call verify_reverse_sort( dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse + work ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a12, 2i7)') 'dummy(i-1:i) = ', dummy(i-1:i) + end if + + dummy = a + call ord_sort( dummy, reverse = .true.) + call verify_reverse_sort( dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a12, 2i7)') 'dummy(i-1:i) = ', dummy(i-1:i) + end if + end subroutine test_int_ord_sort - subroutine test_char_ord_sorts( ) + subroutine test_char_ord_sorts( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy - call test_char_ord_sort( char_decrease, "Char. Decrease" ) - call test_char_ord_sort( char_increase, "Char. Increase" ) - call test_char_ord_sort( char_rand, "Char. Random" ) + ltest = .true. + + call test_char_ord_sort( char_decrease, "Char. Decrease", ldummy ) + ltest = (ltest .and. ldummy) + call test_char_ord_sort( char_increase, "Char. Increase", ldummy ) + ltest = (ltest .and. ldummy) + call test_char_ord_sort( char_rand, "Char. Random", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_char_ord_sorts - subroutine test_char_ord_sort( a, a_name ) + subroutine test_char_ord_sort( a, a_name, ltest ) character(len=4), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat char_dummy = a @@ -243,34 +300,71 @@ subroutine test_char_ord_sort( a, a_name ) tdiff = tdiff/repeat call verify_char_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "ORD_SORT did not sort " // a_name // "." write(*,*) 'i = ', i - write(*,'(a17, 2(1x,a4))') 'char_dummy(i-1:i) = ', char_dummy(i-1:i) + write(*,'(a, 2(1x,a4))') 'char_dummy(i-1:i) = ', char_dummy(i-1:i) end if write( lun, '("| Character |", 1x, i7, 2x, "|", 1x, a15, " |", ' // & 'a12, " |", F10.5, " |" )' ) & char_size, a_name, "Ord_Sort", tdiff/rate + !reverse + char_dummy = a + call ord_sort( char_dummy, char_work, reverse = .true. ) + + call verify_char_reverse_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse + work ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a, 2(1x,a4))') 'char_dummy(i-1:i) = ', char_dummy(i-1:i) + end if + + char_dummy = a + call ord_sort( char_dummy, reverse = .true. ) + + call verify_char_reverse_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse + work ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a, 2(1x,a4))') 'char_dummy(i-1:i) = ', char_dummy(i-1:i) + end if + end subroutine test_char_ord_sort - subroutine test_string_ord_sorts( ) + subroutine test_string_ord_sorts( ltest ) + logical, intent(out) :: ltest + + logical:: ldummy + + ltest = .true. + + call test_string_ord_sort( string_decrease, "String Decrease", ldummy ) + ltest = (ltest .and. ldummy) + + call test_string_ord_sort( string_increase, "String Increase", ldummy ) + ltest = (ltest .and. ldummy) - call test_string_ord_sort( string_decrease, "String Decrease" ) - call test_string_ord_sort( string_increase, "String Increase" ) - call test_string_ord_sort( string_rand, "String Random" ) + call test_string_ord_sort( string_rand, "String Random" , ldummy) + ltest = (ltest .and. ldummy) end subroutine test_string_ord_sorts - subroutine test_string_ord_sort( a, a_name ) + subroutine test_string_ord_sort( a, a_name, ltest ) type(string_type), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat string_dummy = a @@ -282,42 +376,85 @@ subroutine test_string_ord_sort( a, a_name ) tdiff = tdiff/repeat call verify_string_sort( string_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "ORD_SORT did not sort " // a_name // "." write(*,*) 'i = ', i - write(*,'(a17, 2(1x,a4))') 'string_dummy(i-1:i) = ', & + write(*,'(a, 2(1x,a))') 'string_dummy(i-1:i) = ', & string_dummy(i-1:i) end if write( lun, '("| String_type |", 1x, i7, 2x, "|", 1x, a15, " |", ' // & 'a12, " |", F10.5, " |" )' ) & string_size, a_name, "Ord_Sort", tdiff/rate - end subroutine test_string_ord_sort + !reverse + string_dummy = a + call ord_sort( string_dummy, string_work, reverse = .true. ) + call verify_string_reverse_sort( string_dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse + work ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a, 2(1x,a))') 'string_dummy(i-1:i) = ', & + string_dummy(i-1:i) + end if - subroutine test_int_sorts( ) + string_dummy = a + call ord_sort( string_dummy, reverse = .true. ) + + call verify_string_reverse_sort( string_dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse ORD_SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a, 2(1x,a))') 'string_dummy(i-1:i) = ', & + string_dummy(i-1:i) + end if + + end subroutine test_string_ord_sort - call test_int_sort( blocks, "Blocks" ) - call test_int_sort( decrease, "Decreasing" ) - call test_int_sort( identical, "Identical" ) - call test_int_sort( increase, "Increasing" ) - call test_int_sort( rand1, "Random dense" ) - call test_int_sort( rand2, "Random order" ) - call test_int_sort( rand0, "Random sparse" ) - call test_int_sort( rand3, "Random 3" ) - call test_int_sort( rand10, "Random 10" ) + + subroutine test_int_sorts( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. + + call test_int_sort( blocks, "Blocks", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( decrease, "Decreasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( identical, "Identical", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( increase, "Increasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( rand1, "Random dense", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( rand2, "Random order", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( rand0, "Random sparse", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( rand3, "Random 3", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort( rand10, "Random 10", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_int_sorts - subroutine test_int_sort( a, a_name ) + subroutine test_int_sort( a, a_name, ltest ) integer(int32), intent(in) :: a(:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat dummy = a @@ -328,7 +465,9 @@ subroutine test_int_sort( a, a_name ) end do tdiff = tdiff/repeat + call verify_sort( dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT did not sort " // a_name // "." write(*,*) 'i = ', i @@ -338,25 +477,50 @@ subroutine test_int_sort( a, a_name ) 'a12, " |", F10.5, " |" )' ) & test_size, a_name, "Sort", tdiff/rate + + ! reverse + dummy = a + call sort( dummy, .true.) + call verify_reverse_sort(dummy, valid, i) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a12, 2i7)') 'dummy(i-1:i) = ', dummy(i-1:i) + end if + end subroutine test_int_sort - subroutine test_char_sorts( ) + subroutine test_char_sorts( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy - call test_char_sort( char_decrease, "Char. Decrease" ) - call test_char_sort( char_increase, "Char. Increase" ) - call test_char_sort( char_rand, "Char. Random" ) + ltest = .true. + + call test_char_sort( char_decrease, "Char. Decrease", ldummy ) + ltest = (ltest .and. ldummy) + + call test_char_sort( char_increase, "Char. Increase", ldummy ) + ltest = (ltest .and. ldummy) + + call test_char_sort( char_rand, "Char. Random", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_char_sorts - subroutine test_char_sort( a, a_name ) + subroutine test_char_sort( a, a_name, ltest ) character(len=4), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat char_dummy = a @@ -368,6 +532,7 @@ subroutine test_char_sort( a, a_name ) tdiff = tdiff/repeat call verify_char_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT did not sort " // a_name // "." write(*,*) 'i = ', i @@ -377,25 +542,47 @@ subroutine test_char_sort( a, a_name ) 'a12, " |", F10.5, " |" )' ) & char_size, a_name, "Sort", tdiff/rate + !reverse + char_dummy = a + call sort( char_dummy, .true.) + call verify_char_reverse_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a17, 2(1x,a4))') 'char_dummy(i-1:i) = ', char_dummy(i-1:i) + end if + end subroutine test_char_sort - subroutine test_string_sorts( ) + subroutine test_string_sorts( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. - call test_string_sort( string_decrease, "String Decrease" ) - call test_string_sort( string_increase, "String Increase" ) - call test_string_sort( string_rand, "String Random" ) + call test_string_sort( string_decrease, "String Decrease", ldummy ) + ltest = (ltest .and. ldummy) + call test_string_sort( string_increase, "String Increase", ldummy ) + ltest = (ltest .and. ldummy) + call test_string_sort( string_rand, "String Random", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_string_sorts - subroutine test_string_sort( a, a_name ) + subroutine test_string_sort( a, a_name, ltest ) type(string_type), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat string_dummy = a @@ -407,6 +594,7 @@ subroutine test_string_sort( a, a_name ) tdiff = tdiff/repeat call verify_string_sort( string_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT did not sort " // a_name // "." write(*,*) 'i = ', i @@ -417,31 +605,61 @@ subroutine test_string_sort( a, a_name ) 'a12, " |", F10.5, " |" )' ) & string_size, a_name, "Sort", tdiff/rate - end subroutine test_string_sort + ! reverse + string_dummy = a + call sort( string_dummy, .true.) + call verify_string_reverse_sort(string_dummy, valid, i) + ltest = (ltest .and. valid) + if ( .not. valid ) then + write( *, * ) "reverse SORT did not sort " // a_name // "." + write(*,*) 'i = ', i + write(*,'(a17, 2(1x,a4))') 'string_dummy(i-1:i) = ', & + string_dummy(i-1:i) + end if - subroutine test_int_sort_indexes( ) - call test_int_sort_index( blocks, "Blocks" ) - call test_int_sort_index( decrease, "Decreasing" ) - call test_int_sort_index( identical, "Identical" ) - call test_int_sort_index( increase, "Increasing" ) - call test_int_sort_index( rand1, "Random dense" ) - call test_int_sort_index( rand2, "Random order" ) - call test_int_sort_index( rand0, "Random sparse" ) - call test_int_sort_index( rand3, "Random 3" ) - call test_int_sort_index( rand10, "Random 10" ) + end subroutine test_string_sort + + subroutine test_int_sort_indexes( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. + + call test_int_sort_index( blocks, "Blocks", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( decrease, "Decreasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( identical, "Identical", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( increase, "Increasing", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( rand1, "Random dense", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( rand2, "Random order", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( rand0, "Random sparse", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( rand3, "Random 3", ldummy ) + ltest = (ltest .and. ldummy) + call test_int_sort_index( rand10, "Random 10", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_int_sort_indexes - subroutine test_int_sort_index( a, a_name ) + subroutine test_int_sort_index( a, a_name, ltest ) integer(int32), intent(inout) :: a(:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat dummy = a @@ -454,6 +672,7 @@ subroutine test_int_sort_index( a, a_name ) dummy = a(index) call verify_sort( dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT_INDEX did not sort " // a_name // "." write(*,*) 'i = ', i @@ -467,6 +686,7 @@ subroutine test_int_sort_index( a, a_name ) call sort_index( dummy, index, work, iwork, reverse=.true. ) dummy = a(index) call verify_reverse_sort( dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT_INDEX did not reverse sort " // & a_name // "." @@ -476,23 +696,34 @@ subroutine test_int_sort_index( a, a_name ) end subroutine test_int_sort_index - subroutine test_char_sort_indexes( ) + subroutine test_char_sort_indexes( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. - call test_char_sort_index( char_decrease, "Char. Decrease" ) - call test_char_sort_index( char_increase, "Char. Increase" ) - call test_char_sort_index( char_rand, "Char. Random" ) + call test_char_sort_index( char_decrease, "Char. Decrease", ldummy ) + ltest = (ltest .and. ldummy) + call test_char_sort_index( char_increase, "Char. Increase", ldummy ) + ltest = (ltest .and. ldummy) + call test_char_sort_index( char_rand, "Char. Random", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_char_sort_indexes - subroutine test_char_sort_index( a, a_name ) + subroutine test_char_sort_index( a, a_name, ltest ) character(len=4), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat char_dummy = a @@ -504,6 +735,7 @@ subroutine test_char_sort_index( a, a_name ) tdiff = tdiff/repeat call verify_char_sort( char_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT_INDEX did not sort " // a_name // "." write(*,*) 'i = ', i @@ -515,23 +747,34 @@ subroutine test_char_sort_index( a, a_name ) end subroutine test_char_sort_index - subroutine test_string_sort_indexes( ) + subroutine test_string_sort_indexes( ltest ) + logical, intent(out) :: ltest + + logical :: ldummy + + ltest = .true. - call test_string_sort_index( string_decrease, "String Decrease" ) - call test_string_sort_index( string_increase, "String Increase" ) - call test_string_sort_index( string_rand, "String Random" ) + call test_string_sort_index( string_decrease, "String Decrease", ldummy ) + ltest = (ltest .and. ldummy) + call test_string_sort_index( string_increase, "String Increase", ldummy ) + ltest = (ltest .and. ldummy) + call test_string_sort_index( string_rand, "String Random", ldummy ) + ltest = (ltest .and. ldummy) end subroutine test_string_sort_indexes - subroutine test_string_sort_index( a, a_name ) + subroutine test_string_sort_index( a, a_name, ltest ) type(string_type), intent(in) :: a(0:) character(*), intent(in) :: a_name + logical, intent(out) :: ltest integer(int64) :: t0, t1, tdiff real(dp) :: rate integer(int64) :: i logical :: valid + ltest = .true. + tdiff = 0 do i = 1, repeat string_dummy = a @@ -543,6 +786,7 @@ subroutine test_string_sort_index( a, a_name ) tdiff = tdiff/repeat call verify_string_sort( string_dummy, valid, i ) + ltest = (ltest .and. valid) if ( .not. valid ) then write( *, * ) "SORT_INDEX did not sort " // a_name // "." write(*,*) 'i = ', i @@ -573,6 +817,7 @@ subroutine verify_sort( a, valid, i ) end subroutine verify_sort + subroutine verify_string_sort( a, valid, i ) type(string_type), intent(in) :: a(0:) logical, intent(out) :: valid @@ -605,6 +850,21 @@ subroutine verify_char_sort( a, valid, i ) end subroutine verify_char_sort + subroutine verify_char_reverse_sort( a, valid, i ) + character(len=4), intent(in) :: a(0:) + logical, intent(out) :: valid + integer(int64), intent(out) :: i + + integer(int64) :: n + + n = size( a, kind=int64 ) + valid = .false. + do i=1, n-1 + if ( a(i-1) < a(i) ) return + end do + valid = .true. + + end subroutine verify_char_reverse_sort subroutine verify_reverse_sort( a, valid, i ) integer(int32), intent(in) :: a(0:) @@ -622,4 +882,20 @@ subroutine verify_reverse_sort( a, valid, i ) end subroutine verify_reverse_sort + subroutine verify_string_reverse_sort( a, valid, i ) + type(string_type), intent(in) :: a(0:) + logical, intent(out) :: valid + integer(int64), intent(out) :: i + + integer(int64) :: n + + n = size( a, kind=int64 ) + valid = .false. + do i=1, n-1 + if ( a(i-1) < a(i) ) return + end do + valid = .true. + + end subroutine verify_string_reverse_sort + end program test_sorting