packages feed

haquil (empty) → 0.1.7.5

raw patch · 9 files changed

+1356/−0 lines, 9 filesdep +MonadRandomdep +QuickCheckdep +basesetup-changed

Dependencies added: MonadRandom, QuickCheck, base, hTensor, template-haskell, vector

Files

+ ChangeLog.md view
@@ -0,0 +1,30 @@+# Revision history for quil++## 0.1.7.5  -- 2017-12-19++* added example usage++## 0.1.7.3  -- 2017-12-18++* added measurement++## 0.1.5.0  -- 2017-12-17++* tested two- and three-qubit gates++## 0.1.4.0  -- 2017-12-16++* renamed product operators+* tested one-qubit gates++## 0.1.3.0  -- 2017-12-16++* added Quil gates++## 0.1.2.0  -- 2017-12-16++* added qubit types and operations++## 0.1.0.0  -- 2017-12-15++* skeleton
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2017 Brian W Bush++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ReadMe.md view
@@ -0,0 +1,38 @@+quil: An instruction set for quantum computing+==============================================++This Haskell library implements the Quil language for quantum computing, as specified in "A Practical Quantum Instruction Set Architecture" <<https://arxiv.org/abs/1608.03355/>>, using the indexing conventions in <<https://arxiv.org/abs/1711.02086/>>.++Please report issues at <<https://bwbush.atlassian.net/projects/HQUIL/issues/>>.+++Example+-------++This example creates a wavefunction for the [Bell state](https://en.wikipedia.org/wiki/Bell_state) and then performs a measurement on its highest qubit.++	> import Control.Monad.Random (evalRandIO)+	> import Data.Qubit ((^^*), groundState)+	> import Data.Qubit.Gate (H, CNOT)+	+	> -- Construct the Bell state.+	> let bell = [h 0, cnot 0 1] ^^* groundState 2+	> bell+	0.7071067811865475|00> + 0.7071067811865475|11> @ [1,0]+	+	> -- Measure the Bell wavefunction.+	> bell' <- evalRandIO $ measure [1] bell+	> bell'+	([(1,0)],1.0|00> @ [1,0])+	+	> -- Measure it again.+	> evalRandIO $ measure [1] bell'+	([(1,0)],1.0|00> @ [1,0])+	+	> -- Measure another Bell wavefunction.+	> evalRandIO $ measure [1] bell+	([(1,0)],1.0|00> @ [1,0])+	+	> -- Measure another Bell wavefunction.+	> evalRandIO $ measure [1] bell+	([(1,1)],1.0|11> @ [1,0])
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ haquil.cabal view
@@ -0,0 +1,55 @@+name               : haquil+version            : 0.1.7.5+synopsis           : A Haskell implementation of the Quil instruction set for quantum computing.+description        : This Haskell library implements the Quil language for quantum computing, as specified in "A Practical Quantum Instruction Set Architecture" \<https:\/\/arxiv.org\/abs\/1608.03355\/\>.++license            : MIT+license-file       : LICENSE+copyright          : (c) 2017-18 Brian W Bush++author             : Brian W Bush <code@functionally.io>+maintainer         : Brian W Bush <code@functionally.io>++homepage           : https://bitbucket.org/functionally/haquil+bug-reports        : https://bwbush.atlassian.net/projects/HQUIL/issues/+package-url        : https://bitbucket.org/functionally/quil/downloads/haquil-0.1.7.5.tar.gz++category           : Language+stability          : Unstable++cabal-version      : >= 1.10+build-type         : Simple+extra-source-files : ReadMe.md+                     ChangeLog.md++source-repository head+  type             : git+  location         : https://bitbucket.org/functionally/haquil++library+  exposed-modules  : Data.Qubit+                     Data.Qubit.Gate+  other-modules    : Data.Int.Util+  hs-source-dirs   : src+  build-depends    : base >= 4.9 && < 4.10+                   , hTensor+                   , MonadRandom+                   , vector+  exposed          : True+  buildable        : True+  default-language : Haskell2010+  ghc-options      : -Wall++test-suite haquil-test+  main-is          : Test.hs+  hs-source-dirs   : src+  build-depends    : base+                   , hTensor+                   , MonadRandom+                   , QuickCheck+                   , template-haskell+                   , vector+  type             : exitcode-stdio-1.0+  buildable        : True+  default-language : Haskell2010+  ghc-options      : -Wall
+ src/Data/Int/Util.hs view
@@ -0,0 +1,85 @@+-----------------------------------------------------------------------------+--+-- Module      :  $Header$+-- Copyright   :  (c) 2017 Brian W Bush+-- License     :  MIT+--+-- Maintainer  :  Brian W Bush <code@functionally.io>+-- Stability   :  Stable+-- Portability :  Portable+--+-- | Integer functions.+--+-----------------------------------------------------------------------------+++{-# LANGUAGE Safe #-}+++module Data.Int.Util (+-- * Functions+  ilog2+, isqrt+, ilog2sqrt+) where+++import Control.Arrow ((&&&))+++-- | Square root of an integer.+--+-- This is equivalent to:+--+-- @+--   isqrt x == floor (sqrt $ from Integral x)+-- @+isqrt :: (Enum a, Num a, Ord a)+      => a -- ^ The integer.+      -> a -- ^ The integral square root.+isqrt n+  | n < fst (head table) = error "isqrt: illegal argument."+  | otherwise            = snd . head $ dropWhile ((< n) . fst) table+    where+      table = tabulate (^ (2 :: Int))+++-- | Base-two logarithm of an integer.+--+-- This is equivalent to:+--+-- @+--   ilog2 x == floor (logBase 2 $ fromIntegral x)+-- @+ilog2 :: (Enum a, Integral a, Ord a)+      => a -- ^ The integer.+      -> a -- ^ The integral base-two logarithm.+ilog2 n+  | n < fst (head table) = error "ilog2: illegal argument."+  | otherwise            = snd . head $ dropWhile ((< n) . fst) table+    where+      table = tabulate (2^)+++-- | Base-two logarithm of the square root of an integer.+--+-- This is equivalent to:+--+-- @+--   ilog2sqrt x == floor (logBase 2 . sqrt $ fromIntegral x)+-- @+ilog2sqrt :: (Enum a, Integral a, Num a, Ord a)+          => a -- ^ The integer.+          -> a -- ^ The integral base-two logarithm of the square root.+ilog2sqrt n+  | n < fst (head table) = error "ilog2sqrt: illegal argument."+  | otherwise            = snd . head $ dropWhile ((< n) . fst) table+    where+      table = tabulate (^ (2 :: Int))+++-- | Tabulate a function for later use.+tabulate :: (Enum a, Num a)+         => (a -> a) -- ^ The function.+         -> [(a, a)] -- ^ Its tabulation.+tabulate f = (f &&& id) <$> [0..]
+ src/Data/Qubit.hs view
@@ -0,0 +1,449 @@+-----------------------------------------------------------------------------+--+-- Module      :  $Header$+-- Copyright   :  (c) 2017 Brian W Bush+-- License     :  MIT+--+-- Maintainer  :  Brian W Bush <code@functionally.io>+-- Stability   :  Stable+-- Portability :  Portable+--+-- | Qubits and operations on them, using the indexing conventions of \<<https://arxiv.org/abs/1711.02086/>\>.+--+-----------------------------------------------------------------------------+++{-# LANGUAGE GeneralizedNewtypeDeriving #-}+++module Data.Qubit (+-- * Types+  QIndex+, QState(..)+, Amplitude+, Wavefunction+, Operator+-- * Construction+, qubit+, pureQubit+, qubits+, groundState+, pureState+, qubitsOperator+-- * Properties+, wavefunctionOrder+, wavefunctionIndices+, wavefunctionAmplitudes+, rawWavefunction+, operatorOrder+, operatorIndices+, operatorAmplitudes+, rawOperator+-- * Operations+, (^*^)+, (^*)+, (*^)+, (^^*)+, (*^^)+, probabilities+, project+, measure+, wavefunctionProbability+) where+++import Control.Arrow (first, second)+import Control.Monad (replicateM)+import Control.Monad.Random.Class (fromList)+import Control.Monad.Random.Lazy (Rand, RandomGen)+import Data.Complex (Complex(..), magnitude)+import Data.Function (on)+import Data.Int.Util (ilog2, isqrt)+import Data.List (elemIndex, groupBy, intersect, intercalate, sortBy)+import Data.Maybe (catMaybes)+import Numeric.LinearAlgebra.Array ((.*))+import Numeric.LinearAlgebra.Array.Util (Idx(iName), asScalar, coords, dims, order, outers, renameExplicit, reorder)+import Numeric.LinearAlgebra.Tensor (Tensor, Variant(..), listTensor, switch)++import qualified Data.Vector.Storable as V (toList)+++-- | States of a quibit.+data QState =+    QState0+  | QState1+    deriving (Bounded, Enum, Eq, Ord)++instance Read QState where+  readsPrec = (fmap (first toEnum) .) . readsPrec++instance Show QState where+  show = show . fromEnum+++-- | Index for qubits in a wavefunction.+type QIndex = Int+++-- | Dimension names in order of storage.+names :: Tensor a -> [String]+names = fmap iName . dims+++-- | Prefixes for 'Tensor' indices.+indexPrefix :: Variant -> Char+indexPrefix Contra = 'm'+indexPrefix Co     = 'n'+++-- | 'Tensor' index for a collection of qubits.+indexLabels :: Variant            -- ^ Whether contravariant or covariant.+            -> [QIndex]           -- ^ Indices of the qubits.+            -> [(String, String)] -- ^ Pairs of default `Tensor` indices and qubit indices.+indexLabels variant indices =+  let+    n = length indices+    o =+      case variant of+        Contra -> 0+        Co     -> n+  in+    zipWith (\k v -> (show k, indexPrefix variant : show v)) [(1+o)..] $ reverse indices+++-- | 'Tensor' index for a wavefunction.+wavefunctionLabels :: Int                -- ^ The number of qubits.+                   -> [(String, String)] -- ^ Pairs of default 'Tensor' indices and qubit indices.+wavefunctionLabels n = indexLabels Contra [0..(n-1)]+++-- | 'Tensor' index for an operator on qubits.+operatorLabels :: [QIndex]           -- ^ Indices of the qubits.+               -> [(String, String)] -- ^ Pairs of default `Tensor` indices and qubit indices.+operatorLabels indices = indexLabels Contra indices ++ indexLabels Co indices+++-- | Amplitude of a state  in a wavefunction.+type Amplitude = Complex Double+++-- | Compactly show an amplitude.+showAmplitude :: Amplitude -> String+showAmplitude (a :+ b)+  | b == 0    = show a+  | a == 0    = show b ++ "i"+  | otherwise = "(" ++ show a ++ "+" ++ show b ++ "i)"+++-- | Show a state and its amplitude.+type ShowState =  Int                   -- ^ Number of qubits in the state.+               -> ([QState], Amplitude) -- ^ The state and its amplitude.+               -> String                -- ^ The string representation.+++-- | Help to compactly show a tensor.+showTensor :: (a -> Tensor Amplitude) -- ^ Function for extracting the tensor of amplitudes.+           -> ShowState               -- ^ Function for showing a state and its amplitude.+           -> a                       -- ^ What to show.+           -> String                  -- ^ The string respresentation.+showTensor toTensor format x =+    let+      x' = canonicalOrder $ toTensor x+      n = order x'+    in+      (++ (show $ tensorIndices x'))+      . (++ " @ ")+      . intercalate " + "+        . fmap (format n)+        . filter ((/= 0) . snd)+        $ tensorAmplitudes x'+++-- | Indices in a tensor.+tensorIndices :: Tensor Amplitude -- ^ The tensor.+              -> [QIndex]         -- ^ The qubit indices.+tensorIndices =+  fmap (read . tail)+    . filter ((== indexPrefix Contra) . head)+    . names+++-- | Transpose a tensor to canonical order.+canonicalOrder :: Tensor Amplitude -> Tensor Amplitude+canonicalOrder x =+  let+    f (v : i) (v' : i') = (v, - read i :: Int) `compare` (v', - read i')+    f _ _ = undefined+  in+    reorder (sortBy f $ names x) x+++-- | Amplitudes in a tensor.+tensorAmplitudes :: Tensor Amplitude        -- ^ The tensor.+                 -> [([QState], Amplitude)] -- ^ List of qubit states and their amplitudes, where indices of states are ordered according to 'tensorIndices'.+tensorAmplitudes x =+  let+    n = order x+  in+    zip (replicateM n [minBound..maxBound])+      . V.toList+     $ coords x+++-- | A wavefunction for qubits.+newtype Wavefunction = Wavefunction {rawWavefunction' :: Tensor Amplitude}+  deriving (Eq, Floating, Fractional, Num)++instance Show Wavefunction where+  show =+    showTensor rawWavefunction'+      $ \_ (k, v) ->+      showAmplitude v ++ "|" ++ concatMap show k ++ ">"+++-- | The 'Tensor' encoding the wavefunction.+rawWavefunction :: Wavefunction -> Tensor Amplitude+rawWavefunction = canonicalOrder . rawWavefunction'+++-- | Number of qubits in a wavefunction.+wavefunctionOrder :: Wavefunction -> Int+wavefunctionOrder = order . rawWavefunction'+++-- | Qubit indices in a wavefunction.+wavefunctionIndices :: Wavefunction -- ^ The wavefunction.+                    -> [QIndex]     -- ^ List of qubit indices.+wavefunctionIndices = tensorIndices . rawWavefunction'+++-- | Amplitudes of states in a qubit wavefunction.+wavefunctionAmplitudes :: Wavefunction            -- ^ The wavefunction.+                       -> [([QState], Amplitude)] -- ^ List of qubit states and their amplitudes, where indices of states are ordered according to 'wavefunctionIndices'.+wavefunctionAmplitudes = tensorAmplitudes . rawWavefunction'+++-- | Construct a qubit from the amplitudes of its states.+--+-- The squares of the norms of the amplitudes must sum to one.+qubit :: QIndex                 -- ^ The index of the qubit in the wavefunction.+      -> (Amplitude, Amplitude) -- ^ The amplitude of the 0 and 1 states, respectively.+      -> Wavefunction           -- ^ The wavefunction for the qubit.+qubit index (a0, a1) =+  Wavefunction+    . renameExplicit [("1", indexPrefix Contra : show index)]+    $ listTensor [2] [a0, a1]+++-- | Construct a qubit with a pure state.+pureQubit :: QIndex       -- ^ Which qubit.+          -> QState       -- ^ The state of the qubit.+          -> Wavefunction -- ^ The wavefunction.+pureQubit index QState0 = qubit index (1, 0)+pureQubit index QState1 = qubit index (0, 1)+++-- | Construct a wavefunction for the amplitudes of its qubit states.+--+-- Amplitudes ordered so that the 0 state appears before the 1 state and the lower qubit indices cycle faster than then higher qubit indices. For example, a two-qubit state has its amplitudes ordered |00>, |01>, |10>, |11>. This ordering can be generated as follows, where qubits are orderd from higher indices to lower ones:+--+-- >>> sequence $ replicate 3 [minBound..maxBound] :: [[QState]]+-- [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]+--+-- The squares of the norms of the amplitudes must sum to one.+qubits :: [Amplitude]  -- ^ The amplitudes.+       -> Wavefunction -- ^ The wavefunction.+qubits amplitudes =+  let+    n = ilog2 $ length amplitudes+  in+    Wavefunction+      . renameExplicit (wavefunctionLabels n)+      $ listTensor (replicate n 2) amplitudes+++-- | Construct the ground state where each qubit is in state 0.+groundState :: Int          -- ^ Number of qubits.+            -> Wavefunction -- ^ The ground state wavefunction.+groundState = pureState . flip replicate QState0+++-- | Constructa a pure state.+pureState :: [QState]     -- ^ The state of each qubit, ordered from higher index to lower index.+          -> Wavefunction -- ^ The wavefunction.+pureState =+  Wavefunction+    . outers+    . (rawWavefunction' <$>)+    . (uncurry pureQubit <$>)+    . zip [0..]+    . reverse+++-- | An operator on wavefunctions.+newtype Operator = Operator {rawOperator' :: Tensor (Complex Double)}+  deriving (Eq, Floating, Fractional, Num)++instance Show Operator where+  show =+    showTensor rawOperator'+      $ \n (k, v) ->+      let+        (kr, kc) = splitAt (n `div` 2) $ concatMap show k+      in+        showAmplitude v ++ "|" ++ kr ++ "><" ++ kc ++ "|"+++-- | The 'Tensor' encoding the operator.+rawOperator :: Operator -> Tensor Amplitude+rawOperator = canonicalOrder . rawOperator'+++-- | Number of qubits for an operator.+operatorOrder :: Operator -> Int+operatorOrder = isqrt . order . rawOperator'+++-- | Qubit indices in an operator.+operatorIndices :: Operator -- ^ The operator.+                -> [QIndex] -- ^ List of qubit indices.+operatorIndices = tensorIndices . rawOperator'+++-- | Amplitudes of state transitions in a qubit operator.+operatorAmplitudes :: Operator                            -- ^ The wavefunction.+                   -> [(([QState], [QState]), Amplitude)] -- ^ List of qubit state transitions and their amplitudes, in row-major order with the states ordered according to 'operatorIndices'.+operatorAmplitudes (Operator x) =+  let+    x' = tensorAmplitudes x+    n = length . fst $ head x'+  in+    first (splitAt $ n `div` 2) <$> x'+++-- | Construct an operator on qubit wavefunctions.+--+-- Amplitudes in row-major order where amplitudes are ordered so that the 0 state appears before the 1 state and the lower qubit indices cycle faster than then higher qubit indices. For example, a three-qubit operator has its amplitudes ordered \<00|00>, \<00|01>, \<00|10>, \<00|11>, \<01|00>, \<01|01>, \<01|10>, \<01|11>, \<10|00>, \<10|01>, \<10|10>, \<10|11>, \<11|00>, \<11|01>, \<11|10>, \<11|11>, where states in the bras and kets are correspond to the order of the first argument to `qubitsOperator`. This ordering can be generated as follows:+--+-- >>> fmap (splitAt 2) . sequence $ replicate (2 * 2) [minBound..maxBound] :: [([QState], [QState])] +-- [([0,0],[0,0]),([0,0],[0,1]),([0,0],[1,0]),([0,0],[1,1]),([0,1],[0,0]),([0,1],[0,1]),([0,1],[1,0]),([0,1],[1,1]),([1,0],[0,0]),([1,0],[0,1]),([1,0],[1,0]),([1,0],[1,1]),([1,1],[0,0]),([1,1],[0,1]),([1,1],[1,0]),([1,1],[1,1])]+--+-- The operator must be unitary.+qubitsOperator :: [QIndex]    -- ^ The qubit indices for which the operator applies, in descending order according to \<<https://arxiv.org/pdf/1711.02086/>\>.+               -> [Amplitude] -- ^ The amplitudes of the operator matrix, in row-major order with the states ordered from higher indices to lower ones.+               -> Operator    -- ^ The wavefunction operator.+qubitsOperator indices =+  let+    n = length indices+  in+    Operator+      . renameExplicit (operatorLabels $ reverse indices)+      . listTensor (replicate n 2 ++ replicate n (-2))+++-- | Multiply two wavefunction or operator tensors.+mult :: Tensor Amplitude -> Tensor Amplitude -> Tensor Amplitude+mult x y =+  let+    lft  = filter ((== indexPrefix Co    ) . head) $ names x+    rght = filter ((== indexPrefix Contra) . head) $ names y+    cmmn = fmap tail lft `intersect` fmap tail rght+    x' = renameExplicit [(i, '@' : tail i) | i <- filter ((`elem` cmmn) . tail) lft ] x+    y' = renameExplicit [(i, '@' : tail i) | i <- filter ((`elem` cmmn) . tail) rght] y+  in+    x' * y' +++-- | Apply two operators in sequence.+(^*^) :: Operator -> Operator -> Operator+Operator x ^*^ Operator y = Operator $ x `mult` y+infixr 7 ^*^+++-- | Apply an operator to a wavefunction.+(^*) :: Operator -> Wavefunction -> Wavefunction+Operator x ^* Wavefunction y = Wavefunction $ x `mult` y+infixr 6 ^*+++-- | Apply an operator to a wavefunction.+(*^) :: Wavefunction -> Operator -> Wavefunction+(*^) = flip (^*)+infixl 6 *^+++-- | Apply a sequence of operators to a wavefunction.+(^^*) :: Foldable t => t Operator -> Wavefunction -> Wavefunction+(^^*) = flip . foldl $ flip (^*)+infixr 6 ^^*+++-- | Apply a sequence of operators to a wavefunction.+(*^^) :: Foldable t => Wavefunction -> t Operator -> Wavefunction+(*^^) = flip (^^*)+infixl 6 *^^+++-- | Probabilities of a selection of qubits.+probabilities :: [QIndex]                       -- ^ Which qubits.+              -> Wavefunction                   -- ^ The wavefunciton.+              -> [([(QIndex, QState)], Double)] -- ^ The probabilities for the combinations of qubit states.+probabilities indices x =+  let+    indices' = wavefunctionIndices x+    positions = catMaybes $ (`elemIndex` indices') <$> indices+  in+    filter ((/= 0) . snd)+    . fmap (\kvs -> (fst $ head kvs, sum $ snd <$> kvs))+    . groupBy ((==) `on` fst)+    $ sortBy (compare `on` fst)+      [+        (+          fmap snd . filter ((`elem` positions) . fst) . zip [0..] $ zip indices' states+        , magnitude amplitude ^ (2::Int)+        )+      |+        (states, amplitude) <- wavefunctionAmplitudes x+      ]+++-- | Project a wavefunction onto a particular state.+project :: [(QIndex, QState)] -- ^ The qubits for the state.+        -> Wavefunction       -- ^ The wavefunction.+        -> Wavefunction       -- ^ The projected wavefunction.+project states x =+  let+    y = canonicalOrder $ rawWavefunction' x+    p =+      canonicalOrder+        . outers+        $ fmap rawWavefunction'+        [+          case i `lookup` states of+            Nothing -> qubit i (1, 1)+            Just s  -> pureQubit i s+        |+          i <- [0..(order y - 1)]+        ]+    z = p .* y+  in+    Wavefunction $ z / sqrt (z * switch z)+++-- | Measure qubits in a wavefunction.+measure :: RandomGen g+        => [QIndex]                                  -- ^ Which qubits to measure.+        -> Wavefunction                              -- ^ The wavefunction.+        -> Rand g ([(QIndex, QState)], Wavefunction) -- ^ Action for the resulting measurement and wavefunction.+measure indices x =+  do+    let+      candidates = probabilities indices x+    collapse <- fromList $ second toRational <$> candidates+    return (collapse, project collapse x)+++-- | The total probability for the wave function, which should be 1.+wavefunctionProbability :: Wavefunction+                        -> Amplitude+wavefunctionProbability (Wavefunction x) = asScalar $ x * switch x
+ src/Data/Qubit/Gate.hs view
@@ -0,0 +1,340 @@+-----------------------------------------------------------------------------+--+-- Module      :  $Header$+-- Copyright   :  (c) 2017 Brian W Bush+-- License     :  MIT+--+-- Maintainer  :  Brian W Bush <code@functionally.io>+-- Stability   :  Stable+-- Portability :  Portable+--+-- | Gates for qubit wavefunctions, mostly as in Quil \<<https://arxiv.org/abs/1608.03355/\>> and using the conventions of \<<https://arxiv.org/abs/1711.02086/>\>.+--+-----------------------------------------------------------------------------+++module Data.Qubit.Gate (+-- * One-Cubit Gates+  i+, x+, y+, z+, h+, s+, t+-- * Parameterized One-Cubit Gates+, phase+, rx+, ry+, rz+-- * Two-Cubit Gates+, cnot+, swap+, iswap+-- * Parameterized Two-Cubit Gates+, cphase00+, cphase01+, cphase10+, cphase+, pswap+, cz+-- * Three-Cubit Gates+, ccnot+, cswap+) where+++import Data.Complex (Complex(..), cis)+import Data.Qubit (Operator, QIndex, qubitsOperator)+++-- | The identity gate. This corresponds to I in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+i :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+i i0 =+  qubitsOperator [i0]+    [+      1, 0+    , 0, 1+    ]+++-- | The Pauli-x gate. This corresponds to X in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+x :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+x i0 =+  qubitsOperator [i0]+    [+      0, 1+    , 1, 0+    ]+++-- | The Pauli-y gate. This corresponds to Y in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+y :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+y i0  =+  qubitsOperator [i0]+    [+      0     , 0 :+ (-1)+    , 0 :+ 1, 0+    ]+++-- | The Pauli-z gate. This corresponds to Z in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+z :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+z i0 =+  qubitsOperator [i0]+    [+      1, 0+    , 0, -1+    ]+++-- | The Hadamard gate. This corresponds to H in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+h :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+h i0 =+  qubitsOperator [i0]+    [+      1, 1+    , 1, -1+    ] / sqrt 2+++-- | The phase-shift gate. This corresponds to PHASE in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+phase :: Double   -- ^ The phase angle [radians].+      -> QIndex   -- ^ The index of the qubit in the wavefunction.+      -> Operator -- ^ The operator.+phase  theta i0 =+  qubitsOperator [i0]+    [+      1, 0+    , 0, cis theta+    ]+++-- | The one-qubit 90-degree phase-shift gate. This corresponds to S in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+s :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+s i0 =+  qubitsOperator [i0]+    [+      1, 0+    , 0, 0 :+ 1+    ]+++-- | The one-qubit 45-degree phase-shift gate. This corresponds to T in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+t :: QIndex   -- ^ The index of the qubit in the wavefunction.+  -> Operator -- ^ The operator.+t i0 =+  qubitsOperator [i0]+    [+      1, 0+    , 0, (1 :+ 1) / sqrt 2+    ]+++-- | A controlled phase gate on |00>. This corresponds to CPHASE00 in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cphase00 :: Double   -- ^ The phase angle [radians].+         -> QIndex   -- ^ The index of the higher qubit in the wavefunction.+         -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+         -> Operator -- ^ The operator.+cphase00 theta i0 i1 =+  qubitsOperator [i0, i1]+    [+      cis theta, 0, 0, 0+    , 0        , 1, 0, 0+    , 0        , 0, 1, 0+    , 0        , 0, 0, 1+    ]+++-- | A controlled phase gate on |01>. This corresponds to CPHASE01 in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cphase01 :: Double   -- ^ The phase angle [radians].+         -> QIndex   -- ^ The index of the higher qubit in the wavefunction.+         -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+         -> Operator -- ^ The operator.+cphase01 theta i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0        , 0, 0+    , 0, cis theta, 0, 0+    , 0, 0        , 1, 0+    , 0, 0        , 0, 1+    ]+++-- | A conrolled pahse gate on |10>. This corresponds to CPHASE10 in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cphase10 :: Double   -- ^ The phase angle [radians].+         -> QIndex   -- ^ The index of the higher qubit in the wavefunction.+         -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+         -> Operator -- ^ The operator.+cphase10 theta i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0, 0        , 0+    , 0, 1, 0        , 0+    , 0, 0, cis theta, 0+    , 0, 0, 0        , 1+    ]+++-- | A controlled phase gate on |11>. This corresponds to CPHASE in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cphase :: Double   -- ^ The phase angle [radians].+       -> QIndex   -- ^ The index of the higher qubit in the wavefunction.+       -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+       -> Operator -- ^ The operator.+cphase theta i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0, 0, 0+    , 0, 1, 0, 0+    , 0, 0, 1, 0+    , 0, 0, 0, cis theta+    ]+++-- | The x-rotation gate. This corresponds to RX in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+rx :: Double   -- ^ The phase angle [radians].+   -> QIndex   -- ^ The index of the qubit in the wavefunction.+   -> Operator -- ^ The operator.+rx theta i0 =+  qubitsOperator [i0]+    [+      cos (theta / 2) :+ 0        , 0 :+ (- sin (theta / 2))+    , 0 :+ (- sin (theta / 2)), cos (theta / 2) :+ 0+    ]+++-- | The y-rotation gate. This corresponds to RY in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+ry :: Double   -- ^ The phase angle [radians].+   -> QIndex   -- ^ The index of the qubit in the wavefunction.+   -> Operator -- ^ The operator.+ry theta i0 =+  qubitsOperator [i0]+    [+      cos (theta / 2) :+ 0, (- sin (theta / 2)) :+ 0+    , sin (theta / 2) :+ 0, cos (theta / 2) :+ 0+    ]+++-- | The z-rotation gate. This corresponds to RZ in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+rz :: Double   -- ^ The phase angle [radians].+   -> QIndex   -- ^ The index of the qubit in the wavefunction.+   -> Operator -- ^ The operator.+rz theta i0 =+  qubitsOperator [i0]+    [+      cis (- theta / 2), 0+    , 0                , cis (theta / 2)+    ]+++-- | The controlled-not gate for two qubits. This corresponds to CNOT in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cnot :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+     -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+     -> Operator -- ^ The operator.+cnot i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0, 0, 0+    , 0, 1, 0, 0+    , 0, 0, 0, 1+    , 0, 0, 1, 0+    ]+++-- | The controlled-not gate by three qubits. This corresponds to CCNOT in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+ccnot :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+      -> QIndex   -- ^ The index of the middle qubit in the wavefunction.+      -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+      -> Operator -- ^ The operator.+ccnot i0 i1 i2 =+  qubitsOperator [i0, i1, i2]+    [+      1, 0, 0, 0, 0, 0, 0, 0+    , 0, 1, 0, 0, 0, 0, 0, 0+    , 0, 0, 1, 0, 0, 0, 0, 0+    , 0, 0, 0, 1, 0, 0, 0, 0+    , 0, 0, 0, 0, 1, 0, 0, 0+    , 0, 0, 0, 0, 0, 1, 0, 0+    , 0, 0, 0, 0, 0, 0, 0, 1+    , 0, 0, 0, 0, 0, 0, 1, 0+    ]+++-- | The phase-swap gate. This corresponds to PSWAP in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+pswap :: Double   -- ^ The phase angle [radians].+      -> QIndex   -- ^ The index of the higher qubit in the wavefunction.+      -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+      -> Operator -- ^ The operator.+pswap theta i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0        , 0        , 0+    , 0, 0        , cis theta, 0+    , 0, cis theta, 0        , 0+    , 0, 0        , 0        , 1+    ]+   ++-- | The swap gate with 0-degree phase. This corresponds to SWAP in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+swap :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+     -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+     -> Operator -- ^ The operator.+swap i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0, 0, 0+    , 0, 0, 1, 0+    , 0, 1, 0, 0+    , 0, 0, 0, 1+    ]++-- | The swap gate with 90-degree phase. This corresponds to ISWAP in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+iswap :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+      -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+      -> Operator -- ^ The operator.+iswap i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0     , 0     , 0+    , 0, 0     , 0 :+ 1, 0+    , 0, 0 :+ 1, 0     , 0+    , 0, 0     , 0     , 1+    ]++-- | The three-qubit controlled-swap gate. This corresponds to CSWAP in Quil \<<https://arxiv.org/abs/1608.03355/\>>, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cswap :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+      -> QIndex   -- ^ The index of the middle qubit in the wavefunction.+      -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+      -> Operator -- ^ The operator.+cswap i0 i1 i2 =+  qubitsOperator [i0, i1, i2]+    [+      1, 0, 0, 0, 0, 0, 0, 0+    , 0, 1, 0, 0, 0, 0, 0, 0+    , 0, 0, 1, 0, 0, 0, 0, 0+    , 0, 0, 0, 1, 0, 0, 0, 0+    , 0, 0, 0, 0, 1, 0, 0, 0+    , 0, 0, 0, 0, 0, 0, 1, 0+    , 0, 0, 0, 0, 0, 1, 0, 0+    , 0, 0, 0, 0, 0, 0, 0, 1+    ]+    ++-- | The controlled-z gate, with the indexing convention of \<<https://arxiv.org/pdf/1711.02086/>\>.+cz :: QIndex   -- ^ The index of the higher qubit in the wavefunction.+   -> QIndex   -- ^ The index of the lower qubit in the wavefunction.+   -> Operator -- ^ The operator.+cz i0 i1 =+  qubitsOperator [i0, i1]+    [+      1, 0, 0, 0+    , 0, 1, 0, 0+    , 0, 0, 1, 0+    , 0, 0, 0, -1+    ]
+ src/Test.hs view
@@ -0,0 +1,337 @@+-----------------------------------------------------------------------------+--+-- Module      :  $Header$+-- Copyright   :  (c) 2017 Brian W Bush+-- License     :  MIT+--+-- Maintainer  :  Brian W Bush <code@functionally.io>+-- Stability   :  Stable+-- Portability :  Portable+--+-- | Testing qbits and operations on them.+--+-- The test data is derived from pyQuil \<<http://pyquil.readthedocs.io>\ and recorded in \<<https://bitbucket.org/functionally/quil/src/99a2efb54fd2c7ac99a9bde3091da130bdadbf6b/test-data.ipynb>\>.+-----------------------------------------------------------------------------+++{-# LANGUAGE TemplateHaskell #-}++{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+++module Main (+  main+) where+++import Control.Monad (replicateM)+import Data.Complex (Complex(..), cis, magnitude)+import Data.Int.Util (ilog2)+import Data.Qubit (QState(..), (^*), groundState, pureQubit, pureState, qubit, qubits, rawWavefunction, wavefunctionAmplitudes, wavefunctionIndices, wavefunctionOrder)+import Numeric.LinearAlgebra.Array ((.*))+import Numeric.LinearAlgebra.Array.Util (coords, scalar)+import Test.QuickCheck.All (quickCheckAll)+import System.Exit (exitFailure, exitSuccess)++import qualified Data.Qubit.Gate as G+import qualified Data.Vector.Storable as V (toList)+++-- Helper functions.++i = scalar $ 0 :+ 1++cos' = scalar . (:+ 0) . cos+sin' = scalar . (:+ 0) . sin+cis' = scalar . cis++applyGate = (rawWavefunction .) . (. (qubits . V.toList . coords)) . (^*)++epsilon = 1e-5++xs ~~ ys = V.toList (coords xs) ~~~ V.toList (coords ys)+infix 4 ~~++(~~~) = (and .) . zipWith (\x y -> magnitude (x - y) <= epsilon)+++-- Wavefunction tests.++prop_qubit n a0 a1 =+  let+    q = qubit n (a0, a1)+  in+       wavefunctionOrder q == 1+    && wavefunctionIndices q == [n]+    && wavefunctionAmplitudes q == [([QState0], a0), ([QState1], a1)]++prop_pure_qubit n b =+  let+    z = if b then QState1 else QState0+    q = pureQubit n z+  in+       wavefunctionOrder q == 1+    && wavefunctionIndices q == [n]+    && fmap fst (wavefunctionAmplitudes q) == [[QState0], [QState1]]+    && fmap snd (wavefunctionAmplitudes q) ~~~ (if b then [0, 1] else [1, 0])++prop_qubits as =+  let+    n = ilog2 $ length as+    as' = take (2^n) as+    q = qubits as'+  in+       length as < 2+    || n > 15+    || wavefunctionOrder q == n+    && wavefunctionIndices q == reverse [0..(n-1)]+    && fmap fst (wavefunctionAmplitudes q) == replicateM n [minBound..maxBound]+    && fmap snd (wavefunctionAmplitudes q) ~~~ as'++prop_ground n =+  let+    q = groundState n+  in+       n < 2+    || n > 15+    || wavefunctionOrder q == n+    && wavefunctionIndices q == [0..(n-1)]+    && fmap fst (wavefunctionAmplitudes q) == replicateM n [minBound..maxBound]+    && fmap snd (wavefunctionAmplitudes q) ~~~ (1 : replicate (2^n - 1) 0)++prop_pure_state bs =+  let+    n = length bs+    z = [if b then QState1 else QState0 | b <- bs]+    q = pureState z+  in+       n < 2+    || n > 15+    || wavefunctionOrder q == n+    && wavefunctionIndices q == [0..(n-1)]+    && fmap fst (wavefunctionAmplitudes q) == replicateM n [minBound..maxBound]+    && fmap snd (wavefunctionAmplitudes q) ~~~ [if z' == reverse z then 1 else 0 | z' <- replicateM n [minBound..maxBound]]+   ++-- Tests for one-qubit gates.++b0 = rawWavefunction $ pureState [QState0]+b1 = rawWavefunction $ pureState [QState1]++prop_gate_i =+  let+    g = applyGate $ G.i 0+  in+       g b0 ~~ b0+    && g b1 ~~ b1++prop_gate_x =+  let+    g = applyGate $ G.x 0+  in+       g b0 ~~ b1+    && g b1 ~~ b0++prop_gate_y =+  let+    g = applyGate $ G.y 0+  in+       g b0 ~~ i .* b1+    && g b1 ~~ - i .* b0++prop_gate_z =+  let+    g = applyGate $ G.z 0+  in+       g b0 ~~ b0+    && g b1 ~~ - b1++prop_gate_h =+  let+    g = applyGate $ G.h 0+  in+       g b0 ~~ (b0 + b1) / sqrt 2+    && g b1 ~~ (b0 - b1) / sqrt 2++prop_gate_phase theta =+  let+    g = applyGate $ G.phase theta 0+  in+       g b0 ~~ b0+    && g b1 ~~ cis' theta .* b1++prop_gate_s =+  let+    g = applyGate $ G.s 0+  in+       g b0 ~~ b0+    && g b1 ~~ i .* b1++prop_gate_t =+  let+    g = applyGate $ G.t 0+  in+       g b0 ~~ b0+    && g b1 ~~ scalar (1 :+ 1) .* b1 / sqrt 2++prop_gate_rx theta =+  let+    g = applyGate $ G.rx theta 0+    theta' = theta / 2+  in+       g b0 ~~   cos' theta'      .* b0 - sin' theta' .* i .* b1+    && g b1 ~~ - sin' theta' .* i .* b0 + cos' theta'      .* b1++prop_gate_ry theta =+  let+    g = applyGate $ G.ry theta 0+    theta' = theta / 2+  in+       g b0 ~~   cos' theta' .* b0 + sin' theta' .* b1+    && g b1 ~~ - sin' theta' .* b0 + cos' theta' .* b1++prop_gate_rz theta =+  let+    g = applyGate $ G.rz theta 0+    theta' = theta / 2+  in+       g b0 ~~ cis' (- theta') .* b0+    && g b1 ~~ cis'    theta'  .* b1+++-- Tests for two-cubit gates.++b00 = rawWavefunction $ pureState [QState0, QState0]+b01 = rawWavefunction $ pureState [QState0, QState1]+b10 = rawWavefunction $ pureState [QState1, QState0]+b11 = rawWavefunction $ pureState [QState1, QState1]++prop_gate_cphase00 theta =+  let+    g = applyGate $ G.cphase00 theta 1 0+  in+       g b00 ~~ cis' theta .* b00+    && g b01 ~~ b01+    && g b10 ~~ b10+    && g b11 ~~ b11++prop_gate_cphase01 theta =+  let+    g = applyGate $ G.cphase01 theta 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ cis' theta .* b01+    && g b10 ~~ b10+    && g b11 ~~ b11++prop_gate_cphase10 theta =+  let+    g = applyGate $ G.cphase10 theta 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ b01+    && g b10 ~~ cis' theta .* b10+    && g b11 ~~ b11++prop_gate_cphase theta =+  let+    g = applyGate $ G.cphase theta 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ b01+    && g b10 ~~ b10+    && g b11 ~~ cis' theta .* b11++prop_gate_cnot =+  let+    g = applyGate $ G.cnot 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ b01+    && g b10 ~~ b11+    && g b11 ~~ b10++prop_gate_pswap theta =+  let+    g = applyGate $ G.pswap theta 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ cis' theta .* b10+    && g b10 ~~ cis' theta .* b01+    && g b11 ~~ b11++prop_gate_swap =+  let+    g = applyGate $ G.swap 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ b10+    && g b10 ~~ b01+    && g b11 ~~ b11++prop_gate_iswap =+  let+    g = applyGate $ G.iswap 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ i .* b10+    && g b10 ~~ i .* b01+    && g b11 ~~ b11++prop_gate_cz =+  let+    g = applyGate $ G.cz 1 0+  in+       g b00 ~~ b00+    && g b01 ~~ b01+    && g b10 ~~ b10+    && g b11 ~~ - b11+++-- Tests for three-cubit gates.++b000 = rawWavefunction $ pureState [QState0, QState0, QState0]+b001 = rawWavefunction $ pureState [QState0, QState0, QState1]+b010 = rawWavefunction $ pureState [QState0, QState1, QState0]+b011 = rawWavefunction $ pureState [QState0, QState1, QState1]+b100 = rawWavefunction $ pureState [QState1, QState0, QState0]+b101 = rawWavefunction $ pureState [QState1, QState0, QState1]+b110 = rawWavefunction $ pureState [QState1, QState1, QState0]+b111 = rawWavefunction $ pureState [QState1, QState1, QState1]++prop_gate_ccnot =+  let+    g = applyGate $ G.ccnot 2 1 0+  in+       g b000 ~~ b000+    && g b001 ~~ b001+    && g b010 ~~ b010+    && g b011 ~~ b011+    && g b100 ~~ b100+    && g b101 ~~ b101+    && g b110 ~~ b111+    && g b111 ~~ b110++prop_gate_cswap =+  let+    g = applyGate $ G.cswap 2 1 0+  in+       g b000 ~~ b000+    && g b001 ~~ b001+    && g b010 ~~ b010+    && g b011 ~~ b011+    && g b100 ~~ b100+    && g b101 ~~ b110+    && g b110 ~~ b101+    && g b111 ~~ b111+++-- Run tests.++return []+main =+  do+    success <- $quickCheckAll+    if success+      then exitSuccess+      else exitFailure