MATMUL(3) - [ARRAY:TRANSFORMATIONAL] Numeric or logical matrix multiplication
result = matmul(matrix_a,matrix_b)
function matmul(matrix_a, matrix_b)type(TYPE1(kind=**)) :: matrix_a(..) type(TYPE2(kind=**)) :: matrix_b(..) type(TYPE(kind=PROMOTED)) :: matmul(..)
o MATRIX_A is a numeric (integer, real, or complex ) or logical array of rank one two. o MATRIX_B is a numeric (integer, real, or complex ) or logical array of rank one two. o At least one argument must be rank two. o the size of the first dimension of MATRIX_B must equal the size of the last dimension of MATRIX_A. o the type of the result is the same as if an element of each argument had been multiplied as a RHS expression (that is, if the arguments are not of the same type the result follows the same rules of promotion as a simple scalar multiplication of the two types would produce) o If one argument is logical, both must be logical. For logicals the resulting type is as if the .and. operator has been used on elements from the arrays. o The shape of the result depends on the shapes of the arguments as described below.
MATMUL(3) performs a matrix multiplication on numeric or logical arguments.
o MATRIX_A : A numeric or logical array with a rank of one or two. o MATRIX_B : A numeric or logical array with a rank of one or two. The last dimension of MATRIX_A and the first dimension of MATRIX_B must be equal. Note that MATRIX_A and MATRIX_B may be different numeric types.
If MATRIX_A and MATRIX_B are numeric the result is an array containing the conventional matrix product of MATRIX_A and MATRIX_B.
First, for the numeric expression C=MATMUL(A,B)
o Any vector A(N) is treated as a row vector A(1,N). o Any vector B(N) is treated as a column vector B(N,1).
The shape of the result can then be determined as the number of rows of the first matrix and the number of columns of the second; but if any argument is of rank one (a vector) the result is also rank one. Conversely when both arguments are of rank two, the result has a rank of two. That is ...
o If MATRIX_A has shape [n,m] and MATRIX_B has shape [m,k], the result has shape [n,k]. o If MATRIX_A has shape [m] and MATRIX_B has shape [m,k], the result has shape [k]. o If MATRIX_A has shape [n,m] and MATRIX_B has shape [m], the result has shape [n].
Then element C(I,J) of the product is obtained by multiplying term-by-term the entries of the ith row of A and the jth column of B, and summing these products. In other words, C(I,J) is the dot product of the ith row of A and the jth column of B.
If MATRIX_A and MATRIX_B are of type logical, the array elements of the result are instead:
Value_of_Element (i,j) = & ANY( (row_i_of_MATRIX_A) .AND. (column_j_of_MATRIX_B) )
Sample program:
program demo_matmul implicit none integer :: a(2,3), b(3,2), c(2), d(3), e(2,2), f(3), g(2), v1(4),v2(4) a = reshape([1, 2, 3, 4, 5, 6], [2, 3]) b = reshape([10, 20, 30, 40, 50, 60], [3, 2]) c = [1, 2] d = [1, 2, 3] e = matmul(a, b) f = matmul(c,a) g = matmul(a,d)Results:call print_matrix_int(A is ,a) call print_matrix_int(B is ,b) call print_vector_int(C is ,c) call print_vector_int(D is ,d) call print_matrix_int(E is matmul(A,B),e) call print_vector_int(F is matmul(C,A),f) call print_vector_int(G is matmul(A,D),g)
! look at argument shapes when one is a vector write(*,(" > shape")) ! at least one argument must be of rank two ! so for two vectors at least one must be reshaped v1=[11,22,33,44] v2=[10,20,30,40]
! these return a vector C(1:1) ! treat A(1:n) as A(1:1,1:n) call print_vector_int(Cd is a vector (not a scalar),& & matmul(reshape(v1,[1,size(v1)]),v2)) ! or treat B(1:m) as B(1:m,1:1) call print_vector_int(cD is a vector too,& & matmul(v1,reshape(v2,[size(v2),1])))
! or treat A(1:n) as A(1:1,1:n) and B(1:m) as B(1:m,1:1) ! but note this returns a matrix C(1:1,1:1) not a vector! call print_matrix_int(CD is a matrix,matmul(& & reshape(v1,[1,size(v1)]), & & reshape(v2,[size(v2),1])))
contains
! CONVENIENCE ROUTINES TO PRINT IN ROW-COLUMN ORDER subroutine print_vector_int(title,arr) character(len=*),intent(in) :: title integer,intent(in) :: arr(:) call print_matrix_int(title,reshape(arr,[1,shape(arr)])) end subroutine print_vector_int
subroutine print_matrix_int(title,arr) !@(#) print small 2d integer arrays in row-column format character(len=*),parameter :: all=(" > ",*(g0,1x)) ! a handy format character(len=*),intent(in) :: title integer,intent(in) :: arr(:,:) integer :: i character(len=:),allocatable :: biggest
print all print all, trim(title) biggest= ! make buffer to write integer into ! find how many characters to use for integers write(biggest,(i0))ceiling(log10(max(1.0,real(maxval(abs(arr))))))+2 ! use this format to write a row biggest=(" > [",*(i//trim(biggest)//:,",")) ! print one row of array at a time do i=1,size(arr,dim=1) write(*,fmt=biggest,advance=no)arr(i,:) write(*,(" ]")) enddo
end subroutine print_matrix_int
end program demo_matmul
> > A is > [ 1, 3, 5 ] > [ 2, 4, 6 ] > > B is > [ 10, 40 ] > [ 20, 50 ] > [ 30, 60 ] > > C is > [ 1, 2 ] > > D is > [ 1, 2, 3 ] > > E is matmul(A,B) > [ 220, 490 ] > [ 280, 640 ] > > F is matmul(C,A) > [ 5, 11, 17 ] > > G is matmul(A,D) > [ 22, 28 ] > shape > > Cd is a vector (not a scalar) > [ 3300 ] > > cD is a vector too > [ 3300 ] > > CD is a matrix > [ 3300 ]
Fortran 95
PRODUCT(3), TRANSPOSE(3)
o Matrix multiplication : Wikipedia o The Winograd variant of Strassens matrix-matrix multiply algorithm may be of interest for optimizing multiplication of very large matrices. See "GEMMW: A portable level 3 BLAS Winograd variant of Strassens matrix-matrix multiply algorithm",The numerical instabilities of Strassens method for matrix multiplication requires special processing.Douglas, C. C., Heroux, M., Slishman, G., and Smith, R. M., Journal of Computational Physics, Vol. 110, No. 1, January 1994, pages 1-10.
Fortran intrinsic descriptions (license: MIT) @urbanjost
Nemo Release 3.1 | matmul (3fortran) | November 02, 2024 |