0

Is it possible to define an array with non-consecutive indices in Fortran 90?


The following code returns an error (Error: The module or main program array 'test' at (1) must have constant shape):

program example
  implicit none
  integer, dimension((/1,3/)) :: test
end

Is there an alternative way to define such an array or is this simply not allowed?

mzp
  • 181
  • 9
  • 2
    *Why* do you think you need this? – Ross May 25 '18 at 22:14
  • It would help me solve the problem in [this question](https://stackoverflow.com/q/50534287/3553449). – mzp May 25 '18 at 22:16
  • 1
    @mzp The answer to your questions are 'no' and 'yes'. The lower and upper bounds for the dimensions of an array are specification expressions. A specification expression is a scalar integer expression. – Steve May 25 '18 at 22:27
  • Ok, thank you for your help! – mzp May 25 '18 at 22:29
  • 1
    rather than trying madness like that, have you thought about how you could vectorize your problem so that you don't need non-consecutive indices? – Fl.pf. May 28 '18 at 09:39
  • @Fl.pf. I have been thinking about that a lot actually. So far I haven't found a solution. Have you seen the other question I link to in the comment above? Any suggestion would be very helpful. – mzp May 28 '18 at 18:33

1 Answers1

1

You can implement the type yourself. Here is a messy and inefficient way of doing it.

module WeirdArray
  implicit none
  private

  type, public :: Warray
    private
    integer, dimension(:), allocatable :: indeces
    real, dimension(:), allocatable :: vals
  contains
    procedure, pass :: init
    procedure, pass :: get
    procedure, pass :: set
  end type

contains
  subroutine init(this, i, v)
    class(warray), intent(out) :: this
    integer, dimension(:) :: i
    real, dimension(size(i)) :: v
    this%indeces = i
    this%vals = v
  end subroutine init

  function get(this, indx) result(x)
    class(warray), intent(in) :: this
    integer, intent(in) :: indx
    real :: x
    integer, dimension(:), allocatable :: p
    integer :: i
    p = pack([(i,i=1,size(this%indeces))],this%indeces==indx)
    x = this%vals( p(1) )
  end function get

  subroutine set(this, indx, x)
    class(warray), intent(inout) :: this
    integer, intent(in) :: indx
    real, intent(in) :: x
    integer, dimension(:), allocatable :: p
    integer :: i
    p = pack([(i,i=1,size(this%indeces))],this%indeces==indx)
    this%vals( p(1) ) = x
  end subroutine set  

end module WeirdArray

And you can use it like this:

program main
  use weirdArray
  implicit none

  type(Warray) :: wa

  call wa%init([5,12], [10.0, 24.0])

  write(*,*) wa%get(5)
  call wa%set(5, 3.14)
  write(*,*) wa%get(5)
  write(*,*) wa%get(12)

end program main
Eliad
  • 894
  • 6
  • 20