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 opertaion 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))))

	 
	 
