Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sorting arrays of bitsets #723

Merged
merged 28 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
07c0e10
added BITSET_KINDS and BITSET_TYPES
degawa Jun 25, 2023
04104b1
added `use` statement for stdlib_bitsets
degawa Jun 25, 2023
b482534
added BITSET_TYPES_ALT_NAME
degawa Jun 25, 2023
799ce0d
appended ALT_NAME of bitsets to IRSC ALT_NAME
degawa Jun 25, 2023
bd92e37
added whitespace after comma
degawa Jun 25, 2023
4d3057a
added tests for bitset_large and bitset_64
degawa Jun 25, 2023
a99f19d
aligned the frame of the table of results
degawa Jun 25, 2023
6154e2b
fixed incorrect right-hand side value
degawa Jun 25, 2023
423a8b4
added an example for sorting array of bitset_large
degawa Jun 25, 2023
0ee5fb1
updated api-docs
degawa Jun 25, 2023
a9254e1
fixed enclosure symbol mismatches
degawa Jun 25, 2023
e1b520c
added a newline to enable the unordered list
degawa Jun 25, 2023
185c695
replaced tab with spaces
degawa Jun 25, 2023
1b0d50a
aligned indent width
degawa Jun 25, 2023
47e9c19
fixed missing stdlib_kinds module
degawa Jun 25, 2023
e27e9af
reduced the size of bitset arrays
degawa Jun 25, 2023
e7e6e41
changed `intent` from `out` to `inout`
degawa Jun 26, 2023
5f1195f
changed component assignment operation
degawa Jun 26, 2023
4100e61
specified the entity to be used in the example
degawa Jul 2, 2023
bdd6dcc
specified the entity to be used in the example
degawa Jul 2, 2023
61029ee
deleted tailing "l"
degawa Jul 2, 2023
7d6d979
removed `block` structures
degawa Jul 2, 2023
de2dbbb
add explicity in test_stdlib_bitset_large
jvdp1 Jul 8, 2023
96763e1
add test following issue #726
jvdp1 Jul 8, 2023
1905c80
Merge branch 'pullreq_727' into support-sorting-bitsets
degawa Jul 15, 2023
efbc0cc
removed `assign_large`
degawa Jul 15, 2023
916d83d
Merge branch 'master' into support-sorting-bitsets
jvdp1 Aug 8, 2023
e661cd2
Removed additional empty lines introduced by resolving conflicts
jvdp1 Aug 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 52 additions & 48 deletions doc/specs/stdlib_sorting.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ to the value of `int64` from the `stdlib_kinds` module.
The `stdlib_sorting` module provides three different overloaded
subroutines intended to sort three different kinds of arrays of
data:

* `ORD_SORT` is intended to sort simple arrays of intrinsic data
that have significant sections that were partially ordered before
the sort;
Expand Down Expand Up @@ -235,8 +236,9 @@ Generic subroutine.

`array` : shall be a rank one array of any of the types:
`integer(int8)`, `integer(int16)`, `integer(int32)`, `integer(int64)`,
`real(sp)`, `real(dp)`, `real(qp)`, `character(*)`, or
`type(string_type)`. It is an `intent(inout)` argument. On input it is
`real(sp)`, `real(dp)`, `real(qp)`, `character(*)`, `type(string_type)`,
`type(bitset_64)`, or `type(bitset_large)`.
It is an `intent(inout)` argument. On input it is
the array to be sorted. If both the type of `array` is real and at
least one of the elements is a `NaN`, then the ordering of the result
is undefined. Otherwise on return its elements will be sorted in order
Expand Down Expand Up @@ -301,8 +303,9 @@ Pure generic subroutine.

`array` : shall be a rank one array of any of the types:
`integer(int8)`, `integer(int16)`, `integer(int32)`, `integer(int64)`,
`real(sp)`, `real(dp)`, `real(qp)`. `character(*)`, or
`type(string_type)`. It is an `intent(inout)` argument. On return its
`real(sp)`, `real(dp)`, `real(qp)`. `character(*)`, `type(string_type)`,
`type(bitset_64)`, or `type(bitset_large)`.
It is an `intent(inout)` argument. On return its
input elements will be sorted in order of non-decreasing value.


Expand Down Expand Up @@ -405,8 +408,9 @@ Generic subroutine.

`array`: shall be a rank one array of any of the types:
`integer(int8)`, `integer(int16)`, `integer(int32)`, `integer(int64)`,
`real(sp)`, `real(dp)`, `real(qp)`, `character(*)`, or
`type(string_type)`. It is an `intent(inout)` argument. On input it
`real(sp)`, `real(dp)`, `real(qp)`, `character(*)`, `type(string_type)`,
`type(bitset_64)`, or `type(bitset_large)`.
It is an `intent(inout)` argument. On input it
will be an array whose sorting indices are to be determined. On return
it will be the sorted array.

Expand Down Expand Up @@ -460,60 +464,60 @@ Sorting a related rank one array:
! Sort `a`, and also sort `b` to be reorderd the same way as `a`
integer, intent(inout) :: a(:)
integer(int32), intent(inout) :: b(:) ! The same size as a
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
! Find the indices to sort a
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
! Find the indices to sort a
call sort_index(a, index(1:size(a)),&
work(1:size(a)/2), iwork(1:size(a)/2))
! Sort b based on the sorting of a
b(:) = b( index(1:size(a)) )
end subroutine sort_related_data
! Sort b based on the sorting of a
b(:) = b( index(1:size(a)) )
end subroutine sort_related_data
```

Sorting a rank 2 array based on the data in a column

```Fortran
subroutine sort_related_data( array, column, work, index, iwork )
! Reorder rows of `array` such that `array(:, column)` is sorted
integer, intent(inout) :: array(:,:)
integer(int32), intent(in) :: column
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
integer, allocatable :: dummy(:)
integer :: i
allocate(dummy(size(array, dim=1)))
! Extract a column of `array`
dummy(:) = array(:, column)
! Find the indices to sort the column
call sort_index(dummy, index(1:size(dummy)),&
work(1:size(dummy)/2), iwork(1:size(dummy)/2))
! Sort a based on the sorting of its column
do i=1, size(array, dim=2)
array(:, i) = array(index(1:size(array, dim=1)), i)
end do
end subroutine sort_related_data
subroutine sort_related_data( array, column, work, index, iwork )
! Reorder rows of `array` such that `array(:, column)` is sorted
integer, intent(inout) :: array(:,:)
integer(int32), intent(in) :: column
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
integer, allocatable :: dummy(:)
integer :: i
allocate(dummy(size(array, dim=1)))
! Extract a column of `array`
dummy(:) = array(:, column)
! Find the indices to sort the column
call sort_index(dummy, index(1:size(dummy)),&
work(1:size(dummy)/2), iwork(1:size(dummy)/2))
! Sort a based on the sorting of its column
do i=1, size(array, dim=2)
array(:, i) = array(index(1:size(array, dim=1)), i)
end do
end subroutine sort_related_data
```

Sorting an array of a derived type based on the data in one component

```fortran
subroutine sort_a_data( a_data, a, work, index, iwork )
! Sort `a_data` in terms or its component `a`
type(a_type), intent(inout) :: a_data(:)
integer(int32), intent(inout) :: a(:)
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
! Extract a component of `a_data`
a(1:size(a_data)) = a_data(:) % a
! Find the indices to sort the component
call sort_index(a(1:size(a_data)), index(1:size(a_data)),&
work(1:size(a_data)/2), iwork(1:size(a_data)/2))
! Sort a_data based on the sorting of that component
a_data(:) = a_data( index(1:size(a_data)) )
end subroutine sort_a_data
subroutine sort_a_data( a_data, a, work, index, iwork )
! Sort `a_data` in terms or its component `a`
type(a_type), intent(inout) :: a_data(:)
integer(int32), intent(inout) :: a(:)
integer(int32), intent(out) :: work(:)
integer(int_size), intent(out) :: index(:)
integer(int_size), intent(out) :: iwork(:)
! Extract a component of `a_data`
a(1:size(a_data)) = a_data(:) % a
! Find the indices to sort the component
call sort_index(a(1:size(a_data)), index(1:size(a_data)),&
work(1:size(a_data)/2), iwork(1:size(a_data)/2))
! Sort a_data based on the sorting of that component
a_data(:) = a_data( index(1:size(a_data)) )
end subroutine sort_a_data
```


Expand Down
3 changes: 2 additions & 1 deletion example/sorting/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ADD_EXAMPLE(ord_sort)
ADD_EXAMPLE(sort)
ADD_EXAMPLE(radix_sort)
ADD_EXAMPLE(radix_sort)
ADD_EXAMPLE(sort_bitset)
45 changes: 45 additions & 0 deletions example/sorting/example_sort_bitset.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
program example_sort_bitset
use stdlib_kinds, only: int32
use stdlib_sorting, only: sort
use stdlib_bitsets, only: bitset_large
implicit none
type(bitset_large), allocatable :: array(:)
integer(int32) :: i

array = [bitset_l("0101"), & ! 5
bitset_l("0100"), & ! 4
bitset_l("0011"), & ! 3
bitset_l("0001"), & ! 1
bitset_l("1010"), & ! 10
bitset_l("0100"), & ! 4
bitset_l("1001")] ! 9

call sort(array)

do i = 1, size(array)
print *, to_string(array(i))
! 0001
! 0011
! 0100
! 0100
! 0101
! 1001
! 1010
end do

deallocate(array)
contains
function bitset_l(str) result(new_bitsetl)
character(*), intent(in) :: str
type(bitset_large) :: new_bitsetl

call new_bitsetl%from_string(str)
end function bitset_l

function to_string(bitset) result(str)
type(bitset_large), intent(in) :: bitset
character(:), allocatable :: str

call bitset%to_string(str)
end function to_string
end program example_sort_bitset
5 changes: 5 additions & 0 deletions src/common.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
#! Collected (kind, type) tuples for string derived types
#:set STRING_KINDS_TYPES = list(zip(STRING_KINDS, STRING_TYPES))

#! Derived type bitsets
#:set BITSET_KINDS = ["bitset_64", "bitset_large"]

#! Bitset types to be considered during templating
#:set BITSET_TYPES = ["type({})".format(k) for k in BITSET_KINDS]

#! Whether Fortran 90 compatible code should be generated
#:set VERSION90 = defined('VERSION90')
Expand Down
28 changes: 18 additions & 10 deletions src/stdlib_sorting.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#:set REAL_TYPES_ALT_NAME = list(zip(REAL_TYPES, REAL_TYPES, REAL_KINDS))
#:set STRING_TYPES_ALT_NAME = list(zip(STRING_TYPES, STRING_TYPES, STRING_KINDS))
#:set CHAR_TYPES_ALT_NAME = list(zip(["character(len=*)"], ["character(len=len(array))"], ["char"]))
#:set BITSET_TYPES_ALT_NAME = list(zip(BITSET_TYPES, BITSET_TYPES, BITSET_KINDS))

#! For better code reuse in fypp, make lists that contain the input types,
#! with each having output types and a separate name prefix for subroutines
#! This approach allows us to have the same code for all input types.
#:set IRSC_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME
#:set IRSCB_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME &
& + BITSET_TYPES_ALT_NAME

!! Licensing:
!!
Expand Down Expand Up @@ -129,6 +131,9 @@ module stdlib_sorting
use stdlib_string_type, only: string_type, assignment(=), operator(>), &
operator(>=), operator(<), operator(<=)

use stdlib_bitsets, only: bitset_64, bitset_large, &
assignment(=), operator(>), operator(>=), operator(<), operator(<=)

implicit none
private

Expand Down Expand Up @@ -165,7 +170,8 @@ module stdlib_sorting
!! * array: the rank 1 array to be sorted. It is an `intent(inout)`
!! argument of any of the types `integer(int8)`, `integer(int16)`,
!! `integer(int32)`, `integer(int64)`, `real(real32)`, `real(real64)`,
!! `real(real128)`, `character(*)`, `type(string_type)`. If both the
!! `real(real128)`, `character(*)`, `type(string_type)`,
!! `type(bitset_64)`, `type(bitset_large)`. If both the
!! type of `array` is real and at least one of the elements is a
!! `NaN`, then the ordering of the result is undefined. Otherwise it
!! is defined to be the original elements in non-decreasing order.
Expand Down Expand Up @@ -215,7 +221,8 @@ module stdlib_sorting
!! * array: the rank 1 array to be sorted. It is an `intent(inout)`
!! argument of any of the types `integer(int8)`, `integer(int16)`,
!! `integer(int32)`, `integer(int64)`, `real(real32)`, `real(real64)`,
!! `real(real128)`, `character(*)`, `type(string_type)`. If both the type
!! `real(real128)`, `character(*)`, `type(string_type)`,
!! `type(bitset_64)`, `type(bitset_large)`. If both the type
!! of `array` is real and at least one of the elements is a `NaN`, then
!! the ordering of the result is undefined. Otherwise it is defined to be the
!! original elements in non-decreasing order.
Expand Down Expand Up @@ -299,7 +306,8 @@ module stdlib_sorting
!! * array: the rank 1 array to be sorted. It is an `intent(inout)`
!! argument of any of the types `integer(int8)`, `integer(int16)`,
!! `integer(int32)`, `integer(int64)`, `real(real32)`, `real(real64)`,
!! `real(real128)`, `character(*)`, `type(string_type)`. If both the
!! `real(real128)`, `character(*)`, `type(string_type)`,
!! `type(bitset_64)`, `type(bitset_large)`. If both the
!! type of `array` is real and at least one of the elements is a `NaN`,
!! then the ordering of the `array` and `index` results is undefined.
!! Otherwise it is defined to be as specified by reverse.
Expand Down Expand Up @@ -410,12 +418,12 @@ module stdlib_sorting
!! sorted data, having O(N) performance on uniformly non-increasing or
!! non-decreasing data.

#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, name1 in IRSCB_TYPES_ALT_NAME
module subroutine ${name1}$_ord_sort( array, work, reverse )
!! Version: experimental
!!
!! `${name1}$_ord_sort( array )` sorts the input `ARRAY` of type `${t1}$`
!! using a hybrid sort based on the `'Rust" sort` algorithm found in `slice.rs`
!! using a hybrid sort based on the `"Rust" sort` algorithm found in `slice.rs`
${t1}$, intent(inout) :: array(0:)
${t2}$, intent(out), optional :: work(0:)
logical, intent(in), optional :: reverse
Expand Down Expand Up @@ -476,7 +484,7 @@ module stdlib_sorting
!! on the `introsort` of David Musser.
!! ([Specification](../page/specs/stdlib_sorting.html#sort-sorts-an-input-array))

#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, name1 in IRSCB_TYPES_ALT_NAME
pure module subroutine ${name1}$_sort( array, reverse )
!! Version: experimental
!!
Expand Down Expand Up @@ -507,15 +515,15 @@ module stdlib_sorting
!! non-decreasing sort, but if the optional argument `REVERSE` is present
!! with a value of `.TRUE.` the indices correspond to a non-increasing sort.

#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, name1 in IRSCB_TYPES_ALT_NAME
module subroutine ${name1}$_sort_index( array, index, work, iwork, &
reverse )
!! Version: experimental
!!
!! `${name1}$_sort_index( array, index[, work, iwork, reverse] )` sorts
!! an input `ARRAY` of type `${t1}$`
!! using a hybrid sort based on the `'Rust" sort` algorithm found in `slice.rs`
!! and returns the sorted `ARRAY` and an array `INDEX of indices in the
!! using a hybrid sort based on the `"Rust" sort` algorithm found in `slice.rs`
!! and returns the sorted `ARRAY` and an array `INDEX` of indices in the
!! order that would sort the input `ARRAY` in the desired direction.
${t1}$, intent(inout) :: array(0:)
integer(int_size), intent(out) :: index(0:)
Expand Down
8 changes: 5 additions & 3 deletions src/stdlib_sorting_ord_sort.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
#:set REAL_TYPES_ALT_NAME = list(zip(REAL_TYPES, REAL_TYPES, REAL_TYPES, REAL_KINDS))
#:set STRING_TYPES_ALT_NAME = list(zip(STRING_TYPES, STRING_TYPES, STRING_TYPES, STRING_KINDS))
#:set CHAR_TYPES_ALT_NAME = list(zip(["character(len=*)"], ["character(len=:)"], ["character(len=len(array))"], ["char"]))
#:set BITSET_TYPES_ALT_NAME = list(zip(BITSET_TYPES, BITSET_TYPES, BITSET_TYPES, BITSET_KINDS))

#! For better code reuse in fypp, make lists that contain the input types,
#! with each having output types and a separate name prefix for subroutines
#! This approach allows us to have the same code for all input types.
#:set IRSC_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME
#:set IRSCB_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME &
& + BITSET_TYPES_ALT_NAME

#:set SIGN_NAME = ["increase", "decrease"]
#:set SIGN_TYPE = [">", "<"]
Expand Down Expand Up @@ -69,7 +71,7 @@ submodule(stdlib_sorting) stdlib_sorting_ord_sort
contains
#:for t1, t2, t3, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, t3, name1 in IRSCB_TYPES_ALT_NAME
module subroutine ${name1}$_ord_sort( array, work, reverse )
${t1}$, intent(inout) :: array(0:)
${t3}$, intent(out), optional :: work(0:)
Expand All @@ -85,7 +87,7 @@ contains
#:endfor
#:for sname, signt, signoppt in SIGN_NAME_TYPE
#:for t1, t2, t3, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, t3, name1 in IRSCB_TYPES_ALT_NAME
subroutine ${name1}$_${sname}$_ord_sort( array, work )
! A translation to Fortran 2008, of the `"Rust" sort` algorithm found in
Expand Down
8 changes: 5 additions & 3 deletions src/stdlib_sorting_sort.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
#:set REAL_TYPES_ALT_NAME = list(zip(REAL_TYPES, REAL_TYPES, REAL_KINDS))
#:set STRING_TYPES_ALT_NAME = list(zip(STRING_TYPES, STRING_TYPES, STRING_KINDS))
#:set CHAR_TYPES_ALT_NAME = list(zip(["character(len=*)"], ["character(len=len(array))"], ["char"]))
#:set BITSET_TYPES_ALT_NAME = list(zip(BITSET_TYPES, BITSET_TYPES, BITSET_KINDS))

#! For better code reuse in fypp, make lists that contain the input types,
#! with each having output types and a separate name prefix for subroutines
#! This approach allows us to have the same code for all input types.
#:set IRSC_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME
#:set IRSCB_TYPES_ALT_NAME = INT_TYPES_ALT_NAME + REAL_TYPES_ALT_NAME + STRING_TYPES_ALT_NAME + CHAR_TYPES_ALT_NAME &
& + BITSET_TYPES_ALT_NAME

#:set SIGN_NAME = ["increase", "decrease"]
#:set SIGN_TYPE = [">", "<"]
Expand Down Expand Up @@ -73,7 +75,7 @@ submodule(stdlib_sorting) stdlib_sorting_sort
contains
#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, name1 in IRSCB_TYPES_ALT_NAME
pure module subroutine ${name1}$_sort( array, reverse )
${t1}$, intent(inout) :: array(0:)
logical, intent(in), optional :: reverse
Expand All @@ -87,7 +89,7 @@ contains
#:endfor
#:for sname, signt, signoppt in SIGN_NAME_TYPE
#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
#:for t1, t2, name1 in IRSCB_TYPES_ALT_NAME
pure subroutine ${name1}$_${sname}$_sort( array )
! `${name1}$_${sname}$_sort( array )` sorts the input `ARRAY` of type `${t1}$`
Expand Down
Loading
Loading