@@ -1006,6 +1006,7 @@ def new_gaussian_control(
1006
1006
See Also
1007
1007
--------
1008
1008
new_modulated_gaussian_control
1009
+ new_drag_control
1009
1010
1010
1011
Notes
1011
1012
-----
@@ -1206,3 +1207,132 @@ def new_modulated_gaussian_control(
1206
1207
detunings = np .zeros (segment_count ),
1207
1208
durations = np .array ([segment_duration ] * segment_count ),
1208
1209
)
1210
+
1211
+
1212
+ def new_drag_control (
1213
+ rabi_rotation : float ,
1214
+ segment_count : int ,
1215
+ duration : float ,
1216
+ width : float ,
1217
+ beta : float ,
1218
+ azimuthal_angle : float = 0.0 ,
1219
+ name : Optional [str ] = None ,
1220
+ ) -> DrivenControl :
1221
+ r"""
1222
+ Generates a Gaussian driven control sequence with a first-order DRAG
1223
+ (Derivative Removal by Adiabatic Gate) correction applied.
1224
+
1225
+ The addition of DRAG further reduces leakage out of the qubit subspace via an additional
1226
+ off-quadrature corrective driving term proportional to the derivative of the Gaussian pulse.
1227
+
1228
+ Parameters
1229
+ ----------
1230
+ rabi_rotation : float
1231
+ Total Rabi rotation :math:`\theta` to be performed by the driven control.
1232
+ segment_count : int
1233
+ Number of segments in the control sequence.
1234
+ duration : float
1235
+ Total duration :math:`t_g` of the control sequence.
1236
+ width : float
1237
+ Width (standard deviation) :math:`\sigma` of the ideal Gaussian pulse.
1238
+ beta : float
1239
+ Amplitude scaling :math:`\beta` of the Gaussian derivative.
1240
+ azimuthal_angle : float, optional
1241
+ The azimuthal angle :math:`\phi` for the rotation. Defaults to 0.
1242
+ name : str, optional
1243
+ An optional string to name the control. Defaults to ``None``.
1244
+
1245
+ Returns
1246
+ -------
1247
+ DrivenControl
1248
+ A control sequence as an instance of DrivenControl.
1249
+
1250
+ See Also
1251
+ --------
1252
+ new_gaussian_control
1253
+
1254
+ Notes
1255
+ -----
1256
+ A DRAG-corrected Gaussian driven control [#]_
1257
+ applies a Hamiltonian consisting of a piecewise constant approximation to an ideal
1258
+ Gaussian pulse controlling :math:`\sigma_x` while its derivative controls the
1259
+ application of the :math:`\sigma_y` operator:
1260
+
1261
+ .. math::
1262
+ H(t) = \frac{1}{2}(\Omega_G(t) \sigma_x + \beta \dot{\Omega}_G(t) \sigma_y)
1263
+
1264
+ where :math:`\Omega_G(t)` is simply given by :doc:`new_gaussian_control`. Optimally,
1265
+ :math:`\beta = -\frac{\lambda_1^2}{4\Delta_2}` where :math:`\Delta_2` is the
1266
+ anharmonicity of the system and :math:`\lambda_1` is the relative strength required
1267
+ to drive a transition :math:`\lvert 1 \rangle \rightarrow \lvert 2 \rangle` vs.
1268
+ :math:`\lvert 0 \rangle \rightarrow \lvert 1 \rangle`. Note
1269
+ that this choice of :math:`\beta`, sometimes called "simple drag" or "half derivative",
1270
+ is a first-order version of DRAG, and it excludes an additional detuning corrective term.
1271
+
1272
+ References
1273
+ ----------
1274
+ .. [#] `Motzoi, F. et al. Physical Review Letters 103, 110501 (2009).
1275
+ <https://doi.org/10.1103/PhysRevLett.103.110501>`_
1276
+ .. [#] `J. M. Gambetta, F. Motzoi, S. T. Merkel, and F. K. Wilhelm,
1277
+ Physical Review A 83, 012308 (2011).
1278
+ <https://doi.org/10.1103/PhysRevA.83.012308>`_
1279
+ """
1280
+
1281
+ check_arguments (
1282
+ duration > 0.0 ,
1283
+ "Pulse duration must be greater than zero." ,
1284
+ {"duration" : duration },
1285
+ )
1286
+
1287
+ check_arguments (
1288
+ segment_count > 0 ,
1289
+ "Segment count must be greater than zero." ,
1290
+ {"segment_count" : segment_count },
1291
+ )
1292
+
1293
+ check_arguments (
1294
+ width > 0.0 ,
1295
+ "Width of ideal Gaussian pulse must be greater than zero." ,
1296
+ {"width" : width },
1297
+ )
1298
+
1299
+ # compute sampling parameters
1300
+ segment_duration = duration / segment_count
1301
+ segment_start_times = np .arange (segment_count ) * segment_duration
1302
+ segment_midpoints = segment_start_times + segment_duration / 2
1303
+
1304
+ # prepare a base (un-normalized) gaussian shaped pulse
1305
+ gaussian_mean = duration / 2
1306
+ base_gaussian_segments = np .exp (
1307
+ - 0.5 * ((segment_midpoints - gaussian_mean ) / width ) ** 2
1308
+ )
1309
+
1310
+ # translate pulse by B/A (from Motzoi '09 paper) to ensure output is 0 at t=0
1311
+ y_translation = - np .exp (- 0.5 * ((0 - gaussian_mean ) / width ) ** 2 )
1312
+ base_gaussian_segments += y_translation
1313
+
1314
+ # compute A (from Motzoi '09 paper)
1315
+ base_gaussian_total_rotation = np .sum (base_gaussian_segments ) * segment_duration
1316
+ normalization_factor = rabi_rotation / base_gaussian_total_rotation
1317
+
1318
+ x_quadrature_segments = base_gaussian_segments * normalization_factor
1319
+ y_quadrature_segments = (
1320
+ beta
1321
+ * (gaussian_mean - segment_midpoints )
1322
+ / width ** 2
1323
+ * (
1324
+ x_quadrature_segments
1325
+ - y_translation * normalization_factor # = B (from Motzoi '09 paper)
1326
+ )
1327
+ )
1328
+
1329
+ rabi_rates = np .sqrt (x_quadrature_segments ** 2 + y_quadrature_segments ** 2 )
1330
+ azimuthal_angles = np .arcsin (y_quadrature_segments / rabi_rates ) + azimuthal_angle
1331
+
1332
+ return DrivenControl (
1333
+ rabi_rates = rabi_rates ,
1334
+ azimuthal_angles = azimuthal_angles ,
1335
+ detunings = np .zeros (segment_count ),
1336
+ durations = np .array ([segment_duration ] * segment_count ),
1337
+ name = name ,
1338
+ )
0 commit comments