Skip to content

Commit 58d8eef

Browse files
committed
Improve the efficiency of diff.
1 parent ec00dfe commit 58d8eef

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/stdlib_math_diff.fypp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#! Inspired by original code (MIT license) written in 2016 by Keurfon Luu (keurfonluu@outlook.com)
2-
#! https://github.com/keurfonluu/Forlab/blob/master/src/lib/forlab.f90#L2673
1+
!> Inspired by original code (MIT license) written in 2016 by Keurfon Luu (keurfonluu@outlook.com)
2+
!> https://github.com/keurfonluu/Forlab/blob/master/src/lib/forlab.f90#L2673
33

44
#:include "common.fypp"
55
#:set RI_KINDS_TYPES = REAL_KINDS_TYPES + INT_KINDS_TYPES
@@ -9,16 +9,15 @@ submodule (stdlib_math) stdlib_math_diff
99

1010
contains
1111

12-
#! `diff` computes differences of adjacent elements of an array of the ${t1}$ type.
12+
!> `diff` computes differences of adjacent elements of an array.
1313

1414
#:for k1, t1 in RI_KINDS_TYPES
1515
pure module function diff_1_${k1}$(x, n, prepend, append) result(y)
1616
${t1}$, intent(in) :: x(:)
1717
integer, intent(in), optional :: n
1818
${t1}$, intent(in), optional :: prepend(:), append(:)
1919
${t1}$, allocatable :: y(:)
20-
integer :: size_prepend, size_append, size_x
21-
${t1}$, allocatable :: work(:)
20+
integer :: size_prepend, size_append, size_x, size_work
2221
integer :: n_, i
2322

2423
n_ = optval(n, 1)
@@ -32,22 +31,31 @@ contains
3231
if (present(prepend)) size_prepend = size(prepend)
3332
if (present(append)) size_append = size(append)
3433
size_x = size(x)
34+
size_work = size_x + size_prepend + size_append
3535

36-
if (size_x + size_prepend + size_append <= n_) then
36+
if (size_work <= n_) then
3737
allocate(y(0))
3838
return
3939
end if
4040

41-
allocate(work(size_x + size_prepend + size_append))
41+
!> Use a quick exit for the common case, to avoid memory allocation.
42+
if (size_prepend == 0 .and. size_append == 0 .and. n_ == 1) then
43+
y = x(2:) - x(1:size_x-1)
44+
return
45+
end if
46+
47+
block
48+
${t1}$ :: work(size_work)
4249
if (size_prepend > 0) work(:size_prepend) = prepend
4350
work(size_prepend+1:size_prepend+size_x) = x
4451
if (size_append > 0) work(size_prepend+size_x+1:) = append
4552

4653
do i = 1, n_
47-
work(1:size(work)-i) = work(2:size(work)-i+1) - work(1:size(work)-i)
54+
work(1:size_work-i) = work(2:size_work-i+1) - work(1:size_work-i)
4855
end do
49-
50-
y = work(1:size(work)-n_)
56+
57+
y = work(1:size_work-n_)
58+
end block
5159

5260
end function diff_1_${k1}$
5361

@@ -56,9 +64,8 @@ contains
5664
integer, intent(in), optional :: n, dim
5765
${t1}$, intent(in), optional :: prepend(:, :), append(:, :)
5866
${t1}$, allocatable :: y(:, :)
59-
integer :: size_prepend, size_append, size_x
67+
integer :: size_prepend, size_append, size_x, size_work
6068
integer :: n_, dim_, i
61-
${t1}$, allocatable :: work(:, :)
6269

6370
n_ = optval(n, 1)
6471
if (n_ <= 0) then
@@ -81,33 +88,48 @@ contains
8188
if (present(prepend)) size_prepend = size(prepend, dim_)
8289
if (present(append)) size_append = size(append, dim_)
8390
size_x = size(x, dim_)
91+
size_work = size_x + size_prepend + size_append
8492

85-
if (size_x + size_prepend + size_append <= n_) then
93+
if (size_work <= n_) then
8694
allocate(y(0, 0))
8795
return
8896
end if
8997

98+
!> Use a quick exit for the common case, to avoid memory allocation.
99+
if (size_prepend == 0 .and. size_append == 0 .and. n_ == 1) then
100+
if (dim_ == 1) then
101+
y = x(2:, :) - x(1:size_x-1, :)
102+
elseif (dim_ == 2) then
103+
y = x(:, 2:) - x(:, 1:size_x-1)
104+
end if
105+
return
106+
end if
107+
90108
if (dim_ == 1) then
91-
allocate(work(size_x+size_prepend+size_append, size(x, 2)))
109+
block
110+
${t1}$ :: work(size_work, size(x, 2))
92111
if (size_prepend > 0) work(1:size_prepend, :) = prepend
93112
work(size_prepend+1:size_x+size_prepend, :) = x
94113
if (size_append > 0) work(size_x+size_prepend+1:, :) = append
95114
do i = 1, n_
96-
work(1:size(work,1)-i, :) = work(2:size(work)-i+1, :) - work(1:size(x, 1)-i, :)
115+
work(1:size_work-i, :) = work(2:size_work-i+1, :) - work(1:size_work-i, :)
97116
end do
98117

99-
y = work(1:size(work)-n_, :)
118+
y = work(1:size_work-n_, :)
119+
end block
100120

101121
elseif (dim_ == 2) then
102-
allocate(work(size(x, 1), size_x+size_prepend+size_append))
122+
block
123+
${t1}$ :: work(size(x, 1), size_work)
103124
if (size_prepend > 0) work(:, 1:size_prepend) = prepend
104125
work(:, size_prepend+1:size_x+size_prepend) = x
105126
if (size_append > 0) work(:, size_x+size_prepend+1:) = append
106127
do i = 1, n_
107-
work(:, 1:size(work,2)-i) = work(:, 2:size(work,2)-i+1) - work(:, 1:size(work, 2)-i)
128+
work(:, 1:size_work-i) = work(:, 2:size_work-i+1) - work(:, 1:size_work-i)
108129
end do
109130

110-
y = work(:, 1:size(work,2)-n_)
131+
y = work(:, 1:size_work-n_)
132+
end block
111133

112134
end if
113135

0 commit comments

Comments
 (0)