Search code examples
fortran

fortran not able to call defined functions power of matrix


I just started learning Fortran and I have this function called matrix_power But I'm having difficulty trying to call the function. The file extension I'm using is .f and my compiler is gfortran.

Here is my code

function transpose_matrix(mat) result(mat_t)
    implicit none
    real, dimension(:,:), intent(in) :: mat
    real, dimension(size(mat,2),size(mat,1)) :: mat_t
    integer :: i, j
    do i = 1, size(mat,1)
    do j = 1, size(mat,2)
        mat_t(j,i) = mat(i,j)
    end do
    end do
end function transpose_matrix

function matrix_power(mat, p) result(mat_p)
    implicit none
    integer, intent(in) :: p
    real, dimension(:,:), intent(in) :: mat
    real, dimension(size(mat,1),size(mat,2)) :: mat_p
    integer :: i
    mat_p = mat
    do i = 2, p
    mat_p = matmul(mat_p, mat)
    end do
end function matrix_power


program matrix
implicit none

real, dimension(5, 5) :: matrix1 = reshape([2.0, 0.0, 0.0, 0.0, 0.0, &
                                            0.0, 2.0, 0.0, 0.0, 0.0, &
                                            0.0, 0.0, 2.0, 0.0, 0.0, &
                                            0.0, 0.0, 0.0, 2.0, 0.0, &
                                            2.0, 0.0, 0.0, 0.0, 2.0], (5, 5))

real, dimension(5, 5) :: mat_t, mat_p
integer :: i

mat_t = transpose_matrix(matrix1)

mat_p = matrix_power(matrix1, 3)
! Print the results
print *, "Matrix 1:"
print *, matrix1
print *, "Matrix 1 Transposed:"
print *, mat_t
print *, "Matrix 1 to the power of 3:"
print *, mat_p

end program matrix

I know that it's saying that there is a mismatch but it doesn't even make sense This is my definition of the mat_p

  real, dimension(m,n) :: mat_t, mat_p

Here is the error I'm receiving enter image description here

here is a text based error

   Return type mismatch of function 'matrix_power' at (1) (UNKNOWN/REAL(4))
Function 'matrix_power' at (1) has no IMPLICIT type

Solution

  • As suspected by @VladimirFГероямслава in the comments, functions returning arrays must have explicit interfaces. Routines/functions with assumed shapes dummy arguments, or intent() attributes for the arguments, do also require explicit interfaces.

    First of all , because you are using implicit none (which is a good practice) in the main program, you have to define the return type of all the non-intrinsic functions you are using. For instance if you had this function:

    function matrix_trace(mat,n) result(t)
        implicit none
        real :: mat(n,n)
        real :: t
        integer :: i
        t = 0.0
        do i = 1, n
            t = t + mat(i,i)
        end do
    end function
    

    You would simply have to insert in your main program:

    real, external :: matrix_trace

    This is an implicit interface, because you don't describe how arguments are passed. The implicit interface is the legacy pre-Fortran 90 way.

    In your case your have to define explicit interfaces, with two possibilities.

    Interface blocks:

    In your main program you insert this code:

    INTERFACE
        function transpose_matrix(mat) result(mat_t)
            implicit none
            real, dimension(:,:), intent(in) :: mat
            real, dimension(size(mat,2),size(mat,1)) :: mat_t
        end function transpose_matrix
    
        function matrix_power(mat, p) result(mat_p)
            implicit none
            integer, intent(in) :: p
            real, dimension(:,:), intent(in) :: mat
            real, dimension(size(mat,1),size(mat,2)) :: mat_p
        end function matrix_power
    END INTERFACE
    

    Modules

    Much better, use modules to encapsulate your functions:

    !*****************************************
    MODULE mymatfuncs
    
    CONTAINS
    
    function transpose_matrix(mat) result(mat_t)
        implicit none
        real, dimension(:,:), intent(in) :: mat
        real, dimension(size(mat,2),size(mat,1)) :: mat_t
        integer :: i, j
        do i = 1, size(mat,1)
        do j = 1, size(mat,2)
            mat_t(j,i) = mat(i,j)
        end do
        end do
    end function transpose_matrix
    
    function matrix_power(mat, p) result(mat_p)
        implicit none
        integer, intent(in) :: p
        real, dimension(:,:), intent(in) :: mat
        real, dimension(size(mat,1),size(mat,2)) :: mat_p
        integer :: i
        mat_p = mat
        do i = 2, p
        mat_p = matmul(mat_p, mat)
        end do
    end function matrix_power
    
    END MODULE mymatfuncs
    !*****************************************
    
    
    
    
    program matrix
    USE mymatfuncs, only: matrix_power, transpose_matrix
    implicit none
    
    real, dimension(5, 5) :: matrix1 = reshape([2.0, 0.0, 0.0, 0.0, 0.0, &
                                                0.0, 2.0, 0.0, 0.0, 0.0, &
                                                0.0, 0.0, 2.0, 0.0, 0.0, &
                                                0.0, 0.0, 0.0, 2.0, 0.0, &
                                                2.0, 0.0, 0.0, 0.0, 2.0], (5, 5))
    
    real, dimension(5, 5) :: mat_t, mat_p
    integer :: i
    
    mat_t = transpose_matrix(matrix1)
    
    mat_p = matrix_power(matrix1, 3)
    ! Print the results
    print *, "Matrix 1:"
    print *, matrix1
    print *, "Matrix 1 Transposed:"
    print *, mat_t
    print *, "Matrix 1 to the power of 3:"
    print *, mat_p
    
    end program matrix