Fortran, LU method can't get it working fine - fortran

I'm doing a fortran homework and i have to program the LU method, i have wrote some lines but i'm stuck because it's not working fine.
My program is doing well the array 1 and 2 and for U, and the col 1 and 2 for L but the 3 and 4 are wrong(L and U).
can you help me please?
this is the program:
program lu
implicit none
real*8 A(4,4),L(4,4),U(4,4)
integer i,j,n,k
open(unit=21,file='mat2.dat')
open(unit=22,file='L.dat')
open(unit=23,file='U.dat')
A=0.0d0
L=0.0d0
U=0.0d0
do i=1,4
read(21,*) (A(i,j),j=1,4) !read A matrix
end do
do i=1,4
L(i,1)=A(i,1) !creating array L(i,1)
U(1,i)=A(1,i)/L(1,1) !creating row U(1,i)
end do
do i=2,4
do j=2,4
if(i.eq.j) then
U(i,j)=1 !creating U diagonal=1, since U(1,1) is already created it can start from 2
end if
do n=1,j-1
if (i>=j) then
L(i,j)=A(i,j)-L(i,n)*U(n,j) !creating the L missing part, i think here is an error, but i can't find it
end if
end do
do n=1,i-1
if (i<j) then
U(i,j)=A(i,j)*1/L(i,i)-L(i,n)*U(n,j)*1/L(i,i) !creating the U missing part
end if
end do
end do
end do
do i=1,4
write(22,*) (L(i,j),j=1,4) !write to check if it's working fine
write(23,*) (U(i,j),j=1,4)
end do
end program
and this is the A matrix
3 -1 4 -1
-1 -1 3 1
2 3 -1 -1
7 1 1 2
L and U should looks like this picture
http://i.cubeupload.com/J6u1VN.png
sorry for my bad english :(

Usually, one stores L and U within a unique matrix, and, usually again, one just modifies the initial matrix which is used as input and output.
The algorithm is rather simple; Here is a variant without pivot search :
SUBROUTINE matrix_lu(matrix)
! decomposing a matrix as a product of two triangular matrices (lower and upper)
! the diagonal belongs to the upper triangular matrix (the diagonal of the lower
! triangular matrix is assumed to be equal to the identity matrix)
! Take care : the diagonal of U is already inversed
DOUBLE PRECISION, INTENT(inout) :: matrix(:,:)
INTEGER :: n,i,k,l
n=SIZE(matrix,1)
DO k = 1, n
matrix(k, k) = 1.d0/matrix(k, k)
DO i = k+1, n
matrix(i, k) = matrix(i, k)*matrix(k, k)
ENDDO
DO l = k+1, n
DO i = k+1, n
matrix(i, l) = matrix(i, l)-matrix(i, k)*matrix(k, l)
END DO
END DO
END DO
END SUBROUTINE
So I don't understand several things in your algorithm :
the second loop over j should be from i to n (or i+1 to n) :
there is no test within the loops
the global complexity (number of multiplications) is n^3/3. Your algorithm is in n^3

Related

Solving a linear system with 0s on the main diagonal in Fortran

As per title, what's the best algorithm to numerically solve a linear system in Fortran, if this system has 0s along the main diagonal?
Up to now, I had been fine using simple Gaussian elimination:
SUBROUTINE solve_lin_sys(A, c, x, n)
! =====================================================
! Uses gauss elimination and backwards substitution
! to reduce a linear system and solve it.
! Problem (0-div) can arise if there are 0s on main diag.
! =====================================================
IMPLICIT NONE
INTEGER:: i, j, k
REAL*8::fakt, summ
INTEGER, INTENT(in):: n
REAL*8, INTENT(inout):: A(n,n)
REAL*8, INTENT(inout):: c(n)
REAL*8, INTENT(out):: x(n)
DO i = 1, n-1 ! pick the var to eliminate
DO j = i+1, n ! pick the row where to eliminate
fakt = A(j,i) / A(i,i) ! elimination factor
DO k = 1, n ! eliminate
A(j,k) = A(j,k) - A(i,k)*fakt
END DO
c(j)=c(j)-c(i)*fakt ! iterate on known terms
END DO
END DO
! Actual solving:
x(n) = c(n) / A(n,n) ! last variable being solved
DO i = n-1, 1, -1
summ = 0.d0
DO j = i+1, n
summ = summ + A(i,j)*x(j)
END DO
x(i) = (c(i) - summ) / A(i,i)
END DO
END SUBROUTINE solve_lin_sys
As you can see I'm dividing by A(i,i) in the calculations. Same problem arises using Gauss-Jordan transformation or Gauss-Seidel elimination.
What's the best solution? I know i'm probably missing some really basic step but I'm a beginner programmer and apparently my linear algebra is getting rusty.

Infinite do loop issue

Just to preface this question, I am a couple weeks new to Fortran and I have run into an infinite do loop error when running the actual program.
I am 99% sure that the infinite sequence is coming from the do loop, but I thought I should ask just to be sure. I am not sure what part of the do loop is causing the infinite do loop but any help would be greatly appreciated!
Here is the code:
implicit none
! Declare variables - Add variables as necessary (integer only!)
! M will store the encoding matrix, MInv will store its inverse
! Decoded_message will store the decoded message
integer :: M(2,2), MInv(2,2), Determinant, a, b, c, d, detM, i, v(:,:), ascIIcode(:,:)
allocatable :: v, ascIIcode
character*32 :: Decoded_Message
! open data file and read in the encoding matrix
open(42,file='Data3.txt')
read(42,*) M(1,1), M(1,2)
read(42,*) M(2,1), M(2,2)
! Invert the encoding matrix and store it in MInv
detM = determinant(M)
MInv(1,1) = +detM *M(2,2)
MInv(1,2) = -detM *M(2,1)
MInv(2,1) = -detM *M(1,2)
MInv(2,2) = +detM *M(1,1)
! Processing steps required:
! Read from the file in 2 numbers at a time and store in a vector array
do i = 2, 31
allocate (v(2,1), ascIIcode(2,1))
read(42,*) v(1,1)
read(42,*) v(2,1)
! decode the 2 numbers read in (1) by multiplying Minv by the vector array from (1)
ascIIcode(1,1) = ((MInv(1,1)*v(1,1))+(MInv(1,2)*v(2,1)))
ascIIcode(2,1) = ((MInv(2,1)*v(1,1))+(MInv(2,2)*v(2,1)))
! Insert the result from (2) into the character string Decoded_Message. To concatinate
Decoded_Message = char(ascIIcode(1,1))//char(ascIIcode(2,1))
! Use a loop that advances in steps of 2 and goes to 31
deallocate (v)
deallocate (ascIIcode)
end do
! print results.
print*, Decoded_Message
! close files
close(42)
end program Decode
integer function Determinant(M)
! This function computes the determinant of matices of size 2 or 3
! M is the matrix for which the determinant is calculated (square matrix only)
! n is the number of rows or columns in M
implicit none
integer :: M(2,2), a, b, c, d, e, f, g, h, i, Det
do
a = M(1,1)
b = M(1,2)
c = M(2,1)
d = M(2,2)
Det = (a*d)-(b*c)
end do
end function Determinant

I want to show a 4*5 matrix and my program is no error,but when I run it show me the program stop work

my program display no error but it can't work?
program hw4
dimension a(i,j)
real a
common i,j
integer i,j
do i=1,4,1
do j=1,5,1
a(1,1)=0
a(1,2)=1
a(1,3)=2
a(1,4)=3
a(1,5)=25
a(2,1)=1
a(2,2)=1
a(2,3)=1
a(2,4)=1
a(2,5)=12
a(3,1)=2
a(3,2)=0
a(3,3)=3
a(3,4)=1
a(3,5)=19
a(4,1)=3
a(4,2)=4
a(4,3)=0
a(4,4)=6
a(4,5)=41
write(*,*) a(i,j)
enddo
enddo
stop
end
I expect it will show 4*5 matrix,but now it will show me the program stop work message
Firstly, your matrix "a" must have constant shape i.e. dimensions "i" and "j" must be explicitly defined.
Secondly, your nested loop sets matrix values every loop. Try putting it before the loop.
Something like:
program hw4
implicit none
integer, parameter :: ni=4, nj=5
real, dimension(ni,nj) :: a
integer :: i, j
! Set matrix values here
a(1,1) = 0
! ...
do i = 1, ni, 1
do j = 1, nj, 1
write(*,*) a(i,j)
end do
end do
end program hw4
Kind regards

Fortran OpenMP code much slower than its not parallel version

I want to solve the Random Walk problem, so i wrote a fortran sequental code and now i need to parallel this code.
subroutine random_walk(walkers)
implicit none
include "omp_lib.h"
integer :: i, j, col, row, walkers,m,n,iter
real, dimension(:, :), allocatable :: matrix, res
real :: point, z
col = 12
row = 12
allocate (matrix(row, col), res(row, col))
! Read from file
open(2, file='matrix.txt')
do i = 1, row
read(2, *)(matrix(i, j), j=1,col)
end do
res = matrix
! Solve task
!$omp parallel private(i,j,m,n,point,iter)
!$omp do collapse(2)
do i= 2, 11
do j=2, 11
m = i
n = j
iter = 1
point = 0
do while (iter <= walkers)
call random_number(z)
if (z <= 0.25) m = m - 1
if (z > 0.25 .and. z <= 0.5) n = n +1
if (z > 0.5 .and. z <= 0.75) m = m +1
if (z > 0.75) n = n - 1
if (m == 1 .or. m == 12 .or. n == 1 .or. n == 12) then
point = point + matrix(m, n)
m = i
n = j
iter = iter + 1
end if
end do
point = point / walkers
res(i, j) = point
end do
end do
!$omp end do
!$omp end parallel
! Write to file
open(2, file='out_omp.txt')
do i = 1, row
write(2, *)(res(i, j), j=1,col)
end do
contains
end
So, the problem is that parallel program computes MUCH lesser than its sequential version.
Where is the mistake?(except my terrible code)
Update: for now the code is with !$omp do directives, but the result is still the same: it is much lesser than its sequential version.
Most probably, the behavior is related to the random number extraction. RANDOM_NUMBER Fortran procedure is not even guaranteed to be thread-safe but it is thread-safe at least in GNU compiler thanks to a GNU extension. But in any case the performances seem to be very bad as you note.
If you switch to a different thread-safe random number generator, the scalability of your code can be good. I used the classical ran2.f generator:
http://www-star.st-and.ac.uk/~kw25/research/montecarlo/ran2.f
modified to make it thread-safe. If I am not wrong, to do that:
in the calling unit declare and define:
integer :: iv(32), iy, idum2, idum
idum2 = 123456789 ; iv(:) = 0 ; iy = 0
in OpenMP directives add idum as private and idum2, iv, iy as firstprivate (by the way you need to add z as private too)
in the parallel section add (before do)
idum = - omp_get_thread_num()
to have different random numbers for different threads
from ran2 function remove DATA and SAVE lines e pass idum2, iv, iy as arguments:
FUNCTION ran2(idum, iv, iy, idum2)
call ran2 instead of random_number intrinsic
z = ran2(idum, iv, iy, idum2)
With walkers=100000 (GNU compiler) these are my times:
1 thread => 4.7s
2 threads => 2.4s
4 threads => 1.5s
8 threads => 0.78s
16 threads => 0.49s
Not strictly related to the question but I have to say that extracting a real number for each 4 "bit"s info you need (+1 or -1) and the usage of conditionals can be probably changed using a more efficient strategy.

How to exit from nested Fortran loops?

I'm trying to write a program (in Fortran 95) that finds the minimal decomposition of natural numbers up to N into a sum of at most 4 positive integers.
I've been trying to add and remove statements for a while to make it stop at only the minimal decomposition but I'm not getting anywhere. How do I make the program stop as soon as it's found the minimal decomposition?
PROGRAM SummeQuadrat
IMPLICIT NONE
real:: start,finish
integer:: a,b,c,d,g,x,y
write(*,*) "Max n"
read (*,*) y
call cpu_time(start)
do x=1,y,1
do a=0,x,1
do b=a,x-a,1
do c=b,x-b,1
do d=c,x-c,1
if (a**2+b**2+c**2+d**2 .eq. x) then
write(*,*) "x=",x,d,c,b,a
end if
end do
end do
end do
end do
end do
call cpu_time(finish)
write(*,*)finish-start
end program SummeQuadrat
As I explained in the comments, I am not sure you are asking only how to break out of the loops or for more.
You can jump out of any loop using the EXIT statement. To exit from a loop which is not the innermost loop you are currently in you use a labeled loop and use the label in the EXIT statement to exit that particular loop.
outer: do x = 1, y
do a = 0, x
do b = a, x-a
do c = b, x-b
do d = c, x-c
if (a**2+b**2+c**2+d**2 == x) then
write(*,*) "x=",x,d,c,b,a
if (minimal(a,b,c,d)) exit outer
end if
end do
end do
end do
end do
end do outer
Old thread, but it's kind of a fun problem so I thought I might post my own interpretation.
First off, if we cheat a little and peek at the solution it can be seen that all 4 squares are only needed when x=4**k*(8*m+7). Thus we can search cheaply for 1 or 2 square solutions and on failure decide by the above criterion whether to search for a 3- or 4-square solution.
Then when we structure our loops, count down from the largest a such that a**2 <= x, then the largest b <= a such that a**2+b**2 <= x and so on. This takes the problem from O(x**4) down to O(x**1.5) so it can go much quicker.
For output format, by judicious use of the colon format we can write a single format that prints out results in perhaps a more readable fashion.
! squares.f90 -- Prints out minimal decomposition x into squares
! for 1 <= x <= y (user input)
program squares
use ISO_FORTRAN_ENV, only: REAL64
implicit none
! Need this constant so we can take the square root of an
! integer.
real(REAL64), parameter :: half = 0.5_REAL64
real start, finish
integer a,b,c
integer amax,bmax,cmax,dmax
integer amin,bmin,cmin
integer x,y
! Format for printing out decomposition into squares
character(40) :: fmt = '(i0," = ",i0"**2":3(" + ",i0,"**2":))'
integer nzero
! Get uper bound from user
write(*,'(a)',advance='no') 'Please enter the max N:> '
read(*,*) y
call cpu_time(start)
! Loop over requested range
outer: do x = 1, y
amax = sqrt(x+half)
! Check for perfect square
if(amax**2 == x) then
write(*,fmt) x,amax
cycle outer
end if
! Check for sum of 2 squares
amin = sqrt(x/2+half)
try2: do a = amax, amin, -1
bmax = sqrt(x-a**2+half)
if(bmax > a) exit try2
if(a**2+bmax**2 == x) then
write(*,fmt) x,a,bmax
cycle outer
end if
end do try2
! If trailz(x) is even, then x = 4**k*z, where z is odd
! If further z = 8*m+7, then 4 squares are required, otherwise
! only 3 should suffice.
nzero = trailz(x)
if(iand(nzero,1)==0 .AND. ibits(x,nzero,3)==7) then
amin = sqrt(x/4+half)
do a = amax, amin, -1
bmax = sqrt(x-a**2+half)
bmin = sqrt((x-a**2)/3+half)
do b = min(bmax,a), bmin, -1
cmax = sqrt(x-a**2-b**2+half)
cmin = sqrt((x-a**2-b**2)/2+half)
do c = min(cmax,b), cmin, -1
dmax = sqrt(x-a**2-b**2-c**2+half)
if(a**2+b**2+c**2+dmax**2 == x) then
write(*,fmt) x,a,b,c,dmax
cycle outer
end if
end do
end do
end do
else
amin = sqrt(x/3+half)
do a = amax, amin, -1
bmax = sqrt(x-a**2+half)
bmin = sqrt((x-a**2)/2+half)
do b = min(bmax,a), bmin, -1
cmax = sqrt(x-a**2-b**2+half)
if(a**2+b**2+cmax**2 == x) then
write(*,fmt) x,a,b,cmax
cycle outer
end if
end do
end do
end if
! We should have a solution by now. If not, print out
! an error message and abort.
write(*,'(*(g0))') 'Failure at x = ',x
stop
end do outer
call cpu_time(finish)
write(*,'(*(g0))') 'CPU time = ',finish-start
end program squares