{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
-- | Helper module for "Quipper.Algorithms.QLS.QSignedInt": some functions
-- defined with Template Haskell.
module Quipper.Algorithms.QLS.QSignedIntAux where

import Quipper
import Quipper.Libraries.Arith



-- | Subtraction on lists of booleans, understood as big-headian,
-- unsigned integers.

-- void definition for now
be_boollist_sub :: [Bool] -> [Bool] -> [Bool]
be_boollist_sub = error "be_boollist_sub yet undefined."


-- Template version of 'be_boollist_sub'.

-- Right now, call to q_sub.
-- template_be_boollist_sub :: Circ ([Qubit] -> Circ ([Qubit] -> Circ [Qubit]))
template_be_boollist_sub = return $ \x -> return $ \y -> do
                let x' = qdint_of_qulist_bh x
                let y' = qdint_of_qulist_bh y
                (_,_,z) <- q_sub x' y'
                return $ qulist_of_qdint_bh z


-- | Addition on lists of booleans, understood as big-headian, unsigned
-- integers.

-- void definition for now.
be_boollist_add :: [Bool] -> [Bool] -> [Bool]
be_boollist_add = error "be_boollist_add yet undefined."



-- Template version of 'be_boollist_add'

-- Right now, call q_add
-- template_be_boollist_add :: Circ ([Qubit] -> Circ ([Qubit] -> Circ [Qubit]))
template_be_boollist_add = return $ \x -> return $ \y -> do
                let x' = qdint_of_qulist_bh x
                let y' = qdint_of_qulist_bh y
                (_,_,z) <- q_add x' y'
                return $ qulist_of_qdint_bh z



-- | Strict ordering on lists of booleans, understood as big-headian
-- unsigned integers. If the lists are not of equal length, the
-- shorter list is treated as if its tail were padded with zeros.

be_boollist_less :: [Bool] -> [Bool] -> Bool
be_boollist_less l1 l2 =
  case (l1,l2) of
    (a,[]) -> False
    ([],a)  -> be_boollist_less [False] a
    (h1:t1, h2:t2) ->
       let parity = if h1 then h2 else not h2 in
       if parity then be_boollist_less t1 t2
       else h2



{-# LINE 64 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
$( decToCircMonad [d| be_boollist_less :: [Bool] -> [Bool] -> Bool
                      be_boollist_less l1 l2 =
                        case (l1,l2) of
                          (a,[]) -> False
                          ([],a)  -> be_boollist_less [False] a
                          (h1:t1, h2:t2) ->
                             let parity = if h1 then h2 else not h2 in
                             if parity then be_boollist_less t1 t2
                             else h2



 |] )
{-# LINE 65 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
-- | Strict ordering on lists of booleans, understood as big-headian
-- signed integers: the 'Bool' in the pair stands for the sign: 'False'
-- is positive, 'True' is negative.

be_signed_boollist_less :: (Bool,[Bool]) -> (Bool,[Bool]) -> Bool
be_signed_boollist_less (b1,l1) (b2,l2) =
    if b1 then (if b2 then be_boollist_less l2 l1  else True)
    else       (if b2 then False else be_boollist_less l1 l2)



{-# LINE 74 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
$( decToCircMonad [d| be_signed_boollist_less :: (Bool,[Bool]) -> (Bool,[Bool]) -> Bool
                      be_signed_boollist_less (b1,l1) (b2,l2) =
                          if b1 then (if b2 then be_boollist_less l2 l1  else True)
                          else       (if b2 then False else be_boollist_less l1 l2)



 |] )
{-# LINE 75 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
-- | Test whether all elements of a list are 'False'.

boollist_is_zero :: [Bool] -> Bool
boollist_is_zero l =
   case l of
     []    -> True
     (h:t) -> if h then boollist_is_zero t else False



{-# LINE 83 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
$( decToCircMonad [d| boollist_is_zero :: [Bool] -> Bool
                      boollist_is_zero l =
                         case l of
                           []    -> True
                           (h:t) -> if h then boollist_is_zero t else False



 |] )
{-# LINE 84 "Quipper/Algorithms/QLS/QSignedIntAux.hs" #-}
-- | Addition on signed integers, encoded as big-headian lists of
-- booleans.

be_signed_boollist_add :: (Bool,[Bool]) -> (Bool,[Bool]) -> (Bool,[Bool])
be_signed_boollist_add (b,x) (c,y) =
    let parity = if b then c else not c in
    let (d,z) = if parity then (b, be_boollist_add x y)
                else if (be_boollist_less x y) then (c, be_boollist_sub y x)
                else (b, be_boollist_sub x y)
    in if (boollist_is_zero z) then (False,z) else (d,z)

$( decToCircMonad [d| be_signed_boollist_add :: (Bool,[Bool]) -> (Bool,[Bool]) -> (Bool,[Bool])
                      be_signed_boollist_add (b,x) (c,y) =
                          let parity = if b then c else not c in
                          let (d,z) = if parity then (b, be_boollist_add x y)
                                      else if (be_boollist_less x y) then (c, be_boollist_sub y x)
                                      else (b, be_boollist_sub x y)
                          in if (boollist_is_zero z) then (False,z) else (d,z)

 |] )