{"id":8182,"date":"2024-05-03T17:02:16","date_gmt":"2024-05-03T15:02:16","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=8182"},"modified":"2024-05-03T17:02:16","modified_gmt":"2024-05-03T15:02:16","slug":"03-may-24","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/03-may-24\/","title":{"rendered":"El mes de abril en Exercitium (Ejercicios con Haskell y Python)"},"content":{"rendered":"<p>Durante el mes de abril he publicado en <a href=\"http:\/\/bit.ly\/2sqPtGs\">Exercitium<\/a> las soluciones de los siguientes problemas:<\/p>\n<ul>\n<li><a href=\"#ej1\">1. Caminos en un tri\u00e1ngulo<\/a><\/li>\n<li><a href=\"#ej2\">2. M\u00e1xima suma de caminos en un tri\u00e1ngulo<\/a><\/li>\n<li><a href=\"#ej3\">3. N\u00fameros amigos<\/a><\/li>\n<li><a href=\"#ej4\">4. Primos equidistantes<\/a><\/li>\n<li><a href=\"#ej5\">5. Numeraci\u00f3n de las ternas de n\u00fameros naturales<\/a><\/li>\n<li><a href=\"#ej6\">6. N\u00fameros triangulares con n cifras distintas<\/a><\/li>\n<\/ul>\n<p>A continuaci\u00f3n se muestran las soluciones.<br \/>\n<!--more--><\/p>\n<h3>1. Caminos en un tri\u00e1ngulo<\/h3>\n<p>Los tri\u00e1ngulos se pueden representar mediante listas de listas. Por ejemplo, el tri\u00e1ngulo<\/p>\n<pre lang=\"haskell\">\n      3\n     7 4\n    2 4 6\n   8 5 9 3\n<\/pre>\n<p>se representa por<\/p>\n<pre lang=\"haskell\">\n   [[3],[7,4],[2,4,6],[8,5,9,3]]\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   caminos :: [[a]] -> [[a]]\n<\/pre>\n<p>tal que (caminos xss) es la lista de los caminos en el tri\u00e1ngulo  donde los caminos comienzan en el elemento de la primera fila, en cada paso se mueve a uno de  sus dos elementos adyacentes en la fila siguiente y terminan en la \u00faltima fila. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   \u03bb> caminos [[3],[7,4]]\n   [[3,7],[3,4]]\n   \u03bb> caminos [[3],[7,4],[2,4,6]]\n   [[3,7,2],[3,7,4],[3,4,4],[3,4,6]]\n   \u03bb> caminos [[3],[7,4],[2,4,6],[8,5,9,3]]\n   [[3,7,2,8],[3,7,2,5],[3,7,4,5],[3,7,4,9],[3,4,4,5],[3,4,4,9],[3,4,6,9],[3,4,6,3]]\n<\/pre>\n<h4>1.1. Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nmodule Caminos_en_un_triangulo where\n\nimport Test.Hspec (Spec, hspec, it, shouldBe)\n\ncaminos :: [[a]] -> [[a]]\ncaminos []    = [[]]\ncaminos [[x]] = [[x]]\ncaminos ([x]:[y1,y2]:zs) =\n  [x:y1:us | (_:us) <- caminos ([y1] : map init zs)] ++\n  [x:y2:vs | (_:vs) <- caminos ([y2] : map tail zs)]\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspec :: Spec\nspec = do\n  it \"e1\" $\n    caminos [[3],[7,4]] `shouldBe`\n    [[3,7],[3,4]]\n  it \"e2\" $\n    caminos [[3],[7,4],[2,4,6]] `shouldBe`\n    [[3,7,2],[3,7,4],[3,4,4],[3,4,6]]\n  it \"e3\" $\n    caminos [[3],[7,4],[2,4,6],[8,5,9,3]] `shouldBe`\n    [[3,7,2,8],[3,7,2,5],[3,7,4,5],[3,7,4,9],[3,4,4,5],[3,4,4,9],[3,4,6,9],[3,4,6,3]]\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--\n--    3 examples, 0 failures\n<\/pre>\n<h4>1.2. Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom typing import TypeVar\n\nA = TypeVar('A')\n\ndef caminos(xss: list[list[A]]) -> list[list[A]]:\n    if not xss:\n        return [[]]\n    if len(xss) == 1:\n        return xss\n    x = xss[0][0]\n    y1 = xss[1][0]\n    y2 = xss[1][1]\n    zss = xss[2:]\n    return [[x, y1] + us for _, *us in caminos([[y1]] + [zs[:-1] for zs in zss])] + \\\n           [[x, y2] + us for _, *us in caminos([[y2]] + [zs[1:] for zs in zss])]\n\n# Verificaci\u00f3n\n# ============\n\ndef test_caminos() -> None:\n    assert caminos([[3],[7,4]]) == \\\n        [[3,7],[3,4]]\n    assert caminos([[3],[7,4],[2,4,6]]) == \\\n        [[3,7,2],[3,7,4],[3,4,4],[3,4,6]]\n    assert caminos([[3],[7,4],[2,4,6],[8,5,9,3]]) == \\\n        [[3,7,2,8],[3,7,2,5],[3,7,4,5],[3,7,4,9],[3,4,4,5],[3,4,4,9],[3,4,6,9],[3,4,6,3]]\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_caminos()\n#    Verificado\n<\/pre>\n<h3>2. M\u00e1xima suma de caminos en un tri\u00e1ngulo<\/h3>\n<p>Los tri\u00e1ngulos se pueden representar mediante listas de listas. Por ejemplo, el tri\u00e1ngulo<\/p>\n<pre lang=\"haskell\">\n      3\n     7 4\n    2 4 6\n   8 5 9 3\n<\/pre>\n<p>se representa por<\/p>\n<pre lang=\"haskell\">\n   [[3],[7,4],[2,4,6],[8,5,9,3]]\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   maximaSuma :: [[Integer]] -> Integer\n<\/pre>\n<p>tal que (maximaSuma xss) es el m\u00e1ximo de las sumas de los  de los caminos en el tri\u00e1ngulo xss donde los caminos comienzan en el elemento de la primera fila, en cada paso se mueve a uno de  sus dos elementos adyacentes en la fila siguiente y terminan en la \u00faltima fila. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   maximaSuma [[3],[7,4]]                    ==  10\n   maximaSuma [[3],[7,4],[2,4,6]]            ==  14\n   maximaSuma [[3],[7,4],[2,4,6],[8,5,9,3]]  ==  23\n   maximaSuma [[n..n+n] | n <- [0..100]]     ==  10100\n   maximaSuma [[n..n+n] | n <- [0..1000]]    ==  1001000\n   maximaSuma [[n..n+n] | n <- [0..2000]]    ==  4002000\n   maximaSuma [[n..n+n] | n <- [0..3000]]    ==  9003000\n   maximaSuma [[n..n+n] | n <- [0..4000]]    ==  16004000\n<\/pre>\n<h4>2.1. Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nmodule Maxima_suma_de_caminos_en_un_triangulo where\n\nimport Data.List (tails)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma1 :: [[Integer]] -> Integer\nmaximaSuma1 xss =\n  maximum [sum ys | ys <- caminos xss]\n\ncaminos :: [[Integer]] -> [[Integer]]\ncaminos []    = [[]]\ncaminos [[x]] = [[x]]\ncaminos ([x]:[y1,y2]:zs) =\n  [x:y1:us | (_:us) <- caminos ([y1] : map init zs)] ++\n  [x:y2:vs | (_:vs) <- caminos ([y2] : map tail zs)]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma2 :: [[Integer]] -> Integer\nmaximaSuma2 xss = maximum (map sum (caminos xss))\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma3 :: [[Integer]] -> Integer\nmaximaSuma3 = maximum . map sum . caminos\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma4 :: [[Integer]] -> Integer\nmaximaSuma4 []    = 0\nmaximaSuma4 [[x]] = x\nmaximaSuma4 ([x]:[y1,y2]:zs) =\n  x + max (maximaSuma4 ([y1] : map init zs))\n          (maximaSuma4 ([y2] : map tail zs))\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma5 :: [[Integer]] -> Integer\nmaximaSuma5 xss = head (foldr1 g xss)\n  where\n    f x y z = x + max y z\n    g xs ys = zipWith3 f xs ys (tail ys)\n\n-- 6\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma6 :: [[Integer]] -> Integer\nmaximaSuma6 xss = head (foldr1 aux xss)\n  where aux a b = zipWith (+) a (zipWith max b (tail b))\n\n-- 7\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma7 :: [[Integer]] -> Integer\nmaximaSuma7 xss = head (foldr (flip f) (last xss) (init xss))\n  where f = zipWith ((+) . maximum . take 2) . tails\n\n-- 8\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma8 :: [[Integer]] -> Integer\nmaximaSuma8 = head . foldr1 aux\n  where\n    aux [] _              = []\n    aux (x:xs) (y0:y1:ys) = x + max y0 y1 : aux xs (y1:ys)\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- Para la comparaciones se usar\u00e1 la siguiente funci\u00f3n que construye un\n-- tri\u00e1ngulo de la altura dada. Por ejemplo,\n--    triangulo 2  ==  [[0],[1,2]]\n--    triangulo 3  ==  [[0],[1,2],[2,3,4]]\n--    triangulo 4  ==  [[0],[1,2],[2,3,4],[3,4,5,6]]\ntriangulo :: Integer -> [[Integer]]\ntriangulo n = [[k..k+k] | k <- [0..n-1]]\n\n-- La comparaci\u00f3n es\n--    (1.97 secs, 876,483,056 bytes)\n--    \u03bb> maximaSuma1 (triangulo 19)\n--    342\n--    (2.37 secs, 1,833,637,824 bytes)\n--    \u03bb> maximaSuma2 (triangulo 19)\n--    342\n--    (2.55 secs, 1,804,276,472 bytes)\n--    \u03bb> maximaSuma3 (triangulo 19)\n--    342\n--    (2.57 secs, 1,804,275,320 bytes)\n--    \u03bb> maximaSuma4 (triangulo 19)\n--    342\n--    (0.28 secs, 245,469,384 bytes)\n--    \u03bb> maximaSuma5 (triangulo 19)\n--    342\n--    (0.01 secs, 153,272 bytes)\n--    \u03bb> maximaSuma6 (triangulo 19)\n--    342\n--    (0.01 secs, 161,360 bytes)\n--    \u03bb> maximaSuma7 (triangulo 19)\n--    342\n--    (0.01 secs, 187,456 bytes)\n--    \u03bb> maximaSuma8 (triangulo 19)\n--    342\n--    (0.01 secs, 191,160 bytes)\n--\n--    \u03bb> maximaSuma4 (triangulo 22)\n--    462\n--    (2.30 secs, 1,963,037,888 bytes)\n--    \u03bb> maximaSuma5 (triangulo 22)\n--    462\n--    (0.00 secs, 173,512 bytes)\n--    \u03bb> maximaSuma6 (triangulo 22)\n--    462\n--    (0.01 secs, 182,904 bytes)\n--    \u03bb> maximaSuma7 (triangulo 22)\n--    462\n--    (0.01 secs, 216,560 bytes)\n--    \u03bb> maximaSuma8 (triangulo 22)\n--    462\n--    (0.01 secs, 224,160 bytes)\n--\n--    \u03bb> maximaSuma5 (triangulo 3000)\n--    8997000\n--    (2.25 secs, 2,059,784,792 bytes)\n--    \u03bb> maximaSuma6 (triangulo 3000)\n--    8997000\n--    (2.15 secs, 2,404,239,896 bytes)\n--    \u03bb> maximaSuma7 (triangulo 3000)\n--    8997000\n--    (1.53 secs, 2,612,659,504 bytes)\n--    \u03bb> maximaSuma8 (triangulo 3000)\n--    8997000\n--    (3.47 secs, 3,520,910,256 bytes)\n--\n--    \u03bb> maximaSuma7 (triangulo 4000)\n--    15996000\n--    (3.12 secs, 4,634,841,200 bytes)\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: ([[Integer]] -> Integer) -> Spec\nspecG maximaSuma = do\n  it \"e1\" $\n    maximaSuma [[3],[7,4]]                    `shouldBe`  10\n  it \"e2\" $\n    maximaSuma [[3],[7,4],[2,4,6]]            `shouldBe`  14\n  it \"e3\" $\n    maximaSuma [[3],[7,4],[2,4,6],[8,5,9,3]]  `shouldBe`  23\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG maximaSuma1\n  describe \"def. 2\" $ specG maximaSuma2\n  describe \"def. 3\" $ specG maximaSuma3\n  describe \"def. 4\" $ specG maximaSuma4\n  describe \"def. 5\" $ specG maximaSuma5\n  describe \"def. 6\" $ specG maximaSuma6\n  describe \"def. 7\" $ specG maximaSuma7\n  describe \"def. 8\" $ specG maximaSuma8\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    Finished in 0.0053 seconds\n--    24 examples, 0 failures\n<\/pre>\n<h4>2.2. Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom timeit import Timer, default_timer\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef caminos(xss: list[list[int]]) -> list[list[int]]:\n    if not xss:\n        return [[]]\n    if len(xss) == 1:\n        return xss\n    x = xss[0][0]\n    y1 = xss[1][0]\n    y2 = xss[1][1]\n    zss = xss[2:]\n    return [[x, y1] + us for _, *us in caminos([[y1]] + [zs[:-1] for zs in zss])] + \\\n           [[x, y2] + us for _, *us in caminos([[y2]] + [zs[1:] for zs in zss])]\n\n# maximaSuma1 :: [[Integer]] -> Integer\ndef maximaSuma1(xss: list[list[int]]) -> int:\n    return max((sum(ys) for ys in caminos(xss)))\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef maximaSuma2(xss: list[list[int]]) -> int:\n    if not xss:\n        return 0\n    if len(xss) == 1:\n        return xss[0][0]\n    x = xss[0][0]\n    y1 = xss[1][0]\n    y2 = xss[1][1]\n    zss = xss[2:]\n    return x + max(maximaSuma2([[y1]] + [us[:-1] for us in zss]),\n                   maximaSuma2([[y2]] + [us[1:] for us in zss]))\n\n# Verificaci\u00f3n\n# ============\n\ndef test_maximaSuma() -> None:\n    for maximaSuma in [maximaSuma1, maximaSuma2]:\n        assert maximaSuma([[3],[7,4]]) == 10\n        assert maximaSuma([[3],[7,4],[2,4,6]]) == 14\n        assert maximaSuma([[3],[7,4],[2,4,6],[8,5,9,3]]) == 23\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_maximaSuma()\n#    Verificado\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\n# Para la comparaciones se usar\u00e1 la siguiente funci\u00f3n que construye un\n# tri\u00e1ngulo de la altura dada. Por ejemplo,\n#    >>> triangulo(2)\n#    [[0], [1, 2]]\n#    >>> triangulo(3)\n#    [[0], [1, 2], [2, 3, 4]]\n#    >>> triangulo(4)\n#    [[0], [1, 2], [2, 3, 4], [3, 4, 5, 6]]\ndef triangulo(n: int) -> list[list[int]]:\n    return [list(range(k, k+k+1)) for k in range(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# La comparaci\u00f3n es\n#    >>> tiempo('maximaSuma1(triangulo(20))')\n#    3.21 segundos\n#    >>> tiempo('maximaSuma2(triangulo(20))')\n#    0.59 segundos\n<\/pre>\n<h3>3. N\u00fameros amigos<\/h3>\n<p>Dos <a href=\"https:\/\/bit.ly\/36gSRHt\">n\u00fameros amigos<\/a> son dos n\u00fameros  positivos distintos tales que la suma de los divisores propios de cada uno es igual al otro. Los divisores propios de un n\u00famero incluyen la unidad pero no al propio n\u00famero. Por ejemplo,  divisores propios de 220 son 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 y 110. La suma de estos n\u00fameros equivale a 284. A su vez, los divisores propios de 284 son 1, 2, 4, 71 y 142. Su suma equivale a 220. Por tanto, 220 y 284 son amigos.<\/p>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   amigos :: Integer -> Integer -> Bool\n<\/pre>\n<p>tal que <code>amigos x y<\/code> se verifica si los n\u00fameros <code>x<\/code> e <code>y<\/code> son amigos. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   amigos 220 284 == True\n   amigos 220 23  == False\n   amigos 42262694537514864075544955198125 42405817271188606697466971841875 == True\n<\/pre>\n<h4>3.1. Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nmodule Numeros_amigos where\n\nimport Data.List (genericLength, group, inits, nub, sort, subsequences)\nimport Data.Numbers.Primes (primeFactors)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\n\n-- 1\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos1 :: Integer -> Integer -> Bool\namigos1 x y = sumaDivisoresPropios1 x == y &&\n              sumaDivisoresPropios1 y == x\n\n-- (sumaDivisoresPropios1 x) es la suma de los divisores propios de\n-- x. Por ejemplo,\n--    sumaDivisoresPropios1 220  ==  284\n--    sumaDivisoresPropios1 284  ==  220\nsumaDivisoresPropios1 :: Integer -> Integer\nsumaDivisoresPropios1 = sum . divisoresPropios1\n\n-- (divisoresPropios1 x) es la lista de los divisores propios de x. Por\n-- ejemplo,\n--    divisoresPropios1 220  ==  [1,2,4,5,10,11,20,22,44,55,110]\n--    divisoresPropios1 284  ==  [1,2,4,71,142]\ndivisoresPropios1 :: Integer -> [Integer]\ndivisoresPropios1 x = [n | n <- [1..x-1], x `mod` n == 0]\n\n-- 2\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos2 :: Integer -> Integer -> Bool\namigos2 x y = sumaDivisoresPropios2 x == y &&\n              sumaDivisoresPropios2 y == x\n\nsumaDivisoresPropios2 :: Integer -> Integer\nsumaDivisoresPropios2 = sum . divisoresPropios2\n\ndivisoresPropios2 :: Integer -> [Integer]\ndivisoresPropios2 x = filter ((== 0) . mod x) [1..x-1]\n\n-- 3\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos3 :: Integer -> Integer -> Bool\namigos3 x y = sumaDivisoresPropios3 x == y &&\n              sumaDivisoresPropios3 y == x\n\nsumaDivisoresPropios3 :: Integer -> Integer\nsumaDivisoresPropios3 = sum . divisoresPropios3\n\ndivisoresPropios3 :: Integer -> [Integer]\ndivisoresPropios3 =\n  init . nub . sort . map product . subsequences . primeFactors\n\n-- 4\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos4 :: Integer -> Integer -> Bool\namigos4 x y = sumaDivisoresPropios4 x == y &&\n              sumaDivisoresPropios4 y == x\n\nsumaDivisoresPropios4 :: Integer -> Integer\nsumaDivisoresPropios4 = sum . divisoresPropios4\n\ndivisoresPropios4 :: Integer -> [Integer]\ndivisoresPropios4 =\n  init\n  . sort\n  . map (product . concat)\n  . productoCartesiano\n  . map inits\n  . group\n  . primeFactors\n\n-- (productoCartesiano xss) es el producto cartesiano de los conjuntos\n-- xss. Por ejemplo,\n--    \u03bb> productoCartesiano [[1,3],[2,5],[6,4]]\n--    [[1,2,6],[1,2,4],[1,5,6],[1,5,4],[3,2,6],[3,2,4],[3,5,6],[3,5,4]]\nproductoCartesiano :: [[a]] -> [[a]]\nproductoCartesiano []       = [[]]\nproductoCartesiano (xs:xss) =\n  [x:ys | x <- xs, ys <- productoCartesiano xss]\n\n-- 5\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos5 :: Integer -> Integer -> Bool\namigos5 x y = sumaDivisoresPropios5 x == y &&\n              sumaDivisoresPropios5 y == x\n\nsumaDivisoresPropios5 :: Integer -> Integer\nsumaDivisoresPropios5 =\n  sum . divisoresPropios5\n\ndivisoresPropios5 :: Integer -> [Integer]\ndivisoresPropios5 =\n  init\n  . sort\n  . map (product . concat)\n  . sequence\n  . map inits\n  . group\n  . primeFactors\n\n-- 6\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos6 :: Integer -> Integer -> Bool\namigos6 x y = sumaDivisoresPropios6 x == y &&\n              sumaDivisoresPropios6 y == x\n\nsumaDivisoresPropios6 :: Integer -> Integer\nsumaDivisoresPropios6 =\n  sum\n  . init\n  . map (product . concat)\n  . sequence\n  . map inits\n  . group\n  . primeFactors\n\n-- 7\u00aa soluci\u00f3n                                                   --\n-- ===========\n\namigos7 :: Integer -> Integer -> Bool\namigos7 x y = sumaDivisoresPropios7 x == y &&\n              sumaDivisoresPropios7 y == x\n\n-- Si la descomposici\u00f3n de x en factores primos es\n--    x = p(1)^e(1) . p(2)^e(2) . .... . p(n)^e(n)\n-- entonces la suma de los divisores de x es\n--    p(1)^(e(1)+1) - 1     p(2)^(e(2)+1) - 1       p(n)^(e(2)+1) - 1\n--   ------------------- . ------------------- ... -------------------\n--        p(1)-1                p(2)-1                  p(n)-1\n-- Ver la demostraci\u00f3n en http:\/\/bit.ly\/2zUXZPc\n\n-- (sumaDivisoresPropios7 x) es la suma de los divisores propios de\n-- x. Por ejemplo,\n--    sumaDivisoresPropios7 220  ==  284\n--    sumaDivisoresPropios7 284  ==  220\nsumaDivisoresPropios7 :: Integer -> Integer\nsumaDivisoresPropios7 x =\n  product [(p^(e+1)-1) `div` (p-1) | (p,e) <- factorizacion x] - x\n\n-- (factorizacion x) es la lista de las bases y exponentes de la\n-- descomposici\u00f3n prima de x. Por ejemplo,\n--    factorizacion 600  ==  [(2,3),(3,1),(5,2)]\nfactorizacion :: Integer -> [(Integer,Integer)]\nfactorizacion = map primeroYlongitud . group . primeFactors\n\n-- (primeroYlongitud xs) es el par formado por el primer elemento de xs\n-- y la longitud de xs. Por ejemplo,\n--    primeroYlongitud [3,2,5,7] == (3,4)\nprimeroYlongitud :: [a] -> (a,Integer)\nprimeroYlongitud (x:xs) = (x, 1 + genericLength xs)\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: (Integer -> Integer -> Bool) -> Spec\nspecG amigos = do\n  it \"e1\" $\n    amigos 220 284 `shouldBe` True\n  it \"e2\" $\n    amigos 220 23  `shouldBe` False\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG amigos1\n  describe \"def. 2\" $ specG amigos2\n  describe \"def. 3\" $ specG amigos3\n  describe \"def. 4\" $ specG amigos4\n  describe \"def. 5\" $ specG amigos5\n  describe \"def. 6\" $ specG amigos6\n  describe \"def. 7\" $ specG amigos7\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    14 examples, 0 failures\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> amigos1 2803580 3716164\n--    True\n--    (2.27 secs, 1,304,055,864 bytes)\n--    \u03bb> amigos2 2803580 3716164\n--    True\n--    (0.81 secs, 782,478,584 bytes)\n--    \u03bb> amigos3 2803580 3716164\n--    True\n--    (0.01 secs, 383,888 bytes)\n--    \u03bb> amigos4 2803580 3716164\n--    True\n--    (0.01 secs, 461,376 bytes)\n--    \u03bb> amigos5 2803580 3716164\n--    True\n--    (0.00 secs, 412,560 bytes)\n--    \u03bb> amigos6 2803580 3716164\n--    True\n--    (0.00 secs, 387,816 bytes)\n--    \u03bb> amigos7 2803580 3716164\n--    True\n--    (0.01 secs, 339,008 bytes)\n--\n--    \u03bb> amigos2 5864660 7489324\n--    True\n--    (1.74 secs, 1,602,582,592 bytes)\n--    \u03bb> amigos3 5864660 7489324\n--    True\n--    (0.00 secs, 277,056 bytes)\n--    \u03bb> amigos4 5864660 7489324\n--    True\n--    (0.01 secs, 354,872 bytes)\n--    \u03bb> amigos5 5864660 7489324\n--    True\n--    (0.01 secs, 305,792 bytes)\n--    \u03bb> amigos6 5864660 7489324\n--    True\n--    (0.00 secs, 281,528 bytes)\n--    \u03bb> amigos7 5864660 7489324\n--    True\n--    (0.01 secs, 237,176 bytes)\n--\n--    \u03bb> amigos3 42262694537514864075544955198125 42405817271188606697466971841875\n--    True\n--    (107.54 secs, 5,594,306,392 bytes)\n--    \u03bb> amigos4 42262694537514864075544955198125 42405817271188606697466971841875\n--    True\n--    (1.03 secs, 942,530,824 bytes)\n--    \u03bb> amigos5 42262694537514864075544955198125 42405817271188606697466971841875\n--    True\n--    (0.51 secs, 591,144,304 bytes)\n--    \u03bb> amigos6 42262694537514864075544955198125 42405817271188606697466971841875\n--    True\n--    (0.26 secs, 379,534,608 bytes)\n--    \u03bb> amigos7 42262694537514864075544955198125 42405817271188606697466971841875\n--    True\n--    (0.05 secs, 25,635,464 bytes)\n<\/pre>\n<h4>3.2. Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom functools import reduce\nfrom operator import mul\nfrom timeit import Timer, default_timer\n\nfrom sympy import divisor_sigma, factorint, is_amicable, proper_divisors\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# divisoresPropios1(x) es la lista de los divisores propios de x. Por\n# ejemplo,\n#    divisoresPropios1(220)  ==  [1,2,4,5,10,11,20,22,44,55,110]\n#    divisoresPropios1(284)  ==  [1,2,4,71,142]\ndef divisoresPropios1(x: int) -> list[int]:\n    return [n for n in range(1, x) if x % n == 0]\n\n# sumaDivisoresPropios1(x) es la suma de los divisores propios de\n# x. Por ejemplo,\n#    sumaDivisoresPropios1(220)  ==  284\n#    sumaDivisoresPropios1(284)  ==  220\ndef sumaDivisoresPropios1(x: int) -> int:\n    return sum(divisoresPropios1(x))\n\ndef amigos1(x: int, y: int) -> bool:\n    return sumaDivisoresPropios1(x)== y and \\\n           sumaDivisoresPropios1(y)== x\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef divisoresPropios2(x: int) -> list[int]:\n    return proper_divisors(x)\n\ndef sumaDivisoresPropios2(x: int) -> int:\n    return sum(divisoresPropios2(x))\n\ndef amigos2(x: int, y: int) -> bool:\n    return sumaDivisoresPropios2(x)== y and \\\n           sumaDivisoresPropios2(y)== x\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\n# Si la descomposici\u00f3n de x en factores primos es\n#    x = p(1)^e(1) . p(2)^e(2) . .... . p(n)^e(n)\n# entonces la suma de los divisores de x es\n#    p(1)^(e(1)+1) - 1     p(2)^(e(2)+1) - 1       p(n)^(e(2)+1) - 1\n#   ------------------- . ------------------- ... -------------------\n#        p(1)-1                p(2)-1                  p(n)-1\n# Ver la demostraci\u00f3n en http:\/\/bit.ly\/2zUXZPc\n\n# producto(xs) es el producto de los elementos de xs. Por ejemplo,\n#    producto([2, 3, 5]) == 30\ndef producto(xs: list[int]) -> int:\n    return reduce(mul, xs)\n\n# sumaDivisoresPropios3(x) es la suma de los divisores propios de\n# x. Por ejemplo,\n#    sumaDivisoresPropios3(220)  ==  284\n#    sumaDivisoresPropios3(284)  ==  220\ndef sumaDivisoresPropios3(x: int) -> int:\n    return producto([(p**(e+1)-1) \/\/ (p-1)\n                     for (p,e) in factorint(x).items()]) - x\n\ndef amigos3(x: int, y: int) -> bool:\n    return sumaDivisoresPropios3(x)== y and \\\n           sumaDivisoresPropios3(y)== x\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\ndef amigos4(x: int, y: int) -> bool:\n    return divisor_sigma(x, 1) == divisor_sigma(y, 1)\n\n# 5\u00aa soluci\u00f3n\n# ===========\n\ndef amigos5(x: int, y: int) -> bool:\n    return is_amicable(x, y)\n\n# Verificaci\u00f3n\n# ============\n\ndef test_amigos() -> None:\n    for amigos in [amigos1, amigos2, amigos3, amigos4, amigos5]:\n        assert amigos(220, 284)\n        assert not amigos(220, 23)\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_amigos()\n#    Verificado\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# La comparaci\u00f3n es\n#    >>> tiempo('amigos1(5864660, 7489324)')\n#    0.65 segundos\n#    >>> tiempo('amigos2(5864660, 7489324)')\n#    0.00 segundos\n#    >>> tiempo('amigos3(5864660, 7489324)')\n#    0.00 segundos\n#    >>> tiempo('amigos4(5864660, 7489324)')\n#    0.00 segundos\n#    >>> tiempo('amigos5(5864660, 7489324)')\n#    0.00 segundos\n#\n#    >>> x = 42262694537514864075544955198125\n#    >>> y = 42405817271188606697466971841875\n#    >>> tiempo('amigos2(x, y)')\n#    0.10 segundos\n#    >>> tiempo('amigos3(x, y)')\n#    0.00 segundos\n#    >>> tiempo('amigos4(x, y)')\n#    0.00 segundos\n#    >>> tiempo('amigos5(x, y)')\n#    0.00 segundos\n<\/pre>\n<h3>4. Primos equidistantes<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   primosEquidistantes :: Integer -> [(Integer,Integer)]\n<\/pre>\n<p>tal que <code>primosEquidistantes k<\/code> es la lista de los pares de primos cuya diferencia es <code>k<\/code>. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   take 3 (primosEquidistantes 2)  ==  [(3,5),(5,7),(11,13)]\n   take 3 (primosEquidistantes 4)  ==  [(7,11),(13,17),(19,23)]\n   take 3 (primosEquidistantes 6)  ==  [(23,29),(31,37),(47,53)]\n   take 3 (primosEquidistantes 8)  ==  [(89,97),(359,367),(389,397)]\n   primosEquidistantes 4 !! (10^5) ==  (18467047,18467051)\n<\/pre>\n<h4>4.1. Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nmodule Primos_equidistantes where\n\nimport Data.Numbers.Primes (primes)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nprimosEquidistantes1 :: Integer -> [(Integer,Integer)]\nprimosEquidistantes1 k = aux primos\n  where aux (x:y:ps) | y - x == k = (x,y) : aux (y:ps)\n                     | otherwise  = aux (y:ps)\n\n-- (primo x) se verifica si x es primo. Por ejemplo,\n--    primo 7  ==  True\n--    primo 8  ==  False\nprimo :: Integer -> Bool\nprimo x = [y | y <- [1..x], x `rem` y == 0] == [1,x]\n\n-- primos es la lista de los n\u00fameros primos. Por ejemplo,\n--    take 10 primos  ==  [2,3,5,7,11,13,17,19,23,29]\nprimos :: [Integer]\nprimos = 2 : [x | x <- [3,5..], primo x]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nprimosEquidistantes2 :: Integer -> [(Integer,Integer)]\nprimosEquidistantes2 k = aux primos2\n  where aux (x:y:ps) | y - x == k = (x,y) : aux (y:ps)\n                     | otherwise  = aux (y:ps)\n\nprimos2 :: [Integer]\nprimos2 = criba [2..]\n  where criba (p:ps) = p : criba [n | n <- ps, mod n p \/= 0]\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nprimosEquidistantes3 :: Integer -> [(Integer,Integer)]\nprimosEquidistantes3 k =\n  [(x,y) | (x,y) <- zip primos2 (tail primos2)\n         , y - x == k]\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nprimosEquidistantes4 :: Integer -> [(Integer,Integer)]\nprimosEquidistantes4 k = aux primes\n  where aux (x:y:ps) | y - x == k = (x,y) : aux (y:ps)\n                     | otherwise  = aux (y:ps)\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\nprimosEquidistantes5 :: Integer -> [(Integer,Integer)]\nprimosEquidistantes5 k =\n  [(x,y) | (x,y) <- zip primes (tail primes)\n         , y - x == k]\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: (Integer -> [(Integer,Integer)]) -> Spec\nspecG primosEquidistantes = do\n  it \"e1\" $\n    take 3 (primosEquidistantes 2) `shouldBe` [(3,5),(5,7),(11,13)]\n  it \"e2\" $\n    take 3 (primosEquidistantes 4) `shouldBe` [(7,11),(13,17),(19,23)]\n  it \"e3\" $\n    take 3 (primosEquidistantes 6) `shouldBe` [(23,29),(31,37),(47,53)]\n  it \"e4\" $\n    take 3 (primosEquidistantes 8) `shouldBe` [(89,97),(359,367),(389,397)]\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG primosEquidistantes1\n  describe \"def. 2\" $ specG primosEquidistantes2\n  describe \"def. 3\" $ specG primosEquidistantes3\n  describe \"def. 4\" $ specG primosEquidistantes4\n  describe \"def. 5\" $ specG primosEquidistantes5\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    20 examples, 0 failures\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_primosEquidistantes :: Int -> Integer -> Bool\nprop_primosEquidistantes n k =\n  all (== take n (primosEquidistantes1 k))\n      [take n (f k) | f <- [primosEquidistantes2,\n                            primosEquidistantes3,\n                            primosEquidistantes4,\n                            primosEquidistantes5]]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> prop_primosEquidistantes 100 4\n--    True\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> primosEquidistantes1 4 !! 200\n--    (9829,9833)\n--    (2.60 secs, 1,126,458,272 bytes)\n--    \u03bb> primosEquidistantes2 4 !! 200\n--    (9829,9833)\n--    (0.44 secs, 249,622,048 bytes)\n--    \u03bb> primosEquidistantes3 4 !! 200\n--    (9829,9833)\n--    (0.36 secs, 207,549,592 bytes)\n--    \u03bb> primosEquidistantes4 4 !! 200\n--    (9829,9833)\n--    (0.02 secs, 4,012,848 bytes)\n--    \u03bb> primosEquidistantes5 4 !! 200\n--    (9829,9833)\n--    (0.01 secs, 7,085,072 bytes)\n--\n--    \u03bb> primosEquidistantes2 4 !! 600\n--    (41617,41621)\n--    (5.67 secs, 3,340,313,480 bytes)\n--    \u03bb> primosEquidistantes3 4 !! 600\n--    (41617,41621)\n--    (5.43 secs, 3,090,994,096 bytes)\n--    \u03bb> primosEquidistantes4 4 !! 600\n--    (41617,41621)\n--    (0.03 secs, 15,465,824 bytes)\n--    \u03bb> primosEquidistantes5 4 !! 600\n--    (41617,41621)\n--    (0.04 secs, 28,858,232 bytes)\n--\n--    \u03bb> primosEquidistantes4 4 !! (10^5)\n--    (18467047,18467051)\n--    (3.99 secs, 9,565,715,488 bytes)\n--    \u03bb> primosEquidistantes5 4 !! (10^5)\n--    (18467047,18467051)\n--    (7.95 secs, 18,712,469,144 bytes)\n<\/pre>\n<h4>4.2. Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom itertools import chain, count, islice, tee\nfrom timeit import Timer, default_timer\nfrom typing import Iterator\n\nfrom sympy import isprime\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# primo(x) se verifica si x es primo. Por ejemplo,\n#    primo(7)  ==  True\n#    primo(8)  ==  False\ndef primo(x: int) -> bool:\n    return [y for y in range(1,x+1) if x % y == 0] == [1,x]\n\n# primos() es la lista de los n\u00fameros primos. Por ejemplo,\n#    >>> list(islice(primos(), 10))\n#    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]\ndef primos() -> Iterator[int]:\n    return chain([2], (x for x in count(3, 2) if primo(x)))\n\ndef primosEquidistantes1(k: int) -> Iterator[tuple[int,int]]:\n    a, b = tee(primos())\n    next(b, None)\n    return ((x,y) for (x,y) in zip(a, b) if y - x == k)\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef primos2() -> Iterator[int]:\n    return (n for n in count() if isprime(n))\n\ndef primosEquidistantes2(k: int) -> Iterator[tuple[int,int]]:\n    a, b = tee(primos2())\n    next(b, None)\n    return ((x,y) for (x,y) in zip(a, b) if y - x == k)\n\n# Verificaci\u00f3n\n# ============\n\ndef test_primosEquidestantes() -> None:\n    for primosEquidistantes in [primosEquidistantes1,\n                                primosEquidistantes2]:\n        assert list(islice(primosEquidistantes(2), 3)) == \\\n            [(3, 5), (5, 7), (11, 13)]\n        assert list(islice(primosEquidistantes(4), 3)) == \\\n            [(7, 11), (13, 17), (19, 23)]\n        assert list(islice(primosEquidistantes(6), 3)) == \\\n            [(23, 29), (31, 37), (47, 53)]\n        assert list(islice(primosEquidistantes(8), 3)) == \\\n            [(89, 97), (359, 367), (389, 397)]\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_primosEquidestantes()\n#    Verificado\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\ndef primosEquidistantes_equiv(n: int, k: int) -> bool:\n    return list(islice(primosEquidistantes1(k), n)) == \\\n           list(islice(primosEquidistantes2(k), n))\n\n# La comprobaci\u00f3n es\n#    >>> primosEquidistantes_equiv(100, 4)\n#    True\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# La comparaci\u00f3n es\n#    >>> tiempo('list(islice(primosEquidistantes1(4), 300))')\n#    3.19 segundos\n#    >>> tiempo('list(islice(primosEquidistantes2(4), 300))')\n#    0.01 segundos\n<\/pre>\n<h3>5. Numeraci\u00f3n de las ternas de n\u00fameros naturales<\/h3>\n<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<h4>5.1. Soluciones en Haskell<\/h4>\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<h4>5.2. Soluciones en Python<\/h4>\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<h3>6. N\u00fameros triangulares con n cifras distintas<\/h3>\n<p>Los n\u00fameros triangulares se forman como sigue<\/p>\n<pre lang=\"haskell\">\n   *     *      *\n        * *    * *\n              * * *\n   1     3      6\n<\/pre>\n<p>La sucesi\u00f3n de los n\u00fameros triangulares se obtiene sumando los n\u00fameros naturales. As\u00ed, los 5 primeros n\u00fameros triangulares son<\/p>\n<pre lang=\"haskell\">\n    1 = 1\n    3 = 1 + 2\n    6 = 1 + 2 + 3\n   10 = 1 + 2 + 3 + 4\n   15 = 1 + 2 + 3 + 4 + 5\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   triangularesConCifras :: Int -> [Integer]\n<\/pre>\n<p>tal que <code>triangularesConCifras n<\/code> es la lista de los n\u00fameros triangulares con <code>n<\/code> cifras distintas. Por  ejemplo,<\/p>\n<pre lang=\"haskell\">\n   take 6 (triangularesConCifras 1)   ==  [1,3,6,55,66,666]\n   take 6 (triangularesConCifras 2)   ==  [10,15,21,28,36,45]\n   take 6 (triangularesConCifras 3)   ==  [105,120,136,153,190,210]\n   take 5 (triangularesConCifras 4)   ==  [1035,1275,1326,1378,1485]\n   take 2 (triangularesConCifras 10)  ==  [1062489753,1239845706]\n<\/pre>\n<h4>6.1. Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nimport Data.List (nub)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\ntriangularesConCifras1 :: Int -> [Integer]\ntriangularesConCifras1 n =\n  [x | x <- triangulares1,\n       nCifras x == n]\n\n-- triangulares1 es la lista de los n\u00fameros triangulares. Por ejemplo,\n--    take 10 triangulares1 == [1,3,6,10,15,21,28,36,45,55]\ntriangulares1 :: [Integer]\ntriangulares1 = map triangular [1..]\n\ntriangular :: Integer -> Integer\ntriangular 1 = 1\ntriangular n = triangular (n-1) + n\n\n-- (nCifras x) es el n\u00famero de cifras distintas del n\u00famero x. Por\n-- ejemplo,\n--    nCifras 325275  ==  4\nnCifras :: Integer -> Int\nnCifras = length . nub . show\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\ntriangularesConCifras2 :: Int -> [Integer]\ntriangularesConCifras2 n =\n  [x | x <- triangulares2,\n       nCifras x == n]\n\ntriangulares2 :: [Integer]\ntriangulares2 = [(n*(n+1)) `div` 2 | n <- [1..]]\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\ntriangularesConCifras3 :: Int -> [Integer]\ntriangularesConCifras3 n =\n  [x | x <- triangulares3,\n       nCifras x == n]\n\ntriangulares3 :: [Integer]\ntriangulares3 = 1 : [x+y | (x,y) <- zip [2..] triangulares3]\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\ntriangularesConCifras4 :: Int -> [Integer]\ntriangularesConCifras4 n =\n  [x | x <- triangulares4,\n       nCifras x == n]\n\ntriangulares4 :: [Integer]\ntriangulares4 = 1 : zipWith (+) [2..] triangulares4\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\ntriangularesConCifras5 :: Int -> [Integer]\ntriangularesConCifras5 n =\n  [x | x <- triangulares5,\n       nCifras x == n]\n\ntriangulares5 :: [Integer]\ntriangulares5 = scanl (+) 1 [2..]\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: (Int -> [Integer]) -> Spec\nspecG triangularesConCifras = do\n  it \"e1\" $\n    take 6 (triangularesConCifras 1) `shouldBe` [1,3,6,55,66,666]\n  it \"e2\" $\n    take 6 (triangularesConCifras 2) `shouldBe` [10,15,21,28,36,45]\n  it \"e3\" $\n    take 6 (triangularesConCifras 3) `shouldBe` [105,120,136,153,190,210]\n  it \"e4\" $\n    take 5 (triangularesConCifras 4) `shouldBe` [1035,1275,1326,1378,1485]\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG triangularesConCifras1\n  describe \"def. 2\" $ specG triangularesConCifras2\n  describe \"def. 3\" $ specG triangularesConCifras3\n  describe \"def. 4\" $ specG triangularesConCifras4\n  describe \"def. 5\" $ specG triangularesConCifras5\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    20 examples, 0 failures\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La 1\u00aa propiedad es\nprop_triangularesConCifras1 :: Bool\nprop_triangularesConCifras1 =\n  [take 2 (triangularesConCifras1 n) | n <- [1..7]] ==\n  [take 2 (triangularesConCifras2 n) | n <- [1..7]]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> prop_triangularesConCifras1\n--    True\n\n-- La 2\u00aa propiedad es\nprop_triangularesConCifras2 :: Int -> Bool\nprop_triangularesConCifras2 n =\n  all (== take 5 (triangularesConCifras2 n'))\n      [take 5 (triangularesConCifras3 n'),\n       take 5 (triangularesConCifras4 n'),\n       take 5 (triangularesConCifras5 n')]\n  where n' = 1 + n `mod` 9\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_triangularesConCifras\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> (triangularesConCifras1 3) !! 220\n--    5456556\n--    (2.48 secs, 1,228,690,120 bytes)\n--    \u03bb> (triangularesConCifras2 3) !! 220\n--    5456556\n--    (0.01 secs, 4,667,288 bytes)\n--\n--    \u03bb> (triangularesConCifras2 3) !! 600\n--    500010500055\n--    (1.76 secs, 1,659,299,872 bytes)\n--    \u03bb> (triangularesConCifras3 3) !! 600\n--    500010500055\n--    (1.67 secs, 1,603,298,648 bytes)\n--    \u03bb> (triangularesConCifras4 3) !! 600\n--    500010500055\n--    (1.20 secs, 1,507,298,248 bytes)\n--    \u03bb> (triangularesConCifras5 3) !! 600\n--    500010500055\n--    (1.15 secs, 1,507,298,256 bytes)\n<\/pre>\n<h4>6.2. Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom itertools import count, islice\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\nfrom typing import Iterator\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# triangular(n) es el n-\u00e9simo n\u00famero triangular. Por ejemplo,\n#    triangular(9) == 45\ndef triangular(n: int) -> int:\n    if n == 1:\n        return 1\n    return triangular(n-1) + n\n\n# triangulares1() es la lista de los n\u00fameros triangulares. Por ejemplo,\n#    >>> list(islice(triangulares1(), 10))\n#    [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]\ndef triangulares1() -> Iterator[int]:\n    return (triangular(n) for n in count(1))\n\n# nCifras(x) es el n\u00famero de cifras distintas del n\u00famero x. Por\n# ejemplo,\n#    nCifras(325275)  ==  4\ndef nCifras(x: int) -> int:\n    return len(set(str(x)))\n\ndef triangularesConCifras1(n: int) -> Iterator[int]:\n    return (x for x in triangulares1() if nCifras(x) == n)\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef triangulares2() -> Iterator[int]:\n    return ((n*(n+1)) \/\/ 2 for n in count(1))\n\ndef triangularesConCifras2(n: int) -> Iterator[int]:\n    return (x for x in triangulares2() if nCifras(x) == n)\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef triangulares3() -> Iterator[int]:\n    x = 0\n    for n in count(1):\n        x += n\n        yield x\n\ndef triangularesConCifras3(n: int) -> Iterator[int]:\n    return (x for x in triangulares3() if nCifras(x) == n)\n\n# Verificaci\u00f3n\n# ============\n\ndef test_triangularesConCifras() -> None:\n    for triangularesConCifras in [triangularesConCifras1,\n                                  triangularesConCifras2,\n                                  triangularesConCifras3]:\n        assert list(islice(triangularesConCifras(1), 6)) == \\\n            [1,3,6,55,66,666]\n        assert list(islice(triangularesConCifras(2), 6)) == \\\n            [10,15,21,28,36,45]\n        assert list(islice(triangularesConCifras(3), 6)) == \\\n            [105,120,136,153,190,210]\n        assert list(islice(triangularesConCifras(4), 5)) == \\\n            [1035,1275,1326,1378,1485]\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_triangularesConCifras()\n#    Verificado\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# La comparaci\u00f3n es\n#    >>> tiempo('list(islice(triangularesConCifras1(3), 300))')\n#    11.18 segundos\n#    >>> tiempo('list(islice(triangularesConCifras2(3), 300))')\n#    0.03 segundos\n#    >>> tiempo('list(islice(triangularesConCifras3(3), 300))')\n#    0.03 segundos\n#\n#    >>> tiempo('list(islice(triangularesConCifras2(3), 700))')\n#    2.19 segundos\n#    >>> tiempo('list(islice(triangularesConCifras3(3), 700))')\n#    2.01 segundos\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Durante el mes de abril he publicado en Exercitium las soluciones de los siguientes problemas: 1. Caminos en un tri\u00e1ngulo 2. M\u00e1xima suma de caminos en un tri\u00e1ngulo 3. N\u00fameros amigos 4. Primos equidistantes 5. Numeraci\u00f3n de las ternas de n\u00fameros naturales 6. N\u00fameros triangulares con n cifras distintas A continuaci\u00f3n se muestran las soluciones.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","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":[337],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/8182"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=8182"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/8182\/revisions"}],"predecessor-version":[{"id":8183,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/8182\/revisions\/8183"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=8182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=8182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=8182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}