Exemplo n.º 1
0
def get_0000_state_operator(qubit_operator):
    """
    Return a simplified QubitOperator U0 s.t.
    U0|0..00>=U1|0..00>
    Args:
        qubit_operator:U1
    """
    new_qubit_operator = QubitOperator()
    for pauli_and_coff in qubit_operator.get_operators():
        for string_pauli in pauli_and_coff.terms:
            new_string = ""
            new_coff = 1
            for terms in string_pauli:
                if terms[1] == 'X':
                    new_string += "X" + str(terms[0]) + ' '
                if terms[1] == 'Y':
                    new_coff *= 1j
                    new_string += "X" + str(terms[0]) + ' '
            new_qubit_operator += new_coff * pauli_and_coff.terms[
                string_pauli] * QubitOperator(new_string)
    new_qubit_operator.compress()
    return new_qubit_operator
Exemplo n.º 2
0
def binary_code_transform(hamiltonian, code):
    """ Transforms a Hamiltonian written in fermionic basis into a Hamiltonian
    written in qubit basis, via a binary code.

    The role of the binary code is to relate the occupation vectors (v0 v1 v2
    ... vN-1) that span the fermionic basis, to the qubit basis, spanned by
    binary vectors (w0, w1, w2, ..., wn-1).

    The binary code has to provide an analytic relation between the binary
    vectors (v0, v1, ..., vN-1) and (w0, w1, ..., wn-1), and possibly has the
    property N>n, when the Fermion basis is smaller than the fermionic Fock
    space. The binary_code_transform function can transform Fermion operators
    to qubit operators for custom- and qubit-saving mappings.
    
    Note:
        Logic multi-qubit operators are decomposed into Pauli-strings (e.g.
        CPhase(1,2) = 0.5 * (1 + Z1 + Z2 - Z1 Z2 ) ), which might increase
        the number of Hamiltonian terms drastically.

    Args:
        hamiltonian (FermionOperator): the fermionic Hamiltonian
        code (BinaryCode): the binary code to transform the Hamiltonian

    Returns (QubitOperator): the transformed Hamiltonian

    Raises:
        TypeError: if the hamiltonian is not a FermionOperator or code is not
        a BinaryCode
    """
    if not isinstance(hamiltonian, FermionOperator):
        raise TypeError('hamiltonian provided must be a FermionOperator'
                        'received {}'.format(type(hamiltonian)))

    if not isinstance(code, BinaryCode):
        raise TypeError('code provided must be a BinaryCode'
                        'received {}'.format(type(code)))

    new_hamiltonian = QubitOperator()
    parity_list = make_parity_list(code)

    # for each term in hamiltonian
    for term, term_coefficient in hamiltonian.terms.items():
        """ the updated parity and occupation account for sign changes due
        changed occupations mid-way in the term """
        updated_parity = 0  # parity sign exponent
        parity_term = SymbolicBinary()
        changed_occupation_vector = [0] * code.n_modes
        transformed_term = QubitOperator(())

        # keep track of indices appeared before
        fermionic_indices = numpy.array([])

        # for each multiplier
        for op_idx, op_tuple in enumerate(reversed(term)):
            # get count exponent, parity exponent addition
            fermionic_indices = numpy.append(fermionic_indices, op_tuple[0])
            count = numpy.count_nonzero(
                fermionic_indices[:op_idx] == op_tuple[0])
            updated_parity += numpy.count_nonzero(
                fermionic_indices[:op_idx] < op_tuple[0])

            # update term
            extracted = extractor(code.decoder[op_tuple[0]])
            extracted *= (((-1)**count) * ((-1)**(op_tuple[1])) * 0.5)
            transformed_term *= QubitOperator((), 0.5) - extracted

            # update parity term and occupation vector
            changed_occupation_vector[op_tuple[0]] += 1
            parity_term += parity_list[op_tuple[0]]

        # the parity sign and parity term
        transformed_term *= QubitOperator((), (-1)**updated_parity)
        transformed_term *= extractor(parity_term)

        # the update operator
        changed_qubit_vector = numpy.mod(
            code.encoder.dot(changed_occupation_vector), 2)
        for index, q_vec in enumerate(changed_qubit_vector):
            if q_vec:
                transformed_term *= QubitOperator('X' + str(index))

        # append new term to new hamiltonian
        new_hamiltonian += term_coefficient * transformed_term

    new_hamiltonian.compress()
    return new_hamiltonian
def XBK_transform(op, r, p):

    n = count_qubits(op)
    op_terms = op.terms
    new_op = QubitOperator()

    #transform operator term by term
    for key in op_terms:
        coeff = op_terms[key]
        term = QubitOperator()

        #cycle through each of the r ancillarly qubit copies
        for j in range(r):
            for k in range(r):
                sign = 1 if (j < p) == (k < p) else -1
                sub_term = QubitOperator('', 1)

                #cycle through each of the n original qubits
                spot = 0
                for i in range(n):
                    try:
                        if key[spot][0] == i:
                            char = key[spot][1]
                            spot += 1
                        else:
                            char = 'I'
                    except IndexError:
                        char = 'I'

                    #use variable type to apply correct mapping
                    if char == 'X':
                        if j == k:
                            sub_term = QubitOperator('', 0)
                            break
                        else:
                            sub_term *= QubitOperator(
                                '', 1 / 2) - QubitOperator(
                                    'Z' + str(i + n * j) + ' Z' +
                                    str(i + n * k), 1 / 2)
                    elif char == 'Y':
                        if j == k:
                            sub_term = QubitOperator('', 0)
                            break
                        else:
                            sub_term *= QubitOperator(
                                'Z' + str(i + n * k), 1j / 2) - QubitOperator(
                                    'Z' + str(i + n * j), 1j / 2)
                    elif char == 'Z':
                        if j == k:
                            sub_term *= QubitOperator('Z' + str(i + n * j), 1)
                        else:
                            sub_term *= QubitOperator(
                                'Z' + str(i + n * j), 1 / 2) + QubitOperator(
                                    'Z' + str(i + n * k), 1 / 2)
                    else:
                        if j == k:
                            continue
                        else:
                            sub_term *= QubitOperator(
                                '', 1 / 2) + QubitOperator(
                                    'Z' + str(i + n * j) + ' Z' +
                                    str(i + n * k), 1 / 2)

                term += sign * sub_term
        new_op += coeff * term

    new_op.compress()
    return new_op