{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Libraries/QuipperASCIIParser/CircInfo.hs" #-}
module Quipper.Libraries.QuipperASCIIParser.CircInfo where
import Quipper.Libraries.QuipperASCIIParser.Parse (GatePlus (..),parse_ascii_line)
import Quipper
import Quipper.Internal.Circuit
import Quipper.Internal.Monad
import Control.Monad.State
import Data.Map (Map)
import qualified Data.Map as Map
data Sub = Sub {
name :: String,
shape :: String,
controllable :: ControllableFlag,
inputs :: [(Wire,Wiretype)],
outputs :: [(Wire,Wiretype)],
circuit :: [Gate]
}
new_subroutine :: String -> Sub
new_subroutine n = Sub {name = n, shape = "", controllable = NoCtl, inputs = [], outputs = [], circuit = []}
data CircInfoState = CircInfoState {
used_wires :: Map Wire (Maybe Wiretype),
defined_inputs :: [(Wire,Wiretype)],
undefined_inputs :: [(Wire,Maybe Wiretype)],
defined_outputs :: Maybe [(Wire,Wiretype)],
current_subroutine :: [Sub]
}
empty_circinfostate :: CircInfoState
empty_circinfostate = CircInfoState { used_wires = Map.empty, defined_inputs = [],
undefined_inputs = [], defined_outputs = Nothing, current_subroutine = [] }
type CircInfo a = State CircInfoState a
add_wire_inputs :: [(Wire,Wiretype)] -> CircInfo ()
add_wire_inputs ws = do
state <- get
let ms = current_subroutine state
case ms of
[] -> do
let ins = defined_inputs state
let wires = used_wires state
put (state {defined_inputs = ws ++ ins,
used_wires = Map.fromList (map (\(w,wt) -> (w,Just wt)) ws)})
(sub:rest) -> do
let ins = inputs sub
let sub' = sub {inputs = ins ++ ws}
put (state {current_subroutine = (sub':rest)})
add_wire_outputs :: [(Wire,Wiretype)] -> CircInfo ()
add_wire_outputs ws = do
state <- get
let ms = current_subroutine state
case ms of
[] -> do
case defined_outputs state of
Nothing -> put (state {defined_outputs = Just ws})
Just outs -> put (state {defined_outputs = Just (outs ++ ws)})
(sub:rest) -> do
let outs = outputs sub
let sub' = sub {outputs = outs ++ ws}
put (state {current_subroutine = (sub':rest)})
check_input :: Map Wire (Maybe Wiretype) -> (Wire,Maybe Wiretype) -> Bool
check_input wires (w,wt) = case Map.lookup w wires of
Just wt -> False
Nothing -> True
check_inputs :: [(Wire,Maybe Wiretype)] -> Map Wire (Maybe Wiretype) -> [(Wire,Maybe Wiretype)]
check_inputs ins wires = filter (check_input wires) ins
add_gate :: Gate -> [(Wire,Wiretype)] -> CircInfo CircInfoOut
add_gate gate ctws = do
state <- get
let ms = current_subroutine state
case ms of
[] -> do
let wires = used_wires state
let ui = undefined_inputs state
let (ws_in,ws_out) = gate_arity gate
let ws = wirelist_of_gate gate
let ws_unchecked = filter (\w -> (notElem w (map fst ws_in))
&& (notElem w (map fst ws_out))
&& (notElem w (map fst ctws))) ws
let ws_in' = (map (\(w,wt) -> (w, Just wt)) (ws_in ++ ctws))
++ (zip ws_unchecked (repeat Nothing))
let ui' = ui ++ check_inputs ws_in' wires
let wires' = Map.union wires (Map.fromList (ws_in'
++ (map (\(w,wt) -> (w, Just wt)) ws_out)))
put (state {used_wires = wires',undefined_inputs = ui'})
return (Lazy gate)
(sub:rest) -> do
let gates = circuit sub
let gates' = gate:gates
let sub' = sub {circuit = gates'}
put (state {current_subroutine = (sub':rest)})
return Empty
enter_subroutine :: String -> CircInfo ()
enter_subroutine name = do
state <- get
let ms = current_subroutine state
put (state {current_subroutine = ((new_subroutine name):ms)})
add_subroutine_shape :: String -> CircInfo ()
add_subroutine_shape s = do
state <- get
let ms = current_subroutine state
case ms of
[] -> error "Shape given outside of Subroutine Definition"
(sub:rest) -> put (state {current_subroutine = ((sub {shape = s}):rest)})
set_controllable :: ControllableFlag -> CircInfo ()
set_controllable val = do
state <- get
let ms = current_subroutine state
case ms of
[] -> error "Controllable not in Subroutine Definition"
(sub:rest) -> put (state {current_subroutine = ((sub {controllable = val}):rest)})
data CircInfoOut = Empty | Lazy Gate | SubDef (BoxId,Sub)
isGate :: CircInfoOut -> Bool
isGate (Lazy _) = True
isGate _ = False
isSub :: CircInfoOut -> Bool
isSub (SubDef _) = True
isSub _ = False
exit_subroutine :: CircInfo CircInfoOut
exit_subroutine = do
state <- get
let ms = current_subroutine state
case ms of
[] -> return Empty
(sub:rest) -> do
let n = name sub
let s = shape sub
put (state {current_subroutine = rest})
return (SubDef ((BoxId n s),sub))
do_gate :: GatePlus -> CircInfo CircInfoOut
do_gate (G gate wts) = add_gate gate wts
do_gate (I ws) = add_wire_inputs ws >> return Empty
do_gate (O ws) = do
add_wire_outputs ws
exit_subroutine
do_gate EmptyLine = return Empty
do_gate (CommentLine comment) = return Empty
do_gate (SubroutineName name) = enter_subroutine name >> return Empty
do_gate (SubroutineShape shape) = add_subroutine_shape shape >> return Empty
do_gate (Controllable b) = set_controllable b >> return Empty
run_ascii_line :: String -> CircInfo CircInfoOut
run_ascii_line s = case parse_ascii_line s of
Nothing -> error ("unrecognized line: " ++ show s)
Just p -> do_gate p
run_ascii_lines :: [String] -> (Maybe [(Wire,Wiretype)],CircInfo [CircInfoOut])
run_ascii_lines [] = (Nothing,return [])
run_ascii_lines [f] = case parse_ascii_line f of
Just (I ws) -> (Just ws, return [])
_ -> (Nothing, run_ascii_line f >>= \x -> return [x])
run_ascii_lines (f:s) =
case parse_ascii_line f of
Just (I ws) -> (Just ws, mapM run_ascii_line s)
_ -> (Nothing, mapM run_ascii_line (f:s))
run :: CircInfo [CircInfoOut] -> ([Gate],Map BoxId Sub,CircInfoState)
run f = (gs, subs, cis)
where
gs = [x | Lazy x <- filter isGate ci_outs]
subs = Map.fromList [x | SubDef x <- filter isSub ci_outs]
(ci_outs,cis) = runState f empty_circinfostate