Ejemplo n.º 1
0
def pauli_terms_for_tpdm_aa(spatial_dim, transform=jordan_wigner):
    """
    Generate a set of pauli operators to measure to evaluate the alpha-alpha
    block of the 2-RDM

    Given a dictionary of expected values of Pauli terms, populate the
    alpha-beta block of the 2-RDM

    :param Int spatial_dim: Dimension of the spatial-orbital basis.
    :param transform: fermion-to-qubit transform from OpenFermion
    :return: List of PauliTerms that corresponds to set of pauli terms to
             measure to construct the 2-RDM.
    """
    # build basis lookup table
    bas_aa = {}
    cnt_aa = 0
    for p, q in product(range(spatial_dim), repeat=2):
        if q < p:
            bas_aa[(p, q)] = cnt_aa
            cnt_aa += 1

    pauli_terms_to_measure = []
    pauli_to_rdm = {}
    for p, q, r, s in product(range(spatial_dim), repeat=4):
        if p < q and s < r:
            # generator 1/sqrt(2) * (a_{p, \alpha}^{\dagger}
            # a_{q, \alpha}^{\dagger} -
            # a_{p, \beta}^{\dagger}a_{q, \beta}^{\dagger})
            spin_adapted_term = FermionOperator(
                ((2 * p, 1), (2 * q, 1), (2 * r, 0), (2 * s, 0))) - \
                                FermionOperator(((2 * p, 1), (2 * q, 1),
                                                 (2 * s, 0), (2 * r, 0))) - \
                                FermionOperator(((2 * q, 1), (2 * p, 1),
                                                 (2 * r, 0), (2 * s, 0))) + \
                                FermionOperator(((2 * q, 1), (2 * p, 1),
                                                 (2 * s, 0), (2 * r, 0)))
            spin_adapted_term *= 0.5

            tpdm_element_as_pauli = remove_imaginary_terms(
                qubitop_to_pyquilpauli(transform(spin_adapted_term)))
            for term in tpdm_element_as_pauli:
                pauli_terms_to_measure.append(term)

    for term in pauli_terms_to_measure:
        # convert term into numerically order pauli tensor term
        pauli_tensor_list = sorted(list(term.operations_as_set()),
                                   key=lambda x: x[0])
        rev_order_pauli_tensor_list = list(
            map(lambda x: (x[1], x[0]), pauli_tensor_list))
        pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                         coefficient=term.coefficient)

        if pauli_term.id() not in pauli_to_rdm.keys():
            pauli_to_rdm[pauli_term.id()] = pauli_term
        else:
            if (abs(pauli_to_rdm[pauli_term.id()].coefficient) < abs(
                    pauli_term.coefficient)):
                pauli_to_rdm[pauli_term.id()] = pauli_term

    return list(pauli_to_rdm.values())
Ejemplo n.º 2
0
def pauli_to_tpdm_bb(spatial_dim, pauli_to_coeff, transform=jordan_wigner):
    """
    Populate the beta-beta block of the 2-RDM

    :param Int spatial_dim: spatial basis set rank
    :param pauli_to_coeff: a map between the Pauli term label to the expected
                           value.
    :param transform: Openfermion fermion-to-qubit transform
    :return: the 2-RDM alpha-beta block of the 2-RDM
    """
    aa_dim = int(spatial_dim * (spatial_dim - 1) / 2)
    d2_aa = np.zeros((aa_dim, aa_dim), dtype=complex)

    # build basis lookup table
    bas_aa = {}
    cnt_aa = 0
    for p, q in product(range(spatial_dim), repeat=2):
        if p < q:
            bas_aa[(p, q)] = cnt_aa
            cnt_aa += 1

    for p, q, r, s in product(range(spatial_dim), repeat=4):
        if p < q and s < r:
            # generator 1/sqrt(2) * (a_{p, \alpha}^{\dagger}
            # a_{q, \alpha}^{\dagger} -
            # a_{p, \beta}^{\dagger}a_{q, \beta}^{\dagger})
            spin_adapted_term = FermionOperator(((2 * p + 1, 1), (2 * q + 1, 1),
                                                 (2 * r + 1, 0),
                                                 (2 * s + 1, 0))) - \
                                FermionOperator(((2 * p + 1, 1), (2 * q + 1, 1),
                                                 (2 * s + 1, 0),
                                                 (2 * r + 1, 0))) - \
                                FermionOperator(((2 * q + 1, 1), (2 * p + 1, 1),
                                                 (2 * r + 1, 0),
                                                 (2 * s + 1, 0))) + \
                                FermionOperator(((2 * q + 1, 1), (2 * p + 1, 1),
                                                 (2 * s + 1, 0),
                                                 (2 * r + 1, 0)))
            spin_adapted_term *= 0.5

            tpdm_element_as_pauli = remove_imaginary_terms(
                qubitop_to_pyquilpauli(transform(spin_adapted_term)))

            for term in tpdm_element_as_pauli:
                pauli_tensor_list = sorted(list(term.operations_as_set()),
                                           key=lambda x: x[0])
                rev_order_pauli_tensor_list = list(
                    map(lambda x: (x[1], x[0]), pauli_tensor_list))
                pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                                 coefficient=term.coefficient)
                try:
                    d2_aa[bas_aa[(p, q)], bas_aa[(s, r)]] += pauli_to_coeff[
                                                        pauli_term.id()] * \
                                                        pauli_term.coefficient
                except KeyError:
                    raise Warning("key was not in the coeff matrix.")
    return d2_aa
Ejemplo n.º 3
0
def pauli_terms_for_tpdm_ab(spatial_dim, transform=jordan_wigner):
    """
    Build the alpha-beta block of the 2-RDM

    Note: OpenFermion ordering is used.  The 2-RDM(alpha-beta) block
          is spatial_dim**2 linear size. (DOI: 10.1021/acs.jctc.6b00190)

    :param spatial_dim: rank of spatial orbitals in the basis set.
    :param transform: type of fermion-to-qubit transformation.
    :return: list of Pauli terms to measure required to construct a the alpha-
             beta block.
    """
    # build basis look up table
    bas_ab = {}
    cnt_ab = 0
    # iterate over spatial orbital indices
    for p, q in product(range(spatial_dim), repeat=2):
        bas_ab[(p, q)] = cnt_ab
        cnt_ab += 1

    pauli_terms_to_measure = []
    pauli_to_rdm = {}
    for p, q, r, s in product(range(spatial_dim), repeat=4):
        spin_adapted_term = FermionOperator(
            ((2 * p, 1), (2 * q + 1, 1), (2 * r + 1, 0), (2 * s, 0)))

        tpdm_element_as_pauli = remove_imaginary_terms(
            qubitop_to_pyquilpauli(transform(spin_adapted_term)))
        for term in tpdm_element_as_pauli:
            pauli_terms_to_measure.append(term)

    for term in pauli_terms_to_measure:
        # convert term into numerically order pauli tensor term
        pauli_tensor_list = sorted(list(term.operations_as_set()),
                                   key=lambda x: x[0])
        rev_order_pauli_tensor_list = list(
            map(lambda x: (x[1], x[0]), pauli_tensor_list))
        pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                         coefficient=term.coefficient)

        if pauli_term.id() not in pauli_to_rdm.keys():
            pauli_to_rdm[pauli_term.id()] = pauli_term
        else:
            if (abs(pauli_to_rdm[pauli_term.id()].coefficient) < abs(
                    pauli_term.coefficient)):
                pauli_to_rdm[pauli_term.id()] = pauli_term

    return list(pauli_to_rdm.values())
Ejemplo n.º 4
0
def pauli_to_tpdm_ab(spatial_dim, pauli_to_coeff, transform=jordan_wigner):
    """
    Populate the alpha-beta block of the 2-RDM

    Given a dictionary of expected values of Pauli terms, populate the
    alpha-beta block of the 2-RDM

    :param Int spatial_dim: spatial basis set rank
    :param pauli_to_coeff: a map between the Pauli term label to the expected
                           value.
    :param transform: Openfermion fermion-to-qubit transform
    :return: the 2-RDM alpha-beta block of the 2-RDM
    """
    d2_ab = np.zeros((spatial_dim**2, spatial_dim**2), dtype=complex)
    # build basis look up table
    bas_ab = {}
    cnt_ab = 0
    # iterate over spatial orbital indices
    for p, q in product(range(spatial_dim), repeat=2):
        bas_ab[(p, q)] = cnt_ab
        cnt_ab += 1

    for p, q, r, s in product(range(spatial_dim), repeat=4):
        spin_adapted_term = FermionOperator(
            ((2 * p, 1), (2 * q + 1, 1), (2 * r + 1, 0), (2 * s, 0)))

        tpdm_element_as_pauli = remove_imaginary_terms(
            qubitop_to_pyquilpauli(transform(spin_adapted_term)))

        for term in tpdm_element_as_pauli:
            pauli_tensor_list = sorted(list(term.operations_as_set()),
                                       key=lambda x: x[0])
            rev_order_pauli_tensor_list = list(
                map(lambda x: (x[1], x[0]), pauli_tensor_list))
            pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                             coefficient=term.coefficient)
            try:
                d2_ab[bas_ab[(p, q)], bas_ab[(s, r)]] += pauli_to_coeff[
                                                         pauli_term.id()] * \
                                                         pauli_term.coefficient
            except KeyError:
                raise Warning("key was not in the coeff matrix.")
    return d2_ab
Ejemplo n.º 5
0
def pauli_to_tpdm(dim, pauli_to_coeff, transform=jordan_wigner):
    """
    Construct the 2-RDM from expected values of Pauli operators

    Construct the 2-RDM by looping over the 2-RDM and loading up the
    coefficients for the expected values of each transformed Pauli operator.
    We assume the fermionic ladder operators are transformed via Jordan-Wigner.
    This constraint can be relaxed later.

    We don't check that the `pauli_expected` dictionary contains an
    informationally complete set of expected values.  This is useful for
    testing if under sampling the 2-RDM is okay if a projection technique is
    included in the calculation.

    :param Int dim: spin-orbital basis dimension
    :param Dict pauli_to_coeff: a map from pauli term ID's to
    :param func transform: optional argument defining how to transform
                           fermionic operators into Pauli operators
    """
    tpdm = np.zeros((dim, dim, dim, dim), dtype=complex)
    for p, q, r, s in product(range(dim), repeat=4):
        if p != q and r != s:
            tpdm_element = FermionOperator(((p, 1), (q, 1), (r, 0), (s, 0)))
            tpdm_element_as_pauli = remove_imaginary_terms(
                qubitop_to_pyquilpauli(transform(tpdm_element)))

            for term in tpdm_element_as_pauli:
                pauli_tensor_list = sorted(list(term.operations_as_set()),
                                           key=lambda x: x[0])
                rev_order_pauli_tensor_list = list(
                    map(lambda x: (x[1], x[0]), pauli_tensor_list))
                pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                                 coefficient=term.coefficient)
                try:
                    tpdm[p, q, r, s] += pauli_to_coeff[pauli_term.id()] * \
                                        pauli_term.coefficient
                except KeyError:
                    raise Warning("key was not in the coeff matrix.")
    return tpdm
Ejemplo n.º 6
0
def test_imaginary_removal():
    """
    remove terms with imaginary coefficients from a pauli sum
    """
    test_term = 0.25 * sX(1) * sZ(2) * sX(3) + 0.25j * sX(1) * sZ(2) * sY(3)
    test_term += -0.25j * sY(1) * sZ(2) * sX(3) + 0.25 * sY(1) * sZ(2) * sY(3)
    true_term = 0.25 * sX(1) * sZ(2) * sX(3) + 0.25 * sY(1) * sZ(2) * sY(3)
    assert remove_imaginary_terms(test_term) == true_term

    test_term = (0.25 + 1j) * sX(0) * sZ(2) + 1j * sZ(2)
    # is_identity in pyquil apparently thinks zero is identity
    assert remove_imaginary_terms(test_term) == 0.25 * sX(0) * sZ(2)

    test_term = 0.25 * sX(0) * sZ(2) + 1j * sZ(2)
    assert remove_imaginary_terms(test_term) == PauliSum([0.25 * sX(0) * sZ(2)])

    with pytest.raises(TypeError):
        remove_imaginary_terms(5)

    with pytest.raises(TypeError):
        remove_imaginary_terms(sX(0))
Ejemplo n.º 7
0
def pauli_terms_for_tpdm(dim, transform=jordan_wigner):
    """
    Generate a set of pauli operators to measure to evaluate the 2-RDM

    :param Int dim: Dimension of the spin-orbital basis.
    :param transform: fermion-to-qubit transform from OpenFermion
    :return: List of PauliTerms that corresponds to set of pauli terms to
             measure to construct the 2-RDM.
    """

    # first make a map between pauli terms and elements of the 2-RDM
    pauli_to_rdm = {}
    pauli_terms_to_measure = []
    for p, q, r, s in product(range(dim), repeat=4):
        if p != q and r != s:
            tpdm_element = FermionOperator(((p, 1), (q, 1), (r, 0), (s, 0)))
            tpdm_element_as_pauli = remove_imaginary_terms(
                qubitop_to_pyquilpauli(transform(tpdm_element)))
            for term in tpdm_element_as_pauli:
                pauli_terms_to_measure.append(term)

    for term in pauli_terms_to_measure:
        # convert term into numerically order pauli tensor term
        pauli_tensor_list = sorted(list(term.operations_as_set()),
                                   key=lambda x: x[0])
        rev_order_pauli_tensor_list = list(
            map(lambda x: (x[1], x[0]), pauli_tensor_list))
        pauli_term = PauliTerm.from_list(rev_order_pauli_tensor_list,
                                         coefficient=term.coefficient)

        if pauli_term.id() not in pauli_to_rdm.keys():
            pauli_to_rdm[pauli_term.id()] = pauli_term
        else:
            if (abs(pauli_to_rdm[pauli_term.id()].coefficient) < abs(
                    pauli_term.coefficient)):
                pauli_to_rdm[pauli_term.id()] = pauli_term

    return list(pauli_to_rdm.values())