This issue is part of unitaryHACK26. You have to be registered to complete this issue.
Learn more about the PR submission process here and about unitaryHACK rules here!
A note about AI Slop: while we are open to collaboration with LLMs for unitaryHACK, fully AI-generated PRs are not acceptable. It is at the maintainers' discretion whether or not LLM-generated PRs are the right fit for the issues, and those that appear fully AI-generated may be immediately rejected. Read unitaryHACK's full AI Policy here.
Note from the maintainer: If you have not contributed before to open source projects, no AI agent use is permitted for this issue.
QuantumClifford already has useful building blocks for noisy simulations:
NoiseOp, NoiseOpAll, NoisyGate, PauliNoise,
UnbiasedUncorrelatedNoise, mctrajectories, and pftrajectories. However,
users currently have to manually insert noise operations into circuit vectors or
write one-off helper functions. A small dispatch-based noisify API would make
it much easier to define a noise model once and apply it consistently to a
noiseless circuit.
Relevant links:
Desired user-facing behavior
A simple noise model should be easy to apply to a vector of operations:
using QuantumClifford
circuit = [sHadamard(1), sCNOT(1, 2), sMZ(1, 1)]
noisy = noisify(circuit, PauliNoise(1e-3, 1e-3, 1e-3))
The core behavior can start from this multiple-dispatch pattern:
noisify(circuit::AbstractVector, noise) = reduce(vcat, noisify.(circuit, (noise,)))
noisify(anything, noise) = [anything]
noisify(g::AbstractSingleQubitOperator, noise) = [NoiseOp(noise, affectedqubits(g)), g]
noisify(g::AbstractTwoQubitOperator, noise) = [NoiseOp(noise, affectedqubits(g)), g]
For practical use, there should also be a structured configuration object for
different noise locations:
noise = CircuitNoise(
single_qubit = PauliNoise(1e-4, 1e-4, 1e-4),
two_qubit = PauliNoise(1e-3, 1e-3, 1e-3),
idle = PauliNoise(1e-5, 1e-5, 1e-5),
measurement = PauliNoise(2e-3, 2e-3, 2e-3),
)
noisy = noisify(circuit, noise; nqubits=2)
frames = pftrajectories(noisy; trajectories=10_000)
The exact names can change, but the API should preserve the ability to extend
behavior with method definitions for new operation types and new noise-model
types.
Suggested implementation
Implement a small CircuitNoise or NoiseModel type with fields for common
locations:
- single-qubit gate noise
- two-qubit gate noise
- idle/waiting noise
- measurement noise
- reset noise, if separate from measurement noise
Also consider a NoNoise sentinel for omitted locations. This avoids requiring
users to pass nothing and makes dispatch cleaner.
Useful behavior to define:
noisify(circuit::AbstractVector, noise_model; nqubits=nothing) returns a new
vector and does not mutate the input.
- Single-qubit and two-qubit Clifford gates get the configured gate noise on
their affected qubits.
- Measurements get the configured measurement noise. It is acceptable for the
first version to model this as pre-measurement Pauli noise on the measured
qubits, as long as the semantics are documented.
NoiseOp and NoisyGate should not accidentally get double-noisified unless
explicitly requested.
- Classical-only operations such as
ClassicalXOR should pass through unchanged.
- Idle noise can be added to
setdiff(1:nqubits, affectedqubits(op)) for each
operation when nqubits is provided. If idle noise is requested and the number
of qubits cannot be inferred, throw a helpful error.
In scope
- A documented
noisify API.
- A structured noise configuration type.
- Dispatch methods for single-qubit gates, two-qubit gates, measurements, reset
measurements, existing noise operations, and classical operations.
- Tests that verify the inserted operation order and affected qubits.
- Tests showing the resulting noisy circuit can be simulated with
pftrajectories or mctrajectories.
- Documentation with a minimal example and a configuration example.
Out of scope
- Automatic circuit scheduling or momentization.
- Importing hardware calibration files.
- General non-Pauli quantum channels.
- Rewriting the existing trajectory simulators.
Acceptance criteria
noisify([sHadamard(1), sCNOT(1, 2)], noise) returns a circuit containing
NoiseOp entries on the expected qubits.
- A structured model can assign different noise to one-qubit gates, two-qubit
gates, idle qubits, and measurements.
- The original circuit is not mutated.
- Existing explicit
NoiseOp operations are handled in a documented way.
- Tests cover the simple dispatch example and the structured configuration case.
- The docs explain where the noise is inserted relative to each operation.
This issue is part of unitaryHACK26. You have to be registered to complete this issue.
Learn more about the PR submission process here and about unitaryHACK rules here!
A note about AI Slop: while we are open to collaboration with LLMs for unitaryHACK, fully AI-generated PRs are not acceptable. It is at the maintainers' discretion whether or not LLM-generated PRs are the right fit for the issues, and those that appear fully AI-generated may be immediately rejected. Read unitaryHACK's full AI Policy here.
Note from the maintainer: If you have not contributed before to open source projects, no AI agent use is permitted for this issue.
QuantumClifford already has useful building blocks for noisy simulations:
NoiseOp,NoiseOpAll,NoisyGate,PauliNoise,UnbiasedUncorrelatedNoise,mctrajectories, andpftrajectories. However,users currently have to manually insert noise operations into circuit vectors or
write one-off helper functions. A small dispatch-based
noisifyAPI would makeit much easier to define a noise model once and apply it consistently to a
noiseless circuit.
Relevant links:
Desired user-facing behavior
A simple noise model should be easy to apply to a vector of operations:
The core behavior can start from this multiple-dispatch pattern:
For practical use, there should also be a structured configuration object for
different noise locations:
The exact names can change, but the API should preserve the ability to extend
behavior with method definitions for new operation types and new noise-model
types.
Suggested implementation
Implement a small
CircuitNoiseorNoiseModeltype with fields for commonlocations:
Also consider a
NoNoisesentinel for omitted locations. This avoids requiringusers to pass
nothingand makes dispatch cleaner.Useful behavior to define:
noisify(circuit::AbstractVector, noise_model; nqubits=nothing)returns a newvector and does not mutate the input.
their affected qubits.
first version to model this as pre-measurement Pauli noise on the measured
qubits, as long as the semantics are documented.
NoiseOpandNoisyGateshould not accidentally get double-noisified unlessexplicitly requested.
ClassicalXORshould pass through unchanged.setdiff(1:nqubits, affectedqubits(op))for eachoperation when
nqubitsis provided. If idle noise is requested and the numberof qubits cannot be inferred, throw a helpful error.
In scope
noisifyAPI.measurements, existing noise operations, and classical operations.
pftrajectoriesormctrajectories.Out of scope
Acceptance criteria
noisify([sHadamard(1), sCNOT(1, 2)], noise)returns a circuit containingNoiseOpentries on the expected qubits.gates, idle qubits, and measurements.
NoiseOpoperations are handled in a documented way.