diff --git a/benchmarks/primes.lua b/benchmarks/primes.lua new file mode 100644 index 00000000..cd609641 --- /dev/null +++ b/benchmarks/primes.lua @@ -0,0 +1,168 @@ +local UPPER_BOUND = 5000000 +local PREFIX = 32338 + +local Node = {} +function Node:new() + local obj = {} + setmetatable(obj, self) + self.__index = self + obj.children = {} + obj.terminal = false + return obj +end + +local Sieve = {} +function Sieve:new(limit) + local obj = {} + setmetatable(obj, self) + self.__index = self + obj.limit = limit + obj.prime = {} + for i = 0, limit do + obj.prime[i] = false + end + return obj +end + +function Sieve:to_list() + local result = {2, 3} + for p = 5, self.limit do + if self.prime[p] then + table.insert(result, p) + end + end + return result +end + +function Sieve:omit_squares() + local r = 5 + while r * r < self.limit do + if self.prime[r] then + local i = r * r + while i < self.limit do + self.prime[i] = false + i = i + r * r + end + end + r = r + 1 + end + return self +end + +function Sieve:step1(x, y) + local n = (4 * x * x) + (y * y) + if n <= self.limit and (n % 12 == 1 or n % 12 == 5) then + self.prime[n] = not self.prime[n] + end +end + +function Sieve:step2(x, y) + local n = (3 * x * x) + (y * y) + if n <= self.limit and n % 12 == 7 then + self.prime[n] = not self.prime[n] + end +end + +function Sieve:step3(x, y) + local n = (3 * x * x) - (y * y) + if x > y and n <= self.limit and n % 12 == 11 then + self.prime[n] = not self.prime[n] + end +end + +function Sieve:loop_y(x) + local y = 1 + while y * y < self.limit do + self:step1(x, y) + self:step2(x, y) + self:step3(x, y) + y = y + 1 + end +end + +function Sieve:loop_x() + local x = 1 + while x * x < self.limit do + self:loop_y(x) + x = x + 1 + end +end + +function Sieve:calc() + self:loop_x() + return self:omit_squares() +end + +local function generate_trie(l) + local root = Node:new() + for _, el in ipairs(l) do + local head = root + -- attempt to call a nil value (method 'split') + -- how to fix? use string.split + el = tostring(el) + for i=1, #el do + local ch = el:sub(i, i) + if not head.children[ch] then + head.children[ch] = Node:new() + end + head = head.children[ch] + end + head.terminal = true + end + return root +end + +local function find(upper_bound, prefix_) + local primes = Sieve:new(upper_bound):calc() + local str_prefix = tostring(prefix_) + local head = generate_trie(primes:to_list()) + for i=1, #str_prefix do + local ch = str_prefix:sub(i, i) + head = head.children[ch] + if head == nil then + return nil + end + end + + local queue, result = {{head, str_prefix}}, {} + while #queue > 0 do + local tuple = table.remove(queue) + local top, prefix = tuple[1], tuple[2] + if top.terminal then + table.insert(result, tonumber(prefix)) + end + for ch, v in pairs(top.children) do + table.insert(queue, 1, {v, prefix .. ch}) + end + end + + table.sort(result) + return result +end + +local function verify() + local left = {2, 23, 29} + local right = find(100, 2) + if #left ~= #right then + print("length not equal") + os.exit(1) + end + for i, v in ipairs(left) do + if v ~= right[i] then + print(string.format("%s != %s", v, right[i])) + os.exit(1) + end + end +end + +verify() +local results = find(UPPER_BOUND, PREFIX) +local expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897} + +for i, v in ipairs(results) do + if v ~= expected[i] then + print(string.format("%s != %s", v, expected[i])) + os.exit(1) + end +end +