fbpx
Wikipedia

QuickCheck

QuickCheck es una herramienta que el lenguaje de programación Haskell provee para poder probar las propiedades que deberían de cumplir las funciones, es decir, cada función tiene propiedades deseables lo que se logra con QuickCheck es ver si se cumplen total o parcialmente estas propiedades. Una ventaja notoria es que la propiedad es probada con una gran cantidad de casos generados aleatoriamente. Por ejemplo si tenemos una función suma:

suma x y = x + y 

para ver si cumple la propiedad conmutativa de la suma de números enteros, para cualquier entero:

prop_suma_conmutativa :: Int ->Int -> Bool prop_suma_conmutativa x y = suma x y == suma y x 

la función prop_suma_conmutativa al ser pasada como parámetro en quickCheck será verificada con varios casos aleatorios de enteros e indicará si eventualmente la función suma cumple o no la propiedad de la suma de números enteros.

Detalles Teóricos importantes

  • QuickCheck toma como parámetro de entrada una propiedad
  • Las propiedades son un conjunto de afirmaciones parametrizadas que en Haskell son funciones normales que pueden ser entendidas por cualquier compilador o intérprete
  • Estas propiedades son verificadas con un número grande de casos de prueba generados de forma aleatoria
  • Los programadores controlan la distribución de los casos de prueba generados con reglas condicionales y generadores
  • Permite programar generadores propios
  • Las funciones que deseamos probar pueden ser polimórficas pero las propiedades a probar deben ser monomórficas. El siguiente ejemplo muestra un error, por esto:
import Test.QuickCheck insertOrdered :: (Ord a) => a -> [a] -> [a] insertOrdered a [] = [a] insertOrdered a (x:xs)| a <= x = a:[x] ++ xs   | a > x = x: insertOrdered a xs prop_insertOrdered a (xs) = ordered(insertOrdered a xs) -- main = quickCheck prop_insertOrdered >:l Main Main> quickCheck prop_insertOrdered ERROR - Unresolved overloading 

Notar en este ejemplo:

  • El nombre de la función para probar la propiedad, comienza con el prefijo prop_ (Ej. prop insertOrdered)esto es por convención.
  • Se usó una función auxiliar ordered para probar la propiedad
  • Podemos llamar la función quickCheck tanto en la línea de comandos como dentro de nuestro programa.
  • Otro punto interesante a notar es que inclusive luego de añadir el tipo a la función, devuelve el siguiente mensaje “Falsifiable, after 3 tests”

Combinadores provistos por QuickCheck

Combinador condicional: Podemos mejorar un poco el ejemplo anterior añadiendo una condición, a nuestra propiedad.

prop_InsertOrdered :: Integer -> [Integer] -> Property prop_InsertOrdered x xs = ordered xs ==> ordered (insertOrdered x xs []) 

La estructura para utilizar el combinador condicional:

   <condition> ==> <property> 
  • La introducción del combinador condicional ==> nos indica que solo se intentara probar la propiedad con casos que satisfagan la condición, si un candidato no satisface la condición es descartado y se probara con otro.
  • Ahora el tipo devuelto de la función es Property
  • Algunas veces la propiedad que es probada con condiciones, saca este mensaje Arguments exhausted after 55 tests. Esto suele suceder si la condición no es satisfecha y se han producido muchos casos que no satisfacen la propiedad, nos indica que por lo menos 55 casos pasaron la prueba, el programador decide aquí si esto es suficiente o no.

Combinador classify: El combinador classify no cambia el significado de la propiedad pero permite clasificar algunos casos, se podría decir que es una forma de etiquetarlos. En el ejemplo anterior veamos la cantidad de listas producidas aleatoriamente de tamaño menor a uno y listas mayores de dos elementos.

prop_InsertOrdered :: Int -> [Int] -> Property prop_InsertOrdered x xs = ordered xs ==>   classify (length xs <= 1) "lista de tam < 1" $   classify (length xs > 2) "lista de tam > 2" $   ordered (insertOrdered x xs) *Main> main OK, passed 100 tests. 79% lista de tam < 1. 4 % lista de tam > 2. *Main> 

La estructura para utilizar el combinador classify:

   classify <condition><string>$ <property> 

Como vemos solo un 4% de las listas generadas aleatoriamente son de tamaño mayor a dos.

Combinador collect: El combinador collect cosecha todos los valores que son pasados e imprime un histograma de esos, aquí podemos darnos cuenta que solo un porcentaje menor de casos de prueba son probados porque (en el caso específico) las listas de 1 o 0 elementos son ordenados pero los mayores a 2 elementos no lo son, este es un riesgo al utilizar leyes condicionales.

prop_InsertOrdered :: Int -> [Int] -> Property prop_InsertOrdered x xs = ordered xs ==>    collect (length xs >1)$    collect (length xs)$    ordered (insertOrdered x xs) *Main> main OK, passed 100 tests. 49% False, 0. 34% False, 1. 13% True, 2. 3% True, 3. 1% True, 4. 

La estructura para utilizar el combinador collect:

   collect <expression> $ <property> 
  • Es importante investigar la proporción de los casos probados
  • Lo que nos indica la salida es que: 49% de los casos no cumplen la expresión (length xs > 1) porque su tama˜no es 0,34% de los casos no cumplen la expresión (length xs > 1) porque su tama˜no es 1, etc.
  • Una solución es que le pasemos un generador de listas ordenadas quickcheck nos facilita esto, al permitirnos crear generadores propios.

Combinador forAll: El combinador forAll nos indica que para toda lista ordenada se podrá probar la propiedad.

prop_InsertOrdered :: Integer -> Property prop_InsertOrdered x = forAll orderedList $ \ xs ->    collect (length xs>2)$    collect (length xs)$    ordered (insertOrdered x xs) -- el generador de listas ordenadas, -- solo es una funcion que crea listas ordenadas orderedList :: (Ord a, Arbitrary a) => Gen [a] orderedList = frequency [(1,return []), (4,do xs <- orderedList  n <- arbitrary  return ((case xs of   [] -> n   x:_ -> n ‘min‘ x)   :xs))] Main> main OK, passed 100 tests. 18% False, 1. 16% False, 0. 15% False, 2. 10% True, 8. 10% True, 3. 8% True, 4. 5% True, 5. 4% True, 9. 4% True, 13. 3% True, 6. 2% True, 7. 2% True, 11. 2% True, 10. 1% True, 16. 

La estructura para utilizar el combinador forAll:

   forAll <generator>$\<pattern> -> <property> 
  • La salida nos indica que el 18% de las listas generadas aleatoriamente, por nuestro generador no es mayor a dos, su tamaño es uno, que el 1% de los casos generados por la funci´on orderedList(que genera listas ordenadas) si es mayor a dos y su tama˜no es 16.
  • Notar que utilizamos el combinador frequency

Solo observando: Veamos la distribución de los casos de prueba...

prop_InsertOrdered :: Integer -> [Integer] -> Property prop_InsertOrdered x xs = ordered xs ==>   (length xs <= 1) ‘trivial‘   ordered (insertOrdered x xs) *Main> main OK, passed 100 tests (86% trivial). 

La estructura para ver la distribución es:

   <condition> ‘trivial‘ <property> 

Indicamos que las listas generadas por la funci´on orderedList son triviales en aquellos casos que su tamaño sea menor o igual a uno La respuesta nos dice que el 86% de los casos son triviales.

Definiendo Generadores Propios Para definir generadores propios para nuestros tipos de datos utilizamos la Clase Arbitrary.

data Insectos = Polillas  | Mariposas  | OtrosBichos instance Arbitrary Insectos where arbitrary = oneof [ return Mariposas,   return Polillas ,  return OtrosBichos] 

oneof: Podemos utilizar el combinador oneof escoge de una lista de generadores alternativos con una distribución uniforme, los constructores. frequency: Veamos la siguiente estructura, un árbol binario con dos funciones tam que nos devuelve el tamaño del árbol y arbolALista que nos devuelve los elementos de un árbol en una lista.

module ArbolBin where import Test.QuickCheck import Control.Monad -- necesitamos para la funciones  -- liftM, liftM2 data ArbolBin a = Hoja a  | Rama (ArbolBin a ) (ArbolBin a )  deriving Show tam :: ArbolBin Int -> Int tam (Hoja a) = 1 tam (Rama i d) = tam i + tam d arbolALista :: ArbolBin Int -> [Int] arbolALista (Hoja x) = [x] arbolALista (Rama i d )= arbolALista i ++ arbolALista d 

Una propiedad que nos gustaría que cumpla la función arbolALista es que el tamaño de la lista sea igual al tamaño del árbol.

 prop_arbolALista:: ArbolBin Int -> Bool prop_arbolALista t = length (arbolALista t )== tam t instance Arbitrary a => Arbitrary (ArbolBin a) where arbitrary = frequency [ (1,liftM Hoja arbitrary ),   (2,liftM2 Rama arbitrary arbitrary )] main = quickCheck prop_arbolALista 

El combinador frequency, que vimos anteriormente es del tipo:

   frequency :: [(Int, Gen a)] -> Gen a 

Su tipo nos dice que recibe una lista de generadores. Como primer parámetro la frecuencia con la que se escogerá cada generador y como segundo el generador en si. En el ejemplo del árbol binario se escogerá dos veces el generador para Rama y solo uno (de cada dos) para el generador de Hoja. En el ejemplo para la inserción para el combinador forAll nos dice que escogerá cuatro veces una lista diferente de vacío([])y una vez una lista vacía ([]).

Algo importante que hay que recalcar es que para utilizar de manera adecuada QuickCheck debemos saber que propiedades necesitamos que cumplan nuestras funciones.

 import Test.QuickCheck Definir Propiedades Opcionalmente definir generadores Main > quickCheck pro_definida 
  •   Datos: Q2886113

quickcheck, herramienta, lenguaje, programación, haskell, provee, para, poder, probar, propiedades, deberían, cumplir, funciones, decir, cada, función, tiene, propiedades, deseables, logra, cumplen, total, parcialmente, estas, propiedades, ventaja, notoria, pr. QuickCheck es una herramienta que el lenguaje de programacion Haskell provee para poder probar las propiedades que deberian de cumplir las funciones es decir cada funcion tiene propiedades deseables lo que se logra con QuickCheck es ver si se cumplen total o parcialmente estas propiedades Una ventaja notoria es que la propiedad es probada con una gran cantidad de casos generados aleatoriamente Por ejemplo si tenemos una funcion suma suma x y x y para ver si cumple la propiedad conmutativa de la suma de numeros enteros para cualquier entero prop suma conmutativa Int gt Int gt Bool prop suma conmutativa x y suma x y suma y x la funcion prop suma conmutativa al ser pasada como parametro en quickCheck sera verificada con varios casos aleatorios de enteros e indicara si eventualmente la funcion suma cumple o no la propiedad de la suma de numeros enteros Detalles Teoricos importantes QuickCheck toma como parametro de entrada una propiedad Las propiedades son un conjunto de afirmaciones parametrizadas que en Haskell son funciones normales que pueden ser entendidas por cualquier compilador o interprete Estas propiedades son verificadas con un numero grande de casos de prueba generados de forma aleatoria Los programadores controlan la distribucion de los casos de prueba generados con reglas condicionales y generadores Permite programar generadores propios Las funciones que deseamos probar pueden ser polimorficas pero las propiedades a probar deben ser monomorficas El siguiente ejemplo muestra un error por esto import Test QuickCheck insertOrdered Ord a gt a gt a gt a insertOrdered a a insertOrdered a x xs a lt x a x xs a gt x x insertOrdered a xs prop insertOrdered a xs ordered insertOrdered a xs main quickCheck prop insertOrdered gt l Main Main gt quickCheck prop insertOrdered ERROR Unresolved overloading Notar en este ejemplo El nombre de la funcion para probar la propiedad comienza con el prefijo prop Ej prop insertOrdered esto es por convencion Se uso una funcion auxiliar ordered para probar la propiedad Podemos llamar la funcion quickCheck tanto en la linea de comandos como dentro de nuestro programa Otro punto interesante a notar es que inclusive luego de anadir el tipo a la funcion devuelve el siguiente mensaje Falsifiable after 3 tests Combinadores provistos por QuickCheck EditarCombinador condicional Podemos mejorar un poco el ejemplo anterior anadiendo una condicion a nuestra propiedad prop InsertOrdered Integer gt Integer gt Property prop InsertOrdered x xs ordered xs gt ordered insertOrdered x xs La estructura para utilizar el combinador condicional lt condition gt gt lt property gt La introduccion del combinador condicional gt nos indica que solo se intentara probar la propiedad con casos que satisfagan la condicion si un candidato no satisface la condicion es descartado y se probara con otro Ahora el tipo devuelto de la funcion es Property Algunas veces la propiedad que es probada con condiciones saca este mensaje Arguments exhausted after 55 tests Esto suele suceder si la condicion no es satisfecha y se han producido muchos casos que no satisfacen la propiedad nos indica que por lo menos 55 casos pasaron la prueba el programador decide aqui si esto es suficiente o no Combinador classify El combinador classify no cambia el significado de la propiedad pero permite clasificar algunos casos se podria decir que es una forma de etiquetarlos En el ejemplo anterior veamos la cantidad de listas producidas aleatoriamente de tamano menor a uno y listas mayores de dos elementos prop InsertOrdered Int gt Int gt Property prop InsertOrdered x xs ordered xs gt classify length xs lt 1 lista de tam lt 1 classify length xs gt 2 lista de tam gt 2 ordered insertOrdered x xs Main gt main OK passed 100 tests 79 lista de tam lt 1 4 lista de tam gt 2 Main gt La estructura para utilizar el combinador classify classify lt condition gt lt string gt lt property gt Como vemos solo un 4 de las listas generadas aleatoriamente son de tamano mayor a dos Combinador collect El combinador collect cosecha todos los valores que son pasados e imprime un histograma de esos aqui podemos darnos cuenta que solo un porcentaje menor de casos de prueba son probados porque en el caso especifico las listas de 1 o 0 elementos son ordenados pero los mayores a 2 elementos no lo son este es un riesgo al utilizar leyes condicionales prop InsertOrdered Int gt Int gt Property prop InsertOrdered x xs ordered xs gt collect length xs gt 1 collect length xs ordered insertOrdered x xs Main gt main OK passed 100 tests 49 False 0 34 False 1 13 True 2 3 True 3 1 True 4 La estructura para utilizar el combinador collect collect lt expression gt lt property gt Es importante investigar la proporcion de los casos probados Lo que nos indica la salida es que 49 de los casos no cumplen la expresion length xs gt 1 porque su tama no es 0 34 de los casos no cumplen la expresion length xs gt 1 porque su tama no es 1 etc Una solucion es que le pasemos un generador de listas ordenadas quickcheck nos facilita esto al permitirnos crear generadores propios Combinador forAll El combinador forAll nos indica que para toda lista ordenada se podra probar la propiedad prop InsertOrdered Integer gt Property prop InsertOrdered x forAll orderedList xs gt collect length xs gt 2 collect length xs ordered insertOrdered x xs el generador de listas ordenadas solo es una funcion que crea listas ordenadas orderedList Ord a Arbitrary a gt Gen a orderedList frequency 1 return 4 do xs lt orderedList n lt arbitrary return case xs of gt n x gt n min x xs Main gt main OK passed 100 tests 18 False 1 16 False 0 15 False 2 10 True 8 10 True 3 8 True 4 5 True 5 4 True 9 4 True 13 3 True 6 2 True 7 2 True 11 2 True 10 1 True 16 La estructura para utilizar el combinador forAll forAll lt generator gt lt pattern gt gt lt property gt La salida nos indica que el 18 de las listas generadas aleatoriamente por nuestro generador no es mayor a dos su tamano es uno que el 1 de los casos generados por la funci on orderedList que genera listas ordenadas si es mayor a dos y su tama no es 16 Notar que utilizamos el combinador frequencySolo observando Veamos la distribucion de los casos de prueba prop InsertOrdered Integer gt Integer gt Property prop InsertOrdered x xs ordered xs gt length xs lt 1 trivial ordered insertOrdered x xs Main gt main OK passed 100 tests 86 trivial La estructura para ver la distribucion es lt condition gt trivial lt property gt Indicamos que las listas generadas por la funci on orderedList son triviales en aquellos casos que su tamano sea menor o igual a uno La respuesta nos dice que el 86 de los casos son triviales Definiendo Generadores Propios Para definir generadores propios para nuestros tipos de datos utilizamos la Clase Arbitrary data Insectos Polillas Mariposas OtrosBichos instance Arbitrary Insectos where arbitrary oneof return Mariposas return Polillas return OtrosBichos oneof Podemos utilizar el combinador oneof escoge de una lista de generadores alternativos con una distribucion uniforme los constructores frequency Veamos la siguiente estructura un arbol binario con dos funciones tam que nos devuelve el tamano del arbol y arbolALista que nos devuelve los elementos de un arbol en una lista module ArbolBin where import Test QuickCheck import Control Monad necesitamos para la funciones liftM liftM2 data ArbolBin a Hoja a Rama ArbolBin a ArbolBin a deriving Show tam ArbolBin Int gt Int tam Hoja a 1 tam Rama i d tam i tam d arbolALista ArbolBin Int gt Int arbolALista Hoja x x arbolALista Rama i d arbolALista i arbolALista d Una propiedad que nos gustaria que cumpla la funcion arbolALista es que el tamano de la lista sea igual al tamano del arbol prop arbolALista ArbolBin Int gt Bool prop arbolALista t length arbolALista t tam t instance Arbitrary a gt Arbitrary ArbolBin a where arbitrary frequency 1 liftM Hoja arbitrary 2 liftM2 Rama arbitrary arbitrary main quickCheck prop arbolALista El combinador frequency que vimos anteriormente es del tipo frequency Int Gen a gt Gen a Su tipo nos dice que recibe una lista de generadores Como primer parametro la frecuencia con la que se escogera cada generador y como segundo el generador en si En el ejemplo del arbol binario se escogera dos veces el generador para Rama y solo uno de cada dos para el generador de Hoja En el ejemplo para la insercion para el combinador forAll nos dice que escogera cuatro veces una lista diferente de vacio y una vez una lista vacia Algo importante que hay que recalcar es que para utilizar de manera adecuada QuickCheck debemos saber que propiedades necesitamos que cumplan nuestras funciones import Test QuickCheck Definir Propiedades Opcionalmente definir generadores Main gt quickCheck pro definida Datos Q2886113Obtenido de https es wikipedia org w index php title QuickCheck amp oldid 117914248, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos