3

Is there a way to populate a constant array in an order specified by other constant variables?

So, in effect this:

integer, parameter :: ired  = 1
integer, parameter :: iblue = 2
real,    parameter :: myarr(2,3)
myarr(ired, :) = [1,0,0]
myarr(iblue,:) = [0,0,1]

Except the above of course will not compile. Is there a way to get to this in some way?

Sampo Smolander
  • 1,605
  • 2
  • 15
  • 33

2 Answers2

1

No, there is no way to assign values to a parameter after program start-up; that's exactly what the attribute parameter is intended to prevent.

You could write

real, parameter :: myarr(2,3) = reshape([1.0,0,0,0,0,1],[2,3])

to initialise myarr. Note that the elements are provided to reshape in the array element order specified by Fortran (ie column major); here it happens to be the same as if you had specified them in row major order. And note that in Fortran initialization means, precisely, setting a value in the declaration statement, which is how parameters acquire values.

I don't immediately see any way to use ired and iblue in the intialisation but I'm struggling to see that as a problem.

EDIT, after OP's comment:

I guess you could write something like

  INTEGER, PARAMETER :: ired  = 1
  INTEGER, PARAMETER :: iblue = 2
  REAL, PARAMETER, DIMENSION(2,3) :: rows = reshape([1,0,0,0,0,1],[2,3])
  REAL, PARAMETER :: myarr(2,3) = RESHAPE([rows(ired,:), rows(iblue,:)], [2,3])

and now you only have to swap the values of ired and blue to change myarr. And the only thing you might forget is why you wrote such convoluted code !

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
  • If I later change `ired = 2 ; iblue = 1`, then I would also need to remember to change `reshape([1.0,0,0,0,0,1],[2,3])` to `reshape([0,0,1,1,0,0],[2,3])`. Potentially forgetting to make changes in two places, is the problem. – Sampo Smolander Apr 19 '16 at 15:28
  • Nice trick! Unfortunately it doesn't generalize to 3 variables. If I first have `ired = 1 ; igreen = 2 ; iblue = 3` and then shuffle the values, the trick doesn't work. – Sampo Smolander Apr 20 '16 at 16:37
1

To generalize @HPM's answer to the case where ired and iblue etc may be discontiguous (e.g, 1 and 3), combined use of implied do-loop + array constructor might be useful. Because arrays in Fortran are column-major, I have aligned the vectors in a matrix such that [ vec1, vec2, ..., vecN ] where vecX is a 3-vector.

integer :: k
integer, parameter :: ired = 1, iblue = 3, mxvec = 4, ndim = 3, zero(3) = [0,0,0]

integer, dimension( ndim * mxvec ), parameter :: &
        red  = [ (zero, k=1,ired-1 ), [1,1,1], (zero, k=ired+1, mxvec) ], &
        blue = [ (zero, k=1,iblue-1), [7,7,7], (zero, k=iblue+1,mxvec) ]

integer, parameter :: myarr( ndim, mxvec ) = reshape( red + blue, [ ndim, mxvec ] )

print "(a,/100(3i2/))", "red   = ", red
print "(a,/100(3i2/))", "blue  = ", blue
print "(a,/100(3i2/))", "myarr = ", myarr

print *, "myarr( :, ired  ) = ", myarr( :, ired  )
print *, "myarr( :, iblue ) = ", myarr( :, iblue )

Result:

red   =
 1 1 1
 0 0 0
 0 0 0
 0 0 0

blue  =
 0 0 0
 0 0 0
 7 7 7
 0 0 0

myarr =
 1 1 1
 0 0 0
 7 7 7
 0 0 0

 myarr( :, ired  ) =            1           1           1
 myarr( :, iblue ) =            7           7           7
roygvib
  • 7,218
  • 2
  • 19
  • 36
  • Nothing wrong with this answer, but it does make me think that using a single call to `reshape` in the initialisation of the array is the most straightforward way to go. Like the first code snippet in my own answer. – High Performance Mark Apr 20 '16 at 17:33
  • Yeah, I definitely agree with you! The problem is that, while I was playing with the above code, I met several strange behaviors (possibly compiler bugs) for gfortran and Sun fortran (ifort always worked). For example, combining two lines + use reshape() at the same time + replacing [1,1,1] by a pre-defined named parameter gave a wrong result (with gfort-5.3). Sun fortran even got frozen... If possible I will try to ask this in comp.lang.fortran later (because this might be a compiler bug). (If it is better to ask here first, I will post a question then.) – roygvib Apr 20 '16 at 17:49