Search code examples
matrixfortrannumerical-computingmatrix-decomposition

How to output 2 or more arrays in a fortran's function?


I am writing a program which computes the LU decomposition of a matrix, with partial pivoting, and I would like the function to output several (2 or 3) matrices without running the program several times to output each one individually, which is a waste of time since it gets me everything I want in one run. Is there a way of doing this? For example, here is my function using Doolittle's algorithm, for square matrix which don't need pivoting. I want my output to be matrix l and u at once, but I know no means of doing that.

function lu_d(aa) result(l)

real, dimension (:,:) :: aa !input matrix
real, dimension (size(aa,1), size(aa,2)) :: a !keeping input variable intact
real, dimension (size(a,1), size(a,2)) :: l , u !lower and upper matrices
integer :: i,j,k !index
real :: s !auxiliar variable

a=aa

do j=1 , size(a,2)
  u(1,j)=a(1,j)
end do

l(1,1)=1

do j=2, size(a,2)
  l(1,j)=0
end do

do i=2, size(a,1)

  l(i,1)=a(i,1)/u(1,1)
  u(i,1)=0

  do j=2, i-1

    s=0
    u(i,j)=0

    do k=1, j-1
      s=s+l(i,k)*u(k,j)
    end do

    l(i,j)=(a(i,j)-s)/u(j,j)

  end do

  l(i,i)=1

  do j=i, size(a,2)

    s=0
    l(i,j)=0

    do k=1, i-1
      s=s+l(i,k)*u(k,j)
    end do

    u(i,j)=a(i,j)-s

  end do

end do

end function

Solution

  • You could switch from using a function to using a subroutine. This way you can output values for multiple arrays in the arguments list. Additionally using the INTENT definition when declaring variables in the subroutine, e.g.:

    REAL,INTENT(IN)::a declares a and does not allow its values to be altered inside the subroutine/function

    REAL,INTENT(OUT)::b declares b and disregards any values it has coming into the subroutine/function

    REAL,INTENT(INOUT)::c this is the case by default, if you don't write anything.

    I will assume you need the output to be l and u (rather than m), in which case the structure would look something like the one below. Note that l and m should either be declared in the main program and their size defined with respect to aa (as in the first case shown below) OR declared with an allocatable size in the main program, passed to the subroutine without being allocated and allocated within the subroutine (second example). The latter may require you to put the subroutine in a module so that the interfaces are handled properly.

    First example:

    SUBROUTINE lu_d(aa,l,m)
    implicit none
    real,intent(in):: a(:,:)
    real,intent(out):: l(:,:), m(:,:)
    integer:: i,j,k
    real:: s
    
    <operations>
    
    RETURN
    END SUBROUTINE lud_d
    

    Second example:

    SUBROUTINE lu_d(aa,l,m)
    implicit none
    real,intent(in):: a(:,:)
    real,allocatable,intent(out):: l(:,:), m(:,:)
    integer:: i,j,k,size_a1,size_a2
    real:: s
    
    size_a1=size(aa,1)
    size_a2=size(aa,2)
    allocate( l(size_a1,size_a2), m(size_a1,size_a2))
    
    <operations>
    
    RETURN
    END SUBROUTINE lud_d