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())
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'
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"
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]
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
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'
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
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))
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)
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
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)
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
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
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
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
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()
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())
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
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
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)
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)