# 6. Arrays

#### 1. Introduction

An array in f90 is a data structure that is used to store a collection of same-type objects. The general syntax for declaring an array is:

type, DIMENSION( extent ) :: array_name1, array_name2,...

The *type* give above is just the type you would use for any variable (eg real, integer, etc). The DIMENSION is a compulsory keyword. The *extent* is the range of entries/subscripts of the array elements. The general syntax for the element is:

start_integer : end_integer

These integers can be positive, negative or zero. You can neglect to give the first element, and f90 will assume this to take a value of 1. An array element can be referred to your code by the following syntax:

array_name1( integer expression )

where the integer expression can be as simple as an integer, or can be an expression to evaluate such as **i + 1 **, where **i** will be an integer variable.

## Example: |

For example, the array declaration: |

integer, DIMENSION( -2 : 2 ) :: a |

declares an integer array, a, that has 5 elements: a(-2), a(-1), a(0), a(1) and a(2). If you had assigned an integer variable i = 2 , then you could refer to your elements as a(i-4), a(i-3), a(i-2), a(i-1) and a(i) |

**WARNING: **You should always be careful to not address elements that are outside your delclared array - in the above example this would be like trying to access a(-3). If you tried to write something to a(-3) in this example, it would be written to random memory - and that can cause unpredicatable things to happen! (usually your program will crash). Note that if you make an error like this in your code, the compiler will not pick it up - so be careful!

#### 2. Multidimensional arrays

Multidimensional arrays are possible in f90. For example, to store a matrix in f90, you can declare a two-dimensional array, e.g. below is a declaration for a 3 by 3 matrix:

real, DIMENSION( extent_1, extent_2 ) :: matrix_3by3

The first extent gives the range of rows in the matrix, the second extent gives the range of columns in the matrix.

Matrices in f90 in stored are in column-major order , as depicted below.

For example, if you tried to print out your array matrix_3by3 by just typing

print*,matrix_3by3

the elements would appear in output in the order given above.

## Putting it into Practice: |

Code up the statements below to see an example of how to assign values to matrix elements, and to print these elements out in column-major form. |

program myarray implicit none integer :: i,j integer, DIMENSION (1:3, 1:3) :: matrix_3by3 do i = 1, 3 do j = 1, 3 matrix_3by3(i,j) = i*j enddo enddo print*,matrix_3by3 end program myarray |

Compile and run this code. Try writing some variations on this code. |

As you have seen in the above example, you can refer to individual array elements as a specific position (eg, matrix_3by3(1,2) refers to the element in row1, column 2). However, in f90 you can also refer to sub-sections of the array, by giving the range of that subsection.

## Example: |

For example, the following references to matrix_3by3 mean..: |

This refers to the entire first row of the matrix |

matrix_3by3(1,1:3)or matrix_3by3(1,:) |

This refers to the entire second column of the matrix |

matrix_3by3(1:3,2)or matrix_3by3(:,2) |

You can also refer to elements in an array by specifying the *stride*. Unless specified, the stride will always be 1. Say you wanted to take every second element of matrix_3by3 (starting at element one), this could be done by specifying:

matrix_3by3(1::2)or alternatively by typing

matrix_3by3(::2)

#### 3. Array operations

In f90, you can apply whole-array operations. However, if more than one array is to be used in expressions, these arrays (or subsections thereof) must be of the same shape (ie have some number of rows and columns). The operators act on an element-by-element basis

## Example: |

An example of multiplying all elements of matrix_3by3 by a number, 2.5 |

matrix_3by3 = matrix_3by3 * 2.5 |

Initialising each element of matrix_3by3 to be set to 1.0 |

matrix_3by3 = 1.0 |

Example of an algebraic expression involving another matrix (same shape) called matrix_2 |

matrix_3by3 = 3.0 * matrix_3by3 + (matrix_2)**2 |

Example of multiplying 2 matrices. NOTE: this does not correspond with "matrix multiplication"! |

matrix_3by3 = matrix_3by3 * matrix_2 |

In the last example above, the multiplication corresponds to

matrix_3by3(i,j) = matrix_3by3(i,j) * matrix2(i,j)

You can also apply intrinsic maths functions (such as trig functions, etc) to arrays in an element-by-element basis.

#### 4. Array-specific functions

There is much much more to find out about manipulating arrays in f90 - in particular there exist many specific "array functions". Two you might find helpful are the functions **dot_product** (takes inner product of two linear arrays) and **matmul** (takes inner product of two matrices - ie, a "proper" matrix multiplication).

## Putting it into Practice: |

Code up the program below to see an example of how to use these array-specific operators. |

program armanip implicit none integer :: i,j,c integer, DIMENSION(1:3, 1:3) :: matrix_3by3,matrix_2,d integer, DIMENSION(3) :: a,b do i = 1, 3 do j = 1, 3 matrix_3by3(i,j) = i*j matrix_2(i,j) = 1.5 * j * (i+1) enddo enddo ! create vector a from the first row of matrix_3by3 a = matrix_3by3(1,:) ! create vector b from the second row of matrix_2 b = matrix_2(2,:) ! take dot product of these two vectors c = dot_product(a,b) print*,c ! take the real matrix inner product of the two matrices d = matmul(matrix_3by3,matrix_2) print*,d end program armanip |

Compile and run this code. Try writing some variations on this code. |

Given an array with a certain number of elements, you can "re-shape" this array into an array of another shape - eg, to turn a 9-element linear array into a 3by3 matrix

## Putting it into Practice: |

Code up the program below to see how the re-shape functionality works. |

program shape implicit none integer :: i integer, DIMENSION(1:3, 1:3) :: matrix_3by3 integer, DIMENSION(9) :: a ! assign elements of a to be 1 -> 9 a = (/ (i,i=1,9) /) ! reshape this array, a, into a 3by3 matrix matrix_3by3 = reshape ( a, (/ 3,3 /) ) print*,matrix_3by3 end program shape |

Compile and run this code. Try writing some variations on this code. |

#### 5. Allocatable arrays

One final area you may find helpful is that of **allocatable arrays**. Sometimes it's not convenient to have to decide on the size of an array at compile time. You can get flexibility by using an **allocatable arrays** - in this case you declare an array by specifying the rank (how many dimensions) only. You declaration must include the word ** allocatable **. In the body of the code, you must allocate the memory for your array, and once you're done with it, free up that memory by de-allocating that memory.

## Putting it into Practice: |

Code up the program below to see how allocatable arrays work. |

program dynamic implicit none integer :: i,j integer, DIMENSION (:,:), allocatable :: matrix print*,"Please enter the desired dimensions of your matrix" read*,i,j allocate ( matrix(0:i-1,0:j-1) ) matrix = 1.0 print*,matrix deallocate ( matrix ) end program dynamic |

Compile and run this code. Try writing some variations on this code. |