module Defs.Structures where
import Data.Ord
import Defs.Util
-- | Data structure for keeping data structures
data Structure = DS { getDSName :: String, -- ^ name of the data structure
getDSOps :: [DSOperation] -- ^ operations along with their complexities
} deriving Eq
instance Show Structure where
show = getDSName
-- | Type for operation names
data OperationName = InsertVal -- ^ Insert an element
| DeleteByRef -- ^ Delete the element
| FindByVal -- ^ Find the element by value
| UpdateByRef -- ^ Update the value
| DeleteExtremalVal -- ^ Delete the extreme value
| ExtremalVal -- ^ Maximum or minimum
| BoundByRef -- ^ Precedessor or successor
| DecreaseValByRef -- ^ Update that decreases the value
| Union -- ^ Union
| Intersection -- ^ Intersection
| Difference -- ^ Difference
| SymDifference -- ^ Symmetric difference
| Map -- ^ Map elements
| Size -- ^ Checking the size
| Empty -- ^ Checking the empiness
deriving (Show, Eq)
-- | Additional complexity qualifiers
data ComplexityCharacteristics = N -- ^ Normal time
| A -- ^ Amortized time
| E -- ^ Expected time
| AE -- ^ Amortized expected time
deriving (Ord, Eq, Show)
-- | Full complexity type
type Complexity = (AsymptoticalComplexity, ComplexityCharacteristics)
-- | Asymptotical complexity type, remembered as the exponent of the @n@ and the number of stacked logarithms
data AsymptoticalComplexity = LinLog { getLin :: Integer, -- ^ exponent of @n@
getLog :: Integer -- ^ number of the stacked logarithms
} deriving (Eq)
-- | Greater structure is slower
instance Ord AsymptoticalComplexity where
compare (LinLog l1 l2) (LinLog r1 r2) = case compare l1 r1 of
EQ -> compare l2 r2
x -> x
instance Show AsymptoticalComplexity where
show (LinLog 0 0) = "O(1)"
show (LinLog 1 0) = "O(n)"
show (LinLog 0 n) = "O(" ++ logs n ++ " n)"
show (LinLog 1 n) = "O(n " ++ logs n ++ " n)"
show (LinLog n 0) = "O(n^" ++ show n ++ ")"
show (LinLog n m) = "O(n^" ++ show n ++ " " ++ logs m ++ " n)"
-- | Function to pretty print stacked logarithms
logs :: Integer -> String
logs 0 = ""
logs n = "log" ++ logs (n-1)
-- | Type for operation and its complexity
data DSOperation = Op { getOpName :: OperationName, -- ^ Operation name
getComplexity :: Complexity -- ^ Complexity of the operation
} deriving (Show, Eq)
instance Ord DSOperation where
compare (Op _ c1) (Op _ c2) = compare c1 c2
-- | Function to check which of the two data structures, on given operations, is better
compareDS :: Structure -> Structure -> [OperationName] -> Ordering
compareDS s1 s2 opns = let ops1 = filter (\x -> getOpName x `elem` opns) (getDSOps s1)
ops2 = filter (\x -> getOpName x `elem` opns) (getDSOps s2) in
case Data.Ord.comparing length ops1 ops2 of
LT -> LT
GT -> GT
EQ -> if null ops1
then EQ
else case Data.Ord.comparing maximum ops1 ops2 of
LT -> GT
GT -> LT
EQ -> let ordList = zipWith compare ops1 ops2 in
compare (countElem GT ordList) (countElem LT ordList)