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
Exemple #4
0
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))
Exemple #6
0
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
Exemple #15
0
    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
Exemple #16
0
    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))
Exemple #18
0
    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