packages feed

stim-parser 0.3.0.0 → 0.4.0.0

raw patch · 7 files changed

+121/−41 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ StimParser.Expr: AnnPauli :: Pauli -> Ind -> AnnTarget
+ StimParser.Expr: AnnQ :: Ind -> AnnTarget
+ StimParser.Expr: AnnRec :: Rec -> AnnTarget
+ StimParser.Expr: data AnnTarget
+ StimParser.Expr: instance GHC.Classes.Eq StimParser.Expr.AnnTarget
+ StimParser.Expr: instance GHC.Classes.Eq StimParser.Expr.Pauli
+ StimParser.Expr: instance GHC.Classes.Eq StimParser.Expr.Rec
+ StimParser.Expr: instance GHC.Classes.Ord StimParser.Expr.Pauli
+ StimParser.Expr: instance GHC.Classes.Ord StimParser.Expr.Rec
+ StimParser.Expr: instance GHC.Show.Show StimParser.Expr.AnnTarget
+ StimParser.Parse: parseAnnPauliTarget :: Parser AnnTarget
+ StimParser.Parse: parseAnnRecTarget :: Parser AnnTarget
+ StimParser.Parse: parseAnnTargetMixed :: Parser AnnTarget
+ StimParser.Parse: parseAnnTargetQ :: Parser AnnTarget
+ StimParser.Trans: instance StimParser.Trans.FlattenQ StimParser.Expr.AnnTarget
- StimParser.Expr: Ann :: AnnTy -> Maybe Tag -> [FInd] -> [Q] -> Ann
+ StimParser.Expr: Ann :: AnnTy -> Maybe Tag -> [FInd] -> [AnnTarget] -> Ann

Files

CHANGELOG.md view
@@ -1,5 +1,18 @@ # Revision history for stim-parser +## 0.4.0.0 -- 2026-07-20++* Add Pauli-target support for `OBSERVABLE_INCLUDE` and `DETECTOR`+  annotations.+  - New `AnnTarget` sum type: `AnnQ Ind | AnnRec Rec | AnnPauli Pauli Ind`.+  - `Ann` now stores `[AnnTarget]` instead of `[Q]`.+  - Single-qubit Pauli targets such as `X0`, `Y1`, `Z2` are accepted and+    preserved, matching Python Stim behavior.+  - Mixed `rec[-k]` and Pauli targets are supported.+  - The `*` combiner remains unsupported inside annotations.+* This is a **breaking API change**. Downstream code pattern-matching on+  `Ann` or constructing annotation values needs to use `AnnTarget`.+ ## 0.3.0.0 -- 2026-07-20  * Add optional tag support for DEM detector and observable declarations.
src/StimParser/Expr.hs view
@@ -4,7 +4,7 @@ type Ind = Int type Ph = Double newtype Rec = Rec Int-  deriving (Show)+  deriving (Show, Eq, Ord) newtype Sweep = Sweep Int   deriving (Show) @@ -17,7 +17,7 @@   deriving (Show)  data Pauli = PX | PY | PZ -  deriving (Show)+  deriving (Show, Eq, Ord) data PauliInd = PauliInd Pauli Ind   deriving (Show) @@ -161,11 +161,29 @@ annTyList :: [AnnTy] annTyList = [DETECTOR ..]  +-- Targets that can appear inside annotations.+--+-- * 'AnnQ' is a plain qubit index (used by QUBIT_COORDS and MPAD).+-- * 'AnnRec' is a measurement-record reference (used by DETECTOR and+--   OBSERVABLE_INCLUDE).+-- * 'AnnPauli' is a single-qubit Pauli operator (used by DETECTOR and+--   OBSERVABLE_INCLUDE to declare Pauli-product detectors/observables).+--+-- Space-separated Pauli targets are implicitly multiplied, matching Python+-- Stim behavior. The '*' combiner is not supported inside annotations.+data AnnTarget+  = AnnQ Ind+  | AnnRec Rec+  | AnnPauli Pauli Ind+  deriving (Show, Eq)+ -- Annotations examples: --    DETECTOR(1, 0) rec[-3] rec[-6] --    DETECTOR(2, 0, 0) rec[-8] --    DETECTOR rec[-3] rec[-4] rec[-7]+--    DETECTOR X0 Z1 --    OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]+--    OBSERVABLE_INCLUDE(0) X0 Z1 --    QUBIT_COORDS(0, 0) 0 --    MPAD 0 0 1 0 1 --    SHIFT_COORDS(500.5)@@ -193,7 +211,7 @@  newtype Coords = Coords [FInd] -data Ann = Ann AnnTy (Maybe Tag) [FInd] [Q]+data Ann = Ann AnnTy (Maybe Tag) [FInd] [AnnTarget]   deriving (Show)  -- repeat example:
src/StimParser/Parse.hs view
@@ -6,6 +6,7 @@ import StimParser.ParseUtils import Control.Monad import Data.List+import Data.Maybe import Text.Megaparsec hiding (State) import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L@@ -241,35 +242,60 @@   -- the order is tricky    try pm2 <|> pm1 +-- | Parse a measurement-record target inside an annotation.+-- Requires a negative index, matching the semantics of rec[] in gates.+parseAnnRecTarget :: Parser AnnTarget+parseAnnRecTarget = do+  lstring "rec"+  lstring "["+  i <- parseInt+  lstring "]"+  if i < 0+    then return $ AnnRec (Rec i)+    else fail "rec[] index in annotations must be negative (e.g., rec[-1])"++-- | Parse a single-qubit Pauli target inside an annotation.+-- The '*' combiner is intentionally not supported here.+parseAnnPauliTarget :: Parser AnnTarget+parseAnnPauliTarget = lexeme $ do+  PauliInd p i <- parsePauliInd+  return $ AnnPauli p i++-- | Parse a target that may appear inside DETECTOR or OBSERVABLE_INCLUDE:+-- either a measurement-record reference or a single-qubit Pauli target.+parseAnnTargetMixed :: Parser AnnTarget+parseAnnTargetMixed =+  try parseAnnRecTarget <|> parseAnnPauliTarget++-- | Parse a plain qubit-index target for annotations such as QUBIT_COORDS.+parseAnnTargetQ :: Parser AnnTarget+parseAnnTargetQ = AnnQ <$> parseInt+ parseAnn :: Parser Ann -parseAnn = do -  let -    -- parser for case: DETECTOR[tag](1, 0) rec[-3] rec[-6]-    pm1 = do -      ty <- parseAnnTy -      tag <- optional parseTag+parseAnn = do+  ty <- parseAnnTy+  tag <- optional parseTag+  case ty of+    TICK ->+      return $ Ann TICK tag [] []+    SHIFT_COORDS -> do       fds <- parseTuple parseFInd-      qs <- parseExhaust parseQ-      return $ Ann ty tag fds qs-    -- parser for case: DETECTOR[tag] rec[-3] rec[-4] rec[-7]-    pm2 = do -      ty <- parseAnnTy-      tag <- optional parseTag-      qs <- parseExhaust parseQ-      return $ Ann ty tag [] qs-    -- parser for case: SHIFT_COORDS[tag](500.5)-    pm3 = do -      ty <- parseAnnTy-      tag <- optional parseTag+      return $ Ann SHIFT_COORDS tag fds []+    QUBIT_COORDS -> do       fds <- parseTuple parseFInd-      return $ Ann ty tag fds []-    -- parser for case: TICK[tag]-    pm4 = do-      ty <- parseShowCI TICK-      tag <- optional parseTag-      return $ Ann ty tag [] []-  -- the order is tricky-  try pm1 <|> try pm2 <|> try pm3 <|> pm4 +      qs <- parseExhaust parseAnnTargetQ+      return $ Ann QUBIT_COORDS tag fds qs+    MPAD -> do+      qs <- parseExhaust parseAnnTargetQ+      return $ Ann MPAD tag [] qs+    DETECTOR -> do+      mfds <- optional (parseTuple parseFInd)+      ts <- parseExhaust parseAnnTargetMixed+      return $ Ann DETECTOR tag (fromMaybe [] mfds) ts+    OBSERVABLE_INCLUDE -> do+      fds <- parseTuple parseFInd+      ts <- parseExhaust parseAnnTargetMixed+      return $ Ann OBSERVABLE_INCLUDE tag fds ts  parseStart :: Parser () parseStart = void (lstring "!!!Start") 
src/StimParser/Trans.hs view
@@ -37,6 +37,17 @@     nqs <- mapM flattenQ qs      return $ Gate gt tag nqs  +-- Annotation targets behave similarly to 'Q': plain qubits and Pauli targets+-- are preserved, while measurement-record references are resolved to absolute+-- qubit indices using the current measurement count.+instance FlattenQ AnnTarget where+  type Out AnnTarget = AnnTarget+  flattenQ (AnnQ i) = return (AnnQ i)+  flattenQ (AnnRec (Rec r)) = do+    (count, _) <- get+    return $ AnnQ (count + r + 1)+  flattenQ (AnnPauli p i) = return (AnnPauli p i)+ -- for each measure, we increase the count by 1 -- currently, we assume measure does not contains (QRec Rec) instance FlattenQ Measure where@@ -74,15 +85,15 @@    -- TODO: type-level constraint that fs and cs should be of the same length   -- TODO: type-level constraint that count should not be used in this case-  flattenQ (Ann DETECTOR tag fs qs) = do+  flattenQ (Ann DETECTOR tag fs ts) = do     (count, Coords cs) <- get     let nfs = zipWith (+) fs cs-    nqs <- mapM flattenQ qs-    return $ Just $ Ann DETECTOR tag nfs nqs+    nts <- mapM flattenQ ts+    return $ Just $ Ann DETECTOR tag nfs nts     -  flattenQ (Ann aty tag fs qs) = do -    nqs <- mapM flattenQ qs -    return $ Just $ Ann aty tag fs nqs+  flattenQ (Ann aty tag fs ts) = do +    nts <- mapM flattenQ ts +    return $ Just $ Ann aty tag fs nts  instance FlattenQ Stim where   type Out Stim = Maybe Stim
stim-parser.cabal view
@@ -20,7 +20,7 @@ -- PVP summary:     +-+------- breaking API changes --                  | | +----- non-breaking API additions --                  | | | +--- code changes with no API change-version:            0.3.0.0+version:            0.4.0.0  -- A short (one-line) description of the package. synopsis:           A parser combinator library for STIM quantum circuit files
test/Test/Parse.hs view
@@ -260,17 +260,26 @@   [ assertShowEqual "parseAnn TICK"        (Ann TICK Nothing [] []) (run parseAnn "TICK")   , assertShowEqual "parseAnn DETECTOR with coords and rec" -      (Ann DETECTOR Nothing [In 1, In 0] [QRec (Rec (-3)), QRec (Rec (-6))]) +      (Ann DETECTOR Nothing [In 1, In 0] [AnnRec (Rec (-3)), AnnRec (Rec (-6))])        (run parseAnn "DETECTOR(1, 0) rec[-3] rec[-6]")   , assertShowEqual "parseAnn DETECTOR without coords" -      (Ann DETECTOR Nothing [] [QRec (Rec (-3)), QRec (Rec (-4))]) +      (Ann DETECTOR Nothing [] [AnnRec (Rec (-3)), AnnRec (Rec (-4))])        (run parseAnn "DETECTOR rec[-3] rec[-4]")   , assertShowEqual "parseAnn SHIFT_COORDS"        (Ann SHIFT_COORDS Nothing [Fl 500.5] [])        (run parseAnn "SHIFT_COORDS(500.5)")   , assertShowEqual "parseAnn OBSERVABLE_INCLUDE" -      (Ann OBSERVABLE_INCLUDE Nothing [In 0] [QRec (Rec (-1))]) +      (Ann OBSERVABLE_INCLUDE Nothing [In 0] [AnnRec (Rec (-1))])        (run parseAnn "OBSERVABLE_INCLUDE(0) rec[-1]")+  , assertShowEqual "parseAnn DETECTOR with Pauli targets" +      (Ann DETECTOR Nothing [] [AnnPauli PX 0, AnnPauli PZ 1]) +      (run parseAnn "DETECTOR X0 Z1")+  , assertShowEqual "parseAnn OBSERVABLE_INCLUDE with Pauli targets" +      (Ann OBSERVABLE_INCLUDE Nothing [In 0] [AnnPauli PX 0, AnnPauli PZ 1]) +      (run parseAnn "OBSERVABLE_INCLUDE(0) X0 Z1")+  , assertShowEqual "parseAnn OBSERVABLE_INCLUDE mixed targets" +      (Ann OBSERVABLE_INCLUDE Nothing [In 0] [AnnRec (Rec (-1)), AnnPauli PZ 0]) +      (run parseAnn "OBSERVABLE_INCLUDE(0) rec[-1] Z0")   ]  -- | Regression test for the noise-before-gate ordering bug.
test/Test/Trans.hs view
@@ -83,8 +83,11 @@   [ assertShowEqual "flattenQ Ann TICK"        (Just (Ann TICK Nothing [] [])) (evalState (flattenQ (Ann TICK Nothing [] [])) (0, Coords [In 0]))   , assertShowEqual "flattenQ Ann DETECTOR" -      (Just (Ann DETECTOR Nothing [In 1, In 0] [Q 10])) -      (evalState (flattenQ (Ann DETECTOR Nothing [In 1, In 0] [Q 10])) (10, Coords [In 0, In 0]))+      (Just (Ann DETECTOR Nothing [In 1, In 0] [AnnQ 10])) +      (evalState (flattenQ (Ann DETECTOR Nothing [In 1, In 0] [AnnQ 10])) (10, Coords [In 0, In 0]))+  , assertShowEqual "flattenQ Ann OBSERVABLE_INCLUDE resolves rec" +      (Just (Ann OBSERVABLE_INCLUDE Nothing [In 0] [AnnQ 10, AnnPauli PZ 0])) +      (evalState (flattenQ (Ann OBSERVABLE_INCLUDE Nothing [In 0] [AnnRec (Rec (-1)), AnnPauli PZ 0])) (10, Coords [In 0]))   ]   -- Note: SHIFT_COORDS test moved to separate test case