Skip to content

Commit e540d6c

Browse files
dstrain115Strilanc
authored andcommitted
Add the ability to customize error gates for depolarizing channel (#254)
This change adds an additional parameter to customize the list of gates that can be added as potential error gates at each moment. Each gate will have its "half_turns" parameter overwritten by a parameterized value.
1 parent 8d319fa commit e540d6c

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

cirq/contrib/jobs/depolarizer_channel.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Error simulator that adds randomly activated error gates after every moment.
1616
"""
1717

18+
import copy
1819
import numpy as np
1920

2021
from cirq.circuits.circuit import Circuit
@@ -33,8 +34,11 @@ class DepolarizerChannel(object):
3334
noise by decohering random qubits at each step. This transform
3435
is intended only for classical simulations only.
3536
36-
This class currently only supports adding a Pauli-Z gate at
37-
each step.
37+
This class currently defaults to adding a Pauli-Z gate at
38+
each step but the gate set to add is configurable. Note that
39+
all gates must be XmonGates or have a half_turns parameter
40+
that will be overwritten by this class with a parameterized
41+
value.
3842
3943
If the job already contains a parameter sweep, this will create
4044
the error sweep as a cartesian product (i.e. a "factor") of the
@@ -45,14 +49,17 @@ class DepolarizerChannel(object):
4549
Attributes:
4650
probability: Probability of a qubit being affected in a given moment
4751
realizations: Number of simulations to create.
52+
depolarizing_gates: A list of XmonGates to include at every moment.
4853
"""
4954

5055
# Prefix for symbols related to error simulation
5156
_parameter_name = 'error_parameter'
5257

53-
def __init__(self, probability=0.001, realizations=1):
58+
def __init__(self, probability=0.001, realizations=1,
59+
depolarizing_gates=(xmon_gates.ExpZGate(),)):
5460
self.p = probability
5561
self.realizations = realizations
62+
self.depolarizing_gates = depolarizing_gates
5663

5764
def transform_job(self, job):
5865
"""Creates a new job object with depolarizing channel.
@@ -95,21 +102,23 @@ def transform_job(self, job):
95102
for moment in circuit.moments:
96103
moments.append(moment)
97104

98-
error_gates = []
99-
for q in qubit_list:
100-
errors = np.random.random(self.realizations) < self.p
101-
if any(errors):
102-
key = self._parameter_name + str(error_number)
103-
error_gates.append(xmon_gates.ExpZGate(
104-
half_turns=Symbol(key)).on(q))
105-
error_sweep += Points(key, list(errors * 1.0))
106-
error_number += 1
107-
108-
if error_gates:
109-
moments.append(Moment(error_gates))
105+
for gate in self.depolarizing_gates:
106+
error_gates = []
107+
for q in qubit_list:
108+
errors = np.random.random(self.realizations) < self.p
109+
if any(errors):
110+
key = self._parameter_name + str(error_number)
111+
new_error_gate = copy.deepcopy(gate)
112+
new_error_gate.half_turns = Symbol(key)
113+
error_gates.append(new_error_gate.on(q))
114+
error_sweep += Points(key, list(errors * 1.0))
115+
error_number += 1
116+
117+
if error_gates:
118+
moments.append(Moment(error_gates))
110119

111120
sweep = job.sweep
112-
if len(error_sweep):
121+
if error_sweep:
113122
sweep *= error_sweep
114123

115124
return Job(Circuit(moments), sweep, job.repetitions)

cirq/contrib/jobs/depolarizer_channel_test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ def test_depolarizer_all_errors():
5555
assert allerrors.transform_job(cnot) == cnot_then_z
5656

5757

58+
def test_depolarizer_different_gate():
59+
q1 = ops.QubitId()
60+
q2 = ops.QubitId()
61+
cnot = Job(circuits.Circuit([
62+
circuits.Moment([ops.CNOT(q1, q2)]),
63+
]))
64+
allerrors = DepolarizerChannel(probability=1.0, depolarizing_gates=
65+
[xmon_gates.ExpZGate(),
66+
xmon_gates.ExpWGate()])
67+
p0 = Symbol(DepolarizerChannel._parameter_name + '0')
68+
p1 = Symbol(DepolarizerChannel._parameter_name + '1')
69+
p2 = Symbol(DepolarizerChannel._parameter_name + '2')
70+
p3 = Symbol(DepolarizerChannel._parameter_name + '3')
71+
72+
error_sweep = (Points(p0.name, [1.0]) + Points(p1.name, [1.0])
73+
+ Points(p2.name, [1.0]) + Points(p3.name, [1.0]))
74+
75+
cnot_then_z = Job(
76+
circuits.Circuit([
77+
circuits.Moment([ops.CNOT(q1, q2)]),
78+
circuits.Moment([xmon_gates.ExpZGate(half_turns=p0).on(q1),
79+
xmon_gates.ExpZGate(half_turns=p1).on(q2)]),
80+
circuits.Moment([xmon_gates.ExpWGate(half_turns=p2).on(q1),
81+
xmon_gates.ExpWGate(half_turns=p3).on(q2)])
82+
]),
83+
cnot.sweep * error_sweep)
84+
85+
assert allerrors.transform_job(cnot) == cnot_then_z
86+
87+
5888
def test_depolarizer_multiple_realizations():
5989
q1 = ops.QubitId()
6090
q2 = ops.QubitId()

0 commit comments

Comments
 (0)