1- TEXTWIDTH = 7.1398920714
2- LINEWIDTH = 3.48692403487
1+ from concurrent .futures import ProcessPoolExecutor # for parallel simulations
32
4- import matplotlib as mpl
3+ import numpy as np
54import matplotlib .pyplot as plt
6-
75from scipy .optimize import curve_fit
86
9- try :
10- global_setup (fontsize = 10 )
11- except :
12- pass
13- plt .rcParams .update ({"text.usetex" : False , "font.size" : 10 })
14- from joblib import Parallel , delayed # for parallel simulations
15- import numpy as np
167from qutip import (
178 fidelity ,
189 sigmax ,
2516 fock_dm ,
2617)
2718from qutip_qip .circuit import QubitCircuit
28- from qutip_qip .operations import Gate
19+ from qutip_qip .operations import AngleParametricGate
20+ from qutip_qip .operations .gates import RX , RY , Z
2921from qutip_qip .device import ModelProcessor , Model
3022from qutip_qip .compiler import GateCompiler , PulseInstruction
3123from qutip_qip .noise import Noise
3224
25+ plt .rcParams .update ({"text.usetex" : False , "font.size" : 10 })
26+ LINEWIDTH = 3.48692403487
27+ TEXTWIDTH = 7.1398920714
28+
29+
30+ class ROT (AngleParametricGate ):
31+ num_qubits = 1
32+ num_params = 1
33+
34+ def __init__ (self , arg_value ):
35+ super ().__init__ (arg_value )
36+
37+ def compute_qobj (args , dtype ) -> Qobj :
38+ # This is not required, because Pules levele implementation
39+ # of this gate is already provided.
40+ pass
41+
3342
3443class MyModel (Model ):
3544 """A custom Hamiltonian model with sigmax and sigmay control."""
@@ -68,16 +77,16 @@ def __init__(self, num_qubits, params):
6877 super ().__init__ (num_qubits , params = params )
6978 self .params = params
7079 self .gate_compiler = {
71- " ROT" : self .rotation_with_phase_compiler ,
72- "RX" : self .single_qubit_gate_compiler ,
73- "RY" : self .single_qubit_gate_compiler ,
80+ ROT : self .rotation_with_phase_compiler ,
81+ RX : self .single_qubit_gate_compiler ,
82+ RY : self .single_qubit_gate_compiler ,
7483 }
7584
76- def generate_pulse (self , gate , tlist , coeff , phase = 0.0 ):
85+ def generate_pulse (self , circ_op , tlist , coeff , phase = 0.0 ):
7786 """Generates the pulses.
7887
7988 Args:
80- gate (qutip_qip.circuit.Gate ): A qutip Gate object.
89+ circ_op (qutip_qip.circuit.GateInstruction ): A GateInstruction object.
8190 tlist (array): A list of times for the evolution.
8291 coeff (array): An array of coefficients for the gate pulses
8392 phase (float): The value of the phase for the gate.
@@ -89,61 +98,65 @@ def generate_pulse(self, gate, tlist, coeff, phase=0.0):
8998
9099 pulse_info = [
91100 # (control label, coeff)
92- ("sx" + str (gate .targets [0 ]), np .cos (phase ) * coeff ),
93- ("sy" + str (gate .targets [0 ]), np .sin (phase ) * coeff ),
101+ ("sx" + str (circ_op .targets [0 ]), np .cos (phase ) * coeff ),
102+ ("sy" + str (circ_op .targets [0 ]), np .sin (phase ) * coeff ),
94103 ]
95- return [PulseInstruction (gate , tlist = tlist , pulse_info = pulse_info )]
104+ return [PulseInstruction (circ_op , tlist = tlist , pulse_info = pulse_info )]
96105
97- def single_qubit_gate_compiler (self , gate , args ):
106+ def single_qubit_gate_compiler (self , circ_op , args ):
98107 """Compiles single qubit gates to pulses.
99108
100109 Args:
101- gate (qutip_qip.circuit.Gate): A qutip Gate object.
110+ circ_op (qutip_qip.circuit.GateInstruction)
102111
103112 Returns:
104113 PulseInstruction (qutip_qip.compiler.instruction.PulseInstruction):
105114 A pulse instruction to implement a gate containing the control pulses.
106115 """
107116 # gate.arg_value is the rotation angle
108- tlist = np .abs (gate .arg_value ) / self .params ["pulse_amplitude" ]
109- coeff = self .params ["pulse_amplitude" ] * np .sign (gate .arg_value )
117+ gate = circ_op .operation
118+ theta = gate .arg_value [0 ]
119+
120+ tlist = np .abs (theta ) / self .params ["pulse_amplitude" ]
121+ coeff = self .params ["pulse_amplitude" ] * np .sign (theta )
110122 coeff /= 2 * np .pi
111123 if gate .name == "RX" :
112- return self .generate_pulse (gate , tlist , coeff , phase = 0.0 )
124+ return self .generate_pulse (circ_op , tlist , coeff , phase = 0.0 )
113125 elif gate .name == "RY" :
114- return self .generate_pulse (gate , tlist , coeff , phase = np .pi / 2 )
126+ return self .generate_pulse (circ_op , tlist , coeff , phase = np .pi / 2 )
115127
116- def rotation_with_phase_compiler (self , gate , args ):
128+ def rotation_with_phase_compiler (self , circ_op , args ):
117129 """Compiles gates with a phase term.
118130
119131 Args:
120- gate (qutip_qip.circuit.Gate): A qutip Gate object.
132+ circ_op (qutip_qip.circuit.GateInstruction):
121133
122134 Returns:
123135 PulseInstruction (qutip_qip.compiler.instruction.PulseInstruction):
124136 A pulse instruction to implement a gate containing the control pulses.
125137 """
126138 # gate.arg_value is the pulse phase
139+ phase = circ_op .operation .arg_value [0 ]
127140 tlist = self .params ["duration" ]
128141 coeff = self .params ["pulse_amplitude" ]
129142 coeff /= 2 * np .pi
130- return self .generate_pulse (gate , tlist , coeff , phase = gate . arg_value )
143+ return self .generate_pulse (circ_op , tlist , coeff , phase = phase )
131144
132145
133146# Define a circuit and run the simulation
134147num_qubits = 1
135148
136149circuit = QubitCircuit (1 )
137- circuit .add_gate ("RX" , targets = 0 , arg_value = np .pi / 2 )
138- circuit .add_gate ("Z" , targets = 0 )
150+ circuit .add_gate (RX ( np .pi / 2 ), targets = 0 )
151+ circuit .add_gate (Z , targets = 0 )
139152result1 = circuit .run (basis (2 , 0 ))
140153
141- myprocessor = ModelProcessor (model = MyModel (num_qubits ))
142- myprocessor .native_gates = ["RX" , "RY" ]
143-
144154mycompiler = MyCompiler (num_qubits , {"pulse_amplitude" : 0.02 })
145155
156+ myprocessor = ModelProcessor (model = MyModel (num_qubits ))
157+ myprocessor .native_gates = ["RX" , "RY" ]
146158myprocessor .load_circuit (circuit , compiler = mycompiler )
159+
147160result2 = myprocessor .run_state (basis (2 , 0 )).states [- 1 ]
148161assert abs (fidelity (result1 , result2 ) - 1 ) < 1.0e-5
149162
@@ -221,14 +234,15 @@ def single_crosstalk_simulation(num_gates):
221234
222235 # Define a randome circuit.
223236 gates_set = [
224- Gate ( name = " ROT" , arg_value = 0 ),
225- Gate ( name = " ROT" , arg_value = np .pi / 2 ),
226- Gate ( name = " ROT" , arg_value = np .pi ),
227- Gate ( name = " ROT" , arg_value = np .pi / 2 * 3 ),
237+ ROT ( arg_value = 0 ),
238+ ROT ( np .pi / 2 ),
239+ ROT ( np .pi ),
240+ ROT ( np .pi / 2 * 3 ),
228241 ]
229242 circuit = QubitCircuit (num_qubits )
230243 for ind in np .random .randint (0 , 4 , num_gates ):
231244 circuit .add_gate (gates_set [ind ], targets = 0 )
245+
232246 # Simulate the circuit.
233247 myprocessor .load_circuit (circuit , compiler = mycompiler )
234248 init_state = tensor (
@@ -245,68 +259,68 @@ def single_crosstalk_simulation(num_gates):
245259 return result
246260
247261
248- num_sample = 2
249- # num_sample = 1600
250- fidelity = []
251- fidelity_error = []
252262init_fid = 0.975
253- num_gates_list = [250 ]
254- # num_gates_list = [250, 500, 750, 1000, 1250, 1500]
255-
256- # The full simulation may take several hours
257- # so we just choose num_sample=2 and num_gates=250 as a test
258- for num_gates in num_gates_list :
259- expect = Parallel (n_jobs = 1 )(
260- delayed (single_crosstalk_simulation )(num_gates )
261- for i in range (num_sample )
262- )
263- fidelity .append (np .mean (expect ))
264- fidelity_error .append (np .std (expect ) / np .sqrt (num_sample ))
265-
266- # Recorded result
267- num_gates_list = [250 , 500 , 750 , 1000 , 1250 , 1500 ]
268- data_y = [
269- 0.9566768747558925 ,
270- 0.9388905075892828 ,
271- 0.9229470389282218 ,
272- 0.9075513000339529 ,
273- 0.8941659320508855 ,
274- 0.8756519016627652 ,
275- ]
276-
277- data_y_error = [
278- 0.00042992029265330223 ,
279- 0.0008339882813741004 ,
280- 0.0012606632769758602 ,
281- 0.0014643550337816722 ,
282- 0.0017695604671714809 ,
283- 0.0020964978542167617 ,
284- ]
285-
286-
287- def rb_curve (x , a ):
288- return (1 / 2 + np .exp (- 2 * a * x ) / 2 ) * 0.975
289-
290-
291- pos , cov = curve_fit (rb_curve , num_gates_list , data_y , p0 = [0.001 ])
292-
293- xline = np .linspace (0 , 1700 , 200 )
294- yline = rb_curve (xline , * pos )
295-
296- fig , ax = plt .subplots (figsize = (LINEWIDTH , 0.65 * LINEWIDTH ), dpi = 200 )
297- ax .errorbar (
298- num_gates_list ,
299- data_y ,
300- yerr = data_y_error ,
301- fmt = "." ,
302- capsize = 2 ,
303- color = "slategrey" ,
304- )
305- ax .plot (xline , yline , color = "slategrey" )
306- ax .set_ylabel ("Average fidelity" )
307- ax .set_xlabel (r"Number of $\pi$ rotations" )
308- ax .set_xlim ((0 , 1700 ))
309263
310- fig .tight_layout ()
311- fig .savefig ("fig4_cross_talk.pdf" )
312- fig .show ()
264+ if __name__ == "__main__" :
265+ num_sample = 2
266+ # num_sample = 1600
267+ fidelity = []
268+ fidelity_error = []
269+ num_gates_list = [250 ]
270+ # num_gates_list = [250, 500, 750, 1000, 1250, 1500]
271+
272+ # The full simulation may take several hours
273+ # so we just choose num_sample=2 and num_gates=250 as a test
274+ for num_gates in num_gates_list :
275+ args = [num_gates ] * num_sample
276+ with ProcessPoolExecutor () as executor :
277+ expect = list (executor .map (single_crosstalk_simulation , args ))
278+
279+ fidelity .append (np .mean (expect ))
280+ fidelity_error .append (np .std (expect ) / np .sqrt (num_sample ))
281+
282+ # Recorded result
283+ num_gates_list = [250 , 500 , 750 , 1000 , 1250 , 1500 ]
284+ data_y = [
285+ 0.9566768747558925 ,
286+ 0.9388905075892828 ,
287+ 0.9229470389282218 ,
288+ 0.9075513000339529 ,
289+ 0.8941659320508855 ,
290+ 0.8756519016627652 ,
291+ ]
292+
293+ data_y_error = [
294+ 0.00042992029265330223 ,
295+ 0.0008339882813741004 ,
296+ 0.0012606632769758602 ,
297+ 0.0014643550337816722 ,
298+ 0.0017695604671714809 ,
299+ 0.0020964978542167617 ,
300+ ]
301+
302+ def rb_curve (x , a ):
303+ return (1 / 2 + np .exp (- 2 * a * x ) / 2 ) * 0.975
304+
305+ pos , cov = curve_fit (rb_curve , num_gates_list , data_y , p0 = [0.001 ])
306+
307+ xline = np .linspace (0 , 1700 , 200 )
308+ yline = rb_curve (xline , * pos )
309+
310+ fig , ax = plt .subplots (figsize = (LINEWIDTH , 0.65 * LINEWIDTH ), dpi = 200 )
311+ ax .errorbar (
312+ num_gates_list ,
313+ data_y ,
314+ yerr = data_y_error ,
315+ fmt = "." ,
316+ capsize = 2 ,
317+ color = "slategrey" ,
318+ )
319+ ax .plot (xline , yline , color = "slategrey" )
320+ ax .set_ylabel ("Average fidelity" )
321+ ax .set_xlabel (r"Number of $\pi$ rotations" )
322+ ax .set_xlim ((0 , 1700 ))
323+
324+ fig .tight_layout ()
325+ fig .savefig ("fig4_cross_talk.pdf" )
326+ fig .show ()
0 commit comments