forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

DO-loop in recursive Function
Goto page 1, 2  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
Garling



Joined: 26 Nov 2014
Posts: 3

PostPosted: Thu Nov 27, 2014 12:35 pm    Post subject: DO-loop in recursive Function Reply with quote

Hello,
task of the recursive function below is to analyse a network of of elements. The elements are characterized by a section no. "iA" and an element no "iM".
Each element can have up to 8 inlets and outlets. IANMSA is the number of oulets of an element. The circuitry of the elements is stored in the arrays IAANRA, IAMNRA.
At runtime the error "Active Do-loop index altered" occurs.

Recursive Function CFBCheckLoop(iA, iM) RESULT(KFehl)
Integer, Intent(in) :: iA, iM
Integer :: KFehl
Integer :: iT, iA1, iM1
if (iA == WSMem%IAVB) then
KFehl = 0
else if (kkdms(iA,iM) == 506) then
KFehl = 1
else
do iT = 1, IANMSA(iA, iM)
iA1 = IAANRA(iA, iM, iT)
iM1 = IAMNRA(iA, iM, iT)
if (iA1 == 0) then
KFehl = 2
else
KFehl = CFBCheckLoop(iA1, iM1)
end if
if (KFehl > 0) Exit
end do
end if
End Function CFBCheckLoop

Obviously the inner instance of the recursive function changes the index "iT" of the calling instance of the function. The variable iT is declared inside the function. Normally each instance of an recursive function should have its own protected internal variables, which cannot be changed from outside. They should also be protected against changes from another instance of the function. I have used recursive functions like this in Delphi/Pascal many times without any problems.
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Thu Nov 27, 2014 2:48 pm    Post subject: Reply with quote

I don't see that the recursion has anything to do with the error. Inside the DO loop, you are passing the loop index as an argument to the function IANMSA. If that function changes its third argument, the code is illegal and runtime behavior is unpredictable. Section 8.1.6.6.2, Clause 2 of the Fortran 2008 standard states, "Except for the incrementation of the DO variable that occurs in step (3), the DO variable shall neither be rede fined nor become unde fined while the DO construct is active." Similar statements can be seen in Section 8.1.6.4.2 of the F2003 standard and earlier standards.
Postscript: If IANMSA is an array, is there a declaration in scope for it?


Last edited by mecej4 on Thu Nov 27, 2014 2:56 pm; edited 1 time in total
Back to top
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Thu Nov 27, 2014 2:49 pm    Post subject: Re: DO-loop in recursive Function Reply with quote

Garling wrote:

Normally each instance of an recursive function should have its own protected internal variables, which cannot be changed from outside. They should also be protected against changes from another instance of the function.


Yes, this is exactly how it works (local variables are created on the stack for each function invocation). This is guaranteed if you use the RECURSIVE declaration but you need to create an explicit interface for the function where you call it from outside.

I have not found any problems with Recursion with this compiler. However, there is too much missing from your example to debug your problem. Too many arrays that are not there.

Could you produce a simpler version which is self-contained that could be compiled and run to demonstrate the error.

Looking at your code I can't see anywhere that IT would be re-defined. What does the stack trace look like when you call this from the debugger; how many times is your function called? Is the error in some other function? (Look at the stack).
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl
Back to top
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Thu Nov 27, 2014 2:51 pm    Post subject: Reply with quote

mecej4

My reading of this is that IANMSA is supposed to be an array (not a function) that is somehow in scope. So that would mean this function is part of a module or an internal function.
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl


Last edited by davidb on Thu Nov 27, 2014 2:58 pm; edited 1 time in total
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Thu Nov 27, 2014 2:52 pm    Post subject: Re: Reply with quote

mecej4 wrote:
I don't see that the recursion has anything to do with the error. Inside the DO loop, you are passing the loop index as an argument to the function IANMSA. If that function changes its third argument, the code is illegal and runtime behavior is unpredictable. Section 8.1.6.6.2, Clause 2 of the Fortran 2008 standard states, "Except for the incrementation of the DO variable that occurs in step (3), the DO variable shall neither be rede fined nor become unde fined while the DO construct is active." Similar statements can be seen in Section 8.1.6.4.2 of the F2003 standard and earlier standards.


Another possible source of error. In a call to CFBCheckLoop from elsewhere (i.e., other than calls to self), the function result type would be wrong with IMPLICIT variable typing.
Back to top
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Thu Nov 27, 2014 2:55 pm    Post subject: Reply with quote

No, the function would need to have an explicit interface so could deduce that the function returns an integer.

There could be numerous problems. We just don't know without seeing the code.

My guess is the error has nothing to do with this function at all, which is why I suggested the OP looks at the stack trace (to find the real culprit)
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl
Back to top
View user's profile Send private message
Garling



Joined: 26 Nov 2014
Posts: 3

PostPosted: Fri Nov 28, 2014 10:05 am    Post subject: Reply with quote

Sorry for the incomplete source code,
as davidb supposed the function is an internal function after a "CONTAINS" in a subroutine. IANMSA, IAANRA, IAMNRA and KKDMS are arrays, which contain information about the circuitry and the type of element. The variable iT is exclusively changed by the Do-loop itself. The function is called once from its owner-subroutine within a complex program containing about 250000 lines of source-code.
I have reduced the problem to some 50 lines:

Program Rekursion
Integer, Dimension (10, 8) :: IANMSA
Integer, Dimension (10, 8, 8) :: IAANRA, IAMNRA
Integer :: iAVB , KF

IANMSA(1, 1) = 2
IANMSA(2, 1) = 2
IANMSA(3, 1) = 1
IANMSA(4, 1) = 1
IANMSA(5, 1) = 1
IANMSA(6, 1) = 0
IAANRA(1, 1, 1) = 2
IAANRA(1, 1, 2) = 5
IAANRA(2, 1, 1) = 3
IAANRA(2, 1, 2) = 4
IAANRA(3, 1, 1) = 6
IAANRA(4, 1, 1) = 6
IAANRA(5, 1, 1) = 6
IAMNRA(1, 1, 1) = 1
IAMNRA(1, 1, 2) = 1
IAMNRA(2, 1, 1) = 1
IAMNRA(2, 1, 2) = 1
IAMNRA(3, 1, 1) = 1
IAMNRA(4, 1, 1) = 1
IAMNRA(5, 1, 1) = 1
IAVB = 6

KF = CFBCheckLoop(1, 1)

CONTAINS

Recursive Function CFBCheckLoop(iA, iM) RESULT(KFehl)
Integer, Intent(in) :: iA, iM
Integer :: KFehl
Integer :: iT, iA1, iM1
if (iA == IAVB) then
KFehl = 0
else
do iT = 1, IANMSA(iA, iM)
iA1 = IAANRA(iA, iM, iT)
iM1 = IAMNRA(iA, iM, iT)
if (iA1 == 0) then
KFehl = 1
else
KFehl = CFBCheckLoop(iA1, iM1)
end if
if (KFehl > 0) Exit
end do
end if
End Function CFBCheckLoop

End Program Rekursion
Back to top
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Fri Nov 28, 2014 8:21 pm    Post subject: Reply with quote

This new version compiles and runs just fine for me (even with CheckMate enabled to check for re-definition of do loop variables). I can confirm the call stack grows and shrinks properly with a different activation record created at each function invocation.

What compiler version are you using?

What compile options have you got set?
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Fri Nov 28, 2014 10:46 pm    Post subject: Reply with quote

I think that in extracting the code and reducing it to a small size you removed the part that was causing the problem. I do not find any problems in the putative "reproducer", and DavidB has said the same.

I do notice a potential problem. In the contained function, if the loop upper limit is less than 1, the function returns without the function value having been defined. This would happen if, for example, you raised the value of IAVB to 7.
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2554
Location: Sydney

PostPosted: Sat Nov 29, 2014 10:36 am    Post subject: Reply with quote

I have changed the sample program to track the calls.
The returned value is always 0.
Is this what it should do ?
Code:
Program Rekursion
 Integer, Dimension (10, 8) :: IANMSA
 Integer, Dimension (10, 8, 8) :: IAANRA, IAMNRA
 Integer :: iAVB , KF, lev

   IANMSA(1, 1) = 2
   IANMSA(2, 1) = 2
   IANMSA(3, 1) = 1
   IANMSA(4, 1) = 1
   IANMSA(5, 1) = 1
   IANMSA(6, 1) = 0
!
   IAANRA(1, 1, 1) = 2
   IAANRA(1, 1, 2) = 5
   IAANRA(2, 1, 1) = 3
   IAANRA(2, 1, 2) = 4
   IAANRA(3, 1, 1) = 6
   IAANRA(4, 1, 1) = 6
   IAANRA(5, 1, 1) = 6
!
   IAMNRA(1, 1, 1) = 1
   IAMNRA(1, 1, 2) = 1
   IAMNRA(2, 1, 1) = 1
   IAMNRA(2, 1, 2) = 1
   IAMNRA(3, 1, 1) = 1
   IAMNRA(4, 1, 1) = 1
   IAMNRA(5, 1, 1) = 1
!
   IAVB = 6
   lev  = 1

   KF = CFBCheckLoop(1, 1, lev, 0)
   write (*,*) Kf

 CONTAINS

 Recursive Function CFBCheckLoop(iA, iM, lev, iTe) RESULT(KFehl)
 Integer, Intent(in) :: iA, iM, lev, iTe
 Integer :: KFehl
 
 Integer :: iT, iA1, iM1, levn

 write (*,fmt='(a,4i4)') 'entry', lev, iA, iM, iTe

 if (iA == IAVB) then
   iT    = -1
   KFehl = 0
 else
   do iT = 1, IANMSA(iA, iM)
     iA1 = IAANRA(iA, iM, iT)
     iM1 = IAMNRA(iA, iM, iT)
     if (iA1 == 0) then
       KFehl = 1
     else
       levn  = lev + 1
       KFehl = CFBCheckLoop (iA1, iM1, levn, iT)
     end if
     if (KFehl > 0) Exit
   end do
 end if
 write (*,fmt='(a,5i4)') 'exit ', lev, iA, iM, iT, KFehl
 End Function CFBCheckLoop

 End Program Rekursion

Results are
Code:
      Lev  iA  iM  iT KFehl
entry   1   1   1   0
entry   2   2   1   1
entry   3   3   1   1
entry   4   6   1   1
exit    4   6   1  -1   0
exit    3   3   1   2   0
entry   3   4   1   2
entry   4   6   1   1
exit    4   6   1  -1   0
exit    3   4   1   2   0
exit    2   2   1   3   0
entry   2   5   1   2
entry   3   6   1   1
exit    3   6   1  -1   0
exit    2   5   1   2   0
exit    1   1   1   3   0
            0
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Sat Nov 29, 2014 2:30 pm    Post subject: Reply with quote

Quote:
The returned value is always 0. Is this what it should do ?

I think that there is no problem there. In fact, KFEHL could have been LOGICAL rather than INTEGER and, for English speakers, KFEHL could have been spelled KFAIL or LERROR.

Thus, it makes sense that KFEHL comes out with a value corresponding to "NO ERROR", indicating that the logic implemented in the program is correct to the extent that the run did not encounter any instance of the logic being wrong. In other words, KFEHL.EQ.0 is a "sanity check".
Back to top
View user's profile Send private message
Garling



Joined: 26 Nov 2014
Posts: 3

PostPosted: Mon Dec 01, 2014 10:41 am    Post subject: Reply with quote

Hello,
I am a little bit surprised, that you have no problems with this code.
When I run this reduced program, I get a runtime error:

Error: Active Do-loop index altered

REKURSION~CFBCHECKLOOP - in file rekursion.f95 at line 45 [+02e6] [recur= 1]
main - in file rekursion.f95 at line 28 [+0138]

I am using the version 7.1.0.0 of the ftn95.exe from 2014/04/27.
My ftn95.cfg contains the following option:

/132
/CHECK
/COLOUR
/DELETE_OBJ_ON_ERROR
/INTL
/LOGL
/NO_BANNER
/PAUSE_ON_ERROR
/SAVE
/ZEROISE
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2554
Location: Sydney

PostPosted: Mon Dec 01, 2014 12:15 pm    Post subject: Reply with quote

/save and Recursive are definitely incompatible. Make sure you understand this is a requirement for recursive.
I am not sure about /zero also.

Remove /save and check that /zero is not needed, by initialising all appropriate variables before use and it should work.

John
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Mon Dec 01, 2014 2:39 pm    Post subject: Reply with quote

Garling: I second what John said about recursion and /save being incompatible. To see this for yourself, take the program that you gave above (Fri Nov 28, 2014 9:05 am)

1. Add "iasav" to the declarations of integer variables in the main program
2. Add "iasav=ia" before the recursive call in the subroutine.
3. Add the following after the recursive call:

if(iasav.ne.ia)then
write(*,*)'IA changed from ',iasav,' to ',ia
stop
endif

Now compile and run (i) first without /save, then with /save. You may be surprised that invoking a function results in IA being changed even though the function arguments (and the variable to which the function value is assigned) are all variables other than IA. But that is precisely what happens when you use /save together with recursion.

Let me point out that it is possible to write a non-recursive version of the function, and you should consider taking this approach if you must use /save for the other portions of the program. However, note that using /save is often a temporary fix for a serious problem.
Back to top
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Tue Dec 02, 2014 9:41 am    Post subject: Reply with quote

I agree. You cannot use /SAVE with recursive subprograms.

However, note that.

(1) The compiler should be detecting the recursive function (in this case) and should switch off the effect of /SAVE in this function. If it doesn't, this may be a bug or an oversight with the compiler (Paul could perhaps look at this?)

(2) If you need to save variables then it is better to insert SAVE statements in the appropriate subroutines and functions. This issue does not then arise. Note the compiler will correctly show an error if SAVE is inserted into a RECURSIVE subprogram.

(3) You may be able to fix your program and still use /SAVE by adding the PURE declaration (as well as RECURSIVE) to your function. The compiler may then switch /SAVE off properly (I have not tried this though).
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group