forked from quantumlib/Cirq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Insertion noise model (quantumlib#4672)
This PR is part of quantumlib#4640. It adds the `InsertionNoiseModel`, which injects noise based on a user-defined map. quantumlib#4671 is a prerequisite for this PR. The only files that need to be reviewed in this PR are: - `cirq-core/cirq/devices/...` - `__init__.py` - `insertion_noise_model[_test].py`
- Loading branch information
1 parent
658c46c
commit c7c0fa8
Showing
3 changed files
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Copyright 2021 The Cirq 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. | ||
|
||
import dataclasses | ||
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence | ||
|
||
from cirq import devices, ops | ||
from cirq.devices import noise_utils | ||
|
||
if TYPE_CHECKING: | ||
import cirq | ||
|
||
|
||
@dataclasses.dataclass | ||
class InsertionNoiseModel(devices.NoiseModel): | ||
"""Simple base noise model for inserting operations. | ||
Operations generated by this model for a given moment are all added into a | ||
single "noise moment", which is added before or after the original moment | ||
based on `prepend`. | ||
Args: | ||
ops_added: a map of gate types (and optionally, qubits they act on) to | ||
operations that should be added. | ||
prepend: whether to add the new moment before the current one. | ||
require_physical_tag: whether to only apply noise to operations tagged | ||
with PHYSICAL_GATE_TAG. | ||
""" | ||
|
||
ops_added: Dict[noise_utils.OpIdentifier, 'cirq.Operation'] = dataclasses.field( | ||
default_factory=dict | ||
) | ||
prepend: bool = False | ||
require_physical_tag: bool = True | ||
|
||
def noisy_moment( | ||
self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] | ||
) -> 'cirq.OP_TREE': | ||
noise_ops: List['cirq.Operation'] = [] | ||
candidate_ops = [ | ||
op | ||
for op in moment | ||
if (not self.require_physical_tag) or noise_utils.PHYSICAL_GATE_TAG in op.tags | ||
] | ||
for op in candidate_ops: | ||
match_id: Optional[noise_utils.OpIdentifier] = None | ||
candidate_ids = [op_id for op_id in self.ops_added if op in op_id] | ||
for op_id in candidate_ids: | ||
if match_id is None or op_id.is_proper_subtype_of(match_id): | ||
match_id = op_id | ||
if match_id is not None: | ||
noise_ops.append(self.ops_added[match_id]) | ||
if not noise_ops: | ||
return [moment] | ||
if self.prepend: | ||
return [ops.Moment(noise_ops), moment] | ||
return [moment, ops.Moment(noise_ops)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# Copyright 2021 The Cirq 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. | ||
|
||
import cirq | ||
from cirq.devices.insertion_noise_model import InsertionNoiseModel | ||
from cirq.devices.noise_utils import ( | ||
PHYSICAL_GATE_TAG, | ||
OpIdentifier, | ||
) | ||
|
||
|
||
def test_insertion_noise(): | ||
q0, q1 = cirq.LineQubit.range(2) | ||
op_id0 = OpIdentifier(cirq.XPowGate, q0) | ||
op_id1 = OpIdentifier(cirq.ZPowGate, q1) | ||
model = InsertionNoiseModel( | ||
{op_id0: cirq.T(q0), op_id1: cirq.H(q1)}, require_physical_tag=False | ||
) | ||
assert not model.prepend | ||
|
||
moment_0 = cirq.Moment(cirq.X(q0), cirq.X(q1)) | ||
assert model.noisy_moment(moment_0, system_qubits=[q0, q1]) == [ | ||
moment_0, | ||
cirq.Moment(cirq.T(q0)), | ||
] | ||
|
||
moment_1 = cirq.Moment(cirq.Z(q0), cirq.Z(q1)) | ||
assert model.noisy_moment(moment_1, system_qubits=[q0, q1]) == [ | ||
moment_1, | ||
cirq.Moment(cirq.H(q1)), | ||
] | ||
|
||
moment_2 = cirq.Moment(cirq.X(q0), cirq.Z(q1)) | ||
assert model.noisy_moment(moment_2, system_qubits=[q0, q1]) == [ | ||
moment_2, | ||
cirq.Moment(cirq.T(q0), cirq.H(q1)), | ||
] | ||
|
||
moment_3 = cirq.Moment(cirq.Z(q0), cirq.X(q1)) | ||
assert model.noisy_moment(moment_3, system_qubits=[q0, q1]) == [moment_3] | ||
|
||
|
||
def test_prepend(): | ||
q0, q1 = cirq.LineQubit.range(2) | ||
op_id0 = OpIdentifier(cirq.XPowGate, q0) | ||
op_id1 = OpIdentifier(cirq.ZPowGate, q1) | ||
model = InsertionNoiseModel( | ||
{op_id0: cirq.T(q0), op_id1: cirq.H(q1)}, prepend=True, require_physical_tag=False | ||
) | ||
|
||
moment_0 = cirq.Moment(cirq.X(q0), cirq.Z(q1)) | ||
assert model.noisy_moment(moment_0, system_qubits=[q0, q1]) == [ | ||
cirq.Moment(cirq.T(q0), cirq.H(q1)), | ||
moment_0, | ||
] | ||
|
||
|
||
def test_require_physical_tag(): | ||
q0, q1 = cirq.LineQubit.range(2) | ||
op_id0 = OpIdentifier(cirq.XPowGate, q0) | ||
op_id1 = OpIdentifier(cirq.ZPowGate, q1) | ||
model = InsertionNoiseModel({op_id0: cirq.T(q0), op_id1: cirq.H(q1)}) | ||
assert model.require_physical_tag | ||
|
||
moment_0 = cirq.Moment(cirq.X(q0).with_tags(PHYSICAL_GATE_TAG), cirq.Z(q1)) | ||
assert model.noisy_moment(moment_0, system_qubits=[q0, q1]) == [ | ||
moment_0, | ||
cirq.Moment(cirq.T(q0)), | ||
] | ||
|
||
|
||
def test_supertype_matching(): | ||
# Demonstrate that the model applies the closest matching type | ||
# if multiple types match a given gate. | ||
q0 = cirq.LineQubit(0) | ||
op_id0 = OpIdentifier(cirq.Gate, q0) | ||
op_id1 = OpIdentifier(cirq.XPowGate, q0) | ||
model = InsertionNoiseModel( | ||
{op_id0: cirq.T(q0), op_id1: cirq.S(q0)}, require_physical_tag=False | ||
) | ||
|
||
moment_0 = cirq.Moment(cirq.Rx(rads=1).on(q0)) | ||
assert model.noisy_moment(moment_0, system_qubits=[q0]) == [ | ||
moment_0, | ||
cirq.Moment(cirq.S(q0)), | ||
] | ||
|
||
moment_1 = cirq.Moment(cirq.Y(q0)) | ||
assert model.noisy_moment(moment_1, system_qubits=[q0]) == [ | ||
moment_1, | ||
cirq.Moment(cirq.T(q0)), | ||
] |