Example #1
0
 def __init__(self, qlm_batch, async_job):
     """
     Args:
         qlm_batch: :class:`~qat.core.Batch` or :class:`~qat.core.Job` object.
                 If a QLM Job object is given, it will be converted in a QLM
                 Batch object
         async_job: Qiskit job instance derived from BaseJob.
                 Result of a previous asynchronous execution of qlm_batch
     """
     self._job_id = async_job.job_id()
     self._handler = async_job
     if isinstance(qlm_batch, Job):
         self._qlm_batch = Batch(jobs=[qlm_batch])
     else:
         self._qlm_batch = qlm_batch
Example #2
0
    def submit(self, qlm_batch):
        """
        Submits a QLM batch of jobs and returns the corresponding QiskitJob.

        Args:
            qlm_batch: :class:`~qat.core.Batch` or :class:`~qat.core.Job`.
                    If a single job is provided, a batch is created
                    from this job.
        Returns:
            :class:`~qat.interop.qiskit.QiskitJob` object with the same
            interface as a job derived from JobV1 for the user to have
            information on their job execution
        """
        if self.backend is None:
            raise ValueError("Backend cannot be None")

        if isinstance(qlm_batch, Job):
            qlm_batch = Batch(jobs=[qlm_batch])
        qiskit_circuits = []
        for qlm_job in qlm_batch.jobs:
            qiskit_circuit = job_to_qiskit_circuit(qlm_job)
            qiskit_circuits.append(qiskit_circuit)
        async_job = execute(qiskit_circuits,
                            self.backend,
                            shots=qlm_batch.jobs[0].nbshots
                            or self.backend.configuration().max_shots,
                            coupling_map=None)
        return QiskitJob(qlm_batch, async_job,
                         self.backend.configuration().max_shots)
Example #3
0
    def _submit_batch(self, qlm_batch):
        """
        Submits a Batch object to execute on a Qiskit backend.

        Args:
            qlm_batch:

        Returns:
            A QLM BatchResult object
        """
        if self.backend is None:
            raise ValueError("Backend cannot be None")

        if isinstance(qlm_batch, Job):
            qlm_batch = Batch(jobs=[qlm_batch])
        qiskit_circuits = []
        for qlm_job in qlm_batch.jobs:
            qiskit_circuit = job_to_qiskit_circuit(qlm_job)
            qiskit_circuits.append(qiskit_circuit)
        qiskit_result = execute(
            qiskit_circuits,
            self.backend,
            shots=qlm_batch.jobs[0].nbshots
            or self.backend.configuration().max_shots,
            coupling_map=None,
            optimization_level=self.optimization_level).result()
        results = generate_qlm_list_results(qiskit_result)
        new_results = []
        for result in results:
            new_results.append(WResult.from_thrift(result))
        return _wrap_results(qlm_batch, new_results,
                             self.backend.configuration().max_shots)
Example #4
0
 def __init__(self, qlm_batch, async_job, max_shots):
     """
     Args:
         qlm_batch: :class:`~qat.core.Batch` or :class:`~qat.core.Job` object.
                 If a QLM Job object is given, it will be converted in a QLM
                 Batch object
         async_job: Qiskit job instance derived from JobV1.
                 Result of a previous asynchronous execution of qlm_batch
         max_shots: Maximal number of shots allowed by the Backend
     """
     self._job_id = async_job.job_id()
     self._handler = async_job
     self._max_shots = max_shots
     if isinstance(qlm_batch, Job):
         self._qlm_batch = Batch(jobs=[qlm_batch])
     else:
         self._qlm_batch = qlm_batch
Example #5
0
    def run(self, run_input, **kwargs):
        """ Convert all the circuits inside qobj into a Batch of
            QLM jobs before sending them into a QLM qpu.

        Args:
            run_input (list or QuantumCircuit or Schedule)
            kwargs: any option that can replace the default ones

        Returns:
            Returns a :class:`~qat.interop.qiskit.QLMJob` object containing
            the results of the QLM qpu execution after being converted into
            Qiskit results
        """
        if self._qpu is None:
            raise NoQpuAttached("No qpu attached to the QLM connector.")
        circuits = run_input if isinstance(run_input, list) else [run_input]

        for kwarg in kwargs:
            if not hasattr(self.options, kwarg):
                raise ValueError(f"'{kwarg}' parameter not supported")
        nbshots = kwargs.get('shots', self.options.shots)
        qobj_id = kwargs.get('qobj_id', self.options.qobj_id)
        qobj_header = kwargs.get('qobj_header', self.options.qobj_header)
        # TODO: use parameter_binds for constructing the job
        # this involves not only iterating on the experiments
        # but also iterating on the parameter sets so provided

        qlm_task = Batch(jobs=[])
        circuits_metadata = []
        for circuit in circuits:
            qlm_circuit = qiskit_to_qlm(circuit)
            circuits_metadata.append({
                'n_qubits': qlm_circuit.nbqbits,
                'memory_slots': qlm_circuit.nbqbits
            })
            job = qlm_circuit.to_job(aggregate_data=False)
            job.nbshots = nbshots
            job.qubits = list(range(0, qlm_circuit.nbqbits))
            qlm_task.jobs.append(job)

        results = self._qpu.submit(qlm_task)
        if not isinstance(results, (BatchResult, WResult)):
            results = results.join()
        for res in results:
            for sample in res.raw_data:
                sample.intermediate_measures = None

        # Creating a job that will contain the results
        job = QLMJob(self, str(self.id_counter))
        self.id_counter += 1
        job.set_results(results, qobj_id, circuits_metadata, qobj_header)
        return job
Example #6
0
    def retrieve_job(self, file_name):
        """
        Retrieves a QiskitJob from a binary file in which the QLM Batch object
        - from which the QiskitJob has been created - has been dumped.

        Args:
            file_name: Name of the binary file

        Returns:
            :class:`~qat.interop.qiskit.providers.QiskitJob` object
        """
        qlm_batch = Batch.load(file_name)
        async_job = self.backend.retrieve_job(qlm_batch.meta_data['job_id'])
        return QiskitJob(qlm_batch, async_job)
Example #7
0
    def test_all_to_all_topology(self) -> None:
        """
        Checks that Sabre doesn't modify the circuit if the topology is of type ALL_TO_ALL.
        """

        for nbqbit in range(min_nbqbit, max_nbqbit):
            circuit = generate_random_circuit(nbqbit)

            sabre = Sabre()
            batch = Batch(jobs=[circuit.to_job()])
            hardware_specs = HardwareSpecs()
            batch_result = sabre.compile(batch, hardware_specs)
            computed_circuit = batch_result.jobs[0].circuit

            check_circuits_equality(circuit, computed_circuit)
Example #8
0
    def run(self, qobj):
        """ Convert all the circuits inside qobj into a Batch of
            QLM jobs before sending them into a QLM qpu.

        Args:
            qobj: Qiskit batch of circuits to run

        Returns:
            Returns a :class:`~qat.interop.qiskit.providers.QLMJob` object containing
            the results of the QLM qpu execution after being converted into
            Qiskit results
        """
        if self._qpu is None:
            raise NoQpuAttached("No qpu attached to the QLM connector.")
        headers = [exp.header.to_dict() for exp in qobj.experiments]
        circuits = disassemble(qobj)[0]
        nbshots = qobj.config.shots
        qlm_task = Batch(jobs=[])
        for circuit in circuits:
            qlm_circuit = qiskit_to_qlm(circuit)
            job = qlm_circuit.to_job(aggregate_data=False)
            job.nbshots = nbshots
            job.qubits = list(range(0, qlm_circuit.nbqbits))
            qlm_task.jobs.append(job)

        results = self._qpu.submit(qlm_task)
        for res in results:
            for sample in res.raw_data:
                sample.intermediate_measures = None
            res = aggregate_data(res)

        # Creating a job that will contain the results
        job = QLMJob(self, str(self.id_counter))
        self.id_counter += 1
        job.set_results(results, qobj.qobj_id, headers)
        return job
Example #9
0
    def test_already_executable_circuit(self) -> None:
        """
        Tests Sabre on a fully executable circuit which means all gates are applied on qubits which are connected on the
        hardware.
        """

        for nbqbit in range(min_nbqbit, max_nbqbit):
            prog = Program()
            qbits = prog.qalloc(nbqbit)

            for i in range(len(qbits) - 1):
                prog.apply(H, qbits[i])
                prog.apply(Z, qbits[i])
                prog.apply(X.ctrl(), qbits[i + 1], qbits[i])

            circuit = prog.to_circ(inline=True)

            sabre = Sabre()
            batch = Batch(jobs=[circuit.to_job()])
            hardware_specs = HardwareSpecs()
            batch_result = sabre.compile(batch, hardware_specs)
            computed_circuit = batch_result.jobs[0].circuit

            check_circuits_equality(circuit, computed_circuit)
Example #10
0
class QiskitJob:
    """
    Wrapper around Qiskit's asynchronous jobs.
    """
    def __init__(self, qlm_batch, async_job, max_shots):
        """
        Args:
            qlm_batch: :class:`~qat.core.Batch` or :class:`~qat.core.Job` object.
                    If a QLM Job object is given, it will be converted in a QLM
                    Batch object
            async_job: Qiskit job instance derived from JobV1.
                    Result of a previous asynchronous execution of qlm_batch
            max_shots: Maximal number of shots allowed by the Backend
        """
        self._job_id = async_job.job_id()
        self._handler = async_job
        self._max_shots = max_shots
        if isinstance(qlm_batch, Job):
            self._qlm_batch = Batch(jobs=[qlm_batch])
        else:
            self._qlm_batch = qlm_batch

    def job_id(self):
        """ Returns the job's ID. """
        return self._job_id

    def status(self):
        """ Returns the job status. """
        return self._handler.status()._name_

    def result(self):
        """
        Returns the result if available.

        Returns:
            :class:`~qat.core.Result` object or
            :class:`~qat.core.BatchResult` object
            if the batch submitted contains several jobs
        """
        if self.status() == 'DONE':
            results = generate_qlm_list_results(self._handler.result())
            new_results = []
            for result in results:
                new_results.append(WResult.from_thrift(result))
            batch_result = _wrap_results(self._qlm_batch, new_results,
                                         self._max_shots)
            if not batch_result.results or len(batch_result.results) == 1:
                return batch_result.results[0]
            return batch_result

        return None

    def cancel(self):
        """
        Attempts to cancel the job.

        Returns:
            Boolean indicating whether the attempt was successful or not
        """
        ret = self._handler.cancel()

        if ret:
            print("job successefully cancelled")
            return True

        print("Unable to cancel job")
        return False

    def dump(self, file_name):
        """
        Dumps the :class:`~qat.core.Batch` object used for creating the job into a
        binary file. This file should later be used with AsyncBackendToQPU's
        :func:`~qat.interop.qiskit.AsyncBackendToQPU.retrieve_job`.

        Args:
            file_name: Name of the binary file to create
        """
        if isinstance(self._qlm_batch.meta_data, dict):
            self._qlm_batch.meta_data['job_id'] = self._job_id
        else:
            self._qlm_batch.meta_data = {'job_id': self._job_id}

        self._qlm_batch.dump(file_name)