def get_exact_expectation_values(self, circuit, qubit_operator, **kwargs): """Run a circuit to prepare a wavefunction and measure the exact expectation values with respect to a given operator. Args: circuit (zquantum.core.circuit.Circuit): the circuit to prepare the state qubit_operator (openfermion.ops.QubitOperator): the operator to measure Returns: zquantum.core.measurement.ExpectationValues: the expectation values of each term in the operator """ self.num_circuits_run += 1 self.num_jobs_run += 1 wavefunction = self.get_wavefunction(circuit) # Pyquil does not support PauliSums with no terms. if len(qubit_operator.terms) == 0: return ExpectationValues(np.zeros((0, ))) values = [] for op in qubit_operator: values.append(expectation(op, wavefunction)) return expectation_values_to_real(ExpectationValues( np.asarray(values)))
def get_expectation_values(self, circuit, qubit_operator, **kwargs): """Run a circuit and measure the expectation values with respect to a given operator. Note: the number of bitstrings measured is derived from self.n_samples - if self.n_samples = None, then this will use self.get_exact_expectation_values Args: circuit (zquantum.core.circuit.Circuit): the circuit to prepare the state qubit_operator (openfermion.ops.QubitOperator): the operator to measure Returns: zquantum.core.measurement.ExpectationValues: the expectation values of each term in the operator """ self.num_circuits_run += 1 self.num_jobs_run += 1 if self.n_samples == None: return self.get_exact_expectation_values(circuit, qubit_operator, **kwargs) else: operator = change_operator_type(qubit_operator, IsingOperator) measurements = self.run_circuit_and_measure(circuit) expectation_values = measurements.get_expectation_values(operator) expectation_values = expectation_values_to_real(expectation_values) return expectation_values
def evaluate_operator_for_parameter_grid(ansatz, grid, backend, operator, previous_layer_params=[]): """Evaluate the expectation value of an operator for every set of circuit parameters in the parameter grid. Args: ansatz (dict): the ansatz grid (zquantum.core.circuit.ParameterGrid): The parameter grid containing the parameters for the last layer of the ansatz backend (zquantum.core.interfaces.backend.QuantumSimulator): the backend to run the circuits on operator (openfermion.ops.QubitOperator): the operator previous_layer_params (array): A list of the parameters for previous layers of the ansatz Returns: value_estimate (zquantum.core.utils.ValueEstimate): stores the value of the expectation and its precision optimal_parameters (numpy array): the ansatz parameters representing the ansatz parameters resulting in the best minimum evaluation. If multiple sets of parameters evaluate to the same value, the first set of parameters is chosen as the optimal. """ parameter_grid_evaluation = [] circuitset = [] params_set = [] for last_layer_params in grid.params_list: # Build the ansatz circuit params = np.concatenate( (np.asarray(previous_layer_params), np.asarray(last_layer_params))) # Build the ansatz circuit circuitset.append(ansatz.get_executable_circuit(params)) params_set.append(params) expectation_values_set = backend.get_expectation_values_for_circuitset( circuitset, operator) min_value_estimate = None for params, expectation_values in zip(params_set, expectation_values_set): expectation_values = expectation_values_to_real(expectation_values) value_estimate = ValueEstimate(sum(expectation_values.values)) parameter_grid_evaluation.append({ "value": value_estimate, "parameter1": params[-2], "parameter2": params[-1], }) if min_value_estimate is None: min_value_estimate = value_estimate optimal_parameters = params elif value_estimate.value < min_value_estimate.value: min_value_estimate = value_estimate optimal_parameters = params return parameter_grid_evaluation, optimal_parameters
def get_expectation_values(self, circuit, qubit_operator, **kwargs): if self.n_samples == None: return self.get_exact_expectation_values(circuit, qubit_operator, **kwargs) else: measurements = self.run_circuit_and_measure(circuit) expectation_values = measurements.get_expectation_values(qubit_operator) expectation_values = expectation_values_to_real(expectation_values) return expectation_values
def get_expectation_values(self, circuit, qubit_operator, **kwargs): if self.device_name == 'wavefunction-simulator' and self.n_samples==None: return self.get_exact_expectation_values(circuit, qubit_operator, **kwargs) else: measurements = self.run_circuit_and_measure(circuit, nthreads=self.nthreads) expectation_values = get_expectation_values_from_measurements( measurements, qubit_operator) expectation_values = expectation_values_to_real(expectation_values) return expectation_values
def test_expectation_values_to_real(): # Given expectation_values = ExpectationValues( np.array([0.0 + 0.1j, 0.0 + 1e-10j, -1.0])) target_expectation_values = ExpectationValues(np.array([0.0, 0.0, -1.0])) # When real_expectation_values = expectation_values_to_real(expectation_values) # Then for value in expectation_values.values: assert not isinstance(value, complex) np.testing.assert_array_equal(real_expectation_values.values, target_expectation_values.values)
def _evaluate_solution_for_hamiltonian(solution: Tuple[int], hamiltonian: QubitOperator) -> float: """Evaluates a solution of a hamiltonian by its calculating expectation value. Args: solution: solution to a problem as a tuple of bits hamiltonian: a Hamiltonian representing a problem. Returns: float: value of a solution. """ hamiltonian = change_operator_type(hamiltonian, IsingOperator) expectation_values = expectation_values_to_real( Measurements([solution]).get_expectation_values(hamiltonian)) return sum(expectation_values.values)
def _get_expval(backend, circuit, ops): """Auxiliary function to get the expectation value of a list of operators given a quantum circuit and a quantum backend. In sampling mode, the same measurement outcomes are post-processed for each operator. In exact mode, the statevector prepared by the quantum circuit is simulated separately for each operator. This is required so that the standard ``get_exact_expectation_values`` method of the ``QuantumBackend`` interface can be used. Args: backend (QuantumBackend): the Orquestra quantum backend to use circuit (zquantum.core.circuit.Circuit): the circuit represented as an OpenQASM 2.0 program operators (list): a list of operators as ``openfermion.QubitOperator`` or ``openfermion.IsingOperator`` objects Returns: list: list of expectation values for each operator """ results = [] if backend.n_samples is not None: measurements = backend.run_circuit_and_measure(circuit) # Iterating through the operators specified e.g., [IsingOperator("[Z0] # + [Z1]"), IsingOperator("[Z1]")] to post-process the measurements # outcomes for op in ops: expectation_values = measurements.get_expectation_values(op) expectation_values = expectation_values_to_real(expectation_values) # Summing the expectation values obtained for each term of the # operator yields the expectation value for the operator # E.g., <psi|Z0 + Z1|psi> = <psi|Z0|psi> + <psi|Z1|psi> val = np.sum(expectation_values.values) results.append(val) else: for op in ops: expectation_values = backend.get_exact_expectation_values( circuit, op) val = np.sum(expectation_values.values) results.append(val) return results
def get_expectation_values_for_circuitset(self, circuitset, operator, **kwargs): """Run a set of circuits and measure the expectation values with respect to a given operator. Args: circuitset (list of zquantum.core.circuit.Circuit objects): the circuits to prepare the states operator (openfermion.ops.IsingOperator or openfermion.ops.QubitOperator): the operator to measure Returns: list of zquantum.core.measurement.ExpectationValues objects: a list of the expectation values of each term in the operator with respect to the various state preparation circuits """ self.num_circuits_run += len(circuitset) self.num_jobs_run += 1 operator = change_operator_type(operator, IsingOperator) measurements_set = self.run_circuitset_and_measure(circuitset) expectation_values_set = [] for measurements in measurements_set: expectation_values = measurements.get_expectation_values(operator) expectation_values = expectation_values_to_real(expectation_values) expectation_values_set.append(expectation_values) return expectation_values_set