Skip to content
Merged
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
48 changes: 48 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
version: 2

updates:
# Rust (Cargo) - security updates only
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
rust-security:
applies-to: security-updates
patterns: ["*"]
# Only open PRs for security advisories
allow:
- dependency-type: "all"
# Ignore all version updates (non-security)
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch", "version-update:semver-minor", "version-update:semver-major"]

# Python (pip) - security updates only
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
python-security:
applies-to: security-updates
patterns: ["*"]
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch", "version-update:semver-minor", "version-update:semver-major"]

# GitHub Actions - security updates only
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
actions-security:
applies-to: security-updates
patterns: ["*"]
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch", "version-update:semver-minor", "version-update:semver-major"]
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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,7 +771,8 @@ 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 set_seed(self, seed: int) -> None: ...
def reset(self) -> SparseSim: ...
@property
def num_qubits(self) -> int: ...
Expand All @@ -788,7 +789,8 @@ 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 set_seed(self, seed: int) -> None: ...
def reset(self) -> Stab: ...
@property
def num_qubits(self) -> int: ...
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,12 +24,20 @@ 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),
},
}
}

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

fn reset(mut slf: PyRefMut<'_, Self>) -> PyRefMut<'_, Self> {
slf.inner.reset();
slf
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,12 +24,20 @@ 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),
},
}
}

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

fn reset(mut slf: PyRefMut<'_, Self>) -> PyRefMut<'_, Self> {
slf.inner.reset();
slf
Expand Down
52 changes: 52 additions & 0 deletions python/pecos-rslib/tests/test_simulator_seeding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 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 simulator seeding via the pecos_rslib bindings."""

import pytest
from pecos_rslib.simulators import SparseSim, Stab


def _measure_sequence(sim_cls: type, *, seed: int, rounds: int = 16) -> list:
"""Create a seeded simulator, apply H then MZ repeatedly, return outcomes."""
sim = sim_cls(1, seed=seed)
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])
class TestSimulatorSeeding:
"""Verify that seeded stabilizer simulators produce reproducible results."""

def test_constructor_seed_is_reproducible(self, sim_cls: type) -> None:
"""Same seed in constructor gives same measurement sequence."""
assert _measure_sequence(sim_cls, seed=42) == _measure_sequence(sim_cls, seed=42)

def test_different_seeds_differ(self, sim_cls: type) -> None:
"""Different seeds give different measurement sequences."""
assert _measure_sequence(sim_cls, seed=42) != _measure_sequence(sim_cls, seed=99)

def test_set_seed_is_reproducible(self, sim_cls: type) -> None:
"""Calling set_seed after construction gives reproducible results."""
sim_a = sim_cls(1)
sim_a.set_seed(42)
outcomes_a = [sim_a.run_1q_gate("H", 0) for _ in range(8)]

sim_b = sim_cls(1)
sim_b.set_seed(42)
outcomes_b = [sim_b.run_1q_gate("H", 0) for _ in range(8)]

assert outcomes_a == outcomes_b
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 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: type,
*,
seed: int | None = None,
reseed: int | None = None,
rounds: int = 16,
) -> list:
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: type) -> None:
"""Verify that seeded stabilizer simulators produce reproducible results."""
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)
36 changes: 18 additions & 18 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading