Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions python/pecos-rslib/pecos_rslib.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,9 @@ class GateBindingsDict:
class SparseSim:
"""Sparse stabilizer simulator."""

def __init__(self, num_qubits: int) -> None: ...
def __init__(self, num_qubits: int, seed: int | None = None) -> None: ...
def reset(self) -> SparseSim: ...
def set_seed(self, seed: int) -> None: ...
@property
def num_qubits(self) -> int: ...
@property
Expand All @@ -788,8 +789,9 @@ class SparseSim:
class Stab:
"""Generic stabilizer simulator (recommended)."""

def __init__(self, num_qubits: int) -> None: ...
def __init__(self, num_qubits: int, seed: int | None = None) -> None: ...
def reset(self) -> Stab: ...
def set_seed(self, seed: int) -> None: ...
@property
def num_qubits(self) -> int: ...
def stab_tableau(self) -> str: ...
Expand Down
12 changes: 10 additions & 2 deletions python/pecos-rslib/src/sparse_stab_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ pub struct PySparseSim {
#[pymethods]
impl PySparseSim {
#[new]
fn new(num_qubits: usize) -> Self {
#[pyo3(signature = (num_qubits, seed=None))]
fn new(num_qubits: usize, seed: Option<u64>) -> Self {
PySparseSim {
inner: SparseStab::new(num_qubits),
inner: match seed {
Some(s) => SparseStab::with_seed(num_qubits, s),
None => SparseStab::new(num_qubits),
},
}
}

Expand All @@ -40,6 +44,10 @@ impl PySparseSim {
self.inner.num_qubits()
}

fn set_seed(&mut self, seed: u64) {
self.inner.set_seed(seed);
}

#[allow(clippy::too_many_lines)]
#[pyo3(signature = (symbol, location, params=None))]
fn run_1q_gate(
Expand Down
12 changes: 10 additions & 2 deletions python/pecos-rslib/src/stab_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ pub struct PyStab {
#[pymethods]
impl PyStab {
#[new]
fn new(num_qubits: usize) -> Self {
#[pyo3(signature = (num_qubits, seed=None))]
fn new(num_qubits: usize, seed: Option<u64>) -> Self {
PyStab {
inner: Stab::new(num_qubits),
inner: match seed {
Some(s) => Stab::with_seed(num_qubits, s),
None => Stab::new(num_qubits),
},
}
}

Expand All @@ -40,6 +44,10 @@ impl PyStab {
self.inner.num_qubits()
}

fn set_seed(&mut self, seed: u64) {
self.inner.set_seed(seed);
}

#[allow(clippy::too_many_lines)]
#[pyo3(signature = (symbol, location, params=None))]
fn run_1q_gate(
Expand Down
45 changes: 45 additions & 0 deletions python/pecos-rslib/tests/test_simulator_seeding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2026 The PECOS Developers
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.

"""Tests for exposing simulator seeding on stabilizer backends."""

import pytest

from pecos_rslib import SparseSim, Stab


def _measurement_sequence(sim_cls, *, seed=None, reseed=None, rounds=32):
sim = sim_cls(1, seed=seed) if seed is not None else sim_cls(1)
if reseed is not None:
sim.set_seed(reseed)

outcomes = []
for _ in range(rounds):
sim.reset()
sim.run_1q_gate("H", 0)
outcomes.append(sim.run_1q_gate("MZ", 0))
return outcomes


@pytest.mark.parametrize("sim_cls", [SparseSim, Stab])
def test_seeded_constructor_repeats_measurement_sequence(sim_cls) -> None:
assert _measurement_sequence(sim_cls, seed=42) == _measurement_sequence(sim_cls, seed=42)


@pytest.mark.parametrize("sim_cls", [SparseSim, Stab])
def test_set_seed_repeats_measurement_sequence(sim_cls) -> None:
assert _measurement_sequence(sim_cls, reseed=42) == _measurement_sequence(sim_cls, reseed=42)


@pytest.mark.parametrize("sim_cls", [SparseSim, Stab])
def test_different_seeds_change_measurement_sequence(sim_cls) -> None:
assert _measurement_sequence(sim_cls, seed=42) != _measurement_sequence(sim_cls, seed=43)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2026 The PECOS Developers
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.

"""High-level tests for seeded stabilizer simulator re-exports."""

import pytest

from pecos.simulators import SparseSim, Stab


def _measurement_sequence(sim_cls, *, seed=None, reseed=None, rounds=16):
sim = sim_cls(1, seed=seed) if seed is not None else sim_cls(1)
if reseed is not None:
sim.set_seed(reseed)

outcomes = []
for _ in range(rounds):
sim.reset()
sim.run_1q_gate("H", 0)
outcomes.append(sim.run_1q_gate("MZ", 0))
return outcomes


@pytest.mark.parametrize("sim_cls", [SparseSim, Stab])
def test_high_level_simulators_accept_seed_and_set_seed(sim_cls) -> None:
assert _measurement_sequence(sim_cls, seed=42) == _measurement_sequence(sim_cls, seed=42)
assert _measurement_sequence(sim_cls, reseed=42) == _measurement_sequence(sim_cls, reseed=42)
Loading