packages feed

bit-stream-0.1.0.0: app/find-foo.hs

{-# LANGUAGE DeriveFunctor        #-}
{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE UndecidableInstances #-}

module Main where

import Data.Bits
import Data.BitStream.WheelMapping

data Expr r
  = Var
  | Const  !Int
  | ShiftL !Int r
  | ShiftR !Int r
  | Add r r
  | Sub r r
  | And r r
  | Or  r r
  | Xor r r
  deriving (Eq, Ord, Functor)

instance Show r => Show (Expr r) where
  showsPrec d = \case
    Var        -> showString "i"
    Const n    -> showString (show n)
    ShiftL k r -> showParen (d > 8) $ showsPrec 9 r . showString " `shiftL` " . showsPrec 9 k
    ShiftR k r -> showParen (d > 8) $ showsPrec 9 r . showString " `shiftR` " . showsPrec 9 k
    Add r s    -> showParen (d > 6) $ showsPrec 7 r . showString " + " . showsPrec 7 s
    Sub r s    -> showParen (d > 6) $ showsPrec 7 r . showString " - " . showsPrec 7 s
    And r s    -> showParen (d > 7) $ showsPrec 8 r . showString " .&. " . showsPrec 8 s
    Or  r s    -> showParen (d > 5) $ showsPrec 6 r . showString " .|. " . showsPrec 6 s
    Xor r s    -> showParen (d > 6) $ showsPrec 7 r . showString " `xor` " . showsPrec 7 s

newtype Fix t = Fix { unFix :: t (Fix t) }

instance Eq (t (Fix t)) => Eq (Fix t) where
  (Fix r) == (Fix s) = r == s

instance Ord (t (Fix t)) => Ord (Fix t) where
  compare (Fix r) (Fix s) = compare r s

instance Show (t (Fix t)) => Show (Fix t) where
  showsPrec d (Fix t) = showsPrec d t

exprs :: [Fix Expr]
exprs = concat bucket
  where
    seed :: [Fix Expr]
    seed = Fix Var : [Fix $ Const 1, Fix $ Const 2]

    bucket = map f [0..]

    maxShift = 2

    unaries :: Fix Expr -> [Fix Expr]
    unaries e = case unFix e of
      ShiftL{} -> []
      ShiftR k _ -> [ Fix (ShiftL l e) | l <- [k .. maxShift] ]
      _ -> concat [ [Fix (ShiftL l e), Fix (ShiftR l e)] | l <- [1 .. maxShift] ]

    f :: Int -> [Fix Expr]
    f 0 = []
    f 1 = seed
    f n = concatMap unaries bucket1
        ++ concatMap (\(x, y) -> [Fix $ Add x y, Fix $ Sub x y, Fix $ And x y, Fix $ Or x y])
          [(x, y) | i <- [0..n-1], i <= n-1-i, x <- bucket !! i, y <- bucket !! (n-1-i), x /= y]
      where
        bucket1 = bucket !! (n - 1)

cata :: Functor t => (t r -> r) -> Fix t -> r
cata f (Fix t) = f (fmap (cata f) t)

eval :: Int -> Fix Expr -> Int
eval v = cata (evalF v)

evalF :: Int -> Expr Int -> Int
evalF v = \case
  Var        -> v
  Const i    -> i
  ShiftL k r -> r `shiftL` k
  ShiftR k r -> r `shiftR` k
  Add r s    -> r + s
  Sub r s    -> r - s
  And r s    -> r .&. s
  Or  r s    -> r .|. s
  Xor r s    -> r `xor` s

toWheel30' :: Int -> Int
toWheel30' = fromIntegral . toWheel30 . fromIntegral

fromWheel30' :: Int -> Int
fromWheel30' = fromIntegral . fromWheel30 . fromIntegral

toWheel210' :: Int -> Int
toWheel210' = fromIntegral . toWheel210 . fromIntegral

fromWheel210' :: Int -> Int
fromWheel210' = fromIntegral . fromWheel210 . fromIntegral

functional :: Int -> Fix Expr -> Maybe Int
functional bestKnown e = alg (1000, -1000) diffs
  where
    ys = [0..47] -- map (fromIntegral . fromWheel210) [0..47]
    diffs = zipWith (-) (map (flip eval e) ys) $ map fromWheel210' [0..47] -- (map fromWheel30' ys)

    alg :: (Int, Int) -> [Int] -> Maybe Int
    alg (currMin, currMax) [] = Just $ currMax - currMin
    alg (currMin, currMax) (x : xs) = if currMax - currMin > bestKnown
      then Nothing
      else alg (newMin, newMax) xs
      where
        newMin = currMin `min` x
        newMax = currMax `max` x

findFunctional :: [(Fix Expr, Int)]
findFunctional = f 1000 exprs
  where
    f _ [] = []
    f acc (e : exs) = case mx of
      Nothing -> f acc exs
      Just x  -> if x <= acc then (e, x) : f x exs else f acc exs
      where
        mx = functional acc e

main :: IO ()
main = mapM_ (putStrLn . show) findFunctional