Example #1
0
    def result(self):
        """
        The result of the job if available
        throws ValueError is result is not available yet
        throws ApiError if server returned an error indicating program execution was not successful
        or if the job was cancelled
        """
        if not self.is_done():
            raise ValueError(
                "Cannot get a result for a program that isn't completed.")

        if self._raw['status'] == 'CANCELLED':
            raise CancellationError(self._raw['result'])
        elif self._raw['status'] == 'ERROR':
            if self._machine == 'QVM':
                raise QVMError(self._raw['result'])
            elif self._machine == 'QPU':
                raise QPUError(self._raw['result'])
            elif self._machine == 'QUILC':
                raise QUILCError(self._raw['result'])
            else:
                raise UnknownApiError(self._raw['result'])

        if self._raw['program']['type'] == 'wavefunction':
            return Wavefunction.from_bit_packed_string(
                base64.b64decode(self._raw['result']),
                self._raw['program']['addresses'])
        elif self._raw['program']['type'] in [
                'multishot', 'multishot-measure', 'expectation'
        ]:
            return np.asarray(self._raw['result'])
        else:
            return self._raw['result']
    def wavefunction(
        self,
        quil_program: Program,
        memory_map: Optional[Dict[str, List[Union[int, float]]]] = None
    ) -> Wavefunction:
        """
        Simulate a Quil program and return the wavefunction.

        .. note:: If your program contains measurements or noisy gates, this method may not do what
            you want. If the execution of ``quil_program`` is **non-deterministic** then the
            final wavefunction only represents a stochastically generated sample and the
            wavefunctions returned by *different* ``wavefunction`` calls *will generally be
            different*.

        :param quil_program: A Quil program.
        :param memory_map: An assignment of classical registers to values, representing an initial
                           state for the QAM's classical memory.

                           This is expected to be of type Dict[str, List[Union[int, float]]],
                           where the keys are memory region names and the values are arrays of
                           initialization data.
        :return: A Wavefunction object representing the state of the QVM.
        """

        if memory_map is not None:
            quil_program = self.augment_program_with_memory_values(
                quil_program, memory_map)

        request = self._wavefunction_request(quil_program=quil_program)
        response = self._qvm_client.get_wavefunction(request)
        return Wavefunction.from_bit_packed_string(response.wavefunction)
Example #3
0
    def result(self):
        """
        The result of the job if available
        throws ValueError is result is not available yet
        throws ApiError if server returned an error indicating program execution was not successful
        or if the job was cancelled
        """
        if not self.is_done():
            raise ValueError(
                "Cannot get a result for a program that isn't completed.")

        if self._raw["status"] == "CANCELLED":
            raise CancellationError(self._raw["result"])
        elif self._raw["status"] == "ERROR":
            if self._machine == "QVM":
                raise QVMError(self._raw["result"])
            elif self._machine == "QPU":
                raise QPUError(self._raw["result"])
            elif self._machine == "QUILC":
                raise QUILCError(self._raw["result"])
            else:
                raise UnknownApiError(self._raw["result"])

        if self._raw["program"]["type"] == "wavefunction":
            return Wavefunction.from_bit_packed_string(
                base64.b64decode(self._raw["result"]),
                self._raw["program"]["addresses"])
        elif self._raw["program"]["type"] in [
                "multishot", "multishot-measure", "expectation"
        ]:
            return np.asarray(self._raw["result"])
        else:
            return self._raw["result"]
Example #4
0
    def wavefunction(self, quil_program, classical_addresses=None):
        """
        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.
        :param list|range classical_addresses: An optional list of classical addresses.
        :return: A tuple whose first element is a Wavefunction object,
                 and whose second element is the list of classical bits corresponding
                 to the classical addresses.
        :rtype: Wavefunction
        """
        if classical_addresses is None:
            classical_addresses = []

        if self.use_queue:
            payload = self._wavefunction_payload(quil_program,
                                                 classical_addresses)
            response = self._post_json(self.async_endpoint + "/job", {
                "machine": "QVM",
                "program": payload
            })
            job = self.wait_for_job(get_job_id(response))
            return job.result()
        else:
            payload = self._wavefunction_payload(quil_program,
                                                 classical_addresses)
            response = self._post_json(self.sync_endpoint + "/qvm", payload)
            return Wavefunction.from_bit_packed_string(response.content,
                                                       classical_addresses)
Example #5
0
    def wavefunction(self, quil_program, classical_addresses=None, needs_compilation=False, isa=None):
        """
        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.
        :param list|range classical_addresses: An optional list of classical addresses.
        :param needs_compilation: If True, preprocesses the job with the compiler.
        :param isa: If set, compiles to this target ISA.
        :return: A Wavefunction object representing the state of the QVM.
        :rtype: Wavefunction
        """
        if classical_addresses is None:
            classical_addresses = []

        if self.use_queue or needs_compilation:
            if needs_compilation and not self.use_queue:
                warnings.warn('Synchronous QVM connection does not support compilation preprocessing. Running this job over the asynchronous endpoint, as if use_queue were set to True.')

            payload = self._wavefunction_payload(quil_program, classical_addresses, needs_compilation, isa)
            response = post_json(self.session, self.async_endpoint + "/job", {"machine": "QVM", "program": payload})
            job = self.wait_for_job(get_job_id(response))
            return job.result()
        else:
            payload = self._wavefunction_payload(quil_program, classical_addresses, needs_compilation, isa)
            response = post_json(self.session, self.sync_endpoint + "/qvm", payload)
            return Wavefunction.from_bit_packed_string(response.content, classical_addresses)
Example #6
0
    def _wavefunction(self, quil_program, random_seed) -> Wavefunction:
        """
        Run a Forest ``wavefunction`` job.

        Users should use :py:func:`WavefunctionSimulator.wavefunction` instead of calling
        this directly.
        """

        payload = wavefunction_payload(quil_program, random_seed)
        response = post_json(self.session, self.sync_endpoint + "/qvm", payload)
        return Wavefunction.from_bit_packed_string(response.content)
Example #7
0
    def result(self):
        """
        The result of the job if available, ValueError otherwise
        """
        if not self.is_done():
            raise ValueError(
                "Cannot get a result for a program that isn't completed.")

        if self.raw['program']['type'] == 'wavefunction':
            return Wavefunction.from_bit_packed_string(
                base64.b64decode(self.raw['result']),
                self.raw['program']['addresses'])
        else:
            return self.raw['result']
Example #8
0
    def _wavefunction(self, quil_program, classical_addresses, random_seed) -> Wavefunction:
        """
        Run a Forest ``wavefunction`` job.

        Users should use :py:func:`WavefunctionSimulator.wavefunction` instead of calling
        this directly.
        """
        if self.use_queue:
            payload = wavefunction_payload(quil_program, classical_addresses, random_seed)
            response = post_json(self.session, self.async_endpoint + "/job",
                                 {"machine": "QVM", "program": payload})
            job = self._wait_for_job(get_job_id(response), machine='QVM')
            return job.result()
        else:
            payload = wavefunction_payload(quil_program, classical_addresses, random_seed)
            response = post_json(self.session, self.sync_endpoint + "/qvm", payload)
            return Wavefunction.from_bit_packed_string(response.content, classical_addresses)
Example #9
0
    def result(self):
        """
        The result of the job if available
        throws ValueError is result is not available yet
        throws RuntimeError if server returned an error indicating program execution was not successful
            or if the job was cancelled
        """
        if not self.is_done():
            raise ValueError("Cannot get a result for a program that isn't completed.")

        if self._raw['status'] == 'CANCELLED':
            raise RuntimeError("Job was cancelled: {}".format(self._raw['result']))
        elif self._raw['status'] == 'ERROR':
            raise RuntimeError("Server returned an error: {}".format(self._raw['result']))

        if self._raw['program']['type'] == 'wavefunction':
            return Wavefunction.from_bit_packed_string(
                base64.b64decode(self._raw['result']), self._raw['program']['addresses'])
        else:
            return self._raw['result']
Example #10
0
    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)