Axelrod-Python / axelrod-fortran

Python wrapper library around TourExec Fortran for Axelrod's second tournament.
Other
4 stars 0 forks source link

Fortran question: why does k90r not behave as expected? #59

Closed drvinceknight closed 7 years ago

drvinceknight commented 7 years ago

The k90r strategy https://github.com/Axelrod-Python/TourExec/blob/master/src/strategies/k90r.f is documented as being Tit For 2 Tats. Looking at the source code it certainly looks like Tf2T:

      FUNCTION K90R(J,M,K,L,R, JA)
C BY JOHN MAYNARD SMITH
C TYPED BY AX 3/27/79 (SAME AS ROUND ONE TIT FOR TWO TATS)
      k90r=ja    ! Added 7/27/93 to report own old value
C recoded by Ax 7/27/93
      if(m.eq.1) jold=0
      k90r=0
      if((jold.eq.1).and.(j.eq.1)) k90r=1
      jold=j
     RETURN
      END

but it does not act as Tf2T:

>>> import axelrod as axl
>>> import axelrod_fortran as axlf
>>> tf2t = axl.TitFor2Tats()
>>> axlf_tf2t = axlf.Player("k90r")
>>> antitft = axl.AntiTitForTat()

Against AntitfT we see that the python version behaves as expected (punishing 2 defections with a defection):

>>> match = axl.Match((tf2t, antitft), turns=5)
>>> match.play()
[(C, C), (C, D), (C, D), (D, D), (D, C)]

However the fortran version does not:

>>> match = axl.Match((axlf_tf2t, antitft), turns=5)
>>> match.play()
[(C, C), (C, D), (C, D), (C, D), (C, D)]

In fact as far as I can tell it never defects:

>>> match = axl.Match((axlf_tf2t, axl.Defector()), turns=500)
>>> results = match.play()
>>> set(results)
{(C, D)}

Returning to the source code, I think this indicates that jold is not being "remembered" correctly? Could this be something to do with the modern Fortran compiler? Is there anything obviously incorrect in the Fortran code? (I'm not suggesting we modify it, just trying to understand.)

(This was brought to my attention because this strategy is one that ranks very differently in the replicated tournament.)

meatballs commented 7 years ago

This could be a "God is real" issue. jold is never declared as an integer, so it will be treated as a real. I wonder if that means the conditional j.eq.1 never evaluates to true.

drvinceknight commented 7 years ago

That would make sense. Would this be something that would have changed/been different with an older version of the Fortan compiler?

meatballs commented 7 years ago

No, this behaviour has been a feature of Fortran from the beginning and still applies today - if you don't explicitly declare a variable's type, the first letter of its name is used: A-N is integers and anything else is a real.

I did have to fix a couple of bugs in the original code with a similar issue. There were variables used as indexes for arrays which had not been declared as integers, were treated as reals and a modern compiler refused to allow that. I had to add the declaration to get them to compile.

drvinceknight commented 7 years ago

No, this behaviour has been a feature of Fortran from the beginning and still applies today - if you don't explicitly declare a variable's type, the first letter of its name is used A-N is integers and anything else is a real.

How strange... Weird because I want to believe that it worked the first time around (given the discrepancy in the results) or perhaps someone modified the code in between.

I did have to fix a couple of bugs in the original code with a similar issue. There were variables used as indexes for arrays which had not been declared as integers, were treated as reals and a modern compiler refused to allow that. I had to add the declaration to get them to compile.

Yeah, looking at https://github.com/Axelrod-Python/TourExec/releases I believe the only one you modified is K74RXX?

(These questions (here and at #60) are just to use in my write up of the revisiting paper, to explain discrepancies etc :))

meatballs commented 7 years ago

It's possible that earlier compilers allowed the conditional to work. i.e. jold.eq.1 might return true if jold were 1.0 It certainly doesn't work now (and didn't even back in 1987 when I last used Fortran)!

drvinceknight commented 7 years ago

Make sense @meatballs. Thanks! I'm closing these and will include relevant explanation in the write up :+1:

meatballs commented 7 years ago

I'd suggest re-opening this, creating a branch, adding the declaration, compiling and testing whether the results are different.

drvinceknight commented 7 years ago

I'd suggest re-opening this, creating a branch, adding the declaration, compiling and testing whether the results are different.

Good idea. If I just change the name of the variable to start with A-N that should do it right?

(I don't think we push the "fixed" version to the TourExec repo. We've already got working version of the two strategies in question and keeping TourExec as close to "as was" is good as it allows for comparisons etc.)

meatballs commented 7 years ago

Good idea. If I just change the name of the variable to start with A-N that should do it right?

Yes, but it might be nicer to just add the declaration - keeps it as close to the original as possible

(I don't think we push the "fixed" version to the TourExec repo. We've already got working version of the two strategies in question and keeping TourExec as close to "as was" is good as it allows for comparisons etc.)

Agreed

drvinceknight commented 7 years ago

Here's what I've gone for:

    1       FUNCTION K90R(J,M,K,L,R, JA)                                                                                                              
    2 C BY JOHN MAYNARD SMITH                                                                                                                         
    3 C TYPED BY AX 3/27/79 (SAME AS ROUND ONE TIT FOR TWO TATS)                                                                                      
+   4       INTEGER jold                                                                                                                              
    5       k90r=ja    ! Added 7/27/93 to report own old value                                                                                        
    6 C recoded by Ax 7/27/93                                                                                                                         
    7       if(m.eq.1) jold=0                                                                                                                         
    8       k90r=0                                                                                                                                    
    9       if((jold.eq.1).and.(j.eq.1)) k90r=1                                                                                                       
   10       jold=j                                                                                                                                    
   11      RETURN                                                                                                                                     
   12       END                                                                                                                                                            

Doesn't seem to be working, am I doing something stupid with the declaration?

meatballs commented 7 years ago

No. I'm an idiot.

It's A-H and O-Z which are reals. I, J, K, L, M and N are integers

meatballs commented 7 years ago

It could be as daft as the mis-alignment of the RETURN statement in line 11. That should have an extra space in front of it.

drvinceknight commented 7 years ago

It could be as daft as the mis-alignment of the RETURN statement in line 11. That should have an extra space in front of it.

Hahaha immediately fixed it!

meatballs commented 7 years ago

I had to fix the alignment of a large amount of the downloaded code. The html formatting played havoc with it.

It looks like I missed one here.

drvinceknight commented 7 years ago

Looking at http://www-personal.umich.edu/~axe/research/Software/CC/CC2/TourExec1.1.f.html it actually looks like the alignment there was correct (it actually has an extra space in the other direction but I've checked and that works)... So I suggest we fix it on TourExec.

meatballs commented 7 years ago

It all 'looks' ok in a browser. Not so much when the raw text is downloaded!!

drvinceknight commented 7 years ago

Cool. I've opened https://github.com/Axelrod-Python/TourExec/pull/5 which fixes it there. Once we've figured out #60 (perhaps something just as trivial?) I'll rerun the original tournament again and see if there are other things that stick out :) :+1:

(Good call on reopening!)