packages feed

hqcsim (empty) → 0.1.0.0

raw patch · 9 files changed

+511/−0 lines, 9 filesdep +basedep +hmatrixdep +hqcsim

Dependencies added: base, hmatrix, hqcsim, random

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for hqcsim++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,28 @@+BSD 3-Clause License++Copyright (c) 2024, Sebastian Mihai Ardelean++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. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ README.md view
@@ -0,0 +1,18 @@+# hqcsim++## Getting started++To get started with the library, clone the repo and then install Haskell Stack.++Next, build the project:++```+$ cabal build++```+Documentation can be generated by running the next command:++```+$ cabal haddock++```
+ app/Main.hs view
@@ -0,0 +1,21 @@+module Main where++import Control.Monad (replicateM)+import QC+++main :: IO ()+main = do+  let machine = Machine (makeQuantumState 2) 0+  let qprog = QProgram [+        (QInstruction hGate [0])+        , (QInstruction hGate [1])+        ]+  machines <- replicateM 10 (runQProg qprog machine)+  --mapM_ print machines+  let measurementRegisters = map measurementRegister machines+  print measurementRegisters+ -- mapM_ (\a -> putStrLn $ show (measurementRegister a)) machines+  --putStrLn $ "Measured state: " ++ show (measurementRegister result)++
+ hqcsim.cabal view
@@ -0,0 +1,56 @@+cabal-version:      2.4+name:               hqcsim+version:            0.1.0.0++-- A short (one-line) description of the package.+synopsis: A library for simulating quantum circuits.++-- A longer description of the package.+description: A library used for simulating quantum circuits, based on the "A tutorial quantum interpreter in 150 lines of Lisp" from https://www.stylewarning.com/posts/quantum-interpreter/+homepage: https://github.com/sebastianardelean/hqcsim#readme+-- A URL where users can report bugs.+-- bug-reports:++-- The license under which the package is released.+license: BSD-3-Clause+license-file: LICENSE+author:             Sebastian Mihai Ardelean+maintainer:         ardeleanasm@gmail.com++-- A copyright notice.+copyright: 2024 Sebastian Mihai Ardelean+category: Algorithms+extra-source-files:    README.md+                     , CHANGELOG.md++library+  hs-source-dirs:      src+                       src/Quantum+                       +  exposed-modules:     QC+                     , Quantum.QDataTypes+                     , Quantum.QProgram+                     , Quantum.Gates+  build-depends:       base ^>= 4.17.2.1 +                     , hmatrix+                     , random+  default-language:    Haskell2010+                    +executable hqcsim-exe+    main-is:          Main.hs++    -- Modules included in this executable, other than Main.+    -- other-modules:++    -- LANGUAGE extensions used by modules in this package.+    -- other-extensions:+    build-depends:    base ^>=4.17.2.1+                    , hmatrix+                    , random+                    , hqcsim+    hs-source-dirs:   app+    default-language: Haskell2010++source-repository head+  type:     git+  location: https://github.com/sebastianardelean/hqcsim
+ src/QC.hs view
@@ -0,0 +1,20 @@+{-|+ -Module      : QC+ -Description : Quantum Computing+ -Copyright   : (c) Mihai Sebastian Ardelean, 2024+ -License     : BSD3+ -Maintainer  : ardeleanasm@gmail.com+ -Portability : POSIX+ + This module is used to import needed modules for Quantum Computing.+ + -}+module QC(+  module Quantum.QDataTypes+  , module Quantum.Gates+  , module Quantum.QProgram+         ) where++import Quantum.QDataTypes+import Quantum.Gates+import Quantum.QProgram
+ src/Quantum/Gates.hs view
@@ -0,0 +1,113 @@+{-|+ -Module      : Gates+ -Description : Basic Quantum Gates+ -Copyright   : (c) Mihai Sebastian Ardelean, 2024+ -License     : BSD3+ -Maintainer  : ardeleanasm@gmail.com+ -Portability : POSIX+ -}+module Quantum.Gates+  (+    iGate+  , swapGate+  , hGate+  , xGate+  , yGate+  , zGate+  , cNotGate+  , Gate+  )where+++import qualified Numeric.LinearAlgebra as LA++import Quantum.QDataTypes++{-|+ -  iGate function represent an Identity Matrix+ + >>>iGate+ (2><2)+ [ 1.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 1.0 :+ 0.0 ]+ -}+iGate :: Gate+iGate = LA.ident 2 :: Gate++{-|+ -  swapGate function represent a Swap Gate+ + >>>swapGate+ (4><4)+ [ 1.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 0.0 :+ 0.0, 1.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 1.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0, 1.0 :+ 0.0 ]+ -}+swapGate :: Gate+swapGate = (4LA.><4)+    [ 1, 0, 0, 0 +    , 0, 0, 1, 0 +    , 0, 1, 0, 0 +    , 0, 0, 0, 1]::Gate++{-|+ -  hGate function represent a Hadamard Gate+  +  >>>hGate+ (2><2)+ [ 0.7071067811865475 :+ 0.0,    0.7071067811865475 :+ 0.0+ , 0.7071067811865475 :+ 0.0, (-0.7071067811865475) :+ 0.0 ]+ -}+hGate :: Gate+hGate = (2LA.><2) [1/sqrt 2,1/sqrt 2,1/sqrt 2,(-1)/sqrt 2] :: Gate++{-|+ -  yGate function represent a Pauli Y-Gate+ + >>>yGate+(2><2)+ [ 0.0 :+ 0.0, 0.0 :+ (-1.0)+ , 0.0 :+ 1.0,    0.0 :+ 0.0 ]+ -}+yGate :: Gate+yGate = (2LA.><2) [0.0,0.0LA.:+(-1.0),0.0LA.:+1.0,0.0] :: Gate++{-|+ -  zGate function represent a Pauli Z-Gate+ + >>>zGate+ (2><2)+ [ 1.0 :+ 0.0,       0.0 :+ 0.0+ , 0.0 :+ 0.0, (-1.0) :+ (-0.0) ]+ -}+zGate :: Gate+zGate = (2LA.><2) [1,0,0,-1] :: Gate++{-|+ -  xGate function represent a Pauli X-Gate+ + >>>xGate+ (2><2)+ [ 0.0 :+ 0.0, 1.0 :+ 0.0+ , 1.0 :+ 0.0, 0.0 :+ 0.0 ]+ -}+xGate :: Gate+xGate = (2LA.><2) [0,1,1,0] :: Gate++{-|+ -  cNotGate function represent a Controlled-Not Gate+ + >>>cNotGate+ (4><4)+ [ 1.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 1.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0+ , 0.0 :+ 0.0, 0.0 :+ 0.0, 0.0 :+ 0.0, 1.0 :+ 0.0+ , 0.0 :+ 0.0, 0.0 :+ 0.0, 1.0 :+ 0.0, 0.0 :+ 0.0 ]+ -}+cNotGate :: Gate+cNotGate = (4LA.><4)+  [1,0,0,0,+   0,1,0,0,+   0,0,0,1+  ,0,0,1,0] :: Gate
+ src/Quantum/QDataTypes.hs view
@@ -0,0 +1,47 @@+{-|+ -Module      : QDataTypes+ -Description : Definitions of datatypes for quantum state and quantum gates.+ -Copyright   : (c) Mihai Sebastian Ardelean, 2024+ -License     : BSD3+ -Maintainer  : ardeleanasm@gmail.com+ -Portability : POSIX+ -}+module Quantum.QDataTypes+  (+    State+  , Gate+  ) where++import qualified Numeric.LinearAlgebra as LA++-- | +-- The `State` type is an alias for a vector of complex numbers.+--+-- In the context of quantum computing, a `State` represents a quantum state+-- as a column vector where each element is a complex number. The length of+-- the vector is typically \(2^n\) for a system of `n` qubits.+--+-- For example, a `State` could be:+-- +-- @+--  [1 :+ 0, 0 :+ 0, 0 :+ 0, 0 :+ 0]  -- Represents |0⟩+-- @+type State = LA.Vector (LA.Complex Double)++-- |+-- The `Gate` type is an alias for a matrix of complex numbers.+--+-- In quantum computing, a `Gate` is a unitary matrix that represents a quantum operation+-- applied to qubits. The matrix elements are complex numbers.+--+-- The `Gate` type is used to describe quantum gates in algorithms. For example:+--+-- @+-- -- Represents a 2x2 Hadamard Gate+-- hGate :: Gate+-- hGate = (2LA.><2)+--   [1/sqrt 2,1/sqrt 2,1/sqrt 2,(-1)/sqrt 2] :: Gate+--+-- @+type Gate = LA.Matrix (LA.Complex Double)+
+ src/Quantum/QProgram.hs view
@@ -0,0 +1,203 @@+{-|+ -Module      : QProgram+ -Description : Definitions of qprogram datatypes and of simulation function.+ -Copyright   : (c) Mihai Sebastian Ardelean, 2024+ -License     : BSD3+ -Maintainer  : ardeleanasm@gmail.com+ -Portability : POSIX+ -}+module Quantum.QProgram+  (+    runQProg+  , makeQuantumState+  , Machine(..)+  , QInstruction(..)+  , QProgram(..)+  ) where++import Quantum.QDataTypes+import Quantum.Gates++import Data.List (nub, foldl')++import System.Random (randomRIO)++import qualified Numeric.LinearAlgebra as LA ++import Control.Monad (replicateM)++{-|+A `Machine` is defined by the quantum state and the measurement register.++It has two fields:+* `qstate` of type `State`+* `measurementRegister` of type `Int`+-}+data Machine = Machine {+    qstate :: State            -- ^ Quantum state.+  , measurementRegister :: Int -- ^ Measurement register.+  } deriving (Eq, Show)+++{-|+A `QInstruction` is defined by the unitary transformation and by the+qubits' index on which the transformation is applied.++It has two fields:+* `gateMatrix` of type `Gate` is the unitary matrix that defines the quantum gate.+* `affectedQubits` of type `[Int]`+-}+data QInstruction = QInstruction {+    gateMatrix ::Gate       -- ^ Quantum gate matrix.+  , affectedQubits :: [Int] -- ^ List of qubits' index that are affected by the quantum gate.+    } deriving (Eq,Show)++{-|+A `QProgram` is defined by the list quantum instructions:+* `instructions` is of type `[QInstruction]`+-}+data QProgram = QProgram {+  instructions :: [QInstruction] -- ^ List of program instructions.+                   } deriving (Eq, Show)++{-|+ - makeQuantumState function initializes a quantum state of `n` qubits+-}+makeQuantumState :: Int -> State+makeQuantumState n = LA.fromList $ 1 : replicate (2 ^ n - 1) 0+++dimensionQubits :: Int -> Int+dimensionQubits size = floor $ logBase 2 (fromIntegral size)++apply :: Gate -> State -> State+apply = (LA.#>)++compose :: Gate -> Gate -> Gate+compose = (LA.<>)++kroneckerMul :: Gate -> Gate -> Gate+kroneckerMul a b = LA.kronecker a b++kroneckerExp :: Gate -> Int -> Gate+kroneckerExp gate n+  | n < 1 = (1LA.><1) [1]::Gate+  | n == 1 = gate+  | otherwise = kroneckerMul (kroneckerExp gate (n - 1)) gate+++lift :: Gate -> Int -> Int -> Gate+lift gate i n = liftResult+  where+    left = kroneckerExp iGate (n - i - (dimensionQubits $ LA.rows gate))+    right = kroneckerExp iGate i+    liftResult = kroneckerMul left $ kroneckerMul gate right++perm2trans :: [Int] -> [(Int, Int)]+perm2trans permutation = nub (concatMap processIndex [0..length permutation - 1])+  where+    -- Process each index to determine necessary swaps+    updateSrc :: Int -> Int -> [Int] -> Int+    updateSrc src dest lst+      |src >= dest = src+      |otherwise = updateSrc (lst !! src) dest lst+    processIndex dest+      | src < dest = [(src, dest)]+      | src > dest = [(dest,src)]+      | otherwise = []+      where+        originalSrc = permutation !! dest+        src = updateSrc originalSrc dest permutation++    +trans2adj :: [(Int, Int)] -> [Int]+trans2adj transpositions = concatMap expandConsecutive transpositions+  where +    expandConsecutive :: (Int, Int) -> [Int]+    expandConsecutive (x, y)+      | y - x == 1 = [x]+      | otherwise  = trans ++ reverse (init trans)+      where+        trans = [x..y-1]++apply1Q :: State -> Gate -> Int -> State+apply1Q s u qubit = q1State+  where+    liftedU = lift u qubit (dimensionQubits $ LA.size s)+    q1State = apply liftedU s++++applyNQ :: State -> Gate -> [Int] -> State+applyNQ s u qubits = qubitsNState+  where+    swap :: Int -> Int -> Gate+    swap i n = lift swapGate i n++    trans2op :: [Int] -> Int -> Gate+    trans2op [] n = LA.ident (2^n)+    trans2op (t:ts) n = foldl' compose (swap t n) (map (`swap` n) ts)++    n = dimensionQubits $ LA.size s+    u01 = lift u 0 n+    fromSpace = reverse qubits ++ [i | i <- [0..n-1], i `notElem` qubits]+    trans = perm2trans fromSpace+    adj = trans2adj trans+    toFrom = trans2op adj n+    fromTo = trans2op (reverse adj) n+    upq = compose toFrom (compose u01 fromTo)+    qubitsNState = apply upq s++applyGate :: State -> Gate -> [Int] -> State+applyGate s u qubits+  | qubitsLength == 1 = apply1Q s u (qubits !! 0)+  | otherwise         = applyNQ s u qubits+  where+    qubitsLength = length qubits+++++sample :: State -> IO Int+sample s = do+  r <- randomRIO (0.0, 1.0)+  return $ sampleIndex (LA.toList s) r 0.0+  where+    sampleIndex :: [LA.Complex Double] -> Double -> Double -> Int+    sampleIndex [] _ _ = error "Invalid state vector"+    sampleIndex (c:cs) r accProb =+      let prob = accProb + (LA.magnitude c) ** 2+      in if r < prob+         then 0+         else 1 + sampleIndex cs r prob++collapse :: State -> Int -> State+collapse st i = LA.fromList collapsedState+  where+    stateLength = LA.size st+    collapsedState = replicate i 0 ++ [1] ++ replicate (stateLength - i - 1) 0    ++observe :: Machine -> IO Machine+observe machine = do+  let state = qstate machine+  i <- sample state+  let newState = collapse state i+  return machine { qstate = newState, measurementRegister = i}+++evolveState :: QInstruction -> Machine ->Machine+evolveState (QInstruction gateMatrix affectedQubits) m = newMachine+  where+    newState = applyGate (qstate m) gateMatrix affectedQubits+    newMachine = Machine newState (measurementRegister m)++{-|+ - runQProg function executes the program's instruction.+-}+runQProg :: QProgram -> Machine -> IO Machine+runQProg qprog machine = runInstruction (instructions qprog) machine+  where+    runInstruction :: [QInstruction] -> Machine -> IO Machine+    runInstruction [] m = observe m+    runInstruction (x:xs) m = runInstruction xs (evolveState x m)+