module Language.ArrayForth.Distance where
import Data.Bits (Bits, popCount, xor)
import Language.ArrayForth.Opcode (F18Word)
import Language.ArrayForth.State
type Distance = State -> State -> Double
countBits :: (Integral n, Bits n) => n -> n -> Int
countBits n₁ n₂ = popCount $ (fromIntegral n₁ :: Int) `xor` fromIntegral n₂
registers :: [State -> F18Word] -> Distance
registers regs s₁ s₂ = fromIntegral . sum $ zipWith countBits (go s₁) (go s₂)
where go state = map ($ state) regs
locations :: [F18Word] -> Distance
locations addresses s₁ s₂ = fromIntegral . sum $ zipWith countBits (go s₁) (go s₂)
where go state = map (memory state !) addresses
distances :: [Distance] -> Distance
distances dists s₁ s₂ = sum [dist s₁ s₂ | dist <- dists]