wildmyron wrote:
Something strange is going on at 2048x2048 with QuickLife in a bounded grid.
@mollwollfumble As you can see from the above results, if you must use a bounded grid then you can get reasonable performance from Golly if you use HashLife. But if you want to run lots of trials then you should switch to QuickLife in an unbounded grid. You can avoid most boundary effects by padding the random pattern outside the area of interest. The size of the padding required can be determined with a script from another thread which explored the propagation speed and distance that a 1 bit flip produces in a large random soup. Sorry, I don't have a link to the thread.
My only reason for choosing 2048*2048 for the size of the toroid is because that's what Achim Flammenkamp used. I'm choosing 5% initial density because that gives room for initial patterns to expand without too much interference, the final ash density is 30% of maximum.
Thanks for that, but I've got my standalone code working now (I think). It totally ignores oscillators with period 2 and limits its calculation on each row to between the first active cell on that row and the last active cell on that row, taking into account that the active zone can expand at the speed of light.
Run times:
Golly on Windows. Quicklife, 23m43s for 10,000 generations
Golly on Android. Rule Loader. 3m31s for 10,000 generations
Optimised standalone on Cygwin. 6.4s for 20,000 generations.
Code for optimised standalone is:
Code: Select all
parameter(numi=2048,numj=2048)
integer a(0:numi+1,0:numj+1),b(0:numi+1,0:numj+1)
integer first0(numj),last0(numj)
a=0
! call system_clock(COUNT=iseed)
! call srand(iseed)
do j=1,numj
do i=1,numi
if(rand().lt.0.05) then
a(i,j)=1
end if
end do
end do
call toroid(a)
b=a
first0=1
last0=numi
! main calculation
do itime=1,10000
call twosteprow(a,b,first0,last0)
call twosteprow(b,a,first0,last0)
end do
! find population
ipop=0
do j=1,numj
do i=1,numi
if(a(i,j).eq.1) then
ipop=ipop+1
end if
end do
end do
print*,itime*2-2,ipop
stop
end
subroutine twosteprow(a,b,first0,last0)
parameter(numi=2048,numj=2048)
integer a(0:numi+1,0:numj+1),b(0:numi+1,0:numj+1)
integer first(0:numj+1),last(0:numj+1),first0(numj),last0(numj)
do j=0,numj
first(j)=numi+1
last(j)=0
do i=first0(j),last0(j)
icount=a(i-1,j-1)+a(i,j-1)+a(i+1,j-1)+a(i-1,j)+a(i+1,j)+a(i-1,j+1)+a(i,j+1)+a(i+1,j+1)
if(a(i,j).eq.0) then ! most common case, empty square
if(icount.eq.3) then ! cell born
if(b(i,j).eq.0) then ! note that b ne a for period 2 oscillators
if(first(j).eq.numi+1) first(j)=i
last(j)=i
b(i,j)=1
end if
else ! cell stays dead
if(b(i,j).eq.1) then
if(first(j).eq.numi+1) first(j)=i
last(j)=i
b(i,j)=0
end if
end if
else ! a(i,j)=1
if(icount.eq.2.or.icount.eq.3) then ! cell survives
if(b(i,j).eq.0) then
if(first(j).eq.numi+1) first(j)=i
last(j)=i
b(i,j)=1
end if
else ! cell dies
if(b(i,j).eq.1) then
if(first(j).eq.numi+1) first(j)=i
last(j)=i
b(i,j)=0
end if
end if
end if
end do
end do
call toroid(b)
! expand first & last at speed of light to get new first0 and last0.
first(0)=first(numj)
first(numj+1)=first(1)
last(0)=last(numj)
last(numj+1)=last(1)
do j=1,numj
first0(j)=min(first(j-1),first(j),first(j+1))-1
last0(j)=max(last(j-1),last(j),last(j+1))+1
if(first0(j).lt.1.or.last0(j).gt.numi) then ! cross toroidal boundaries
first0(j)=1
last0(j)=numi
end if
end do
return
end
subroutine toroid(a)
parameter(numi=2048,numj=2048)
integer a(0:numi+1,0:numj+1)
! apply toroidal boundary conditions
do i=1,numi
a(i,0)=a(i,numj)
a(i,numj+1)=a(i,1)
end do
do j=0,numj+1
a(0,j)=a(numi,j)
a(numi+1,j)=a(1,j)
end do
return
end