1
1
import numpy as np
2
2
import tensorflow as tf
3
+ import copy
4
+ import os
5
+ import tempfile
3
6
from typing import Any , Dict , Iterator , Tuple
4
7
from qiskit import QuantumCircuit , ClassicalRegister , QuantumRegister
5
8
from c3 .utils .tf_utils import (
9
12
super_to_choi ,
10
13
tf_project_to_comp ,
11
14
)
15
+ from c3 .experiment import Experiment
16
+ from c3 .model import Model
17
+ from c3 .libraries .chip import Qubit , Coupling , Drive
18
+ from c3 .signal .pulse import Envelope , Carrier
19
+ from c3 .libraries .envelopes import no_drive , gaussian_nonorm
20
+ from c3 .libraries .hamiltonians import int_XX , x_drive
12
21
from c3 .parametermap import ParameterMap
22
+ from c3 .signal .gates import Instruction
13
23
from c3 .generator .generator import Generator
14
- from c3 .generator .devices import Crosstalk
24
+ from c3 .generator .devices import (
25
+ AWG ,
26
+ Crosstalk ,
27
+ DigitalToAnalog ,
28
+ LO ,
29
+ Mixer ,
30
+ VoltsToHertz ,
31
+ )
15
32
from c3 .libraries .constants import Id , X , Y , Z
16
33
from c3 .c3objs import Quantity
34
+ from c3 .optimizers .optimalcontrol import OptimalControl
35
+ from c3 .libraries .fidelities import unitary_infid_set
36
+ from c3 .libraries .algorithms import algorithms
17
37
from c3 .qiskit .c3_gates import RX90pGate , CR90Gate
18
38
import pytest
19
39
@@ -27,7 +47,7 @@ def get_exp_problem() -> Iterator[Tuple[np.ndarray, np.ndarray]]:
27
47
a = np .random .rand (1 )
28
48
b = np .random .rand (1 )
29
49
c = np .random .rand (1 )
30
- norm = np .sqrt (a ** 2 + b ** 2 + c ** 2 )
50
+ norm = np .sqrt (a ** 2 + b ** 2 + c ** 2 )
31
51
# Normalized random coefficients
32
52
a = a / norm
33
53
b = b / norm
@@ -235,3 +255,272 @@ def get_test_dimensions() -> list:
235
255
"""Functions in qt_utils that allow arbitrary numbers of dimensions will be tested for all dimensions in this
236
256
list."""
237
257
return [3 , 5 , 10 , 50 ]
258
+
259
+
260
+ @pytest .fixture ()
261
+ def get_two_qubit_chip () -> Experiment :
262
+ """Setup a two qubit example with pre-optimized gates."""
263
+ qubit_lvls = 2
264
+ freq_q1 = 5e9
265
+ q1 = Qubit (
266
+ name = "Q1" ,
267
+ desc = "Qubit 1" ,
268
+ freq = Quantity (value = freq_q1 , min_val = 4.995e9 , max_val = 5.005e9 , unit = "Hz 2pi" ),
269
+ hilbert_dim = qubit_lvls ,
270
+ )
271
+
272
+ freq_q2 = 5.6e9
273
+ q2 = Qubit (
274
+ name = "Q2" ,
275
+ desc = "Qubit 2" ,
276
+ freq = Quantity (value = freq_q2 , min_val = 5.595e9 , max_val = 5.605e9 , unit = "Hz 2pi" ),
277
+ hilbert_dim = qubit_lvls ,
278
+ )
279
+
280
+ coupling_strength = 20e6
281
+ q1q2 = Coupling (
282
+ name = "Q1-Q2" ,
283
+ desc = "coupling" ,
284
+ comment = "Coupling qubit 1 to qubit 2" ,
285
+ connected = ["Q1" , "Q2" ],
286
+ strength = Quantity (
287
+ value = coupling_strength , min_val = - 1 * 1e3 , max_val = 200e6 , unit = "Hz 2pi"
288
+ ),
289
+ hamiltonian_func = int_XX ,
290
+ )
291
+
292
+ drive = Drive (
293
+ name = "d1" ,
294
+ desc = "Drive 1" ,
295
+ comment = "Drive line 1 on qubit 1" ,
296
+ connected = ["Q1" ],
297
+ hamiltonian_func = x_drive ,
298
+ )
299
+ drive2 = Drive (
300
+ name = "d2" ,
301
+ desc = "Drive 2" ,
302
+ comment = "Drive line 2 on qubit 2" ,
303
+ connected = ["Q2" ],
304
+ hamiltonian_func = x_drive ,
305
+ )
306
+
307
+ model = Model (
308
+ [q1 , q2 ], # Individual, self-contained components
309
+ [drive , drive2 , q1q2 ], # Interactions between components
310
+ )
311
+
312
+ model .set_lindbladian (False )
313
+ model .set_dressed (True )
314
+
315
+ sim_res = 100e9 # Resolution for numerical simulation
316
+ awg_res = 2e9 # Realistic, limited resolution of an AWG
317
+ v2hz = 1e9
318
+
319
+ generator = Generator (
320
+ devices = {
321
+ "LO" : LO (name = "lo" , resolution = sim_res , outputs = 1 ),
322
+ "AWG" : AWG (name = "awg" , resolution = awg_res , outputs = 1 ),
323
+ "DigitalToAnalog" : DigitalToAnalog (
324
+ name = "dac" , resolution = sim_res , inputs = 1 , outputs = 1
325
+ ),
326
+ "Mixer" : Mixer (name = "mixer" , inputs = 2 , outputs = 1 ),
327
+ "VoltsToHertz" : VoltsToHertz (
328
+ name = "v_to_hz" ,
329
+ V_to_Hz = Quantity (
330
+ value = v2hz , min_val = 0.9e9 , max_val = 1.1e9 , unit = "Hz 2pi/V"
331
+ ),
332
+ inputs = 1 ,
333
+ outputs = 1 ,
334
+ ),
335
+ },
336
+ chains = {
337
+ "d1" : {
338
+ "LO" : [],
339
+ "AWG" : [],
340
+ "DigitalToAnalog" : ["AWG" ],
341
+ "Mixer" : ["LO" , "DigitalToAnalog" ],
342
+ "VoltsToHertz" : ["Mixer" ],
343
+ },
344
+ "d2" : {
345
+ "LO" : [],
346
+ "AWG" : [],
347
+ "DigitalToAnalog" : ["AWG" ],
348
+ "Mixer" : ["LO" , "DigitalToAnalog" ],
349
+ "VoltsToHertz" : ["Mixer" ],
350
+ },
351
+ },
352
+ )
353
+
354
+ t_final = 7e-9 # Time for single qubit gates
355
+ amp = 359e-3 # prev optimized
356
+ sideband = 50e6
357
+ shift = coupling_strength ** 2 / (freq_q2 - freq_q1 )
358
+ gauss_params_single = {
359
+ "amp" : Quantity (value = amp , min_val = 0.1 , max_val = 0.6 , unit = "V" ),
360
+ "t_final" : Quantity (
361
+ value = t_final , min_val = 0.5 * t_final , max_val = 1.5 * t_final , unit = "s"
362
+ ),
363
+ "sigma" : Quantity (
364
+ value = t_final / 4 , min_val = t_final / 8 , max_val = t_final / 2 , unit = "s"
365
+ ),
366
+ "xy_angle" : Quantity (
367
+ value = 0.0 , min_val = - 0.5 * np .pi , max_val = 2.5 * np .pi , unit = "rad"
368
+ ),
369
+ "freq_offset" : Quantity (
370
+ value = - sideband - shift , min_val = - 56 * 1e6 , max_val = - 48 * 1e6 , unit = "Hz 2pi"
371
+ ),
372
+ }
373
+
374
+ gauss_env_single = Envelope (
375
+ name = "gauss" ,
376
+ desc = "Gaussian comp for single-qubit gates" ,
377
+ params = gauss_params_single ,
378
+ shape = gaussian_nonorm ,
379
+ )
380
+
381
+ nodrive_env = Envelope (
382
+ name = "no_drive" ,
383
+ params = {
384
+ "t_final" : Quantity (
385
+ value = t_final , min_val = 0.5 * t_final , max_val = 1.5 * t_final , unit = "s"
386
+ )
387
+ },
388
+ shape = no_drive ,
389
+ )
390
+
391
+ lo_freq_q1 = 5e9 + sideband
392
+ carrier_parameters = {
393
+ "freq" : Quantity (value = lo_freq_q1 , min_val = 4.5e9 , max_val = 6e9 , unit = "Hz 2pi" ),
394
+ "framechange" : Quantity (
395
+ value = 0.0 , min_val = - np .pi , max_val = 3 * np .pi , unit = "rad"
396
+ ),
397
+ }
398
+
399
+ carr = Carrier (
400
+ name = "carrier" ,
401
+ desc = "Frequency of the local oscillator" ,
402
+ params = carrier_parameters ,
403
+ )
404
+
405
+ lo_freq_q2 = 5.6e9 + sideband
406
+ carr_2 = copy .deepcopy (carr )
407
+ carr_2 .params ["freq" ].set_value (lo_freq_q2 )
408
+
409
+ rx90p_q1 = Instruction (
410
+ name = "rx90p" ,
411
+ targets = [0 ],
412
+ t_start = 0.0 ,
413
+ t_end = t_final ,
414
+ channels = ["d1" , "d2" ],
415
+ params = {"use_t_before" : True },
416
+ )
417
+ rx90p_q2 = Instruction (
418
+ name = "rx90p" ,
419
+ targets = [1 ],
420
+ t_start = 0.0 ,
421
+ t_end = t_final ,
422
+ channels = ["d1" , "d2" ],
423
+ params = {"use_t_before" : True },
424
+ )
425
+ QId_q1 = Instruction (
426
+ name = "id" ,
427
+ targets = [0 ],
428
+ t_start = 0.0 ,
429
+ t_end = t_final ,
430
+ channels = ["d1" , "d2" ],
431
+ params = {"use_t_before" : True },
432
+ )
433
+ QId_q2 = Instruction (
434
+ name = "id" ,
435
+ targets = [1 ],
436
+ t_start = 0.0 ,
437
+ t_end = t_final ,
438
+ channels = ["d1" , "d2" ],
439
+ params = {"use_t_before" : True },
440
+ )
441
+
442
+ rx90p_q1 .add_component (gauss_env_single , "d1" )
443
+ rx90p_q1 .add_component (carr , "d1" )
444
+ rx90p_q1 .add_component (nodrive_env , "d2" )
445
+ rx90p_q1 .add_component (copy .deepcopy (carr_2 ), "d2" )
446
+ rx90p_q1 .comps ["d2" ]["carrier" ].params ["framechange" ].set_value (
447
+ (- sideband * t_final ) * 2 * np .pi % (2 * np .pi )
448
+ )
449
+
450
+ rx90p_q2 .add_component (copy .deepcopy (gauss_env_single ), "d2" )
451
+ rx90p_q2 .add_component (carr_2 , "d2" )
452
+ rx90p_q2 .add_component (nodrive_env , "d1" )
453
+ rx90p_q2 .add_component (copy .deepcopy (carr ), "d1" )
454
+ rx90p_q2 .comps ["d1" ]["carrier" ].params ["framechange" ].set_value (
455
+ (- sideband * t_final ) * 2 * np .pi % (2 * np .pi )
456
+ )
457
+
458
+ QId_q1 .add_component (nodrive_env , "d1" )
459
+ QId_q1 .add_component (copy .deepcopy (carr ), "d1" )
460
+ QId_q1 .add_component (nodrive_env , "d2" )
461
+ QId_q1 .add_component (copy .deepcopy (carr_2 ), "d2" )
462
+ QId_q2 .add_component (copy .deepcopy (nodrive_env ), "d2" )
463
+ QId_q2 .add_component (copy .deepcopy (carr_2 ), "d2" )
464
+ QId_q2 .add_component (nodrive_env , "d1" )
465
+ QId_q2 .add_component (copy .deepcopy (carr ), "d1" )
466
+
467
+ Y90p_q1 = copy .deepcopy (rx90p_q1 )
468
+ Y90p_q1 .name = "ry90p"
469
+ X90m_q1 = copy .deepcopy (rx90p_q1 )
470
+ X90m_q1 .name = "rx90m"
471
+ Y90m_q1 = copy .deepcopy (rx90p_q1 )
472
+ Y90m_q1 .name = "ry90m"
473
+ Y90p_q1 .comps ["d1" ]["gauss" ].params ["xy_angle" ].set_value (0.5 * np .pi )
474
+ X90m_q1 .comps ["d1" ]["gauss" ].params ["xy_angle" ].set_value (np .pi )
475
+ Y90m_q1 .comps ["d1" ]["gauss" ].params ["xy_angle" ].set_value (1.5 * np .pi )
476
+ single_q_gates = [QId_q1 , rx90p_q1 , Y90p_q1 , X90m_q1 , Y90m_q1 ]
477
+
478
+ Y90p_q2 = copy .deepcopy (rx90p_q2 )
479
+ Y90p_q2 .name = "ry90p"
480
+ X90m_q2 = copy .deepcopy (rx90p_q2 )
481
+ X90m_q2 .name = "rx90m"
482
+ Y90m_q2 = copy .deepcopy (rx90p_q2 )
483
+ Y90m_q2 .name = "ry90m"
484
+ Y90p_q2 .comps ["d2" ]["gauss" ].params ["xy_angle" ].set_value (0.5 * np .pi )
485
+ X90m_q2 .comps ["d2" ]["gauss" ].params ["xy_angle" ].set_value (np .pi )
486
+ Y90m_q2 .comps ["d2" ]["gauss" ].params ["xy_angle" ].set_value (1.5 * np .pi )
487
+ single_q_gates .extend ([QId_q2 , rx90p_q2 , Y90p_q2 , X90m_q2 , Y90m_q2 ])
488
+
489
+ pmap = ParameterMap (single_q_gates , generator , model )
490
+
491
+ pmap .set_opt_map (
492
+ [
493
+ [["rx90p[0]" , "d1" , "gauss" , "amp" ]],
494
+ [["rx90p[0]" , "d1" , "gauss" , "freq_offset" ]],
495
+ [["rx90p[0]" , "d1" , "gauss" , "xy_angle" ]],
496
+ ]
497
+ )
498
+ return Experiment (pmap )
499
+
500
+
501
+ @pytest .fixture (
502
+ params = [
503
+ "single_eval" ,
504
+ "tf_sgd" ,
505
+ "lbfgs" ,
506
+ "lbfgs_grad_free" ,
507
+ "cmaes" ,
508
+ "cma_pre_lbfgs" ,
509
+ ]
510
+ )
511
+ def get_OC_optimizer (request , get_two_qubit_chip ) -> OptimalControl :
512
+ """Create a general optimizer object with each algorithm with a decorator in the lib."""
513
+ exp = get_two_qubit_chip
514
+ exp .set_opt_gates (["rx90p[0]" ])
515
+ logdir = os .path .join (tempfile .TemporaryDirectory ().name , "c3logs" )
516
+ opt = OptimalControl (
517
+ dir_path = logdir ,
518
+ fid_func = unitary_infid_set ,
519
+ pmap = exp .pmap ,
520
+ fid_subspace = ["Q1" , "Q2" ],
521
+ algorithm = algorithms [request .param ],
522
+ options = {"maxiters" : 2 } if request .param == "tf_sgd" else {"maxiter" : 2 },
523
+ run_name = f"better_X90_{ request .param } " ,
524
+ )
525
+ opt .set_exp (exp )
526
+ return opt
0 commit comments