Arrays
February 2020
Back to index.html.
Arrays
Use of 1-dimensional array
Array basics
Small examples
Fortran can manage a set of variables by a single name. In other words, a single object can have multiple variables with the same type. This object is called array, and each variable in the array is element. The array is often explained as a 1-dimensional structure with multiple variables.
This structure is useful to define a vector that has multiple elements. The array is not exclusively used in the vector. It is useful whenever you need multiple (possibly many) variables.
The following program defines an integer array with 3 elements and assigns a value to each element. Equivalently, you can see it as a vector with 3 elements.
program arr
implicit none
integer :: vec(3)
vec(1) = 32
vec(2) = 128
vec(3) = -1024
print *,vec
end program arr
32 128 -1024
You can see the essential feature of an array in this example.
- An array holds a sequence of the same type of elements.
- The declaration of an array is the same as a single variable except with the size of the array in
()
. - You can access each element by a subscript (i.e., index). The subscript is an integer number, starting from 1, and it is enclosed with
()
. - Each element can be treated as a single variable.
- The array elements are operated collectively in
print
.
The subscript 3
in the above example means the number of elements and the last subscript (index) because the subscript starts from 1. You may feel uncomfortable of this system if you like C or Python which has the 0-origin subscript. Fortran is a language of 1-origin subscript, and it is useful to describe mathematical algorithms.
When an array is declared, its elements are not defined. So, we do not expect that a just-declared array has particular numbers. It is the same as a variable, and the programmer is responsible for assigning some values to the array before using it.
Contrary to R or Python, in Fortran, the array holds only a particular type of data declared in the program. In the above example, integer::vec(3)
can contain only integer numbers. With this limitation, Fortran can efficiently manipulate the arrays.
It is still possible to develop a system in Fortran to hold the various data types in a single array in Fortran (like data.frame
in R) if you develop it from scratch (or look for existing programs to do this). Or, you just avoid to deal with such a flexible array at a time, look for a workaround to use simple arrays. For example, if you should hold both characters and numbers, you can replace all the characters with sequential integer code, and all the information is represented as numbers.
Another way of declaration
There is another way to declare an array: the dimension
attribute. The following piece of program is equivalent to integer::vec(3)
.
program arr
implicit none
integer,dimension(3) :: vec
end program arr
In my personal opinion, this style is less intuitive than vec(3)
to declare a 3-element array. I will not use dimension
in the following sections.
Arbitrary subscript
You can use any range of subscript in the array. The range should be declared as (stard index:end index)
in the declaration statement. You can not use real numbers a subscript in the array. For example, the following program supports the range \(-1\) to \(2\) for the array.
program arr
implicit none
integer :: vec(-1:2)
vec(-1) = 32
vec(0) = 128
vec(1) = -1024
vec(2) = 12345
print *,vec
end program arr
Using this feature, you can create a 0-origin subscript easily. Nevertheless, you should not abuse this feature because of a lack of readability.
Array section (sub-array)
You can extract a section of an array and use it as a separate array, like a section of characters. The following program shows only the 2nd and the 3rd elements.
program arr
implicit none
integer :: vec(3)
read *,vec
print *,vec(2:3)
end program arr
The sub-array is defined with a range, (start index:end index)
, instead of a single subscript. In the above case, it shows only the elements 2 and 3. The index system is very similar to for characters.
Assignment to array
Literal arrays
There are several options to assign literal values to an array. The easiest way is to put a single value to each element, as shown in the previous example. Another way assigns multiple literal-values to the array at the same time. The following program has the same results as the previous one.
program arr
implicit none
integer :: vec(3)
vec = [32, 128, -1024]
print *,vec
end program arr
The multiple literals are encircled with [
and ]
, and its number of elements should be the same as the array variable. Similar to a single variable, the initialization can be done in the declaration statement.
program arr
implicit none
integer :: vec(3) = [32, 128, -1024]
print *,vec
end program arr
When assigning multiple-literals, you have to check the size of the data. For example, the following statement fails.
vec(3) = [32, 128, -1024]
The brackets [
and ]
to define an array was introduced in Fortran 2003. Traditionally, a combination of a slash symbol and parentheses, (/
and /)
, was used (and is still used). The above code looks like this using the traditional symbols.
vec = (/32, 128, -1024/)
Literal scalar
When you assign a scalar to an array, all elements of the array are the scalar value. It is useful to initialize an array with a particular value.
program arr
implicit none
integer :: vec(3)
vec = 0
print *,vec
end program arr
0 0 0
Substitution
If you have two arrays with the same size, you can directly substitute one to another.
program arr
implicit none
integer :: a(3),b(3)
a = [1,2,3]
b = a
end program arr
If the arrays have different sizes, the compiler may fail (or, it passes, but the executable may fail in run time).
Reading from keyboard
The multiple values can also be from the keyboard with the read
statement. It reads multiple values at the same time as multiple variables are specified.
program arr
implicit none
integer :: vec(3)
read *,vec
print *,vec
end program arr
Unknown size of an array
In many cases, the size of the vector (array) is unknown at the beginning of the program, but it will be determined in the program. Fortran has an allocatable array which size is not defined in the declaration statement but fixed in the program. The following example is for an allocatable array.
program arr
implicit none
integer,allocatable :: vec(:)
integer :: n
n = 5
allocate(vec(n))
read *,vec
print *,vec
deallocate(vec)
end program arr
You can see the usage of allocatable arrays.
- The declaration of allocatable arrays is the same as the fixed-length array except for
allocatable
with the range as(:)
. - To fix the size, use the
allocatable
statement asallocate(variable(size))
. - The allocated array can be used in the same way as a fixed-length array.
- After using the allocated array, the
deallocate
statement releases the storage of the array. It is not needed if you do not resize this array with a different size.
Precisely, allocate
reserves the storage in memory and assign it to the array. If the memory requirement is too large, the program stops with an error. If successful, the array is tied with the allocated memory with the specified size. The deallocate
statement releases the allocated memory, and the status of an array is back to non-allocated. If you want to resize the array, you have to deallocate it once, then call allocate
with the new size (it was relaxed in Fortran 2003, see the later chapter). When the program stops, regardless of normal end or error stop, all the allocated arrays will be automatically deallocated, so you should not be concerned about the arrays.
The allocated array initially has nonsense values i.e., uninitialized. The initialization of the array is the responsibility of the programmer.
There is an intrinsic function to test if an allocatable array has already allocated or not.
Function | Description | Example |
---|---|---|
allocated() |
.true. if an allocatable array is allocated |
allocated(x) |
Summary
- An array is a collective object of variables.
- An array is defined with the variable name followed by the range of subscripts
(start:end)
in the declaration statement. - An arbitrary range of subscripts can be defined.
- Multiple values can be assigned to an array using
[ ]
, or equivalently(/ /)
. - An array-section is available as the variable name followed by
(start:end)
. - When the size of the array is unknown, an allocatable array should be declared with
allocatable
and(:)
in the declaration. Useallocate
to define the size anddeallocate
to release the storage. - An intrinsic function,
allocated()
, returns.true.
if the allocatable array is allocated.
Exercises
- Define
integer,parameter::n=5
and use it to specify the size of an array. See if it works when the definition ofn
is changed tointeger::n=5
is used. - Define a real array with 5 elements, read the values from a keyboard, swap between 1st and the 3rd elements, and between 2nd and 4th elements, then print all the elements.
- Create a program to read an integer \(n\), allocate an array with \(n\) elements, read the values to this array, and print the values.
Array operations
Array arithmetic
One of the advantages of using arrays is to make array operations much more straightforward than a single scalar variable. Primarily if you treat an array as a vector, the vector operation is simply written like a mathematical formula. The following program calculates a sum of two vectors (i.e. \(\mathbf{c}=\mathbf{a}+\mathbf{b}\)).
program arr
implicit none
integer :: a(3),b(3),c(3)
a = [1,2,3]
b = [4,5,6]
c = a + b
print *,c
end program arr
5 7 9
The arithmetic operators such as +
, -
, *
, /
, and **
perform element-by-element operations for arrays. Note that *
does not mean the matrix multiplication but the element-by-element multiplication.
When the operation involves both array and scalar, the scalar will be broadcasted to all the elements in the array. See the following example.
program arr
implicit none
integer :: a(3)
a = [1,2,3]
print *,a+5
end program arr
6 7 8
By the way, the above code may secretly allocate a temporary array to store the result of a+5
as a single variable. In the current computers, it should not be a performance bottleneck.
Elemental functions
The element-wise operation is also applied in mathematical functions. For example, sin(x)
for the array x
returns the array with the sine of each element in x
. The size of the return value is the array with the same size as input.
program arr
implicit none
real :: x(3)
x = [1.0, 1.1, 1.2]
print *,sin(x)
end program arr
Such elemental functions include sin
, cos
, tan
, log
, exp
, abs
, sqrt
, and so on.
Logical array
As the arithmetic operations and elemental functions, the logical operations can be applied to an array, and the result is also the array with the same size as input. The following example shows that the resulting array can be logical
and stored in an array.
program arr
implicit none
real :: x(3)
logical :: status(3)
x = [1.0, 1.1, 1.2]
print *,x<=1.1 ! determine in each element
status = x<=1.1 ! can be saved to a logical array
print *,status
end program arr
T T F
T T F
Array functions
Fortran has many functions to summarize or to inquire about an array. A typical function is sum(a)
which computes the summation of elements in the array a
. The function size(a)
returns the size (the number of elements) of an array. The following table shows some useful functions.
Function | Effect |
---|---|
size(x) |
the size of x |
sum(x) |
the sum of all elements |
minval(x) |
the minimum value in x |
maxval(x) |
the maximum value in x |
minloc(x) |
the location of the minimum value |
maxloc(x) |
the location of the maximum value |
dot_product(x,y) |
the sum of square i.e. \(\mathbf{x}'\mathbf{y}\) |
count(a) |
the number of .true. in the logical array a |
all(a) |
.true. if all elements in logical a is true |
any(a) |
.true. if any elements in logical a is true |
Most of the above functions can accept a mask vector, as a second argument with a mask=
identifier, defining which elements are involved in the computation. The mask vector is logical, and it has the same size as the input vector. If an element of the mask is .true.
, the corresponding input is used, and if .false.
, the corresponding input is ignored.
For example, the following example computes the sum of an array using only positive numbers.
program arr
implicit none
real :: x(3)
logical :: status(3)
x = [1.0, -2.0, 3.0]
print *,sum(x,x>0.0)
! equivalent
status = x>0
print *,sum(x,mask=status)
end program arr
Summary
- Basic arithmetics and mathematical functions can be applied to each element.
- The multiplication between arrays (
*
) performs element-by-element. - A scalar will be broadcasted to all elements through arithmetic operations.
- Many array functions are available.
Exercises
- See what happens when incompatible sized arrays are involved in an arithmetic operation.
- Read 5-element integer array and compute the average of the values.
- Modify the above program to compute the average only from positive input values.
- Compute the standard deviation of a given real array.
- Compute the figure-skating average of a real array. This average is calculated from the data in which the highest and the lowest values have been discarded.
Multi-dimensional array
2-dimensional array
Fortran can take care of higher dimensional arrays. The 2-dimensional array is often used as a matrix (and the 1-dimensional array is for a vector). Fortran is designed to efficiently manipulate the arrays (i.e., vectors and matrices). Here we deal only with the 2-dimensional array. See the other textbooks for details of higher-order arrays.
The higher-dimensional array has the same usage as the 1-dimensional array in deceleration, array functions, subarrays, allocation, and so forth. The only difference is the subscript (index) to specify the element. We will look at the basic features of a 2-dimensional array in the next sections.
Decrelation
The following code defines a \(2 \times 2\) array (matrix), and each of4 elements has a value.
program arr
implicit none
integer :: mat(2,2)
mat(1,1) = 10
mat(1,2) = 20
mat(2,1) = 30
mat(2,2) = 40
print *,mat
end program arr
10 30 20 40
The above array defines the following matrix. \[
\left[
\begin{array}{cc}
10&20 \\
30&40
\end{array}
\right]
\] The usage of 2-dimensional array is similar to a vector except for subscripts (indices). The matrix has 2 indices in ()
separated by a comma. The first index is for ow, the second is for column same as the mathematical notation like \(A_{ij}\) where \(i\) is for row and \(j\) is for a column.
- The declaration of the array is the same as a single variable with the size of the array in
()
as(row, column)
. - You can access each element by a subscript (i.e., index). The subscript is an integer number, starting from 1, and it is enclosed with
()
. - Each element can be treated as a single variable.
- The array elements are operated collectively in
print
.
The multi-dimensional array can be defined with dimension
. We will not use this method in this tutorial.
integer,dimention(2,2) :: mat
Order in memory
In the previous example, you may notice that the order of elements in output is not intuitive. A computer should rearrange the multi-dimensional data into a 1-dimensional structure in memory. In Fortran, the 2-dimensional array is treated as a collection of column vectors (so-called the column-major storage).
\[ \left[ \begin{array}{c|c} 10&20 \\ 30&40 \end{array} \right] \rightarrow \left[ \begin{array}{c} 10\\ 30\\ \hline 20\\ 40 \end{array} \right] \]
This rearrangement (column-major) is reasonable in mathematics; R is also using this order. However, it is different from C and some other languages (row-major), and when you come from such languages, please be careful about the array rearrangement in memory.
The order becomes an issue when you read a matrix from the keyboard.
program arr
implicit none
integer :: mat(2,2)
read *,mat
print *,mat
end program arr
If you type 1 2 3 4
in terminal, the matrix will be as follows. \[
\left[
\begin{array}{cc}
1&3 \\
2&4
\end{array}
\right]
\]
If you want to access the matrix along with rows, you have to write loops (see exercises).
Inquery functions for array shape
Fortran has several functions to get the size of an array.
Function | Effect | Return value |
---|---|---|
size(x) |
the size of x |
the number of all elements in x |
shape(x) |
the dimention of x |
a vector with the length of the dimention |
For example, using the \(2 \times 3\) matrix, the above functions return the following values.
program arr
implicit none
integer :: a(2,3)
print *,size(a)
print *,shape(a)
end program arr
size(a)
returns6
(scalar).shape(a)
returns[2,3]
(vector).
The size
function can get the number of elements in a row (or column) as scalar using the 2nd parameter.
program arr
implicit none
integer :: a(2,3)
print *,size(a,1) ! dimension 1 = elements within column
print *,size(a,2) ! dimension 2 = elements within row
print *,size(a) ! all elements
end program arr
2
3
6
Assignment to array
Literals
The assignment of literal values to a 2-dimensional array (hereafter a matrix) is not straightforward because we have to consider the dimension. There are several ways to assign values to a matrix. In the following example, we try to have the following \(2 \times 2\) matrix.
\[ \left[ \begin{array}{cc} 10&20 \\ 30&40 \end{array} \right] \]
The Fortran program shows 3 different ways to do it.
program arr
implicit none
integer :: mat(2,2)
! method 1
mat(1,1:2) = [10, 20]
mat(2,1:2) = [30, 40]
! method 2
mat(1:2,1) = [10, 30]
mat(1:2,2) = [20, 40]
! method 3
mat = reshape([10,30,20,40],shape(mat))
end program arr
The first method substitute rows to the matrix. The second is the same way as first but in a column-wise manner. The third uses the reshape
function, which rearranges a vector to fit the matrix with a given shape. Using reshape
, you should consider the column-major order of elements to be aligned in the matrix.
Function | Effect | Return value |
---|---|---|
reshape(x,s) |
rearrange x with shape s |
rearranged array |
The 3rd method is the same as reshape([10,30,20,40],[2,2])
instead of using shape(mat)
.
Other values
You can assign a scalar to an array so that all the elements have the same value. It is useful to initialize an array. You can also assign a (sub)array to another array.
! for exercise 1
program arr
implicit none
integer :: a(3,3),b(2,2)
a = reshape([1,2,3,4,5,6,7,8,9],shape(a))
b = 0
b = a(2:3,1:2)
end program arr
Computations
Element-by-element operations
As 1-dimensional arrays, higher-dimensional arrays can be involved in simple arithmetic such as +
and *
. Also, most of the mathematical functions like log()
can be applied to all elements at the same time.
! for exercise 2
program arr
implicit none
integer :: a(2,2),b(2,2),c(2,2)
a = reshape([1,2,3,4],shape(a))
b = reshape([5,6,7,8],shape(b))
! element-by-element product
c = a * b
print *,c
end program arr
Matrix multiplication and manipulation
In Fortran, the function for matrix multiplication matmul
is available by default. It accepts 2 arrays, and compute the product, and return the result as a matrix. If the size of matrices is unconformable, the compilation fails, or the program fails in run time (or returns wrong results). See the following example.
program arr
implicit none
integer :: a(2,2),b(2,2),c(2,2)
a = reshape([1,2,3,4],shape(a))
b = reshape([5,6,7,8],shape(b))
! matrix multiplication
c = matmul(a,b)
print *,c
end program arr
The function transpose
gives you a transposed matrix.
program arr
implicit none
integer :: a(2,2),b(2,2),c(2,2)
a = reshape([1,2,3,4],shape(a))
b = reshape([5,6,7,8],shape(b))
! matrix multiplication
c = matmul(a,transpose(b))
print *,c
end program arr
Array functions
You can apply array functions to a particular dimension of an array using the second argument. For example, given a(2,2)
, you can compute the sum of elements by column (along rows) as sum(a,1)
. With this, the function returns a vector containing all results for rows (or columns).
! for exercise 3
program arr
implicit none
integer :: a(2,2)
a = reshape([1,2,3,4],shape(a))
print *,sum(a)
print *,sum(a,1)
print *,sum(a,2)
end program arr
Summary
- A 1-dimensional array represents a vector, and 2-dimensional array, a matrix.
- A 2-dimensional array (matrix) is a collection of 1-dimensional arrays (vectors).
- To access an element of a 2-dimensional array, use 2 indices in
()
; row the first and column the second. - For a matrix, you can use the same arithmetics rules and functions as a vector.
- Use
matmul()
for matrix multiplication;*
performs element-by-element operations. - The transposed matrix is available by
transpose()
. - An array function can be applied to a particular dimension (i.e., row-wise or column-wise).
Exercises
See the above code.
- What does
b
have? Why do we needb=0
? - What does
c
have? How do you compute the square root of each element inc
? - What will be shown?
- Write a program to show a matrix in row-wise (as in mathematical formula).
Back to index.html.