Ejemplo n.º 1
0
def test_run_program__returns_results(
        client_configuration: QCSClientConfiguration):
    qvm_client = QVMClient(client_configuration=client_configuration)

    respx.post(
        url=client_configuration.profile.applications.pyquil.qvm_url,
        json={
            "type": "multishot",
            "compiled-quil": "some-program",
            "addresses": {
                "ro": True
            },
            "trials": 1,
            "measurement-noise": (3.14, 1.61, 6.28),
            "gate-noise": (1.0, 2.0, 3.0),
            "rng-seed": 314,
        },
    ).respond(status_code=200, json={"ro": [[1, 0, 1]]})

    request = RunProgramRequest(
        program="some-program",
        addresses={"ro": True},
        trials=1,
        measurement_noise=(3.14, 1.61, 6.28),
        gate_noise=(1.0, 2.0, 3.0),
        seed=314,
    )
    assert qvm_client.run_program(request) == RunProgramResponse(
        results={"ro": [[1, 0, 1]]})
Ejemplo n.º 2
0
class QVM(QAM[QVMExecuteResponse]):
    def __init__(
        self,
        noise_model: Optional[NoiseModel] = None,
        gate_noise: Optional[Tuple[float, float, float]] = None,
        measurement_noise: Optional[Tuple[float, float, float]] = None,
        random_seed: Optional[int] = None,
        timeout: float = 10.0,
        client_configuration: Optional[QCSClientConfiguration] = None,
    ) -> None:
        """
        A virtual machine that classically emulates the execution of Quil programs.

        :param noise_model: A noise model that describes noise to apply when emulating a program's
            execution.
        :param gate_noise: A tuple 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. The
           default value of None indicates no noise.
        :param measurement_noise: A tuple of three numbers [Px, Py, Pz] indicating the probability
            of an X, Y, or Z gate getting applied before a measurement. The default value of
            None indicates no noise.
        :param random_seed: A seed for the QVM's random number generators. Either None (for an
            automatically generated seed) or a non-negative integer.
        :param timeout: Time limit for requests, in seconds.
        :param client_configuration: Optional client configuration. If none is provided, a default one will be loaded.
        """
        super().__init__()

        if (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 Kraus noise model
(by supplying a `noise_model` 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.
""")

        self.noise_model = noise_model

        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")

        client_configuration = client_configuration or QCSClientConfiguration.load(
        )
        self._qvm_client = QVMClient(client_configuration=client_configuration,
                                     request_timeout=timeout)
        self.connect()

    def connect(self) -> None:
        try:
            version = self.get_version_info()
            check_qvm_version(version)
        except ConnectionError:
            raise QVMNotRunning(
                f"No QVM server running at {self._qvm_client.base_url}")

    def execute(self, executable: QuantumExecutable) -> QVMExecuteResponse:
        """
        Synchronously execute the input program to completion.
        """
        executable = executable.copy()

        if not isinstance(executable, Program):
            raise TypeError(
                f"`QVM#executable` argument must be a `Program`; got {type(executable)}"
            )

        result_memory = {}

        for region in executable.declarations.keys():
            result_memory[region] = np.ndarray((executable.num_shots, 0),
                                               dtype=np.int64)

        trials = executable.num_shots
        classical_addresses = get_classical_addresses_from_program(executable)

        if self.noise_model is not None:
            executable = apply_noise_model(executable, self.noise_model)

        executable._set_parameter_values_at_runtime()

        request = qvm_run_request(
            executable,
            classical_addresses,
            trials,
            self.measurement_noise,
            self.gate_noise,
            self.random_seed,
        )
        response = self._qvm_client.run_program(request)
        ram = {key: np.array(val) for key, val in response.results.items()}
        result_memory.update(ram)

        return QVMExecuteResponse(executable=executable, memory=result_memory)

    def get_result(self,
                   execute_response: QVMExecuteResponse) -> QAMExecutionResult:
        """
        Return the results of execution on the QVM.

        Because QVM execution is synchronous, this is a no-op which returns its input.
        """
        return QAMExecutionResult(executable=execute_response.executable,
                                  readout_data=execute_response.memory)

    def get_version_info(self) -> str:
        """
        Return version information for the QVM.

        :return: String with version information
        """
        return self._qvm_client.get_version()