ユーマちゃんのブログ

質問・要望はTwitterもしくはコメントで。返信はTwitterで。

Programming Example 12

Red characters are codes I wrote by myself today. 2018/01/05

But these can be changed like below using "matmul".

 

---------------------------------------------------------------------

  do while ( (err>TOL).and.(k<k_max) )
     k= k + 1
     H=Hessian(x) !Get Hessian matrix as H using Hessian Function
     Minv=Minverse(H) !Get inverse of Hessian matrix using Minverse Function
     x=x-matmul(Minv,R) ! Update x
     R = Residual(x) !Set Residual matrix as R.

     err=sqrt(dot_product(R,R))
     write(*,'(I10, $)') k
     do i=1, m
       write(*,'(F10.3, $)') x(i)
     end do
     write(*,'(E20.3)') err
  end do

---------------------------------------------------------------------

This is the main code.

------------------------------------------------------------------------

 

Program nonlinear_system
! Global variables
integer, parameter:: m=3      ! Maximum number of variables
real(8):: S(m), H(m,m)    ! Unknown variable vector S
real(8), parameter:: TOL=1D-6 ! Numerical tolerance

Call Guess(S)
Call Solve(S)

contains

Function Residual(x)
  real(8):: Residual(m), x(m)
  Residual(1)=-x(1)+2*x(2)+x(3)-2
  Residual(2)=2*( (x(1)+3)**2) + 5*x(2)**2- (x(3)+1)**2
  Residual(3)=(x(1)-5)*(x(2)+2) + 3
end Function Residual

Function Hessian(x)
  real(8):: Hessian(m,m), x(m), x_(m), v(m), v_(m)
  integer:: i,j
  do i = 1, m
     do j = 1, m
        x_ = x; x_(j) = x(j) + TOL ! Perturb x
        v_ = Residual(x_)
        v = Residual(x)
        Hessian(i,j) = ( v_(i) - v(i) ) / TOL
     end do
  end do
end Function Hessian

Subroutine Guess(x)
  real(8), INTENT(OUT):: x(m) ! dummy variables
  Integer:: i

  Write(*,*) "Nonlinear system of", m, "equations"
  do i = 1, m
    write(*, '(A, I2, A)', advance="no") "Input the guessed value no.", i, " = "
    Read(*,*) x(i)
  end do
End Subroutine Guess

Subroutine Solve(x)
  real(8), INTENT(INOUT):: x(m) ! dummy variables
  ! local variables
  Integer, parameter:: k_max=50 ! Maximum iteration number
  Integer:: k, n
  real(8):: err, R(m), H(m,m),Minv(m,m),rs(m)

  write(*,'(A10, $)') "Iteration"
  do i=1, m
    write(*,'(A9, I1,$)') "x", i
  end do
  write(*,'(A20)') "Norm of errors"
  write(*, '(A)') repeat('-',60)

  R = Residual(x)
  err=sqrt(dot_product(R,R))
  k=0
  write(*,'(I10, $)') k
  do i=1, m
    write(*,'(F10.3, $)') x(i)
  end do
  write(*,'(E20.3)') ERR

  do while ( (err>TOL).and.(k<k_max) )
     k= k + 1
     H=Hessian(x) !Get Hessian matrix as H using Hessian Function
     Minv=Minverse(H) !Get inverse of Hessian matrix using Minverse Function
     R = Residual(x) !Set Residual matrix as R.
     rs=0.0
     do i =1,m
       do j =1,m
         rs(i)=rs(i)+Minv(i,j)*R(j) !Get H(x_k)[-1]*r(x_k)
       end do
       x(i)=x(i)-rs(i) !Set New x
     end do

     R = Residual(x) !Set Residual matrix as R again.
     err=sqrt(dot_product(R,R))
     write(*,'(I10, $)') k
     do i=1, m
       write(*,'(F10.3, $)') x(i)
     end do
     write(*,'(E20.3)') err
  end do
  if (k==k_max) then
    print*, "Divergence!"
  end if
  write(*, '(A)') repeat('-',60)
End Subroutine Solve

function Minverse(A)
  real(8), dimension(:,:):: A
  real(8), dimension(:,:), allocatable:: Minverse, B, V
  real(8), dimension(:), allocatable:: temp
  real(8), parameter:: TOL=1D-6
  real(8):: pivot
  integer:: i, j, jmax, k, n,l
  n=size(A)**0.5
  allocate(Minverse(n,n),B(n,n),V(n,n),temp(n))
  B=A
  V(:,:)=0.0
  do i=1, n
    V(i,i)=1.0
  end do
  do i=1, n
    jmax=i
    do j=i+1, n
      if (abs(B(j,i))>abs(B(jmax,i))) then
        jmax=j
        temp=B(i,:);B(i,:)=B(jmax,:);B(jmax,:)=temp
        temp=V(i,:);V(i,:)=V(jmax,:);V(jmax,:)=temp
      end if
    end do
    pivot=B(i,i)
    if (abs(pivot)<TOL) then
      print *, "The matrix is singular!"
    end if
    B(i,:)=B(i,:)/pivot
    V(i,:)=V(i,:)/pivot
    do k =1,n
      if (i .ne. k) then
        pivot=B(k,i)
        do l=1,n
          B(k,l)=B(k,l)-B(i,l)*pivot
          V(k,l)=V(k,l)-V(i,l)*pivot
        end do
      end if
    enddo
  end do
  Minverse=V
end function Minverse
end Program nonlinear_system