Exemple #1
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())
Exemple #2
0
def test_simplify_sum_terms():
    sum_term = PauliSum([PauliTerm('X', 0, 0.5), PauliTerm('Z', 0, 0.5j)])
    str_sum_term = str(sum_term + sum_term)
    assert str_sum_term == '(1+0j)*X0 + 1j*Z0' or str_sum_term == '1j*Z0 + (1+0j)*X0'
    sum_term = PauliSum([PauliTerm('X', 0, 0.5), PauliTerm('X', 0, 0.5)])
    assert str(sum_term.simplify()) == '(1+0j)*X0'

    # test the simplify on multiplication
    sum_term = PauliSum([PauliTerm('X', 0, 0.5), PauliTerm('X', 0, 0.5)])
    assert str(sum_term * sum_term) == '(1+0j)*I'
Exemple #3
0
def test_simplify_sum_terms():
    sum_term = PauliSum([PauliTerm("X", 0, 0.5), PauliTerm("Z", 0, 0.5j)])
    str_sum_term = str(sum_term + sum_term)
    assert str_sum_term == "(1+0j)*X0 + 1j*Z0" or str_sum_term == "1j*Z0 + (1+0j)*X0"
    sum_term = PauliSum([PauliTerm("X", 0, 0.5), PauliTerm("X", 0, 0.5)])
    assert str(sum_term.simplify()) == "(1+0j)*X0"

    # test the simplify on multiplication
    sum_term = PauliSum([PauliTerm("X", 0, 0.5), PauliTerm("X", 0, 0.5)])
    assert str(sum_term * sum_term) == "(1+0j)*I"
Exemple #4
0
def test_get_angles():
    p = 2
    n_qubits = 2
    fakeQVM = Mock()
    with patch('grove.pyqaoa.qaoa.VQE', spec=VQE) as mockVQEClass:
        inst = mockVQEClass.return_value
        result = Mock()
        result.x = [1.2, 2.1, 3.4, 4.3]
        inst.vqe_run.return_value = result
        MCinst = QAOA(fakeQVM,
                      list(range(n_qubits)),
                      steps=p,
                      cost_ham=[PauliSum([PauliTerm("X", 0)])])
        betas, gammas = MCinst.get_angles()
        assert betas == [1.2, 2.1]
        assert gammas == [3.4, 4.3]
Exemple #5
0
    def in_operator(self):
        warnings.warn(
            "ExperimentSetting.in_operator is deprecated in favor of in_state", stacklevel=2
        )

        # Backwards compat
        pt = sI()
        for oneq_state in self.in_state.states:
            if oneq_state.label not in ["X", "Y", "Z"]:
                raise ValueError(f"Can't shim {oneq_state.label} into a pauli term. Use in_state.")
            if oneq_state.index != 0:
                raise ValueError(f"Can't shim {oneq_state} into a pauli term. Use in_state.")

            pt *= PauliTerm(op=oneq_state.label, index=oneq_state.qubit)

        return pt
def str_to_pauli_term(pauli_str: str, qubit_labels=None):
    """
    Convert a string into a :class:`~pyquil.paulis.PauliTerm`.

    >>> str_to_pauli_term('XY', [])

    :param str pauli_str: The input string, made of of 'I', 'X', 'Y' or 'Z'
    :param qubit_labels: The integer labels for the qubits in the string
        If None, default to the range of the length of pauli_str.
    :return: the corresponding PauliTerm
    :rtype: pyquil.paulis.PauliTerm
    """
    if qubit_labels is None:
        qubit_labels = [qubit for qubit in range(len(pauli_str))]

    pauli_term = PauliTerm.from_list(list(zip(pauli_str, qubit_labels)))
    return pauli_term
Exemple #7
0
    def create_penalty_operators_for_qubit_range(self, range_of_qubits):
        cost_operators = []
        weight = -100 * np.max(self.distance_matrix)
        for i in range_of_qubits:
            if i == range_of_qubits[0]:
                z_term = PauliTerm("Z", i, weight)
                all_ones_term = PauliTerm("I", 0, 0.5 * weight) - PauliTerm("Z", i, 0.5 * weight)
            else:
                z_term = z_term * PauliTerm("Z", i)
                all_ones_term = all_ones_term * (PauliTerm("I", 0, 0.5) - PauliTerm("Z", i, 0.5))

        z_term = PauliSum([z_term])
        cost_operators.append(PauliTerm("I", 0, weight) - z_term - all_ones_term)

        return cost_operators
def test_simplify_sum_terms():
    q0 = QubitPlaceholder()
    sum_term = PauliSum([PauliTerm('X', q0, 0.5), PauliTerm('Z', q0, 0.5j)])
    str_sum_term = str(sum_term + sum_term)
    assert (str_sum_term == '(1+0j)*X{q0} + 1j*Z{q0}'.format(q0=q0)
            or str_sum_term == '1j*Z{q0} + (1+0j)*X{q0}'.format(q0=q0))
    sum_term = PauliSum([PauliTerm('X', q0, 0.5), PauliTerm('X', q0, 0.5)])
    assert str(sum_term.simplify()) == '(1+0j)*X{q0}'.format(q0=q0)

    # test the simplify on multiplication
    sum_term = PauliSum([PauliTerm('X', q0, 0.5), PauliTerm('X', q0, 0.5)])
    assert str(sum_term * sum_term) == '(1+0j)*I'
Exemple #9
0
    def _operator_generator(index, conj):
        """
        Internal method to generate the appropriate operator
        """
        pterm = PauliTerm('I', 0, 1.0)
        Zstring = PauliTerm('I', 0, 1.0)
        for j in range(index):
            Zstring = Zstring * PauliTerm('Z', j, 1.0)

        pterm1 = Zstring * PauliTerm('X', index, 0.5)
        scalar = 0.5 * conj * 1.0j
        pterm2 = Zstring * PauliTerm('Y', index, scalar)
        pterm = pterm * (pterm1 + pterm2)

        pterm = pterm.simplify()
        return pterm
Exemple #10
0
def test_sampling_expectation():
    bitstring1 = np.array([[1, 0], [0, 1], [1, 1], [1, 1]])
    bitstring2 = np.array([[1, 0], [0, 1], [1, 1], [1, 1]])
    bitstrings = [bitstring1, bitstring2]
    # ham1 = PauliSum.from_compact_str("1.0*Z0*Z1 + 0.5*Z0 + (-1)*Z1")
    # ham2 = PauliSum.from_compact_str("1.0*X0*Z1 + 0.5*X0 + (-1)*Z1")
    term1 = PauliTerm("Z", 0) * PauliTerm("Z", 1)
    term2 = PauliTerm("Z", 0, 0.5)
    term3 = PauliTerm("Z", 1, -1)
    term4 = PauliTerm("X", 0) * PauliTerm("Z", 1)
    term5 = PauliTerm("X", 0, 0.5)
    ham1 = PauliSum([term1, term2, term3])
    ham2 = PauliSum([term4, term5, term3])
    hams = [ham1, ham2]
    out = sampling_expectation(hams, bitstrings)
    assert np.allclose(out, (0.5, 1.3385315336840842))
def test_exp_circuit():
    true_wf = np.array([
        0.54030231 - 0.84147098j, 0.00000000 + 0.j, 0.00000000 + 0.j,
        0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j,
        0.00000000 + 0.j
    ])

    create2kill1 = PauliTerm("X", 1, -0.25) * PauliTerm("Y", 2)
    create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("Y", 2)
    create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("X", 2)
    create2kill1 += PauliTerm("X", 1, 0.25) * PauliTerm("X", 2)
    create2kill1 += PauliTerm("I", 0, 1.0)
    prog = Program()
    for term in create2kill1.terms:
        single_exp_prog = exponentiate(term)
        prog += single_exp_prog

    qam = PyQVM(n_qubits=3,
                quantum_simulator_type=ReferenceWavefunctionSimulator)
    qam.execute(prog)
    wf = qam.wf_simulator.wf
    np.testing.assert_allclose(wf.dot(np.conj(wf).T),
                               true_wf.dot(np.conj(true_wf).T))
Exemple #12
0
    def _in_operator(self) -> PauliTerm:
        # Backwards compat
        pt = sI()
        for oneq_state in self.in_state.states:
            if oneq_state.label not in ["X", "Y", "Z"]:
                raise ValueError(
                    f"Can't shim {oneq_state.label} into a pauli term. Use in_state."
                )
            if oneq_state.index != 0:
                raise ValueError(
                    f"Can't shim {oneq_state} into a pauli term. Use in_state."
                )

            new_pt = pt * PauliTerm(op=oneq_state.label,
                                    index=oneq_state.qubit)
            pt = cast(PauliTerm, new_pt)

        return pt
def str_to_pauli_term(pauli_str: str, qubit_labels=None):
    """
    Convert a string into a pyquil.paulis.PauliTerm.

    >>> str_to_pauli_term('XY', [])

    :param str pauli_str: The input string, made of of 'I', 'X', 'Y' or 'Z'
    :param set qubit_labels: The integer labels for the qubits in the string, given in reverse
    order. If None, default to the range of the length of pauli_str.
    :return: the corresponding PauliTerm
    :rtype: pyquil.paulis.PauliTerm
    """
    if qubit_labels is None:
        labels_list = [qubit for qubit in reversed(range(len(pauli_str)))]
    else:
        labels_list = sorted(qubit_labels)[::-1]
    pauli_term = PauliTerm.from_list(list(zip(pauli_str, labels_list)))
    return pauli_term
class TestTimeEvolutionOfHamiltonian:
    @pytest.fixture(
        params=[
            PauliSum(
                [
                    PauliTerm("X", 0) * PauliTerm("X", 1),
                    PauliTerm("Y", 0, 0.5) * PauliTerm("Y", 1),
                    PauliTerm("Z", 0, 0.3) * PauliTerm("Z", 1),
                ]
            ),
            QubitOperator("[X0 X1] + 0.5[Y0 Y1] + 0.3[Z0 Z1]"),
        ]
    )
    def hamiltonian(self, request):
        return request.param

    @pytest.mark.parametrize("time", [0.1])  # [0.1, 0.4, 1.0])
    @pytest.mark.parametrize("order", [2])  # [1, 2, 3])
    def test_evolution_with_numerical_time_produces_correct_result(
        self, hamiltonian, time, order
    ):
        cirq_qubits = cirq.LineQubit(0), cirq.LineQubit(1)
        expected_cirq_circuit = _cirq_exponentiate_hamiltonian(
            hamiltonian, cirq_qubits, time, order
        )

        reference_unitary = cirq.unitary(expected_cirq_circuit)
        unitary = time_evolution(hamiltonian, time, trotter_order=order).to_unitary()
        assert compare_unitary(unitary, reference_unitary, tol=1e-10)

    @pytest.mark.parametrize("time_value", [0.1, 0.4, 1.0])
    @pytest.mark.parametrize("order", [1, 2, 3])
    def test_time_evolution_with_symbolic_time_produces_correct_unitary(
        self, hamiltonian, time_value, order
    ):
        time_symbol = sympy.Symbol("t")
        symbols_map = [(time_symbol, time_value)]

        cirq_qubits = cirq.LineQubit(0), cirq.LineQubit(1)

        expected_cirq_circuit = _cirq_exponentiate_hamiltonian(
            hamiltonian, cirq_qubits, time_value, order
        )

        reference_unitary = cirq.unitary(expected_cirq_circuit)

        unitary = (
            time_evolution(hamiltonian, time_symbol, trotter_order=order)
            .evaluate(symbols_map)
            .to_unitary()
        )
        assert compare_unitary(unitary, reference_unitary, tol=1e-10)
Exemple #15
0
def generate_t2_echo_experiments(
        qubits: Sequence[int],
        times: Sequence[float],
        detuning: float = 1e6) -> List[ObservablesExperiment]:
    """
    Return ObservablesExperiments containing programs which constitute a T2 echo experiment to
    measure the T2 echo coherence decay time.

    For each delay time in times a single program will be generated in which all qubits are
    initialized to the minusY state and later simultaneously measured along the Y axis. Unlike in
    the t2_star experiment above there is a 'echo' applied in the middle of the delay in which
    the qubit is rotated by pi radians around the Y axis.

    Similarly to t2_star, if the qubit frequency is perfectly calibrated then the Y expectation
    will oscillate at the given detuning frequency as the qubit is rotated about the Z axis (with
    respect to the lab frame, which by hypothesis matches the natural qubit frame). Unlike in a
    t2_star experiment, even if the qubit frequency is off such that there is some spurious
    rotation about the Z axis during the DELAY, the effect of an ideal echo is to cancel the
    effect of this rotation so that the qubit returns to the initial state minusY before the
    detuning rotation is applied.

    :param qubits: list of qubits to measure.
    :param times: the times at which to measure, given in seconds. Each time is rounded to the
        nearest .1 microseconds.
    :param detuning: The additional detuning frequency about the z axis.
    :return: ObservablesExperiments which can be run to acquire an estimate of T2 for each qubit.
    """
    expts = []
    for t in times:
        half_time = round(t / 2, 7)  # enforce 100ns boundaries
        t = round(t, 7)
        program = Program()
        settings = []
        for q in qubits:
            half_delay = Pragma('DELAY', [q], str(half_time))
            # echo
            program += [half_delay, RY(pi, q), half_delay]
            # apply detuning
            program += RZ(2 * pi * t * detuning, q)
            settings.append(ExperimentSetting(minusY(q), PauliTerm('Y', q)))

        expts.append(ObservablesExperiment(settings, program))

    return expts
    def create_penalty_operators_for_qubit_range(self, range_of_qubits):
        cost_operators = []
        tsp_matrix = TSP_utilities.get_tsp_matrix(self.nodes_array)
        weight = -10 * np.max(tsp_matrix)
        # weight = -0.5
        for i in range_of_qubits:
            if i == range_of_qubits[0]:
                z_term = PauliTerm("Z", i, weight)
                all_ones_term = PauliTerm("I", 0, 0.5 * weight) - PauliTerm("Z", i, 0.5 * weight)
            else:
                z_term = z_term * PauliTerm("Z", i)
                all_ones_term = all_ones_term * (PauliTerm("I", 0, 0.5) - PauliTerm("Z", i, 0.5))

        z_term = PauliSum([z_term])
        cost_operators.append(PauliTerm("I", 0, weight) - z_term + self.all_ones_coefficient * all_ones_term)

        return cost_operators
Exemple #17
0
def test_check_commutation():
    term1 = PauliTerm("X", 0) * PauliTerm("X", 1)
    term2 = PauliTerm("Y", 0) * PauliTerm("Y", 1)
    term3 = PauliTerm("Y", 0) * PauliTerm("Z", 2)
    # assert check_commutation(PauliSum([term1]), term2)
    assert check_commutation([term2], term3)
    assert check_commutation([term2], term3)
    assert not check_commutation([term1], term3)

    # more rigorous test.  Get all operators in Pauli group
    p_n_group = ("I", "X", "Y", "Z")
    pauli_list = list(product(p_n_group, repeat=3))
    pauli_ops = [list(zip(x, range(3))) for x in pauli_list]
    pauli_ops_pq = []
    for op in pauli_ops:
        reduced = PauliTerm(op[0][0], op[0][1])
        for y in op[1:]:
            reduced *= PauliTerm(y[0], y[1])
        pauli_ops_pq.append(reduced)

    def commutator(t1, t2):
        return t1 * t2 + -1 * t2 * t1

    non_commuting_pairs = []
    commuting_pairs = []
    for x in range(len(pauli_ops_pq)):
        for y in range(x, len(pauli_ops_pq)):

            tmp_op = commutator(pauli_ops_pq[x], pauli_ops_pq[y])
            assert len(tmp_op.terms) == 1
            if tmp_op.terms[0].id() == '':
                commuting_pairs.append((pauli_ops_pq[x], pauli_ops_pq[y]))
            else:
                non_commuting_pairs.append((pauli_ops_pq[x], pauli_ops_pq[y]))

    # now that we have our sets let's check against our code.
    for t1, t2 in non_commuting_pairs:
        assert not check_commutation([t1], t2)

    for t1, t2 in commuting_pairs:
        assert check_commutation([t1], t2)
Exemple #18
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
Exemple #19
0
def test_base_change_fun():
    # this also tests apply_H and apply_RX
    term1 = PauliTerm("Z", 0) * PauliTerm("Z", 1)
    term2 = PauliTerm("Z", 1) * PauliTerm("Z", 2)
    term3 = PauliTerm("X", 0) * PauliTerm("X", 2)
    ham = PauliSum([term1, term2, term3])
    wf = np.array([0, 1, 2, 3, 4, 5, 6, 7])
    wfs = []
    wfs.append(np.array([5, -1, 9, -1, -4, 0, -4, 0]))
    wfs.append(np.array([0, 1, 2, 3, 4, 5, 6, 7]))
    hams = commuting_decomposition(ham)
    for w, h in zip(wfs, hams):
        fun = base_change_fun(h, [0, 1, 2])
        assert np.allclose(fun(wf), w)
def _max_weight_operator(ops: Iterable[PauliTerm]) -> Union[None, PauliTerm]:
    """Construct a PauliTerm operator by taking the non-identity single-qubit operator at each
    qubit position.

    This function will return ``None`` if the input operators do not share a natural tensor
    product basis.

    For example, the max_weight_operator of ["XI", "IZ"] is "XZ". Asking for the max weight
    operator of something like ["XI", "ZI"] will return None.
    """
    mapping = dict()  # type: Dict[int, str]
    for op in ops:
        for idx, op_str in op:
            if idx in mapping:
                if mapping[idx] != op_str:
                    return None
            else:
                mapping[idx] = op_str
    op = functools.reduce(mul, (PauliTerm(op, q) for q, op in mapping.items()), sI())
    return op
Exemple #21
0
def test_qubitop_to_paulisum():
    """
    Conversion of QubitOperator; accuracy test
    """
    hop_term = FermionOperator(((2, 1), (0, 0)))
    term = hop_term + hermitian_conjugated(hop_term)

    pauli_term = jordan_wigner(term)

    forest_term = qubitop_to_pyquilpauli(pauli_term)
    ground_truth = PauliTerm("X", 0) * PauliTerm("Z", 1) * PauliTerm("X", 2)
    ground_truth += PauliTerm("Y", 0) * PauliTerm("Z", 1) * PauliTerm("Y", 2)
    ground_truth *= 0.5

    assert ground_truth == forest_term
Exemple #22
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
Exemple #23
0
    def _operator_generator(self, index, conj):
        """
        Internal method to generate the appropriate ladder operator at fermion
        orbital at 'index'
        If conj == -1 --> creation
           conj == +1 --> annihilation

        :param int index: fermion orbital to generate ladder operator at
        :param int conj: -1 for creation, +1 for annihilation
        """
        if conj != -1 and conj != +1:
            raise ValueError("Improper conjugate coefficient")
        if index >= self.n_qubits or index < 0:
            raise IndexError("Operator index outside number of qubits for "
                             "current Bravyi-Kitaev transform.")

        # parity set P(j). apply Z to, for parity sign.
        parity_set = [node.index for node in self.tree.get_parity_set(index)]

        # update set U(j). apply X to, for updating purposes.
        ancestors = [node.index for node in self.tree.get_update_set(index)]

        # remainder set C(j) = P(j) \ F(j)
        ancestor_children = [
            node.index for node in self.tree.get_remainder_set(index)
        ]

        # Under Majorana basis, creation/annihilation operators given by
        # a^{\pm} = (c \mp id) / 2

        # c_j = a_j + a_j^{\dagger} = X_{U(j)} X_j Z_{P(j)}
        c_maj = PauliTerm('X', index)
        for node_idx in parity_set:
            c_maj *= PauliTerm('Z', node_idx)
        for node_idx in ancestors:
            c_maj *= PauliTerm('X', node_idx)

        # d_j = i(a_j^{\dagger} - a_j) = X_{U(j)} Y_j Z_{C(j)}
        d_maj = PauliTerm('Y', index)
        for node_idx in ancestors:
            d_maj *= PauliTerm('X', node_idx)
        for node_idx in ancestor_children:
            d_maj *= PauliTerm('Z', node_idx)

        result = 0.5 * (c_maj + 1j * conj * d_maj)
        return result.simplify()
Exemple #24
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())
Exemple #25
0
def _max_key_overlap(pauli_term, diagonal_sets):
    """
    Calculate the max overlap of a pauli term ID with keys of diagonal_sets

    Returns a different key if we find any collisions.  If no collisions is
    found then the pauli term is added and the key is updated so it has the
    largest weight.

    :param pauli_term:
    :param diagonal_sets:
    :return: dictionary where key value pair is tuple indicating diagonal basis
             and list of PauliTerms that share that basis
    :rtype: dict
    """
    # a lot of the ugliness comes from the fact that
    # list(PauliTerm._ops.items()) is not the appropriate input for
    # Pauliterm.from_list()
    for key in list(diagonal_sets.keys()):
        pauli_from_key = PauliTerm.from_list(
            list(map(lambda x: tuple(reversed(x)), key)))
        if diagonal_basis_commutes(pauli_term, pauli_from_key):
            updated_pauli_set = diagonal_sets[key] + [pauli_term]
            diagonalizing_term = get_diagonalizing_basis(updated_pauli_set)
            if len(diagonalizing_term) > len(key):
                del diagonal_sets[key]
                new_key = tuple(sorted(diagonalizing_term._ops.items(),
                                       key=lambda x: x[0]))
                diagonal_sets[new_key] = updated_pauli_set
            else:
                diagonal_sets[key] = updated_pauli_set
            return diagonal_sets
    # made it through all keys and sets so need to make a new set
    else:
        # always need to sort because new pauli term functionality
        new_key = tuple(sorted(pauli_term._ops.items(), key=lambda x: x[0]))
        diagonal_sets[new_key] = [pauli_term]
        return diagonal_sets
Exemple #26
0
def vqe_parametric(vqe_strategy, vqe_tomography, vqe_method):
    """
    Initialize a VQE experiment with a custom hamiltonian
    given as constant input
    """

    _vqe = None

    if vqe_strategy == "custom_program":
        custom_ham = PauliSum([PauliTerm(*x) for x in HAMILTONIAN])
        _vqe = VQEexperiment(hamiltonian=custom_ham,
                             method=vqe_method,
                             strategy=vqe_strategy,
                             parametric=True,
                             tomography=vqe_tomography,
                             shotN=NSHOTS_FLOAT)
    elif vqe_strategy == "HF":
        cwd = os.path.abspath(os.path.dirname(__file__))
        fname = os.path.join(cwd, "resources", "H.hdf5")
        molecule = MolecularData(filename=fname)
        _vqe = VQEexperiment(molecule=molecule,
                             method=vqe_method,
                             strategy=vqe_strategy,
                             parametric=True,
                             tomography=vqe_tomography,
                             shotN=NSHOTS_FLOAT)
    elif vqe_strategy == "UCCSD":
        cwd = os.path.abspath(os.path.dirname(__file__))
        fname = os.path.join(cwd, "resources", "H2.hdf5")
        molecule = MolecularData(filename=fname)
        _vqe = VQEexperiment(molecule=molecule,
                             method=vqe_method,
                             strategy=vqe_strategy,
                             parametric=True,
                             tomography=vqe_tomography,
                             shotN=NSHOTS_FLOAT)
    return _vqe
Exemple #27
0
def generate_rabi_experiments(qubits: Sequence[int], angles: Sequence[float]) \
        -> List[ObservablesExperiment]:
    """
    Return ObservablesExperiments containing programs which constitute a Rabi experiment.

    Rabi oscillations are observed by applying successively larger rotations to the same initial
    state.

    :param qubits: list of qubits to measure.
    :param angles: A list of angles at which to make a measurement
    :return: ObservablesExperiments which can be run to verify the  RX(angle, q) calibration
        for each qubit
    """
    expts = []
    for angle in angles:
        program = Program()
        settings = []
        for q in qubits:
            program += RX(angle, q)
            settings.append(ExperimentSetting(plusZ(q), PauliTerm('Z', q)))

        expts.append(ObservablesExperiment([settings], program))

    return expts
def pauli_term_relabel(pauli_sum, label_map):
    """
    Relabel the elements of a pauli_sum via the `label_map`

    :param pauli_sum: pauli sum to relabel.  this can be a PauliTerm, PauliSum,
                      or even better a LIST!
    :param label_map: a dictionary mapping old label to new label
    :return: a list of pauli_terms relabeled
    """
    if isinstance(pauli_sum, PauliTerm):
        pauli_sum = PauliSum([pauli_sum])

    if isinstance(pauli_sum, PauliSum):
        pauli_sum = pauli_sum.terms

    relabeled_terms = []
    for term in pauli_sum:
        new_term_as_list = []
        for qlabel, pauli_element in term._ops.items():
            new_term_as_list.append((pauli_element, label_map[qlabel]))
        relabeled_terms.append(
            PauliTerm.from_list(new_term_as_list,
                                coefficient=term.coefficient))
    return relabeled_terms
def test_ExtendedParams_plot():
    ham_no_bias = PauliTerm("Z", 0)
    ham_no_bias *= PauliTerm("Z", 1)
    next_term = PauliTerm("Z", 0, -2.0)
    next_term *= PauliTerm("Z", 2)
    ham_no_bias += next_term

    p = 5
    params = ExtendedParams.linear_ramp_from_hamiltonian(ham_no_bias, p)
    fig, ax = plt.subplots()
    params.plot(ax=ax)
    # plt.show()

    p = 8
    params = ExtendedParams((ham_no_bias, p),
                            ([0.1] * p * len(ham_no_bias.get_qubits()), [],
                             [0.2] * p * len(ham_no_bias)))
    fig, ax = plt.subplots()
    params.plot(ax=ax)
Exemple #30
0
def test_pass_hamiltonians():
    ref_ham = [PauliSum([PauliTerm("X", 0, -1.0)]), PauliSum([PauliTerm("X", 1,
                                                              -1.0)])]
    cost_ham = [PauliTerm("I", 0, 0.5) + PauliTerm("Z", 0, -0.5) *
                PauliTerm("Z", 1, 1.0)]
    fakeQVM = Mock()
    inst = QAOA(fakeQVM, range(2), steps=1,
                cost_ham=cost_ham, ref_ham=ref_ham)

    c = inst.cost_ham
    r = inst.ref_ham
    assert isinstance(c, list)
    assert isinstance(r, list)
    assert isinstance(c[0], PauliSum)
    assert isinstance(r[0], PauliSum)
    assert len(c) == 1
    assert len(r) == 2

    with pytest.raises(TypeError):
        QAOA(fakeQVM, 2, steps=1,
             cost_ham=PauliTerm("X", 0, 1.0), ref_ham=ref_ham,
             rand_seed=42)