def unitary_channel(dimension,desired_fidelity,error): noise_operator = qt.to_super(qt.rand_unitary(dimension)) count=0 while np.abs(qt.average_gate_fidelity(noise_operator)-desired_fidelity)>error and count<400: noise_operator = qt.to_super(qt.rand_unitary(dimension)) count=count+1 if count>=400: print("Could not achieve desired fidelity within margin of error") return noise_operator
def two_qubit_cliffords(): '''returns the two qubit clifford group as a list of qutip superoperators''' rot_cliffords = [qt.identity(2), qt.rotation((2/(np.sqrt(3))),(qt.sigmax()+qt.sigmay()+qt.sigmaz())/3),qt.rotation((4/(np.sqrt(3))),(qt.sigmax()+qt.sigmay()+qt.sigmaz())/3)] rot_class_cliffords = [qt.to_super(qt.tensor(x,y)) for x in rot_cliffords for y in rot_cliffords] class_one_cliffords = [qt.to_super(qt.tensor(x,y)) for x in qt.qubit_clifford_group() for y in qt.qubit_clifford_group()] class_two_cliffords = [x*qt.to_super(qt.cnot())*y for x in class_one_cliffords for y in rot_class_cliffords] class_three_cliffords = [x*qt.to_super(qt.iswap())*y for x in class_one_cliffords for y in rot_class_cliffords] class_four_cliffords = [x*qt.to_super(qt.swap()) for x in class_one_cliffords] return class_one_cliffords+class_two_cliffords+ class_three_cliffords+ class_four_cliffords
def rotating_frame_transformation_new(U, t: float, H): """ Transforms the frame of the unitary according to U' = U_{RF}*U*U_{RF}^dag NOTE: remember that this is how the time evolution operator changes from one picture to another Args: U (QObj): Unitary to be transformed t (float): time at which to transform H (QObj): hamiltonian to be rotated away """ U_RF = ( 1j * H * t).expm() #wrong: it shouldn't affect avgatefid_compsubspace though if U.type == 'super': U_RF = qtp.to_super(U_RF) U_prime = U_RF * U """ U_RF only on one side because that's the operator that satisfies the Schroedinger equation in the interaction picture. """ return U_prime
def correct_reference(U, w_q1, w_q0, t): # w_qi should be a frequency (not including the 2*pi factor). Moreover they and t should be in the same scale. # this functions should be used just to make sanity checks. phase_to_correct_q1 = w_q1 * (2 * np.pi) * t phase_to_correct_q0 = w_q0 * (2 * np.pi) * t Ucorrection = qtp.Qobj( [[1, 0, 0, 0, 0, 0, 0, 0, 0], [0, np.exp(1j * phase_to_correct_q0), 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, np.exp(1j * phase_to_correct_q1), 0, 0, 0, 0, 0], [ 0, 0, 0, 0, np.exp(1j * (phase_to_correct_q0 + phase_to_correct_q1)), 0, 0, 0, 0 ], [0, 0, 0, 0, 0, np.exp(1j * phase_to_correct_q1), 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, np.exp(1j * phase_to_correct_q0), 0], [0, 0, 0, 0, 0, 0, 0, 0, 1]], type='oper', dims=[[3, 3], [3, 3]]) if U.type == 'oper': return Ucorrection * U elif U.type == 'super': return qtp.to_super(Ucorrection) * U
def rotating_frame_transformation(U, t: float, w_q0: float = 0, w_q1: float = 0): """ Transforms the frame of the unitary according to U' = U_{RF}*U NOTE: remember that this is how the time evolution operator changes from one picture to another with U_{RF} = e^{-i w_q0 a^dag a t } otimes e^{-i w_q1 b^dag b t } (method for the case where we are simply rotating away the two qubit frequencies) Args: U (QObj): Unitary to be transformed t (float): time at which to transform w_q0 (float): freq of frame for q0 w_q1 (float): freq of frame for q1 """ logging.warning( 'Recommended to use rotating_frame_transformation_new passing the hamiltonian as an argument.' ) U_RF = (1j * w_q0 * n_q0 * t).expm() * (1j * w_q1 * n_q1 * t).expm() if U.type == 'super': U_RF = qtp.to_super(U_RF) U_prime = U_RF * U """ U_RF only on one side because that's the operator that satisfies the Schroedinger equation in the interaction picture. """ return U_prime
class TestTypeFromDims: @pytest.mark.parametrize(["base", "expected", "enforce_square"], [ pytest.param([[2], [2]], 'oper', True), pytest.param([[2, 3], [2, 3]], 'oper', True), pytest.param([[2], [3]], 'other', True), pytest.param([[2], [3]], 'oper', False), pytest.param([[2], [1]], 'ket', True), pytest.param([[1], [2]], 'bra', True), pytest.param([[[2, 3], [2, 3]], [1]], 'operator-ket', True), pytest.param([[1], [[2, 3], [2, 3]]], 'operator-bra', True), pytest.param([[[3], [3]], [[2, 3], [2, 3]]], 'other', True), pytest.param([[[3], [3]], [[2, 3], [2, 3]]], 'super', False), pytest.param([[[2], [3, 3]], [[3], [2, 3]]], 'other', True), ]) def test_type_from_dims(self, base, expected, enforce_square): assert type_from_dims(base, enforce_square=enforce_square) == expected @pytest.mark.parametrize("qobj", [ pytest.param(qutip.rand_ket(10), id='ket'), pytest.param(qutip.rand_ket(10).dag(), id='bra'), pytest.param(qutip.rand_dm(10), id='oper'), pytest.param(qutip.to_super(qutip.rand_dm(10)), id='super'), ]) def test_qobj_dims_match_qobj(self, qobj): assert type_from_dims(qobj.dims) == qobj.type
class Test_unitarity: @pytest.mark.parametrize(['operator', 'expected'], [ pytest.param(to_super(sigmax()), 1, id="sigmax"), pytest.param(0.25 * sum(to_super(x) for x in paulis), 0, id="paulis"), pytest.param(0.5 * (to_super(qeye(2)) + to_super(sigmax())), 1 / 3, id="id+sigmax"), ]) def test_known_cases(self, operator, expected): assert unitarity(operator) == pytest.approx(expected, abs=1e-7) @pytest.mark.parametrize('n_qubits', [1, 2, 3, 4, 5]) def test_bounded(self, n_qubits): tol = 1e-7 operator = rand_super_bcsz(2**n_qubits) assert -tol <= unitarity(operator) <= 1 + tol
def pro_avfid_superoperator_phasecorrected(U,phases): """ Average process (gate) fidelity in the whole space for a qubit and qutrit Qubit Z rotation and qutrit "Z" rotations are applied, taking into account the anharmonicity as well """ Ucorrection = qtp.Qobj([[np.exp(-1j*np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0, 0, 0], [0, np.exp(-1j*np.deg2rad(phases[1])), 0, 0, 0, 0, 0, 0, 0], [0, 0, np.exp(-1j*np.deg2rad(phases[4]-phases[-1])), 0, 0, 0, 0, 0, 0], [0, 0, 0, np.exp(-1j*np.deg2rad(phases[2])), 0, 0, 0, 0, 0], [0, 0, 0, 0, np.exp(-1j*np.deg2rad(phases[3]-phases[-1])), 0, 0, 0, 0], [0, 0, 0, 0, 0, np.exp(-1j*np.deg2rad(phases[4]-phases[-1]+phases[2]-phases[0])), 0, 0, 0], [0, 0, 0, 0, 0, 0, np.exp(-1j*np.deg2rad(phases[5])), 0, 0], [0, 0, 0, 0, 0, 0, 0, np.exp(-1j*np.deg2rad(phases[5]+phases[1]-phases[0])), 0], [0, 0, 0, 0, 0, 0, 0, 0, np.exp(-1j*np.deg2rad(phases[4]-phases[-1]+phases[5]-phases[0]))]], type='oper', dims=[[3, 3], [3, 3]]) if U.type=='oper': U=Ucorrection*U ptrace = np.abs((U.dag()*U_target).tr())**2 dim = 9 # dimension of the whole space return np.real((ptrace+dim)/(dim*(dim+1))) elif U.type=='super': U=qtp.to_super(Ucorrection)*U return np.real(qtp.average_gate_fidelity(U,target=U_target_diffdims))
def transform_basis(C, S): # C (operator or superoperator) # S: matrix change of basis if C.type == 'oper': return S.dag() * C * S elif C.type == 'super': S = qtp.to_super(S) return S.dag() * C * S
def pro_avfid_superoperator_compsubspace_phasecorrected(U, L1, phases): """ Average process (gate) fidelity in the qubit computational subspace for two qutrits Leakage has to be taken into account, see Woods & Gambetta The phase is corrected with Z rotations considering both transmons as qubits. The correction is done perfectly. The function assumes that the computational subspace (:= the 4 energy levels chosen as the two qubits) is given by the standard basis |0> /otimes |0>, |0> /otimes |1>, |1> /otimes |0>, |1> /otimes |1>. If this is not the case, one need to change the basis to that one, before calling this function. """ Ucorrection = qtp.Qobj( [[np.exp(-1j * np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0, 0, 0], [0, np.exp(-1j * np.deg2rad(phases[1])), 0, 0, 0, 0, 0, 0, 0], [0, 0, np.exp(-1j * np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0], [0, 0, 0, np.exp(-1j * np.deg2rad(phases[2])), 0, 0, 0, 0, 0], [ 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[3] - phases[-1])), 0, 0, 0, 0 ], [0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[2])), 0, 0, 0], [0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[0])), 0, 0], [0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[1])), 0], [0, 0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[0]))]], type='oper', dims=[[3, 3], [3, 3]]) if U.type == 'oper': U = Ucorrection * U inner = U.dag() * U_target part_idx = [0, 1, 3, 4] # only computational subspace ptrace = 0 for i in part_idx: ptrace += inner[i, i] dim = 4 # 2 qubits comp subspace return np.real( ((np.abs(ptrace))**2 + dim * (1 - L1)) / (dim * (dim + 1))) elif U.type == 'super': U = qtp.to_super(Ucorrection) * U kraus_form = qtp.to_kraus(U) dim = 4 # 2 qubits in the computational subspace part_idx = [0, 1, 3, 4] # only computational subspace psum = 0 for A_k in kraus_form: ptrace = 0 inner = U_target_diffdims.dag( ) * A_k # otherwise dimension mismatch for i in part_idx: ptrace += inner[i, i] psum += (np.abs(ptrace))**2 return np.real((dim * (1 - L1) + psum) / (dim * (dim + 1)))
def time_series(U_final_vec_timeseries, S, weights, repetitions, samplingpoints_gaussian_q0, axis_overrotation): trace_PTM_vec = [] trace_GTM_vec = [] for n_rep in range(repetitions): print(n_rep) U_final_vec = np.copy(U_final_vec_timeseries) for i in range(len(U_final_vec)): if U_final_vec[i].type == 'oper': U_final_vec[i] = qtp.to_super( U_final_vec[i] ) # weighted averaging needs to be done for superoperators over_rot = czf.qubit_to_2qutrit_unitary( czf.bloch_sphere_rotation(samplingpoints_gaussian_q0[i], axis_overrotation), 'right') U_final_vec[i] = qtp.to_super(over_rot) * U_final_vec[i] U_final_vec[i] = U_final_vec[i]**n_rep U_final_vec[i] = U_final_vec[i] * weights[i] U_superop_average = np.sum( np.array(U_final_vec)) # computing resulting average propagator #print(czf.verify_CPTP(U_superop_average)) U_superop_average = czf.correct_phases(U_superop_average) U_superop_average = transform_basis(U_superop_average, S.dag()) GTM = get_PTM_or_GTM(U_superop_average, 'GTM') PTM = get_PTM_or_GTM(U_superop_average, 'PTM') T_GTM = extract_T_matrix(GTM) T_PTM = extract_T_matrix(PTM) trace_PTM = np.trace(T_PTM) trace_GTM = np.trace(T_GTM) trace_GTM_vec.append(trace_GTM) trace_PTM_vec.append(trace_PTM) return trace_GTM_vec, trace_PTM_vec
def test_reshuffle(self): U1 = rand_unitary(2) U2 = rand_unitary(3) U3 = rand_unitary(4) U = tensor(U1, U2, U3) S = to_super(U) S_col = reshuffle(S) assert_equal(S_col.dims[0], [[2, 2], [3, 3], [4, 4]]) assert_(reshuffle(S_col) == S)
def calc_populations(U): hadamard_singleq = qtp.Qobj([[1, 1, 0], [1, -1, 0], [0, 0, 0] ]) / np.sqrt(2) hadamard_q0 = qtp.tensor(qtp.qeye(3), hadamard_singleq) if U.type == 'oper': U_pi2_pulsed = hadamard_q0 * U * hadamard_q0 populations = { 'population_in_0': np.abs(U_pi2_pulsed[0, 0])**2, 'population_in_1': np.abs(U_pi2_pulsed[0, 1])**2 } elif U.type == 'super': U_pi2_pulsed = qtp.to_super(hadamard_q0) * U * qtp.to_super( hadamard_q0) populations = { 'population_in_0': np.real(U_pi2_pulsed[0, 0]), 'population_in_1': np.real(U_pi2_pulsed[0, 10]) } return populations
def pro_avfid_superoperator_compsubspace_phasecorrected(U, L1, phases): """ Average process (gate) fidelity in the qubit computational subspace for two qutrits Leakage has to be taken into account, see Woods & Gambetta The phase is corrected with Z rotations considering both transmons as qubits """ Ucorrection = qtp.Qobj( [[np.exp(-1j * np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0, 0, 0], [0, np.exp(-1j * np.deg2rad(phases[1])), 0, 0, 0, 0, 0, 0, 0], [0, 0, np.exp(-1j * np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0], [0, 0, 0, np.exp(-1j * np.deg2rad(phases[2])), 0, 0, 0, 0, 0], [ 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[3] - phases[-1])), 0, 0, 0, 0 ], [0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[2])), 0, 0, 0], [0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[0])), 0, 0], [0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[1])), 0], [0, 0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[0]))]], type='oper', dims=[[3, 3], [3, 3]]) if U.type == 'oper': U = Ucorrection * U inner = U.dag() * U_target part_idx = [0, 1, 3, 4] # only computational subspace ptrace = 0 for i in part_idx: ptrace += inner[i, i] dim = 4 # 2 qubits comp subspace return np.real( ((np.abs(ptrace))**2 + dim * (1 - L1)) / (dim * (dim + 1))) elif U.type == 'super': U = qtp.to_super(Ucorrection) * U kraus_form = qtp.to_kraus(U) dim = 4 # 2 qubits in the computational subspace part_idx = [0, 1, 3, 4] # only computational subspace psum = 0 for A_k in kraus_form: ptrace = 0 inner = U_target_diffdims.dag( ) * A_k # otherwise dimension mismatch for i in part_idx: ptrace += inner[i, i] psum += (np.abs(ptrace))**2 return np.real((dim * (1 - L1) + psum) / (dim * (dim + 1)))
def pro_avfid_superoperator_phasecorrected(U, phases): """ Average process (gate) fidelity in the whole space for two qutrits Qubit Z rotation and qutrit "Z" rotations are applied, taking into account the anharmonicity as well. The function assumes that the computational subspace (:= the 4 energy levels chosen as the two qubits) is given by the standard basis |0> /otimes |0>, |0> /otimes |1>, |1> /otimes |0>, |1> /otimes |1>. If this is not the case, one need to change the basis to that one, before calling this function. This function is quite useless because we are always interested in the computational subspace only. """ Ucorrection = qtp.Qobj( [[np.exp(-1j * np.deg2rad(phases[0])), 0, 0, 0, 0, 0, 0, 0, 0], [0, np.exp(-1j * np.deg2rad(phases[1])), 0, 0, 0, 0, 0, 0, 0], [ 0, 0, np.exp(-1j * np.deg2rad(phases[4] - phases[-1])), 0, 0, 0, 0, 0, 0 ], [0, 0, 0, np.exp(-1j * np.deg2rad(phases[2])), 0, 0, 0, 0, 0], [ 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[3] - phases[-1])), 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, np.exp( -1j * np.deg2rad(phases[4] - phases[-1] + phases[2] - phases[0])), 0, 0, 0 ], [0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[5])), 0, 0], [ 0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[5] + phases[1] - phases[0])), 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, np.exp(-1j * np.deg2rad(phases[4] - phases[-1] + phases[5] - phases[0])) ]], type='oper', dims=[[3, 3], [3, 3]]) if U.type == 'oper': U = Ucorrection * U ptrace = np.abs((U.dag() * U_target).tr())**2 dim = 9 # dimension of the whole space return np.real((ptrace + dim) / (dim * (dim + 1))) elif U.type == 'super': U = qtp.to_super(Ucorrection) * U return np.real(qtp.average_gate_fidelity(U, target=U_target_diffdims))
def verify_phicond( U ): # benchmark to check that cond phase is computed correctly. Benchmark succeeded # superoperator case if U.type == 'oper': U = qtp.to_super(U) def calc_phi(U, list): # lists of 4 matrix elements 0 or 1 number = 3 * list[0] + list[1] + list[2] * 27 + list[3] * 9 phase = np.rad2deg(np.angle(U[number, number])) return phase phi_01 = calc_phi(U, [0, 1, 0, 0]) phi_10 = calc_phi(U, [1, 0, 0, 0]) phi_11 = calc_phi(U, [1, 1, 0, 0]) phi_cond = (phi_11 - phi_01 - phi_10) % 360 print(phi_cond) phi_01 = -calc_phi(U, [0, 0, 0, 1]) phi_10 = calc_phi(U, [1, 0, 0, 1]) phi_11 = calc_phi(U, [1, 1, 0, 1]) phi_cond = (phi_11 - phi_01 - phi_10) % 360 print(phi_cond) phi_01 = -calc_phi(U, [0, 0, 1, 0]) phi_10 = calc_phi(U, [0, 1, 1, 0]) phi_11 = calc_phi(U, [1, 1, 1, 0]) phi_cond = (phi_11 - phi_01 - phi_10) % 360 print(phi_cond) phi_01 = -calc_phi(U, [0, 0, 1, 1]) phi_10 = calc_phi(U, [0, 1, 1, 1]) phi_11 = -calc_phi(U, [1, 0, 1, 1]) phi_cond = (phi_11 - phi_01 - phi_10) % 360 print(phi_cond) return phi_cond
def state_twirl(N): square = itertools.product(range(-N, N + 1, 1), range(-N, N + 1, 1)) Twirl = sum(Prob(n, m, N) * qt.to_super(Disp(n, m)) for n, m in square) return Twirl
def chan_twirl(S, N): square = itertools.product(range(-N, N + 1, 1), range(-N, N + 1, 1)) Twirled = sum( Prob(n, m, N) * qt.to_super(Disp(-n, -m)) * S * qt.to_super(Disp(n, m)) for n, m in square) return Twirled
Hq2_t_ind = qt.tensor(Iq1, rot2) #Hq2_rot(constant term) Hq2_t_dep = qt.tensor(Iq1, q2Freqs) #Hq2_rot(modulation term) Hint = QQ.Hint12 * (2 * pi) H_rot = [Hq1_lab + Hq2_t_ind + Hint, [Hq2_t_dep, MW_shaped]] tgstart = 48 tgend = 48 for gt in range(tgstart, tgend + 1): pulsesystem = CZpulse(Q1, Q2, g, the_f=0.88, lambda2=0.13, gatetime=gt) tg = pulsesystem.tg t_list, adiabaticpulse = pulsesystem.netzeropulse() degeneracy_freq = pulsesystem.qFreq20 args = {'mwamp': 1.0, 'shape': adiabaticpulse} #res = qt.sesolve(H_rot, ini_state, t_list, e_ops=[], args=args, options=opts, progress_bar=None) _res = qt.propagator(H_rot, t_list, e_ops=[], args=args, options=opts, progress_bar=None) res = [] for i in range(len(_res)): sp = qt.to_super(_res[i]) res.append(sp) res = np.array(res) print(len(res)) print(res[1].dims) print(res[1].shape)
def acquire_data_point(self, **kw): ### Extract relevant parameters to recreate the instrument locally (necessary for parallelization since intruments cannot be pickled) fluxlutman_args = { 'sampling_rate': self.fluxlutman.sampling_rate(), 'cz_length': self.fluxlutman.cz_length(), 'q_J2': self.fluxlutman.q_J2(), 'czd_double_sided': self.fluxlutman.czd_double_sided(), 'cz_lambda_2': self.fluxlutman.cz_lambda_2(), 'cz_lambda_3': self.fluxlutman.cz_lambda_3(), 'cz_theta_f': self.fluxlutman.cz_theta_f(), 'czd_length_ratio': self.fluxlutman.czd_length_ratio(), 'q_polycoeffs_freq_01_det': self.fluxlutman.q_polycoeffs_freq_01_det(), 'q_polycoeffs_anharm': self.fluxlutman.q_polycoeffs_anharm(), 'q_freq_01': self.fluxlutman.q_freq_01(), 'q_freq_10': self.fluxlutman.q_freq_10() } noise_parameters_CZ_args = { 'Z_rotations_length': self.noise_parameters_CZ.Z_rotations_length(), 'voltage_scaling_factor': self.noise_parameters_CZ.voltage_scaling_factor(), 'distortions': self.noise_parameters_CZ.distortions(), 'T1_q0': self.noise_parameters_CZ.T1_q0(), 'T1_q1': self.noise_parameters_CZ.T1_q1(), 'T2_q0_amplitude_dependent': self.noise_parameters_CZ.T2_q0_amplitude_dependent(), 'T2_q1': self.noise_parameters_CZ.T2_q1(), 'w_q1_sweetspot': self.noise_parameters_CZ.w_q1_sweetspot(), 'alpha_q1': self.noise_parameters_CZ.alpha_q1(), 'w_bus': self.noise_parameters_CZ.w_bus(), 'dressed_compsub': self.noise_parameters_CZ.dressed_compsub(), 'sigma_q0': self.noise_parameters_CZ.sigma_q0(), 'sigma_q1': self.noise_parameters_CZ.sigma_q1(), 'T2_scaling': self.noise_parameters_CZ.T2_scaling() } ### Discretize average (integral) over a Gaussian distribution mean = 0 sigma_q0 = self.noise_parameters_CZ.sigma_q0() sigma_q1 = self.noise_parameters_CZ.sigma_q1( ) # one for each qubit, in units of Phi_0 # 4e-6 is the same value as in the surface-17 paper of tom&brian. We see that 25 reproduces the T_phi^quasi-static for a Ramsey exp. qoi_plot = [ ] # used to verify convergence properties. If len(n_sampling_gaussian_vec)==1, it is useless n_sampling_gaussian_vec = self.noise_parameters_CZ.n_sampling_gaussian_vec( ) # 11 guarantees excellent convergence. # We choose it odd so that the central point of the Gaussian is included. # ALWAYS choose it odd for n_sampling_gaussian in n_sampling_gaussian_vec: # If sigma=0 there's no need for sampling if sigma_q0 != 0: samplingpoints_gaussian_q0 = np.linspace( -5 * sigma_q0, 5 * sigma_q0, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q0 = samplingpoints_gaussian_q0[ 1] - samplingpoints_gaussian_q0[0] values_gaussian_q0 = czf.gaussian(samplingpoints_gaussian_q0, mean, sigma_q0) else: samplingpoints_gaussian_q0 = np.array([0]) delta_x_q0 = 1 values_gaussian_q0 = np.array([1]) if sigma_q1 != 0: samplingpoints_gaussian_q1 = np.linspace( -5 * sigma_q1, 5 * sigma_q1, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q1 = samplingpoints_gaussian_q1[ 1] - samplingpoints_gaussian_q1[0] values_gaussian_q1 = czf.gaussian(samplingpoints_gaussian_q1, mean, sigma_q1) else: samplingpoints_gaussian_q1 = np.array([0]) delta_x_q1 = 1 values_gaussian_q1 = np.array([1]) input_to_parallelize = [] weights = [] number = -1 # used to number instruments that are created in the parallelization, to avoid conflicts for j_q0 in range(len(samplingpoints_gaussian_q0)): fluxbias_q0 = samplingpoints_gaussian_q0[ j_q0] # q0 fluxing qubit for j_q1 in range(len(samplingpoints_gaussian_q1)): fluxbias_q1 = samplingpoints_gaussian_q1[ j_q1] # q1 spectator qubit number = number + 1 if self.noise_parameters_CZ.cluster(): input_point = { 'fluxbias_q0': fluxbias_q0, # need to pass it like this to the cluster 'fluxbias_q1': fluxbias_q1, 'fluxlutman_args': fluxlutman_args, 'noise_parameters_CZ_args': noise_parameters_CZ_args, 'fitted_stepresponse_ty': self.fitted_stepresponse_ty, 'number': number, 'cluster': self.noise_parameters_CZ.cluster() } else: input_point = { 'fluxbias_q0': fluxbias_q0, # need to pass it like this to the cluster 'fluxbias_q1': fluxbias_q1, 'fluxlutman': self.fluxlutman, 'noise_parameters_CZ': self.noise_parameters_CZ, 'fitted_stepresponse_ty': self.fitted_stepresponse_ty, 'number': number, 'cluster': self.noise_parameters_CZ.cluster() } weight = values_gaussian_q0[ j_q0] * delta_x_q0 * values_gaussian_q1[ j_q1] * delta_x_q1 weights.append(weight) input_to_parallelize.append(input_point) if self.noise_parameters_CZ.cluster(): y_list_of_lists = map_jobqueue_repeat( compute_propagator_parallelizable, input_to_parallelize ) # function defined in notebook cluster y_list_of_lists = np.array(y_list_of_lists) U_final_vec = y_list_of_lists[:, 0] t_final_vec = y_list_of_lists[:, 1] else: U_final_vec = [] t_final_vec = [] for input_arglist in input_to_parallelize: result_list = compute_propagator_parallelizable( input_arglist) U_final_vec.append(result_list[0]) t_final_vec.append(result_list[1]) for i in range(len(U_final_vec)): if U_final_vec[i].type == 'oper': U_final_vec[i] = qtp.to_super( U_final_vec[i] ) # weighted averaging needs to be done for superoperators U_final_vec[i] = U_final_vec[i] * weights[i] U_superop_average = np.sum(np.array( U_final_vec)) # computing resulting average propagator #print(czf.verify_CPTP(U_superop_average)) t_final = t_final_vec[ 0] # equal for all entries, we need it to compute phases in the rotating frame w_q0, w_q1 = czf.dressed_frequencies( self.fluxlutman, self.noise_parameters_CZ ) # needed to compute phases in the rotating frame qoi = czf.simulate_quantities_of_interest_superoperator_new( U=U_superop_average, t_final=t_final, w_q0=w_q0, w_q1=w_q1) if self.noise_parameters_CZ.look_for_minimum( ): # if we look only for the minimum avgatefid_pc in the heat maps, # then we optimize the search via higher-order cost function cost_func_val = ( -np.log10(1 - qoi['avgatefid_compsubspace_pc']))**4 else: cost_func_val = ( -np.log10(1 - qoi['avgatefid_compsubspace_pc'])) quantities_of_interest = [ cost_func_val, qoi['phi_cond'], qoi['L1'] * 100, qoi['L2'] * 100, qoi['avgatefid_pc'] * 100, qoi['avgatefid_compsubspace_pc'] * 100, qoi['phase_q0'], qoi['phase_q1'], qoi['avgatefid_compsubspace'] * 100, qoi['avgatefid_compsubspace_pc_onlystaticqubit'] * 100, qoi['population_02_state'] * 100 ] qoi_vec = np.array(quantities_of_interest) qoi_plot.append(qoi_vec) qoi_plot = np.array(qoi_plot) ## Plot to study the convergence properties of averaging over a Gaussian # for i in range(len(qoi_plot[0])): # czf.plot(x_plot_vec=[n_sampling_gaussian_vec], # y_plot_vec=[qoi_plot[:,i]], # title='Study of convergence of average', # xlabel='n_sampling_gaussian points',ylabel=self.value_names[i]) return qoi_plot[0,0], qoi_plot[0,1], qoi_plot[0,2], qoi_plot[0,3], qoi_plot[0,4], qoi_plot[0,5], qoi_plot[0,6], \ qoi_plot[0,7], qoi_plot[0,8], qoi_plot[0,9], qoi_plot[0,10]
def acquire_data_point(self, **kw): ramsey = self.control_parameters_ramsey.ramsey( ) # True for Ram-Z, False for Echo-Z sigma = self.control_parameters_ramsey.sigma( ) # width of the Gaussian distribution of the fluxbias detuning = self.control_parameters_ramsey.detuning_ramsey( ) # how much the freq of q0 is offset from the sweetspot t = self.control_parameters_ramsey.pulse_length( ) # separation time between the two pi/2 pulses qoi_plot = list( ) # used to verify convergence properties. If len(n_sampling_gaussian_vec)==1, it is useless n_sampling_gaussian_vec = [ 101 ] # 11 guarantees excellent convergence. We choose it odd so that the central point of the Gaussian is included. # ALWAYS choose it odd for n_sampling_gaussian in n_sampling_gaussian_vec: # If sigma=0 there's no need for sampling weights = [] if sigma != 0: samplingpoints_gaussian = np.linspace( -5 * sigma, 5 * sigma, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x = samplingpoints_gaussian[1] - samplingpoints_gaussian[ 0] values_gaussian = czu.gaussian(samplingpoints_gaussian, mean=0, sigma=sigma) else: samplingpoints_gaussian = np.array([0]) delta_x = 1 values_gaussian = np.array([1]) U_final_vec = list() for j_q0 in range(len(samplingpoints_gaussian)): fluxbias_q0 = samplingpoints_gaussian[j_q0] if sigma != 0: weight = values_gaussian[j_q0] * delta_x weights.append(weight) else: weight = 1 weights.append(weight) f_q0_sweetspot = self.fluxlutman.q_freq_01() f_q0_detuned = f_q0_sweetspot + detuning H = [] if ramsey: # the freq shift takes a different sign at first order on the two sides of Echo-Z positive = [True] else: positive = [True, False] for pos in positive: f_q0_biased = freq_shift_from_fluxbias(f_q0_detuned, f_q0_sweetspot, fluxbias_q0, positive_arc=pos) freq_rotating_frame_detuned = f_q0_biased - f_q0_sweetspot - detuning H.append( czu.coupled_transmons_hamiltonian_new( w_q0=freq_rotating_frame_detuned, w_q1=0, alpha_q0=-2 * freq_rotating_frame_detuned, alpha_q1=0, J=0)) # convenient way of getting the uncpupled Hamiltonian for one qubit sim_step = t / len(positive) c_ops = [] U_final = time_evolution(H, c_ops, sim_step) if U_final.type == 'oper': U_final = qtp.to_super(U_final) U_final_vec.append(U_final * weight) weights = np.array(weights) U_superop_average = np.sum( np.array(U_final_vec)) # computing resulting superoperator qoi = calc_populations(U_superop_average) quantities_of_interest = [ qoi['population_in_0'] * 100, qoi['population_in_1'] * 100 ] qoi_vec = np.array(quantities_of_interest) qoi_plot.append(qoi_vec) qoi_plot = np.array(qoi_plot) ### Plot to study the convergence properties of averaging over a Gaussian # for i in range(len(qoi_plot[0])): # czu.plot(x_plot_vec=[n_sampling_gaussian_vec], # y_plot_vec=[qoi_plot[:,i]], # title='Study of convergence of average', # xlabel='n_sampling_gaussian points',ylabel=self.value_names[i]) return qoi_plot[0, 0], qoi_plot[0, 1]
def overrotation(x): return to_super((1j * np.pi * x * sigmax() / 2).expm())
def acquire_data_point(self, **kw): #czf.plot_spectrum(fluxlutman=self.fluxlutman,noise_parameters_CZ=self.noise_parameters_CZ) ### Discretize average (integral) over a Gaussian distribution mean = 0 sigma_q0 = self.noise_parameters_CZ.sigma_q0() sigma_q1 = self.noise_parameters_CZ.sigma_q1() # one for each qubit, in units of Phi_0 # 4e-6 is the same value as in the surface-17 paper of tom&brian. We see that 25 reproduces the T_phi^quasi-static for a Ramsey exp. qoi_plot = [] # used to verify convergence properties. If len(n_sampling_gaussian_vec)==1, it is useless n_sampling_gaussian_vec = self.noise_parameters_CZ.n_sampling_gaussian_vec() # 11 guarantees excellent convergence. # We choose it odd so that the central point of the Gaussian is included. # ALWAYS choose it odd for n_sampling_gaussian in n_sampling_gaussian_vec: # If sigma=0 there's no need for sampling if sigma_q0 != 0: samplingpoints_gaussian_q0 = np.linspace(-5*sigma_q0,5*sigma_q0,n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q0 = samplingpoints_gaussian_q0[1]-samplingpoints_gaussian_q0[0] values_gaussian_q0 = czf.gaussian(samplingpoints_gaussian_q0,mean,sigma_q0) else: samplingpoints_gaussian_q0 = np.array([0]) delta_x_q0 = 1 values_gaussian_q0 = np.array([1]) if sigma_q1 != 0: samplingpoints_gaussian_q1 = np.linspace(-5*sigma_q1,5*sigma_q1,n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q1 = samplingpoints_gaussian_q1[1]-samplingpoints_gaussian_q1[0] values_gaussian_q1 = czf.gaussian(samplingpoints_gaussian_q1,mean,sigma_q1) else: samplingpoints_gaussian_q1 = np.array([0]) delta_x_q1 = 1 values_gaussian_q1 = np.array([1]) input_to_parallelize = [] weights=[] number=-1 # used to number instruments that are created in the parallelization, to avoid conflicts for j_q0 in range(len(samplingpoints_gaussian_q0)): fluxbias_q0 = samplingpoints_gaussian_q0[j_q0] # q0 fluxing qubit for j_q1 in range(len(samplingpoints_gaussian_q1)): fluxbias_q1 = samplingpoints_gaussian_q1[j_q1] # q1 spectator qubit input_point = {'fluxbias_q0': fluxbias_q0, # need to pass it like this to the cluster 'fluxbias_q1': fluxbias_q1, 'fluxlutman': self.fluxlutman, 'noise_parameters_CZ': self.noise_parameters_CZ, 'fitted_stepresponse_ty': self.fitted_stepresponse_ty} weight = values_gaussian_q0[j_q0]*delta_x_q0 * values_gaussian_q1[j_q1]*delta_x_q1 weights.append(weight) input_to_parallelize.append(input_point) U_final_vec = [] t_final_vec = [] for input_arglist in input_to_parallelize: result_list = compute_propagator(input_arglist) U_final_vec.append(result_list[0]) t_final_vec.append(result_list[1]) for i in range(len(U_final_vec)): if U_final_vec[i].type == 'oper': U_final_vec[i] = qtp.to_super(U_final_vec[i]) # weighted averaging needs to be done for superoperators U_final_vec[i] = U_final_vec[i] * weights[i] U_superop_average = np.sum(np.array(U_final_vec)) # computing resulting average propagator #print(czf.verify_CPTP(U_superop_average)) t_final = t_final_vec[0] # equal for all entries, we need it to compute phases in the rotating frame w_q0, w_q1, alpha_q0 = czf.dressed_frequencies(self.fluxlutman, self.noise_parameters_CZ) # needed to compute phases in the rotating frame qoi = czf.quantities_of_interest_ramsey(U=U_superop_average,initial_state=self.noise_parameters_CZ.initial_state(),fluxlutman=self.fluxlutman,noise_parameters_CZ=self.noise_parameters_CZ) quantities_of_interest = [qoi['population_higher_state'], qoi['population_lower_state']] qoi_vec=np.array(quantities_of_interest) qoi_plot.append(qoi_vec) qoi_plot = np.array(qoi_plot) ## Uncomment to study the convergence properties of averaging over a Gaussian # for i in range(len(qoi_plot[0])): # czf.plot(x_plot_vec=[n_sampling_gaussian_vec], # y_plot_vec=[qoi_plot[:,i]], # title='Study of convergence of average', # xlabel='n_sampling_gaussian points',ylabel=self.value_names[i]) return qoi_plot[0,0], qoi_plot[0,1]
def test_unitaries_equal_1(self, dimension): """Tests that for random unitaries U, AGF(U, U) = 1.""" tol = 1e-7 U = rand_unitary_haar(dimension) SU = to_super(U) assert average_gate_fidelity(SU, target=U) == pytest.approx(1, abs=tol)
def acquire_data_point(self, **kw): ### Discretize average (integral) over a Gaussian distribution mean = 0 sigma_q0 = self.noise_parameters_CZ.sigma_q0() sigma_q1 = self.noise_parameters_CZ.sigma_q1( ) # one for each qubit, in units of Phi_0 qoi_plot = [ ] # used to verify convergence properties. If len(n_sampling_gaussian_vec)==1, it is useless n_sampling_gaussian_vec = self.noise_parameters_CZ.n_sampling_gaussian_vec( ) # 11 guarantees excellent convergence. # We choose it odd so that the central point of the Gaussian is included. # Always choose it odd for n_sampling_gaussian in n_sampling_gaussian_vec: # If sigma=0 there's no need for sampling if sigma_q0 != 0: samplingpoints_gaussian_q0 = np.linspace( -5 * sigma_q0, 5 * sigma_q0, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q0 = samplingpoints_gaussian_q0[ 1] - samplingpoints_gaussian_q0[0] values_gaussian_q0 = czf.gaussian(samplingpoints_gaussian_q0, mean, sigma_q0) else: samplingpoints_gaussian_q0 = np.array([0]) delta_x_q0 = 1 values_gaussian_q0 = np.array([1]) if sigma_q1 != 0: samplingpoints_gaussian_q1 = np.linspace( -5 * sigma_q1, 5 * sigma_q1, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q1 = samplingpoints_gaussian_q1[ 1] - samplingpoints_gaussian_q1[0] values_gaussian_q1 = czf.gaussian(samplingpoints_gaussian_q1, mean, sigma_q1) else: samplingpoints_gaussian_q1 = np.array([0]) delta_x_q1 = 1 values_gaussian_q1 = np.array([1]) input_to_parallelize = [ ] # This is actually the input that was parallelized in an old version. # Currently it just creates a list that is provided sequentially to compute_propagator weights = [] number = -1 # used to number instruments that are created in the parallelization, to avoid conflicts in the cluster for j_q0 in range(len(samplingpoints_gaussian_q0)): fluxbias_q0 = samplingpoints_gaussian_q0[ j_q0] # q0 fluxing qubit for j_q1 in range(len(samplingpoints_gaussian_q1)): fluxbias_q1 = samplingpoints_gaussian_q1[ j_q1] # q1 spectator qubit input_point = { 'fluxbias_q0': fluxbias_q0, 'fluxbias_q1': fluxbias_q1, 'fluxlutman': self.fluxlutman, 'noise_parameters_CZ': self.noise_parameters_CZ, 'fitted_stepresponse_ty': self.fitted_stepresponse_ty } weight = values_gaussian_q0[ j_q0] * delta_x_q0 * values_gaussian_q1[ j_q1] * delta_x_q1 weights.append(weight) input_to_parallelize.append(input_point) U_final_vec = [] t_final_vec = [] for input_arglist in input_to_parallelize: result_list = compute_propagator(input_arglist) U_final_vec.append(result_list[0]) t_final_vec.append(result_list[1]) t_final = t_final_vec[ 0] # equal for all entries, we need it to compute phases in the rotating frame #w_q0, w_q1, alpha_q0, alpha_q1 = czf.dressed_frequencies(self.fluxlutman, self.noise_parameters_CZ) # needed to compute phases in the rotating frame # not used anymore ## Reproducing Leo's plots of cond_phase and leakage vs. flux offset (I order vs II order) #czf.sensitivity_to_fluxoffsets(U_final_vec,input_to_parallelize,t_final,self.fluxlutman,self.noise_parameters_CZ) for i in range(len(U_final_vec)): if U_final_vec[i].type == 'oper': U_final_vec[i] = qtp.to_super( U_final_vec[i] ) # weighted averaging needs to be done for superoperators U_final_vec[i] = U_final_vec[i] * weights[i] U_superop_average = sum( U_final_vec) # computing resulting average propagator #print(czf.verify_CPTP(U_superop_average)) qoi = czf.simulate_quantities_of_interest_superoperator_new( U=U_superop_average, t_final=t_final, fluxlutman=self.fluxlutman, noise_parameters_CZ=self.noise_parameters_CZ) if self.noise_parameters_CZ.look_for_minimum( ): # if we look only for the minimum avgatefid_pc in the heat maps, # then we optimize the search via higher-order cost function cost_func_val = ( -np.log10(1 - qoi['avgatefid_compsubspace_pc']))**4 else: cost_func_val = ( -np.log10(1 - qoi['avgatefid_compsubspace_pc'])) quantities_of_interest = [ cost_func_val, qoi['phi_cond'], qoi['L1'] * 100, qoi['L2'] * 100, qoi['avgatefid_pc'] * 100, qoi['avgatefid_compsubspace_pc'] * 100, qoi['phase_q0'], qoi['phase_q1'], qoi['avgatefid_compsubspace'] * 100, qoi['avgatefid_compsubspace_pc_onlystaticqubit'] * 100, qoi['population_02_state'] * 100, qoi['cond_phase02'], qoi['coherent_leakage11'] * 100, qoi['offset_difference'] * 100, qoi['missing_fraction'] * 100, qoi['population_transfer_12_21'] * 100, qoi['population_transfer_12_03'] * 100, qoi['phase_diff_12_02'], qoi['phase_diff_21_20'], qoi['cond_phase12'], qoi['cond_phase21'], qoi['cond_phase03'], qoi['cond_phase20'] ] qoi_vec = np.array(quantities_of_interest) qoi_plot.append(qoi_vec) ## To study the effect of the coherence of leakage on repeated CZs (simpler than simulating a full RB experiment): #czf.repeated_CZs_decay_curves(U_superop_average,t_final,self.fluxlutman,self.noise_parameters_CZ) #czf.plot_spectrum(self.fluxlutman,self.noise_parameters_CZ) qoi_plot = np.array(qoi_plot) ## Uncomment to study the convergence properties of averaging over a Gaussian # for i in range(len(qoi_plot[0])): # czf.plot(x_plot_vec=[n_sampling_gaussian_vec], # y_plot_vec=[qoi_plot[:,i]], # title='Study of convergence of average', # xlabel='n_sampling_gaussian points',ylabel=self.value_names[i]) return_values = [qoi_plot[0,0], qoi_plot[0,1], qoi_plot[0,2], qoi_plot[0,3], \ qoi_plot[0,4], qoi_plot[0,5], qoi_plot[0,6], \ qoi_plot[0,7], qoi_plot[0,8], qoi_plot[0,9], qoi_plot[0,10], \ qoi_plot[0,11], qoi_plot[0,12], qoi_plot[0,13], qoi_plot[0,14], qoi_plot[0,15], qoi_plot[0,16], qoi_plot[0,17], qoi_plot[0,18], qoi_plot[0,19], qoi_plot[0,20], qoi_plot[0,21], qoi_plot[0,22]] if self.qois != 'all': return np.array(return_values)[self.qoi_mask] else: return return_values
def had_mixture(x): id_chan = to_choi(qeye(2)) S_eye = to_super(id_chan) S_H = to_super(hadamard_transform()) return (1 - x) * S_eye + x * S_H
[0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1]], type='oper', dims=[[3, 3], [3, 3]]) #U_target._type = 'oper' U_target_diffdims = qtp.Qobj( [[1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, -1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, -1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1]], type='oper', dims=[[9], [9]]) # otherwise average_gate_fidelity doesn't work # if there is noise the target is the corresponding superoperator U_super_target = qtp.to_super(U_target) ''' remember that qutip uses the Liouville (matrix) representation for superoperators, with column stacking. This means that rho_{xy,x'y'}=rho[3*x+y,3*x'+y'] rho_{xy,x'y'}=operator_to_vector(rho)[3*x+y+27*x'+9*y'] VERIFY where xy is the row and x'y' is the column ''' def jump_operators(T1_q0, T1_q1, Tphi_q0_ket0toket0, Tphi_q0_ket1toket1, Tphi_q0_ket2toket2, Tphi_q1_ket0toket0, Tphi_q1_ket1toket1, Tphi_q0_sigmaZ_01, Tphi_q0_sigmaZ_12, Tphi_q0_sigmaZ_02, Tphi_q1_sigmaZ_01, Tphi_q1_sigmaZ_12, Tphi_q1_sigmaZ_02): # time independent case
def acquire_data_point(self, **kw): # Discretize average (integral) over a Gaussian distribution mean_q0 = self.sim_control_CZ.fluxbias_mean() mean_q1 = self.sim_control_CZ.fluxbias_mean_q1() sigma_q0 = self.sim_control_CZ.sigma_q0() sigma_q1 = (self.sim_control_CZ.sigma_q1() ) # one for each qubit, in units of Phi_0 qoi_plot = ( [] ) # used to verify convergence properties. If len(n_sampling_gaussian_vec)==1, it is useless # 11 guarantees excellent convergence. # We choose it odd so that the central point of the Gaussian is included. # Always choose it odd n_sampling_gaussian_vec = self.sim_control_CZ.n_sampling_gaussian_vec() for n_sampling_gaussian in n_sampling_gaussian_vec: # If sigma=0 there's no need for sampling if sigma_q0 != 0: samplingpoints_gaussian_q0 = np.linspace( -5 * sigma_q0 + mean_q0, 5 * sigma_q0 + mean_q0, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q0 = (samplingpoints_gaussian_q0[1] - samplingpoints_gaussian_q0[0]) values_gaussian_q0 = czf_v2.gaussian( samplingpoints_gaussian_q0, mean_q0, sigma_q0) else: samplingpoints_gaussian_q0 = np.array([mean_q0]) delta_x_q0 = 1 values_gaussian_q0 = np.array([1]) if sigma_q1 != 0: samplingpoints_gaussian_q1 = np.linspace( -5 * sigma_q1 + mean_q1, 5 * sigma_q1 + mean_q1, n_sampling_gaussian) # after 5 sigmas we cut the integral delta_x_q1 = (samplingpoints_gaussian_q1[1] - samplingpoints_gaussian_q1[0]) values_gaussian_q1 = czf_v2.gaussian( samplingpoints_gaussian_q1, mean_q1, sigma_q1) else: samplingpoints_gaussian_q1 = np.array([mean_q1]) delta_x_q1 = 1 values_gaussian_q1 = np.array([1]) # This is actually the input that was parallelized in an old version. # Currently it just creates a list that is provided sequentially to compute_propagator input_to_parallelize = [] weights = [] number = ( -1 ) # used to number instruments that are created in the parallelization, to avoid conflicts in the cluster for j_q0 in range(len(samplingpoints_gaussian_q0)): fluxbias_q0 = samplingpoints_gaussian_q0[ j_q0] # q0 fluxing qubit for j_q1 in range(len(samplingpoints_gaussian_q1)): fluxbias_q1 = samplingpoints_gaussian_q1[ j_q1] # q1 spectator qubit input_point = { "fluxbias_q0": fluxbias_q0, "fluxbias_q1": fluxbias_q1, "fluxlutman": self.fluxlutman, "fluxlutman_static": self.fluxlutman_static, "sim_control_CZ": self.sim_control_CZ, "fitted_stepresponse_ty": self.fitted_stepresponse_ty, } weight = (values_gaussian_q0[j_q0] * delta_x_q0 * values_gaussian_q1[j_q1] * delta_x_q1) weights.append(weight) input_to_parallelize.append(input_point) U_final_vec = [] t_final_vec = [] for input_arglist in input_to_parallelize: result_list = compute_propagator(input_arglist) if self.sim_control_CZ.double_cz_pi_pulses() != "": # Experimenting with single qubit ideal pi pulses if self.sim_control_CZ.double_cz_pi_pulses( ) == "with_pi_pulses": pi_single_qubit = qtp.Qobj([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) # pi_pulse = qtp.tensor(pi_single_qubit, qtp.qeye(n_levels_q0)) pi_op = qtp.tensor(pi_single_qubit, pi_single_qubit) # pi_super_op = qtp.to_super(pi_op) U_final = result_list[0] U_final = pi_op * U_final * pi_op * U_final elif self.sim_control_CZ.double_cz_pi_pulses( ) == "no_pi_pulses": U_final = result_list[0] U_final = U_final * U_final t_final = 2 * result_list[1] else: U_final = result_list[0] t_final = result_list[1] U_final_vec.append(U_final) t_final_vec.append(t_final) t_final = t_final_vec[ 0] # equal for all entries, we need it to compute phases in the rotating frame # needed to compute phases in the rotating frame, not used anymore # w_q0, w_q1, alpha_q0, alpha_q1 = czf_v2.dressed_frequencies(self.fluxlutman, self.fluxlutman_static, self.sim_control_CZ, which_gate=self.sim_control_CZ.which_gate()) # Reproducing Leo's plots of cond_phase and leakage vs. flux offset (I order vs II order) # czf_v2.sensitivity_to_fluxoffsets(U_final_vec,input_to_parallelize,t_final,self.fluxlutman,self.fluxlutman_static, which_gate=self.sim_control_CZ.which_gate()) for i in range(len(U_final_vec)): if U_final_vec[i].type == "oper": U_final_vec[i] = qtp.to_super( U_final_vec[i] ) # weighted averaging needs to be done for superoperators U_final_vec[i] = U_final_vec[i] * weights[i] U_superop_average = sum( U_final_vec) # computing resulting average propagator # print(czf_v2.verify_CPTP(U_superop_average)) qoi = czf_v2.simulate_quantities_of_interest_superoperator_new( U=U_superop_average, t_final=t_final, fluxlutman=self.fluxlutman, fluxlutman_static=self.fluxlutman_static, sim_control_CZ=self.sim_control_CZ, which_gate=self.sim_control_CZ.which_gate(), ) # if we look only for the minimum avgatefid_pc in the heat maps, # then we optimize the search via higher-order cost function if self.sim_control_CZ.cost_func() is not None: cost_func_val = self.sim_control_CZ.cost_func()(qoi) elif self.sim_control_CZ.look_for_minimum(): cost_func_val = (np.log10(1 - qoi["avgatefid_compsubspace_pc"]) )**4 # sign removed for even powers else: cost_func_val = -np.log10(1 - qoi["avgatefid_compsubspace_pc"]) quantities_of_interest = [ cost_func_val, qoi["phi_cond"], qoi["L1"] * 100, qoi["L2"] * 100, qoi["avgatefid_pc"] * 100, qoi["avgatefid_compsubspace_pc"] * 100, qoi["phase_q0"], qoi["phase_q1"], qoi["avgatefid_compsubspace"] * 100, qoi["avgatefid_compsubspace_pc_onlystaticqubit"] * 100, qoi["population_02_state"] * 100, qoi["cond_phase02"], qoi["coherent_leakage11"] * 100, qoi["offset_difference"] * 100, qoi["missing_fraction"] * 100, qoi["population_transfer_12_21"] * 100, qoi["population_transfer_12_03"] * 100, qoi["phase_diff_12_02"], qoi["phase_diff_21_20"], qoi["cond_phase12"], qoi["cond_phase21"], qoi["cond_phase03"], qoi["cond_phase20"], self.fluxlutman.get("vcz_amp_sq_{}".format( self.sim_control_CZ.which_gate())), self.fluxlutman.get("vcz_amp_fine_{}".format( self.sim_control_CZ.which_gate())), qoi["population_transfer_01_10"], qoi["population_20_state"] * 100 ] qoi_vec = np.array(quantities_of_interest) qoi_plot.append(qoi_vec) # To study the effect of the coherence of leakage on repeated CZs (simpler than simulating a full RB experiment): # czf_v2.repeated_CZs_decay_curves(U_superop_average,t_final,self.fluxlutman,self.fluxlutman_static, which_gate=self.sim_control_CZ.which_gate()) # czf_v2.plot_spectrum(self.fluxlutman,self.fluxlutman_static, which_gate=self.sim_control_CZ.which_gate()) qoi_plot = np.array(qoi_plot) # Uncomment to study the convergence properties of averaging over a Gaussian # for i in range(len(qoi_plot[0])): # czf_v2.plot(x_plot_vec=[n_sampling_gaussian_vec], # y_plot_vec=[qoi_plot[:,i]], # title='Study of convergence of average', # xlabel='n_sampling_gaussian points',ylabel=self.value_names[i]) return_values = [ qoi_plot[0, 0], qoi_plot[0, 1], qoi_plot[0, 2], qoi_plot[0, 3], qoi_plot[0, 4], qoi_plot[0, 5], qoi_plot[0, 6], qoi_plot[0, 7], qoi_plot[0, 8], qoi_plot[0, 9], qoi_plot[0, 10], qoi_plot[0, 11], qoi_plot[0, 12], qoi_plot[0, 13], qoi_plot[0, 14], qoi_plot[0, 15], qoi_plot[0, 16], qoi_plot[0, 17], qoi_plot[0, 18], qoi_plot[0, 19], qoi_plot[0, 20], qoi_plot[0, 21], qoi_plot[0, 22], qoi_plot[0, 23], qoi_plot[0, 24], qoi_plot[0, 25], qoi_plot[0, 26] ] if self.qois != "all": return np.array(return_values)[self.qoi_mask] else: return return_values
def test_super_operator_creation(to_test): size = 2 implicit = to_test([[size], [size]]) explicit = qutip.to_super(to_test(size)) assert implicit == explicit
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Wed Aug 1 07:06:18 2018 @author: huang """ import qutip as qt import numpy as np X = qt.sigmax() S = qt.spre(X) * qt.spost(X.dag()) # Represents conjugation by X. print(X) print(S) S2 = qt.to_super(X) print(S2) # type of S is super # Check if S is completely positive print(S.iscp)