module Sad where -- We take the following specification for the sum of absolute -- differences, and develop a program that generates circuits that -- have the same behaviour sad :: [Int] -> [Int] -> Int sad xs ys = sum (map abs (zipWith (-) xs ys)) type Bit = Bool low :: Bit low = False high :: Bit high = True inv :: Bit -> Bit inv a = not a and2 :: Bit -> Bit -> Bit and2 a b = a && b or2 a b = a || b xor2 a b = a /= b xnor2 a b = a == b mux2 :: Bit -> Bit -> Bit -> Bit mux2 sel a b = (sel && b) || (not sel && a) bitAdd :: Bit -> [Bit] -> [Bit] bitAdd x [] = [x] bitAdd x (y:ys) = let (sum,carry) = halfAdd x y in sum:bitAdd carry ys halfAdd x y = (xor2 x y,and2 x y) binAdd :: [Bit] -> [Bit] -> [Bit] binAdd xs ys = binAdd' low xs ys binAdd' cin [] [] = [cin] binAdd' cin (x:xs) [] = bitAdd cin (x:xs) binAdd' cin [] (y:ys) = bitAdd cin (y:ys) binAdd' cin (x:xs) (y:ys) = let (sum,cout) = fullAdd cin x y in sum:binAdd' cout xs ys fullAdd cin a b = let (s0,c0) = halfAdd a b (s1,c1) = halfAdd cin s0 in (s1,xor2 c0 c1) binGte :: [Bit] -> [Bit] -> Bit binGte xs ys = binGte' high xs ys binGte' gin [] [] = gin binGte' gin (x:xs) [] = orl (gin:x:xs) binGte' gin [] (y:ys) = and2 gin (orl (y:ys)) binGte' gin (x:xs) (y:ys) = let gout = gteCell gin x y in binGte' gout xs ys gteCell gin x y = mux2 (xnor2 x y) x gin orl :: [Bit] -> Bit orl xs = tree or2 low xs binDiff :: [Bit] -> [Bit] -> [Bit] binDiff xs ys = let xs' = pad (length ys) xs ys' = pad (length xs) ys gte = binGte xs' ys' xs'' = map (xor2 (inv gte)) xs' ys'' = map (xor2 gte) ys' in init (binAdd' high xs'' ys'') pad :: Int -> [Bit] -> [Bit] pad n xs | m > n = xs | otherwise = xs ++ replicate (n-m) False where m = length xs tree :: (a -> a -> a) -> a -> [a] -> a tree f z [] = z tree f z [x] = x tree f z (x:y:ys) = tree f z (ys ++ [f x y]) binSum :: [[Bit]] -> [Bit] binSum xs = tree binAdd [] xs binSad :: [[Bit]] -> [[Bit]] -> [Bit] binSad xs ys = binSum (zipWith binDiff xs ys) num :: [Bit] -> Int num [] = 0 num (a:as) = fromEnum a + 2 * num as -- Properties prop_binSad (xs, ys) = sad (map num xs) (map num ys) == num (binSad xs ys)