{"id":8543,"date":"2024-04-24T14:15:01","date_gmt":"2024-04-24T12:15:01","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/?p=8543"},"modified":"2024-04-30T14:41:42","modified_gmt":"2024-04-30T12:41:42","slug":"24-abr-24","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/24-abr-24\/","title":{"rendered":"Numeraci\u00f3n de las ternas de n\u00fameros naturales"},"content":{"rendered":"<p>Las ternas de n\u00fameros naturales se pueden ordenar como sigue<\/p>\n<pre lang=\"haskell\">\n   (0,0,0),\n   (0,0,1),(0,1,0),(1,0,0),\n   (0,0,2),(0,1,1),(0,2,0),(1,0,1),(1,1,0),(2,0,0),\n   (0,0,3),(0,1,2),(0,2,1),(0,3,0),(1,0,2),(1,1,1),(1,2,0),(2,0,1),...\n   ...\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   posicion :: (Int,Int,Int) -> Int\n<\/pre>\n<p>tal que <code>posicion (x,y,z)<\/code> es la posici\u00f3n de la terna de n\u00fameros naturales <code>(x,y,z)<\/code> en la ordenaci\u00f3n anterior. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   posicion (0,1,0)  ==  2\n   posicion (0,0,2)  ==  4\n   posicion (0,1,1)  ==  5\n<\/pre>\n<p>Comprobar con QuickCheck que<\/p>\n<ul>\n<li>la posici\u00f3n de (x,0,0) es x(x\u00b2+6x+11)\/6<\/li>\n<li>la posici\u00f3n de (0,y,0) es y(y\u00b2+3y+ 8)\/6<\/li>\n<li>la posici\u00f3n de (0,0,z) es z(z\u00b2+3z+ 2)\/6<\/li>\n<li>la posici\u00f3n de (x,x,x) es x(9x\u00b2+14x+7)\/2<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h2>1. Soluciones en Haskell<\/h2>\n<pre lang=\"haskell\">\nimport Data.List (elemIndex)\nimport Data.Maybe (fromJust)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nposicion1 :: (Int,Int,Int) -> Int\nposicion1 t = aux 0 ternas\n  where aux n (t':ts) | t' == t   = n\n                      | otherwise = aux (n+1) ts\n\n-- ternas es la lista ordenada de las ternas de n\u00fameros naturales. Por ejemplo,\n--    \u03bb> take 9 ternas\n--    [(0,0,0),(0,0,1),(0,1,0),(1,0,0),(0,0,2),(0,1,1),(0,2,0),(1,0,1),(1,1,0)]\nternas :: [(Int,Int,Int)]\nternas = [(x,y,n-x-y) | n <- [0..], x <- [0..n], y <- [0..n-x]]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nposicion2 :: (Int,Int,Int) -> Int\nposicion2 t =\n  head [n | (n,t') <- zip [0..] ternas, t' == t]\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nposicion3 :: (Int,Int,Int) -> Int\nposicion3 t = indice t ternas\n\n-- (indice x ys) es el \u00edndice de x en ys. Por ejemplo,\n--    indice 5 [0..]  ==  5\nindice :: Eq a => a -> [a] -> Int\nindice x ys = length (takeWhile (\/= x) ys)\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nposicion4 :: (Int,Int,Int) -> Int\nposicion4 t = fromJust (elemIndex t ternas)\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\nposicion5 :: (Int,Int,Int) -> Int\nposicion5 = fromJust . (`elemIndex` ternas)\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: ((Int,Int,Int) -> Int) -> Spec\nspecG posicion = do\n  it \"e1\" $\n    posicion (0,1,0)  `shouldBe`  2\n  it \"e2\" $\n    posicion (0,0,2)  `shouldBe`  4\n  it \"e3\" $\n    posicion (0,1,1)  `shouldBe`  5\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG posicion1\n  describe \"def. 2\" $ specG posicion2\n  describe \"def. 3\" $ specG posicion3\n  describe \"def. 4\" $ specG posicion4\n  describe \"def. 5\" $ specG posicion5\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    15 examples, 0 failures\n\n-- Equivalencia\n-- ============\n\n-- La propiedad es\nprop_posicion_equiv :: NonNegative Int\n                    -> NonNegative Int\n                    -> NonNegative Int\n                    -> Bool\nprop_posicion_equiv (NonNegative x) (NonNegative y) (NonNegative z) =\n  all (== posicion1 (x,y,z))\n      [f (x,y,z) | f <- [ posicion2\n                        , posicion3\n                        , posicion4\n                        , posicion5 ]]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheckWith (stdArgs {maxSize=20}) prop_posicion_equiv\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> posicion1 (147,46,116)\n--    5000000\n--    (5.84 secs, 2,621,428,184 bytes)\n--    \u03bb> posicion2 (147,46,116)\n--    5000000\n--    (3.63 secs, 2,173,230,200 bytes)\n--    \u03bb> posicion3 (147,46,116)\n--    5000000\n--    (2.48 secs, 1,453,229,880 bytes)\n--    \u03bb> posicion4 (147,46,116)\n--    5000000\n--    (1.91 secs, 1,173,229,840 bytes)\n--    \u03bb> posicion5 (147,46,116)\n--    5000000\n--    (1.94 secs, 1,173,229,960 bytes)\n\n-- Propiedades\n-- ===========\n\n-- La 1\u00aa propiedad es\nprop_posicion1 :: NonNegative Int -> Bool\nprop_posicion1 (NonNegative x) =\n  posicion5 (x,0,0) == x * (x^2 + 6*x + 11) `div` 6\n\n-- Su comprobaci\u00f3n es\n--    \u03bb> quickCheckWith (stdArgs {maxSize=20}) prop_posicion1\n--    +++ OK, passed 100 tests.\n\n-- La 2\u00aa propiedad es\nprop_posicion2 :: NonNegative Int -> Bool\nprop_posicion2 (NonNegative y) =\n  posicion5 (0,y,0) == y * (y^2 + 3*y + 8) `div` 6\n\n-- Su comprobaci\u00f3n es\n--    \u03bb> quickCheckWith (stdArgs {maxSize=20}) prop_posicion2\n--    +++ OK, passed 100 tests.\n\n-- La 3\u00aa propiedad es\nprop_posicion3 :: NonNegative Int -> Bool\nprop_posicion3 (NonNegative z) =\n  posicion5 (0,0,z) == z * (z^2 + 3*z + 2) `div` 6\n\n-- Su comprobaci\u00f3n es\n--    \u03bb> quickCheckWith (stdArgs {maxSize=20}) prop_posicion3\n--    +++ OK, passed 100 tests.\n\n-- La 4\u00aa propiedad es\nprop_posicion4 :: NonNegative Int -> Bool\nprop_posicion4 (NonNegative x) =\n  posicion5 (x,x,x) == x * (9 * x^2 + 14 * x + 7) `div` 2\n\n-- Su comprobaci\u00f3n es\n--    \u03bb> quickCheckWith (stdArgs {maxSize=20}) prop_posicion4\n--    +++ OK, passed 100 tests.\n<\/pre>\n<h2>2. Soluciones en Python<\/h2>\n<pre lang=\"python\">\nfrom itertools import count, islice, takewhile\nfrom timeit import Timer, default_timer\nfrom typing import Iterator\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# ternas es la lista ordenada de las ternas de n\u00fameros naturales. Por ejemplo,\n#    >>> list(islice(ternas(), 9))\n#    [(0,0,0),(0,0,1),(0,1,0),(1,0,0),(0,0,2),(0,1,1),(0,2,0),(1,0,1),(1,1,0)]\ndef ternas() -> Iterator[tuple[int, int, int]]:\n    return ((x, y, n-x-y)\n            for n in count()\n            for x in range(n+1)\n            for y in range(n-x+1))\n\ndef posicion1(t: tuple[int,int,int]) -> int:\n    r = 0\n    for t1 in ternas():\n        if t == t1:\n            return r\n        r = r + 1\n    return -1\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef posicion2(t: tuple[int,int,int]) -> int:\n    for (n,t1) in enumerate(ternas()):\n        if t1 == t:\n            return n\n    return -1\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef posicion3(t: tuple[int,int,int]) -> int:\n    return len(list(takewhile(lambda t1 : t1 != t, ternas())))\n\n# Verificaci\u00f3n\n# ============\n\ndef test_posicion() -> None:\n    assert list(islice(ternas(), 9)) == \\\n        [(0,0,0),(0,0,1),(0,1,0),(1,0,0),(0,0,2),(0,1,1),(0,2,0),(1,0,1),(1,1,0)]\n    for posicion in [posicion1, posicion2, posicion3]:\n        assert posicion((0,1,0)) == 2\n        assert posicion((0,0,2)) == 4\n        assert posicion((0,1,1)) == 5\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_posicion()\n#    Verificado\n\n# Equivalencia\n# ============\n\n@given(st.integers(min_value=1, max_value=10),\n       st.integers(min_value=1, max_value=10),\n       st.integers(min_value=1, max_value=10))\ndef test_posicion_equiv(x: int, y: int, z: int) -> None:\n    r = posicion1((x, y, z))\n    assert posicion2((x, y, z)) == r\n    assert posicion3((x, y, z)) == r\n\n# La comprobaci\u00f3n es\n#    >>> test_posicion_equiv()\n#    >>>\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n\n# La comparaci\u00f3n es\n#    >>> tiempo('posicion1((147,46,116))')\n#    0.72 segundos\n#    >>> tiempo('posicion2((147,46,116))')\n#    0.68 segundos\n#    >>> tiempo('posicion3((147,46,116))')\n#    0.93 segundos\n\n# Propiedades\n# ===========\n\n# La 1\u00aa propiedad es\n@given(st.integers(min_value=1, max_value=100))\ndef prop_posicion1(x: int) -> None:\n    assert posicion1((x,0,0)) == x * (x**2 + 6*x + 11) \/\/ 6\n\n# Su comprobaci\u00f3n es\n#    >>> prop_posicion1()\n#    >>>\n\n# La 2\u00aa propiedad es\n@given(st.integers(min_value=1, max_value=100))\ndef prop_posicion2(y: int) -> None:\n    assert posicion1((0,y,0)) == y * (y**2 + 3*y + 8) \/\/ 6\n\n# Su comprobaci\u00f3n es\n#    >>> prop_posicion2()\n#    >>>\n\n# La 3\u00aa propiedad es\n@given(st.integers(min_value=1, max_value=100))\ndef prop_posicion3(z: int) -> None:\n    assert posicion1((0,0,z)) == z * (z**2 + 3*z + 2) \/\/ 6\n\n# Su comprobaci\u00f3n es\n#    >>> prop_posicion3()\n#    >>>\n\n# La 4\u00aa propiedad es\n@given(st.integers(min_value=1, max_value=10))\ndef prop_posicion4(x: int) -> None:\n    assert posicion1((x,x,x)) == x * (9 * x**2 + 14 * x + 7) \/\/ 2\n\n# Su comprobaci\u00f3n es\n#    >>> prop_posicion4()\n#    >>>\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Las ternas de n\u00fameros naturales se pueden ordenar como sigue (0,0,0), (0,0,1),(0,1,0),(1,0,0), (0,0,2),(0,1,1),(0,2,0),(1,0,1),(1,1,0),(2,0,0), (0,0,3),(0,1,2),(0,2,1),(0,3,0),(1,0,2),(1,1,1),(1,2,0),(2,0,1),&#8230; &#8230; Definir la funci\u00f3n posicion :: (Int,Int,Int) -> Int tal que posicion (x,y,z) es la posici\u00f3n de la terna de n\u00fameros naturales (x,y,z) en la ordenaci\u00f3n anterior. Por ejemplo, posicion (0,1,0) == 2 posicion (0,0,2) == 4 posicion (0,1,1) == 5&#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":"default","_kad_post_title":"default","_kad_post_layout":"default","_kad_post_sidebar_id":"","_kad_post_content_style":"default","_kad_post_vertical_padding":"default","_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":[581],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8543"}],"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=8543"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8543\/revisions"}],"predecessor-version":[{"id":8544,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8543\/revisions\/8544"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/media?parent=8543"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/categories?post=8543"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/tags?post=8543"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}