I am using online IDE, and seems that none of them supports debugging. If I have a 4D array like below? How can I print all the elements of the array by the element's order in the memory?
Program Hello
integer :: test(2,3,4,5), i1,i2,i3,i4, val;
val = 0
do i1=1,2
do i2=1,3
do i3=1,4
do i4=1,5
test(i1, i2, i3, i4) = val
val = val +1
end do
end do
end do
end do
End Program Hello
Array/matrix memory in fortran is column-ordered, i.e. contiguous elements in memory are those of the leftmost dimension in your array.
You can print the whole one by just sending a print or write command of the whole array.
In this example, first we fill a 1D array with incremental indices; then, reshape them to a 4D array, so you can see how the 4D array items increment the leftmost dimension first:
program test_print
use iso_fortran_env, only: output_unit
implicit none
integer :: test(2,3,4,5), global_index(2*3*4*5)
integer :: i,j,k,l
! Fill 1D array with incremental values
forall(i=1:size(global_index)) global_index(i) = i
! Reshape 1D array to 4D
test = reshape(global_index,[2,3,4,5])
! Print whole array to screen
! Should print 1 2 3 4 5 6 7......
print "(*(1x,i0))", test
! This is same as:
write(output_unit,"(*(1x,i0))") test
end program test_print
After your attempt at loading the array then try:
Test2 = RESHAPE(Test,/120/)
Do I = 1, 120
WRITE… test2
That will reform the array into a linear vector or 1D array, and you can see how the contiguous array is stored.
Related
Is it possible to assign labels for cells in arrays? I am just experimenting with arrays and I was curious if you could label different cells with descriptors. There is a diagram below for the kind of thing I wish to achieve-
Arrays are always indexed with integer indexes.
If the meaning of the rows and columns is constant and known at compile-time, you can have integer constants,that have the desired name and the value of the index, e.g.,
integer, parameter :: Plant1 = 1, Plant2 = 2,...
integer, parameter :: Day1 = 1, Day2 = 2,...
Array(Plant2, Day2) = 92
If this is not constant and and can be different every time you run your program for different data, you could certainly have an array of labels
character(label_len), allocatable :: rows(:)
rows = [character(label_len) :: "Plant 1", "Plant 2",...]
but you cannot use this for indexing. To find out which integer index corresponds to "Plant 2" you would have to search the array. This can be slow.
There is a data structure called dictionary that is used to retrieve such data assigned to character string labels more efficiently (still it takes some time). There are some Fortran implementations at https://fortranwiki.org/fortran/show/Hash+tables and hopefully one will also be developed for stdlib.
Suppose I have an array A in Fortran of dimension 10 with numbers.
However I'm only interested in a subset of those numbers (for example 3).
I store those number in a smaller array B
B(1) = A(1)
B(2) = A(5)
B(3) = A(6)
I can also define a mapping table to store index 1, 5, 6 for example
MAP(1) = 1
MAP(2) = 5
MAP(3) = 6
How can I create an inverse map INVMAP such that
INVMAP(1) = 1
INVMAP(5) = 2
INVMAP(6) = 3
with the constrain that INVMAP has dimension 3 (and not 10).
The point is that the array A is too big to be stored in memory and B
is obtained iteratively (A is never really allocated).
Considerations:
I do not care about the 7 discarded values but I care about the position of the one we keep.
Since MAP and INVMAP are storing positions, there will never be collision (its a one to one correspondence).
Maybe it could be possible with HASH or Fortran table but I'm not really sure how because I'm mapping numbers, not keys. Any idea ?
Thanks a lot,
Sam
Here's a very simple solution. No Fortran on this machine so not entirely sure that I have the syntax absolutely correct. Define a derived type like this:
type :: row
integer :: a_index
integer :: a_value ! I've assumed that your A array contains integers
! use another type if you want to
end type
then
type(row), dimension(100) :: b ! In practice you'll probably want b to be
! allocatable
and
b(1) = (1, a(1)) ! each row of b contains the value at an index into a and
! the index
b(2) = (5, a(5))
b(3) = (6, a(6))
Now your map function is simply, in pseudo-code, map(n) = b(n)%a_index
and your inverse map is, again in pseudo-code, invmap(n) = findloc(b%a_index, n).
Since the inverse map is a simple scan, it might become too time-consuming for your taste when b becomes large. Then I might introduce an auxiliary index array pointing into b at intervals, or I might go crazy and start a binary search of b%a_index.
I can also define a mapping table to store index 1, 5, 6 for example
MAP(1) = 1
MAP(2) = 5
MAP(3) = 6
I don't know if you know, but Fortran has a nice feature (one of my favorites) known as Vector Subscripts. You can pass an 'array of indices' as an index to an array, and get the elements corresponding to each index, like this:
integer :: A(10) = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
integer :: map(3) = [1, 5, 6]
print *, A(map)
! outputs 10 50 60
How can I create an inverse map INVMAP such that
INVMAP(1) = 1
INVMAP(5) = 2
INVMAP(6) = 3
Well, if your INVMAP will have a domain and an image of different sizes, it must be a function, not an array. I mean, INVMAP cannot be an array of length 3 and accept indices from 1 to 6, right? Arrays in Fortran (and in most languages) imply contiguous indices.
The intrinsic function FINDLOC can be pretty handy here (I am asuming your function is bijector).
function invmap(map, ids)
integer :: ids(:), map(:), invmap(size(ids))
invmap = [(findloc(map, i), i = 1, size(ids))]
end
You could use this function to relate each map value to its position on map
integer :: myinvmap = invmap(map, [6, 1, 5])
print *, myinvmap ! outputs 3 1 2
print *, invmap(map, [5]) ! outputs 2
The point is that the array A is too big to be stored in memory and B
is obtained iteratively (A is never really allocated).
Now, if you will never allocate the big array, then its values will also be accessed by some function (you can consider it a function actually). You have basically two options here:
Have two arrays, one with the values got from big_array_function, and one with the parameter you passed to big_array (the indices).
Have one array of pairs [index, value]. It is the answer that #HighPerformanceMark provided.
Alternatively... (and not tested...)
Integer, dimension(100) :: A
Logical, dimension(100) :: A_Mask
Integer, dimension( 3) :: B
Integer, dimension(. 3) :: A_pos
Integer, dimension(. 3) :: I, J
A_Mask = .false.
A_Mask(1) = .true.
A_Mask(1) = .true.
A_Mask(1) = .true.
B = PACK(A, MASK=A_Mask)
J = 0
Collect_Positions: Do I = 1, SIZE(A)
If(.not. A_Mask(I)) CYCLE Collect_Positions
J = J+1
A_Pos(J) = I
ENDDO Collect_Positions
...
And then if one want to UNPACK, then the mask has the position... so it is possible to not worry about the position of A in general sense (but may be needed in the OP's case)
I have an array with multiple dimensions (the goal is to allow for about 100) and each dimension has a size of about 2^10 and I only need to store in it about 1000 double precision coefficients. I don't need to do any operation with this array aside from reading and writing into it. The code is written in Fortran 90.
I assume that if I a library like one of the ones mentioned in this answer I would be able to store the do this, but would this be optimized for the simple reading and writing operations? Is there a library that would be most efficient for that purpose?
Edit: By "simple reading and writing operations" I mean the following. Suppose
REAL(8), DIMENSION(1000) :: coeff1
INTEGER, DIMENSION(1000,5) :: index
I want to define coeff2 to store the values in coeff1 and then read itat the indices in index, that is
DO i = 1,1000
index(i,:) = [something]
coeff1(i) = [another something]
coeff2(index(i,1),index(i,2),index(i,3),index(i,4),index(i,5)) = coeff1(i)
ENDDO
Then, for any i I would like to access the value of
coeff2(index(i,1),index(i,2),index(i,3),index(i,4),index(i,5))
as quickly as possible. Being able to do this fast is what I mean by "efficient".
Since the indices in [something] are at most 2^10 I am currently defining coeff2 as follows:
REAL(8), DIMENSION(2**10,2**10,2**10,2**10,2**10) :: coeff2
but this is too wasteful of memory specially since I need to increase the number of dimensions, now 5, to the order of 100 and most elements of this array are equal to 0. So, another measure of efficiency that is relevant to me is that the memory necessary to store coeff2 should not explode as I increase the number of dimensions.
Well, It's still not totally clear to me the nature of your data and the way you want to use it.
If what you need is indexed data, whose indices are not consecutive,
Sparse matrix can be an answer, and there are many solutions already implemented over the internet (as shown in the link you provided). But maybe it would be overkill for what I think you are trying to do. Maybe a simple datatype could serve your purpose, like this:
program indexed_values
implicit none
type :: indexed
integer :: index
real(8) :: value
end type
integer, parameter :: n_coeffs = 1000
integer, parameter :: n_indices = 5
integer :: i
real(8), dimension(n_coeffs) :: coeff1
integer, dimension(n_coeffs, n_indices) :: index
type(indexed), dimension(n_coeffs, n_indices) :: coeff2
type(indexed) :: var
do i = 1, n_coeffs
index(i, :) = [1, 2, 4, 16, 32] * i ! your calc here
coeff1(i) = real(i * 3, 8) ! more calc here
coeff2(i, :)%index = index(i, :)
coeff2(i, :)%value = coeff1(i)
end do
! that's how you fetch the indices and values by stored position
var = coeff2(500, 2)
print*, var%index, var%value ! outputs: 1000 1500.0
! that's how you fetch a value by its index
print*, fetch_by_index(coeff2(500, :), 1000) ! outputs: 1500.0
contains
real(8) function fetch_by_index(indexed_pairs, index)
type(indexed), dimension(:) :: indexed_pairs
integer, intent(in) :: index
integer :: i
do i=1, size(indexed_pairs)
if(index == indexed_pairs(i)%index) then
fetch_by_index = indexed_pairs(i)%value
return
end if
end do
stop "No value stored for this index"
end
end
The provided function for fetching values by its indices could be improved if your indices will be alwyas stored in ascending order (no need to traverse the whole list to fail). Moreover, if you will assing a constant result of coeff1 to all the indices at each row, you could do even better and just not having a coeff2 array at all, just have coeff1 for values and index for the indices, and correlate them by position.
I want to fill an array with unknown size in fortran90.
This is the equivalent code in MATLAB :
for i=1:10
A[i] = i
end
I know that i can pass the size, but
How can i do this in fortran90 without passing the size of the array. I read that we can use pointers, but i really dont know how to deal with pointers
I understand you want to start adding elements to an array before you know the final size of the array.
As an example, you want to read values from a file until you reach the end of the file, not knowing how many values there are.
There are three ways I can think of:
Create an array of sufficient size, and remember the final value.
integer :: a(200), n
n = 1
do
a(n) = <value>
if (<finished>) exit
n = n + 1
end do
<use a(1:n)>
Create two allocatable arrays, when you reach the end of one, make the other bigger, and swap them:
integer, allocatable :: a(:), tmp(:)
integer :: i, n
n = 8
allocate(a(n))
i = 1
do
if (i > n) then
allocate(tmp(2*n))
tmp(1:n) = a(:)
call move_alloc(tmp, a)
n = n * 2
end if
a(i) = <value>
if (<finished>) exit
i = i + 1
end do
allocate(tmp(i))
tmp(:) = a(1:i)
call move_alloc(tmp, a)
I do no longer recommend this. Pointers can be confusing and create weird and hard-to-debug bugs. But I leave it in for posterity: Create a linked list (here using a stack)
type t_node
integer :: value
type(t_node), pointer :: next => NULL()
end type t_node
type(t_node), pointer :: list, tmp
integer, allocatable :: a(:), i, n
nullify(list)
nullify(tmp)
do
allocate(tmp)
tmp % value = <value>
tmp % next => list
list => tmp
nullify(tmp)
if (<finished>) exit
n = n + 1
end do
allocate(a(n))
do i = n, 1, -1
a(i) = list % value
tmp => list
list => list % next
deallocate(tmp)
end do
The way I read your question, you have a subroutine that needs to fill an array, but that array is of unknown size, and you do not want to pass in the size. So you do NOT want this:
SUBROUTINE FILL( A, N )
INTEGER N
INTEGER A(N)
INTEGER I
DO I=1,N
A(I) = I
END DO
END SUBROUTINE FILL
Instead, you want to get the SIZE of the array:
SUBROUTINE FILL( A )
INTEGER A(:)
INTEGER I
DO I=1,SIZE(A)
A(I) = I
END DO
END SUBROUTINE FILL
Suppose I've a scrambled vector of consecutive integers 1:n, say {3,6,2,1,4,5}. My problem is to find, for each element, the number of elements to its left that are smaller than itself. So I'd like the program to return {0,1,0,0,3,4} for this example. This is what I've written in Fortran:
subroutine iterrank(n,invec,outvec,tempvec)
implicit none
integer :: n, i, currank
integer, dimension(n) :: invec, outvec, tempvec
tempvec = 0
outvec = 0
do i = 1,n
currank = invec(i)
outvec(i) = tempvec(currank)
tempvec(currank:n) = tempvec(currank:n) + 1
end do
return
end subroutine
It takes a temporary array (vector), and for each digit d the loop comes across, it adds 1 to every element beyond position d in the temporary vector. The next iteration then takes the appropriate element in the temporary vector as the count of elements smaller than itself. My questions are:
1) I believe this is of complexity O(n^2), since there are O(n) writes to the temporary vector in each iteration of the loop. Am I correct?
2) Is there a more efficient way of doing this for large n (say, >100k)?
I believe this would be more efficient, and you could also reduce the temporary integer array to a single byte.
subroutine iterrank(n,invec,outvec,tempvec)
implicit none
integer :: n, i, currank
integer, dimension(n) :: invec, outvec, tempvec
tempvec = 0
!outvec = 0 ! no need to initialize something overwritten below
do i = 1 , n
currank = invec(i)
outvec(i) = sum( tempvec(1:currank) )
tempvec(currank) = 1
end do
end subroutine
The gain is that you are only writing twice per index, however you are reading elements a maximum of n*n times.
EDIT:
I haven't tried this, but it should do less reads, with a possible overhead of branching. It is possibly faster for extremely large arrays, I would however expect it to be slower for short arrays:
subroutine iterrank(n,invec,outvec,tempvec)
implicit none
integer :: n, i, currank, prevrank
integer, dimension(n) :: invec, outvec, tempvec
tempvec = 0
outvec(1) = 0
tempvec(invec(1)) = 1
do i = 2 , n
prevrank = invec(i-1)
currank = invec(i)
if ( abs(prevrank-currank) > currank ) then
outvec(i) = sum( tempvec(1:currank) )
else if ( prevrank < currank ) then
outvec(i) = outvec(i-1) + sum( tempvec(prevrank:currank) )
else
outvec(i) = outvec(i-1) - sum( tempvec(currank:prevrank-1) )
end if
tempvec(currank) = 1
end do
end subroutine iterrank
Complete rewrite of the answer. If the memory is not a concern, you can add another vector and use an algorithm like the one bellow. The additional vector is used to compute the permutation. Thanks to the fact that the original vector is a permutation of integer 1 to n, the permutation is computed in O(n). with vectors of size 100k on my computer, this algorithm runs in 1.9 sec in average (100 runs) and the initial proposition of zeroth is 2.8 sec in average. I suggested this solution simply because zeroth said he did not test his new solution, you will test and use the best one.
subroutine iterrank(n,invec,outvec,tempvec,ord)
implicit none
!
integer :: n, i, currPos, prevPos, currOut, prevOut
integer, dimension(n) :: invec, outvec, tempvec,ord
!
tempvec = 0
do i = 1, n
ord(invec(i)) = i
end do
!
currPos = ord(1)
tempvec(currPos) = 1
currOut = 0
outvec(currPos) = currOut
! last = 0
do i = 2 , n
prevPos = currPos
currPos = ord(i)
!
if(currPos>prevPos)then
currOut = currOut+sum( tempvec(prevPos:currPos) )
else
currOut = sum( tempvec(1:currPos) )
end if
!
outvec(currPos) = currOut
tempvec(currPos) = 1
end do
!
end subroutine iterrank
The down side of this solution is the random access to vectors outvec and tempvec, that does not make the best use of cache and registers. It is possible to solve that and reduce significantly the time, possibly at the expense of additional temporary vectors.