def double_exchange(angle, qubit_pair_1, qubit_pair_2, parity_dependence=False, d_exc_correction=False): assert len(qubit_pair_1) == 2 assert len(qubit_pair_2) == 2 theta_1 = numpy.pi / 2 - angle qasm = [''] # 1st exchange + 0-2 qasm.append(QasmUtils.controlled_xz(qubit_pair_2[0], qubit_pair_1[0])) qasm.append('ry({}) q[{}];\n'.format(theta_1, qubit_pair_2[0])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[0])) qasm.append('ry({}) q[{}];\n'.format(-theta_1, qubit_pair_2[0])) # 2nd exchange + 1-3 qasm.append(QasmUtils.controlled_xz(qubit_pair_2[1], qubit_pair_1[1])) qasm.append('ry({}) q[{}];\n'.format(theta_1, qubit_pair_2[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[1], qubit_pair_2[1])) qasm.append('ry({}) q[{}];\n'.format(-theta_1, qubit_pair_2[1])) # CZ gates qasm.append('cz q[{}], q[{}];\n'.format(qubit_pair_2[0], qubit_pair_2[1])) # qasm.append('cz q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) # correction 3rd order terms approximates the operation of a double exchange if d_exc_correction: angle_2 = DoubleExchange.second_angle(angle) # not correcting 3rd order terms approximates the operation of a double excitation (with 3rd order error terms) else: angle_2 = angle theta_2 = numpy.pi / 2 - angle_2 # 3rd exchange - 0-2 qasm.append('ry({}) q[{}];\n'.format(theta_2, qubit_pair_2[0])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[0])) qasm.append('ry({}) q[{}];\n'.format(-theta_2, qubit_pair_2[0])) qasm.append( QasmUtils.controlled_xz(qubit_pair_2[0], qubit_pair_1[0], reverse=True)) # 4th exchange -1-3 qasm.append('ry({}) q[{}];\n'.format(theta_2, qubit_pair_2[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[1], qubit_pair_2[1])) qasm.append('ry({}) q[{}];\n'.format(-theta_2, qubit_pair_2[1])) qasm.append( QasmUtils.controlled_xz(qubit_pair_2[1], qubit_pair_1[1], reverse=True)) # correcting for parameter sign if parity_dependence: # do not include the first qubit of the second pair parity_qubits = list(range( min(qubit_pair_1), max(qubit_pair_1))) + list( range(min(qubit_pair_2) + 1, max(qubit_pair_2))) # ladder of CNOT used to determine the parity cnot_ladder = [''] for i in range(len(parity_qubits) - 1): cnot_ladder.append('cx q[{}], q[{}];\n'.format( parity_qubits[i], parity_qubits[i + 1])) if angle > 0: # applies a CZ correction in front, to get a negative sign for the excitation term, if the parity is 1 # (or the parity of "parity_qubits" is 0) front = [''] # this is the CZ that determines the sign of the excitation term front.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) # this bit determines the parity and applies a CZ to negate the correction if the parity is wrong front += cnot_ladder front.append('x q[{}];\n'.format(parity_qubits[-1])) front.append('cz q[{}], q[{}];\n'.format( parity_qubits[-1], qubit_pair_2[0])) front.append('x q[{}];\n'.format(parity_qubits[-1])) front += cnot_ladder[::-1] # .. positive sign for the excitation term, if the parity is 0 (or the parity of "parity_qubits" is 1) rear = [''] # .. sign correction rear.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) # .. parity correction rear += cnot_ladder rear.append('cz q[{}], q[{}];\n'.format( parity_qubits[-1], qubit_pair_2[0])) rear += cnot_ladder[::-1] # additional correction of states 010 and 110 rear.append('x q[{}];\n'.format(qubit_pair_2[1])) rear.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) rear.append('x q[{}];\n'.format(qubit_pair_2[1])) qasm = front + qasm + rear else: front = [''] # sign correction front.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) # parity correction front += cnot_ladder front.append('cz q[{}], q[{}];\n'.format( parity_qubits[-1], qubit_pair_2[0])) front += cnot_ladder[::-1] rear = [''] # sign correction rear.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) # parity correction rear += cnot_ladder rear.append('x q[{}];\n'.format(parity_qubits[-1])) rear.append('cz q[{}], q[{}];\n'.format( parity_qubits[-1], qubit_pair_2[0])) rear.append('x q[{}];\n'.format(parity_qubits[-1])) rear += cnot_ladder[::-1] # 010 and 011 correction rear.append('x q[{}];\n'.format(qubit_pair_2[1])) rear.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) rear.append('x q[{}];\n'.format(qubit_pair_2[1])) qasm = front + qasm + rear else: if angle > 0: # adding a correcting CZ gate at the end will result in a minus sign qasm.append('cz q[{}], q[{}];\n'.format( qubit_pair_2[0], qubit_pair_2[1])) # qasm.append('cz q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) else: # adding a correcting CZ gate at the front will result in a plus sign qasm = ['cz q[{}], q[{}];\n'.format(qubit_pair_2[0], qubit_pair_2[1]), ] \ + qasm # 'cz q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1]) return ''.join(qasm)
def efficient_double_excitation_2(angle, qubit_pair_1, qubit_pair_2): qasm = [''] theta = angle / 8 # determine the parity of the two pairs qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_1)) qasm.append('x q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_2)) qasm.append('x q[{}];\n'.format(qubit_pair_2[1])) # apply a partial swap of qubits 0 and 2, controlled by 1 and 3 ## qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[0])) # # partial ccc_y operation qasm.append('rz({}) q[{}];\n'.format(numpy.pi / 2, qubit_pair_1[0])) qasm.append('rx({}) q[{}];\n'.format(theta, qubit_pair_1[0])) # + qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) # 0 1 qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('rx({}) q[{}];\n'.format(-theta, qubit_pair_1[0])) # - qasm.append('h q[{}];\n'.format(qubit_pair_2[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[1])) # 0 3 qasm.append('h q[{}];\n'.format(qubit_pair_2[1])) qasm.append('rx({}) q[{}];\n'.format(theta, qubit_pair_1[0])) # + qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) # 0 1 qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('rx({}) q[{}];\n'.format(-theta, qubit_pair_1[0])) # - qasm.append('h q[{}];\n'.format(qubit_pair_2[0])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[0])) # 0 2 qasm.append('h q[{}];\n'.format(qubit_pair_2[0])) qasm.append('rx({}) q[{}];\n'.format(theta, qubit_pair_1[0])) # + qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) # 0 1 qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('rx({}) q[{}];\n'.format(-theta, qubit_pair_1[0])) # - qasm.append('h q[{}];\n'.format(qubit_pair_2[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[1])) # 0 3 qasm.append('h q[{}];\n'.format(qubit_pair_2[1])) qasm.append('rx({}) q[{}];\n'.format(theta, qubit_pair_1[0])) # + qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_1[1])) # 0 1 qasm.append('h q[{}];\n'.format(qubit_pair_1[1])) qasm.append('rx({}) q[{}];\n'.format(-theta, qubit_pair_1[0])) # - qasm.append('rz({}) q[{}];\n'.format(-numpy.pi / 2, qubit_pair_1[0])) ##### test ##### # qasm.append('h q[{}];\n'.format(qubit_pair_2[0])) # qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_1[0], qubit_pair_2[0])) # 0 2 # qasm.append('h q[{}];\n'.format(qubit_pair_2[0])) # ############### # partial ccc_y operation ############ to here qasm.append( QasmUtils.controlled_xz(qubit_pair_1[0], qubit_pair_2[0], reverse=True)) # correct for parity determination qasm.append('x q[{}];\n'.format(qubit_pair_1[1])) qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_1)) qasm.append('x q[{}];\n'.format(qubit_pair_2[1])) qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_2)) return ''.join(qasm)