INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Recursion Fortran

Recursion Fortran

(OP)
I have a problem.

I can only a little bit fortran. So I write a program first in Java, then I try to translate it in Fortran.

First my Java-Prgram:

CODE --> Java

public static void main(String[] args) 
	{
	int matrix_groesse=4;
	double [][] array=new double[matrix_groesse][matrix_groesse];
	
	array[0][0]=4;
	array[0][1]=1;
	array[0][2]=0;
	array[0][3]=1;
	//array[0][4]=-3;
	//array[0][5]=-4;
	//array[0][6]=-5;
	
	
	array[1][0]=-2; 
	array[1][1]=0;
	array[1][2]=-2;
	array[1][3]=2;
	//array[1][4]=-4;	
	//array[1][5]=-0;
	//array[1][6]=-1;	

	
	array[2][0]=-1;
	array[2][1]=1;
	array[2][2]=-4;
	array[2][3]=4;
	//array[4][4]=4;		
	//array[4][5]=1;
	//array[4][6]=-3;		

	
	array[3][0]=-5;
	array[3][1]=-4;
	array[3][2]=5;
	array[3][3]=0;	
	//array[2][4]=0;		
	//array[2][5]=1;	
	//array[2][6]=-4;		

	
	/*array[3][0]=-2; 
	array[3][1]=-4;
	array[3][2]=2;
	array[3][3]=-5;	
	array[3][4]=-1;		
	array[3][5]=2;	
	array[3][6]=0;		

	array[5][0]=3;
	array[5][1]=-3;
	array[5][2]=-3;
	array[5][3]=4;	
	array[5][4]=-2;		
	array[5][5]=-5;	
	array[5][6]=1;		

	array[6][0]=-2;
	array[6][1]=-5;
	array[6][2]=3;
	array[6][3]=-2;	
	array[6][4]=3;		
	array[6][5]=1;	
	array[6][6]=-5;*/		
	
	Zeitmesser.startMessung(1);
	System.out.println("Determinante = "+Double.toString(Formelsammlung.determinante(array,matrix_groesse)));
	Zeitmesser.stopMessung(1);
	System.out.println("Zeit: "+Double.toString(Zeitmesser.getErgebnis(1)/1000)+" Sekunde");
	}

public static double determinante(double [][] array) //2x2 Matrix => det = 0/0*1/1-0/1*1/0
{
	return (array[0][0]*array[1][1])-(array[0][1]*array[1][0]);
}

public static double[][] laplace(double [][] array,int groesse_matrix, int spalte) //reduce matrix nxn into a matrix n-1*n-1
{
	double [][] array_=new double[groesse_matrix-1][groesse_matrix-1];
	int k,l;
	
	k=0;
	l=0;
	for (int i=1;i<groesse_matrix;i++)//beginn mit zeile 1, da zeile 0 immer die ausgewählte Zeile ist
		{
			{
			for(int j=0;j<groesse_matrix;j++)
				{
				if(j!=spalte) //aktuelle spalte wird nicht berücksichtigt
					array_[k][l++]=array[i][j];
				}
			}
		k++;
		l=0;
		}
	
	return array_;
}

public static double determinante(double [][] array, int matrix_groesse)
{
	int vorzeichen=1;
	double [][] array2;
	double faktor;
	double zwischensumme=0;
	double endsumme=0;
	
	if (matrix_groesse==2) //terminated by 2x2 matrix, liefert determinante einer 2x2-matrix
		{
		return Formelsammlung.determinante(array);
		}
	else
		{
		for (int i=0;i<matrix_groesse;i++)
			{
			zwischensumme=0;
			array2=laplace(array, matrix_groesse,i);
			faktor=array[0][i]*vorzeichen;
			vorzeichen*=-1;

			if(faktor!=0)
				{
				zwischensumme=faktor*determinante(array2,matrix_groesse-1);
				}
			
			endsumme+=zwischensumme;
			}
		return endsumme;
		}
} 

This program calculates the determinant of a nxn matrix by Laplace. This program works.
The methode public static double determinante(double [][] array, int matrix_groesse) is the recursive methode, the heart of the program.
Termination condition is the Size of Matrix -> 2x2.
This program solve all testing problems. For example the test you see in the program. Determinante=6

Now my Fortran-Program

CODE --> Fortran

program determinante

    double precision, dimension(:,:),allocatable::array		!Startmatrix mit groesse matrix_groesse
    integer::groesse_matrix						!Groesse der Startmatrix 
	integer ::i,j								!schleifenvariablen
	double precision ::ergebnis=0								!Ergebnis der Determinante für die Startmatrix
    character(len=10)::hilf						!Wird nur für die sichtbare Lösung aus Start der Exe-Datei benötigt

	! Öffnen der Eingabedatei, Einlesen
	!**************************************************************************!
	open(10,file='vierer.txt')
	read(10,*) groesse_matrix

	! Zuweisung der Matrixgrößen, Einlesen der Matrix und Schließen der Eingabedatei
	allocate(array(groesse_matrix,groesse_matrix))
            
	do i=1,groesse_matrix
		read(10,*) (array(i,j),j=1,groesse_matrix)
	end do
	close(10)      

!Darstellung der zu berechnenden Matrix
	print*, 'Berechnung der Determinanten von zweier bis siebener Matrix'
    print*, '==========================================================='
    print*
    print*, 'gewaehlte Matrixgroesse = ', groesse_matrix
	print*
	print*,'Matrix ='
    do i=1,groesse_matrix
      do j=1,groesse_matrix
		write(*,'(F7.1)',advance="no") array(i,j)
      end do
      print*
    end do
   	print*

    ergebnis=determinante_laplace(array,groesse_matrix)
    
!Freigeben des Speichers array
    deallocate(array)

!Ergebnisausgabe
    print*
    print*,'Determinante = ', ergebnis

!Unterbrechung damit das Programm mit sichtbaren Ergebnis auch bei Start der Exe-Datei angezeigt bleibt. Weiter mit beliebiger Eingabe und Return	
read *, hilf

contains
!Liefert die Determinante einer 2er Matrix zurück
function determinante_matrix_2(array)result(d)
	double precision, dimension(2,2) :: array
    double precision ::d
	d= (array(1,1)*array(2,2))-(array(1,2)*array(2,1))
end function determinante_matrix_2

!Reduziert eine quadratische Matrix nach dem laplaceschem Verfahren um 1 (5er Matrix zu einer 4er Matrix, 4er zu einer 3er Matrix, usw.
function laplace(array, groesse_matrix, spalte)result(array_)
	integer :: groesse_matrix,spalte
	double precision, dimension(groesse_matrix,groesse_matrix), intent(in) :: array
   
	double precision, dimension(groesse_matrix-1,groesse_matrix-1) :: array_

	integer:: k,l
    integer:: i,j
	
	k=1
	l=1
    
	do i=2,groesse_matrix!beginn mit zeile 2, da zeile 1 immer die ausgewählte Zeile ist (Kann man optimieren, in dem man die  Zeile oder Spalte raussucht mit den meisten Nullen)
		do j=1,groesse_matrix
				if(j/=spalte) then!aktuelle spalte wird nicht berücksichtigt
					array_(k,l)=array(i,j)
                    l=l+1
				end if
		end do
		k=k+1
		l=1
	end do

end function laplace

double precision recursive function determinante_laplace(array, groesse_matrix)result(det)
	integer, intent(in) :: groesse_matrix	
	double precision, dimension (groesse_matrix,groesse_matrix) :: array
	double precision, dimension (groesse_matrix-1,groesse_matrix-1) :: array2
    double precision :: det
	integer,save :: vorzeichen=1
	double precision :: faktor
	double precision :: zwischensumme
	double precision :: ergebnis=0
    double precision :: hilf=0
    integer::i !schleifenvariable

	if (groesse_matrix==2) then
    	hilf=determinante_matrix_2(array)
    	det=hilf
	else
		do i=1,groesse_matrix
			zwischensumme=0
			array2=laplace(array, groesse_matrix,i)
			faktor=array(1,i)*vorzeichen
			vorzeichen=vorzeichen*(-1)
			if(array(1,i)/=0) then
				zwischensumme=faktor*determinante_laplace(array2,groesse_matrix-1)
			end if	
			ergebnis=ergebnis+zwischensumme
		end do
        det=ergebnis
	end if

end function determinante_laplace

end program determinante 

The recursive function is double precision recursive function determinante_laplace(array, groesse_matrix)result(det).
In my opinion this function is equal to the methode in java.

But it isn't so. The Fortran-program solve only 3x3 Matrix. Is the matrix higher, the result is wrong. Why?

I'am sorry for my bad english. I hope, you can understand my problem and can help to solve it.

RE: Recursion Fortran

(OP)
Thanks for the example.

But I would like to know why my function does not work. It seems to be equal to my recursive in Java. In Java it works fine. In Fortran not. I want to understand why this is so.

RE: Recursion Fortran

Quote (Runninghigh)


But I would like to know why my function does not work.
It seems to be equal to my recursive in Java.

Hallo Runninghigh,
Yes I tried your Java program and it worked fine.

There were two problems in your Fortran program in the recursive function determinante_laplace:
1. On the beginning the result was initialized, i.e.:

CODE

double precision :: ergebnis=0 
2. The sign, i.e. vorzeichen was not properly computed.
I changed the computation like in my older example

CODE

vorzeichen = merge(1, -1, mod(i,2) .eq. 1) 

Here is the corrected code which now works:

CODE

module determinante
  implicit none
contains  
  subroutine print_matrix(matrix)
    implicit none
    double precision, dimension(:,:), intent(in) :: matrix
    integer :: msize(2), i, j, m, n
    msize = shape(matrix)
    m = msize(1)
    n = msize(2)
    do i=1, m
      do j=1, n
        write(*,'(f8.2)',advance = 'no') matrix(i,j)
      end do
      write(*,*)
    end do
    write(*,*)
  end subroutine print_matrix 

  ! Liefert die Determinante einer 2er Matrix zurück
  function determinante_matrix_2(array) result(d)
    implicit none
    double precision, dimension(2,2) :: array
    double precision ::d
    d= (array(1,1)*array(2,2))-(array(1,2)*array(2,1))
  end function determinante_matrix_2

  ! Reduziert eine quadratische Matrix nach dem laplaceschem Verfahren um 1 
  ! (5er Matrix zu einer 4er Matrix, 4er zu einer 3er Matrix, usw.
  function laplace(array, groesse_matrix, spalte) result(array_)
    implicit none
    integer :: groesse_matrix,spalte
    double precision, dimension(groesse_matrix,groesse_matrix), intent(in) :: array
    double precision, dimension(groesse_matrix-1,groesse_matrix-1) :: array_
    integer:: k,l
    integer:: i,j
    k=1
    l=1
    ! beginn mit zeile 2, da zeile 1 immer die ausgewählte Zeile ist 
    ! (Kann man optimieren, in dem man die Zeile oder Spalte raussucht mit den meisten Nullen)
    do i=2,groesse_matrix
      do j=1,groesse_matrix
        if(j/=spalte) then !aktuelle spalte wird nicht berücksichtigt
          array_(k,l)=array(i,j)
          l=l+1
        end if
      end do
      k=k+1
      l=1
    end do
  end function laplace

  recursive function determinante_laplace(array, groesse_matrix) result(det)
    implicit none
    integer, intent(in) :: groesse_matrix
    double precision, dimension (groesse_matrix,groesse_matrix) :: array
    double precision, dimension (groesse_matrix-1,groesse_matrix-1) :: array2
    double precision :: det
    integer :: vorzeichen
    double precision :: faktor
    double precision :: zwischensumme
    double precision :: ergebnis
    double precision :: hilf=0
    integer::i !schleifenvariable

    if (groesse_matrix==2) then
      hilf=determinante_matrix_2(array)
      det=hilf
    else
      do i=1,groesse_matrix
        zwischensumme=0
        array2=laplace(array, groesse_matrix,i)
        ! computing sign
        if (mod(i,2) .eq. 1) then
          vorzeichen = 1
        else
          vorzeichen = -1
        end if
        ! or shorter:  
        !vorzeichen = merge(1, -1, mod(i,2) .eq. 1)
        faktor=array(1,i) * vorzeichen
        if(faktor/=0) then
          zwischensumme=faktor * determinante_laplace(array2,groesse_matrix-1)
        end if
        ergebnis=ergebnis + zwischensumme
      end do
      det=ergebnis
    end if
  end function determinante_laplace
end module determinante

program runninghigh
  use determinante
  implicit none
  double precision :: A1(1,1), A2(2, 2), A3(3, 3), A4(4,4), A5(5,5)
  double precision :: det 

  ! matrix A2
  A2(1,:)=(/7, 6/)
  A2(2,:)=(/3, 9/)
  write(*,*) 'Matrix A2:'
  write(*,*) '----------'
  call print_matrix(A2)
  write(*,*) 'Determinant of A2:'
  write(*,*) '-----------------'
  write(*,*) determinante_laplace(A2, 2)
  write(*,*)

  ! matrix A3
  A3(1,:)=(/-2, 2, -3/)
  A3(2,:)=(/-1, 1,  3/)
  A3(3,:)=(/ 2, 0, -1/)
  write(*,*) 'Matrix A3:'
  write(*,*) '----------'
  call print_matrix(A3)
  write(*,*) 'Determinant of A3:'
  write(*,*) '-----------------'
  write(*,*) determinante_laplace(A3, 3)
  write(*,*)

  ! matrix A4
  A4(1,:)=(/3, 0, 2, -1/)
  A4(2,:)=(/1, 2, 0, -2/)
  A4(3,:)=(/4, 0, 6, -3/)
  A4(4,:)=(/5, 0, 2,  0/)
  write(*,*) 'Matrix A4:'
  write(*,*) '----------'
  call print_matrix(A4)
  write(*,*) 'Determinant of A4:'
  write(*,*) '-----------------'
  write(*,*) determinante_laplace(A4, 4)
  write(*,*)

  ! matrix A5
  A5(1,:)=(/5, 2, 0, 0, 2/)
  A5(2,:)=(/0, 1, 4, 3, 2/)
  A5(3,:)=(/0, 0, 6, 2, 3/)
  A5(4,:)=(/0, 0, 4, 3, 1/)
  A5(5,:)=(/0, 0, 0, 0, 2/)
  write(*,*) 'Matrix A5:'
  write(*,*) '----------'
  call print_matrix(A5)
  write(*,*) 'Determinant of A5:'
  write(*,*) '-----------------'
  write(*,*) determinante_laplace(A5, 5)
  write(*,*)    
end program runninghigh 

Compilation and running

CODE

$ gfortran runninghigh.f95 -o runninghig

$ runninghigh
 Matrix A2:
 ----------
    7.00    6.00
    3.00    9.00

 Determinant of A2:
 -----------------
   45.000000000000000

 Matrix A3:
 ----------
   -2.00    2.00   -3.00
   -1.00    1.00    3.00
    2.00    0.00   -1.00

 Determinant of A3:
 -----------------
   18.000000000000000

 Matrix A4:
 ----------
    3.00    0.00    2.00   -1.00
    1.00    2.00    0.00   -2.00
    4.00    0.00    6.00   -3.00
    5.00    0.00    2.00    0.00

 Determinant of A4:
 -----------------
   20.000000000000000

 Matrix A5:
 ----------
    5.00    2.00    0.00    0.00    2.00
    0.00    1.00    4.00    3.00    2.00
    0.00    0.00    6.00    2.00    3.00
    0.00    0.00    4.00    3.00    1.00
    0.00    0.00    0.00    0.00    2.00

 Determinant of A5:
 -----------------
   100.00000000000000 




RE: Recursion Fortran

P.S.:
I forgot to remove the variable hilf

CODE

double precision :: hilf 
It's not needed, you can can assign the result of a function to det

CODE

...
    if (groesse_matrix==2) then
      det=determinante_matrix_2(array)
    else
... 

RE: Recursion Fortran

(OP)
Thank you, great work. Now it works. Very fine.

Hilf I used only for debugging, but in vain.

Can you tell me why it is in Fortran a mistake to initialize Ergebnis?
In Java the Compiler complains, then I write ergebnis+=zwischensumme, because ergebnis has no current value. So I initialize ergebnis with 0, the value in the beginning.
If the first time is reached , the line Ergebnis=Ergebnis+1 , which makes the Compiler in Fortran when ergebnis is not initialized ?

RE: Recursion Fortran

Quote:


Can you tell me why it is in Fortran a mistake to initialize Ergebnis?
The same question I asked myself smile
I'm not sure ... but there must be a diffrence how the function behave in fortran and in Java.

If you initialize your variables in the declaration section of the function i.e. here

CODE

...
    integer :: vorzeichen=1
    ...
    double precision :: ergebnis=0
... 
the results are false.

But, if you initialize your variables in the function body i.e.

CODE

...
    integer :: vorzeichen
    ...
    double precision :: ergebnis
    integer::i !schleifenvariable
    ...
    vorzeichen=1
    ergebnis=0
    if (groesse_matrix==2) then
      det=determinante_matrix_2(array)
    else
... 
then the computation works as expected.

Maybe in the first case, the compiler thinks, that ergebnis and vorzeichen are constants and not variables?

So you can keep your formula
vorzeichen = vorzeichen * (-1)
too, i.e. the working function is

CODE

recursive function determinante_laplace(array, groesse_matrix) result(det)
    implicit none
    integer, intent(in) :: groesse_matrix
    double precision, dimension (groesse_matrix,groesse_matrix) :: array
    double precision, dimension (groesse_matrix-1,groesse_matrix-1) :: array2
    double precision :: det
    integer :: vorzeichen
    double precision :: faktor
    double precision :: zwischensumme
    double precision :: ergebnis
    integer::i !schleifenvariable

    vorzeichen=1
    ergebnis=0
    if (groesse_matrix==2) then
      det=determinante_matrix_2(array)
    else
      do i=1,groesse_matrix
        zwischensumme=0
        array2=laplace(array, groesse_matrix,i)
        faktor=array(1,i) * vorzeichen
        vorzeichen=vorzeichen * (-1)
        if(faktor/=0) then
          zwischensumme=faktor * determinante_laplace(array2,groesse_matrix-1)
        end if
        ergebnis=ergebnis + zwischensumme
      end do
      det=ergebnis
    end if
  end function determinante_laplace 

To answer your question exactly, I needed to install a debugger, because when I try to print out the values of some variables in the code, for example like here

CODE

recursive function determinante_laplace(array, groesse_matrix) result(det)
    ...
    vorzeichen=1
    ergebnis=0
    write(*,*) ergebnis
    if (groesse_matrix==2) then
      det=determinante_matrix_2(array)
    else
      do i=1,groesse_matrix
    ... 
then the programm execution seems to stop.

RE: Recursion Fortran

(OP)
That's the solution I think. The Compiler thinks, that are constants, even though the keyword Parameter is missing.

On the idea that since the error might be , I would never have come.

RE: Recursion Fortran

Quote:


The Compiler thinks, that are constants,...
It doesn't seem to be true with the constant, it was only my frustrated guess smile

But according to the link from salgerman, it seems that the variables ergebnis and vorzeichen were initialized only in the first function call and not on the subsequent recursive calls.
You can install a debugger and explore this fact.

RE: Recursion Fortran

(OP)
This is really unexpected . I have checked two days ago with print*, individual values ​​and it was from matrix size 4x4 all nonsense , that was in ergebnis. I could not explain it.

Many thanks for the help. The problem is solve. smile

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close