{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Libraries/ClassicalOptim/Simplification.hs" #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE DoAndIfThenElse #-}
module Quipper.Libraries.ClassicalOptim.Simplification where
import qualified Data.Map as M
import qualified Data.List as L
import qualified Data.Set as S
import qualified Data.IntSet as IS
import qualified Data.IntMap.Strict as IM
import qualified Control.DeepSeq as Seq
import Control.Applicative (Applicative(..))
import Control.Monad (liftM, ap)
import qualified Quipper.Utils.Auxiliary as Q
import Quipper.Libraries.ClassicalOptim.Circuit
import Quipper.Libraries.ClassicalOptim.AlgExp
trace :: String -> b -> b
trace a b = b
moveWire :: Wire -> Wire -> Gate -> Gate
moveWire from to NoOp = NoOp
moveWire from to (Init b w) = if (w == from) then error "moveWire" else (Init b w)
moveWire from to (Cnot w ctls) = Cnot w' ctls'
where
w' = if (from == w) then to else w
ctls' = map moveCtls ctls
moveCtls (w,b) = if (from == w) then (to,b) else (w,b)
flipCtl :: Wire -> Gate -> Gate
flipCtl _ NoOp = NoOp
flipCtl _ (Init b w) = Init b w
flipCtl w (Cnot w' ctls) = Cnot w' $ map (\(x,b) -> if (x == w) then (x,not b) else (x,b)) ctls
moveWireFlip :: Wire -> Wire -> Gate -> Gate
moveWireFlip from to NoOp = NoOp
moveWireFlip from to (Init b w) = if (w == from) then error "moveWire" else (Init b w)
moveWireFlip from to (Cnot w ctls) = Cnot w' ctls'
where
w' = if (from == w) then to else w
ctls' = map moveCtls ctls
moveCtls (w,b) = if (from == w) then (to,b) else if (to == w) then (w,not b) else (w,b)
suppress_garbage :: [Gate] -> IS.IntSet -> [Gate]
suppress_garbage ((Cnot w ctls):gs) used =
if (IS.member w used) then g:gs1 else gs2
where
g = Cnot w ctls
gs1 = suppress_garbage gs $ IS.union (IS.insert w used) $ IS.fromList $ L.map fst ctls
gs2 = suppress_garbage gs used
suppress_garbage (g:gs) used = g:(suppress_garbage gs used)
suppress_garbage [] _ = []
suppressGarbageGates :: ([Gate],[Wire]) -> ([Gate],[Wire])
suppressGarbageGates (gs,out) = (reverse $ suppress_garbage (reverse gs) $ IS.fromList out, out)
getAllWires :: [Gate] -> IS.IntSet
getAllWires gs = L.foldl' IS.union IS.empty $ L.map aux gs
where
aux (Cnot w ctls) = IS.insert w $ L.foldl' (flip IS.insert) IS.empty $ L.map fst ctls
aux (Init _ w) = IS.singleton w
aux NoOp = IS.empty
getInitWires :: [Gate] -> IS.IntSet
getInitWires gs = L.foldl' IS.union IS.empty $ map aux gs
where
aux (Cnot _ _) = IS.empty
aux (Init _ w) = IS.singleton w
aux NoOp = IS.empty
getInputWires :: [Gate] -> IS.IntSet
getInputWires gs = IS.difference (getAllWires gs) (getInitWires gs)
compressWires :: [Wire] -> ([Gate],[Wire]) -> ([Gate],[Wire])
compressWires inputwires (gs,output) = (gs',out')
where
iws = getInitWires gs
begin = if inputwires == []
then 0
else 1 + (head $ reverse $ L.sort inputwires)
end = begin + (IS.size iws)
listmap = zip ([0..begin-1] ++ (IS.toAscList iws)) [0 .. end]
remap = M.fromList $ trace (show listmap) listmap
out' = map (remap M.!) output
gs' = map (rewire remap) gs
rewire m (Cnot w ctls) = Cnot (m M.! w) $ map (\(x,b) -> (m M.! x, b)) ctls
rewire m (Init b w) = Init b (m M.! w)
rewire m NoOp = NoOp
type GateId = Int
type GateIdSet = IS.IntSet
type UsedWire = IM.IntMap GateIdSet
gateIdFindMin :: GateIdSet -> Maybe GateId
gateIdFindMin g = if (IS.null g) then Nothing else Just (IS.findMin g)
gateIdFindMax :: GateIdSet -> Maybe GateId
gateIdFindMax g = if (IS.null g) then Nothing else Just (IS.findMax g)
pairUsedWire :: UsedWire -> Wire -> GateIdSet
pairUsedWire m w = IM.findWithDefault IS.empty w m
firstUsedWire :: UsedWire -> Wire -> Maybe GateId
firstUsedWire = curry $ gateIdFindMin . (uncurry pairUsedWire)
lastUsedWire :: UsedWire -> Wire -> GateId
lastUsedWire w w'=
case (curry $ gateIdFindMax . (uncurry pairUsedWire)) w w' of
Just w -> w
Nothing -> 0
nextUsedGate :: UsedWire -> GateId -> GateId -> Wire -> GateId
nextUsedGate ws g g' w =
case (do gs <- IM.lookup w ws; IS.lookupGT g gs) of
Just g -> g
Nothing -> g'
circuitControlWires :: GateId -> [Gate] -> UsedWire
circuitControlWires id gs = aux id IM.empty gs
where
aux _ m [] = m
aux g m (Init _ _:gs) = aux (g+1) m gs
aux g m ((Cnot _ ctls):gs) = aux (g+1) m' gs
where
wires = map fst ctls
m' = L.foldl (\m'' w -> IM.alter (f g) w m'') m wires
f g Nothing = Just $ IS.singleton g
f g (Just s) = Just $ IS.insert g s
aux g m (NoOp:_) = error "circuitControlWires cannot deal with NoOp"
circuitNotWires :: GateId -> [Gate] -> UsedWire
circuitNotWires id gs = aux id IM.empty gs
where
aux _ m [] = m
aux g m (Init _ _:gs) = aux (g+1) m gs
aux g m ((Cnot w _):gs) = aux (g+1) m' gs
where
m' = IM.alter (f g) w m
f g Nothing = Just $ IS.singleton g
f g (Just s) = Just $ IS.insert g s
aux g m (_:gs) = aux (g+1) m gs
exp_length :: Exp -> Int
exp_length e = L.foldl' (+) 0 $ L.map (\x -> let y = IS.size x in seq y y) $ S.toList e
exp_list_and :: [S.Set Exp] -> S.Set Exp
exp_list_and [] = S.singleton exp_true
exp_list_and [l] = l
exp_list_and (h:k:t) = exp_list_and (S.fromList [exp_and x y | x <- S.toList h, y <- S.toList k]:t)
expEvalCtl :: (IM.IntMap (S.Set (Exp,Int))) -> (Wire,Bool) -> S.Set Exp
expEvalCtl m (w,True) = S.map fst (m IM.! w)
expEvalCtl m (w,False) = S.map exp_not $ S.map fst $ (IM.!) m w
expEvalGate :: (IM.IntMap (S.Set (Exp,Int))) -> Gate -> IM.IntMap (S.Set (Exp,Int))
expEvalGate m (Init False w) = IM.insert w (S.singleton (exp_false,0)) m
expEvalGate m (Init True w) = IM.insert w (S.singleton (exp_true,1)) m
expEvalGate m NoOp = m
expEvalGate m (Cnot w ctls) = IM.insert w cnot m
where
ands = exp_list_and $ L.map (expEvalCtl m) ctls
cnot = S.map (\x -> (x,exp_length x)) (S.fromList [exp_xor x y |
x <- S.toList $ S.map fst $ (IM.!) m w,
y <- S.toList ands ])
data ExpState = ExpState {
gates_to_skip :: IM.IntMap Gate,
allWiresInCirc :: IS.IntSet,
gateId :: GateId,
usedControlWires :: UsedWire,
usedNotWires :: UsedWire,
future :: [Gate],
past :: [Gate],
expMap :: IM.IntMap (S.Set (Exp,Int)),
freshVar :: Integer,
outWires :: [Wire],
sizeCirc :: Int
}
instance Seq.NFData Gate where
rnf (Init a b) = a `seq` b `seq` ()
rnf (Cnot w ctls) = ctls `Seq.deepseq` w `Seq.deepseq` ()
rnf NoOp = ()
initExpState :: IS.IntSet -> [Wire] -> [Gate] -> ExpState
initExpState ws_in ws_out gs = ExpState {
gates_to_skip = IM.empty,
allWiresInCirc = getAllWires gs,
gateId = 1,
usedControlWires = circuitControlWires 1 gs,
usedNotWires = circuitNotWires 1 gs,
future = gs,
past = [],
expMap = IM.fromList $ L.map (\x -> (x, S.singleton (exp_var x, 1))) $ IS.toAscList ws_in,
freshVar = fromIntegral $ (+) 1 $ IS.findMax ws_in,
outWires = ws_out,
sizeCirc = length gs
}
data EvalCirc a = EvalCirc (ExpState -> (ExpState, a))
instance Monad EvalCirc where
return x = EvalCirc (\y -> (y,x))
(>>=) (EvalCirc c) f = EvalCirc (\s -> let (s',x) = c s in
let (EvalCirc c') = f x in
c' s')
instance Applicative EvalCirc where
pure = return
(<*>) = ap
instance Functor EvalCirc where
fmap = liftM
runEvalCirc :: IS.IntSet -> [Wire] -> [Gate] -> EvalCirc a -> ExpState
runEvalCirc ws_in ws_out gs (EvalCirc e) = fst $ e $ initExpState ws_in ws_out gs
getExpState :: EvalCirc ExpState
getExpState = EvalCirc (\s -> (s,s))
setExpState :: ExpState -> EvalCirc ()
setExpState s = EvalCirc (\_ -> (s,()))
newFreshVar :: EvalCirc Integer
newFreshVar = do
s <- getExpState
let v = freshVar s
setExpState (s { freshVar = v + 1 })
return v
pullNewGate :: EvalCirc (Maybe Gate)
pullNewGate = do
s <- getExpState
case (future s) of
(h:t) -> do setExpState (s { future = t } )
return (Just h)
[] -> return Nothing
changeFuture :: [Gate] -> EvalCirc ()
changeFuture gs = do
s <- getExpState
setExpState (s { future = gs } )
return ()
updateFuture :: (Gate -> Gate) -> EvalCirc (IS.IntSet,IS.IntSet)
updateFuture f = do
s <- getExpState
let ((_,!gsModifCtls,!gsModifNots),new_future) =
L.mapAccumL (\(gid,gs,gs') g -> let g' = f g in
((
gid+1
,
if (ctlsOfGate g == ctlsOfGate g')
then gs
else IS.insert gid gs
,
if (wireOfGate g == wireOfGate g')
then gs'
else IS.insert gid gs'
),
g'))
(1 + (gateId s), IS.empty,IS.empty) (future s)
changeFuture new_future
return (gsModifCtls,gsModifNots)
storeOldGate :: Gate -> EvalCirc ()
storeOldGate g = do
s <- getExpState
let p = past s
seq g $ seq p $ setExpState (s { past = g:p } )
return ()
incrGateId :: EvalCirc ()
incrGateId = do
s <- getExpState
setExpState (s { gateId = 1 + (gateId s) } )
return ()
getAllWiresInCirc :: EvalCirc IS.IntSet
getAllWiresInCirc = do
s <- getExpState
return (allWiresInCirc s)
setAllWiresInCirc :: IS.IntSet -> EvalCirc ()
setAllWiresInCirc ws = do
s <- getExpState
ws `seq` setExpState (s {allWiresInCirc = ws})
return ()
removeFromAllWiresInCirc :: Int -> EvalCirc ()
removeFromAllWiresInCirc w = do
ws <- getAllWiresInCirc
setAllWiresInCirc $ IS.delete w ws
return ()
getExpMap :: EvalCirc (IM.IntMap (S.Set (Exp,Int)))
getExpMap = do
s <- getExpState
s `seq` return (expMap s)
setExpMap :: (IM.IntMap (S.Set (Exp,Int))) -> EvalCirc ()
setExpMap m = do
s <- getExpState
m `seq` setExpState (s { expMap = m } )
return ()
updateUsedControlWires :: (UsedWire -> UsedWire) -> EvalCirc ()
updateUsedControlWires f = do
s <- getExpState
let c = f $ usedControlWires s
c `seq` setExpState (s { usedControlWires = c } )
return ()
updateUsedNotWires :: (UsedWire -> UsedWire) -> EvalCirc ()
updateUsedNotWires f = do
s <- getExpState
let c = f $ usedNotWires s
c `seq` setExpState (s { usedNotWires = c } )
return ()
updateOutWires :: ([Wire] -> [Wire]) -> EvalCirc ()
updateOutWires f = do
s <- getExpState
let c = f $ outWires s
c `seq` setExpState (s { outWires = c } )
return ()
addToSkipGates :: GateId -> Gate -> EvalCirc ()
addToSkipGates id g = do
s <- getExpState
let c = IM.insert id g (gates_to_skip s)
c `seq` setExpState (s {gates_to_skip = c} )
return ()
sendEndOfTime :: Gate -> EvalCirc ()
sendEndOfTime g = do
s <- getExpState
changeFuture ((future s) ++ [g])
return ()
shiftGate :: Gate -> GateId -> EvalCirc ()
shiftGate g x = do
s <- getExpState
let (!head, !tail) = splitAt x (future s)
let z = head ++ [g] ++ tail
z `Seq.deepseq` changeFuture z
return ()
pairEqualExp :: (IM.IntMap [Exp]) -> (IM.IntMap [Exp]) -> [Wire] -> [(Wire,Wire)]
pairEqualExp m1 m2 ws =
L.map fst $ L.filter aux $ L.zip pair_ws (L.map value pair_ws)
where
all_pairs l = [(x,y) | x <- l, y <- l]
pair_ws = all_pairs ws
value (x,y) = (m2 IM.! x, m1 IM.! x, m1 IM.! y)
aux ((_,_),(a,b,c)) = a == b && b == c
pruneListExp :: Int -> S.Set (Exp,Int) -> S.Set (Exp,Int)
pruneListExp n l = S.filter (\x -> snd x <= n) l
stepEvalCirc :: EvalCirc Bool
stepEvalCirc = do
m_before <- getExpMap
trace ("the state of the system is " ++ (show $ m_before)) $ return ()
s <- getExpState
if ((gateId s) `mod` 1000 == 0) then trace ("Timestamp... " ++ (show (gateId s))) (return ()) else return ()
s <- getExpState
trace ("outside wires " ++ (show $ outWires s)) $ return ()
maybe_g <- pullNewGate
trace ("pulled new gate " ++ (show maybe_g)) $ return ()
s <- getExpState
case maybe_g of
Nothing -> return False
Just g -> do
m_before <- getExpMap
let m_after = expEvalGate m_before g
case g of
NoOp -> error "stepEvalCirc cannot deal with NoOp"
Init b w | not ((IM.member w $ usedNotWires s) || (IM.member w $ usedControlWires s) || L.elem w (outWires s))-> do
trace "got an orphan init, removing it" $ return ()
storeOldGate NoOp
incrGateId
removeFromAllWiresInCirc w
return True
Init _ _ -> do
trace "got a regular init" $ return ()
storeOldGate g
setExpMap m_after
incrGateId
return True
Cnot w _ | not $ S.null $ S.intersection (m_before IM.! w) (m_after IM.! w) -> do
trace "got a cnot where no change happened..." $ return ()
trace (show m_before) $ return ()
trace (show m_after) $ return ()
storeOldGate NoOp
incrGateId
return True
Cnot w [] | not (L.elem w $ outWires s) -> do
trace "got a not-gate that can be removed..." $ return ()
s <- getExpState
changeFuture $ L.map (flipCtl w) $ future s
s <- getExpState
trace (show $ future s) $ return ()
storeOldGate NoOp
incrGateId
return True
Cnot w ctls | otherwise -> do
trace "got a general cnot" $ return ()
trace ("state after the gate is " ++ (show m_after)) $ return ()
allWs <- getAllWiresInCirc
s <- getExpState
let my_elem x = not (L.elem x $ outWires s)
let all_ws = IS.toAscList $ IS.filter future_ctl $
IS.filter (\x -> my_elem x) $
IS.filter (\x -> not $ S.null $
S.intersection (m_after IM.! x)
(m_after IM.! w)) $
IS.filter (w /=) allWs
where
future_ctl x =
(lastUsedWire (usedNotWires s) x) <= gateId s
&&
(lastUsedWire (usedNotWires s) w) <= gateId s
let all_ws_neg = IS.toAscList $ IS.filter future_ctl $
IS.filter (\x -> not (L.elem x $ outWires s)) $
IS.filter (\x -> not $ S.null $
S.intersection (m_after IM.! x)
(S.map (\(e,i) -> (exp_not e, i)) (m_after IM.! w))) $
IS.filter (w /=) $ IS.fromList $ L.map fst ctls
where
future_ctl x =
(lastUsedWire (usedNotWires s) x) <= gateId s
&&
(lastUsedWire (usedNotWires s) w) <= gateId s
trace ("List of outside wires: " ++ (show $ outWires s)) (return ())
trace ("List of available wires: " ++ (show all_ws)) (return ())
trace ("List of available wires with neg: " ++ (show all_ws_neg)) (return ())
case all_ws of
[] -> do
case all_ws_neg of
[] -> do
s <- getExpState
let getOlderCnot w = case (do set <- IM.lookup w (usedNotWires s); IS.lookupLT (gateId s) set) of
Nothing -> Nothing
Just g' ->
case ((past s) !! ((gateId s) - g' - 1)) of
Cnot _ [ctl] -> Just (g',ctl)
_ -> Nothing
let getOlderCnot_actOnCtls w1 [(w,b)] = do
other_ctl <- getOlderCnot w1
other_ctl `seq` return ((w,b),other_ctl)
getOlderCnot_actOnCtls _ _ = Nothing
let retrieveHiddenCnot w1 ctls = do
((w2,b2),(g',(w3,b3))) <- getOlderCnot_actOnCtls w1 ctls
if (w2 == w3) then Nothing else return ()
let m = m_after
if (S.null $ S.intersection
(S.fromList [exp_xor x y | (x,_) <- S.toList (m IM.! w2), (y,_) <- S.toList (m IM.! w3)])
(S.fromList [x | (x,_) <- S.toList (m IM.! w1)]))
then Nothing
else if ((not (L.elem w2 $ outWires s))
&&
(lastUsedWire (usedNotWires s) w2) <= gateId s
&&
(lastUsedWire (usedControlWires s) w2) <= gateId s)
then Just ((w2,b2),(w3,b3))
else if ((not (L.elem w3 $ outWires s))
&&
(lastUsedWire (usedNotWires s) w3) <= g'
&&
(lastUsedWire (usedControlWires s) w3) <= g')
then Just ((w3,b3),(w2,b2))
else Nothing
case retrieveHiddenCnot w ctls of
Just ((w2,b2),(w3,b3)) ->
do
trace "found one hidden copy-cat" $ return ()
updateOutWires $ map (\x -> if x == w then w2 else x)
(gsModifCtls,gsModifNots) <- updateFuture $ moveWire w w2
trace ("moving " ++ (show w) ++ " to " ++ (show w2)) $ return ()
trace (show gsModifCtls) $ return ()
trace (show gsModifNots) $ return ()
s <- getExpState
trace ("before: usedNotWire = " ++ (show $ usedNotWires s)) $ return ()
updateUsedControlWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.union gs gsModifCtls
Nothing -> Just gsModifCtls) w2 $
IM.update (\gs -> Just $ IS.difference gs gsModifCtls) w c
updateUsedControlWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w2 c
updateUsedControlWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.insert (gateId s) gs
Nothing -> Just $ IS.singleton (gateId s)) w3 c
updateUsedNotWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.union gs gsModifNots
Nothing -> Just gsModifNots) w2 $
IM.update (\gs -> Just $ IS.difference gs gsModifNots) w c
updateUsedNotWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w $
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.insert (gateId s) gs
Nothing -> Just $ IS.singleton (gateId s)) w2 c
s <- getExpState
trace ("after: usedNotWire = " ++ (show $ usedNotWires s)) $ return ()
setExpMap $ IM.insert w (m_before IM.! w) $
IM.insert w2 (m_after IM.! w) m_after
storeOldGate $ Cnot w2 [(w3,True)]
incrGateId
return True
_ ->
do
let mw = m_after IM.! w
f <- if ((S.foldl' (\a (_,i) -> min a i) 3 mw) <= 1)
then return id
else do
v <- newFreshVar
return (S.insert (exp_var $ fromIntegral v, 1))
setExpMap $ IM.adjust (\a -> pruneListExp 3 a) w $
IM.adjust f w m_after
storeOldGate g
incrGateId
return True
(w':_) -> do
s <- getExpState
updateOutWires $ map (\x -> if x == w then w' else x)
s <- getExpState
trace (show $ future s) $ return ()
(gsModifCtls,_) <- updateFuture $ moveWireFlip w w'
expMap <- getExpMap
setExpMap $ IM.insert w (m_before IM.! w) $
IM.insert w' (S.map (\(e,i) -> (exp_not e,i)) (expMap IM.! w')) expMap
trace ("moving " ++ (show w) ++ " to " ++ (show w')) $ return ()
trace (show gsModifCtls) $ return ()
s <- getExpState
trace (show $ future s) $ return ()
s <- getExpState
updateUsedControlWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.union gs gsModifCtls
Nothing -> Just gsModifCtls) w' $
IM.update (\gs -> Just $ IS.difference gs gsModifCtls) w c
updateUsedNotWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w c
storeOldGate (Cnot w' [])
incrGateId
return True
(w':_) -> do
s <- getExpState
updateOutWires $ map (\x -> if x == w then w' else x)
s <- getExpState
trace (show $ future s) $ return ()
trace ("usedNotWire = " ++ (show $ usedNotWires s)) $ return ()
(gsModifCtls,_) <- updateFuture $ moveWire w w'
trace ("moving " ++ (show w) ++ " to " ++ (show w')) $ return ()
trace (show gsModifCtls) $ return ()
s <- getExpState
trace (show $ future s) $ return ()
s <- getExpState
updateUsedControlWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.union gs gsModifCtls
Nothing -> Just gsModifCtls
) w' $
IM.update (\gs -> Just $ IS.difference gs gsModifCtls) w c
updateUsedNotWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w c
storeOldGate NoOp
incrGateId
return True
stepSwapCirc :: EvalCirc Bool
stepSwapCirc = do
s <- getExpState
case (IM.lookup (gateId s) (gates_to_skip s)) of
Just g -> do
storeOldGate g
incrGateId
return True
Nothing -> do
maybe_g <- pullNewGate
trace ("pulled new gate " ++ (show maybe_g)) $ return ()
s <- getExpState
if ((gateId s) `mod` 1000 == 0) then trace ("Timestamp (swap)... " ++ (show (gateId s))) (return ()) else return ()
case maybe_g of
Nothing -> return False
Just g@(Cnot w1 [(w2,b2)]) | IM.notMember (gateId s) (gates_to_skip s) -> do
trace ("got a cnot to analyze " ++ (show $ gateId s) ++ " " ++ (show $ gates_to_skip s)) $ return ()
let id = min (nextUsedGate (usedNotWires s) (gateId s) (1 + sizeCirc s) w2) $
(nextUsedGate (usedControlWires s) (gateId s) (1 + sizeCirc s) w1)
trace ("found id = " ++ (show id)) $ return ()
if ( id > 1 + gateId s )
then do
trace ("can be shifted to " ++ (show (id - 1))) $ return ()
addToSkipGates (id - 1) g
s <- getExpState
trace (show $ future s) $ return ()
updateUsedControlWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w2 c
updateUsedNotWires $ \c ->
IM.update (\gs -> Just $ IS.delete (gateId s) gs) w1 c
updateUsedNotWires $
IM.map $ IS.map $ \x -> if (x <= gateId s) || (x >= id) then x
else x - 1
updateUsedControlWires $
IM.map $ IS.map $ \x -> if (x <= gateId s) || (x >= id) then x
else x - 1
s <- getExpState
let z = IM.mapKeys (\x -> if (x <= gateId s) || (x >= id) then x
else x - 1) (gates_to_skip s) in
z `seq` setExpState (s { gates_to_skip = z} )
updateUsedControlWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.insert (id - 1) gs
Nothing -> Just $ IS.singleton (id - 1)) w2 c
updateUsedNotWires $ \c ->
IM.alter (\maybe_gs -> case maybe_gs of
Just gs -> Just $ IS.insert (id - 1) gs
Nothing -> Just $ IS.singleton (id - 1)) w1 c
else do
trace "cannot be shifted" $ return ()
storeOldGate g
incrGateId
return True
Just g -> do
trace ("got a random " ++ (show g)) $ return ()
storeOldGate g
incrGateId
return True
stepSwapCirc_simple :: EvalCirc Bool
stepSwapCirc_simple = do
maybe_g <- pullNewGate
trace ("pulled new gate " ++ (show maybe_g)) $ return ()
s <- getExpState
case maybe_g of
Nothing -> return False
Just g | (gateId s) == (length $ past s) + (length $ future s) -> do
storeOldGate g
return False
Just g@(Cnot w1 [(w2,b2)]) |
(lastUsedWire (usedNotWires s) w2) <= gateId s &&
(lastUsedWire (usedNotWires s) w1) <= gateId s &&
(lastUsedWire (usedControlWires s) w1) <= gateId s -> do
trace "got a cnot that can be sent to the end" $ return ()
sendEndOfTime g
incrGateId
return True
Just g -> do
storeOldGate g
incrGateId
return True
runWhile :: Monad m => (a -> Bool) -> m a -> m ()
runWhile f c = do
r <- c
if f r then runWhile f c else return ()
stripNoOp :: [Gate] -> [Gate]
stripNoOp = L.filter (/= NoOp)
alg_simplify :: ([Gate],[Wire]) -> ([Gate],[Wire])
alg_simplify (gs,out) = (stripNoOp gs',out')
where
gs' = (reverse $ past s) ++ (future s)
out' = outWires s
ws_in = getAllWires gs
s = runEvalCirc ws_in out gs $ trace "Starting new circuit!" (runWhile id stepEvalCirc)
alg_swap :: ([Gate],[Wire]) -> ([Gate],[Wire])
alg_swap (gs,out) = (stripNoOp gs',out')
where
gs' = (reverse $ past s) ++ (future s)
out' = outWires s
ws_in = getAllWires gs
s = runEvalCirc ws_in out gs $ trace "Starting new circuit!" (runWhile id stepSwapCirc)
alg_swap_simple :: ([Gate],[Wire]) -> ([Gate],[Wire])
alg_swap_simple (gs,out) = (stripNoOp gs',out')
where
gs' = (reverse $ past s) ++ (future s)
out' = outWires s
ws_in = getAllWires gs
s = runEvalCirc ws_in out gs $ trace "Starting new circuit!" (runWhile id stepSwapCirc_simple)
is_equal_list :: Eq a => [a] -> [a] -> Int -> (Int,Bool)
is_equal_list [] [] n = (n,True)
is_equal_list (h1:t1) (h2:t2) n | h1 == h2 = is_equal_list t1 t2 (n+1)
is_equal_list t1 t2 n = (n + max (length t1) (length t2),False)
get_list_init :: [Gate] -> [Wire]
get_list_init ((Init _ w):gs) = w:(get_list_init gs)
get_list_init (g:gs) = get_list_init gs
get_list_init [] = []
simplRec' :: ([Gate],[Wire]) -> ([Gate],[Wire])
simplRec' (l,output) = trace (show (l,output)) $
let (l',output') = alg_simplify (l, output) in
let (n,b) = is_equal_list l l' 0 in
if b then (l,output)
else trace (show n) simplRec' $ suppressGarbageGates (l',output')
simplRec :: ([Gate],[Wire]) -> ([Gate],[Wire])
simplRec (l1,o1) =
let (l3,o3) = simplRec' $ alg_swap (l1,o1) in
let (n,b) = is_equal_list l1 l3 0 in
if b then (l3,o3)
else trace "Swapping!" $ simplRec $ (l3,o3)