Számok és számosztályok

A Num osztály

-- class (Eq a, Show a) => Num a where
--    (+), (-), (*)    :: a -> a -> a
--    negate           :: a -> a
--    abs, signum      :: a -> a
--    fromInteger      :: Integer -> a
--    -- alapértelmezett metódusok
--    x - y            =  x + negate y
--    negate x         =  0 - x

Peano számok

Példányosítsuk a Num osztályt a Peano számokra.
Definiáljuk csak a (+), (*), fromInteger metódusokat.

data Nat          -- egy természetes szám
   = Zero         -- vagy nulla,
   | Succ Nat     -- vagy egy természetes szám rákövetkezője
        deriving (Eq, Show, Data, Typeable)
instance Num Nat where

    Zero   + m = m
    Succ n + m = Succ (n + m)

    Zero   * m = Zero
    Succ n * m = m + n * m

    fromInteger 0 = Zero
    fromInteger n = Succ $ fromInteger $ n-1

    abs = undefined
    signum = undefined
    negate = undefined
 -- mintaillesztés, rekurzió, Peano-axiómák
Test>
Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))) :: Nat
Test>
Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))))))))))))))) :: Nat

Hatékonyabb ábrázolás

data Nat2   -- egy természetes szám
    = One         -- vagy 1
    | D  Nat2     -- vagy egy term. szám kétszerese
    | SD Nat2     -- vagy egy term. szám kétszerese + 1
        deriving (Eq, Show, Data, Typeable)

Feladat: A rákövetkező függvényt

s :: Nat2 -> Nat2

Test>
[One, D One, SD One, D (D One), SD (D One), D (SD One), SD (SD One)] :: [Nat2]

Feladat: Num példány

Példányosítsuk a Num osztályt a Nat2 típusra.
Definiáljuk csak a (+), (*), fromInteger metódusokat.

instance Num Nat2 where

    fromInteger 1 = One
    fromInteger n = (if even n then D else SD) $ fromInteger $ n `div` 2

    One  + m    = s m
    n    + One  = s n
    D  n + D  m = D  (n + m)    -- 2*n   + 2*m   = 2*(n+m)
    SD n + D  m = SD (n + m)    -- 2*n+1 + 2*m   = 2*(n+m)+1
    D  n + SD m = SD (n + m)    -- 2*n   + 2*m+1 = 2*(n+m)+1
    SD n + SD m = D  (s (n + m))-- 2*n+1 + 2*m+1 = 2*(1+n+m)+1

    One  * m    = m
    D  n * m    = D (n*m)        --  2*n    * m   = 2*(n*m)
    SD n * m    = D (n*m) + m    -- (2*n+1) * m   = 2*(n*m) + m

    abs = undefined
    signum = undefined
    negate = undefined
 -- mintaillesztés, rekurzió
Test>
D (SD (D One)) :: Nat2
Test>
SD (D (D (SD One))) :: Nat2
Test>
SD (D (SD (D (SD (SD (D (D (D (D (SD One)))))))))) :: Nat2
sqr :: Nat2 -> Nat2  -- négyzetreemelés
sqr  One   = One
sqr (D  n) = D (D (sqr n))        -- (2*n)^2   = 2*2*n^2
sqr (SD n) = SD (D (n + sqr n))    -- (2*n+1)^2 = 2*(2*(n + n^2))+1

2*2-es mátrixok ===============

data Mat2x2 a = Mat2x2 a a
                       a a
        deriving (Eq, Show, Data, Typeable)

Feladat: (+), (*), fromInteger metódusok

instance Num a => Num (Mat2x2 a) where
    
    Mat2x2 a b c d + Mat2x2 a' b' c' d' 
        = Mat2x2 (a+a') (b+b') (c+c') (d+d')

    Mat2x2 a b 
           c d * Mat2x2 a' b' 
                        c' d' 
        = Mat2x2 (a*a'+b*c') (a*b'+b*d') 
                 (c*a'+d*c') (c*b'+d*d')

    fromInteger n = Mat2x2 (fromInteger n) 0
                           0 (fromInteger n)

    abs = undefined
    signum = undefined
    negate = undefined
 -- mintaillesztés
Test>
Mat2x2 2 3 4 5 :: Mat2x2 Integer
Test>
Mat2x2 3 4 2 1 :: Mat2x2 Integer
Test>
Mat2x2 2 4 6 8 :: Mat2x2 Integer
Test>
Mat2x2 37 54 81 118 :: Mat2x2 Integer

Fibonacci számok

Lassú definíció (exponenciális):

fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

Gyorsabb (lineáris):

fib2 0 = (0, 1)
fib2 1 = (1, 1)
fib2 n = (b, b+a) where (a, b) = fib2 (n-1)

Ezek azonosak:

Test>
True :: Bool

A következő definícióban az elvégzett alapműveletek száma O(log(n)).

Számolás mátrixokkal és gyors hatványozással

A fib2 függvény egyetlen lépése:

Numc9462e731a787f9bff8f3e26a73cf909.png

Ebből:

Numfb4581b8bec4aeac685b9f6bd180c1f7.png

Num3c10b6f654016f50144e5d792ec2023b.png

fastFib n = x where
    (Mat2x2 _ x _ _) = Mat2x2 1 1 1 0 ^ n

Azonosság vizsgálat:

Test>
True :: Bool

Duális számok

-- -- http://sigfpe.blogspot.com/2006/09/practical-synthetic-differential.html

A duális számok a + bε alakú számok, ahol ε2=0.

Reprezentáljuk az a + bε számot a Dual a b értékkel:

data Dual a = Dual a a  
  deriving (Eq, Show, Data, Typeable)

Definiáljuk a (+), (-), (*), fromInteger metódusokat.

instance (Num a) => Num (Dual a) where

    Dual a b + Dual c d =  Dual (a + c) (b + d)
 -- (a + b*ε) + (c + d*ε) =  (a+c) + (b+d)*ε

    Dual a b - Dual c d =  Dual (a - c) (b - d)
 -- (a + b*ε) - (c + d*ε) =  (a-c) + (b-d)*ε

    Dual a b * Dual c d =  Dual (a * c) (a * d + b * c)
 -- (a + b*ε) * (c + d*ε) =  (a*c) + (a*d+b*c)*ε


    abs = undefined
    signum = undefined
    fromInteger n =  Dual (fromInteger n) 0
Test>
Dual 2 1 :: Dual Integer
Test>
Dual 0 2 :: Dual Integer

Differenciálás duális számokkal

variable :: (Num a) => a -> Dual a
variable a = Dual a 1
diff :: (Num a) => Dual a -> a
diff (Dual _ b) = b
deriv :: (Num a, Num b) => (Dual a -> Dual b) -> (a -> b)

Test>
2 :: Integer
Test>
11 :: Integer

Törtek

A Fractional osztály:

-- class  (Num a) => Fractional a  where
--     (/)              :: a -> a -> a
--     recip            :: a -> a
--     fromRational     :: Rational -> a
--     -- alapértelmezett metódusok
--     recip x          =  1 / x
--     x / y            =  x * recip y

2x2-es mátrix invertálás

Példányosítsuk Fractional-t Mat2x2-re.

instance Fractional a => Fractional (Mat2x2 a) where

   fromRational r = Mat2x2 (fromRational r) 0
                           0 (fromRational r)

   recip (Mat2x2 a b c d) = Mat2x2 (m*d) (-m*b) (-m*c) (m*a)  where
   
       m = 1/(a*d-b*c)
 -- lásd a következő képletet

Num2afc8ee04601d5dbc3d13d56fa504afb.png

Test>
Mat2x2 (1 :% 1) (0 :% 1) (0 :% 1) (1 :% 1) :: Mat2x2 Rational

Fibonacci számok kiterjesztése

fastFib' :: Int -> Integer
fastFib' n = numerator x where
    (Mat2x2 _ x _ _) 
       = Mat2x2 1 1 1 0 ^^ n :: Mat2x2 Rational

Példa:

Test>
[5, -3, 2, -1, 1, 0, 1, 1, 2, 3, 5] :: [Integer]
Test>
True :: Bool

Felhasznált függvények:

(^^) :: (Fractional a, Integral b) => a -> b -> a
numerator :: Ratio a -> a

Duális számok osztása

Példányosítsuk Fractional-t Dual-ra.

instance (Eq a, Fractional a) => Fractional (Dual a) where

   fromRational r = Dual (fromRational r) 0

   Dual 0 a / Dual 0 b = Dual (a/b) 0
   Dual a b / Dual c d = Dual (a/c) ((b*c-a*d)/c^2)
-- ...

Numaf51c92272d9a9a9c9787e1b746d4e79.png

Num92e0c3743ca13c30dcd9cad76ac7182e.png

Test>
Dual (1 :% 2) (-1 :% 4) :: Dual Rational

Szingularitások eltüntetése

-- -- http://sigfpe.blogspot.com/2008/05/desingularisation-and-its-applications.html
desingularise :: (Num a, Num b) => 
   (Dual a -> Dual b) -> (a -> b)

Test>
2 :% 1 :: Rational