{"id":6994,"date":"2022-05-02T21:16:58","date_gmt":"2022-05-02T19:16:58","guid":{"rendered":"http:\/\/www.glc.us.es\/~jalonso\/exercitium\/?p=6994"},"modified":"2022-05-03T13:31:01","modified_gmt":"2022-05-03T11:31:01","slug":"clausura-de-un-conjunto-respecto-de-una-funcion","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/clausura-de-un-conjunto-respecto-de-una-funcion\/","title":{"rendered":"Clausura de un conjunto respecto de una funci\u00f3n"},"content":{"rendered":"<p>Un conjunto A est\u00e1 cerrado respecto de una funci\u00f3n  f si para  elemento x de A se tiene que f(x) pertenece a A. La clausura de un conjunto B respecto de una funci\u00f3n f es el menor conjunto A que contiene a B y es cerrado respecto de f. Por ejemplo, la clausura de {0,1,2] respecto del opuesto es {-2,-1,0,1,2}.<\/p>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   clausura :: Ord a => (a -> a) -> [a] -> [a]\n<\/pre>\n<p>tal que <code>(clausura f xs)<\/code> es la clausura de <code>xs<\/code> respecto de f. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   clausura (\\x -> -x) [0,1,2]         ==  [-2,-1,0,1,2]\n   clausura (\\x -> (x+1) `mod` 5) [0]  ==  [0,1,2,3,4]\n   length (clausura (\\x -> (x+1) `mod` (10^6)) [0]) == 1000000\n<\/pre>\n<h4>Soluciones<\/h4>\n<pre lang=\"haskell\">\nmodule Clausura where\n\nimport Data.List ((\\\\), nub, sort, union)\nimport Test.QuickCheck.HigherOrder (quickCheck')\nimport qualified Data.Set as S (Set, difference, fromList, map, null, toList, union)\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nclausura1 :: Ord a => (a -> a) -> [a] -> [a]\nclausura1 f xs\n  | esCerrado f xs = sort xs\n  | otherwise      = clausura1 f (expansion f xs)\n\n-- (esCerrado f xs) se verifica si al aplicar f a cualquier elemento de\n-- xs se obtiene un elemento de xs. Por ejemplo,\n--    \u03bb> esCerrado (\\x -> -x) [0,1,2]\n--    False\n--    \u03bb> esCerrado (\\x -> -x) [0,1,2,-2,-1]\n--    True\nesCerrado :: Ord a => (a -> a) -> [a] -> Bool\nesCerrado f xs = all (`elem` xs) (map f xs)\n\n-- (expansion f xs) es la lista (sin repeticiones) obtenidas a\u00f1adi\u00e9ndole\n-- a xs el resulta de aplicar f a sus elementos. Por ejemplo,\n--    expansion (\\x -> -x) [0,1,2]  ==  [0,1,2,-1,-2]\nexpansion :: Ord a => (a -> a) -> [a] -> [a]\nexpansion f xs = xs `union` map f xs\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nclausura2 :: Ord a => (a -> a) -> [a] -> [a]\nclausura2 f xs = sort (until (esCerrado f) (expansion f) xs)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nclausura3 :: Ord a => (a -> a) -> [a] -> [a]\nclausura3 f xs = aux xs xs\n  where aux ys vs | null ns   = sort vs\n                  | otherwise = aux ns (vs ++ ns)\n          where ns = nub (map f ys) \\\\ vs\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nclausura4 :: Ord a => (a -> a) -> [a] -> [a]\nclausura4 f xs = S.toList (clausura4' f (S.fromList xs))\n\nclausura4' :: Ord a => (a -> a) -> S.Set a -> S.Set a\nclausura4' f xs = aux xs xs\n  where aux ys vs | S.null ns = vs\n                  | otherwise = aux ns (vs `S.union` ns)\n          where ns = S.map f ys `S.difference` vs\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_clausura :: (Int -> Int) -> [Int] -> Bool\nprop_clausura f xs =\n  all (== clausura1 f xs')\n      [ clausura2 f xs'\n      , clausura3 f xs'\n      , clausura4 f xs'\n      ]\n  where xs' = sort (nub xs)\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck' prop_clausura\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> length (clausura1 (\\x -> (x+1) `mod` 800) [0])\n--    800\n--    (1.95 secs, 213,481,560 bytes)\n--    \u03bb> length (clausura2 (\\x -> (x+1) `mod` 800) [0])\n--    800\n--    (1.96 secs, 213,372,824 bytes)\n--    \u03bb> length (clausura3 (\\x -> (x+1) `mod` 800) [0])\n--    800\n--    (0.03 secs, 42,055,128 bytes)\n--    \u03bb> length (clausura4 (\\x -> (x+1) `mod` 800) [0])\n--    800\n--    (0.01 secs, 1,779,768 bytes)\n--\n--    \u03bb> length (clausura3 (\\x -> (x+1) `mod` (10^4)) [0])\n--    10000\n--    (2.50 secs, 8,080,105,816 bytes)\n--    \u03bb> length (clausura4 (\\x -> (x+1) `mod` (10^4)) [0])\n--    10000\n--    (0.05 secs, 27,186,920 bytes)\n<\/pre>\n<p>El c\u00f3digo se encuentra en <a href=\"https:\/\/github.com\/jaalonso\/Exercitium\/blob\/main\/src\/Clausura.hs\">GitHub<\/a>.<\/p>\n<p>La elaboraci\u00f3n de las soluciones se describe en el siguiente v\u00eddeo<\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/UQUzByuY_dQ\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Un conjunto A est\u00e1 cerrado respecto de una funci\u00f3n f si para elemento x de A se tiene que f(x) pertenece a A. La clausura de un conjunto B respecto de una funci\u00f3n f es el menor conjunto A que contiene a B y es cerrado respecto de f. Por ejemplo, la clausura de {0,1,2]&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[2],"tags":[561,41,498,506,406,26,392,10,390,24,141,404,11,6,14,146,562,349,242,367],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/6994"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/comments?post=6994"}],"version-history":[{"count":5,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/6994\/revisions"}],"predecessor-version":[{"id":6999,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/6994\/revisions\/6999"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/media?parent=6994"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/categories?post=6994"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/tags?post=6994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}