I want to store something in 2 dimensional array in my code and later want to scan that array. There are N_{1} rows (number of first indices, say i) in the array. However, for a given value of i, number of j values is not fixed though I know the maximum possible value of j (say that it is N_{2}).
I can of course create array of size (N_{1},N_{2}) to store my data. This, however seems wastage of space because my N_{2} values fluctuate a lot and the total number of elements in my array is also very large. Is is possible to create a 2D array that can have different number of j values depending on i value? Alternatively, even if I could create many-many 1D arrays by a single Fortran command and allocate them properly, that is also OK with me.
As you suggest that the answer to another question, looking at ragged arrays may be what you want, I'll briefly mention a usability extension to that answer (hinted at in comment by Doug Lipinski).
For a base type, representing the variable-length dimension, given by High Performance Mark
type :: vector
integer, dimension(:), allocatable :: elements
end type vector
and a type for an array of those
type :: ragged_array
type(vector), dimension(:), allocatable :: vectors
end type ragged_array
one has the allocation steps
type(ragged_array) :: ragarr
allocate(ragarr%vectors(5))
allocate(ragarr%vectors(1)%elements(3))
! etc.
[Alternatively, one may be tempted to just have an array of type(vector).]
For the usability aspect one could create a structure constructor which does the numerous allocations, or even rely on automatic allocation for the variable length components.
In the latter case, which makes sense if the values, not just the extents, are known at creation.
allocate(ragarr%vectors(5))
ragarr%vectors(1)%elements = [1, 6, 13]
! etc.
For the former case, something like
module ragged
implicit none
type :: vector
integer, dimension(:), allocatable :: elements
end type vector
type :: ragged_array
type(vector), dimension(:), allocatable :: vectors
end type ragged_array
interface ragged_array
module procedure ragged_constructor
end interface ragged_array
contains
function ragged_constructor(sizes) result(ra)
integer, intent(in) :: sizes(:)
type(ragged_array) ra
integer i
allocate(ra%vectors(SIZE(sizes)))
do i=1,SIZE(sizes)
allocate(ra%vectors(i)%elements(sizes(i)))
end do
end function ragged_constructor
end module ragged
program test
use ragged
implicit none
type(ragged_array) :: ra
ra = ragged_array([3,4,6,1,12])
end program
Related
I'm trying to decide which one of these two options would be the best:
subroutine sqtrace( Msize, Matrix, Value )
integer, intent(in) :: Msize
real*8, intent(in) :: Matrix(Msize, Msize)
real*8, intent(out) :: Value
[instructions...]
end subroutine sqtrace
VS
subroutine sqtrace( Matrix, Value )
real*8, intent(in) :: Matrix(:,:)
real*8, intent(out) :: Value
if ( size(Matrix,1) /= size(Matrix,2) ) then
[error case instructions]
end if
[instructions...]
end subroutine sqtrace
I understand that when you compile with warnings, the first case should automatically check at compile time if calls to sqtrace comply with the size indicated. However, I don't know if the compiler can perform those checks when the given arguments are allocatable, for example (more so if such allocation depends on other things that are determined at runtime). The second one requires an explicit interface and has more code (the checks), but would seem to catch more errors.
Which are the advantages/disadvantages of using each and in which cases should one go with one over the other?
First, some terminology. Consider the dummy arguments declared as
real :: a(n) ! An explicit shape array
real :: b(:) ! An assumed shape array
real, allocatable :: c(:) ! A deferred shape array (allocatable)
real, pointer :: d(:) ! A deferred shape array (pointer)
real :: e(*) ! An assumed size array
real :: f(..) ! An assumed rank array/scalar
I won't answer in terms of which is better in a given situation, but will simply detail some of the important characteristics leaving choice, where there is one, to the programmer. Crudely (and incorrectly), many view explicit shape arrays as "Fortran 77" and assumed and deferred shape arrays as "Fortran 90+".
Assumed size and assumed rank arguments are beyond the scope of this question and answer.
Shape:
the shape of an explicit shape array follows its declaration;
the shape of an assumed shape array dummy argument is that of the actual argument;
the shape of a deferred shape dummy argument may be undefined, becoming defined in the procedure, or that of the actual argument.
Contiguousness:
an explicit shape array is simply contiguous;
an assumed shape array dummy argument's contiguousness relates to that of the associated actual argument;
a deferred shape dummy argument may be that of the actual argument, or depending on the procedure's execution.
Restrictions on actual argument:
an actual argument associated with an explicit shape array must have at least as many elements as the dummy argument;
an actual argument associated with an assumed shape array must not itself be assumed size;
an actual argument associated with an assumed or deferred shape array must be of the same rank as the dummy argument.
Interfaces in the calling scope:
if a dummy argument is of assumed or deferred shape, the referencing scope must have accessible an explicit interface for the procedure.
Consider real a(6). This may be an actual argument to the dummies
real b(3)
real c(2,3)
real d(:) ! With an explicit interface available
a(1::2) may be associated with b but as b is contiguous copy-in/copy-out will be involved. Copy-in/copy-out needn't be involved when associated with d, but it may be.
There are plenty of other aspects, but hopefully this is an initial high-level introduction.
In Fortran, is the PARAMETER attribute set at runtime or compilation time?
I was wondering if I can pass in the size the of the array at run time and have this set as PARAMETER.
Can this be done? If so, how? If not, why?
Yes, as repeatedly answered, a named constant (an object with the parameter attribute) must have its initial value "known at compile time". However, as you talk about the size of arrays I'll note something else.
When declaring the shape of an array there are many times when the bounds needn't be given by constant expressions (of which a simple named constant is one example). So, in the main program or a module
implicit none
...
integer, dimension(n) :: array ! Not allowed unless n is a named constant.
end program
the n must be a constant. In many other contexts, though, n need only be a specification expression.
implicit none
integer n
read(*,*) n
block
! n is valid specification expression in the block construct
integer, dimension(n) :: array1
call hello(n)
end block
contains
subroutine hello(n)
integer, intent(in) :: n ! Again, n is a specification expression.
integer, dimension(2*n) :: array2
end subroutine
end program
That is, array1 and array2 are explicit shape automatic objects. For many purposes one doesn't really need a named constant.
Beyond the array size, the following is certainly not allowed, though.
implicit none
integer n, m
read(*,*) n, m
block
! n and m are specifications expression in the block construct
integer(kind=m), dimension(n) :: array ! But the kind needs a constant expression.
...
end block
You need dynamic allocation if the size of your array is to be defined as runtime. All parameter (constants) must be defined as compiling time.
The value of a parameter is set at compile time.
A declaration such as
integer, parameter :: number_of_widgets = numwidge
requires that numwidge be known at compile time, indeed known before it is encountered on the rhs of the declaration.
I would like to create a structure with different type.
for example create a structure that contain integers in one row and "ragged_Array" in the other.
MODULE NewType
TYPE :: vector
INTEGER, DIMENSION(:, :), ALLOCATABLE :: elements
END TYPE vector
TYPE :: ragged_array
TYPE(VECTOR), DIMENSION(:), ALLOCATABLE :: vectors
END TYPE ragged_array
!This part I don't know how to declare :
TYPE::List_RA
TYPE(ragged_array), DIMENSION(:)::ListCont
INTEGER, DIMENSION(:)::listInd
END TYPE List_RA
END MODULE
Thanks a lot !
In Fortran, is the PARAMETER attribute set at runtime or compilation time?
I was wondering if I can pass in the size the of the array at run time and have this set as PARAMETER.
Can this be done? If so, how? If not, why?
Yes, as repeatedly answered, a named constant (an object with the parameter attribute) must have its initial value "known at compile time". However, as you talk about the size of arrays I'll note something else.
When declaring the shape of an array there are many times when the bounds needn't be given by constant expressions (of which a simple named constant is one example). So, in the main program or a module
implicit none
...
integer, dimension(n) :: array ! Not allowed unless n is a named constant.
end program
the n must be a constant. In many other contexts, though, n need only be a specification expression.
implicit none
integer n
read(*,*) n
block
! n is valid specification expression in the block construct
integer, dimension(n) :: array1
call hello(n)
end block
contains
subroutine hello(n)
integer, intent(in) :: n ! Again, n is a specification expression.
integer, dimension(2*n) :: array2
end subroutine
end program
That is, array1 and array2 are explicit shape automatic objects. For many purposes one doesn't really need a named constant.
Beyond the array size, the following is certainly not allowed, though.
implicit none
integer n, m
read(*,*) n, m
block
! n and m are specifications expression in the block construct
integer(kind=m), dimension(n) :: array ! But the kind needs a constant expression.
...
end block
You need dynamic allocation if the size of your array is to be defined as runtime. All parameter (constants) must be defined as compiling time.
The value of a parameter is set at compile time.
A declaration such as
integer, parameter :: number_of_widgets = numwidge
requires that numwidge be known at compile time, indeed known before it is encountered on the rhs of the declaration.
I want to store something in 2 dimensional array in my code and later want to scan that array. There are N_{1} rows (number of first indices, say i) in the array. However, for a given value of i, number of j values is not fixed though I know the maximum possible value of j (say that it is N_{2}).
I can of course create array of size (N_{1},N_{2}) to store my data. This, however seems wastage of space because my N_{2} values fluctuate a lot and the total number of elements in my array is also very large. Is is possible to create a 2D array that can have different number of j values depending on i value? Alternatively, even if I could create many-many 1D arrays by a single Fortran command and allocate them properly, that is also OK with me.
As you suggest that the answer to another question, looking at ragged arrays may be what you want, I'll briefly mention a usability extension to that answer (hinted at in comment by Doug Lipinski).
For a base type, representing the variable-length dimension, given by High Performance Mark
type :: vector
integer, dimension(:), allocatable :: elements
end type vector
and a type for an array of those
type :: ragged_array
type(vector), dimension(:), allocatable :: vectors
end type ragged_array
one has the allocation steps
type(ragged_array) :: ragarr
allocate(ragarr%vectors(5))
allocate(ragarr%vectors(1)%elements(3))
! etc.
[Alternatively, one may be tempted to just have an array of type(vector).]
For the usability aspect one could create a structure constructor which does the numerous allocations, or even rely on automatic allocation for the variable length components.
In the latter case, which makes sense if the values, not just the extents, are known at creation.
allocate(ragarr%vectors(5))
ragarr%vectors(1)%elements = [1, 6, 13]
! etc.
For the former case, something like
module ragged
implicit none
type :: vector
integer, dimension(:), allocatable :: elements
end type vector
type :: ragged_array
type(vector), dimension(:), allocatable :: vectors
end type ragged_array
interface ragged_array
module procedure ragged_constructor
end interface ragged_array
contains
function ragged_constructor(sizes) result(ra)
integer, intent(in) :: sizes(:)
type(ragged_array) ra
integer i
allocate(ra%vectors(SIZE(sizes)))
do i=1,SIZE(sizes)
allocate(ra%vectors(i)%elements(sizes(i)))
end do
end function ragged_constructor
end module ragged
program test
use ragged
implicit none
type(ragged_array) :: ra
ra = ragged_array([3,4,6,1,12])
end program