quipper-utils (empty) → 0.9.0.0
raw patch · 19 files changed
+3912/−0 lines, 19 filesdep +basedep +containersdep +mtlbuild-type:Customsetup-changed
Dependencies added: base, containers, mtl, newsynth, process, random, template-haskell, unix
Files
- COPYRIGHT +66/−0
- ChangeLog +76/−0
- Quipper/Utils/Auxiliary.hs +898/−0
- Quipper/Utils/CommandLine.hs +66/−0
- Quipper/Utils/PortableSignals.hs +133/−0
- Quipper/Utils/Preview.hs +84/−0
- Quipper/Utils/RandomSource.hs +19/−0
- Quipper/Utils/Sampling.hs +279/−0
- Quipper/Utils/Stabilizers/Clifford.hs +731/−0
- Quipper/Utils/Stabilizers/Pauli.hs +199/−0
- Quipper/Utils/Template.hs +66/−0
- Quipper/Utils/Template/Auxiliary.hs +82/−0
- Quipper/Utils/Template/ErrorMsgQ.hs +56/−0
- Quipper/Utils/Template/LiftQ.hs +282/−0
- Quipper/Utils/Template/Lifting.hs +630/−0
- Quipper/Utils/Tuple.hs +97/−0
- Quipper/Utils/Typeable.hs +52/−0
- Setup.hs +2/−0
- quipper-utils.cabal +94/−0
+ COPYRIGHT view
@@ -0,0 +1,66 @@+Contributors are listed here, in alphabetical order by last name.+Unless otherwise noted, the copyright for his or her contributions+rests with each individual author. For contributions by authors whose+name is marked (ACS), the copyright rests with Applied Communication+Sciences.++Copyright (C) 2011-2019. All rights reserved.+Copyright (C) 2012-2013 Applied Communication Sciences. All rights+reserved.++Richard Eisenberg+Alexander S. Green+Peter LeFanu Lumsdaine+Keith Kim (ACS)+Siun-Chuon Mau (ACS)+Baranidharan Mohan+Won Ng (ACS)+Joel Ravelomanantsoa-Ratsimihah+Neil J. Ross+Artur Scherer (ACS)+Peter Selinger+Benoît Valiron+Alexandr Virodov (ACS)+Stephan A. Zdancewic++This research was supported by the Intelligence Advanced Research+Projects Activity (IARPA) via Department of Interior National Business+Center contract numbers D11PC20168 and D12PC00527. The U.S. Government+is authorized to reproduce and distribute reprints for Governmental+purposes notwithstanding any copyright annotation thereon. Disclaimer:+The views and conclusions contained herein are those of the authors+and should not be interpreted as necessarily representing the official+policies or endorsements, either expressed or implied, of IARPA,+DoI/NBC, or the U.S. Government.++----------------------------------------------------------------------+LICENSE++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the+ distribution.++3. The name of the authors and copyright holders may not be used to+ endorse or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.+----------------------------------------------------------------------
+ ChangeLog view
@@ -0,0 +1,76 @@+December 29, 2019: Release 0.9.0.0++ * Overhauled module structure:+ + Old: New:+ ==== ====+ + Quipper.XYZ Quipper.Internal.XYZ+ QuipperLib.XYZ Quipper.Libraries.XYZ+ Libraries.XYZ Quipper.Utils.XYZ+ Algorithms.XYZ Quipper.Algorithms.XYZ+ tests Quipper.Demos+ Programs Quipper.Programs++ * Re-packaged Quipper as Cabal packages. Added executables quipper,+ quipper-pp, quipperi, quipperdoc in lieu of shell scripts.+ * Moved PDF Previewer to a separate library in Quipper.Utils.Preview+ * Added a MonadFail instance to Circ, to keep ghc >= 7.4 happy+ * Use type class synonyms to avoid warnings about simplifiable class.+ * Compatibility: removed obsolete functoin Map.insertWith'.+ * Added MultiControlledNot demo.+ * Removed dependency on set-monad, which is broken upstream.+ * Fixed some bugs in the stabilizer simulation.+ * Moved QuantumIf from BF to Libraries.+ * Added --help option to all Quipper tools.+ * Removed Quipper.Utils.ShowAll+ * Fixed some compiler errors and removed some unnecessary type class+ assumptions.++July 27, 2016: Release 0.8++ * Portability: compatibility fixes for GHC 8.0. Note: GHC 7.10 is too+ broken and will not be supported by Quipper.+ * Added tests/SimulationTest+ * Added QPrep and QUnPrep to the simulator++October 14, 2014: Release 0.7++ * Portability: compatibility fixes for GHC 7.8.++January 16, 2014: Release 0.6++ * Minor edits and documentation updates.+ * Added a new gate gate_iX_inv+ * Added "alternate" version of synthesis algorithm, using only+ generators of determinant 1 if possible.+ * Synthesis code is now in an external package "newsynth".+ * Rendering code is now in an external package "easyrender".+ * Updated for use with fixedprec-0.2.1.0.++September 2, 2013: Release 0.5++ * Portability: compatibility fixes for GHC 7.6.2.+ * Portability: fixed Windows incompatibility bug. Handling of Ctrl-C+ may or may not work on Windows, depending on console.+ * Added quipperi script, analogous to ghci.+ * New library QuipperLib.ClassicalOptim: algebraic optimization of+ auto-generated classical circuits. Added "optimized" oracle to BWT+ algorithm.+ * QuipperLib.Decompose: Added decomposition into a "standard" gate+ set, consisting of X, Y, Z, H, S, S-dagger, T, T-dagger, and CNOT.+ Added KeepPhase flag to some transformers.+ * QuipperLib.GateDecompositions: added more gates.+ * New library Libraries.Synthesis.RotationDecomposition: implements a+ variant of the algorithm from Nielsen and Chuang to decompose an+ nxn unitary operator into one- and two-level rotations.+ * New library QuipperLib.Unboxing: unboxing transformers.+ * Updated ASCII output format; improved circuit parser efficiency.+ * Miscellaneous bug fixes: malformed W-gates, qdata_of_qubits,+ floorlog.+ * Fixed handling of iterated subroutines in depth transformer.+ * Documentation updates and minor refactoring.++June 19, 2013: Release 0.4++ * First public release.
+ Quipper/Utils/Auxiliary.hs view
@@ -0,0 +1,898 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}++-- | This module provides miscellaneous general-purpose auxiliary+-- functions.++module Quipper.Utils.Auxiliary (+ -- * List operations+ applyAt,+ overwriteAt,+ has_duplicates,+ substitute,+ + -- * Set and Map related operations+ map_provide,+ intset_inserts,+ intmap_zip,+ intmap_zip_errmsg,+ intmap_map,+ intmap_mapM,+ + -- * XIntMaps+ XIntMap,+ xintmap_delete,+ xintmap_deletes,+ xintmap_insert,+ xintmap_inserts,+ xintmap_lookup,+ xintmap_member,+ xintmap_empty,+ xintmap_freshkey,+ xintmap_freshkeys,+ xintmap_to_intmap,+ xintmap_size,+ xintmap_dirty,+ xintmap_reserves,+ xintmap_unreserves, + xintmap_makeclean,+ + -- * Various map- and fold-like list combinators+ loop,+ loop_with_index,+ fold_right_zip,+ zip_strict,+ zip_strict_errmsg,+ zip_rightstrict,+ zip_rightstrict_errmsg,+ zipWith_strict,+ zipWith_rightstrict,+ + -- * Monadic versions of list combinators+ loopM,+ loop_with_indexM,+ zipRightWithRightStrictM,+ zipRightWithRightStrictM_,+ fold_right_zipM,+ foldRightPairM,+ foldRightPairM_,+ sequence_right,+ sequence_right_,+ + -- * Loops+ -- $LOOPS+ for,+ endfor,+ foreach,+ + -- * Operations for monads+ mmap,+ monad_join1,+ + -- * Operations for disjoint unions+ map_either,+ map_eitherM,+ + -- * Operations for tuples+ map_pair,+ map_pairM,+ + -- * Arithmetic operations+ int_ceiling,+ + -- * Bit vectors+ Boollist(..),+ boollist_of_int_bh,+ boollist_of_int_lh,+ int_of_boollist_unsigned_bh,+ int_of_boollist_signed_bh,+ bool_xor,+ boollist_xor,+ + -- * Formatting of lists and strings+ string_of_list,+ optional,+ + -- * Lists optimized for fast concatenation+ BList,+ blist_of_list,+ list_of_blist,+ (+++),+ blist_empty,+ blist_concat,+ + -- * Strings optimized for fast concatenation+ Strbuf,+ strbuf_of_string,+ string_of_strbuf,+ strbuf_empty,+ strbuf_concat,+ + -- * The identity monad+ Id(..),+ + -- * Identity types+ Identity,+ reflexivity,+ symmetry,+ transitivity,+ identity,+ + -- * Error messages+ ErrMsg,+ + -- * The Curry type class+ Curry (..)+ ) where++-- import other stuff+import Data.List (foldl')++import Data.Set (Set)+import qualified Data.Set as Set++import Data.Map (Map)+import qualified Data.Map as Map++import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet++import Data.IntMap (IntMap)+import qualified Data.IntMap as IntMap++import qualified Data.Traversable as Traversable++import Control.Applicative (Applicative(..))+import Control.Monad (liftM, ap)++-- ----------------------------------------------------------------------+-- * List operations++-- | Apply a function to a specified position in a list.+applyAt :: Int -> (a -> a) -> [a] -> [a]+applyAt _ _ [] = []+applyAt 0 f (x:xs) = (f x):xs+applyAt n f (x:xs) = x:(applyAt (n-1) f xs)++-- | Overwrite an element at a specified position in a list.+overwriteAt :: Int -> a -> [a] -> [a]+overwriteAt n a = applyAt n (const a)++-- | Check whether a list has duplicates.+has_duplicates :: Ord a => [a] -> Bool+has_duplicates list = aux list (Set.empty) where+ aux [] _ = False+ aux (h:t) set = if Set.member h set then True else aux t (Set.insert h set)++-- | @'substitute' string character replacement@: +-- Replace the first occurrence of /character/ in /string/ by /replacement/.+substitute :: (Eq a) => [a] -> a -> [a] -> [a]+substitute string character replacement = + case break (== character) string of+ (x, []) -> x+ (x, h:y) -> x ++ replacement ++ y++-- ----------------------------------------------------------------------+-- * Set related operations++-- | Insert the elements of a list in an 'IntSet' (cf. 'IntSet.insert').+intset_inserts :: [Int] -> IntSet -> IntSet+intset_inserts list set =+ foldl' (\t x -> IntSet.insert x t) set list+++-- ----------------------------------------------------------------------+-- * Map related operations++-- | Insert the given key-value pair in a 'Map', but only if the given+-- key is not already present. If the key is present, keep the old+-- value.+map_provide :: Ord k => k -> a -> Map k a -> Map k a+map_provide = Map.insertWith (\x y -> y)++-- | Take two 'IntMap's /m/[sub 1] and /m/[sub 2], and form a new+-- 'IntMap' whose domain is that of /m/[sub 2], and whose value at /k/+-- is the pair (/m/[sub 1] ! /k/, /m/[sub 2] ! /k/). It is an error if+-- the domain of /m/[sub 2] is not a subset of the domain of /m/[sub 1].+intmap_zipright :: IntMap x -> IntMap y -> IntMap (x, y)+intmap_zipright m1 m2 = m where+ m = IntMap.mapWithKey f m2+ f k y = case IntMap.lookup k m1 of+ Just x -> (x, y)+ Nothing -> error "intmap_zipright: shape mismatch"+ +-- | Take two 'IntMap's with the same domain, and form a new 'IntMap'+-- whose values are pairs. It is an error if the two inputs don't have+-- identical domains.+intmap_zip :: IntMap x -> IntMap y -> IntMap (x, y)+intmap_zip m1 m2 = intmap_zip_errmsg m1 m2 "intmap_zip: shape mismatch"+ +-- | Like 'intmap_zip', but also takes an error message to use in case of+-- domain mismatch.+intmap_zip_errmsg :: IntMap x -> IntMap y -> String -> IntMap (x, y)+intmap_zip_errmsg m1 m2 errmsg = + if all (\k -> IntMap.member k m2) (IntMap.keys m1) + then intmap_zipright m1 m2+ else error errmsg+ +-- | Map a function over all values in an 'IntMap'.+intmap_map :: (x -> y) -> IntMap x -> IntMap y+intmap_map = IntMap.map++-- | Monadic version of 'intmap_map'. Map a function over all values+-- in an 'IntMap'.+intmap_mapM :: (Monad m) => (x -> m y) -> IntMap x -> m (IntMap y)+intmap_mapM = Traversable.mapM++-- ----------------------------------------------------------------------+-- * XIntMaps. ++-- | A 'XIntMap' is just like an 'IntMap', except that it supports+-- some additional efficient operations: to find the smallest unused+-- key, to find the set of all keys ever used in the past, and to+-- reserve a set of keys so that they will not be allocated. Moreover,+-- it keeps track of the highest key ever used (whether or not it is+-- still used in the current map).++-- This is implemented as a tuple (/m/, /n/, /free/, /h/), where /m/ is an+-- 'IntMap', /n/ is an integer such that dom /m/ ⊆ [0../n/-1], /free/+-- ⊆ [0../n/-1] \\ dom /m/ is a set of integers not currently reserved+-- or used, and /h/ is the set of all integers used in the past (the+-- set of /touched/ wires).++data XIntMap a = XIntMap !(IntMap a) !Int !IntSet !IntSet++instance (Show a) => Show (XIntMap a) where+ show = show . xintmap_to_intmap+ +-- | Delete a key from the 'XIntMap'.+xintmap_delete :: Int -> XIntMap a -> XIntMap a+xintmap_delete k (XIntMap m n free h) = (XIntMap m' n free' h) where+ m' = IntMap.delete k m+ free' = IntSet.insert k free+ +-- | Delete a list of keys from a 'XIntMap'.+xintmap_deletes :: [Int] -> XIntMap a -> XIntMap a+xintmap_deletes list map =+ foldl' (\map k -> xintmap_delete k map) map list++-- | Insert a new key-value pair in the 'XIntMap'. +xintmap_insert :: Int -> a -> XIntMap a -> XIntMap a+xintmap_insert k v (XIntMap m n free h) = (XIntMap m' n' free' h') where+ m' = IntMap.insert k v m+ h' = IntSet.insert k h+ n' = max n (k+1)+ free' = IntSet.delete k (intset_inserts [n..n'-1] free)++-- | Insert a list of key-value pairs in the 'XIntMap'.+xintmap_inserts :: [(Int,a)] -> XIntMap a -> XIntMap a+xintmap_inserts list map =+ foldl' (\map (k,v) -> xintmap_insert k v map) map list++-- | Look up the value at a key in the 'XIntMap'. Return 'Nothing' if+-- not found.+xintmap_lookup :: Int -> XIntMap a -> Maybe a+xintmap_lookup k (XIntMap m n free h) =+ IntMap.lookup k m++-- | Check whether the given key is in the 'XIntMap'.+xintmap_member :: Int -> XIntMap a -> Bool+xintmap_member k (XIntMap m n free h) =+ IntMap.member k m++-- | The empty 'XIntMap'.+xintmap_empty :: XIntMap a+xintmap_empty = (XIntMap m n free h) where+ m = IntMap.empty+ n = 0+ free = IntSet.empty+ h = IntSet.empty++-- | Return the first free key in the 'XIntMap', but without actually+-- using it yet.+xintmap_freshkey :: XIntMap a -> Int+xintmap_freshkey (XIntMap m n free h) = + if IntSet.null free then n else IntSet.findMin free++-- | Return the next /k/ unused keys in the 'XIntMap', but without+-- actually using them yet.+xintmap_freshkeys :: Int -> XIntMap a -> [Int]+xintmap_freshkeys k (XIntMap m n free h) = ks1 ++ ks2 where+ ks1 = take k (IntSet.elems free)+ delta = k - (length ks1)+ ks2 = [n .. n+delta-1]++-- | Convert a 'XIntMap' to an 'IntMap'.+xintmap_to_intmap :: XIntMap a -> IntMap a+xintmap_to_intmap (XIntMap m n free h) = m++-- | Return the smallest key never used in the 'XIntMap'.+xintmap_size :: XIntMap a -> Int+xintmap_size (XIntMap m n free k) = n++-- | Return the set of all keys ever used in the 'XIntMap'.+xintmap_touched :: XIntMap a -> IntSet+xintmap_touched (XIntMap m n free h) = h ++-- | A wire is /dirty/ if it is touched but currently free. +xintmap_dirty :: XIntMap a -> IntSet+xintmap_dirty (XIntMap m n free h) = h `IntSet.intersection` free++-- | Reserve a key in the 'XIntMap'. If the key is not free, do+-- nothing. The key must have been used before; for example, this is+-- the case if it was returned by 'xintmap_dirty'.+xintmap_reserve :: Int -> XIntMap a -> XIntMap a+xintmap_reserve k (XIntMap m n free h) = (XIntMap m n free' h) where+ free' = IntSet.delete k free+ +-- | Reserve a set of keys in the 'XIntMap'. For any keys that are not+-- free, do nothing. All keys must have been used before; for example,+-- this is the case if they were returned by 'xintmap_dirty'.+xintmap_reserves :: IntSet -> XIntMap a -> XIntMap a+xintmap_reserves ks (XIntMap m n free h) = (XIntMap m n free' h) where+ free' = free `IntSet.difference` ks++-- | Unreserve a key in the 'XIntMap'. If the key is currently used,+-- do nothing. The key must have been reserved before, and (therefore)+-- must have been used before.+xintmap_unreserve :: Int -> XIntMap a -> XIntMap a+xintmap_unreserve k (XIntMap m n free h) + | IntMap.member k m = (XIntMap m n free h)+ | otherwise = (XIntMap m n free' h)+ where+ free' = IntSet.insert k free++-- | Unreserve a list of keys in the 'XIntMap'. If any key is+-- currently used, do nothing. All keys must have been reserved+-- before, and (therefore) must have been used before.+xintmap_unreserves :: IntSet -> XIntMap a -> XIntMap a+xintmap_unreserves ks map = + IntSet.fold (\k map -> xintmap_unreserve k map) map ks++-- | Make an exact copy of the 'XIntMap', except that the set of+-- touched wires is initially set to the set of used wires. In other+-- words, we mark all free and reserved wires as untouched.+xintmap_makeclean :: XIntMap a -> XIntMap a+xintmap_makeclean (XIntMap m n free h) = (XIntMap m n free h') where+ h' = IntMap.keysSet m++-- ----------------------------------------------------------------------+-- * Map- and fold-like list combinators++-- ** Combinators for looping++-- | Like 'loop', but also pass a loop counter to the function being+-- iterated. Example:+-- +-- > loop_with_index 3 x f = f 2 (f 1 (f 0 x))+loop_with_index :: (Eq int, Num int) => int -> t -> (int -> t -> t) -> t+loop_with_index n x f = aux 0 x+ where+ aux i x = if i == n then x else aux (i+1) (f i x)++-- | Monadic version of 'loop_with_index'. Thus, +-- +-- > loop_with_indexM 3 x0 f+-- +-- will do the following:+-- +-- > do+-- > x1 <- f 0 x0+-- > x2 <- f 1 x1+-- > x3 <- f 2 x2 +-- > return x3+loop_with_indexM :: (Eq int, Num int, Monad m) => int -> t -> (int -> t -> m t) -> m t+loop_with_indexM n x f = aux 0 x+ where+ aux i x =+ if i == n then return x else do+ x <- f i x+ aux (i+1) x++-- | Iterate a function /n/ times. Example: +-- +-- > loop 3 x f = f (f (f x))+loop :: (Eq int, Num int) => int -> t -> (t -> t) -> t+loop n x f = loop_with_index n x (\_ -> f)++-- | Monadic version of 'loop'.+loopM :: (Eq int, Num int, Monad m) => int -> t -> (t -> m t) -> m t+loopM n x f = loop_with_indexM n x (\_ -> f)++-- ** Combinators for sequencing++-- | A right-to-left version of 'sequence': Evaluate each action in the+-- sequence from right to left, and collect the results.+sequence_right :: Monad m => [m a] -> m [a]+sequence_right [] = return []+sequence_right (x:xs) = do+ ys <- sequence_right xs+ y <- x+ return (y:ys)++-- | Same as 'sequence_right', but ignore the result.+sequence_right_ :: Monad m => [m a] -> m ()+sequence_right_ [] = return ()+sequence_right_ (x:xs) = do+ ys <- sequence_right_ xs+ y <- x+ return ()++-- ** Combinators for zipping++-- | A \"strict\" version of 'zip', i.e., raises an error when the+-- lists are not of the same length.+zip_strict :: [a] -> [b] -> [(a, b)]+zip_strict a b = zip_strict_errmsg a b "zip_strict: lists are not of the same length"++-- | Like 'zip_strict', but also takes an explicit error message to+-- use in case of failure.+zip_strict_errmsg :: [a] -> [b] -> String -> [(a, b)]+zip_strict_errmsg [] [] e = []+zip_strict_errmsg (h:t) (h':t') e = (h,h') : zip_strict_errmsg t t' e+zip_strict_errmsg _ _ e = error e++-- | A \"right strict\" version of 'zip', i.e., raises an error when the+-- left list is shorter than the right one. +zip_rightstrict :: [a] -> [b] -> [(a, b)]+zip_rightstrict a b = zip_rightstrict_errmsg a b "zip_rightstrict: list too short"++-- | A version of 'zip_rightstrict' that also takes an explicit error+-- message to use in case of failure.+zip_rightstrict_errmsg :: [a] -> [b] -> String -> [(a, b)]+zip_rightstrict_errmsg _ [] s = []+zip_rightstrict_errmsg (h:t) (h':t') s = (h,h') : zip_rightstrict_errmsg t t' s+zip_rightstrict_errmsg _ _ s = error s++-- | A \"strict\" version of 'zipWith', i.e., raises an error when the+-- lists are not of the same length.+zipWith_strict :: (a -> b -> c) -> [a] -> [b] -> [c]+zipWith_strict f [] [] = []+zipWith_strict f (h:t) (h':t') = f h h' : zipWith_strict f t t'+zipWith_strict f _ _ = error "zipWith_strict: lists are not of the same length"++-- | A \"right strict\" version of 'zipWith', i.e., raises an error when the+-- right list is shorter than the left one.+zipWith_rightstrict :: (a -> b -> c) -> [a] -> [b] -> [c]+zipWith_rightstrict f _ [] = []+zipWith_rightstrict f (h:t) (h':t') = f h h' : zipWith_rightstrict f t t'+zipWith_rightstrict f _ _ = error "zipWith_rightstrict: list too short"++-- | A right-to-left version of 'Control.Monad.zipWithM', which is+-- also \"right strict\", i.e., raises an error when the right list is+-- shorter than the left one. Example:+-- +-- > zipRightWithM f [a,b] [x,y] = [f a x, f b y],+-- +-- computed right-to-left.+zipRightWithRightStrictM :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m [c]+zipRightWithRightStrictM f l1 l2 =+ sequence_right $ zipWith_rightstrict f l1 l2++-- | Same as 'zipRightWithRightStrictM', but ignore the result.+zipRightWithRightStrictM_ :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m ()+zipRightWithRightStrictM_ f l1 l2 =+ sequence_right_ $ zipWith_rightstrict f l1 l2++-- ** Combinators combining mapping with folding++-- | Fold over two lists with state, and do it right-to-left. For example,+-- +-- > foldRightPairM (w0, [1,2,3], [a,b,c]) f+-- +-- will do the following:+-- +-- > do+-- > w1 <- f (w0, 3, c)+-- > w2 <- f (w1, 2, b)+-- > w3 <- f (w2, 1, a)+-- > return w3+foldRightPairM :: (Monad m) => (w, [a], [b]) -> ((w, a, b) -> m w) -> m w+foldRightPairM (w, [], _) f = return w+foldRightPairM (w, _, []) f = return w+foldRightPairM (w, a:as, b:bs) f = do+ w <- foldRightPairM (w, as, bs) f+ w <- f (w, a, b)+ return w++-- | Like 'foldRightPairM', but ignore the final result.+foldRightPairM_ :: (Monad m) => (w, [a], [b]) -> ((w, a, b) -> m w) -> m ()+foldRightPairM_ x f = do+ foldRightPairM x f+ return ()++-- | Combine right-to-left zipping and folding. Example:+-- +-- > fold_right_zip f (w0, [a,b,c], [x,y,z]) = (w3, [a',b',c'])+-- > where f (w0,c,z) = (w1,c')+-- > f (w1,b,y) = (w2,b')+-- > f (w2,a,x) = (w3,a')+fold_right_zip :: ((w, a, b) -> (w, c)) -> (w, [a], [b]) -> (w, [c])+fold_right_zip f (w, [], []) = (w, [])+fold_right_zip f (w, a:bb, x:yy) = (w2, a':bb')+ where+ (w1, bb') = fold_right_zip f (w, bb, yy)+ (w2, a') = f (w1, a, x)+fold_right_zip f _ = error "fold_right_zip"++-- | Monadic version of 'fold_right_zip'.+fold_right_zipM ::+ (Monad m) => ((w, a, b) -> m(w, c)) -> (w, [a], [b]) -> m(w, [c])+fold_right_zipM f (w, [], []) = return (w, [])+fold_right_zipM f (w, a:bb, x:yy) = do+ (w1, bb') <- fold_right_zipM f (w, bb, yy)+ (w2, a') <- f (w1, a, x)+ return (w2, a':bb')+fold_right_zipM f _ = error "fold_right_zipM"++-- ----------------------------------------------------------------------+-- * Loops.++-- $LOOPS We provide a syntax for \"for\"-style loops.++-- | A \"for\" loop. Counts from /a/ to /b/ in increments of /s/.+-- +-- Standard notation: +-- +-- > for i = a to b by s do+-- > commands +-- > end for+-- +-- Our notation: +-- +-- > for a b s $ \i -> do+-- > commands+-- > endfor++for :: Monad m => Int -> Int -> Int -> (Int -> m()) -> m()+for a b s f = if s > 0 then aux a (<= b) else aux a (>= b)+ where+ aux i cond = + if cond i then do+ f i+ aux (i+s) cond+ else+ return ()++-- | Mark the end of a \"for\"-loop. This command actually does+-- nothing, but can be used to make the loop look prettier.+endfor :: Monad m => m()+endfor = return ()++-- | Iterate a parameter over a list of values. It can be used as+-- follows:+-- +-- > foreach [1,2,3,4] $ \n -> do+-- > <<<loop body depending on the parameter n>>>+-- > endfor+-- +-- The loop body will get executed once for each /n/ ∈ {1,2,3,4}.++foreach :: Monad m => [a] -> (a -> m b) -> m ()+foreach l f = mapM_ f l++-- ----------------------------------------------------------------------+-- * Operations for monads++-- | Every monad is a functor. Input a function /f/ : /a/ → /b/ and output+-- /m/ /f/ : /m/ /a/ → /m/ /b/.+mmap :: (Monad m) => (a -> b) -> m a -> m b+mmap f a = a >>= (return . f)++-- | Remove an outer application of a monad from a monadic function.+monad_join1 :: (Monad m) => m (a -> m b) -> a -> m b+monad_join1 mf a = do+ f <- mf+ f a++-- ----------------------------------------------------------------------+-- * Operations for disjoint unions++-- | Take two functions /f/ : /a/ → /b/ and /g/ : /c/ → /d/, and return+-- /f/ ⊕ /g/ : /a/ ⊕ /c/ → /c/ ⊕ /d/.+map_either :: (a -> b) -> (c -> d) -> Either a c -> Either b d+map_either f g (Left x) = Left (f x)+map_either f g (Right x) = Right (g x)++-- | Monadic version of 'map_either'.+map_eitherM :: (Monad m) => (a -> m b) -> (c -> m d) -> Either a c -> m (Either b d)+map_eitherM f g (Left x) = mmap Left (f x)+map_eitherM f g (Right x) = mmap Right (g x)++-- ----------------------------------------------------------------------+-- * Operations for tuples++-- | Take two functions /f/ : /a/ → /b/ and /g/ : /c/ → /d/, and return+-- /f/ × /g/ : /a/ × /c/ → /c/ × /d/.+map_pair :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)+map_pair f g (x, y) = (f x, g y)++-- | Monadic version of 'map_pair'.+map_pairM :: (Monad m) => (a -> m b) -> (c -> m d) -> (a, c) -> m (b, d)+map_pairM f g (a, c) = do+ b <- f a+ d <- g c+ return (b, d)++-- ----------------------------------------------------------------------+-- * Arithmetic operations+ +-- | A version of the 'ceiling' function that returns an 'Integer'.+int_ceiling :: RealFrac a => a -> Integer+int_ceiling = toInteger . ceiling++-- ----------------------------------------------------------------------+-- * Bit vectors++-- | The type of bit vectors. True = 1, False = 0.+type Boollist = [Bool]++-- | Convert an integer to a bit vector. The first argument is the+-- length in bits, and the second argument the integer to be+-- converted. The conversion is big-headian (or equivalently,+-- little-tailian), i.e., the head of the list holds the integer's most+-- significant digit.+boollist_of_int_bh :: Integral a => Int -> a -> Boollist+boollist_of_int_bh m = reverse . boollist_of_int_lh m++-- | Convert an integer to a bit vector. The first argument is the+-- length in bits, and the second argument the integer to be+-- converted. The conversion is little-headian (or equivalently,+-- big-tailian), i.e., the head of the list holds the integer's least+-- significant digit.+boollist_of_int_lh :: Integral a => Int -> a -> Boollist+boollist_of_int_lh m x | m <= 0 = []+boollist_of_int_lh m x = digit : boollist_of_int_lh (m-1) tail where+ digit = (x `mod` 2 == 1)+ tail = x `div` 2++-- | Convert a bit vector to an integer. The conversion is big-headian+-- (or equivalently, little-tailian), i.e., the head of the list holds+-- the integer's most significant digit. This function is unsigned,+-- i.e., the integer returned is ≥ 0.+int_of_boollist_unsigned_bh :: Integral a => Boollist -> a+int_of_boollist_unsigned_bh v = aux v 0+ where+ aux v acc =+ case v of+ [] -> acc+ digit : vs -> aux vs (2*acc+(if digit then 1 else 0))++-- | Convert a bit vector to an integer, signed.+int_of_boollist_signed_bh :: Integral a => Boollist -> a+int_of_boollist_signed_bh [] = 0+int_of_boollist_signed_bh (False:v) = int_of_boollist_unsigned_bh v+int_of_boollist_signed_bh (True:v) = -1 - int_of_boollist_unsigned_bh (map not v)++-- | Exclusive or operation on booleans.+bool_xor :: Bool -> Bool -> Bool+bool_xor a b = (a /= b)++-- | Exclusive or operation on bit vectors.+boollist_xor :: Boollist -> Boollist -> Boollist+boollist_xor = zipWith bool_xor++-- ----------------------------------------------------------------------+-- * Formatting of lists and strings++-- | A general list-to-string function. Example:+-- +-- > string_of_list "{" ", " "}" "{}" show [1,2,3] = "{1, 2, 3}"+string_of_list :: String -> String -> String -> String -> (t -> String) -> [t] -> String+string_of_list lpar comma rpar nil string_of_elt lst =+ let string_of_tail lst =+ case lst of+ [] -> ""+ h:t -> comma ++ string_of_elt h ++ string_of_tail t+ in+ case lst of+ [] -> nil+ h:t -> lpar ++ string_of_elt h ++ string_of_tail t ++ rpar++-- | @'optional' b s@: if /b/ = 'True', return /s/, else the empty+-- string. This function is for convenience.+optional :: Bool -> String -> String+optional True s = s+optional False s = ""++-- ----------------------------------------------------------------------+-- * Lists optimized for fast concatenation++-- | The type of bidirectional lists. This is similar to [a], but+-- optimized for fast concatenation and appending on both sides.+newtype BList a = BList { getBList :: [a] -> [a] }++-- | Convert a List to a 'BList'.+blist_of_list :: [a] -> BList a+blist_of_list s = BList (\x -> s ++ x)++-- | Convert a 'BList' to a List.+list_of_blist :: BList a -> [a]+list_of_blist buf = getBList buf []++-- | Fast concatenation of 'BList's or string buffers.+(+++) :: BList a -> BList a -> BList a+(+++) buf1 buf2 = BList ((getBList buf1) . (getBList buf2))++-- | The empty 'BList'.+blist_empty :: BList a+blist_empty = BList id++-- | Concatenate a list of 'BList's.+blist_concat :: [BList a] -> BList a+blist_concat l = foldr (+++) blist_empty l++instance (Show a) => Show (BList a) where+ show bl = show (list_of_blist bl) ++-- ----------------------------------------------------------------------+-- * Strings optimized for fast concatenation++-- | A string buffer holds a string that is optimized for fast+-- concatenation. Note that this is an instance of 'BList', and hence+-- 'BList' operations (in particular '+++') can be applied to string+-- buffers. The following functions are synonyms of the respective+-- 'BList' functions, and are provided for convenience.+type Strbuf = BList Char++-- | Convert a string to a string buffer.+strbuf_of_string :: String -> Strbuf+strbuf_of_string = blist_of_list++-- | Convert a string buffer to a string.+string_of_strbuf :: Strbuf -> String+string_of_strbuf = list_of_blist++-- | The empty string buffer.+strbuf_empty :: Strbuf+strbuf_empty = blist_empty++-- | Concatenate a list of string buffers.+strbuf_concat :: [Strbuf] -> Strbuf+strbuf_concat = blist_concat++-- ----------------------------------------------------------------------+-- * The identity monad+ +-- | The identity monad. Using /m/ = 'Id' gives useful special cases+-- of monadic functions.+newtype Id a = Id { getId :: a }++instance Monad Id where+ return a = Id a+ (Id a) >>= b = b a++instance Applicative Id where+ pure = return+ (<*>) = ap++instance Functor Id where+ fmap = liftM++-- ----------------------------------------------------------------------+-- * Identity types+ +-- | The type 'Identity' /a/ /b/ witnesses the fact that /a/ and /b/+-- are the same type. In other words, this type is non-empty if and+-- only if /a/ = /b/. This property is not guaranteed by the type+-- system, but by the API, via the fact that the operators+-- 'reflexivity', 'symmetry', and 'transitivity' are the only exposed+-- constructors for this type. The implementation of this type is+-- deliberately hidden, as this is the only way to guarantee its+-- defining property.+-- +-- Identity types are useful in certain situations. For example, they+-- can be used to define a data type which is polymorphic in some type+-- variable /x/, and which has certain constructors that are only+-- available when /x/ is a particular type. For example, in the+-- declaration+-- +-- > data ExampleType x = Constructor1 x | Constructor2 x (Identity x Bool),+-- +-- @Constructor1@ is available for all /x/, but @Constructor2@ is only+-- available when /x/ = 'Bool'.+newtype Identity a b = Identity (a -> b, b -> a)++-- | Witness the fact that /a/=/a/.+reflexivity :: Identity a a+reflexivity = Identity (id, id)++-- | Witness the fact that /a/=/b/ implies /b/=/a/.+symmetry :: Identity a b -> Identity b a+symmetry (Identity (f,g)) = Identity (g,f)++-- | Witness the fact that /a/=/b/ and /b/=/c/ implies /a/=/c/.+transitivity :: Identity a b -> Identity b c -> Identity a c+transitivity (Identity (f,g)) (Identity (f',g')) = Identity (f'',g'') where+ f'' = f' . f+ g'' = g . g'++-- | The identity function 'id' : /a/ → /b/, provided that /a/ and /b/+-- are the same type.+identity :: Identity a b -> a -> b+identity (Identity (f,g)) = f++instance Show (Identity a b) where+ show x = "id"++-- ======================================================================+-- * Error messages++-- | Often a low-level function, such as+-- 'Quipper.Internal.QData.qcdata_zip' or+-- 'Quipper.Internal.QData.qcdata_promote', throws an error because of+-- a failure of some low-level condition, such as \"list too+-- short\". To produce error messages that are meaningful to+-- user-level code, these functions do not have a hard-coded error+-- message. Instead, they input a stub error message.+-- +-- A meaningful error message typically consists of at least three parts:+-- +-- * the name of the user-level function where the error occurred, for+-- example: \"reverse_generic\";+-- +-- * what the function was doing when the error occurred, for example:+-- \"operation not permitted in reversible circuit\";+-- +-- * a specific low-level reason for the error, for example: \"dynamic+-- lifting\".+-- +-- Thus, a meaningful error message may be: \"reverse_generic:+-- operation not permitted in reversible circuit: dynamic lifting\".+-- +-- The problem is that the three pieces of information are not usually+-- present in the same place. The user-level function is often a+-- wrapper function that performs several different mid-level+-- operations (e.g., transforming, reversing). The mid-level function+-- knows what operation was being performed when the error occurred,+-- but often calls a lower-level function to do the actual work (e.g.,+-- encapsulating).+-- +-- Therefore, a stub error message is a function that inputs some+-- lower-level reason for a failure (example: \"list too short\") and+-- translates this into a higher-level error message (example:+-- \"qterm: shape of parameter does not data: list too short\").+-- +-- Sometimes, the stub error message may also ignore the low-level+-- message and completely replace it by a higher-level one. For+-- example, a function that implements integers as bit lists may wish+-- to report a problem with integers, rather than a problem with the+-- underlying lists.+type ErrMsg = String -> String++-- ======================================================================+-- * The Curry type class++-- | The 'Curry' type class is used to implement functions that have a+-- variable number of arguments. It provides a family of type+-- isomorphisms+-- +-- @fun ≅ args -> res,@+-- +-- where+-- +-- > fun = a1 -> a2 -> ... -> an -> res,+-- > args = (a1, (a2, (..., (an, ())))).++class Curry fun args res | args res -> fun where+ -- | Multiple curry: map a function + -- (/a/[sub 1], (/a/[sub 2], (…, ())) → /b/ + -- to its curried form + -- /a/[sub 1] → /a/[sub 2] → … → /b/.+ mcurry :: (args -> res) -> fun+ -- | Multiple uncurry: map a function+ -- /a/[sub 1] → /a/[sub 2] → … → /b/+ -- to its uncurried form + -- (/a/[sub 1], (/a/[sub 2], (…, ())) → /b/.+ muncurry :: fun -> (args -> res)+ +instance Curry b () b where+ mcurry g = g ()+ muncurry x = const x++instance Curry fun args res => Curry (a -> fun) (a,args) res where+ mcurry g x = mcurry (\xs -> g (x,xs))+ muncurry f (x,xs) = muncurry (f x) xs+
+ Quipper/Utils/CommandLine.hs view
@@ -0,0 +1,66 @@+-- | This module provides some functions that are useful in the+-- processing of command line options, and that are shared between+-- several algorithms.++module Quipper.Utils.CommandLine where++import Quipper.Utils.Auxiliary (string_of_list)++-- import other stuff+import System.Exit+import System.IO+import Data.List+import Data.Char++-- ----------------------------------------------------------------------+-- * Option processing+ +-- | Exit with an error message after a command line error. This also+-- outputs information on where to find command line help.+optfail :: String -> IO a+optfail msg = do+ hPutStr stderr msg+ hPutStrLn stderr "Try --help for more info."+ exitFailure++-- | Parse a string to an integer, or return 'Nothing' on failure.+parse_int :: (Integral r) => String -> Maybe r+parse_int s = case reads s of+ [(n, "")] -> Just (fromInteger n)+ _ -> Nothing++-- | Parse a string to a list of integers, or return 'Nothing' on failure.+parse_list_int :: String -> Maybe [Int] +parse_list_int s = case reads s of+ [(ns, "")] -> Just ns+ _ -> Nothing++-- | Parse a string to a 'Double', or return 'Nothing' on failure.+parse_double :: String -> Maybe Double+parse_double s = case reads s of+ [(n, "")] -> Just n+ _ -> Nothing++-- | In an association list, find the key that best matches the given+-- string. If one key matches exactly, return the corresponding+-- key-value pair. Otherwise, return a list of all key-value pairs+-- whose key have the given string as a prefix. This list could be of+-- length 0 (no match), 1 (unique match), or greater (ambiguous key).+-- Note: the keys in the association list must be lower case. The+-- input string is converted to lower case as well, resulting in+-- case-insensitive matching.+match_enum :: [(String, a)] -> String -> [(String, a)]+match_enum list key =+ case lookup s list of+ Just v -> [(s,v)]+ Nothing -> filter (\(k,v) -> isPrefixOf s k) list+ where+ s = map toLower key+ +-- | Pretty-print a list of possible values for a parameter. The+-- first argument is the name of the parameter, and the second+-- argument is its enumeration.+show_enum :: String -> [(String, a)] -> String +show_enum param list =+ "Possible values for " ++ param ++ " are: " +++ string_of_list "" ", " "" "no possible values" fst list ++ ".\n"
+ Quipper/Utils/PortableSignals.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE CPP #-}++-- | This module provides a thin portability layer for handling user+-- interrupts.+-- +-- The reason is that in the standard Haskell library, this+-- functionality is only available in operating system specific+-- modules, namely "System.Posix.Signals" (for POSIX systems,+-- including Linux) and "GHC.ConsoleHandler" (for Windows).+-- +-- Note that despite this compatibility layer, there are some+-- operating system specific quirks:+-- +-- * In Windows, console events (such as Control-C) can only be+-- received by an application running in a Windows console. Certain+-- environments that look like consoles do not support console events,+-- such as xterm and rxvt windows, and Cygwin shells with @CYGWIN=tty@+-- set.+-- +-- * In Windows, setting a handler for any one signal automatically+-- overrides the handlers for all signals (effectively ignoring them).+-- Also, if the 'Default' or 'Ignore' handler is specified, it+-- applies to all signals. We do not currently provide a way to+-- specify handlers for multiple signals.++module Quipper.Utils.PortableSignals (+ Signal(..),+ Handler(Default,Ignore,Catch,CatchOnce),+ installHandler,+ with_handler+ ) where++#ifdef mingw32_HOST_OS+import qualified GHC.ConsoleHandler as OS+#else+import qualified System.Posix.Signals as OS+#endif+ +-- ----------------------------------------------------------------------+-- * Common interface++-- | A data type for signals. This can be extended as needed.+data Signal =+ Interrupt -- ^ Control-C event.+ | Close -- ^ TERM signal (POSIX) or Close event (Windows).++-- | A data type for handlers.+data Handler =+ Default -- ^ Default action.+ | Ignore -- ^ Ignore the signal.+ | Catch (IO ()) -- ^ Handle the signal in a new thread when the signal is received.+ | CatchOnce (IO ()) -- ^ Like 'Catch', but only handle the first such signal.+ | OSHandler OS.Handler -- ^ An operating system specific handler.++-- | Install a handler for the given signal. The old handler is+-- returned. +installHandler :: Signal -> Handler -> IO Handler+#ifdef mingw32_HOST_OS+installHandler = installHandler_windows+#else+installHandler = installHandler_posix+#endif++-- | Run a block of code with a given signal handler. The previous+-- handler is restored when the block terminates.+with_handler :: Signal -> Handler -> IO a -> IO a+with_handler signal handler body = do+ oldhandler <- installHandler signal handler+ a <- body+ installHandler signal oldhandler+ return a++-- ----------------------------------------------------------------------+-- * Windows specific code++#ifdef mingw32_HOST_OS++-- | Check if the Windows 'ConsoleEvent' matches the given abstract+-- 'Signal'. We implement this as a relation, rather than a function,+-- to allow for more than one 'ConsoleEvent' to match the same+-- 'Signal', or for more than one 'Signal' to match the same+-- 'ConsoleEvent'.+signal_matches :: OS.ConsoleEvent -> Signal -> Bool+signal_matches OS.ControlC Interrupt = True+signal_matches OS.Close Close = True+signal_matches _ _ = False++-- | Windows implementation of 'installHandler'.+installHandler_windows :: Signal -> Handler -> IO Handler+installHandler_windows signal handler = do+ oldhandler <- OS.installHandler (oshandler handler)+ return (OSHandler oldhandler)+ where+ oshandler Default = OS.Default+ oshandler Ignore = OS.Ignore+ oshandler (Catch body) = OS.Catch $ \event -> do+ if signal_matches event signal+ then body + else return ()+ oshandler (CatchOnce body) = OS.Catch $ \event -> do+ if signal_matches event signal + then do+ -- uninstall the handler+ OS.installHandler OS.Default+ body+ else return ()+ oshandler (OSHandler h) = h+ +-- ----------------------------------------------------------------------+-- * POSIX specific code++#else++-- | Map an abstract 'Signal' to a POSIX specific 'OS.Signal'.+ossignal :: Signal -> OS.Signal+ossignal Interrupt = OS.keyboardSignal+ossignal Close = OS.softwareTermination++-- | Map a 'Handler' to a POSIX specific handler.+oshandler :: Handler -> OS.Handler+oshandler Default = OS.Default+oshandler Ignore = OS.Ignore+oshandler (Catch body) = OS.Catch body+oshandler (CatchOnce body) = OS.CatchOnce body+oshandler (OSHandler h) = h++-- | POSIX implementation of 'installHandler'.+installHandler_posix :: Signal -> Handler -> IO Handler+installHandler_posix signal handler = do+ oldhandler <- OS.installHandler (ossignal signal) (oshandler handler) Nothing+ return (OSHandler oldhandler)++#endif
+ Quipper/Utils/Preview.hs view
@@ -0,0 +1,84 @@+-- | Platform dependent previewing of PDF files. On Windows, we try to+-- run Acrobat Reader. On Mac, we try to run Preview. On Linux, we try+-- to run Acrobat Reader or Xpdf. If this fails, we abort the program+-- with a platform dependent error message.++module Quipper.Utils.Preview where++import Control.Exception+import System.Environment+import System.Exit+import System.Info+import System.IO+import System.IO.Error+import System.Process++-- | Sequentially try one or more IO computations, until one of them+-- completes without an IO error. If all of them fail, re-throw the+-- error from the last one.+try_several_IO :: [IO a] -> IO a+try_several_IO [] = error "try_several_IO"+try_several_IO [h] = do+ catchIOError h (\e -> throw e)+try_several_IO (h:t) = do+ catchIOError h (\e -> try_several_IO t)++-- | @'system_pdf_viewer' zoom pdffile@: Call a system-specific PDF+-- viewer on /pdffile/ file. The /zoom/ argument is out of 100 and may+-- or may not be ignored by the viewer.+system_pdf_viewer :: Double -> String -> IO ()+system_pdf_viewer zoom pdffile = do+ envList <- getEnvironment+ if (elem ("OS", "Windows_NT") envList) then+ windows_pdf_viewer zoom pdffile+ else if (os == "darwin") then+ macos_pdf_viewer zoom pdffile+ else+ linux_pdf_viewer zoom pdffile++-- | Like 'system_pdf_viewer', but specialized to Windows.+windows_pdf_viewer :: Double -> String -> IO ()+windows_pdf_viewer zoom pdffile = catchIOError body handler+ where+ body = do+ r <- system ("start /WAIT AcroRd32 " ++ pdffile)+ case r of+ ExitSuccess -> return ()+ ExitFailure n -> acrord32_error n+ handler e = do+ name <- getProgName+ hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that Acrobat Reader is installed."+ exitFailure+ acrord32_error n = do+ name <- getProgName+ hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that Acrobat Reader is installed."+ exitFailure+ ++-- | Like 'system_pdf_viewer', but specialized to Mac OS.+macos_pdf_viewer :: Double -> String -> IO ()+macos_pdf_viewer zoom pdffile = catchIOError body handler+ where+ body = do+ rawSystem "open" [pdffile]+ rawSystem "sleep" ["1"] -- required or the file may be deleted too soon+ return ()+ handler e = do+ name <- getProgName+ hPutStrLn stderr $ name ++ ": unable to preview PDF file. There seems to be a problem with Preview."+ exitFailure+ +-- | Like 'system_pdf_viewer', but specialized to Linux.+linux_pdf_viewer :: Double -> String -> IO ()+linux_pdf_viewer zoom pdffile = catchIOError body handler+ where+ body = do+ try_several_IO [+ rawSystem "acroread" ["/a", "zoom=" ++ show zoom, pdffile],+ rawSystem "xpdf" ["-z", show zoom, pdffile]+ ]+ return ()+ handler e = do+ name <- getProgName+ hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that either Acrobat Reader or Xpdf are installed."+ exitFailure
+ Quipper/Utils/RandomSource.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}++-- | This module provides a container type for sources of+-- randomness. This makes it possible for a source of randomness (any+-- instance of the 'RandomGen' class) to be stored in a data structure+-- without having to specify its type explicitly.++module Quipper.Utils.RandomSource where++import System.Random++-- | A container type to hold a source of randomness. This can hold+-- any instance of the 'RandomGen' class.+data RandomSource where+ RandomSource :: forall g.(RandomGen g) => g -> RandomSource++instance Show RandomSource where+ show x = "g"
+ Quipper/Utils/Sampling.hs view
@@ -0,0 +1,279 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}++-- --------------------------------------------------------------------+-- | This module provides functions for generating lists of samples+-- from a range of input values. This is primarily useful for+-- generating test cases. Ranges can be specified for types that are+-- members of the 'Interval' class. Each sampling procedure generates+-- a (finite or infinite) list of values from the range. We provide+-- sampling procedures for+-- +-- * generating the range in its entirety ('sample_all')+-- +-- * sampling every /n/th element from a range ('sample_step')+-- +-- * generating a random sample from the range ('sample_random')++module Quipper.Utils.Sampling (+ + -- * Interval class+ Interval(..),+ + -- * Zero class+ Zero(..),+ + -- * Random class+ -- $Random+ Random,+ + -- * Functions+ sample_all,+ sample_step,+ sample_random,+ sample_all0,+ sample_step0,+ sample_random0 + ) where++import Quipper.Utils.Tuple++import System.Random+import Data.Tuple+import Data.List++-- --------------------------------------------------------------------+-- | The 'Interval' class contains types for which an interval of+-- values can be specified by giving a lower bound and an upper+-- bound. Intervals are specified as @'interval' min max@, for+-- example: +-- +-- > interval (0,0) (1,2) = [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)].++class Interval a where+ -- | Takes a range (/min/,/max/) and returns a list of all values with+ -- lower bound /min/ and upper bound /max/.+ interval :: a -> a -> [a]++instance Interval Int where+ interval x y = [x..y]+ +instance Interval Integer where+ interval x y = [x..y]++instance Interval Double where+ interval x y = [x..y]+ +instance Interval Bool where+ interval x y = [x..y]++instance Interval () where+ interval () () = [()]+ +instance (Interval a, Interval b) => Interval (a,b) where+ interval (x0,y0) (x1,y1) = [ (x,y) | x <- interval x0 x1, y <- interval y0 y1 ]++instance (Interval a, Interval b, Interval c) => Interval (a,b,c) where+ interval x y = map tuple (interval (untuple x) (untuple y))+ +instance (Interval a, Interval b, Interval c, Interval d) => Interval (a,b,c,d) where+ interval x y = map tuple (interval (untuple x) (untuple y))+ +instance (Interval a, Interval b, Interval c, Interval d, Interval e) => Interval (a,b,c,d,e) where+ interval x y = map tuple (interval (untuple x) (untuple y))+ +instance (Interval a, Interval b, Interval c, Interval d, Interval e, Interval f) => Interval (a,b,c,d,e,f) where+ interval x y = map tuple (interval (untuple x) (untuple y))+ +instance (Interval a, Interval b, Interval c, Interval d, Interval e, Interval f, Interval g) => Interval (a,b,c,d,e,f,g) where+ interval x y = map tuple (interval (untuple x) (untuple y))+ +instance Interval a => Interval [a] where+ interval x y = l where+ xy = safe_zip x y "interval: upper and lower bound contain lists of non-matching lengths"+ l = aux xy+ aux [] = [[]]+ aux ((x,y):t) = [ h:t' | h <- interval x y, t' <- aux t ]++-- --------------------------------------------------------------------+-- | Types in the 'Zero' class have an \"origin\", i.e., an element+-- that can conveniently serve as the starting point for intervals.++class Zero a where+ -- | Inputs any element of the type and outputs the corresponding+ -- \"zero\" element, for example:+ -- + -- > zero ([1,2],3,True) = ([0,0],0,False)+ zero :: a -> a+ +instance Zero Int where+ zero _ = 0+ +instance Zero Integer where+ zero _ = 0++instance Zero Double where+ zero _ = 0++instance Zero Bool where+ zero _ = False++instance Zero () where+ zero () = ()++instance (Zero a, Zero b) => Zero (a,b) where+ zero (a,b) = (zero a, zero b)+ +instance (Zero a, Zero b, Zero c) => Zero (a,b,c) where+ zero x = tuple (zero (untuple x))+ +instance (Zero a, Zero b, Zero c, Zero d) => Zero (a,b,c,d) where+ zero x = tuple (zero (untuple x))+ +instance (Zero a, Zero b, Zero c, Zero d, Zero e) => Zero (a,b,c,d,e) where+ zero x = tuple (zero (untuple x))+ +instance (Zero a, Zero b, Zero c, Zero d, Zero e, Zero f) => Zero (a,b,c,d,e,f) where+ zero x = tuple (zero (untuple x))+ +instance (Zero a, Zero b, Zero c, Zero d, Zero e, Zero f, Zero g) => Zero (a,b,c,d,e,f,g) where+ zero x = tuple (zero (untuple x))+ +instance Zero a => Zero [a] where+ zero l = map zero l+ +-- --------------------------------------------------------------------+-- $Random +-- We extend the class 'System.Random' with tuples and lists.++-- | 0-tuples+instance Random () where+ randomR ((),()) g = ((), g)+ random g = ((), g)++-- | Pairs+instance (Random a, Random b) => Random (a,b) where+ randomR ((a0,b0),(a1,b1)) g = ((a,b), g'') where+ (a,g') = randomR (a0,a1) g+ (b,g'') = randomR (b0,b1) g'+ random g = ((a,b), g'') where+ (a,g') = random g+ (b,g'') = random g'++-- | Triples+instance (Random a, Random b, Random c) => Random (a,b,c) where+ randomR (a,b) g = (t, g') where+ a1 = untuple a+ b1 = untuple b+ (t1,g') = randomR (a1,b1) g+ t = tuple t1+ random g = (t, g') where+ (t1,g') = random g+ t = tuple t1++-- | 4-Tuples+instance (Random a, Random b, Random c, Random d) => Random (a,b,c,d) where+ randomR (a,b) g = (t, g') where+ a1 = untuple a+ b1 = untuple b+ (t1,g') = randomR (a1,b1) g+ t = tuple t1+ random g = (t, g') where+ (t1,g') = random g+ t = tuple t1++-- | 5-Tuples+instance (Random a, Random b, Random c, Random d, Random e) => Random (a,b,c,d,e) where+ randomR (a,b) g = (t, g') where+ a1 = untuple a+ b1 = untuple b+ (t1,g') = randomR (a1,b1) g+ t = tuple t1+ random g = (t, g') where+ (t1,g') = random g+ t = tuple t1++-- | 6-Tuples+instance (Random a, Random b, Random c, Random d, Random e, Random f) => Random (a,b,c,d,e,f) where+ randomR (a,b) g = (t, g') where+ a1 = untuple a+ b1 = untuple b+ (t1,g') = randomR (a1,b1) g+ t = tuple t1+ random g = (t, g') where+ (t1,g') = random g+ t = tuple t1++-- | 7-Tuples+instance (Random a, Random b, Random c, Random d, Random e, Random f, Random g) => Random (a,b,c,d,e,f,g) where+ randomR (a,b) g = (t, g') where+ a1 = untuple a+ b1 = untuple b+ (t1,g') = randomR (a1,b1) g+ t = tuple t1+ random g = (t, g') where+ (t1,g') = random g+ t = tuple t1++-- | Lists+instance Random a => Random [a] where+ randomR (a,b) g = (l, g') where+ ab = safe_zip a b "randomR: upper and lower bound contain lists of non-matching lengths"+ (g', l) = mapAccumL (\g r -> swap $ randomR r g) g ab+ random g = ([a], g') where+ (a, g') = random g++-- --------------------------------------------------------------------+-- Functions:++-- | @'sample_all' min max@: +-- returns a list of all elements from the range (/min/,/max/). This+-- is actually just a synonym of 'interval'.+sample_all :: Interval a => a -> a -> [a]+sample_all = interval++-- | @'sample_step' n k min max@: +-- returns every /n/th element from the range (/min/,/max/), starting+-- with the /k/th element.+sample_step :: (Integral a, Integral b, Interval c) => a -> b -> c -> c -> [c]+sample_step n k x y = list_step n k (interval x y)++-- | @'sample_random' g min max@: +-- returns an infinite list of random samples from the range+-- (/min/,/max/), using the random number generator /g/.+sample_random :: (Random a, RandomGen g) => g -> a -> a -> [a]+sample_random g x y = randomRs (x,y) g++-- | A variant of 'sample_all' that omits the /min/ argument, and uses+-- the 'zero' element of the type instead.+sample_all0 :: (Zero a, Interval a) => a -> [a]+sample_all0 a = sample_all (zero a) a++-- | A variant of 'sample_step' that omits the /min/ argument, and uses+-- the 'zero' element of the type instead.+sample_step0 :: (Integral a, Integral b, Zero c, Interval c) => a -> b -> c -> [c]+sample_step0 n k a = sample_step n k (zero a) a++-- | A variant of 'sample_random' that omits the /min/ argument, and uses+-- the 'zero' element of the type instead.+sample_random0 :: (Random a, Zero a, RandomGen g) => g -> a -> [a]+sample_random0 g a = sample_random g (zero a) a++-- --------------------------------------------------------------------+-- Local functions:++-- | samples every /n/th element from the list, starting with element /k/+list_step :: (Integral a, Integral b) => a -> b -> [c] -> [c]+list_step n k [] = []+list_step n k (h:t) =+ if k==0 then + h:(list_step n (n-1) t) + else+ list_step n (k-1) t+ +-- | same as 'zip', but throw an error if length don't match+safe_zip :: [a] -> [b] -> String -> [(a,b)]+safe_zip l1 l2 msg = + if length l1 == length l2 + then zip l1 l2+ else error msg
+ Quipper/Utils/Stabilizers/Clifford.hs view
@@ -0,0 +1,731 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE BangPatterns #-}++-- | This module contains an implementation of a quantum simulator that +-- uses the stabilizer states of the Clifford group (i.e. the Pauli group),+-- to provide efficient simulation of quantum circuits constructed from+-- elements of the Clifford group. The module provides an implementation+-- of the Clifford group operators {x,y,z,h,s,controlled-x} which form a+-- generating set for the Clifford group.+module Quipper.Utils.Stabilizers.Clifford where++import Prelude hiding (lookup,negate)+import Quipper.Utils.Stabilizers.Pauli+import Data.List (foldl')+import Data.Map (Map)+import qualified Data.Map as Map+import Control.Monad.State+import System.Random+import Quantum.Synthesis.Ring (Cplx (..), i)++-- | A qubit is defined as an integer reference.+type Qubit = Int++-- | The state of the system is a representation of a stabilizer tableau.++-- note this isn't a record, so as to help with strictness annotations +data Tableau = ST Qubit !(Map Qubit Sign) !(Map (Qubit,Qubit) Pauli) !(Map Qubit Sign) !(Map (Qubit,Qubit) Pauli)++-- | Accessor function for the next_qubit field of a Tableau+next_qubit :: Tableau -> Qubit+next_qubit (ST nq _ _ _ _) = nq++-- | Accessor function for the sign field of a Tableau+sign :: Tableau -> Map Qubit Sign+sign (ST _ s _ _ _) = s++-- | Accessor function for the tableau field of a Tableau+tableau :: Tableau -> Map (Qubit,Qubit) Pauli+tableau (ST _ _ t _ _) = t++-- | Accessor function for the de_sign field of a Tableau+de_sign :: Tableau -> Map Qubit Sign+de_sign (ST _ _ _ de_s _) = de_s++-- | Accessor function for the de_tableau field of a Tableau+de_tableau :: Tableau -> Map (Qubit,Qubit) Pauli+de_tableau (ST _ _ _ _ de_t) = de_t+++-- | A local Map lookup function that throws an error if the key doesn't exist.+lookup :: (Ord k,Show k, Show v) => k -> Map k v -> v+lookup k m = + case Map.lookup k m of+ Just b -> b+ Nothing -> error ("key: " ++ show k ++ " not in map: " ++ show m)++-- | A tableau can be shown, by enumerating over the qubits in scope.+instance Show Tableau where+ show tab = unlines $ ("Stabilizer:":map show_row qs) ++ ("Destabilizer:":map show_de_row qs)+ where + qs :: [Qubit]+ qs = [0..(next_qubit tab) - 1]+ show_row :: Qubit -> String + show_row q_row = show (lookup q_row (sign tab)) + ++ unwords (map (show_pauli q_row) qs)+ show_pauli :: Qubit -> Qubit -> String+ show_pauli q_row q_column = show (lookup (q_row,q_column) (tableau tab))+ show_de_row :: Qubit -> String + show_de_row q_row = show (lookup q_row (de_sign tab)) + ++ unwords (map (show_de_pauli q_row) qs)+ show_de_pauli :: Qubit -> Qubit -> String+ show_de_pauli q_row q_column = show (lookup (q_row,q_column) (de_tableau tab))++-- | An initial (empty) tableau.+empty_tableau :: Tableau+empty_tableau = ST 0 Map.empty Map.empty Map.empty Map.empty++-- | A new qubit in the state |0〉 or |1〉 can be added to a tableau.+add_qubit :: Bool -> Tableau -> Tableau+add_qubit b tab = ST (nq + 1) sign' tableau' de_sign' de_tableau'+ where+ nq = next_qubit tab+ sign' = Map.insert nq (if b then Minus else Plus) (sign tab)+ de_sign' = Map.insert nq Plus (de_sign tab)+ tableau' = foldl' insertI (foldl' insertZ (tableau tab) [0..nq]) [0..nq-1]+ de_tableau' = foldl' insertI (foldl' insertX (de_tableau tab) [0..nq]) [0..nq-1]+ insertZ :: Map (Qubit,Qubit) Pauli -> Qubit -> Map (Qubit,Qubit) Pauli+ insertZ tab cq = Map.insert (nq,cq) (if nq == cq then Z else I) tab+ insertX :: Map (Qubit,Qubit) Pauli -> Qubit -> Map (Qubit,Qubit) Pauli+ insertX tab cq = Map.insert (nq,cq) (if nq == cq then X else I) tab+ insertI :: Map (Qubit,Qubit) Pauli -> Qubit -> Map (Qubit,Qubit) Pauli+ insertI tab cq = Map.insert (cq,nq) I tab++-- | A (Clifford) unitary can be defined as a function acting on Pauli operators.+type Unitary = Pauli -> (Sign,Pauli)++instance Eq Unitary where+ u1 == u2 = and [ u1 x == u2 x | x <- ixyz]+ where ixyz = [I,X,Y,Z] ++-- for a unitary U, the action on each Pauli (P) should be defined+-- as the result of UPU*. A complete set of generators for the Clifford+-- group is defined below, so defining a Unitary shouldn't be required+-- at the user-level++-- | The minimal definition of a unitary requires the actions on /X/ and /Z/.+data MinPauli = Xmin | Zmin++-- | The minimal definition of a unitary requires the actions on /X/ and /Z/.+type MinUnitary = MinPauli -> (Sign,Pauli)++-- | The definition of a 'Unitary' can be constructed from a 'MinUnitary'.+from_minimal :: MinUnitary -> Unitary+from_minimal f I = (Plus,I)+from_minimal f X = f Xmin+from_minimal f Z = f Zmin+from_minimal f Y = (sign,pauli)+ where+ (sx,px) = f Xmin+ (sz,pz) = f Zmin+ (spc,pauli) = commute px pz+ sign = signPlus_to_sign $ multiply_signPlus (multiply_signPlus (One sx) (One sz)) (multiply_signPlus (PlusI) (spc))++-- | It is possible to construct a 'Unitary' from a 2×2-matrix.+from_matrix :: (Floating r, Eq r, Show r) => Matrix1 (Cplx r) -> Unitary+from_matrix m = from_minimal minimal+ where+ minimal xy = sp+ where+ xy' = case xy of + Xmin -> X+ Zmin -> Z+ m_dagger = transpose1 m+ sp = fromMatrix1 $ multiplyMatrix1 m (multiplyMatrix1 (toMatrix1 xy') m_dagger)+ +-- | A unitary can be applied to a qubit in a given tableau. By folding through each row+apply_unitary :: Unitary -> Qubit -> Tableau -> Tableau+apply_unitary u q_column tab = foldl' (apply_unitary_row u q_column) tab [0..nq-1]+ where+ nq = next_qubit tab++-- | Apply the unitary to the given column, in the given row.+apply_unitary_row :: Unitary -> Qubit -> Tableau -> Qubit -> Tableau+apply_unitary_row u q_column tab q_row = ST (next_qubit tab) sign' tableau' de_sign' de_tableau'+ where + s = sign tab+ current_sign = lookup q_row s+ t = tableau tab+ current_pauli = lookup (q_row,q_column) t+ (change_sign,new_pauli) = u current_pauli+ new_sign = if negative change_sign then negate current_sign else current_sign+ sign' = Map.insert q_row new_sign s+ tableau' = Map.insert (q_row,q_column) new_pauli t+ de_s = de_sign tab+ de_current_sign = lookup q_row de_s+ de_t = de_tableau tab+ de_current_pauli = lookup (q_row,q_column) de_t+ (de_change_sign,de_new_pauli) = u de_current_pauli+ de_new_sign = if negative de_change_sign then negate de_current_sign else de_current_sign+ de_sign' = Map.insert q_row de_new_sign de_s+ de_tableau' = Map.insert (q_row,q_column) de_new_pauli de_t++-- | A two-qubit (Clifford) unitary can be defined as a function acting+-- on a pair of Pauli operators.+type Unitary2 = (Pauli,Pauli) -> (Sign,Pauli,Pauli)++instance Eq Unitary2 where+ u1 == u2 = and [ u1 (x,y) == u2 (x,y) | x <- ixyz, y <- ixyz]+ where ixyz = [I,X,Y,Z] ++-- | The minimal definition of a two-qubit unitary requires the actions on /IX/, /XI/, /IZ/, and /ZI/.+data MinPauli2 = IX | XI | IZ | ZI++-- | The minimal definition of a two-qubit unitary requires the actions on /IX/, /XI/, /IZ/, and /ZI/.+type MinUnitary2 = MinPauli2 -> (Sign,Pauli,Pauli)++-- | The definition of a 'Unitary2' can be constructed from a 'MinUnitary2'.+from_minimal2 :: MinUnitary2 -> Unitary2+from_minimal2 f (I,I) = (Plus,I,I)+from_minimal2 f (I,X) = f IX+from_minimal2 f (X,I) = f XI+from_minimal2 f (I,Z) = f IZ+from_minimal2 f (Z,I) = f ZI+from_minimal2 f (I,Y) = (sign,p1,p2)+ where+ (six,pix1,pix2) = from_minimal2 f (I,X) + (siz,piz1,piz2) = from_minimal2 f (I,Z)+ (spc1,p1) = commute pix1 piz1+ (spc2,p2) = commute pix2 piz2+ sign = signPlus_to_sign $ multiply_signPlus (PlusI) (multiply_signPlus (multiply_signPlus (One six) (One siz)) (multiply_signPlus (spc1) (spc2)))+from_minimal2 f (Y,I) = (sign,p1,p2)+ where+ (six,pix1,pix2) = from_minimal2 f (X,I) + (siz,piz1,piz2) = from_minimal2 f (Z,I)+ (spc1,p1) = commute pix1 piz1+ (spc2,p2) = commute pix2 piz2+ sign = signPlus_to_sign $ multiply_signPlus (PlusI) (multiply_signPlus (multiply_signPlus (One six) (One siz)) (multiply_signPlus (spc1) (spc2)))+from_minimal2 f (pauli1,pauli2) = (sign,p1,p2)+ where+ (six,pix1,pix2) = from_minimal2 f (pauli1,I) + (siz,piz1,piz2) = from_minimal2 f (I,pauli2)+ (spc1,p1) = commute pix1 piz1+ (spc2,p2) = commute pix2 piz2+ sign = signPlus_to_sign $ multiply_signPlus (multiply_signPlus (One six) (One siz)) (multiply_signPlus (spc1) (spc2))++-- | It is possible to construct a 'Unitary2' from a 4×4-matrix.+from_matrix2 :: (Floating r, Eq r, Show r) => Matrix2 (Cplx r) -> Unitary2+from_matrix2 m = from_minimal2 minimal+ where+ minimal xy = sp+ where+ xy' = case xy of + IX -> (I,X)+ XI -> (X,I) + IZ -> (I,Z)+ ZI -> (Z,I)+ m_dagger = transpose2 m+ sp = fromMatrix2 $ multiplyMatrix2 m (multiplyMatrix2 (toMatrix2 xy') m_dagger)++-- | It is possible to construct a 'Unitary2' from controlling a 2×2-matrix.+from_matrix_controlled :: (Floating r, Show r, Eq r) => Matrix1 (Cplx r) -> Unitary2+from_matrix_controlled m1 = from_matrix2 (control1 m1)++-- | A two-qubit unitary can be applied to a pair of qubits in a given tableau.+apply_unitary2 :: Unitary2 -> (Qubit,Qubit) -> Tableau -> Tableau+apply_unitary2 u (q1,q2) tab = foldl' apply_unitary2' tab [0..nq-1]+ where+ nq = next_qubit tab+ apply_unitary2' :: Tableau -> Qubit -> Tableau+ apply_unitary2' tab q_row = ST (next_qubit tab) sign' tableau'' de_sign' de_tableau''+ where+ s = sign tab+ current_sign = lookup q_row s+ t = tableau tab+ current_pauli1 = lookup (q_row,q1) t+ current_pauli2 = lookup (q_row,q2) t+ (change_sign,new_pauli1,new_pauli2) = u (current_pauli1,current_pauli2)+ new_sign = if negative change_sign then negate current_sign else current_sign+ sign' = Map.insert q_row new_sign s+ tableau' = Map.insert (q_row,q1) new_pauli1 t+ tableau'' = Map.insert (q_row,q2) new_pauli2 tableau'+ de_s = de_sign tab+ de_current_sign = lookup q_row de_s+ de_t = de_tableau tab+ de_current_pauli1 = lookup (q_row,q1) de_t+ de_current_pauli2 = lookup (q_row,q2) de_t+ (de_change_sign,de_new_pauli1,de_new_pauli2) = u (de_current_pauli1,de_current_pauli2)+ de_new_sign = if negative de_change_sign then negate de_current_sign else de_current_sign+ de_sign' = Map.insert q_row de_new_sign de_s+ de_tableau' = Map.insert (q_row,q1) de_new_pauli1 de_t+ de_tableau'' = Map.insert (q_row,q2) de_new_pauli2 de_tableau'++-- | A measurement, in the computational basis, can be made of a qubit+-- in the Tableau, returning the measurement result, and the resulting+-- Tableau.+measure :: Qubit -> Tableau -> IO (Bool,Tableau)+measure q tab = case anticommute_with_z of+ [] -> -- all of the stabilizers commute with z, so the measurement is + -- deterministic and doesn't change the tableau, + -- but we need to calculate the result! + -- the stabilzer either contains Z_q or -Z_q+ case (filter (\(row,_) -> row == z_row) z_rows) of+ [] -> do -- in this case, we need to see whether the generators form Z_q or -Z_q+ let tab' = reduce q tab+ (res,_) <- measure q tab'+ return (res,tab)+ [(_,row)] -> return (negative (lookup row s),tab)+ _ -> error "measure: multiple Zs found" -- should never occur!+ where+ z_row :: [Pauli]+ z_row = map (\q_col -> if q_col == q then Z else I) [0..(nq-1)]+ z_rows :: [([Pauli],Qubit)]+ z_rows = map (\q_row -> ((map (\q_col ->(lookup (q_row,q_col) t)) [0..(nq-1)]),q_row)) [0..(nq-1)] + [(_,q_row)] -> do -- exaclty one anti-commutes, measurement result is 50/50+ let tab' = foldl' (\tab r -> if lookup (r,q) (de_tableau tab) `elem` [X,Y] then multiply_de r q_row tab else tab) tab [0..(nq-1)]+ let de_t = de_tableau tab'+ let de_s = de_sign tab'+ let de_s' = Map.insert q_row (lookup q_row s) de_s+ let de_t' = foldl' (\de_t q' -> Map.insert (q_row,q') (lookup (q_row,q') t) de_t) de_t [0..(nq-1)]+ b <- randomIO+ let eigen_value = if b then Minus else Plus+ let s' = Map.insert q_row eigen_value s+ let t' = foldl' (\t q' -> Map.insert (q_row,q') (if q == q' then Z else I) t) t [0..(nq-1)]+ let tab'' = ST nq s' t' de_s' de_t'+ return (negative eigen_value,tab'')+ ((_,q_row1):((_,q_row2):_)) -> -- more than one anti-commutes, so we update the set of stabilizers with the product of the first two anti-commuters+ measure q (multiply q_row2 q_row1 tab)+ where + nq = next_qubit tab+ t = tableau tab+ s = sign tab+ de_t = de_tableau tab+ de_s = de_sign tab+ gs = map (\q_row -> (lookup (q_row,q) t,q_row)) [0..(nq-1)]+ anticommute_with_z = filter (\(ixyz,_) -> ixyz == X || ixyz == Y) gs++-- | This function reduces a tableau so that it contains either plus+-- or minus /Z/[sub /q/]. Note that it is only called in the case+-- where /Z/[sub /q/] is generated by the tableau (i.e., during+-- measurement).+reduce :: Qubit -> Tableau -> Tableau+reduce qubit tab = foldl' (\t q -> multiply r q t) tab ows+ where+ nq = next_qubit tab+ t = tableau tab+ de_t = de_tableau tab+ (r:ows) = filter (\q_row -> isXY (lookup (q_row,qubit) de_t) ) [0..nq-1]+ isXY p = p == X || p == Y++-- | Multiply the stabilizers for the two given rows, in the given tableau, and+-- update the first row with the result of the multiplication.+multiply :: Qubit -> Qubit -> Tableau -> Tableau+multiply q_row1 q_row2 tab = ST nq s' t' (de_sign tab) (de_tableau tab)+ where+ nq = next_qubit tab+ t = tableau tab+ s = sign tab + sign1 = lookup q_row1 s+ sign2 = lookup q_row2 s+ sp = One (multiply_sign sign1 sign2)+ (t',sp') = foldl' mul_col (t,sp) [0..(nq-1)] + s' = Map.insert q_row1 (signPlus_to_sign sp') s+ mul_col :: (Map (Qubit,Qubit) Pauli, SignPlus) -> Qubit -> (Map (Qubit,Qubit) Pauli, SignPlus)+ mul_col (tab,sp) q_col = (Map.insert (q_row1,q_col) p' tab,multiply_signPlus sp sp')+ where+ p1 = lookup (q_row1,q_col) tab+ p2 = lookup (q_row2,q_col) tab+ (sp',p') = commute p1 p2++-- | Multiply row1 of the destabilizer by row2 of the stabilizer. +multiply_de :: Qubit -> Qubit -> Tableau -> Tableau+multiply_de q_row1 q_row2 tab = ST nq s t s_de' t_de'+ where+ nq = next_qubit tab+ t = tableau tab+ s = sign tab+ t_de = de_tableau tab+ s_de = de_sign tab+ sign1 = lookup q_row1 s_de+ sign2 = lookup q_row2 s+ sp = One (multiply_sign sign1 sign2)+ (t_de',sp') = foldl' mul_col (t_de,sp) [0..(nq-1)] + s_de' = Map.insert q_row1 (signPlus_to_sign sp') s_de+ mul_col :: (Map (Qubit,Qubit) Pauli, SignPlus) -> Qubit -> (Map (Qubit,Qubit) Pauli, SignPlus)+ mul_col (tab_de,sp) q_col = (Map.insert (q_row1,q_col) p' tab_de,multiply_signPlus sp sp')+ where+ p1 = lookup (q_row1,q_col) tab_de+ p2 = lookup (q_row2,q_col) t+ (sp',p') = commute p1 p2++---------------------------------------+-- Generators for the Clifford group --+---------------------------------------++-- All Clifford group operators can be defined in terms of the+-- following gates. The Monadic interface can be used for this+-- purpose. For example.++-- | The Pauli /X/ operator is a Clifford group unitary.+x :: Unitary+x I = (Plus,I)+x X = (Plus,X)+x Y = (Minus,Y)+x Z = (Minus,Z)++-- | We can (equivalently) define Pauli-/X/ as a 'MinUnitary'.+x_min :: MinUnitary+x_min Xmin = (Plus,X)+x_min Zmin = (Minus,Z)++-- | We can (equivalently) construct Pauli-/X/ from a 'MinUnitary'.+x' :: Unitary+x' = from_minimal x_min++-- | We can (equivalently) construct Pauli-/X/ from a matrix.+x'' :: Unitary+x'' = from_matrix (0,1,1,0)++-- | The Pauli /Y/-operator is a Clifford group unitary.+y :: Unitary+y I = (Plus,I)+y X = (Minus,X)+y Y = (Plus,Y)+y Z = (Minus,Z)++-- | We can (equivalently) define Pauli-/Y/ as a 'MinUnitary'.+y_min :: MinUnitary+y_min Xmin = (Minus,X)+y_min Zmin = (Minus,Z)++-- | We can (equivalently) construct Pauli-/Y/ from a 'MinUnitary'.+y' :: Unitary+y' = from_minimal y_min++-- | We can (equivalently) construct Pauli-/Y/ from a matrix.+y'' :: Unitary+y'' = from_matrix (0,-i,i,0)++-- | The Pauli /Z/-operator is a Clifford group unitary.+z :: Unitary+z I = (Plus,I)+z X = (Minus,X)+z Y = (Minus,Y)+z Z = (Plus,Z)++-- | We can (equivalently) define Pauli-/Z/ as a 'MinUnitary'.+z_min :: MinUnitary+z_min Xmin = (Minus,X)+z_min Zmin = (Plus,Z)++-- | We can (equivalently) construct Pauli-/Z/ from a 'MinUnitary'.+z' :: Unitary+z' = from_minimal z_min++-- | We can (equivalently) construct Pauli-/Z/ from a matrix.+z'' :: Unitary+z'' = from_matrix (1,0,0,-1)++-- | The Hadamard-gate is a Clifford group unitary.+h :: Unitary+h I = (Plus,I)+h X = (Plus,Z)+h Y = (Minus,Y)+h Z = (Plus,X)++-- | We can (equivalently) define Hadamard as a 'MinUnitary'.+h_min :: MinUnitary+h_min Xmin = (Plus,Z)+h_min Zmin = (Plus,X)++-- | We can (equivalently) construct Hadamard from a 'MinUnitary'.+h' :: Unitary+h' = from_minimal h_min++-- | We can (equivalently) construct Hadamard from a matrix.+-- Although rounding errors break this!!!+h'' :: Unitary+h'' = from_matrix $ scale1 (Cplx (1/sqrt 2) 0) (1,1,1,-1)++-- | The phase-gate is a Clifford group unitary.+s :: Unitary+s I = (Plus,I) +s X = (Plus,Y)+s Y = (Minus,X)+s Z = (Plus,Z)++-- | We can (equivalently) define phase gate as a 'MinUnitary'.+s_min :: MinUnitary+s_min Xmin = (Plus,Y)+s_min Zmin = (Plus,Z)++-- | We can (equivalently) construct phase gate from a 'MinUnitary'.+s' :: Unitary+s' = from_minimal s_min++-- | We can (equivalently) construct phase gate from a matrix.+s'' :: Unitary+s'' = from_matrix (1,0,0,i)++-- | The phase-gate is a Clifford group unitary.+e :: Unitary+e I = (Plus,I) +e X = (Plus,Y)+e Y = (Plus,Z)+e Z = (Plus,X)++-- | We can (equivalently) define phase gate as a 'MinUnitary'.+e_min :: MinUnitary+e_min Xmin = (Plus,Y)+e_min Zmin = (Plus,X)++-- | We can (equivalently) construct phase gate from a 'MinUnitary'.+e' :: Unitary+e' = from_minimal e_min++-- | We can (equivalently) construct phase gate from a matrix.+e'' :: Unitary+e'' = from_matrix ((-1+i)/2, (1+i)/2, (-1+i)/2, (-1-i)/2)++-- | The controlled-not is a Clifford group 2-qubit unitary.+cnot :: Unitary2+cnot (I,I) = (Plus,I,I)+cnot (I,X) = (Plus,I,X)+cnot (I,Y) = (Plus,Z,Y)+cnot (I,Z) = (Plus,Z,Z)+cnot (X,I) = (Plus,X,X)+cnot (X,X) = (Plus,X,I)+cnot (X,Y) = (Plus,Y,Z)+cnot (X,Z) = (Minus,Y,Y)+cnot (Y,I) = (Plus,Y,X)+cnot (Y,X) = (Plus,Y,I)+cnot (Y,Y) = (Minus,X,Z)+cnot (Y,Z) = (Plus,X,Y)+cnot (Z,I) = (Plus,Z,I)+cnot (Z,X) = (Plus,Z,X)+cnot (Z,Y) = (Plus,I,Y)+cnot (Z,Z) = (Plus,I,Z)++-- | We can (equivalently) define CNot as a 'MinUnitary2'.+cnot_min :: MinUnitary2+cnot_min IX = (Plus,I,X)+cnot_min XI = (Plus,X,X)+cnot_min IZ = (Plus,Z,Z)+cnot_min ZI = (Plus,Z,I)++-- | We can (equivalently) construct CNot from a 'MinUnitary2'.+cnot' :: Unitary2+cnot' = from_minimal2 cnot_min++-- | We can (equivalently) construct CNot from a matrix.+cnot'' :: Unitary2+cnot'' = from_matrix2 ((1,0,0,1),(0,0,0,0),(0,0,0,0),(0,1,1,0))++-- | The controlled-/Z/ is a Clifford group 2-qubit unitary.+cz :: Unitary2+cz (I,I) = (Plus,I,I)+cz (I,X) = (Plus,Z,X)+cz (I,Y) = (Plus,Z,Y)+cz (I,Z) = (Plus,I,Z)+cz (X,I) = (Plus,X,Z)+cz (X,X) = (Plus,Y,Y)+cz (X,Y) = (Minus,Y,X)+cz (X,Z) = (Plus,X,I)+cz (Y,I) = (Plus,Y,Z)+cz (Y,X) = (Minus,X,Y)+cz (Y,Y) = (Plus,X,X)+cz (Y,Z) = (Plus,Y,I)+cz (Z,I) = (Plus,Z,I)+cz (Z,X) = (Plus,I,X)+cz (Z,Y) = (Plus,I,Y)+cz (Z,Z) = (Plus,Z,Z)++-- | We can (equivalently) define controlled-/Z/ as a 'MinUnitary2'.+cz_min :: MinUnitary2+cz_min IX = (Plus,Z,X)+cz_min XI = (Plus,X,Z)+cz_min IZ = (Plus,I,Z)+cz_min ZI = (Plus,Z,I)++-- | We can (equivalently) construct controlled-/Z/ from a 'MinUnitary2'.+cz' :: Unitary2+cz' = from_minimal2 cz_min++-- | We can (equivalently) construct controlled-/Z/ from a matrix.+cz'' :: Unitary2+cz'' = from_matrix2 ((1,0,0,1),(0,0,0,0),(0,0,0,0),(1,0,0,-1))++------------------------------------------------------------------+-- A Monadic Interface for constructing Clifford group circuits --+------------------------------------------------------------------++-- Larger Clifford group circuits can be defined in terms of the+-- following operations. It is envisaged that a Quipper Transformer+-- can be defined to translate appropriate Quipper circuits (i.e.+-- circuits that only use Clifford group operators) into a+-- CliffordCirc so that it can be simulated (efficiently).++-- | A Clifford group circuit is implicitly simulated using+-- a state monad over a 'Tableau'.+type CliffordCirc a = StateT Tableau IO a++-- | Initialize a new qubit.+init_qubit :: Bool -> CliffordCirc Qubit+init_qubit b = do+ tab <- get+ let nq = next_qubit tab+ put (add_qubit b tab)+ return nq ++-- | Initialize multiple qubits.+init_qubits :: [Bool] -> CliffordCirc [Qubit]+init_qubits = mapM init_qubit++-- | Apply a Pauli-/X/ gate to the given qubit.+gate_X :: Qubit -> CliffordCirc ()+gate_X q = do+ tab <- get+ put (apply_unitary x q tab)++-- | Apply a Pauli-/Y/ gate to the given qubit.+gate_Y :: Qubit -> CliffordCirc ()+gate_Y q = do+ tab <- get+ put (apply_unitary y q tab)++-- | Apply a Pauli-/Z/ gate to the given qubit.+gate_Z :: Qubit -> CliffordCirc ()+gate_Z q = do+ tab <- get+ put (apply_unitary z q tab)++-- | Apply a Hadamard gate to the given qubit.+gate_H :: Qubit -> CliffordCirc ()+gate_H q = do+ tab <- get+ put (apply_unitary h q tab)++-- | Apply a phase gate to the given qubit.+gate_S :: Qubit -> CliffordCirc ()+gate_S q = do+ tab <- get+ put (apply_unitary s q tab)++-- | Apply a given 'Unitary' to the given qubit.+gate_Unitary :: Unitary -> Qubit -> CliffordCirc ()+gate_Unitary u q = do+ tab <- get+ put (apply_unitary u q tab)++-- | Apply a controlled-/X/ gate to the given qubits.+controlled_X :: Qubit -> Qubit -> CliffordCirc ()+controlled_X q1 q2 = do+ tab <- get+ put (apply_unitary2 cnot (q1,q2) tab)++-- | Apply a controlled-/Z/ gate to the given qubits.+controlled_Z :: Qubit -> Qubit -> CliffordCirc ()+controlled_Z q1 q2 = do+ tab <- get+ put (apply_unitary2 cz (q1,q2) tab)++-- | Apply a given 'Unitary2' to the given qubits+gate_Unitary2 :: Unitary2 -> Qubit -> Qubit -> CliffordCirc ()+gate_Unitary2 u q1 q2 = do+ tab <- get+ put (apply_unitary2 u (q1,q2) tab)++-- | Measure the given qubit in the computational basis.+measure_qubit :: Qubit -> CliffordCirc Bool+measure_qubit q = do+ tab <- get+ (res,tab') <- lift $ measure q tab+ put tab'+ return res++-- | Measure the given list of qubits.+measure_qubits :: [Qubit] -> CliffordCirc [Bool]+measure_qubits = mapM measure_qubit++-- | For testing purposes, we can show the tableau during a simulation.+show_tableau :: CliffordCirc ()+show_tableau = do+ tab <- get+ lift $ putStrLn (show tab)++----------------------------------------------------+-- Evaluation and Simulation of Clifford circuits --+----------------------------------------------------++-- | Return the evaluated 'Tableau' for the given circuit.+eval :: CliffordCirc a -> IO Tableau+eval cc = execStateT cc empty_tableau++-- | Return the result of simulating the given circuit.+sim :: CliffordCirc a -> IO a+sim cc = evalStateT cc empty_tableau++---------------------------------+-- Some test Clifford circuits --+---------------------------------++-- | A swap gate can be defined in terms of three controlled-not gates.+swap :: Qubit -> Qubit -> CliffordCirc ()+swap q1 q2 = do+ controlled_X q1 q2+ controlled_X q2 q1+ controlled_X q1 q2++-- | A controlled-/Z/ gate can (equivalently) be defined in terms of+-- Hadamard and controlled-/X/.+controlled_Z' :: Qubit -> Qubit -> CliffordCirc ()+controlled_Z' q1 q2 = do+ gate_H q2+ controlled_X q1 q2+ gate_H q2+++-- | Each of the four Bell states can be generated, indexed by a pair+-- of boolean values.+bell :: (Bool,Bool) -> CliffordCirc (Qubit,Qubit)+bell (bx,by) = do+ x <- init_qubit bx+ --show_tableau+ y <- init_qubit by+ --show_tableau+ gate_H x+ --show_tableau+ controlled_X x y+ --show_tableau+ return (x,y)++-- | Create a Bell state, and measure it.+measure_bell00 :: CliffordCirc (Bool,Bool)+measure_bell00 = do+ (bx,by) <- bell (False,False)+ mx <- measure_qubit bx+ --show_tableau+ my <- measure_qubit by+ --show_tableau+ return (mx,my)++-- | A single-qubit operation can be controlled by a classical boolean value.+controlled_if :: Bool -> (Qubit -> CliffordCirc ()) -> Qubit -> CliffordCirc ()+controlled_if b u q = if b then u q else return ()++-- | A simple, single qubit, teleportation circuit.+teleport :: Qubit -> CliffordCirc Qubit+teleport q1 = do+ (q2,q3) <- bell (False,False)+ controlled_X q1 q2+ gate_H q1+ [b1,b2] <- measure_qubits [q1,q2]+ controlled_if b2 gate_X q3+ controlled_if b1 gate_Z q3+ return q3++-- | A wrapper around the teleportation circuit that initializes a qubit+-- in the given boolean state, and measures the teleported qubit.+test_teleport :: Bool -> CliffordCirc Bool+test_teleport b = do+ q <- init_qubit b+ q' <- teleport q+ measure_qubit q'++-- | Measure an equal superposition.+random_bool :: CliffordCirc Bool+random_bool = do+ q <- init_qubit False+ gate_H q+ measure_qubit q
+ Quipper/Utils/Stabilizers/Pauli.hs view
@@ -0,0 +1,199 @@+-- | This module contains a data type to represent the four Pauli operators,+-- along with various operations on them, including commutativity relations.+module Quipper.Utils.Stabilizers.Pauli where++import Prelude hiding (negate)+import Quantum.Synthesis.Ring (Cplx (..), i)++-- | The Pauli operators can be used to generate a stabilizer group for+-- the Clifford operators.+data Pauli = I | X | Y | Z deriving (Show,Eq)++-- | The generators of a stabilizer group require a sign.+data Sign = Plus | Minus deriving (Ord,Eq)++instance Show Sign where+ show Plus = "+"+ show Minus = "-"++-- | Returns a boolean as to whether a 'Sign' is negative (i.e.. 'Minus').+negative :: Sign -> Bool+negative Plus = False+negative Minus = True++-- | Returns the negation of a 'Sign'.+negate :: Sign -> Sign+negate Plus = Minus+negate Minus = Plus++-- | Two signs can be multiplied.+multiply_sign :: Sign -> Sign -> Sign+multiply_sign Plus s = s+multiply_sign Minus s = negate s++--------------------------------------+-- Helper Functions for Commutation --+--------------------------------------++-- | In general, Pauli operators can commute, or anti-commute, so we+-- need to add signs or ±/i/.+data SignPlus = MinusI | PlusI | One Sign++instance Show SignPlus where+ show (One x) = " " ++ show x+ show PlusI = "+i"+ show MinusI = "-i"++-- | Two 'SignPlus's can be multiplied.+multiply_signPlus :: SignPlus -> SignPlus -> SignPlus+multiply_signPlus (One Plus) s = s+multiply_signPlus (One Minus) (One Minus) = One Plus+multiply_signPlus (One Minus) PlusI = MinusI+multiply_signPlus (One Minus) MinusI = PlusI+multiply_signPlus PlusI PlusI = One Minus+multiply_signPlus PlusI MinusI = One Plus+multiply_signPlus MinusI MinusI = One Minus+multiply_signPlus s1 s2 = multiply_signPlus s2 s1++-- | Extract a 'Sign' embedded in a 'SignPlus', or throw an error+-- if the argument is not an embedded 'Sign'.+signPlus_to_sign :: SignPlus -> Sign+signPlus_to_sign (One s) = s+signPlus_to_sign _ = error "signPlus_to_sign: i in sign"++-- | The Levi-Civita symbol, for the permutations of three Pauli operators.+levi_civita :: Pauli -> Pauli -> Pauli -> SignPlus+levi_civita X Y Z = PlusI+levi_civita X Z Y = MinusI+levi_civita Y X Z = MinusI+levi_civita Y Z X = PlusI+levi_civita Z X Y = PlusI+levi_civita Z Y X = MinusI+levi_civita _ _ _ = One Plus++-- | The Kronecker delta for two Pauli operators.+kronecker_delta :: Pauli -> Pauli -> Bool+kronecker_delta x y = x == y++-- | The combination of the commutation and anti-commutation operators can+-- be used to essentially multiply an (ordered) pair of Pauli operators.+commute :: Pauli -> Pauli -> (SignPlus,Pauli)+commute I p = (One Plus,p)+commute p I = (One Plus,p)+commute x y = + if kronecker_delta x y then (One Plus,I) + else case (levi_civita x y X,levi_civita x y Y,levi_civita x y Z) of+ (s,One _,One _) -> (s,X)+ (One _,s,One _) -> (s,Y)+ (One _,One _,s) -> (s,Z)+ _ -> error "commute: Impossible clause reached, somehow"++-- map (\(x,y) -> (x,y,commute x y)) [(x,y) | x <- [I,X,Y,Z], y <- [I,X,Y,Z]]+-- [(I,I,( +,I)),(I,X,( +,X)),(I,Y,( +,Y)),(I,Z,( +,Z)),(X,I,( +,X)),(X,X,( +,I)),(X,Y,(+i,Z)),(X,Z,(-i,Y)),(Y,I,( +,Y)),(Y,X,(-i,Z)),(Y,Y,( +,I)),(Y,Z,(+i,X)),(Z,I,( +,Z)),(Z,X,(+i,Y)),(Z,Y,(-i,X)),(Z,Z,( +,I))]++-- | Represent a 2×2-matrix as a 4-tuple.+type Matrix1 a = (a,a,a,a)++++-- | Give the matrix for each Pauli operator.+toMatrix1 :: (Floating r) => Pauli -> Matrix1 (Cplx r)+toMatrix1 I = (1,0,0,1)+toMatrix1 X = (0,1,1,0)+toMatrix1 Y = (0,-i,i,0)+toMatrix1 Z = (1,0,0,-1)++-- | Scale a 2-by-2 matrix.+scale1 :: (Num a) => a -> Matrix1 a -> Matrix1 a+scale1 x (a,b,c,d) = (x*a,x*b,x*c,x*d)++-- | If a matrix is Pauli, then return the Pauli operator, otherwise+-- throw an error.+fromMatrix1 :: (Floating r, Eq r,Show r) => Matrix1 (Cplx r) -> (Sign,Pauli)+fromMatrix1 m = case filter (\(b,_) -> b) [(toMatrix1 x == m,x) | x <- ixyz] of+ [(_,p)] -> (Plus,p)+ _ -> case filter (\(b,_) -> b) [((scale1 (-1) (toMatrix1 x)) == m,x) | x <- ixyz] of+ [(_,p)] -> (Minus,p)+ _ -> error ("fromMatrix1: " ++ show m ++ " is not a pauli matrix")+ where+ ixyz = [I,X,Y,Z]++-- | Matrix multiplication for 2×2-matrices.+multiplyMatrix1 :: (Num a) => Matrix1 a -> Matrix1 a -> Matrix1 a+multiplyMatrix1 (a00,a01,a10,a11) (b00,b01,b10,b11) = (c00,c01,c10,c11)+ where+ c00 = a00*b00 + a01*b10+ c01 = a00*b01 + a01*b11+ c10 = a10*b00 + a11*b10+ c11 = a10*b01 + a11*b11++-- | Compute the transpose of a 2×2 complex-valued matrix.+transpose1 :: (Num r) => Matrix1 (Cplx r) -> Matrix1 (Cplx r)+transpose1 (a00,a01,a10,a11) = (conjugate a00, conjugate a10, conjugate a01, conjugate a11)+ where+ conjugate (Cplx a b) = Cplx a (-b) ++-- | Return the matrix for Pauli-/Y/, which is /iXZ/.+my_Y :: (Floating r) => Matrix1 (Cplx r)+my_Y = scale1 i $ multiplyMatrix1 (toMatrix1 X) (toMatrix1 Z)++-- | A 4×4-matrix is represented as a 2×2-matrix of 2×2-matrices.+type Matrix2 a = Matrix1 (Matrix1 a)++-- | The tensor product of two 2×2-matrices is a 4×4 matrix.+tensor1 :: (Num a) => Matrix1 a -> Matrix1 a -> Matrix2 a+tensor1 (a,b,c,d) m = (scale1 a m,scale1 b m,scale1 c m,scale1 d m) ++-- | A controlled operation can be expressed with just the operation to be controlled.+control1 :: (Num a) => Matrix1 a -> Matrix2 a+control1 m1 = ((1,0,0,1),(0,0,0,0),(0,0,0,0),m1)++-- | Take the tensor of a pair of Pauli operators, and return a 4×4 matrix.+toMatrix2 :: (Floating r) => (Pauli,Pauli) -> Matrix2 (Cplx r)+toMatrix2 (x,y) = tensor1 (toMatrix1 x) (toMatrix1 y)++-- | Scale a 4×4 matrix.+scale2 :: (Num a) => a -> Matrix2 a -> Matrix2 a+scale2 x (a,b,c,d) = (scale1 x a,scale1 x b,scale1 x c,scale1 x d)++-- | If a matrix is the tensor product of two Pauli operators, then+-- return the pair of Pauli operators, otherwise throw an error.+fromMatrix2 :: (Floating r, Eq r, Show r) => Matrix2 (Cplx r) -> (Sign,Pauli,Pauli)+fromMatrix2 m = case filter (\(b,_) -> b) [(toMatrix2 (x,y) == m,(x,y)) | x <- ixyz, y <- ixyz] of+ [(_,(p1,p2))] -> (Plus,p1,p2)+ _ -> case filter (\(b,_) -> b) [(scale2 (-1) (toMatrix2 (x,y)) == m,(x,y)) | x <- ixyz, y <- ixyz] of+ [(_,(p1,p2))] -> (Minus,p1,p2)+ _ -> error ("fromMatrix2: " ++ show m ++ " is not a tensor product of two Pauli matrices")+ where+ ixyz = [I,X,Y,Z]++-- | Matrix multiplication for 4×4 matrices.+multiplyMatrix2 :: (Num a) => Matrix2 a -> Matrix2 a -> Matrix2 a+multiplyMatrix2 ((a00,a01,a10,a11),(a02,a03,a12,a13),(a20,a21,a30,a31),(a22,a23,a32,a33)) ((b00,b01,b10,b11),(b02,b03,b12,b13),(b20,b21,b30,b31),(b22,b23,b32,b33)) = ((c00,c01,c10,c11),(c02,c03,c12,c13),(c20,c21,c30,c31),(c22,c23,c32,c33))+ where+ c00 = a00*b00 + a01*b10 + a02*b20 + a03*b30+ c01 = a00*b01 + a01*b11 + a02*b21 + a03*b31+ c02 = a00*b02 + a01*b12 + a02*b22 + a03*b32+ c03 = a00*b03 + a01*b13 + a02*b23 + a03*b33+ c10 = a10*b00 + a11*b10 + a12*b20 + a13*b30+ c11 = a10*b01 + a11*b11 + a12*b21 + a13*b31+ c12 = a10*b02 + a11*b12 + a12*b22 + a13*b32+ c13 = a10*b03 + a11*b13 + a12*b23 + a13*b33+ c20 = a20*b00 + a21*b10 + a22*b20 + a23*b30+ c21 = a20*b01 + a21*b11 + a22*b21 + a23*b31+ c22 = a20*b02 + a21*b12 + a22*b22 + a23*b32+ c23 = a20*b03 + a21*b13 + a22*b23 + a23*b33+ c30 = a30*b00 + a31*b10 + a32*b20 + a33*b30+ c31 = a30*b01 + a31*b11 + a32*b21 + a33*b31+ c32 = a30*b02 + a31*b12 + a32*b22 + a33*b32+ c33 = a30*b03 + a31*b13 + a32*b23 + a33*b33++-- | The transpose of a 4×4 complex valued matrix.+transpose2 :: (Floating r) => Matrix2 (Cplx r) -> Matrix2 (Cplx r)+transpose2 ((a00,a01,a10,a11),(a02,a03,a12,a13),(a20,a21,a30,a31),(a22,a23,a32,a33)) = ((conjugate a00,conjugate a10,conjugate a01,conjugate a11),(conjugate a20,conjugate a30,conjugate a21,conjugate a31),(conjugate a02,conjugate a12,conjugate a03,conjugate a13),(conjugate a22,conjugate a32,conjugate a23,conjugate a33))+ where+ conjugate (Cplx a b) = Cplx a (-b) ++-- | The tensor product /IY/ can be defined by /i/(/IX/)(/IZ/).+my_IY :: (Floating r) => Matrix2 (Cplx r) +my_IY = scale2 i $ multiplyMatrix2 (toMatrix2 (I,X)) (toMatrix2 (I,Z))
+ Quipper/Utils/Template.hs view
@@ -0,0 +1,66 @@+-- | This module provides the public interface to the template lifting+-- library. It provides functions that input a Haskell declaration or+-- expression (in the form of a Haskell abstract syntax tree), and+-- lift this to another declaration or expression, with all functions+-- lifted into a specified monad.+-- +-- This can be combined with Template Haskell to convert source code+-- to Haskell abstract syntax trees and vice versa.++module Quipper.Utils.Template (+ -- * Example+ -- $EXAMPLE+ + -- * General lifting functions+ decToMonad,+ expToMonad,+ + -- * Liftings of specific constants+ module Quipper.Utils.Template.Auxiliary,++ -- * Re-exports from "Language.Haskell.TH".+ TH.Q,+ TH.Dec+ ) where++import Quipper.Utils.Template.Lifting+import Quipper.Utils.Template.Auxiliary+import Language.Haskell.TH as TH++-- $EXAMPLE +-- +-- We give an example to illustrate what is meant by \"lifting\" a+-- term to a monad. Consider the expression+-- +-- > f = \g x -> g x x,+-- +-- which has type+-- +-- > f :: (a -> a -> b) -> (a -> b).+-- +-- We can lift this to the 'IO' monad by +-- +-- * converting the expression to an abstract syntax tree, using the+-- special Template Haskell notation [nobr @[| ... |]@];+-- +-- * applying the 'expToMonad' function;+-- +-- * converting the resulting abstract syntax tree back to a term,+-- using the special Template Haskell notation [nobr @$( ... )@].+-- +-- This allows us to write the following:+-- +-- > f' = $( expToMonad "IO" [| \g x -> g x x |] ),+-- +-- which has type+-- +-- > f' :: IO ((a -> IO (a -> IO b)) -> IO (a -> IO b)),+-- +-- and is in fact equivalent to+-- +-- > f'' = return $ \g ->+-- > return $ \x -> do+-- > h <- g x+-- > y <- h x+-- > return y+
+ Quipper/Utils/Template/Auxiliary.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- | This module is for use with "Quipper.Utils.Template.Lifting". +-- It contains various lifted functions of general use. They are not+-- intended to be used directly (although this would not break+-- anything).++module Quipper.Utils.Template.Auxiliary where++import Quipper.Utils.Auxiliary (fold_right_zip,fold_right_zipM)+import Data.List+import Control.Monad++-- ----------------------------------------------------------------------+-- * List operations++-- | Lifted version of @'(:)' :: a -> [a] -> [a]@.+template_symb_colon_ :: Monad m => m (a -> m ([a] -> m [a]))+template_symb_colon_ = return $ \h -> return $ \t -> return (h:t)++-- | Lifted version of @'[]' :: [a]@.+template_symb_obracket_symb_cbracket_ :: Monad m => m [a]+template_symb_obracket_symb_cbracket_ = return []++-- | Lifted version of @'init' :: [a] -> [a]@.+template_init :: Monad m => m ([a] -> m [a])+template_init = return $ \l -> return (init l)++-- | Lifted version of @'last' :: [a] -> [a]@.+template_last :: Monad m => m ([a] -> m a)+template_last = return $ \l -> return (last l)++-- | Lifted version of @'(++)' :: [a] -> [a] -> [a]@.+template_symb_plus_symb_plus_ :: Monad m => m ([a] -> m ([a] -> m [a]))+template_symb_plus_symb_plus_ = return $ \l1 -> return $ \l2-> return (l1 ++ l2)++-- | Lifted version of 'zip3'.+template_zip3 :: Monad m => m ([a] -> m ([b] -> m ([c] -> m [(a,b,c)])))+template_zip3 = return $ \x -> return $ \y -> return $ \z -> return (zip3 x y z)++-- | lifted version of @'foldl'@+template_foldl :: Monad m => m ((a -> m (b -> m a)) -> m (a -> m ([b] -> m a)))+template_foldl = return $ \f -> return $ \a -> return $ \lb -> foldM (auxf f) a lb+ where auxf f a b = do+ g <- f a+ g b++-- | lifted version of @'reverse'@+template_reverse :: Monad m => m ([a] -> m [a])+template_reverse = return $ \x -> return (reverse x)+++-- | lifted version of @'zipWith'@+template_zipWith :: Monad m => m ((a -> m (b -> m c)) -> m ([a] -> m ([b] -> m [c])))+template_zipWith = return $ \f -> return $ \a -> return $ \b -> zipWithM (auxf f) a b+ where auxf f a b = do+ g <- f a+ g b++-- | Lifted version of @'fold_right_zip'@+template_fold_right_zip :: + Monad m => m (((a,b,c) -> m (a,d)) -> m ((a,[b],[c]) -> m (a,[d])))+template_fold_right_zip = return $ \f -> return $ \x -> (fold_right_zipM f x)++-- ----------------------------------------------------------------------+-- * Other operations++-- | Lifted version of the combinator '$'.+template_symb_dollar_ :: Monad m => m ((a -> m b) -> m (a -> m b))+template_symb_dollar_ = return $ \f -> return $ \x -> f x++-- | Lifted version of @'error' :: String -> a@. Using it will make the+-- circuit generation fail with the error described in 'String'.+template_error :: Monad m => m (String -> m a)+template_error = return $ error++-- | Lifted version of @'snd' :: (a,b) -> b@+template_snd :: Monad m => m ((a,b) -> m b)+template_snd = return $ \(a,b) -> return b++
+ Quipper/Utils/Template/ErrorMsgQ.hs view
@@ -0,0 +1,56 @@+-- | This module provides a simple monad to encapsulate error+-- messages within the 'Q' monad.++module Quipper.Utils.Template.ErrorMsgQ where++import Language.Haskell.TH++import Control.Applicative (Applicative(..))+import Control.Monad (liftM, ap)++-- | Shortcut for 'Either String a'.+type ErrMsg a = Either String a++-- | Type for the monad encapsulating error messages.+data ErrMsgQ a = ErrMsgQ (Q (ErrMsg a))++instance Monad ErrMsgQ where+ return x = ErrMsgQ $ return $ return x+ (>>=) (ErrMsgQ x) f = ErrMsgQ $ do+ x' <- x+ case x' of + Left s -> return (Left s)+ Right r -> let (ErrMsgQ y) = f r in y++instance Applicative ErrMsgQ where+ pure = return+ (<*>) = ap++instance Functor ErrMsgQ where+ fmap = liftM++-- | Set an error message, to be thrown.+-- Usage: +-- +-- > errorMsg "an error happened" +errorMsg :: String -> ErrMsgQ a+errorMsg s = ErrMsgQ (return (Left s))++-- | Make a 'Q' computation error-message aware.+embedQ :: Q a -> ErrMsgQ a+embedQ x = ErrMsgQ $ do x' <- x; return (return x')++-- | Throw the error that has been created, using the given string as+-- a prefix. Usage:+-- +-- > extractQ "name of function: " $ do+-- > <<commands that may thow an error>>+extractQ :: String -> ErrMsgQ a -> Q a+extractQ prefix (ErrMsgQ x) = + do+ x' <- x+ case x' of+ Left s -> error (prefix ++ s)+ Right x -> return x++
+ Quipper/Utils/Template/LiftQ.hs view
@@ -0,0 +1,282 @@+-- | This module defines the state monad used in+-- 'Quipper.Utils.Template.Lifting' for Template Haskell +-- term manipulation.+module Quipper.Utils.Template.LiftQ where++import qualified Language.Haskell.TH as TH+import qualified Data.Map as Map+import qualified Data.Set as Set+import qualified Data.List as List++import Language.Haskell.TH (Name)+import Control.Monad.State+import Data.Map (Map)+import Data.Set (Set)++import Control.Applicative (Applicative(..))+import Control.Monad (liftM, ap)++import qualified Quipper.Utils.Template.ErrorMsgQ as Err+import Quipper.Utils.Template.ErrorMsgQ (ErrMsgQ)++-- | State of the monad.+data LiftState = LiftState {+ boundVar :: Map Name Int, -- ^ How many times each name is bound.+ prefix :: Maybe String, -- ^ The template prefix .+ monadName :: Maybe String -- ^ The name of the monad.+}++-- | An empty state.+emptyLiftState :: LiftState+emptyLiftState = LiftState { + boundVar = Map.empty, + prefix = Nothing,+ monadName = Nothing+}++-- | Shortcut to @StateT LiftState ErrMsgQ@.+type LiftQState = StateT LiftState ErrMsgQ++-- | The monad.+data LiftQ a = LiftQ (LiftQState a)++instance Monad LiftQ where+ return x = LiftQ $ return x+ (>>=) (LiftQ x) f = LiftQ $ do+ x' <- x+ let (LiftQ y) = f x'+ y++instance Applicative LiftQ where+ pure = return+ (<*>) = ap++instance Functor LiftQ where+ fmap = liftM++-- | Retrieve the state from the monad.+getState :: LiftQ LiftState+getState = LiftQ $ mapStateT (\x -> do ((),s) <- x; return (s,s))+ (return ())++-- | Set the state of the monad.+setState :: LiftState -> LiftQ ()+setState s = LiftQ $ mapStateT (\_ -> return ((),s))+ ((return ()) :: LiftQState ())++-- * Various functions to go back and forth between monads.++-- | From 'ErrMsgQ' to 'LiftQ'.+embedErrMsgQ :: ErrMsgQ a -> LiftQ a+embedErrMsgQ q = LiftQ $ mapStateT (\x -> do ((),s) <- x; y <- q; return (y,s))+ (return ())++-- | From 'TH.Q' to 'LiftQ'.+embedQ :: TH.Q a -> LiftQ a+embedQ q = LiftQ $ mapStateT (\x -> do ((),s) <- x; y <- Err.embedQ q; return (y,s))+ (return ())++-- | Get 'TH.Q' out of 'LiftQ'+extractQ :: String -> LiftQ a -> TH.Q a+extractQ s (LiftQ x) = Err.extractQ s $ evalStateT x emptyLiftState++-- | Set an error message.+errorMsg :: String -> LiftQ a+errorMsg s = embedErrMsgQ $ Err.errorMsg s+++-- * Working with variable names.++-- | Increase the number of binds of a variable name.+addToBoundVar :: Name -> LiftQ ()+addToBoundVar n = do+ s <- getState+ let new_value = + if (Map.member n $ boundVar s)+ then 1 + ((boundVar s) Map.! n) + else 0+ setState $ s { boundVar = Map.insert n new_value $ boundVar s }++-- | Decrease the number of binds of a variable name.+removeFromBoundVar :: Name -> LiftQ ()+removeFromBoundVar n = do+ s <- getState+ if (not $ Map.member n $ boundVar s) + then errorMsg ((show n) ++ " is not a bound value")+ else let old_value = (boundVar s) Map.! n in+ if old_value == 0+ then setState $ s { boundVar = Map.delete n $ boundVar s }+ else setState $ s { boundVar = Map.insert n (old_value - 1) $ boundVar s }++-- | Run a computation with a particular name being bound.+withBoundVar :: Name -> LiftQ a -> LiftQ a+withBoundVar n comp = do+ addToBoundVar n+ a <- comp+ removeFromBoundVar n+ return a++-- | Run a computation with a particular list of names being bound.+withBoundVars :: [Name] -> LiftQ a -> LiftQ a+withBoundVars names comp = foldl (flip withBoundVar) comp names++-- | Say whether a given name is bound.+isBoundVar :: Name -> LiftQ Bool+isBoundVar n = do+ s <- getState+ return $ Map.member n $ boundVar s+++-- * Other operations on monad state.++-- | Set the template prefix.+setPrefix :: String -> LiftQ ()+setPrefix p = do+ s <- getState+ case (prefix s) of+ Just p' -> errorMsg ("cannot set the prefix to " ++ + (show p) ++ + ": prefix already defined as " ++ + p') + Nothing -> setState $ s { prefix = Just p }+++-- | Get the template prefix.+getPrefix :: LiftQ String+getPrefix = do+ s <- getState+ case (prefix s) of+ Nothing -> errorMsg "undefined prefix"+ Just p -> return p++-- | Set the monad name.+setMonadName :: String -> LiftQ ()+setMonadName m = do+ s <- getState+ case (monadName s) of+ Just m' -> errorMsg ("cannot set the monad to " ++ + (show m) ++ + ": monad already defined as " ++ + m') + Nothing -> setState $ s { monadName = Just m }++-- | Get the monad name.+getMonadName :: LiftQ String+getMonadName = do+ s <- getState+ case (monadName s) of+ Nothing -> errorMsg "undefined monad"+ Just m -> return m+++++-- * Functions dealing with variable names.++-- | Make a name out of a string.+mkName :: String -> Name+mkName s = TH.mkName s++-- | Make a name out of a string, monadic-style.+newName :: String -> LiftQ Name+newName st = embedQ $ TH.newName st+++++-- | Make any string into a string containing only @[0-9a-zA-Z_.]@.+-- For example, it replaces any occurrence of @\"+\"@ with+-- @\"symb_plus_\"@.+sanitizeString :: String -> String+sanitizeString name = + List.concat (List.map + (\c -> + Map.findWithDefault c c + (Map.map (\s -> "symb_" ++ s ++ "_")+ unicodeNames))+ (List.map (\x -> [x]) name))+ where+ unicodeNames :: Map.Map String String+ unicodeNames = Map.fromList+ [("!","exclamation"),+ ("\"","doublequote"),+ ("#","sharp"),+ ("$","dollar"),+ ("%","percent"),+ ("&","ampersand"),+ ("'","quote"),+ ("(","oparent"),+ (")","cparent"),+ ("*","star"),+ ("+","plus"),+ (",","comma"),+ ("-","minus"),+ -- we keep dots+ ("/","slash"),+ (":","colon"),+ (";","semicolon"),+ ("<","oangle"),+ ("=","equal"),+ (">","cangle"),+ ("?","question"),+ ("@","at"),+ ("[","obracket"),+ ("\\","backslash"),+ ("]","cbracket"),+ ("^","caret"),+ -- we keep _+ ("`","graveaccent"),+ ("{","obrace"),+ ("|","vbar"),+ ("}","cbrace"),+ ("~","tilde")]+++-- | Take a string and make it into a valid Haskell name starting with+-- @\"template_\"@.+templateString :: String -> LiftQ String+templateString s = do+ p <- getPrefix+ return (p ++ (sanitizeString s))++-- | Look for the corresponding "template" name.+lookForTemplate :: Name -> LiftQ (Maybe Name)+lookForTemplate n = do+ t_string <- templateString $ TH.nameBase n+ embedQ $ TH.lookupValueName t_string++-- | Make a the template version of a given name.+makeTemplateName :: Name -> LiftQ Name+makeTemplateName n = do+ t_string <- templateString $ TH.nameBase n+ return $ TH.mkName t_string+++-- * Other functions.++-- | Print on the terminal a monadic, printable object.+prettyPrint :: TH.Ppr a => LiftQ a -> IO ()+prettyPrint x = (TH.runQ $ extractQ "prettyPrint: " x) >>= (putStrLn . TH.pprint)+++-- | Project patterns out of a clause.+clauseGetPats :: TH.Clause -> [TH.Pat]+clauseGetPats (TH.Clause pats _ _) = pats+++-- | Check that the list is a non-empty repetition of the same+-- element.+equalNEListElts :: Eq a => [a] -> Bool+equalNEListElts [] = True+equalNEListElts (h:list) = foldl (&&) True $ map (== h) list+++-- | Returns the length of the patterns in a list of clauses. Throw an+-- error if the patterns do not have all the same size.+clausesLengthPats :: [TH.Clause] -> LiftQ Int+clausesLengthPats [] = errorMsg "empty clause"+clausesLengthPats clauses + | (equalNEListElts $ map length $ map clauseGetPats clauses) = + return $ length $ clauseGetPats $ head clauses +clausesLengthPats _ = errorMsg "patterns in clause are not of equal size"+
+ Quipper/Utils/Template/Lifting.hs view
@@ -0,0 +1,630 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE RankNTypes #-}++-- | This module describes stripped-down Template Haskell abstract+-- syntax trees (ASTs) for a subset of Haskell.++module Quipper.Utils.Template.Lifting where++import Control.Monad.State++import qualified Data.Map as Map+import Data.Map (Map)++import qualified Data.List as List++import Data.Maybe (catMaybes)++import qualified Data.Set as Set+import Data.Set (Set)++import qualified Language.Haskell.TH as TH+import Language.Haskell.TH (Name)++-- Get the monad to build the lifting.+import Quipper.Utils.Template.LiftQ+++-- * Abstract syntax trees of a simplified language++-- | There are no \"guarded bodies\". One net effect is to make the+-- \"where\" construct equivalent to a simple \"let\".+type Body = Exp++-- | Literals.+data Lit =+ CharL Char -- ^ Characters.+ | IntegerL Integer -- ^ Integers.+ | RationalL Rational -- ^ Reals.+ deriving (Show)+++-- | Patterns.+data Pat = + LitP Lit -- ^ Literal.+ | VarP Name -- ^ Variable name.+ | TupP [Pat] -- ^ Tuple.+ | WildP -- ^ Wildchar.+ | ListP [Pat] -- ^ List as @[...]@.+ | ConP Name [Pat] -- ^ Cons: @h:t@.+ deriving (Show)++-- | Match term construct.+data Match =+ Match Pat Body+ deriving (Show)++-- | First-level declaration.+data Dec = + ValD Name Body+ deriving (Show)++-- | Expression+data Exp = + VarE Name -- ^ Variable name.+ | ConE Name -- ^ Constant name.+ | LitE Lit -- ^ Literal.+ | AppE Exp Exp -- ^ Application.+ | LamE Name Exp -- ^ Lambda abstraction.+ | TupE [Exp] -- ^ Tuple.+ | CondE Exp Exp Exp -- ^ If-then-else.+ | LetE [Dec] Exp -- ^ Let-construct.+ | CaseE Exp [Match] -- ^ Case distinction+ | ListE [Exp] -- ^ List: @[...]@.+ | ReturnE -- ^ hardcoded constant for @'return'@.+ | MAppE -- ^ hardcoded constant for @'>>='@.+ deriving (Show)+++-- $ Syntactic sugar to recover do-notation.++-- | Datatype to encode the notation @x <- expr@.+data BindS = BindS Name Exp++-- | A simple @do@: list of monadic @let@ followed by a computation.+doE :: [BindS] -> Exp -> Exp +doE binds exp = foldr doOne exp binds+ where+ doOne :: BindS -> Exp -> Exp+ doOne (BindS n value) computation = AppE (AppE MAppE value) (LamE n computation)+++-- * Variable substitution+ ++-- | Get the set of variable names in a pattern.+getVarNames :: Pat -> Set Name+getVarNames (VarP n) = Set.singleton n+getVarNames (TupP pats) = Set.unions $ map getVarNames pats+getVarNames (ListP pats) = Set.unions $ map getVarNames pats+getVarNames _ = Set.empty++-- | Substitution in a @'Match'@.+substMatch :: Name -> Exp -> Match -> Match+substMatch n s (Match p e) | Set.member n (getVarNames p) = Match p e+ | True = Match p (substExp n s e)+++-- | Substitution in a @'Dec'@.+substDec :: Name -> Exp -> Dec -> Dec+substDec n s (ValD m e) | n == m = ValD m e+ | True = ValD m (substExp n s e)++-- | Substitution in an @'Exp'@.+substExp :: Name -> Exp -> Exp -> Exp+substExp n s (VarE m) | n == m = s+ | True = (VarE m)+substExp n s (ConE m) = ConE m+substExp n s (LitE l) = LitE l+substExp n s (AppE e1 e2) = AppE (substExp n s e1) (substExp n s e2)+substExp n s (LamE m exp) | n == m = LamE m exp+ | True = LamE m $ substExp n s exp+substExp n s (TupE exps) = TupE $ map (substExp n s) exps+substExp n s (CondE e1 e2 e3) = CondE (substExp n s e1) (substExp n s e2) (substExp n s e3)+substExp n s (LetE decs exp) = LetE (map (substDec n s) decs) (substExp n s exp)+substExp n s (CaseE exp matches) = CaseE (substExp n s exp) $ map (substMatch n s) matches+substExp n s (ListE exps) = ListE $ map (substExp n s) exps+substExp n s ReturnE = ReturnE+substExp n s MAppE = MAppE+++-- | Substitution of several variables in one go.+mapSubstExp :: (Map Name Exp) -> Exp -> Exp+mapSubstExp map exp = List.foldl (\exp (x,y) -> substExp x y exp) exp $ Map.toList map+++-- * Downgrading Template Haskell to AST++-- | Downgrading TH literals to @'Exp'@.+litTHtoExpAST :: TH.Lit -> LiftQ Exp+litTHtoExpAST (TH.CharL c) = return $ LitE $ CharL c+litTHtoExpAST (TH.StringL s) = return $ ListE $ map (LitE . CharL) s+litTHtoExpAST (TH.IntegerL i) = return $ LitE $ IntegerL i +litTHtoExpAST (TH.RationalL r) = return $ LitE $ RationalL r+litTHtoExpAST x = errorMsg ("lifting not handled for " ++ (show x))++-- | Downgrading TH literals to @'Pat'@.+litTHtoPatAST :: TH.Lit -> LiftQ Pat+litTHtoPatAST (TH.CharL c) = return $ LitP $ CharL c+litTHtoPatAST (TH.StringL s) = return $ ListP $ map (LitP . CharL) s+litTHtoPatAST (TH.IntegerL i) = return $ LitP $ IntegerL i +litTHtoPatAST (TH.RationalL r) = return $ LitP $ RationalL r+litTHtoPatAST x = errorMsg ("lifting not handled for " ++ (show x))+++-- | Take a list of patterns coming from a @where@ section and output+-- a list of fresh names for normalized @let@s. Also gives a mapping+-- for substituting inside the expressions. Assume all names in the+-- list of patterns are distinct.+normalizePatInExp :: [Pat] -> LiftQ ([Name], Map Name Exp)+normalizePatInExp pats = do+ fresh_names <- mapM newName $ replicate (length pats) "normalizePat"+ let sets_of_old_names = List.map getVarNames pats+ let old_to_fresh old_name =+ List.lookup True $ zip (List.map (Set.member old_name) sets_of_old_names) fresh_names+ let old_to_pat old_name =+ List.lookup True $ zip (List.map (Set.member old_name) sets_of_old_names) pats+ let list_of_old_names = List.concat $ List.map Set.toList sets_of_old_names+ let maybe_list_map = mapM+ (\x -> do+ fresh <- old_to_fresh x+ pat <- old_to_pat x+ return (x, CaseE (VarE fresh) [Match pat (VarE x)]))+ list_of_old_names+ case maybe_list_map of+ Nothing -> errorMsg "error in patterns..."+ Just l -> return $ (fresh_names, Map.fromList l)+ ++-- | Build a @let@-expression out of pieces.+whereToLet :: Exp -> [(Pat,Exp)] -> LiftQ Exp+whereToLet exp [] = return exp+whereToLet exp list = do+ (fresh_names, pmap) <- normalizePatInExp $ map fst list+ let decs'' = map (uncurry ValD) $ zip fresh_names $ map snd list+ let decs' = map (\(ValD n e) -> ValD n $ mapSubstExp pmap e) decs''+ return $ + LetE decs' $ + CaseE (TupE $ map VarE fresh_names) [Match (TupP $ map fst list) exp]++-- | Build a @'Match'@ out of a TH clause+clauseToMatch :: TH.Clause -> LiftQ Match+clauseToMatch (TH.Clause pats body decs) = do+ pats' <- mapM patTHtoAST pats + body' <- bodyTHtoAST body + decs' <- mapM decTHtoAST decs+ exp <- whereToLet body' decs'+ return $ Match (TupP pats') exp++-- | From a list of TH clauses, make a case-distinction wrapped in a+-- lambda abstraction.+clausesToLambda :: [TH.Clause] -> LiftQ Exp+clausesToLambda clauses = do+ -- get length of patterns+ pats_length <- clausesLengthPats clauses+ -- make a list of new names from the function name+ fresh_names <- mapM newName $ replicate pats_length "x"+ -- make matches out of the clauses.+ matches <- mapM clauseToMatch clauses+ -- return a simple function with a case-distinction+ return $ foldr LamE + (CaseE (TupE $ map VarE fresh_names) matches)+ fresh_names+++-- | Downgrade expressions.+expTHtoAST :: TH.Exp -> LiftQ Exp++expTHtoAST (TH.VarE v) = return $ VarE v+expTHtoAST (TH.ConE n) = return $ ConE n+expTHtoAST (TH.LitE l) = litTHtoExpAST l++expTHtoAST (TH.AppE e1 e2) = do + e1' <- expTHtoAST e1+ e2' <- expTHtoAST e2+ return $ AppE e1' e2'++expTHtoAST (TH.InfixE (Just e1) e2 (Just e3)) = do+ e1' <- expTHtoAST e1+ e2' <- expTHtoAST e2+ e3' <- expTHtoAST e3+ return $ AppE (AppE e2' e1') e3'++expTHtoAST (TH.InfixE Nothing e2 (Just e3)) = do+ e2' <- expTHtoAST e2+ e3' <- expTHtoAST e3+ n <- newName "x"+ return $ LamE n $ AppE (AppE e2' (VarE n)) e3'++expTHtoAST (TH.InfixE (Just e1) e2 Nothing) = do+ e1' <- expTHtoAST e1+ e2' <- expTHtoAST e2+ return $ AppE e2' e1'++expTHtoAST (TH.InfixE Nothing e2 Nothing) = do+ e2' <- expTHtoAST e2+ return e2'++expTHtoAST (TH.LamE pats exp) = + clausesToLambda [TH.Clause pats (TH.NormalB exp) []]++expTHtoAST (TH.TupE exps) = do+ exps' <- mapM expTHtoAST exps+ return (TupE exps')++expTHtoAST (TH.CondE e1 e2 e3) = do+ e1' <- expTHtoAST e1+ e2' <- expTHtoAST e2+ e3' <- expTHtoAST e3+ return $ CondE e1' e2' e3'++expTHtoAST (TH.LetE decs exp) = do+ decs' <- mapM decTHtoAST decs+ exp' <- expTHtoAST exp+ whereToLet exp' decs' ++expTHtoAST (TH.CaseE exp matches) = do+ exp' <- expTHtoAST exp+ matches' <- mapM matchTHtoAST matches+ return $ CaseE exp' matches'+ +expTHtoAST (TH.ListE exps) = do+ exps' <- mapM expTHtoAST exps+ return $ ListE exps'+ ++expTHtoAST (TH.SigE e _) = expTHtoAST e++expTHtoAST x = errorMsg ("lifting not handled for " ++ (show x))+++-- | Downgrade match-constructs.+matchTHtoAST :: TH.Match -> LiftQ Match+matchTHtoAST (TH.Match pat body decs) = do+ pat' <- patTHtoAST pat+ body' <- bodyTHtoAST body+ decs' <- mapM decTHtoAST decs+ exp <- whereToLet body' decs'+ return $ Match pat' exp++-- | Downgrade bodies into expressions.+bodyTHtoAST :: TH.Body -> LiftQ Exp+bodyTHtoAST (TH.NormalB exp) = expTHtoAST exp+bodyTHtoAST (TH.GuardedB x) = errorMsg ("guarded body not allowed in lifting: " ++ (show x))++-- | Downgrade patterns.+patTHtoAST :: TH.Pat -> LiftQ Pat+patTHtoAST (TH.LitP l) = litTHtoPatAST l+patTHtoAST (TH.VarP n) = return $ VarP n+patTHtoAST (TH.TupP pats) = do pats' <- mapM patTHtoAST pats; return $ TupP pats'+patTHtoAST (TH.WildP) = return WildP+patTHtoAST (TH.ListP pats) = do pats' <- mapM patTHtoAST pats; return $ ListP pats'+patTHtoAST (TH.ConP n pats) = do pats' <- mapM patTHtoAST pats; return $ ConP n pats'+patTHtoAST (TH.InfixP p1 n p2) = do+ p1' <- patTHtoAST p1+ p2' <- patTHtoAST p2+ return $ ConP n [p1',p2']+patTHtoAST x = errorMsg ("non-implemented lifting: " ++ (show x))+++++-- | Downgrade first-level declarations.+firstLevelDecTHtoAST :: TH.Dec -> Maybe (LiftQ Dec)+firstLevelDecTHtoAST (TH.FunD name clauses) = Just $ do+ exp <- clausesToLambda clauses+ name' <- makeTemplateName name+ return $ ValD name' $ substExp name (VarE name') exp++firstLevelDecTHtoAST (TH.ValD (TH.VarP name) body decs) = Just $ do+ body' <- bodyTHtoAST body + decs' <- mapM decTHtoAST decs+ exp <- whereToLet body' decs' + name' <- makeTemplateName name+ return $ ValD name' $ substExp name (VarE name') exp++firstLevelDecTHtoAST (TH.ValD _ _ _) = Just $+ errorMsg ("only variables and functions can be lifted as first-level declarations")++firstLevelDecTHtoAST (TH.SigD _ _) = Nothing++firstLevelDecTHtoAST x = Just $ errorMsg ("non-implemented lifting: " ++ (show x))+++-- | Downgrade any declarations (including the ones in @where@-constructs).+decTHtoAST :: TH.Dec -> LiftQ (Pat,Exp)++decTHtoAST (TH.FunD name clauses) = do+ exp <- clausesToLambda clauses+ return $ (VarP name, exp)++decTHtoAST (TH.ValD pat body decs) = do+ pat' <- patTHtoAST pat+ body' <- bodyTHtoAST body + decs' <- mapM decTHtoAST decs+ exp <- whereToLet body' decs'+ return $ (pat', exp)++decTHtoAST x = errorMsg ("non-implemented lifting: " ++ (show x))+++++-- * Upgrade AST to Template Haskell++-- | Abstract syntax tree of the type of the function 'return'.+typReturnE :: LiftQ TH.Type+typReturnE = do+ m_string <- getMonadName+ let m = TH.conT (mkName m_string)+ embedQ [t| forall x. x -> $(m) x |]++-- | Abstract syntax tree of the type of the function '>>='.+typMAppE :: LiftQ TH.Type+typMAppE = do+ m_string <- getMonadName+ let m = TH.conT (mkName m_string)+ embedQ [t| forall x y. $(m) x -> (x -> $(m) y) -> $(m) y |]+++-- | Upgrade literals+litASTtoTH :: Lit -> TH.Lit+litASTtoTH (CharL c) = TH.CharL c+litASTtoTH (IntegerL i) = TH.IntegerL i+litASTtoTH (RationalL r) = TH.RationalL r++-- | Upgrade patterns.+patASTtoTH :: Pat -> TH.Pat+patASTtoTH (LitP l) = TH.LitP $ litASTtoTH l+patASTtoTH (VarP n) = TH.VarP n+patASTtoTH (TupP pats) = TH.TupP $ map patASTtoTH pats+patASTtoTH WildP = TH.WildP+patASTtoTH (ListP pats) = TH.ListP $ map patASTtoTH pats+patASTtoTH (ConP n pats) = TH.ConP n $ map patASTtoTH pats++-- | Upgrade match-constructs.+matchASTtoTH :: Match -> LiftQ TH.Match+matchASTtoTH (Match p b) = do+ exp <- expASTtoTH b+ return $ TH.Match (patASTtoTH p) (TH.NormalB exp) []++-- | Upgrade declarations.+decASTtoTH :: Dec -> LiftQ TH.Dec++decASTtoTH (ValD n b) = do+ exp <- expASTtoTH b+ return $ TH.ValD (TH.VarP n) (TH.NormalB exp) []+++-- | Upgrade expressions.+expASTtoTH :: Exp -> LiftQ TH.Exp++expASTtoTH (VarE n) = return $ TH.VarE n+expASTtoTH (ConE n) = return $ TH.ConE n+expASTtoTH (LitE l) = return $ TH.LitE $ litASTtoTH l++expASTtoTH (AppE e1 e2) = do+ e1' <- expASTtoTH e1+ e2' <- expASTtoTH e2+ return $ TH.AppE e1' e2'++expASTtoTH (LamE n e) = do+ e' <- expASTtoTH e+ return $ TH.LamE [TH.VarP n] e'++expASTtoTH (TupE exps) = do+ exps' <- mapM expASTtoTH exps+ return $ TH.TupE exps'++expASTtoTH (CondE e1 e2 e3) = do+ e1' <- expASTtoTH e1+ e2' <- expASTtoTH e2+ e3' <- expASTtoTH e3+ return $ TH.CondE e1' e2' e3'++expASTtoTH (LetE decs e) = do+ decs' <- mapM decASTtoTH decs+ e' <- expASTtoTH e+ return $ TH.LetE decs' e'++expASTtoTH (CaseE e matches) = do+ e' <- expASTtoTH e+ m' <- mapM matchASTtoTH matches+ return $ TH.CaseE e' m'++expASTtoTH (ListE exps) = do+ exps' <- mapM expASTtoTH exps+ return $ TH.ListE exps'++expASTtoTH ReturnE = do+ t <- typReturnE+ maybe_r <- embedQ $ TH.lookupValueName "return"+ case maybe_r of+ Just r -> return $ TH.SigE (TH.VarE r) t+ Nothing -> errorMsg "\'return\' undefined"+ +expASTtoTH MAppE = do+ t <- typMAppE+ maybe_a <- embedQ $ TH.lookupValueName ">>="+ case maybe_a of+ Just a -> return $ TH.SigE (TH.VarE a) t+ Nothing -> errorMsg "\'>>=\' undefined"+++++-- * Lifting AST terms (into AST terms)++-- | Variable referring to the lifting function for integers.+liftIntegerL :: Exp+liftIntegerL = VarE $ mkName "template_integer"++-- | Variable referring to the lifting function for reals.+liftRationalL :: Exp+liftRationalL = VarE $ mkName "template_rational"++-- | Lifting literals.+liftLitAST :: Lit -> LiftQ Exp+liftLitAST (CharL c) = return (AppE ReturnE (LitE $ CharL c))+liftLitAST (IntegerL i) = return $ AppE liftIntegerL (LitE $ IntegerL i)+liftLitAST (RationalL r) = return $ AppE liftRationalL (LitE $ RationalL r)++-- | Lifting patterns.+liftPatAST :: Pat -> LiftQ Pat+liftPatAST pat = return pat++-- | Lifting match-constructs.+liftMatchAST :: Match -> LiftQ Match+liftMatchAST (Match pat exp) = do+ exp' <- liftExpAST exp+ return $ Match pat exp' ++-- | Lifting declarations.+liftDecAST :: Dec -> LiftQ Dec+liftDecAST (ValD name exp) = do+ exp' <- liftExpAST exp+ return $ ValD name exp'++-- | Lifting first-level declarations.+liftFirstLevelDecAST :: Dec -> LiftQ Dec+liftFirstLevelDecAST (ValD name exp) = withBoundVar name $ do+ exp' <- liftExpAST exp+ return $ ValD name exp'++-- | Lifting expressions.+liftExpAST :: Exp -> LiftQ Exp++liftExpAST (VarE x) = do+ template_name <- lookForTemplate x+ case template_name of+ Nothing -> do+ b <- isBoundVar x+ if b + then return $ VarE x+ else return $ AppE ReturnE $ VarE x+ Just t -> return $ VarE t++liftExpAST (ConE n) = do+ template_name <- lookForTemplate n+ case template_name of+ Nothing -> do + t <- templateString $ TH.nameBase n+ errorMsg ("variable " ++ t ++ " undefined")+ Just t -> return $ VarE t++liftExpAST (LitE l) = liftLitAST l++liftExpAST (AppE e1 e2) = do+ e1' <- liftExpAST e1+ e2' <- liftExpAST e2+ n1 <- newName "app1"+ n2 <- newName "app2"+ return $ doE [BindS n1 e1', BindS n2 e2'] $ AppE (VarE n1) (VarE n2)++liftExpAST (LamE n exp) = do+ exp' <- liftExpAST exp+ return $ AppE ReturnE $ LamE n exp'++liftExpAST (TupE exps) = do+ exps' <- mapM liftExpAST exps+ fresh_names <- mapM newName $ replicate (length exps) "tupe"+ return $ + doE (map (uncurry BindS) $ zip fresh_names exps')+ (AppE ReturnE $ TupE $ map VarE fresh_names)++liftExpAST (CondE e1 e2 e3) = do+ e1' <- liftExpAST e1+ e2' <- liftExpAST e2+ e3' <- liftExpAST e3+ return $ AppE (AppE (AppE (VarE (mkName "template_if")) (e1')) (e2')) (e3')+++liftExpAST (LetE decs exp) = + let existing_names = map (\(ValD n _) -> n) decs+ in+ withBoundVars existing_names $ do+ decs' <- mapM liftDecAST decs+ exp' <- liftExpAST exp+ return $ + LetE decs' exp'+++liftExpAST (CaseE exp matches) = do+ exp' <- liftExpAST exp+ matches' <- mapM liftMatchAST matches+ fresh_name <- newName "varfromcase"+ return $ doE [BindS fresh_name exp']+ $ CaseE (VarE fresh_name) matches'+ +liftExpAST (ListE exps) = do+ exps' <- mapM liftExpAST exps+ fresh_names <- mapM newName $ replicate (length exps) "varfromlist"+ return $ + doE (map (uncurry BindS) $ zip fresh_names exps')+ $ AppE ReturnE $ ListE $ map VarE fresh_names++-- These two are not supposed to be there!+liftExpAST ReturnE = undefined+liftExpAST MAppE = undefined+++-- | make a declaration into a template-declaration (by renaming with+-- the template-prefix).+makeDecTemplate :: Dec -> LiftQ Dec+makeDecTemplate (ValD name exp) = do+ name' <- makeTemplateName name+ return $ ValD name' $ substExp name (VarE name') exp+++-- * Various pretty printing functions+++-- | pretty-printing Template Haskell declarations.+prettyPrintAST :: TH.Q [TH.Dec] -> IO ()+prettyPrintAST x = prettyPrint $ do+ x' <- embedQ x+ y <- sequence $ catMaybes $ map firstLevelDecTHtoAST x'+ mapM decASTtoTH y++-- | Pretty-printing Template Haskell expressions.+prettyPrintLiftExpTH :: TH.Q (TH.Exp) -> IO ()+prettyPrintLiftExpTH x = prettyPrint $ do+ x' <- embedQ x+ y <- expTHtoAST x'+ z <- liftExpAST y+ expASTtoTH z++-- | Pretty-printing expressions.+prettyPrintLiftExpAST :: LiftQ (Exp) -> IO ()+prettyPrintLiftExpAST x = prettyPrint $ do+ z <- x+ z' <- liftExpAST z+ expASTtoTH z'+++-- * The main lifting functions.+++-- | Lift a list of declarations. The first argument is the name of+-- the monad to lift into.+decToMonad :: String -> TH.Q [TH.Dec] -> TH.Q [TH.Dec]+decToMonad s x = extractQ "decToMonad: " $ do+ setMonadName s+ setPrefix "template_"+ dec <- embedQ x+ decAST <- sequence $ catMaybes $ map firstLevelDecTHtoAST dec+ liftedAST <- mapM liftFirstLevelDecAST decAST+ mapM decASTtoTH liftedAST++-- | Lift an expression. The first argument is the name of the monad+-- to lift into.+expToMonad :: String -> TH.Q TH.Exp -> TH.Q TH.Exp+expToMonad s x = extractQ "expToMonad: " $ do+ setMonadName s+ setPrefix "template_"+ dec <- embedQ x+ decAST <- expTHtoAST dec+ liftedAST <- liftExpAST decAST+ expASTtoTH liftedAST++
+ Quipper/Utils/Tuple.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}++-- | This module provides isomorphisms between /n/-tuples and repeated+-- pairs. It is used to be able to write type classes for /n/-tuples+-- more generically. Essentially we want to be able to write code for+-- 17-tuples once and for all, rather than once for each type class we+-- define. Ideally there would be a standard Haskell library for this.+--+-- Two type classes are provided: 'Tuple', and 'TupleOrUnary'.+-- 'Tuple' is recommended for most uses.++module Quipper.Utils.Tuple where++-- I only want to write code involving explicit 7-tuples once in my life++-- | This type class relates types of the form @t = (a,b,c,d)@ (“tupled form”) to+-- types of the form @s = (a,(b,(c,(d,()))))@ (“standard form”), and provides a way to+-- convert between the two representations.+--+-- The tupled form can always be deduced from the standard form.++class TupleOrUnary t s | s -> t where+ -- | For example, maps @(a,(b,(c,(d,()))))@ to @(a,b,c,d)@.+ weak_tuple :: s -> t+ -- | For example, maps @(a,b,c,d)@ to @(a,(b,(c,(d,()))))@.+ weak_untuple :: t -> s++instance TupleOrUnary () () where+ weak_tuple () = ()+ weak_untuple () = ()++instance TupleOrUnary a (a,()) where+ weak_tuple (a,()) = a+ weak_untuple a = (a,())++instance TupleOrUnary (a,b) (a,(b,())) where+ weak_tuple (a,(b,())) = (a,b)+ weak_untuple (a,b) = (a,(b,()))+ +instance TupleOrUnary (a,b,c) (a,(b,(c,()))) where+ weak_tuple (a,(b,(c,()))) = (a,b,c)+ weak_untuple (a,b,c) = (a,(b,(c,())))+ +instance TupleOrUnary (a,b,c,d) (a,(b,(c,(d,())))) where+ weak_tuple (a,(b,(c,(d,())))) = (a,b,c,d)+ weak_untuple (a,b,c,d) = (a,(b,(c,(d,()))))++instance TupleOrUnary (a,b,c,d,e) (a,(b,(c,(d,(e,()))))) where+ weak_tuple (a,(b,(c,(d,(e,()))))) = (a,b,c,d,e)+ weak_untuple (a,b,c,d,e) = (a,(b,(c,(d,(e,())))))++instance TupleOrUnary (a,b,c,d,e,f) (a,(b,(c,(d,(e,(f,())))))) where+ weak_tuple (a,(b,(c,(d,(e,(f,())))))) = (a,b,c,d,e,f)+ weak_untuple (a,b,c,d,e,f) = (a,(b,(c,(d,(e,(f,()))))))++instance TupleOrUnary (a,b,c,d,e,f,g) (a,(b,(c,(d,(e,(f,(g,()))))))) where+ weak_tuple (a,(b,(c,(d,(e,(f,(g,()))))))) = (a,b,c,d,e,f,g)+ weak_untuple (a,b,c,d,e,f,g) = (a,(b,(c,(d,(e,(f,(g,())))))))++instance TupleOrUnary (a,b,c,d,e,f,g,h) (a,(b,(c,(d,(e,(f,(g,(h,())))))))) where+ weak_tuple (a,(b,(c,(d,(e,(f,(g,(h,())))))))) = (a,b,c,d,e,f,g,h)+ weak_untuple (a,b,c,d,e,f,g,h) = (a,(b,(c,(d,(e,(f,(g,(h,()))))))))++instance TupleOrUnary (a,b,c,d,e,f,g,h,i) (a,(b,(c,(d,(e,(f,(g,(h,(i,()))))))))) where+ weak_tuple (a,(b,(c,(d,(e,(f,(g,(h,(i,()))))))))) = (a,b,c,d,e,f,g,h,i)+ weak_untuple (a,b,c,d,e,f,g,h,i) = (a,(b,(c,(d,(e,(f,(g,(h,(i,())))))))))++instance TupleOrUnary (a,b,c,d,e,f,g,h,i,j) (a,(b,(c,(d,(e,(f,(g,(h,(i,(j,())))))))))) where+ weak_tuple (a,(b,(c,(d,(e,(f,(g,(h,(i,(j,())))))))))) = (a,b,c,d,e,f,g,h,i,j)+ weak_untuple (a,b,c,d,e,f,g,h,i,j) = (a,(b,(c,(d,(e,(f,(g,(h,(i,(j,()))))))))))++-- | In almost all instances, the standard form can also be deduced from the tupled form; +-- the only exception is the unary case. The 'Tuple' class includes no new methods, +-- adding just this functional dependency.+--+-- While the methods of 'Tuple' are always copied from those of 'TupleOrUnary', +-- they are renamed, so that use of these methods tells the type checker it+-- can use the extra functional dependency.+class (TupleOrUnary t s) => Tuple t s | s -> t, t -> s where+ tuple :: s -> t+ tuple = weak_tuple++ untuple :: t -> s+ untuple = weak_untuple+ +instance Tuple () ()+instance Tuple (a,b) (a,(b,()))+instance Tuple (a,b,c) (a,(b,(c,())))+instance Tuple (a,b,c,d) (a,(b,(c,(d,()))))+instance Tuple (a,b,c,d,e) (a,(b,(c,(d,(e,())))))+instance Tuple (a,b,c,d,e,f) (a,(b,(c,(d,(e,(f,()))))))+instance Tuple (a,b,c,d,e,f,g) (a,(b,(c,(d,(e,(f,(g,())))))))+instance Tuple (a,b,c,d,e,f,g,h) (a,(b,(c,(d,(e,(f,(g,(h,()))))))))+instance Tuple (a,b,c,d,e,f,g,h,i) (a,(b,(c,(d,(e,(f,(g,(h,(i,())))))))))+instance Tuple (a,b,c,d,e,f,g,h,i,j) (a,(b,(c,(d,(e,(f,(g,(h,(i,(j,()))))))))))
+ Quipper/Utils/Typeable.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE CPP #-}++{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE DeriveDataTypeable #-}++#if __GLASGOW_HASKELL__ < 780+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+#endif++-- | The standard Haskell module "Data.Typeable" only provides+-- instances for tuples up to length 7. Since we need larger tuples,+-- we provide the missing instances here. +-- +-- Unfortunately, there is no easy way to do this portably; once the+-- instances get added to "Data.Typeable", we must remove them here.+-- +-- Please note: type instances do not generate documentation, so there+-- is nothing here to document. Please click on \"Source\" above to+-- see the source code.++module Quipper.Utils.Typeable where++import Data.Typeable++#if __GLASGOW_HASKELL__ >= 708++deriving instance Typeable (,,,,,,,)+deriving instance Typeable (,,,,,,,,)+deriving instance Typeable (,,,,,,,,,)++#else++-- Note: we use scoped type variables so that the typerep is constant;+-- it can be computed at compile time. Same trick as in+-- Data.Typeable.Internal.+instance (Typeable a, Typeable b, Typeable c, Typeable d, Typeable e, Typeable f, Typeable g, Typeable h) => Typeable (a,b,c,d,e,f,g,h) where+ typeOf _ = typerep+ where+ typerep = mkTyCon3 "GHC" "Tuple" "(,,,,,,,)" `mkTyConApp` [ typeOf (undefined :: a), typeOf (undefined :: b), typeOf (undefined :: c), typeOf (undefined :: d), typeOf (undefined :: e), typeOf (undefined :: f), typeOf (undefined :: g), typeOf (undefined :: h) ]++instance (Typeable a, Typeable b, Typeable c, Typeable d, Typeable e, Typeable f, Typeable g, Typeable h, Typeable i) => Typeable (a,b,c,d,e,f,g,h,i) where+ typeOf _ = typerep+ where+ typerep = mkTyCon3 "GHC" "Tuple" "(,,,,,,,,)" `mkTyConApp` [ typeOf (undefined :: a), typeOf (undefined :: b), typeOf (undefined :: c), typeOf (undefined :: d), typeOf (undefined :: e), typeOf (undefined :: f), typeOf (undefined :: g), typeOf (undefined :: h), typeOf (undefined :: i) ]++instance (Typeable a, Typeable b, Typeable c, Typeable d, Typeable e, Typeable f, Typeable g, Typeable h, Typeable i, Typeable j) => Typeable (a,b,c,d,e,f,g,h,i,j) where+ typeOf _ = typerep+ where+ typerep = mkTyCon3 "GHC" "Tuple" "(,,,,,,,,,)" `mkTyConApp` [ typeOf (undefined :: a), typeOf (undefined :: b), typeOf (undefined :: c), typeOf (undefined :: d), typeOf (undefined :: e), typeOf (undefined :: f), typeOf (undefined :: g), typeOf (undefined :: h), typeOf (undefined :: i), typeOf (undefined :: j) ]++#endif
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Superdoc+main = superdocMain
+ quipper-utils.cabal view
@@ -0,0 +1,94 @@+-- The name of the package.+name: quipper-utils++-- The package version. See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.9.0.0++-- A short (one-line) description of the package.+synopsis: Utility libraries for Quipper.++-- A longer description of the package.+description: ++ This package provides some utility libraries for Quipper, the+ embedded functional programming language for quantum computing. These+ libraries are used by Quipper, but do not depend on it. They provide+ general-purpose functionality that could in principle be used by+ other programs, but are are not sufficiently interesting to warrant+ their own packages.++-- URL for the project homepage or repository.+homepage: http://www.mathstat.dal.ca/~selinger/quipper/++-- The license under which the package is released.+license: BSD3++-- The file containing the license text.+license-file: COPYRIGHT++-- The package author(s).+author: Alexander S. Green, Peter LeFanu Lumsdaine,+ Neil J. Ross, Peter Selinger, Benoît Valiron++-- An email address to which users can send suggestions, bug reports, and +-- patches.+maintainer: selinger@mathstat.dal.ca++-- A copyright notice.+copyright: Copyright (c) 2011-2019. All rights reserved.++-- A classification category for future use by the package catalogue+-- Hackage. These categories have not yet been specified, but the+-- upper levels of the module hierarchy make a good start.+category: Quipper++-- The type of build used by this package.+build-type: Custom++-- Constraint on the version of Cabal needed to build this package.+cabal-version: >= 1.8++-- A list of additional files to be included in source distributions+-- built with setup sdist.+extra-source-files: ChangeLog++library+ -- Modules exported by the library.+ exposed-modules: Quipper.Utils.Auxiliary,+ Quipper.Utils.CommandLine,+ Quipper.Utils.PortableSignals,+ Quipper.Utils.Preview,+ Quipper.Utils.RandomSource,+ Quipper.Utils.Sampling,+ Quipper.Utils.Stabilizers.Clifford,+ Quipper.Utils.Stabilizers.Pauli,+ Quipper.Utils.Template,+ Quipper.Utils.Tuple,+ Quipper.Utils.Typeable + + -- Modules included in this library but not exported.+ other-modules: Quipper.Utils.Template.Auxiliary+ Quipper.Utils.Template.ErrorMsgQ+ Quipper.Utils.Template.LiftQ+ Quipper.Utils.Template.Lifting + + -- Other library packages from which modules are imported.+ build-depends: base >= 4.5 && < 5,+ template-haskell >= 2.7,+ containers >= 0.5.2.1,+ mtl >= 2.1.2,+ newsynth >= 0.3.0.1,+ random >= 1.0.1.1,+ process >= 1.4.2.0++ if !os(windows)+ build-depends: unix >= 2.7++ +custom-setup+ setup-depends: base >= 4.5, superdoc >= 0.1