<jupyter_start><jupyter_text>![qiskit_header.png](attachment:qiskit_header.png)  Calibrating a two-qubit gate<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

from qiskit import IBMQ
import qiskit.pulse as pulse
import qiskit.pulse.pulse_lib as pulse_lib
from qiskit.compiler import assemble
from qiskit.qobj.utils import MeasLevel, MeasReturnType<jupyter_output><empty_output><jupyter_text>In the previous [tutorial](1a_calibrating_a_qubit.ipynb) we demonstrated how to control a single-qubit device with pulse and calibrate a single qubit gate. In this tutorial we will calibrate a two-qubit gate with a cross-resonance pulse using `ibmq_almaden`, a 20 qubit client-only system.<jupyter_code>IBMQ.load_account()
ibmq_provider = IBMQ.get_provider(
    hub='provide_your_hub_name_here',
    group='provide_your_group_name_here',
    project='provide_your_project_name_here'
)
backend = ibmq_provider.get_backend('ibmq_almaden')
config = backend.configuration()
defaults = backend.defaults()<jupyter_output><empty_output><jupyter_text>Measuring CR Rabi oscillationIn this section, we measure cross resonance Rabi oscillation on qubit0 and qubit1. The basic idea of a cross resonance gate is to apply a microwave pulse to the control qubit at the frequency of the target qubit resonance frequency. For more information, see this [paper](https://arxiv.org/abs/1603.04821). As the frequency of the drive channel used in previous experiments is adjusted to be at the resonance frequency of corresponding qubit, a cross resonance pulse must be applied from another channel so that a different frequency may be used for the pulse. This is why we use a control channel (`U channel`) in this experiment.  It should be noted that the role of control channels is not only applying CR pulses, but any possible Hamiltonian term as described in `config.hamiltonian`, and consequently the effect of `ControlChannel` stimulus strongly depends on the design of the specific quantum computing backend.<jupyter_code># qubit to use for exeperiment
control_qubit = 1
target_qubit = 0
control_channel_index = 1

# exp configuration
exps = 30
shots = 512

# Rabi pulse
cr_amps = np.linspace(0, 0.2, exps)
cr_samples = 200
cr_sigma = 4
cr_rise_fall = 16

# scaling factor for data returned by backend
# note: You may have to adjust this for the backend you use
scale_factor= 1e-14<jupyter_output><empty_output><jupyter_text>You can check if your control qubit and target qubit are connected by bus<jupyter_code>[control_qubit, target_qubit] in config.coupling_map<jupyter_output><empty_output><jupyter_text>Usually we use a qubit with higher frequency as a control.<jupyter_code>defaults.qubit_freq_est[control_qubit] > defaults.qubit_freq_est[target_qubit]<jupyter_output><empty_output><jupyter_text>For the above qubit configuration, control channel 0 is available to realize a CR pulse. For other configurations, you can refer to the `InstructionScheduleMap` which may be found in `defaults.circuit_instruction_map` to find the proper control channel index.<jupyter_code>config.u_channel_lo[control_channel_index]<jupyter_output><empty_output><jupyter_text>In this experiment, we use two-pulse echoed CR sequence to eliminate unwanted interactions.<jupyter_code># Create schedule
schedules = []
for ii, cr_amp in enumerate(cr_amps):
    # drive pulse
    cr_rabi_pulse_p = pulse_lib.gaussian_square(duration=cr_samples,
                                                amp=cr_amp,
                                                sigma=cr_sigma,
                                                risefall=cr_rise_fall,
                                                name='cr_rabi_pulse_p%d' % ii)
    cr_rabi_pulse_m = pulse_lib.gaussian_square(duration=cr_samples,
                                                amp=-cr_amp,
                                                sigma=cr_sigma,
                                                risefall=cr_rise_fall,
                                                name='cr_rabi_pulse_m%d' % ii)
    
    control_channel = pulse.ControlChannel(control_channel_index)
    
    # We get the state preparation and measurement pulses we need from the
    # defaults `circuit_instruction_map`
    pi_pulse_q0 = defaults.circuit_instruction_map.get('u3', (control_qubit,), np.pi, 0, np.pi)
    measure = defaults.circuit_instruction_map.get('measure', config.meas_map[0])
    
    # add commands to schedule
    schedule = pulse.Schedule(name='CR Rabi Experiment at drive amp = %s' % cr_amp)
    
    schedule |= cr_rabi_pulse_p(control_channel)
    schedule |= pi_pulse_q0 << schedule.duration
    schedule |= cr_rabi_pulse_m(control_channel) << schedule.duration
    schedule |= measure << schedule.duration
 
    schedules.append(schedule)
schedules[1].draw(channels_to_plot=[pulse.DriveChannel(control_qubit),
                                    pulse.DriveChannel(target_qubit),
                                    control_channel,
                                    pulse.MeasureChannel(control_qubit),
                                    pulse.MeasureChannel(target_qubit)],
                   scaling=10.0, label=False, plot_range=(0, 700))
cr_rabi_qobj = assemble(schedules, backend, meas_level=MeasLevel.KERNELED, 
                        meas_return=MeasReturnType.AVERAGE, shots=shots)
job = backend.run(cr_rabi_qobj)
job.job_id()
job.status()
cr_rabi_result = job.result(timeout=3600)<jupyter_output><empty_output><jupyter_text>Analyze the result<jupyter_code>target_qubit_rabi_data = np.ones(exps, dtype=np.complex_)
control_qubit_rabi_data = np.ones(exps, dtype=np.complex_)

for i in range(exps):
    target_qubit_rabi_data[i] = cr_rabi_result.get_memory(i)[target_qubit]
    control_qubit_rabi_data[i] = cr_rabi_result.get_memory(i)[control_qubit]<jupyter_output><empty_output><jupyter_text>As expected below we can observe the oscillation of the measured signal of only the target qubit.<jupyter_code># auto-phase the output measurement signal

def get_amplitude(vec):
    i_signal = np.imag(vec)
    r_signal = np.real(vec)

    mvec = [np.mean(r_signal), np.mean(i_signal)]

    src_mat = np.vstack((r_signal - mvec[0], i_signal - mvec[1])).T
    (_, _, v_mat) = np.linalg.svd(src_mat)

    dvec = v_mat[0, 0:2]

    if dvec.dot(mvec) < 0:
        dvec = -dvec

    return src_mat.dot(dvec)
target_rabi_amp_data = get_amplitude(target_qubit_rabi_data)*scale_factor
control_rabi_amp_data = get_amplitude(control_qubit_rabi_data)*scale_factor

fit_func = lambda x,A,B,T,phi: (A*np.cos(2*np.pi*x/T+phi)+B)

#Fit the data
fitparams, conv = curve_fit(fit_func, cr_amps, target_rabi_amp_data, [3.0,0.0,0.1,0])

#get the pi amplitude
cr_pi_2_amp = (np.pi-fitparams[3])*fitparams[2]/4/np.pi

plt.plot(cr_amps, fit_func(cr_amps, *fitparams), color='red')
plt.axvline(cr_pi_2_amp, color='black', linestyle='dashed')
plt.scatter(cr_amps, target_rabi_amp_data, label='target qubit')
plt.scatter(cr_amps, control_rabi_amp_data, label='control qubit')
plt.xlim(0, 0.2)
plt.ylim(-5, 5)
plt.legend()
plt.xlabel('CR pulse amplitude, a.u.', fontsize=20)
plt.ylabel('Signal, a.u.', fontsize=20)
plt.title('CR Rabi oscillation', fontsize=20)

print(cr_pi_2_amp)<jupyter_output>0.027191350692821387<jupyter_text>From the fit we obtain the CR Rabi oscillation frequency. We may use this to extract the amplitude of a CR π/2 pulse, which is the foundation of the `cx`(CNOT) gate in our systems. To see the pulse schedule for a `cx` gate look in the `defaults.circuit_instruction_map`<jupyter_code>defaults.circuit_instruction_map.get('cx', (control_qubit, target_qubit)).draw(show_framechange_channels=False)
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08543489449305199, 'fraction_numerical': 0.013252702007205353, 'mean_word_length': 3.9922928709055876, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 41, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '226616', 'license': 'Apache-2.0', 'n_tokens_mistral': 2578, 'n_tokens_neox': 2409, 'n_words': 624, 'path': 'qiskit/advanced/ignis/1b_calibrating_a_two_qubit_gate.ipynb', 'repo_name': 'gvvynplaine/qiskit-iqx-tutorials', 'size': '7772'}