module Trit (Trit, rationalToTrit, getIntegral, getFraction, getFraction',
                neg, addTrits, subTrits, shiftLeft, shiftRight, multiply
                ) where

import Stream
import Utilities
import Data.Ratio

type Mantissa = Stream
type Fraction = Stream
type Trit     = (Mantissa, Fraction)


-- Convert from a Rational number to its Trit representation (Integral, Fraction)
rationalToTrit :: Rational -> Trit
rationalToTrit x
                |x<1            = ([0], rationalToStream x)
                |otherwise      = (u', rationalToStream v)
                where   u = n `div` d
                        u' = toBinary u
                        v = x - (toRational u)
                        n = numerator x
                        d = denominator x


-- Get the integral part of Trit
getIntegral :: Trit -> Mantissa
getIntegral = fst



-- Get the fraction part of Trit, with n digit of the stream
getFraction :: Int -> Trit -> Stream
getFraction n = take n. snd


-- Get the fraction part of Trit
getFraction' :: Trit -> Stream
getFraction' = snd



-- Negate a Trit
neg :: Trit -> Trit
neg (a, b) = (negate' a, negate' b)



-- Add two Trits
addTrits :: Trit -> Trit -> Trit
addTrits (m1, (x1:x2:xs)) (m2, (y1:y2:ys)) = (u,addStream (x1:x2:xs) (y1:y2:ys))
                                           where u' = addFiniteStream m1 m2
                                                 c = [carry x1 x2 y1 y2]
                                                 u = addFiniteStream u' c



-- Substraction of 2 Trits
subTrits :: Trit -> Trit -> Trit
subTrits x y = addTrits x (neg y)



-- Shift left = *2 operation with Trit
shiftLeft :: Trit -> Trit
shiftLeft (x, (y:ys)) = (x++ [y], ys)


-- Shift right = /2 operation with Trit
shiftRight :: Trit -> Integer -> Trit
shiftRight (x, xs) 1 = (init x, (u:xs))
                    where u = last x
shiftRight (x, xs) n = shiftRight (init x, (u:xs)) (n-1)
                    where u = last x



-- Multiply a Trit stream by 1,0 or -1, simply return the stream
mulOneDigit :: Integer -> Stream -> Stream
mulOneDigit x xs
              |x==1      = xs
              |x==0      = zero'
              |otherwise = negate' xs
              where zero' = (0:zero')






-- Multiplication of two streams
multiply :: Stream -> Stream -> Stream
multiply (a0:a1:x) (b0:b1:y) = average p q
                               where p = average (a1*b0: (average (mulOneDigit b1 x)
                                                                 (mulOneDigit a1 y)))
                                                 (average (mulOneDigit b0 x)
                                                          (mulOneDigit a0 y))
                                     q = (a0*b0:a0*b1:a1*b1:(multiply x y))




start0 = take 30 (multiply (rationalToStream (1%2)) zo)

zo :: Stream
zo = 1:(-1):zero
     where zero = 0:zero

start1 = take 30 (average (rationalToStream (1%2)) (negate' (rationalToStream (1%4))))



