Skip to content

Commit

Permalink
Convert backend.run() tests to use SamplerV2 (#1571)
Browse files Browse the repository at this point in the history
* Initial commit

* update integration tests

* Update test_fake_backends

* convert test_fake_backends

* convert test_backend

* more tests

* Remove remaining backend.run tests

* black

* update test_ibm_job

* Update last job tags tests
  • Loading branch information
kt474 authored May 10, 2024
1 parent 3034bb2 commit 279b937
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 379 deletions.
7 changes: 5 additions & 2 deletions qiskit_ibm_runtime/fake_provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from qiskit import QuantumCircuit
from qiskit import transpile
from qiskit.visualization import plot_histogram
from qiskit_ibm_runtime import SamplerV2
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
# Get a fake backend from the fake provider
Expand All @@ -55,8 +56,10 @@
transpiled_circuit.draw('mpl', style="iqp")
# Run the transpiled circuit using the simulated fake backend
job = backend.run(transpiled_circuit)
counts = job.result().get_counts()
sampler = SamplerV2(backend)
job = sampler.run([transpiled_circuit])
pub_result = job.result()[0]
counts = pub_result.data.meas.get_counts()
plot_histogram(counts)
.. important::
Expand Down
23 changes: 12 additions & 11 deletions test/integration/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@
from qiskit import QuantumCircuit
from qiskit.providers.exceptions import QiskitBackendNotFoundError
from qiskit.providers.backend import QubitProperties
from qiskit_ibm_runtime.exceptions import IBMInputValueError

from qiskit_ibm_runtime.exceptions import IBMBackendValueError

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

from ..ibm_test_case import IBMIntegrationTestCase
from ..decorators import run_integration_test, production_only, quantum_only
Expand Down Expand Up @@ -250,10 +249,9 @@ 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(bell(), shots=1, foo="foo").inputs
self.assertEqual(inputs["shots"], 1)
self.assertTrue(inputs["memory"])
self.assertEqual(inputs["foo"], "foo")
sampler = Sampler(backend=backend)
inputs = sampler.run([bell()], shots=1).inputs
self.assertEqual(inputs["pubs"][0][2], 1)

@production_only
def test_paused_backend_warning(self):
Expand All @@ -263,7 +261,8 @@ 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(bell())
sampler = Sampler(backend=backend)
sampler.run([bell()])

def test_backend_wrong_instance(self):
"""Test that an error is raised when retrieving a backend not in the instance."""
Expand Down Expand Up @@ -296,9 +295,11 @@ def test_too_many_qubits_in_circuit(self):
num = len(self.backend.properties().qubits)
num_qubits = num + 1
circuit = QuantumCircuit(num_qubits, num_qubits)
with self.assertRaises(IBMBackendValueError) as err:
_ = self.backend.run(circuit)
with self.assertRaises(IBMInputValueError) as err:
sampler = Sampler(backend=self.backend)
job = sampler.run([circuit])
job.cancel()
self.assertIn(
f"Circuit contains {num_qubits} qubits, but backend has only {num}.",
f"circuit has {num_qubits} qubits but the target system requires {num}",
str(err.exception),
)
23 changes: 15 additions & 8 deletions test/integration/test_fake_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
CZGate,
ECRGate,
)
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_ibm_runtime import SamplerV2 as Sampler

from qiskit_ibm_runtime.fake_provider import (
FakeProviderForBackendV2,
Expand Down Expand Up @@ -63,11 +66,13 @@ def setUpClass(cls):
def test_circuit_on_fake_backend_v2(self, backend, optimization_level):
if not optionals.HAS_AER and backend.num_qubits > 20:
self.skipTest("Unable to run fake_backend %s without qiskit-aer" % backend.backend_name)
circuit = transpile(self.circuit, optimization_level=optimization_level, seed_transpiler=42)
backend.set_options(seed_simulator=42)
job = backend.run(circuit)
result = job.result()
counts = result.get_counts()
pm = generate_preset_pass_manager(backend=backend, optimization_level=optimization_level)
isa_circuit = pm.run(self.circuit)
sampler = Sampler(backend)
job = sampler.run([isa_circuit])
pub_result = job.result()[0]
counts = pub_result.data.meas.get_counts()
max_count = max(counts.items(), key=operator.itemgetter(1))[0]
self.assertEqual(max_count, "11")

Expand All @@ -84,11 +89,13 @@ def test_circuit_on_fake_backend(self, backend, optimization_level):
"Unable to run fake_backend %s without qiskit-aer"
% backend.configuration().backend_name
)
circuit = transpile(self.circuit, optimization_level=optimization_level, seed_transpiler=42)
backend.set_options(seed_simulator=42)
job = backend.run(circuit)
result = job.result()
counts = result.get_counts()
pm = generate_preset_pass_manager(backend=backend, optimization_level=optimization_level)
isa_circuit = pm.run(self.circuit)
sampler = Sampler(backend)
job = sampler.run([isa_circuit])
pub_result = job.result()[0]
counts = pub_result.data.meas.get_counts()
max_count = max(counts.items(), key=operator.itemgetter(1))[0]
self.assertEqual(max_count, "11")

Expand Down
61 changes: 25 additions & 36 deletions test/integration/test_ibm_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
from dateutil import tz
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.compiler import transpile
from qiskit.providers.jobstatus import JobStatus, JOB_FINAL_STATES

from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_ibm_runtime.exceptions import RuntimeJobTimeoutError, RuntimeJobNotFound

from ..ibm_test_case import IBMIntegrationTestCase
Expand All @@ -35,7 +35,8 @@ def setUp(self):
super().setUp()
self.sim_backend = self.service.backend("ibmq_qasm_simulator")
self.bell = bell()
self.sim_job = self.sim_backend.run(self.bell)
sampler = Sampler(backend=self.sim_backend)
self.sim_job = sampler.run([self.bell])
self.last_month = datetime.now() - timedelta(days=30)

def test_run_multiple_simulator(self):
Expand All @@ -48,26 +49,26 @@ def test_run_multiple_simulator(self):
quantum_circuit.cx(quantum_register[i], quantum_register[i + 1])
quantum_circuit.measure(quantum_register, classical_register)
num_jobs = 4
sampler = Sampler(backend=self.sim_backend)
job_array = [
self.sim_backend.run(transpile([quantum_circuit] * 20), shots=2048)
for _ in range(num_jobs)
sampler.run(transpile([quantum_circuit] * 20), shots=2048) for _ in range(num_jobs)
]
timeout = 30
start_time = time.time()
while True:
check = sum(job.status() is JobStatus.RUNNING for job in job_array)
check = sum(job.status() == "RUNNING" for job in job_array)
if check >= 2:
self.log.info("found %d simultaneous jobs", check)
break
if all((job.status() is JobStatus.DONE for job in job_array)):
if all((job.status() == "DONE" for job in job_array)):
# done too soon? don't generate error
self.log.warning("all jobs completed before simultaneous jobs could be detected")
break
for job in job_array:
self.log.info(
"%s %s %s %s",
job.status(),
job.status() is JobStatus.RUNNING,
job.status() == "RUNNING",
check,
job.job_id(),
)
Expand All @@ -81,8 +82,8 @@ def test_run_multiple_simulator(self):
result_array = [job.result() for job in job_array]
self.log.info("got back all job results")
# Ensure all jobs have finished.
self.assertTrue(all((job.status() is JobStatus.DONE for job in job_array)))
self.assertTrue(all((result.success for result in result_array)))
self.assertTrue(all((job.status() == "DONE" for job in job_array)))
self.assertTrue(all((result.metadata for result in result_array)))

# Ensure job ids are unique.
job_ids = [job.job_id() for job in job_array]
Expand Down Expand Up @@ -114,20 +115,19 @@ def test_retrieve_completed_jobs(self):
backend_name=self.sim_backend.name, limit=3, pending=False
)
for job in completed_job_list:
self.assertTrue(job.status() in [JobStatus.DONE, JobStatus.CANCELLED, JobStatus.ERROR])
self.assertTrue(job.status() in ["DONE", "CANCELLED", "ERROR"])

def test_retrieve_pending_jobs(self):
"""Test retrieving jobs with the pending filter."""
pending_job_list = self.service.jobs(program_id="sampler", limit=3, pending=True)
for job in pending_job_list:
self.assertTrue(job.status() in [JobStatus.QUEUED, JobStatus.RUNNING])
self.assertTrue(job.status() in ["QUEUED", "RUNNING"])

def test_retrieve_job(self):
"""Test retrieving a single job."""
retrieved_job = self.service.job(self.sim_job.job_id())
self.assertEqual(self.sim_job.job_id(), retrieved_job.job_id())
self.assertEqual(self.sim_job.inputs["circuits"], retrieved_job.inputs["circuits"])
self.assertEqual(self.sim_job.result().get_counts(), retrieved_job.result().get_counts())
self.assertEqual(self.sim_job.result().metadata, retrieved_job.result().metadata)

def test_retrieve_job_error(self):
"""Test retrieving an invalid job."""
Expand All @@ -146,7 +146,7 @@ def test_retrieve_jobs_status(self):

for job in backend_jobs:
self.assertTrue(
job.status() in JOB_FINAL_STATES,
job.status() in ["DONE", "CANCELLED", "ERROR"],
"Job {} has status {} when it should be DONE, CANCELLED, or ERROR".format(
job.job_id(), job.status()
),
Expand Down Expand Up @@ -218,7 +218,8 @@ def test_retrieve_jobs_between_datetimes(self):

def test_retrieve_jobs_order(self):
"""Test retrieving jobs with different orders."""
job = self.sim_backend.run(self.bell)
sampler = Sampler(backend=self.sim_backend)
job = sampler.run([self.bell])
job.wait_for_final_state()
newest_jobs = self.service.jobs(
limit=20,
Expand All @@ -241,25 +242,26 @@ def test_refresh_job_result(self):
result = self.sim_job.result()

# Save original cached results.
cached_result = copy.deepcopy(result.to_dict())
cached_result = copy.deepcopy(result.metadata)
self.assertTrue(cached_result)

# Modify cached results.
result.results[0].header.name = "modified_result"
self.assertNotEqual(cached_result, result.to_dict())
self.assertEqual(result.results[0].header.name, "modified_result")
result.metadata["test"] = "modified_result"
self.assertNotEqual(cached_result, result.metadata)
self.assertEqual(result.metadata["test"], "modified_result")

# Re-retrieve result.
result = self.sim_job.result()
self.assertDictEqual(cached_result, result.to_dict())
self.assertNotEqual(result.results[0].header.name, "modified_result")
self.assertDictEqual(cached_result, result.metadata)
self.assertFalse("test" in result.metadata)

def test_wait_for_final_state_timeout(self):
"""Test waiting for job to reach final state times out."""
if self.dependencies.channel == "ibm_cloud":
raise SkipTest("Cloud account does not have real backend.")
backend = most_busy_backend(TestIBMJob.service)
job = backend.run(transpile(bell(), backend=backend))
sampler = Sampler(backend=backend)
job = sampler.run([transpile(bell(), backend=backend)])
try:
self.assertRaises(RuntimeJobTimeoutError, job.wait_for_final_state, timeout=0.1)
finally:
Expand All @@ -270,17 +272,4 @@ def test_wait_for_final_state_timeout(self):

def test_job_circuits(self):
"""Test job circuits."""
self.assertEqual(str(self.bell), str(self.sim_job.inputs["circuits"][0]))

def test_job_options(self):
"""Test job options."""
run_config = {"shots": 2048, "memory": True}
job = self.sim_backend.run(self.bell, **run_config)
self.assertLessEqual(run_config.items(), job.inputs.items())

def test_job_header(self):
"""Test job header."""
custom_header = {"test": "test_job_header"}
job = self.sim_backend.run(self.bell, header=custom_header)
self.assertEqual(custom_header["test"], job.inputs["header"]["test"])
self.assertLessEqual(custom_header.items(), job.inputs["header"].items())
self.assertEqual(str(self.bell), str(self.sim_job.inputs["pubs"][0][0]))
Loading

0 comments on commit 279b937

Please sign in to comment.