Skip to content

Commit ae608ee

Browse files
committed
Implement trueloc/falseloc
1 parent bae6be5 commit ae608ee

File tree

11 files changed

+308
-0
lines changed

11 files changed

+308
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Features available from the latest git source
44

5+
- new module `stdlib_array`
6+
[#603](https://github.com/fortran-lang/stdlib/pull/603)
7+
- new procedures `trueloc`, `falseloc`
58
- new module `stdlib_distribution_uniform`
69
[#272](https://github.com/fortran-lang/stdlib/pull/272)
710
- new module `stdlib_selection`

doc/specs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This is and index/directory of the specifications (specs) for each new module/fe
1111

1212
## Experimental Features & Modules
1313

14+
- [array](./stdlib_array.html) - Procedures for index manipulation and array handling
1415
- [ascii](./stdlib_ascii.html) - Procedures for handling ASCII characters
1516
- [bitsets](./stdlib_bitsets.html) - Bitset data types and procedures
1617
- [error](./stdlib_error.html) - Catching and handling errors

doc/specs/stdlib_array.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: array
3+
---
4+
5+
# The `stdlib_array` module
6+
7+
[TOC]
8+
9+
## Introduction
10+
11+
Module for index manipulation and array handling tasks.
12+
13+
## Procedures and methods provided
14+
15+
16+
### `trueloc`
17+
18+
#### Status
19+
20+
Experimental
21+
22+
#### Description
23+
24+
Turn a logical mask into an index array by selecting all true values.
25+
26+
#### Syntax
27+
28+
`call [[trueloc(function)]] (array[, lbound])`
29+
30+
#### Arguments
31+
32+
`array`: List of default logical arrays. This argument is `intent(in)`.
33+
34+
`lbound`: Lower bound of the array to index. This argument is `optional` and `intent(in)`.
35+
36+
#### Examples
37+
38+
```fortran
39+
program demo
40+
use stdlib_array, only : trueloc
41+
implicit none
42+
real, allocatable :: array(:)
43+
allocate(array(500))
44+
call random_number(array)
45+
array(trueloc(array > 0.5)) = 0.0
46+
end program demo
47+
```
48+
49+
50+
### `falseloc`
51+
52+
#### Status
53+
54+
Experimental
55+
56+
#### Description
57+
58+
Turn a logical mask into an index array by selecting all false values.
59+
60+
#### Syntax
61+
62+
`call [[falseloc(function)]] (array[, lbound])`
63+
64+
#### Arguments
65+
66+
`array`: List of default logical arrays. This argument is `intent(in)`.
67+
68+
`lbound`: Lower bound of the array to index. This argument is `optional` and `intent(in)`.
69+
70+
#### Examples
71+
72+
```fortran
73+
program demo
74+
use stdlib_array, only : falseloc
75+
implicit none
76+
real, allocatable :: array(:)
77+
allocate(array(-200:200))
78+
call random_number(array)
79+
array(falseloc(array < 0.5), lbound(array)) = 0.0
80+
end program demo
81+
```

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ list(
7171
fypp_f90("${fyppFlags}" "${fppFiles}" outFiles)
7272

7373
set(SRC
74+
stdlib_array.f90
7475
stdlib_error.f90
7576
stdlib_logger.f90
7677
stdlib_system.F90

src/Makefile.manual

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ SRCFYPP = \
4646
stdlib_version.fypp
4747

4848
SRC = f18estop.f90 \
49+
stdlib_array.f90 \
4950
stdlib_error.f90 \
5051
stdlib_specialfunctions.f90 \
5152
stdlib_specialfunctions_legendre.f90 \

src/stdlib_array.f90

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
! SPDX-Identifier: MIT
2+
3+
!> Module for index manipulation and general array handling
4+
module stdlib_array
5+
implicit none
6+
private
7+
8+
public :: trueloc, falseloc
9+
10+
contains
11+
12+
!> Return the positions of the true elements in array
13+
pure function trueloc(array, lbound) result(loc)
14+
!> Mask of logicals
15+
logical, intent(in) :: array(:)
16+
!> Lower bound of array to index
17+
integer, intent(in), optional :: lbound
18+
!> Locations of true elements
19+
integer :: loc(count(array))
20+
21+
loc = logicalloc(array, .true., lbound)
22+
end function trueloc
23+
24+
!> Return the positions of the false elements in array
25+
pure function falseloc(array, lbound) result(loc)
26+
!> Mask of logicals
27+
logical, intent(in) :: array(:)
28+
!> Lower bound of array to index
29+
integer, intent(in), optional :: lbound
30+
!> Locations of false elements
31+
integer :: loc(count(.not.array))
32+
33+
loc = logicalloc(array, .false., lbound)
34+
end function falseloc
35+
36+
!> Return the positions of the truthy elements in array
37+
pure function logicalloc(array, truth, lbound) result(loc)
38+
!> Mask of logicals
39+
logical, intent(in) :: array(:)
40+
!> Truthy value
41+
logical, intent(in) :: truth
42+
!> Lower bound of array to index
43+
integer, intent(in), optional :: lbound
44+
!> Locations of truthy elements
45+
integer :: loc(count(array.eqv.truth))
46+
integer :: i, pos, offset
47+
48+
offset = 0
49+
if (present(lbound)) offset = lbound - 1
50+
51+
i = 0
52+
do pos = 1, size(array)
53+
if (array(pos).eqv.truth) then
54+
i = i + 1
55+
loc(i) = pos + offset
56+
end if
57+
end do
58+
end function logicalloc
59+
60+
end module stdlib_array

src/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ list(
1515
"-I${PROJECT_SOURCE_DIR}/src"
1616
)
1717

18+
add_subdirectory(array)
1819
add_subdirectory(ascii)
1920
add_subdirectory(bitsets)
2021
add_subdirectory(io)

src/tests/Makefile.manual

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ testdrive.F90:
1212
$(FETCH) https://github.com/fortran-lang/test-drive/raw/v0.4.0/src/testdrive.F90 > $@
1313

1414
all test clean::
15+
$(MAKE) -f Makefile.manual --directory=array $@
1516
$(MAKE) -f Makefile.manual --directory=ascii $@
1617
$(MAKE) -f Makefile.manual --directory=bitsets $@
1718
$(MAKE) -f Makefile.manual --directory=io $@

src/tests/array/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ADDTEST(logicalloc)

src/tests/array/Makefile.manual

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
PROGS_SRC = test_logicalloc.f90
2+
3+
4+
include ../Makefile.manual.test.mk

src/tests/array/test_logicalloc.f90

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
! SPDX-Identifier: MIT
2+
3+
module test_logicalloc
4+
use stdlib_array, only : trueloc, falseloc
5+
use stdlib_string_type, only : string_type, len
6+
use testdrive, only : new_unittest, unittest_type, error_type, check
7+
implicit none
8+
private
9+
10+
public :: collect_logicalloc
11+
12+
contains
13+
14+
!> Collect all exported unit tests
15+
subroutine collect_logicalloc(testsuite)
16+
!> Collection of tests
17+
type(unittest_type), allocatable, intent(out) :: testsuite(:)
18+
19+
testsuite = [ &
20+
new_unittest("trueloc-where", test_trueloc_where), &
21+
new_unittest("trueloc-merge", test_trueloc_merge), &
22+
new_unittest("falseloc-where", test_falseloc_where), &
23+
new_unittest("falseloc-merge", test_falseloc_merge) &
24+
]
25+
end subroutine collect_logicalloc
26+
27+
subroutine test_trueloc_where(error)
28+
!> Error handling
29+
type(error_type), allocatable, intent(out) :: error
30+
31+
integer :: ndim
32+
real, allocatable :: avec(:), bvec(:), cvec(:)
33+
34+
do ndim = 100, 12000, 100
35+
allocate(avec(ndim))
36+
37+
call random_number(avec)
38+
avec(:) = avec - 0.5
39+
40+
bvec = avec
41+
bvec(trueloc(bvec > 0)) = 0.0
42+
43+
cvec = avec
44+
where(cvec > 0) cvec = 0.0
45+
46+
call check(error, all(bvec == cvec))
47+
deallocate(avec, bvec, cvec)
48+
if (allocated(error)) exit
49+
end do
50+
end subroutine test_trueloc_where
51+
52+
subroutine test_trueloc_merge(error)
53+
!> Error handling
54+
type(error_type), allocatable, intent(out) :: error
55+
56+
integer :: ndim
57+
real, allocatable :: avec(:), bvec(:), cvec(:)
58+
59+
do ndim = 100, 12000, 100
60+
allocate(avec(ndim))
61+
62+
call random_number(avec)
63+
avec(:) = avec - 0.5
64+
65+
bvec = avec
66+
bvec(trueloc(bvec > 0)) = 0.0
67+
68+
cvec = avec
69+
cvec(:) = merge(0.0, cvec, cvec > 0)
70+
71+
call check(error, all(bvec == cvec))
72+
deallocate(avec, bvec, cvec)
73+
if (allocated(error)) exit
74+
end do
75+
end subroutine test_trueloc_merge
76+
77+
subroutine test_falseloc_where(error)
78+
!> Error handling
79+
type(error_type), allocatable, intent(out) :: error
80+
81+
integer :: ndim
82+
real, allocatable :: avec(:), bvec(:), cvec(:)
83+
84+
do ndim = 100, 12000, 100
85+
allocate(avec(ndim))
86+
87+
call random_number(avec)
88+
avec(:) = avec - 0.5
89+
90+
bvec = avec
91+
bvec(falseloc(bvec > 0)) = 0.0
92+
93+
cvec = avec
94+
where(.not.(cvec > 0)) cvec = 0.0
95+
96+
call check(error, all(bvec == cvec))
97+
deallocate(avec, bvec, cvec)
98+
if (allocated(error)) exit
99+
end do
100+
end subroutine test_falseloc_where
101+
102+
subroutine test_falseloc_merge(error)
103+
!> Error handling
104+
type(error_type), allocatable, intent(out) :: error
105+
106+
integer :: ndim
107+
real, allocatable :: avec(:), bvec(:), cvec(:)
108+
109+
do ndim = 100, 12000, 100
110+
allocate(avec(ndim))
111+
112+
call random_number(avec)
113+
avec(:) = avec - 0.5
114+
115+
bvec = avec
116+
bvec(falseloc(bvec > 0)) = 0.0
117+
118+
cvec = avec
119+
cvec(:) = merge(cvec, 0.0, cvec > 0)
120+
121+
call check(error, all(bvec == cvec))
122+
deallocate(avec, bvec, cvec)
123+
if (allocated(error)) exit
124+
end do
125+
end subroutine test_falseloc_merge
126+
127+
end module test_logicalloc
128+
129+
130+
program tester
131+
use, intrinsic :: iso_fortran_env, only : error_unit
132+
use testdrive, only : run_testsuite, new_testsuite, testsuite_type
133+
use test_logicalloc, only : collect_logicalloc
134+
implicit none
135+
integer :: stat, is
136+
type(testsuite_type), allocatable :: testsuites(:)
137+
character(len=*), parameter :: fmt = '("#", *(1x, a))'
138+
139+
stat = 0
140+
141+
testsuites = [ &
142+
new_testsuite("logicalloc", collect_logicalloc) &
143+
]
144+
145+
do is = 1, size(testsuites)
146+
write(error_unit, fmt) "Testing:", testsuites(is)%name
147+
call run_testsuite(testsuites(is)%collect, error_unit, stat)
148+
end do
149+
150+
if (stat > 0) then
151+
write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!"
152+
error stop
153+
end if
154+
end program

0 commit comments

Comments
 (0)