Section: BLAS/LAPACK - Vector Copy#

Adapted from: gjbex/Fortran-MOOC

This program demonstrates copying vectors using BLAS/LAPACK in Fortran.#

The Fortran program copy_test demonstrates the usage of the scopy subroutine, which is typically from the BLAS (Basic Linear Algebra Subprograms) library. The subroutine is used for copying and optionally scaling elements from one vector to another. Here’s a step-by-step explanation of what each part of the program does:

Initialization and Vector Setup#

  1. Vector Initialization:

    • vector1 is initialized with the first ten positive real numbers. This is achieved through an array constructor [ (real(i), i=1, v_size) ], where i runs from 1 to v_size (10).

    • vector2 is another vector of the same size (v_size), intended to be the target for copying elements from vector1.

    • large_vector is a vector twice the size of vector1, used to demonstrate copying with different increments and scaling.

Printing the Original Vector#

  1. Displaying vector1:

    • The program prints the original content of vector1 using a formatted print statement.

Copying Elements with Different Parameters#

  1. First Copy Operation (scopy(size(vector1), vector1, 1, vector2, 1)):

    • Copies the contents of vector1 directly into vector2 without any scaling or skipping elements (both source and destination increments are 1). The result is that vector2 becomes an exact copy of vector1.

  2. Second Copy Operation (scopy(size(vector1), vector1, 1, vector2, 2)):

    • Copies elements from vector1 into vector2 but with a destination increment of 2. This means every second element in vector2 is filled, leaving alternate elements as zero (since vector2 was reset to 0.0 before this operation).

  3. Third Copy Operation (scopy(size(vector1), vector1, 2, vector2, 1)):

    • Copies every second element from vector1 to vector2 with a source increment of 2 and destination increment of 1. This results in vector2 containing every second element of vector1, with remaining positions in vector2 being zero.

  4. Fourth Copy Operation (scopy(size(vector1), vector1, 2, vector2, 2)):

    • Both source and destination increments are set to 2, which means every second element from vector1 is copied to every second position in vector2.

Demonstrating with a Larger Vector#

  1. Fifth Copy Operation (scopy(size(vector1), vector1, 1, large_vector, 2)):

    • Similar to the second copy operation but targets large_vector. Elements from vector1 are placed in every second slot of large_vector.

  2. Sixth Copy Operation with Scaling (scopy(size(vector1), 3.0*vector1, 1, large_vector(2), 2)):

    • This operation is more complex as it involves scaling vector1 by 3.0 and copying into large_vector starting from the second element and skipping every second slot. This demonstrates the ability to combine scaling and non-contiguous memory access in a single operation.

Summary#

The program is a comprehensive demonstration of various capabilities of the scopy subroutine, including element-wise copying with different strides and scaling. Each operation is followed by a print statement to visualize the results of these operations, showcasing how scopy handles different configurations of source and destination vectors. This type of functionality is typically used in numerical and scientific computations where efficient manipulation of large arrays is necessary.

Program Code#

program copy_test
  implicit none
  integer, parameter :: v_size = 10
  integer :: i
  real, dimension(v_size) :: vector1 = [ (real(i), i=1, v_size) ], vector2
  real, dimension(2*v_size) :: large_vector

  interface
    subroutine scopy(n, sx, incx, sy, incy)
      integer :: n, incx, incy
      real, dimension(*) :: sx, sy
    end subroutine scopy
  end interface

  print '(A20, *(F5.1))', 'original: ', vector1
  vector2 = 0.0
  large_vector = 0.0
  call scopy(size(vector1), vector1, 1, vector2, 1)
  print '(A20, *(F5.1))', 'copy N 1 1: ', vector2

  vector2 = 0.0
  call scopy(size(vector1), vector1, 1, vector2, 2)
  print '(A20, *(F5.1))', 'copy N 1 2: ', vector2

  vector2 = 0.0
  call scopy(size(vector1), vector1, 2, vector2, 1)
  print '(A20, *(F5.1))', 'copy N 2 1: ', vector2

  vector2 = 0.0
  call scopy(size(vector1), vector1, 2, vector2, 2)
  print '(A20, *(F5.1))', 'copy N 2 2: ', vector2

  large_vector = 0.0
  call scopy(size(vector1), vector1, 1, large_vector, 2)
  print '(A20, *(F5.1))', 'copy N 1 2: ', large_vector
  call scopy(size(vector1), 3.0*vector1, 1, large_vector(2), 2)
  print '(A20, *(F5.1))', 'shift copy N 1 2: ', large_vector

end program copy_test

The above program is compiled and run using Fortran Package Manager (fpm):

Build the Program using FPM (Fortran Package Manager)#

import os
root_dir = ""
root_dir = os.getcwd()

Since the code makes use of the LAPACK library, the following FPM configuration file (fpm.toml) was used:

name = "Section_BLAS_LAPACK_Copy"

[build]
auto-executables = true
auto-tests = true
auto-examples = true
link = ["blas", "lapack"]

[install]
library = false

[[executable]]
name="Section_BLAS_LAPACK_Copy"
source-dir="app"
main="section_blas_lapack_copy.f90"
code_dir = root_dir + "/" + "Fortran_Code/Section_BLAS_LAPACK_Copy"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")

Run the Program using FPM (Fortran Package Manager)#

exec_status = \
    os.system("fpm run 2>/dev/null")
          original:   1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0
        copy N 1 1:   1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0
        copy N 1 2:   1.0  0.0  2.0  0.0  3.0  0.0  4.0  0.0  5.0  0.0
        copy N 2 1:   1.0  3.0  5.0  7.0  9.0  0.0  0.0  0.0  0.0  0.0
        copy N 2 2:   1.0  0.0  3.0  0.0  5.0  0.0  7.0  0.0  9.0  0.0
        copy N 1 2:   1.0  0.0  2.0  0.0  3.0  0.0  4.0  0.0  5.0  0.0  6.0  0.0  7.0  0.0  8.0  0.0  9.0  0.0 10.0  0.0
  shift copy N 1 2:   1.0  3.0  2.0  6.0  3.0  9.0  4.0 12.0  5.0 15.0  6.0 18.0  7.0 21.0  8.0 24.0  9.0 27.0 10.0 30.0