Beispiel #1
0
    def test_partial_exchange(self):
        qubit_1 = 0
        qubit_2 = 1

        qasm_1 = QasmUtils.qasm_header(2)
        qasm_1 += 'x q[{}];\n'.format(qubit_1)

        qasm_2 = QasmUtils.qasm_header(2)
        qasm_2 += 'x q[{}];\n'.format(qubit_2)

        angles = [0, numpy.pi / 4, numpy.pi / 3, numpy.pi / 2, numpy.pi]

        for angle in angles:

            statevector_1 = QiskitSimBackend.\
                statevector_from_qasm(qasm_1 + QasmUtils.partial_exchange(angle, qubit_1, qubit_2)).round(3)

            expected_statevector_1 = numpy.array(
                [0, numpy.cos(angle), -numpy.sin(angle), 0])
            expected_statevector_1 = expected_statevector_1.round(3)

            for i in range(len(statevector_1)):
                self.assertEqual(statevector_1[i], expected_statevector_1[i])

            statevector_2 = QiskitSimBackend.\
                statevector_from_qasm(qasm_2 + QasmUtils.partial_exchange(angle, qubit_1, qubit_2)).round(3)

            expected_statevector_2 = numpy.array(
                [0, numpy.sin(angle), numpy.cos(angle), 0])
            expected_statevector_2 = expected_statevector_2.round(3)

            for i in range(len(statevector_2)):
                self.assertEqual(statevector_2[i], expected_statevector_2[i])
Beispiel #2
0
    def test_double_exchange_extended(self):
        angles = [-0.2, 0.2]

        for angle in angles:

            qasm = ['']
            qasm.append(QasmUtils.qasm_header(6))
            # qasm_1.append('x q[3];\n')
            qasm.append('h q[4];\n')
            qasm.append('x q[2];\n')
            qasm.append('x q[0];\n')

            qasm.append(
                DFExc([0, 2], [3, 5],
                      rescaled_parameter=True,
                      parity_dependence=True).get_qasm([angle]))
            statevector = QiskitSimBackend.statevector_from_qasm(''.join(qasm))

            self.assertEqual(statevector[56].real.round(5),
                             -statevector[40].real.round(5))

            qasm = ['']
            qasm.append(QasmUtils.qasm_header(6))
            # qasm_1.append('x q[3];\n')
            qasm.append('h q[4];\n')
            qasm.append('x q[2];\n')
            qasm.append('x q[0];\n')

            qasm.append(
                DFExc([0, 2], [3, 5],
                      rescaled_parameter=True).get_qasm([angle]))
            statevector = QiskitSimBackend.statevector_from_qasm(''.join(qasm))

            self.assertEqual(statevector[56].real.round(5),
                             statevector[40].real.round(5))
Beispiel #3
0
    def statevector_from_ansatz(ansatz,
                                var_parameters,
                                n_qubits,
                                n_electrons,
                                init_state_qasm=None):
        assert n_electrons < n_qubits
        qasm = ['']
        qasm.append(QasmUtils.qasm_header(n_qubits))

        # initial state
        if init_state_qasm is None:
            qasm.append(QasmUtils.hf_state(n_electrons))
        else:
            qasm.append(init_state_qasm)

        ansatz_qasm = QiskitSimBackend.qasm_from_ansatz(ansatz, var_parameters)
        qasm += ansatz_qasm

        # Get a circuit of SWAP gates to reverse the order of qubits. This is required in order the statevector to
        # match the reversed order of qubits used by openfermion when obtaining the Hamiltonian Matrix.
        qasm.append(QasmUtils.reverse_qubits_qasm(n_qubits))

        qasm = ''.join(qasm)
        statevector = QiskitSimBackend.statevector_from_qasm(qasm)
        # print(qasm)
        return statevector
    def test_pauli_gates_circuit_statevector(self):

        qubit_operator = openfermion.QubitOperator('X0 Y1')
        qasm_circuit = QasmUtils.qasm_header(2)
        qasm_circuit += QasmUtils.pauli_word_qasm(qubit_operator)
        statevector = QiskitSimBackend.statevector_from_qasm(qasm_circuit)

        expected_statevector = numpy.array([0, 0, 0, 1j])

        self.assertEqual(len(expected_statevector), len(statevector))

        for i in range(len(statevector)):
            self.assertEqual(statevector[i], expected_statevector[i])
Beispiel #5
0
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == 1

        qasm = QasmUtils.eff_s_f_exc_qasm(var_parameters[0], self.qubits[0][0],
                                          self.qubits[1][0])

        if {*self.qubits[0], *self.qubits[1]} != {*self.complement_qubits[0], *self.complement_qubits[1]} and \
           {*self.qubits[0], *self.qubits[1]} != {*self.complement_qubits[1], *self.complement_qubits[0]}:

            qasm += QasmUtils.eff_s_f_exc_qasm(var_parameters[0],
                                               self.complement_qubits[0][0],
                                               self.complement_qubits[1][0])

        return qasm
Beispiel #6
0
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == 1

        qasm = QasmUtils.partial_exchange(-var_parameters[0],
                                          self.qubits[0][0], self.qubits[1][0])

        if {*self.qubits[0], *self.qubits[1]} != {*self.complement_qubits[0], *self.complement_qubits[1]} and \
           {*self.qubits[0], *self.qubits[1]} != {*self.complement_qubits[1], *self.complement_qubits[0]}:

            qasm += QasmUtils.partial_exchange(-self.sign * var_parameters[0],
                                               self.complement_qubits[0][0],
                                               self.complement_qubits[1][0])

        return qasm
Beispiel #7
0
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == 1
        parameter_1 = var_parameters[0]

        qasm = QasmUtils.d_q_exc_qasm(parameter_1, self.qubits[0],
                                      self.qubits[1])

        if [set(self.qubits[0]), set(self.qubits[1])] != [set(self.complement_qubits[0]), set(self.complement_qubits[1])] and \
           [set(self.qubits[0]), set(self.qubits[1])] != [set(self.complement_qubits[1]), set(self.complement_qubits[0])]:

            qasm += QasmUtils.d_q_exc_qasm(self.sign * parameter_1,
                                           self.complement_qubits[0],
                                           self.complement_qubits[1])

        return qasm
    def test_hf_states(self):
        n_qubits = 5
        n_electrons = 3

        qasm = QasmUtils.qasm_header(n_qubits)
        qasm += QasmUtils.hf_state(n_electrons)
        qasm += QasmUtils.reverse_qubits_qasm(n_qubits)
        qiskit_statevector = QiskitSimBackend.statevector_from_qasm(qasm)

        sparse_statevector = scipy.sparse.csr_matrix(
            openfermion.utils.jw_hartree_fock_state(n_electrons, n_qubits))
        array_statevector = numpy.array(sparse_statevector.todense())[0]

        for i in range(len(qiskit_statevector)):
            self.assertEqual(qiskit_statevector[i], array_statevector[i])
Beispiel #9
0
    def test_controlled_y_gate_1(self):
        control = 0
        target = 1

        # case 1
        qasm = QasmUtils.qasm_header(2)
        qasm += 'x q[{}];\n'.format(control)
        qasm += QasmUtils.controlled_y_rotation(numpy.pi / 2, control, target)
        statevector = QiskitSimBackend.statevector_from_qasm(qasm).round(3)

        expected_statevector = numpy.array([0, 1, 0, 1]) / numpy.sqrt(2)
        expected_statevector = expected_statevector.round(3)

        for i in range(len(statevector)):
            self.assertEqual(statevector[i], expected_statevector[i])
Beispiel #10
0
    def test_exponent_statevector(self):

        exp_operator = ((0, 'X'), (1, 'Z'), (2, 'Z'))
        qasm = QasmUtils.qasm_header(3)
        qasm += QasmUtils.exponent_qasm(exp_operator, -numpy.pi / 2)
        statevector = QiskitSimBackend.statevector_from_qasm(qasm)

        expected_statevector = numpy.zeros(8)
        expected_statevector[1] = 1

        self.assertEqual(len(expected_statevector), len(statevector))

        for i in range(len(statevector)):
            self.assertEqual(statevector[i].round(3),
                             expected_statevector[i].round(3))
Beispiel #11
0
    def get_statevector(self, ansatz, var_parameters, init_state_qasm=None):
        assert len(var_parameters) == len(ansatz)
        if self.var_parameters is not None and var_parameters == self.var_parameters:  # this condition is not neccessarily sufficient
            assert self.sparse_statevector is not None
        else:
            if self.init_sparse_statevector is not None:
                sparse_statevector = self.init_sparse_statevector.transpose(
                ).conj()
            else:
                if init_state_qasm is not None:
                    # TODO check
                    qasm = QasmUtils.qasm_header(
                        self.n_qubits) + init_state_qasm
                    statevector = QiskitSimBackend.statevector_from_qasm(qasm)
                else:
                    statevector = self.hf_statevector()
                sparse_statevector = scipy.sparse.csr_matrix(
                    statevector).transpose().conj()

            for i, excitation in enumerate(ansatz):
                parameter = var_parameters[i]
                excitation_matrices = self.get_ansatz_element_excitations_matrices(
                    excitation, parameter)
                excitation_matrix = self.identity
                for exc_matrix in excitation_matrices[::
                                                      -1]:  # the first should be the right most (confusing)
                    excitation_matrix *= exc_matrix

                sparse_statevector = excitation_matrix.dot(sparse_statevector)

            self.sparse_statevector = sparse_statevector.transpose().conj()
            self.var_parameters = var_parameters

        return self.sparse_statevector
    def custom_double_excitation(angle, qubit_pair_1, qubit_pair_2):
        qasm = ['']

        # determine tha parity of the two qubit pairs
        qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_1))
        qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_2))

        # perform partial single qubit exchange on q0 and q2, controlled by q1 = |0> and q3 = |0>

        qasm.append('x q[{}];\n'.format(qubit_pair_1[1]))
        qasm.append('x q[{}];\n'.format(qubit_pair_2[1]))

        # TODO add parity dependence
        qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_2[0],
                                                qubit_pair_1[0]))
        qasm.append(
            QasmUtils.n_controlled_y_rotation(
                angle=angle,
                controls=[*qubit_pair_1, qubit_pair_2[1]],
                target=qubit_pair_2[0]))
        qasm.append('cx q[{}], q[{}];\n'.format(qubit_pair_2[0],
                                                qubit_pair_1[0]))

        qasm.append('x q[{}];\n'.format(qubit_pair_1[1]))
        qasm.append('x q[{}];\n'.format(qubit_pair_2[1]))

        qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_1))
        qasm.append('cx q[{}], q[{}];\n'.format(*qubit_pair_2))

        return ''.join(qasm)
Beispiel #13
0
 def get_qasm(self, var_parameters):
     assert len(var_parameters) == 1
     qasm = ''
     for excitation_generator in self.excitations_generators:
         qasm += QasmUtils.excitation_qasm(excitation_generator,
                                           var_parameters[0])
     return qasm
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == self.n_var_parameters
        var_parameters_cycle = itertools.cycle(var_parameters)
        qasm = ['']
        for block in range(self.n_blocks):
            unoccupied_orbitals = list(range(self.n_electrons,
                                             self.n_orbitals))
            for occupied_orbital in reversed(range(0, self.n_electrons)):
                if len(unoccupied_orbitals) == 0:
                    break
                if occupied_orbital == self.n_electrons - 1:
                    virtual_orbital = self.n_electrons + block
                else:
                    virtual_orbital = min(unoccupied_orbitals)
                unoccupied_orbitals.remove(virtual_orbital)

                # add a phase rotation for the excited orbitals only
                angle = var_parameters_cycle.__next__()
                qasm.append('rz({}) q[{}];\n'.format(angle, virtual_orbital))

                angle = var_parameters_cycle.__next__()
                qasm.append(
                    QasmUtils.partial_exchange(angle, occupied_orbital,
                                               virtual_orbital))

            # TODO add exchanges between the last unoccupied orbitals?

        return ''.join(qasm)
Beispiel #15
0
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == 1
        parameter_1 = var_parameters[0]

        qasm = QasmUtils.eff_d_f_exc_qasm(parameter_1, self.qubits[0],
                                          self.qubits[1])

        # if the spin complement is different, add a qasm for it
        if [set(self.qubits[0]), set(self.qubits[1])] != [set(self.complement_qubits[0]), set(self.complement_qubits[1])] and \
           [set(self.qubits[0]), set(self.qubits[1])] != [set(self.complement_qubits[1]), set(self.complement_qubits[0])]:

            qasm += QasmUtils.eff_d_f_exc_qasm(parameter_1,
                                               self.complement_qubits[0],
                                               self.complement_qubits[1])

        return qasm
Beispiel #16
0
 def gate_count_from_ansatz(ansatz, n_qubits, var_parameters=None):
     n_var_parameters = sum([x.n_var_parameters for x in ansatz])
     if var_parameters is None:
         var_parameters = numpy.zeros(n_var_parameters)
     else:
         assert n_var_parameters == len(var_parameters)
     qasm = backends.QiskitSimBackend.qasm_from_ansatz(ansatz, var_parameters)
     return QasmUtils.gate_count_from_qasm(qasm, n_qubits)
Beispiel #17
0
    def elements_individual_vqe_energy_reductions(vqe_runner, ansatz_elements, elements_parameters=None, ansatz=None,
                                                  ansatz_parameters=None, excited_state=0, global_cache=None):

        if ansatz is None:
            ansatz = []
            ansatz_parameters = []

        # TODO this will work only if the ansatz element has 1 var. par.
        if elements_parameters is None:
            elements_parameters = list(numpy.zeros(len(ansatz_elements)))

        if vqe_runner.backend == backends.QiskitSimBackend:
            ansatz_qasm = QasmUtils.hf_state(vqe_runner.q_system.n_electrons)
            ansatz_qasm += vqe_runner.backend.qasm_from_ansatz(ansatz, ansatz_parameters)
        else:
            ansatz_qasm = None

        def get_thread_cache(element):
            if global_cache is not None:
                init_sparse_statevector = global_cache.get_statevector(ansatz, ansatz_parameters)
                return global_cache.single_par_vqe_thread_cache(element, init_sparse_statevector)
            else:
                return None

        if config.multithread:
            elements_results = []
            chunk_size = config.multithread_chunk_size
            if chunk_size is None:
                chunk_size = len(ansatz_elements)
            n_chunks = int(len(ansatz_elements) / chunk_size) + 1
            for i in range(n_chunks):
                # logging.info('Calculating commutators, patch No: {}'.format(i))
                ansatz_elements_chunk = ansatz_elements[i * chunk_size:][:chunk_size]

                ray.init(num_cpus=config.ray_options['n_cpus'], object_store_memory=config.ray_options['object_store_memory'])
                elements_ray_ids = [
                    [element,
                     vqe_runner.vqe_run_multithread.remote(self=vqe_runner, ansatz=[element], init_state_qasm=ansatz_qasm,
                                                           init_guess_parameters=[elements_parameters[i]],
                                                           excited_state=excited_state, cache=get_thread_cache(element))
                     ]
                    # TODO this will work only if the ansatz element has 1 var. par.
                    for i, element in enumerate(ansatz_elements_chunk)
                ]
                elements_results += [[element_ray_id[0], ray.get(element_ray_id[1])] for element_ray_id in
                                     elements_ray_ids]
                ray.shutdown()
        else:
            # use thread cache even if not multithreading since it contains the precalculated init_sparse_statevector
            elements_results = [
                [element, vqe_runner.vqe_run(ansatz=[element], init_guess_parameters=[elements_parameters[i]],
                                             excited_state=excited_state, init_state_qasm=ansatz_qasm,
                                             cache=get_thread_cache(element))
                 ]
                for i, element in enumerate(ansatz_elements)
            ]

        return elements_results
Beispiel #18
0
    def test_exponent_statevectors(self):

        qubit_operators = []
        # only symetric qubit operators will works, because qiskit and openfermion use different qubit orderings
        qubit_operators.append(openfermion.QubitOperator('Z0 Y1 Z2'))
        qubit_operators.append(openfermion.QubitOperator('X0 Y1 X2'))
        qubit_operators.append(openfermion.QubitOperator('Y0 X1 X2 Y3'))

        for qubit_operator in qubit_operators:

            qubit_operator_tuple = list(qubit_operator.terms.keys())[0]
            n_qubits = len(qubit_operator_tuple)

            for angle in range(10):
                angle = 2 * numpy.pi / 10

                # <<< create a statevector using QiskitSimulation.get_exponent_qasm >>>
                qasm = QasmUtils.qasm_header(n_qubits)
                qasm += QasmUtils.exponent_qasm(qubit_operator_tuple, angle)
                qiskit_statevector = QiskitSimBackend.statevector_from_qasm(
                    qasm)
                qiskit_statevector = qiskit_statevector * numpy.exp(
                    1j * angle)  # correct for a global phase
                qiskit_statevector = qiskit_statevector.round(
                    2)  # round for the purpose of testing

                # <<< create a statevector using MatrixCalculation.get_qubit_operator_exponent_matrix >>>
                exp_matrix = MatrixUtils.get_excitation_matrix(
                    1j * qubit_operator, n_qubits, angle).todense()
                # prepare initial statevector corresponding to state |0>
                array_statevector = numpy.zeros(2**n_qubits)
                array_statevector[0] = 1
                # update statevector
                array_statevector = numpy.array(
                    exp_matrix.dot(array_statevector))[0].round(
                        2)  # round for the purpose of testing

                # <<<< compare both state vectors >>>>
                self.assertEqual(len(array_statevector),
                                 len(qiskit_statevector))
                # check the components of the two vectors are equal
                for i in range(len(qiskit_statevector)):
                    self.assertEqual(qiskit_statevector[i],
                                     array_statevector[i])
 def double_exchange_old(angle, qubit_pair_1, qubit_pair_2):
     assert len(qubit_pair_1) == 2
     assert len(qubit_pair_2) == 2
     qasm = ['']
     qasm.append(
         QasmUtils.partial_exchange(angle, qubit_pair_1[1],
                                    qubit_pair_2[0]))
     qasm.append(
         QasmUtils.partial_exchange(-angle, qubit_pair_1[0],
                                    qubit_pair_2[1]))
     qasm.append('cz q[{}], q[{}];\n'.format(qubit_pair_2[0],
                                             qubit_pair_2[1]))
     qasm.append(
         QasmUtils.partial_exchange(-angle, qubit_pair_1[1],
                                    qubit_pair_2[0]))
     qasm.append(
         QasmUtils.partial_exchange(angle, qubit_pair_1[0],
                                    qubit_pair_2[1]))
     # corrections
     qasm.append('cz q[{}], q[{}];\n'.format(qubit_pair_2[0],
                                             qubit_pair_2[1]))
     return ''.join(qasm)
 def get_qasm(self, var_parameters):
     var_parameters_cycle = itertools.cycle(var_parameters)
     count = 0
     qasm = ['']
     # add single qubit n rotations
     # for qubit in range(self.n_orbitals):
     #     qasm.append('rz ({}) q[{}];\n'.format(var_parameters_cycle.__next__(), qubit))
     #     count += 1
     # double orbital exchanges
     for qubit in range(self.n_orbitals):
         if qubit % 4 == 0:
             q_0 = qubit
             q_1 = (qubit + 1) % self.n_orbitals
             q_2 = (qubit + 2) % self.n_orbitals
             q_3 = (qubit + 3) % self.n_orbitals
             q_4 = (qubit + 4) % self.n_orbitals
             # qasm.append(DoubleExchangeAnsatzElement.double_exchange(var_parameters_cycle.__next__(), [q_0, q_1], [q_2, q_3]))
             # count += 1
             qasm.append(
                 DoubleExchangeAnsatzElement.double_exchange(
                     var_parameters_cycle.__next__(), [q_1, q_2],
                     [q_3, q_4]))
             count += 1
     # single orbital exchanges
     for qubit in range(self.n_orbitals):
         if qubit % 2 == 0:
             qasm.append(
                 QasmUtils.partial_exchange(var_parameters_cycle.__next__(),
                                            qubit,
                                            (qubit + 1) % self.n_orbitals))
             count += 1
             qasm.append(
                 QasmUtils.partial_exchange(var_parameters_cycle.__next__(),
                                            (qubit + 1) % self.n_orbitals,
                                            (qubit + 2) % self.n_orbitals))
             count += 1
     assert count == len(var_parameters)
     return ''.join(qasm)
def get_excitation_list_qasm(excitation_list, var_parameters, gate_counter):
    qasm = ['']
    # iterate over all excitations (each excitation is represented by a sum of products of pauli operators)
    for i, excitation in enumerate(excitation_list):
        # print('Excitation ', i)  # testing
        # iterate over the terms of each excitation (each term is a product of pauli operators, on different qubits)
        # TODO replace with the function from QasmUtils
        for exponent_term in excitation.terms:
            exponent_angle = var_parameters[i] * excitation.terms[exponent_term]
            assert exponent_angle.real == 0
            exponent_angle = exponent_angle.imag
            qasm.append(QasmUtils.exponent_qasm(exponent_term, exponent_angle))

    return ''.join(qasm)
Beispiel #22
0
 def get_qasm(self, var_parameters):
     assert len(var_parameters) == 1
     return QasmUtils.partial_exchange(
         -var_parameters[0], self.qubits[0][0], self.qubits[1][0]
     )  # the minus sign is important for consistence with the d_q_exc, as well obtaining the correct sign for grads...
Beispiel #23
0
    def get_qasm(self, var_parameters):
        assert len(var_parameters) == 1
        parameter = var_parameters[0]

        return QasmUtils.eff_d_f_exc_qasm(parameter, self.qubits[0],
                                          self.qubits[1])
    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)
Beispiel #26
0
 def get_qasm(self, var_parameters):
     assert len(var_parameters) == 1
     return QasmUtils.eff_s_f_exc_qasm(var_parameters[0], self.qubits[0][0],
                                       self.qubits[1][0])