]> git.newer.systems - setclass.git/commitdiff
analysis completed main
authorTucker Johnson <tucker@newer.systems>
Tue, 24 Jun 2025 13:15:26 +0000 (09:15 -0400)
committerTucker Johnson <tucker@newer.systems>
Tue, 24 Jun 2025 13:15:26 +0000 (09:15 -0400)
core.lua
generator.lua
init.lua

index 2448465147984420cf48d89f464427ab4b4653ad..ef8ae96c014c90017d7c426464eb491eaaa1d3c1 100644 (file)
--- a/core.lua
+++ b/core.lua
@@ -14,7 +14,7 @@ local function load_csv()
     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,
@@ -28,18 +28,32 @@ local function load_csv()
   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)
@@ -47,41 +61,12 @@ 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 {
@@ -94,4 +79,45 @@ function M.analyze_set(inputStr)
   }
 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
index 7eda678ac0241ca5e6e7f9dd600f694f54e6dc7d..72deb9ef7752da8db233504988d9bfc1f64351fc 100644 (file)
@@ -1,8 +1,6 @@
-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
@@ -13,8 +11,7 @@ local function mask_to_pcs(mask)
   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))
@@ -22,12 +19,10 @@ local function pcs_to_hex(pcs)
   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
@@ -39,7 +34,6 @@ local function invert(mask)
   return result
 end
 
--- Find prime form of bitmask
 local function prime_form_bitmask(mask)
   local min = 0xFFF + 1
   for i = 0, 11 do
@@ -51,7 +45,6 @@ local function prime_form_bitmask(mask)
   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}
@@ -68,21 +61,21 @@ local function icv_from_mask(mask)
   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()
index 5365bd0faac9bd516070c94b67abfd837d24242a..b33604f0145853092402ded4353795afad301201 100644 (file)
--- a/init.lua
+++ b/init.lua
@@ -2,15 +2,21 @@ local M = {}
 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