Skip to content

Commit 8234647

Browse files
committed
Implemented full matrix LCS.
1 parent 7cc6ef8 commit 8234647

File tree

1 file changed

+13
-60
lines changed

1 file changed

+13
-60
lines changed

xtra/DIFF.LUA

Lines changed: 13 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,25 @@ local function diff_u(fn1,fn2)
99
local function eol()if c=='\r'then local d=f:read(1)if not d then return true end f:seek("cur",-1)return d~='\n'end return c=='\n'end
1010
o=o+1 table.insert(l,c)if eol()then break end end
1111
if #l==0 then break end l=table.concat(l)local ln,c=#l,crc32(l)p=p..string.pack(PF,ln,c,ls)end f:close()return p end
12-
local f1,f2,ps,i,j,la,fh,h,w,m,u=open(fn1),open(fn2),string.packsize(PF),1,1
12+
local f1,f2,ps,i,j,la,fh,h,w,m,u,L=open(fn1),open(fn2),string.packsize(PF),1,1
1313
local function cmp(x,y)
1414
local l1,c1,o1,l2,c2,o2,b1,e,b2,f=string.unpack(PF,f1,(x-1)*ps+1)l2,c2,o2=string.unpack(PF,f2,(y-1)*ps+1)if l1~=l2 or c1~=c2 then return false end
1515
local function li(fn,o,l)f,e=io.open(fn,"rb")if not f then return nil,e end f:seek(S,o)local g=f:read(l)f:close()return g end
1616
b1,e,b2=li(fn1,o1,l1)if not b1 then error(e)end b2,e=li(fn2,o2,l2)if not b2 then error(e)end return b1==b2 end
17-
h,w,la,m=#f1//ps,#f2//ps,1,{}
18-
local function build(a1,a2,alo,ahi,blo,bhi)
19-
if alo>ahi or blo>bhi then return end
20-
if alo==ahi then
21-
for j=blo,bhi do
22-
if cmp(alo,j) then
23-
m[#m+1] = { x=alo, y=j, l=1 }
24-
break
25-
end
26-
end
27-
return
28-
end
29-
local mid = (alo+ahi)//2
30-
-- forward DP from alo..mid
31-
local F = {}
32-
for j=blo, bhi do F[j]=0 end
33-
for i=alo, mid do
34-
local prev = 0
35-
for j=blo, bhi do
36-
local save = F[j]
37-
if cmp(i,j) then F[j] = prev + 1
38-
elseif F[j-1] and F[j-1] > F[j] then F[j] = F[j-1] end
39-
prev = save
40-
end
41-
end
42-
-- backward DP from ahi..mid+1
43-
local B = {}
44-
for j=blo, bhi do B[j]=0 end
45-
for i=ahi, mid+1, -1 do
46-
local prev = 0
47-
for j=bhi, blo, -1 do
48-
local save = B[j]
49-
if cmp(i,j) then B[j] = prev + 1
50-
elseif B[j+1] and B[j+1] > B[j] then B[j] = B[j+1] end
51-
prev = save
52-
end
53-
end
54-
-- find best split on the B-axis
55-
local best,jcut = -1,blo
56-
for j=blo,bhi do
57-
local s = (F[j] or 0) + (B[j] or 0)
58-
if s>best then best,s,jcut = s,s,j end
59-
end
60-
-- recurse on the two halves
61-
build(a1,a2,alo, mid, blo, jcut)
62-
build(a1,a2,mid+1,ahi, jcut+1, bhi)
63-
end
17+
h,w,la,m,L=#f1//ps,#f2//ps,1,{},{}
18+
-- full matrix LCS
19+
for x=0,h do L[x]={}for y=0,w do if x==0 or y==0 then L[x][y]=0
20+
elseif cmp(x,y)then L[x][y]=L[x-1][y-1]+1
21+
else L[x][y]=(L[x-1][y]>L[x][y-1])and L[x-1][y]or L[x][y-1]end end end
6422

65-
build(fn1,fn2, 1, h, 1, w)
23+
-- backtrack to extract the matching coordinates
24+
i,j=h,w while i > 0 and j > 0 do
25+
if cmp(i,j)then table.insert(m,1,{x=i,y=j,l=1})i,j=i-1,j-1
26+
elseif L[i-1][j]>=L[i][j-1]then i=i-1 else j=j-1 end end
6627

67-
local co = {}
68-
for _,p in ipairs(m) do
69-
local t = co[#co]
70-
if t and t.x+t.l==p.x and t.y+t.l==p.y then
71-
t.l = t.l + 1
72-
else
73-
co[#co+1] = { x=p.x, y=p.y, l=1 }
74-
end
75-
end
76-
m = co
77-
la=nil
28+
-- coalesce adjacent 1‐line runs into multi‐line matches
29+
local co={}for _,p in ipairs(m)do local t=co[#co] if t and t.x+t.l==p.x and t.y+t.l==p.y then t.l=t.l+1 else co[#co+1]={x=p.x,y=p.y,l=p.l}end end
30+
m,la,i,j=co,nil,1,1
7831

7932
local function get(fn,p,x)local l,_,o,f,r=string.unpack(PF,p,(x-1)*ps+1)f=assert(io.open(fn,"rb"))f:seek(S,o)r=f:read(l)f:close()return r end
8033
local function pfl(p,s)return(p..s:gsub('\n$',''):gsub('\r$',''))end

0 commit comments

Comments
 (0)