Static array elements in modern Fortran [duplicate] - fortran

Is there possibility to use indexing directly on a function's return value? Something like this:
readStr()(2:5)
where readStr() is a function which returns a character string or an array. In many other languages it is quite possible, but what about Fortran? The syntax in my example of course does not compile. Is there any other syntax to be used?

No, that is not possible in Fortran. You could, however, alter your function to take an additional index array that determines which elements are returned. This example illustrates this possibility using an interface to allow for an optional specification of the indices (simplified greatly thanks to the comment by IanH):
module test_mod
implicit none
contains
function squareOpt( arr, idx ) result(res)
real, intent(in) :: arr(:)
integer, intent(in), optional :: idx(:)
real,allocatable :: res( : )
real :: res_( size(arr) )
integer :: stat
! Calculate as before
res_ = arr*arr
if ( present(idx) ) then
! Take the sub-set
allocate( res(size(idx)), stat=stat )
if ( stat /= 0 ) stop 'Cannot allocate memory!'
res = res_(idx)
else
! Take the the whole array
allocate( res(size(arr)), stat=stat )
if ( stat /= 0 ) stop 'Cannot allocate memory!'
res = res_
endif
end function
end module
program test
use test_mod
implicit none
real :: arr(4)
integer :: idx(2)
arr = [ 1., 2., 3., 4. ]
idx = [ 2, 3]
print *, 'w/o indices',squareOpt(arr)
print *, 'w/ indices',squareOpt(arr, idx)
end program

No.
But if it bothers you, you can write your own user defined functions and operators to achieve a similar outcome without having to store the result of the function reference in a separate variable.

You can avoid declaring another variable if you use associate. Whether it is any better or clearer than a temporary variable must be decided by the user. The result has to be stored somewhere anyway.
associate(str=>readStr())
print *, str(2:5)
end associate
It will not be very useful for this specific case with a potentially long string but might be more useful for other similar cases that get linked here as duplicates.

Related

Should the use of the INTENT keyword speed the code up?

This question is based on an answer to the post Fortran intent(inout) versus omitting intent, namely the one by user Vladimyr, #Vladimyr.
He says that "<...> Fortran copies that data into a contiguous section of memory, and passes the new address to the routine. Upon returning, the data is copied back into its original location. By specifying INTENT, the compiler can know to skip one of the copying operations."
I did not know this at all, I thought Fortran passes by reference exactly as C.
The first question is, why would Fortran do so, what is the rationale behind this choice?
As a second point, I put this behaviour to the test. If I understood correctly, use of INTENT(IN) would save the time spent in copying back the data to th original location, as the compiler is sure the data has not been changed.
I tried this little piece of code
function funco(inp) result(j)
!! integer, dimension(:), intent (in) :: inp
integer, dimension(:):: inp
integer, dimension(SIZE(inp)) :: j ! output
j = 0.0 !! clear whole vector
N = size(inp)
DO i = 1, N
j(i) = inp(i)
END DO
end function
program main
implicit none
interface
function funco(inp) result(j)
!! integer, dimension(:), intent (in) :: inp
integer, dimension(:) :: inp
integer, dimension(SIZE(inp)) :: j ! output
end function
end interface
integer, dimension(3000) :: inp , j
!! integer, dimension(3000) :: funco
integer :: cr, cm , c1, c2, m
real :: rate, t1, t2
! Initialize the system_clock
CALL system_clock(count_rate=cr)
CALL system_clock(count_max=cm)
CALL CPU_TIME(t1)
rate = REAL(cr)
WRITE(*,*) "system_clock rate ",rate
inp = 2
DO m = 1,1000000
j = funco(inp) + 1
END DO
CALL SYSTEM_CLOCK(c2)
CALL CPU_TIME(t2)
WRITE(*,*) "system_clock : ",(c2 - c1)/rate
WRITE(*,*) "cpu_time : ",(t2-t1)
end program
The function copies an array, and in the main body this is repeated many times.
According to the claim above, the time spent in copying back the array should somehow show up.
system_clock rate 1000.00000
system_clock : 2068.07910
cpu_time : 9.70935345
but the results are pretty much the same independently from whether INTENT is use or not.
Could anybody share some light on these two points, why does Fortran performs an additional copy (which seems ineffective at first, efficiency-wise) instead of passing by reference, and does really INTENT save the time of a copying operation?
The answer you are referring to speaks about passing some specific type of subsection, not of the whole array. In that case a temporary copy might be necessary, depending on the function. Your function uses and assumed shape array and a temporary array will not be necessary even if you try quite hard.
An example of what the author (it wasn't me) might have had in mind is
module functions
implicit none
contains
function fun(a, n) result(res)
real :: res
! note the explicit shape !!!
integer, intent(in) :: n
real, intent(in) :: a(n, n)
integer :: i, j
do j = 1, n
do i = 1, n
res = res + a(i,j) *i + j
end do
end do
end function
end module
program main
use functions
implicit none
real, allocatable :: array(:,:)
real :: x, t1, t2
integer :: fulln
fulln = 400
allocate(array(1:fulln,1:fulln))
call random_number(array)
call cpu_time(t1)
x = fun(array(::2,::2),(fulln/2))
call cpu_time(t2)
print *,x
print *, t2-t1
end program
This program is somewhat faster with intent(in) when compared to intent(inout) in Gfortran (not so much in Intel). However, it is even much faster with an assumed shape array a(:,:). Then no copy is performed.
I am also getting some strange uninitialized accesses in gfortran when running without runtime checks. I do not understand why.
Of course this is a contrived example and there are real cases in production programs where array copies are made and then intent(in) can make a difference.

Using maxval or minval functions [duplicate]

I would like to access the the elements of an array in a an arrayed derived type using the subroutine sum_real. That is: sum over first entry in the weight for all people.
type my_type
real, dimension(:), allocatable :: weight
real :: total_weight
end type my_type
type (my_type), dimension (:), allocatable :: people
type (my_type) :: answer
allocate (people (2))
allocate (people (1)%weight(2))
allocate (people (2)%weight(2))
people (1) % weight(1) = 1
people (2) % weight(1) = 1
people (1) % weight(2) = 3
people (2) % weight(2) = 3
call sum_real ( people (:) % weight(1), answer % total_weight )
What I want to do is similar to the answer found in Array of derived type: select entry, except for the fact that I have an allocated array in an arrayed derived type instead of an single element.
But, I get a compiler error:
error #7828: The part-name to the right of a part-ref with nonzero rank has the ALLOCATABLE attribute (6.1.2). [WEIGHT]
What you try is not possible if your component is allocatable. The reference (6.1.2) is actually a reference to the official standard documents, which prohibits this.
The reason is simple, the allocatable components (scalar or arrays) are stored in a different part of memory than the derived type itself. Therefore if you write
sum(people%total_weight)
or
people%total_weight = 0
it is no problem, total_weight is not allocatable, it is stored within the derived type and the compiler just goes in a simple loop and sets one field after another to zero. You can know the address of each %totalweight beforehand.
On the other hand
sum(people%weight)
or
people%weight = 0
each %weight is stored elsewhere and you don't have any simple formula to compute where is each %weight(i).
The solution is either, to fix the size of the array, if possible
real, dimension(2) :: weight
or use a do loop
s = 0
do i = 1, size(people)
S = S + sum(people(i)%weight)
end do
If you have a F2003 compiler, and the bounds of the component array are the same for a particular parent array object, a third approach to the size specified by constant expression/use a do loop methods specified by VladimirF is to parameterize the type.
type my_type(n) ! This type has one parameter - n
integer, len :: n ! The parameter n is a length parameter.
real :: weight(n) ! This component depends on that parameter.
end type my_type
type (my_type(:)), dimension(:), allocatable :: people
! This integer is the size of the people component. Because
! people is allocatable it can be determined at runtime.
number_of_people = 2
! This integer is the size of the weight component that we want
! in the array people. Other arrays and scalars of type
! my_type can have different sizes for that component.
! Because people is allocatable this can be determined at
! runtime.
number_of_weights = 2
allocate( my_type(number_of_weights) :: people(number_of_people) )
! Define people%weight here.
people(1)%weight(1) = 1
...
! Using sum intrinsic for the sake of example
do i = 1, people%n
! The argument to sum is an array section.
print *, sum(people%weight(i))
! ^ ^ Reference to an element of a component
! | Reference to the entire people array
end do
Every element in an array of parameterized type has the same type parameters, hence every weight component in people has the same bounds, hence references such as people%weight become "regular".
Code using this approach (or the constant component size specification approach) still has to follow the restriction for component references that only one part of the reference can have non-zero rank (you can't work with people%weight as a whole as both people and the weight component have rank one).
In the allocatable component case some components in some elements might not be allocated and where they are allocated the component might have different bounds, making a "regular" reference to the data in the component across the elements of the array conceptually difficult.

Fortran - lbound throws error 6366 "The shapes of the array expressions do not conform"

So I've been confounded again by Fortran. Go figure. Anyway, I'm trying to write a pretty simple routine the strips values off the end of an array. Everything complicated works fine, except I want to write the subroutine such that I don't have to pass the lower bound of the input array to it. Here is the subroutine:
subroutine Strip(list,lstart, index)
implicit none
integer :: i, index, isize, tsize, lstart, istart
real, dimension(:), allocatable, intent(inout) :: list
real, dimension(:), allocatable :: tlist
isize = size(list)
tsize = index-1
print *, 'index', index
print *, 'isize', isize
print*, 'lbound', INT(lbound(list))
print*, 'tsize', tsize
istart = lbound(list) !<---- This lines throws the error
!These are commented out because everything below here works
!allocate(tlist(lstart:tsize))
!tlist = list(lstart:index-1)
!deallocate(list)
!call move_alloc(tlist,list)
end subroutine Strip
Right now I'm passing the lower bound of the input list into the subroutine (lstart), but I'd like not to do that. Anyway, this code doesn't compile, the compiler throws the error 6366: The shapes of the array expressions do not conform [ISTART]
I don't know how to fix this. Any suggestions?
Lbound() returns an array! Read The Fortran Manual (RTFM) at https://gcc.gnu.org/onlinedocs/gfortran/LBOUND.html
It returns an array with as many elements as is the rank ("dimension" 1D,2D,...) of the array.
To get a single number, for a specific dimension, use the optional argument DIM.
istart = lbound(list, 1)

Index multiple non-adjacent elements of a Fortran array

Is there a way in Fortran to access many elements of an array without using a loop?
For example given array of 100 elements
real(100) :: a
can I do something like this to access elements 1,4,7,54,81 that do not follow a regular step?
a(1,4,7,54,81)= 3.21423
you could use a vector subscript: a( (/1,4,7,54,81/) )= 3.21423
As noted before, an array may be used as the indexes of an array. This is a so-called vector subscript.
A([1,4,7,54,81]) = 3.21423
sets the elements given to that value. (This is the same as the earlier answer but using the Fortran 2003+/modern array constructor notation.)
The array can be any rank-1 array, such as a variable or expression:
integer :: idx(5)=[1,4,7,54,81]
A(idx) = 3.21423
A(idx-1+1) = 3.21423
Of course, vector subscripts are of use in other settings, such as referencing:
print *, A(idx)
call sub(A(idx))
A(idx) = A(idx+1) + 5
However, array sections with vector subscripts are subject to various restrictions, such as:
not always may they be arguments to a procedure;
a pointer may not point to them;
not all such sections may be assigned to.
In the third case, if the same index appears more than once in the subscript we can't define it. So
print *, A([1,5,1])
is allowed, but
A([1,5,1]) = 3.
is not.
RESHAPE and WHERE are worth looking at.
If you are determining which elements to 'pull out' then maybe ALLOCATE a new variable and stuff the elements of A into B.
Maybe something like this:
REAL, DIMENSION(100) :: A
LOGICAL, DIMENSION(100) :: A_Mask
INTEGER :: SizeB
REAL, DIMENSION(:), ALLOCATABLE :: B
!...
A_Mask = .FALSE.
WHERE(A > 1.0)
A_Mask = .TRUE.
ENDWHERE
SizeB = SUM(A_Mask)
!... then allocate B and fill it.

access operators "[ ], ( ), { }" overloading in Fortran 90 or 2003

Can I overload entry access operators [], () or {} for derived data types in FORTRAN 2003? In the following example, I want to define access scheme for the derived data type "custom".
type custom
integer, dimension(:), allocatable :: a
end type custom
type(custom) :: t
! after some initialization
! .....
! .....
! .....
!
t%a( (/ 1, 2, 5 /) ) ! return entries located in positions 1, 2, and 5
t{ (/ 1, 2, 5 /) } ! ?????? I want to define what stuff it should return
How can I do that?
Update:
Note that I don't want to use the array "t%a" directly and do conventional sub-array operation on that. Instead, I want to redefine array operation for data type "custom" such that t{'first'} should return a pointer the first entry in t%a or t%a(1) so I can say
t['first']= 18
or
print *, t['first'].
Also with additional overloading I want to get a functionality like t[1] = 18 works like t['first'] = 18.
This rather depends on what you mean by "return".
By itself the example offered
t%a([1,2,5]) ! Using syntax offered by Fortran 2003
doesn't return anything: it's a subobject. With a reference to that subobject we can do various things:
print *, t%a([1,2,5])
t%a([1,2,5]) = 27
t%a([1,2,5]) = sin(real(t%a([1,2,5])))
but there's still no concept of "returning". Crucially, as we shall see, these are not expressions.
Coming to the question, can t[], t(), t{} mean something, then the answer is, simply, "no".* You may want, for example, to say:
t[1,2,5] = 1
to mean
t%a[1,2,5] = 1
but that is not something to consider.
It would be possible to create an expression like
print *, t%ref([1,2,5])
but we're quite in the non-definable territory.
However, as you now mention pointers, there's more to say. Whilst the preferred syntax t[1] or t["first"] is not available we still have the option of type-bound procedures. For example, a function call t%ref("first") may well be able to return a pointer to the first element of t%a. For example, t%ref(1) could be like
module reference
implicit none
type custom
integer, dimension(:), allocatable :: a
contains
procedure ref
end type custom
contains
function ref(t, idx)
class(custom), target, intent(in) :: t
integer, intent(in) :: idx
integer, pointer :: ref
ref => t%a(idx)
end function ref
end module reference
use reference
implicit none
type(custom), target :: t
integer, pointer :: b
t%a = [1, 2, 3, 4, 5]
print *, t%a
b => t%ref(1) ! Fortran 2008 allows direct assignment
b = 8 ! but compiler support is very limited.
print *, t%a
end
If desired ref can be made generic so that t%ref("first") (etc.) is acceptable.
* I'm basing that on the fact that here t is a scalar. However, as mentioned by Vladimir F in a comment () and [] potentially do mean things. The first relates to arrays and the second to co-arrays. Syntax, then, is an issue, but this answer looks more at the mechanism than syntax.