Code Comments
Programming Forum and web based access to our favorite programming groups.Is there any way to overload the index operator in fortran? For example if I want to index an array with a derived type? Or if I want to access a N-d array with a single subscript (possible of a derived type)? As a specific example, if I had a 2-d array: real foo(2,2) foo(1,1)=10 foo(2,1)=20 foo(1,2)=30 foo(2,2)=40 and if real bar bar=[2,4] then I would like to be able to access: foo(bar) and it would be a rank 1 array: [20,40] Can this be done in fortran?
Post Follow-up to this messageBen Barrowes wrote: > Is there any way to overload the index operator in fortran? For example > if I want to index an array with a derived type? Or if I want to access > a N-d array with a single subscript (possible of a derived type)? > > As a specific example, if I had a 2-d array: > > real foo(2,2) > foo(1,1)=10 > foo(2,1)=20 > foo(1,2)=30 > foo(2,2)=40 > > and if > real bar > bar=[2,4] > > then I would like to be able to access: > foo(bar) > > and it would be a rank 1 array: > [20,40] > > Can this be done in fortran? No and yes. Unlike C/C++, where anything goes, there is no concept in Fortran of an index operator. Hence, you can't index an array with a derived type. However, in the example you gave, you are trying to index one array using another array of indices. This is permitted by Fortran 90/95/03; but these "vector subscripts" work in a slightly different way than your example above. In fact, for the desired result, your code would have to read something like this: --- real foo(2,2) foo(1,1)=10. foo(2,1)=20. foo(1,2)=30. foo(2,2)=40. integer bar_1(2), bar_2(2) bar_1 = (/2,2/) bar_2 = (/1,2/) print *,foo(bar_1,bar_2) --- This would give the desired output "20. 40.". However, a number of points to note: 1) You need two separate arrays, bar_1 and bar_2, to index foo, since foo has two dimensions 2) bar_1 and bar_2 *must* be declared as integers if they are to be used for indexing 3) Array literals are enclosed inside (/.../) delimiters. The [...] syntax is introduced in the new Fortran 2003 standard; however, it is *not* part of the F90/F95 standards, and should be avoided if you wish to write portable code based on these standards. 4) There are restrictions on the use of vector subscripts on the left-hand side of assignments -- basically, to prevent the same element being written to twice. Should you wish to know more, the book "Fortran 95/2003 Explained", co-authored by c.l.f regular Mike Metcalf, gives a good discussion of vector subscripts. cheers, Rich -- Dr Richard H D Townsend Bartol Research Institute University of Delaware [ Delete VOID for valid email address ]
Post Follow-up to this messageRich, I appreciate your response. This indexing, however, does not give what I expected. With your example, I get: 20.0000000000000 20.0000000000000 40.0000000000000 40.0000000000000 In fact, consider: program zztest1 real foo(3,3) integer bar_1(3), bar_2(3) foo(1,1:3)=(/10.,40.,70./) foo(2,1:3)=(/20.,50.,80./) foo(3,1:3)=(/30.,60.,90./) bar_1 = (/2,2,1/) bar_2 = (/1,3,2/) print *,foo(bar_1,bar_2) end program zztest1 Both ifc and g95 yield: > test1 20.0000000000000 20.0000000000000 10.0000000000000 80.0000000000000 80.0000000000000 70.0000000000000 50.0000000000000 50.0000000000000 40.0000000000000 Where from your post, I expected: (/20,80,40/) Ben Rich Townsend wrote: > Ben Barrowes wrote: > > > > No and yes. Unlike C/C++, where anything goes, there is no concept in > Fortran of an index operator. Hence, you can't index an array with a > derived type. > > However, in the example you gave, you are trying to index one array > using another array of indices. This is permitted by Fortran 90/95/03; > but these "vector subscripts" work in a slightly different way than your > example above. In fact, for the desired result, your code would have to > read something like this: > > --- > real foo(2,2) > foo(1,1)=10. > foo(2,1)=20. > foo(1,2)=30. > foo(2,2)=40. > > integer bar_1(2), bar_2(2) > bar_1 = (/2,2/) > bar_2 = (/1,2/) > > print *,foo(bar_1,bar_2) > --- > > This would give the desired output "20. 40.". However, a number of > points to note: > > 1) You need two separate arrays, bar_1 and bar_2, to index foo, since > foo has two dimensions > 2) bar_1 and bar_2 *must* be declared as integers if they are to be used > for indexing > 3) Array literals are enclosed inside (/.../) delimiters. The [...] > syntax is introduced in the new Fortran 2003 standard; however, it is > *not* part of the F90/F95 standards, and should be avoided if you wish > to write portable code based on these standards. > 4) There are restrictions on the use of vector subscripts on the > left-hand side of assignments -- basically, to prevent the same element > being written to twice. > > Should you wish to know more, the book "Fortran 95/2003 Explained", > co-authored by c.l.f regular Mike Metcalf, gives a good discussion of > vector subscripts. > > cheers, > > Rich >
Post Follow-up to this messageBen Barrowes wrote: > Rich, > I appreciate your response. This indexing, however, does not give > what I expected. With your example, I get: > 20.0000000000000 20.0000000000000 40.0000000000000 40.0000000000000 > > In fact, consider: > > program zztest1 > > real foo(3,3) > integer bar_1(3), bar_2(3) > foo(1,1:3)=(/10.,40.,70./) > foo(2,1:3)=(/20.,50.,80./) > foo(3,1:3)=(/30.,60.,90./) > bar_1 = (/2,2,1/) > bar_2 = (/1,3,2/) > > print *,foo(bar_1,bar_2) > > end program zztest1 > > > Both ifc and g95 yield: > 20.0000000000000 20.0000000000000 10.0000000000000 > 80.0000000000000 80.0000000000000 70.0000000000000 > 50.0000000000000 50.0000000000000 40.0000000000000 > > Where from your post, I expected: > (/20,80,40/) > > Ben Oh dear, I've had a monster brain fart. I apologize for giving you a wholly-misleading example -- I appear to have forgotten that vector subscripts along different dimensions are applied independently of one another. A better example would have been something like this: --- real foo(4) foo(1)=10. foo(2)=20. foo(3)=30. foo(4)=40. integer bar(2) bar = (/2,4/) print *,foo(bar) --- This will produce the desired output "20. 40."; but note that foo is now a one-dimensional array, and I have a single index array bar. cheers, Rich -- Dr Richard H D Townsend Bartol Research Institute University of Delaware [ Delete VOID for valid email address ]
Post Follow-up to this messageBen Barrowes wrote: > Rich, > I appreciate your response. This indexing, however, does not give > what I expected. With your example, I get: > 20.0000000000000 20.0000000000000 40.0000000000000 40.0000000000000 > Yep, that's what you get. Vector Valued Subscripts give the outer product of the subscript ranges. There is no good way in Fortran to collapse a 2 dimensional array into one dimension that way you want to. In your first example, you seem to be thinking of foo(2,2) as the 4th element of foo. It really isn't, it's the (2,2) element. The only thing I can think of is to equivalence a one dimensional array to foo and subsctipr into that. Something like real foo(2,2), big_foo(4) equivalence (foo, big_foo) .. the big_foo( (/2,4/) ) will be a rank one array with values 20 and 40. Unfortunately, you can only EQUIVALENCE this way with arrays of known size and that aren't dummy arguments. That's often a killer limitation for most uses. As Rcih mentioned, you can use a one dimensional integer scalar array name in place of the array constructor for the (/ 2,4 /). You can always copy the 2D array into a 1D array, manipulate it with vector valued subscripts, and copy it back. Whether or not that's a good idea depends on how much you do to what. Dick Hendrickson > In fact, consider: > > program zztest1 > > real foo(3,3) > integer bar_1(3), bar_2(3) > foo(1,1:3)=(/10.,40.,70./) > foo(2,1:3)=(/20.,50.,80./) > foo(3,1:3)=(/30.,60.,90./) > bar_1 = (/2,2,1/) > bar_2 = (/1,3,2/) > > print *,foo(bar_1,bar_2) > > end program zztest1 > > > Both ifc and g95 yield: > 20.0000000000000 20.0000000000000 10.0000000000000 > 80.0000000000000 80.0000000000000 70.0000000000000 > 50.0000000000000 50.0000000000000 40.0000000000000 > > Where from your post, I expected: > (/20,80,40/) > > Ben > > > > Rich Townsend wrote:
Post Follow-up to this message"Ben Barrowes" <barrowes@alum.mit.edu> wrote in message news:416ff3b7$1_5@news3.es.net... > Is there any way to overload the index operator in fortran? For example > if I want to index an array with a derived type? Or if I want to access > a N-d array with a single subscript (possible of a derived type)? > As a specific example, if I had a 2-d array: > real foo(2,2) > foo(1,1)=10 > foo(2,1)=20 > foo(1,2)=30 > foo(2,2)=40 > and if > real bar > bar=[2,4] > then I would like to be able to access: > foo(bar) > and it would be a rank 1 array: > [20,40] > Can this be done in fortran? Sort of. Try this: module extra_index implicit none contains subroutine repoint(old,n,new) integer n real, target :: old(n) real, pointer :: new(:) new => old end subroutine repoint end module extra_index program test use extra_index implicit none real, target :: foo(2,2) integer, allocatable :: bar(:) real, pointer :: foo1(:) foo = reshape((/10,20,30,40/),shape(foo)) call repoint(foo,size(foo),foo1) allocate(bar(2)) bar = (/2,4/) write(*,*) foo1(bar) end program test -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
Post Follow-up to this messageOn Fri, 15 Oct 2004, James Van Buskirk wrote: > > > "Ben Barrowes" <barrowes@alum.mit.edu> wrote in message > news:416ff3b7$1_5@news3.es.net... > > > > > > > > > Sort of. Try this: > > module extra_index > implicit none > contains > subroutine repoint(old,n,new) > integer n > real, target :: old(n) > real, pointer :: new(:) > > new => old > end subroutine repoint > end module extra_index > > program test > use extra_index > implicit none > real, target :: foo(2,2) > integer, allocatable :: bar(:) > real, pointer :: foo1(:) > > foo = reshape((/10,20,30,40/),shape(foo)) > call repoint(foo,size(foo),foo1) > allocate(bar(2)) > bar = (/2,4/) > write(*,*) foo1(bar) > end program test > > -- > write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & > 6.0134700243160014d-154/),(/'x'/)); end > I usually do something along the following: program zztest1 real foo(3,3) logical lfoo(3,3) foo(1,1:3)=(/10.,40.,70./) foo(2,1:3)=(/20.,50.,80./) foo(3,1:3)=(/30.,60.,90./) lfoo=.false. lfoo(1,2)=.true. lfoo(2,(/1,3/))=.true. print *, pack(foo,mask=lfoo) end program zztest1 of course you won't get the order that you had specified (column-wise as opposed to row-wise). Now all you have to do is update lfoo as you iterate through your program to pull off the elements you want. Not sure if this is what you were going for though. Cheers, Jason
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.