Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Gotta modify the mod function because taking the mod of a negative number just returns that same number.
- local function mod(x, y)
- return (x>=0) and math.fmod(x,y) or math.fmod(x,y)+y
- end
- -- Can you believe Lua doesn't have a built-in sign function?
- local function sign(x)
- if x>0 then -- For this application, we want x to be either -1 or 1 so we can choose a backdrop color, hence no x=0 case.
- return 1
- else
- return -1
- end
- end
- -- So it turns out gui.drawLine doesn't accept lines of one pixel in length. Boo!
- local function line(x1, y1, x2, y2, color)
- if x1==x2 and y1==y2 then
- gui.drawPixel(x1, y1, color)
- else
- gui.drawLine(x1, y1, x2, y2, color)
- end
- end
- local function initialize(width, height)
- local grid={}
- for i=0,width-1 do
- grid[i]={}
- for j=0,height-1 do
- --grid[i][j]=math.floor(2*math.random()-1) -- Selecting random numbers in this way doesn't work and I have no idea why.
- grid[i][j]=2*math.random(2)-3
- --grid[i][j]=-1
- end
- end
- return grid
- end
- -- Copy a table.
- local function tablecopy(t)
- local tcopy={}
- for k, v in pairs(t) do
- if type(v)=="table" then
- tcopy[k]=tablecopy(v)
- else
- tcopy[k]=v
- end
- end
- return tcopy
- end
- local function pickrandom(dimension) -- dimension can be either width or height
- return math.random(dimension)-1 -- Subtract 1 because indexing starts at 0.
- end
- local function magnetization(grid)
- local mag=0
- for i=0,#grid do
- for j=0,#grid[i] do
- mag=mag+grid[i][j]
- end
- end
- --local width, height = #grid+1, #grid[1]+1
- --mag=mag/(width*height)
- return mag
- end
- -- Draws the grid pixel by pixel. Turns out this is extremely inefficient.
- local function pixelbypixel(grid)
- local colorkey={"white", [-1]="black"}
- local mag=sign(magnetization(grid))
- gui.drawRectangle(0,0,#grid,#grid[1],colorkey[mag],colorkey[mag]) -- drawPixel is computationally expensive, so we use the magnetization to set the backdrop color.
- for i=0,#grid do
- for j=0,#grid[i] do
- if not(grid[i][j]==mag) then
- gui.drawPixel(i, j, colorkey[grid[i][j]])
- end
- end
- end
- end
- -- Draws pixels row by row, hopefully saving computation. Also updates the magnetization.
- local function linebyline(grid, mag)
- local colorkey={"white", [-1]="black"}
- signmag = sign(mag)
- gui.drawRectangle(0,0,#grid,#grid[1],colorkey[signmag],colorkey[signmag])
- mag=0 -- Reset magnetization to 0.
- for row=0,#grid[1] do
- ---[[
- local prev=0
- for i=0,#grid-1 do
- if not(grid[i][row]==grid[i+1][row]) then
- if not(grid[prev][row]==signmag) then
- line(prev, row, i, row, colorkey[-signmag])
- end
- mag=mag+grid[prev][row]*(i-prev+1)
- prev=i+1
- end
- end
- if not(grid[prev][row]==signmag) then
- line(prev, row, #grid, row, colorkey[-signmag])
- end
- mag=mag+grid[prev][row]*(#grid-prev+1)
- --]]
- --[[
- local s = 0
- local e = 1
- while e<#grid do
- if not(grid[s][row]==grid[e][row]) then
- if not(grid[s][row]==signmag) then
- gui.drawLine(s, row, e-1, row, colorkey[-signmag])
- end
- mag=mag+grid[s][row]*(e-s)
- s=e
- end
- e=e+1
- end
- if not(grid[s][row]==signmag) then
- gui.drawLine(s, row, e-1, row, colorkey[-signmag])
- end
- mag=mag+grid[s][row]*(e-s)
- --]]
- end
- return mag
- end
- -- Draws the grid in blocks of 15x10. Compare with the known "quadtree" algorithm. Why 15x10? It's a nice round number that divides the width and height, plus it roughly evenly divides the task of drawing the block magnetization and pixel magnetization.
- local function blockbyblock(grid, blockmag)
- local mag = sign(magnetization(blockmag)) -- Assumes the sign of the overall magnetization is the sign of the aggregate magnetization of the blocks.
- local colorkey={"white", [-1]="black"}
- gui.drawRectangle(0,0,#grid,#grid[1],colorkey[mag],colorkey[mag])
- for blockcol = 0, 15 do -- I'm subdividing this into a 16x16 grid of blocks of size 15x10, which presumes a width of 240 and height of 160. This code will need to be altered if other widths/heights are to be accomodated.
- for blockrow = 0, 15 do
- local signmag=sign(blockmag[blockcol][blockrow])
- local color=colorkey[signmag]
- if not(signmag == mag) then
- gui.drawRectangle(blockcol*15, blockrow*10, 14, 9, color, color)
- end
- blockmag[blockcol][blockrow] = 0
- for j=0,9 do
- local prev=0
- for i=0,13 do
- if not(grid[15*blockcol+i][10*blockrow+j]==grid[15*blockcol+i+1][10*blockrow+j]) then
- if not(grid[15*blockcol+prev][10*blockrow+j]==signmag) then
- line(15*blockcol+prev, 10*blockrow+j, 15*blockcol+i, 10*blockrow+j, colorkey[-signmag])
- end
- blockmag[blockcol][blockrow]=blockmag[blockcol][blockrow]+grid[15*blockcol+prev][10*blockrow+j]*(i-prev+1)
- prev=i+1
- end
- end
- if not(grid[15*blockcol+prev][10*blockrow+j]==signmag) then
- line(15*blockcol+prev, 10*blockrow+j, 15*blockcol+15, 10*blockrow+j, colorkey[-signmag])
- end
- blockmag[blockcol][blockrow]=blockmag[blockcol][blockrow]+grid[15*blockcol+prev][10*blockrow+j]*(14-prev+1)
- end
- end
- end
- return blockmag
- end
- local function neighbors(grid, i, j, width, height)
- local l=mod(i-1, width)
- local r=mod(i+1, width)
- local u=mod(j-1, height)
- local d=mod(j+1, height)
- -- This is all broken, samples the wrong points.
- --[=[
- local horz={l, r}
- local vert={u, d}
- local eightneighbors = false -- Use eight neighbors instead of four.
- if eightneighbors then
- table.insert(horz, 0)
- table.insert(vert, 0)
- end
- local nearest={}
- for m=1,#horz do
- for n=1,#vert do
- table.insert(nearest, grid[horz[m]][vert[n]])
- end
- end
- if mod(#nearest, 2)==1 then -- If #nearest is odd, we must have included the center square and need to remove it
- table.remove(nearest,#nearest)
- end
- --]=]
- local nearest = {grid[l][j], grid[r][j], grid[i][u], grid[i][d]}
- return nearest
- end
- local function deltaU(grid, i, j, width, height)
- nearest=neighbors(grid, i, j, width, height)
- local sum=0
- for ii=1,#nearest do -- Already using i as an argument, although Lua's scoping means we could use i if we wanted.
- sum=sum+nearest[ii]
- end
- return 2*grid[i][j]*sum
- end
- local function atrandom(grid, width, height, temp, iterations)
- for k=1,iterations do
- i, j = pickrandom(width), pickrandom(height)
- local Ediff = deltaU(grid, i, j, width, height)
- if Ediff<=0 or math.random()<math.exp(-Ediff/temp) then
- grid[i][j] = -grid[i][j]
- end
- end
- return grid
- end
- local function allatonce(oldgrid, width, height, temp, iterations)
- local newgrid=tablecopy(oldgrid)
- for k=1,iterations do
- for i=0,width-1 do
- for j=0,height-1 do
- local Ediff = deltaU(oldgrid, i, j, width, height)
- if Ediff<=0 or math.random()<math.exp(-Ediff/temp) then
- newgrid[i][j] = -oldgrid[i][j]
- end
- end
- end
- oldgrid=tablecopy(newgrid)
- end
- return newgrid
- end
- local width=240 -- Width and height are 240 and 160 (for GBA), but indexing starts at 0 so we subtract 1 when initializing the grid. We still use these values for modular arithmetic.
- local height=160
- -- Critical temperature is ~2.26918531421
- local kT=2.26918531421
- local rate=0.2*width*height -- Number of iterations to perform before drawing all the pixels, which is computationally expensive.
- local startframe=emu.framecount()
- local grid = initialize(width, height)
- local keys, last = input.get(), input.get()
- local printmag = true
- local printtemp = true
- local mag=-1
- local drawstyle=0
- local blockmag={}
- for i=0,15 do
- blockmag[i]={}
- for j=0,15 do
- blockmag[i][j] = 0
- end
- end
- while true do
- --gui.pixelText(80, 20, math.exp(-1/2))
- --gui.pixelText(80, 30, deltaU(grid, 30, 30, 50, 50))
- local t = emu.framecount()-startframe
- local A = 0.8
- local omega = math.pi/500
- local lambda = math.log(1/0.8)/500 -- omega*t=pi ==> exp(-lambda*t) = 0.8 ==> -lambda*pi/omega = ln(0.8) ==> lambda = omega/pi * ln(1/0.8)
- local temp = 2.26918531421 - A * math.exp(-lambda*t) * math.cos(omega*t)
- keys, last = input.get(), tablecopy(keys)
- if keys["Space"] and not last["Space"] then
- printmag = not printmag
- end
- if keys["Enter"] and not last["Enter"] then
- printtemp = not printtemp
- end
- if keys["D"] and not last["D"] then
- drawstyle = math.fmod(drawstyle+1, 3)
- end
- if drawstyle == 0 then
- mag = linebyline(grid, mag)
- elseif drawstyle == 1 then
- blockmag = blockbyblock(grid, blockmag)
- mag=magnetization(blockmag)
- else
- --pixelbypixel(grid) -- Commenting out this line because pixelbypixel is inefficient and we can instead just draw nothing.
- end
- if printmag then
- --local mag = magnetization(grid)
- gui.pixelText(80, 20, mag, "yellow", "black")
- end
- if printtemp then gui.pixelText(80, 30, temp, "yellow", "black") end
- local grid = atrandom(grid, width, height, temp, rate)
- --gui.pixelText(80, 20, kT,nil,"black")
- --gui.pixelText(80, 30, emu.framecount()-startframe,nil,"black")
- emu.frameadvance()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement