packages feed

symplectic-chp-0.1.0.0: app/CHPCircuit.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}

-- | Intermediate representation for CHP circuits translated from STIM.
-- This module defines a simple IR that bridges the gap between STIM AST
-- and the symplectic-chp simulator.
module CHPCircuit
  ( CHPCircuit(..)
  , CHPOperation(..)
  , emptyCircuit
  , addGate
  , addMeasure
  , circuitFromOps
  ) where

import Data.Bits (setBit, testBit)
import Data.Word (Word64)

import SymplecticCHP (Pauli(..), SymplecticGate(..), LocalSymplectic(..))

-- | A CHP circuit is a sequence of operations on qubits.
-- We track the number of qubits and the sequence of operations.
data CHPCircuit = CHPCircuit
  { numQubits :: Int
  , operations :: [CHPOperation]
  } deriving (Show)

-- | A single operation in a CHP circuit.
-- Either a Clifford gate or a Pauli measurement.
data CHPOperation
  = GateOp SymplecticGate
  | MeasureOp Pauli Int  -- ^ Pauli operator and measurement result index
  deriving (Show)

-- | Create an empty circuit for n qubits.
emptyCircuit :: Int -> CHPCircuit
emptyCircuit n = CHPCircuit n []

-- | Add a gate operation to a circuit.
addGate :: SymplecticGate -> CHPCircuit -> CHPCircuit
addGate g circ = circ { operations = operations circ ++ [GateOp g] }

-- | Add a measurement operation to a circuit.
addMeasure :: Pauli -> Int -> CHPCircuit -> CHPCircuit
addMeasure p idx circ = circ { operations = operations circ ++ [MeasureOp p idx] }

-- | Create a circuit from a list of operations.
-- Infers qubit count from operations.
circuitFromOps :: [CHPOperation] -> CHPCircuit
circuitFromOps ops = CHPCircuit n ops
  where
    n = maximum $ 0 : concatMap opQubits ops
    
    opQubits (GateOp g) = gateQubits g
    opQubits (MeasureOp p _) = pauliQubits p
    
    gateQubits (SymplecticCHP.Local (SymplecticCHP.Hadamard q)) = [q]
    gateQubits (SymplecticCHP.Local (SymplecticCHP.Phase q)) = [q]
    gateQubits (SymplecticCHP.CNOT c t) = [c, t]
    
    pauliQubits (Pauli x z _) = 
      filter (testBitWord x) [0..63] ++ filter (testBitWord z) [0..63]
    testBitWord w i = (fromIntegral w :: Integer) `div` (2^i) `mod` 2 == 1