Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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
4 changes: 4 additions & 0 deletions cirq-core/cirq/devices/noise_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ def __init__(self, noise_properties: NoiseProperties) -> None:
self._noise_properties = noise_properties
self.noise_models = self._noise_properties.build_noise_models()

@property
def noise_properties(self):
return self._noise_properties

def _value_equality_values_(self):
return self._noise_properties

Expand Down
31 changes: 30 additions & 1 deletion cirq-core/cirq/sim/simulator_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,42 @@ def _core_iterator(
StepResults from simulating a Moment of the Circuit.

Raises:
TypeError: The simulator encounters an op it does not support.
TypeError: The simulator encounters an op it or its noise model
does not support.
"""

if len(circuit) == 0:
yield self._create_step_result(sim_state)
return

# For any noise model derived from noise properties, check the circuit to ensure it
# is compatible with the noise properties.
if isinstance(self._noise, devices.NoiseModelFromNoiseProperties):
noise_props = self._noise.noise_properties
# So far, only SuperconductingQubitsNoiseProperties implements such constraints on
# the circuit.
if isinstance(noise_props, devices.SuperconductingQubitsNoiseProperties):
circuit_gates = {op.gate for op in circuit.all_operations()}
if not all(
any(
isinstance(gate, expected_gate)
for expected_gate in noise_props.expected_gates()
)
for gate in circuit_gates
):
raise TypeError(
f"Circuit uses "
f"{circuit_gates.difference(noise_props.expected_gates())} "
f"which is not supported by noise properties "
f'"{noise_props.__class__.__name__}"'
)
if not circuit.all_qubits().issubset(noise_props.qubits):
raise TypeError(
f"Circuit uses "
f"{circuit.all_qubits().difference(noise_props.qubits)} "
f"which is not supported by noise properties "
f'"{noise_props.__class__.__name__}"'
)
noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits()))
measured: dict[tuple[cirq.Qid, ...], bool] = collections.defaultdict(bool)
for moment in noisy_moments:
Expand Down
49 changes: 49 additions & 0 deletions cirq-core/cirq/sim/simulator_base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import sympy

import cirq
from cirq import devices, ops
from cirq.devices import noise_utils


class CountingState(cirq.qis.QuantumStateRepresentation):
Expand Down Expand Up @@ -454,3 +456,50 @@ def test_inhomogeneous_measurement_count_padding() -> None:
results = sim.run(c, repetitions=10)
for i in range(10):
assert np.sum(results.records['m'][i, :, :]) == 1


def test_simulates_noise_only_on_valid_gates_and_qubits() -> None:
expected_single_qubit_gates = [cirq.XPowGate, cirq.ZPowGate]
expected_qubits = [cirq.GridQubit(1, 2)]

unexpected_qubits = [cirq.GridQubit(2, 2)]

class TestNoiseProperties(devices.SuperconductingQubitsNoiseProperties):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the TestNoiseProperties created for this test might not make sense from a QC point of view just because of my limited domain knowledge - feel free to re-implement to something more sensible if this is a concern!

@classmethod
def single_qubit_gates(cls) -> set[type[ops.Gate]]:
return set(expected_single_qubit_gates)

@classmethod
def symmetric_two_qubit_gates(cls) -> set[type[ops.Gate]]:
return set()

@classmethod
def asymmetric_two_qubit_gates(cls) -> set[type[ops.Gate]]:
return set()

noise_props = TestNoiseProperties(
gate_times_ns=dict.fromkeys(expected_single_qubit_gates, 1e9),
t1_ns=dict.fromkeys(expected_qubits, 1e9),
tphi_ns=dict.fromkeys(expected_qubits, 1e9),
readout_errors=dict.fromkeys(expected_qubits, [0.5, 0.5]),
gate_pauli_errors={
noise_utils.OpIdentifier(gate, expected_qubits[0]): 0
for gate in expected_single_qubit_gates
},
)
noise_model = devices.NoiseModelFromNoiseProperties(noise_props)

simulator = cirq.Simulator(noise=noise_model)

valid_circuit_invalid_qubits = cirq.Circuit(cirq.X(unexpected_qubits[0]))
valid_circuit_valid_qubits = cirq.Circuit(cirq.X(expected_qubits[0]))
invalid_circuit_invalid_qubits = cirq.Circuit(cirq.Y(unexpected_qubits[0]))
invalid_circuit_valid_qubits = cirq.Circuit(cirq.Y(expected_qubits[0]))

with pytest.raises(TypeError):
simulator.simulate(invalid_circuit_invalid_qubits)
with pytest.raises(TypeError):
simulator.simulate(invalid_circuit_valid_qubits)
with pytest.raises(TypeError):
simulator.simulate(valid_circuit_invalid_qubits)
simulator.simulate(valid_circuit_valid_qubits)
Loading