{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DoAndIfThenElse #-}
module Quipper.Internal.Printing where
import Quipper.Utils.Auxiliary
import Quipper.Utils.Preview
import Quipper.Internal.Circuit
import Quipper.Internal.Generic
import Quipper.Internal.Monad
import Quipper.Internal.QData
import Prelude
import Text.Printf
import Data.Char(isSpace)
import Data.List
import Data.Maybe
import Control.Monad(when)
import Graphics.EasyRender
import System.IO
import System.Directory
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Map.Strict as MapS
import qualified Data.IntMap as IntMap
self_inverse :: String -> [Wire] -> [Wire] -> Bool
self_inverse "X" [q] [] = True
self_inverse "Y" [q] [] = True
self_inverse "Z" [q] [] = True
self_inverse "H" [q] [] = True
self_inverse "not" [q] [] = True
self_inverse "swap" [q1,q2] [] = True
self_inverse "W" [q1,q2] [] = True
self_inverse _ _ _ = False
type WireTypeMap = IntMap.IntMap Wiretype
track_wiretype :: WireTypeMap -> Gate -> WireTypeMap
track_wiretype wtm (QInit _ w _ ) = IntMap.insert w Qbit wtm
track_wiretype wtm (CInit _ w _ ) = IntMap.insert w Cbit wtm
track_wiretype wtm (QMeas w ) = IntMap.insert w Cbit wtm
track_wiretype wtm (CGate _ w _ _) = IntMap.insert w Cbit wtm
track_wiretype wtm (CGateInv _ w _ _) = IntMap.insert w Cbit wtm
track_wiretype wtm (QPrep w _ ) = IntMap.insert w Qbit wtm
track_wiretype wtm (QUnprep w _ ) = IntMap.insert w Cbit wtm
track_wiretype wtm (Subroutine boxid inv ws1 a1 ws2 a2 c ncf scf rep) = a2 `IntMap.union` wtm
track_wiretype wtm _ = wtm
ascii_of_boxid :: BoxId -> String
ascii_of_boxid (BoxId name shape) = show name ++ ", shape " ++ show shape
ascii_render_control :: WireTypeMap -> Signed Wire -> String
ascii_render_control wtm (Signed w b) =
(if b then "+" else "-") ++ show w ++ ascii_render_control_type wtype
where
wtype = if (w `IntMap.member` wtm) then (wtm IntMap.! w) else Qbit
ascii_render_control_type Qbit = ""
ascii_render_control_type Cbit = "c"
ascii_render_controls :: WireTypeMap -> Controls -> String
ascii_render_controls wtm c =
string_of_list " with controls=[" ", " "]" "" (ascii_render_control wtm) c
ascii_render_nocontrolflag :: NoControlFlag -> String
ascii_render_nocontrolflag False = ""
ascii_render_nocontrolflag True = " with nocontrol"
ascii_render_gate :: WireTypeMap -> Gate -> String
ascii_render_gate wtm (QGate "trace" _ _ _ _ _) = ""
ascii_render_gate wtm (QGate name inv ws1 ws2 c ncf) =
"QGate[" ++ show name ++ "]"
++ optional inv' "*"
++ (string_of_list "(" "," ")" "()" show ws1)
++ (string_of_list "; [" "," "]" "" show ws2)
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
where
inv' = inv && not (self_inverse name ws1 ws2)
ascii_render_gate wtm (QRot name inv theta ws1 ws2 c ncf) =
"QRot[" ++ show name ++ "," ++ (show theta) ++ "]"
++ optional inv "*"
++ (string_of_list "(" "," ")" "()" show ws1)
++ (string_of_list "; [" "," "]" "" show ws2)
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (GPhase t ws c ncf) =
"GPhase() with t=" ++ show t
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
++ string_of_list " with anchors=[" ", " "]" "" show ws
ascii_render_gate wtm (CNot w c ncf) =
"CNot(" ++ show w ++ ")"
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (CGate n w c ncf) =
"CGate[" ++ show n ++ "]" ++ (string_of_list "(" "," ")" "()" show (w:c))
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (CGateInv n w c ncf) =
"CGate[" ++ show n ++ "]" ++ "*" ++ (string_of_list "(" "," ")" "()" show (w:c))
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (CSwap w1 w2 c ncf) =
"CSwap(" ++ show w1 ++ "," ++ show w2 ++ ")"
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (QPrep w ncf) =
"QPrep(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (QUnprep w ncf) =
"QUnprep(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (QInit b w ncf) =
"QInit" ++ (if b then "1" else "0") ++ "(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (CInit b w ncf) =
"CInit" ++ (if b then "1" else "0") ++ "(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (QTerm b w ncf) =
"QTerm" ++ (if b then "1" else "0") ++ "(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (CTerm b w ncf) =
"CTerm" ++ (if b then "1" else "0") ++ "(" ++ show w ++ ")"
++ ascii_render_nocontrolflag ncf
ascii_render_gate wtm (QMeas w) =
"QMeas(" ++ show w ++ ")"
ascii_render_gate wtm (QDiscard w) =
"QDiscard(" ++ show w ++ ")"
ascii_render_gate wtm (CDiscard w) =
"CDiscard(" ++ show w ++ ")"
ascii_render_gate wtm (DTerm b w) =
"DTerm" ++ (if b then "1" else "0") ++ "(" ++ show w ++ ")"
ascii_render_gate wtm (Subroutine boxid inv ws1 a1 ws2 a2 c ncf scf rep) =
"Subroutine" ++ show_rep ++ "[" ++ ascii_of_boxid boxid ++ "]"
++ optional inv "*"
++ " "
++ (string_of_list "(" "," ")" "()" show ws1)
++ (string_of_list " -> (" "," ")" "()" show ws2)
++ ascii_render_controls wtm c
++ ascii_render_nocontrolflag ncf
where
show_rep = if rep == RepeatFlag 1 then "" else "(x" ++ show rep ++ ")"
ascii_render_gate wtm (Comment s inv ws) =
"Comment[" ++ show s ++ "]"
++ optional inv "*"
++ (string_of_list "(" ", " ")" "()" (\(w,s) -> show w ++ ":" ++ show s) ws)
ascii_render_gatelist :: WireTypeMap -> [Gate] -> String
ascii_render_gatelist wtm [] = ""
ascii_render_gatelist wtm (g:gs) =
(ascii_render_gate wtm g) ++ "\n" ++
(ascii_render_gatelist (track_wiretype wtm g) gs)
where
ascii_render_wiretype :: Wiretype -> String
ascii_render_wiretype Qbit = "Qbit"
ascii_render_wiretype Cbit = "Cbit"
ascii_render_typeas :: (Wire, Wiretype) -> String
ascii_render_typeas (w, t) =
show w ++ ":" ++ ascii_render_wiretype t
ascii_render_arity :: String -> Arity -> String
ascii_render_arity title a =
title ++ ": " ++ (string_of_list "" ", " "" "none" ascii_render_typeas (IntMap.toList a)) ++ "\n"
ascii_render_oarity :: String -> [Wire] -> Arity -> String
ascii_render_oarity title ws a =
title ++ ": "
++ (string_of_list "" ", " "" "none" ascii_render_typeas tas_list) ++ "\n"
where
tas_list = [ (w, a IntMap.! w) | w <- ws ]
ascii_of_ocircuit :: OCircuit -> String
ascii_of_ocircuit ocircuit =
(ascii_render_oarity "Inputs" win a1) ++
(ascii_render_gatelist a1 gl) ++
(ascii_render_oarity "Outputs" wout a2)
where
OCircuit (win, circuit, wout) = ocircuit
(a1, gl, a2, _) = circuit
ascii_of_circuit :: Circuit -> String
ascii_of_circuit circuit = ascii_of_ocircuit ocircuit where
ocircuit = OCircuit (w_in, circuit, w_out)
(a1, _, a2, _) = circuit
w_in = IntMap.keys a1
w_out = IntMap.keys a2
ascii_of_bcircuit :: BCircuit -> String
ascii_of_bcircuit (c,s) =
(ascii_of_circuit c) ++
(concat $ map ascii_of_subroutine (Map.toList s)) ++
"\n"
ascii_of_subroutine :: (BoxId, TypedSubroutine) -> String
ascii_of_subroutine (boxid, TypedSubroutine ocirc input_strux output_strux ctrble) =
"\n"
++ "Subroutine: " ++ show name ++ "\n"
++ "Shape: " ++ show shape ++ "\n"
++ "Controllable: " ++ (case ctrble of {AllCtl -> "yes"; NoCtl -> "no"; OnlyClassicalCtl -> "classically"}) ++ "\n"
++ ascii_of_ocircuit ocirc
where
BoxId name shape = boxid
prompt :: String -> IO ()
prompt s = do
putStr s
hFlush stdout
getBit :: IO Bool
getBit = do
c <- getChar
case c of
'0' -> return False
'1' -> return True
'#' -> do
getLine
getBit
c | isSpace c -> getBit
c -> do
getLine
prompt $ "# Expecting 0 or 1. Please try again: "
getBit
run_readwrite_ascii :: WireTypeMap -> ReadWrite a -> Namespace -> IO (a, Namespace)
run_readwrite_ascii wtm (RW_Return a) ns = return (a, ns)
run_readwrite_ascii wtm (RW_Write gate comp) ns = do
putStrLn (ascii_render_gate wtm gate)
run_readwrite_ascii (track_wiretype wtm gate) comp ns
run_readwrite_ascii wtm (RW_Read w cont) ns = do
prompt $ "# Value of wire " ++ show w ++ ": "
bool <- getBit
putStrLn $ "# Value: " ++ show bool
run_readwrite_ascii wtm (cont bool) ns
run_readwrite_ascii wtm (RW_Subroutine name subroutine comp) ns = do
let !ns' = map_provide name subroutine ns
run_readwrite_ascii wtm comp ns'
print_dbcircuit_ascii :: ErrMsg -> DBCircuit a -> IO ()
print_dbcircuit_ascii _ (a0, comp) = do
hSetBuffering stdout LineBuffering
putStr (ascii_render_arity "Inputs" a0)
((a1, _, _),ns) <- run_readwrite_ascii a0 comp namespace_empty
putStr (ascii_render_arity "Outputs" a1)
sequence_ [ putStr $ ascii_of_subroutine subr | subr <- Map.toList ns ]
putStr "\n"
white :: Color
white = Color_Gray 1.0
black :: Color
black = Color_Gray 0.0
data FormatStyle = FormatStyle {
renderformat :: RenderFormat,
backgroundcolor :: Color,
foregroundcolor :: Color,
linewidth :: Double,
coffs :: Double,
dotradius :: Double,
oplusradius :: Double,
xoff :: Double,
gatepad :: Double,
gateheight :: Double,
crossradius :: Double,
stringbase :: Double,
barwidth :: Double,
barheight :: Double,
dwidth :: Double,
dheight :: Double,
maxgatelabelwidth :: Double,
maxlabelwidth :: Double,
maxnumberwidth :: Double,
gatefont :: Font,
commentfont :: Font,
commentcolor :: Color,
labelfont :: Font,
labelcolor :: Color,
numberfont :: Font,
numbercolor :: Color,
subroutineshape :: Bool
} deriving Show
defaultStyle :: RenderFormat -> FormatStyle
defaultStyle rf = FormatStyle {
renderformat = rf,
backgroundcolor = white,
foregroundcolor = black,
linewidth = 0.02,
coffs = 0.03,
dotradius = 0.15,
oplusradius = 0.25,
xoff = 1.5,
gatepad = 0.3,
gateheight = 0.8,
crossradius = 0.2,
stringbase = 0.25,
barwidth = 0.1,
barheight = 0.5,
dwidth = 0.3,
dheight = 0.4,
maxgatelabelwidth = 1.1,
maxlabelwidth = 0.7,
maxnumberwidth = 0.7,
gatefont = Font TimesRoman 0.5,
commentfont = Font TimesRoman 0.3,
commentcolor = Color_RGB 1 0.2 0.2,
labelfont = Font TimesRoman 0.3,
labelcolor = Color_RGB 0 0 1,
numberfont = Font Helvetica 0.5,
numbercolor = Color_RGB 0 0.7 0,
subroutineshape = True
}
pdf :: FormatStyle
pdf = defaultStyle Format_PDF
eps :: FormatStyle
eps = defaultStyle (Format_EPS 1)
ps :: FormatStyle
ps = defaultStyle (Format_PS)
ps_escape :: String -> String
ps_escape [] = []
ps_escape ('\\' : t) = '\\' : '\\' : ps_escape t
ps_escape ('(' : t) = '\\' : '(' : ps_escape t
ps_escape (')' : t) = '\\' : ')' : ps_escape t
ps_escape (h : t) = h : ps_escape t
string_of_boxid :: BoxId -> String
string_of_boxid (BoxId name shape) = name ++ ", shape " ++ shape
assign_x_coordinates :: FormatStyle -> [Gate] -> X -> (X, [(Gate, X)])
assign_x_coordinates fs gs x0 =
let ((x,ws), xgs) = mapAccumL (\ (x, ws) g ->
let merge = case (g, wirelist_of_gate g) of
(Comment _ _ _, _) -> Nothing
(_, [w]) -> Just w
(_, _) -> Nothing
in
case merge of
Just w ->
if not (w `elem` ws) then
((x, w:ws), (g, x))
else
((x + (xoff fs), [w]), (g, x + (xoff fs)))
_ ->
if ws == [] then
((x + (xoff fs), []), (g, x))
else
((x + 2.0 * (xoff fs), []), (g, x + (xoff fs)))
) (x0, []) gs
in
if ws == [] then
(x, xgs)
else
(x + (xoff fs), xgs)
type Xarity = Map Wire (Wiretype, X)
update_xarity :: Xarity -> Gate -> X -> (Xarity, Xarity)
update_xarity xarity gate x =
let (win, wout) = gate_arity gate
safe_lookup xarity w =
case Map.lookup w xarity of
Just x -> x
Nothing -> (Qbit, x)
(win', wout') = (win \\ wout, wout \\ win)
xarity_term = foldl (\xar (w,_) -> Map.insert w (xarity `safe_lookup` w) xar) Map.empty win'
xarity_cont = foldl (\xar (w,_) -> Map.delete w xar) xarity win'
xarity_new = foldl (\xar (w,t) -> Map.insert w (t,x) xar) xarity_cont wout'
in
(xarity_term, xarity_new)
render_line :: X -> Y -> X -> Y -> Draw ()
render_line x0 y0 x1 y1 | x0 == x1 && y0 == y1 = return ()
render_line x0 y0 x1 y1 = draw_subroutine alt $ do
moveto x0 y0
lineto x1 y1
stroke
where
alt = [custom_ps $ printf "%f %f %f %f line\n" x0 y0 x1 y1]
render_dot :: FormatStyle -> X -> Y -> Draw ()
render_dot fs x y = draw_subroutine alt $ do
arc x y (dotradius fs) 0 360
fill (foregroundcolor fs)
where
alt = [custom_ps $ printf "%f %f dot\n" x y]
render_circle :: FormatStyle -> X -> Y -> Draw ()
render_circle fs x y = draw_subroutine alt $ do
arc x y (dotradius fs) 0 360
fillstroke (backgroundcolor fs)
where
alt = [custom_ps $ printf "%f %f circ\n" x y]
render_not :: FormatStyle -> X -> Y -> Draw ()
render_not fs x y = draw_subroutine alt $ do
arc x y (oplusradius fs) 0 360
fillstroke (backgroundcolor fs)
render_line (x-(oplusradius fs)) y (x+(oplusradius fs)) y
render_line x (y-(oplusradius fs)) x (y+(oplusradius fs))
where
alt = [custom_ps $ printf "%f %f oplus\n" x y]
render_swap :: FormatStyle -> X -> Y -> Draw ()
render_swap fs x y = draw_subroutine alt $ do
render_line (x-(crossradius fs)) (y-(crossradius fs)) (x+(crossradius fs)) (y+(crossradius fs))
render_line (x-(crossradius fs)) (y+(crossradius fs)) (x+(crossradius fs)) (y-(crossradius fs))
where
alt = [custom_ps $ printf "%f %f cross\n" x y]
render_bar :: FormatStyle -> X -> Y -> Draw ()
render_bar fs x y = draw_subroutine alt $ do
rectangle (x - (barwidth fs)/2) (y - (barheight fs)/2) (barwidth fs) (barheight fs)
fill (foregroundcolor fs)
where
alt = [custom_ps $ printf "%f %f bar\n" x y]
render_dbar :: FormatStyle -> X -> Y -> Draw ()
render_dbar fs x y = draw_subroutine alt $ do
block $ do
translate (x+(barwidth fs)/2) y
scale (dwidth fs) (dheight fs)
moveto (-1) (-0.5)
arc_append (-0.5) 0 0.5 (-90) 90
lineto (-1) 0.5
closepath
fill (foregroundcolor fs)
where
alt = [custom_ps $ printf "%f %f dbar\n" x y]
render_init :: FormatStyle -> String -> X -> Y -> Draw ()
render_init fs name x y = draw_subroutine alt $ do
render_bar fs x y
textbox align_right (gatefont fs) (foregroundcolor fs) (x-(xoff fs)/2+(gatepad fs)/2) y (x-(gatepad fs)/2) y (stringbase fs) name
where
alt = [custom_ps $ printf "(%s) %f %f init\n" (ps_escape name) x y]
render_term :: FormatStyle -> String -> X -> Y -> Draw ()
render_term fs name x y = draw_subroutine alt $ do
render_bar fs x y
textbox align_left (gatefont fs) (foregroundcolor fs) (x+(gatepad fs)/2) y (x+(xoff fs)/2-(gatepad fs)/2) y (stringbase fs) name
where
alt = [custom_ps $ printf "(%s) %f %f term\n" (ps_escape name) x y]
render_dterm :: FormatStyle -> String -> X -> Y -> Draw ()
render_dterm fs name x y = draw_subroutine alt $ do
render_dbar fs x y
textbox align_left (gatefont fs) (foregroundcolor fs) (x+(gatepad fs)/2) y (x+(xoff fs)/2-(gatepad fs)/2) y (stringbase fs) name
where
alt = [custom_ps $ printf "(%s) %f %f dterm\n" (ps_escape name) x y]
render_namedgate :: FormatStyle -> String -> InverseFlag -> X -> Y -> Draw ()
render_namedgate fs name inv x y = draw_subroutine alt $ do
rectangle (x-gatewidth/2) (y-(gateheight fs)/2) gatewidth (gateheight fs)
fillstroke (backgroundcolor fs)
textbox align_center (gatefont fs) (foregroundcolor fs) (x-labelwidth/2) y (x+labelwidth/2) y (stringbase fs) name'
where
alt = [custom_ps $ printf "(%s) %f %f gate\n" (ps_escape name') x y]
name' = name ++ optional inv "*"
w = text_width (gatefont fs) name'
labelwidth = min w (maxgatelabelwidth fs)
gatewidth = labelwidth + (gatepad fs)
render_gphasegate :: FormatStyle -> String -> X -> Y -> Draw ()
render_gphasegate fs name x y = draw_subroutine alt $ do
render_circgate fs name x (y-0.5)
where
alt = [custom_ps $ printf "(%s) %f %f gphase\n" (ps_escape name) x y]
render_circgate :: FormatStyle -> String -> X -> Y -> Draw ()
render_circgate fs name x y = draw_subroutine alt $ do
oval x y (0.5*gatewidth) (0.4*(gateheight fs))
fillstroke (backgroundcolor fs)
textbox align_center (gatefont fs) (foregroundcolor fs) (x-labelwidth/2) y (x+labelwidth/2) y (stringbase fs) name
where
alt = [custom_ps $ printf "(%s) %f %f circgate\n" (ps_escape name) x y]
w = text_width (gatefont fs) name
labelwidth = min w (maxgatelabelwidth fs)
gatewidth = labelwidth + (gatepad fs)
render_blankgate :: FormatStyle -> String -> X -> Y -> Draw ()
render_blankgate fs name x y = draw_subroutine alt $ do
rectangle (x-gatewidth/2) (y-(gateheight fs)/2) gatewidth (gateheight fs)
fillstroke (backgroundcolor fs)
where
alt = [custom_ps $ printf "(%s) %f %f box\n" (ps_escape name) x y]
w = text_width (gatefont fs) name
labelwidth = min w (maxgatelabelwidth fs)
gatewidth = labelwidth + (gatepad fs)
render_comment :: FormatStyle -> Bool -> String -> X -> Y -> Y -> Draw ()
render_comment fs center s x y maxh = draw_subroutine alt $ do
textbox align_right (commentfont fs) (commentcolor fs) x (y-maxh) x (y+0.4) b s
where
alt = [custom_ps $ printf "(%s) %f %f %f %f comment\n" (ps_escape s) x y maxh yshift]
b = if center then 0.15 else -0.25
yshift = -b * nominalsize (commentfont fs)
render_label :: FormatStyle -> Bool -> String -> X -> Y -> Draw ()
render_label fs True s x y = draw_subroutine alt $ do
textbox align_center (labelfont fs) (labelcolor fs) (x-(maxlabelwidth fs)) y' (x+(maxlabelwidth fs)) y' (-0.5) s
where
alt = [custom_ps $ printf "(%s) %f %f clabel\n" (ps_escape s) x y']
y' = y + 0.5 * (coffs fs)
render_label fs False s x y = draw_subroutine alt $ do
textbox align_left (labelfont fs) (labelcolor fs) x y' (x+(maxlabelwidth fs)) y' (-0.5) s
where
alt = [custom_ps $ printf "(%s) %f %f rlabel\n" (ps_escape s) x y']
y' = y + 0.5 * (coffs fs)
render_number :: FormatStyle -> Int -> Bool -> X -> Y -> Draw ()
render_number fs i True x y = draw_subroutine alt $ do
textbox align_left (numberfont fs) (numbercolor fs) (x+0.2) y (x+0.2+(maxnumberwidth fs)) y (stringbase fs) (show i)
where
alt = [custom_ps $ printf "(%s) %f %f rnumber\n" (ps_escape (show i)) x y]
render_number fs i False x y = draw_subroutine alt $ do
textbox align_right (numberfont fs) (numbercolor fs) (x-0.2-(maxnumberwidth fs)) y (x-0.2) y (stringbase fs) (show i)
where
alt = [custom_ps $ printf "(%s) %f %f lnumber\n" (ps_escape (show i)) x y]
render_typeas :: FormatStyle -> Map Wire Y -> X -> X -> Wire -> Wiretype -> Draw ()
render_typeas fs ys oldx x w t =
let y = ys Map.! w in
case t of
Qbit -> do
render_line oldx y x y
Cbit -> do
render_line oldx (y + (coffs fs)) x (y + (coffs fs))
render_line oldx (y - (coffs fs)) x (y - (coffs fs))
render_xarity :: FormatStyle -> Map Wire Y -> Xarity -> X -> Draw ()
render_xarity fs ys xarity x = do
sequence_ [ render_typeas fs ys oldx x w t | (w,(t,oldx)) <- Map.toList xarity ]
dshow :: Double -> String
dshow dbl =
if abs dbl < 0.01
then
printf "%.1e" dbl
else
(reverse . strip . reverse) (printf "%.3f" dbl)
where
strip [] = []
strip ('.' : t) = t
strip ('0' : t) = strip t
strip t = t
render_controlwire :: X -> Map Wire Y -> [Wire] -> Controls -> Draw ()
render_controlwire x ys ws c =
case ws of
[] -> return ()
w:ws -> render_line x y0 x y1
where
ymap w = ys Map.! w
y = ymap w
cy = map (\(Signed w _) -> ymap w) c
yy = map (\w -> ymap w) ws
y0 = foldr min y (cy ++ yy)
y1 = foldr max y (cy ++ yy)
render_controlwire_float :: X -> Map Wire Y -> Y -> Controls -> Draw ()
render_controlwire_float x ys y c = render_line x y0 x y1
where
y' = y - 0.5
cy = map (\(Signed w _) -> ys Map.! w) c
y0 = minimum (y':cy)
y1 = maximum (y':cy)
render_controldots :: FormatStyle -> X -> Map Wire Y -> Controls -> Draw ()
render_controldots fs x ys c = do
sequence_ [ renderdot x | x <- c ]
where
renderdot (Signed w True) = render_dot fs x (ys Map.! w)
renderdot (Signed w False) = render_circle fs x (ys Map.! w)
render_multi_gate :: FormatStyle -> X -> Map Wire Y -> String -> InverseFlag -> [Wire] -> Draw ()
render_multi_gate fs x ys name inv [w] =
render_namedgate fs name inv x (ys Map.! w)
render_multi_gate fs x ys name inv ws =
sequence_ [ render_namedgate fs (name ++ " " ++ show i) inv x (ys Map.! a) | (a,i) <- zip ws [1..] ]
render_multi_named_ctrl :: FormatStyle -> X -> Map Wire Y -> [Wire] -> [String] -> Draw ()
render_multi_named_ctrl fs x ys ws names =
sequence_ [ render_circgate fs name x (ys Map.! a) | (a,name) <- IntMap.toList map ]
where
map = IntMap.fromListWith (\x y -> y ++ "," ++ x) (zip ws names)
render_multi_genctrl :: FormatStyle -> X -> Map Wire Y -> [Wire] -> Draw ()
render_multi_genctrl fs x ys ws = render_multi_named_ctrl fs x ys ws names
where
names = map show [1..]
render_ordering :: FormatStyle -> X -> Map Wire Y -> Bool -> [Wire] -> Draw ()
render_ordering fs x ys b ws =
sequence_ [ render_number fs i b x (ys Map.! w) | (w,i) <- numbering ]
where
numbering = zip ws [1..]
render_gate :: FormatStyle -> Gate -> X -> Map Wire Y -> Y -> (Draw (), Draw ())
render_gate fs g x ys maxh =
let ymap w = ys Map.! w
in
case g of
QGate "not" _ [w] [] c ncf -> (s2, t2 >> t3)
where
y = ymap w
s2 = render_controlwire x ys [w] c
t2 = render_controldots fs x ys c
t3 = (render_not fs x y)
QGate "multinot" _ ws [] c ncf -> (s2, t2 >> t3)
where
s2 = render_controlwire x ys ws c
t2 = render_controldots fs x ys c
t3 = sequence_ (map (\w -> (render_not fs x (ymap w))) ws)
QGate "swap" _ [w1,w2] [] c ncf -> (s2, t2 >> t3)
where
y1 = ymap w1
y2 = ymap w2
s2 = render_controlwire x ys [w1,w2] c
t2 = render_controldots fs x ys c
t3 = (render_swap fs x y1) >> (render_swap fs x y2)
QGate "trace" _ _ _ _ _ -> (return (), return ())
QGate name inv ws1 ws2 c ncf -> (s2, t2 >> t3 >> t4)
where
s2 = render_controlwire x ys (ws1 ++ ws2) c
t2 = render_multi_gate fs x ys name inv' ws1
t3 = render_controldots fs x ys c
t4 = render_multi_genctrl fs x ys ws2
inv' = inv && not (self_inverse name ws1 ws2)
QRot name inv theta ws1 ws2 c ncf -> (s2, t2 >> t3 >> t4)
where
s2 = render_controlwire x ys (ws1 ++ ws2) c
t2 = render_multi_gate fs x ys name' inv ws1
t3 = render_controldots fs x ys c
t4 = render_multi_genctrl fs x ys ws2
name' = substitute name '%' (dshow theta)
GPhase t ws c ncf -> (s2, t2 >> t3)
where
y = case (ws, c) of
([], []) -> maximum (0.0 : Map.elems ys)
([], c) -> minimum [ ymap w | Signed w b <- c ]
(ws, c) -> minimum [ ymap w | w <- ws ]
s2 = render_controlwire_float x ys y c
t2 = render_controldots fs x ys c
t3 = (render_gphasegate fs (dshow t) x y)
CNot w c ncf -> (s2, t2 >> t3)
where
y = ymap w
s2 = render_controlwire x ys [w] c
t2 = render_controldots fs x ys c
t3 = (render_not fs x y)
CGate "if" w [a,b,c] ncf -> (s2, t1 >> t3)
where
y = ymap w
s2 = render_controlwire x ys [w,a,b,c] []
t1 = render_multi_named_ctrl fs x ys [a,b,c] ["if", "then", "else"]
t3 = render_namedgate fs ">" False x y
CGateInv "if" w [a,b,c] ncf -> (s2, t1 >> t3)
where
y = ymap w
s2 = render_controlwire x ys [w,a,b,c] []
t1 = render_multi_named_ctrl fs x ys [a,b,c] ["if", "then", "else"]
t3 = render_namedgate fs "<" False x y
CGate name w c ncf -> (s2, t2 >> t3)
where
y = ymap w
s2 = render_controlwire x ys (w:c) []
t2 = render_multi_named_ctrl fs x ys c [ " " | a <- c ]
t3 = render_namedgate fs name False x y
CGateInv name w c ncf -> (s2, t2 >> t3)
where
y = ymap w
s2 = render_controlwire x ys (w:c) []
t2 = render_multi_named_ctrl fs x ys c [ " " | a <- c ]
t3 = render_namedgate fs name True x y
CSwap w1 w2 c ncf -> (s2, t2 >> t3)
where
y1 = ymap w1
y2 = ymap w2
s2 = render_controlwire x ys [w1,w2] c
t2 = render_controldots fs x ys c
t3 = (render_swap fs x y1) >> (render_swap fs x y2)
QPrep w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_namedgate fs "prep" False x y)
QUnprep w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_namedgate fs "unprep" False x y)
QInit b w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_init fs (if b then "1" else "0") x y)
CInit b w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_init fs (if b then "1" else "0") x y)
QTerm b w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_term fs (if b then "1" else "0") x y)
CTerm b w ncf -> (return (), t3)
where
y = ymap w
t3 = (render_term fs (if b then "1" else "0") x y)
QMeas w -> (return (), t3)
where
y = ymap w
t3 = (render_namedgate fs "meas" False x y)
QDiscard w -> (return (), t3)
where
y = ymap w
t3 = (render_bar fs x y)
CDiscard w -> (return (), t3)
where
y = ymap w
t3 = (render_bar fs x y)
DTerm b w -> (return (), t3)
where
y = ymap w
t3 = (render_dterm fs (if b then "1" else "0") x y)
Subroutine boxid inv ws1 a1 ws2 a2 c ncf scf rep -> (s2, t2 >> t3)
where
ws = union ws1 ws2
s2 = render_controlwire x ys ws c
t2 = render_multi_gate fs x ys label inv ws
t3 = render_controldots fs x ys c
show_rep = if rep == RepeatFlag 1 then "" else "(x" ++ show rep ++ ")"
BoxId name shape = boxid
label = name ++ show_rep ++ if (subroutineshape fs) then (", shape " ++ shape) else ""
Comment s inv ws -> (return (), t1 >> t2)
where
t1 = render_comment fs (null ws) s' x (ymap 0) maxh
t2 = sequence_ [render_label fs (null s) l x (ymap w) | (w,l) <- ws]
s' = s ++ optional inv "*"
render_gates :: FormatStyle -> Xarity -> [(Gate, X)] -> Map Wire Y -> X -> Y -> (Draw (), Draw ())
render_gates fs xarity xgs ys x maxh =
case xgs of
[] ->
let s2 = render_xarity fs ys xarity x
in (s2, return ())
(g,newx):gls ->
let (xarity_term, xarity_new) = update_xarity xarity g newx in
let s1 = render_xarity fs ys xarity_term newx in
let (s2, t2) = render_gate fs g newx ys maxh in
let (sx, tx) = render_gates fs xarity_new gls ys x maxh in
(s1 >> s2 >> sx, t2 >> tx)
ps_parameters :: FormatStyle -> String
ps_parameters fs =
"% some parameters\n"
++ printf "%f setlinewidth\n" (linewidth fs)
++ printf "/gatepad %f def\n" (gatepad fs)
++ printf "/gateheight %f def\n" (gateheight fs)
++ printf "/stringbase %f def\n" (stringbase fs)
++ printf "/dotradius %f def\n" (dotradius fs)
++ printf "/oplusradius %f def\n" (oplusradius fs)
++ printf "/crossradius %f def\n" (crossradius fs)
++ printf "/barwidth %f def\n" (barwidth fs)
++ printf "/barheight %f def\n" (barheight fs)
++ printf "/dwidth %f def\n" (dwidth fs)
++ printf "/dheight %f def\n" (dheight fs)
++ printf "/maxgatelabelwidth %f def\n" (maxgatelabelwidth fs)
++ printf "/maxlabelwidth %f def\n" (maxlabelwidth fs)
++ printf "/maxnumberwidth %f def\n" (maxnumberwidth fs)
++ "/gatefont { /Times-Roman findfont .5 scalefont setfont } def\n"
++ "/labelfont { /Times-Roman findfont .3 scalefont setfont } def\n"
++ "/commentfont { /Times-Roman findfont .3 scalefont setfont } def\n"
++ "/numberfont { /Times-Roman findfont .5 scalefont setfont } def\n"
++ "/labelcolor { 0 0 1 setrgbcolor } def\n"
++ "/commentcolor { 1 0.2 0.2 setrgbcolor } def\n"
++ "/numbercolor { 0 0.7 0 setrgbcolor } def\n"
ps_subroutines :: String
ps_subroutines =
"% subroutine definitions\n"
++ "/line { moveto lineto stroke } bind def\n"
++ "/dashedline { moveto gsave [0.3 0.2] .15 setdash lineto stroke grestore } bind def\n"
++ "/rect { /H exch def /W exch def -.5 W mul .5 H mul moveto W 0 rlineto 0 H neg rlineto W neg 0 rlineto closepath } bind def\n"
++ "/oval { /H exch def /W exch def gsave .5 W mul .5 H mul scale 0 0 1 0 360 newpath arc gsave 1.0 setgray fill grestore stroke grestore } bind def\n"
++ "/dot { dotradius 0 360 newpath arc gsave 0 setgray fill grestore newpath } bind def\n"
++ "/circ { dotradius 0 360 newpath arc gsave 1.0 setgray fill grestore stroke } bind def\n"
++ "/oplus { gsave translate 0 0 oplusradius 0 360 newpath arc gsave 1.0 setgray fill grestore stroke 0 oplusradius neg 0 oplusradius line oplusradius neg 0 oplusradius 0 line grestore } bind def\n"
++ "/cross { gsave translate crossradius dup dup neg dup line crossradius dup neg dup dup neg line grestore } bind def\n"
++ "/bar { gsave translate barwidth barheight rect fill grestore } bind def\n"
++ "/dbar { gsave translate barwidth 0.5 mul 0 translate dwidth dheight scale -1 -.5 moveto -.5 0 .5 -90 90 arc -1 .5 lineto closepath fill grestore } bind def\n"
++ "/box { gsave translate gatefont stringwidth pop /w exch def /w1 w gatepad add def w1 gateheight rect gsave 1.0 setgray fill grestore stroke grestore } bind def\n"
++ "/gate { gsave translate dup gatefont stringwidth pop /w exch def /fontscale w maxgatelabelwidth div def /fontscale fontscale 1 le {1} {fontscale} ifelse def /w2 w fontscale div def /w1 w2 gatepad add def w1 gateheight rect gsave 1.0 setgray fill grestore stroke 1 fontscale div dup scale 0 .5 w mul sub -0.5 stringbase mul moveto show grestore } bind def\n"
++ "/circgate { gsave translate dup gatefont stringwidth pop /w exch def /fontscale w maxgatelabelwidth div def /fontscale fontscale 1 le {1} {fontscale} ifelse def /w2 w fontscale div def /w1 w2 gatepad add def w1 0.8 gateheight mul oval gsave 1.0 setgray fill grestore stroke 1 fontscale div dup scale 0 .5 w mul sub -0.5 stringbase mul moveto show grestore } bind def\n"
++ "/gphase { gsave translate 0 -0.5 circgate grestore } bind def\n"
++ "/init { gsave translate dup gatefont stringwidth pop /w exch def /w1 w gatepad add def -.5 w1 mul 0 translate 0.5 w1 mul 0 bar 0 .5 w mul sub -0.5 stringbase mul moveto show grestore } bind def\n"
++ "/term { gsave translate dup gatefont stringwidth pop /w exch def /w1 w gatepad add def .5 w1 mul 0 translate -0.5 w1 mul 0 bar 0 .5 w mul sub -0.5 stringbase mul moveto show grestore } bind def\n"
++ "/dterm { gsave translate dup gatefont stringwidth pop /w exch def /w1 w gatepad add def .5 w1 mul 0 translate -0.5 w1 mul 0 dbar 0 .5 w mul sub -0.5 stringbase mul moveto show grestore } bind def\n"
++ "/comment { gsave /b exch def /maxh exch def /y exch def /x exch def commentfont commentcolor x y maxh sub x y 0.4 add 1.0 b textbox grestore } bind def\n"
++ "/clabel { gsave translate dup labelfont stringwidth pop /w exch def /fontscale w maxlabelwidth 2 mul div def /fontscale fontscale 1 le {1} {fontscale} ifelse def 0 0.15 translate 1 fontscale div dup scale -0.5 w mul 0 moveto labelcolor show grestore } bind def\n"
++ "/rlabel { gsave translate dup labelfont stringwidth pop /w exch def /fontscale w maxlabelwidth div def /fontscale fontscale 1 le {1} {fontscale} ifelse def 0 0.15 translate 1 fontscale div dup scale 0 0 moveto labelcolor show grestore } bind def\n"
++ "/lnumber { gsave translate dup numberfont stringwidth pop /w exch def /fontscale w maxnumberwidth div def /fontscale fontscale 1 le {1} {fontscale} ifelse def -0.2 -0.15 translate 1 fontscale div dup scale -1 w mul 0 moveto numbercolor show grestore } bind def\n"
++ "/rnumber { gsave translate dup numberfont stringwidth pop /w exch def /fontscale w maxnumberwidth div def /fontscale fontscale 1 le {1} {fontscale} ifelse def 0.2 -0.15 translate 1 fontscale div dup scale 0 0 moveto numbercolor show grestore } bind def\n"
page_of_ocircuit :: FormatStyle -> Maybe BoxId -> OCircuit -> Document ()
page_of_ocircuit fs boxid ocirc = do
newpage bboxx bboxy $ do
when (isJust boxid) $ do
comment ("drawing commands for " ++ string_of_boxid (fromJust boxid))
scale sc sc
translate ((xoff fs) + 1) 1
setlinewidth (linewidth fs)
when (isJust boxid) $ do
textbox align_left (gatefont fs) (foregroundcolor fs) (-(xoff fs)) (raw_height-0.25) raw_width (raw_height-0.25) (stringbase fs) ("Subroutine " ++ string_of_boxid (fromJust boxid) ++ ":")
rendered_wires
rendered_gates
render_ordering fs (-(xoff fs)) ys False w_in
render_ordering fs raw_width ys True w_out
where
sc = 10
OCircuit (w_in, circ, w_out) = ocirc
(a1,gs,a2,_) = circ
ws = wirelist_of_circuit circ
raw_height = fromIntegral $ length ws
ys = Map.fromList (zip (reverse ws) [0.0 ..])
maxh = raw_height + 0.3
bboxy = sc * (raw_height + 1)
(raw_width,xgs) = assign_x_coordinates fs gs 0.0
bboxx = sc * (raw_width + (xoff fs) + 2.0)
xa1 = IntMap.map (\t -> (t, -(xoff fs))) a1
(rendered_wires, rendered_gates) = render_gates fs (Map.fromList (IntMap.assocs xa1)) xgs ys raw_width maxh
render_bcircuit :: FormatStyle -> BCircuit -> Document ()
render_bcircuit fs (circ, namespace) = do
page_of_ocircuit fs Nothing (OCircuit ([], circ, []))
sequence_ [ page_of_ocircuit fs (Just boxid) ocirc | (boxid, TypedSubroutine ocirc _ _ _) <- Map.toList namespace]
render_dbcircuit :: FormatStyle -> ErrMsg -> DBCircuit a -> Document ()
render_dbcircuit fs e dbcirc = render_bcircuit fs bcirc where
(bcirc, _) = bcircuit_of_static_dbcircuit errmsg dbcirc
errmsg x = e ("operation not permitted during graphical rendering: " ++ x)
print_bcircuit_format :: FormatStyle -> BCircuit -> IO ()
print_bcircuit_format fs bcirc =
render_custom_stdout (renderformat fs) cust (render_bcircuit fs bcirc)
where
cust = custom {
creator = "Quipper",
ps_defs = ps_parameters fs ++ ps_subroutines
}
print_dbcircuit_format :: FormatStyle -> ErrMsg -> DBCircuit a -> IO ()
print_dbcircuit_format fs e dbcirc =
render_custom_stdout (renderformat fs) cust (render_dbcircuit fs e dbcirc)
where
cust = custom {
creator = "Quipper",
ps_defs = ps_parameters fs ++ ps_subroutines
}
preview_document :: Document a -> IO a
preview_document = preview_document_custom custom
preview_document_custom :: Custom -> Document a -> IO a
preview_document_custom custom doc = do
tmpdir <- getTemporaryDirectory
(pdffile, fd) <- openTempFile tmpdir "Quipper.pdf"
a <- render_custom_file fd Format_PDF custom doc
hClose fd
system_pdf_viewer 100 pdffile
removeFile pdffile
return a
preview_bcircuit :: BCircuit -> IO ()
preview_bcircuit bcirc =
preview_document doc
where
doc = render_bcircuit pdf bcirc
preview_dbcircuit :: ErrMsg -> DBCircuit a -> IO ()
preview_dbcircuit e dbcirc = preview_bcircuit bcirc where
(bcirc, _) = bcircuit_of_static_dbcircuit errmsg dbcirc
errmsg x = e ("operation not permitted for PDF preview: " ++ x)
type ControlType = (Int,Int)
controltype :: Controls -> ControlType
controltype c =
(length $ filter get_sign c, length $ filter (not . get_sign) c)
nocontrols :: ControlType
nocontrols = (0,0)
data Gatetype =
Gatetype String ControlType
| GatetypeSubroutine BoxId InverseFlag ControlType
deriving (Eq, Ord, Show)
data AnnGatetype =
AnnGatetype String (Maybe String) ControlType NoControlFlag ControllableFlag
| AnnGatetypeSubroutine BoxId InverseFlag ControlType NoControlFlag ControllableFlag
deriving (Eq, Ord, Show)
unannotate_gatetype :: AnnGatetype -> Gatetype
unannotate_gatetype (AnnGatetype n _ cs _ _) = Gatetype n cs
unannotate_gatetype (AnnGatetypeSubroutine n i cs _ _) = GatetypeSubroutine n i cs
add_controls_gatetype :: ErrMsg -> ControlType -> AnnGatetype -> AnnGatetype
add_controls_gatetype e (x',y') g@(AnnGatetype n n_inv (x,y) ncf cf) =
if ncf then g
else case cf of
AllCtl -> AnnGatetype n n_inv (x+x',y+y') ncf cf
OnlyClassicalCtl -> AnnGatetype n n_inv (x+x',y+y') ncf cf
NoCtl -> error $ e "add_controls_gatetype: gate " ++ n ++ " is not controllable."
add_controls_gatetype e (x',y') g@(AnnGatetypeSubroutine n inv (x,y) ncf cf) =
if ncf then g
else case cf of
AllCtl -> AnnGatetypeSubroutine n inv (x+x',y+y') ncf cf
OnlyClassicalCtl -> AnnGatetypeSubroutine n inv (x+x',y+y') ncf cf
NoCtl -> error $ e "add_controls_gatetype: subroutine " ++ show n ++ " is not controllable."
reverse_gatetype :: ErrMsg -> AnnGatetype -> AnnGatetype
reverse_gatetype e g@(AnnGatetype n n_inv cs ncf cf) =
case n_inv of
Just n' -> (AnnGatetype n' (Just n) cs ncf cf)
Nothing -> error $ e "reverse_gatetype: gate " ++ n ++ " is not reversible"
reverse_gatetype e g@(AnnGatetypeSubroutine n inv cs ncf cf) =
(AnnGatetypeSubroutine n (not inv) cs ncf cf)
set_ncf_gatetype :: AnnGatetype -> AnnGatetype
set_ncf_gatetype (AnnGatetype n n_inv cs ncf cf) =
(AnnGatetype n n_inv cs True cf)
set_ncf_gatetype (AnnGatetypeSubroutine n inv cs ncf cf) =
(AnnGatetypeSubroutine n inv cs True cf)
with_arity :: String -> Int -> String
n `with_arity` a = n ++ ", arity " ++ show a
gatetype :: Gate -> AnnGatetype
gatetype (QGate n inv ws vs c ncf) =
AnnGatetype (n' inv') (Just $ n' $ notinv') (controltype c) ncf AllCtl
where
n' b = (n ++ optional b "*") `with_arity` (length ws + length vs)
inv' = inv && not (self_inverse n ws vs)
notinv' = not inv && not (self_inverse n ws vs)
gatetype (QRot n inv t ws vs c ncf) =
AnnGatetype (n' inv) (Just $ n' $ not inv) (controltype c) ncf AllCtl
where n' b = (printf "Rot(%s,%f)" (n++ optional b "*") t) `with_arity` (length ws + length vs)
gatetype (GPhase t w c ncf) =
AnnGatetype (phase_name t) (Just $ phase_name (-t)) (controltype c) ncf AllCtl
where phase_name t = (printf "exp^(%f i pi)" t)
gatetype (CNot w c ncf) =
AnnGatetype "CNot" (Just "CNot") (controltype c) ncf AllCtl
gatetype (CGate n w ws ncf) =
AnnGatetype (n' True) (Just $ n' False) nocontrols ncf AllCtl
where n' b = n ++ optional b "*" `with_arity` length ws
gatetype (CGateInv n w ws ncf) =
AnnGatetype (n' False) (Just $ n' True) nocontrols ncf AllCtl
where n' b = n ++ optional b "*" `with_arity` length ws
gatetype (CSwap w v c ncf) =
AnnGatetype "CSwap" (Just "CSwap") (controltype c) ncf AllCtl
gatetype (QPrep w ncf) =
AnnGatetype "Prep" (Just "Unprep") nocontrols ncf NoCtl
gatetype (QUnprep w ncf) =
AnnGatetype "Unprep" (Just "Prep") nocontrols ncf NoCtl
gatetype (QInit b w ncf) =
AnnGatetype ("Init" ++ b') (Just $ "Term" ++ b') nocontrols ncf NoCtl
where b' = show $ if b then 1 else 0
gatetype (CInit b w ncf) =
AnnGatetype ("CInit" ++ b') (Just $ "CTerm" ++ b') nocontrols ncf NoCtl
where b' = show $ if b then 1 else 0
gatetype (QTerm b w ncf) =
AnnGatetype ("Term" ++ b') (Just $ "Init" ++ b') nocontrols ncf NoCtl
where b' = show $ if b then 1 else 0
gatetype (CTerm b w ncf) =
AnnGatetype ("CTerm" ++ b') (Just $ "CInit" ++ b') nocontrols ncf NoCtl
where b' = show $ if b then 1 else 0
gatetype (QMeas w) =
AnnGatetype "Meas" Nothing nocontrols False NoCtl
gatetype (QDiscard w) =
AnnGatetype "Discard" Nothing nocontrols False NoCtl
gatetype (CDiscard w) =
AnnGatetype "CDiscard" Nothing nocontrols False NoCtl
gatetype (DTerm b w) =
AnnGatetype "CDiscard" Nothing nocontrols False NoCtl
gatetype (Subroutine boxid inv ws1 a1 ws2 a2 c ncf ctrble reps) =
AnnGatetypeSubroutine boxid inv (controltype c) ncf ctrble
gatetype (Comment _ inv ws) = AnnGatetype ("Comment") (Just "Comment") nocontrols True NoCtl
string_of_gatetype :: Gatetype -> String
string_of_gatetype (Gatetype s (c1,c2)) =
printf "\"%s\"" s
++ if c2==0 && c1==0 then "" else
if c2==0 then printf ", controls %d" c1 else
printf " controls %d+%d" c1 c2
string_of_gatetype (GatetypeSubroutine boxid i (c1,c2)) =
"Subroutine" ++ optional i "*" ++ cs ++ ": " ++ string_of_boxid boxid
where
cs = if c2==0 && c1==0 then "" else
if c2==0 then printf ", controls %d" c1 else
printf " controls %d+%d" c1 c2
type Gatecount = Map Gatetype Integer
type AnnGatecount = Map AnnGatetype Integer
reverse_gatecount :: ErrMsg -> AnnGatecount -> AnnGatecount
reverse_gatecount e = Map.mapKeysWith (+) (reverse_gatetype e)
add_controls_gatecount :: ErrMsg -> ControlType -> AnnGatecount -> AnnGatecount
add_controls_gatecount e cs = Map.mapKeysWith (+) (add_controls_gatetype e cs)
set_ncf_gatecount :: AnnGatecount -> AnnGatecount
set_ncf_gatecount = Map.mapKeysWith (+) set_ncf_gatetype
unannotate_gatecount :: AnnGatecount -> Gatecount
unannotate_gatecount = Map.mapKeysWith (+) unannotate_gatetype
count :: (Ord a, Num int) => [(int,a)] -> Map a int
count list =
foldl' (\mp (i,x) -> MapS.insertWith (+) x i mp) Map.empty list
anngatecount_of_circuit :: Circuit -> AnnGatecount
anngatecount_of_circuit (_,gs,_,_) = count $ map (\x -> (repeated x, gatetype x)) $ filter (not . is_comment) gs
where
is_comment (Comment _ _ _) = True
is_comment _ = False
repeated (Subroutine _ _ _ _ _ _ _ _ _ (RepeatFlag repeat)) = repeat
repeated _ = 1
gatecount_of_circuit :: Circuit -> Gatecount
gatecount_of_circuit = unannotate_gatecount . anngatecount_of_circuit
gatecount_of_subroutine_call :: ErrMsg -> AnnGatetype -> RepeatFlag -> AnnGatecount -> AnnGatecount
gatecount_of_subroutine_call e (AnnGatetypeSubroutine boxid inv cs ncf ctrble) (RepeatFlag reps) =
(if inv then reverse_gatecount err_inv else id)
. (if cs == nocontrols then id
else case ctrble of
AllCtl -> add_controls_gatecount err_ctrl cs
OnlyClassicalCtl -> add_controls_gatecount err_ctrl cs
NoCtl -> error $ err_ctrble)
. (if reps == 1 then id else (Map.map (* reps)))
. (if ncf then set_ncf_gatecount else id)
where
err_inv = e . (("gatecount_of_subroutine_call, inverting subroutine " ++ longname ++ ": ") ++)
err_ctrl = e . (("gatecount_of_subroutine_call, controlling subroutine " ++ longname ++ ": ") ++)
err_ctrble = e $ "gatecount_of_subroutine_call: subroutine " ++ longname ++ " not controllable"
longname = string_of_boxid boxid
gatecount_of_subroutine_call e _ _ = error $ e "internal error (gatecount_of_subroutine_call called on non-subroutine)"
anngatecount_of_circuit_with_sub_cts :: ErrMsg -> Map BoxId AnnGatecount -> Circuit -> AnnGatecount
anngatecount_of_circuit_with_sub_cts e sub_cts (_,gs,_,_) =
foldr action Map.empty gs
where
action (Comment _ _ _) = id
action g@(Subroutine n _ _ _ _ _ _ _ _ reps) =
case Map.lookup n sub_cts of
Nothing -> error $ e $ "subroutine not found: " ++ show n
Just n_ct -> flip (Map.unionWith (+)) $
gatecount_of_subroutine_call e (gatetype g) reps n_ct
action g = MapS.insertWith (+) (gatetype g) 1
aggregate_gatecounts_of_bcircuit :: BCircuit -> Gatecount
aggregate_gatecounts_of_bcircuit (main_circ, namespace)
= unannotate_gatecount $
anngatecount_of_circuit_with_sub_cts e sub_cts main_circ
where
sub_cts = Map.map (anngatecount_of_circuit_with_sub_cts e sub_cts . circuit_of_typedsubroutine) namespace
e = ("aggregate_gatecounts_of_bcircuit: " ++)
gate_wires_change :: Gate -> Integer
gate_wires_change g =
let (a_in,a_out) = gate_arity g
in fromIntegral $ length a_out - length a_in
aggregate_maxwires_of_bcircuit :: BCircuit -> Integer
aggregate_maxwires_of_bcircuit (main_circ, namespace)
= maxwires_of_circuit_with_sub_maxwires e sub_maxs main_circ
where
e = ("aggregate_maxwires_of_bcircuit: " ++)
sub_maxs = Map.map (maxwires_of_circuit_with_sub_maxwires e sub_maxs . circuit_of_typedsubroutine) namespace
maxwires_of_circuit_with_sub_maxwires :: ErrMsg -> Map BoxId Integer -> Circuit -> Integer
maxwires_of_circuit_with_sub_maxwires e sub_maxs (a1,gs,a2,_) =
snd $ foldl (flip action) (in_wires, in_wires) gs
where
in_wires = fromIntegral $ IntMap.size a1
update w_change (!w_old, !wmax_old) =
let w_new = w_old + w_change in (w_new, max wmax_old w_new)
action g@(Subroutine n _ ws1 _ ws2 _ _ _ _ (RepeatFlag r)) =
case Map.lookup n sub_maxs of
Nothing -> error $ "subroutine not found: " ++ show n
Just n_max -> (update $ (fromIntegral $ length ws2) - n_max)
. (update $ n_max - (fromIntegral $ length ws1))
action g = update $ gate_wires_change g
print_gatecount :: Gatecount -> IO ()
print_gatecount cts = mapM_
(\(gt,k) -> putStr (printf ("%" ++ show max_digits ++ "d: %s\n") k (string_of_gatetype gt)))
(Map.assocs cts)
where
max_digits = maximum $ 5:(map ((1+) . floor . logBase 10 . fromIntegral) (Map.elems cts))
print_gatecounts_circuit :: Circuit -> IO ()
print_gatecounts_circuit circ@(a1,gs,a2,n) = do
print_gatecount cts
putStrLn $ printf "Total gates: %d" $ sum $ Map.elems cts
putStrLn $ printf "Inputs: %d" $ IntMap.size a1
putStrLn $ printf "Outputs: %d" $ IntMap.size a2
putStrLn $ printf "Qubits in circuit: %d" n
where
cts = gatecount_of_circuit circ
print_gatecounts_bcircuit :: BCircuit -> IO ()
print_gatecounts_bcircuit bcirc@(circ@(a1,_,a2,_),namespace) = do
print_gatecounts_circuit circ
when (not $ Map.null namespace) $ do
sequence_ [ (putStrLn "") >> (print_gatecounts_subroutine sub) | sub <- Map.toList namespace ]
putStrLn ""
putStrLn "Aggregated gate count:"
let aggregate_cts = aggregate_gatecounts_of_bcircuit bcirc
maxwires = aggregate_maxwires_of_bcircuit bcirc
print_gatecount aggregate_cts
putStrLn $ printf "Total gates: %d" $ sum $ Map.elems aggregate_cts
putStrLn $ printf "Inputs: %d" $ IntMap.size a1
putStrLn $ printf "Outputs: %d" $ IntMap.size a2
putStrLn $ printf "Qubits in circuit: %d" maxwires
print_gatecounts_subroutine :: (BoxId, TypedSubroutine) -> IO ()
print_gatecounts_subroutine (boxid, TypedSubroutine ocirc _ _ _) = do
putStrLn ("Subroutine: " ++ show name)
putStrLn ("Shape: " ++ show shape)
print_gatecounts_circuit circ
where
OCircuit (_, circ, _) = ocirc
BoxId name shape = boxid
print_gatecounts_dbcircuit :: ErrMsg -> DBCircuit a -> IO ()
print_gatecounts_dbcircuit e dbcirc = print_gatecounts_bcircuit bcirc where
(bcirc, _) = bcircuit_of_static_dbcircuit errmsg dbcirc
errmsg x = e ("operation not permitted during gate count: " ++ x)
data Format =
EPS
| PDF
| PS
| ASCII
| Preview
| GateCount
| CustomStyle FormatStyle
deriving Show
format_enum :: [(String, Format)]
format_enum = [
("eps", EPS),
("pdf", PDF),
("ps", PS),
("postscript", PS),
("ascii", ASCII),
("preview", Preview),
("gatecount", GateCount)
]
print_dbcircuit :: Format -> ErrMsg -> DBCircuit a -> IO ()
print_dbcircuit EPS = print_dbcircuit_format eps
print_dbcircuit PDF = print_dbcircuit_format pdf
print_dbcircuit PS = print_dbcircuit_format ps
print_dbcircuit ASCII = print_dbcircuit_ascii
print_dbcircuit Preview = preview_dbcircuit
print_dbcircuit GateCount = print_gatecounts_dbcircuit
print_dbcircuit (CustomStyle fs) = print_dbcircuit_format fs
print_of_document :: Format -> Document a -> IO a
print_of_document = print_of_document_custom custom
print_of_document_custom :: Custom -> Format -> Document a -> IO a
print_of_document_custom custom PS doc = render_custom_stdout Format_PS custom doc
print_of_document_custom custom PDF doc = render_custom_stdout Format_PDF custom doc
print_of_document_custom custom EPS doc = render_custom_stdout (Format_EPS 1) custom doc
print_of_document_custom custom Preview doc = preview_document_custom custom doc
print_of_document_custom custom format doc = error ("print_of_document: method " ++ show format ++ " can't be used in this context")
print_errmsg :: (QCData qa) => ErrMsg -> Format -> (qa -> Circ b) -> qa -> IO ()
print_errmsg e format f shape = print_dbcircuit format e dbcircuit
where
(in_bind, dbcircuit) = encapsulate_dynamic f shape
print_unary :: (QCData qa) => Format -> (qa -> Circ b) -> qa -> IO ()
print_unary = print_errmsg errmsg
where
errmsg x = "print_unary: " ++ x
print_generic :: (QCData qa, QCurry qfun qa b, Curry fun qa (IO())) => Format -> qfun -> fun
print_generic format f = g where
f1 = quncurry f
g1 = print_errmsg errmsg format f1
g = mcurry g1
errmsg x = "print_generic: " ++ x
print_simple :: (QCData qa, QCurry qfun qa b, Curry fun qa (IO()), QCData_Simple qa) => Format -> qfun -> IO ()
print_simple format f = print_errmsg errmsg format f1 fs_shape where
f1 = quncurry f
errmsg x = "print_simple: " ++ x