コード例 #1
0
def _get_qvm_qc(name: str,
                qvm_type: 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 qvm_type: The type of QVM. Either qvm or pyqvm.
    :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=_get_qvm_or_pyqvm(qvm_type=qvm_type,
                              connection=connection,
                              noise_model=noise_model,
                              device=device,
                              requires_executable=requires_executable),
        device=device,
        compiler=QVMCompiler(device=device,
                             endpoint=connection.compiler_endpoint))
コード例 #2
0
def _get_qvm_compiler_based_on_endpoint(endpoint=None, device=None):
    if endpoint.startswith("http"):
        return LocalQVMCompiler(endpoint=endpoint, device=device)
    elif endpoint.startswith("tcp"):
        return QVMCompiler(endpoint=endpoint, device=device)
    else:
        raise ValueError(
            "Protocol for QVM compiler endpoints must be HTTP or TCP.")
コード例 #3
0
def _get_qvm_qc(
    *,
    client_configuration: QCSClientConfiguration,
    name: str,
    qvm_type: str,
    quantum_processor: AbstractQuantumProcessor,
    compiler_timeout: float,
    execution_timeout: float,
    noise_model: Optional[NoiseModel],
) -> QuantumComputer:
    """Construct a QuantumComputer backed by a QVM.

    This is a minimal wrapper over the QuantumComputer, QVM, and QVMCompiler constructors.

    :param client_configuration: Client configuration.
    :param name: A string identifying this particular quantum computer.
    :param qvm_type: The type of QVM. Either qvm or pyqvm.
    :param quantum_processor: A quantum_processor following the AbstractQuantumProcessor interface.
    :param noise_model: An optional noise model
    :param compiler_timeout: Time limit for compilation requests, in seconds.
    :param execution_timeout: Time limit for execution requests, in seconds.
    :return: A QuantumComputer backed by a QVM with the above options.
    """

    return QuantumComputer(
        name=name,
        qam=_get_qvm_or_pyqvm(
            client_configuration=client_configuration,
            qvm_type=qvm_type,
            noise_model=noise_model,
            quantum_processor=quantum_processor,
            execution_timeout=execution_timeout,
        ),
        compiler=QVMCompiler(
            quantum_processor=quantum_processor,
            timeout=compiler_timeout,
            client_configuration=client_configuration,
        ),
    )
コード例 #4
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
コード例 #5
0
ファイル: _qvm.py プロジェクト: kylegulshen/pyquil
    def __init__(self,
                 device=None,
                 endpoint=None,
                 gate_noise=None,
                 measurement_noise=None,
                 random_seed=None,
                 compiler_endpoint=None):
        """
        Constructor for QVMConnection. Sets up any necessary security, and establishes the noise
        model to use.

        :param Device device: The optional device, from which noise will be added by default to all
                              programs run on this instance.
        :param endpoint: The endpoint of the server for running small jobs
        :param gate_noise: A list of three numbers [Px, Py, Pz] indicating the probability of an X,
                           Y, or Z gate getting applied to each qubit after a gate application or
                           reset. (default None)
        :param measurement_noise: A list of three numbers [Px, Py, Pz] indicating the probability of
                                  an X, Y, or Z gate getting applied before a a measurement.
                                  (default None)
        :param random_seed: A seed for the QVM's random number generators. Either None (for an
                            automatically generated seed) or a non-negative integer.
        """
        if endpoint is None:
            pyquil_config = PyquilConfig()
            endpoint = pyquil_config.qvm_url

        if compiler_endpoint is None:
            pyquil_config = PyquilConfig()
            compiler_endpoint = pyquil_config.quilc_url

        if (device is not None and device.noise_model is not None) and \
                (gate_noise is not None or measurement_noise is not None):
            raise ValueError("""
You have attempted to supply the QVM with both a device noise model
(by having supplied a device argument), as well as either gate_noise
or measurement_noise. At this time, only one may be supplied.

To read more about supplying noise to the QVM, see http://pyquil.readthedocs.io/en/latest/noise_models.html#support-for-noisy-gates-on-the-rigetti-qvm.
""")

        if device is not None and device.noise_model is None:
            warnings.warn("""
You have supplied the QVM with a device that does not have a noise model. No noise will be added to
programs run on this QVM.
""")

        self.noise_model = device.noise_model if device else None
        self.compiler = QVMCompiler(endpoint=compiler_endpoint, device=device) if device \
            else None

        self.sync_endpoint = endpoint

        validate_noise_probabilities(gate_noise)
        validate_noise_probabilities(measurement_noise)
        self.gate_noise = gate_noise
        self.measurement_noise = measurement_noise

        if random_seed is None:
            self.random_seed = None
        elif isinstance(random_seed, int) and random_seed >= 0:
            self.random_seed = random_seed
        else:
            raise TypeError("random_seed should be None or a non-negative int")

        self._connection = ForestConnection(sync_endpoint=endpoint)
        self.session = self._connection.session  # backwards compatibility
        self.connect()
コード例 #6
0
ファイル: _qvm.py プロジェクト: kylegulshen/pyquil
class QVMConnection(object):
    """
    Represents a connection to the QVM.
    """
    @_record_call
    def __init__(self,
                 device=None,
                 endpoint=None,
                 gate_noise=None,
                 measurement_noise=None,
                 random_seed=None,
                 compiler_endpoint=None):
        """
        Constructor for QVMConnection. Sets up any necessary security, and establishes the noise
        model to use.

        :param Device device: The optional device, from which noise will be added by default to all
                              programs run on this instance.
        :param endpoint: The endpoint of the server for running small jobs
        :param gate_noise: A list of three numbers [Px, Py, Pz] indicating the probability of an X,
                           Y, or Z gate getting applied to each qubit after a gate application or
                           reset. (default None)
        :param measurement_noise: A list of three numbers [Px, Py, Pz] indicating the probability of
                                  an X, Y, or Z gate getting applied before a a measurement.
                                  (default None)
        :param random_seed: A seed for the QVM's random number generators. Either None (for an
                            automatically generated seed) or a non-negative integer.
        """
        if endpoint is None:
            pyquil_config = PyquilConfig()
            endpoint = pyquil_config.qvm_url

        if compiler_endpoint is None:
            pyquil_config = PyquilConfig()
            compiler_endpoint = pyquil_config.quilc_url

        if (device is not None and device.noise_model is not None) and \
                (gate_noise is not None or measurement_noise is not None):
            raise ValueError("""
You have attempted to supply the QVM with both a device noise model
(by having supplied a device argument), as well as either gate_noise
or measurement_noise. At this time, only one may be supplied.

To read more about supplying noise to the QVM, see http://pyquil.readthedocs.io/en/latest/noise_models.html#support-for-noisy-gates-on-the-rigetti-qvm.
""")

        if device is not None and device.noise_model is None:
            warnings.warn("""
You have supplied the QVM with a device that does not have a noise model. No noise will be added to
programs run on this QVM.
""")

        self.noise_model = device.noise_model if device else None
        self.compiler = QVMCompiler(endpoint=compiler_endpoint, device=device) if device \
            else None

        self.sync_endpoint = endpoint

        validate_noise_probabilities(gate_noise)
        validate_noise_probabilities(measurement_noise)
        self.gate_noise = gate_noise
        self.measurement_noise = measurement_noise

        if random_seed is None:
            self.random_seed = None
        elif isinstance(random_seed, int) and random_seed >= 0:
            self.random_seed = random_seed
        else:
            raise TypeError("random_seed should be None or a non-negative int")

        self._connection = ForestConnection(sync_endpoint=endpoint)
        self.session = self._connection.session  # backwards compatibility
        self.connect()

    def connect(self):
        try:
            version_dict = self.get_version_info()
            check_qvm_version(version_dict)
        except ConnectionError:
            raise QVMNotRunning(
                f'No QVM server running at {self._connection.sync_endpoint}')

    @_record_call
    def get_version_info(self):
        """
        Return version information for the QVM.

        :return: Dictionary with version information
        """
        return self._connection._qvm_get_version_info()

    @_record_call
    def run(self,
            quil_program,
            classical_addresses: List[int] = None,
            trials=1):
        """
        Run a Quil program multiple times, accumulating the values deposited in
        a list of classical addresses.

        :param Program quil_program: A Quil program.
        :param classical_addresses: The classical memory to retrieve. Specified as a list of
            integers that index into a readout register named ``ro``. This function--and
            particularly this argument--are included for backwards compatibility and will
            be removed in the future.
        :param int trials: Number of shots to collect.
        :return: A list of dictionaries of bits. Each dictionary corresponds to the values in
            `classical_addresses`.
        :rtype: list
        """
        if classical_addresses is None:
            caddresses = get_classical_addresses_from_program(quil_program)

        else:
            caddresses = {'ro': classical_addresses}

        buffers = self._connection._qvm_run(quil_program, caddresses, trials,
                                            self.measurement_noise,
                                            self.gate_noise, self.random_seed)

        if len(buffers) == 0:
            return []
        if 'ro' in buffers:
            return buffers['ro'].tolist()

        raise ValueError(
            "You are using QVMConnection.run with multiple readout registers not "
            "named `ro`. Please use the new `QuantumComputer` abstraction.")

    @_record_call
    def run_and_measure(self, quil_program, qubits, trials=1):
        """
        Run a Quil program once to determine the final wavefunction, and measure multiple times.

        :note: If the execution of ``quil_program`` is **non-deterministic**, i.e., if it includes
            measurements and/or noisy quantum gates, then the final wavefunction from which the
            returned bitstrings are sampled itself only represents a stochastically generated sample
            and the outcomes sampled from *different* ``run_and_measure`` calls *generally sample
            different bitstring distributions*.

        :param Program quil_program: A Quil program.
        :param list|range qubits: A list of qubits.
        :param int trials: Number of shots to collect.
        :return: A list of a list of bits.
        :rtype: list
        """
        # Developer note: This code is for backwards compatibility. It can't be replaced with
        # ForestConnection._run_and_measure because we've turned off the ability to set
        # `needs_compilation` (that usually indicates the user is doing something iffy like
        # using a noise model with this function)

        payload = self._run_and_measure_payload(quil_program, qubits, trials)
        response = post_json(self.session, self.sync_endpoint + "/qvm",
                             payload)
        return response.json()

    @_record_call
    def _run_and_measure_payload(self, quil_program, qubits, trials):
        if not quil_program:
            raise ValueError(
                "You have attempted to run an empty program."
                " Please provide gates or measure instructions to your program."
            )

        if not isinstance(quil_program, Program):
            raise TypeError("quil_program must be a Quil program object")
        qubits = validate_qubit_list(qubits)
        if not isinstance(trials, int):
            raise TypeError("trials must be an integer")

        if self.noise_model is not None:
            compiled_program = self.compiler.quil_to_native_quil(quil_program)
            quil_program = apply_noise_model(compiled_program,
                                             self.noise_model)

        payload = {
            "type": TYPE_MULTISHOT_MEASURE,
            "qubits": list(qubits),
            "trials": trials,
            "compiled-quil": quil_program.out()
        }

        self._maybe_add_noise_to_payload(payload)
        self._add_rng_seed_to_payload(payload)

        return payload

    @_record_call
    def wavefunction(self, quil_program):
        """
        Simulate a Quil program and get the wavefunction back.

        :note: If the execution of ``quil_program`` is **non-deterministic**, i.e., if it includes
            measurements and/or noisy quantum gates, then the final wavefunction from which the
            returned bitstrings are sampled itself only represents a stochastically generated sample
            and the wavefunctions returned by *different* ``wavefunction`` calls *will generally be
            different*.

        :param Program quil_program: A Quil program.
        :return: A Wavefunction object representing the state of the QVM.
        :rtype: Wavefunction
        """
        # Developer note: This code is for backwards compatibility. It can't be replaced with
        # ForestConnection._wavefunction because we've turned off the ability to set
        # `needs_compilation` (that usually indicates the user is doing something iffy like
        # using a noise model with this function)

        payload = self._wavefunction_payload(quil_program)
        response = post_json(self.session, self.sync_endpoint + "/qvm",
                             payload)
        return Wavefunction.from_bit_packed_string(response.content)

    @_record_call
    def _wavefunction_payload(self, quil_program):
        # Developer note: This code is for backwards compatibility. It can't be replaced with
        # _base_connection._wavefunction_payload because we've turned off the ability to set
        # `needs_compilation` (that usually indicates the user is doing something iffy like
        # using a noise model with this function)
        if not isinstance(quil_program, Program):
            raise TypeError("quil_program must be a Quil program object")

        payload = {
            'type': TYPE_WAVEFUNCTION,
            'compiled-quil': quil_program.out()
        }

        self._maybe_add_noise_to_payload(payload)
        self._add_rng_seed_to_payload(payload)

        return payload

    @_record_call
    def expectation(self, prep_prog, operator_programs=None):
        """
        Calculate the expectation value of operators given a state prepared by
        prep_program.

        :note: If the execution of ``quil_program`` is **non-deterministic**, i.e., if it includes
            measurements and/or noisy quantum gates, then the final wavefunction from which the
            expectation values are computed itself only represents a stochastically generated
            sample. The expectations returned from *different* ``expectation`` calls *will then
            generally be different*.

        To measure the expectation of a PauliSum, you probably want to
        do something like this::

                progs, coefs = hamiltonian.get_programs()
                expect_coeffs = np.array(cxn.expectation(prep_program, operator_programs=progs))
                return np.real_if_close(np.dot(coefs, expect_coeffs))

        :param Program prep_prog: Quil program for state preparation.
        :param list operator_programs: A list of Programs, each specifying an operator whose expectation to compute.
            Default is a list containing only the empty Program.
        :return: Expectation values of the operators.
        :rtype: List[float]
        """
        # Developer note: This code is for backwards compatibility. It can't be replaced with
        # ForestConnection._expectation because we've turned off the ability to set
        # `needs_compilation` (that usually indicates the user is doing something iffy like
        # using a noise model with this function)

        if isinstance(operator_programs, Program):
            warnings.warn(
                "You have provided a Program rather than a list of Programs. The results from expectation "
                "will be line-wise expectation values of the operator_programs.",
                SyntaxWarning)

        payload = self._expectation_payload(prep_prog, operator_programs)
        response = post_json(self.session, self.sync_endpoint + "/qvm",
                             payload)
        return response.json()

    @_record_call
    def pauli_expectation(self, prep_prog, pauli_terms):
        """
        Calculate the expectation value of Pauli operators given a state prepared by prep_program.

        If ``pauli_terms`` is a ``PauliSum`` then the returned value is a single ``float``,
        otherwise the returned value is a list of ``float``s, one for each ``PauliTerm`` in the
        list.

        :note: If the execution of ``quil_program`` is **non-deterministic**, i.e., if it includes
            measurements and/or noisy quantum gates, then the final wavefunction from which the
            expectation values are computed itself only represents a stochastically generated
            sample. The expectations returned from *different* ``expectation`` calls *will then
            generally be different*.

        :param Program prep_prog: Quil program for state preparation.
        :param Sequence[PauliTerm]|PauliSum pauli_terms: A list of PauliTerms or a PauliSum.
        :return: If ``pauli_terms`` is a PauliSum return its expectation value. Otherwise return
          a list of expectation values.
        :rtype: float|List[float]
        """

        is_pauli_sum = False
        if isinstance(pauli_terms, PauliSum):
            progs, coeffs = pauli_terms.get_programs()
            is_pauli_sum = True
        else:
            coeffs = [pt.coefficient for pt in pauli_terms]
            progs = [pt.program for pt in pauli_terms]

        bare_results = self.expectation(prep_prog, progs)
        results = [c * r for c, r in zip(coeffs, bare_results)]
        if is_pauli_sum:
            return sum(results)
        return results

    def _expectation_payload(self, prep_prog, operator_programs):
        if operator_programs is None:
            operator_programs = [Program()]

        if not isinstance(prep_prog, Program):
            raise TypeError("prep_prog variable must be a Quil program object")

        payload = {
            'type': TYPE_EXPECTATION,
            'state-preparation': prep_prog.out(),
            'operators': [x.out() for x in operator_programs]
        }

        self._add_rng_seed_to_payload(payload)

        return payload

    def _maybe_add_noise_to_payload(self, payload):
        """
        Set the gate noise and measurement noise of a payload.
        """
        if self.measurement_noise is not None:
            payload["measurement-noise"] = self.measurement_noise
        if self.gate_noise is not None:
            payload["gate-noise"] = self.gate_noise

    def _add_rng_seed_to_payload(self, payload):
        """
        Add a random seed to the payload.
        """
        if self.random_seed is not None:
            payload['rng-seed'] = self.random_seed