never executed always true always false
    1 {-# LANGUAGE AllowAmbiguousTypes #-}
    2 {-# LANGUAGE PartialTypeSignatures #-}
    3 {-# LANGUAGE TypeFamilies #-}
    4 
    5 {- |
    6 Module      : NITTA.Model.ProcessIntegrity
    7 Description : Checking the target process integrity
    8 Copyright   : (c) Artyom Kostyuchik, Aleksandr Penskoi, 2022
    9 License     : BSD3
   10 Maintainer  : aleksandr.penskoi@gmail.com
   11 Stability   : experimental
   12 -}
   13 module NITTA.Model.ProcessIntegrity (
   14     ProcessIntegrity (checkProcessIntegrity),
   15 ) where
   16 
   17 import Data.Either
   18 import Data.List qualified as L
   19 import Data.Map.Strict qualified as M
   20 import Data.Maybe
   21 import Data.Set qualified as S
   22 import Data.String.Utils qualified as S
   23 import NITTA.Model.ProcessorUnits
   24 import NITTA.Utils
   25 
   26 class ProcessIntegrity u where
   27     checkProcessIntegrity :: u -> Either String ()
   28 
   29 instance ProcessorUnit (pu v x t) v x t => ProcessIntegrity (pu v x t) where
   30     checkProcessIntegrity pu =
   31         collectChecks
   32             [ checkVerticalRelations (up2down pu) (pid2intermediate pu) (pid2endpoint pu) "intermediate not related to endpoint"
   33             , checkVerticalRelations (down2up pu) (pid2endpoint pu) (pid2intermediate pu) "endpoint not related to intermediate"
   34             , checkVerticalRelations (up2down pu) (pid2endpoint pu) (pid2instruction pu) "endpoint not related to instruction"
   35             , checkVerticalRelations (down2up pu) (pid2instruction pu) (pid2endpoint pu) "instruction not related to endpoint"
   36             ]
   37 
   38 checkVerticalRelations f dom codom errmsg =
   39     collectChecks
   40         $ map
   41             ( \x ->
   42                 let ys = M.findWithDefault S.empty x f
   43                  in if any (`M.member` codom) $ S.elems ys
   44                         then Right ()
   45                         else Left $ errmsg <> ": " <> show (dom M.! x)
   46             )
   47         $ M.keys dom
   48 
   49 -- TODO: #205 Divider: missing vertical relation between Do instruction and Endpoint
   50 skipIntegrityErrors = ["instruction not related to endpoint: Instruction: Do"]
   51 
   52 collectChecks checks = case lefts checks of
   53     [] -> Right ()
   54     errs -> case filter (`L.notElem` skipIntegrityErrors) errs of
   55         [] -> Right ()
   56         errs' -> Left $ S.join "; " errs'
   57 
   58 relationsMap pairs = M.fromList $ map merge $ L.groupBy (\a b -> fst a == fst b) $ L.sortOn fst pairs
   59     where
   60         merge xs@((a, _) : _) = (a, S.fromList $ map snd xs)
   61         merge _ = error "internal error"
   62 
   63 up2down pu = relationsMap $ mapMaybe get $ relations $ process pu
   64     where
   65         get Vertical{vUp, vDown} = Just (vUp, vDown)
   66         get _ = Nothing
   67 
   68 down2up pu = relationsMap $ mapMaybe get $ relations $ process pu
   69     where
   70         get Vertical{vUp, vDown} = Just (vDown, vUp)
   71         get _ = Nothing
   72 
   73 pid2intermediate pu = M.fromList $ mapMaybe get $ steps $ process pu
   74     where
   75         get s@Step{pID}
   76             | Just f <- getIntermediate s = Just (pID, f)
   77             | otherwise = Nothing
   78 
   79 pid2endpoint pu = M.fromList $ mapMaybe get $ steps $ process pu
   80     where
   81         get s@Step{pID}
   82             | Just ep <- getEndpoint s = Just (pID, ep)
   83             | otherwise = Nothing
   84 
   85 pid2instruction pu = M.fromList $ mapMaybe get $ steps $ process pu
   86     where
   87         get s@Step{pID}
   88             | Just instr <- getInstruction s = Just (pID, instr)
   89             | otherwise = Nothing