Skip to content

Commit

Permalink
[SDS-NNN] Some changes/bugs while testing plugin for quantuminspire (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
QFer authored Jun 16, 2022
1 parent a15919b commit f4987cd
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 68 deletions.
49 changes: 0 additions & 49 deletions .github/ISSUE_TEMPLATE.md

This file was deleted.

31 changes: 31 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior.
If applicable include the code you tried to run. In case you do, please try
to minimize the code example to the least amount of code required to trigger
the bug.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Operating System (please complete the following information):**
- OS: [e.g. Linux]
- Version [e.g. 22.04 LTS]
- Distribution [e.g. Ubuntu]

**Additional context**
Add any other context about the problem here:
- Python version (`python --version`) and distribution:
- List of installed packages (`pip list` or equivalent):
- Anything else that might be relevant
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is, for example:

As a [...] I want [...] so that [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Acceptance criteria**
Please specify the acceptance criteria in as much detail as possible,
for example:

- if this feature is available how would you invoke it (code example)
- what would the output look like?
- if it is an object, what would the members be?
- if it is a plot, a sketch would help
- anything else that clarifies what would constitute a satisfactory
implementation?

**Additional context**
Add any other context or screenshots about the feature request here.
4 changes: 2 additions & 2 deletions src/quantuminspire/projectq/backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,10 +673,10 @@ def _execute_cqasm(self) -> None:
full_state_projection=self._full_state_projection
)

if not self._quantum_inspire_result.get("histogram", []):
if not self._quantum_inspire_result.get("histogram", [{}])[0]:
raw_text = self._quantum_inspire_result.get("raw_text", "no raw_text in result structure")
raise ProjectQBackendError(
f"Result structure does not contain proper histogram. raw_text field: {raw_text}")
f"Result from backend contains no histogram data!\n{raw_text}")

def _filter_result_by_measured_qubits(self) -> None:
""" Filters the raw result by collapsing states so that unmeasured qubits are ignored.
Expand Down
2 changes: 1 addition & 1 deletion src/quantuminspire/qiskit/backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def _get_experiment_results(self, jobs: List[Dict[str, Any]]) -> List[Experiment
results = [self.__api.get_result_from_job(job['id']) for job in jobs]
experiment_results = []
for result, job in zip(results, jobs):
if not result.get('histogram', []):
if not result.get('histogram', [{}])[0]:
raise QiskitBackendError(
f"Result from backend contains no histogram data!\n{result.get('raw_text')}")

Expand Down
13 changes: 9 additions & 4 deletions src/quantuminspire/qiskit/quantum_inspire_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class QuantumInspireProvider(Provider): # type: ignore

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self._backends: List[QuantumInspireBackend] = []
self._backends: Optional[List[QuantumInspireBackend]] = None
self._filter: Optional[str] = None
self._api: Optional[QuantumInspireAPI] = None

def __str__(self) -> str:
Expand All @@ -58,20 +59,24 @@ def backends(self, name: Optional[str] = None, **kwargs: Any) -> List[QuantumIns
:return:
List of backends that meet the filter requirements (is_allow == True).
"""
if self._backends is not None and self._filter == name:
return self._backends

if self._api is None:
raise QiskitBackendError('Authentication details have not been set.')

available_backends = self._api.get_backend_types()
if name is not None:
available_backends = list(filter(lambda b: b['name'] == name, available_backends))
backends = []
self._filter = name
self._backends = []
for backend in available_backends:
if backend['is_allowed']:
config = copy(QuantumInspireBackend.DEFAULT_CONFIGURATION)
self._adjust_backend_configuration(config, backend)
backends.append(QuantumInspireBackend(self._api, provider=self, configuration=config))
self._backends.append(QuantumInspireBackend(self._api, provider=self, configuration=config))

return backends
return self._backends

@staticmethod
def _adjust_backend_configuration(config: QasmBackendConfiguration, backend: Dict[str, Any]) -> None:
Expand Down
13 changes: 8 additions & 5 deletions src/tests/quantuminspire/projectq/test_backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import warnings
import json
import coreapi
from collections import OrderedDict
from functools import reduce
from unittest import mock, TestCase
from unittest.mock import MagicMock, patch, call
from unittest.mock import MagicMock, patch

from projectq.meta import LogicalQubitIDTag
from projectq.ops import (CNOT, NOT, Allocate, Barrier,
Expand Down Expand Up @@ -925,9 +926,10 @@ def test_run_raises_error_no_result(self):
self.qi_backend.main_engine = MagicMock()
self.qi_backend.main_engine.mapper.current_mapping = {0: 0, 1: 1}
result_mock = MagicMock()
result_mock.get.return_value = {}
result_mock.get.return_value = [OrderedDict()]
self.api.execute_qasm.return_value = result_mock
self.assertRaisesRegex(ProjectQBackendError, 'raw_text', self.qi_backend.run)
self.assertRaisesRegex(ProjectQBackendError, 'Result from backend contains no histogram data!',
self.qi_backend.run)
self.api.execute_qasm.assert_called_once()

@patch('quantuminspire.projectq.backend_qx.Measure')
Expand All @@ -940,7 +942,8 @@ def test_run_no_measurements(self, measure_mock):
self.qi_backend.main_engine.active_qubits = [0, 1]
self.qi_backend.main_engine.mapper.current_mapping = {0: 0, 1: 1}
result_mock = MagicMock()
result_mock.get.return_value = {}
result_mock.get.return_value = [{}]
self.api.execute_qasm.return_value = result_mock
self.assertRaisesRegex(ProjectQBackendError, 'raw_text', self.qi_backend.run)
self.assertRaisesRegex(ProjectQBackendError, 'Result from backend contains no histogram data!',
self.qi_backend.run)
self.api.execute_qasm.assert_called_once()
9 changes: 5 additions & 4 deletions src/tests/quantuminspire/qiskit/test_backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import json
import unittest
from collections import OrderedDict
from unittest.mock import Mock, patch, ANY

import numpy as np
Expand Down Expand Up @@ -133,14 +134,14 @@ def test_run_a_circuit_returns_correct_result(self):

def test_get_experiment_results_raises_simulation_error_when_no_histogram(self):
api = Mock()
api.get_jobs_from_project.return_value = [{'id': 42, 'results': '{}'}]
api.get_result_from_job.return_value = {'histogram': [], 'raw_text': 'Error'}
api.get_jobs_from_project.return_value = [{'id': 42, 'results': '{}', 'user_data': 'data'}]
api.get_result_from_job.return_value = {'histogram': [OrderedDict()], 'raw_text': 'Simulation failed'}
job = Mock()
job.job_id.return_value = '42'
simulator = QuantumInspireBackend(api, Mock())
with self.assertRaises(QiskitBackendError) as error:
simulator.get_experiment_results_from_all_jobs(job)
self.assertEqual(('Result from backend contains no histogram data!\nError',), error.exception.args)
self.assertEqual(('Result from backend contains no histogram data!\nSimulation failed',), error.exception.args)

def test_get_experiment_results_raises_simulation_error_when_no_user_data(self):
api = Mock()
Expand Down Expand Up @@ -747,7 +748,7 @@ def test_empty_histogram(self):
[{'name': 'h', 'qubits': [0]},
{'name': 'cx', 'qubits': [0, 1]},
{'name': 'measure', 'qubits': [1], 'memory': [1]}]),
mock_result1={'id': 1, 'histogram': [], 'execution_time_in_seconds': 2.1,
mock_result1={'id': 1, 'histogram': [{}], 'execution_time_in_seconds': 2.1,
'number_of_qubits': 2, 'raw_text': 'oopsy daisy',
'raw_data_url': 'http://saevar-qutech-nginx/api/results/24/raw-data/'},
mock_result2=[],
Expand Down
24 changes: 21 additions & 3 deletions src/tests/quantuminspire/qiskit/test_quantum_inspire_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TestQuantumInspireProvider(unittest.TestCase):
'topology': {'edges': [[1], [0]]},
'number_of_qubits': 2}

def test_backends(self):
def test_no_backends(self):
with mock.patch('quantuminspire.qiskit.quantum_inspire_provider.QuantumInspireAPI') as api:
quantum_inpire_provider = QuantumInspireProvider()
with self.assertRaises(QiskitBackendError):
Expand All @@ -80,12 +80,30 @@ def test_backends(self):
authentication = BasicAuthentication(email, secret)
api.assert_called_with(QI_URL, authentication, None)
quantum_inpire_provider._api.get_backend_types.return_value = [self.simulator_backend_type]
backend = quantum_inpire_provider.get_backend(name='qi_simulator')
self.assertEqual('qi_simulator', backend.name())
with self.assertRaises(QiskitBackendNotFoundError) as error:
quantum_inpire_provider.get_backend(name='not-quantum-inspire')
self.assertEqual(('No backend matches the criteria',), error.exception.args)

def test_backends_return_cached(self):
with mock.patch('quantuminspire.qiskit.quantum_inspire_provider.QuantumInspireAPI') as api:
quantum_inpire_provider = QuantumInspireProvider()
email = 'bla@bla.bla'
secret = 'secret'
quantum_inpire_provider.set_basic_authentication(email, secret)
authentication = BasicAuthentication(email, secret)
api.assert_called_with(QI_URL, authentication, None)
quantum_inpire_provider._api.get_backend_types.return_value = [self.simulator_backend_type]
backend = quantum_inpire_provider.get_backend(name='qi_simulator')
self.assertEqual('qi_simulator', backend.name())
self.assertEqual(quantum_inpire_provider._api.get_backend_types.call_count, 1)
# again, return cached
backend = quantum_inpire_provider.get_backend(name='qi_simulator')
self.assertEqual('qi_simulator', backend.name())
self.assertEqual(quantum_inpire_provider._api.get_backend_types.call_count, 1)
backend = quantum_inpire_provider.get_backend()
self.assertEqual('qi_simulator', backend.name())
self.assertEqual(quantum_inpire_provider._api.get_backend_types.call_count, 2)

def test_simulator_backend(self):
with mock.patch('quantuminspire.qiskit.quantum_inspire_provider.QuantumInspireAPI') as api:
quantum_inpire_provider = QuantumInspireProvider()
Expand Down

0 comments on commit f4987cd

Please sign in to comment.