Silverfrost Forums

Welcome to our forums

PACK function

6 Mar 2021 11:49 #27213

Hello,

I have a large one-dimensional array consisting of about 2000 elements, most of them has ZERO values and only small part of them contains NON-zero value: I need to extract from it the NON-zero values only.

So, I used the PACK function with mask as follows:

...
INTEGER, ALLOCATABLE :: D(:)
...

IF (.not. ALLOCATED (D)) ALLOCATE (D(en))

d=pack(up,mask=up.ne.0)

....

The number of non-zero elements (en) is found in a procedure preceding the call to the PACK function.

Basically, the PACK function works fine and I get the array D(en) with non-zero values only, which becomes then an one-dimensional array with 20 non-zero values only.

If I create a release EXE version - it runs (apart from a problem with DRAW_POLYLINED@ which does not join the lines).

However, when I check the /UNDEF option for debugging and run the debug process - the debugger says:

RUN-TIME error 112. Reference to undefined variable, array element or function result (/UNDEF) and points to the newly created one-dimensional array with 20 elements (array named UP in the code above).

My question is: when I use the PACK function, it creates a new array of the same dimension (one dimension with 20 non-zero elements in my case) and the rest zero elements are disregarded (I suppose so) or not and still keeps the information about the original input array (in my case - one-dimensional array named UP with 2000 elements)?

Thanks!

Martin

6 Mar 2021 12:21 #27215

Martin

Can you demonstrate the runtime error in a short program and post it here?

6 Mar 2021 7:45 #27217

Paul,

here is the link to download main program and the module along with the input data file: https://www.dropbox.com/h?preview=TEST_PACK_FUNCTION.zip

I also included two JPG screen shots, one with RUN-TIME error message and the other one with a look in compiler options in my PLATO test project for this purpose.

I repeat once again, when I uncheck the option CHECK FOR UNDEFINED VARIABLES, the program runs problem free both in RELEASE/X64 and DEBUG/X64 (the results are output to the screen and are correct). As soon as I check the above mentioned option, the program crashes in both variants (release and debug).

I think, when this will be explained, where I am wrong, it could have the connection to my problem with DRAW_POLYLINED@.

DO not forget to setup the option UNICODE UTF8 without signature, when you load in both files into a PLATO project. The OC_points.TXT file with the input data is also attached to test the problem on real data.

6 Mar 2021 8:55 #27218

Something went wrong with the previous link - here is once again:

https://www.dropbox.com/s/etoj5vrfjsxrv9r/TEST_PACK_FUNCTION.zip?dl=0

7 Mar 2021 5:02 #27220

The use of PACK in Fortran 90/95 has some limitations, as there is no report of the extent of D that has been used.

for your statement: d=pack(up,mask=up.ne.0)

What part of D has been initialised ? Also, was UP initialised ?

It is probably easier not to use PACK and just keep a list of active points as they are reviewed.

In F03, using PACK with auto-allocate, it works much better using: INTEGER, ALLOCATABLE :: D(:) D=pack(up,mask=up.ne.0) ; num = size (D)

Imagine the problems if UP was real !!

7 Mar 2021 9:25 #27223

Thanks John.

I initialised neither D nor UP. Now, I did so (all elements of both arrays are after initialising equal zero), but the symptoms are the same (when CHECK FOR UNDEFINED VARIABLE is active, program crashes, without this checking, program runs fine).

7 Mar 2021 12:22 #27229

Paul,

I think there may be an issue with allocate on assignment for logical arrays. The following code does not behave as expected:

program t
implicit none
integer, parameter :: dp=kind(1.d0)
integer, parameter :: n = 20
real(kind=dp) a(1:n)
logical, allocatable :: mask(:)
real(kind=dp), allocatable :: copy_a(:)

integer i, counter

a = 0.d0
do i = 1, n, 5
  call random_number(a(i))
end do

do i = 1, n ; print*, i, a(i) ; end do

counter = 0
do i = 1, n
  if ( a(i) .ne. 0.d0) counter = counter + 1
end do
print*
print*, 'No of non-zero entries ', counter

mask = (a .ne. 0.d0)   !Allocate mask on assignment
print*
print*, 'Size of auto-allocated mask array', size(mask)   

copy_a = a
print*
print*, 'Size of auto-allocated copy of a', size(copy_a)
end program t

!Size(mask):-
!Checkmate + Win32 returns 0
!Release   + Win32 fails on access violation
!Checkmate + x64 returns 0
!Release   + x64 fails on access violation
!
!Alternative compiler returns 20 as expected.

This may be relevant to the issue that Martin is experiencing.

PS Curiosity got the better of me. It appears there are issues with allocate on assignment for complex arrays:-

program t
implicit none
integer, parameter :: dp=kind(1.d0)
complex(kind=dp) :: mat(1:3,1:3)
complex(kind=dp), allocatable :: mat_c(:,:)
integer i

!Create matrix with j on main diagonal, zero otherwise
mat = 0.d0
do i = 1, 3, 1
  mat(i,i) = cmplx(0.d0,1.d0,kind=dp) 
end do

print*, mat

mat_c = mat

print*
print*, mat_c

end program t

! Checkmate + Win32  'Nonconformant arrays'
! Release + Win32    Process hangs
! Checkmate + X64    'Nonconformant arrays'
! Release + X64      OK
7 Mar 2021 2:09 #27231

Martin

John has pointed out that the arrays must be initialised. Also D must have the right number of elements.

en has the correct value which is COUNT(up.ne.0) but this must be the current size of D. So you could write...

     IF(ALLOCATED(D)) DEALLOCATE(D)
     ALLOCATE (D(en))
     D = 0
7 Mar 2021 2:27 #27232

Ken

Thank you for the feedback. I have made a note of that allocate on assignment does not work in these cases.

7 Mar 2021 3:22 #27235

Thanks guys for your comments.

Paul,

I did exactly what John said:

IF (.not. ALLOCATED (D)) ALLOCATE (D(en))
D(en)=0

print*,d
pause

d=pack(up,mask=up.ne.0)

The same I did for the UP(K).

The result can be seen here (in yellow are the D(en) values after initialisation. Their number is correct and also - after executing the PACK commad (last three lines in the picture below), the number of D(en) values is correct and filled up with correct values.

https://i.postimg.cc/gJ8s8khH/INIT.jpg

Nevertheless, it does not help, the symptoms remain the same (program crashes when using /UNDEF option).

An additional observation: Originally, I used for initialisation the commands UP = 0 and D = 0.

When I run the program after such initialisation, when I want to print the values UP(k) and D(en), it displays only the UP values and exits automatically, although after every initialisation I use the PAUSE command. It also should display D values. It displays them (the initialised D values) for a second and program ends automattically, although I also used the PAUSE command after the PACK function, when it is executed.

Therefore I used UP(K) = 0 and D(en) = 0, instead of UP = 0 and D = 0.

7 Mar 2021 4:07 #27236

Martin

It works for me but with the changes that I have recommended.

UP(K) = 0 sets just one element to zero whilst UP = 0 sets all the array values to zero.

Also the array D must be the right size which is why I have suggested that you you deallocate D and re-allocate to the current size.

7 Mar 2021 4:08 #27237

I forgot to mention that I also used the Paul“s alternative:

IF (ALLOCATED (D)) DEALLOCATE (D)
ALLOCATE (D(en))

D(en)=0

All results and behaviour are exactly the same as in my alternative:

IF (.not. ALLOCATED (D)) ALLOCATE (D(en))
D(en)=0 
7 Mar 2021 4:11 #27238

Martin

Our posts may have crossed.

D(en) = 0 is not the same as D = 0.

7 Mar 2021 4:53 #27239

Paul,

here are two 20s videos that demonstrate what I wrote about D = 0 and D(en) =0:

https://www.dropbox.com/s/d4bdgz81hd9by5f/videos.zip?dl=0

Simply, when I use D=0, program ignores the PAUSE command located immediately after initialisation D=0 and PRINT*,D command

IF (ALLOCATED (D)) DEALLOCATE (D)
ALLOCATE (D(en))
D=0
print*,d
pause

d=pack(up,mask=up.ne.0) ! to select ONLY the points with NON-ZERO values

print*,'Now - below - follows D(en) array correctly filled up with correct NON-ZERO values:'
print*,d
pause

and neither displays the PACK results, nor wait for pressing END, simply ends automatically without any intervention.

When I use (D(en) = 0 because D=0 does not work well with me, you say that only one element (which one of 20 elements?) has assigned the ZERO value. But as can be seen in one of my video, after such assignment (D(en) = 0) all 20 elements have assigned ZERO values. Or am I wrong?

Moreover, even when I use your alternative method for allocation with /UNDEF option, program always crashes. Both things are mystery for me.

7 Mar 2021 8:19 #27240

Martin

Try running the debugger SDBG or SDBG64. Set a break point at the point you talk about and then look at the array elements.

7 Mar 2021 10:46 #27241

I did it. The videos can be downloaded here (their play lengths are about 35s): https://www.dropbox.com/s/prz8sck5je7b4a8/debug_videos.zip?dl=0

I am even more confused now.

Couple of observations:

DEBUG/x64:

There are two videos. The first run of debugger/x64 ends with error message: ACCESS VIOLATION AT ADDRESS ... I immediately run it once again and the second run ends with error message: Heap corruption.

I have a variable named BOTTOM and it is initialised as equals ZERO. However, during debug process, when pointing the cursor over it on the line where BOTTOM=0 is declared, the debugger shows the value of 2 for it (this is clearly showed in the second video).

DEBUG/x32: There is one video. During the debugging, the debugger shows for the variable of D array and UPPER variable totally wrong values when pointing the cursor over them during debugging.

I have no idea where is the problem.

8 Mar 2021 4:55 #27246

I ran across a few limitations with PACK.

I found that it is best if one does a COUNT to get the number of elements that will be returned, then use that on the left hand side of the equal to have the number of elements specified more precisely.

I was having (with 32-bit) a crash (sometimes). This little 'trick' cured the problem.

Since what I was doing is not something done repetitively, the additional time to do the COUNT operation was trivial enough. Preventing a crash was priceless!

8 Mar 2021 11:51 #27252

At the beginning I used the COUNT function. But I abandoned it since it does not provide information what I wanted - the COUNT provides me only information, how many different sections of points with the same feature code are available in the input data set (see picture below - the data with the number 20).

https://i.postimg.cc/P5g6j7tq/count-function.jpg

I get this information (how many different sections are available) by using a complex DO LOOP in my program. The function PACK provides me the particular information HOW MANY points with the same feature code
are available within EVERY section, in which the points have the same feature code (see the picture below in yellow).

https://i.postimg.cc/sxwrHhZ5/pack-points.jpg And this is what I need to know for next complex DO LOOPS which differ each other with respect to the numbers provided by PACK. This DO LOOPS has also consequences for next DRAW_POLYLINED@ function, since they (the numbers provided by PACK) determine which section of points are to be joined. The reason for it is to avoid zick-zack joining when using %PL with the option LINK=LINES which also creates unwanted joining (across sections of points, whereas every section should be isolated - it means, not connected by joining its points with the other one).

8 Mar 2021 4:14 #27255

Thanks for the explanation.

I have no help for your issue, sorry!

10 Apr 2021 1:36 #27475

The missing parts of 'allocate on assignment' described above have now been added for the next release of FTN95.

Please login to reply.