One day I wondered how to prevent the simultaneous and redundant tasks on a single point (or tile) on the map. The short answer is the sets and the caching.
Sets in the Lua looks, for example, like:
Code: Select all
cached = { [ID1] = true, [ID3] = true, ... , [ID2] = true }
Code: Select all
if not cached[ID] then
add(x, y, action)
[EDIT]: Most likely I'm wrong in that I use the pairing functions to generate the hash from the two values. The main advantage of the pairing function is that the unpairing functions exist
![Smile :)](./images/smilies/icon_e_smile.gif)
![Question :?:](./images/smilies/icon_question.gif)
The easiest way is the concatenation of these two coordinates as strings with a delimiter between:
Code: Select all
IDxy = tostring(x).."/"..tostring(y)
![Confused :?](./images/smilies/icon_e_confused.gif)
Probably it is not a better way at all. And I managed to find on the web at least another two examples of the pairing functions:
- 1. The Cantor pairing function;
2. An Elegant Pairing Function by Matthew Szudzik.
For the Z -> N mapping we can use such a way:
Code: Select all
n = z * 2, for n >= 0;
n = -z * 2 - 1, for n < 0.
profiler.lua
Code: Select all
local profiler = {}
require "socket"
local Timer
local function getTime()
-- time in milliseconds instead of os.time() in seconds
return socket.gettime()*1000
end
function profiler.start()
Timer = getTime()
end
function profiler.stop()
return tostring(os.difftime(getTime(), Timer))
end
return profiler
Code: Select all
------------------------------------------------------
-- Test environment section
------------------------------------------------------
local profiler = require("profiler")
local p =
{
x = {},
y = {}
}
local out1 = {}
local out2 = {}
local out3 = {}
local out4 = {}
local out5 = {}
local out6 = {}
local out7 = {}
local function genPolyline(n, max)
for i = 1, n do
p.x[i] = math.random(-max, max)
p.y[i] = math.random(-max, max)
end
end
------------------------------------------------------
-- The mappings
------------------------------------------------------
-- ZxZ -> {strings}
local function concatPair(x, y)
return tostring(x).."/"..tostring(y)
end
-- Z -> N
local function NtoZ(x, y)
return (x >= 0 and (x * 2) or (-x * 2 - 1)), (y >= 0 and (y * 2) or (-y * 2 - 1))
end
-- ZxZ -> N, i.e. (x, y) -> IDxy
local function cantorPair_v1(x, y)
x,y = NtoZ(x, y)
return (x + y +1)*(x + y)/2 + x
end
local function cantorPair_v2(x, y)
x,y = NtoZ(x, y)
-- other representation, same result
return (x*x + 3*x + 2*x*y + y + y*y) / 2
end
local function cantorPair_v3(x, y)
x,y = NtoZ(x, y)
-- the same values * 2
return x*x + 3*x + 2*x*y + y + y*y
end
local function elegantPair_v1(x, y)
x,y = NtoZ(x, y)
return (x >= y and (x * x + x + y) or (y * y + x))
end
local function elegantPair_v2(x, y)
x,y = NtoZ(x, y)
if x >= y then
return x * x + x + y
end
return y * y + x
end
local function godelPair(x, y)
x,y = NtoZ(x, y)
return (2^x)*(3^y)
end
------------------------------------------------------
-- Profiling section
------------------------------------------------------
-- init test data
local n = 5000000
print("Generating test data..")
genPolyline(n, 12000)
print("Profiling:")
print("Test #1 - concatPair")
profiler.start()
for i = 1, n do
out1[i] = concatPair(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #2 - cantorPair v1")
profiler.start()
for i = 1, n do
out2[i] = cantorPair_v1(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #3 - cantorPair v2")
profiler.start()
for i = 1, n do
out3[i] = cantorPair_v2(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #4 - cantorPair v3")
profiler.start()
for i = 1, n do
out4[i] = cantorPair_v3(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #5 - elegantPair v1")
profiler.start()
for i = 1, n do
out5[i] = elegantPair_v1(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #6 - elegantPair v2")
profiler.start()
for i = 1, n do
out6[i] = elegantPair_v2(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Test #7 - godelPair")
profiler.start()
for i = 1, n do
out7[i] = godelPair(p.x[i], p.y[i])
end
local result = profiler.stop()
print(result.." ms")
print("Done!")
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
concatPair: 15199 ms
cantorPair v1: 1949 ms
cantorPair v2: 2312 ms
cantorPair v3: 2266 ms
elegantPair v1: 2017 ms
elegantPair v2: 1974 ms
[EDIT]: godelPair: ~3000-3500ms
As we can see, the way of multiple concatenations is dramatically slow. I was rooting for the elegantPair() function but I did not manage to implement it to be faster than the Cantor's method.
The more efficient ways are welcome! For me the current winner is:
Code: Select all
-- Z -> N
local function NtoZ(x, y)
return (x >= 0 and (x * 2) or (-x * 2 - 1)), (y >= 0 and (y * 2) or (-y * 2 - 1))
end
-- ZxZ -> N, i.e. (x, y) -> IDxy
local function cantorPair_v1(x, y)
x,y = NtoZ(x, y)
return (x + y +1)*(x + y)/2 + x
end
Materials used:
http://szudzik.com/ElegantPairing.pdf (an Elegant Pairing Function by Matthew Szudzik)
https://en.wikipedia.org/wiki/Pairing_function (The Cantor pairing function)
https://www.lua.org/gems/sample.pdf (Lua Performance Tips by Roberto Ierusalimschy)
https://www.lua.org/pil/11.5.html (Lua - Sets)
[EDIT]:https://hbfs.wordpress.com/2011/09/27/p ... functions/ (some more examples of the pairing functions)