Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove qiskit.test #1292

Merged
merged 9 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions qiskit_ibm_runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
Below is an example of using primitives within a session::
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Estimator, Options
from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.circuit.library import RealAmplitudes
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.quantum_info import SparsePauliOp
# Initialize account.
Expand All @@ -49,15 +49,21 @@
options = Options(optimization_level=3)
# Prepare inputs.
bell = ReferenceCircuits.bell()
psi = RealAmplitudes(num_qubits=2, reps=2)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
theta = [0, 1, 1, 2, 3, 5]
# Bell Circuit
qr = QuantumRegister(2, name="qr")
cr = ClassicalRegister(2, name="qc")
qc = QuantumCircuit(qr, cr, name="bell")
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.measure(qr, cr)
with Session(service=service, backend="ibmq_qasm_simulator") as session:
# Submit a request to the Sampler primitive within the session.
sampler = Sampler(session=session, options=options)
job = sampler.run(circuits=bell)
job = sampler.run(circuits=qc)
print(f"Sampler results: {job.result()}")
# Submit a request to the Estimator primitive within the session.
Expand Down Expand Up @@ -130,17 +136,25 @@
program by passing in the ``callback`` parameter, or at a later time using
the :meth:`RuntimeJob.stream_results` method. For example::
from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
service = QiskitRuntimeService()
backend = service.backend("ibmq_qasm_simulator")
# Bell Circuit
qr = QuantumRegister(2, name="qr")
cr = ClassicalRegister(2, name="qc")
qc = QuantumCircuit(qr, cr, name="bell")
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.measure(qr, cr)
def result_callback(job_id, result):
print(result)
# Stream results as soon as the job starts running.
job = Sampler(backend).run(ReferenceCircuits.bell(), callback=result_callback)
job = Sampler(backend).run(qc, callback=result_callback)
print(job.result())
Expand Down
13 changes: 10 additions & 3 deletions qiskit_ibm_runtime/qiskit_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class QiskitRuntimeService(Provider):
A sample workflow of using the runtime service::

from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Estimator, Options
from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.circuit.library import RealAmplitudes
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.quantum_info import SparsePauliOp

# Initialize account.
Expand All @@ -82,15 +82,22 @@ class QiskitRuntimeService(Provider):
options = Options(optimization_level=1)

# Prepare inputs.
bell = ReferenceCircuits.bell()
psi = RealAmplitudes(num_qubits=2, reps=2)
H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
theta = [0, 1, 1, 2, 3, 5]

# Bell Circuit
qr = QuantumRegister(2, name="qr")
cr = ClassicalRegister(2, name="qc")
qc = QuantumCircuit(qr, cr, name="bell")
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.measure(qr, cr)

with Session(service=service, backend="ibmq_qasm_simulator") as session:
# Submit a request to the Sampler primitive within the session.
sampler = Sampler(session=session, options=options)
job = sampler.run(circuits=bell)
job = sampler.run(circuits=qc)
print(f"Sampler results: {job.result()}")

# Submit a request to the Estimator primitive within the session.
Expand Down
13 changes: 10 additions & 3 deletions qiskit_ibm_runtime/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,23 @@ class Sampler(BasePrimitive, BaseSampler):

Example::

from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler

service = QiskitRuntimeService(channel="ibm_cloud")
bell = ReferenceCircuits.bell()

# Bell Circuit
qr = QuantumRegister(2, name="qr")
cr = ClassicalRegister(2, name="qc")
qc = QuantumCircuit(qr, cr, name="bell")
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.measure(qr, cr)

with Session(service, backend="ibmq_qasm_simulator") as session:
sampler = Sampler(session=session)

job = sampler.run(bell, shots=1024)
job = sampler.run(qc, shots=1024)
print(f"Job ID: {job.job_id()}")
print(f"Job result: {job.result()}")

Expand Down
12 changes: 10 additions & 2 deletions qiskit_ibm_runtime/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,22 @@ class Session:

For example::

from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_ibm_runtime import Sampler, Session, Options

# Bell Circuit
qr = QuantumRegister(2, name="qr")
cr = ClassicalRegister(2, name="qc")
qc = QuantumCircuit(qr, cr, name="bell")
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.measure(qr, cr)

options = Options(optimization_level=3)

with Session(backend="ibmq_qasm_simulator") as session:
sampler = Sampler(session=session, options=options)
job = sampler.run(ReferenceCircuits.bell())
job = sampler.run(qc)
print(f"Sampler job ID: {job.job_id()}")
print(f"Sampler job result: {job.result()}")

Expand Down
44 changes: 0 additions & 44 deletions qiskit_ibm_runtime/test/ibm_runtime_service_mock.py

This file was deleted.

104 changes: 97 additions & 7 deletions test/ibm_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@
import logging
import inspect
import warnings
from unittest import TestCase
from unittest.util import safe_repr
from contextlib import suppress
from collections import defaultdict
from typing import DefaultDict, Dict

from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.test.base import BaseQiskitTestCase

from qiskit_ibm_runtime import QISKIT_IBM_RUNTIME_LOGGER_NAME
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Options

from .utils import setup_test_logging
from .utils import setup_test_logging, bell
from .decorators import IntegrationTestDependencies, integration_test_setup


class IBMTestCase(BaseQiskitTestCase):
class IBMTestCase(TestCase):
"""Custom TestCase for use with qiskit-ibm-runtime."""

log: logging.Logger
Expand Down Expand Up @@ -69,6 +68,97 @@ def _set_logging_level(cls, logger: logging.Logger) -> None:
logger.addHandler(logging.StreamHandler())
logger.propagate = False

def assert_dict_almost_equal(
self, dict1, dict2, delta=None, msg=None, places=None, default_value=0
):
"""Assert two dictionaries with numeric values are almost equal.

Fail if the two dictionaries are unequal as determined by
comparing that the difference between values with the same key are
not greater than delta (default 1e-8), or that difference rounded
to the given number of decimal places is not zero. If a key in one
dictionary is not in the other the default_value keyword argument
will be used for the missing value (default 0). If the two objects
compare equal then they will automatically compare almost equal.

Args:
dict1 (dict): a dictionary.
dict2 (dict): a dictionary.
delta (number): threshold for comparison (defaults to 1e-8).
msg (str): return a custom message on failure.
places (int): number of decimal places for comparison.
default_value (number): default value for missing keys.

Raises:
TypeError: if the arguments are not valid (both `delta` and
`places` are specified).
AssertionError: if the dictionaries are not almost equal.
"""

error_msg = self.dicts_almost_equal(dict1, dict2, delta, places, default_value)

if error_msg:
msg = self._formatMessage(msg, error_msg)
raise self.failureException(msg)

def dicts_almost_equal(self, dict1, dict2, delta=None, places=None, default_value=0):
"""Test if two dictionaries with numeric values are almost equal.

Fail if the two dictionaries are unequal as determined by
comparing that the difference between values with the same key are
not greater than delta (default 1e-8), or that difference rounded
to the given number of decimal places is not zero. If a key in one
dictionary is not in the other the default_value keyword argument
will be used for the missing value (default 0). If the two objects
compare equal then they will automatically compare almost equal.

Args:
dict1 (dict): a dictionary.
dict2 (dict): a dictionary.
delta (number): threshold for comparison (defaults to 1e-8).
places (int): number of decimal places for comparison.
default_value (number): default value for missing keys.

Raises:
TypeError: if the arguments are not valid (both `delta` and
`places` are specified).

Returns:
String: Empty string if dictionaries are almost equal. A description
of their difference if they are deemed not almost equal.
"""

def valid_comparison(value):
"""compare value to delta, within places accuracy"""
if places is not None:
return round(value, places) == 0
else:
return value < delta

# Check arguments.
if dict1 == dict2:
return ""
if places is not None:
if delta is not None:
raise TypeError("specify delta or places not both")
msg_suffix = " within %s places" % places
else:
delta = delta or 1e-8
msg_suffix = " within %s delta" % delta

# Compare all keys in both dicts, populating error_msg.
error_msg = ""
for key in set(dict1.keys()) | set(dict2.keys()):
val1 = dict1.get(key, default_value)
val2 = dict2.get(key, default_value)
if not valid_comparison(abs(val1 - val2)):
error_msg += f"({safe_repr(key)}: {safe_repr(val1)} != {safe_repr(val2)}), "

if error_msg:
return error_msg[:-2] + msg_suffix
else:
return ""


class IBMIntegrationTestCase(IBMTestCase):
"""Custom integration test case for use with qiskit-ibm-runtime."""
Expand Down Expand Up @@ -163,7 +253,7 @@ def _run_program(
if inputs is not None
else {
"interim_results": interim_results or {},
"circuits": circuits or ReferenceCircuits.bell(),
"circuits": circuits or bell(),
}
)
pid = program_id or self.program_ids[service.channel]
Expand All @@ -184,7 +274,7 @@ def _run_program(
if max_execution_time:
options.max_execution_time = max_execution_time
sampler = Sampler(backend=backend, options=options)
job = sampler.run(circuits or ReferenceCircuits.bell(), callback=callback)
job = sampler.run(circuits or bell(), callback=callback)
else:
job = service.run(
program_id=pid,
Expand Down
6 changes: 3 additions & 3 deletions test/integration/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from qiskit.transpiler.target import Target
from qiskit import QuantumCircuit
from qiskit.providers.exceptions import QiskitBackendNotFoundError
from qiskit.test.reference_circuits import ReferenceCircuits

from qiskit_ibm_provider.ibm_qubit_properties import IBMQubitProperties
from qiskit_ibm_provider.exceptions import IBMBackendValueError
Expand All @@ -28,6 +27,7 @@

from ..ibm_test_case import IBMIntegrationTestCase
from ..decorators import run_integration_test, production_only, quantum_only
from ..utils import bell


class TestIntegrationBackend(IBMIntegrationTestCase):
Expand Down Expand Up @@ -243,7 +243,7 @@ def test_sim_backend_options(self):
backend = self.service.backend("ibmq_qasm_simulator")
backend.options.shots = 2048
backend.set_options(memory=True)
inputs = backend.run(ReferenceCircuits.bell(), shots=1, foo="foo").inputs
inputs = backend.run(bell(), shots=1, foo="foo").inputs
self.assertEqual(inputs["shots"], 1)
self.assertTrue(inputs["memory"])
self.assertEqual(inputs["foo"], "foo")
Expand All @@ -256,7 +256,7 @@ def test_paused_backend_warning(self):
paused_status.status_msg = "internal"
backend.status = mock.MagicMock(return_value=paused_status)
with self.assertWarns(Warning):
backend.run(ReferenceCircuits.bell())
backend.run(bell())

def test_backend_wrong_instance(self):
"""Test that an error is raised when retrieving a backend not in the instance."""
Expand Down
Loading
Loading