Section: BLAS/LAPACK - SV#
Adapted from: gjbex/Fortran-MOOC
This program demonstrates using the BLAS/LAPACK SV subroutine to solve sets of linear equations in Fortran.#
In file util_mod.f90
module util_mod
implicit none
private
public :: print_vector, print_matrix
contains
subroutine print_vector(vector, label, fmt_str_in)
implicit none
real, dimension(:), intent(in) :: vector
character(len=*), intent(in), optional :: label, fmt_str_in
character(len=20) :: fmt_str
if (present(fmt_str_in)) then
fmt_str = fmt_str_in
else
fmt_str = '(*(E18.7))'
end if
if (present(label)) print '(A)', label
print fmt_str, vector
end subroutine print_vector
subroutine print_matrix(matrix, label, fmt_str_in)
implicit none
real, dimension(:, :), intent(in) :: matrix
character(len=*), intent(in), optional :: label, fmt_str_in
character(len=20) :: fmt_str
integer :: row
if (present(fmt_str_in)) then
fmt_str = fmt_str_in
else
fmt_str = '(*(E18.7))'
end if
if (present(label)) print '(A)', label
do row = 1, size(matrix, 1)
print fmt_str, matrix(row, :)
end do
end subroutine print_matrix
end module util_mod
In file section_blas_lapack_sv.f90
program sv
use util_mod, only : print_matrix
use, intrinsic :: iso_fortran_env, only : error_unit
implicit none
integer, parameter :: n_matrix = 3, nr_rhs = 1
real, dimension(n_matrix, n_matrix) :: A, A_orig
real, dimension(n_matrix, nr_rhs) :: X, B, B_orig
integer, dimension(n_matrix) :: P
integer :: info
! Explicit interface for LAPACK routine sgesv
interface
subroutine sgesv(n, nrhs, A, lda, ipiv, B, ldb, info)
integer, intent(in) :: n, nrhs, lda, ldb
integer, intent(out) :: info
integer, dimension(*), intent(out) :: ipiv
real, dimension(lda, *), intent(inout) :: A
real, dimension(ldb, *), intent(inout) :: B
end subroutine sgesv
subroutine sgemm(transa, transb, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc)
character :: transa, transb
integer :: m, n, k, lda, ldb, ldc
real :: alpha, beta
real, dimension(lda, *) :: A
real, dimension(ldb, *) :: B
real, dimension(ldc, *) :: C
end subroutine sgemm
end interface
A = reshape( [ &
3.0, 5.0, 7.0, &
11.0, 13.0, 17.0, &
19.0, 23.0, 29.0, 31.0 &
], [ 3, 3 ])
A_orig = A
B = reshape( [ 1.0, 11.0, 3.0 ], [ 3, 1 ])
B_orig = B
! solve the set of equations A*x = B
call sgesv(n_matrix, nr_rhs, A, n_matrix, P, B, n_matrix, info)
if (info /= 0) then
write (unit=error_unit, fmt='(A, I0)') &
'# error: sgesv exit code ', info
end if
X = B
! check solution
call sgemm('N', 'N', n_matrix, nr_rhs, n_matrix, 1.0, A_orig, n_matrix, &
X, n_matrix, 0.0, B, n_matrix)
call print_matrix(A_orig, 'orig. A', '(*(F9.3))')
call print_matrix(X, 'X', '(F12.6)')
call print_matrix(B, 'B', '(F12.6)')
call print_matrix(B_orig, 'orig. B', '(F9.3)')
! compute and print relative error
print '(A, E10.3)', 'relative error = ', compute_error(B_orig, B)
contains
function compute_error(orig_A, A) result(rel_err)
implicit none
real, dimension(:, :), intent(in) :: orig_A, A
real :: rel_err
integer :: i, j
real :: norm
rel_err = 0.0
do j = 1, size(A, 2)
do i = 1, size(A, 1)
norm = abs(orig_A(i, j))
rel_err = rel_err + abs(A(i, j) - orig_A(i, j))/norm
end do
end do
rel_err = rel_err/(size(A, 1)*size(A, 2))
end function compute_error
end program sv
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_SV"
[build]
auto-executables = true
auto-tests = true
auto-examples = true
link = ["blas", "lapack"]
[install]
library = false
[[executable]]
name="Section_BLAS_LAPACK_SV"
source-dir="app"
main="section_blas_lapack_sv.f90"
code_dir = root_dir + "/" + "Fortran_Code/Section_BLAS_LAPACK_SV"
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")
orig. A
3.000 11.000 19.000
5.000 13.000 23.000
7.000 17.000 29.000
X
2.399998
-20.600016
11.600009
B
1.000000
10.999985
3.000000
orig. B
1.000
11.000
3.000
relative error = 0.462E-06