예제 #1
0
 def test_get_job_identifier(self):
     api = Mock()
     type(api).__name__ = 'QuantumInspireAPI'
     job_identifier = 1234
     qi_job = QuantumInspireJob(api, job_identifier)
     actual = qi_job.get_job_identifier()
     self.assertEqual(actual, job_identifier)
예제 #2
0
 def test_retrieve_result(self):
     expected = dict([
         ('id', 502),
         ('url', 'https,//api.quantum-inspire.com/results/502/'),
         ('job', 'https,//api.quantum-inspire.com/jobs/10/'),
         ('created_at', '1900-01-01T01:00:00:00000Z'),
         ('number_of_qubits', 2), ('seconds', 0.0), ('raw_text', ''),
         ('raw_data_url',
          'https,//api.quantum-inspire.com/results/502/raw-data/f2b6/'),
         ('histogram', {'3', 0.5068359375, '0', 0.4931640625}),
         ('histogram_url',
          'https,//api.quantum-inspire.com/results/502/histogram/f2b6/'),
         ('measurement_mask', 0),
         ('quantum_states_url',
          'https,//api.quantum-inspire.com/results/502/quantum-states/f2b6d/'
          ),
         ('measurement_register_url',
          'https,//api.quantum-inspire.com/results/502/f2b6d/')
     ])
     api = Mock()
     api.get_result_from_job.return_value = expected
     type(api).__name__ = 'QuantumInspireAPI'
     job_identifier = 1
     qi_job = QuantumInspireJob(api, job_identifier)
     actual = qi_job.retrieve_results()
     self.assertDictEqual(expected, actual)
     api.get_result_from_job.assert_called_once_with(job_identifier)
예제 #3
0
 def test_check_status(self):
     expected = 'RUNNING'
     api = Mock()
     api.get_job.return_value = {'status': expected}
     type(api).__name__ = 'QuantumInspireAPI'
     job_identifier = 1
     qi_job = QuantumInspireJob(api, job_identifier)
     actual = qi_job.check_status()
     self.assertEqual(expected, actual)
예제 #4
0
    def test_get_project_identifier(self):
        api = Mock()
        expected = 2
        asset = {'project_id': expected}
        type(api).__name__ = 'QuantumInspireAPI'
        api.get_job.return_value = {'input': asset}
        api.get_asset_from_job.return_value = asset

        job_identifier = 1
        qi_job = QuantumInspireJob(api, job_identifier)
        actual = qi_job.get_project_identifier()
        self.assertEqual(expected, actual)
        api.get_asset_from_job.assert_called_once_with(job_identifier)
        api.get_job.assert_called_with(job_identifier)
    def test_run_a_circuit_returns_correct_result(self):
        api = Mock()
        type(api).__name__ = 'QuantumInspireAPI'
        api.create_project.return_value = {'id': 42}
        api.get_asset_from_job.return_value = {'project_id': '42'}
        api.execute_qasm_async.return_value = QuantumInspireJob(api, 42)
        api.get_backend_type_by_name.return_value = {
            'max_number_of_shots': 4096
        }
        simulator = QuantumInspireBackend(api, Mock())

        qc = QuantumCircuit(2, 2)
        qc.cx(0, 1)
        qc.measure(0, 1)
        job = simulator.run(qc, shots=1024)

        self.assertEqual('42', job.job_id())
예제 #6
0
    def _wait_for_completed_job(quantum_inspire_job: QuantumInspireJob, collect_max_tries: Optional[int],
                                sec_retry_delay: float = 0.5) -> bool:
        """ Holds the process and requests the job status until completed or when
            the maximum number of tries has been reached.

        Args:
            quantum_inspire_job: A job object.
            collect_max_tries: The maximum number of request tries.
            sec_retry_delay: The time delay in between job status checks in seconds.

        Returns:
            True if the job result could be collected else False.
        """
        attempts = itertools.count() if collect_max_tries is None else range(collect_max_tries)
        for _ in attempts:
            time.sleep(sec_retry_delay)
            if quantum_inspire_job.check_status() == 'COMPLETE':
                return True
        return False
예제 #7
0
    def _wait_for_completed_job(quantum_inspire_job: QuantumInspireJob, collect_max_tries: Optional[int] = None,
                                sec_retry_delay: float = 0.5) -> Tuple[bool, str]:
        """ Delays the process and requests the job status. The waiting loop is broken when the job status is
            completed or cancelled, or when the maximum number of tries is set and has been reached.

        Args:
            quantum_inspire_job: A job object.
            collect_max_tries: The maximum number of times the job status is checked. When set, the value should be > 0.
                               When not set, the method waits until the job status is either completed or cancelled.
            sec_retry_delay: The time delay in between job status checks in seconds.

        Returns:
            True if the job result could be collected else False in hte first part of the tuple.
            The latter part of the tuple contains an (error)message.
        """
        attempts = itertools.count() if collect_max_tries is None else range(collect_max_tries)
        for _ in attempts:
            time.sleep(sec_retry_delay)
            status = quantum_inspire_job.check_status()
            if status == 'COMPLETE':
                return True, 'Job completed.'
            if status == 'CANCELLED':
                return False, 'Failed getting result: job cancelled.'
        return False, 'Failed getting result: timeout reached.'
예제 #8
0
    def execute_qasm_async(self, qasm: str, backend_type: Optional[Union[Dict[str, Any], int, str]] = None,
                           number_of_shots: int = 256, default_number_of_shots: int = 256,
                           identifier: Optional[str] = None, full_state_projection: bool = False,
                           project: Optional[Dict[str, Any]] = None, job_name: Optional[str] = None,
                           user_data: str = '') -> QuantumInspireJob:
        """ With this method a cQASM program (job) is scheduled to be executed asynchronously. The method returns
            directly without waiting for the job to complete, as opposed to method `execute_qasm` which waits for
            the job to finish and returns the result.

            To execute a cQASM program a job is scheduled on a backend of type 'backend type' as given by the
            parameter backend_type. Currently there are 3 backend types available:
            1. 'QX single-node simulator'          (default for anonymous accounts)
            2. 'QX single-node simulator SurfSara' (advanced account credentials needed)
            3. 'QX multi-node simulator SurfSara'  (advanced account credentials needed)
            When no backend_type is given, the default backend type currently being 'QX single-node simulator', is used.

            The job has to be linked with a project before it can be scheduled to execute.

            When a project name was supplied when the QuantumInspireAPI was created (see __init__), the job
            is linked to an existing project with this project name. When no project exists with this name a
            project with this name is created.
            When no project name was given when the QuantumInspireAPI was created, the job is linked to the project
            that is given as an argument 'project'. When this 'project' argument is empty, a project is created.
            First a project name is generated using the parameter 'identifier' or when parameter 'identifier' is
            empty an identifier is generated.

            When the project is created, it is created for the backend type and the default number of shots given.
            When the project already existed the values of the existing project are used for backend type and
            default number of shots.

            An asset with a unique id is created containing the cQASM program. This asset is linked to the project.

            When the project and the asset containing the program are known, a job is created with the name given by
            parameter job_name. When this parameter job_name is not filled, a job name is generated.
            The job that is created for running the program (contained in the asset) is linked to the project and will
            be executed number_of_shots times (as given by the parameter) before the results can be collected.
            The jobs' user_data is filled with the user data given as a parameter. This user data can be fetched and
            used later in the process. The default value of job parameter full_state_projection is set to False which
            means that the algorithm is treated as non-deterministic. As a result a deterministic algorithm may take
            longer to execute than strictly needed. When full_state_projection is set to True, a non-deterministic
            algorithm may give wrong results. Parameter full_state_projection is only used for simulations.
            Once the job is created, the method returns directly without waiting for the job to complete.
            The job is returned as a QuantumInspireJob. This class encapsulates the job and contains methods the get
            the status of the job and retrieve the execution results when the job is completed.

        Args:
            qasm: The qasm code as a string object.
            backend_type: The backend_type to execute the algorithm on.
            number_of_shots: Execution times of the algorithm before the results can be collected.
            default_number_of_shots: The default used number of shots for the project.
            identifier: The identifier used for generating names for the project, asset and job.
            full_state_projection: Do not use full state projection when set to False (default).
            project: The properties of an existing project, the asset and job are linked to. Only used
                     when the project_name member of the api is empty.
            job_name: Name for the job that is to be executed, when None a job name is generated (see identifier)
            user_data: Data that the user wants to pass along with the job.

        Returns:
            An encapsulated job object containing methods the get the status of the job and
            retrieve the execution results.
        """
        if not isinstance(backend_type, OrderedDict):
            if backend_type is None:
                backend_type = self.get_backend_type(None)
            elif isinstance(backend_type, int):
                backend_type = self.get_backend_type(int(backend_type))
            elif isinstance(backend_type, str):
                backend_type = self.get_backend_type(str(backend_type))

        if identifier is None:
            identifier = str(uuid.uuid1())

        if self.project_name is not None:
            project = next((project for project in self.get_projects()
                            if project['name'] == self.project_name), None)

        if project is None:
            project_name = self.project_name if self.project_name else f'qi-sdk-project-{identifier}'
            project = self.create_project(project_name, default_number_of_shots, backend_type)

        qasm = qasm.lstrip()
        qasm = re.sub(r'[ \t]*\n[ \t]*', r'\n', qasm)
        asset_name = f'qi-sdk-asset-{identifier}'
        asset = self._create_asset(asset_name, project, qasm)

        if job_name is None:
            job_name = f'qi-sdk-job-{identifier}'
        job = self._create_job(job_name, asset, project, number_of_shots, backend_type, user_data=user_data,
                               full_state_projection=full_state_projection)

        return QuantumInspireJob(self, job['id'])