never executed always true always false
    1 module HelVM.HelMA.Automata.Piet.Compiler
    2   ( compile
    3   , label4
    4   , label4With
    5   ) where
    6 
    7 import           HelVM.HelMA.Automata.Piet.Types.Color
    8 import           HelVM.HelMA.Automata.Piet.Types.Coordinates ( Coordinates )
    9 import           HelVM.HelMA.Automata.Piet.Types.Image
   10 import           HelVM.HelMA.Automata.Piet.Types.Label
   11 import           HelVM.HelMA.Automata.Piet.Types.Labelling
   12 import           HelVM.HelMA.Automata.Piet.Types.Program     ( Program (Program) )
   13 
   14 import           Data.IntMap                                 hiding ( filter )
   15 
   16 import           Lens.Micro
   17 import           Lens.Micro.TH                               ( makeLenses )
   18 
   19 import qualified Relude.Extra                                as Extra
   20 
   21 type EquivalenceMap = IntMap LabelKey
   22 
   23 data LabellingStatus
   24   = LabellingStatus
   25       { _currentCoords :: Coordinates
   26       , _nextKey       :: LabelKey
   27       , _labelling     :: Labelling
   28       , _equivalences  :: EquivalenceMap
   29       }
   30   deriving stock (Show)
   31 
   32 makeLenses ''LabellingStatus
   33 
   34 compile ∷ Image Color → Program
   35 compile image_ = Program image_ (label4 image_)
   36 
   37 label4 ∷ Eq a ⇒ Image a → Labelling
   38 label4 = label4With (==)
   39 
   40 label4With ∷ (a → a → Bool) → Image a → Labelling
   41 label4With neighbours img = Labelling img' inf where
   42   initialLabelling = Labelling (newImage (witdthImage img, heightImage img) []) mempty
   43   status           = label4With' neighbours img (LabellingStatus (0, 0) 0 initialLabelling mempty)
   44   currentLabelling = status ^. labelling
   45 
   46   img' = fmap (applyEquivClass (status ^. equivalences)) (currentLabelling ^. mask)
   47   inf  = foldrWithKey (mergeClass (status ^. equivalences)) mempty (currentLabelling ^. info)
   48 
   49   applyEquivClass eqMap lbl = equivClass lbl eqMap
   50 
   51   mergeClass eqMap label labelInfo = alter (updateMap labelInfo) (equivClass label eqMap)
   52 
   53   updateMap Nothing    Nothing            = Nothing
   54   updateMap (Just new) Nothing            = Just (Just new)
   55   updateMap Nothing    (Just old)         = Just old
   56   updateMap (Just new) (Just (Just oldS)) = Just (Just (new <> oldS))
   57   updateMap _          _                  = Nothing
   58 
   59 label4With' ∷ (a → a → Bool) → Image a → LabellingStatus → LabellingStatus
   60 label4With' neighbours img status = checkNext (nextCoords xy) (updateStatus mergeLabels) where
   61   xy@(x, y) = status ^. currentCoords
   62   pixel     = pixelImage (x, y) img
   63   lblng     = status ^. labelling
   64 
   65   mergeLabels = fmap getMaskLabel $ filter isNeighbour $ addPixelInfo <$> previousNeighbours xy
   66 
   67   addPixelInfo (nx, ny) = (nx, ny, pixelImage (nx, ny) img)
   68   isNeighbour (_, _, e) = neighbours pixel e
   69   getMaskLabel (nx, ny, _) = pixelImage (nx, ny) (lblng ^. mask)
   70 
   71   updateStatus [] = status
   72     & (labelling . mask %~ setPixelImage (x, y) (status ^. nextKey))
   73     & (labelling . info %~ insert (status ^. nextKey) (addPixel (x, y) Nothing))
   74     & (nextKey %~ Extra.next)
   75 
   76   updateStatus [l] = status
   77     & (labelling . mask %~ setPixelImage (x, y) l)
   78     & (labelling . info %~ adjust (addPixel (x, y)) l)
   79 
   80   updateStatus [l1, l2] = status
   81     & (labelling . mask %~ setPixelImage (x, y) (max l1 l2))
   82     & (labelling . info %~ adjust (addPixel (x, y)) (max l1 l2))
   83     & (equivalences %~ equivInsert l1 l2)
   84 
   85   updateStatus _ = error "too many neighbours in HelVM.HelMA.Automata.Piet.Compiler.ImageProcessor.label4With'"
   86 
   87   checkNext (Just xy') s = label4With' neighbours img (s & currentCoords .~ xy')
   88   checkNext Nothing    s = s
   89 
   90   previousNeighbours (cx, cy) = filter validCoord [ (cx-1, cy), (cx, cy-1) ]
   91   validCoord (nx, ny) = nx >= 0 && ny >= 0
   92 
   93   nextCoords (cx, cy) = guardX (cx < witdthImage img - 1) cx cy
   94   guardX True  cx cy = Just (cx + 1, cy)
   95   guardX False _ cy  = guardY (cy < heightImage img - 1) cy
   96   guardY True  cy = Just (0, cy + 1)
   97   guardY False _  = Nothing
   98 
   99 equivClass ∷ LabelKey → EquivalenceMap → LabelKey
  100 equivClass e = findWithDefault e e
  101 
  102 equivInsert ∷ LabelKey → LabelKey → EquivalenceMap → EquivalenceMap
  103 equivInsert x y mp = guardInsert (x /= y) where
  104   guardInsert True  = fmap replaceClass $ insert x newClass $ insert y newClass mp
  105   guardInsert False = mp
  106 
  107   class1   = equivClass x mp
  108   class2   = equivClass y mp
  109   classes  = x :| [y, class1, class2]
  110   newClass = Extra.minimum1 classes
  111 
  112   replaceClass eqClass = checkInClass (eqClass `elem` classes) eqClass
  113   checkInClass True  _   = newClass
  114   checkInClass False eqc = eqc