def _get_9q_square_qvm(connection: ForestConnection, noisy: bool) -> QuantumComputer: """ A nine-qubit 3x3 square lattice. This uses a "generic" lattice not tied to any specific device. 9 qubits is large enough to do vaguely interesting algorithms and small enough to simulate quickly. Users interested in building their own QuantumComputer from parts may wish to look to this function for inspiration, but should not use this private function directly. :param connection: The connection to use to talk to external services :param noisy: Whether to construct a noisy quantum computer :return: A pre-configured QuantumComputer """ nineq_square = nx.convert_node_labels_to_integers(nx.grid_2d_graph(3, 3)) nineq_device = NxDevice(topology=nineq_square) if noisy: noise_model = decoherence_noise_with_asymmetric_ro( gates=gates_in_isa(nineq_device.get_isa())) else: noise_model = None name = '9q-square-noisy-qvm' if noisy else '9q-square-qvm' return QuantumComputer(name=name, qam=QVM(connection=connection, noise_model=noise_model), device=nineq_device, compiler=_get_qvm_compiler_based_on_endpoint( device=nineq_device, endpoint=connection.compiler_endpoint))
def test_measure_bitstrings(client_configuration: QCSClientConfiguration): quantum_processor = NxQuantumProcessor(nx.complete_graph(2)) dummy_compiler = DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration) qc_pyqvm = QuantumComputer(name="testy!", qam=PyQVM(n_qubits=2), compiler=dummy_compiler) qc_forest = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration, gate_noise=(0.00, 0.00, 0.00)), compiler=dummy_compiler, ) prog = Program(I(0), I(1)) meas_qubits = [0, 1] sym_progs, flip_array = _symmetrization(prog, meas_qubits, symm_type=-1) results = _measure_bitstrings(qc_pyqvm, sym_progs, meas_qubits, num_shots=1) # test with pyQVM answer = [ np.array([[0, 0]]), np.array([[0, 1]]), np.array([[1, 0]]), np.array([[1, 1]]) ] assert all([np.allclose(x, y) for x, y in zip(results, answer)]) # test with regular QVM results = _measure_bitstrings(qc_forest, sym_progs, meas_qubits, num_shots=1) assert all([np.allclose(x, y) for x, y in zip(results, answer)])
def test_qc_joint_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10) # ZZ experiment sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]]) e = Experiment(settings=[sz], program=p) results = qc.run_experiment(e) # ZZ expectation value for state |01> is -1 assert np.isclose(results[0].expectation, -1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # Z0 expectation value for state |01> is -1 assert np.isclose(results[0].additional_results[0].expectation, -1) assert results[0].additional_results[1].total_counts == 40 # Z1 expectation value for state |01> is 1 assert np.isclose(results[0].additional_results[1].expectation, 1) assert results[0].additional_results[1].total_counts == 40
def _get_qvm_qc(name: str, device: AbstractDevice, noise_model: NoiseModel = None, requires_executable: bool = False, connection: ForestConnection = None) -> QuantumComputer: """Construct a QuantumComputer backed by a QVM. This is a minimal wrapper over the QuantumComputer, QVM, and QVMCompiler constructors. :param name: A string identifying this particular quantum computer. :param device: A device following the AbstractDevice interface. :param noise_model: An optional noise model :param requires_executable: Whether this QVM will refuse to run a :py:class:`Program` and only accept the result of :py:func:`compiler.native_quil_to_executable`. Setting this to True better emulates the behavior of a QPU. :param connection: An optional :py:class:`ForestConnection` object. If not specified, the default values for URL endpoints will be used. :return: A QuantumComputer backed by a QVM with the above options. """ if connection is None: connection = ForestConnection() return QuantumComputer(name=name, qam=QVM( connection=connection, noise_model=noise_model, requires_executable=requires_executable), device=device, compiler=_get_qvm_compiler_based_on_endpoint( device=device, endpoint=connection.compiler_endpoint))
def _get_unrestricted_qvm(connection: ForestConnection, noisy: bool, n_qubits: int = 34) -> QuantumComputer: """ A qvm with a fully-connected topology. This is obviously the least realistic QVM, but who am I to tell users what they want. Users interested in building their own QuantumComputer from parts may wish to look to this function for inspiration, but should not use this private function directly. :param connection: The connection to use to talk to external services :param noisy: Whether to construct a noisy quantum computer :param n_qubits: 34 qubits ought to be enough for anybody. :return: A pre-configured QuantumComputer """ fully_connected_device = NxDevice(topology=nx.complete_graph(n_qubits)) if noisy: # note to developers: the noise model specifies noise for each possible gate. In a fully # connected topology, there are a lot. noise_model = decoherence_noise_with_asymmetric_ro( gates=gates_in_isa(fully_connected_device.get_isa())) else: noise_model = None name = f'{n_qubits}q-noisy-qvm' if noisy else f'{n_qubits}q-qvm' return QuantumComputer(name=name, qam=QVM(connection=connection, noise_model=noise_model), device=fully_connected_device, compiler=_get_qvm_compiler_based_on_endpoint( device=fully_connected_device, endpoint=connection.compiler_endpoint))
def _get_qvm_or_pyqvm(qvm_type, connection, noise_model=None, device=None, requires_executable=False): if qvm_type == 'qvm': return QVM(connection=connection, noise_model=noise_model, requires_executable=requires_executable) elif qvm_type == 'pyqvm': return PyQVM(n_qubits=device.qubit_topology().number_of_nodes()) raise ValueError("Unknown qvm type {}".format(qvm_type))
def _get_qvm_or_pyqvm( *, client_configuration: QCSClientConfiguration, qvm_type: str, noise_model: Optional[NoiseModel], quantum_processor: Optional[AbstractQuantumProcessor], execution_timeout: float, ) -> Union[QVM, PyQVM]: if qvm_type == "qvm": return QVM(noise_model=noise_model, timeout=execution_timeout, client_configuration=client_configuration) elif qvm_type == "pyqvm": assert quantum_processor is not None return PyQVM( n_qubits=quantum_processor.qubit_topology().number_of_nodes()) raise ValueError("Unknown qvm type {}".format(qvm_type))
def test_run_with_bad_parameters(client_configuration: QCSClientConfiguration, param): quantum_processor = NxQuantumProcessor(nx.complete_graph(3)) qc = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration), compiler=DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration), ) executable = Program( Declare(name="theta", memory_type="REAL"), Declare(name="ro", memory_type="BIT"), RX(MemoryReference("theta"), 0), MEASURE(0, MemoryReference("ro")), ).wrap_in_numshots_loop(1000) with pytest.raises(TypeError, match=r"Parameter must be"): executable.write_memory(region_name="theta", value=param)
def test_qc_expectation_larger_lattice( client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) q0 = 2 q1 = 3 # bell state program p = Program() p += RESET() p += H(q0) p += CNOT(q0, q1) p.wrap_in_numshots_loop(10) # XX, YY, ZZ experiment sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(q0) * sZ(q1)), out_operator=sX(q0) * sX(q1)) sy = ExperimentSetting(in_state=_pauli_to_product_state(sZ(q0) * sZ(q1)), out_operator=sY(q0) * sY(q1)) sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(q0) * sZ(q1)), out_operator=sZ(q0) * sZ(q1)) e = Experiment(settings=[sx, sy, sz], program=p) results = qc.run_experiment(e) # XX expectation value for bell state |00> + |11> is 1 assert np.isclose(results[0].expectation, 1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # YY expectation value for bell state |00> + |11> is -1 assert np.isclose(results[1].expectation, -1) assert np.isclose(results[1].std_err, 0) assert results[1].total_counts == 40 # ZZ expectation value for bell state |00> + |11> is 1 assert np.isclose(results[2].expectation, 1) assert np.isclose(results[2].std_err, 0) assert results[2].total_counts == 40
def test_reset(client_configuration: QCSClientConfiguration): quantum_processor = NxQuantumProcessor(nx.complete_graph(3)) qc = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration), compiler=DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration), ) p = Program( Declare(name="theta", memory_type="REAL"), Declare(name="ro", memory_type="BIT"), RX(MemoryReference("theta"), 0), MEASURE(0, MemoryReference("ro")), ).wrap_in_numshots_loop(10) p.write_memory(region_name="theta", value=np.pi) result = qc.qam.run(p) aref = ParameterAref(name="theta", index=0) assert p._memory.values[aref] == np.pi assert result.readout_data["ro"].shape == (10, 1) assert all([bit == 1 for bit in result.readout_data["ro"]])
def test_run_with_parameters(client_configuration: QCSClientConfiguration, param): quantum_processor = NxQuantumProcessor(nx.complete_graph(3)) qc = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration), compiler=DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration), ) executable = Program( Declare(name="theta", memory_type="REAL"), Declare(name="ro", memory_type="BIT"), RX(MemoryReference("theta"), 0), MEASURE(0, MemoryReference("ro")), ).wrap_in_numshots_loop(1000) executable.write_memory(region_name="theta", value=param) bitstrings = qc.run(executable).readout_data.get("ro") assert bitstrings.shape == (1000, 1) assert all([bit == 1 for bit in bitstrings])
def test_qc_expectation_on_qvm(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): # regression test for https://github.com/rigetti/forest-tutorials/issues/2 qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) p = Program() theta = p.declare("theta", "REAL") p += RESET() p += RY(theta, 0) p.wrap_in_numshots_loop(10000) sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sX(0)) e = Experiment(settings=[sx], program=p) thetas = [-np.pi / 2, 0.0, np.pi / 2] results = [] # Verify that multiple calls to qc.experiment with the same experiment backed by a QVM that # requires_exectutable does not raise an exception. for theta in thetas: results.append(qc.run_experiment(e, memory_map={"theta": [theta]})) assert np.isclose(results[0][0].expectation, -1.0, atol=0.01) assert np.isclose(results[0][0].std_err, 0) assert results[0][0].total_counts == 20000 # bounds on atol and std_err here are a little loose to try and avoid test flakiness. assert np.isclose(results[1][0].expectation, 0.0, atol=0.1) assert results[1][0].std_err < 0.01 assert results[1][0].total_counts == 20000 assert np.isclose(results[2][0].expectation, 1.0, atol=0.01) assert np.isclose(results[2][0].std_err, 0) assert results[2][0].total_counts == 20000
def test_readout_symmetrization(client_configuration: QCSClientConfiguration): quantum_processor = NxQuantumProcessor(nx.complete_graph(3)) noise_model = decoherence_noise_with_asymmetric_ro( quantum_processor.to_compiler_isa()) qc = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration, noise_model=noise_model), compiler=DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration), ) prog = Program( Declare("ro", "BIT", 2), I(0), X(1), MEASURE(0, MemoryReference("ro", 0)), MEASURE(1, MemoryReference("ro", 1)), ) prog.wrap_in_numshots_loop(1000) result_1 = qc.run(prog) bitstrings_1 = result_1.readout_data.get("ro") avg0_us = np.mean(bitstrings_1[:, 0]) avg1_us = 1 - np.mean(bitstrings_1[:, 1]) diff_us = avg1_us - avg0_us assert diff_us > 0.03 prog = Program( I(0), X(1), ) bitstrings_2 = qc.run_symmetrized_readout(prog, 1000) avg0_s = np.mean(bitstrings_2[:, 0]) avg1_s = 1 - np.mean(bitstrings_2[:, 1]) diff_s = avg1_s - avg0_s assert diff_s < 0.05
def test_run(client_configuration: QCSClientConfiguration): quantum_processor = NxQuantumProcessor(nx.complete_graph(3)) qc = QuantumComputer( name="testy!", qam=QVM(client_configuration=client_configuration, gate_noise=(0.01, 0.01, 0.01)), compiler=DummyCompiler(quantum_processor=quantum_processor, client_configuration=client_configuration), ) result = qc.run( Program( Declare("ro", "BIT", 3), H(0), CNOT(0, 1), CNOT(1, 2), MEASURE(0, MemoryReference("ro", 0)), MEASURE(1, MemoryReference("ro", 1)), MEASURE(2, MemoryReference("ro", 2)), ).wrap_in_numshots_loop(1000)) bitstrings = result.readout_data.get("ro") assert bitstrings.shape == (1000, 3) parity = np.sum(bitstrings, axis=1) % 3 assert 0 < np.mean(parity) < 0.15
def __init__(self, clauses, m=None, steps=1, grid_size=None, tol=1e-5, gate_noise=None, verbose=False, visualize=False): self.clauses = clauses self.m = m self.verbose = verbose self.visualize = visualize self.step_by_step_results = None self.optimization_history = None self.gate_noise = gate_noise if grid_size is None: self.grid_size = len(clauses) + len(qubits) else: self.grid_size = grid_size cost_operators, mapping = self.create_operators_from_clauses() self.mapping = mapping driver_operators = self.create_driver_operators() # minimizer_kwargs = {'method': 'BFGS', # 'options': {'gtol': tol, 'disp': False}} # bounds = [(0, np.pi)]*steps + [(0, 2*np.pi)]*steps # minimizer_kwargs = {'method': 'L-BFGS-B', # 'options': {'gtol': tol, 'disp': False}, # 'bounds': bounds} minimizer_kwargs = { 'method': 'Nelder-Mead', 'options': { 'ftol': tol, 'tol': tol, 'disp': False } } if self.verbose: print_fun = print else: print_fun = pass_fun qubits = list(range(len(mapping))) if gate_noise: self.samples = int(1e3) pauli_channel = [gate_noise] * 3 else: self.samples = None pauli_channel = None connection = ForestConnection() qvm = QVM(connection=connection, gate_noise=pauli_channel) topology = nx.complete_graph(len(qubits)) device = NxDevice(topology=topology) qc = QuantumComputer(name="my_qvm", qam=qvm, device=device, compiler=QVMCompiler( device=device, endpoint=connection.compiler_endpoint)) vqe_option = { 'disp': print_fun, 'return_all': True, 'samples': self.samples } self.qaoa_inst = QAOA(qc, qubits, steps=steps, init_betas=None, init_gammas=None, cost_ham=cost_operators, ref_ham=driver_operators, minimizer=scipy.optimize.minimize, minimizer_kwargs=minimizer_kwargs, rand_seed=None, vqe_options=vqe_option, store_basis=True) self.ax = None
def vqe_run(self, variational_state_evolve, hamiltonian, initial_params, gate_noise=None, measurement_noise=None, jacobian=None, qc=None, disp=None, samples=None, return_all=False): """ functional minimization loop. :param variational_state_evolve: function that takes a set of parameters and returns a pyQuil program. :param hamiltonian: (PauliSum) object representing the hamiltonian of which to take the expectation value. :param initial_params: (ndarray) vector of initial parameters for the optimization :param gate_noise: list of Px, Py, Pz probabilities of gate being applied to every gate after each get application :param measurement_noise: list of Px', Py', Pz' probabilities of a X, Y or Z being applied before a measurement. :param jacobian: (optional) method of generating jacobian for parameters (Default=None). :param qc: (optional) QuantumComputer object. :param disp: (optional, bool) display level. If True then each iteration expectation and parameters are printed at each optimization iteration. :param samples: (int) Number of samples for calculating the expectation value of the operators. If `None` then faster method ,dotting the wave function with the operator, is used. Default=None. :param return_all: (optional, bool) request to return all intermediate parameters determined during the optimization. :return: (vqe.OptResult()) object :func:`OptResult <vqe.OptResult>`. The following fields are initialized in OptResult: -x: set of w.f. ansatz parameters -fun: scalar value of the objective function -iteration_params: a list of all intermediate parameter vectors. Only returned if 'return_all=True' is set as a vqe_run() option. -expectation_vals: a list of all intermediate expectation values. Only returned if 'return_all=True' is set as a vqe_run() option. """ self._disp_fun = disp if disp is not None else lambda x: None iteration_params = [] expectation_vals = [] self._current_expectation = None if samples is None: print("""WARNING: Fast method for expectation will be used. Noise models will be ineffective""") if qc is None: qubits = hamiltonian.get_qubits() qc = QuantumComputer(name=f"{len(qubits)}q-noisy-qvm", qam=QVM(gate_noise=gate_noise, measurement_noise=measurement_noise)) else: self.qc = qc def objective_function(params): """ closure representing the functional :param params: (ndarray) vector of parameters for generating the the function of the functional. :return: (float) expectation value """ pyquil_prog = variational_state_evolve(params) mean_value = self.expectation(pyquil_prog, hamiltonian, samples, qc) self._current_expectation = mean_value # store for printing return mean_value def print_current_iter(iter_vars): self._disp_fun("\tParameters: {} ".format(iter_vars)) if jacobian is not None: grad = jacobian(iter_vars) self._disp_fun("\tGrad-L1-Norm: {}".format(np.max( np.abs(grad)))) self._disp_fun("\tGrad-L2-Norm: {} ".format( np.linalg.norm(grad))) self._disp_fun("\tE => {}".format(self._current_expectation)) if return_all: iteration_params.append(iter_vars) expectation_vals.append(self._current_expectation) # using self.minimizer arguments = funcsigs.signature(self.minimizer).parameters.keys() if disp is not None and 'callback' in arguments: self.minimizer_kwargs['callback'] = print_current_iter args = [objective_function, initial_params] args.extend(self.minimizer_args) if 'jac' in arguments: self.minimizer_kwargs['jac'] = jacobian result = self.minimizer(*args, **self.minimizer_kwargs) if hasattr(result, 'status'): if result.status != 0: self._disp_fun( "Classical optimization exited with an error index: %i" % result.status) results = OptResults() if hasattr(result, 'x'): results.x = result.x results.fun = result.fun else: results.x = result if return_all: results.iteration_params = iteration_params results.expectation_vals = expectation_vals return results
def get_qc(name: str, *, as_qvm: bool = None, noisy: bool = None, connection: ForestConnection = None) -> QuantumComputer: """ Get a quantum computer. A quantum computer is an object of type :py:class:`QuantumComputer` and can be backed either by a QVM simulator ("Quantum/Quil Virtual Machine") or a physical Rigetti QPU ("Quantum Processing Unit") made of superconducting qubits. You can choose the quantum computer to target through a combination of its name and optional flags. There are multiple ways to get the same quantum computer. The following are equivalent:: >>> qc = get_qc("Aspen-0-12Q-A-noisy-qvm") >>> qc = get_qc("Aspen-0-12Q-A", as_qvm=True, noisy=True) and will construct a simulator of the 8q-agave chip with a noise model based on device characteristics. We also provide a means for constructing generic quantum simulators that are not related to a given piece of Rigetti hardware:: >>> qc = get_qc("9q-square-qvm") >>> qc = get_qc("9q-square", as_qvm=True) Finally, you can get request a QVM with "no" topology of a given number of qubits (technically, it's a fully connected graph among the given number of qubits) with:: >>> qc = get_qc("5q-qvm") # or "6q-qvm", or "34q-qvm", ... Redundant flags are acceptable, but conflicting flags will raise an exception:: >>> qc = get_qc("9q-square-qvm") # qc is fully specified by its name >>> qc = get_qc("9q-square-qvm", as_qvm=True) # redundant, but ok >>> qc = get_qc("9q-square-qvm", as_qvm=False) # Error! Use :py:func:`list_quantum_computers` to retrieve a list of known qc names. This method is provided as a convenience to quickly construct and use QVM's and QPU's. Power users may wish to have more control over the specification of a quantum computer (e.g. custom noise models, bespoke topologies, etc.). This is possible by constructing a :py:class:`QuantumComputer` object by hand. Please refer to the documentation on :py:class:`QuantumComputer` for more information. :param name: The name of the desired quantum computer. This should correspond to a name returned by :py:func:`list_quantum_computers`. Names ending in "-qvm" will return a QVM. Names ending in "-noisy-qvm" will return a QVM with a noise model. Otherwise, we will return a QPU with the given name. :param as_qvm: An optional flag to force construction of a QVM (instead of a QPU). If specified and set to ``True``, a QVM-backed quantum computer will be returned regardless of the name's suffix :param noisy: An optional flag to force inclusion of a noise model. If specified and set to ``True``, a quantum computer with a noise model will be returned regardless of the name's suffix. The noise model for QVM's based on a real QPU is an empirically parameterized model based on real device noise characteristics. The generic QVM noise model is simple T1 and T2 noise plus readout error. See :py:func:`decoherance_noise_with_asymmetric_ro`. :param connection: An optional :py:class:ForestConnection` object. If not specified, the default values for URL endpoints, ping time, and status time will be used. Your user id and API key will be read from ~/.pyquil_config. If you deign to change any of these parameters, pass your own :py:class:`ForestConnection` object. :return: """ if connection is None: connection = ForestConnection() full_name = name name, as_qvm, noisy = _parse_name(name, as_qvm, noisy) ma = re.fullmatch(r'(\d+)q', name) if ma is not None: n_qubits = int(ma.group(1)) if not as_qvm: raise ValueError("Please name a valid device or run as a QVM") return _get_unrestricted_qvm(connection=connection, noisy=noisy, n_qubits=n_qubits) if name == '9q-generic' or name == '9q-square': if name == '9q-generic': warnings.warn("Please prefer '9q-square' instead of '9q-generic'", DeprecationWarning) if not as_qvm: raise ValueError( "The device '9q-square' is only available as a QVM") return _get_9q_square_qvm(connection=connection, noisy=noisy) device = get_lattice(name) if not as_qvm: if noisy is not None and noisy: warnings.warn( "You have specified `noisy=True`, but you're getting a QPU. This flag " "is meant for controlling noise models on QVMs.") return QuantumComputer(name=full_name, qam=QPU(endpoint=pyquil_config.qpu_url, user=pyquil_config.user_id), device=device, compiler=QPUCompiler( endpoint=pyquil_config.compiler_url, device=device)) if noisy: noise_model = device.noise_model else: noise_model = None return QuantumComputer(name=full_name, qam=QVM(connection=connection, noise_model=noise_model), device=device, compiler=_get_qvm_compiler_based_on_endpoint( device=device, endpoint=connection.compiler_endpoint))
def vqe_run(self, variational_state_evolve, hamiltonian, initial_params, gate_noise=None, measurement_noise=None, jacobian=None, qc=None, disp=False, samples=None, return_all=False, callback=None, max_meas=np.inf): """ functional minimization loop. :param variational_state_evolve: function that takes a set of parameters and returns a pyQuil program. :param hamiltonian: (PauliSum) object representing the hamiltonian of which to take the expectation value. :param initial_params: (ndarray) vector of initial parameters for the optimization :param gate_noise: list of Px, Py, Pz probabilities of gate being applied to every gate after each get application :param measurement_noise: list of Px', Py', Pz' probabilities of a X, Y or Z being applied before a measurement. :param jacobian: (optional) method of generating jacobian for parameters (Default=None). :param qc: (optional) QuantumComputer object. :param disp: (optional, bool/callable) display level. If True then each iteration expectation and parameters are printed at each optimization iteration. If callable, called after each iteration. The signature: ``disp(xk, state)`` where ``xk`` is the current parameter vector. and ``state`` is the current expectation value. :param samples: (int) Number of samples for calculating the expectation value of the operators. If `None` then faster method ,dotting the wave function with the operator, is used. Default=None. :param return_all: (optional, bool) request to return all intermediate parameters determined during the optimization. :return: (vqe.OptResult()) object :func:`OptResult <vqe.OptResult>`. The following fields are initialized in OptResult: -x: set of w.f. ansatz parameters -fun: scalar value of the objective function -iteration_params: a list of all intermediate parameter vectors. Only returned if 'return_all=True' is set as a vqe_run() option. -expectation_vals: a list of all intermediate expectation values. Only returned if 'return_all=True' is set as a vqe_run() option. """ """ if (disp is not None and disp is not True and disp is not False): self._disp_fun = disp else: pass """ if samples is not None and max_meas <= samples: raise ValueError('Need more than one fun eval.') self._disp_fun = print iteration_params = [] expectation_vals = [] expectation_vars = [] fun_evals = 0 meas = 0 restarts = 0 callback_idx = [] # Problem: expectation_vals did not (for Nelder-Mead in # scipy.optimize) correspond to objective_function( self._current_expectation = None self._current_variance = None if qc is None: qubits = hamiltonian.get_qubits() qc = QuantumComputer(name=f"{len(qubits)}q-noisy-qvm", qam=QVM(gate_noise=gate_noise, measurement_noise=measurement_noise)) else: self.qc = qc coeffs = np.array([term.coefficient for term in hamiltonian.terms]) sample_list = calc_samples(samples, coeffs) def objective_function(params): """ closure representing the functional :param params: (ndarray) vector of parameters for generating the the function of the functional. :return: (float) expectation value """ pyquil_prog = variational_state_evolve(params) mean_value, tmp_vars = self.expectation(pyquil_prog, hamiltonian, sample_list, qc) self._current_variance = tmp_vars self._current_expectation = mean_value # store for printing # Save params, exp_val and exp_var iteration_params.append(params) expectation_vals.append(mean_value) expectation_vars.append(tmp_vars) nonlocal fun_evals, meas fun_evals += 1 if samples is not None: meas += samples if meas >= max_meas: raise RestartError # attempt restart and break while below return mean_value def print_current_iter(iter_vars): self._disp_fun('\nFunction evaluations: {}'.format(fun_evals)) self._disp_fun("Parameters: {} ".format(iter_vars)) if jacobian is not None: grad = jacobian(iter_vars) self._disp_fun( "\tGrad-L1-Norm: {}".format(np.max(np.abs(grad)))) self._disp_fun( "\tGrad-L2-Norm: {} ".format(np.linalg.norm(grad))) self._disp_fun("E => {}".format(self._current_expectation)) # using self.minimizer arguments = funcsigs.signature(self.minimizer).parameters.keys() if callback is None: def callback(*args, **kwargs): pass def wrap_callbacks(iter_vars, *args, **kwargs): # save values callback_idx.append(fun_evals-1) # display if disp is True: print_current_iter(iter_vars) # call VQE's callback callback(iteration_params, expectation_vals, expectation_vars) if 'callback' in arguments: self.minimizer_kwargs['callback'] = wrap_callbacks args = [objective_function, initial_params] args.extend(self.minimizer_args) if 'jac' in arguments: self.minimizer_kwargs['jac'] = jacobian results = OptResults() result = None while meas < max_meas: break_ = True try: result = self.minimizer(*args, **self.minimizer_kwargs) except BreakError: results.status = -1 results.message = 'Stopped by BreakError.' except RestartError as e: restarts += 1 break_ = False args[1] = iteration_params[int(np.argmin(expectation_vals))] if e.samples is not None: samples = e.samples sample_list = calc_samples(samples, coeffs) else: results.status = 0 results.message = 'Minimizer stopped naturally.' if hasattr(result, 'status'): if result.status != 0: self._disp_fun( "Classical optimization exited with an error index: %i" % result.status) if hasattr(result, 'x'): results.x = result.x results.fun = result.fun else: results.x = result results.fun = expectation_vals[-1] if break_: break else: results.status = 1 results.message = 'Exceeded maximum number of measurements.' if disp: print(f"Exceeded maximum of {max_meas} measurements" f"and terminated.") # Save results in case of Break- or RestartError if not hasattr(results, 'x'): idx = int(np.argmin(expectation_vals)) results.x = iteration_params[idx] results.fun = expectation_vals[idx] if return_all: # Convert to ndarray for better indexing options (se bellow) iteration_params = np.array(iteration_params) expectation_vals = np.array(expectation_vals) expectation_vars = np.array(expectation_vars) # From each time callback is called results.iteration_params = iteration_params[callback_idx] results.expectation_vals = expectation_vals[callback_idx] results.expectation_vars = expectation_vars[callback_idx] # From every function evaluation results.iteration_params_all = iteration_params results.expectation_vals_all = expectation_vals results.expectation_vars_all = expectation_vars results.fun_evals = fun_evals results.meas = meas results.restarts = restarts # Return last model from bayes if hasattr(result, 'models') and hasattr(result, 'space'): results.bayes_special = [result.models[-1], result.space] # x_gp = results.x # if isinstance(x_gp, np.ndarray): # x_gp = [x_gp.tolist()] # x_gp = result.space.transform(x_gp) # try: # Ugly code (seems like we get an index error here) # gp = result.models[-1] # except: # print('Failed on gp = result.models[-1] in vqe_override') # fun, var = gp.predict(x_gp, return_std=True) # results.var = var return results