packages feed

haquil 0.2.1.5 → 0.2.1.14

raw patch · 7 files changed

+483/−58 lines, 7 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ Language.Quil.Types: IntBits16 :: Int16 -> BitData
+ Language.Quil.Types: IntBits32 :: Int32 -> BitData
+ Language.Quil.Types: IntBits64 :: Int64 -> BitData
+ Language.Quil.Types: IntBits8 :: Int8 -> BitData
+ Language.Quil.Types: WordBits16 :: Word16 -> BitData
+ Language.Quil.Types: WordBits32 :: Word32 -> BitData
+ Language.Quil.Types: WordBits64 :: Word64 -> BitData
+ Language.Quil.Types: WordBits8 :: Word8 -> BitData
+ Language.Quil.Types: finiteBitsFromBitVector :: (Integral a, FiniteBits a) => Int -> BV -> a

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Revision history for quil +## 0.2.1.14  -- 2018-03-04++* execution of Quil programs+* additional test cases+ ## 0.2.0.0  -- 2017-12-19  * added types for Quil
ReadMe.md view
@@ -13,7 +13,7 @@  	> import Control.Monad.Random (evalRandIO) 	> import Data.Qubit ((^^*), groundState, measure)-	> import Data.Qubit.Gate (H, CNOT)+	> import Data.Qubit.Gate (h, cnot) 	 	> -- Construct the Bell state. 	> let bell = [h 0, cnot 0 1] ^^* groundState 2
haquil.cabal view
@@ -1,5 +1,5 @@ name               : haquil-version            : 0.2.1.5+version            : 0.2.1.14 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\/\>. @@ -12,7 +12,7 @@  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.2.1.5.tar.gz+package-url        : https://bitbucket.org/functionally/quil/downloads/haquil-0.2.1.14.tar.gz  category           : Language stability          : Unstable
src/Data/Qubit.hs view
@@ -9,7 +9,34 @@ -- Portability :  Portable -- -- | Qubits and operations on them, using the indexing conventions of \<<https://arxiv.org/abs/1711.02086/>\>.---+-- +-- The example below 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, measure)+-- > >>> 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]) -----------------------------------------------------------------------------  @@ -53,19 +80,19 @@   import Control.Arrow (first, second)-import Control.Monad (replicateM)+import Control.Monad (ap, mapM, replicateM) import Control.Monad.Random.Class (fromList) import Control.Monad.Random.Lazy (Rand, RandomGen)-import Data.Complex (Complex(..), magnitude)+import Data.Complex (Complex(..), conjugate, 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 Numeric.LinearAlgebra.Array.Util (Idx(iName), asScalar, coords, dims, mapArray, order, outers, renameExplicit, reorder, setType)+import Numeric.LinearAlgebra.Tensor (Tensor, Variant(..), contrav, listTensor, switch) -import qualified Data.Vector.Storable as V (toList)+import qualified Data.Vector.Storable as V (map, toList)   -- | States of a quibit.@@ -90,12 +117,25 @@ names = fmap iName . dims  --- | Prefixes for 'Tensor' indices.-indexPrefix :: Variant -> Char-indexPrefix Contra = 'm'-indexPrefix Co     = 'n'+-- | Prefixes for 'Tensor' variants.+variantPrefix :: Variant -> Char+variantPrefix Contra = 'm'+variantPrefix Co     = 'n'  +-- | 'Tensor' variants for index prefixes.+prefixVariant :: String -> Variant+prefixVariant ('m' : _) = Contra+prefixVariant ('n' : _) = Co+prefixVariant _         = error "Unexpected index."+++prefixDimension :: String -> Int+prefixDimension ('m' : _) = 2+prefixDimension ('n' : _) = -2+prefixDimension _         = error "Unexpected index."++ -- | 'Tensor' index for a collection of qubits. indexLabels :: Variant            -- ^ Whether contravariant or covariant.             -> [QIndex]           -- ^ Indices of the qubits.@@ -108,7 +148,7 @@         Contra -> 0         Co     -> n   in-    zipWith (\k v -> (show k, indexPrefix variant : show v)) [(1+o)..] $ reverse indices+    zipWith (\k v -> (show k, variantPrefix variant : show v)) [(1+o)..] $ reverse indices   -- | 'Tensor' index for a wavefunction.@@ -132,6 +172,7 @@ showAmplitude (a :+ b)   | b == 0    = show a   | a == 0    = show b ++ "i"+  | b <  0    = "(" ++ show a ++        show b ++ "i)"   | otherwise = "(" ++ show a ++ "+" ++ show b ++ "i)"  @@ -147,16 +188,16 @@            -> 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'+  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.@@ -164,19 +205,39 @@               -> [QIndex]         -- ^ The qubit indices. tensorIndices =   fmap (read . tail)-    . filter ((== indexPrefix Contra) . head)+    . filter ((== variantPrefix 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-+  if False+    then let -- See <https://bwbush.atlassian.net/browse/HQUIL-9>.+           n = order x+           f (v : i) (v' : i') = (v, - read i :: Int) `compare` (v', - read i')+           f _ _ = undefined+           ns = names x+           ns' = sortBy f ns+           Just permutation = (mapM . flip elemIndex) ns ns'+           permute y = map (y !!) permutation+           x' =+             renameExplicit (zip (show <$> ([1..] :: [Int])) ns')+               . listTensor (prefixDimension <$> ns')+               . fmap snd+               . sortBy (compare `on` fst)+               . fmap (first permute)+               . zip (replicateM n [(minBound::QState)..maxBound])+               . V.toList+              $ coords x+         in+           foldl (flip $ ap setType prefixVariant) (contrav x') ns'+    else 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.@@ -231,7 +292,7 @@       -> Wavefunction           -- ^ The wavefunction for the qubit. qubit index (a0, a1) =   Wavefunction-    . renameExplicit [("1", indexPrefix Contra : show index)]+    . renameExplicit [("1", variantPrefix Contra : show index)]     $ listTensor [2] [a0, a1]  @@ -345,8 +406,8 @@ 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+    lft  = filter ((== variantPrefix Co    ) . head) $ names x+    rght = filter ((== variantPrefix 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@@ -427,7 +488,7 @@         ]     z = p .* y   in-    Wavefunction $ z / sqrt (z * switch z)+    Wavefunction $ z / sqrt (mapArray (V.map conjugate) z * switch z)   -- | Measure qubits in a wavefunction.@@ -446,4 +507,4 @@ -- | The total probability for the wave function, which should be 1. wavefunctionProbability :: Wavefunction                         -> Amplitude-wavefunctionProbability (Wavefunction x) = asScalar $ x * switch x+wavefunctionProbability (Wavefunction x) = asScalar $ mapArray (V.map conjugate) x * switch x
src/Language/Quil/Execute.hs view
@@ -10,6 +10,33 @@ -- -- | Executing Quil programs. --+-- This example makes measurements on a prepared state.+--+-- > >>> import Language.Quil.Execute+-- > >>> import Language.Quil.Types+-- >+-- > -- Run a simple program and examine the quantum and classical states..+-- > >>> let program = [H 0, CNOT 0 1, RX (Expression . Number $ pi/4) 1]+-- > >>> runProgramWithStdRandom 2 [BoolBit False] program+-- > Quantum state:   0.6532814824381882|00> + -0.27059805007309845i|01> + -0.27059805007309845i|10> + 0.6532814824381882|11> @ [1,0]+-- > Classical state: 0x0 [1]+-- > Program counter: 3+-- > Halted?          False+-- >+-- > -- Add measurement to the program and re-run it.+-- > >>> let program' = program ++ [MEASURE 0 (Just 0)]+-- > >>> runProgramWithStdRandom 2 [BoolBit False] program'+-- > Quantum state:   0.9238795325112867|00> + -0.3826834323650897i|10> @ [1,0]+-- > Classical state: 0x0 [1]+-- > Program counter: 4+-- > Halted?          False+-- >+-- > -- Run the program again.+-- > >>> runProgramWithStdRandom 2 [BoolBit False] program'+-- > Quantum state:   -0.3826834323650897i|01> + 0.9238795325112867|11> @ [1,0]+-- > Classical state: 0x1 [1]+-- > Program counter: 4+-- > Halted?          False -----------------------------------------------------------------------------  @@ -29,10 +56,10 @@ ) where  -import Control.Monad (foldM)+import Control.Monad (foldM, join) import Control.Monad.Random.Lazy (Rand, RandomGen, evalRand, evalRandIO)-import Data.Bits (clearBit, complementBit, setBit, testBit)-import Data.BitVector (BV)+import Data.Bits (complementBit, setBit, testBit)+import Data.BitVector (BV, size) import Data.Complex (Complex((:+))) import Data.Function (on) import Data.Qubit (Operator, Wavefunction, (^*), groundState, measure, qubitsOperator, wavefunctionOrder)@@ -48,7 +75,7 @@ runProgramWithStdGen :: StdGen        -- ^ The random number generator.                      -> Int           -- ^ The number of qubits.                      -> [BitData]     -- ^ The classical bits.-                     -> [Instruction] -- ^ The instructions+                     -> [Instruction] -- ^ The instructions.                      -> Machine       -- ^ The resulting state of the machine. runProgramWithStdGen stdGen n cstate' instructions = runProgram n cstate' instructions `evalRand` stdGen @@ -56,7 +83,7 @@ -- | Run a program, starting from the ground state and using a particular random-number generator. runProgramWithStdRandom :: Int           -- ^ The number of qubits.                         -> [BitData]     -- ^ The classical bits.-                        -> [Instruction] -- ^ The instructions+                        -> [Instruction] -- ^ The instructions.                         -> IO Machine    -- ^ Action for the resulting state of the machine. runProgramWithStdRandom n cstate' instructions = evalRandIO $ runProgram n cstate' instructions @@ -65,14 +92,14 @@ runProgram :: RandomGen g            => Int            -- ^ The number of qubits.            -> [BitData]      -- ^ The classical bits.-           -> [Instruction]  -- ^ The instructions+           -> [Instruction]  -- ^ The instructions.            -> Rand g Machine -- ^ Action for the resulting state of the machine. runProgram n cstate' instructions = executeInstructions instructions $ Q.machine n cstate'   -- | Execute a series of instructions. executeInstructions :: RandomGen g-                    => [Instruction]  -- ^ The instructions+                    => [Instruction]  -- ^ The instructions.                     -> Machine        -- ^ The state of the machine.                     -> Rand g Machine -- ^ Action for the resulting state of the machine. executeInstructions = flip $ foldM (flip executeInstruction)@@ -204,7 +231,13 @@        => (BV -> BV)     -- ^ The transformation of the bits.        -> Machine        -- ^ THe machine.        -> Rand g Machine -- ^ Action for the resulting state of the machine.-onBits transition machine@Machine{..} = noop machine { cstate = transition cstate }+onBits transition machine@Machine{..} =+  let+    cstate' = transition cstate+  in+    if size cstate == size cstate'+      then noop machine { cstate = transition cstate }+      else error "Cannot enlarge tne number of classical bits."   -- | Set a bit.@@ -213,7 +246,7 @@         -> BV   -- ^ The initial bits.         -> BV   -- ^ The result. setBit' True  = flip setBit-setBit' False = flip clearBit+setBit' False = flip (join . (complementBit .) . setBit) -- See <https://bwbush.atlassian.net/browse/HQUIL-7>.   -- | Compile a gate.@@ -230,7 +263,7 @@ -- | Compile an expression. compileExpression :: Parameters -- ^ The formal parameters.                   -> Expression -- ^ The expression.-                  -> Arguments  -- ^ The argument.+                  -> Arguments  -- ^ The arguments.                   -> Number     -- ^ The result. compileExpression parameters (Power  x y) = \z -> ((**) `on` flip (compileExpression parameters) z) x y compileExpression parameters (Times  x y) = \z -> ((*)  `on` flip (compileExpression parameters) z) x y
src/Language/Quil/Types.hs view
@@ -43,6 +43,7 @@ , BitData(..) , toBitVector , boolFromBitVector+, finiteBitsFromBitVector , integerFromBitVector , doubleFromBitVector , complexFromBitVector@@ -50,12 +51,15 @@   import Data.Binary.IEEE754 (doubleToWord, wordToDouble)-import Data.BitVector (BV, bitVec, extract, showHex, testBit)+import Data.BitVector (BV, bitVec, extract, showHex, size, testBit)+import Data.Bits (FiniteBits(finiteBitSize)) import Data.Complex (Complex((:+)), imagPart, realPart) import Data.Default (Default(def))+import Data.Int (Int8, Int16, Int32, Int64) import Data.Monoid ((<>)) import Data.Qubit (Operator, Wavefunction, groundState) import Data.Vector (Vector)+import Data.Word (Word8, Word16, Word32, Word64)   -- | A quantum abstract machine.@@ -63,7 +67,7 @@   Machine   {     qstate       :: Wavefunction -- ^ The qubits.-  , cstate       :: BV           -- ^ The classical bits+  , cstate       :: BV           -- ^ The classical bits.   , definitions  :: Definitions  -- ^ Definitions of gates and circuits.   , counter      :: Int          -- ^ The program counter.   , halted       :: Bool         -- ^ Whether the machine has halted.@@ -74,7 +78,7 @@     unlines       [         "Quantum state:   " ++ show    qstate-      , "Classical state: " ++ showHex cstate+      , "Classical state: " ++ showHex cstate ++ " [" ++ show (size cstate) ++ "]"       , "Program counter: " ++ show    counter       , "Halted?          " ++ show    halted       ]@@ -101,6 +105,14 @@ -- | Data types for encoding as bit vectors. data BitData =     BoolBit Bool+  | IntBits8 Int8+  | IntBits16 Int16+  | IntBits32 Int32+  | IntBits64 Int64+  | WordBits8 Word8+  | WordBits16 Word16+  | WordBits32 Word32+  | WordBits64 Word64   | IntegerBits Int Integer   | DoubleBits Double   | ComplexBits Number@@ -109,10 +121,18 @@  -- | Encode data as a bit vector. toBitVector :: BitData -> BV-toBitVector (BoolBit       x) = bitVec 1 $ fromEnum x-toBitVector (IntegerBits n x) = bitVec n x+toBitVector (BoolBit       x) = bitVec  1 $ fromEnum x+toBitVector (IntBits8      x) = bitVec  8 $ toInteger x+toBitVector (IntBits16     x) = bitVec 16 $ toInteger x+toBitVector (IntBits32     x) = bitVec 32 $ toInteger x+toBitVector (IntBits64     x) = bitVec 64 $ toInteger x+toBitVector (WordBits8     x) = bitVec  8 $ toInteger x+toBitVector (WordBits16    x) = bitVec 16 $ toInteger x+toBitVector (WordBits32    x) = bitVec 32 $ toInteger x+toBitVector (WordBits64    x) = bitVec 64 $ toInteger x+toBitVector (IntegerBits n x) = bitVec  n   x toBitVector (DoubleBits    x) = bitVec 64 $ doubleToWord x-toBitVector (ComplexBits   x) = bitVec 64 (doubleToWord $ realPart x) <> bitVec 64 (doubleToWord $ imagPart x)+toBitVector (ComplexBits   x) = bitVec 64   (doubleToWord $ realPart x) <> bitVec 64 (doubleToWord $ imagPart x)   -- | Extract a boolean from a bit vector.@@ -122,11 +142,22 @@ boolFromBitVector = flip testBit  +-- | Extract a finite bits from a bit vector.+finiteBitsFromBitVector :: (Integral a, FiniteBits a)+                        => Int  -- ^ Which bit to start from, counting from zero.+                        -> BV   -- ^ The bit vector.+                        -> a    -- ^ The finite bits.+finiteBitsFromBitVector k v =+  let+    y = fromIntegral . toInteger $ extract (k + finiteBitSize y - 1) k v+  in+    y+ -- | Extract an integer from a bit vector. integerFromBitVector :: Int -- ^ Which bit to start from, counting from zero.-                     -> Int -- ^ How many bits to encode.-                     -> BV  -- ^ The bit vector-                     -> Integer -- ^ The integer.+                     -> Int     -- ^ How many bits to encode.+                     -> BV      -- ^ The bit vector+                     -> Integer -- ^ The integer (unsigned). integerFromBitVector k n = toInteger . extract (k + n - 1) k  @@ -134,14 +165,14 @@ doubleFromBitVector :: Int    -- ^ Which bit to start from, counting from zero.                     -> BV     -- ^ THe bit vector.                     -> Double -- ^ The double.-doubleFromBitVector k = wordToDouble . toEnum . fromEnum . extract (k + 63) k+doubleFromBitVector k = wordToDouble . fromIntegral . extract (k + 63) k   -- | Extract a complex number from a bit vector. complexFromBitVector :: Int -- ^ Which bit to start from, counting from zero.                      -> BV  -- ^ THe bit vector.                      -> Number -- ^ The complex number.-complexFromBitVector k x = doubleFromBitVector k x :+ doubleFromBitVector (k + 64) x+complexFromBitVector k x = doubleFromBitVector (k + 64) x :+ doubleFromBitVector k x   -- | Definitions of gates and circuits.
src/Test.hs view
@@ -14,6 +14,7 @@ -----------------------------------------------------------------------------  +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-}  {-# OPTIONS_GHC -fno-warn-missing-signatures #-}@@ -25,20 +26,38 @@   import Control.Monad (replicateM)+import Control.Monad.Random.Lazy (evalRandIO)+import Data.BitVector (BV)+import Data.Bits (bit, complementBit, setBit, testBit, xor) 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 Language.Quil.Execute (compileExpression, executeInstruction, runProgramWithStdRandom)+import Language.Quil.Types (Address, BitData(..), Expression(..), Instruction(..), Machine(..), Parameter(..), boolFromBitVector, complexFromBitVector, doubleFromBitVector, finiteBitsFromBitVector, integerFromBitVector, machine, toBitVector) import Numeric.LinearAlgebra.Array ((.*))-import Numeric.LinearAlgebra.Array.Util (coords, scalar)+import Numeric.LinearAlgebra.Array.Util (asScalar, coords, scalar)+import Numeric.LinearAlgebra.Tensor (switch) import Test.QuickCheck.All (quickCheckAll)+import Test.QuickCheck.Monadic (assert, monadicIO, run)+import Test.QuickCheck.Property (Property) import System.Exit (exitFailure, exitSuccess)  import qualified Data.Qubit.Gate as G+import qualified Data.Vector as V (empty, fromList) import qualified Data.Vector.Storable as V (toList)   -- Helper functions. +p = Expression . Number++clearBit x k = -- See <https://bwbush.atlassian.net/browse/HQUIL-7>.+  if testBit x k+    then x `xor` bit k+    else x++few = (+ 1) . (`mod` 10)+ i = scalar $ 0 :+ 1  cos' = scalar . (:+ 0) . cos@@ -54,6 +73,11 @@  (~~~) = (and .) . zipWith (\x y -> magnitude (x - y) <= epsilon) +(~=~) x y =+  let+    z = rawWavefunction x - rawWavefunction y+  in+    magnitude (asScalar  $ z * switch z) < epsilon  -- Wavefunction tests. @@ -324,6 +348,277 @@     && g b101 ~~ b110     && g b110 ~~ b101     && g b111 ~~ b111++-- Bit data.++prop_bitdata_bool x =+  x == boolFromBitVector 0 (toBitVector $ BoolBit x)++prop_bitdata_int8 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ IntBits8 x)++prop_bitdata_int16 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ IntBits16 x)++prop_bitdata_int32 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ IntBits32 x)++prop_bitdata_int64 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ IntBits64 x)++prop_bitdata_word8 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ WordBits8 x)++prop_bitdata_word16 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ WordBits16 x)++prop_bitdata_word32 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ WordBits32 x)++prop_bitdata_word64 x =+  x == finiteBitsFromBitVector 0 (toBitVector $ WordBits64 x)++prop_bitdata_integer x =+  x < 0 || x == integerFromBitVector 0 n (toBitVector $ IntegerBits n x)+    where+      n = if x == 0 then 1 else fromIntegral (ilog2 x + 1)++prop_bitdata_double x =+  x == doubleFromBitVector 0 (toBitVector $ DoubleBits x)++prop_bitdata_complex x =+  x == complexFromBitVector 0 (toBitVector $ ComplexBits x)+++-- Expressions.++prop_expression_power x y =+  x ** y == compileExpression V.empty (Power (Number x) (Number y)) V.empty++prop_expression_times x y =+  x * y == compileExpression V.empty (Times (Number x) (Number y)) V.empty++prop_expression_divide x y =+  y == 0 || x / y == compileExpression V.empty (Divide (Number x) (Number y)) V.empty++prop_expression_plus x y =+  x + y == compileExpression V.empty (Plus (Number x) (Number y)) V.empty++prop_expression_minus x y =+  x - y == compileExpression V.empty (Minus (Number x) (Number y)) V.empty++prop_expression_negate x =+  - x == compileExpression V.empty (Negate $ Number x) V.empty++prop_expression_sin x =+  sin x == compileExpression V.empty (Sin $ Number x) V.empty++prop_expression_cos x =+  cos x == compileExpression V.empty (Cos $ Number x) V.empty++prop_expression_sqrt x =+  sqrt x == compileExpression V.empty (Sqrt $ Number x) V.empty++prop_expression_exp x =+  exp x == compileExpression V.empty (Exp $ Number x) V.empty++prop_expression_cis x =+  cis x == compileExpression V.empty (Cis .Number $ x :+ 0) V.empty++prop_expression_number x =+  x == compileExpression V.empty (Number x) V.empty++prop_expression_variable x y z w =+  y == compileExpression (V.fromList [x, z]) (Variable x) (V.fromList [y, w])+++-- Classical bits.++classicalSingle :: (Address -> Instruction) -> (BV -> Int -> BV) -> Integer -> Int -> Property+classicalSingle g f x k =+  monadicIO+    $ do+      let+        n = if x <= 0 then 1 else fromIntegral (ilog2 x + 1)+        k' = k `mod` n+        m = machine 1 [IntegerBits n x]+      m' <- run . evalRandIO $ executeInstruction (g k') m+      assert $ x < 0 || f (cstate m) k' == cstate m'++classicalDouble :: (Address -> Address -> Instruction) -> (BV -> Int -> Int -> BV) -> Integer -> Int -> Int -> Property+classicalDouble g f x k l =+  monadicIO+    $ do+      let+        n = if x <= 0 then 1 else fromIntegral (ilog2 x + 1)+        k' = k `mod` n+        l' = l `mod` n+        m = machine 1 [IntegerBits n x]+      m' <- run . evalRandIO $ executeInstruction (g k' l') m+      assert $ x < 0 || f (cstate m) k' l' == cstate m'++prop_classical_false =+  classicalSingle FALSE clearBit++prop_classical_true =+  classicalSingle TRUE setBit++prop_classical_not =+  classicalSingle NOT complementBit++prop_classical_and =+  classicalDouble AND+    $ \bv k l -> +      if testBit bv k && testBit bv l+        then bv `setBit` l+        else bv `clearBit` l+++prop_classical_or =+  classicalDouble OR+    $ \bv k l -> +      if testBit bv k || testBit bv l+        then bv `setBit` l+        else bv `clearBit` l++prop_classical_move =+  classicalDouble MOVE+    $ \bv k l -> +      if testBit bv k+        then bv `setBit` l+        else bv `clearBit` l++prop_classical_exchange =+  classicalDouble EXCHANGE+    $ \bv k l -> +      case (testBit bv k, testBit bv l) of+        (False, True ) -> bv `setBit`   k `clearBit` l+        (True , False) -> bv `clearBit` k `setBit`   l+        _              -> bv+++-- Quantum bits.++prop_quantum_reset n =+  monadicIO+    $ do+      let n' = few n+      Machine{..} <- run $ runProgramWithStdRandom n' [] [RESET]+      assert $ qstate == groundState n'++prop_quantum_one =+  monadicIO+    $ do+      Machine{..} <-+        run+          $ runProgramWithStdRandom 1 [IntBits8 0]+          [+            RX (p $ pi/2) 0+          , T 0+          , H 0+          , S 0+          , RY (p 0.2) 0+          , I 0+          , PHASE (p 0.3) 0+          ]+      assert $ qstate ~=~ qubits [+                                    0.8845856219   :+ (-0.3664073617)+                                 , (-0.2872987275) :+   0.0267088763+                                 ]++prop_quantum_two =+  monadicIO+    $ do+      Machine{..} <-+        run+          $ runProgramWithStdRandom 2 [IntBits8 0]+          [+            RX (p $ pi/2) 0+          , T 1+          , H 0+          , S 0+          , RY (p 0.2) 1+          , I 0+          , PHASE (p 0.3) 0+          ]+      assert $ qstate ~=~ qubits [+                                     0.4975020826  :+ (-0.4975020826)+                                 , (-0.6223038112) :+   0.3282599747+                                 ,   0.0499167083  :+ (-0.0499167083)+                                 , (-0.0624386488) :+   0.0329358569+                                 ]++prop_quantum_three =+  monadicIO+    $ do+      Machine{..} <-+        run+          $ runProgramWithStdRandom 3 [IntBits8 0]+          [+            RX (p 0.1) 0+          , RY (p 0.2) 1+          , H 0+          , RZ (p 0.3) 2+          , PSWAP (p 0.4) 2 1+          , CSWAP 1 0 2+          , H 1+          ]+      assert $ qstate ~=~ qubits [+                                   0.4875851636 :+ (-0.0988384058)+                                 , 0.4950166445 :+ (-0.0496673327)+                                 , 0.4875851636 :+ (-0.0988384058)+                                 , 0.4950166445 :+ (-0.0496673327)+                                 , 0.0489216975 :+   0.009916919+                                 , 0.0476872529 :+   0.014751396+                                 , 0.0489216975 :+   0.009916919+                                 , 0.0476872529 :+   0.014751396+                                 ]++prop_quantum_four =+  monadicIO+    $ do+      Machine{..} <-+        run+          $ runProgramWithStdRandom 4 [IntBits8 0]+          [+            CPHASE00 (p 0.1) 0 1+          , H 3+          , CPHASE01 (p 0.2) 2 3+          , CCNOT 3 0 1+          , CPHASE10 (p 0.3) 2 1+          , ISWAP 3 2+          , PHASE (p 0.5) 3+          , CPHASE (p 0.4) 3 0+          , Z 3+          , CZ 1 3+          ]+      assert $ qstate ~=~ qubits [+                                     0.7035741926  :+ 0.0705928859 -- |0000>+                                 ,   0+                                 ,   0+                                 ,   0+                                 , (-0.2089643421) :+ 0.6755249098 -- |0100>+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ,   0+                                 ]++prop_quantum_measure =+  monadicIO+    $ do+      Machine{..} <-+        run+          $ runProgramWithStdRandom 2 [IntBits8 0] [H 0, CNOT 0 1, MEASURE 1 (Just 2)]+      assert $  cstate == toBitVector (IntBits8 0) && qstate ~=~ qubits [1, 0, 0, 0]+             || cstate == toBitVector (IntBits8 4) && qstate ~=~ qubits [0, 0, 0, 1]   -- Run tests.