# 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 as`allocate(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. Use`allocate`

to define the size and`deallocate`

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 of`n`

is changed to`integer::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)`

returns`6`

(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 need`b=0`

? - What does
`c`

have? How do you compute the square root of each element in`c`

? - What will be shown?
- Write a program to show a matrix in row-wise (as in mathematical formula).

Back to index.html.