Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

reordering a vector

dboggs
New Contributor I
439 Views

I have a vector, REAL(4)::V(1000). Say that the largest one happens to be V(123). I need to re-order the values so that V begins with the largest, i.e. Vnew(1) = Vold(123)
Vnew(2) = Vold(124)
​;
​Vnew(878) = Vold(1000)
​Vnew(879) = Vold(1)
Vnew(880) = Vold(2)
​:
Vnew(1000) = Vold(122)

That is, the sequence is to remain but the starting point must shift (it is NOT a matter of sorting in numerical order). Of course this can be done in an elementary straightforward manner by creating a copy, say Vaux, reassigning every element in a loop, and then copying Vaux back to V. I suspect there is a better way. Can anyone suggest an optimal algorithm, reducing both the memory required and the execution time?
 

0 Kudos
6 Replies
andrew_4619
Honored Contributor II
439 Views

You could mess with pointers maybe but it isn't that big I would do a couple of block copies and a move_alloc rather than copying everything twice.

    subroutine order
        implicit none 
        integer, parameter :: vsize = 1000
        integer            :: ip1, isz, l1, istat
        real, allocatable  :: V(:), Vtmp(:)
        
        allocate(V(vsize), stat = istat)
        if (istat /= 0) stop 'poo!'
        
        do l1 = 1 , vsize  ! fill V
            V(l1) = 1.0*l1
        enddo
        
        ip1 = 123             ! the pivot point in V
        isz = vsize - ip1 + 1 ! size of the lower chunk
        
        allocate (Vtmp(vsize), stat = istat)
        if (istat /= 0) stop 'poo!'
        
        vtmp(1:isz)       = V(ip1:vsize)
        vtmp(isz+1:vsize) = V(1:ip1-1)
        call move_alloc(Vtmp, V)
    end subroutine order

 

0 Kudos
FortranFan
Honored Contributor II
439 Views

You can simply do the following using the intrinsic CSHIFT

      V = cshift( V, shift=maxloc(V, dim=1)-1 )

Note though MAXLOC returns "a value equal to the first element of MAXLOC .."

CSHIFT is very efficient for rank-one arrays.

0 Kudos
andrew_4619
Honored Contributor II
439 Views

FortranFan wrote:

You can simply do the following using the intrinsic CSHIFT

      V = cshift( V, shift=maxloc(V, dim=1)-1 )

Note though MAXLOC returns "a value equal to the first element of MAXLOC .."

CSHIFT is very efficient for rank-one arrays.

Certainly concise but that would surely create temporaries and data (2?) data copies?

0 Kudos
andrew_4619
Honored Contributor II
439 Views

cshift looks a useful function! Another bit of learning! I would guess that will copy into a temp and then copy the temp back to the original but that isn't really a penalty if the data size is not huge.

0 Kudos
FortranFan
Honored Contributor II
439 Views

andrew_4619 wrote:

.. I would guess that will copy into a temp and then copy the temp back to the original but that isn't really a penalty if the data size is not huge.

With array transformations, one might as well as employ intrinsics as much as possible: if one can do better than Intel Fortran, then bring it up with Intel to improve their implementaton.

0 Kudos
andrew_4619
Honored Contributor II
439 Views

FortranFan wrote:
With array transformations, one might as well as employ intrinsics as much as possible: if one can do better than Intel Fortran, then bring it up with Intel to improve their implementaton.

Yes I agree with that, in a bored moment later in the week I might make some tests for my own amusement and report back if there is anything of interest.

0 Kudos
Reply