module Language.ArrayForth.Distance where
import Data.Bits (Bits, popCount, xor)
import Data.List (genericLength)
import Data.Maybe (fromJust)
import Data.Monoid
import Language.ArrayForth.Interpreter (Trace)
import Language.ArrayForth.Opcode (F18Word)
import Language.ArrayForth.State
import Language.Synthesis.Synthesis (Score (..))
type Distance = Sum Double
instance Score Distance where toScore = getSum
countBits :: (Integral n, Bits n) => n -> n -> Int
countBits n₁ n₂ = popCount $ (fromIntegral n₁ :: Int) `xor` fromIntegral n₂
registers :: [State -> F18Word] -> (State -> State -> Distance)
registers regs s₁ s₂ = Sum . fromIntegral . sum $ zipWith countBits (go s₁) (go s₂)
where go state = map ($ state) regs
locations :: [F18Word] -> (State -> State -> Distance)
locations addresses s₁ s₂ = Sum . fromIntegral . sum $ zipWith countBits (go s₁) (go s₂)
where go state = map (fromJust . (memory state !)) addresses
matching :: Eq a => (State -> a) -> (Trace -> Trace -> Distance)
matching f t₁ t₂ = Sum $ (genericLength t₂ resultLength)
where resultLength = genericLength $ filter (`elem` map f t₁) (map f t₂)