-1

I was hoping that someone would be able to review my code for a summer project and let me know where I messed up. This is a random walk, but I make it so that when a walker goes over 6, it goes back to 1 and vise versa. Additionally, when there are multiple walkers, then the program makes sure that only two max can occupy the same "site". Whenever I try to build this program through SilverFrost and Geany, it fails, whereas when I use an online Fortran builder and make it print instead of write the data on a text file, it works. The error message was

Error 112, Reference to undefined variable, array element or function result (/UNDEF) main - in file dddd.f95 at line 102 [+0c8d]

Line 102 is this:

position(e,n)=position(e,n)+2

Here's the code:

program FiniteRandomWalkWithSites
implicit none
integer :: position(4,1000),n,y,g,m,z,e ! The 2 used in the declaration can be changed in order to create n-number of walkers
real::x,onethird,twothird
real, dimension(1000)::random
onethird=1.00/3.00
twothird=2.00/3.00
do n=1,1000
    position(1,n)=n
end do
do z=2,4 !Despite the fact that this do loop is redundant with just 1 "position column", the ending value ought to be modified to the same value as the one made on line 3
    y=1
    m=0
    do n=1,1000
        call random_number(x)
        random(n)=x
            if (x .le. onethird) then
                m=y+1
                if (m .gt. 6) then
                    m=1
                    y=m
                    position(z,n)=m          
                else if (m .lt. 1) then
                    m=6
                    y=m
                    position(z,n)=m
                else
                    m=m
                    y=m
                    position(z,n)=m
                end if
            else if ((x .gt. onethird) .and. (x .le. twothird)) then
                m=y-1
                if (m .gt. 6) then
                    m=1
                    y=m
                    position(z,n)=m
                else if (m .lt. 1) then
                    m=6
                    y=m
                    position(z,n)=m
                else
                    m=m
                    y=m
                    position(z,n)=m
                end if
            else               
                m=y+0
                if (m .gt. 6) then
                    m=1
                    y=m    
                    position(z,n)=m
                else if (m .lt. 1) then
                    m=6
                    y=m
                    position(z,n)=m
                else
                    m=m
                    y=m
                    position(z,n)=m
                end if
            end if
    end do
end do
jloop:do z=2,4
    ploop:do n=1,1000
        if ((position(z,n) .eq. position(z+1,n)) .and. (position(z,n) .eq. position(z+2,n))) then
            call random_number(x)
            if (z .eq. 2) then            
                if (x .le. onethird) then
                    e=z
                else if ((x .gt. onethird) .and. (x .le. twothird)) then
                    e=z+1
                else
                    e=z+2
                end if
            else if (z .eq. 3) then            
                if (x .le. onethird) then
                    e=z
                else if ((x .gt. onethird) .and. (x .le. twothird)) then
                    e=z+1
                else
                    e=z-1
                end if
            else if (z .eq. 4) then            
                if (x .le. onethird) then
                    e=z
                else if ((x .gt. onethird) .and. (x .le. twothird)) then
                    e=z-1
                else
                    e=z-2
                end if
            end if                                                
        end if
        if (random(n) .le. onethird) then
            if (x .lt. .50) then
                position(e,n)=position(e,n)+1
                if (position(e,n) .gt. 6) then
                    position(e,n)=1
                end if                
            else if (x .gt. .50) then
                position(e,n)=position(e,n)+2
                if (position(e,n) .gt. 6) then
                    position(e,n)=1
                end if                
            end if
        else if ((random(n) .gt. onethird) .and. (random(n) .le. twothird)) then
            if (x .lt. .50) then
                position(e,n)=position(e,n)-1
                if (position(e,n) .lt. 1) then
                    position(e,n)=6
                end if
            else if (x .gt. .50) then
                position(e,n)=position(e,n)-2
                if (position(e,n) .lt. 1) then
                    position(e,n)=6
                end if                
            end if
        else
            if (x .lt. .50) then
                position(e,n)=position(e,n)+1
                if (position(e,n) .gt. 6) then
                    position(e,n)=1
                end if
            else if (x .gt. .50) then
                position(e,n)=position(e,n)-1
                if (position(e,n) .lt. 1) then
                    position(e,n)=6
                end if
            end if
        end if
    end do ploop
end do jloop
do g=1,1000
        print*, position(1,g),position(2,g),position(3,g),position(4,g)!...position(a,g) [where a is rightmost column #]
end do

end program FiniteRandomWalkWithSites
Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36
Jack Tapay
  • 15
  • 3
  • Please supply the error messages you get as well. Furthermore you mention " 0 down vote favorite I was hoping that someone would be able to review my code for a summer project" this is off-topic here and should be asked at https://codereview.stackexchange.com/ – albert Jul 13 '18 at 14:48
  • @albert, generally questions about reviewing code on that site should be about code that works. From the question I gather it doesn't. – francescalus Jul 13 '18 at 14:52
  • Thanks for adding the error message. In this case, however, the message tells you about all you need to know (assuming it's correct - without counting to see which is line 102 I can't tell): you are referencing a variable that hasn't yet been defined. If you have somethng like `x=y` then you should make sure `y` has first been given a value. – francescalus Jul 13 '18 at 15:19
  • 1
    If you need help understanding what is meant by the error message, then it may be better for you to come up with code which is a lot clearer (and shorter). See [mcve], for example. – francescalus Jul 13 '18 at 15:19
  • @francescalus Indeed code should work, but the question states it works online. – albert Jul 13 '18 at 15:27
  • @albert, perhaps it may be better stated as "_appears_ to work online". Looking at the error message the working is just because the online compiler was less fussy. [I agree that CR is a plausible site for reviewing working code, and a shame there aren't more questions I'd like to answer there.] – francescalus Jul 13 '18 at 15:28
  • @francescalus I agree with that. – albert Jul 13 '18 at 15:30
  • I'd say it could be an undefined element in one of your arrays. Do like francescakus said: elaborate a minimum example, with lower array sizes too. If you have access to a debugger, put a break point and check the contents of your variables there. – Rodrigo Rodrigues Jul 13 '18 at 15:31
  • Also, there is no point in local caching `onethird` and `twothird`, because `1.0 / 2.0` is a constant-valued expression and would be changed to a constant value at compile time. It would be useful if you plan to change the ratios later, but in this case you should really rename your variables. – Rodrigo Rodrigues Jul 13 '18 at 15:39
  • 1
    `if ((position(z,n) .eq. position(z+1,n)) .and. (position(z,n) .eq. position(z+2,n)))` what is supposed to happen when z=3 or z=4? – Rodrigo Rodrigues Jul 13 '18 at 15:45
  • 2
    I can imagine the program flow to be such that `e` hasn't been set by the time line 102 is reached. – francescalus Jul 13 '18 at 16:32
  • Indeed, @francescalus, if this `if ((position(z,n) .eq. position(z+1,n)) .and. (position(z,n) .eq. position(z+2,n)))` is false, `e` is never assigned. (And by the way, this if statement is broken, as I said in previous comment) – Rodrigo Rodrigues Jul 13 '18 at 17:22

1 Answers1

0

I don't understand why this Fortran program won't build

Short answer

Me neither. Probably because it is broken in many ways. It may or may not compile depending on the compiler and the specific compile options passed. It also may or may not crash at runtime.


Extended answer

Error 112, Reference to undefined variable, array element or function result (/UNDEF) main - in file dddd.f95 at line 102 [+0c8d]

My compiler actually compiles, but gives a better error report at runtime:

forrtl: severe (194): Run-Time Check Failure. The variable 'FINITERANDOMWALKWITHSITES$E' is being used in '.\main.f90(102,17)' without being defined

The variable e reaches this point of the program without being defined. What does it mean? Fortran Standard calls "defined" a data object that has a valid value. Roughly speaking, it means that you have assigned a value to this variable at any previous time in the program run. "But I did assign a value to it in the previous if block!", you may say.

if ((position(z,n) .eq. position(z+1,n)) .and. (position(z,n) .eq. position(z+2,n))) then
  call random_number(x)
  if (z .eq. 2) then            
    if (x .le. onethird) then
      e=z
  ! (...)
end if

The problem is: if the condition of your if statement is not met (and it won't meet in many iterations, depending on the random number generated), the inner code won't be executed. If this happen at the first iteration, you have not passed through the body of the if construct anytime yet and e had never had any value given to it when you reach the line of code indicated by the error.

A compiler is not supposed to detect this kind of error at compile time, that's why it is so strange that you couldn't get it compiled. Maybe your compiler can parse and scan all conditional branches of the code and look for possibly undefined variables. I've never seen that, to be honest.

But that is not that important. What is important here is that it is a severe error and your program may crash (or, unluckly, not) because of access violation, that is when you try to access a memory address that is not managed by your program (or write a readonly), sometimes cause by an array out-of-bounds problem.

How could it happen? Well, by default, Fortran do not check array indices at runtime. You are supposed to do it, at code time. If e is undefined (and you didn't specify checks for undefined variables as compiler options) and you try to use it, it's value may contain some garbage value that was already set on the memory address it is using. That's a Pandora's box for all sort of unpredictable behavior. E.g., if e has a value 0, position(e,n)=position(e,n)+2 would try to find a column 0 of the array (that could be any other memory address of the system) and try to write/read it. If it don't crash, it produces wrong results.


Solution

Add an else clause to your if construct that sets a value to e in the general case. What value would it be depends on your program logic - you will figure out by yourself.

if ((position(z,n) .eq. position(z+1,n)) .and. (position(z,n) .eq. position(z+2,n))) then
  call random_number(x)
  if (z .eq. 2) then            
    if (x .le. onethird) then
      e=z
  ! (...)
else
  e = some value that makes sense for your program
end if

All good now?

Err... no. You should really review all your program logic and structure, and debug it. There are many details to address. For example, you are doing position(z+1,n) and position(z+2,n) inside a loop with z=2,4 when your array's shape is (4,np). What will happen when z=3 or z=4? You should probably initialize the random seed before call random_number(x). Also, you could review things like making your algorithm more abstract, by not hardcoding array dimensions or other parameters...

I highly recommend you turning on all compile options for checks and warnings while you are developing the code, specially checks for undefined variables and bounds checking.

Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36