I1M2015: Ejercicios sobre la numeración de los racionales en Haskell
En la clase de hoy de Informática de 1º del Grado en Matemáticas hemos comentado las soluciones a los ejercicios sobre la numeración de los números racionales en Haskell de la relación 22.
Los ejercicios y su solución se muestran a continuación
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
-- --------------------------------------------------------------------- -- Introducción -- -- --------------------------------------------------------------------- -- El objetivo de esta relación es construir dos enumeraciones de los -- números racionales. Concretamente, -- * una enumeración basada en las representaciones hiperbinarias y -- * una enumeración basada en los los árboles de Calkin-Wilf. -- También se incluye la comprobación de la igualdad de las dos -- sucesiones y una forma alternativa de calcular el número de -- representaciones hiperbinarias mediante la función fucs. -- -- Esta relación se basa en los siguientes artículos: -- * Gaussianos "Sorpresa sumando potencias de 2" http://goo.gl/AHdAG -- * N. Calkin y H.S. Wilf "Recounting the rationals" http://goo.gl/gVZtW -- * Wikipedia "Calkin-Wilf tree" http://goo.gl/cB3vn -- --------------------------------------------------------------------- -- Importación de librerías -- -- --------------------------------------------------------------------- import Data.List import Test.QuickCheck -- --------------------------------------------------------------------- -- Numeración de los racionales mediante representaciones hiperbinarias -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 1. Definir la constante -- potenciasDeDos :: [Integer] -- tal que potenciasDeDos es la lista de las potencias de 2. Por -- ejemplo, -- take 10 potenciasDeDos == [1,2,4,8,16,32,64,128,256,512] -- --------------------------------------------------------------------- potenciasDeDos :: [Integer] potenciasDeDos = [2^n | n <- [0..]] -- --------------------------------------------------------------------- -- Ejercicio 2. Definir la función -- empiezaConDos :: Eq a => a -> [a] -> Bool -- tal que (empiezaConDos x ys) se verifica si los dos primeros -- elementos de ys son iguales a x. Por ejemplo, -- empiezaConDos 5 [5,5,3,7] == True -- empiezaConDos 5 [5,3,5,7] == False -- empiezaConDos 5 [5,5,5,7] == True -- --------------------------------------------------------------------- empiezaConDos x (y1:y2:ys) = y1 == x && y2 == x empiezaConDos x (y1:y2:ys) = y1 == x && y2 == x empiezaConDos x _ = False -- --------------------------------------------------------------------- -- Ejercicio 3. Definir la función -- representacionesHB :: Integer -> [[Integer]] -- tal que (representacionesHB n) es la lista de las representaciones -- hiperbinarias del número n como suma de potencias de 2 donde cada -- sumando aparece como máximo 2 veces. Por ejemplo -- representacionesHB 5 == [[1,2,2],[1,4]] -- representacionesHB 6 == [[1,1,2,2],[1,1,4],[2,4]] -- --------------------------------------------------------------------- representacionesHB :: Integer -> [[Integer]] representacionesHB n = aux n potenciasDeDos aux n (x:xs) | n == 0 = [[]] | x == n = [[x]] | x < n = [x:ys | ys <- aux (n-x) (x:xs), not (empiezaConDos x ys)] ++ aux n xs | otherwise = [] -- --------------------------------------------------------------------- -- Ejercicio 4. Definir la función -- nRepresentacionesHB :: Integer -> Integer -- tal que (nRepresentacionesHB n) es el número de las representaciones -- hiperbinarias del número n como suma de potencias de 2 donde cada -- sumando aparece como máximo 2 veces. Por ejemplo, -- ghci> [nRepresentacionesHB n | n <- [0..20]] -- [1,1,2,1,3,2,3,1,4,3,5,2,5,3,4,1,5,4,7,3,8] -- --------------------------------------------------------------------- nRepresentacionesHB :: Integer -> Integer nRepresentacionesHB = genericLength . representacionesHB -- --------------------------------------------------------------------- -- Ejercicio 5. Definir la función -- termino :: Integer -> (Integer,Integer) -- tal que (termino n) es el par formado por el número de -- representaciones hiperbinarias de n y de n+1 (que se interpreta como -- su cociente). Por ejemplo, -- termino 4 == (3,2) -- --------------------------------------------------------------------- termino :: Integer -> (Integer,Integer) termino n = (nRepresentacionesHB n, nRepresentacionesHB (n+1)) -- --------------------------------------------------------------------- -- Ejercicio 6. Definir la función -- sucesionHB :: [(Integer,Integer)] -- sucesionHB es la la sucesión cuyo témino n-ésimo es (termino n); es -- decir, el par formado por el número de representaciones hiperbinarias -- de n y de n+1. Por ejemplo, -- ghci> take 10 sucesionHB -- [(1,1),(1,2),(2,1),(1,3),(3,2),(2,3),(3,1),(1,4),(4,3),(3,5)] -- --------------------------------------------------------------------- sucesionHB :: [(Integer,Integer)] sucesionHB = [termino n | n <- [0..]] -- --------------------------------------------------------------------- -- Ejercicio 7. Comprobar con QuickCheck que, para todo n, -- (nRepresentacionesHB n) y (nRepresentacionesHB (n+1)) son primos -- entre sí. -- --------------------------------------------------------------------- prop_irreducibles :: Integer -> Property prop_irreducibles n = n >= 0 ==> gcd (nRepresentacionesHB n) (nRepresentacionesHB (n+1)) == 1 -- La comprobación es -- ghci> quickCheck prop_irreducibles -- +++ OK, passed 100 tests. -- --------------------------------------------------------------------- -- Ejercicio 8. Comprobar con QuickCheck que todos los elementos de la -- sucesionHB son distintos. -- --------------------------------------------------------------------- prop_distintos :: Integer -> Integer -> Bool prop_distintos n m = termino n1 /= termino m1 where n1 = abs n m1 = n1 + abs m + 1 -- La comprobación es -- ghci> quickCheck prop_distintos -- +++ OK, passed 100 tests. -- --------------------------------------------------------------------- -- Ejercicio 9. Definir la función -- contenido :: Integer -> Integer -> Bool -- tal que (contenido n) se verifica si la expresiones reducidas de -- todas las fracciones x/y, con x e y entre 1 y n, pertenecen a la -- sucesionHB. Por ejemplo, -- contenidos 5 == True -- --------------------------------------------------------------------- contenido :: Integer -> Bool contenido n = and [pertenece (reducida (x,y)) sucesionHB | x <- [1..n], y <- [1..n]] where pertenece x (y:ys) = x == y || pertenece x ys reducida (x,y) = (x `div` z, y `div` z) where z = gcd x y -- --------------------------------------------------------------------- -- Ejercicio 10. Definir la función -- indice :: (Integer,Integer) -> Integer -- tal que (indice (a,b)) es el índice del par (a,b) en la sucesión de -- los racionales. Por ejemplo, -- indice (3,2) == 4 -- --------------------------------------------------------------------- indice :: (Integer,Integer) -> Integer indice (a,b) = head [n | (n,(x,y)) <- zip [0..] sucesionHB, (x,y) == (a,b)] -- --------------------------------------------------------------------- -- Numeraciones mediante árboles de Calkin-Wilf -- -- --------------------------------------------------------------------- -- El árbol de Calkin-Wilf es el árbol definido por las siguientes -- reglas: -- * El nodo raíz es el (1,1) -- * Los hijos del nodo (x,y) son (x,x+y) y (x+y,y) -- Por ejemplo, los 4 primeros niveles del árbol de Calkin-Wilf son -- (1,1) -- | -- +-----------+-----------+ -- | | -- (1,2) (2,1) -- | | -- +-----+-----+ +-----+-----+ -- | | | | -- (1,3) (3,2) (2,3) (3,1) -- | | | | -- +--+--+ +--+--+ +--+--+ +--+--+ -- | | | | | | | | -- (1,4) (4,3) (3,5) (5,2) (2,5) (5,3) (3,4) (4,1) -- --------------------------------------------------------------------- -- Ejercicio 11. Definir la función -- sucesores :: (Integer,Integer) -> [(Integer,Integer)] -- tal que (sucesores (x,y)) es la lista de los hijos del par (x,y) en -- el árbol de Calkin-Wilf. Por ejemplo, -- sucesores (3,2) == [(3,5),(5,2)] -- --------------------------------------------------------------------- sucesores :: (Integer,Integer) -> [(Integer,Integer)] sucesores (x,y) = [(x,x+y),(x+y,y)] -- --------------------------------------------------------------------- -- Ejercicio 12. Definir la función -- siguiente :: [(Integer,Integer)] -> [(Integer,Integer)] -- tal que (siguiente xs) es la lista formada por los hijos de los -- elementos de xs en el árbol de Calkin-Wilf. Por ejemplo, -- ghci> siguiente [(1,3),(3,2),(2,3),(3,1)] -- [(1,4),(4,3),(3,5),(5,2),(2,5),(5,3),(3,4),(4,1)] -- --------------------------------------------------------------------- siguiente :: [(Integer,Integer)] -> [(Integer,Integer)] siguiente xs = [p | x <- xs, p <- sucesores x] -- --------------------------------------------------------------------- -- Ejercicio 13. Definir la constante -- nivelesCalkinWilf:: [[(Integer,Integer)]] -- tal que nivelesCalkinWilf es la lista de los niveles del árbol de -- Calkin-Wilf. Por ejemplo, -- ghci> take 4 nivelesCalkinWilf -- [[(1,1)], -- [(1,2),(2,1)], -- [(1,3),(3,2),(2,3),(3,1)], -- [(1,4),(4,3),(3,5),(5,2),(2,5),(5,3),(3,4),(4,1)]] -- --------------------------------------------------------------------- nivelesCalkinWilf:: [[(Integer,Integer)]] nivelesCalkinWilf = iterate siguiente [(1,1)] -- --------------------------------------------------------------------- -- Ejercicio 14. Definir la constante -- sucesionCalkinWilf :: [(Integer,Integer)] -- tal que sucesionCalkinWilf es la lista correspondiente al recorrido -- en anchura del árbol de Calkin-Wilf. Por ejemplo, -- ghci> take 10 sucesionCalkinWilf -- [(1,1),(1,2),(2,1),(1,3),(3,2),(2,3),(3,1),(1,4),(4,3),(3,5)] -- --------------------------------------------------------------------- sucesionCalkinWilf :: [(Integer,Integer)] sucesionCalkinWilf = concat nivelesCalkinWilf -- --------------------------------------------------------------------- -- Ejercicio 15. Definir la función -- igual_sucesion_HB_CalkinWilf :: Int -> Bool -- tal que (igual_sucesion_HB_CalkinWilf n) se verifica si los n -- primeros términos de la sucesión HB son iguales que los de la -- sucesión de Calkin-Wilf. Por ejemplo, -- igual_sucesion_HB_CalkinWilf 20 == True -- --------------------------------------------------------------------- igual_sucesion_HB_CalkinWilf :: Int -> Bool igual_sucesion_HB_CalkinWilf n = take n sucesionCalkinWilf == take n sucesionHB -- --------------------------------------------------------------------- -- Número de representaciones hiperbinarias mediante la función fusc -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 16. Definir la función -- fusc :: Integer -> Integer -- tal que -- fusc(0) = 1 -- fusc(2n+1) = fusc(n) -- fusc(2n+2) = fusc(n+1)+fusc(n) -- Por ejemplo, -- fusc 4 == 3 -- --------------------------------------------------------------------- fusc :: Integer -> Integer fusc 0 = 1 fusc n | odd n = fusc ((n-1) `div` 2) | otherwise = fusc(m+1) + fusc m where m = (n-2) `div` 2 -- --------------------------------------------------------------------- -- Ejercicio 17. Comprobar con QuickCheck que, para todo n, (fusc n) es -- el número de las representaciones hiperbinarias del número n como -- suma de potencias de 2 donde cada sumando aparece como máximo 2 -- veces; es decir, que las funciones fusc y nRepresentacionesHB son -- equivalentes. -- --------------------------------------------------------------------- prop_fusc :: Integer -> Bool prop_fusc n = nRepresentacionesHB n1 == fusc n1 where n1 = abs n -- La comprobación es -- ghci> quickCheck prop_fusc -- +++ OK, passed 100 tests. |
El código anterior se encuentra también en GitHub.