-
Notifications
You must be signed in to change notification settings - Fork 185
[stdlib_linalg] Add empty function. #477
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
Conversation
The main purpose of implicit none
real, pointer :: array(:)
integer :: n = 6000000
array => empty_ptr(n)
! ... do something with array
deallocate(array) ! explicit free required
contains
function empty_ptr(n) result(array)
integer, intent(in) :: n
real, pointer :: array(:)
allocate(array(n))
end function
end The current implementation uses an automatic array to trigger an automatic LHS (re)allocation. This has several drawback, first the automatic array will most likely be created on the stack and cannot be moved to an allocatable array on the heap, but must be copied to the newly allocated array. This will be considerably worse than just using Preferably, to match the original intent of the functionality provided by function empty(n) result(array)
integer, intent(in) :: n
real, allocatable :: array(:)
allocate(array(n))
end function empty In the best case the compiler might move the allocation produced by the function to the LHS array instead of separately allocating and copying the uninitialized array. |
Take a look at these two examples @awvwgk , I see from examples here, the current code implementation is more efficient in gfortran (not ifort), and the code implementation method you mentioned can also be (re)allocated. Example 1In the case of small stack usage, program test
real :: stime, etime
real(kind=8), allocatable :: A(:,:), B(:,:)
call cpu_time(stime)
A = empty1(100,100)
A = empty1(200,200)
call cpu_time(etime)
print *, "etime - stime (seconds) : ", etime - stime !! 3.4e-4 (gfortran); 1.5e-5 (ifx); 5.5e-4 (ifort)
call cpu_time(stime)
B = empty2(100,100)
B = empty2(200,200)
call cpu_time(etime)
print *, "etime - stime (seconds) : ", etime - stime !! 8.0e-6 (gfortran); 4.3e-4 (ifx); 4.5e-4 (ifort)
contains
pure function empty1(ndim1, ndim2) result(result)
implicit none
integer, intent(in) :: ndim1, ndim2
real(kind=8), allocatable :: result(:,:)
allocate(result(ndim1, ndim2))
end function empty1
pure function empty2(ndim1, ndim2) result(result)
implicit none
integer, intent(in) :: ndim1, ndim2
real(kind=8) :: result(ndim1, ndim2)
end function empty2
end program test Example 2In the case of large stack usage, program test
real :: stime, etime
real(kind=8), allocatable :: A(:,:), B(:,:)
call cpu_time(stime)
A = empty1(1000,1000)
A = empty1(2000,2000)
call cpu_time(etime)
print *, "etime - stime (seconds) : ", etime - stime !! 3.3e-2 (gfortran); 2.2e-5 (ifx); 5.3e-2 (ifort)
call cpu_time(stime)
B = empty2(1000,1000)
B = empty2(2000,2000)
call cpu_time(etime)
print *, "etime - stime (seconds) : ", etime - stime !! 1.6e-5 (gfortran); stack overflow (ifx/ifort)
contains
pure function empty1(ndim1, ndim2) result(result)
implicit none
integer, intent(in) :: ndim1, ndim2
real(kind=8), allocatable :: result(:,:)
allocate(result(ndim1, ndim2))
end function empty1
pure function empty2(ndim1, ndim2) result(result)
implicit none
integer, intent(in) :: ndim1, ndim2
real(kind=8) :: result(ndim1, ndim2)
end function empty2
end program test |
I think based on the above examples, to be compatible with |
1. automatic array -> allocatable array. 2. add `empty` tests for `real/complex` type.
program demo_linlag_empty_1 | ||
|
||
use stdlib_linlag, only: empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
program demo_linlag_empty_1 | |
use stdlib_linlag, only: empty | |
program demo_linalg_empty_1 | |
use stdlib_linalg, only: empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like with eye
, I don't think that the allocatable
result is a better choice here over the automatic array and the examples show it. However, the difference is probably low impact because this is likely to be used as a convenience function rather than a high-performance one, and in my view UX > performance. I think this can go forward as is.
The only use case I see for this function is to trigger an automatic LHS allocation, which I think is rather limited compared to the intrinsic function, because it will always require a statement to make use of this. allocate(array(n, n))
array = empty(n, n) Using it in an expression would only work when multiplying by zero, because the initial entries are undefined, but for this purpose we could use I can see why this function is required in numpy to return a pointer to a memory allocation, but I don't think there is need for it in Fortran. |
I think the purpose of |
empty
function. (see numpy/empty)Tasks
allocatable
solution. (see [stdlib_linalg] Add empty function. #477 (comment))More routines to do, not this PR
see #476.