----------------------------------------------------------------------------
-- HNU CE 데이터베이스(2025년 2학기 02분반): FD 관련 프로그래밍 과제
----------------------------------------------------------------------------
-- 이름: 이재혁
-- 학번: 20210501
----------------------------------------------------------------------------
import Data. List
-- representing sets withi lists
subset xs ys
= null ( xs\\ys
) -- subset test in terms of set subtraction
-- functional dependency A B C -> D E encoded as (["A","B","C"],["D","E"])
type FD = ( [ Attr] , [ Attr] )
type Attr
= String -- attributes are represented as strings
-- 3.2.4절 Algorithm 3.7
closure :: [ FD] -> [ Attr] -> [ Attr]
closure fds xs = if xs/= xs1 then closure fds xs1 else sort xs
where xs1
= foldr union xs
[ cs
| ( bs
, cs
) <- fds
, bs `subset` xs
]
-- fd가 기존의 fds로부터 유도 가능한지 검사 (closure 활용한 간단한 함수)
is
_ derived
_ from
:: FD
-> [ FD
] -> Bool is
_ derived
_ from fd fds
= all ( `
elem ` closureSet
) rhs
where
closureSet = closure fds lhs
-- 3.2.7절 관련 fds의 basis인지 검사
is
_ basis
_ of
:: [ FD
] -> [ FD
] -> Bool is_ basis_ of basis fds =
equivalent basis fds &&
where
nonredundant fd
= not ( is
_ derived
_ from fd
( filter ( /= fd
) basis
) )
equivalent a b =
all ( `is
_ derived
_ from` a
) b
&& all ( `is
_ derived
_ from` b
) a
-- 3.2.7절 basis가 미니멀한지 검사
is
_ minimal
:: [ FD
] -> Bool is_ minimal basis =
all singletonRHS basis
&& all nonredundant basis
&& where
singletonRHS
( _, rhs
) = length rhs
== 1
nonredundant fd
= not ( is
_ derived
_ from fd
( remove fd basis
) )
minimalLHS ( lhs, rhs) =
let lhs' = lhs \\ [a]
in if null lhs'
then True
else not ( is
_ derived
_ from
( lhs
', rhs) basis) ) lhs
remove x = filter (/= x)
-- 3.2.8절 Algorithm 3.12
project_FDs :: [Attr] -> [FD] -> [Attr] -> [FD]
project_FDs as fds as1 =
let
subsets = filter (not . null) (subsequences as1)
projected = nub [ (x, [a])
| x <- subsets
, let xplus = closure fds x
, a <- (xplus \\ x) `intersect` as1
]
minimizeLHS fd@(lhs,rhs) =
let smaller = [ (lhs \\ [a], rhs) | a <- lhs, length lhs > 1,is_derived_from (lhs \\ [a], rhs) projected ]
in case smaller of
(fd' :_ ) -> minimizeLHS fd'
[] -> fd
minimalT = filter (\f d -> not (is_derived_from fd (filter (/= fd) projected)))
(map minimizeLHS projected)
in nub minimalT
-- the main function for running test examples
main = do
--
putStrLn "== my Example for is_minimal test =========================="
let basis = [ (["A"], ["B"]), (["B"], ["C"]) ]
putStrLn $ "B = " ++ showFDs basis
putStrLn $ "B is minimal : " ++ show (is_minimal basis)
putStrLn ""
let basis = [ (["A", "D"], ["C", "W"]), (["B"], ["C"]) ]
putStrLn $ "B = " ++ showFDs basis
putStrLn $ "B is minimal : " ++ show (is_minimal basis)
putStrLn ""
--
putStrLn "== my Example for project_FDs test ========================="
let l_attrs= ["A", "B", "C", "D", "E", "F"]
let s_fds = [ (["A"], ["B"]) ,(["C"], ["D"]), (["E"], ["E"])]
let l1_attrs = ["A", "B", "C"]
putStrLn $ "L = " ++ showAttrSet l_attrs
putStrLn $ "S = " ++ showFDs s_fds
putStrLn $ "L1 = " ++ showAttrSet l1_attrs
let s1_fds = project_FDs l_attrs s_fds l1_attrs
putStrLn $ "S1 = " ++ showFDs s1_fds
putStrLn ""
let l_attrs2 = ["A","B","C","D","E","F","G"]
let s_fds2 = [ (["A"], ["C"]), (["D"], ["E"]), (["E","F"], ["G"]) ]
let l1_attrs2 = ["A","D","E"]
putStrLn $ "L = " ++ showAttrSet l_attrs2
putStrLn $ "S = " ++ showFDs s_fds2
putStrLn $ "L1 = " ++ showAttrSet l1_attrs2
let s2_fds = project_FDs l_attrs2 s_fds2 l1_attrs2
putStrLn $ "S1 = " ++ showFDs s2_fds
putStrLn ""
--
-- helper functions for pretty printing
showFD :: FD -> String
showFD (as,bs) = concat $ intersperse " " (as ++ "->" : bs)
showFDs :: [FD] -> String
showFDs fds = "{" ++ concat (intersperse ", " $ map showFD fds) ++ "}"
showAttrSet :: [Attr] -> String
showAttrSet as = "{" ++ concat (intersperse "," as) ++ "}"
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQotLSBITlUgQ0Ug642w7J207YSw67Kg7J207IqkKDIwMjXrhYQgMu2Vmeq4sCAwMuu2hOuwmCk6IEZEIOq0gOugqCDtlITroZzqt7jrnpjrsI0g6rO87KCcCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLS0g7J2066aEOiDsnbTsnqztmIEKLS0g7ZWZ67KIOiAyMDIxMDUwMQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgppbXBvcnQgRGF0YS5MaXN0Ci0tIHJlcHJlc2VudGluZyBzZXRzIHdpdGhpIGxpc3RzCgpzdWJzZXQgeHMgeXMgPSBudWxsICh4c1xceXMpCS0tIHN1YnNldCB0ZXN0IGluIHRlcm1zIG9mIHNldCBzdWJ0cmFjdGlvbgoKLS0gZnVuY3Rpb25hbCBkZXBlbmRlbmN5IEEgQiBDIC0+IEQgRSBlbmNvZGVkIGFzIChbIkEiLCJCIiwiQyJdLFsiRCIsIkUiXSkKdHlwZSBGRCA9IChbQXR0cl0sIFtBdHRyXSkKdHlwZSBBdHRyID0gU3RyaW5nICAtLSBhdHRyaWJ1dGVzIGFyZSByZXByZXNlbnRlZCBhcyBzdHJpbmdzCgoKLS0gIDMuMi407KCIIEFsZ29yaXRobSAzLjcKY2xvc3VyZSA6OiBbRkRdIC0+IFtBdHRyXSAtPiBbQXR0cl0gICAKY2xvc3VyZSBmZHMgeHMgPSBpZiB4cy89eHMxIHRoZW4gY2xvc3VyZSBmZHMgeHMxIGVsc2Ugc29ydCB4cwoJd2hlcmUgeHMxID0gZm9sZHIgdW5pb24geHMgW2NzIHwgKGJzLGNzKSA8LSBmZHMsIGJzIGBzdWJzZXRgIHhzXQoKLS0gZmTqsIAg6riw7KG07J2YIGZkc+uhnOu2gO2EsCDsnKDrj4Qg6rCA64ql7ZWc7KeAIOqygOyCrCAoY2xvc3VyZSDtmZzsmqntlZwg6rCE64uo7ZWcIO2VqOyImCkKaXNfZGVyaXZlZF9mcm9tIDo6IEZEIC0+IFtGRF0gLT4gQm9vbAppc19kZXJpdmVkX2Zyb20gZmQgZmRzID0gYWxsIChgZWxlbWAgY2xvc3VyZVNldCkgcmhzCiAgd2hlcmUKICAgIGxocyA9IGZzdCBmZAogICAgcmhzID0gc25kIGZkCiAgICBjbG9zdXJlU2V0ID0gY2xvc3VyZSBmZHMgbGhzCiAKLS0gMy4yLjfsoIgg6rSA66CoIGZkc+ydmCBiYXNpc+yduOyngCDqsoDsgqwKaXNfYmFzaXNfb2YgOjogW0ZEXSAtPiBbRkRdIC0+IEJvb2wKaXNfYmFzaXNfb2YgYmFzaXMgZmRzID0KICAgIGVxdWl2YWxlbnQgYmFzaXMgZmRzICYmICAgICAgICAgICAgIAogICAgYWxsIG5vbnJlZHVuZGFudCBiYXNpcyAgICAgICAgICAgICAgICAKICB3aGVyZQogICAgCiAgICBub25yZWR1bmRhbnQgZmQgPSBub3QgKGlzX2Rlcml2ZWRfZnJvbSBmZCAoZmlsdGVyICgvPSBmZCkgYmFzaXMpKQoKICAgIGVxdWl2YWxlbnQgYSBiID0KICAgICAgICBhbGwgKGBpc19kZXJpdmVkX2Zyb21gIGEpIGIgJiYKICAgICAgICBhbGwgKGBpc19kZXJpdmVkX2Zyb21gIGIpIGEKCi0tICAzLjIuN+ygiCBiYXNpc+qwgCDrr7jri4jrqYDtlZzsp4Ag6rKA7IKsCmlzX21pbmltYWwgOjogW0ZEXSAtPiBCb29sCmlzX21pbmltYWwgYmFzaXMgPQogICAgYWxsIHNpbmdsZXRvblJIUyBiYXNpcyAmJiAgICAgICAgCiAgICBhbGwgbm9ucmVkdW5kYW50IGJhc2lzICYmICAgICAgICAKICAgIGFsbCBtaW5pbWFsTEhTIGJhc2lzICAgICAgICAgICAgIAogIHdoZXJlCiAgICBzaW5nbGV0b25SSFMgKF8sIHJocykgPSBsZW5ndGggcmhzID09IDEKCiAgICBub25yZWR1bmRhbnQgZmQgPSBub3QgKGlzX2Rlcml2ZWRfZnJvbSBmZCAocmVtb3ZlIGZkIGJhc2lzKSkKCiAgICBtaW5pbWFsTEhTIChsaHMsIHJocykgPQogICAgICAgIGFsbCAoXGEgLT4KICAgICAgICAgICAgbGV0IGxocycgPSBsaHMgXFwgW2FdCiAgICAgICAgICAgIGluIGlmIG51bGwgbGhzJyAKICAgICAgICAgICAgICAgIHRoZW4gVHJ1ZSAgICAgIAogICAgICAgICAgICAgICAgZWxzZSBub3QgKGlzX2Rlcml2ZWRfZnJvbSAobGhzJywgcmhzKSBiYXNpcykKICAgICAgICApIGxocwoKICAgIHJlbW92ZSB4ID0gZmlsdGVyICgvPSB4KQoKLS0gMy4yLjjsoIggQWxnb3JpdGhtIDMuMTIKcHJvamVjdF9GRHMgOjogW0F0dHJdIC0+IFtGRF0gLT4gW0F0dHJdIC0+IFtGRF0KcHJvamVjdF9GRHMgYXMgZmRzIGFzMSA9IAogIGxldAogICAgc3Vic2V0cyA9IGZpbHRlciAobm90IC4gbnVsbCkgKHN1YnNlcXVlbmNlcyBhczEpCiAgICBwcm9qZWN0ZWQgPSBudWIgWyAoeCwgW2FdKQogICAgICAgICAgICAgICAgICAgIHwgeCA8LSBzdWJzZXRzCiAgICAgICAgICAgICAgICAgICAgLCBsZXQgeHBsdXMgPSBjbG9zdXJlIGZkcyB4CiAgICAgICAgICAgICAgICAgICAgLCBhIDwtICh4cGx1cyBcXCB4KSBgaW50ZXJzZWN0YCBhczEKICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgICAgCiAgICBtaW5pbWl6ZUxIUyBmZEAobGhzLHJocykgPSAKICAgICAgbGV0IHNtYWxsZXIgPSBbIChsaHMgXFwgW2FdLCByaHMpIHwgYSA8LSBsaHMsIGxlbmd0aCBsaHMgPiAxLGlzX2Rlcml2ZWRfZnJvbSAobGhzIFxcIFthXSwgcmhzKSBwcm9qZWN0ZWQgXQogICAgICBpbiBjYXNlIHNtYWxsZXIgb2YKICAgICAgICAgICAoZmQnOl8pIC0+IG1pbmltaXplTEhTIGZkJyAKICAgICAgICAgICBbXSAgICAgIC0+IGZkCiAgICBtaW5pbWFsVCA9IGZpbHRlciAoXGZkIC0+IG5vdCAoaXNfZGVyaXZlZF9mcm9tIGZkIChmaWx0ZXIgKC89IGZkKSBwcm9qZWN0ZWQpKSkgCiAgICAgICAgICAgICAgIChtYXAgbWluaW1pemVMSFMgcHJvamVjdGVkKQogIGluIG51YiBtaW5pbWFsVAotLSB0aGUgbWFpbiBmdW5jdGlvbiBmb3IgcnVubmluZyB0ZXN0IGV4YW1wbGVzCm1haW4gPSBkbwoJLS0KCXB1dFN0ckxuICI9PSBteSBFeGFtcGxlIGZvciBpc19taW5pbWFsIHRlc3QgPT09PT09PT09PT09PT09PT09PT09PT09PT0iCglsZXQgYmFzaXMgPSBbIChbIkEiXSwgWyJCIl0pLCAoWyJCIl0sIFsiQyJdKSBdCglwdXRTdHJMbiAkICJCID0gIiArKyBzaG93RkRzIGJhc2lzCglwdXRTdHJMbiAkICJCIGlzIG1pbmltYWwgOiAiICsrIHNob3cgKGlzX21pbmltYWwgYmFzaXMpCglwdXRTdHJMbiAiIgoJCglsZXQgYmFzaXMgPSBbIChbIkEiLCAiRCJdLCBbIkMiLCAiVyJdKSwgKFsiQiJdLCBbIkMiXSkgXQoJcHV0U3RyTG4gJCAiQiA9ICIgKysgc2hvd0ZEcyBiYXNpcwoJcHV0U3RyTG4gJCAiQiBpcyBtaW5pbWFsIDogIiArKyBzaG93IChpc19taW5pbWFsIGJhc2lzKQoJcHV0U3RyTG4gIiIKCS0tCglwdXRTdHJMbiAiPT0gbXkgRXhhbXBsZSBmb3IgcHJvamVjdF9GRHMgdGVzdCA9PT09PT09PT09PT09PT09PT09PT09PT09IgoKCWxldCBsX2F0dHJzPSBbIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIsICJGIl0gICAgICAgICAgICAgICAgCglsZXQgc19mZHMgPSBbIChbIkEiXSwgWyJCIl0pICwoWyJDIl0sIFsiRCJdKSwgKFsiRSJdLCBbIkUiXSldIAoJbGV0IGwxX2F0dHJzID0gWyJBIiwgIkIiLCAiQyJdICAgICAgICAgICAgICAgICAgIAoKCXB1dFN0ckxuICQgIkwgPSAiICsrIHNob3dBdHRyU2V0IGxfYXR0cnMKCXB1dFN0ckxuICQgIlMgPSAiICsrIHNob3dGRHMgc19mZHMKCXB1dFN0ckxuICQgIkwxID0gIiArKyBzaG93QXR0clNldCBsMV9hdHRycwoKCWxldCBzMV9mZHMgPSBwcm9qZWN0X0ZEcyBsX2F0dHJzIHNfZmRzIGwxX2F0dHJzCglwdXRTdHJMbiAkICJTMSA9ICIgKysgc2hvd0ZEcyBzMV9mZHMKCXB1dFN0ckxuICIiCgoKCWxldCBsX2F0dHJzMiA9IFsiQSIsIkIiLCJDIiwiRCIsIkUiLCJGIiwiRyJdCglsZXQgc19mZHMyID0gWyAoWyJBIl0sIFsiQyJdKSwgKFsiRCJdLCBbIkUiXSksIChbIkUiLCJGIl0sIFsiRyJdKSBdCglsZXQgbDFfYXR0cnMyID0gWyJBIiwiRCIsIkUiXQoKCXB1dFN0ckxuICQgIkwgPSAiICsrIHNob3dBdHRyU2V0IGxfYXR0cnMyCglwdXRTdHJMbiAkICJTID0gIiArKyBzaG93RkRzIHNfZmRzMgoJcHV0U3RyTG4gJCAiTDEgPSAiICsrIHNob3dBdHRyU2V0IGwxX2F0dHJzMgoJCglsZXQgczJfZmRzID0gcHJvamVjdF9GRHMgbF9hdHRyczIgc19mZHMyIGwxX2F0dHJzMgoJcHV0U3RyTG4gJCAiUzEgPSAiICsrIHNob3dGRHMgczJfZmRzCglwdXRTdHJMbiAiIgoKCS0tCgotLSBoZWxwZXIgZnVuY3Rpb25zIGZvciBwcmV0dHkgcHJpbnRpbmcKc2hvd0ZEIDo6IEZEIC0+IFN0cmluZwpzaG93RkQgKGFzLGJzKSA9IGNvbmNhdCAkIGludGVyc3BlcnNlICIgIiAoYXMgKysgIi0+IiA6IGJzKQoKc2hvd0ZEcyA6OiBbRkRdIC0+IFN0cmluZwpzaG93RkRzIGZkcyA9ICJ7IiArKyBjb25jYXQgKGludGVyc3BlcnNlICIsICIgJCBtYXAgc2hvd0ZEIGZkcykgKysgIn0iCgpzaG93QXR0clNldCA6OiBbQXR0cl0gLT4gU3RyaW5nCnNob3dBdHRyU2V0IGFzID0gInsiICsrIGNvbmNhdCAoaW50ZXJzcGVyc2UgIiwiIGFzKSArKyAifSIK