Array of pointer to section of messy array

Can I have a pointer array that points to the messy section of the target array? In the following program:

program test
  implicit none

  integer :: i
  integer, dimension(4), target :: orig
  integer, dimension(:), pointer :: ref

  orig = (/ (i , i = 1,4) /)

  ref(1:2) => orig(1:2)   
  ref(3:3) => orig(4:4)

  print *, 'orig = ', orig
  print *, 'ref = ', ref

end program test

      

I want the pointer to ref

point to the unchecked section of the (/1,2,4/)

target array orig

. The code compiles without warning, however no output is needed:

code output:
 orig =            1           2           3           4
 ref =            4

      

It seems that the compiler is forcing the pointer to point to a contiguous subsection, although I point to indices first 1:2

, but the compiler only points to 4:4

. As a result, my pointer at the end only points to one record.

I can pack the records (/1,2,4/)

into another array and then use it contiguously, but that won't be efficient Fortrans coding for a large dataset. Do you know how to do it?

+3


source to share


2 answers


Following the suggestion by "@IanH" I have applied a wrapper that has pointers to indices and data and everything is done in PLACE, so this should be more suitable for big data. For a small dataset, I think the idea of ​​"vector indexing" "Vladimir F" is better and readable. The following code passed valgrind full memleak validation and I tried to use a large dataset (double precision 6GB) and it does not copy data.

module any_stride
  implicit none
  private
  ! ------------------------------------------------------------
  ! data = pointer to the contiguous 1D double precision array
  ! indx = pointer to the non-uniform indices
  ! example: for a stride where: 
  ! stride%data => (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
  ! stride%indx => (/ 1, 4 /)
  ! is a wrapper around 1d data array with four elements
  ! that only elements 1 and 4 are visible to the outside world  
  !
  type stride
     private
     real*8, dimension(:), pointer, public :: data => null()
     integer, dimension(:), pointer, public :: indx => null()
   contains
     procedure :: assgn_from_scalar
     procedure :: assgn_from_array
     ! ... 
     ! ...
     ! ... add more overloaded procs if you want 
     generic :: assignment(=) => assgn_from_scalar &
          , assgn_from_array
     generic :: operator(+) => add_to_scalar &
          , add_to_array
     ! ... 
     ! ...
     ! ... add more overloaded procs if you want 
  end type stride

  public :: stride

contains

   subroutine assgn_from_scalar(this, rhs)
    implicit none
    class(stride), intent(inout) :: this
    real*8, intent(in) :: rhs

    ! local vars
    integer :: i

    do i = 1, size(this%indx)
       this%data(this%indx(i)) = rhs
    end do

    ! done here
  end subroutine assgn_from_scalar

  subroutine assgn_from_array(this, rhs)
    implicit none
    class(stride), intent(inout) :: this
    real*8, dimension(:), intent(in) :: rhs

    ! local vars
    integer :: i

    do i = 1, size(this%indx)
       this%data(this%indx(i)) = rhs(i)
    end do

    ! done here
  end subroutine assgn_from_array


  function add_to_scalar(lhs, rhs)
    implicit none
    class(stride), intent(in), target :: lhs
    real*8, intent(in) :: rhs
    class(stride), pointer :: add_to_scalar

    ! local vars
    integer :: i

    do i = 1, size(lhs%indx)
       lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs
    end do

    add_to_scalar => lhs

    ! done here
  end function add_to_scalar

  function add_to_array(lhs, rhs)
    implicit none
    class(stride), intent(in), target :: lhs
    real*8, dimension(:), intent(in) :: rhs
    class(stride), pointer :: add_to_array

    ! local vars
    integer :: i

    do i = 1, size(lhs%indx)
       lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs(i)
    end do

    add_to_array => lhs

    ! done here
  end function add_to_array

end module any_stride

! a little tester program
!
! COMMENT and UNCOMMENT after this line 
! when using the module in this file
!
program test
  use any_stride
  implicit none

  ! local vars
  integer :: i
  real*8, dimension(4), target :: data
  real*8, dimension(2) :: rhs = (/ 3.0d0, 6.0d0 /)
  integer, dimension(2), target :: indx
  type(stride) :: astride

  data = (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
  indx = (/ 1, 4 /)
  astride = stride(data, indx)


  astride = astride + rhs
  print *, 'astride data= ', astride%data

  ! done here
end program test

      



values ​​1 and 4 are added only to the first and last data record of the array.

0


source


Pointer assignments have so-called border overrides. An "integer" pointer object is assigned by a pointer, but it is given the bounds specified in parentheses on the left side. This allows you to have a different lower bound than one and have a pointer rank different from the target. This function is similar to the capabilities you have with the association of array arguments when the dummy array is an explicit or intended size.

You don't have a pointer to arbitrary elements of the target array - the elements in the target must be "regular" - have a constant spacing between them.



As an alternative to repackaging, you can obviously store these indices in an array, and use a combination of the target and that array of indices to get the desired behavior, perhaps by wrapping the pointer over the entire target and the array of indices in a derived type with specific assignments.

+5


source







All Articles