NB. comparison utilities
NB.
NB. This has utilities to compare character data and files.

cocurrent 'z'

NB. =========================================================
NB.*compare v compare character data
NB.
NB. returns list of differences.
NB.
NB. arguments may be character strings, with lines delimited
NB. by LF, or character matrices (trailing blanks ignored).
NB.
NB. for Mac, tolerates lines delimited by CR.
NB.
NB. result shows lines not matched, in form:
NB.    n [l] text
NB.
NB. where:
NB.    n    =  0=left argument, 1=right argument
NB.   [l]   =  line number
NB.   text  =  text on line
NB.
NB. omits comparison of swapped lines where
NB. 1e7 <: product of number of non-trivial lines

compare=: 4 : 0
if. x. -: y. do. 'no difference' return. end.
if. 0=#x. do. 'empty left argument' return. end.
if. 0=#y. do. 'empty right argument' return. end.

NB. ---------------------------------------------------------
if. (LF e. ,x.) +. LF e. ,y. do.
  sep=. LF
else.
  sep=. CR
end.

dtb=. {.~ [: i.&1 [: *./\. =&' '
each=. &.>

NB. ---------------------------------------------------------
if. 2=#$x. do. x=. <@dtb"1 x.
else. x=. <;._2 x.,sep -. {:x. end.
if. 2=#$y. do. y=. <@dtb"1 y.
else. y=. <;._2 y.,sep -. {:y. end.

lx=. #x
ly=. #y

NB. ---------------------------------------------------------
NB. filter out small fry (handled later):
fry=. , each ' ';CR;a:
bfx=. x e. fry
bfy=. y e. fry

fx=. bfx # x
fy=. bfy # y
x=. (-. bfx) # x
y=. (-. bfy) # y

NB. ---------------------------------------------------------
nx=. i.#x
bx=. x e. y
rx=. (-.bx)#x
sx=. (-.bx)#nx

ny=. i.#y
by=. y e. x
ry=. (-.by)#y
sy=. (-.by)#ny

NB. ---------------------------------------------------------
if. 1e7 > (+/bx) * +/by do.
  
  nx=. bx#nx
  ny=. by#ny
  b=. (bx#x) =/ (by#y)
  
  while. 1 do.
    
NB. flag lines swapped around exact matches:
    m=. -.(>./rb=. $b){.(<0 1)|:b
    b=. b *. rb{. =/~ (i.#m)-+/\m
    
NB. remove exact matches and lines not in both:
    sx=. sx,(-. b1=. +./"1 b)#nx
    nx=. (b1=. b1*.($b1){.m)#nx
    sy=. sy,(-. b2=. +./b)#ny
    ny=. (b2=. b2*.($b2){.m)#ny
    b=. b2#"1 b1#b
    if. 0 e. $b do. break. end.
    if. -. rb -: $b do. continue. end.
    
NB. if no change in loop, remove most likely line:
    t=. (2$rb=. >./$b){.b
    if. (0.5*+/,t) >: +/,t*</~i.rb do.
      sx=. sx,{.nx
      nx=. }.nx
      b=. }.b
    else.
      sy=. sy,{.ny
      ny=. }.ny
      b=. 0 1}.b
    end.
  end.
  sx=. sx,nx
  sy=. sy,ny
  
end.

NB. ---------------------------------------------------------
NB. here:
NB. lx = length of x
NB. fx = small fry of x
NB. nx = rest of x
NB. sx = indices into nx, redefined below as indices into lx

NB. reset x and y:
x=. sx { x
y=. sy { y
sx=. sx { I. -. bfx
sy=. sy { I. -. bfy

NB. ---------------------------------------------------------
NB. small fry:

rx=. ry=. ''
nx=. I. bfx
ny=. I. bfy

if. (#nx) + #ny do.
  
NB. lx = length of x
NB. sx = indices of different lines
NB. nx = indices of small fry
NB. px = remaining indices
  
  px=. (i.lx) -. sx, nx
  py=. (i.ly) -. sy, ny
  ix=. /: nx, px
  iy=. /: ny, py
  bal=. ": each i. (# px) >. # py
  dx=. (<'x'), ix { fx, bal
  dy=. (<'x'), iy { fy, bal
  idx=. 0, (i.lx) -. sx
  idy=. 0, (i.ly) -. sy
  cl2=. $~ -:@# , 2:
  
  while.
    mx=. (> _1&|.) dx e. fry
    my=. (> _1&|.) dy e. fry
    +/ mx, my do.
    tx=. cl2 (mx +. 1 |. mx) # dx
    ty=. cl2 (my +. 1 |. my) # dy
    rx=. rx, (-. tx e. ty) # mx # idx
    ry=. ry, (-. ty e. tx) # my # idy
    dx=. (-. mx) # dx
    dy=. (-. my) # dy
    idx=. (-. mx) # idx
    idy=. (-. my) # idy
  end.
  
end.

NB. ---------------------------------------------------------
NB. sort and format result:
nx=. /: sx, rx
ny=. /: sy, ry
sx=. nx { sx, rx
sy=. ny { sy, ry
x=. nx { (#sx) {. x
y=. ny { (#sy) {. y
ix=. '0 ['&,@(,&'] ')@": each sx
iy=. '1 ['&,@(,&'] ')@": each sy
r=. (ix ,each x), iy ,each y
r=. r /: (sx,.0),sy,.1
}: ; r ,each sep
)

NB. =========================================================
NB.*fcompare v compare two text files
NB.
NB. form: opt fcompare files
NB.   opt is optional suffix
NB.   files is 2 file names or prefixes
NB.
NB. files as character string is cut on blanks
NB.
NB. example:
NB.
NB.   fcompare jpath '~system\main\myutil.ijs \jbak\system\main\myutil.ijs'
NB.   '\myutil.ijs' fcompare jpath '~system\main';'\jbak\system\main'
fcompare=: 3 : 0
'' fcompare y.
:
'x y'=. _2 {. ,&x. each cutopen y.
f=. 1!:1 :: _1:
tx=. f <x
if. tx -: _1 do. 'unable to read ',x return. end.
ty=. f <y
if. ty -: _1 do. 'unable to read ',y return. end.
f=. _3&{.@('0'&,@(":@]))
mth=. _3[\'   JanFebMarAprMayJunJulAugSepOctNovDec'
'a m d h n s'=. 6{.1 pick dx=. ,1!:0 <x
fx=. (4":d),' ',(m{mth),'  ::' 0 3 6 9};f &.> 100|a,h,n,s
'a m d h n s'=. 6{.1 pick dy=. ,1!:0 <y
fy=. (4":d),' ',(m{mth),'  ::' 0 3 6 9};f &.> 100|a,h,n,s
'x y'=. <"1>x;y
r=. 'comparing:',LF
r=. r,x,fx,'  ',(":2 pick dx),LF
r=. r,y,fy,'  ',(":2 pick dy),LF
r,tx compare ty
)
