{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/BWT/BWT.hs" #-}
module Quipper.Algorithms.BWT.BWT where
import Quipper
import Quipper.Algorithms.BWT.Definitions
import Quipper.Libraries.Qureg
import Quipper.Libraries.Decompose
import Quipper.Utils.Auxiliary
import Text.Printf
data Oracle = Oracle {
n :: Int,
m :: Int,
k :: Int,
entrance :: Boollist,
oraclefun :: Int -> (Qureg, Qureg, Qubit) -> Circ ()
}
qrwbwt :: Oracle -> Int -> Timestep -> Circ [Bit]
qrwbwt oracle s dt = do
comment (printf "ENTER: qrwbwt (s=%d, dt=%.3e)" s dt)
a <- qinit_register (entrance oracle)
with_ancilla_reg (m oracle) $ \b -> do
with_ancilla $ \r -> do
loopM_boxed_if (s > 1) "qrwbwt_loop" s (a,b,r) $ \(a,b,r) -> do
for 0 (k oracle-1) 1 $ \c -> do
(oraclefun oracle) c (a, b, r)
timestep (a, b, r, dt, m oracle)
(oraclefun oracle) c (a, b, r)
endfor
return (a,b,r)
endfor
exit <- qmeasure_register a
comment_with_label "EXIT: qrwbwt" exit "exit"
return exit
timestep :: (Qureg, Qureg, Qubit, Timestep, Int) -> Circ ()
timestep (a, b, r, dt, m) = do
comment_with_label "ENTER: timestep" (a,b,r) ("a","b","r")
with_ancilla $ \h -> do
for 0 (m-1) 1 $ \i -> do
wGate (a.!(i), b.!(i))
endfor
for 0 (m-1) 1 $ \i -> do
toffoliGate (a.!(i), b.!(i), h)
endfor
controlledExpGate (dt, r, h)
for (m-1) 0 (-1) $ \i -> do
toffoliGate (a.!(i), b.!(i), h)
endfor
for (m-1) 0 (-1) $ \i -> do
wGateInverse (a.!(i), b.!(i))
endfor
comment_with_label "EXIT: timestep" (a,b,r) ("a","b","r")
return ()
oracle :: (Qureg, Qureg, Qubit, Boolreg, Boolreg, Boolreg, Int) -> Circ ()
oracle (a, b, r, color, f, g, n) = do
let c = int_of_boolreg_unsigned_le color :: Int
comment_with_label (printf "ENTER: oracle (color=%d)" c) (a,b,r) ("a","b","r")
with_ancilla $ \root -> do
with_ancilla $ \even -> do
with_ancilla $ \isparent -> do
with_ancilla $ \ischild -> do
with_ancilla $ \direction -> do
with_ancilla $ \ismatch -> do
parseNodeRoot (a, root, even, n)
parseNodeEven (a, even, n)
testIsParent (a, root, even, isparent, color, n, 1, ismatch)
testIsChild (even, ischild, direction, color, n)
setParent (a, b, isparent, n)
setChild (a, b, ischild, direction, f, g, n)
with_controls (isparent .==. 0 .&&. ischild .==. 0) $ do {
qnot_at r
}
testIsChild (even, ischild, direction, color, n)
testIsParent (a, root, even, isparent, color, n, 0, ismatch)
parseNodeEven (a, even, n)
parseNodeRoot (a, root, even, n)
comment_with_label (printf "EXIT: oracle (color=%d)" c) (a,b,r) ("a","b","r")
return ()
parseNodeRoot :: (Qureg, Qubit, Qubit, Int) -> Circ ()
parseNodeRoot (a, root, even, n) = do
comment_with_label "ENTER: parseNodeRoot" (a, root, even) ("a", "root", "even")
with_ancilla_reg (n+1) $ \scratch -> do
for n 1 (-1) $ \index -> do
with_controls (scratch.!(index) .==. 0 .&&. a.!(index) .==. 1) $ do {
qnot_at (scratch.!(index - 1))
}
with_controls (scratch.!(index) .==. 1) $ do {
qnot_at (scratch.!(index - 1))
}
endfor
with_controls (scratch.!(0) .==. 0) $ do {
qnot_at root;
qnot_at even
}
for 1 n 1 $ \index -> do
with_controls (scratch.!(index) .==. 1) $ do {
qnot_at (scratch.!(index - 1))
}
with_controls (scratch.!(index) .==. 0 .&&. a.!(index) .==. 1) $ do {
qnot_at (scratch.!(index-1))
}
endfor
comment_with_label "EXIT: parseNodeRoot" (a, root, even) ("a", "root", "even")
return ()
parseNodeEven :: (Qureg, Qubit, Int) -> Circ ()
parseNodeEven (a, even, n) = do
comment_with_label "ENTER: parseNodeEven" (a, even) ("a", "even")
with_ancilla_reg (n+1) $ \scratch -> do
for n 1 (-1) $ \index -> do
with_controls (scratch.!(n) .==. 0 .&&. a.!(index) .==. 1) $ do {
qnot_at (scratch.!(index-1));
with_controls (Prelude.even index) $ do {
qnot_at even
}
}
with_controls (scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(n))
}
endfor
for 1 n 1 $ \index -> do
with_controls (scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(n))
}
with_controls (scratch.!(n) .==. 0 .&&. a.!(index) .==. 1) $ do {
qnot_at (scratch.!(index-1))
}
endfor
comment_with_label "EXIT: parseNodeEven" (a, even) ("a", "even")
return ()
testIsParent :: (Qureg, Qubit, Qubit, Qubit, Boolreg, Int, Int, Qubit) -> Circ ()
testIsParent (a, root, even, isparent, color, n, really, ismatch) = do
let c = int_of_boolreg_unsigned_le color :: Int
comment_with_label (printf "ENTER: testIsParent (color=%d really=%d)" c really) (a, root, even, isparent, ismatch) ("a", "root", "even", "isparent", "ismatch")
with_controls (really == 0) $ do {
with_controls (root .==. 0 .&&. ismatch .==. 1) $ do {
qnot_at isparent
}
}
if color.!(1) == 1
then
if color.!(0) == 1 then
with_controls (even .==. 1 .&&. a.!(0) .==. 1) $ do {
qnot_at ismatch
}
else
with_controls (even .==. 1 .&&. a.!(0) .==. 0) $ do {
qnot_at ismatch
}
else
if color.!(0) == 1 then
with_controls (even .==. 0 .&&. a.!(0) .==. 1) $ do {
qnot_at isparent
}
else
with_controls (even .==. 0 .&&. a.!(0) .==. 0) $ do {
qnot_at isparent
}
with_controls (root .==. 0 .&&. ismatch .==. 1) $ do {
qnot_at isparent
}
comment_with_label (printf "EXIT: testIsParent (color=%d really=%d)" c really) (a, root, even, isparent, ismatch) ("a", "root", "even", "isparent", "ismatch")
return ()
testIsChild :: (Qubit, Qubit, Qubit, Boolreg, Int) -> Circ ()
testIsChild (even, ischild, direction, color, n) = do
comment_with_label "ENTER: testIsChild" (even, ischild, direction) ("even", "ischild", "direction")
if color.!(1) == 1
then
with_controls (even .==. 0) $ do {
qnot_at ischild
}
else
with_controls (even .==. 1) $ do {
qnot_at ischild
}
with_controls (color.!(0) == 1) $ do {
qnot_at direction
}
comment_with_label "EXIT: testIsChild" (even, ischild, direction) ("even", "ischild", "direction")
return ()
setParent :: (Qureg, Qureg, Qubit, Int) -> Circ ()
setParent (a, b, isparent, n) = do
comment_with_label "ENTER: setParent" (a, b, isparent) ("a", "b", "isparent")
for 0 (n-1) 1 $ \index -> do
with_controls (isparent .==. 1 .&&. a.!(index+1) .==. 1) $ do {
qnot_at (b.!(index))
}
endfor
with_controls (isparent .==. 1 .&&. a.!(n+1) .==. 1) $ do {
qnot_at (b.!(n+1))
}
comment_with_label "EXIT: setParent" (a, b, isparent) ("a", "b", "isparent")
return ()
setChild :: (Qureg, Qureg, Qubit, Qubit, Boolreg, Boolreg, Int) -> Circ ()
setChild (a, b, ischild, direction, f, g, n) = do
comment_with_label "ENTER: setChild" (a, b, ischild, direction) ("a", "b", "ischild", "direction")
with_ancilla $ \childctrl -> do
with_controls (ischild .==. 1 .&&. a.!(n) .==. 1) $ do {
qnot_at childctrl
}
setWeld (a, b, childctrl, direction, f, g, n)
with_controls (ischild .==. 1) $ do {
qnot_at childctrl
}
setChildInTree (a, b, childctrl, direction, n)
with_controls (ischild .==. 1 .&&. a.!(n) .==. 0) $ do {
qnot_at childctrl
}
comment_with_label "EXIT: setChild" (a, b, ischild, direction) ("a", "b", "ischild", "direction")
return ()
setChildInTree :: (Qureg, Qureg, Qubit, Qubit, Int) -> Circ ()
setChildInTree (a, b, childctrl, direction, n) = do
comment_with_label "ENTER: setChildInTree" (a, b, childctrl, direction) ("a", "b", "childctrl", "direction")
with_controls (childctrl .==. 1 .&&. direction .==. 1) $ do {
qnot_at (b.!(0))
}
for 1 n 1 $ \index -> do
with_controls (childctrl .==. 1 .&&. a.!(index-1) .==. 1) $ do {
qnot_at (b.!(index))
}
endfor
with_controls (childctrl .==. 1 .&&. a.!(n+1) .==. 1) $ do {
qnot_at (b.!(n+1))
}
comment_with_label "EXIT: setChildInTree" (a, b, childctrl, direction) ("a", "b", "childctrl", "direction")
return ()
setWeld :: (Qureg, Qureg, Qubit, Qubit, Boolreg, Boolreg, Int) -> Circ ()
setWeld (a, b, childctrl, direction, f, g, n) = do
comment_with_label "ENTER: setWeld" (a, b, childctrl, direction) ("a", "b", "childctrl", "direction")
with_ancilla $ \weldctrl -> do
with_controls (childctrl .==. 1 .&&. direction .==. 0) $ do {
qnot_at weldctrl
}
doWeld0 (a, b, weldctrl, f, n)
with_controls (childctrl .==. 1) $ do {
qnot_at weldctrl
}
doWeld1 (a, b, weldctrl, g, n)
with_controls (childctrl .==. 1 .&&. direction .==. 1) $ do {
qnot_at weldctrl
}
with_controls (childctrl .==. 1 .&&. a.!(n+1) .==. 1) $ do {
qnot_at (b.!(n+1))
}
with_controls (childctrl .==. 1) $ do {
qnot_at (b.!(n));
qnot_at (b.!(n+1))
}
comment_with_label "EXIT: setWeld" (a, b, childctrl, direction) ("a", "b", "childctrl", "direction")
return ()
doWeld1 :: (Qureg, Qureg, Qubit, Boolreg, Int) -> Circ ()
doWeld1 (a, b, weldctrl, g, n) = do
comment_with_label "ENTER: doWeld1" (a, b, weldctrl) ("a", "b", "weldctrl")
with_ancilla $ \addsub -> do
with_controls (weldctrl .==. 1 .&&. a.!(n+1) .==. 0) $ do {
qnot_at addsub
}
cAddNum (addsub, b, a, g, n)
with_controls (weldctrl .==. 1) $ do {
qnot_at addsub
}
cSubNum (addsub, b, a, g, n)
with_controls (weldctrl .==. 1 .&&. a.!(n+1) .==. 1) $ do {
qnot_at addsub
}
comment_with_label "EXIT: doWeld1" (a, b, weldctrl) ("a", "b", "weldctrl")
return ()
doWeld0 :: (Qureg, Qureg, Qubit, Boolreg, Int) -> Circ ()
doWeld0 (a, b, weldctrl, f, n) = do
comment_with_label "ENTER: doWeld0" (a, b, weldctrl) ("a", "b", "weldctrl")
for 0 (n-1) 1 $ \index -> do
with_controls (weldctrl .==. 1) $ do {
qnot_at (b.!(index)) `controlled` a.!(index) ./=. f.!(index)
}
endfor
comment_with_label "EXIT: doWeld0" (a, b, weldctrl) ("a", "b", "weldctrl")
return ()
cAddNum :: (Qubit, Qureg, Qureg, Boolreg, Int) -> Circ ()
cAddNum (control, out, input, num, n) = do
comment_with_label "ENTER: cAddNum" (control, out, input) ("control", "out", "input")
with_ancilla_reg n $ \scratch -> do
let maskbit = 0
with_controls (control .==. 1 .&&. input.!(0) .==. 1) $ do {
qnot_at (out.!(0))
}
with_controls (num.!(maskbit) /= 0) $ do {
with_controls (control .==. 1) $ do {
qnot_at (out.!(0))
};
with_controls (input.!(0) .==. 1) $ do {
qnot_at (scratch.!(0))
}
}
for 1 (n-1) 1 $ \index -> do
let maskbit = index
with_controls (control .==. 1 .&&. input.!(index) .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. control .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (control .==. 1 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. input.!(index) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (input.!(index) .==. 1 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
endfor
cAddNumClear (control, scratch, input, num, n)
comment_with_label "EXIT: cAddNum" (control, out, input) ("control", "out", "input")
return ()
cAddNumClear :: (Qubit, Qureg, Qureg, Boolreg, Int) -> Circ ()
cAddNumClear (control, scratch, input, num, n) = do
comment_with_label "ENTER: cAddNumClear" (control, scratch, input) ("control", "scratch", "input")
for (n-1) 1 (-1) $ \index -> do
let maskbit = index
with_controls (num.!(maskbit) /= 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (input.!(index) .==. 1 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. input.!(index) .==. 1) $ do {
qnot_at (scratch.!(index))
}
endfor
let maskbit = 0
with_controls (num.!(maskbit) /= 0 .&&. input.!(0) .==. 1) $ do {
qnot_at (scratch.!(0))
}
comment_with_label "EXIT: cAddNumClear" (control, scratch, input) ("control", "scratch", "input")
return ()
cSubNum :: (Qubit, Qureg, Qureg, Boolreg, Int) -> Circ ()
cSubNum (control, out, input, num, n) = do
comment_with_label "ENTER: cSubNum" (control, out, input) ("control", "out", "input")
with_ancilla_reg n $ \scratch -> do
let maskbit = 0
with_controls (control .==. 1 .&&. input.!(0) .==. 1) $ do {
qnot_at (out.!(0))
}
with_controls (num.!(maskbit) /= 0) $ do {
with_controls (control .==. 1) $ do {
qnot_at (out.!(0))
};
with_controls (input.!(0) .==. 0) $ do {
qnot_at (scratch.!(0))
}
}
for 1 (n-1) 1 $ \index -> do
let maskbit = index
with_controls (control .==. 1 .&&. input.!(index) .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. control .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (control .==. 1 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (out.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. input.!(index) .==. 0) $ do {
qnot_at (scratch.!(index))
}
with_controls (input.!(index) .==. 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
endfor
cSubNumClear (control, scratch, input, num, n)
comment_with_label "EXIT: cSubNum" (control, out, input) ("control", "out", "input")
return ()
cSubNumClear :: (Qubit, Qureg, Qureg, Boolreg, Int) -> Circ ()
cSubNumClear (control, scratch, input, num, n) = do
comment_with_label "ENTER: cSubNumClear" (control, scratch, input) ("control", "scratch", "input")
for (n-1) 1 (-1) $ \index -> do
let maskbit = index
with_controls (num.!(maskbit) /= 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (input.!(index) .==. 0 .&&. scratch.!(index-1) .==. 1) $ do {
qnot_at (scratch.!(index))
}
with_controls (num.!(maskbit) /= 0 .&&. input.!(index) .==. 0) $ do {
qnot_at (scratch.!(index))
}
endfor
let maskbit = 0
with_controls (num.!(maskbit) /= 0 .&&. input.!(0) .==. 0) $ do {
qnot_at (scratch.!(0))
}
comment_with_label "EXIT: cSubNumClear" (control, scratch, input) ("control", "scratch", "input")
return ()
oracle_orthodox :: Boollist -> Boollist -> Oracle
oracle_orthodox f g =
Oracle { n = n,
m = m,
k = k,
entrance = entrance,
oraclefun = oraclefun
} where
n = length f
m = n+2
k = 4
entrance = boollist_of_int_bh m 1
f_reg = boolreg_of_boollist_te f
g_reg = boolreg_of_boollist_te g
oraclefun :: Int -> (Qureg, Qureg, Qubit) -> Circ ()
oraclefun c (a,b,r) = do
let color = boolreg_of_int_le 2 c
oracle (a, b, r, color, f_reg, g_reg, n)
return ()
main_circuit :: Format -> GateBase -> Oracle -> Int -> Timestep -> IO()
main_circuit format base oracle s dt =
print_generic format (decompose_generic base circuit)
where
circuit = qrwbwt oracle s dt
main_oracle :: Format -> GateBase -> Oracle -> Int -> IO()
main_oracle format base oracle c =
let m' = m oracle
ofun = oraclefun oracle
circuit = (\(a,b,r) -> ofun c (qureg_of_qulist_te a, qureg_of_qulist_te b, r))
in
print_generic format (decompose_generic base circuit) (replicate m' qubit, replicate m' qubit, qubit)