return false
end
for line in f:lines() do
- local dec, set, sc, icv = line:match("^(%d+),([0-9AB]+),([0-9AB]+),(<[0-9AB]+>)")
+ local dec, set, sc, icv = line:match("^(%d+),(.+),(.+),(.+)")
if dec then
lookup[tonumber(dec)] = {
set = set,
return true
end
+local function parse_set(input)
+ local mask = 0
+ for i = 1, #input do
+ local char = input:sub(i, i)
+ local pc = tonumber(char, 16)
+ if pc and pc <= 11 then
+ mask = bit.bor(mask, bit.lshift(1, pc))
+ end
+ end
+ return mask
+end
-function M.get_visual_selection()
- local start_pos = vim.fn.getpos("'<")
- local end_pos = vim.fn.getpos("'>")
- local lines = vim.fn.getline(start_pos[2], end_pos[2])
- if #lines == 0 then return "" end
- if #lines == 1 then
- return string.sub(lines[1], start_pos[3], end_pos[3])
+local function m5_bitmask(mask)
+ local m5Map = { [0]=0,5,10,3,8,1,6,11,4,9,2,7 }
+ local result = 0
+ for i = 0, 11 do
+ if bit.band(mask, bit.lshift(1, i)) ~= 0 then
+ local mapped = m5Map[i]
+ result = bit.bor(result, bit.lshift(1, mapped))
+ end
end
- lines[1] = string.sub(lines[1], start_pos[3])
- lines[#lines] = string.sub(lines[#lines], 1, end_pos[3])
- return table.concat(lines, "\n")
+ return result
+end
+
+local function complement(mask)
+ return bit.band(bit.bnot(mask), 0xFFF)
end
function M.analyze_set(inputStr)
if not csvLoaded then
local success = load_csv()
if not success then
- print("[SetClass] CSV not found — generating now...")
+ vim.notify("generating csv...")
generator.generate_csv(csvPath)
assert(load_csv(), "Failed to load generated set-classes.csv")
end
end
- local function parse_set(input)
- input = input:upper():gsub("[^0-9ABCDEF]","")
- local mask = 0
- for i =1, #input do
- local char = input:sub(i, i)
- local pc = tonumber(char, 16)
- if pc and pc <= 11 then
- mask = bit.bor(mask, bit.lshift(1, pc))
- end
- end
- return mask
- end
-
- local function m5_bitmask(mask)
- local m5Map = { [0]=0,5,10,3,8,1,6,11,4,9,2,7 }
- local result = 0
- for i = 0, 11 do
- if bit.band(mask, bit.lshift(1, i)) ~= 0 then
- local mapped = m5Map[i]
- result = bit.bor(result, bit.lshift(1, mapped))
- end
- end
- return result
- end
-
- local function complement(mask)
- return bit.band(bit.bnot(mask), 0xFFF)
- end
-
local mask = parse_set(inputStr)
return {
}
end
+function M.get_visual_selection()
+ local _, start_row, start_col, _ = unpack(vim.fn.getpos("'<"))
+ local _, end_row, end_col, _ = unpack(vim.fn.getpos("'>"))
+
+ -- Ensure proper order
+ if start_row > end_row or (start_row == end_row and start_col > end_col) then
+ start_row, end_row = end_row, start_row
+ start_col, end_col = end_col, start_col
+ end
+
+ local lines = vim.api.nvim_buf_get_lines(0, start_row - 1, end_row, false)
+
+ if #lines == 0 then return "", {}, {} end
+
+ lines[1] = string.sub(lines[1], start_col)
+ if #lines > 1 then
+ lines[#lines] = string.sub(lines[#lines], 1, end_col)
+ else
+ lines[1] = string.sub(lines[1], 1, end_col - start_col + 1)
+ end
+
+ local selection = table.concat(lines, "\n")
+
+ local collections = {}
+ local delimiters = {}
+ local allHex = {}
+
+ for hex, delim in selection:gmatch("([0-9A-Fa-f]+)([^0-9A-Fa-f]*)") do
+ table.insert(collections, hex)
+ table.insert(allHex, hex)
+ if delim ~= "" and not selection:match(delim .. "$") then
+ table.insert(delimiters, delim)
+ end
+ end
+
+ if #collections > 1 then
+ table.insert(collections, table.concat(allHex))
+ end
+ return selection, collections, delimiters
+end
+
return M
-local M = {}
-
local bit = require("bit")
+local M = {}
--- Convert bitmask to PC list (integers)
local function mask_to_pcs(mask)
local pcs = {}
for i = 0, 11 do
return pcs
end
--- Convert PC list to hex string (e.g., 10 -> A, 11 -> B)
-local function pcs_to_hex(pcs)
+local function format_set(pcs)
local out = {}
for _, pc in ipairs(pcs) do
table.insert(out, string.format("%X", pc))
return table.concat(out)
end
--- Transpose bitmask left by n
local function transpose(mask, n)
return bit.band(bit.lshift(mask, n) + bit.rshift(mask, 12 - n), 0xFFF)
end
--- Invert a bitmask (I-transform)
local function invert(mask)
local result = 0
for i = 0, 11 do
return result
end
--- Find prime form of bitmask
local function prime_form_bitmask(mask)
local min = 0xFFF + 1
for i = 0, 11 do
return min
end
--- Generate ICV from bitmask
local function icv_from_mask(mask)
local pcs = mask_to_pcs(mask)
local icv = {0, 0, 0, 0, 0, 0}
for _, v in ipairs(icv) do
table.insert(out, string.format("%X", v))
end
- return "<" .. table.concat(out) .. ">"
+ return table.concat(out)
end
--- Generate CSV with format: decimal,pc_order,prime_form,icv
function M.generate_csv(path)
local out = io.open(path, "w")
local total = 4096
for mask = 0, total - 1 do
- local pcs = mask_to_pcs(mask)
- if #pcs > 0 then
- local pc_order = pcs_to_hex(pcs)
+ if mask > 0 then
+ local pc_order = format_set(mask_to_pcs(mask))
local prime_mask = prime_form_bitmask(mask)
- local prime_form = pcs_to_hex(mask_to_pcs(prime_mask))
+ local prime_form = format_set(mask_to_pcs(prime_mask))
local icv = icv_from_mask(mask)
out:write(string.format("%d,%s,%s,%s\n", mask, pc_order, prime_form, icv))
+ else
+ out:write(string.format("%d,%s,%s,%s\n", mask, "null set", "null set", "null set"))
end
end
out:close()
local core = require("setclass.core")
function M.analyze_selection()
- local input = core.get_visual_selection()
- local result = core.analyze_set(input)
- if result then
- vim.notify(" input: " .. result.input .. " (" .. result.decimal .. ")")
- vim.notify(" set class: " .. result.set_class .. " " .. result.interval_class_vector)
- vim.notify("abs. complement: " .. result.complement_class)
- vim.notify(" m5 class: " .. result.m5_class)
- else
- vim.notify("unable to parse collection")
+ local input, collections, delimiters = core.get_visual_selection()
+ local analysis = {}
+ for i = 1, #collections do
+ table.insert(analysis, core.analyze_set(collections[i]))
+ end
+ for i = 1, #analysis do
+ if i == #analysis then
+ vim.notify("UNION", 3)
+ else
+ vim.notify("SUBSET" .. i, 3)
+ end
+ vim.notify("input: " .. analysis[i].input .. " (" .. analysis[i].decimal .. ")")
+ vim.notify("set class: " .. analysis[i].set_class .. " <" .. analysis[i].interval_class_vector ..">")
+ vim.notify("abs. comp: " .. analysis[i].complement_class)
+ vim.notify("m5 class: " .. analysis[i].m5_class)
end
end