-- I1M 2009-10: Relación 20 (26 de marzo de 2010)
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

-- ---------------------------------------------------------------------
-- Importación de librerías                                           --
-- ---------------------------------------------------------------------

import Test.QuickCheck

-- ---------------------------------------------------------------------
-- Diferenciación numérica                                            --
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 2.1. Definir la función
--    derivada :: Float -> (Float -> Float) -> Float -> Float
-- tal que (derivada a f x) es el valor de la derivada de la función f
-- en el punto x con aproximación a. Por ejemplo, 
--    derivada 0.001 sin pi  ==>  -0.9999273
--    derivada 0.001 cos pi  ==>  0.0004768371  
-- ---------------------------------------------------------------------

derivada :: Float -> (Float -> Float) -> Float -> Float
derivada a f x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 2.2. Definir las funciones
--    derivadaBurda :: (Float -> Float) -> Float -> Float
--    derivadaFina  :: (Float -> Float) -> Float -> Float
--    derivadaSuper :: (Float -> Float) -> Float -> Float
-- tales que 
--    * (derivadaBurda f x) es el valor de la derivada de la función f 
--      en el punto x con aproximación 0.01,
--    * (derivadaFina f x) es el valor de la derivada de la función f 
--      en el punto x con aproximación 0.0001.
--    * (derivadauperBurda f x) es el valor de la derivada de la función f 
--      en el punto x con aproximación 0.000001.
-- Por ejemplo,
--    derivadaFina cos pi  ==>  0.0
-- ---------------------------------------------------------------------

derivadaBurda :: (Float -> Float) -> Float -> Float
derivadaBurda = undefined

derivadaFina :: (Float -> Float) -> Float -> Float
derivadaFina  = undefined

derivadaSuper :: (Float -> Float) -> Float -> Float
derivadaSuper = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 2.3. Definir la función
--    derivadaFinaDelSeno :: Float -> Float
-- tal que (derivadaFinaDelSeno x) es el valor de la derivada fina del
-- seno en x. Por ejemplo,
--    derivadaFinaDelSeno pi  ==>  -0.9989738  
-- ---------------------------------------------------------------------

derivadaFinaDelSeno :: Float -> Float
derivadaFinaDelSeno = undefined

-- ---------------------------------------------------------------------
-- Cálculo de la raíz cuadrada                                        --
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 3. En los siguientes apartados de este ejercicio se va a
-- calcular la raíz cuadrada de un número basándose en las siguientes
-- propiedades:
-- * Si y es una aproximación de la raíz cuadradad de x, entonces 
--   (y+x/y) es una aproximación mejor. 
--       x_0     = 1 
--       x_{n+1} = (x_n+x/x_n)
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 3.2. Definir, por iteración con until, la función
--    raiz :: (Fractional a, Ord a) => a -> a
-- tal que (raiz x) es la raíz cuadrada de x calculada usando la
-- propiedad anterior con una aproximación de 0.00001 y tomando como
-- v. Por ejemplo, 
--    raiz 9  ==  3.000000001396984
-- ---------------------------------------------------------------------

raiz :: (Fractional a, Ord a) => a -> a
raiz x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.2. Definir el operador 
--    (~=) :: Float -> Float -> Bool
-- tal que (x ~= y) si |x-y| < 0.001. Por ejemplo,
--    3.05 ~= 3.07        ==  False
--    3.00005 ~= 3.00007  == True
-- ---------------------------------------------------------------------

infix 5 ~=
(~=) :: Float -> Float -> Bool
x ~= y = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.3. Comprobar con QuickCheck que si x es positivo,
-- entonces 
--    (raiz x)^2 ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_raiz :: Float -> Property
prop_raiz x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 3.4. Definir por recursión la función
--    until' :: (a -> Bool) -> (a -> a) -> a -> a
-- tal que (until' p f x) es el resultado de aplicar la función f a x el
-- menor número posible de veces, hasta alcanzar un valor que satisface
-- el predicado p. Por ejemplo, 
--    until' (>1000) (2*) 1  ==>  1024
-- Nota: until' es equivalente a la predefinida until.
-- ---------------------------------------------------------------------

until' :: (a -> Bool) -> (a -> a) -> a -> a
until' p f x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.5. Definir, por iteración con until, la función
--    raizI :: (Fractional a, Ord a) => a -> a
-- tal que (raizI x) es la raíz cuadrada de x calculada usando la
-- propiedad anterior. Por ejemplo, 
--    raizI 9  ==  3.000000001396984
-- ---------------------------------------------------------------------

raizI :: (Fractional a, Ord a) => a -> a
raizI x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.6. Comprobar con QuickCheck que si x es positivo,
-- entonces 
--    (raizI x)^2 ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_raizI :: Float -> Property
prop_raizI x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ceros de una función                                               --
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 4. Los ceros de una función pueden calcularse mediante el
-- método de Newton basándose en las siguientes propiedades:
-- * Si b es una aproximación para el punto cero de f, entonces 
--   b-f(b)/f'(b) es una mejor aproximación.
-- * el límite de la sucesión x_n definida por
--      x_0     = 1 
--      x_{n+1} = x_n-f(x_n)/f'(x_n)
--   es un cero de f.
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 4.1. Definir por recursión la función
--    puntoCero :: (Float -> Float) -> Float
-- tal que (puntoCero f) es un cero de la función f calculado usando la
-- propiedad anterior. Por ejemplo, 
--    puntoCero cos  ==>  1.570796  
-- ---------------------------------------------------------------------

puntoCero :: (Float -> Float) -> Float
puntoCero f = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 4.2. Definir, por iteración con until, la función
--    puntoCeroI :: (Float -> Float) -> Float
-- tal que (puntoCeroI f) es un cero de la función f calculado usando la
-- propiedad anterior. Por ejemplo, 
--    puntoCeroI cos  ==>  1.570796  
-- ---------------------------------------------------------------------

puntoCeroI :: (Float -> Float) -> Float
puntoCeroI f = undefined

-- ---------------------------------------------------------------------
-- Funciones inversas                                                 --
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 5. En este ejercicio se usará la función puntoCero para
-- definir la inversa de distintas funciones.
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 5.1. Definir, usando puntoCero, la función
--    raizCuadrada :: Float -> Float
-- tal que (raizCuadrada x) es la raíz cuadrada de x. Por ejemplo,
--    raizCuadrada 9  ==>  3.0
-- ---------------------------------------------------------------------

raizCuadrada :: Float -> Float
raizCuadrada a = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5.2. Comprobar con QuickCheck que si x es positivo,
-- entonces 
--    (raizCuadrada x)^2 ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_raizCuadrada :: Float -> Property
prop_raizCuadrada x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5.3. Definir, usando puntoCero, la función
--    raizCubica :: Float -> Float
-- tal que (raizCubica x) es la raíz cuadrada de x. Por ejemplo,
--    raizCubica 27  ==>  3.0
-- ---------------------------------------------------------------------

raizCubica :: Float -> Float
raizCubica a = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5.4. Comprobar con QuickCheck que si x es positivo,
-- entonces 
--    (raizCubica x)^3 ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_raizCubica :: Float -> Property
prop_raizCubica x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5.5. Definir, usando puntoCero, la función
--    arcoseno :: Float -> Float
-- tal que (arcoseno x) es el arcoseno de x. Por ejemplo,
--    arcoseno 1  ==  1.566332
-- ---------------------------------------------------------------------

arcoseno :: Float -> Float
arcoseno a = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5.6. Comprobar con QuickCheck que si x está entre 0 y 1,
-- entonces 
--    sin (arcoseno x) ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_arcoseno :: Float -> Property
prop_arcoseno x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5.7. Definir, usando puntoCero, la función
--    arcocoseno :: Float -> Float
-- tal que (arcoseno x) es el arcoseno de x. Por ejemplo,
--    arcocoseno 0  == 1.5707963
-- ---------------------------------------------------------------------

arcocoseno :: Float -> Float
arcocoseno a = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5.8. Comprobar con QuickCheck que si x está entre 0 y 1,
-- entonces 
--    cos (arcocoseno x) ~= x
-- ---------------------------------------------------------------------

-- La propiedad es
prop_arcocoseno :: Float -> Property
prop_arcocoseno x = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5.7. Definir, usando puntoCero, la función
--    inversa :: (Float -> Float) -> Float -> Float
-- tal que (inversa g x) es el valor de la inversa de g en x. Por
-- ejemplo, 
--    inversa (^2) 9  ==  3.0
-- ---------------------------------------------------------------------

inversa :: (Float -> Float) -> Float -> Float
inversa g a = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5.8. Redefinir, usando inversa, las funciones raizCuadrada,
-- raizCubica, arcoseno y arcocoseno.
-- ---------------------------------------------------------------------

raizCuadrada' = undefined
raizCubica'   = undefined
arcoseno'     = undefined  
arcocoseno'   = undefined
