def _measure_list_of_pauli_terms(pauli_terms, variance_bound, program, quantum_resource): """ Measure the expected value of a list of Pauli terms and return as a dict :param pauli_terms: Pauli Terms to measure :param variance_bound: variance bound for measurement. Right now this is the bound on the variance if you summed up all the individual terms. 1.0E-6 is a good place to start. :param program: pyquil Program preparing state :param quantum_resource: quantum abstract machine connection object :return: results dictionary where the key is the Pauli term ID and the value is the expected value """ # group them into commuting sets and then measure grouped_terms = commuting_sets_by_zbasis(sum(pauli_terms)) # measure the terms result_dictionary = {} for key, terms in grouped_terms.items(): pauli_sum, identity_term = remove_identity(terms) if isinstance(identity_term, int): # no identity term pass elif isinstance(identity_term, PauliSum): result_dictionary[identity_term[0].id()] = 1.0 else: print(identity_term, type(identity_term)) raise TypeError("This type is not recognized for identity_term") results = estimate_pauli_sum(pauli_sum, dict(key), program, variance_bound / len(terms), quantum_resource) for idx, term in enumerate(pauli_sum.terms): result_dictionary[term.id()] = results.pauli_expectations[idx] / \ term.coefficient return result_dictionary
def test_estimate_pauli_sum(): """ Full test of the estimation procedures """ quantum_resource = QVMConnection() # type checks with pytest.raises(TypeError): estimate_pauli_sum('5', {0: 'X', 1: 'Z'}, Program(), 1.0E-3, quantum_resource) with pytest.raises(CommutationError): estimate_pauli_sum([sX(0), sY(0)], {0: 'X', 1: 'Z'}, Program(), 1.0E-3, quantum_resource) with pytest.raises(TypeError): estimate_pauli_sum(sX(0), {0: 'X', 1: 'Z'}, Program(), 1.0E-3, quantum_resource) # mock out qvm np.random.seed(87655678) brv1 = bernoulli(p=0.25) brv2 = bernoulli(p=0.4) n = 500 two_qubit_measurements = list(zip(brv1.rvs(size=n), brv2.rvs(size=n))) pauli_terms = [sZ(0), sZ(1), sZ(0) * sZ(1)] fakeQVM = Mock(spec=QVMConnection()) fakeQVM.run = Mock(return_value=two_qubit_measurements) mean, means, cov, estimator_var, shots = estimate_pauli_sum(pauli_terms, {0: 'Z', 1: 'Z'}, Program(), 1.0E-1, fakeQVM) parity_results = np.zeros((len(pauli_terms), n)) parity_results[0, :] = [-2 * x[0] + 1 for x in two_qubit_measurements] parity_results[1, :] = [-2 * x[1] + 1 for x in two_qubit_measurements] parity_results[2, :] = [-2 * (sum(x) % 2) + 1 for x in two_qubit_measurements] assert np.allclose(np.cov(parity_results), cov) assert np.isclose(np.sum(np.mean(parity_results, axis=1)), mean) assert np.allclose(np.mean(parity_results, axis=1), means) assert np.isclose(shots, n) variance_to_beat = np.sum(cov) / n assert np.isclose(variance_to_beat, estimator_var) # Double the shots by ever so slightly decreasing variance bound double_two_q_measurements = two_qubit_measurements + two_qubit_measurements mean, means, cov, estimator_var, shots = estimate_pauli_sum(pauli_terms, {0: 'Z', 1: 'Z'}, Program(), variance_to_beat - \ 1.0E-8, fakeQVM) parity_results = np.zeros((len(pauli_terms), 2 * n)) parity_results[0, :] = [-2 * x[0] + 1 for x in double_two_q_measurements] parity_results[1, :] = [-2 * x[1] + 1 for x in double_two_q_measurements] parity_results[2, :] = [-2 * (sum(x) % 2) + 1 for x in double_two_q_measurements] assert np.allclose(np.cov(parity_results), cov) assert np.isclose(np.sum(np.mean(parity_results, axis=1)), mean) assert np.allclose(np.mean(parity_results, axis=1), means) assert np.isclose(shots, 2 * n) assert np.isclose(np.sum(cov) / (2 * n), estimator_var)
def test_estimate_pauli_sum(): """ Full test of the estimation procedures """ quantum_resource = Mock(QuantumComputer) # type checks with pytest.raises(TypeError): estimate_pauli_sum('5', { 0: 'X', 1: 'Z' }, Program(), 1.0E-3, quantum_resource) with pytest.raises(CommutationError): estimate_pauli_sum([sX(0), sY(0)], { 0: 'X', 1: 'Z' }, Program(), 1.0E-3, quantum_resource) with pytest.raises(TypeError): estimate_pauli_sum(sX(0), { 0: 'X', 1: 'Z' }, Program(), 1.0E-3, quantum_resource) # mock out qvm np.random.seed(87655678) brv1 = bernoulli(p=0.25) brv2 = bernoulli(p=0.4) n = 500 two_qubit_measurements = list(zip(brv1.rvs(size=n), brv2.rvs(size=n))) pauli_terms = [sZ(0), sZ(1), sZ(0) * sZ(1)] with patch("pyquil.api.QuantumComputer") as qc: # Mock the response qc.run.return_value = two_qubit_measurements mean, means, cov, estimator_var, shots = \ estimate_pauli_sum(pauli_terms, basis_transform_dict={0: 'Z', 1: 'Z'}, program=Program(), variance_bound=1.0E-1, quantum_resource=qc) parity_results = np.zeros((len(pauli_terms), n)) parity_results[0, :] = [-2 * x[0] + 1 for x in two_qubit_measurements] parity_results[1, :] = [-2 * x[1] + 1 for x in two_qubit_measurements] parity_results[2, :] = [ -2 * (sum(x) % 2) + 1 for x in two_qubit_measurements ] assert np.allclose(np.cov(parity_results), cov) assert np.isclose(np.sum(np.mean(parity_results, axis=1)), mean) assert np.allclose(np.mean(parity_results, axis=1), means) assert np.isclose(shots, n) variance_to_beat = np.sum(cov) / n assert np.isclose(variance_to_beat, estimator_var) # Double the shots by ever so slightly decreasing variance bound double_two_q_measurements = two_qubit_measurements + two_qubit_measurements mean, means, cov, estimator_var, shots = \ estimate_pauli_sum(pauli_terms, basis_transform_dict={0: 'Z', 1: 'Z'}, program=Program(), variance_bound=variance_to_beat - 1.0E-8, quantum_resource=qc) parity_results = np.zeros((len(pauli_terms), 2 * n)) parity_results[0, :] = [-2 * x[0] + 1 for x in double_two_q_measurements] parity_results[1, :] = [-2 * x[1] + 1 for x in double_two_q_measurements] parity_results[2, :] = [ -2 * (sum(x) % 2) + 1 for x in double_two_q_measurements ] assert np.allclose(np.cov(parity_results), cov) assert np.isclose(np.sum(np.mean(parity_results, axis=1)), mean) assert np.allclose(np.mean(parity_results, axis=1), means) assert np.isclose(shots, 2 * n) assert np.isclose(np.sum(cov) / (2 * n), estimator_var)