Skip to content

Commit

Permalink
[SDS-NNN] Some documentation improvements (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
QFer committed Jun 25, 2021
1 parent 81afdb9 commit 6cc321f
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 92 deletions.
2 changes: 1 addition & 1 deletion docs/projectq.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Module projectq
Module ProjectQ
===============

.. toctree::
Expand Down
4 changes: 2 additions & 2 deletions docs/qiskit.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Module qiskit
============================
Module Qiskit
=============

.. toctree::
:maxdepth: 2
Expand Down
6 changes: 3 additions & 3 deletions src/quantuminspire/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
"""


class QisKitBackendError(Exception):
""" Exception for SDK errors related to the qiskit backend."""
class QiskitBackendError(Exception):
""" Exception for SDK errors related to the Qiskit backend."""


class ProjectQBackendError(Exception):
""" Exception for SDK errors related to the projectq backend."""
""" Exception for SDK errors related to the ProjectQ backend."""


class AuthenticationError(Exception):
Expand Down
4 changes: 2 additions & 2 deletions src/quantuminspire/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class QuantumInspireJob:
def __init__(self, api: Any, job_identifier: int) -> None:
""" Encapsulation of a job.
The QuantumInspire Job class encapsulates the base job of the API and has
The :py:class:`QuantumInspireJob` class encapsulates the base job of the API and has
methods to check the status and retrieve the results from the API.
:param api: An instance to the API.
Expand All @@ -48,7 +48,7 @@ def __check_arguments(api: Any, job_identifier: int) -> None:
:param api: An instance to the API.
:param job_identifier: The job identification number.
:raises ValueError: When the api is not a QuantumInspireApi or when the
:raises ValueError: When the api is not a :py:class:`QuantumInspireAPI` or when the
job identifier is not found.
"""
if type(api).__name__ != 'QuantumInspireAPI':
Expand Down
6 changes: 3 additions & 3 deletions src/quantuminspire/projectq/backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def three_qubit_gates(self) -> Tuple[Any, ...]:
return self._three_qubit_gates

def cqasm(self) -> str:
""" Return cqasm code that is generated last. """
""" Return cQASM code that is generated last. """
return self._cqasm

@property
Expand Down Expand Up @@ -211,14 +211,14 @@ def _allocate_qubit(self, index_to_add: int) -> None:
:attr:`_allocation_map` is the store in which the administration
is done for assigning physical qubits that are used
with in ProjectQ to the simulation qubits, this is as they appear in the cqasm.
with in ProjectQ to the simulation qubits, this is as they appear in the cQASM.
:attr:`_allocation_map` stores the assignments as tuples (simulation_bit, physical_bit)
where 'physical_bit' is requested by ProjectQ and simulation_bit is the assignment to a bit in the simulator.
A de-allocated physical bit is registered as -1, which means the corresponding simulation bit can be re-used.
We strive for x-to-x allocation for qubits, which means we want to allocate a physical qubit to its
corresponding simulation qubit. We do this to respect as much as possible the qubits of the original algorithm
in the generated cqasm for readability.
in the generated cQASM for readability.
Only when the requested physical bit is higher than the max number of bits supported by the backend, we try
to search for an de-allocatd ancilla bit to re-use. When an ancilla is re-used, we have to reset the qubit
Expand Down
82 changes: 41 additions & 41 deletions src/quantuminspire/qiskit/backend_qx.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from qiskit.qobj import QobjExperimentHeader

from quantuminspire.api import QuantumInspireAPI
from quantuminspire.exceptions import QisKitBackendError, ApiError
from quantuminspire.exceptions import QiskitBackendError, ApiError
from quantuminspire.job import QuantumInspireJob
from quantuminspire.qiskit.circuit_parser import CircuitToString
from quantuminspire.qiskit.qi_job import QIJob
Expand Down Expand Up @@ -61,30 +61,30 @@ def __init__(self, api: QuantumInspireAPI, provider: Any,
:param api: The interface instance to the Quantum Inspire API.
:param provider: Provider for this backend.
:param configuration: The configuration of the quantum inspire backend. The
:param configuration: The configuration of the Quantum Inspire backend. The
configuration must implement the fields given by the QiSimulatorPy.DEFAULT_CONFIGURATION. All
configuration fields are listed in the table below. The table rows with an asterisk specify fields which
can have a custom value and are allowed to be changed according to the description column.
=============== ============= =========================================================================
Key Type Description
=============== ============= =========================================================================
backend_name * str The name of the quantum inspire backend. The API can list the name of
each available backend using the function api.list_backend_types(). One
of the listed names must be used.
backend_version str Backend version in the form X.Y.Z.
n_qubits int Number of qubits.
basis_gates list[str] A list of basis gates to compile to.
gates GateConfig List of basis gates on the backend. Not used.
local bool Indicates whether the system is running locally or remotely.
simulator bool Specifies whether the backend is a simulator or a quantum system.
conditional bool Backend supports conditional operations.
open_pulse bool Backend supports open pulse. False.
memory bool Backend supports memory. True.
max_shots int Maximum number of shots supported.
max_experiments int Optional: Maximum number of experiments (circuits) per job.
coupling_map (list(tuple)) Define the edges.
=============== ============= =========================================================================
=================== ============= =====================================================================
Key Type Description
=================== ============= =====================================================================
``backend_name`` * str The name of the Quantum Inspire backend. The API can list the name of
each available backend using the function api.list_backend_types().
One of the listed names must be used.
``backend_version`` str Backend version in the form X.Y.Z.
``n_qubits`` int Number of qubits.
``basis_gates`` list[str] A list of basis gates to compile to.
``gates`` GateConfig List of basis gates on the backend. Not used.
``local`` bool Indicates whether the system is running locally or remotely.
``simulator`` bool Specifies whether the backend is a simulator or a quantum system.
``conditional`` bool Backend supports conditional operations.
``open_pulse`` bool Backend supports open pulse. False.
``memory`` bool Backend supports memory. True.
``max_shots`` int Maximum number of shots supported.
``max_experiments`` int Optional: Maximum number of experiments (circuits) per job.
``coupling_map`` (list(tuple)) Define the edges.
=================== ============= =====================================================================
"""
super().__init__(configuration=(configuration or
QuantumInspireBackend.DEFAULT_CONFIGURATION),
Expand All @@ -99,7 +99,7 @@ def backend_name(self) -> str:
def run(self, qobj: QasmQobj) -> QIJob:
""" Submits a quantum job to the Quantum Inspire platform.
:param qobj: The quantum job with the Qiskit algorithm and quantum inspire backend.
:param qobj: The quantum job with the Qiskit algorithm and Quantum Inspire backend.
:return:
A job that has been submitted.
Expand Down Expand Up @@ -127,7 +127,7 @@ def run(self, qobj: QasmQobj) -> QIJob:
self.__api.delete_project(int(project['id']))
project = None
job.set_job_id(str(job_for_experiment.get_project_identifier()))
except (ApiError, QisKitBackendError) as error:
except (ApiError, QiskitBackendError) as error:
# delete the empty project
if project is not None:
self.__api.delete_project(int(project['id']))
Expand All @@ -144,12 +144,12 @@ def retrieve_job(self, job_id: str) -> QIJob:
:return:
The job that has been retrieved.
:raises QisKitBackendError: If job not found or error occurs during retrieval of the job.
:raises QiskitBackendError: If job not found or error occurs during retrieval of the job.
"""
try:
self.__api.get_project(int(job_id))
except (ApiError, ValueError):
raise QisKitBackendError("Could not retrieve job with job_id '{}' ".format(job_id))
raise QiskitBackendError("Could not retrieve job with job_id '{}' ".format(job_id))
return QIJob(self, job_id, self.__api)

@staticmethod
Expand Down Expand Up @@ -192,7 +192,7 @@ def _get_experiment_results(self, jobs: List[Dict[str, Any]]) -> List[Experiment
:param jobs: A list of jobs
:raises QisKitBackendError: If an error occurred while executing the job on the Quantum Inspire backend.
:raises QiskitBackendError: If an error occurred while executing the job on the Quantum Inspire backend.
:return:
A list of experiment results; containing the data, execution time, status, etc. for the list of jobs.
Expand All @@ -201,7 +201,7 @@ def _get_experiment_results(self, jobs: List[Dict[str, Any]]) -> List[Experiment
experiment_results = []
for result, job in zip(results, jobs):
if not result.get('histogram', {}):
raise QisKitBackendError(
raise QiskitBackendError(
'Result from backend contains no histogram data!\n{}'.format(result.get('raw_text')))

user_data = json.loads(str(job.get('user_data')))
Expand Down Expand Up @@ -243,13 +243,13 @@ def get_experiment_results_from_all_jobs(self, qi_job: QIJob) -> List[Experiment
def __validate_number_of_shots(self, job: QasmQobj) -> None:
""" Checks whether the number of shots has a valid value.
:param job: The quantum job with the Qiskit algorithm and quantum inspire backend.
:param job: The quantum job with the Qiskit algorithm and Quantum Inspire backend.
:raises QisKitBackendError: When the value is not correct.
:raises QiskitBackendError: When the value is not correct.
"""
number_of_shots = job.config.shots
if number_of_shots < 1 or number_of_shots > self.__backend['max_number_of_shots']:
raise QisKitBackendError('Invalid shots (number_of_shots={})'.format(number_of_shots))
raise QiskitBackendError('Invalid shots (number_of_shots={})'.format(number_of_shots))

def __validate_number_of_clbits(self, experiment: QasmQobjExperiment) -> None:
""" Validate the number of classical bits
Expand All @@ -274,17 +274,17 @@ def __validate_number_of_clbits(self, experiment: QasmQobjExperiment) -> None:
:param experiment: The experiment with gate operations and header.
:raises QisKitBackendError: When the value is not correct.
:raises QiskitBackendError: When the value is not correct.
"""
number_of_clbits = experiment.header.memory_slots
if number_of_clbits < 1:
raise QisKitBackendError("Invalid amount of classical bits ({})!".format(number_of_clbits))
raise QiskitBackendError("Invalid amount of classical bits ({})!".format(number_of_clbits))

measurements = self._collect_measurements(experiment)
number_of_classical_bits = measurements['number_of_clbits']
max_measurement_index = max(measurement[1] for measurement in measurements['measurements'])
if max_measurement_index >= number_of_classical_bits:
raise QisKitBackendError(f"Number of classical bits ({number_of_classical_bits}) is not sufficient for "
raise QiskitBackendError(f"Number of classical bits ({number_of_classical_bits}) is not sufficient for "
f"storing the outcomes of the experiment")

if BaseBackend.configuration(self).conditional:
Expand All @@ -293,7 +293,7 @@ def __validate_number_of_clbits(self, experiment: QasmQobjExperiment) -> None:
# no problem when there are no conditional gate operations
for instruction in experiment.instructions:
if hasattr(instruction, 'conditional'):
raise QisKitBackendError("Number of classical bits must be less than or equal to the"
raise QiskitBackendError("Number of classical bits must be less than or equal to the"
" number of qubits when using conditional gate operations")

@staticmethod
Expand Down Expand Up @@ -330,17 +330,17 @@ def __validate_unsupported_measurements(experiment: QasmQobjExperiment) -> None:
:param experiment: The experiment with gate operations and header.
:raises QisKitBackendError: When the circuit contains an invalid non-FSP measurement
:raises QiskitBackendError: When the circuit contains an invalid non-FSP measurement
"""
measurements: List[List[int]] = []
for instruction in experiment.instructions:
if instruction.name == 'measure':
for q, m in measurements:
if q == instruction.qubits[0] and m != instruction.memory[0]:
raise QisKitBackendError('Measurement of qubit {} to different classical registers '
raise QiskitBackendError('Measurement of qubit {} to different classical registers '
'is not supported'.format(q))
if q != instruction.qubits[0] and m == instruction.memory[0]:
raise QisKitBackendError('Measurement of different qubits to the same classical register {0} '
raise QiskitBackendError('Measurement of different qubits to the same classical register {0} '
'is not supported'.format(m))
measurements.append([instruction.qubits[0], instruction.memory[0]])

Expand Down Expand Up @@ -394,12 +394,12 @@ def __qubit_to_classical_hex(qubit_register: str, measurements: Dict[str, Any],
def __convert_histogram(result: Dict[str, Any], measurements: Dict[str, Any]) -> Dict[str, float]:
"""Convert histogram
The quantum inspire backend always uses full state projection. The SDK user
The Quantum Inspire backend always uses full state projection. The SDK user
can measure not all qubits and change the combined classical bits. This function
converts the result to a histogram output that represents the probabilities
measured with the classical bits.
:param result: The result output from the quantum inspire backend with full-
:param result: The result output from the Quantum Inspire backend with full-
state projection histogram output.
:param measurements: The dictionary contains a measured qubits/classical bits map (list) and the
number of classical bits (int).
Expand All @@ -423,7 +423,7 @@ def __convert_result_data(self, result: Dict[str, Any], measurements: Dict[str,
List[str]]:
"""Conver result data
The quantum inspire backend returns the single shot values as raw data. This function
The Quantum Inspire backend returns the single shot values as raw data. This function
converts this list of single shot values to hexadecimal memory data according the Qiskit spec.
From this memory data the counts histogram is constructed by counting the single shot values.
Expand All @@ -446,7 +446,7 @@ def __convert_result_data(self, result: Dict[str, Any], measurements: Dict[str,
When random is in the range [0.7, 1) the last value of the probability histogram is taken (0x6).
:param result: The result output from the quantum inspire backend with full-
:param result: The result output from the Quantum Inspire backend with full-
state projection histogram output.
:param measurements: The dictionary contains a measured qubits/classical bits map (list) and the
number of classical bits (int).
Expand Down
2 changes: 1 addition & 1 deletion src/quantuminspire/qiskit/circuit_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def _c_rz(stream: StringIO, instruction: QasmQobjInstruction, binary_control: st
def _u(stream: StringIO, instruction: QasmQobjInstruction) -> None:
""" Translates the U element to U3.
The u element is used by qiskit for the u_base gate and when a u0-gate
The u element is used by Qiskit for the u_base gate and when a u0-gate
is used in the circuit but not supported as a basis gate for the backend.
:param stream: The string-io stream to where the resulting cQASM is written.
Expand Down
Loading

0 comments on commit 6cc321f

Please sign in to comment.